2024-12-18 16:46:39 +08:00
|
|
|
|
#include "tmrrelayassociation.h"
|
|
|
|
|
#include "ui_tmrrelayassociation.h"
|
2025-04-19 16:25:33 +08:00
|
|
|
|
#include "vibrationdata.h"
|
|
|
|
|
#include <QStack>
|
|
|
|
|
#include <QMenu>
|
2025-04-21 17:23:38 +08:00
|
|
|
|
#include <QMessageBox>
|
2025-04-19 19:54:56 +08:00
|
|
|
|
|
2025-04-19 16:25:33 +08:00
|
|
|
|
TMRRelayAssociation::TMRRelayAssociation(int slot,int cardtype,QWidget *parent)
|
2024-12-18 16:46:39 +08:00
|
|
|
|
: QDialog(parent)
|
|
|
|
|
, ui(new Ui::TMRRelayAssociation)
|
|
|
|
|
{
|
|
|
|
|
ui->setupUi(this);
|
2025-04-19 16:25:33 +08:00
|
|
|
|
slot_no = slot;
|
|
|
|
|
car_type = static_cast<CardType>(cardtype);
|
2025-04-21 17:23:38 +08:00
|
|
|
|
if(car_type == kCardRelaySingle){
|
|
|
|
|
ui->checkBox_sgcc->setVisible(0);
|
|
|
|
|
}
|
2025-04-19 16:25:33 +08:00
|
|
|
|
ui->label_slot_no->setText(QString::number(slot_no));
|
|
|
|
|
QVBoxLayout *layout_available = new QVBoxLayout(ui->widget_available);
|
2025-04-23 14:44:58 +08:00
|
|
|
|
list_widget_available = new QListWidget();
|
2025-04-19 16:25:33 +08:00
|
|
|
|
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, &TMRRelayAssociation::onComboBoxIndexChanged);
|
|
|
|
|
treeView_relay->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
|
|
|
connect(treeView_relay,&QTreeView::customContextMenuRequested,this,&TMRRelayAssociation::on_treeView_Relay_customContextMenuRequested);
|
|
|
|
|
current_index = ui->comboBox_relay_ch->currentIndex();
|
2025-04-21 17:23:38 +08:00
|
|
|
|
Init();
|
2025-04-23 14:44:58 +08:00
|
|
|
|
onComboBoxIndexChanged(current_index);
|
2025-04-19 16:25:33 +08:00
|
|
|
|
// QString expr = "((S01C01A1 + S01C02A1 + (S02C01A1 * S02C01A2)) * (S02C01A2 + S02C01A1 + (S02C01A1 + S02C01A2)) * (S02C01A1 * S02C01A2))";
|
|
|
|
|
// setExpressionToTreeView(treeView_relay, expr);
|
2024-12-18 16:46:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TMRRelayAssociation::~TMRRelayAssociation()
|
|
|
|
|
{
|
|
|
|
|
delete ui;
|
|
|
|
|
}
|
2025-04-19 16:25:33 +08:00
|
|
|
|
void TMRRelayAssociation::Init(){
|
2025-04-19 19:54:56 +08:00
|
|
|
|
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<TmrrelayassociationData>();
|
|
|
|
|
relay_data->card_type_ = car_type;
|
|
|
|
|
relay_data->slot_ = slot_no;
|
|
|
|
|
ConfigMgr::Instance()->AddCard(relay_data);
|
2025-04-21 20:30:12 +08:00
|
|
|
|
|
|
|
|
|
std::shared_ptr<TmrrelayassociationData> relay_data_backup = std::make_shared<TmrrelayassociationData>();
|
|
|
|
|
relay_data_backup->card_type_ = kCardRelayTMRBackup;
|
|
|
|
|
relay_data_backup->slot_ = slot_no + 1;
|
|
|
|
|
ConfigMgr::Instance()->AddCard(relay_data_backup);
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<TmrrelayassociationData> relay_data_backup2 = std::make_shared<TmrrelayassociationData>();
|
|
|
|
|
relay_data_backup2->card_type_ = kCardRelayTMRBackup;
|
|
|
|
|
relay_data_backup2->slot_ = slot_no + 2;
|
|
|
|
|
ConfigMgr::Instance()->AddCard(relay_data_backup2);
|
|
|
|
|
|
2025-04-19 19:54:56 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
relay_data = std::dynamic_pointer_cast<TmrrelayassociationData>(base_ptr);
|
2025-04-23 14:44:58 +08:00
|
|
|
|
|
2025-04-21 17:23:38 +08:00
|
|
|
|
qDebug() << "logic" <<relay_data->tmr_relay[current_index].logic_expression;
|
2025-04-23 14:44:58 +08:00
|
|
|
|
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);
|
|
|
|
|
}
|
2025-04-27 15:23:05 +08:00
|
|
|
|
channelNameMap[item_data] = item_str;
|
2025-04-23 14:44:58 +08:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}else if(cardbase_ptr != nullptr &&
|
2025-04-23 17:13:05 +08:00
|
|
|
|
cardbase_ptr->card_type_ == kCardSpeedSingle){
|
2025-04-19 16:25:33 +08:00
|
|
|
|
|
2025-04-23 14:44:58 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ui->checkBox_sgcc->setChecked(relay_data->sgcc_enable);
|
|
|
|
|
if(!relay_data->tmr_relay[current_index].logic_expression.isEmpty()){
|
|
|
|
|
setExpressionToTreeView(treeView_relay, relay_data->tmr_relay[current_index].logic_expression);
|
|
|
|
|
}
|
2025-04-19 16:25:33 +08:00
|
|
|
|
}
|
2025-04-23 17:13:05 +08:00
|
|
|
|
|
2025-04-19 16:25:33 +08:00
|
|
|
|
ExprNode* TMRRelayAssociation::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() && expr[pos].isLetterOrNumber()) {
|
|
|
|
|
token += expr[pos++];
|
|
|
|
|
}
|
|
|
|
|
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* TMRRelayAssociation::buildItemTree(ExprNode* node) {
|
|
|
|
|
if (!node) return nullptr;
|
2025-04-23 14:44:58 +08:00
|
|
|
|
QString displayText;
|
|
|
|
|
if (node->value == "+" || node->value == "*") {
|
|
|
|
|
displayText = (node->value == "+") ? "OR" : "AND"; // 运算符显示
|
|
|
|
|
} else {
|
|
|
|
|
displayText = channelNameMap.value(node->value, node->value); // 显示名
|
2025-04-27 15:23:05 +08:00
|
|
|
|
qDebug() << "display" <<displayText << node->value;
|
2025-04-23 14:44:58 +08:00
|
|
|
|
}
|
|
|
|
|
QStandardItem* item = new QStandardItem(displayText);
|
|
|
|
|
item->setData(node->value, Qt::UserRole); // 原始表达式key
|
2025-04-19 16:25:33 +08:00
|
|
|
|
for (ExprNode* child : node->children) {
|
|
|
|
|
item->appendRow(buildItemTree(child));
|
|
|
|
|
}
|
|
|
|
|
return item;
|
|
|
|
|
}
|
|
|
|
|
void TMRRelayAssociation::setExpressionToTreeView(QTreeView* treeView, const QString& expr) {
|
|
|
|
|
int pos = 0;
|
2025-04-19 19:54:56 +08:00
|
|
|
|
model_Relay->clear();
|
2025-04-19 16:25:33 +08:00
|
|
|
|
ExprNode* root = parseExpression(expr, pos);
|
|
|
|
|
QStandardItem* rootItem = buildItemTree(root);
|
|
|
|
|
|
2025-04-19 19:54:56 +08:00
|
|
|
|
model_Relay->appendRow(rootItem);
|
|
|
|
|
treeView_relay->expandAll();
|
2025-04-19 16:25:33 +08:00
|
|
|
|
}
|
|
|
|
|
QString TMRRelayAssociation::buildLogicExpression(QStandardItem *item) {
|
|
|
|
|
if (!item) return "";
|
|
|
|
|
|
|
|
|
|
int childCount = item->rowCount();
|
2025-04-23 14:44:58 +08:00
|
|
|
|
QVariant userData = item->data(Qt::UserRole);
|
|
|
|
|
QString text = userData.toString().trimmed();
|
2025-04-19 16:25:33 +08:00
|
|
|
|
|
|
|
|
|
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 + " ") + ")";
|
|
|
|
|
}
|
|
|
|
|
QStandardItem* TMRRelayAssociation::parseExpression(const QString &expr) {
|
|
|
|
|
QStack<QStandardItem*> stack; // 用来存储节点
|
|
|
|
|
QStack<QString> ops; // 用来存储操作符
|
|
|
|
|
|
|
|
|
|
int pos = 0;
|
|
|
|
|
int length = expr.length();
|
|
|
|
|
|
|
|
|
|
while (pos < length) {
|
|
|
|
|
QRegExp regex("(\\()|([A-Za-z0-9]+)|([+*])|(\\))");
|
|
|
|
|
|
|
|
|
|
if (regex.indexIn(expr, pos) != -1) {
|
|
|
|
|
QString matchedText = regex.cap(0);
|
|
|
|
|
QString group1 = regex.cap(1); // (
|
|
|
|
|
QString group2 = regex.cap(2); // S01C01A1
|
|
|
|
|
QString group3 = regex.cap(3); // + or *
|
|
|
|
|
QString group4 = regex.cap(4); // )
|
|
|
|
|
|
|
|
|
|
// 处理左括号,表示子表达式的开始
|
|
|
|
|
if (!group1.isEmpty()) {
|
|
|
|
|
ops.push("("); // 推入栈
|
|
|
|
|
}
|
|
|
|
|
// 处理右括号,表示子表达式的结束
|
|
|
|
|
else if (!group4.isEmpty()) {
|
|
|
|
|
// 遇到右括号时开始弹出栈中的操作符,直到遇到左括号
|
|
|
|
|
while (!ops.isEmpty() && ops.top() != "(") {
|
|
|
|
|
QString op = ops.pop();
|
|
|
|
|
QStandardItem* right = stack.pop();
|
|
|
|
|
QStandardItem* left = stack.pop();
|
|
|
|
|
QStandardItem* node = new QStandardItem(op);
|
|
|
|
|
node->appendRow(left); // 左子树
|
|
|
|
|
node->appendRow(right); // 右子树
|
|
|
|
|
stack.push(node); // 将新的节点推入栈
|
|
|
|
|
}
|
|
|
|
|
ops.pop(); // 弹出左括号
|
|
|
|
|
}
|
|
|
|
|
// 处理操作符 + 和 *
|
|
|
|
|
else if (!group3.isEmpty()) {
|
|
|
|
|
ops.push(group3); // 操作符入栈
|
|
|
|
|
}
|
|
|
|
|
// 处理终端元素(比如 S01C01A1)
|
|
|
|
|
else if (!group2.isEmpty()) {
|
|
|
|
|
QStandardItem* item = new QStandardItem(group2);
|
|
|
|
|
stack.push(item); // 将数据节点推入栈
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pos = regex.pos(0) + regex.matchedLength();
|
|
|
|
|
} else {
|
|
|
|
|
break; // 防止无限循环
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 最终合并栈中的所有内容
|
|
|
|
|
while (!ops.isEmpty()) {
|
|
|
|
|
QString op = ops.pop();
|
|
|
|
|
QStandardItem* right = stack.pop();
|
|
|
|
|
QStandardItem* left = stack.pop();
|
|
|
|
|
QStandardItem* node = new QStandardItem(op);
|
|
|
|
|
node->appendRow(left); // 左子树
|
|
|
|
|
node->appendRow(right); // 右子树
|
|
|
|
|
stack.push(node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 返回栈顶的节点,应该是根节点
|
|
|
|
|
return stack.isEmpty() ? nullptr : stack.pop();
|
|
|
|
|
}
|
2025-04-21 17:23:38 +08:00
|
|
|
|
|
|
|
|
|
ExprValidationResult TMRRelayAssociation::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 {
|
|
|
|
|
return {false, i, QString("不支持的字符 '%1'").arg(ch)};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bracketCount != 0) {
|
|
|
|
|
return {false, expr.length(), "括号不匹配"};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (lastWasOperator) {
|
|
|
|
|
return {false, expr.length() - 1, "表达式不能以运算符结尾"};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {true, -1, ""};
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-19 16:25:33 +08:00
|
|
|
|
void TMRRelayAssociation::buildTreeFromExpression(QTreeView *treeView, const QString &expr) {
|
|
|
|
|
QStandardItem* rootItem = parseExpression(expr);
|
|
|
|
|
|
|
|
|
|
if (rootItem) {
|
|
|
|
|
model_Relay->appendRow(rootItem);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
treeView_relay->setModel(model_Relay);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TMRRelayAssociation::OnButtonGroup(QAbstractButton *slot_btn) {
|
|
|
|
|
if (slot_btn != NULL) {
|
|
|
|
|
list_widget_available->clear();
|
|
|
|
|
QString object_name = slot_btn->objectName();
|
2025-04-21 17:23:38 +08:00
|
|
|
|
if(slot_btn->text().isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
qDebug() << object_name;
|
2025-04-19 16:25:33 +08:00
|
|
|
|
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);
|
2025-04-23 14:44:58 +08:00
|
|
|
|
QListWidgetItem *item_and = new QListWidgetItem("AND");
|
|
|
|
|
item_and->setData(Qt::UserRole, "*");
|
2025-04-21 17:23:38 +08:00
|
|
|
|
list_widget_available->addItem(item_and);
|
2025-04-23 14:44:58 +08:00
|
|
|
|
|
|
|
|
|
QListWidgetItem *item_or = new QListWidgetItem("OR");
|
|
|
|
|
item_or->setData(Qt::UserRole, "+");
|
|
|
|
|
list_widget_available->addItem(item_or);
|
2025-04-19 16:25:33 +08:00
|
|
|
|
for(int var = 0; var < CHANNEL_COUNT ; ++var){
|
2025-04-25 16:29:08 +08:00
|
|
|
|
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){
|
2025-04-27 15:23:05 +08:00
|
|
|
|
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'));
|
2025-04-25 16:29:08 +08:00
|
|
|
|
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){
|
2025-04-27 15:23:05 +08:00
|
|
|
|
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'));
|
2025-04-25 16:29:08 +08:00
|
|
|
|
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);
|
|
|
|
|
}
|
2025-04-19 16:25:33 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void TMRRelayAssociation::on_pushButton_cancel_clicked()
|
|
|
|
|
{
|
|
|
|
|
this->close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void TMRRelayAssociation::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;
|
|
|
|
|
}
|
2025-04-21 17:23:38 +08:00
|
|
|
|
ExprValidationResult result = validateLogicExpression(finalExpr);
|
|
|
|
|
if (!result.isValid && !finalExpr.isEmpty()) {
|
|
|
|
|
QMessageBox::warning(this, "表达式错误",
|
|
|
|
|
QString("错误位置:%1\n错误描述:%2").arg(result.errorPos).arg(result.errorMsg));
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-04-19 19:54:56 +08:00
|
|
|
|
relay_data->tmr_relay[current_index].logic_expression = finalExpr;
|
2025-04-21 20:30:12 +08:00
|
|
|
|
relay_data->sgcc_enable = ui->checkBox_sgcc->checkState();
|
2025-04-19 16:25:33 +08:00
|
|
|
|
qDebug() << "逻辑表达式:" << finalExpr;
|
|
|
|
|
this->close();
|
|
|
|
|
}
|
|
|
|
|
void TMRRelayAssociation::onComboBoxIndexChanged(int index){
|
|
|
|
|
|
2025-04-19 19:54:56 +08:00
|
|
|
|
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;
|
|
|
|
|
}
|
2025-04-21 17:23:38 +08:00
|
|
|
|
ExprValidationResult result = validateLogicExpression(finalExpr);
|
|
|
|
|
if (!result.isValid && !finalExpr.isEmpty()) {
|
|
|
|
|
QMessageBox::warning(this, "表达式错误",
|
|
|
|
|
QString("错误位置:%1\n错误描述:%2").arg(result.errorPos).arg(result.errorMsg));
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-05-17 10:58:08 +08:00
|
|
|
|
qDebug() << "finalExpr" << finalExpr;
|
2025-04-19 19:54:56 +08:00
|
|
|
|
relay_data->tmr_relay[current_index].logic_expression = finalExpr;
|
|
|
|
|
current_index = index;
|
|
|
|
|
|
|
|
|
|
if(relay_data->tmr_relay[index].logic_expression != "")
|
|
|
|
|
setExpressionToTreeView(treeView_relay, relay_data->tmr_relay[index].logic_expression);
|
|
|
|
|
else
|
|
|
|
|
model_Relay->clear();
|
2025-04-19 16:25:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TMRRelayAssociation::on_pushButton_and_clicked()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void TMRRelayAssociation::on_pushButton_or_clicked()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
void TMRRelayAssociation::slotDeleteItem()
|
|
|
|
|
{
|
|
|
|
|
QModelIndex curIndex = treeView_relay->currentIndex();
|
|
|
|
|
if(curIndex.isValid()){
|
|
|
|
|
model_Relay->removeRow(curIndex.row(),curIndex.parent());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
void TMRRelayAssociation::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()); //显示菜单
|
|
|
|
|
}
|
2025-04-21 17:23:38 +08:00
|
|
|
|
|
|
|
|
|
void TMRRelayAssociation::on_checkBox_sgcc_stateChanged(int arg1)
|
|
|
|
|
{
|
|
|
|
|
if(ui->checkBox_sgcc->checkState()){
|
|
|
|
|
treeView_relay->setEnabled(false);
|
|
|
|
|
list_widget_available->setEnabled(false);
|
2025-04-21 20:30:12 +08:00
|
|
|
|
ui->comboBox_relay_ch->setEnabled(false);
|
|
|
|
|
ui->pushButton_logic->setEnabled(false);
|
|
|
|
|
ui->textEdit_logic->setEnabled(false);
|
2025-04-21 17:23:38 +08:00
|
|
|
|
}else{
|
|
|
|
|
treeView_relay->setEnabled(true);
|
|
|
|
|
list_widget_available->setEnabled(true);
|
2025-04-21 20:30:12 +08:00
|
|
|
|
ui->comboBox_relay_ch->setEnabled(true);
|
|
|
|
|
ui->pushButton_logic->setEnabled(true);
|
|
|
|
|
ui->textEdit_logic->setEnabled(true);
|
2025-04-21 17:23:38 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void TMRRelayAssociation::on_pushButton_logic_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;
|
|
|
|
|
}
|
|
|
|
|
ui->textEdit_logic->setPlainText(finalExpr);
|
|
|
|
|
}
|
|
|
|
|
|