v1.2: .VSC 文件格式 & 跨平台安装程序
【文件格式】 - 工程文件扩展名从 .json 改为 .VSC(内容仍为 JSON) - 文件对话框过滤、保存/打开全部适配 .VSC - 双击 .VSC 文件可直接打开工程(命令行传参) 【安装程序】 - Windows: NSIS 安装脚本 (installer/voiletcstudio.nsi) 支持注册 .VSC 文件关联、开始菜单/桌面快捷方式、卸载 - Linux: install.sh/uninstall.sh 一键安装/卸载 自动注册 MIME 类型、.desktop 文件、命令行软链接 - 内置 --register/--unregister 命令行参数用于文件关联 【代码清理】 - 移除所有拖拽功能(dragEnter/Move/DropEvent) - 新增 MainWindow::openProjectFile() 用于命令行打开 - main.cpp 完整重写,加入命令行解析器 【其他】 - .gitignore 排除 NSIS 输出 (.exe)
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -12,3 +12,8 @@ VoiletCStudio
|
||||
.idea/
|
||||
*.user
|
||||
*.pro.user
|
||||
|
||||
# Installer output
|
||||
*.exe
|
||||
VoiletCStudio-Setup-*.exe
|
||||
installer/build/
|
||||
|
||||
92
installer/install.sh
Normal file
92
installer/install.sh
Normal file
@@ -0,0 +1,92 @@
|
||||
#!/bin/bash
|
||||
# =====================================================
|
||||
# VoiletCStudio Linux 安装脚本
|
||||
# 用法: sudo bash installer/install.sh
|
||||
# =====================================================
|
||||
|
||||
set -e
|
||||
|
||||
APP_NAME="VoiletCStudio"
|
||||
VERSION="1.2"
|
||||
INSTALL_DIR="/opt/${APP_NAME}"
|
||||
BIN_DIR="/usr/local/bin"
|
||||
DESKTOP_DIR="/usr/share/applications"
|
||||
MIME_DIR="/usr/share/mime/packages"
|
||||
ICON_DIR="/usr/share/icons/hicolor/256x256/apps"
|
||||
|
||||
echo "========================================="
|
||||
echo " VoiletCStudio v${VERSION} - Linux 安装程序"
|
||||
echo "========================================="
|
||||
|
||||
# 检查 root
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "请使用 sudo 运行: sudo bash installer/install.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "[1/5] 编译程序..."
|
||||
mkdir -p build && cd build
|
||||
qmake ../VoiletCStudio.pro && make -j$(nproc)
|
||||
cd ..
|
||||
|
||||
echo ""
|
||||
echo "[2/5] 安装到 ${INSTALL_DIR}..."
|
||||
mkdir -p "${INSTALL_DIR}"
|
||||
cp build/VoiletCStudio "${INSTALL_DIR}/"
|
||||
chmod +x "${INSTALL_DIR}/VoiletCStudio"
|
||||
|
||||
# 创建命令行软链接
|
||||
ln -sf "${INSTALL_DIR}/VoiletCStudio" "${BIN_DIR}/voiletcstudio"
|
||||
|
||||
echo ""
|
||||
echo "[3/5] 安装图标..."
|
||||
mkdir -p "${ICON_DIR}"
|
||||
cp resources/voiletcstudio.png "${ICON_DIR}/voiletcstudio.png"
|
||||
|
||||
echo ""
|
||||
echo "[4/5] 注册 MIME 类型和 .desktop..."
|
||||
mkdir -p "${MIME_DIR}"
|
||||
cat > "${MIME_DIR}/voiletcstudio.xml" << 'MIMEXML'
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
|
||||
<mime-type type="application/x-voiletcstudio">
|
||||
<comment>VoiletCStudio Project</comment>
|
||||
<comment xml:lang="zh_CN">VoiletCStudio 工程文件</comment>
|
||||
<glob pattern="*.VSC"/>
|
||||
<glob pattern="*.vsc"/>
|
||||
</mime-type>
|
||||
</mime-info>
|
||||
MIMEXML
|
||||
|
||||
mkdir -p "${DESKTOP_DIR}"
|
||||
cat > "${DESKTOP_DIR}/voiletcstudio.desktop" << DESKTOPEOF
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=VoiletCStudio
|
||||
Name[zh_CN]=紫罗兰 C 工程配置器
|
||||
Comment=C Project Configurator with CMake
|
||||
Comment[zh_CN]=C 语言工程配置器,自动生成 CMakeLists.txt
|
||||
Exec=${INSTALL_DIR}/VoiletCStudio %f
|
||||
Icon=voiletcstudio
|
||||
MimeType=application/x-voiletcstudio;
|
||||
Categories=Development;IDE;
|
||||
Terminal=false
|
||||
DESKTOPEOF
|
||||
|
||||
echo ""
|
||||
echo "[5/5] 更新系统数据库..."
|
||||
update-mime-database /usr/share/mime
|
||||
update-desktop-database
|
||||
gtk-update-icon-cache /usr/share/icons/hicolor 2>/dev/null || true
|
||||
|
||||
echo ""
|
||||
echo "========================================="
|
||||
echo " ✅ VoiletCStudio 安装完成!"
|
||||
echo "========================================="
|
||||
echo ""
|
||||
echo " 命令行: voiletcstudio"
|
||||
echo " 或双击 .VSC 工程文件自动打开"
|
||||
echo ""
|
||||
echo " 卸载: sudo bash installer/uninstall.sh"
|
||||
echo ""
|
||||
25
installer/uninstall.sh
Normal file
25
installer/uninstall.sh
Normal file
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
# =====================================================
|
||||
# VoiletCStudio Linux 卸载脚本
|
||||
# =====================================================
|
||||
set -e
|
||||
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "请使用 sudo 运行"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
APP_NAME="VoiletCStudio"
|
||||
|
||||
echo "正在卸载 ${APP_NAME}..."
|
||||
|
||||
rm -rf "/opt/${APP_NAME}"
|
||||
rm -f "/usr/local/bin/voiletcstudio"
|
||||
rm -f "/usr/share/applications/voiletcstudio.desktop"
|
||||
rm -f "/usr/share/mime/packages/voiletcstudio.xml"
|
||||
rm -f "/usr/share/icons/hicolor/256x256/apps/voiletcstudio.png"
|
||||
|
||||
update-mime-database /usr/share/mime 2>/dev/null || true
|
||||
update-desktop-database 2>/dev/null || true
|
||||
|
||||
echo "✅ ${APP_NAME} 已卸载"
|
||||
85
installer/voiletcstudio.nsi
Normal file
85
installer/voiletcstudio.nsi
Normal file
@@ -0,0 +1,85 @@
|
||||
; =====================================================
|
||||
; VoiletCStudio Windows 安装脚本 (NSIS)
|
||||
; 用法: makensis installer/voiletcstudio.nsi
|
||||
; =====================================================
|
||||
|
||||
!define PRODUCT_NAME "VoiletCStudio"
|
||||
!define PRODUCT_VERSION "1.2"
|
||||
!define PRODUCT_PUBLISHER "LinuxAcme"
|
||||
!define PRODUCT_EXE "VoiletCStudio.exe"
|
||||
|
||||
Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
|
||||
OutFile "VoiletCStudio-Setup-${PRODUCT_VERSION}.exe"
|
||||
InstallDir "$PROGRAMFILES\${PRODUCT_NAME}"
|
||||
RequestExecutionLevel admin
|
||||
|
||||
; ----- 安装页面 -----
|
||||
Page directory
|
||||
Page instfiles
|
||||
|
||||
; ----- 默认安装路径 -----
|
||||
Section "Install"
|
||||
SetOutPath "$INSTDIR"
|
||||
|
||||
; 复制主程序
|
||||
File "VoiletCStudio.exe"
|
||||
|
||||
; 复制 Qt 运行时 DLL(需要提前准备好)
|
||||
; File /r "Qt5Core.dll"
|
||||
; File /r "Qt5Gui.dll"
|
||||
; File /r "Qt5Widgets.dll"
|
||||
|
||||
; 复制 MinGW 运行时
|
||||
; File /r "libgcc_s_seh-1.dll"
|
||||
; File /r "libstdc++-6.dll"
|
||||
; File /r "libwinpthread-1.dll"
|
||||
|
||||
; 创建卸载程序
|
||||
WriteUninstaller "$INSTDIR\uninstall.exe"
|
||||
|
||||
; 注册 .VSC 文件关联
|
||||
WriteRegStr HKCR ".VSC" "" "VoiletCStudio.VSC"
|
||||
WriteRegStr HKCR "VoiletCStudio.VSC" "" "VoiletCStudio 工程文件"
|
||||
WriteRegStr HKCR "VoiletCStudio.VSC\DefaultIcon" "" "$INSTDIR\${PRODUCT_EXE},0"
|
||||
WriteRegStr HKCR "VoiletCStudio.VSC\shell\open\command" "" '"$INSTDIR\${PRODUCT_EXE}" "%1"'
|
||||
|
||||
; 注册表卸载信息
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "DisplayName" "${PRODUCT_NAME}"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "UninstallString" "$INSTDIR\uninstall.exe"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "DisplayVersion" "${PRODUCT_VERSION}"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "Publisher" "${PRODUCT_PUBLISHER}"
|
||||
|
||||
; 开始菜单快捷方式
|
||||
CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}"
|
||||
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\VoiletCStudio.lnk" "$INSTDIR\${PRODUCT_EXE}"
|
||||
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\卸载.lnk" "$INSTDIR\uninstall.exe"
|
||||
|
||||
; 桌面快捷方式
|
||||
CreateShortCut "$DESKTOP\VoiletCStudio.lnk" "$INSTDIR\${PRODUCT_EXE}"
|
||||
|
||||
; 通知系统刷新文件关联
|
||||
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
|
||||
SectionEnd
|
||||
|
||||
; ----- 卸载 -----
|
||||
Section "Uninstall"
|
||||
; 删除程序
|
||||
Delete "$INSTDIR\${PRODUCT_EXE}"
|
||||
Delete "$INSTDIR\uninstall.exe"
|
||||
RMDir "$INSTDIR"
|
||||
|
||||
; 删除文件关联
|
||||
DeleteRegKey HKCR ".VSC"
|
||||
DeleteRegKey HKCR "VoiletCStudio.VSC"
|
||||
|
||||
; 删除注册表
|
||||
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
|
||||
|
||||
; 删除快捷方式
|
||||
Delete "$SMPROGRAMS\${PRODUCT_NAME}\VoiletCStudio.lnk"
|
||||
Delete "$SMPROGRAMS\${PRODUCT_NAME}\卸载.lnk"
|
||||
RMDir "$SMPROGRAMS\${PRODUCT_NAME}"
|
||||
Delete "$DESKTOP\VoiletCStudio.lnk"
|
||||
|
||||
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
|
||||
SectionEnd
|
||||
@@ -4,7 +4,8 @@ Name=VoiletCStudio
|
||||
Name[zh_CN]=紫罗兰 C 工程配置器
|
||||
Comment=C Project Configurator with CMake
|
||||
Comment[zh_CN]=C 语言工程配置器,自动生成 CMakeLists.txt
|
||||
Exec=VoiletCStudio
|
||||
Exec=VoiletCStudio %f
|
||||
Icon=voiletcstudio
|
||||
MimeType=application/x-voiletcstudio;
|
||||
Categories=Development;IDE;
|
||||
Terminal=false
|
||||
|
||||
156
src/main.cpp
156
src/main.cpp
@@ -1,8 +1,125 @@
|
||||
#include <QApplication>
|
||||
#include <QStyleFactory>
|
||||
#include <QIcon>
|
||||
#include <QCommandLineParser>
|
||||
#include <QSettings>
|
||||
#include <QMessageBox>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QProcess>
|
||||
#include <QStandardPaths>
|
||||
#include <QDebug>
|
||||
#include "mainwindow.h"
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
#endif
|
||||
|
||||
// ===== 文件关联注册 =====
|
||||
static void registerFileAssociation()
|
||||
{
|
||||
#ifdef Q_OS_WIN32
|
||||
QString appPath = QCoreApplication::applicationFilePath();
|
||||
appPath.replace("/", "\\");
|
||||
|
||||
// 注册 .VSC 扩展名
|
||||
QSettings settings("HKEY_CLASSES_ROOT\\.VSC", QSettings::NativeFormat);
|
||||
settings.setValue("Default", "VoiletCStudio.VSC");
|
||||
settings.sync();
|
||||
|
||||
// 注册文件类型描述
|
||||
QSettings typeSettings("HKEY_CLASSES_ROOT\\VoiletCStudio.VSC", QSettings::NativeFormat);
|
||||
typeSettings.setValue("Default", "VoiletCStudio 工程文件");
|
||||
typeSettings.sync();
|
||||
|
||||
// 注册图标
|
||||
QSettings iconSettings("HKEY_CLASSES_ROOT\\VoiletCStudio.VSC\\DefaultIcon", QSettings::NativeFormat);
|
||||
iconSettings.setValue("Default", appPath + ",0");
|
||||
iconSettings.sync();
|
||||
|
||||
// 注册打开命令
|
||||
QSettings cmdSettings("HKEY_CLASSES_ROOT\\VoiletCStudio.VSC\\shell\\open\\command", QSettings::NativeFormat);
|
||||
cmdSettings.setValue("Default", "\"" + appPath + "\" \"%1\"");
|
||||
cmdSettings.sync();
|
||||
|
||||
// 通知系统刷新
|
||||
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);
|
||||
|
||||
qDebug() << "[OK] .VSC file association registered on Windows";
|
||||
#else
|
||||
// Linux: 写入 MIME 类型定义 + 更新 desktop 数据库
|
||||
QString mimeDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/mime/packages";
|
||||
QDir().mkpath(mimeDir);
|
||||
|
||||
QString mimeFile = mimeDir + "/voiletcstudio.xml";
|
||||
QFile f(mimeFile);
|
||||
if (f.open(QIODevice::WriteOnly)) {
|
||||
f.write(R"(<?xml version="1.0" encoding="UTF-8"?>
|
||||
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
|
||||
<mime-type type="application/x-voiletcstudio">
|
||||
<comment>VoiletCStudio Project</comment>
|
||||
<comment xml:lang="zh_CN">VoiletCStudio 工程文件</comment>
|
||||
<glob pattern="*.VSC"/>
|
||||
<glob pattern="*.vsc"/>
|
||||
</mime-type>
|
||||
</mime-info>
|
||||
)");
|
||||
f.close();
|
||||
}
|
||||
|
||||
// 写入 .desktop 文件
|
||||
QString appsDir = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
|
||||
QDir().mkpath(appsDir);
|
||||
|
||||
QString desktopFile = appsDir + "/voiletcstudio.desktop";
|
||||
QFile df(desktopFile);
|
||||
if (df.open(QIODevice::WriteOnly)) {
|
||||
df.write(R"([Desktop Entry]
|
||||
Type=Application
|
||||
Name=VoiletCStudio
|
||||
Name[zh_CN]=紫罗兰 C 工程配置器
|
||||
Comment=C Project Configurator
|
||||
Comment[zh_CN]=C 语言工程配置器
|
||||
Exec=)" + QCoreApplication::applicationFilePath().toUtf8() + R"( %f
|
||||
Icon=voiletcstudio
|
||||
MimeType=application/x-voiletcstudio;
|
||||
Categories=Development;IDE;
|
||||
Terminal=false
|
||||
)");
|
||||
df.close();
|
||||
}
|
||||
|
||||
// 更新 MIME 数据库
|
||||
QProcess::execute("update-mime-database", QStringList() <<
|
||||
QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/mime");
|
||||
QProcess::execute("update-desktop-database", QStringList());
|
||||
|
||||
qDebug() << "[OK] .VSC file association registered on Linux";
|
||||
#endif
|
||||
}
|
||||
|
||||
static void unregisterFileAssociation()
|
||||
{
|
||||
#ifdef Q_OS_WIN32
|
||||
QSettings settings("HKEY_CLASSES_ROOT\\.VSC", QSettings::NativeFormat);
|
||||
settings.remove("Default");
|
||||
settings.sync();
|
||||
|
||||
QSettings("HKEY_CLASSES_ROOT\\VoiletCStudio.VSC", QSettings::NativeFormat).remove("");
|
||||
SHDeleteKey(HKEY_CLASSES_ROOT, L"VoiletCStudio.VSC");
|
||||
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);
|
||||
|
||||
qDebug() << "[OK] .VSC file association removed";
|
||||
#else
|
||||
QString mimeFile = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/mime/packages/voiletcstudio.xml";
|
||||
QFile::remove(mimeFile);
|
||||
QProcess::execute("update-mime-database", QStringList() <<
|
||||
QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/mime");
|
||||
qDebug() << "[OK] .VSC file association removed";
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
@@ -12,14 +129,49 @@ int main(int argc, char *argv[])
|
||||
|
||||
// 设置应用程序信息
|
||||
app.setApplicationName("VoiletCStudio");
|
||||
app.setApplicationVersion("1.1");
|
||||
app.setApplicationVersion("1.2");
|
||||
app.setOrganizationName("LinuxAcme");
|
||||
|
||||
// 设置样式(使用系统原生样式)
|
||||
// 命令行参数解析
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription("紫罗兰 C 工程配置器 - 自动生成 CMakeLists.txt");
|
||||
parser.addHelpOption();
|
||||
parser.addVersionOption();
|
||||
|
||||
QCommandLineOption registerOpt("register", "注册 .VSC 文件关联到系统");
|
||||
QCommandLineOption unregisterOpt("unregister", "取消 .VSC 文件关联");
|
||||
parser.addOption(registerOpt);
|
||||
parser.addOption(unregisterOpt);
|
||||
|
||||
// 接受 .VSC 文件作为位置参数(双击打开)
|
||||
parser.addPositionalArgument("file", "要打开的 .VSC 工程文件");
|
||||
|
||||
parser.process(app);
|
||||
|
||||
// 处理注册/取消注册
|
||||
if (parser.isSet(registerOpt)) {
|
||||
registerFileAssociation();
|
||||
return 0;
|
||||
}
|
||||
if (parser.isSet(unregisterOpt)) {
|
||||
unregisterFileAssociation();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 设置样式
|
||||
app.setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
MainWindow window;
|
||||
window.show();
|
||||
|
||||
// 通过命令行传入的文件自动打开
|
||||
QStringList posArgs = parser.positionalArguments();
|
||||
if (!posArgs.isEmpty()) {
|
||||
QString filePath = posArgs.first();
|
||||
if (filePath.endsWith(".VSC", Qt::CaseInsensitive) || filePath.endsWith(".json", Qt::CaseInsensitive)) {
|
||||
window.openProjectFile(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "mainwindow.h"
|
||||
#include <QApplication>
|
||||
#include <QFile>
|
||||
#include <QMenuBar>
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
@@ -18,9 +19,6 @@
|
||||
#include <QProcess>
|
||||
#include <QDir>
|
||||
#include <QScrollBar>
|
||||
#include <QDragEnterEvent>
|
||||
#include <QDragMoveEvent>
|
||||
#include <QDropEvent>
|
||||
#include <QMimeData>
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
@@ -31,9 +29,6 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
config = new ProjectConfig(this);
|
||||
cmakeGenerator = new CMakeGenerator(this);
|
||||
|
||||
// ★ 启用拖拽
|
||||
setAcceptDrops(true);
|
||||
|
||||
setupUI();
|
||||
setupConnections();
|
||||
updateWindowTitle();
|
||||
@@ -109,7 +104,7 @@ void MainWindow::setupUI()
|
||||
basicLayout->addWidget(projectNameEdit);
|
||||
|
||||
basicLayout->addStretch();
|
||||
basicLayout->addWidget(new QLabel("📂 工程路径:同 JSON 配置文件所在目录"));
|
||||
basicLayout->addWidget(new QLabel("📂 工程路径:同 VSC 工程文件所在目录"));
|
||||
|
||||
mainLayout->addWidget(basicGroup);
|
||||
|
||||
@@ -280,22 +275,6 @@ void MainWindow::setupUI()
|
||||
|
||||
// 状态栏
|
||||
statusBar()->showMessage("就绪");
|
||||
|
||||
// ★ 禁用子控件的拖拽,让所有拖拽事件由 MainWindow 统一处理
|
||||
sourceTree->setAcceptDrops(false);
|
||||
sourceTree->viewport()->setAcceptDrops(false);
|
||||
includeDirList->setAcceptDrops(false);
|
||||
includeDirList->viewport()->setAcceptDrops(false);
|
||||
libraryList->setAcceptDrops(false);
|
||||
libraryList->viewport()->setAcceptDrops(false);
|
||||
defineList->setAcceptDrops(false);
|
||||
defineList->viewport()->setAcceptDrops(false);
|
||||
optionList->setAcceptDrops(false);
|
||||
optionList->viewport()->setAcceptDrops(false);
|
||||
projectNameEdit->setAcceptDrops(false);
|
||||
compilerPathEdit->setAcceptDrops(false);
|
||||
assemblerPathEdit->setAcceptDrops(false);
|
||||
linkerPathEdit->setAcceptDrops(false);
|
||||
}
|
||||
|
||||
void MainWindow::setupConnections()
|
||||
@@ -361,99 +340,6 @@ bool MainWindow::maybeSave()
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
if (event->mimeData()->hasUrls()) {
|
||||
QList<QUrl> urls = event->mimeData()->urls();
|
||||
if (!urls.isEmpty()) {
|
||||
QString file = urls.first().toLocalFile();
|
||||
if (file.endsWith(".json", Qt::CaseInsensitive)) {
|
||||
event->acceptProposedAction();
|
||||
statusBar()->showMessage("📂 释放鼠标打开工程:" + file, 3000);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
void MainWindow::dragMoveEvent(QDragMoveEvent *event)
|
||||
{
|
||||
// 拖拽移动时也要接受,否则 Qt 不会触发 dropEvent
|
||||
if (event->mimeData()->hasUrls()) {
|
||||
QList<QUrl> urls = event->mimeData()->urls();
|
||||
if (!urls.isEmpty()) {
|
||||
QString file = urls.first().toLocalFile();
|
||||
if (file.endsWith(".json", Qt::CaseInsensitive)) {
|
||||
event->acceptProposedAction();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
void MainWindow::dropEvent(QDropEvent *event)
|
||||
{
|
||||
if (event->mimeData()->hasUrls()) {
|
||||
QList<QUrl> urls = event->mimeData()->urls();
|
||||
if (!urls.isEmpty()) {
|
||||
QString file = urls.first().toLocalFile();
|
||||
if (file.endsWith(".json", Qt::CaseInsensitive)) {
|
||||
if (!maybeSave()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (config->loadConfig(file)) {
|
||||
currentFilePath = file;
|
||||
modified = false;
|
||||
|
||||
// 更新 UI
|
||||
projectNameEdit->setText(config->getProjectName());
|
||||
compilerPathEdit->setText(config->getCompilerPath());
|
||||
assemblerPathEdit->setText(config->getAssemblerPath());
|
||||
linkerPathEdit->setText(config->getLinkerPath());
|
||||
|
||||
// 更新虚拟目录树
|
||||
sourceTree->clear();
|
||||
QMap<QString, VirtualDir> dirs = config->getVirtualDirs();
|
||||
for (auto it = dirs.begin(); it != dirs.end(); ++it) {
|
||||
QTreeWidgetItem *dirItem = new QTreeWidgetItem(sourceTree);
|
||||
dirItem->setText(0, "📁 " + it.key());
|
||||
for (const QString &f : it->files) {
|
||||
QTreeWidgetItem *fileItem = new QTreeWidgetItem(dirItem);
|
||||
fileItem->setText(0, "📄 " + QFileInfo(f).fileName());
|
||||
fileItem->setToolTip(0, f);
|
||||
}
|
||||
}
|
||||
sourceTree->expandAll();
|
||||
|
||||
// 更新包含目录
|
||||
includeDirList->clear();
|
||||
includeDirList->addItems(config->getIncludeDirs());
|
||||
|
||||
// 更新库文件
|
||||
libraryList->clear();
|
||||
libraryList->addItems(config->getLibraries());
|
||||
|
||||
// 更新编译宏
|
||||
defineList->clear();
|
||||
defineList->addItems(config->getDefines());
|
||||
|
||||
// 更新编译选项
|
||||
optionList->clear();
|
||||
optionList->addItems(config->getCompilerOptions());
|
||||
|
||||
updateWindowTitle();
|
||||
statusBar()->showMessage("✅ 工程已加载:" + file, 5000);
|
||||
} else {
|
||||
QMessageBox::critical(this, "错误", "无法加载工程文件:" + file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::newProject()
|
||||
{
|
||||
if (!maybeSave()) {
|
||||
@@ -485,7 +371,7 @@ void MainWindow::openProject()
|
||||
}
|
||||
|
||||
QString filePath = QFileDialog::getOpenFileName(this, "打开工程", "",
|
||||
"JSON 配置文件 (*.json);;所有文件 (*)");
|
||||
"VSC 工程文件 (*.VSC);;所有文件 (*)");
|
||||
|
||||
if (filePath.isEmpty()) {
|
||||
return;
|
||||
@@ -530,6 +416,54 @@ void MainWindow::openProject()
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::openProjectFile(const QString &filePath)
|
||||
{
|
||||
// 直接打开指定文件(用于命令行和双击打开),跳过 maybeSave
|
||||
if (!QFile::exists(filePath)) {
|
||||
QMessageBox::critical(this, "错误", "文件不存在:" + filePath);
|
||||
return;
|
||||
}
|
||||
|
||||
if (config->loadConfig(filePath)) {
|
||||
currentFilePath = filePath;
|
||||
modified = false;
|
||||
|
||||
projectNameEdit->setText(config->getProjectName());
|
||||
compilerPathEdit->setText(config->getCompilerPath());
|
||||
assemblerPathEdit->setText(config->getAssemblerPath());
|
||||
linkerPathEdit->setText(config->getLinkerPath());
|
||||
|
||||
sourceTree->clear();
|
||||
QMap<QString, VirtualDir> dirs = config->getVirtualDirs();
|
||||
for (auto it = dirs.begin(); it != dirs.end(); ++it) {
|
||||
QTreeWidgetItem *dirItem = new QTreeWidgetItem(sourceTree);
|
||||
dirItem->setText(0, it.key());
|
||||
for (const QString &file : it->files) {
|
||||
QTreeWidgetItem *fileItem = new QTreeWidgetItem(dirItem);
|
||||
fileItem->setText(0, file);
|
||||
}
|
||||
}
|
||||
sourceTree->expandAll();
|
||||
|
||||
includeDirList->clear();
|
||||
includeDirList->addItems(config->getIncludeDirs());
|
||||
|
||||
libraryList->clear();
|
||||
libraryList->addItems(config->getLibraries());
|
||||
|
||||
defineList->clear();
|
||||
defineList->addItems(config->getDefines());
|
||||
|
||||
optionList->clear();
|
||||
optionList->addItems(config->getCompilerOptions());
|
||||
|
||||
updateWindowTitle();
|
||||
statusBar()->showMessage("✅ 工程已加载:" + filePath, 5000);
|
||||
} else {
|
||||
QMessageBox::critical(this, "错误", "无法加载工程文件:" + filePath);
|
||||
}
|
||||
}
|
||||
|
||||
bool MainWindow::saveProject()
|
||||
{
|
||||
if (currentFilePath.isEmpty()) {
|
||||
@@ -555,7 +489,7 @@ bool MainWindow::saveProject()
|
||||
bool MainWindow::saveProjectAs()
|
||||
{
|
||||
QString filePath = QFileDialog::getSaveFileName(this, "保存工程", "",
|
||||
"JSON 配置文件 (*.json);;所有文件 (*)");
|
||||
"VSC 工程文件 (*.VSC);;所有文件 (*)");
|
||||
|
||||
if (filePath.isEmpty()) {
|
||||
return false;
|
||||
@@ -572,7 +506,7 @@ void MainWindow::generateCMake()
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取工程目录(JSON 配置文件所在目录)
|
||||
// 获取工程目录(VSC 工程文件所在目录)
|
||||
QString projectDir = QFileInfo(currentFilePath).absolutePath();
|
||||
QString buildDir = projectDir + "/build";
|
||||
QString cmakePath = projectDir + "/CMakeLists.txt";
|
||||
|
||||
@@ -20,6 +20,9 @@ public:
|
||||
MainWindow(QWidget *parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
// 通过命令行/双击打开工程文件
|
||||
void openProjectFile(const QString &filePath);
|
||||
|
||||
private slots:
|
||||
// 文件操作
|
||||
void newProject();
|
||||
@@ -67,11 +70,6 @@ private slots:
|
||||
void browseAssemblerPath();
|
||||
void browseLinkerPath();
|
||||
|
||||
protected:
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
void dragMoveEvent(QDragMoveEvent *event) override;
|
||||
void dropEvent(QDropEvent *event) override;
|
||||
|
||||
private:
|
||||
void setupUI();
|
||||
void setupConnections();
|
||||
|
||||
Reference in New Issue
Block a user