XNSim/XNEditor/mainwindow.cpp

2226 lines
72 KiB
C++
Raw Normal View History

2025-04-28 12:25:20 +08:00
/**
* @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 <QFileDialog>
#include <QFile>
#include <QTextStream>
#include <QMessageBox>
#include <QXmlStreamReader>
#include <QHBoxLayout>
#include <QTreeWidget>
#include <QSplitter>
#include <QGroupBox>
#include <QLabel>
#include <QGridLayout>
#include <QTableWidget>
#include <QCheckBox>
#include <QHeaderView>
#include <QPushButton>
#include <QInputDialog>
#include <QFileInfo>
#include <QXmlStreamWriter>
#include <QDir>
#include <QTimer>
#include <QDateTimeEdit>
#include <QSet>
#include <algorithm>
#include <QSharedPointer>
#include <QStack>
#include <QRegularExpression>
#include <QDebug>
#include <QDomDocument>
#include <QDomElement>
#include <QDomNode>
#include <QDomNamedNodeMap>
//构造函数
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<QTreeWidget *>("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<NamespaceDefinition>(&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<QTreeWidget *>("ModelWidget");
if (ModelWidget) {
ModelWidget->clear();
}
QTreeWidget *ServiceWidget = findChild<QTreeWidget *>("ServiceWidget");
if (ServiceWidget) {
ServiceWidget->clear();
}
QVBoxLayout *layout = findChild<QVBoxLayout *>("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<QVBoxLayout *>("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<QDomNamedNodeMap> 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<QDomNamedNodeMap> 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<QTableWidget *>();
// if (modelsTable) {
// UpdateModelList(modelsTable);
// }
// QTableWidget *servicesTable = findChild<QTableWidget *>();
// if (servicesTable) {
// UpdateServiceList(servicesTable);
// }
updateWindowTitle();
}
file.close();
}
// 打开模型文件
void MainWindow::openModelFile()
{
// 获取右布局
QVBoxLayout *layout = findChild<QVBoxLayout *>("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<QDomNamedNodeMap> 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<void(QGridLayout *, QDomNode &)> 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<QVBoxLayout *>("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<QDomNamedNodeMap> 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<void(QGridLayout *, QDomNode &)> 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<QSharedPointer<NamespaceDefinition>> namespaceStack;
// 当前结构体
QSharedPointer<StructDefinition> 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<NamespaceDefinition> newNS =
QSharedPointer<NamespaceDefinition>::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<StructDefinition>::create();
}
inStruct = true;
braceCount++;
if (!currentStruct) {
currentStruct = QSharedPointer<StructDefinition>::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<MemberVariable> var = QSharedPointer<MemberVariable>::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<StructDefinition>::create();
}
} else {
if (!namespaceStack.isEmpty()) {
QSharedPointer<NamespaceDefinition> 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<QTreeWidget *>("leftWidget");
if (!treeWidget)
return;
// 清空现有项
treeWidget->clear();
// 递归添加命名空间及其子命名空间的辅助函数
std::function<void(QTreeWidgetItem *, const QSharedPointer<NamespaceDefinition> &)>
addNamespaceToTree = [&addNamespaceToTree](QTreeWidgetItem *parentItem,
const QSharedPointer<NamespaceDefinition> &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<QTableWidget *>("rightWidget");
if (!tableWidget)
return;
// 清空表格
tableWidget->setRowCount(0);
// 获取选中的结构体名称
QString structName = item->text(0);
std::function<QSharedPointer<StructDefinition>(const QString &,
QSharedPointer<NamespaceDefinition> &)>
findStruct =
[&findStruct](
const QString &structName,
QSharedPointer<NamespaceDefinition> &ns) -> QSharedPointer<StructDefinition> {
// 在当前命名空间中查找结构体
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<StructDefinition>();
};
QSharedPointer<StructDefinition> 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<QDomNamedNodeMap> 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<QTreeWidget *>("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<QTreeWidget *>("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<QTreeWidget *>("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<QTreeWidget *>("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<QGroupBox *>("Environment");
if (envGroupBox) {
xmlWriter.writeStartElement("Environment");
QGridLayout *gridLayout = qobject_cast<QGridLayout *>(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<QLabel *>(labelItem->widget());
QLineEdit *lineEdit = qobject_cast<QLineEdit *>(lineEditItem->widget());
if (label && lineEdit) {
xmlWriter.writeAttribute(label->text(), lineEdit->text());
}
}
}
}
xmlWriter.writeEndElement(); // Environment
}
// 保存ConsoleOutput和Log部分
QGroupBox *consoleGroupBox = findChild<QGroupBox *>("ConsoleOutput");
if (consoleGroupBox) {
xmlWriter.writeStartElement("ConsoleOutput");
QHBoxLayout *hLayout = qobject_cast<QHBoxLayout *>(consoleGroupBox->layout());
if (hLayout) {
for (int i = 0; i < hLayout->count(); ++i) {
QCheckBox *checkBox = qobject_cast<QCheckBox *>(hLayout->itemAt(i)->widget());
if (checkBox) {
xmlWriter.writeAttribute(checkBox->text(),
checkBox->isChecked() ? "true" : "false");
}
}
}
xmlWriter.writeEndElement(); // ConsoleOutput
}
QGroupBox *logGroupBox = findChild<QGroupBox *>("Log");
if (logGroupBox) {
xmlWriter.writeStartElement("Log");
QHBoxLayout *hLayout = qobject_cast<QHBoxLayout *>(logGroupBox->layout());
if (hLayout) {
for (int i = 0; i < hLayout->count(); ++i) {
QCheckBox *checkBox = qobject_cast<QCheckBox *>(hLayout->itemAt(i)->widget());
if (checkBox) {
xmlWriter.writeAttribute(checkBox->text(),
checkBox->isChecked() ? "true" : "false");
}
}
}
xmlWriter.writeEndElement(); // Log
}
// 保存ModelsList部分
QGroupBox *modelsGroupBox = findChild<QGroupBox *>("ModelsList");
if (modelsGroupBox) {
xmlWriter.writeStartElement("ModelsList");
QTableWidget *tableWidget = modelsGroupBox->findChild<QTableWidget *>();
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<QGroupBox *>("ServicesList");
if (servicesGroupBox) {
xmlWriter.writeStartElement("ServicesList");
QTableWidget *tableWidget = servicesGroupBox->findChild<QTableWidget *>();
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<QGroupBox *>("Model Info");
if (modelInfoBox) {
QGridLayout *gridLayout = qobject_cast<QGridLayout *>(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<QLabel *>(labelItem->widget());
if (QLineEdit *lineEdit = qobject_cast<QLineEdit *>(valueItem->widget())) {
if (label) {
xmlWriter.writeStartElement(label->text());
xmlWriter.writeCharacters(lineEdit->text());
xmlWriter.writeEndElement();
}
} else if (QDateTimeEdit *dateTimeEdit =
qobject_cast<QDateTimeEdit *>(valueItem->widget())) {
if (label) {
xmlWriter.writeStartElement(label->text());
xmlWriter.writeCharacters(
dateTimeEdit->dateTime().toString(Qt::ISODate));
xmlWriter.writeEndElement();
}
}
}
}
}
}
// 保存CommandList部分
QGroupBox *commandListBox = findChild<QGroupBox *>("CommandList");
if (commandListBox) {
xmlWriter.writeStartElement("CommandList");
QTableWidget *tableWidget = commandListBox->findChild<QTableWidget *>();
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<QGroupBox *>("Other Info");
if (otherInfoBox) {
// 创建递归处理GroupBox的lambda函数
std::function<void(QGridLayout *)> 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<QLabel *>(labelItem->widget());
if (QLineEdit *lineEdit = qobject_cast<QLineEdit *>(valueItem->widget())) {
if (label && !lineEdit->text().isEmpty()) {
// 写入最终元素及其值
xmlWriter.writeStartElement(label->text());
xmlWriter.writeCharacters(lineEdit->text());
xmlWriter.writeEndElement();
}
}
} else if (QGroupBox *groupBox =
qobject_cast<QGroupBox *>(layout->itemAt(i)->widget())) {
// 递归处理子GroupBox
xmlWriter.writeStartElement(groupBox->title());
QGridLayout *subLayout = qobject_cast<QGridLayout *>(groupBox->layout());
if (subLayout) {
processGroupBox(subLayout);
}
xmlWriter.writeEndElement();
}
}
};
// 开始处理Other Info GroupBox
QGridLayout *gridLayout = qobject_cast<QGridLayout *>(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<QGroupBox *>("Service Info");
if (serviceInfoBox) {
QGridLayout *gridLayout = qobject_cast<QGridLayout *>(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<QLabel *>(labelItem->widget());
if (QLineEdit *lineEdit = qobject_cast<QLineEdit *>(valueItem->widget())) {
if (label && !lineEdit->text().isEmpty()) {
xmlWriter.writeStartElement(label->text());
xmlWriter.writeCharacters(lineEdit->text());
xmlWriter.writeEndElement();
}
} else if (QDateTimeEdit *dateTimeEdit =
qobject_cast<QDateTimeEdit *>(valueItem->widget())) {
if (label) {
xmlWriter.writeStartElement(label->text());
xmlWriter.writeCharacters(
dateTimeEdit->dateTime().toString(Qt::ISODate));
xmlWriter.writeEndElement();
}
}
}
}
}
}
// 保存CommandList部分
QGroupBox *commandListBox = findChild<QGroupBox *>("CommandList");
if (commandListBox) {
xmlWriter.writeStartElement("CommandList");
QTableWidget *tableWidget = commandListBox->findChild<QTableWidget *>();
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<QGroupBox *>("Other Info");
if (otherInfoBox) {
// 创建递归处理GroupBox的lambda函数
std::function<void(QGridLayout *)> 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<QLabel *>(labelItem->widget());
if (QLineEdit *lineEdit = qobject_cast<QLineEdit *>(valueItem->widget())) {
if (label && !lineEdit->text().isEmpty()) {
// 写入最终元素及其值
xmlWriter.writeStartElement(label->text());
xmlWriter.writeCharacters(lineEdit->text());
xmlWriter.writeEndElement();
}
}
} else if (QGroupBox *groupBox =
qobject_cast<QGroupBox *>(layout->itemAt(i)->widget())) {
// 递归处理子GroupBox
xmlWriter.writeStartElement(groupBox->title());
QGridLayout *subLayout = qobject_cast<QGridLayout *>(groupBox->layout());
if (subLayout) {
processGroupBox(subLayout);
}
xmlWriter.writeEndElement();
}
}
};
// 开始处理Other Info GroupBox
QGridLayout *gridLayout = qobject_cast<QGridLayout *>(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<QLineEdit *>(widget)) {
connect(lineEdit, &QLineEdit::textChanged, [this]() {
isModified = true;
updateWindowTitle();
});
} else if (QCheckBox *checkBox = qobject_cast<QCheckBox *>(widget)) {
connect(checkBox, &QCheckBox::checkStateChanged, [this]() {
isModified = true;
updateWindowTitle();
});
} else if (QTableWidget *tableWidget = qobject_cast<QTableWidget *>(widget)) {
connect(tableWidget, &QTableWidget::itemChanged, [this]() {
isModified = true;
updateWindowTitle();
});
} else if (QDateTimeEdit *dateTimeEdit = qobject_cast<QDateTimeEdit *>(widget)) {
connect(dateTimeEdit, &QDateTimeEdit::dateTimeChanged, [this]() {
isModified = true;
updateWindowTitle();
});
}
// 递归处理子控件
for (QObject *child : widget->children()) {
if (QWidget *childWidget = qobject_cast<QWidget *>(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();
}