新增数据映射页面,表映射、函数映射;新增版本更新提示功能
This commit is contained in:
@@ -1,9 +1,16 @@
|
||||
#include "batchconvertpage.h"
|
||||
#include "src/utils/Constants.h"
|
||||
#include "src/utils/uf2configreader.h"
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QGroupBox>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QRegularExpression>
|
||||
#include <QCoreApplication>
|
||||
#include <QHeaderView>
|
||||
#include <QMessageBox>
|
||||
@@ -48,19 +55,24 @@ BatchConvertPage::BatchConvertPage(QWidget *parent)
|
||||
{
|
||||
initUI();
|
||||
loadFromCustJson();
|
||||
|
||||
m_configWatcher = new QFileSystemWatcher(this);
|
||||
QString configPath = getConfigFilePath();
|
||||
if (!configPath.isEmpty() && QFile::exists(configPath)) {
|
||||
m_configWatcher->addPath(configPath);
|
||||
connect(m_configWatcher, &QFileSystemWatcher::fileChanged, this, &BatchConvertPage::onConfigFileChanged);
|
||||
}
|
||||
|
||||
// 防抖定时器:编辑器保存可能触发多次信号,合并为一次重载
|
||||
m_reloadTimer = new QTimer(this);
|
||||
m_reloadTimer->setSingleShot(true);
|
||||
m_reloadTimer->setInterval(300);
|
||||
connect(m_reloadTimer, &QTimer::timeout, this, &BatchConvertPage::onReloadTimeout);
|
||||
|
||||
// 记录初始 mtime
|
||||
m_lastFileMtime = currentFileMtime();
|
||||
|
||||
setupConfigWatcher();
|
||||
}
|
||||
|
||||
BatchConvertPage::~BatchConvertPage()
|
||||
{
|
||||
if (m_configWatcher) {
|
||||
m_configWatcher->removePaths(m_configWatcher->files());
|
||||
m_configWatcher->removePaths(m_configWatcher->directories());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,140 +378,112 @@ void BatchConvertPage::onClearTable()
|
||||
|
||||
bool BatchConvertPage::saveToCustJson(const QStringList &funcList)
|
||||
{
|
||||
QString jsonPath = QCoreApplication::applicationDirPath() + "/uf2touft3/cust.json";
|
||||
|
||||
QString jsonPath = Constants::custJson();
|
||||
|
||||
// 读取原始文件内容(保留全部格式不重序列化)
|
||||
QFile file(jsonPath);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
LogManager::instance()->logWarning(
|
||||
QString("业务转码 - 保存配置失败,无法打开: %1").arg(jsonPath));
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray data = file.readAll();
|
||||
|
||||
QString content = QString::fromUtf8(file.readAll());
|
||||
file.close();
|
||||
|
||||
QString content = QString::fromUtf8(data);
|
||||
|
||||
int convertStart = content.indexOf("\"convert\":");
|
||||
if (convertStart < 0) {
|
||||
convertStart = content.indexOf("\"convert\" :");
|
||||
}
|
||||
if (convertStart < 0) {
|
||||
|
||||
// 用正则定位 "convert" 节点(兼容任意空格)
|
||||
static QRegularExpression convertRe(R"("convert"\s*:)");
|
||||
auto convertMatch = convertRe.match(content);
|
||||
if (!convertMatch.hasMatch()) {
|
||||
LogManager::instance()->logWarning("业务转码 - 保存配置失败,未找到 convert 节点");
|
||||
return false;
|
||||
}
|
||||
|
||||
int dirStart = content.indexOf("\"dir\":[", convertStart);
|
||||
if (dirStart < 0) {
|
||||
dirStart = content.indexOf("\"dir\" : [", convertStart);
|
||||
}
|
||||
if (dirStart < 0) {
|
||||
|
||||
// 在 convert 之后定位 "dir" 数组起始 [
|
||||
static QRegularExpression dirRe(R"("dir"\s*:\s*\[)");
|
||||
auto dirMatch = dirRe.match(content, convertMatch.capturedEnd());
|
||||
if (!dirMatch.hasMatch()) {
|
||||
LogManager::instance()->logWarning("业务转码 - 保存配置失败,未找到 dir 数组");
|
||||
return false;
|
||||
}
|
||||
|
||||
int arrayStart = content.indexOf('[', dirStart);
|
||||
|
||||
int bracketStart = dirMatch.capturedEnd() - 1; // 指向 '['
|
||||
|
||||
// 括号计数找到匹配的 ']'
|
||||
int bracketCount = 1;
|
||||
int pos = arrayStart + 1;
|
||||
int pos = bracketStart + 1;
|
||||
while (pos < content.length() && bracketCount > 0) {
|
||||
if (content[pos] == '[') bracketCount++;
|
||||
else if (content[pos] == ']') bracketCount--;
|
||||
QChar ch = content[pos];
|
||||
if (ch == '[') bracketCount++;
|
||||
else if (ch == ']') bracketCount--;
|
||||
pos++;
|
||||
}
|
||||
int arrayEnd = pos;
|
||||
|
||||
QString newDirArray = "[";
|
||||
int bracketEnd = pos; // 指向 ']' 之后一位
|
||||
|
||||
// 构建新数组(保持原始缩进风格:项 12 空格,闭合 ] 8 空格)
|
||||
QString newArray = "[";
|
||||
for (int i = 0; i < funcList.size(); ++i) {
|
||||
if (i > 0) newDirArray += ",";
|
||||
newDirArray += "\n \"" + funcList[i] + ".service_design\"";
|
||||
if (i > 0) newArray += ",";
|
||||
newArray += "\n \"" + funcList[i] + ".service_design\"";
|
||||
}
|
||||
newDirArray += "\n ]";
|
||||
|
||||
content.replace(arrayStart, arrayEnd - arrayStart, newDirArray);
|
||||
|
||||
if (!funcList.isEmpty()) {
|
||||
newArray += "\n ";
|
||||
}
|
||||
newArray += "]";
|
||||
|
||||
// 只替换 [bracketStart, bracketEnd) 区间,其余内容原样保留
|
||||
content.replace(bracketStart, bracketEnd - bracketStart, newArray);
|
||||
|
||||
// 写回
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
LogManager::instance()->logWarning(
|
||||
QString("业务转码 - 保存配置失败,无法写入: %1").arg(jsonPath));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
file.write(content.toUtf8());
|
||||
file.close();
|
||||
|
||||
|
||||
// 程序自身写入后更新 mtime,避免触发无谓的重载
|
||||
m_lastFileMtime = currentFileMtime();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BatchConvertPage::loadFromCustJson()
|
||||
{
|
||||
QString jsonPath = QCoreApplication::applicationDirPath() + "/uf2touft3/cust.json";
|
||||
|
||||
QString jsonPath = Constants::custJson();
|
||||
|
||||
QFile file(jsonPath);
|
||||
int retryCount = 0;
|
||||
const int maxRetries = 3;
|
||||
const int retryDelayMs = 100;
|
||||
|
||||
while (!file.open(QIODevice::ReadOnly) && retryCount < maxRetries) {
|
||||
retryCount++;
|
||||
QThread::msleep(retryDelayMs);
|
||||
}
|
||||
|
||||
if (!file.isOpen()) {
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
LogManager::instance()->logWarning(
|
||||
QString("业务转码 - 加载配置失败,无法打开: %1").arg(jsonPath));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
QByteArray data = file.readAll();
|
||||
file.close();
|
||||
|
||||
QString content = QString::fromUtf8(data);
|
||||
|
||||
int convertStart = content.indexOf("\"convert\":");
|
||||
if (convertStart < 0) {
|
||||
convertStart = content.indexOf("\"convert\" :");
|
||||
}
|
||||
if (convertStart < 0) {
|
||||
|
||||
QJsonParseError parseError;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(data, &parseError);
|
||||
if (parseError.error != QJsonParseError::NoError) {
|
||||
LogManager::instance()->logWarning(
|
||||
QString("业务转码 - 加载配置 JSON 解析失败: %1").arg(parseError.errorString()));
|
||||
return;
|
||||
}
|
||||
|
||||
int dirStart = content.indexOf("\"dir\":[", convertStart);
|
||||
if (dirStart < 0) {
|
||||
dirStart = content.indexOf("\"dir\" : [", convertStart);
|
||||
}
|
||||
if (dirStart < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int arrayStart = content.indexOf('[', dirStart);
|
||||
|
||||
int bracketCount = 1;
|
||||
int pos = arrayStart + 1;
|
||||
while (pos < content.length() && bracketCount > 0) {
|
||||
if (content[pos] == '[') bracketCount++;
|
||||
else if (content[pos] == ']') bracketCount--;
|
||||
pos++;
|
||||
}
|
||||
int arrayEnd = pos;
|
||||
|
||||
QString arrayContent = content.mid(arrayStart + 1, arrayEnd - arrayStart - 1).trimmed();
|
||||
|
||||
if (arrayContent.isEmpty() || arrayContent == "null") {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
QJsonObject root = doc.object();
|
||||
QJsonArray dir = root["convert"].toObject()["dir"].toArray();
|
||||
|
||||
QStringList items;
|
||||
int itemPos = 0;
|
||||
while (itemPos < arrayContent.length()) {
|
||||
int itemStart = arrayContent.indexOf('"', itemPos);
|
||||
if (itemStart < 0) break;
|
||||
|
||||
int itemEnd = arrayContent.indexOf('"', itemStart + 1);
|
||||
if (itemEnd < 0) break;
|
||||
|
||||
QString item = arrayContent.mid(itemStart + 1, itemEnd - itemStart - 1);
|
||||
items.append(item);
|
||||
|
||||
itemPos = itemEnd + 1;
|
||||
}
|
||||
|
||||
for (QString &item : items) {
|
||||
for (const QJsonValue &val : dir) {
|
||||
QString item = val.toString();
|
||||
if (item.endsWith(".service_design")) {
|
||||
item = item.left(item.length() - static_cast<int>(strlen(".service_design")));
|
||||
item.chop(static_cast<int>(strlen(".service_design")));
|
||||
}
|
||||
items.append(item);
|
||||
}
|
||||
|
||||
|
||||
m_funcList = items;
|
||||
updateTable();
|
||||
}
|
||||
@@ -566,17 +550,71 @@ void BatchConvertPage::addFunction(const QString &funcName)
|
||||
}
|
||||
}
|
||||
|
||||
void BatchConvertPage::setupConfigWatcher()
|
||||
{
|
||||
QString configPath = getConfigFilePath();
|
||||
if (configPath.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_configWatcher = new QFileSystemWatcher(this);
|
||||
|
||||
// 1. 监视文件本身(覆盖直接编辑场景)
|
||||
if (QFile::exists(configPath)) {
|
||||
m_configWatcher->addPath(configPath);
|
||||
}
|
||||
|
||||
// 2. 监视文件所在目录(覆盖编辑器原子替换:写临时文件→删除→重命名)
|
||||
// Windows 上 fileChanged 在文件被替换后常失效,directoryChanged 更可靠
|
||||
QString dir = QFileInfo(configPath).absolutePath();
|
||||
if (QDir(dir).exists()) {
|
||||
m_configWatcher->addPath(dir);
|
||||
}
|
||||
|
||||
connect(m_configWatcher, &QFileSystemWatcher::fileChanged,
|
||||
this, &BatchConvertPage::onConfigFileChanged);
|
||||
connect(m_configWatcher, &QFileSystemWatcher::directoryChanged,
|
||||
this, &BatchConvertPage::onConfigDirChanged);
|
||||
}
|
||||
|
||||
QDateTime BatchConvertPage::currentFileMtime() const
|
||||
{
|
||||
QFileInfo info(getConfigFilePath());
|
||||
return info.exists() ? info.lastModified() : QDateTime();
|
||||
}
|
||||
|
||||
void BatchConvertPage::onConfigFileChanged(const QString &path)
|
||||
{
|
||||
QStringList oldList = m_funcList;
|
||||
loadFromCustJson();
|
||||
|
||||
if (m_configWatcher && !m_configWatcher->files().contains(path)) {
|
||||
{
|
||||
// 文件可能被编辑器替换导致监视失效,尝试重新添加
|
||||
if (m_configWatcher && !m_configWatcher->files().contains(path)
|
||||
&& QFile::exists(path)) {
|
||||
m_configWatcher->addPath(path);
|
||||
}
|
||||
m_reloadTimer->start(); // 防抖
|
||||
}
|
||||
|
||||
void BatchConvertPage::onConfigDirChanged(const QString & /*dirPath*/)
|
||||
{
|
||||
// 目录变化时重新监视文件(可能之前文件不存在/被替换)
|
||||
QString configPath = getConfigFilePath();
|
||||
if (m_configWatcher && QFile::exists(configPath)
|
||||
&& !m_configWatcher->files().contains(configPath)) {
|
||||
m_configWatcher->addPath(configPath);
|
||||
}
|
||||
m_reloadTimer->start(); // 防抖
|
||||
}
|
||||
|
||||
void BatchConvertPage::onReloadTimeout()
|
||||
{
|
||||
// 比较 mtime,避免无谓重载
|
||||
QDateTime now = currentFileMtime();
|
||||
if (now.isValid() && now != m_lastFileMtime) {
|
||||
m_lastFileMtime = now;
|
||||
loadFromCustJson();
|
||||
}
|
||||
}
|
||||
|
||||
QString BatchConvertPage::getConfigFilePath() const
|
||||
{
|
||||
return QCoreApplication::applicationDirPath() + "/uf2touft3/cust.json";
|
||||
return Constants::custJson();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user