/** * @file mainwindow.cpp * @author jinchao * @brief 主窗口类实现 * @version 1.0 * @date 2025-02-14 * * @copyright Copyright (c) 2025 COMAC * */ #include "mainwindow.h" #include "./ui_mainwindow.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //构造函数 MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); isModified = false; // 初始化 // 设置窗口标题 setWindowTitle("XNEditor"); // 设置窗口图标 setWindowIcon(QIcon(":/icon/XNEditor.png")); // 设置窗口大小 resize(700, 1000); // 初始化菜单栏 initMenu(); //初始化中央控件 initCentralWidget(0); } // 构造函数 MainWindow::MainWindow(QString fileName, QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); // 设置窗口标题 setWindowTitle("XNEditor"); // 设置窗口图标 setWindowIcon(QIcon(":/icon/XNEditor.png")); // 设置窗口大小 resize(500, 1000); // 初始化菜单栏 initMenu(); // 设置当前文件路径 currentFilePath = fileName; isModified = false; // 根据文件类型初始化中央控件 if (currentFilePath.endsWith(".mcfg")) { // 模型配置文件 initCentralWidget(1); currentFileType = 1; // 打开模型配置文件 openModelFile(); } else if (currentFilePath.endsWith(".scfg")) { // 服务配置文件 initCentralWidget(1); currentFileType = 2; // 打开服务配置文件 openServiceFile(); } else if (currentFilePath.endsWith(".idl")) { // IDL文件 initCentralWidget(2); currentFileType = 3; // 打开IDL文件 openIDLFile(); } } // 析构函数 MainWindow::~MainWindow() { delete ui; } // 初始化菜单栏 void MainWindow::initMenu() { // 初始化文件菜单 initFileMenu(); //初始化编辑菜单 initEditMenu(); } // 初始化文件菜单 void MainWindow::initFileMenu() { // 获取菜单栏 QMenuBar *menuBar = ui->menubar; // 设置菜单 QMenu *fileMenu = new QMenu("&File", this); menuBar->addMenu(fileMenu); // New菜单项 QAction *newAction = new QAction("&New Scenario", this); fileMenu->addAction(newAction); newAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_N)); connect(newAction, &QAction::triggered, this, &MainWindow::onNewFileTriggered); // 添加分隔 fileMenu->addSeparator(); // Open菜单项 QAction *openAction = new QAction("&Open", this); openAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_O)); fileMenu->addAction(openAction); connect(openAction, &QAction::triggered, this, &MainWindow::onOpenFileTriggered); // 添加分隔 fileMenu->addSeparator(); // Save菜单项 QAction *saveAction = new QAction("&Save", this); fileMenu->addAction(saveAction); saveAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_S)); connect(saveAction, &QAction::triggered, [this]() { if (currentFilePath.isEmpty()) { return; } //保存文件 saveFile(currentFilePath); }); //Save As 菜单项 QAction *saveAsAction = new QAction("Save As...", this); fileMenu->addAction(saveAsAction); saveAsAction->setShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_S)); connect(saveAsAction, &QAction::triggered, [this]() { // 打开选择保存路径对话框 QString filePath = QFileDialog::getSaveFileName( this, tr("Save As"), "", tr("Scenario Files (*.sce);;All Files (*)")); if (!filePath.isEmpty()) { currentFilePath = filePath; //保存文件 saveFile(filePath); } }); // 添加分隔 fileMenu->addSeparator(); // Close 菜单项 QAction *closeAction = new QAction("&Close File", this); fileMenu->addAction(closeAction); closeAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_W)); connect(closeAction, &QAction::triggered, this, &MainWindow::onCloseFileTriggered); // 添加分隔 fileMenu->addSeparator(); // Exit 菜单项 QAction *exitAction = new QAction("&Exit", this); fileMenu->addAction(exitAction); exitAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q)); connect(exitAction, &QAction::triggered, [this]() { close(); }); } // 初始化编辑菜单 void MainWindow::initEditMenu() { // 获取菜单栏 QMenuBar *menuBar = ui->menubar; //TODO 添加编辑相关菜单项 } // 初始化中心组件 void MainWindow::initCentralWidget(int style) { // 清理旧中心组件 QWidget *oldCentralWidget = centralWidget(); if (oldCentralWidget) { delete oldCentralWidget; } // 新建新中心组件 QWidget *centralWidget = new QWidget(this); setCentralWidget(centralWidget); // 中心组件水平布局 QHBoxLayout *layout = new QHBoxLayout(centralWidget); if (style == 0) { //如果是运行环境配置文件类型 // 创建一个水平分割器 QSplitter *splitter = new QSplitter(Qt::Horizontal, centralWidget); splitter->setObjectName("splitter"); layout->addWidget(splitter); // 创建左边窗口 QWidget *leftWidget = new QWidget(splitter); leftWidget->setObjectName("leftWidget"); //左侧窗口垂直布局 QVBoxLayout *leftLayout = new QVBoxLayout(leftWidget); // 创建模型配置文件树型控件 QTreeWidget *ModelWidget = new QTreeWidget(leftWidget); ModelWidget->setObjectName("ModelWidget"); ModelWidget->setHeaderLabels(QStringList() << "Models"); leftLayout->addWidget(ModelWidget); // 创建服务配置文件树型控件 QTreeWidget *ServiceWidget = new QTreeWidget(leftWidget); ServiceWidget->setObjectName("ServiceWidget"); ServiceWidget->setHeaderLabels(QStringList() << "Services"); leftLayout->addWidget(ServiceWidget); // 为模型配置文件树型控件添加右键菜单 ModelWidget->setContextMenuPolicy(Qt::CustomContextMenu); connect(ModelWidget, &QTreeWidget::customContextMenuRequested, this, [=](const QPoint &pos) { //获取点击右键时选中的元素 QTreeWidgetItem *item = ModelWidget->itemAt(pos); if (item) { //新建右键菜单 QMenu contextMenu; //添加在新窗口打开的选项 QAction *openAction = new QAction("Open in New Window", this); contextMenu.addAction(openAction); // 链接打开选项的槽 connect(openAction, &QAction::triggered, this, [this, item]() { //获取选中元素的文件名 QString fileName = modelPath + "/" + item->text(0); //在新窗口打开文件 openFileInNewWindow(fileName); }); //显示右键菜单 contextMenu.exec(ModelWidget->mapToGlobal(pos)); } }); // 为服务配置文件树型控件添加右键菜单 ServiceWidget->setContextMenuPolicy(Qt::CustomContextMenu); connect(ServiceWidget, &QTreeWidget::customContextMenuRequested, this, [=](const QPoint &pos) { //获取点击右键时选中的元素 QTreeWidgetItem *item = ServiceWidget->itemAt(pos); if (item) { //新建右键菜单 QMenu contextMenu; //添加在新窗口打开的选项 QAction *openAction = new QAction("Open in New Window", this); contextMenu.addAction(openAction); // 链接打开选项的槽 connect(openAction, &QAction::triggered, this, [this, item]() { //获取选中元素的文件名 QString fileName = ServicePath + "/" + item->text(0); //在新窗口打开文件 openFileInNewWindow(fileName); }); //显示右键菜单 contextMenu.exec(ServiceWidget->mapToGlobal(pos)); } }); // 将左边窗口添加到分割器 splitter->addWidget(leftWidget); // 创建右边窗口 QWidget *rightWidget = new QWidget(splitter); rightWidget->setObjectName("rightWidget"); //右侧窗口垂直布局 QVBoxLayout *rightLayout = new QVBoxLayout(rightWidget); rightLayout->setObjectName("rightLayout"); // 将右边窗口添加到分割器 splitter->addWidget(rightWidget); // 设置分割器两侧大小 splitter->setSizes({200, 400}); } else if (style == 1) { //如果是模型/服务配置文件类型 // 创建右边窗口 QWidget *rightWidget = new QWidget(centralWidget); rightWidget->setObjectName("rightWidget"); //右侧窗口垂直布局 QVBoxLayout *rightLayout = new QVBoxLayout(rightWidget); rightLayout->setObjectName("rightLayout"); layout->addWidget(rightWidget); } else if (style == 2) { //如果是IDL文件类型 // 创建一个水平分割器 QSplitter *splitter = new QSplitter(Qt::Horizontal, centralWidget); splitter->setObjectName("splitter"); layout->addWidget(splitter); // 创建左边窗口,为树型控件,显示IDL结构 QTreeWidget *leftWidget = new QTreeWidget(splitter); leftWidget->setObjectName("leftWidget"); // 初始化该树型控件 initIDLTreeWidget(); // 将左边窗口添加到分割器 splitter->addWidget(leftWidget); // 创建右边窗口,为表格控件,显示结构体内容 QTableWidget *rightWidget = new QTableWidget(splitter); rightWidget->setObjectName("rightWidget"); // 设置表格为4列 rightWidget->setColumnCount(4); // 设置列标题 QStringList headers; headers << "Name" << "Type" << "Size" << "Description"; rightWidget->setHorizontalHeaderLabels(headers); // 设置表格只能单选 rightWidget->setSelectionMode(QAbstractItemView::SingleSelection); // 设置表头自动伸缩 rightWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); // 将右边窗口添加到分割器 splitter->addWidget(rightWidget); // 设置分割器两侧大小 splitter->setSizes({200, 400}); // Adjust these values as needed } } // 初始化IDL文件结构窗口 void MainWindow::initIDLTreeWidget() { // 获取左边窗口 QTreeWidget *leftWidget = findChild("leftWidget"); if (leftWidget) { // 设置右键菜单策略 leftWidget->setContextMenuPolicy(Qt::CustomContextMenu); // 连接右键菜单信号 connect( leftWidget, &QTreeWidget::customContextMenuRequested, this, [this, leftWidget](const QPoint &pos) { // 获取点击右键时选择的元素 QTreeWidgetItem *item = leftWidget->itemAt(pos); QMenu contextMenu; if (!item) { // 在空白处右键,只能添加顶层namespace // 新建添加namespace的选项 QAction *addNamespaceAction = new QAction("Add Module", this); // 链接添加namespace的槽 connect(addNamespaceAction, &QAction::triggered, [this, leftWidget]() { bool ok; QString name; do { // 打开输入namespace名称的对话框 name = QInputDialog::getText( this, tr("Add Module"), tr("Module name (must be a valid C++ identifier):"), QLineEdit::Normal, "", &ok); if (!ok) return; // 用户点击取消 // 只能输入c++标准的类名 QRegularExpression regex("^[A-Za-z_][A-Za-z0-9_]*$"); if (!regex.match(name).hasMatch()) { // 如果输入的名称不符合c++标准的类名,则提示错误 QMessageBox::warning( this, tr("Invalid Name"), tr("Module name must start with a letter or underscore and " "contain only letters, numbers and underscores.")); ok = false; } } while (!ok || name.isEmpty()); // 新建一个namespace QTreeWidgetItem *newItem = new QTreeWidgetItem(QStringList() << name); // 将namespace添加到树型控件 leftWidget->addTopLevelItem(newItem); // 将namespace添加到存储好的结构中 NamespaceDefinition newNamespace; newNamespace.namespaceName = name; namespaces.push_back(QSharedPointer(&newNamespace)); // 设置修改状态 isModified = true; // 更新窗口标题 updateWindowTitle(); }); contextMenu.addAction(addNamespaceAction); } else { //如果不是空白处 //计算在第几层 int level = 0; QTreeWidgetItem *parent = item; while (parent->parent()) { parent = parent->parent(); level++; } if (level < 2) { // 第一层或第二层可以添加module和struct // 新建添加module的选项 QAction *addNamespaceAction = new QAction("Add Module", this); // 链接添加module的槽 connect(addNamespaceAction, &QAction::triggered, [this, item]() { bool ok; QString name; do { // 打开输入namespace名称的对话框 name = QInputDialog::getText( this, tr("Add Module"), tr("Module name (must be a valid C++ identifier):"), QLineEdit::Normal, "", &ok); if (!ok) return; // 用户点击取消 // 只能输入c++标准的类名 QRegularExpression regex("^[A-Za-z_][A-Za-z0-9_]*$"); if (!regex.match(name).hasMatch()) { QMessageBox::warning( this, tr("Invalid Name"), tr("Module name must start with a letter or underscore and " "contain only letters, numbers and underscores.")); ok = false; } } while (!ok || name.isEmpty()); // 将namespace添加为该元素的子元素 QTreeWidgetItem *newItem = new QTreeWidgetItem(QStringList() << name); item->addChild(newItem); item->setExpanded(true); isModified = true; updateWindowTitle(); }); contextMenu.addAction(addNamespaceAction); // 新建添加Struct的选项 QAction *addStructAction = new QAction("Add Struct", this); // 链接添加Struct的槽 connect(addStructAction, &QAction::triggered, [this, item]() { bool ok; QString name; do { // 打开输入Struct名称的对话框 name = QInputDialog::getText( this, tr("Add Struct"), tr("Struct name (must be a valid C++ identifier):"), QLineEdit::Normal, "", &ok); if (!ok) return; // 用户点击取消 // 只能输入c++标准的类名 QRegularExpression regex("^[A-Za-z_][A-Za-z0-9_]*$"); if (!regex.match(name).hasMatch()) { QMessageBox::warning( this, tr("Invalid Name"), tr("Struct name must start with a letter or underscore and " "contain only letters, numbers and underscores.")); ok = false; } } while (!ok || name.isEmpty()); // 新建一个Struct QTreeWidgetItem *newItem = new QTreeWidgetItem(QStringList() << name); // 将Struct添加为该元素的子元素 item->addChild(newItem); item->setExpanded(true); // 设置修改状态 isModified = true; // 更新窗口标题 updateWindowTitle(); }); contextMenu.addAction(addStructAction); } else if (level == 2) { // 第三层只能添加struct // 新建添加Struct的选项 QAction *addStructAction = new QAction("Add Struct", this); // 链接添加Struct的槽 connect(addStructAction, &QAction::triggered, [this, item]() { bool ok; QString name; do { // 打开输入Struct名称的对话框 name = QInputDialog::getText( this, tr("Add Struct"), tr("Struct name (must be a valid C++ identifier):"), QLineEdit::Normal, "", &ok); if (!ok) return; // 用户点击取消 // 只能输入c++标准的类名 QRegularExpression regex("^[A-Za-z_][A-Za-z0-9_]*$"); if (!regex.match(name).hasMatch()) { QMessageBox::warning( this, tr("Invalid Name"), tr("Struct name must start with a letter or underscore and " "contain only letters, numbers and underscores.")); ok = false; } } while (!ok || name.isEmpty()); // 新建一个Struct QTreeWidgetItem *newItem = new QTreeWidgetItem(QStringList() << name); // 将Struct添加为该元素的子元素 item->addChild(newItem); item->setExpanded(true); // 设置修改状态 isModified = true; // 更新窗口标题 updateWindowTitle(); }); contextMenu.addAction(addStructAction); } // 所有层级都可以删除 contextMenu.addSeparator(); QAction *deleteAction = new QAction("Delete", this); connect(deleteAction, &QAction::triggered, [this, item]() { delete item; isModified = true; updateWindowTitle(); }); contextMenu.addAction(deleteAction); } if (!contextMenu.actions().isEmpty()) { contextMenu.exec(leftWidget->mapToGlobal(pos)); } }); } } // 新建文件 void MainWindow::onNewFileTriggered() { // 如果文件被修改,则先关闭文件 if (isModified) { // 关闭文件 onCloseFileTriggered(); } // 打开新建环境配置文件对话框 QString filePath = QFileDialog::getSaveFileName(this, tr("New Scenario"), "", tr("Scenario Files (*.sce);;All Files (*)")); // 如果文件路径不为空 if (!filePath.isEmpty()) { // 打开模板文件 QFile templateFile("template/Template.sce.tmp"); // 如果模板文件存在 if (templateFile.exists()) { // 打开模板文件 if (templateFile.open(QIODevice::ReadOnly | QIODevice::Text)) { QFile newFile(filePath); if (newFile.open(QIODevice::WriteOnly | QIODevice::Text)) { // 读取模板文件 QTextStream in(&templateFile); // 写入新文件 QTextStream out(&newFile); out << in.readAll(); // 关闭模板文件 templateFile.close(); // 关闭新文件 newFile.close(); // 设置当前文件路径 currentFilePath = filePath; // 设置当前文件类型 currentFileType = 0; // 打开环境配置文件 openScenarioFile(); } else { // 如果新建文件失败,则提示错误 QMessageBox::warning(this, tr("Error"), tr("Failed to create new scenario file.")); } } else { // 如果打开模板文件失败,则提示错误 QMessageBox::warning(this, tr("Error"), tr("Failed to open template file.")); } } else { // 如果模板文件不存在,则提示错误 QMessageBox::warning(this, tr("Error"), tr("Template file does not exist.")); } } } // 打开文件 void MainWindow::onOpenFileTriggered() { // 如果文件被修改,则先关闭文件 if (isModified) { // 关闭文件 onCloseFileTriggered(); } // 打开打开文件对话框 QString filePath = QFileDialog::getOpenFileName( this, tr("Open File"), "", tr("All Supported Files (*.sce *.xml *.mcfg *.scfg *.idl);;All Files (*)")); // 如果文件路径不为空 if (!filePath.isEmpty()) { // 设置当前文件路径 currentFilePath = filePath; if (filePath.endsWith(".idl")) { //如果是IDL文件 currentFileType = 3; // 重新初始化布局 initCentralWidget(2); // 打开IDL文件 openIDLFile(); return; } // 打开文件 QFile file(filePath); if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { // 读取文件 QXmlStreamReader xmlReader(&file); while (!xmlReader.atEnd() && !xmlReader.hasError()) { // 读取下一个元素 QXmlStreamReader::TokenType token = xmlReader.readNext(); if (token == QXmlStreamReader::StartElement) { // 获取元素名称 QString rootElement = xmlReader.name().toString(); if (rootElement == "Scenario") { //如果是环境配置文件 currentFileType = 0; resize(700, 1000); initCentralWidget(0); // 重新初始化布局 file.close(); // 打开环境配置文件 openScenarioFile(); return; } else if (rootElement == "Model") { //如果是模型文件 currentFileType = 1; resize(500, 1000); initCentralWidget(1); // 重新初始化布局 file.close(); // 打开模型文件 openModelFile(); return; } else if (rootElement == "Service") { //如果是服务文件 currentFileType = 2; resize(500, 1000); initCentralWidget(1); // 重新初始化布局 file.close(); // 打开服务文件 openServiceFile(); return; } break; } } file.close(); } else { // 如果打开文件失败,则提示错误 QMessageBox::warning(this, tr("Error"), tr("Failed to open file.")); } } } // 关闭文件 void MainWindow::onCloseFileTriggered() { if (isModified) { // 只在文件被修改时提示保存 // 提示保存 QMessageBox::StandardButton reply; reply = QMessageBox::question(this, tr("Save Changes"), tr("Do you want to save changes to the current file?"), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); if (reply == QMessageBox::Yes) { // 如果选择保存 if (currentFilePath.isEmpty()) { // 如果当前文件路径为空 // 打开保存文件对话框 QString filePath = QFileDialog::getSaveFileName(this, tr("Save As"), "", tr("All Files (*)")); if (!filePath.isEmpty()) { // 如果文件路径不为空 // 保存文件 saveFile(filePath); } } else { // 保存文件 saveFile(currentFilePath); } } else if (reply == QMessageBox::Cancel) { // 如果选择取消 return; } } // 清除内容 QTreeWidget *ModelWidget = findChild("ModelWidget"); if (ModelWidget) { ModelWidget->clear(); } QTreeWidget *ServiceWidget = findChild("ServiceWidget"); if (ServiceWidget) { ServiceWidget->clear(); } QVBoxLayout *layout = findChild("rightLayout"); if (layout) { QLayoutItem *child; while ((child = layout->takeAt(0)) != nullptr) { if (child->widget()) { child->widget()->setParent(nullptr); } delete child; } } isModified = false; // 重置修改状态 currentFilePath = ""; currentFileType = 0; // 更新窗口标题 updateWindowTitle(); } // 打开场景配置文件 void MainWindow::openScenarioFile() { // 获取右布局 QVBoxLayout *layout = findChild("rightLayout"); if (!layout) { QMessageBox::warning(this, tr("Error"), tr("Software error.")); return; } // 打开文件 QFile file(currentFilePath); if (!file.open(QIODevice::ReadOnly)) { QMessageBox::warning(this, tr("Error"), tr("Failed to open file.")); return; } // 创建DOM文档 QDomDocument doc; if (!doc.setContent(&file)) { QMessageBox::warning(this, tr("Error"), tr("Failed to parse scenario file.")); file.close(); return; } // 重置模型路径和服务路径 modelPath = ""; ServicePath = ""; // 获取根元素 QDomElement root = doc.documentElement(); if (root.tagName() == "Scenario") { // 遍历子元素 QDomNode node = root.firstChild(); while (!node.isNull()) { QDomElement element = node.toElement(); if (!element.isNull()) { QString elementName = element.tagName(); if (elementName == "Environment") { QDomNamedNodeMap elementAttributes = element.attributes(); addGroupBox(layout, elementName, elementAttributes); } else if (elementName == "ConsoleOutput" || elementName == "Log") { // 添加控制台输出/日志组框 QDomNamedNodeMap elementAttributes = element.attributes(); addGroupBox2(layout, elementName, elementAttributes); } else if (elementName == "ModelGroup") { QDomNamedNodeMap elementAttributes = element.attributes(); // 处理模型列表 QVector modelList; QDomNodeList models = element.elementsByTagName("Model"); for (int i = 0; i < models.count(); i++) { QDomElement modelElement = models.at(i).toElement(); QDomNamedNodeMap attributes = modelElement.attributes(); modelList.append(attributes); } // 添加模型列表组框 addGroupBox3(layout, elementName, elementAttributes, modelList, 0); } else if (elementName == "ServicesList") { QDomNamedNodeMap elementAttributes = element.attributes(); // 处理服务列表 QVector serviceList; QDomNodeList services = element.elementsByTagName("Service"); for (int i = 0; i < services.count(); i++) { QDomElement serviceElement = services.at(i).toElement(); QDomNamedNodeMap attributes = serviceElement.attributes(); serviceList.append(attributes); } // 添加服务列表组框 addGroupBox3(layout, elementName, elementAttributes, serviceList, 1); } } node = node.nextSibling(); } // // 更新模型和服务列表 // QTableWidget *modelsTable = findChild(); // if (modelsTable) { // UpdateModelList(modelsTable); // } // QTableWidget *servicesTable = findChild(); // if (servicesTable) { // UpdateServiceList(servicesTable); // } updateWindowTitle(); } file.close(); } // 打开模型文件 void MainWindow::openModelFile() { // 获取右布局 QVBoxLayout *layout = findChild("rightLayout"); if (!layout) { QMessageBox::warning(this, tr("Error"), tr("Software error.")); return; } // 打开文件 QFile file(currentFilePath); if (!file.open(QIODevice::ReadOnly)) { QMessageBox::warning(this, tr("Error"), tr("Failed to open file.")); return; } // 创建DOM文档 QDomDocument doc; if (!doc.setContent(&file)) { QMessageBox::warning(this, tr("Error"), tr("Failed to parse model config file.")); file.close(); return; } // 获取根元素 QDomElement root = doc.documentElement(); if (root.tagName() == "Model") { // 添加组框 QGroupBox *groupBox = new QGroupBox("Model Info", this); groupBox->setObjectName("Model Info"); layout->addWidget(groupBox); QGridLayout *groupBoxLayout = new QGridLayout(groupBox); groupBox->setLayout(groupBoxLayout); // 遍历子元素 QDomNode node = root.firstChild(); while (!node.isNull()) { QDomElement element = node.toElement(); if (!element.isNull()) { QString elementName = element.tagName(); if (elementName == "Name" || elementName == "Description" || elementName == "Author" || elementName == "Version" || elementName == "Node" || elementName == "Priority" || elementName == "MathLib") { // 添加基本信息 addItemIntoGroupBox(groupBoxLayout, elementName, element.text(), 0); } else if (elementName == "CreateTime" || elementName == "ChangeTime") { // 添加时间信息 addItemIntoGroupBox(groupBoxLayout, elementName, element.text(), 3); } else if (elementName == "CommandList") { // 处理命令列表 QVector commandList; QDomNodeList commands = element.elementsByTagName("Command"); for (int i = 0; i < commands.count(); i++) { QDomElement commandElement = commands.at(i).toElement(); QDomNamedNodeMap attributes = commandElement.attributes(); commandList.append(attributes); } // 添加命令列表组框 addGroupBox3(layout, "CommandList", QDomNamedNodeMap(), commandList, 2); } else { QGroupBox *otherGroupBox = new QGroupBox("Other Info", this); otherGroupBox->setObjectName("Other Info"); layout->addWidget(otherGroupBox); QGridLayout *otherGroupBoxLayout = new QGridLayout(otherGroupBox); otherGroupBox->setLayout(otherGroupBoxLayout); // 递归处理其他自定义元素 std::function processChildNodes = [&](QGridLayout *subLayout, QDomNode &subNode) { QDomElement subElement = subNode.toElement(); QString subElementName = subElement.nodeName(); if (subNode.hasChildNodes() && !subNode.firstChild().isText()) { QGroupBox *groupBox = new QGroupBox(subElementName, this); subLayout->addWidget(groupBox); QGridLayout *subGroupBoxLayout = new QGridLayout(groupBox); groupBox->setLayout(subGroupBoxLayout); QDomNode childNode = subNode.firstChild(); while (!childNode.isNull()) { processChildNodes(subGroupBoxLayout, childNode); childNode = childNode.nextSibling(); } addPlusButton(subGroupBoxLayout); } else { addItemIntoGroupBox(subLayout, subElementName, subElement.text(), 99); } }; processChildNodes(otherGroupBoxLayout, node); } } node = node.nextSibling(); } // 添加"+"按钮用于添加新属性 addPlusButton(groupBoxLayout); updateWindowTitle(); } file.close(); } // 打开服务文件 void MainWindow::openServiceFile() { // 获取右布局 QVBoxLayout *layout = findChild("rightLayout"); if (!layout) { QMessageBox::warning(this, tr("Error"), tr("Software error.")); return; } // 打开文件 QFile file(currentFilePath); if (!file.open(QIODevice::ReadOnly)) { QMessageBox::warning(this, tr("Error"), tr("Failed to open file.")); return; } // 创建DOM文档 QDomDocument doc; if (!doc.setContent(&file)) { QMessageBox::warning(this, tr("Error"), tr("Failed to parse service config file.")); file.close(); return; } // 获取根元素 QDomElement root = doc.documentElement(); if (root.tagName() == "Service") { // 添加组框 QGroupBox *groupBox = new QGroupBox("Service Info", this); groupBox->setObjectName("Service Info"); layout->addWidget(groupBox); QGridLayout *groupBoxLayout = new QGridLayout(groupBox); groupBox->setLayout(groupBoxLayout); // 遍历子元素 QDomNode node = root.firstChild(); while (!node.isNull()) { QDomElement element = node.toElement(); if (!element.isNull()) { QString elementName = element.tagName(); if (elementName == "Name" || elementName == "Description" || elementName == "Author" || elementName == "Version" || elementName == "Priority") { // 添加基本信息 addItemIntoGroupBox(groupBoxLayout, elementName, element.text(), 0); } else if (elementName == "CreateTime" || elementName == "ChangeTime") { // 添加时间信息 addItemIntoGroupBox(groupBoxLayout, elementName, element.text(), 3); } else if (elementName == "CommandList") { // 处理命令列表 QVector commandList; QDomNodeList commands = element.elementsByTagName("Command"); for (int i = 0; i < commands.count(); i++) { QDomElement commandElement = commands.at(i).toElement(); QDomNamedNodeMap attributes = commandElement.attributes(); commandList.append(attributes); } // 添加命令列表组框 addGroupBox3(layout, "CommandList", QDomNamedNodeMap(), commandList, 2); } else { QGroupBox *otherGroupBox = new QGroupBox("Other Info", this); otherGroupBox->setObjectName("Other Info"); layout->addWidget(otherGroupBox); QGridLayout *otherGroupBoxLayout = new QGridLayout(otherGroupBox); otherGroupBox->setLayout(otherGroupBoxLayout); // 递归处理其他自定义元素 std::function processChildNodes = [&](QGridLayout *subLayout, QDomNode &subNode) { QDomElement subElement = subNode.toElement(); QString subElementName = subElement.nodeName(); if (subNode.hasChildNodes() && !subNode.firstChild().isText()) { QGroupBox *groupBox = new QGroupBox(subElementName, this); subLayout->addWidget(groupBox); QGridLayout *subGroupBoxLayout = new QGridLayout(groupBox); groupBox->setLayout(subGroupBoxLayout); QDomNode childNode = subNode.firstChild(); while (!childNode.isNull()) { processChildNodes(subGroupBoxLayout, childNode); childNode = childNode.nextSibling(); } addPlusButton(subGroupBoxLayout); } else { addItemIntoGroupBox(subLayout, subElementName, subElement.text(), 99); } }; processChildNodes(otherGroupBoxLayout, node); } } node = node.nextSibling(); } // 添加"+"按钮用于添加新属性 addPlusButton(groupBoxLayout); updateWindowTitle(); } file.close(); } void MainWindow::addPlusButton(QGridLayout *layout) { QPushButton *addButton = new QPushButton("+", this); addButton->setFlat(true); layout->addWidget(addButton, layout->rowCount(), 0, 1, 3); connect(addButton, &QPushButton::clicked, [this, layout, addButton]() { bool ok; QString attributeName = QInputDialog::getText( this, tr("Add Attribute"), tr("Attribute Name:"), QLineEdit::Normal, "", &ok); if (ok && !attributeName.isEmpty()) { isModified = true; updateWindowTitle(); layout->removeWidget(addButton); addItemIntoGroupBox(layout, attributeName, "", 99); layout->addWidget(addButton, layout->rowCount(), 0, 1, 3); } }); } // 打开IDL文件 void MainWindow::openIDLFile() { // 打开文件 QFile file(currentFilePath); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { QMessageBox::warning(this, tr("Error"), tr("Failed to open file.")); return; } // 清空现有数据 namespaces.clear(); // 读取文件 QTextStream in(&file); // 命名空间栈 QStack> namespaceStack; // 当前结构体 QSharedPointer currentStruct; QString line; bool inStruct = false; int braceCount = 0; // 逐行读取IDL文件 while (!in.atEnd()) { line = in.readLine().trimmed(); // 跳过空行和注释 if (line.isEmpty() || line.startsWith("//")) continue; // 处理命名空间开始 if (line.startsWith("module")) { braceCount++; // 创建新的命名空间 QSharedPointer newNS = QSharedPointer::create(); // 获取命名空间名称 QString nsNames = line.mid(7).trimmed(); newNS->namespaceName = nsNames.split(" ").first(); // 直接使用完整名称 namespaceStack.push(newNS); continue; } // 处理结构体开始 if (line.startsWith("struct")) { if (inStruct && currentStruct && !currentStruct->structName.isEmpty()) { namespaceStack.top()->structDefinitions.append(currentStruct); currentStruct = QSharedPointer::create(); } inStruct = true; braceCount++; if (!currentStruct) { currentStruct = QSharedPointer::create(); } currentStruct->structName = line.split(" ").at(1); continue; } // 处理成员变量 if (inStruct && currentStruct) { if (!line.startsWith("{") && !line.startsWith("}")) { QString description; int commentPos = line.indexOf("//"); if (commentPos != -1) { description = line.mid(commentPos + 2).trimmed(); line = line.left(commentPos).trimmed(); } QStringList parts = line.split(";").first().split(" ", Qt::SkipEmptyParts); if (parts[0].startsWith("@")) { parts.pop_front(); } if (parts.size() >= 2) { QSharedPointer var = QSharedPointer::create(); var->dataType = parts[0]; QString varDecl = parts[1]; if (varDecl.contains("[")) { var->isArray = true; var->variableName = varDecl.split("[").first(); QRegularExpression re("\\[(\\d+)\\]"); QRegularExpressionMatchIterator i = re.globalMatch(varDecl); while (i.hasNext()) { QRegularExpressionMatch match = i.next(); var->arraySizes.append(match.captured(1).toInt()); } } else { var->isArray = false; var->variableName = varDecl; } var->description = description; currentStruct->memberVariables.append(var); } } } // 处理花括号闭合 if (line.contains("}")) { braceCount--; if (inStruct) { inStruct = false; if (currentStruct && !currentStruct->structName.isEmpty()) { namespaceStack.top()->structDefinitions.append(currentStruct); currentStruct = QSharedPointer::create(); } } else { if (!namespaceStack.isEmpty()) { QSharedPointer completedNS = namespaceStack.pop(); if (namespaceStack.isEmpty()) { namespaces.append(completedNS); } else { namespaceStack.top()->childNamespaces.append(completedNS); } } } } } file.close(); // 更新IDL Tree updateIDLTreeWidget(); updateWindowTitle(); } // 根据namespaces更新树形控件 void MainWindow::updateIDLTreeWidget() { QTreeWidget *treeWidget = findChild("leftWidget"); if (!treeWidget) return; // 清空现有项 treeWidget->clear(); // 递归添加命名空间及其子命名空间的辅助函数 std::function &)> addNamespaceToTree = [&addNamespaceToTree](QTreeWidgetItem *parentItem, const QSharedPointer &ns) { // 添加结构体 for (const auto &structDef : ns->structDefinitions) { if (structDef && !structDef->structName.isEmpty()) { QTreeWidgetItem *structItem = new QTreeWidgetItem(QStringList() << structDef->structName); if (parentItem) { parentItem->addChild(structItem); } } } // 递归处理子命名空间 for (const auto &childNS : ns->childNamespaces) { if (childNS && !childNS->namespaceName.isEmpty()) { QTreeWidgetItem *childItem = new QTreeWidgetItem(QStringList() << childNS->namespaceName); if (parentItem) { parentItem->addChild(childItem); addNamespaceToTree(childItem, childNS); } } } }; // 处理顶层命名空间 for (const auto &ns : namespaces) { if (ns && !ns->namespaceName.isEmpty()) { QTreeWidgetItem *nsItem = new QTreeWidgetItem(QStringList() << ns->namespaceName); treeWidget->addTopLevelItem(nsItem); addNamespaceToTree(nsItem, ns); } } // 展开整个树形控件 treeWidget->expandAll(); // 连接树形控件的项目选择信号 disconnect(treeWidget, &QTreeWidget::itemClicked, this, &MainWindow::onTreeWidgetItemClicked); connect(treeWidget, &QTreeWidget::itemClicked, this, &MainWindow::onTreeWidgetItemClicked); } void MainWindow::onTreeWidgetItemClicked(QTreeWidgetItem *item) { if (!item->parent()) return; // 如果是顶层项目(命名空间),则返回 QTableWidget *tableWidget = findChild("rightWidget"); if (!tableWidget) return; // 清空表格 tableWidget->setRowCount(0); // 获取选中的结构体名称 QString structName = item->text(0); std::function(const QString &, QSharedPointer &)> findStruct = [&findStruct]( const QString &structName, QSharedPointer &ns) -> QSharedPointer { // 在当前命名空间中查找结构体 for (auto &structDef : ns->structDefinitions) { if (structDef && structDef->structName == structName) { return structDef; } } // 在子命名空间中递归查找 for (auto &childNS : ns->childNamespaces) { auto result = findStruct(structName, childNS); if (result) { return result; } } return QSharedPointer(); }; QSharedPointer structDef; for (auto &ns : namespaces) { structDef = findStruct(structName, ns); if (structDef) { break; } } if (structDef) { // 找到对应的结构体,显示其成员变量 tableWidget->setRowCount(structDef->memberVariables.size()); int row = 0; for (const auto &member : structDef->memberVariables) { // 变量名 QTableWidgetItem *nameItem = new QTableWidgetItem(member->variableName); tableWidget->setItem(row, 0, nameItem); // 数据类型 QTableWidgetItem *typeItem = new QTableWidgetItem(member->dataType); tableWidget->setItem(row, 1, typeItem); // 数组大小 QString sizeStr; if (member->isArray) { QStringList sizes; for (int size : member->arraySizes) { sizes << QString::number(size); } sizeStr = "[" + sizes.join("][") + "]"; } else { sizeStr = "1"; } QTableWidgetItem *sizeItem = new QTableWidgetItem(sizeStr); tableWidget->setItem(row, 2, sizeItem); // 描述(注释) QTableWidgetItem *descItem = new QTableWidgetItem(member->description); tableWidget->setItem(row, 3, descItem); row++; } } } // 添加组框1 void MainWindow::addGroupBox(QVBoxLayout *layout, QString name, QDomNamedNodeMap attributes) { // 工作路径 QString workPath; // 创建组框 QGroupBox *groupBox = new QGroupBox(name, this); // 设置组框名称 groupBox->setObjectName(name); // 添加到布局 layout->addWidget(groupBox); // 创建网格布局 QGridLayout *gridLayout = new QGridLayout(groupBox); // 设置布局 groupBox->setLayout(gridLayout); // 遍历属性添加控件 for (int i = 0; i < attributes.count(); i++) { QDomNode attr = attributes.item(i); if (attr.nodeName() == "WorkPath") { // 如果是WorkPath,多添加一个选择路径按钮 addItemIntoGroupBox(gridLayout, attr.nodeName(), attr.nodeValue(), 1); } else if (attr.nodeName() == "ModelsPath") { // 如果是ModelsPath,正常添加 addItemIntoGroupBox(gridLayout, attr.nodeName(), attr.nodeValue(), 0); // 记录ModelsPath modelPath = attr.nodeValue(); } else if (attr.nodeName() == "ServicesPath") { // 如果是ServicesPath,正常添加 addItemIntoGroupBox(gridLayout, attr.nodeName(), attr.nodeValue(), 0); // 记录ServicesPath ServicePath = attr.nodeValue(); } else if (attr.nodeName() == "OSName" || attr.nodeName() == "Version" || attr.nodeName() == "RTXVersion" || attr.nodeName() == "CPUAffinity" || attr.nodeName() == "BaseFrequency" || attr.nodeName() == "DomainID") { // 如果是OSName、Version、RTXVersion、CPUAffinity、BaseFrequency、DomainID,正常添加 addItemIntoGroupBox(gridLayout, attr.nodeName(), attr.nodeValue(), 0); } else { // 如果是其他属性,添加一个删除按钮 addItemIntoGroupBox(gridLayout, attr.nodeName(), attr.nodeValue(), 99); } } // 如果工作路径不为空 if (!workPath.isEmpty()) { // 如果工作路径不以"/"结尾 if (!workPath.endsWith("/")) { // 添加"/" workPath.append("/"); } // 添加工作路径到模型路径和服务路径 modelPath = workPath + modelPath; ServicePath = workPath + ServicePath; } // 添加"+"按钮 addPlusButton(gridLayout); } // 添加组框2 void MainWindow::addGroupBox2(QVBoxLayout *layout, QString name, QDomNamedNodeMap attributes) { // 创建组框 QGroupBox *groupBox = new QGroupBox(name, this); // 设置组框名称 groupBox->setObjectName(name); // 添加到布局 layout->addWidget(groupBox); // 创建水平布局 QHBoxLayout *hLayout = new QHBoxLayout(groupBox); // 设置布局 groupBox->setLayout(hLayout); // 遍历属性添加控件 for (int i = 0; i < attributes.count(); i++) { QDomNode attr = attributes.item(i); // 创建复选框 QCheckBox *checkBox = new QCheckBox(attr.nodeName(), this); // 如果属性值为true或1或True或TRUE,则设置为选中 if (attr.nodeValue() == "true" || attr.nodeValue() == "1" || attr.nodeValue() == "True" || attr.nodeValue() == "TRUE") { checkBox->setChecked(true); } else { checkBox->setChecked(false); } // 添加到布局 hLayout->addWidget(checkBox); // 连接修改信号 connectModificationSignals(checkBox); } } // 添加组框3 void MainWindow::addGroupBox3(QVBoxLayout *layout, QString name, QDomNamedNodeMap groupAttributes, QVector vecAttributes, int type) { // 创建组框 QGroupBox *groupBox = new QGroupBox(name, this); // 设置组框名称 groupBox->setObjectName(name); // 添加到布局 layout->addWidget(groupBox); // 创建垂直布局 QGridLayout *groupBoxLayout = new QGridLayout(groupBox); // 遍历组属性 for (int i = 0; i < groupAttributes.count(); i++) { QDomNode attr = groupAttributes.item(i); addItemIntoGroupBox(groupBoxLayout, attr.nodeName(), attr.nodeValue(), 0); } // 创建水平布局 QHBoxLayout *buttonLayout = new QHBoxLayout(); // 创建添加按钮 QPushButton *addButton = new QPushButton("Add", this); // 创建删除按钮 QPushButton *removeButton = new QPushButton("Remove", this); // 添加按钮到水平布局 buttonLayout->addWidget(addButton); // 添加按钮到水平布局 buttonLayout->addWidget(removeButton); // 添加水平布局到垂直布局 groupBoxLayout->addLayout(buttonLayout, groupBoxLayout->rowCount(), 0, 1, groupBoxLayout->columnCount()); // 创建表格 QTableWidget *tableWidget = new QTableWidget(groupBox); // 设置表格拉伸模式 tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); // 设置表格行数 tableWidget->setRowCount(vecAttributes.size()); // 设置表格选择模式 tableWidget->setSelectionMode(QAbstractItemView::SingleSelection); // 如果类型为0或1,即模型列表或服务列表 if (type == 0 || type == 1) { // 设置表格列数 tableWidget->setColumnCount(2); // 创建表头 QStringList headers; // 设置表头 headers << "Name" << "ClassName"; // 设置表头 tableWidget->setHorizontalHeaderLabels(headers); } else if (type == 2) { // 如果类型为2,即命令列表 // 设置表格列数 tableWidget->setColumnCount(3); // 创建表头 QStringList headers; // 设置表头 headers << "Name" << "Description" << "Call"; // 设置表头 tableWidget->setHorizontalHeaderLabels(headers); } // 添加表格到组框布局 groupBoxLayout->addWidget(tableWidget, groupBoxLayout->rowCount(), 0, 1, groupBoxLayout->columnCount()); int rowCount = 0; // 遍历属性 for (QDomNamedNodeMap &attributes : vecAttributes) { // 遍历属性 for (int i = 0; i < attributes.count(); i++) { // 如果类型为0或1,即模型列表或服务列表 if (type == 0 || type == 1) { if (attributes.item(i).nodeName() == "ClassName") { // 如果属性名称为ClassName,设置表格项第2列 tableWidget->setItem(rowCount, 1, new QTableWidgetItem(attributes.item(i).nodeValue())); } else if (attributes.item(i).nodeName() == "Name") { // 如果属性名称为Name,设置表格项第1列 tableWidget->setItem(rowCount, 0, new QTableWidgetItem(attributes.item(i).nodeValue())); } } else if (type == 2) { // 如果类型为2,即命令列表 if (attributes.item(i).nodeName() == "Name") { // 如果属性名称为Name,设置表格项第1列 tableWidget->setItem(rowCount, 0, new QTableWidgetItem(attributes.item(i).nodeValue())); } else if (attributes.item(i).nodeName() == "Description") { // 如果属性名称为Description,设置表格项第2列 tableWidget->setItem(rowCount, 1, new QTableWidgetItem(attributes.item(i).nodeValue())); } else if (attributes.item(i).nodeName() == "Call") { // 如果属性名称为Call,设置表格项第3列 tableWidget->setItem(rowCount, 2, new QTableWidgetItem(attributes.item(i).nodeValue())); } } } rowCount++; } // 更新模型列表或服务列表 if (type == 0) { UpdateModelList(tableWidget); } else if (type == 1) { UpdateServiceList(tableWidget); } // 链接add按钮的槽 connect(addButton, &QPushButton::clicked, [tableWidget]() { int row = tableWidget->rowCount(); tableWidget->insertRow(row); }); // 链接remove的槽 connect(removeButton, &QPushButton::clicked, [this, tableWidget]() { int currentRow = tableWidget->currentRow(); if (currentRow >= 0) { if (!tableWidget->item(currentRow, 0)->text().isEmpty()) { isModified = true; updateWindowTitle(); } tableWidget->removeRow(currentRow); tableWidget->clearSelection(); } }); // 链接元素改变的槽 connect(tableWidget, &QTableWidget::itemChanged, [this, tableWidget, type]() { if (type == 0) { UpdateModelList(tableWidget); } else if (type == 1) { UpdateServiceList(tableWidget); } isModified = true; updateWindowTitle(); }); } // 向组框1添加元素 void MainWindow::addItemIntoGroupBox(QGridLayout *gridLayout, QString itemName, QString itemValue, int itemStyle) { int row = gridLayout->rowCount(); QLabel *label = new QLabel(itemName, this); gridLayout->addWidget(label, row, 0); if (itemStyle == 0) { //普通模式 QLineEdit *lineEdit = new QLineEdit(itemValue, this); gridLayout->addWidget(lineEdit, row, 1); setLineEditRules(lineEdit, itemName); connectModificationSignals(lineEdit); } else if (itemStyle == 1) { //路径模式 QLineEdit *lineEdit = new QLineEdit(itemValue, this); gridLayout->addWidget(lineEdit, row, 1); QPushButton *openPathButton = new QPushButton("...", this); gridLayout->addWidget(openPathButton, row, 2); connect(openPathButton, &QPushButton::clicked, [this, lineEdit]() { QString newPath = QFileDialog::getExistingDirectory(this, tr("Select Directory"), lineEdit->text()); if (!newPath.isEmpty()) { lineEdit->setText(newPath); } }); connectModificationSignals(lineEdit); } else if (itemStyle == 2) { //文件选择模式 QLineEdit *lineEdit = new QLineEdit(itemValue, this); gridLayout->addWidget(lineEdit, row, 1); QPushButton *openFileButton = new QPushButton("...", this); gridLayout->addWidget(openFileButton, row, 2); connect(openFileButton, &QPushButton::clicked, [this, lineEdit]() { QString newPath = QFileDialog::getOpenFileName(this, tr("Select File"), lineEdit->text(), tr("All Files (*)")); if (!newPath.isEmpty()) { lineEdit->setText(newPath); } }); connectModificationSignals(lineEdit); } else if (itemStyle == 3) { //时间选择模式 QDateTimeEdit *dateTimeEdit = new QDateTimeEdit(this); gridLayout->addWidget(dateTimeEdit, row, 1); dateTimeEdit->setCalendarPopup(true); dateTimeEdit->setDateTime(QDateTime::currentDateTime()); connectModificationSignals(dateTimeEdit); } else if (itemStyle == 99) { //自定义模式,支持删除 QLineEdit *lineEdit = new QLineEdit(itemValue, this); gridLayout->addWidget(lineEdit, row, 1); QPushButton *minuseButton = new QPushButton("-", this); minuseButton->setFixedSize(20, 20); connect(minuseButton, &QPushButton::clicked, [this, gridLayout, label, lineEdit, minuseButton]() { QMessageBox::StandardButton reply; reply = QMessageBox::question(this, tr("Confirm Deletion"), tr("Are you sure you want to delete this attribute?"), QMessageBox::Yes | QMessageBox::No); if (reply == QMessageBox::Yes) { isModified = true; updateWindowTitle(); gridLayout->removeWidget(label); gridLayout->removeWidget(lineEdit); gridLayout->removeWidget(minuseButton); delete label; delete lineEdit; delete minuseButton; } }); gridLayout->addWidget(minuseButton, row, 2); connectModificationSignals(lineEdit); } } void MainWindow::setLineEditRules(QLineEdit *lineEdit, QString name) { if (name == "WorkPath" || name == "ModelsPath" || name == "ServicesPath") { // 实时验证目录是否存在 connect(lineEdit, &QLineEdit::textChanged, [this, lineEdit, name](const QString &text) { QDir dir(text); if (!dir.exists()) { lineEdit->setStyleSheet("border: 2px solid red;"); lineEdit->setToolTip(tr("Directory does not exist")); } else { lineEdit->setStyleSheet(""); lineEdit->setToolTip(""); } }); } else if (name == "Name") { connect(lineEdit, &QLineEdit::textChanged, [this, lineEdit, name](const QString &text) { // 检查是否是C++标准的名称 QRegularExpression regex("^[A-Za-z_][A-Za-z0-9_]*$"); if (!regex.match(text).hasMatch()) { lineEdit->setStyleSheet("border: 2px solid red;"); lineEdit->setToolTip(tr("Invalid class name. Must start with letter/underscore and " "contain only letters, numbers and underscores")); } else { lineEdit->setStyleSheet(""); lineEdit->setToolTip(""); } }); } else if (name == "CPUAffinity") { // 检查是否是逗号分割的数字列表 connect(lineEdit, &QLineEdit::textChanged, [this, lineEdit, name](const QString &text) { QRegularExpression regex("^[0-9,]+$"); if (!regex.match(text).hasMatch()) { lineEdit->setStyleSheet("border: 2px solid red;"); lineEdit->setToolTip( tr("Invalid CPU affinity format. Must be a comma-separated list of numbers")); } else { lineEdit->setStyleSheet(""); lineEdit->setToolTip(""); } }); } else if (name == "BaseFrequency" || name == "DomainID" || name == "Priority") { // 检查是否是数字 connect(lineEdit, &QLineEdit::textChanged, [this, lineEdit, name](const QString &text) { QRegularExpression regex("^[0-9]+$"); if (!regex.match(text).hasMatch()) { lineEdit->setStyleSheet("border: 2px solid red;"); lineEdit->setToolTip(tr("Invalid base frequency. Must be a number")); } else { lineEdit->setStyleSheet(""); lineEdit->setToolTip(""); } }); } else if (name == "Node") { connect(lineEdit, &QLineEdit::textChanged, [this, lineEdit, name](const QString &text) { // 验证"数字-数字"的格式 QRegularExpression regex("^\\d+-\\d+$"); if (!regex.match(text).hasMatch()) { lineEdit->setStyleSheet("border: 2px solid red;"); lineEdit->setToolTip( tr("Invalid format. Must be in the form of 'number-number' (e.g. 3-5)")); } else { // 进一步验证第一个数字是否小于第二个数字 QStringList parts = text.split('-'); int first = parts[0].toInt(); int second = parts[1].toInt(); if (first > 5) { lineEdit->setStyleSheet("border: 2px solid red;"); lineEdit->setToolTip(tr("First number must be less than 5")); } else { if (second >= pow(2, first)) { lineEdit->setStyleSheet("border: 2px solid red;"); lineEdit->setToolTip(tr( "Second number must be less than 2 to the power of the first number")); } else { lineEdit->setStyleSheet(""); lineEdit->setToolTip(""); } } } }); } } // 寻找模型 bool MainWindow::findModel(QString modelName, QString ModelPath) { //查找模型动态库是否存在 QFile modelsoFile(ModelPath + "/lib" + modelName + ".so"); if (!modelsoFile.exists()) { return false; } //查找模型配置文件是否存在 QFile modelFile(ModelPath + "/" + modelName + ".mcfg"); if (!modelFile.exists()) { return false; } QTreeWidget *modelWidget = findChild("ModelWidget"); if (modelWidget) { // 检查模型列表中是否已存在同名模型 bool exists = false; for (int i = 0; i < modelWidget->topLevelItemCount(); i++) { if (modelWidget->topLevelItem(i)->text(0) == modelName + ".mcfg") { exists = true; break; } } if (!exists) modelWidget->addTopLevelItem(new QTreeWidgetItem(QStringList() << modelName + ".mcfg")); else return false; } return true; } // 寻找服务 bool MainWindow::findService(QString serviceName, QString ServicePath) { // 查找服务动态库是否存在 QFile servicesoFile(ServicePath + "/lib" + serviceName + ".so"); if (!servicesoFile.exists()) { return false; } // 查找服务配置文件是否存在 QFile serviceFile(ServicePath + "/" + serviceName + ".scfg"); if (!serviceFile.exists()) { return false; } QTreeWidget *serviceWidget = findChild("ServiceWidget"); if (serviceWidget) { // 检查服务列表中是否已存在同名模型 bool exists = false; for (int i = 0; i < serviceWidget->topLevelItemCount(); i++) { if (serviceWidget->topLevelItem(i)->text(0) == serviceName + ".scfg") { exists = true; break; } } if (!exists) serviceWidget->addTopLevelItem( new QTreeWidgetItem(QStringList() << serviceName + ".scfg")); else return false; } return true; } // 更新模型配置文件列表 void MainWindow::UpdateModelList(QTableWidget *tabWidget) { if (currentFileType != 0 || tabWidget == nullptr) return; QTreeWidget *modelWidget = findChild("ModelWidget"); if (modelWidget) { modelWidget->clear(); } for (int row = 0; row < tabWidget->rowCount(); row++) { QTableWidgetItem *item = tabWidget->item(row, 1); // Get item from ClassName column if (item) { QString className = item->text(); if (!findModel(className, modelPath)) { item->setForeground(Qt::red); item->setToolTip("Model not found or already exists"); } else { item->setForeground(Qt::white); item->setToolTip(""); } } } } // 更新服务配置文件列表 void MainWindow::UpdateServiceList(QTableWidget *tabWidget) { if (currentFileType != 0 || tabWidget == nullptr) return; QTreeWidget *serviceWidget = findChild("ServiceWidget"); if (serviceWidget) { serviceWidget->clear(); } for (int row = 0; row < tabWidget->rowCount(); row++) { QTableWidgetItem *item = tabWidget->item(row, 1); // Get item from ClassName column if (item) { QString className = item->text(); if (!findService(className, ServicePath)) { item->setForeground(Qt::red); item->setToolTip("Service not found or already exists"); } else { item->setForeground(Qt::white); item->setToolTip(""); } } } } // 保存文件 void MainWindow::saveFile(QString filePath) { if (!filePath.isEmpty()) { if (currentFileType == 0) { saveScenarioFile(filePath); } else if (currentFileType == 1) { saveModelFile(filePath); } else if (currentFileType == 2) { saveServiceFile(filePath); } else if (currentFileType == 3) { saveIDLFile(filePath); } isModified = false; // 文件保存后重置修改状态 updateWindowTitle(); } } // 保存运行环境配置文件 void MainWindow::saveScenarioFile(QString filePath) { QFile file(filePath); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { QMessageBox::warning(this, tr("Error"), tr("Failed to save file.")); return; } QXmlStreamWriter xmlWriter(&file); xmlWriter.setAutoFormatting(true); xmlWriter.writeStartDocument(); xmlWriter.writeStartElement("Scenario"); // 保存Environment部分 QGroupBox *envGroupBox = findChild("Environment"); if (envGroupBox) { xmlWriter.writeStartElement("Environment"); QGridLayout *gridLayout = qobject_cast(envGroupBox->layout()); if (gridLayout) { for (int i = 0; i < gridLayout->rowCount(); ++i) { QLayoutItem *labelItem = gridLayout->itemAtPosition(i, 0); QLayoutItem *lineEditItem = gridLayout->itemAtPosition(i, 1); if (labelItem && lineEditItem) { QLabel *label = qobject_cast(labelItem->widget()); QLineEdit *lineEdit = qobject_cast(lineEditItem->widget()); if (label && lineEdit) { xmlWriter.writeAttribute(label->text(), lineEdit->text()); } } } } xmlWriter.writeEndElement(); // Environment } // 保存ConsoleOutput和Log部分 QGroupBox *consoleGroupBox = findChild("ConsoleOutput"); if (consoleGroupBox) { xmlWriter.writeStartElement("ConsoleOutput"); QHBoxLayout *hLayout = qobject_cast(consoleGroupBox->layout()); if (hLayout) { for (int i = 0; i < hLayout->count(); ++i) { QCheckBox *checkBox = qobject_cast(hLayout->itemAt(i)->widget()); if (checkBox) { xmlWriter.writeAttribute(checkBox->text(), checkBox->isChecked() ? "true" : "false"); } } } xmlWriter.writeEndElement(); // ConsoleOutput } QGroupBox *logGroupBox = findChild("Log"); if (logGroupBox) { xmlWriter.writeStartElement("Log"); QHBoxLayout *hLayout = qobject_cast(logGroupBox->layout()); if (hLayout) { for (int i = 0; i < hLayout->count(); ++i) { QCheckBox *checkBox = qobject_cast(hLayout->itemAt(i)->widget()); if (checkBox) { xmlWriter.writeAttribute(checkBox->text(), checkBox->isChecked() ? "true" : "false"); } } } xmlWriter.writeEndElement(); // Log } // 保存ModelsList部分 QGroupBox *modelsGroupBox = findChild("ModelsList"); if (modelsGroupBox) { xmlWriter.writeStartElement("ModelsList"); QTableWidget *tableWidget = modelsGroupBox->findChild(); if (tableWidget) { for (int row = 0; row < tableWidget->rowCount(); ++row) { if (!tableWidget->item(row, 1)->text().isEmpty()) { xmlWriter.writeStartElement("Model"); for (int col = 0; col < tableWidget->columnCount(); ++col) { QTableWidgetItem *item = tableWidget->item(row, col); if (item) { xmlWriter.writeAttribute(tableWidget->horizontalHeaderItem(col)->text(), item->text()); } } xmlWriter.writeEndElement(); // Model } } } xmlWriter.writeEndElement(); // ModelsList } // 保存ServicesList部分 QGroupBox *servicesGroupBox = findChild("ServicesList"); if (servicesGroupBox) { xmlWriter.writeStartElement("ServicesList"); QTableWidget *tableWidget = servicesGroupBox->findChild(); if (tableWidget) { for (int row = 0; row < tableWidget->rowCount(); ++row) { if (!tableWidget->item(row, 1)->text().isEmpty()) { xmlWriter.writeStartElement("Service"); for (int col = 0; col < tableWidget->columnCount(); ++col) { QTableWidgetItem *item = tableWidget->item(row, col); if (item) { xmlWriter.writeAttribute(tableWidget->horizontalHeaderItem(col)->text(), item->text()); } } xmlWriter.writeEndElement(); // Service } } } xmlWriter.writeEndElement(); // ServicesList } xmlWriter.writeEndElement(); // Scenario xmlWriter.writeEndDocument(); file.close(); } // 保存模型配置文件 void MainWindow::saveModelFile(QString filePath) { QFile file(filePath); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { QMessageBox::warning(this, tr("Error"), tr("Failed to save file.")); return; } QXmlStreamWriter xmlWriter(&file); xmlWriter.setAutoFormatting(true); xmlWriter.writeStartDocument(); xmlWriter.writeStartElement("Model"); // 保存Model Info部分 QGroupBox *modelInfoBox = findChild("Model Info"); if (modelInfoBox) { QGridLayout *gridLayout = qobject_cast(modelInfoBox->layout()); if (gridLayout) { for (int i = 0; i < gridLayout->rowCount(); ++i) { QLayoutItem *labelItem = gridLayout->itemAtPosition(i, 0); QLayoutItem *valueItem = gridLayout->itemAtPosition(i, 1); if (labelItem && valueItem) { QLabel *label = qobject_cast(labelItem->widget()); if (QLineEdit *lineEdit = qobject_cast(valueItem->widget())) { if (label) { xmlWriter.writeStartElement(label->text()); xmlWriter.writeCharacters(lineEdit->text()); xmlWriter.writeEndElement(); } } else if (QDateTimeEdit *dateTimeEdit = qobject_cast(valueItem->widget())) { if (label) { xmlWriter.writeStartElement(label->text()); xmlWriter.writeCharacters( dateTimeEdit->dateTime().toString(Qt::ISODate)); xmlWriter.writeEndElement(); } } } } } } // 保存CommandList部分 QGroupBox *commandListBox = findChild("CommandList"); if (commandListBox) { xmlWriter.writeStartElement("CommandList"); QTableWidget *tableWidget = commandListBox->findChild(); if (tableWidget) { for (int row = 0; row < tableWidget->rowCount(); ++row) { if (!tableWidget->item(row, 0)->text().isEmpty()) { xmlWriter.writeStartElement("Command"); for (int col = 0; col < tableWidget->columnCount(); ++col) { QTableWidgetItem *item = tableWidget->item(row, col); if (item) { xmlWriter.writeAttribute(tableWidget->horizontalHeaderItem(col)->text(), item->text()); } } xmlWriter.writeEndElement(); // Command } } } xmlWriter.writeEndElement(); // CommandList } // 保存Other Info部分 QGroupBox *otherInfoBox = findChild("Other Info"); if (otherInfoBox) { // 创建递归处理GroupBox的lambda函数 std::function processGroupBox = [&](QGridLayout *layout) { for (int i = 0; i < layout->rowCount(); ++i) { QLayoutItem *labelItem = layout->itemAtPosition(i, 0); QLayoutItem *valueItem = layout->itemAtPosition(i, 1); if (labelItem && valueItem) { QLabel *label = qobject_cast(labelItem->widget()); if (QLineEdit *lineEdit = qobject_cast(valueItem->widget())) { if (label && !lineEdit->text().isEmpty()) { // 写入最终元素及其值 xmlWriter.writeStartElement(label->text()); xmlWriter.writeCharacters(lineEdit->text()); xmlWriter.writeEndElement(); } } } else if (QGroupBox *groupBox = qobject_cast(layout->itemAt(i)->widget())) { // 递归处理子GroupBox xmlWriter.writeStartElement(groupBox->title()); QGridLayout *subLayout = qobject_cast(groupBox->layout()); if (subLayout) { processGroupBox(subLayout); } xmlWriter.writeEndElement(); } } }; // 开始处理Other Info GroupBox QGridLayout *gridLayout = qobject_cast(otherInfoBox->layout()); if (gridLayout) { processGroupBox(gridLayout); } } xmlWriter.writeEndElement(); // Model xmlWriter.writeEndDocument(); file.close(); } // 保存服务配置文件 void MainWindow::saveServiceFile(QString filePath) { QFile file(filePath); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { QMessageBox::warning(this, tr("Error"), tr("Failed to save file.")); return; } QXmlStreamWriter xmlWriter(&file); xmlWriter.setAutoFormatting(true); xmlWriter.writeStartDocument(); xmlWriter.writeStartElement("Service"); // 保存Service Info部分 QGroupBox *serviceInfoBox = findChild("Service Info"); if (serviceInfoBox) { QGridLayout *gridLayout = qobject_cast(serviceInfoBox->layout()); if (gridLayout) { for (int i = 0; i < gridLayout->rowCount(); ++i) { QLayoutItem *labelItem = gridLayout->itemAtPosition(i, 0); QLayoutItem *valueItem = gridLayout->itemAtPosition(i, 1); if (labelItem && valueItem) { QLabel *label = qobject_cast(labelItem->widget()); if (QLineEdit *lineEdit = qobject_cast(valueItem->widget())) { if (label && !lineEdit->text().isEmpty()) { xmlWriter.writeStartElement(label->text()); xmlWriter.writeCharacters(lineEdit->text()); xmlWriter.writeEndElement(); } } else if (QDateTimeEdit *dateTimeEdit = qobject_cast(valueItem->widget())) { if (label) { xmlWriter.writeStartElement(label->text()); xmlWriter.writeCharacters( dateTimeEdit->dateTime().toString(Qt::ISODate)); xmlWriter.writeEndElement(); } } } } } } // 保存CommandList部分 QGroupBox *commandListBox = findChild("CommandList"); if (commandListBox) { xmlWriter.writeStartElement("CommandList"); QTableWidget *tableWidget = commandListBox->findChild(); if (tableWidget) { for (int row = 0; row < tableWidget->rowCount(); ++row) { // 只保存非空行 if (!tableWidget->item(row, 0)->text().isEmpty()) { xmlWriter.writeStartElement("Command"); for (int col = 0; col < tableWidget->columnCount(); ++col) { QTableWidgetItem *item = tableWidget->item(row, col); if (item) { xmlWriter.writeAttribute(tableWidget->horizontalHeaderItem(col)->text(), item->text()); } } xmlWriter.writeEndElement(); // Command } } } xmlWriter.writeEndElement(); // CommandList } // 保存Other Info部分 QGroupBox *otherInfoBox = findChild("Other Info"); if (otherInfoBox) { // 创建递归处理GroupBox的lambda函数 std::function processGroupBox = [&](QGridLayout *layout) { for (int i = 0; i < layout->rowCount(); ++i) { QLayoutItem *labelItem = layout->itemAtPosition(i, 0); QLayoutItem *valueItem = layout->itemAtPosition(i, 1); if (labelItem && valueItem) { QLabel *label = qobject_cast(labelItem->widget()); if (QLineEdit *lineEdit = qobject_cast(valueItem->widget())) { if (label && !lineEdit->text().isEmpty()) { // 写入最终元素及其值 xmlWriter.writeStartElement(label->text()); xmlWriter.writeCharacters(lineEdit->text()); xmlWriter.writeEndElement(); } } } else if (QGroupBox *groupBox = qobject_cast(layout->itemAt(i)->widget())) { // 递归处理子GroupBox xmlWriter.writeStartElement(groupBox->title()); QGridLayout *subLayout = qobject_cast(groupBox->layout()); if (subLayout) { processGroupBox(subLayout); } xmlWriter.writeEndElement(); } } }; // 开始处理Other Info GroupBox QGridLayout *gridLayout = qobject_cast(otherInfoBox->layout()); if (gridLayout) { processGroupBox(gridLayout); } } xmlWriter.writeEndElement(); // Service xmlWriter.writeEndDocument(); file.close(); } // 保存IDL文件 void MainWindow::saveIDLFile(QString filePath) { //TODO 还没实现 } // 在新窗口打开文件 void MainWindow::openFileInNewWindow(QString fileName) { MainWindow *newWindow = new MainWindow(fileName, nullptr); newWindow->show(); } // 添加一个辅助函数来连接控件的修改信号 void MainWindow::connectModificationSignals(QWidget *widget) { if (QLineEdit *lineEdit = qobject_cast(widget)) { connect(lineEdit, &QLineEdit::textChanged, [this]() { isModified = true; updateWindowTitle(); }); } else if (QCheckBox *checkBox = qobject_cast(widget)) { connect(checkBox, &QCheckBox::checkStateChanged, [this]() { isModified = true; updateWindowTitle(); }); } else if (QTableWidget *tableWidget = qobject_cast(widget)) { connect(tableWidget, &QTableWidget::itemChanged, [this]() { isModified = true; updateWindowTitle(); }); } else if (QDateTimeEdit *dateTimeEdit = qobject_cast(widget)) { connect(dateTimeEdit, &QDateTimeEdit::dateTimeChanged, [this]() { isModified = true; updateWindowTitle(); }); } // 递归处理子控件 for (QObject *child : widget->children()) { if (QWidget *childWidget = qobject_cast(child)) { connectModificationSignals(childWidget); } } } // 添加一个辅助函数来更新标题 void MainWindow::updateWindowTitle() { QString title = "XNEditor"; if (!currentFilePath.isEmpty()) { title += " - " + QFileInfo(currentFilePath).fileName(); } if (isModified) { title += " *"; } setWindowTitle(title); } // 窗口关闭事件的响应 void MainWindow::closeEvent(QCloseEvent *event) { if (isModified) { onCloseFileTriggered(); // 如果用户选择了Cancel,我们需要阻止窗口关闭 if (isModified) { event->ignore(); return; } } event->accept(); }