XNSim/XNEditor/mainwindow.cpp
2025-04-28 12:25:20 +08:00

2226 lines
72 KiB
C++
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

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

/**
* @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();
}