From 0da645594fbb0e8cd0b791e0901e9311d20d9b16 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Thu, 27 Mar 2025 01:20:07 +0800 Subject: [PATCH 01/16] Adjust instance view sorting mode to QComboBox and add renaming behavior Signed-off-by: Yihe Li --- launcher/Application.cpp | 2 + launcher/ui/pages/global/LauncherPage.cpp | 48 +++++++++++++++--- launcher/ui/pages/global/LauncherPage.ui | 62 ++++++++++++++++------- 3 files changed, 86 insertions(+), 26 deletions(-) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index c3477d331..816f7b8ab 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -709,7 +709,9 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) m_settings->registerSetting("ToolbarsLocked", false); + // Instance m_settings->registerSetting("InstSortMode", "Name"); + m_settings->registerSetting("InstRenamingMode", "AskEverytime"); m_settings->registerSetting("SelectedInstance", QString()); // Window state and geometry diff --git a/launcher/ui/pages/global/LauncherPage.cpp b/launcher/ui/pages/global/LauncherPage.cpp index 04ee01b00..fab1bfe38 100644 --- a/launcher/ui/pages/global/LauncherPage.cpp +++ b/launcher/ui/pages/global/LauncherPage.cpp @@ -65,13 +65,19 @@ enum InstSortMode { Sort_LastLaunch }; +enum InstRenamingMode { + // Rename metadata only. + Rename_Metadata, + // Rename physical directory too. + Rename_Physical, + // Ask everytime. + Rename_Ask +}; + LauncherPage::LauncherPage(QWidget* parent) : QWidget(parent), ui(new Ui::LauncherPage) { ui->setupUi(this); - ui->sortingModeGroup->setId(ui->sortByNameBtn, Sort_Name); - ui->sortingModeGroup->setId(ui->sortLastLaunchedBtn, Sort_LastLaunch); - defaultFormat = new QTextCharFormat(ui->fontPreview->currentCharFormat()); m_languageModel = APPLICATION->translations(); @@ -234,7 +240,8 @@ void LauncherPage::applySettings() s->set("DownloadsDirWatchRecursive", ui->downloadsDirWatchRecursiveCheckBox->isChecked()); s->set("MoveModsFromDownloadsDir", ui->downloadsDirMoveCheckBox->isChecked()); - auto sortMode = (InstSortMode)ui->sortingModeGroup->checkedId(); + // Instance + auto sortMode = (InstSortMode) ui->viewSortingComboBox->currentIndex(); switch (sortMode) { case Sort_LastLaunch: s->set("InstSortMode", "LastLaunch"); @@ -245,6 +252,20 @@ void LauncherPage::applySettings() break; } + auto renamingMode = (InstRenamingMode) ui->renamingBehaviorComboBox->currentIndex(); + switch (renamingMode) { + case Rename_Metadata: + s->set("InstRenamingMode", "MetadataOnly"); + break; + case Rename_Physical: + s->set("InstRenamingMode", "PhysicalDir"); + break; + case Rename_Ask: + default: + s->set("InstRenamingMode", "AskEverytime"); + break; + } + // Cat s->set("CatOpacity", ui->catOpacitySpinBox->value()); @@ -299,13 +320,26 @@ void LauncherPage::loadSettings() ui->downloadsDirWatchRecursiveCheckBox->setChecked(s->get("DownloadsDirWatchRecursive").toBool()); ui->downloadsDirMoveCheckBox->setChecked(s->get("MoveModsFromDownloadsDir").toBool()); + // Instance QString sortMode = s->get("InstSortMode").toString(); - + InstSortMode sortModeEnum; if (sortMode == "LastLaunch") { - ui->sortLastLaunchedBtn->setChecked(true); + sortModeEnum = Sort_LastLaunch; } else { - ui->sortByNameBtn->setChecked(true); + sortModeEnum = Sort_Name; } + ui->viewSortingComboBox->setCurrentIndex(sortModeEnum); + + QString renamingMode = s->get("InstRenamingMode").toString(); + InstRenamingMode renamingModeEnum; + if (renamingMode == "MetadataOnly") { + renamingModeEnum = Rename_Metadata; + } else if (renamingMode == "PhysicalDir"){ + renamingModeEnum = Rename_Physical; + } else { + renamingModeEnum = Rename_Ask; + } + ui->renamingBehaviorComboBox->setCurrentIndex(renamingModeEnum); // Cat ui->catOpacitySpinBox->setValue(s->get("CatOpacity").toInt()); diff --git a/launcher/ui/pages/global/LauncherPage.ui b/launcher/ui/pages/global/LauncherPage.ui index 31c878f3e..01aad7af7 100644 --- a/launcher/ui/pages/global/LauncherPage.ui +++ b/launcher/ui/pages/global/LauncherPage.ui @@ -401,32 +401,59 @@ - + true - Instance view sorting mode + Instance - - - + + + - &By last launched + Instance view sorting mode - - sortingModeGroup - - - + + + + + By last launched + + + + + By name + + + + + + - By &name + Instance renaming behavior - - sortingModeGroup - + + + + + + + Rename metadata only + + + + + Rename physical directory + + + + + Ask everytime + + @@ -674,7 +701,7 @@ numberOfConcurrentDownloadsSpinBox numberOfManualRetriesSpinBox timeoutSecondsSpinBox - sortLastLaunchedBtn + sortLastLaunchedComboBox sortByNameBtn catOpacitySpinBox preferMenuBarCheckBox @@ -686,7 +713,4 @@ - - - \ No newline at end of file From 4b20e3bc3985c6de37120a462d32c8fa33e41fa2 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Thu, 27 Mar 2025 03:10:25 +0800 Subject: [PATCH 02/16] Implement instance renaming Signed-off-by: Yihe Li --- launcher/InstanceList.cpp | 7 ++- launcher/InstanceList.h | 1 + launcher/ui/MainWindow.cpp | 63 +++++++++++++++++++++++ launcher/ui/MainWindow.h | 2 + launcher/ui/pages/global/LauncherPage.cpp | 6 +-- launcher/ui/pages/global/LauncherPage.ui | 2 - 6 files changed, 75 insertions(+), 6 deletions(-) diff --git a/launcher/InstanceList.cpp b/launcher/InstanceList.cpp index 918fa1073..a9e86cd7f 100644 --- a/launcher/InstanceList.cpp +++ b/launcher/InstanceList.cpp @@ -149,6 +149,11 @@ QStringList InstanceList::getLinkedInstancesById(const QString& id) const return linkedInstances; } +QString InstanceList::getInstanceRootById(const InstanceId& id) const +{ + return FS::PathCombine(m_instDir, id); +} + int InstanceList::rowCount(const QModelIndex& parent) const { Q_UNUSED(parent); @@ -627,7 +632,7 @@ InstancePtr InstanceList::loadInstance(const InstanceId& id) loadGroupList(); } - auto instanceRoot = FS::PathCombine(m_instDir, id); + auto instanceRoot = getInstanceRootById(id); auto instanceSettings = std::make_shared(FS::PathCombine(instanceRoot, "instance.cfg")); InstancePtr inst; diff --git a/launcher/InstanceList.h b/launcher/InstanceList.h index c85fe55c7..b04a289d2 100644 --- a/launcher/InstanceList.h +++ b/launcher/InstanceList.h @@ -152,6 +152,7 @@ class InstanceList : public QAbstractListModel { QMimeData* mimeData(const QModelIndexList& indexes) const override; QStringList getLinkedInstancesById(const QString& id) const; + QString getInstanceRootById(const InstanceId& id) const; signals: void dataIsInvalid(); diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index a9473ac15..f413ac05d 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -564,6 +565,67 @@ void MainWindow::showInstanceContextMenu(const QPoint& pos) myMenu.exec(view->mapToGlobal(pos)); } +void MainWindow::updateInstanceRoot() +{ + QString renamingMode = APPLICATION->settings()->get("InstRenamingMode").toString(); + if (renamingMode == "MetadataOnly") + return; + + auto oldRoot = m_selectedInstance->instanceRoot(); + auto newID = m_selectedInstance->name(); + auto newRoot = APPLICATION->instances()->getInstanceRootById(newID); + if (oldRoot == newRoot) + return; + + // Check for conflict + if (QDir(newRoot).exists()) { + QMessageBox::warning(this, tr("Cannot rename instance"), + tr("New instance root (%1) already exists.
Only the metadata will be renamed.").arg(newRoot)); + return; + } + + // Ask if we should rename + if (renamingMode == "AskEverytime") { + QMessageBox messageBox(this); + messageBox.setText(tr("Do you want to also rename the instance\'s physical directory?")); + messageBox.setInformativeText(tr("The following renaming operation will be performed:
" + " - Old instance root: %1
" + " - New instance root: %2") + .arg(oldRoot, newRoot)); + messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + messageBox.setDefaultButton(QMessageBox::Yes); + messageBox.setIcon(QMessageBox::Question); + + auto checkBox = new QCheckBox(tr("&Remember my choice"), this); + checkBox->setChecked(true); + messageBox.setCheckBox(checkBox); + + auto res = messageBox.exec(); + if (checkBox->isChecked()) { + if (res == QMessageBox::Yes) + APPLICATION->settings()->set("InstRenamingMode", "PhysicalDir"); + else + APPLICATION->settings()->set("InstRenamingMode", "MetadataOnly"); + } + if (res == QMessageBox::No) + return; + } + + // Now we can confirm that a renaming is happening + auto ret = QFile::rename(oldRoot, newRoot); + if (!ret) { + QMessageBox::warning(this, tr("Cannot rename instance"), + tr("An error occurred when performing the following renaming operation:
" + " - Old instance root: %1
" + " - New instance root: %2
" + "Only the metadata is renamed.") + .arg(oldRoot, newRoot)); + return; + } + refreshInstances(); + setSelectedInstanceById(newID); +} + void MainWindow::updateMainToolBar() { ui->menuBar->setVisible(APPLICATION->settings()->get("MenuBarInsteadOfToolBar").toBool()); @@ -1703,6 +1765,7 @@ void MainWindow::instanceDataChanged(const QModelIndex& topLeft, const QModelInd QItemSelection test(topLeft, bottomRight); if (test.contains(current)) { instanceChanged(current, current); + updateInstanceRoot(); } } diff --git a/launcher/ui/MainWindow.h b/launcher/ui/MainWindow.h index 0e692eda7..9ac1d39e0 100644 --- a/launcher/ui/MainWindow.h +++ b/launcher/ui/MainWindow.h @@ -176,6 +176,8 @@ class MainWindow : public QMainWindow { void showInstanceContextMenu(const QPoint&); + void updateInstanceRoot(); + void updateMainToolBar(); void updateLaunchButton(); diff --git a/launcher/ui/pages/global/LauncherPage.cpp b/launcher/ui/pages/global/LauncherPage.cpp index fab1bfe38..db37d548a 100644 --- a/launcher/ui/pages/global/LauncherPage.cpp +++ b/launcher/ui/pages/global/LauncherPage.cpp @@ -241,7 +241,7 @@ void LauncherPage::applySettings() s->set("MoveModsFromDownloadsDir", ui->downloadsDirMoveCheckBox->isChecked()); // Instance - auto sortMode = (InstSortMode) ui->viewSortingComboBox->currentIndex(); + auto sortMode = (InstSortMode)ui->viewSortingComboBox->currentIndex(); switch (sortMode) { case Sort_LastLaunch: s->set("InstSortMode", "LastLaunch"); @@ -252,7 +252,7 @@ void LauncherPage::applySettings() break; } - auto renamingMode = (InstRenamingMode) ui->renamingBehaviorComboBox->currentIndex(); + auto renamingMode = (InstRenamingMode)ui->renamingBehaviorComboBox->currentIndex(); switch (renamingMode) { case Rename_Metadata: s->set("InstRenamingMode", "MetadataOnly"); @@ -334,7 +334,7 @@ void LauncherPage::loadSettings() InstRenamingMode renamingModeEnum; if (renamingMode == "MetadataOnly") { renamingModeEnum = Rename_Metadata; - } else if (renamingMode == "PhysicalDir"){ + } else if (renamingMode == "PhysicalDir") { renamingModeEnum = Rename_Physical; } else { renamingModeEnum = Rename_Ask; diff --git a/launcher/ui/pages/global/LauncherPage.ui b/launcher/ui/pages/global/LauncherPage.ui index 01aad7af7..c1ba1d428 100644 --- a/launcher/ui/pages/global/LauncherPage.ui +++ b/launcher/ui/pages/global/LauncherPage.ui @@ -701,8 +701,6 @@ numberOfConcurrentDownloadsSpinBox numberOfManualRetriesSpinBox timeoutSecondsSpinBox - sortLastLaunchedComboBox - sortByNameBtn catOpacitySpinBox preferMenuBarCheckBox lineLimitSpinBox From abac3db125ee462b117a378a84130a8a20476921 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Thu, 27 Mar 2025 04:11:29 +0800 Subject: [PATCH 03/16] Make remember checkbox off by default Signed-off-by: Yihe Li --- launcher/ui/MainWindow.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index f413ac05d..0e6deacee 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -597,7 +597,6 @@ void MainWindow::updateInstanceRoot() messageBox.setIcon(QMessageBox::Question); auto checkBox = new QCheckBox(tr("&Remember my choice"), this); - checkBox->setChecked(true); messageBox.setCheckBox(checkBox); auto res = messageBox.exec(); From 7ea5b6173c14a269eb544de00661f38d3c6a8c33 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Thu, 27 Mar 2025 04:51:13 +0800 Subject: [PATCH 04/16] Refactor updateInstanceRoot() to BaseInstance Signed-off-by: Yihe Li --- launcher/BaseInstance.cpp | 60 ++++++++++++++++++++++++++++++++++ launcher/BaseInstance.h | 3 ++ launcher/InstanceList.cpp | 7 +--- launcher/InstanceList.h | 1 - launcher/ui/MainWindow.cpp | 66 +++----------------------------------- launcher/ui/MainWindow.h | 2 -- 6 files changed, 69 insertions(+), 70 deletions(-) diff --git a/launcher/BaseInstance.cpp b/launcher/BaseInstance.cpp index ccfd0b847..886075624 100644 --- a/launcher/BaseInstance.cpp +++ b/launcher/BaseInstance.cpp @@ -37,11 +37,13 @@ #include "BaseInstance.h" +#include #include #include #include #include #include +#include #include #include "settings/INISettingsObject.h" @@ -327,6 +329,64 @@ QString BaseInstance::instanceRoot() const return m_rootDir; } +bool BaseInstance::updateInstanceRoot(QWidget* parent) +{ + QString renamingMode = globalSettings()->get("InstRenamingMode").toString(); + if (renamingMode == "MetadataOnly") + return false; + + auto oldRoot = instanceRoot(); + auto newRoot = FS::PathCombine(QFileInfo(oldRoot).dir().absolutePath(), name()); + if (oldRoot == newRoot) + return false; + + // Check for conflict + if (QDir(newRoot).exists()) { + QMessageBox::warning(parent, tr("Cannot rename instance"), + tr("New instance root (%1) already exists.
Only the metadata will be renamed.").arg(newRoot)); + return false; + } + + // Ask if we should rename + if (renamingMode == "AskEverytime") { + QMessageBox messageBox(parent); + messageBox.setText(tr("Do you want to also rename the instance\'s physical directory?")); + messageBox.setInformativeText(tr("The following renaming operation will be performed:
" + " - Old instance root: %1
" + " - New instance root: %2") + .arg(oldRoot, newRoot)); + messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + messageBox.setDefaultButton(QMessageBox::Yes); + messageBox.setIcon(QMessageBox::Question); + + auto checkBox = new QCheckBox(tr("&Remember my choice"), parent); + messageBox.setCheckBox(checkBox); + + auto res = messageBox.exec(); + if (checkBox->isChecked()) { + if (res == QMessageBox::Yes) + globalSettings()->set("InstRenamingMode", "PhysicalDir"); + else + globalSettings()->set("InstRenamingMode", "MetadataOnly"); + } + if (res == QMessageBox::No) + return false; + } + + // Now we can confirm that a renaming is happening + auto ret = QFile::rename(oldRoot, newRoot); + if (!ret) { + QMessageBox::warning(parent, tr("Cannot rename instance"), + tr("An error occurred when performing the following renaming operation:
" + " - Old instance root: %1
" + " - New instance root: %2
" + "Only the metadata is renamed.") + .arg(oldRoot, newRoot)); + return false; + } + return true; +} + SettingsObjectPtr BaseInstance::settings() { loadSpecificSettings(); diff --git a/launcher/BaseInstance.h b/launcher/BaseInstance.h index 9827a08b4..8efb9e9d8 100644 --- a/launcher/BaseInstance.h +++ b/launcher/BaseInstance.h @@ -117,6 +117,9 @@ class BaseInstance : public QObject, public std::enable_shared_from_this(FS::PathCombine(instanceRoot, "instance.cfg")); InstancePtr inst; diff --git a/launcher/InstanceList.h b/launcher/InstanceList.h index b04a289d2..c85fe55c7 100644 --- a/launcher/InstanceList.h +++ b/launcher/InstanceList.h @@ -152,7 +152,6 @@ class InstanceList : public QAbstractListModel { QMimeData* mimeData(const QModelIndexList& indexes) const override; QStringList getLinkedInstancesById(const QString& id) const; - QString getInstanceRootById(const InstanceId& id) const; signals: void dataIsInvalid(); diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index 0e6deacee..17e5a0bc9 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -565,66 +565,6 @@ void MainWindow::showInstanceContextMenu(const QPoint& pos) myMenu.exec(view->mapToGlobal(pos)); } -void MainWindow::updateInstanceRoot() -{ - QString renamingMode = APPLICATION->settings()->get("InstRenamingMode").toString(); - if (renamingMode == "MetadataOnly") - return; - - auto oldRoot = m_selectedInstance->instanceRoot(); - auto newID = m_selectedInstance->name(); - auto newRoot = APPLICATION->instances()->getInstanceRootById(newID); - if (oldRoot == newRoot) - return; - - // Check for conflict - if (QDir(newRoot).exists()) { - QMessageBox::warning(this, tr("Cannot rename instance"), - tr("New instance root (%1) already exists.
Only the metadata will be renamed.").arg(newRoot)); - return; - } - - // Ask if we should rename - if (renamingMode == "AskEverytime") { - QMessageBox messageBox(this); - messageBox.setText(tr("Do you want to also rename the instance\'s physical directory?")); - messageBox.setInformativeText(tr("The following renaming operation will be performed:
" - " - Old instance root: %1
" - " - New instance root: %2") - .arg(oldRoot, newRoot)); - messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); - messageBox.setDefaultButton(QMessageBox::Yes); - messageBox.setIcon(QMessageBox::Question); - - auto checkBox = new QCheckBox(tr("&Remember my choice"), this); - messageBox.setCheckBox(checkBox); - - auto res = messageBox.exec(); - if (checkBox->isChecked()) { - if (res == QMessageBox::Yes) - APPLICATION->settings()->set("InstRenamingMode", "PhysicalDir"); - else - APPLICATION->settings()->set("InstRenamingMode", "MetadataOnly"); - } - if (res == QMessageBox::No) - return; - } - - // Now we can confirm that a renaming is happening - auto ret = QFile::rename(oldRoot, newRoot); - if (!ret) { - QMessageBox::warning(this, tr("Cannot rename instance"), - tr("An error occurred when performing the following renaming operation:
" - " - Old instance root: %1
" - " - New instance root: %2
" - "Only the metadata is renamed.") - .arg(oldRoot, newRoot)); - return; - } - refreshInstances(); - setSelectedInstanceById(newID); -} - void MainWindow::updateMainToolBar() { ui->menuBar->setVisible(APPLICATION->settings()->get("MenuBarInsteadOfToolBar").toBool()); @@ -1764,7 +1704,11 @@ void MainWindow::instanceDataChanged(const QModelIndex& topLeft, const QModelInd QItemSelection test(topLeft, bottomRight); if (test.contains(current)) { instanceChanged(current, current); - updateInstanceRoot(); + if (m_selectedInstance && m_selectedInstance->updateInstanceRoot(this)) { + auto newID = m_selectedInstance->name(); + refreshInstances(); + setSelectedInstanceById(newID); + } } } diff --git a/launcher/ui/MainWindow.h b/launcher/ui/MainWindow.h index 9ac1d39e0..0e692eda7 100644 --- a/launcher/ui/MainWindow.h +++ b/launcher/ui/MainWindow.h @@ -176,8 +176,6 @@ class MainWindow : public QMainWindow { void showInstanceContextMenu(const QPoint&); - void updateInstanceRoot(); - void updateMainToolBar(); void updateLaunchButton(); From b550a6c5c488ca441199f1be16e492302267805e Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Thu, 27 Mar 2025 05:20:58 +0800 Subject: [PATCH 05/16] Revert the radio button changes Signed-off-by: Yihe Li --- launcher/BaseInstance.cpp | 8 +- launcher/ui/pages/global/LauncherPage.cpp | 27 +- launcher/ui/pages/global/LauncherPage.ui | 287 +++++++++++----------- 3 files changed, 166 insertions(+), 156 deletions(-) diff --git a/launcher/BaseInstance.cpp b/launcher/BaseInstance.cpp index 886075624..92353da10 100644 --- a/launcher/BaseInstance.cpp +++ b/launcher/BaseInstance.cpp @@ -336,6 +336,7 @@ bool BaseInstance::updateInstanceRoot(QWidget* parent) return false; auto oldRoot = instanceRoot(); + auto oldName = QFileInfo(oldRoot).baseName(); auto newRoot = FS::PathCombine(QFileInfo(oldRoot).dir().absolutePath(), name()); if (oldRoot == newRoot) return false; @@ -350,11 +351,8 @@ bool BaseInstance::updateInstanceRoot(QWidget* parent) // Ask if we should rename if (renamingMode == "AskEverytime") { QMessageBox messageBox(parent); - messageBox.setText(tr("Do you want to also rename the instance\'s physical directory?")); - messageBox.setInformativeText(tr("The following renaming operation will be performed:
" - " - Old instance root: %1
" - " - New instance root: %2") - .arg(oldRoot, newRoot)); + messageBox.setText(tr("Would you also like to rename the instance folder?")); + messageBox.setInformativeText(tr("Renaming \'%1\' -> \'%2\'").arg(oldName, name())); messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); messageBox.setDefaultButton(QMessageBox::Yes); messageBox.setIcon(QMessageBox::Question); diff --git a/launcher/ui/pages/global/LauncherPage.cpp b/launcher/ui/pages/global/LauncherPage.cpp index db37d548a..d89a65a85 100644 --- a/launcher/ui/pages/global/LauncherPage.cpp +++ b/launcher/ui/pages/global/LauncherPage.cpp @@ -67,17 +67,20 @@ enum InstSortMode { enum InstRenamingMode { // Rename metadata only. - Rename_Metadata, - // Rename physical directory too. - Rename_Physical, + Rename_Always, // Ask everytime. - Rename_Ask + Rename_Ask, + // Rename physical directory too. + Rename_Never }; LauncherPage::LauncherPage(QWidget* parent) : QWidget(parent), ui(new Ui::LauncherPage) { ui->setupUi(this); + ui->sortingModeGroup->setId(ui->sortByNameBtn, Sort_Name); + ui->sortingModeGroup->setId(ui->sortLastLaunchedBtn, Sort_LastLaunch); + defaultFormat = new QTextCharFormat(ui->fontPreview->currentCharFormat()); m_languageModel = APPLICATION->translations(); @@ -241,7 +244,7 @@ void LauncherPage::applySettings() s->set("MoveModsFromDownloadsDir", ui->downloadsDirMoveCheckBox->isChecked()); // Instance - auto sortMode = (InstSortMode)ui->viewSortingComboBox->currentIndex(); + auto sortMode = (InstSortMode)ui->sortingModeGroup->checkedId(); switch (sortMode) { case Sort_LastLaunch: s->set("InstSortMode", "LastLaunch"); @@ -254,10 +257,10 @@ void LauncherPage::applySettings() auto renamingMode = (InstRenamingMode)ui->renamingBehaviorComboBox->currentIndex(); switch (renamingMode) { - case Rename_Metadata: + case Rename_Always: s->set("InstRenamingMode", "MetadataOnly"); break; - case Rename_Physical: + case Rename_Never: s->set("InstRenamingMode", "PhysicalDir"); break; case Rename_Ask: @@ -322,20 +325,18 @@ void LauncherPage::loadSettings() // Instance QString sortMode = s->get("InstSortMode").toString(); - InstSortMode sortModeEnum; if (sortMode == "LastLaunch") { - sortModeEnum = Sort_LastLaunch; + ui->sortLastLaunchedBtn->setChecked(true); } else { - sortModeEnum = Sort_Name; + ui->sortByNameBtn->setChecked(true); } - ui->viewSortingComboBox->setCurrentIndex(sortModeEnum); QString renamingMode = s->get("InstRenamingMode").toString(); InstRenamingMode renamingModeEnum; if (renamingMode == "MetadataOnly") { - renamingModeEnum = Rename_Metadata; + renamingModeEnum = Rename_Always; } else if (renamingMode == "PhysicalDir") { - renamingModeEnum = Rename_Physical; + renamingModeEnum = Rename_Never; } else { renamingModeEnum = Rename_Ask; } diff --git a/launcher/ui/pages/global/LauncherPage.ui b/launcher/ui/pages/global/LauncherPage.ui index c1ba1d428..7942f4f4f 100644 --- a/launcher/ui/pages/global/LauncherPage.ui +++ b/launcher/ui/pages/global/LauncherPage.ui @@ -112,40 +112,76 @@ Folders - - + + - &Downloads: + I&nstances: - downloadsDirTextBox + instDirTextBox - - + + + + + Browse - - - - - - - - + + + - &Skins: - - - skinsDirTextBox + Rename instance folders + + + + + Never + + + + + Ask + + + + + Always + + + + + + + + &Mods: + + + modsDirTextBox + + + + + + + + + + Browse + + + + + &Icons: @@ -155,7 +191,81 @@ - + + + + + + + Browse + + + + + + + + &Java: + + + javaDirTextBox + + + + + + + + + + Browse + + + + + + + + &Skins: + + + skinsDirTextBox + + + + + + + + + + Browse + + + + + + + + &Downloads: + + + downloadsDirTextBox + + + + + + + + + + Browse + + + + + @@ -179,83 +289,6 @@ - - - - - - - &Java: - - - javaDirTextBox - - - - - - - &Mods: - - - modsDirTextBox - - - - - - - - - - - - - - - - Browse - - - - - - - Browse - - - - - - - Browse - - - - - - - I&nstances: - - - instDirTextBox - - - - - - - Browse - - - - - - - Browse - - -
@@ -401,59 +434,32 @@ - + true - Instance + Instance view sorting mode - - - + + + - Instance view sorting mode + &By last launched + + sortingModeGroup + - - - - - By last launched - - - - - By name - - - - - - + + - Instance renaming behavior + By &name - - - - - - - Rename metadata only - - - - - Rename physical directory - - - - - Ask everytime - - + + sortingModeGroup + @@ -701,6 +707,8 @@ numberOfConcurrentDownloadsSpinBox numberOfManualRetriesSpinBox timeoutSecondsSpinBox + sortLastLaunchedBtn + sortByNameBtn catOpacitySpinBox preferMenuBarCheckBox lineLimitSpinBox @@ -711,4 +719,7 @@ + + + \ No newline at end of file From 7b511f4c676392c077c9ae4b90de36464f0221a9 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Thu, 27 Mar 2025 05:47:29 +0800 Subject: [PATCH 06/16] Refactor into InstanceDirUpdate.h Signed-off-by: Yihe Li --- launcher/BaseInstance.cpp | 56 ------------------- launcher/BaseInstance.h | 3 -- launcher/CMakeLists.txt | 2 + launcher/InstanceDirUpdate.cpp | 99 ++++++++++++++++++++++++++++++++++ launcher/InstanceDirUpdate.h | 43 +++++++++++++++ launcher/ui/MainWindow.cpp | 3 +- 6 files changed, 146 insertions(+), 60 deletions(-) create mode 100644 launcher/InstanceDirUpdate.cpp create mode 100644 launcher/InstanceDirUpdate.h diff --git a/launcher/BaseInstance.cpp b/launcher/BaseInstance.cpp index 92353da10..0087b44f0 100644 --- a/launcher/BaseInstance.cpp +++ b/launcher/BaseInstance.cpp @@ -329,62 +329,6 @@ QString BaseInstance::instanceRoot() const return m_rootDir; } -bool BaseInstance::updateInstanceRoot(QWidget* parent) -{ - QString renamingMode = globalSettings()->get("InstRenamingMode").toString(); - if (renamingMode == "MetadataOnly") - return false; - - auto oldRoot = instanceRoot(); - auto oldName = QFileInfo(oldRoot).baseName(); - auto newRoot = FS::PathCombine(QFileInfo(oldRoot).dir().absolutePath(), name()); - if (oldRoot == newRoot) - return false; - - // Check for conflict - if (QDir(newRoot).exists()) { - QMessageBox::warning(parent, tr("Cannot rename instance"), - tr("New instance root (%1) already exists.
Only the metadata will be renamed.").arg(newRoot)); - return false; - } - - // Ask if we should rename - if (renamingMode == "AskEverytime") { - QMessageBox messageBox(parent); - messageBox.setText(tr("Would you also like to rename the instance folder?")); - messageBox.setInformativeText(tr("Renaming \'%1\' -> \'%2\'").arg(oldName, name())); - messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); - messageBox.setDefaultButton(QMessageBox::Yes); - messageBox.setIcon(QMessageBox::Question); - - auto checkBox = new QCheckBox(tr("&Remember my choice"), parent); - messageBox.setCheckBox(checkBox); - - auto res = messageBox.exec(); - if (checkBox->isChecked()) { - if (res == QMessageBox::Yes) - globalSettings()->set("InstRenamingMode", "PhysicalDir"); - else - globalSettings()->set("InstRenamingMode", "MetadataOnly"); - } - if (res == QMessageBox::No) - return false; - } - - // Now we can confirm that a renaming is happening - auto ret = QFile::rename(oldRoot, newRoot); - if (!ret) { - QMessageBox::warning(parent, tr("Cannot rename instance"), - tr("An error occurred when performing the following renaming operation:
" - " - Old instance root: %1
" - " - New instance root: %2
" - "Only the metadata is renamed.") - .arg(oldRoot, newRoot)); - return false; - } - return true; -} - SettingsObjectPtr BaseInstance::settings() { loadSpecificSettings(); diff --git a/launcher/BaseInstance.h b/launcher/BaseInstance.h index 8efb9e9d8..9827a08b4 100644 --- a/launcher/BaseInstance.h +++ b/launcher/BaseInstance.h @@ -117,9 +117,6 @@ class BaseInstance : public QObject, public std::enable_shared_from_this + * Copyright (c) 2022 Jamie Mansfield + * Copyright (C) 2023 TheKodeToad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "InstanceDirUpdate.h" + +#include +#include + +#include "FileSystem.h" + +bool askToUpdateInstanceDirName(SettingsObjectPtr globalSettings, InstancePtr instance, QWidget* parent) +{ + QString renamingMode = globalSettings->get("InstRenamingMode").toString(); + if (renamingMode == "MetadataOnly") + return false; + + auto oldRoot = instance->instanceRoot(); + auto oldName = QFileInfo(oldRoot).baseName(); + auto newRoot = FS::PathCombine(QFileInfo(oldRoot).dir().absolutePath(), instance->name()); + if (oldRoot == newRoot) + return false; + + // Check for conflict + if (QDir(newRoot).exists()) { + QMessageBox::warning(parent, QObject::tr("Cannot rename instance"), + QObject::tr("New instance root (%1) already exists.
Only the metadata will be renamed.").arg(newRoot)); + return false; + } + + // Ask if we should rename + if (renamingMode == "AskEverytime") { + QMessageBox messageBox(parent); + messageBox.setText(QObject::tr("Would you also like to rename the instance folder?")); + messageBox.setInformativeText(QObject::tr("Renaming \'%1\' -> \'%2\'").arg(oldName, instance->name())); + messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + messageBox.setDefaultButton(QMessageBox::Yes); + messageBox.setIcon(QMessageBox::Question); + + auto checkBox = new QCheckBox(QObject::tr("&Remember my choice"), parent); + messageBox.setCheckBox(checkBox); + + auto res = messageBox.exec(); + if (checkBox->isChecked()) { + if (res == QMessageBox::Yes) + globalSettings->set("InstRenamingMode", "PhysicalDir"); + else + globalSettings->set("InstRenamingMode", "MetadataOnly"); + } + if (res == QMessageBox::No) + return false; + } + + // Now we can confirm that a renaming is happening + auto ret = QFile::rename(oldRoot, newRoot); + if (!ret) { + QMessageBox::warning(parent, QObject::tr("Cannot rename instance"), + QObject::tr("An error occurred when performing the following renaming operation:
" + " - Old instance root: %1
" + " - New instance root: %2
" + "Only the metadata is renamed.") + .arg(oldRoot, newRoot)); + return false; + } + return true; +} diff --git a/launcher/InstanceDirUpdate.h b/launcher/InstanceDirUpdate.h new file mode 100644 index 000000000..fc0931779 --- /dev/null +++ b/launcher/InstanceDirUpdate.h @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 Sefa Eyeoglu + * Copyright (c) 2022 Jamie Mansfield + * Copyright (C) 2023 TheKodeToad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "BaseInstance.h" + +/// Update instanceRoot to make it sync with name/id; return true if a refresh is needed +bool askToUpdateInstanceDirName(SettingsObjectPtr globalSettings, InstancePtr instance, QWidget* parent); diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index 17e5a0bc9..23cd6f8c8 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -124,6 +124,7 @@ #include "KonamiCode.h" #include "InstanceCopyTask.h" +#include "InstanceDirUpdate.h" #include "Json.h" @@ -1704,7 +1705,7 @@ void MainWindow::instanceDataChanged(const QModelIndex& topLeft, const QModelInd QItemSelection test(topLeft, bottomRight); if (test.contains(current)) { instanceChanged(current, current); - if (m_selectedInstance && m_selectedInstance->updateInstanceRoot(this)) { + if (m_selectedInstance && askToUpdateInstanceDirName(APPLICATION->settings(), m_selectedInstance, this)) { auto newID = m_selectedInstance->name(); refreshInstances(); setSelectedInstanceById(newID); From ea44c2465c30ad048df7047007059d668edd6cfb Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Thu, 27 Mar 2025 05:47:47 +0800 Subject: [PATCH 07/16] Add link instance detection Signed-off-by: Yihe Li --- launcher/InstanceDirUpdate.cpp | 41 ++++++++++++++++++++++++++++------ launcher/InstanceDirUpdate.h | 5 ++++- launcher/ui/MainWindow.cpp | 18 +++------------ 3 files changed, 41 insertions(+), 23 deletions(-) diff --git a/launcher/InstanceDirUpdate.cpp b/launcher/InstanceDirUpdate.cpp index f24adb642..0b61ddb88 100644 --- a/launcher/InstanceDirUpdate.cpp +++ b/launcher/InstanceDirUpdate.cpp @@ -40,11 +40,15 @@ #include #include +#include "Application.h" #include "FileSystem.h" -bool askToUpdateInstanceDirName(SettingsObjectPtr globalSettings, InstancePtr instance, QWidget* parent) +#include "InstanceList.h" +#include "ui/dialogs/CustomMessageBox.h" + +bool askToUpdateInstanceDirName(InstancePtr instance, QWidget* parent) { - QString renamingMode = globalSettings->get("InstRenamingMode").toString(); + QString renamingMode = APPLICATION->settings()->get("InstRenamingMode").toString(); if (renamingMode == "MetadataOnly") return false; @@ -76,24 +80,47 @@ bool askToUpdateInstanceDirName(SettingsObjectPtr globalSettings, InstancePtr in auto res = messageBox.exec(); if (checkBox->isChecked()) { if (res == QMessageBox::Yes) - globalSettings->set("InstRenamingMode", "PhysicalDir"); + APPLICATION->settings()->set("InstRenamingMode", "PhysicalDir"); else - globalSettings->set("InstRenamingMode", "MetadataOnly"); + APPLICATION->settings()->set("InstRenamingMode", "MetadataOnly"); } if (res == QMessageBox::No) return false; } + // Check for linked instances + if (!checkLinkedInstances(instance->id(), parent)) + return false; + // Now we can confirm that a renaming is happening auto ret = QFile::rename(oldRoot, newRoot); if (!ret) { QMessageBox::warning(parent, QObject::tr("Cannot rename instance"), QObject::tr("An error occurred when performing the following renaming operation:
" - " - Old instance root: %1
" - " - New instance root: %2
" - "Only the metadata is renamed.") + " - Old instance root: %1
" + " - New instance root: %2
" + "Only the metadata is renamed.") .arg(oldRoot, newRoot)); return false; } return true; } + +bool checkLinkedInstances(const QString& id, QWidget* parent) +{ + auto linkedInstances = APPLICATION->instances()->getLinkedInstancesById(id); + if (!linkedInstances.empty()) { + auto response = CustomMessageBox::selectable(parent, QObject::tr("There are linked instances"), + QObject::tr("The following instance(s) might reference files in this instance:\n\n" + "%1\n\n" + "Deleting it could break the other instance(s), \n\n" + "Do you wish to proceed?", + nullptr, linkedInstances.count()) + .arg(linkedInstances.join("\n")), + QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No) + ->exec(); + if (response != QMessageBox::Yes) + return false; + } + return true; +} diff --git a/launcher/InstanceDirUpdate.h b/launcher/InstanceDirUpdate.h index fc0931779..0059d8b7b 100644 --- a/launcher/InstanceDirUpdate.h +++ b/launcher/InstanceDirUpdate.h @@ -40,4 +40,7 @@ #include "BaseInstance.h" /// Update instanceRoot to make it sync with name/id; return true if a refresh is needed -bool askToUpdateInstanceDirName(SettingsObjectPtr globalSettings, InstancePtr instance, QWidget* parent); +bool askToUpdateInstanceDirName(InstancePtr instance, QWidget* parent); + +/// Check if there are linked instances, and display a warning; return true if the operation should proceed +bool checkLinkedInstances(const QString& id, QWidget* parent); diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index 23cd6f8c8..d5a2b477d 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -1379,20 +1379,8 @@ void MainWindow::on_actionDeleteInstance_triggered() if (response != QMessageBox::Yes) return; - auto linkedInstances = APPLICATION->instances()->getLinkedInstancesById(id); - if (!linkedInstances.empty()) { - response = CustomMessageBox::selectable(this, tr("There are linked instances"), - tr("The following instance(s) might reference files in this instance:\n\n" - "%1\n\n" - "Deleting it could break the other instance(s), \n\n" - "Do you wish to proceed?", - nullptr, linkedInstances.count()) - .arg(linkedInstances.join("\n")), - QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No) - ->exec(); - if (response != QMessageBox::Yes) - return; - } + if (!checkLinkedInstances(id, this)) + return; if (APPLICATION->instances()->trashInstance(id)) { ui->actionUndoTrashInstance->setEnabled(APPLICATION->instances()->trashedSomething()); @@ -1705,7 +1693,7 @@ void MainWindow::instanceDataChanged(const QModelIndex& topLeft, const QModelInd QItemSelection test(topLeft, bottomRight); if (test.contains(current)) { instanceChanged(current, current); - if (m_selectedInstance && askToUpdateInstanceDirName(APPLICATION->settings(), m_selectedInstance, this)) { + if (m_selectedInstance && askToUpdateInstanceDirName(m_selectedInstance, this)) { auto newID = m_selectedInstance->name(); refreshInstances(); setSelectedInstanceById(newID); From 8fea37b8b73f09d35d73e54f059d62dd7b6883ae Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Thu, 27 Mar 2025 06:53:57 +0800 Subject: [PATCH 08/16] Only call on interactive uses Signed-off-by: Yihe Li --- launcher/BaseInstance.cpp | 11 +++++++++++ launcher/BaseInstance.h | 3 +++ launcher/InstanceDirUpdate.cpp | 3 +-- launcher/ui/MainWindow.cpp | 12 +++++++----- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/launcher/BaseInstance.cpp b/launcher/BaseInstance.cpp index 0087b44f0..5ffbb809b 100644 --- a/launcher/BaseInstance.cpp +++ b/launcher/BaseInstance.cpp @@ -388,6 +388,17 @@ void BaseInstance::setName(QString val) emit propertiesChanged(this); } +bool BaseInstance::syncInstanceDirName() const +{ + auto oldRoot = instanceRoot(); + auto newRoot = FS::PathCombine(QFileInfo(oldRoot).dir().absolutePath(), name()); + if (oldRoot == newRoot) + return true; + if (!QFile::rename(oldRoot, newRoot)) + return false; + return true; +} + QString BaseInstance::name() const { return m_settings->get("name").toString(); diff --git a/launcher/BaseInstance.h b/launcher/BaseInstance.h index 9827a08b4..b19f1fd27 100644 --- a/launcher/BaseInstance.h +++ b/launcher/BaseInstance.h @@ -126,6 +126,9 @@ class BaseInstance : public QObject, public std::enable_shared_from_thissyncInstanceDirName()) { QMessageBox::warning(parent, QObject::tr("Cannot rename instance"), QObject::tr("An error occurred when performing the following renaming operation:
" " - Old instance root: %1
" diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index d5a2b477d..f357b0765 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -1428,6 +1428,13 @@ void MainWindow::on_actionExportInstanceFlamePack_triggered() void MainWindow::on_actionRenameInstance_triggered() { if (m_selectedInstance) { + connect(view->itemDelegate(), &QAbstractItemDelegate::closeEditor, this, [this] { + if (askToUpdateInstanceDirName(m_selectedInstance, this)) { + auto newID = m_selectedInstance->name(); + refreshInstances(); + setSelectedInstanceById(newID); + } + }, Qt::SingleShotConnection); view->edit(view->currentIndex()); } } @@ -1693,11 +1700,6 @@ void MainWindow::instanceDataChanged(const QModelIndex& topLeft, const QModelInd QItemSelection test(topLeft, bottomRight); if (test.contains(current)) { instanceChanged(current, current); - if (m_selectedInstance && askToUpdateInstanceDirName(m_selectedInstance, this)) { - auto newID = m_selectedInstance->name(); - refreshInstances(); - setSelectedInstanceById(newID); - } } } From 294448a01e07f44e0df99f67541f2a18e24069ac Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Thu, 27 Mar 2025 06:54:10 +0800 Subject: [PATCH 09/16] Filter out invalid chars Signed-off-by: Yihe Li --- launcher/BaseInstance.cpp | 3 +-- launcher/BaseInstance.h | 2 +- launcher/InstanceDirUpdate.cpp | 7 ++++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/launcher/BaseInstance.cpp b/launcher/BaseInstance.cpp index 5ffbb809b..92d41521b 100644 --- a/launcher/BaseInstance.cpp +++ b/launcher/BaseInstance.cpp @@ -388,10 +388,9 @@ void BaseInstance::setName(QString val) emit propertiesChanged(this); } -bool BaseInstance::syncInstanceDirName() const +bool BaseInstance::syncInstanceDirName(const QString& newRoot) const { auto oldRoot = instanceRoot(); - auto newRoot = FS::PathCombine(QFileInfo(oldRoot).dir().absolutePath(), name()); if (oldRoot == newRoot) return true; if (!QFile::rename(oldRoot, newRoot)) diff --git a/launcher/BaseInstance.h b/launcher/BaseInstance.h index b19f1fd27..2a2b4dc4a 100644 --- a/launcher/BaseInstance.h +++ b/launcher/BaseInstance.h @@ -127,7 +127,7 @@ class BaseInstance : public QObject, public std::enable_shared_from_thisinstanceRoot(); auto oldName = QFileInfo(oldRoot).baseName(); - auto newRoot = FS::PathCombine(QFileInfo(oldRoot).dir().absolutePath(), instance->name()); + auto newName = FS::DirNameFromString(instance->name(), QFileInfo(oldRoot).dir().absolutePath()); + auto newRoot = FS::PathCombine(QFileInfo(oldRoot).dir().absolutePath(), newName); if (oldRoot == newRoot) return false; @@ -69,7 +70,7 @@ bool askToUpdateInstanceDirName(InstancePtr instance, QWidget* parent) if (renamingMode == "AskEverytime") { QMessageBox messageBox(parent); messageBox.setText(QObject::tr("Would you also like to rename the instance folder?")); - messageBox.setInformativeText(QObject::tr("Renaming \'%1\' -> \'%2\'").arg(oldName, instance->name())); + messageBox.setInformativeText(QObject::tr("Renaming \'%1\' -> \'%2\'").arg(oldName, newName)); messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); messageBox.setDefaultButton(QMessageBox::Yes); messageBox.setIcon(QMessageBox::Question); @@ -93,7 +94,7 @@ bool askToUpdateInstanceDirName(InstancePtr instance, QWidget* parent) return false; // Now we can confirm that a renaming is happening - if (!instance->syncInstanceDirName()) { + if (!instance->syncInstanceDirName(newRoot)) { QMessageBox::warning(parent, QObject::tr("Cannot rename instance"), QObject::tr("An error occurred when performing the following renaming operation:
" " - Old instance root: %1
" From a7af120cf0635f048e5df18e6ca6c1e853071825 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Thu, 27 Mar 2025 07:22:05 +0800 Subject: [PATCH 10/16] Fix interaction with invalid chars Signed-off-by: Yihe Li --- launcher/InstanceDirUpdate.cpp | 19 +++++++++++-------- launcher/InstanceDirUpdate.h | 4 ++-- launcher/InstanceList.cpp | 17 +++++++++++++++++ launcher/InstanceList.h | 2 ++ launcher/ui/MainWindow.cpp | 25 ++++++++++++++++++------- launcher/ui/MainWindow.h | 1 + 6 files changed, 51 insertions(+), 17 deletions(-) diff --git a/launcher/InstanceDirUpdate.cpp b/launcher/InstanceDirUpdate.cpp index a6ca6ca23..8064082fd 100644 --- a/launcher/InstanceDirUpdate.cpp +++ b/launcher/InstanceDirUpdate.cpp @@ -46,24 +46,27 @@ #include "InstanceList.h" #include "ui/dialogs/CustomMessageBox.h" -bool askToUpdateInstanceDirName(InstancePtr instance, QWidget* parent) +QString askToUpdateInstanceDirName(InstancePtr instance, QWidget* parent) { QString renamingMode = APPLICATION->settings()->get("InstRenamingMode").toString(); if (renamingMode == "MetadataOnly") - return false; + return QString(); auto oldRoot = instance->instanceRoot(); auto oldName = QFileInfo(oldRoot).baseName(); + if (oldName == FS::RemoveInvalidFilenameChars(instance->name(), '-')) + return QString(); + auto newName = FS::DirNameFromString(instance->name(), QFileInfo(oldRoot).dir().absolutePath()); auto newRoot = FS::PathCombine(QFileInfo(oldRoot).dir().absolutePath(), newName); if (oldRoot == newRoot) - return false; + return QString(); // Check for conflict if (QDir(newRoot).exists()) { QMessageBox::warning(parent, QObject::tr("Cannot rename instance"), QObject::tr("New instance root (%1) already exists.
Only the metadata will be renamed.").arg(newRoot)); - return false; + return QString(); } // Ask if we should rename @@ -86,12 +89,12 @@ bool askToUpdateInstanceDirName(InstancePtr instance, QWidget* parent) APPLICATION->settings()->set("InstRenamingMode", "MetadataOnly"); } if (res == QMessageBox::No) - return false; + return QString(); } // Check for linked instances if (!checkLinkedInstances(instance->id(), parent)) - return false; + return QString(); // Now we can confirm that a renaming is happening if (!instance->syncInstanceDirName(newRoot)) { @@ -101,9 +104,9 @@ bool askToUpdateInstanceDirName(InstancePtr instance, QWidget* parent) " - New instance root: %2
" "Only the metadata is renamed.") .arg(oldRoot, newRoot)); - return false; + return QString(); } - return true; + return newRoot; } bool checkLinkedInstances(const QString& id, QWidget* parent) diff --git a/launcher/InstanceDirUpdate.h b/launcher/InstanceDirUpdate.h index 0059d8b7b..23738a19a 100644 --- a/launcher/InstanceDirUpdate.h +++ b/launcher/InstanceDirUpdate.h @@ -39,8 +39,8 @@ #include "BaseInstance.h" -/// Update instanceRoot to make it sync with name/id; return true if a refresh is needed -bool askToUpdateInstanceDirName(InstancePtr instance, QWidget* parent); +/// Update instanceRoot to make it sync with name/id; return newRoot if a directory rename happened +QString askToUpdateInstanceDirName(InstancePtr instance, QWidget* parent); /// Check if there are linked instances, and display a warning; return true if the operation should proceed bool checkLinkedInstances(const QString& id, QWidget* parent); diff --git a/launcher/InstanceList.cpp b/launcher/InstanceList.cpp index 918fa1073..a4f694e2e 100644 --- a/launcher/InstanceList.cpp +++ b/launcher/InstanceList.cpp @@ -583,6 +583,18 @@ InstancePtr InstanceList::getInstanceById(QString instId) const return InstancePtr(); } +InstancePtr InstanceList::getInstanceByRoot(QString instanceRoot) const +{ + if (instanceRoot.isEmpty()) + return InstancePtr(); + for (auto& inst : m_instances) { + if (inst->instanceRoot() == instanceRoot) { + return inst; + } + } + return InstancePtr(); +} + InstancePtr InstanceList::getInstanceByManagedName(const QString& managed_name) const { if (managed_name.isEmpty()) @@ -601,6 +613,11 @@ QModelIndex InstanceList::getInstanceIndexById(const QString& id) const return index(getInstIndex(getInstanceById(id).get())); } +QModelIndex InstanceList::getInstanceIndexByRoot(const QString& instanceRoot) const +{ + return index(getInstIndex(getInstanceByRoot(instanceRoot).get())); +} + int InstanceList::getInstIndex(BaseInstance* inst) const { int count = m_instances.count(); diff --git a/launcher/InstanceList.h b/launcher/InstanceList.h index c85fe55c7..dace9e5cf 100644 --- a/launcher/InstanceList.h +++ b/launcher/InstanceList.h @@ -99,9 +99,11 @@ class InstanceList : public QAbstractListModel { /* O(n) */ InstancePtr getInstanceById(QString id) const; + InstancePtr getInstanceByRoot(QString instanceRoot) const; /* O(n) */ InstancePtr getInstanceByManagedName(const QString& managed_name) const; QModelIndex getInstanceIndexById(const QString& id) const; + QModelIndex getInstanceIndexByRoot(const QString& instanceRoot) const; QStringList getGroups(); bool isGroupCollapsed(const QString& groupName); diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index f357b0765..43fe5c067 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -294,6 +294,12 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWi view->setFrameShape(QFrame::NoFrame); // do not show ugly blue border on the mac view->setAttribute(Qt::WA_MacShowFocusRect, false); + connect(view->itemDelegate(), &QAbstractItemDelegate::closeEditor, this, [this] { + if (auto newRoot = askToUpdateInstanceDirName(m_selectedInstance, this); !newRoot.isEmpty()) { + refreshInstances(); + setSelectedInstanceByRoot(newRoot); + } + }); view->installEventFilter(this); view->setContextMenuPolicy(Qt::CustomContextMenu); @@ -1133,6 +1139,18 @@ void MainWindow::setSelectedInstanceById(const QString& id) } } +void MainWindow::setSelectedInstanceByRoot(const QString& instanceRoot) +{ + if (instanceRoot.isNull()) + return; + const QModelIndex index = APPLICATION->instances()->getInstanceIndexByRoot(instanceRoot); + if (index.isValid()) { + QModelIndex selectionIndex = proxymodel->mapFromSource(index); + view->selectionModel()->setCurrentIndex(selectionIndex, QItemSelectionModel::ClearAndSelect); + updateStatusCenter(); + } +} + void MainWindow::on_actionChangeInstGroup_triggered() { if (!m_selectedInstance) @@ -1428,13 +1446,6 @@ void MainWindow::on_actionExportInstanceFlamePack_triggered() void MainWindow::on_actionRenameInstance_triggered() { if (m_selectedInstance) { - connect(view->itemDelegate(), &QAbstractItemDelegate::closeEditor, this, [this] { - if (askToUpdateInstanceDirName(m_selectedInstance, this)) { - auto newID = m_selectedInstance->name(); - refreshInstances(); - setSelectedInstanceById(newID); - } - }, Qt::SingleShotConnection); view->edit(view->currentIndex()); } } diff --git a/launcher/ui/MainWindow.h b/launcher/ui/MainWindow.h index 0e692eda7..02e9bb31e 100644 --- a/launcher/ui/MainWindow.h +++ b/launcher/ui/MainWindow.h @@ -224,6 +224,7 @@ class MainWindow : public QMainWindow { void setCatBackground(bool enabled); void updateInstanceToolIcon(QString new_icon); void setSelectedInstanceById(const QString& id); + void setSelectedInstanceByRoot(const QString& instanceRoot); void updateStatusCenter(); void setInstanceActionsEnabled(bool enabled); From 45368fbf2f93aba8d224058d4ee53284e28e6f23 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Thu, 27 Mar 2025 07:31:24 +0800 Subject: [PATCH 11/16] Get rid of unused includes Signed-off-by: Yihe Li --- launcher/BaseInstance.cpp | 2 -- launcher/ui/MainWindow.cpp | 1 - 2 files changed, 3 deletions(-) diff --git a/launcher/BaseInstance.cpp b/launcher/BaseInstance.cpp index 92d41521b..114275b3c 100644 --- a/launcher/BaseInstance.cpp +++ b/launcher/BaseInstance.cpp @@ -37,13 +37,11 @@ #include "BaseInstance.h" -#include #include #include #include #include #include -#include #include #include "settings/INISettingsObject.h" diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index 43fe5c067..05afea0b4 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -54,7 +54,6 @@ #include #include #include -#include #include #include #include From 11a0dbf81059a39521d12c43fde7c5f07175ada2 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Thu, 27 Mar 2025 15:59:10 +0800 Subject: [PATCH 12/16] Make deleting a verb Signed-off-by: Yihe Li --- launcher/InstanceDirUpdate.cpp | 9 +++++---- launcher/InstanceDirUpdate.h | 2 +- launcher/ui/MainWindow.cpp | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/launcher/InstanceDirUpdate.cpp b/launcher/InstanceDirUpdate.cpp index 8064082fd..49010e6c9 100644 --- a/launcher/InstanceDirUpdate.cpp +++ b/launcher/InstanceDirUpdate.cpp @@ -93,7 +93,7 @@ QString askToUpdateInstanceDirName(InstancePtr instance, QWidget* parent) } // Check for linked instances - if (!checkLinkedInstances(instance->id(), parent)) + if (!checkLinkedInstances(instance->id(), parent, QObject::tr("Renaming"))) return QString(); // Now we can confirm that a renaming is happening @@ -109,17 +109,18 @@ QString askToUpdateInstanceDirName(InstancePtr instance, QWidget* parent) return newRoot; } -bool checkLinkedInstances(const QString& id, QWidget* parent) +bool checkLinkedInstances(const QString& id, QWidget* parent, const QString& verb) { auto linkedInstances = APPLICATION->instances()->getLinkedInstancesById(id); if (!linkedInstances.empty()) { auto response = CustomMessageBox::selectable(parent, QObject::tr("There are linked instances"), QObject::tr("The following instance(s) might reference files in this instance:\n\n" "%1\n\n" - "Deleting it could break the other instance(s), \n\n" + "%2 it could break the other instance(s), \n\n" "Do you wish to proceed?", nullptr, linkedInstances.count()) - .arg(linkedInstances.join("\n")), + .arg(linkedInstances.join("\n")) + .arg(verb), QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ->exec(); if (response != QMessageBox::Yes) diff --git a/launcher/InstanceDirUpdate.h b/launcher/InstanceDirUpdate.h index 23738a19a..354eba465 100644 --- a/launcher/InstanceDirUpdate.h +++ b/launcher/InstanceDirUpdate.h @@ -43,4 +43,4 @@ QString askToUpdateInstanceDirName(InstancePtr instance, QWidget* parent); /// Check if there are linked instances, and display a warning; return true if the operation should proceed -bool checkLinkedInstances(const QString& id, QWidget* parent); +bool checkLinkedInstances(const QString& id, QWidget* parent, const QString& verb); diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index 05afea0b4..7e9c72da7 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -1396,7 +1396,7 @@ void MainWindow::on_actionDeleteInstance_triggered() if (response != QMessageBox::Yes) return; - if (!checkLinkedInstances(id, this)) + if (!checkLinkedInstances(id, this, tr("Deleting"))) return; if (APPLICATION->instances()->trashInstance(id)) { From a2e44c0ef76a73befc9c31e243b675d8df6eb751 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Thu, 27 Mar 2025 17:13:38 +0800 Subject: [PATCH 13/16] Use custom signals to record previous name Signed-off-by: Yihe Li --- launcher/InstanceDirUpdate.cpp | 15 ++++++------- launcher/InstanceDirUpdate.h | 2 +- launcher/InstanceList.cpp | 17 --------------- launcher/InstanceList.h | 2 -- launcher/ui/MainWindow.cpp | 21 +++++-------------- launcher/ui/MainWindow.h | 1 - launcher/ui/instanceview/InstanceDelegate.cpp | 1 + launcher/ui/instanceview/InstanceDelegate.h | 3 +++ 8 files changed, 18 insertions(+), 44 deletions(-) diff --git a/launcher/InstanceDirUpdate.cpp b/launcher/InstanceDirUpdate.cpp index 49010e6c9..ac6dddc37 100644 --- a/launcher/InstanceDirUpdate.cpp +++ b/launcher/InstanceDirUpdate.cpp @@ -46,21 +46,22 @@ #include "InstanceList.h" #include "ui/dialogs/CustomMessageBox.h" -QString askToUpdateInstanceDirName(InstancePtr instance, QWidget* parent) +QString askToUpdateInstanceDirName(InstancePtr instance, const QString& oldName, const QString& newName, QWidget* parent) { + if (oldName == newName) + return QString(); + QString renamingMode = APPLICATION->settings()->get("InstRenamingMode").toString(); if (renamingMode == "MetadataOnly") return QString(); auto oldRoot = instance->instanceRoot(); - auto oldName = QFileInfo(oldRoot).baseName(); - if (oldName == FS::RemoveInvalidFilenameChars(instance->name(), '-')) - return QString(); - - auto newName = FS::DirNameFromString(instance->name(), QFileInfo(oldRoot).dir().absolutePath()); - auto newRoot = FS::PathCombine(QFileInfo(oldRoot).dir().absolutePath(), newName); + auto newDirName = FS::DirNameFromString(newName, QFileInfo(oldRoot).dir().absolutePath()); + auto newRoot = FS::PathCombine(QFileInfo(oldRoot).dir().absolutePath(), newDirName); if (oldRoot == newRoot) return QString(); + if (oldRoot == FS::PathCombine(QFileInfo(oldRoot).dir().absolutePath(), newName)) + return QString(); // Check for conflict if (QDir(newRoot).exists()) { diff --git a/launcher/InstanceDirUpdate.h b/launcher/InstanceDirUpdate.h index 354eba465..94dd3b933 100644 --- a/launcher/InstanceDirUpdate.h +++ b/launcher/InstanceDirUpdate.h @@ -40,7 +40,7 @@ #include "BaseInstance.h" /// Update instanceRoot to make it sync with name/id; return newRoot if a directory rename happened -QString askToUpdateInstanceDirName(InstancePtr instance, QWidget* parent); +QString askToUpdateInstanceDirName(InstancePtr instance, const QString& oldName, const QString& newName, QWidget* parent); /// Check if there are linked instances, and display a warning; return true if the operation should proceed bool checkLinkedInstances(const QString& id, QWidget* parent, const QString& verb); diff --git a/launcher/InstanceList.cpp b/launcher/InstanceList.cpp index a4f694e2e..918fa1073 100644 --- a/launcher/InstanceList.cpp +++ b/launcher/InstanceList.cpp @@ -583,18 +583,6 @@ InstancePtr InstanceList::getInstanceById(QString instId) const return InstancePtr(); } -InstancePtr InstanceList::getInstanceByRoot(QString instanceRoot) const -{ - if (instanceRoot.isEmpty()) - return InstancePtr(); - for (auto& inst : m_instances) { - if (inst->instanceRoot() == instanceRoot) { - return inst; - } - } - return InstancePtr(); -} - InstancePtr InstanceList::getInstanceByManagedName(const QString& managed_name) const { if (managed_name.isEmpty()) @@ -613,11 +601,6 @@ QModelIndex InstanceList::getInstanceIndexById(const QString& id) const return index(getInstIndex(getInstanceById(id).get())); } -QModelIndex InstanceList::getInstanceIndexByRoot(const QString& instanceRoot) const -{ - return index(getInstIndex(getInstanceByRoot(instanceRoot).get())); -} - int InstanceList::getInstIndex(BaseInstance* inst) const { int count = m_instances.count(); diff --git a/launcher/InstanceList.h b/launcher/InstanceList.h index dace9e5cf..c85fe55c7 100644 --- a/launcher/InstanceList.h +++ b/launcher/InstanceList.h @@ -99,11 +99,9 @@ class InstanceList : public QAbstractListModel { /* O(n) */ InstancePtr getInstanceById(QString id) const; - InstancePtr getInstanceByRoot(QString instanceRoot) const; /* O(n) */ InstancePtr getInstanceByManagedName(const QString& managed_name) const; QModelIndex getInstanceIndexById(const QString& id) const; - QModelIndex getInstanceIndexByRoot(const QString& instanceRoot) const; QStringList getGroups(); bool isGroupCollapsed(const QString& groupName); diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index 7e9c72da7..6c5f86d0a 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -289,14 +289,15 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWi view->setSelectionMode(QAbstractItemView::SingleSelection); // FIXME: leaks ListViewDelegate - view->setItemDelegate(new ListViewDelegate(this)); + auto delegate = new ListViewDelegate(this); + view->setItemDelegate(delegate); view->setFrameShape(QFrame::NoFrame); // do not show ugly blue border on the mac view->setAttribute(Qt::WA_MacShowFocusRect, false); - connect(view->itemDelegate(), &QAbstractItemDelegate::closeEditor, this, [this] { - if (auto newRoot = askToUpdateInstanceDirName(m_selectedInstance, this); !newRoot.isEmpty()) { + connect(delegate, &ListViewDelegate::textChanged, this, [this](QString before, QString after) { + if (auto newRoot = askToUpdateInstanceDirName(m_selectedInstance, before, after, this); !newRoot.isEmpty()) { refreshInstances(); - setSelectedInstanceByRoot(newRoot); + setSelectedInstanceById(QFileInfo(newRoot).fileName()); } }); @@ -1138,18 +1139,6 @@ void MainWindow::setSelectedInstanceById(const QString& id) } } -void MainWindow::setSelectedInstanceByRoot(const QString& instanceRoot) -{ - if (instanceRoot.isNull()) - return; - const QModelIndex index = APPLICATION->instances()->getInstanceIndexByRoot(instanceRoot); - if (index.isValid()) { - QModelIndex selectionIndex = proxymodel->mapFromSource(index); - view->selectionModel()->setCurrentIndex(selectionIndex, QItemSelectionModel::ClearAndSelect); - updateStatusCenter(); - } -} - void MainWindow::on_actionChangeInstGroup_triggered() { if (!m_selectedInstance) diff --git a/launcher/ui/MainWindow.h b/launcher/ui/MainWindow.h index 02e9bb31e..0e692eda7 100644 --- a/launcher/ui/MainWindow.h +++ b/launcher/ui/MainWindow.h @@ -224,7 +224,6 @@ class MainWindow : public QMainWindow { void setCatBackground(bool enabled); void updateInstanceToolIcon(QString new_icon); void setSelectedInstanceById(const QString& id); - void setSelectedInstanceByRoot(const QString& instanceRoot); void updateStatusCenter(); void setInstanceActionsEnabled(bool enabled); diff --git a/launcher/ui/instanceview/InstanceDelegate.cpp b/launcher/ui/instanceview/InstanceDelegate.cpp index d947163bc..c7115801e 100644 --- a/launcher/ui/instanceview/InstanceDelegate.cpp +++ b/launcher/ui/instanceview/InstanceDelegate.cpp @@ -397,6 +397,7 @@ void ListViewDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, // Prevent instance names longer than 128 chars text.truncate(128); if (text.size() != 0) { + emit textChanged(model->data(index).toString(), text); model->setData(index, text); } } diff --git a/launcher/ui/instanceview/InstanceDelegate.h b/launcher/ui/instanceview/InstanceDelegate.h index 69dd32ba7..98ff9a2fc 100644 --- a/launcher/ui/instanceview/InstanceDelegate.h +++ b/launcher/ui/instanceview/InstanceDelegate.h @@ -33,6 +33,9 @@ class ListViewDelegate : public QStyledItemDelegate { void setEditorData(QWidget* editor, const QModelIndex& index) const override; void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const override; + signals: + void textChanged(QString before, QString after) const; + private slots: void editingDone(); }; From 694959ef7f56e5f8d0f7918b61bd059483707cab Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Thu, 27 Mar 2025 20:25:30 +0800 Subject: [PATCH 14/16] Remove names from header comments Signed-off-by: Yihe Li --- launcher/InstanceDirUpdate.cpp | 3 --- launcher/InstanceDirUpdate.h | 3 --- 2 files changed, 6 deletions(-) diff --git a/launcher/InstanceDirUpdate.cpp b/launcher/InstanceDirUpdate.cpp index ac6dddc37..65a62129b 100644 --- a/launcher/InstanceDirUpdate.cpp +++ b/launcher/InstanceDirUpdate.cpp @@ -1,9 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only /* * Prism Launcher - Minecraft Launcher - * Copyright (C) 2022 Sefa Eyeoglu - * Copyright (c) 2022 Jamie Mansfield - * Copyright (C) 2023 TheKodeToad * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/launcher/InstanceDirUpdate.h b/launcher/InstanceDirUpdate.h index 94dd3b933..b92a59c4c 100644 --- a/launcher/InstanceDirUpdate.h +++ b/launcher/InstanceDirUpdate.h @@ -1,9 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only /* * Prism Launcher - Minecraft Launcher - * Copyright (C) 2022 Sefa Eyeoglu - * Copyright (c) 2022 Jamie Mansfield - * Copyright (C) 2023 TheKodeToad * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From 02ca6bea8c4261776500862159d61817abf246cc Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Sat, 29 Mar 2025 14:11:09 +0800 Subject: [PATCH 15/16] Sync group after updating instance Signed-off-by: Yihe Li --- launcher/ui/MainWindow.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index 6c5f86d0a..ddf726373 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -296,8 +296,18 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWi view->setAttribute(Qt::WA_MacShowFocusRect, false); connect(delegate, &ListViewDelegate::textChanged, this, [this](QString before, QString after) { if (auto newRoot = askToUpdateInstanceDirName(m_selectedInstance, before, after, this); !newRoot.isEmpty()) { + auto oldID = m_selectedInstance->id(); + auto newID = QFileInfo(newRoot).fileName(); + QString origGroup(APPLICATION->instances()->getInstanceGroup(oldID)); + bool syncGroup = origGroup != GroupId() && oldID != newID; + if (syncGroup) + APPLICATION->instances()->setInstanceGroup(oldID, GroupId()); + refreshInstances(); - setSelectedInstanceById(QFileInfo(newRoot).fileName()); + setSelectedInstanceById(newID); + + if (syncGroup) + APPLICATION->instances()->setInstanceGroup(newID, origGroup); } }); From da007d62123b3022f1afd09a7a3577405e5e4310 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Mon, 31 Mar 2025 07:11:05 +0800 Subject: [PATCH 16/16] Use CustomMessageBox::selectable Signed-off-by: Yihe Li --- launcher/BaseInstance.cpp | 6 +----- launcher/InstanceDirUpdate.cpp | 18 ++++++++---------- launcher/ui/dialogs/CustomMessageBox.cpp | 5 ++++- launcher/ui/dialogs/CustomMessageBox.h | 3 ++- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/launcher/BaseInstance.cpp b/launcher/BaseInstance.cpp index 114275b3c..eab91a5eb 100644 --- a/launcher/BaseInstance.cpp +++ b/launcher/BaseInstance.cpp @@ -389,11 +389,7 @@ void BaseInstance::setName(QString val) bool BaseInstance::syncInstanceDirName(const QString& newRoot) const { auto oldRoot = instanceRoot(); - if (oldRoot == newRoot) - return true; - if (!QFile::rename(oldRoot, newRoot)) - return false; - return true; + return oldRoot == newRoot || QFile::rename(oldRoot, newRoot); } QString BaseInstance::name() const diff --git a/launcher/InstanceDirUpdate.cpp b/launcher/InstanceDirUpdate.cpp index 65a62129b..8be0dccac 100644 --- a/launcher/InstanceDirUpdate.cpp +++ b/launcher/InstanceDirUpdate.cpp @@ -35,7 +35,6 @@ #include "InstanceDirUpdate.h" #include -#include #include "Application.h" #include "FileSystem.h" @@ -69,17 +68,16 @@ QString askToUpdateInstanceDirName(InstancePtr instance, const QString& oldName, // Ask if we should rename if (renamingMode == "AskEverytime") { - QMessageBox messageBox(parent); - messageBox.setText(QObject::tr("Would you also like to rename the instance folder?")); - messageBox.setInformativeText(QObject::tr("Renaming \'%1\' -> \'%2\'").arg(oldName, newName)); - messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); - messageBox.setDefaultButton(QMessageBox::Yes); - messageBox.setIcon(QMessageBox::Question); - auto checkBox = new QCheckBox(QObject::tr("&Remember my choice"), parent); - messageBox.setCheckBox(checkBox); + auto dialog = + CustomMessageBox::selectable(parent, QObject::tr("Rename instance folder"), + QObject::tr("Would you also like to rename the instance folder?\n\n" + "Old name: %1\n" + "New name: %2") + .arg(oldName, newName), + QMessageBox::Question, QMessageBox::No | QMessageBox::Yes, QMessageBox::NoButton, checkBox); - auto res = messageBox.exec(); + auto res = dialog->exec(); if (checkBox->isChecked()) { if (res == QMessageBox::Yes) APPLICATION->settings()->set("InstRenamingMode", "PhysicalDir"); diff --git a/launcher/ui/dialogs/CustomMessageBox.cpp b/launcher/ui/dialogs/CustomMessageBox.cpp index 1af47a449..ca0fe99e0 100644 --- a/launcher/ui/dialogs/CustomMessageBox.cpp +++ b/launcher/ui/dialogs/CustomMessageBox.cpp @@ -21,7 +21,8 @@ QMessageBox* selectable(QWidget* parent, const QString& text, QMessageBox::Icon icon, QMessageBox::StandardButtons buttons, - QMessageBox::StandardButton defaultButton) + QMessageBox::StandardButton defaultButton, + QCheckBox* checkBox) { QMessageBox* messageBox = new QMessageBox(parent); messageBox->setWindowTitle(title); @@ -31,6 +32,8 @@ QMessageBox* selectable(QWidget* parent, messageBox->setTextInteractionFlags(Qt::TextSelectableByMouse); messageBox->setIcon(icon); messageBox->setTextInteractionFlags(Qt::TextBrowserInteraction); + if (checkBox) + messageBox->setCheckBox(checkBox); return messageBox; } diff --git a/launcher/ui/dialogs/CustomMessageBox.h b/launcher/ui/dialogs/CustomMessageBox.h index a9bc6a24a..1ee29903e 100644 --- a/launcher/ui/dialogs/CustomMessageBox.h +++ b/launcher/ui/dialogs/CustomMessageBox.h @@ -23,5 +23,6 @@ QMessageBox* selectable(QWidget* parent, const QString& text, QMessageBox::Icon icon = QMessageBox::NoIcon, QMessageBox::StandardButtons buttons = QMessageBox::Ok, - QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); + QMessageBox::StandardButton defaultButton = QMessageBox::NoButton, + QCheckBox* checkBox = nullptr); }