新增缓存数据库存储、转码进度显示

This commit is contained in:
taocong 2026-05-26 14:33:03 +08:00
parent fd38553be1
commit c097120ca3
15 changed files with 1239 additions and 100 deletions

View File

@ -1,4 +1,4 @@
QT += core gui widgets QT += core gui widgets sql
TARGET = Uft30ChangeCode TARGET = Uft30ChangeCode
TEMPLATE = app TEMPLATE = app
@ -12,7 +12,11 @@ SOURCES += main.cpp \
src/pages/batchconvert/batchconvertpage.cpp \ src/pages/batchconvert/batchconvertpage.cpp \
src/pages/functionsearch/functionsearchpage.cpp \ src/pages/functionsearch/functionsearchpage.cpp \
src/pages/help/helppage.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 \ HEADERS += src/mainwindow/mainwindow.h \
src/pythonrunner/PythonRunner.h \ src/pythonrunner/PythonRunner.h \
@ -20,7 +24,11 @@ HEADERS += src/mainwindow/mainwindow.h \
src/pages/batchconvert/batchconvertpage.h \ src/pages/batchconvert/batchconvertpage.h \
src/pages/functionsearch/functionsearchpage.h \ src/pages/functionsearch/functionsearchpage.h \
src/pages/help/helppage.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 RESOURCES += resources.qrc

View File

@ -1,7 +1,7 @@
<RCC> <RCC>
<qresource prefix="/"> <qresource prefix="/">
<file>resources/images/ChangeCode.png</file> <file>resources/images/ChangeCode.png</file>
<file>resources/images/delect.png</file> <file>resources/images/bianji.png</file>
<file>resources/images/zhedie_left.png</file> <file>resources/images/zhedie_left.png</file>
<file>resources/images/zhedie_right.png</file> <file>resources/images/zhedie_right.png</file>
<file>resources/images/max.png</file> <file>resources/images/max.png</file>

BIN
resources/images/bianji.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -3,6 +3,9 @@
#include "ElaText.h" #include "ElaText.h"
#include "ElaTheme.h" #include "ElaTheme.h"
#include "ElaToolButton.h" #include "ElaToolButton.h"
#include "utils/uf2configreader.h"
#include "utils/uft3configreader.h"
#include "utils/logmanager.h"
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QLabel> #include <QLabel>
@ -30,39 +33,73 @@ MainWindow::MainWindow(QWidget *parent)
initWindow(); initWindow();
initContent(); initContent();
// 获取应用程序目录 LogManager::instance()->initLogFile();
LogManager::instance()->logInfo("应用程序启动");
QString appDir = QCoreApplication::applicationDirPath(); QString appDir = QCoreApplication::applicationDirPath();
// 配置 Python 运行器 - 只使用打包好的 exe路径是 uf2touft3/uf2touft3.exe loadConfigCache();
m_pythonRunner->setRunMode(PythonRunner::UsePackagedExe); m_pythonRunner->setRunMode(PythonRunner::UsePackagedExe);
// 设置打包好的可执行文件路径和工作目录
QString exePath = appDir + "/uf2touft3/uf2touft3.exe"; QString exePath = appDir + "/uf2touft3/uf2touft3.exe";
QString workDir = appDir + "/uf2touft3"; QString workDir = appDir + "/uf2touft3";
m_pythonRunner->setPackagedExePath(exePath); m_pythonRunner->setPackagedExePath(exePath);
m_pythonRunner->setWorkingDirectory(workDir); m_pythonRunner->setWorkingDirectory(workDir);
// 检查 exe 是否存在
QFileInfo exeInfo(exePath); QFileInfo exeInfo(exePath);
if (!exeInfo.exists() || !exeInfo.isFile()) { if (!exeInfo.exists() || !exeInfo.isFile()) {
m_batchLogEdit->append("⚠️ 警告:未找到 uf2touft3/uf2touft3.exe"); LogManager::instance()->logWarning("⚠️ 警告:未找到 uf2touft3/uf2touft3.exe");
m_batchLogEdit->append(QString(" 期望位置:%1").arg(exePath)); LogManager::instance()->log(QString(" 期望位置:%1").arg(exePath));
} else { } else {
m_batchLogEdit->append("✓ Python 工具准备就绪"); LogManager::instance()->log("✓ Python 工具准备就绪");
} }
connect(m_pythonRunner, &PythonRunner::finished, this, &MainWindow::onPythonRunnerFinished); connect(m_pythonRunner, &PythonRunner::finished, this, &MainWindow::onPythonRunnerFinished);
connect(m_pythonRunner, &PythonRunner::standardOutput, this, &MainWindow::onPythonRunnerOutput); connect(m_pythonRunner, &PythonRunner::standardOutput, this, &MainWindow::onPythonRunnerOutput);
connect(m_pythonRunner, &PythonRunner::standardError, this, &MainWindow::onPythonRunnerError); connect(m_pythonRunner, &PythonRunner::standardError, this, &MainWindow::onPythonRunnerError);
connect(m_pythonRunner, &PythonRunner::started, [this]() { connect(m_pythonRunner, &PythonRunner::started, []() {
m_batchLogEdit->append("转换任务已启动..."); LogManager::instance()->log("转换任务已启动...");
}); });
// 延迟查找并更新导航按钮(等待窗口完全显示后)
QTimer::singleShot(100, this, &MainWindow::updateNavigationButtonIcon); 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() MainWindow::~MainWindow()
{ {
} }
@ -72,6 +109,7 @@ void MainWindow::initWindow()
setWindowTitle("UFT30 Change Code"); setWindowTitle("UFT30 Change Code");
setWindowIcon(QIcon(":/resources/images/ChangeCode.png")); setWindowIcon(QIcon(":/resources/images/ChangeCode.png"));
resize(900, 600); resize(900, 600);
setMinimumSize(800, 500);
setUserInfoCardVisible(false); setUserInfoCardVisible(false);
// 隐藏返回和前进按钮 // 隐藏返回和前进按钮
@ -94,15 +132,10 @@ void MainWindow::initContent()
QWidget* MainWindow::createBatchConvertPage() QWidget* MainWindow::createBatchConvertPage()
{ {
BatchConvertPage *page = new BatchConvertPage; m_batchConvertPage = new BatchConvertPage;
m_batchLogEdit = page->getLogEdit(); connect(m_batchConvertPage, &BatchConvertPage::startConvert, this, &MainWindow::onBatchConvertStart);
connect(page, &BatchConvertPage::startConvert, this, &MainWindow::onBatchConvertStart); connect(m_batchConvertPage, &BatchConvertPage::stopConvert, this, &MainWindow::onBatchConvertStop);
connect(m_pythonRunner, &PythonRunner::started, [this]() { return m_batchConvertPage;
if (m_batchLogEdit) {
m_batchLogEdit->append("转换任务已启动...");
}
});
return page;
} }
QWidget* MainWindow::createFunctionSearchPage() QWidget* MainWindow::createFunctionSearchPage()
@ -128,7 +161,7 @@ QWidget* MainWindow::createSettingsPage()
void MainWindow::onBatchConvertStart() void MainWindow::onBatchConvertStart()
{ {
if (m_pythonRunner->isRunning()) { if (m_pythonRunner->isRunning()) {
m_batchLogEdit->append("警告: 上一个任务还在运行中..."); LogManager::instance()->logWarning("警告: 上一个任务还在运行中...");
QMessageBox::warning(this, "提示", "上一个转换任务正在运行,请等待完成或停止当前任务。"); QMessageBox::warning(this, "提示", "上一个转换任务正在运行,请等待完成或停止当前任务。");
return; return;
} }
@ -137,47 +170,124 @@ void MainWindow::onBatchConvertStart()
QString exePath = appDir + "/uf2touft3/uf2touft3.exe"; QString exePath = appDir + "/uf2touft3/uf2touft3.exe";
if (!m_pythonRunner->canRun()) { if (!m_pythonRunner->canRun()) {
m_batchLogEdit->append("错误: 找不到 uf2touft3/uf2touft3.exe!"); LogManager::instance()->logError("错误: 找不到 uf2touft3/uf2touft3.exe!");
QMessageBox::critical(this, "错误", QMessageBox::critical(this, "错误",
QString("无法启动转换任务!\n\n请确保:\nuf2touft3/uf2touft3.exe 存在,且该目录下包含 config.ini\n\n期望路径:\n%1") QString("无法启动转换任务!\n\n请确保:\nuf2touft3/uf2touft3.exe 存在,且该目录下包含 config.ini\n\n期望路径:\n%1")
.arg(exePath)); .arg(exePath));
return; return;
} }
m_batchLogEdit->append("========================================"); if (m_batchConvertPage) {
m_batchLogEdit->append("开始执行 UFT2 到 UFT3 的代码转换..."); m_totalFunctions = m_batchConvertPage->getFunctionCount();
m_batchLogEdit->append(QString("工具路径: %1").arg(exePath)); m_functionList = m_batchConvertPage->getFunctionList();
m_batchLogEdit->append("========================================"); 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()) { 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) 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) { if (exitStatus == QProcess::NormalExit && exitCode == 0) {
m_batchLogEdit->append("✓ 代码转换完成!"); LogManager::instance()->log("✓ 代码转换完成!");
QMessageBox::information(this, "完成", "代码转换任务已成功完成!"); QMessageBox::information(this, "完成", "代码转换任务已成功完成!");
} else { } else {
m_batchLogEdit->append(QString("✗ 转换失败! 退出码: %1").arg(exitCode)); LogManager::instance()->logError(QString("✗ 转换失败! 退出码: %1").arg(exitCode));
QMessageBox::warning(this, "失败", QString("代码转换任务失败,退出码: %1").arg(exitCode)); QMessageBox::warning(this, "失败", QString("代码转换任务失败,退出码: %1").arg(exitCode));
} }
m_batchLogEdit->append("========================================"); LogManager::instance()->log("========================================");
} }
void MainWindow::onPythonRunnerOutput(const QString &output) void MainWindow::onPythonRunnerOutput(const QString &output)
{ {
if (!output.trimmed().isEmpty()) { 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) void MainWindow::onPythonRunnerError(const QString &error)
{ {
if (!error.trimmed().isEmpty()) { if (!error.trimmed().isEmpty()) {
m_batchLogEdit->append(QString("[ERROR] %1").arg(error)); LogManager::instance()->logError(QString("[ERROR] %1").arg(error));
} }
} }

View File

@ -4,7 +4,6 @@
#include "ElaWindow.h" #include "ElaWindow.h"
#include "ElaToolButton.h" #include "ElaToolButton.h"
#include <QWidget> #include <QWidget>
#include <QTextEdit>
#include "src/pythonrunner/PythonRunner.h" #include "src/pythonrunner/PythonRunner.h"
#include "src/pages/batchconvert/batchconvertpage.h" #include "src/pages/batchconvert/batchconvertpage.h"
#include "src/pages/functionsearch/functionsearchpage.h" #include "src/pages/functionsearch/functionsearchpage.h"
@ -30,7 +29,10 @@ private:
QWidget* createAboutPage(); QWidget* createAboutPage();
QWidget* createSettingsPage(); QWidget* createSettingsPage();
void loadConfigCache();
void onBatchConvertStart(); void onBatchConvertStart();
void onBatchConvertStop();
void onPythonRunnerFinished(int exitCode, QProcess::ExitStatus exitStatus); void onPythonRunnerFinished(int exitCode, QProcess::ExitStatus exitStatus);
void onPythonRunnerOutput(const QString &output); void onPythonRunnerOutput(const QString &output);
void onPythonRunnerError(const QString &error); void onPythonRunnerError(const QString &error);
@ -40,10 +42,14 @@ private:
void onNavigationButtonClicked(); void onNavigationButtonClicked();
PythonRunner *m_pythonRunner; PythonRunner *m_pythonRunner;
QTextEdit *m_batchLogEdit;
bool m_iconsSet; bool m_iconsSet;
ElaToolButton* m_navigationButton; ElaToolButton* m_navigationButton;
bool m_isNavigationExpanded; bool m_isNavigationExpanded;
BatchConvertPage *m_batchConvertPage;
int m_totalFunctions;
int m_currentFunctionIndex;
QStringList m_functionList;
}; };
#endif // MAINWINDOW_H #endif // MAINWINDOW_H

View File

@ -1,4 +1,5 @@
#include "batchconvertpage.h" #include "batchconvertpage.h"
#include "src/utils/uf2configreader.h"
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QLabel> #include <QLabel>
@ -12,6 +13,7 @@
#include <QInputDialog> #include <QInputDialog>
#include <QDialog> #include <QDialog>
#include <QTextEdit> #include <QTextEdit>
#include "src/utils/logmanager.h"
BatchConvertPage::BatchConvertPage(QWidget *parent) BatchConvertPage::BatchConvertPage(QWidget *parent)
: QWidget(parent) : QWidget(parent)
@ -63,37 +65,62 @@ void BatchConvertPage::initUI()
layout->addWidget(funcBox); layout->addWidget(funcBox);
QHBoxLayout *btnLayout = new QHBoxLayout; QGroupBox *progressBox = new QGroupBox("转换进度");
QPushButton *startBtn = new QPushButton("开始转换"); progressBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
startBtn->setStyleSheet("background-color: #1abc9c; color: white; padding: 10px 30px; font-size: 14px; border: none; border-radius: 4px;"); QVBoxLayout *progressLayout = new QVBoxLayout(progressBox);
connect(startBtn, &QPushButton::clicked, this, &BatchConvertPage::onStartConvert); progressLayout->setSpacing(10);
QPushButton *clearLogBtn = new QPushButton("清空日志");
connect(clearLogBtn, &QPushButton::clicked, this, &BatchConvertPage::onClearLog);
btnLayout->addStretch();
btnLayout->addWidget(startBtn);
btnLayout->addWidget(clearLogBtn);
layout->addLayout(btnLayout);
m_logEdit = new QTextEdit; m_progressLabel = new QLabel("等待开始...");
m_logEdit->setReadOnly(true); m_progressLabel->setStyleSheet("color: #666;");
m_logEdit->setStyleSheet("background-color: #2c3e50; color: #ecf0f1;"); m_progressLabel->setFixedHeight(20);
m_logEdit->append("转码工具已准备就绪..."); m_progressLabel->setWordWrap(false);
layout->addWidget(m_logEdit); 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) bool BatchConvertPage::checkFunctionExists(const QString &funcName)
{ {
QString jsonPath = QCoreApplication::applicationDirPath() + "/uf2touft3/cust.json"; return UF2ConfigReader::checkFuncExistsStatic(funcName);
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 + "\"");
} }
void BatchConvertPage::updateTable() void BatchConvertPage::updateTable()
@ -123,15 +150,15 @@ void BatchConvertPage::updateTable()
} }
m_funcTable->setItem(i, 1, statusItem); m_funcTable->setItem(i, 1, statusItem);
QPushButton *delBtn = new QPushButton; QPushButton *editBtn = new QPushButton;
delBtn->setIcon(QIcon(":/resources/images/delect.png")); editBtn->setIcon(QIcon(":/resources/images/bianji.png"));
delBtn->setIconSize(QSize(20, 20)); editBtn->setIconSize(QSize(20, 20));
delBtn->setStyleSheet("padding: 2px; border: none; background-color: transparent;"); editBtn->setStyleSheet("padding: 2px; border: none; background-color: transparent;");
delBtn->setToolTip("删除"); editBtn->setToolTip("修改");
connect(delBtn, &QPushButton::clicked, this, [this, i]() { connect(editBtn, &QPushButton::clicked, this, [this, i]() {
onDeleteRow(i); onEditRow(i);
}); });
m_funcTable->setCellWidget(i, 2, delBtn); m_funcTable->setCellWidget(i, 2, editBtn);
} }
int totalWidth = m_funcTable->width(); 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()) { if (row < 0 || row >= m_funcList.size()) {
m_funcList.removeAt(row); return;
updateTable();
} }
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() void BatchConvertPage::onAddFunction()
@ -264,7 +326,7 @@ bool BatchConvertPage::saveToCustJson(const QStringList &funcList)
QFile file(jsonPath); QFile file(jsonPath);
if (!file.open(QIODevice::ReadOnly)) { if (!file.open(QIODevice::ReadOnly)) {
m_logEdit->append("[ERROR] 无法打开文件: " + jsonPath); LogManager::instance()->logError(QString("无法打开文件: %1").arg(jsonPath));
return false; return false;
} }
@ -278,7 +340,7 @@ bool BatchConvertPage::saveToCustJson(const QStringList &funcList)
dirStart = content.indexOf("\"dir\" : ["); dirStart = content.indexOf("\"dir\" : [");
} }
if (dirStart < 0) { if (dirStart < 0) {
m_logEdit->append("[ERROR] 未找到 \"dir\" 节点"); LogManager::instance()->logError("未找到 \"dir\" 节点");
return false; return false;
} }
@ -302,7 +364,7 @@ bool BatchConvertPage::saveToCustJson(const QStringList &funcList)
content.replace(arrayStart, arrayEnd - arrayStart, newDirArray); content.replace(arrayStart, arrayEnd - arrayStart, newDirArray);
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
m_logEdit->append("[ERROR] 无法写入文件: " + jsonPath); LogManager::instance()->logError(QString("无法写入文件: %1").arg(jsonPath));
return false; return false;
} }
@ -314,33 +376,54 @@ bool BatchConvertPage::saveToCustJson(const QStringList &funcList)
void BatchConvertPage::onStartConvert() void BatchConvertPage::onStartConvert()
{ {
if (m_funcList.isEmpty()) { if (m_startBtn->text() == "停止转换") {
m_logEdit->append("请先添加需要转码的函数!"); LogManager::instance()->log("用户请求停止转换...");
m_progressLabel->setText("正在停止转换...");
emit stopConvert();
return; return;
} }
m_logEdit->append("========================================"); if (m_funcList.isEmpty()) {
m_logEdit->append("正在写入 cust.json ..."); QMessageBox::warning(this, "提示", "请先添加需要转码的函数!");
m_logEdit->append("功能列表:"); 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) { 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)) { if (saveToCustJson(m_funcList)) {
m_logEdit->append("[OK] cust.json 写入成功!"); LogManager::instance()->log("cust.json 写入成功!");
m_progressLabel->setText("配置加载成功,开始转换...");
m_progressBar->setValue(20);
} else { } else {
m_logEdit->append("[FAIL] cust.json 写入失败!"); LogManager::instance()->logError("cust.json 写入失败!");
m_logEdit->append("========================================"); LogManager::instance()->log("========================================");
m_progressLabel->setText("配置加载失败");
return; return;
} }
m_logEdit->append("========================================"); LogManager::instance()->log("========================================");
emit startConvert(); emit startConvert();
} }
void BatchConvertPage::onClearLog() void BatchConvertPage::onConvertStarted()
{ {
m_logEdit->clear(); m_startBtn->setText("停止转换");
m_logEdit->append("转码工具已准备就绪..."); 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;");
}

View File

@ -3,9 +3,10 @@
#include <QWidget> #include <QWidget>
#include <QLineEdit> #include <QLineEdit>
#include <QTextEdit>
#include <QTableWidget> #include <QTableWidget>
#include <QPushButton> #include <QPushButton>
#include <QProgressBar>
#include <QLabel>
class BatchConvertPage : public QWidget class BatchConvertPage : public QWidget
{ {
@ -15,18 +16,24 @@ public:
explicit BatchConvertPage(QWidget *parent = nullptr); explicit BatchConvertPage(QWidget *parent = nullptr);
~BatchConvertPage(); ~BatchConvertPage();
QTextEdit* getLogEdit() { return m_logEdit; }
signals: signals:
void startConvert(); 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: private slots:
void onStartConvert(); void onStartConvert();
void onClearLog();
void onAddFunction(); void onAddFunction();
void onRemoveFunction(); void onRemoveFunction();
void onClearTable(); void onClearTable();
void onDeleteRow(int row); void onEditRow(int row);
private: private:
void initUI(); void initUI();
@ -36,8 +43,10 @@ private:
void resizeEvent(QResizeEvent *event) override; void resizeEvent(QResizeEvent *event) override;
QTableWidget *m_funcTable; QTableWidget *m_funcTable;
QTextEdit *m_logEdit;
QStringList m_funcList; QStringList m_funcList;
QProgressBar *m_progressBar;
QLabel *m_progressLabel;
QPushButton *m_startBtn;
}; };
#endif // BATCHCONVERTPAGE_H #endif

365
src/utils/datacache.cpp Normal file
View File

@ -0,0 +1,365 @@
#include "datacache.h"
#include "logmanager.h"
#include <QSqlQuery>
#include <QSqlError>
#include <QJsonDocument>
#include <QCoreApplication>
#include <QDir>
#include <QDateTime>
#include <QElapsedTimer>
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<QString> DataCache::getAllUF20Cnames()
{
QSet<QString> 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<QString> DataCache::getAllUFT3Cnames()
{
QSet<QString> 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;
}

46
src/utils/datacache.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef DATACACHE_H
#define DATACACHE_H
#include <QObject>
#include <QSqlDatabase>
#include <QJsonObject>
#include <QSet>
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<QString> getAllUF20Cnames();
bool checkUFT3CnameExists(const QString& cname);
QSet<QString> 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

93
src/utils/logmanager.cpp Normal file
View File

@ -0,0 +1,93 @@
#include "logmanager.h"
#include <QCoreApplication>
#include <QDir>
#include <QDateTime>
#include <QDebug>
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);
}

37
src/utils/logmanager.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef LOGMANAGER_H
#define LOGMANAGER_H
#include <QObject>
#include <QString>
#include <QFile>
#include <QTextStream>
#include <QMutex>
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

View File

@ -0,0 +1,154 @@
#include "uf2configreader.h"
#include "datacache.h"
#include "logmanager.h"
#include <QFile>
#include <QJsonDocument>
#include <QCoreApplication>
#include <QDir>
QSet<QString> 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缓存已清空");
}

View File

@ -0,0 +1,37 @@
#ifndef UF2CONFIGREADER_H
#define UF2CONFIGREADER_H
#include <QObject>
#include <QStringList>
#include <QJsonObject>
#include <QSet>
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<QString> m_cnameCache;
static bool m_cnameCacheLoaded;
};
#endif

View File

@ -0,0 +1,154 @@
#include "uft3configreader.h"
#include "datacache.h"
#include "logmanager.h"
#include <QFile>
#include <QJsonDocument>
#include <QCoreApplication>
#include <QDir>
QSet<QString> 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缓存已清空");
}

View File

@ -0,0 +1,37 @@
#ifndef UFT3CONFIGREADER_H
#define UFT3CONFIGREADER_H
#include <QObject>
#include <QStringList>
#include <QJsonObject>
#include <QSet>
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<QString> m_cnameCache;
static bool m_cnameCacheLoaded;
};
#endif