TSI_Config/singlerelay.cpp

447 lines
18 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "singlerelay.h"
#include "ui_singlerelay.h"
#include "vibrationdata.h"
#include <QStack>
#include <QMessageBox>
#include <QMenu>
SingleRelay::SingleRelay(int slot,int cardtype,QWidget *parent)
: QDialog(parent)
, ui(new Ui::SingleRelay) {
ui->setupUi(this);
slot_no = slot;
car_type = static_cast<CardType>(cardtype);
ui->label_slot_no->setText(QString::number(slot_no));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
QVBoxLayout *layout_available = new QVBoxLayout(ui->widget_available);
list_widget_available = new QListWidget();
layout_available->addWidget(list_widget_available);
list_widget_available->setDragEnabled(true);
QVBoxLayout *layout_relay = new QVBoxLayout(ui->widget_relay);
treeView_relay = new QTreeView;
layout_relay->addWidget(treeView_relay);
treeView_relay->setDragEnabled(true); // 启用拖动
treeView_relay->setAcceptDrops(true); // 接受放下
treeView_relay->setDropIndicatorShown(true); // 显示放置指示器
treeView_relay->setDragDropMode(QAbstractItemView::DropOnly);
model_Relay = new DropTreeModel(this); //创建模型指定父类
treeView_relay->setModel(model_Relay);
treeView_relay->setHeaderHidden(true);
btnGroup_slot = new QButtonGroup(this);
btnGroup_slot->addButton(ui->pushButton_slot1);
btnGroup_slot->addButton(ui->pushButton_slot2);
btnGroup_slot->addButton(ui->pushButton_slot3);
btnGroup_slot->addButton(ui->pushButton_slot4);
btnGroup_slot->addButton(ui->pushButton_slot5);
btnGroup_slot->addButton(ui->pushButton_slot6);
btnGroup_slot->addButton(ui->pushButton_slot7);
btnGroup_slot->addButton(ui->pushButton_slot8);
btnGroup_slot->addButton(ui->pushButton_slot9);
btnGroup_slot->addButton(ui->pushButton_slot10);
btnGroup_slot->addButton(ui->pushButton_slot11);
btnGroup_slot->addButton(ui->pushButton_slot12);
btnGroup_slot->addButton(ui->pushButton_slot13);
btnGroup_slot->addButton(ui->pushButton_slot14);
btnGroup_slot->addButton(ui->pushButton_slot15);
btnGroup_slot->addButton(ui->pushButton_slot16);
connect(btnGroup_slot, SIGNAL(buttonClicked(QAbstractButton *)), this, SLOT(OnButtonGroup(QAbstractButton *)));
connect(ui->comboBox_relay_ch, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &SingleRelay::onComboBoxIndexChanged);
treeView_relay->setContextMenuPolicy(Qt::CustomContextMenu);
connect(treeView_relay,&QTreeView::customContextMenuRequested,this,&SingleRelay::on_treeView_Relay_customContextMenuRequested);
current_index = ui->comboBox_relay_ch->currentIndex();
Init();
onComboBoxIndexChanged(current_index);
}
SingleRelay::~SingleRelay() {
delete ui;
}
void SingleRelay::Init(){
QList<QAbstractButton *> buttonList = btnGroup_slot->buttons();
for (int i = 1; i < buttonList.count() + 1; i++) {
std::shared_ptr<CardBase> base_ptr = ConfigMgr::Instance()->GetSlotPtr(i);
if(base_ptr != nullptr){
switch (base_ptr->card_type_) {
case kCardVibSingle :{
buttonList[i - 1]->setText("振动");
break;
}
case kCardKeyphaseSingle:{
buttonList[i - 1]->setText("键相");
break;
}
case kCardSpeedSingle:{
buttonList[i - 1]->setText("转速");
break;
}
case kCardRelaySingle:
case kCardRelaySingleNOK:
case kCardRelayTMRPrimary:{
buttonList[i - 1]->setText("继电器");
break;
}
default:
break;
}
}
}
std::shared_ptr<CardBase> base_ptr = ConfigMgr::Instance()->GetSlotPtr(slot_no);
if (base_ptr == nullptr) {
// do nothing or use template to init it.
relay_data = std::make_shared<SingleRelayData>();
relay_data->card_type_ = car_type;
relay_data->slot_ = slot_no;
ConfigMgr::Instance()->AddCard(relay_data);
return;
}
relay_data = std::dynamic_pointer_cast<SingleRelayData>(base_ptr);
qDebug() << "logic" <<relay_data->single_relay[current_index].logic_expression;
for(int i = 0 ; i < SLOT_NUM ; i++){
std::shared_ptr<CardBase> cardbase_ptr = ConfigMgr::Instance()->GetSlotPtr(i + 1);
if(cardbase_ptr != nullptr &&
cardbase_ptr->card_type_ == kCardVibSingle){
qDebug() << "i" << i;
std::shared_ptr<VibrationData> ptr = std::dynamic_pointer_cast<VibrationData>(cardbase_ptr);
for (int var = 0; var < CHANNEL_COUNT; ++var) {
QString item_data,item_str;
if(ptr->alert_danger[var].direct_enable ||
ptr->alert_danger[var].x1_ampl_enable ||
ptr->alert_danger[var].x2_ampl_enable){
item_str = QString("%1 (槽位 %2 通道 %3 警报)").arg(ptr->base_config_[var].point_name).arg(ptr->base_config_[var].chan_id.mid(1,2)).arg(ptr->base_config_[var].chan_id.mid(4,2));
item_data = QString("%1A1").arg(ptr->base_config_[var].chan_id);
}
channelNameMap[item_data] = item_str;
if(ptr->alert_danger[var].danger_enable){
item_str = QString("%1 (槽位 %2 通道 %3 危险)").arg(ptr->base_config_[var].point_name).arg(ptr->base_config_[var].chan_id.mid(1,2)).arg(ptr->base_config_[var].chan_id.mid(4,2));
item_data = QString("%1A2").arg(ptr->base_config_[var].chan_id);
}
channelNameMap[item_data] = item_str;
item_str = QString("%1 (槽位 %2 通道 %3 非OK)").arg(ptr->base_config_[var].point_name).arg(ptr->base_config_[var].chan_id.mid(1,2)).arg(ptr->base_config_[var].chan_id.mid(4,2));
item_data = QString("%1P##NO").arg(ptr->base_config_[var].chan_id);
channelNameMap[item_data] = item_str;
}
}else if(cardbase_ptr != nullptr &&
cardbase_ptr->card_type_ == kCardSpeedSingle){
}
}
if(!relay_data->single_relay[current_index].logic_expression.isEmpty()){
setExpressionToTreeView(treeView_relay, relay_data->single_relay[current_index].logic_expression);
}
}
void SingleRelay::on_pushButton_cancel_clicked() {
this->close();
}
void SingleRelay::OnButtonGroup(QAbstractButton *slot_btn) {
if (slot_btn != NULL) {
list_widget_available->clear();
QString object_name = slot_btn->objectName();
qDebug() << object_name ;
int button_id = object_name.right(object_name.length() - 15).toInt();
std::shared_ptr<CardBase> base_ptr = ConfigMgr::Instance()->GetSlotPtr(button_id);
std::shared_ptr<VibrationData> ptr = std::dynamic_pointer_cast<VibrationData>(base_ptr);
QListWidgetItem *item_and = new QListWidgetItem("AND");
item_and->setData(Qt::UserRole, "*");
list_widget_available->addItem(item_and);
QListWidgetItem *item_or = new QListWidgetItem("OR");
item_or->setData(Qt::UserRole, "+");
list_widget_available->addItem(item_or);
for(int var = 0; var < CHANNEL_COUNT ; ++var){
std::shared_ptr<CardBase> base_ptr = ConfigMgr::Instance()->GetSlotPtr(button_id);
if(base_ptr->card_type_ == kCardVibSingle){
QString item_data;
if(ptr->base_config_[var].standby && (var % 2))
continue;
if(ptr->alert_danger[var].direct_enable ||
ptr->alert_danger[var].x1_ampl_enable ||
ptr->alert_danger[var].x2_ampl_enable){
QString item_str = QString("%1 (槽位 %3 通道 %4 警报)").arg(ptr->base_config_[var].point_name).arg(QString::number(button_id, 10).rightJustified(2, '0')).arg(QString::number(var+1, 10).rightJustified(2, '0'));
QListWidgetItem *item = new QListWidgetItem(item_str);
item_data = QString("S%1C%2A1").arg(QString::number(button_id, 10).rightJustified(2, '0')).arg(QString::number(var+1, 10).rightJustified(2, '0'));
item->setData(Qt::UserRole, item_data);
list_widget_available->addItem(item);
}
if(ptr->alert_danger[var].danger_enable){
QString item_str = QString("%1 (槽位 %3 通道 %4 危险)").arg(ptr->base_config_[var].point_name).arg(QString::number(button_id, 10).rightJustified(2, '0')).arg(QString::number(var+1, 10).rightJustified(2, '0'));
QListWidgetItem *item = new QListWidgetItem(item_str);
item_data = QString("S%1C%2A2").arg(QString::number(button_id, 10).rightJustified(2, '0')).arg(QString::number(var+1, 10).rightJustified(2, '0'));
item->setData(Qt::UserRole, item_data);
list_widget_available->addItem(item);
}
QString item_str = QString("%1 (槽位 %2 通道 %3 非OK)").arg(ptr->base_config_[var].point_name).arg(QString::number(button_id, 10).rightJustified(2, '0')).arg(QString::number(var+1, 10).rightJustified(2, '0'));
QListWidgetItem *item = new QListWidgetItem(item_str);
QString item_data_nok = QString("S%1C%2P##NO").arg(QString::number(button_id, 10).rightJustified(2, '0')).arg(QString::number(var+1, 10).rightJustified(2, '0'));
item->setData(Qt::UserRole, item_data_nok);
list_widget_available->addItem(item);
}
}
}
}
void SingleRelay::keyPressEvent(QKeyEvent *event) {
// if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {
// removeLastElement();
// return;
// }
// QTextEdit::keyPressEvent(event);
}
QString SingleRelay::buildLogicExpression(QStandardItem *item) {
if (!item) return "";
int childCount = item->rowCount();
QVariant userData = item->data(Qt::UserRole);
QString text = userData.toString().trimmed();
qDebug() << "item" << userData;
if (childCount == 0) {
// 叶子节点,直接返回表达式,比如 S01C01A1
return text;
}
// 判断当前是 +OR还是 *AND
QString opStr = (text == "+") ? "+" :
(text == "*") ? "*" : "";
// 如果不是 +/*,视为叶子节点
if (opStr.isEmpty()) {
return text;
}
QStringList subExprs;
for (int i = 0; i < childCount; ++i) {
QStandardItem *child = item->child(i);
subExprs << buildLogicExpression(child);
}
return "(" + subExprs.join(" " + opStr + " ") + ")";
}
void SingleRelay::on_pushButton_confirm_clicked()
{
QStandardItemModel *model = qobject_cast<QStandardItemModel *>(treeView_relay->model());
if (!model) return;
QStandardItem *root = model->invisibleRootItem();
QString finalExpr;
for (int i = 0; i < root->rowCount(); ++i) {
QStandardItem *topItem = root->child(i);
QString expr = buildLogicExpression(topItem);
finalExpr += expr;
}
ExprValidationResult result = validateLogicExpression(finalExpr);
if (!result.isValid && !finalExpr.isEmpty()) {
QMessageBox::warning(this, "表达式错误",
QString("错误位置:%1\n错误描述:%2").arg(result.errorPos).arg(result.errorMsg));
return;
}
relay_data->single_relay[current_index].logic_expression = finalExpr;
qDebug() << "逻辑表达式:" << finalExpr;
this->close();
}
void SingleRelay::onComboBoxIndexChanged(int index){
qDebug()<< "[SingleRelay]:index " << index;
QStandardItemModel *model = qobject_cast<QStandardItemModel *>(treeView_relay->model());
if (!model) return;
QStandardItem *root = model->invisibleRootItem();
QString finalExpr;
for (int i = 0; i < root->rowCount(); ++i) {
QStandardItem *topItem = root->child(i);
QString expr = buildLogicExpression(topItem);
finalExpr += expr;
}
ExprValidationResult result = validateLogicExpression(finalExpr);
if (!result.isValid && !finalExpr.isEmpty()) {
QMessageBox::warning(this, "表达式错误",
QString("错误位置:%1\n错误描述:%2").arg(result.errorPos).arg(result.errorMsg));
return;
}
qDebug() << "finalExpr" << finalExpr;
relay_data->single_relay[current_index].logic_expression = finalExpr;
current_index = index;
if(relay_data->single_relay[index].logic_expression != "")
setExpressionToTreeView(treeView_relay, relay_data->single_relay[index].logic_expression);
else
model_Relay->clear();
}
ExprNode* SingleRelay::parseExpression(const QString& expr, int& pos) {
auto skipSpaces = [&]() {
while (pos < expr.length() && expr[pos].isSpace()) pos++;
};
QStack<ExprNode*> nodeStack;
QStack<QString> opStack;
while (pos < expr.length()) {
skipSpaces();
if (pos >= expr.length()) break;
QChar ch = expr[pos];
if (ch == '(') {
pos++;
nodeStack.push(parseExpression(expr, pos));
} else if (ch == ')') {
pos++;
break;
} else if (ch == '+' || ch == '*') {
opStack.push(QString(ch));
pos++;
} else {
QString token;
while (pos < expr.length() && !QString("()+* ").contains(expr[pos])) {
token += expr[pos++];
}
if (!token.isEmpty()) {
nodeStack.push(new ExprNode{token, {}});
}
}
while (opStack.size() > 0 && nodeStack.size() >= 2) {
QString op = opStack.pop();
ExprNode* right = nodeStack.pop();
ExprNode* left = nodeStack.pop();
if (left->value == op) {
left->children.append(right);
nodeStack.push(left);
} else if (right->value == op) {
right->children.prepend(left);
nodeStack.push(right);
} else {
ExprNode* parent = new ExprNode{op, {left, right}};
nodeStack.push(parent);
}
}
}
return nodeStack.isEmpty() ? nullptr : nodeStack.top();
}
QStandardItem* SingleRelay::buildItemTree(ExprNode* node) {
if (!node) return nullptr;
QString displayText;
if (node->value == "+" || node->value == "*") {
displayText = (node->value == "+") ? "OR" : "AND"; // 运算符显示
} else {
displayText = channelNameMap.value(node->value, node->value); // 显示名
qDebug() << "display" <<displayText << node->value;
}
QStandardItem* item = new QStandardItem(displayText);
item->setData(node->value, Qt::UserRole); // 原始表达式key
for (ExprNode* child : node->children) {
item->appendRow(buildItemTree(child));
}
return item;
}
ExprValidationResult SingleRelay::validateLogicExpression(const QString& expr) {
int bracketCount = 0;
bool lastWasOperator = true;
bool lastWasOpenParen = false;
for (int i = 0; i < expr.length(); ++i) {
QChar ch = expr[i];
if (ch.isSpace()) continue;
if (ch == '(') {
bracketCount++;
lastWasOpenParen = true;
lastWasOperator = true;
} else if (ch == ')') {
bracketCount--;
if (bracketCount < 0) {
return {false, i, "多余的右括号 ')'"};
}
lastWasOpenParen = false;
lastWasOperator = false;
} else if (ch == '+' || ch == '*') {
if (lastWasOperator || lastWasOpenParen) {
return {false, i, QString("无效的运算符 '%1' 的位置").arg(ch)};
}
lastWasOperator = true;
lastWasOpenParen = false;
} else if (ch.isLetterOrNumber()) {
QString token;
int start = i;
while (i < expr.length() && expr[i].isLetterOrNumber()) {
token += expr[i];
++i;
}
--i; // 修正多读了一位
if (token.isEmpty()) {
return {false, start, "变量名称缺失"};
}
lastWasOperator = false;
lastWasOpenParen = false;
} else if (ch.isLetterOrNumber() || ch == '#' || ch.unicode() > 127) {
QString token;
int start = i;
while (i < expr.length() &&
(expr[i].isLetterOrNumber() || expr[i] == '#' || expr[i].unicode() > 127)) {
token += expr[i];
++i;
}
--i;
if (token.isEmpty()) {
return {false, start, "变量名称缺失"};
}
lastWasOperator = false;
lastWasOpenParen = false;
}else {
return {false, i, QString("不支持的字符 '%1'").arg(ch)};
}
}
if (bracketCount != 0) {
return {false, expr.length(), "括号不匹配"};
}
if (lastWasOperator) {
return {false, expr.length() - 1, "表达式不能以运算符结尾"};
}
return {true, -1, ""};
}
void SingleRelay::setExpressionToTreeView(QTreeView* treeView, const QString& expr) {
int pos = 0;
model_Relay->clear();
ExprNode* root = parseExpression(expr, pos);
QStandardItem* rootItem = buildItemTree(root);
model_Relay->appendRow(rootItem);
treeView_relay->expandAll();
}
void SingleRelay::slotDeleteItem()
{
QModelIndex curIndex = treeView_relay->currentIndex();
if(curIndex.isValid()){
model_Relay->removeRow(curIndex.row(),curIndex.parent());
}
}
void SingleRelay::on_treeView_Relay_customContextMenuRequested(const QPoint &pos)
{
qDebug() << "on_treeView_Relay_customContextMenuRequested" <<endl;
QModelIndex curIndex = treeView_relay->indexAt(pos); //当前点击的元素的index
QModelIndex index = curIndex.sibling(curIndex.row(),0); //该行的第1列元素的index
QMenu menu(this);
if (index.isValid()){
//添加一行菜单,进行展开
menu.addAction(QStringLiteral("删除"), this, SLOT(slotDeleteItem()));
menu.addSeparator(); //添加一个分隔线
}
menu.exec(QCursor::pos()); //显示菜单
}