新增按需转码功能;支持批量查询和批量添加
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
#include "src/mainwindow/mainwindow.h"
|
||||
#include "ElaApplication.h"
|
||||
#include "ElaTheme.h"
|
||||
#include "src/utils/configmanager.h"
|
||||
#include "src/utils/logmanager.h"
|
||||
#include "src/utils/version.h"
|
||||
#include <QApplication>
|
||||
#include <QElapsedTimer>
|
||||
#include <QIcon>
|
||||
#include <QCoreApplication>
|
||||
#include <QEvent>
|
||||
@@ -11,6 +15,17 @@
|
||||
#include <QLabel>
|
||||
#include <QAbstractItemView>
|
||||
#include <QModelIndex>
|
||||
#include <QSplashScreen>
|
||||
#include <QPainter>
|
||||
#include <QScreen>
|
||||
#include <QSettings>
|
||||
#include <QLockFile>
|
||||
#include <QMessageBox>
|
||||
#include <QStandardPaths>
|
||||
#ifdef Q_OS_WIN
|
||||
#include <windows.h>
|
||||
#include <dwmapi.h>
|
||||
#endif
|
||||
#include <algorithm>
|
||||
|
||||
// 全局文字可复制过滤器:
|
||||
@@ -87,19 +102,126 @@ private:
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 启动分段计时: 每段耗时写入日志(带累计值), 用于定位启动慢的具体环节
|
||||
QElapsedTimer startupTimer;
|
||||
startupTimer.start();
|
||||
auto mark = [&startupTimer](const char *stage) {
|
||||
LogManager::instance()->logInfo(
|
||||
QString("[启动计时] %1 - 累计 %2 ms").arg(QString::fromUtf8(stage)).arg(startupTimer.elapsed()));
|
||||
};
|
||||
|
||||
QApplication a(argc, argv);
|
||||
a.setWindowIcon(QIcon(":resources/images/ChangeCode.png"));
|
||||
|
||||
// 单实例保护: 双开会并发互写日志文件、并发覆盖 config.ini, 还会重复弹出升级提示。
|
||||
// QLockFile 持有方进程崩溃后残留锁可被下次启动自动接管(按锁内 PID 探测存活)
|
||||
const QString lockPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation)
|
||||
+ "/UFT30ChangeCode.lock";
|
||||
QLockFile lockFile(lockPath);
|
||||
if (!lockFile.tryLock(0)) {
|
||||
LogManager::instance()->logWarning("检测到已有实例在运行, 本次启动退出");
|
||||
QMessageBox::warning(nullptr, "程序已在运行",
|
||||
"UFT30 Change Code 已经在运行中,请勿重复启动。");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 启动画面: main() 最先显示, 覆盖后续主窗口首帧的小几何闪现("跳动框"),
|
||||
// 主窗口显示完成后由 finish() 自动关闭
|
||||
QPixmap splashPix(640, 400);
|
||||
splashPix.fill(QColor(0x27, 0x43, 0x5B));
|
||||
{
|
||||
QPainter p(&splashPix);
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
QPixmap icon(":resources/images/ChangeCode.png");
|
||||
if (!icon.isNull()) {
|
||||
p.drawPixmap((640 - 128) / 2, 96, 128, 128, icon);
|
||||
}
|
||||
QFont titleFont = p.font();
|
||||
titleFont.setPixelSize(30);
|
||||
titleFont.setBold(true);
|
||||
p.setFont(titleFont);
|
||||
p.setPen(Qt::white);
|
||||
p.drawText(QRect(0, 248, 640, 44), Qt::AlignHCenter,
|
||||
QString("UFT30 Change Code %1").arg(Version::getVersionString()));
|
||||
QFont subFont = p.font();
|
||||
subFont.setPixelSize(16);
|
||||
p.setFont(subFont);
|
||||
p.drawText(QRect(0, 302, 640, 28), Qt::AlignHCenter, QString("正在启动..."));
|
||||
}
|
||||
QSplashScreen splash(splashPix);
|
||||
// 置顶显示: 启动画面默认非 topmost, 期间出现的任何窗口(主窗口半透明首帧、
|
||||
// 系统提示等)都可能绘制到它之上形成"残影", 置顶后可完全覆盖
|
||||
splash.setWindowFlag(Qt::WindowStaysOnTopHint, true);
|
||||
splash.show();
|
||||
// 排除用户输入事件: 启动阶段积压的鼠标/键盘事件若被分发, 可能触发意料之外的
|
||||
// 焦点/点击行为(例如误点即将出现的窗口), 只处理绘制类事件保证 splash 正常上屏
|
||||
a.processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
|
||||
// 安装全局过滤器:所有页面文字 / 表格树单元格允许用户复制
|
||||
TextSelectableFilter textSelectableFilter;
|
||||
a.installEventFilter(&textSelectableFilter);
|
||||
|
||||
// 日志初始化提前到启动最前: 此后所有分段耗时都能落盘, 便于排查启动瓶颈
|
||||
LogManager::instance()->initLogConfig();
|
||||
LogManager::instance()->initLogFile();
|
||||
mark("QApplication 就绪");
|
||||
|
||||
eApp->init();
|
||||
|
||||
mark("ElaApplication::init 完成");
|
||||
|
||||
// 应用上次保存的主题模式(未保存过时为夜间模式, 与 Ela 默认一致):
|
||||
// 必须在主窗口构造前设置, 保证主窗口首帧即为正确主题, 避免启动后闪色。
|
||||
// 此前主题从未被应用(设置页 onThemeChanged 为空), 界面始终是 Ela 默认夜间模式
|
||||
{
|
||||
QSettings settings("UFT30", "ChangeCode");
|
||||
const QString theme = settings.value("Theme", "夜间模式").toString();
|
||||
ElaTheme::getInstance()->setThemeMode(
|
||||
theme == QString::fromUtf8("日间模式") ? ElaThemeType::Light : ElaThemeType::Dark);
|
||||
mark("主题模式应用完成");
|
||||
}
|
||||
|
||||
QString basePath = QCoreApplication::applicationDirPath();
|
||||
ConfigManager::instance()->loadConfig(basePath);
|
||||
|
||||
MainWindow w;
|
||||
w.showMaximized();
|
||||
return a.exec();
|
||||
mark("config.ini 加载完成");
|
||||
|
||||
int exitCode = 0;
|
||||
// 启动异常兜底: MainWindow 构造涉及 8 页面 + 缓存库 + 索引扫描, 任何一环抛出
|
||||
// 未捕获异常都会直接 std::terminate 无提示退出; 这里统一转弹窗 + 日志后有序退出
|
||||
try {
|
||||
MainWindow w;
|
||||
mark("MainWindow 构造完成(8 页面 + 缓存库)");
|
||||
|
||||
// show 前把窗口几何预设为屏幕可用区域: 使 native 窗口创建即为最大化尺寸,
|
||||
// 避免 showMaximized 首帧从默认小尺寸几何跳变到最大化("跳动框")
|
||||
w.setGeometry(QGuiApplication::primaryScreen()->availableGeometry());
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
// 禁用 DWM 窗口过渡动画: 最大化显示时不再从旧几何帧动画跳变, 消除首帧"闪动框"。
|
||||
// 必须放在 setGeometry 之后: winId() 会提前创建 native 窗口, 若在几何预设前调用,
|
||||
// native 窗口将以默认小尺寸创建, setGeometry 的预设效果被削弱
|
||||
HWND hwnd = reinterpret_cast<HWND>(w.winId());
|
||||
BOOL disableTransitions = TRUE;
|
||||
DwmSetWindowAttribute(hwnd, DWMWA_TRANSITIONS_FORCEDISABLED,
|
||||
&disableTransitions, sizeof(disableTransitions));
|
||||
#endif
|
||||
|
||||
w.showMaximized();
|
||||
mark("窗口已显示");
|
||||
splash.finish(&w); // 主窗口已上屏, 关闭启动画面
|
||||
exitCode = a.exec();
|
||||
} catch (const std::exception &e) {
|
||||
splash.close();
|
||||
LogManager::instance()->logError(
|
||||
QString("启动阶段未捕获异常: %1").arg(QString::fromUtf8(e.what())));
|
||||
QMessageBox::critical(nullptr, "启动失败",
|
||||
QString("程序初始化发生异常: %1\n详情请查看日志文件。").arg(QString::fromUtf8(e.what())));
|
||||
exitCode = 1;
|
||||
} catch (...) {
|
||||
splash.close();
|
||||
LogManager::instance()->logError("启动阶段未捕获未知异常");
|
||||
QMessageBox::critical(nullptr, "启动失败",
|
||||
"程序初始化发生未知异常。\n详情请查看日志文件。");
|
||||
exitCode = 1;
|
||||
}
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user