TSI_Config/singlerelay.cpp

447 lines
18 KiB
C++
Raw Normal View History

2024-12-18 16:46:39 +08:00
#include "singlerelay.h"
#include "ui_singlerelay.h"
2025-04-21 20:30:12 +08:00
#include "vibrationdata.h"
2025-07-09 20:24:50 +08:00
#include <QStack>
#include <QMessageBox>
#include <QMenu>
2025-04-19 16:25:33 +08:00
SingleRelay::SingleRelay(int slot,int cardtype,QWidget *parent)
2024-12-18 16:46:39 +08:00
: QDialog(parent)
2025-03-27 10:16:01 +08:00
, ui(new Ui::SingleRelay) {
2024-12-18 16:46:39 +08:00
ui->setupUi(this);
2025-04-19 16:25:33 +08:00
slot_no = slot;
car_type = static_cast<CardType>(cardtype);
ui->label_slot_no->setText(QString::number(slot_no));
2025-03-27 10:16:01 +08:00
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
2025-04-19 16:25:33 +08:00
QVBoxLayout *layout_available = new QVBoxLayout(ui->widget_available);
2025-04-25 14:28:27 +08:00
list_widget_available = new QListWidget();
2025-04-19 16:25:33 +08:00
layout_available->addWidget(list_widget_available);
2025-04-23 17:13:05 +08:00
list_widget_available->setDragEnabled(true);
2025-04-19 16:25:33 +08:00
2025-04-25 14:28:27 +08:00
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);
2025-04-19 16:25:33 +08:00
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);
2025-04-17 20:33:26 +08:00
2025-04-19 16:25:33 +08:00
connect(btnGroup_slot, SIGNAL(buttonClicked(QAbstractButton *)), this, SLOT(OnButtonGroup(QAbstractButton *)));
connect(ui->comboBox_relay_ch, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &SingleRelay::onComboBoxIndexChanged);
2025-07-09 20:24:50 +08:00
treeView_relay->setContextMenuPolicy(Qt::CustomContextMenu);
connect(treeView_relay,&QTreeView::customContextMenuRequested,this,&SingleRelay::on_treeView_Relay_customContextMenuRequested);
2025-04-19 16:25:33 +08:00
current_index = ui->comboBox_relay_ch->currentIndex();
2025-07-09 20:24:50 +08:00
Init();
onComboBoxIndexChanged(current_index);
2024-12-18 16:46:39 +08:00
}
2025-03-27 10:16:01 +08:00
SingleRelay::~SingleRelay() {
2024-12-18 16:46:39 +08:00
delete ui;
}
2025-03-27 10:16:01 +08:00
2025-04-19 16:25:33 +08:00
void SingleRelay::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;
}
}
}
2025-04-19 16:25:33 +08:00
std::shared_ptr<CardBase> base_ptr = ConfigMgr::Instance()->GetSlotPtr(slot_no);
if (base_ptr == nullptr) {
// do nothing or use template to init it.
2025-07-09 20:24:50 +08:00
relay_data = std::make_shared<SingleRelayData>();
relay_data->card_type_ = car_type;
relay_data->slot_ = slot_no;
ConfigMgr::Instance()->AddCard(relay_data);
2025-04-19 16:25:33 +08:00
return;
}
2025-07-09 20:24:50 +08:00
relay_data = std::dynamic_pointer_cast<SingleRelayData>(base_ptr);
qDebug() << "logic" <<relay_data->single_relay[current_index].logic_expression;
2025-04-23 17:13:05 +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){
2025-07-09 20:24:50 +08:00
qDebug() << "i" << i;
2025-04-23 17:13:05 +08:00
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;
2025-07-09 20:24:50 +08:00
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;
2025-04-23 17:13:05 +08:00
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){
}
}
2025-07-09 20:24:50 +08:00
if(!relay_data->single_relay[current_index].logic_expression.isEmpty()){
setExpressionToTreeView(treeView_relay, relay_data->single_relay[current_index].logic_expression);
}
2025-04-19 16:25:33 +08:00
}
2025-03-27 10:16:01 +08:00
void SingleRelay::on_pushButton_cancel_clicked() {
this->close();
}
2025-04-19 16:25:33 +08:00
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();
2025-07-09 20:24:50 +08:00
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);
2025-04-19 16:25:33 +08:00
for(int var = 0; var < CHANNEL_COUNT ; ++var){
2025-04-21 20:30:12 +08:00
std::shared_ptr<CardBase> base_ptr = ConfigMgr::Instance()->GetSlotPtr(button_id);
2025-04-25 14:28:27 +08:00
if(base_ptr->card_type_ == kCardVibSingle){
2025-07-09 20:24:50 +08:00
QString item_data;
if(ptr->base_config_[var].standby && (var % 2))
2025-04-25 14:28:27 +08:00
continue;
2025-07-09 20:24:50 +08:00
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'));
2025-04-25 14:28:27 +08:00
QListWidgetItem *item = new QListWidgetItem(item_str);
2025-07-09 20:24:50 +08:00
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);
2025-04-25 14:28:27 +08:00
list_widget_available->addItem(item);
}
2025-04-19 16:25:33 +08:00
}
}
}
void SingleRelay::keyPressEvent(QKeyEvent *event) {
// if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {
// removeLastElement();
// return;
// }
// QTextEdit::keyPressEvent(event);
}
2025-07-09 20:24:50 +08:00
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;
}
2025-04-19 16:25:33 +08:00
2025-07-09 20:24:50 +08:00
// 判断当前是 +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 + " ") + ")";
}
2025-04-19 16:25:33 +08:00
void SingleRelay::on_pushButton_confirm_clicked()
{
2025-04-25 14:28:27 +08:00
QStandardItemModel *model = qobject_cast<QStandardItemModel *>(treeView_relay->model());
if (!model) return;
2025-07-09 20:24:50 +08:00
2025-04-25 14:28:27 +08:00
QStandardItem *root = model->invisibleRootItem();
QString finalExpr;
2025-07-09 20:24:50 +08:00
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;
2025-04-19 16:25:33 +08:00
this->close();
}
void SingleRelay::onComboBoxIndexChanged(int index){
qDebug()<< "[SingleRelay]:index " << index;
2025-07-09 20:24:50 +08:00
2025-04-25 14:28:27 +08:00
QStandardItemModel *model = qobject_cast<QStandardItemModel *>(treeView_relay->model());
if (!model) return;
QStandardItem *root = model->invisibleRootItem();
2025-07-09 20:24:50 +08:00
QString finalExpr;
for (int i = 0; i < root->rowCount(); ++i) {
QStandardItem *topItem = root->child(i);
QString expr = buildLogicExpression(topItem);
finalExpr += expr;
2025-04-23 17:13:05 +08:00
}
2025-07-09 20:24:50 +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;
}
qDebug() << "finalExpr" << finalExpr;
relay_data->single_relay[current_index].logic_expression = finalExpr;
2025-04-19 16:25:33 +08:00
current_index = index;
2025-04-25 14:28:27 +08:00
2025-07-09 20:24:50 +08:00
if(relay_data->single_relay[index].logic_expression != "")
setExpressionToTreeView(treeView_relay, relay_data->single_relay[index].logic_expression);
else
2025-04-25 14:28:27 +08:00
model_Relay->clear();
2025-07-09 20:24:50 +08:00
}
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));
2025-04-25 14:28:27 +08:00
}
2025-07-09 20:24:50 +08:00
return item;
2025-04-19 16:25:33 +08:00
}
2025-07-09 20:24:50 +08:00
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()); //显示菜单
}