From c097120ca3e0dee988445fbb443e8cde39c3f9ac Mon Sep 17 00:00:00 2001 From: taocong Date: Tue, 26 May 2026 14:33:03 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=BC=93=E5=AD=98=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=E5=AD=98=E5=82=A8=E3=80=81=E8=BD=AC=E7=A0=81?= =?UTF-8?q?=E8=BF=9B=E5=BA=A6=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Uft30ChangeCode.pro | 14 +- resources.qrc | 2 +- resources/images/bianji.png | Bin 0 -> 3805 bytes src/mainwindow/mainwindow.cpp | 174 ++++++++-- src/mainwindow/mainwindow.h | 10 +- src/pages/batchconvert/batchconvertpage.cpp | 193 ++++++++--- src/pages/batchconvert/batchconvertpage.h | 23 +- src/utils/datacache.cpp | 365 ++++++++++++++++++++ src/utils/datacache.h | 46 +++ src/utils/logmanager.cpp | 93 +++++ src/utils/logmanager.h | 37 ++ src/utils/uf2configreader.cpp | 154 +++++++++ src/utils/uf2configreader.h | 37 ++ src/utils/uft3configreader.cpp | 154 +++++++++ src/utils/uft3configreader.h | 37 ++ 15 files changed, 1239 insertions(+), 100 deletions(-) create mode 100644 resources/images/bianji.png create mode 100644 src/utils/datacache.cpp create mode 100644 src/utils/datacache.h create mode 100644 src/utils/logmanager.cpp create mode 100644 src/utils/logmanager.h create mode 100644 src/utils/uf2configreader.cpp create mode 100644 src/utils/uf2configreader.h create mode 100644 src/utils/uft3configreader.cpp create mode 100644 src/utils/uft3configreader.h diff --git a/Uft30ChangeCode.pro b/Uft30ChangeCode.pro index 2ed4392..4af9ea4 100644 --- a/Uft30ChangeCode.pro +++ b/Uft30ChangeCode.pro @@ -1,4 +1,4 @@ -QT += core gui widgets +QT += core gui widgets sql TARGET = Uft30ChangeCode TEMPLATE = app @@ -12,7 +12,11 @@ SOURCES += main.cpp \ src/pages/batchconvert/batchconvertpage.cpp \ src/pages/functionsearch/functionsearchpage.cpp \ src/pages/help/helppage.cpp \ - src/pages/settings/settingspage.cpp + src/pages/settings/settingspage.cpp \ + src/utils/datacache.cpp \ + src/utils/uf2configreader.cpp \ + src/utils/uft3configreader.cpp \ + src/utils/logmanager.cpp HEADERS += src/mainwindow/mainwindow.h \ src/pythonrunner/PythonRunner.h \ @@ -20,7 +24,11 @@ HEADERS += src/mainwindow/mainwindow.h \ src/pages/batchconvert/batchconvertpage.h \ src/pages/functionsearch/functionsearchpage.h \ src/pages/help/helppage.h \ - src/pages/settings/settingspage.h + src/pages/settings/settingspage.h \ + src/utils/datacache.h \ + src/utils/uf2configreader.h \ + src/utils/uft3configreader.h \ + src/utils/logmanager.h RESOURCES += resources.qrc diff --git a/resources.qrc b/resources.qrc index 282607c..8fc6235 100644 --- a/resources.qrc +++ b/resources.qrc @@ -1,7 +1,7 @@ resources/images/ChangeCode.png - resources/images/delect.png + resources/images/bianji.png resources/images/zhedie_left.png resources/images/zhedie_right.png resources/images/max.png diff --git a/resources/images/bianji.png b/resources/images/bianji.png new file mode 100644 index 0000000000000000000000000000000000000000..25299d2c149535bdb0cf761d243a5ea2f9da4595 GIT binary patch literal 3805 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 #include #include @@ -30,39 +33,73 @@ MainWindow::MainWindow(QWidget *parent) initWindow(); initContent(); - // 获取应用程序目录 + LogManager::instance()->initLogFile(); + LogManager::instance()->logInfo("应用程序启动"); + QString appDir = QCoreApplication::applicationDirPath(); - // 配置 Python 运行器 - 只使用打包好的 exe,路径是 uf2touft3/uf2touft3.exe + loadConfigCache(); + m_pythonRunner->setRunMode(PythonRunner::UsePackagedExe); - // 设置打包好的可执行文件路径和工作目录 QString exePath = appDir + "/uf2touft3/uf2touft3.exe"; QString workDir = appDir + "/uf2touft3"; m_pythonRunner->setPackagedExePath(exePath); m_pythonRunner->setWorkingDirectory(workDir); - // 检查 exe 是否存在 QFileInfo exeInfo(exePath); if (!exeInfo.exists() || !exeInfo.isFile()) { - m_batchLogEdit->append("⚠️ 警告:未找到 uf2touft3/uf2touft3.exe!"); - m_batchLogEdit->append(QString(" 期望位置:%1").arg(exePath)); + LogManager::instance()->logWarning("⚠️ 警告:未找到 uf2touft3/uf2touft3.exe!"); + LogManager::instance()->log(QString(" 期望位置:%1").arg(exePath)); } else { - m_batchLogEdit->append("✓ Python 工具准备就绪"); + LogManager::instance()->log("✓ Python 工具准备就绪"); } connect(m_pythonRunner, &PythonRunner::finished, this, &MainWindow::onPythonRunnerFinished); connect(m_pythonRunner, &PythonRunner::standardOutput, this, &MainWindow::onPythonRunnerOutput); connect(m_pythonRunner, &PythonRunner::standardError, this, &MainWindow::onPythonRunnerError); - connect(m_pythonRunner, &PythonRunner::started, [this]() { - m_batchLogEdit->append("转换任务已启动..."); + connect(m_pythonRunner, &PythonRunner::started, []() { + LogManager::instance()->log("转换任务已启动..."); }); - // 延迟查找并更新导航按钮(等待窗口完全显示后) QTimer::singleShot(100, this, &MainWindow::updateNavigationButtonIcon); } +void MainWindow::loadConfigCache() +{ + LogManager::instance()->log("正在加载配置缓存..."); + + UF2ConfigReader uf2Reader; + bool uf2Loaded = uf2Reader.loadAllUF20Config(); + + UFT3ConfigReader uft3Reader; + bool uft3Loaded = uft3Reader.loadAllUFT3Config(); + + if (uf2Loaded && uft3Loaded) { + LogManager::instance()->log("✓ 配置缓存加载完成"); + } else { + LogManager::instance()->logWarning("⚠️ 部分配置加载失败"); + + QStringList uf2Failed = uf2Reader.getFailedFiles(); + QStringList uft3Failed = uft3Reader.getFailedFiles(); + + if (!uf2Failed.isEmpty()) { + LogManager::instance()->log(" UF20 加载失败:"); + foreach (const QString& file, uf2Failed) { + LogManager::instance()->log(QString(" - %1").arg(file)); + } + } + + if (!uft3Failed.isEmpty()) { + LogManager::instance()->log(" UFT3 加载失败:"); + foreach (const QString& file, uft3Failed) { + LogManager::instance()->log(QString(" - %1").arg(file)); + } + } + } +} + MainWindow::~MainWindow() { } @@ -72,6 +109,7 @@ void MainWindow::initWindow() setWindowTitle("UFT30 Change Code"); setWindowIcon(QIcon(":/resources/images/ChangeCode.png")); resize(900, 600); + setMinimumSize(800, 500); setUserInfoCardVisible(false); // 隐藏返回和前进按钮 @@ -94,15 +132,10 @@ void MainWindow::initContent() QWidget* MainWindow::createBatchConvertPage() { - BatchConvertPage *page = new BatchConvertPage; - m_batchLogEdit = page->getLogEdit(); - connect(page, &BatchConvertPage::startConvert, this, &MainWindow::onBatchConvertStart); - connect(m_pythonRunner, &PythonRunner::started, [this]() { - if (m_batchLogEdit) { - m_batchLogEdit->append("转换任务已启动..."); - } - }); - return page; + m_batchConvertPage = new BatchConvertPage; + connect(m_batchConvertPage, &BatchConvertPage::startConvert, this, &MainWindow::onBatchConvertStart); + connect(m_batchConvertPage, &BatchConvertPage::stopConvert, this, &MainWindow::onBatchConvertStop); + return m_batchConvertPage; } QWidget* MainWindow::createFunctionSearchPage() @@ -128,7 +161,7 @@ QWidget* MainWindow::createSettingsPage() void MainWindow::onBatchConvertStart() { if (m_pythonRunner->isRunning()) { - m_batchLogEdit->append("警告: 上一个任务还在运行中..."); + LogManager::instance()->logWarning("警告: 上一个任务还在运行中..."); QMessageBox::warning(this, "提示", "上一个转换任务正在运行,请等待完成或停止当前任务。"); return; } @@ -137,47 +170,124 @@ void MainWindow::onBatchConvertStart() QString exePath = appDir + "/uf2touft3/uf2touft3.exe"; if (!m_pythonRunner->canRun()) { - m_batchLogEdit->append("错误: 找不到 uf2touft3/uf2touft3.exe!"); + LogManager::instance()->logError("错误: 找不到 uf2touft3/uf2touft3.exe!"); QMessageBox::critical(this, "错误", QString("无法启动转换任务!\n\n请确保:\nuf2touft3/uf2touft3.exe 存在,且该目录下包含 config.ini\n\n期望路径:\n%1") .arg(exePath)); return; } - m_batchLogEdit->append("========================================"); - m_batchLogEdit->append("开始执行 UFT2 到 UFT3 的代码转换..."); - m_batchLogEdit->append(QString("工具路径: %1").arg(exePath)); - m_batchLogEdit->append("========================================"); + if (m_batchConvertPage) { + m_totalFunctions = m_batchConvertPage->getFunctionCount(); + m_functionList = m_batchConvertPage->getFunctionList(); + m_currentFunctionIndex = 0; + } else { + m_totalFunctions = 0; + m_currentFunctionIndex = 0; + m_functionList.clear(); + } + + LogManager::instance()->log("========================================"); + LogManager::instance()->log("开始执行 UFT2 到 UFT3 的代码转换..."); + LogManager::instance()->log(QString("工具路径: %1").arg(exePath)); + LogManager::instance()->log(QString("待转换函数数量: %1").arg(m_totalFunctions)); + LogManager::instance()->log("========================================"); if (!m_pythonRunner->start()) { - m_batchLogEdit->append("错误: 无法启动转换进程!"); + LogManager::instance()->logError("错误: 无法启动转换进程!"); + } else { + if (m_batchConvertPage) { + m_batchConvertPage->onConvertStarted(); + } + } +} + +void MainWindow::onBatchConvertStop() +{ + if (m_pythonRunner->isRunning()) { + LogManager::instance()->log("正在停止转换进程..."); + m_pythonRunner->stop(); } } void MainWindow::onPythonRunnerFinished(int exitCode, QProcess::ExitStatus exitStatus) { - m_batchLogEdit->append("========================================"); + if (m_batchConvertPage) { + m_batchConvertPage->onConvertFinished(); + } + + LogManager::instance()->log("========================================"); if (exitStatus == QProcess::NormalExit && exitCode == 0) { - m_batchLogEdit->append("✓ 代码转换完成!"); + LogManager::instance()->log("✓ 代码转换完成!"); QMessageBox::information(this, "完成", "代码转换任务已成功完成!"); } else { - m_batchLogEdit->append(QString("✗ 转换失败! 退出码: %1").arg(exitCode)); + LogManager::instance()->logError(QString("✗ 转换失败! 退出码: %1").arg(exitCode)); QMessageBox::warning(this, "失败", QString("代码转换任务失败,退出码: %1").arg(exitCode)); } - m_batchLogEdit->append("========================================"); + LogManager::instance()->log("========================================"); } void MainWindow::onPythonRunnerOutput(const QString &output) { if (!output.trimmed().isEmpty()) { - m_batchLogEdit->append(output); + LogManager::instance()->log(output); + + QString trimmedOutput = output.trimmed(); + + QRegularExpression progressRegExp(R"(progress\s*[:=]\s*(\d+))"); + QRegularExpressionMatch match = progressRegExp.match(trimmedOutput); + if (match.hasMatch()) { + int progress = match.captured(1).toInt(); + QString status = trimmedOutput; + if (status.contains("progress", Qt::CaseInsensitive)) { + status = status.replace(progressRegExp, "").trimmed(); + if (status.isEmpty()) { + status = QString("转换中 %1%").arg(progress); + } + } + if (m_batchConvertPage) { + m_batchConvertPage->onProgressUpdate(progress, status); + } + } else { + if (m_batchConvertPage) { + QString currentFunction; + QRegularExpression funcRegExp(R"(([\w_]+))"); + QRegularExpressionMatch funcMatch = funcRegExp.match(trimmedOutput); + if (funcMatch.hasMatch()) { + currentFunction = funcMatch.captured(1); + } + + if (!currentFunction.isEmpty() && m_totalFunctions > 0) { + int index = m_functionList.indexOf(currentFunction); + if (index >= 0 && index >= m_currentFunctionIndex) { + m_currentFunctionIndex = index + 1; + int progress = 20 + (m_currentFunctionIndex * 80) / m_totalFunctions; + QString status = QString("正在转换: %1").arg(currentFunction); + m_batchConvertPage->onProgressUpdate(progress, status); + return; + } + } + + int currentProgress = 20; + if (trimmedOutput.contains("开始转换", Qt::CaseInsensitive)) { + currentProgress = 25; + } else if (trimmedOutput.contains("处理文件", Qt::CaseInsensitive)) { + currentProgress = 30; + } else if (trimmedOutput.contains("生成代码", Qt::CaseInsensitive)) { + currentProgress = 75; + } else if (trimmedOutput.contains("完成", Qt::CaseInsensitive)) { + currentProgress = 95; + } + m_batchConvertPage->onProgressUpdate(currentProgress, trimmedOutput); + } + } } } void MainWindow::onPythonRunnerError(const QString &error) { if (!error.trimmed().isEmpty()) { - m_batchLogEdit->append(QString("[ERROR] %1").arg(error)); + LogManager::instance()->logError(QString("[ERROR] %1").arg(error)); } } diff --git a/src/mainwindow/mainwindow.h b/src/mainwindow/mainwindow.h index 5f2ba20..cb30eb0 100644 --- a/src/mainwindow/mainwindow.h +++ b/src/mainwindow/mainwindow.h @@ -4,7 +4,6 @@ #include "ElaWindow.h" #include "ElaToolButton.h" #include -#include #include "src/pythonrunner/PythonRunner.h" #include "src/pages/batchconvert/batchconvertpage.h" #include "src/pages/functionsearch/functionsearchpage.h" @@ -30,7 +29,10 @@ private: QWidget* createAboutPage(); QWidget* createSettingsPage(); + void loadConfigCache(); + void onBatchConvertStart(); + void onBatchConvertStop(); void onPythonRunnerFinished(int exitCode, QProcess::ExitStatus exitStatus); void onPythonRunnerOutput(const QString &output); void onPythonRunnerError(const QString &error); @@ -40,10 +42,14 @@ private: void onNavigationButtonClicked(); PythonRunner *m_pythonRunner; - QTextEdit *m_batchLogEdit; bool m_iconsSet; ElaToolButton* m_navigationButton; bool m_isNavigationExpanded; + BatchConvertPage *m_batchConvertPage; + + int m_totalFunctions; + int m_currentFunctionIndex; + QStringList m_functionList; }; #endif // MAINWINDOW_H \ No newline at end of file diff --git a/src/pages/batchconvert/batchconvertpage.cpp b/src/pages/batchconvert/batchconvertpage.cpp index e8eea2d..5342d5b 100644 --- a/src/pages/batchconvert/batchconvertpage.cpp +++ b/src/pages/batchconvert/batchconvertpage.cpp @@ -1,4 +1,5 @@ #include "batchconvertpage.h" +#include "src/utils/uf2configreader.h" #include #include #include @@ -12,6 +13,7 @@ #include #include #include +#include "src/utils/logmanager.h" BatchConvertPage::BatchConvertPage(QWidget *parent) : QWidget(parent) @@ -63,37 +65,62 @@ void BatchConvertPage::initUI() layout->addWidget(funcBox); - QHBoxLayout *btnLayout = new QHBoxLayout; - QPushButton *startBtn = new QPushButton("开始转换"); - startBtn->setStyleSheet("background-color: #1abc9c; color: white; padding: 10px 30px; font-size: 14px; border: none; border-radius: 4px;"); - connect(startBtn, &QPushButton::clicked, this, &BatchConvertPage::onStartConvert); - QPushButton *clearLogBtn = new QPushButton("清空日志"); - connect(clearLogBtn, &QPushButton::clicked, this, &BatchConvertPage::onClearLog); - btnLayout->addStretch(); - btnLayout->addWidget(startBtn); - btnLayout->addWidget(clearLogBtn); - layout->addLayout(btnLayout); + QGroupBox *progressBox = new QGroupBox("转换进度"); + progressBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + QVBoxLayout *progressLayout = new QVBoxLayout(progressBox); + progressLayout->setSpacing(10); - m_logEdit = new QTextEdit; - m_logEdit->setReadOnly(true); - m_logEdit->setStyleSheet("background-color: #2c3e50; color: #ecf0f1;"); - m_logEdit->append("转码工具已准备就绪..."); - layout->addWidget(m_logEdit); + m_progressLabel = new QLabel("等待开始..."); + m_progressLabel->setStyleSheet("color: #666;"); + m_progressLabel->setFixedHeight(20); + m_progressLabel->setWordWrap(false); + m_progressLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + progressLayout->addWidget(m_progressLabel); + + m_progressBar = new QProgressBar; + m_progressBar->setRange(0, 100); + m_progressBar->setValue(0); + m_progressBar->setFixedHeight(25); + m_progressBar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + m_progressBar->setStyleSheet(R"( + QProgressBar { + border: 1px solid #ddd; + border-radius: 4px; + background-color: #f0f0f0; + text-align: center; + } + QProgressBar::chunk { + background-color: #1abc9c; + border-radius: 4px; + } + )"); + progressLayout->addWidget(m_progressBar); + + layout->addWidget(progressBox); + + QHBoxLayout *btnLayout = new QHBoxLayout; + m_startBtn = new QPushButton("开始转换"); + m_startBtn->setStyleSheet("background-color: #1abc9c; color: white; padding: 10px 30px; font-size: 14px; border: none; border-radius: 4px;"); + connect(m_startBtn, &QPushButton::clicked, this, &BatchConvertPage::onStartConvert); + btnLayout->addStretch(); + btnLayout->addWidget(m_startBtn); + layout->addLayout(btnLayout); +} + +void BatchConvertPage::onProgressUpdate(int progress, const QString& status) +{ + m_progressBar->setValue(progress); + + QString displayStatus = status; + if (displayStatus.length() > 80) { + displayStatus = displayStatus.left(80) + "..."; + } + m_progressLabel->setText(displayStatus); } bool BatchConvertPage::checkFunctionExists(const QString &funcName) { - QString jsonPath = QCoreApplication::applicationDirPath() + "/uf2touft3/cust.json"; - QFile file(jsonPath); - if (!file.open(QIODevice::ReadOnly)) { - return false; - } - - QByteArray data = file.readAll(); - file.close(); - - QString content = QString::fromUtf8(data); - return content.contains("\"" + funcName + "\""); + return UF2ConfigReader::checkFuncExistsStatic(funcName); } void BatchConvertPage::updateTable() @@ -123,15 +150,15 @@ void BatchConvertPage::updateTable() } m_funcTable->setItem(i, 1, statusItem); - QPushButton *delBtn = new QPushButton; - delBtn->setIcon(QIcon(":/resources/images/delect.png")); - delBtn->setIconSize(QSize(20, 20)); - delBtn->setStyleSheet("padding: 2px; border: none; background-color: transparent;"); - delBtn->setToolTip("删除"); - connect(delBtn, &QPushButton::clicked, this, [this, i]() { - onDeleteRow(i); + QPushButton *editBtn = new QPushButton; + editBtn->setIcon(QIcon(":/resources/images/bianji.png")); + editBtn->setIconSize(QSize(20, 20)); + editBtn->setStyleSheet("padding: 2px; border: none; background-color: transparent;"); + editBtn->setToolTip("修改"); + connect(editBtn, &QPushButton::clicked, this, [this, i]() { + onEditRow(i); }); - m_funcTable->setCellWidget(i, 2, delBtn); + m_funcTable->setCellWidget(i, 2, editBtn); } int totalWidth = m_funcTable->width(); @@ -151,12 +178,47 @@ void BatchConvertPage::resizeEvent(QResizeEvent *event) } } -void BatchConvertPage::onDeleteRow(int row) +void BatchConvertPage::onEditRow(int row) { - if (row >= 0 && row < m_funcList.size()) { - m_funcList.removeAt(row); - updateTable(); + if (row < 0 || row >= m_funcList.size()) { + return; } + + QString oldName = m_funcList[row]; + QString newName = oldName; + + while (true) { + QInputDialog dialog(this); + dialog.setWindowTitle("修改函数名"); + dialog.setLabelText("请输入新的函数名:"); + dialog.setTextValue(oldName); + dialog.resize(300, 150); + + if (dialog.exec() != QDialog::Accepted) { + return; + } + + newName = dialog.textValue().trimmed(); + + if (newName.isEmpty()) { + QMessageBox::warning(this, "提示", "函数名不能为空!"); + continue; + } + + if (newName == oldName) { + return; + } + + if (m_funcList.contains(newName)) { + QMessageBox::warning(this, "提示", "该函数名已存在,请重新输入!"); + continue; + } + + break; + } + + m_funcList[row] = newName; + updateTable(); } void BatchConvertPage::onAddFunction() @@ -264,7 +326,7 @@ bool BatchConvertPage::saveToCustJson(const QStringList &funcList) QFile file(jsonPath); if (!file.open(QIODevice::ReadOnly)) { - m_logEdit->append("[ERROR] 无法打开文件: " + jsonPath); + LogManager::instance()->logError(QString("无法打开文件: %1").arg(jsonPath)); return false; } @@ -278,7 +340,7 @@ bool BatchConvertPage::saveToCustJson(const QStringList &funcList) dirStart = content.indexOf("\"dir\" : ["); } if (dirStart < 0) { - m_logEdit->append("[ERROR] 未找到 \"dir\" 节点"); + LogManager::instance()->logError("未找到 \"dir\" 节点"); return false; } @@ -302,7 +364,7 @@ bool BatchConvertPage::saveToCustJson(const QStringList &funcList) content.replace(arrayStart, arrayEnd - arrayStart, newDirArray); if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { - m_logEdit->append("[ERROR] 无法写入文件: " + jsonPath); + LogManager::instance()->logError(QString("无法写入文件: %1").arg(jsonPath)); return false; } @@ -314,33 +376,54 @@ bool BatchConvertPage::saveToCustJson(const QStringList &funcList) void BatchConvertPage::onStartConvert() { - if (m_funcList.isEmpty()) { - m_logEdit->append("请先添加需要转码的函数!"); + if (m_startBtn->text() == "停止转换") { + LogManager::instance()->log("用户请求停止转换..."); + m_progressLabel->setText("正在停止转换..."); + emit stopConvert(); return; } - m_logEdit->append("========================================"); - m_logEdit->append("正在写入 cust.json ..."); - m_logEdit->append("功能列表:"); + if (m_funcList.isEmpty()) { + QMessageBox::warning(this, "提示", "请先添加需要转码的函数!"); + return; + } + + m_progressBar->setValue(0); + m_progressLabel->setText("正在准备转换..."); + + LogManager::instance()->log("========================================"); + LogManager::instance()->log("正在写入 cust.json ..."); + LogManager::instance()->log("功能列表:"); for (const QString &func : m_funcList) { - m_logEdit->append(" - " + func + ".service_design"); + LogManager::instance()->log(QString(" - %1.service_design").arg(func)); } if (saveToCustJson(m_funcList)) { - m_logEdit->append("[OK] cust.json 写入成功!"); + LogManager::instance()->log("cust.json 写入成功!"); + m_progressLabel->setText("配置加载成功,开始转换..."); + m_progressBar->setValue(20); } else { - m_logEdit->append("[FAIL] cust.json 写入失败!"); - m_logEdit->append("========================================"); + LogManager::instance()->logError("cust.json 写入失败!"); + LogManager::instance()->log("========================================"); + m_progressLabel->setText("配置加载失败"); return; } - m_logEdit->append("========================================"); + LogManager::instance()->log("========================================"); emit startConvert(); } -void BatchConvertPage::onClearLog() +void BatchConvertPage::onConvertStarted() { - m_logEdit->clear(); - m_logEdit->append("转码工具已准备就绪..."); -} \ No newline at end of file + m_startBtn->setText("停止转换"); + m_startBtn->setStyleSheet("background-color: #e74c3c; color: white; padding: 10px 30px; font-size: 14px; border: none; border-radius: 4px;"); +} + +void BatchConvertPage::onConvertFinished() +{ + m_progressBar->setValue(100); + m_progressLabel->setText("转换完成"); + m_startBtn->setText("开始转换"); + m_startBtn->setStyleSheet("background-color: #1abc9c; color: white; padding: 10px 30px; font-size: 14px; border: none; border-radius: 4px;"); +} diff --git a/src/pages/batchconvert/batchconvertpage.h b/src/pages/batchconvert/batchconvertpage.h index 4b4e8d7..e48dfba 100644 --- a/src/pages/batchconvert/batchconvertpage.h +++ b/src/pages/batchconvert/batchconvertpage.h @@ -3,9 +3,10 @@ #include #include -#include #include #include +#include +#include class BatchConvertPage : public QWidget { @@ -15,18 +16,24 @@ public: explicit BatchConvertPage(QWidget *parent = nullptr); ~BatchConvertPage(); - QTextEdit* getLogEdit() { return m_logEdit; } - signals: void startConvert(); + void stopConvert(); + +public slots: + void onProgressUpdate(int progress, const QString& status); + void onConvertFinished(); + void onConvertStarted(); + + int getFunctionCount() const { return m_funcList.size(); } + QStringList getFunctionList() const { return m_funcList; } private slots: void onStartConvert(); - void onClearLog(); void onAddFunction(); void onRemoveFunction(); void onClearTable(); - void onDeleteRow(int row); + void onEditRow(int row); private: void initUI(); @@ -36,8 +43,10 @@ private: void resizeEvent(QResizeEvent *event) override; QTableWidget *m_funcTable; - QTextEdit *m_logEdit; QStringList m_funcList; + QProgressBar *m_progressBar; + QLabel *m_progressLabel; + QPushButton *m_startBtn; }; -#endif // BATCHCONVERTPAGE_H \ No newline at end of file +#endif diff --git a/src/utils/datacache.cpp b/src/utils/datacache.cpp new file mode 100644 index 0000000..af09222 --- /dev/null +++ b/src/utils/datacache.cpp @@ -0,0 +1,365 @@ +#include "datacache.h" +#include "logmanager.h" +#include +#include +#include +#include +#include +#include +#include + +DataCache* DataCache::m_instance = nullptr; + +DataCache::DataCache(QObject *parent) : QObject(parent), m_dataLoaded(false) +{ +} + +DataCache::~DataCache() +{ + if (m_db.isOpen()) { + m_db.close(); + } +} + +DataCache* DataCache::instance() +{ + if (!m_instance) { + m_instance = new DataCache(); + } + return m_instance; +} + +QString DataCache::getDatabasePath() +{ + QString appDir = QCoreApplication::applicationDirPath(); + QDir dbDir(appDir + "/cache"); + if (!dbDir.exists()) { + if (!dbDir.mkpath(dbDir.absolutePath())) { + LogManager::instance()->logError(QString("数据缓存 - 创建缓存目录失败: %1").arg(dbDir.absolutePath())); + } + } + return dbDir.absoluteFilePath("config_cache.db"); +} + +bool DataCache::createTables() +{ + QSqlQuery query(m_db); + + query.exec("PRAGMA synchronous = OFF"); + query.exec("PRAGMA journal_mode = MEMORY"); + + QString createUF20Table = R"( + CREATE TABLE IF NOT EXISTS uf20_cname_table ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + cname TEXT UNIQUE NOT NULL, + e_name TEXT, + function_no TEXT, + update_time TEXT NOT NULL + ) + )"; + + QString createUFT3Table = R"( + CREATE TABLE IF NOT EXISTS uft3_cname_table ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + cname TEXT UNIQUE NOT NULL, + e_name TEXT, + function_no TEXT, + update_time TEXT NOT NULL + ) + )"; + + if (!query.exec(createUF20Table)) { + LogManager::instance()->logError(QString("数据缓存 - 创建uf20_cname_table失败: %1").arg(query.lastError().text())); + return false; + } + + if (!query.exec(createUFT3Table)) { + LogManager::instance()->logError(QString("数据缓存 - 创建uft3_cname_table失败: %1").arg(query.lastError().text())); + return false; + } + + LogManager::instance()->log("数据缓存 - 表创建成功"); + return true; +} + +bool DataCache::initDatabase() +{ + QString dbPath = getDatabasePath(); + LogManager::instance()->log(QString("数据缓存 - 数据库路径: %1").arg(dbPath)); + + if (QSqlDatabase::contains("qt_sql_default_connection")) { + m_db = QSqlDatabase::database("qt_sql_default_connection"); + if (m_db.isOpen()) { + LogManager::instance()->log("数据缓存 - 数据库已打开"); + return true; + } + } + + m_db = QSqlDatabase::addDatabase("QSQLITE"); + m_db.setDatabaseName(dbPath); + + if (!m_db.open()) { + LogManager::instance()->logError(QString("数据缓存 - 打开数据库失败: %1").arg(m_db.lastError().text())); + QString drivers = QSqlDatabase::drivers().join(", "); + LogManager::instance()->logError(QString("数据缓存 - 可用的数据库驱动: %1").arg(drivers)); + return false; + } + + m_db.exec("PRAGMA synchronous = OFF"); + m_db.exec("PRAGMA journal_mode = MEMORY"); + + LogManager::instance()->log("数据缓存 - 数据库打开成功"); + return createTables(); +} + +bool DataCache::isDataLoaded() const +{ + return m_dataLoaded; +} + +void DataCache::setDataLoaded(bool loaded) +{ + m_dataLoaded = loaded; +} + +bool DataCache::saveUF20Config(const QString& fileName, const QJsonObject& data) +{ + if (!m_db.isOpen()) { + return false; + } + + if (fileName != "uf2.json") { + return true; + } + + QElapsedTimer timer; + timer.start(); + + QSqlQuery query(m_db); + query.exec("DELETE FROM uf20_cname_table"); + + QStringList cnames; + QStringList eNames; + QStringList functionNos; + + for (auto it = data.begin(); it != data.end(); ++it) { + if (it.value().isObject()) { + QJsonObject obj = it.value().toObject(); + QString cname = obj.value("cname").toString(); + if (!cname.isEmpty()) { + cnames.append(cname); + eNames.append(obj.value("eName").toString()); + functionNos.append(obj.value("function_no").toString()); + } + } + } + + if (cnames.isEmpty()) { + LogManager::instance()->logWarning("数据缓存 - UF20没有找到cname记录"); + return true; + } + + m_db.transaction(); + + query.prepare("INSERT INTO uf20_cname_table (cname, e_name, function_no, update_time) VALUES (?, ?, ?, ?)"); + + QString updateTime = QDateTime::currentDateTime().toString(Qt::ISODate); + for (int i = 0; i < cnames.size(); ++i) { + query.addBindValue(cnames[i]); + query.addBindValue(eNames[i]); + query.addBindValue(functionNos[i]); + query.addBindValue(updateTime); + query.exec(); + } + + m_db.commit(); + + LogManager::instance()->logInfo(QString("数据缓存 - UF20成功保存 %1 个cname记录,耗时: %2ms").arg(cnames.size()).arg(timer.elapsed())); + return true; +} + +bool DataCache::saveUFT3Config(const QString& fileName, const QJsonObject& data) +{ + if (!m_db.isOpen()) { + return false; + } + + if (fileName != "uft3.json") { + return true; + } + + QElapsedTimer timer; + timer.start(); + + QSqlQuery query(m_db); + query.exec("DELETE FROM uft3_cname_table"); + + QStringList cnames; + QStringList eNames; + QStringList functionNos; + + for (auto it = data.begin(); it != data.end(); ++it) { + if (it.value().isObject()) { + QJsonObject obj = it.value().toObject(); + QString cname = obj.value("cname").toString(); + if (!cname.isEmpty()) { + cnames.append(cname); + eNames.append(obj.value("eName").toString()); + functionNos.append(obj.value("function_no").toString()); + } + } + } + + if (cnames.isEmpty()) { + LogManager::instance()->logWarning("数据缓存 - UFT3没有找到cname记录"); + return true; + } + + m_db.transaction(); + + query.prepare("INSERT INTO uft3_cname_table (cname, e_name, function_no, update_time) VALUES (?, ?, ?, ?)"); + + QString updateTime = QDateTime::currentDateTime().toString(Qt::ISODate); + for (int i = 0; i < cnames.size(); ++i) { + query.addBindValue(cnames[i]); + query.addBindValue(eNames[i]); + query.addBindValue(functionNos[i]); + query.addBindValue(updateTime); + query.exec(); + } + + m_db.commit(); + + LogManager::instance()->logInfo(QString("数据缓存 - UFT3成功保存 %1 个cname记录,耗时: %2ms").arg(cnames.size()).arg(timer.elapsed())); + return true; +} + +bool DataCache::hasUF20Config(const QString& fileName) +{ + if (!m_db.isOpen()) { + return false; + } + + if (fileName != "uf2.json") { + return true; + } + + QSqlQuery query(m_db); + if (query.exec("SELECT COUNT(*) FROM uf20_cname_table")) { + if (query.next()) { + return query.value(0).toInt() > 0; + } + } + + return false; +} + +bool DataCache::hasUFT3Config(const QString& fileName) +{ + if (!m_db.isOpen()) { + return false; + } + + if (fileName != "uft3.json") { + return true; + } + + QSqlQuery query(m_db); + if (query.exec("SELECT COUNT(*) FROM uft3_cname_table")) { + if (query.next()) { + return query.value(0).toInt() > 0; + } + } + + return false; +} + +bool DataCache::checkUF20CnameExists(const QString& cname) +{ + if (!m_db.isOpen()) { + return false; + } + + QSqlQuery query(m_db); + query.prepare("SELECT COUNT(*) FROM uf20_cname_table WHERE cname = :cname"); + query.bindValue(":cname", cname); + + if (query.exec() && query.next()) { + return query.value(0).toInt() > 0; + } + + return false; +} + +QSet DataCache::getAllUF20Cnames() +{ + QSet result; + + if (!m_db.isOpen()) { + return result; + } + + QElapsedTimer timer; + timer.start(); + + QSqlQuery query(m_db); + if (query.exec("SELECT cname FROM uf20_cname_table")) { + while (query.next()) { + result.insert(query.value(0).toString()); + } + } + + LogManager::instance()->logInfo(QString("数据缓存 - 获取UF20 Cname缓存,耗时: %1ms").arg(timer.elapsed())); + return result; +} + +bool DataCache::checkUFT3CnameExists(const QString& cname) +{ + if (!m_db.isOpen()) { + return false; + } + + QSqlQuery query(m_db); + query.prepare("SELECT COUNT(*) FROM uft3_cname_table WHERE cname = :cname"); + query.bindValue(":cname", cname); + + if (query.exec() && query.next()) { + return query.value(0).toInt() > 0; + } + + return false; +} + +QSet DataCache::getAllUFT3Cnames() +{ + QSet result; + + if (!m_db.isOpen()) { + return result; + } + + QElapsedTimer timer; + timer.start(); + + QSqlQuery query(m_db); + if (query.exec("SELECT cname FROM uft3_cname_table")) { + while (query.next()) { + result.insert(query.value(0).toString()); + } + } + + LogManager::instance()->logInfo(QString("数据缓存 - 获取UFT3 Cname缓存,耗时: %1ms").arg(timer.elapsed())); + return result; +} + +void DataCache::clearCache() +{ + if (!m_db.isOpen()) { + return; + } + + QSqlQuery query(m_db); + query.exec("DELETE FROM uf20_cname_table"); + query.exec("DELETE FROM uft3_cname_table"); + m_dataLoaded = false; +} diff --git a/src/utils/datacache.h b/src/utils/datacache.h new file mode 100644 index 0000000..1100b3f --- /dev/null +++ b/src/utils/datacache.h @@ -0,0 +1,46 @@ +#ifndef DATACACHE_H +#define DATACACHE_H + +#include +#include +#include +#include + +class DataCache : public QObject +{ + Q_OBJECT + +public: + static DataCache* instance(); + + bool initDatabase(); + bool isDataLoaded() const; + void setDataLoaded(bool loaded); + + bool saveUF20Config(const QString& fileName, const QJsonObject& data); + bool saveUFT3Config(const QString& fileName, const QJsonObject& data); + + bool hasUF20Config(const QString& fileName); + bool hasUFT3Config(const QString& fileName); + + bool checkUF20CnameExists(const QString& cname); + QSet getAllUF20Cnames(); + + bool checkUFT3CnameExists(const QString& cname); + QSet getAllUFT3Cnames(); + + void clearCache(); + +private: + explicit DataCache(QObject *parent = nullptr); + ~DataCache(); + + bool createTables(); + QString getDatabasePath(); + + static DataCache* m_instance; + QSqlDatabase m_db; + bool m_dataLoaded; +}; + +#endif diff --git a/src/utils/logmanager.cpp b/src/utils/logmanager.cpp new file mode 100644 index 0000000..fce4aab --- /dev/null +++ b/src/utils/logmanager.cpp @@ -0,0 +1,93 @@ +#include "logmanager.h" +#include +#include +#include +#include + +LogManager* LogManager::m_instance = nullptr; + +LogManager::LogManager(QObject *parent) : QObject(parent) +{ +} + +LogManager::~LogManager() +{ + if (m_logFile.isOpen()) { + m_logFile.close(); + } +} + +LogManager* LogManager::instance() +{ + if (!m_instance) { + m_instance = new LogManager(); + } + return m_instance; +} + +void LogManager::initLogFile() +{ + QString appDir = QCoreApplication::applicationDirPath(); + QDir logDir(appDir + "/logs"); + if (!logDir.exists()) { + logDir.mkpath("."); + } + + QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd"); + m_logFilePath = logDir.absoluteFilePath(QString("uft3_change_code_%1.log").arg(timestamp)); + + m_logFile.setFileName(m_logFilePath); + if (!m_logFile.open(QIODevice::Append | QIODevice::Text)) { + qDebug() << "无法打开日志文件:" << m_logFilePath; + return; + } + + writeLog("INFO", "日志系统初始化完成"); +} + +QString LogManager::getLogFilePath() const +{ + return m_logFilePath; +} + +void LogManager::writeLog(const QString& level, const QString& message) +{ + QMutexLocker locker(&m_mutex); + + QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"); + QString logLine = QString("[%1] [%2] %3\n").arg(timestamp, level, message); + + if (m_logFile.isOpen()) { + QTextStream stream(&m_logFile); + stream << logLine; + stream.flush(); + } + + if (level == "ERROR") { + qCritical() << message; + } else if (level == "WARNING") { + qWarning() << message; + } else { + qDebug() << message; + } +} + +void LogManager::log(const QString& message) +{ + writeLog("INFO", message); +} + +void LogManager::logInfo(const QString& message) +{ + writeLog("INFO", message); +} + +void LogManager::logWarning(const QString& message) +{ + writeLog("WARNING", message); +} + +void LogManager::logError(const QString& message) +{ + writeLog("ERROR", message); +} \ No newline at end of file diff --git a/src/utils/logmanager.h b/src/utils/logmanager.h new file mode 100644 index 0000000..b229a15 --- /dev/null +++ b/src/utils/logmanager.h @@ -0,0 +1,37 @@ +#ifndef LOGMANAGER_H +#define LOGMANAGER_H + +#include +#include +#include +#include +#include + +class LogManager : public QObject +{ + Q_OBJECT + +public: + static LogManager* instance(); + + void initLogFile(); + void log(const QString& message); + void logInfo(const QString& message); + void logWarning(const QString& message); + void logError(const QString& message); + + QString getLogFilePath() const; + +private: + explicit LogManager(QObject *parent = nullptr); + ~LogManager(); + + void writeLog(const QString& level, const QString& message); + + static LogManager* m_instance; + QFile m_logFile; + QMutex m_mutex; + QString m_logFilePath; +}; + +#endif // LOGMANAGER_H \ No newline at end of file diff --git a/src/utils/uf2configreader.cpp b/src/utils/uf2configreader.cpp new file mode 100644 index 0000000..7d05567 --- /dev/null +++ b/src/utils/uf2configreader.cpp @@ -0,0 +1,154 @@ +#include "uf2configreader.h" +#include "datacache.h" +#include "logmanager.h" +#include +#include +#include +#include + +QSet UF2ConfigReader::m_cnameCache; +bool UF2ConfigReader::m_cnameCacheLoaded = false; + +UF2ConfigReader::UF2ConfigReader(QObject *parent) : QObject(parent), m_loaded(false) +{ +} + +QString UF2ConfigReader::getBinPath() +{ + QString appDir = QCoreApplication::applicationDirPath(); + return appDir + "/uf2touft3"; +} + +bool UF2ConfigReader::loadAllUF20Config() +{ + m_failedFiles.clear(); + + if (!DataCache::instance()->initDatabase()) { + LogManager::instance()->logError("UF20配置加载 - 数据库初始化失败"); + m_failedFiles.append("uf2.json"); + return false; + } + + QString binPath = getBinPath(); + QString filePath = binPath + "/uf2.json"; + + if (DataCache::instance()->hasUF20Config("uf2.json")) { + LogManager::instance()->log("UF20配置加载 - 已缓存,跳过: uf2.json"); + } else { + QFile file(filePath); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + LogManager::instance()->logError(QString("UF20配置加载 - 无法打开文件: %1").arg(filePath)); + m_failedFiles.append("uf2.json"); + return false; + } + + QByteArray data = file.readAll(); + QJsonDocument doc = QJsonDocument::fromJson(data); + file.close(); + + if (doc.isNull() || !doc.isObject()) { + LogManager::instance()->logError(QString("UF20配置加载 - JSON解析失败: %1").arg(filePath)); + m_failedFiles.append("uf2.json"); + return false; + } + + QJsonObject config = doc.object(); + if (!DataCache::instance()->saveUF20Config("uf2.json", config)) { + LogManager::instance()->logError("UF20配置加载 - 保存失败: uf2.json"); + m_failedFiles.append("uf2.json"); + return false; + } + + LogManager::instance()->log("UF20配置加载 - 成功: uf2.json"); + } + + m_loaded = true; + DataCache::instance()->setDataLoaded(true); + LogManager::instance()->logInfo("UF20配置加载 - 全部加载完成"); + + return true; +} + +QStringList UF2ConfigReader::getFailedFiles() const +{ + return m_failedFiles; +} + +bool UF2ConfigReader::reloadUF20Config() +{ + QString binPath = getBinPath(); + QString filePath = binPath + "/uf2.json"; + + QFile file(filePath); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + LogManager::instance()->logError(QString("UF20配置加载 - 无法打开文件: %1").arg(filePath)); + return false; + } + + QByteArray data = file.readAll(); + QJsonDocument doc = QJsonDocument::fromJson(data); + file.close(); + + if (doc.isNull() || !doc.isObject()) { + LogManager::instance()->logError(QString("UF20配置加载 - JSON解析失败: %1").arg(filePath)); + return false; + } + + QJsonObject config = doc.object(); + if (!DataCache::instance()->saveUF20Config("uf2.json", config)) { + LogManager::instance()->logError("UF20配置加载 - 保存失败: uf2.json"); + return false; + } + + clearCnameCache(); + LogManager::instance()->logInfo("UF20配置重新加载完成"); + return true; +} + +bool UF2ConfigReader::isUF20Loaded() const +{ + return m_loaded; +} + +bool UF2ConfigReader::loadCnameCache() +{ + if (m_cnameCacheLoaded) { + return true; + } + + m_cnameCache.clear(); + + if (!DataCache::instance()->initDatabase()) { + LogManager::instance()->logError("Cname缓存加载 - 数据库初始化失败"); + return false; + } + + m_cnameCache = DataCache::instance()->getAllUF20Cnames(); + m_cnameCacheLoaded = true; + LogManager::instance()->logInfo(QString("Cname缓存加载完成,共加载 %1 个函数名").arg(m_cnameCache.size())); + + return true; +} + +bool UF2ConfigReader::checkFuncExistsStatic(const QString& funcName) +{ + if (!m_cnameCacheLoaded) { + loadCnameCache(); + } + + bool exists = m_cnameCache.contains(funcName); + LogManager::instance()->log(QString("检查函数名 [%1] 是否存在: %2").arg(funcName).arg(exists ? "是" : "否")); + return exists; +} + +bool UF2ConfigReader::checkFunctionExists(const QString& funcName) +{ + return checkFuncExistsStatic(funcName); +} + +void UF2ConfigReader::clearCnameCache() +{ + m_cnameCache.clear(); + m_cnameCacheLoaded = false; + LogManager::instance()->logInfo("Cname缓存已清空"); +} diff --git a/src/utils/uf2configreader.h b/src/utils/uf2configreader.h new file mode 100644 index 0000000..1156e53 --- /dev/null +++ b/src/utils/uf2configreader.h @@ -0,0 +1,37 @@ +#ifndef UF2CONFIGREADER_H +#define UF2CONFIGREADER_H + +#include +#include +#include +#include + +class UF2ConfigReader : public QObject +{ + Q_OBJECT + +public: + explicit UF2ConfigReader(QObject *parent = nullptr); + + bool loadAllUF20Config(); + bool reloadUF20Config(); + + bool isUF20Loaded() const; + QStringList getFailedFiles() const; + bool checkFunctionExists(const QString& funcName); + static bool checkFuncExistsStatic(const QString& funcName); + static void clearCnameCache(); + +private: + static bool loadCnameCache(); + + QString getBinPath(); + + QStringList m_failedFiles; + bool m_loaded; + + static QSet m_cnameCache; + static bool m_cnameCacheLoaded; +}; + +#endif diff --git a/src/utils/uft3configreader.cpp b/src/utils/uft3configreader.cpp new file mode 100644 index 0000000..0ead172 --- /dev/null +++ b/src/utils/uft3configreader.cpp @@ -0,0 +1,154 @@ +#include "uft3configreader.h" +#include "datacache.h" +#include "logmanager.h" +#include +#include +#include +#include + +QSet UFT3ConfigReader::m_cnameCache; +bool UFT3ConfigReader::m_cnameCacheLoaded = false; + +UFT3ConfigReader::UFT3ConfigReader(QObject *parent) : QObject(parent), m_loaded(false) +{ +} + +QString UFT3ConfigReader::getBinPath() +{ + QString appDir = QCoreApplication::applicationDirPath(); + return appDir + "/uf2touft3"; +} + +bool UFT3ConfigReader::loadAllUFT3Config() +{ + m_failedFiles.clear(); + + if (!DataCache::instance()->initDatabase()) { + LogManager::instance()->logError("UFT3配置加载 - 数据库初始化失败"); + m_failedFiles.append("uft3.json"); + return false; + } + + QString binPath = getBinPath(); + QString filePath = binPath + "/uft3.json"; + + if (DataCache::instance()->hasUFT3Config("uft3.json")) { + LogManager::instance()->log("UFT3配置加载 - 已缓存,跳过: uft3.json"); + } else { + QFile file(filePath); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + LogManager::instance()->logError(QString("UFT3配置加载 - 无法打开文件: %1").arg(filePath)); + m_failedFiles.append("uft3.json"); + return false; + } + + QByteArray data = file.readAll(); + QJsonDocument doc = QJsonDocument::fromJson(data); + file.close(); + + if (doc.isNull() || !doc.isObject()) { + LogManager::instance()->logError(QString("UFT3配置加载 - JSON解析失败: %1").arg(filePath)); + m_failedFiles.append("uft3.json"); + return false; + } + + QJsonObject config = doc.object(); + if (!DataCache::instance()->saveUFT3Config("uft3.json", config)) { + LogManager::instance()->logError("UFT3配置加载 - 保存失败: uft3.json"); + m_failedFiles.append("uft3.json"); + return false; + } + + LogManager::instance()->log("UFT3配置加载 - 成功: uft3.json"); + } + + m_loaded = true; + DataCache::instance()->setDataLoaded(true); + LogManager::instance()->logInfo("UFT3配置加载 - 全部加载完成"); + + return true; +} + +QStringList UFT3ConfigReader::getFailedFiles() const +{ + return m_failedFiles; +} + +bool UFT3ConfigReader::reloadUFT3Config() +{ + QString binPath = getBinPath(); + QString filePath = binPath + "/uft3.json"; + + QFile file(filePath); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + LogManager::instance()->logError(QString("UFT3配置加载 - 无法打开文件: %1").arg(filePath)); + return false; + } + + QByteArray data = file.readAll(); + QJsonDocument doc = QJsonDocument::fromJson(data); + file.close(); + + if (doc.isNull() || !doc.isObject()) { + LogManager::instance()->logError(QString("UFT3配置加载 - JSON解析失败: %1").arg(filePath)); + return false; + } + + QJsonObject config = doc.object(); + if (!DataCache::instance()->saveUFT3Config("uft3.json", config)) { + LogManager::instance()->logError("UFT3配置加载 - 保存失败: uft3.json"); + return false; + } + + clearCnameCache(); + LogManager::instance()->logInfo("UFT3配置重新加载完成"); + return true; +} + +bool UFT3ConfigReader::isUFT3Loaded() const +{ + return m_loaded; +} + +bool UFT3ConfigReader::loadCnameCache() +{ + if (m_cnameCacheLoaded) { + return true; + } + + m_cnameCache.clear(); + + if (!DataCache::instance()->initDatabase()) { + LogManager::instance()->logError("UFT3 Cname缓存加载 - 数据库初始化失败"); + return false; + } + + m_cnameCache = DataCache::instance()->getAllUFT3Cnames(); + m_cnameCacheLoaded = true; + LogManager::instance()->logInfo(QString("UFT3 Cname缓存加载完成,共加载 %1 个函数名").arg(m_cnameCache.size())); + + return true; +} + +bool UFT3ConfigReader::checkFuncExistsStatic(const QString& funcName) +{ + if (!m_cnameCacheLoaded) { + loadCnameCache(); + } + + bool exists = m_cnameCache.contains(funcName); + LogManager::instance()->log(QString("检查UFT3函数名 [%1] 是否存在: %2").arg(funcName).arg(exists ? "是" : "否")); + return exists; +} + +bool UFT3ConfigReader::checkFunctionExists(const QString& funcName) +{ + return checkFuncExistsStatic(funcName); +} + +void UFT3ConfigReader::clearCnameCache() +{ + m_cnameCache.clear(); + m_cnameCacheLoaded = false; + LogManager::instance()->logInfo("UFT3 Cname缓存已清空"); +} diff --git a/src/utils/uft3configreader.h b/src/utils/uft3configreader.h new file mode 100644 index 0000000..73f111a --- /dev/null +++ b/src/utils/uft3configreader.h @@ -0,0 +1,37 @@ +#ifndef UFT3CONFIGREADER_H +#define UFT3CONFIGREADER_H + +#include +#include +#include +#include + +class UFT3ConfigReader : public QObject +{ + Q_OBJECT + +public: + explicit UFT3ConfigReader(QObject *parent = nullptr); + + bool loadAllUFT3Config(); + bool reloadUFT3Config(); + + bool isUFT3Loaded() const; + QStringList getFailedFiles() const; + bool checkFunctionExists(const QString& funcName); + static bool checkFuncExistsStatic(const QString& funcName); + static void clearCnameCache(); + +private: + static bool loadCnameCache(); + + QString getBinPath(); + + QStringList m_failedFiles; + bool m_loaded; + + static QSet m_cnameCache; + static bool m_cnameCacheLoaded; +}; + +#endif