diff options
23 files changed, 230 insertions, 51 deletions
diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 1659eb44..724e6e44 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -376,33 +376,33 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) // init the logger { - static const QString logBase = BuildConfig.LAUNCHER_NAME + "-%0.log"; - auto moveFile = [](const QString &oldName, const QString &newName) - { + static const QString baseLogFile = BuildConfig.LAUNCHER_NAME + "-%0.log"; + static const QString logBase = FS::PathCombine("logs", baseLogFile); + auto moveFile = [](const QString& oldName, const QString& newName) { QFile::remove(newName); QFile::copy(oldName, newName); QFile::remove(oldName); }; + if (FS::ensureFolderPathExists("logs")) { // if this did not fail + for (auto i = 0; i <= 4; i++) + if (auto oldName = baseLogFile.arg(i); + QFile::exists(oldName)) // do not pointlessly delete new files if the old ones are not there + moveFile(oldName, logBase.arg(i)); + } - moveFile(logBase.arg(3), logBase.arg(4)); - moveFile(logBase.arg(2), logBase.arg(3)); - moveFile(logBase.arg(1), logBase.arg(2)); - moveFile(logBase.arg(0), logBase.arg(1)); + for (auto i = 4; i > 0; i--) + moveFile(logBase.arg(i - 1), logBase.arg(i)); logFile = std::unique_ptr<QFile>(new QFile(logBase.arg(0))); - if(!logFile->open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) - { - showFatalErrorMessage( - "The launcher data folder is not writable!", - QString( - "The launcher couldn't create a log file - the data folder is not writable.\n" - "\n" - "Make sure you have write permissions to the data folder.\n" - "(%1)\n" - "\n" - "The launcher cannot continue until you fix this problem." - ).arg(dataPath) - ); + if (!logFile->open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { + showFatalErrorMessage("The launcher data folder is not writable!", + QString("The launcher couldn't create a log file - the data folder is not writable.\n" + "\n" + "Make sure you have write permissions to the data folder.\n" + "(%1)\n" + "\n" + "The launcher cannot continue until you fix this problem.") + .arg(dataPath)); return; } qInstallMessageHandler(appDebugOutput); @@ -1699,6 +1699,7 @@ bool Application::handleDataMigration(const QString& currentData, matcher->add(std::make_shared<SimplePrefixMatcher>(configFile)); matcher->add(std::make_shared<SimplePrefixMatcher>( BuildConfig.LAUNCHER_CONFIGFILE)); // it's possible that we already used that directory before + matcher->add(std::make_shared<SimplePrefixMatcher>("logs/")); matcher->add(std::make_shared<SimplePrefixMatcher>("accounts.json")); matcher->add(std::make_shared<SimplePrefixMatcher>("accounts/")); matcher->add(std::make_shared<SimplePrefixMatcher>("assets/")); diff --git a/launcher/InstanceTask.cpp b/launcher/InstanceTask.cpp index 06682782..b16a40ba 100644 --- a/launcher/InstanceTask.cpp +++ b/launcher/InstanceTask.cpp @@ -45,7 +45,10 @@ QString InstanceName::name() const { if (!m_modified_name.isEmpty()) return modifiedName(); - return QString("%1 %2").arg(m_original_name, m_original_version); + if (!m_original_version.isEmpty()) + return QString("%1 %2").arg(m_original_name, m_original_version); + + return m_original_name; } QString InstanceName::originalName() const diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index 2c624a36..f8ed5214 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -149,9 +149,10 @@ void MinecraftInstance::loadSpecificSettings() // special! m_settings->registerPassthrough(global_settings->getSetting("JavaTimestamp"), javaOrLocation); - m_settings->registerPassthrough(global_settings->getSetting("JavaVersion"), javaOrLocation); m_settings->registerPassthrough(global_settings->getSetting("JavaArchitecture"), javaOrLocation); m_settings->registerPassthrough(global_settings->getSetting("JavaRealArchitecture"), javaOrLocation); + m_settings->registerPassthrough(global_settings->getSetting("JavaVersion"), javaOrLocation); + m_settings->registerPassthrough(global_settings->getSetting("JavaVendor"), javaOrLocation); // Window Size auto windowSetting = m_settings->registerSetting("OverrideWindow", false); diff --git a/launcher/settings/INIFile.cpp b/launcher/settings/INIFile.cpp index cb909ae7..d16256b9 100644 --- a/launcher/settings/INIFile.cpp +++ b/launcher/settings/INIFile.cpp @@ -50,7 +50,7 @@ INIFile::INIFile() {} bool INIFile::saveFile(QString fileName) { if (!contains("ConfigVersion")) - insert("ConfigVersion", "1.1"); + insert("ConfigVersion", "1.2"); QSettings _settings_obj{ fileName, QSettings::Format::IniFormat }; _settings_obj.setFallbacksEnabled(false); @@ -97,6 +97,20 @@ QString unescape(QString orig) } return out; } + +QString unquote(QString str) +{ + if ((str.contains(QChar(';')) || str.contains(QChar('=')) || str.contains(QChar(','))) && str.endsWith("\"") && str.startsWith("\"")) { +#if QT_VERSION < QT_VERSION_CHECK(6, 5, 0) + str = str.remove(0, 1); + str = str.remove(str.size() - 1, 1); +#else + str = str.removeFirst().removeLast(); +#endif + } + return str; +} + bool parseOldFileFormat(QIODevice& device, QSettings::SettingsMap& map) { QTextStream in(device.readAll()); @@ -124,7 +138,7 @@ bool parseOldFileFormat(QIODevice& device, QSettings::SettingsMap& map) QString key = line.left(eqPos).trimmed(); QString valueStr = line.right(line.length() - eqPos - 1).trimmed(); - valueStr = unescape(valueStr); + valueStr = unquote(unescape(valueStr)); QVariant value(valueStr); map.insert(key, value); @@ -154,7 +168,17 @@ bool INIFile::loadFile(QString fileName) file.close(); for (auto&& key : map.keys()) insert(key, map.value(key)); - insert("ConfigVersion", "1.1"); + insert("ConfigVersion", "1.2"); + } else if (_settings_obj.value("ConfigVersion").toString() == "1.1") { + for (auto&& key : _settings_obj.allKeys()) { + if (auto valueStr = _settings_obj.value(key).toString(); + (valueStr.contains(QChar(';')) || valueStr.contains(QChar('=')) || valueStr.contains(QChar(','))) && + valueStr.endsWith("\"") && valueStr.startsWith("\"")) { + insert(key, unquote(valueStr)); + } else + insert(key, _settings_obj.value(key)); + } + insert("ConfigVersion", "1.2"); } else for (auto&& key : _settings_obj.allKeys()) insert(key, _settings_obj.value(key)); diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index 1addfe21..e04011ca 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -1234,6 +1234,12 @@ void MainWindow::on_actionViewInstanceFolder_triggered() DesktopServices::openDirectory(str); } +void MainWindow::on_actionViewLauncherRootFolder_triggered() +{ + const QString dataPath = QDir::currentPath(); + DesktopServices::openDirectory(dataPath); +} + void MainWindow::refreshInstances() { APPLICATION->instances()->loadList(); diff --git a/launcher/ui/MainWindow.h b/launcher/ui/MainWindow.h index a0f912df..3bb20c4a 100644 --- a/launcher/ui/MainWindow.h +++ b/launcher/ui/MainWindow.h @@ -113,6 +113,8 @@ private slots: void on_actionViewInstanceFolder_triggered(); + void on_actionViewLauncherRootFolder_triggered(); + void on_actionViewSelectedInstFolder_triggered(); void refreshInstances(); diff --git a/launcher/ui/MainWindow.ui b/launcher/ui/MainWindow.ui index 9e639ab0..f67fb185 100644 --- a/launcher/ui/MainWindow.ui +++ b/launcher/ui/MainWindow.ui @@ -187,6 +187,7 @@ <bool>true</bool> </property> <addaction name="actionViewInstanceFolder"/> + <addaction name="actionViewLauncherRootFolder"/> <addaction name="actionViewCentralModsFolder"/> </widget> <widget class="QMenu" name="accountsMenu"> @@ -541,6 +542,18 @@ <string>Open the instance folder in a file browser.</string> </property> </action> + <action name="actionViewLauncherRootFolder"> + <property name="icon"> + <iconset theme="viewfolder"> + <normaloff>.</normaloff>.</iconset> + </property> + <property name="text"> + <string>&View Launcher Root Folder</string> + </property> + <property name="toolTip"> + <string>Open the launcher's root folder in a file browser.</string> + </property> + </action> <action name="actionViewCentralModsFolder"> <property name="icon"> <iconset theme="centralmods"> diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.cpp b/launcher/ui/pages/instance/InstanceSettingsPage.cpp index a583ab1d..08977841 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.cpp +++ b/launcher/ui/pages/instance/InstanceSettingsPage.cpp @@ -60,6 +60,10 @@ InstanceSettingsPage::InstanceSettingsPage(BaseInstance *inst, QWidget *parent) m_settings = inst->settings(); ui->setupUi(this); + // As the signal will (probably) not be triggered once we click edit, let's update it manually instead. + updateRunningStatus(m_instance->isRunning()); + + connect(m_instance, &BaseInstance::runningStatusChanged, this, &InstanceSettingsPage::updateRunningStatus); connect(ui->openGlobalJavaSettingsButton, &QCommandLinkButton::clicked, this, &InstanceSettingsPage::globalSettingsButtonClicked); connect(APPLICATION, &Application::globalSettingsAboutToOpen, this, &InstanceSettingsPage::applySettings); connect(APPLICATION, &Application::globalSettingsClosed, this, &InstanceSettingsPage::loadSettings); @@ -70,11 +74,6 @@ InstanceSettingsPage::InstanceSettingsPage(BaseInstance *inst, QWidget *parent) updateThresholds(); } -bool InstanceSettingsPage::shouldDisplay() const -{ - return !m_instance->isRunning(); -} - InstanceSettingsPage::~InstanceSettingsPage() { delete ui; @@ -524,3 +523,8 @@ void InstanceSettingsPage::updateThresholds() ui->labelMaxMemIcon->setPixmap(pix); } } + +void InstanceSettingsPage::updateRunningStatus(bool running) +{ + setEnabled(!running); +} diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.h b/launcher/ui/pages/instance/InstanceSettingsPage.h index 043c3e25..0438fe3b 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.h +++ b/launcher/ui/pages/instance/InstanceSettingsPage.h @@ -75,12 +75,12 @@ public: { return "Instance-settings"; } - virtual bool shouldDisplay() const override; void retranslate() override; void updateThresholds(); private slots: + void updateRunningStatus(bool running); void on_javaDetectBtn_clicked(); void on_javaTestBtn_clicked(); void on_javaBrowseBtn_clicked(); diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp index afd8b292..b7537890 100644 --- a/launcher/ui/pages/modplatform/ModModel.cpp +++ b/launcher/ui/pages/modplatform/ModModel.cpp @@ -6,12 +6,14 @@ #include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" +#include "minecraft/mod/ModFolderModel.h" #include <QMessageBox> +#include <algorithm> namespace ResourceDownload { -ModModel::ModModel(BaseInstance const& base_inst, ResourceAPI* api) : ResourceModel(api), m_base_instance(base_inst) {} +ModModel::ModModel(BaseInstance& base_inst, ResourceAPI* api) : ResourceModel(api), m_base_instance(base_inst) {} /******** Make data requests ********/ @@ -24,7 +26,7 @@ ResourceAPI::SearchArgs ModModel::createSearchArguments() std::optional<std::list<Version>> versions{}; - { // Version filter + { // Version filter if (!m_filter->versions.empty()) versions = m_filter->versions; } @@ -67,4 +69,14 @@ void ModModel::searchWithTerm(const QString& term, unsigned int sort, bool filte refresh(); } +bool ModModel::isPackInstalled(ModPlatform::IndexedPack::Ptr pack) const +{ + auto allMods = static_cast<MinecraftInstance&>(m_base_instance).loaderModList()->allMods(); + return std::any_of(allMods.cbegin(), allMods.cend(), [pack](Mod* mod) { + if (auto meta = mod->metadata(); meta) + return meta->provider == pack->provider && meta->project_id == pack->addonId; + return false; + }); +} + } // namespace ResourceDownload diff --git a/launcher/ui/pages/modplatform/ModModel.h b/launcher/ui/pages/modplatform/ModModel.h index 5d4a7785..805d8b9a 100644 --- a/launcher/ui/pages/modplatform/ModModel.h +++ b/launcher/ui/pages/modplatform/ModModel.h @@ -24,7 +24,7 @@ class ModModel : public ResourceModel { Q_OBJECT public: - ModModel(const BaseInstance&, ResourceAPI* api); + ModModel(BaseInstance&, ResourceAPI* api); /* Ask the API for more information */ void searchWithTerm(const QString& term, unsigned int sort, bool filter_changed); @@ -42,9 +42,10 @@ class ModModel : public ResourceModel { protected: auto documentToArray(QJsonDocument& obj) const -> QJsonArray override = 0; + virtual bool isPackInstalled(ModPlatform::IndexedPack::Ptr) const override; protected: - const BaseInstance& m_base_instance; + BaseInstance& m_base_instance; std::shared_ptr<ModFilterWidget::Filter> m_filter = nullptr; }; diff --git a/launcher/ui/pages/modplatform/ResourceModel.cpp b/launcher/ui/pages/modplatform/ResourceModel.cpp index a5ea1ca9..49405a02 100644 --- a/launcher/ui/pages/modplatform/ResourceModel.cpp +++ b/launcher/ui/pages/modplatform/ResourceModel.cpp @@ -77,6 +77,8 @@ auto ResourceModel::data(const QModelIndex& index, int role) const -> QVariant return pack->description; case UserDataTypes::SELECTED: return pack->isAnyVersionSelected(); + case UserDataTypes::INSTALLED: + return this->isPackInstalled(pack); default: break; } @@ -95,6 +97,7 @@ QHash<int, QByteArray> ResourceModel::roleNames() const roles[UserDataTypes::TITLE] = "title"; roles[UserDataTypes::DESCRIPTION] = "description"; roles[UserDataTypes::SELECTED] = "selected"; + roles[UserDataTypes::INSTALLED] = "installed"; return roles; } diff --git a/launcher/ui/pages/modplatform/ResourceModel.h b/launcher/ui/pages/modplatform/ResourceModel.h index 69e23473..6533d9c6 100644 --- a/launcher/ui/pages/modplatform/ResourceModel.h +++ b/launcher/ui/pages/modplatform/ResourceModel.h @@ -116,6 +116,8 @@ class ResourceModel : public QAbstractListModel { virtual void loadExtraPackInfo(ModPlatform::IndexedPack&, QJsonObject&); virtual void loadIndexedPackVersions(ModPlatform::IndexedPack&, QJsonArray&); + virtual bool isPackInstalled(ModPlatform::IndexedPack::Ptr) const { return false; } + protected: /* Basic search parameters */ enum class SearchState { None, CanFetchMore, ResetRequested, Finished } m_search_state = SearchState::None; diff --git a/launcher/ui/pages/modplatform/flame/FlameModel.cpp b/launcher/ui/pages/modplatform/flame/FlameModel.cpp index 5961ea02..d9d5ef5b 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModel.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModel.cpp @@ -60,6 +60,8 @@ QVariant ListModel::data(const QModelIndex& index, int role) const return pack.description; case UserDataTypes::SELECTED: return false; + case UserDataTypes::INSTALLED: + return false; default: break; } diff --git a/launcher/ui/pages/modplatform/flame/FlameResourceModels.cpp b/launcher/ui/pages/modplatform/flame/FlameResourceModels.cpp index e3d0bc14..667a52d0 100644 --- a/launcher/ui/pages/modplatform/flame/FlameResourceModels.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameResourceModels.cpp @@ -11,7 +11,7 @@ namespace ResourceDownload { -FlameModModel::FlameModModel(BaseInstance const& base) : ModModel(base, new FlameAPI) {} +FlameModModel::FlameModModel(BaseInstance& base) : ModModel(base, new FlameAPI) {} void FlameModModel::loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) { diff --git a/launcher/ui/pages/modplatform/flame/FlameResourceModels.h b/launcher/ui/pages/modplatform/flame/FlameResourceModels.h index 0252ac40..221c8f7a 100644 --- a/launcher/ui/pages/modplatform/flame/FlameResourceModels.h +++ b/launcher/ui/pages/modplatform/flame/FlameResourceModels.h @@ -14,7 +14,7 @@ class FlameModModel : public ModModel { Q_OBJECT public: - FlameModModel(const BaseInstance&); + FlameModModel(BaseInstance&); ~FlameModModel() override = default; private: diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index 346a00b0..55d287b0 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -106,6 +106,8 @@ auto ModpackListModel::data(const QModelIndex& index, int role) const -> QVarian return pack.description; case UserDataTypes::SELECTED: return false; + case UserDataTypes::INSTALLED: + return false; default: break; } diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthResourceModels.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthResourceModels.cpp index f5d1cc28..7f857485 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthResourceModels.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthResourceModels.cpp @@ -25,7 +25,7 @@ namespace ResourceDownload { -ModrinthModModel::ModrinthModModel(BaseInstance const& base) : ModModel(base, new ModrinthAPI) {} +ModrinthModModel::ModrinthModModel(BaseInstance& base) : ModModel(base, new ModrinthAPI) {} void ModrinthModModel::loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) { diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthResourceModels.h b/launcher/ui/pages/modplatform/modrinth/ModrinthResourceModels.h index b351b19b..66461807 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthResourceModels.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthResourceModels.h @@ -30,7 +30,7 @@ class ModrinthModModel : public ModModel { Q_OBJECT public: - ModrinthModModel(const BaseInstance&); + ModrinthModModel(BaseInstance&); ~ModrinthModModel() override = default; private: diff --git a/launcher/ui/widgets/ProjectItem.cpp b/launcher/ui/widgets/ProjectItem.cpp index d1ff9dbc..0085d6b2 100644 --- a/launcher/ui/widgets/ProjectItem.cpp +++ b/launcher/ui/widgets/ProjectItem.cpp @@ -64,6 +64,17 @@ void ProjectItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o font.setBold(true); font.setUnderline(true); } + if (index.data(UserDataTypes::INSTALLED).toBool()) { + auto hRect = opt.rect; + hRect.setX(hRect.x() + 1); + hRect.setY(hRect.y() + 1); + hRect.setHeight(hRect.height() - 2); + hRect.setWidth(hRect.width() - 2); + // Set nice font + font.setItalic(true); + font.setOverline(true); + painter->drawRect(hRect); + } font.setPointSize(font.pointSize() + 2); painter->setFont(font); diff --git a/launcher/ui/widgets/ProjectItem.h b/launcher/ui/widgets/ProjectItem.h index f668edf6..196055ea 100644 --- a/launcher/ui/widgets/ProjectItem.h +++ b/launcher/ui/widgets/ProjectItem.h @@ -6,7 +6,8 @@ enum UserDataTypes { TITLE = 257, // QString DESCRIPTION = 258, // QString - SELECTED = 259 // bool + SELECTED = 259, // bool + INSTALLED = 260 // bool }; /** This is an item delegate composed of: diff --git a/nix/dev.nix b/nix/dev.nix index a4ff2cc4..635c6bb4 100644 --- a/nix/dev.nix +++ b/nix/dev.nix @@ -37,7 +37,7 @@ nil ]; - inputsFrom = [self.packages.${system}.default]; + inputsFrom = [self.packages.${system}.prismlauncher-unwrapped]; buildInputs = with pkgs; [ccache ninja]; }; diff --git a/tests/INIFile_test.cpp b/tests/INIFile_test.cpp index 2f49e573..95730e24 100644 --- a/tests/INIFile_test.cpp +++ b/tests/INIFile_test.cpp @@ -2,7 +2,10 @@ #include <settings/INIFile.h> #include <QList> +#include <QSettings> +#include <QTemporaryFile> #include <QVariant> +#include "FileSystem.h" #include <QVariantUtils.h> @@ -72,32 +75,120 @@ class IniFileTest : public QObject { QCOMPARE(out_list_numbers, list_numbers); } - void test_SaveAleardyExistingFile() + void test_SaveAlreadyExistingFile() { - QString fileName = "test_SaveAleardyExistingFile.ini"; QString fileContent = R"(InstanceType=OneSix iconKey=vanillia_icon name=Minecraft Vanillia OverrideCommands=true PreLaunchCommand="$INST_JAVA" -jar packwiz-installer-bootstrap.jar link -)"; +Wrapperommand=)"; + fileContent += "\""; + fileContent += +R"(\"$INST_JAVA\" -jar packwiz-installer-bootstrap.jar link =)"; + fileContent += "\"\n"; +#if defined(Q_OS_WIN) + QString fileName = "test_SaveAlreadyExistingFile.ini"; QFile file(fileName); - - if (file.open(QFile::WriteOnly | QFile::Text)) { - QTextStream stream(&file); - stream << fileContent; - file.close(); - } + QCOMPARE(file.open(QFile::WriteOnly | QFile::Text), true); +#else + QTemporaryFile file; + QCOMPARE(file.open(), true); + QCOMPARE(file.fileName().isEmpty(), false); + QString fileName = file.fileName(); +#endif + QTextStream stream(&file); + stream << fileContent; + file.close(); // load INIFile f1; f1.loadFile(fileName); QCOMPARE(f1.get("PreLaunchCommand", "NOT SET").toString(), "\"$INST_JAVA\" -jar packwiz-installer-bootstrap.jar link"); + QCOMPARE(f1.get("Wrapperommand", "NOT SET").toString(), "\"$INST_JAVA\" -jar packwiz-installer-bootstrap.jar link ="); f1.saveFile(fileName); INIFile f2; f2.loadFile(fileName); QCOMPARE(f2.get("PreLaunchCommand", "NOT SET").toString(), "\"$INST_JAVA\" -jar packwiz-installer-bootstrap.jar link"); - QCOMPARE(f2.get("ConfigVersion", "NOT SET").toString(), "1.1"); + QCOMPARE(f2.get("Wrapperommand", "NOT SET").toString(), "\"$INST_JAVA\" -jar packwiz-installer-bootstrap.jar link ="); + QCOMPARE(f2.get("ConfigVersion", "NOT SET").toString(), "1.2"); +#if defined(Q_OS_WIN) + FS::deletePath(fileName); +#endif + } + + void test_SaveAlreadyExistingFileWithSpecialChars() + { +#if defined(Q_OS_WIN) + QString fileName = "test_SaveAlreadyExistingFileWithSpecialChars.ini"; +#else + QTemporaryFile file; + QCOMPARE(file.open(), true); + QCOMPARE(file.fileName().isEmpty(), false); + QString fileName = file.fileName(); + file.close(); +#endif + QSettings settings{ fileName, QSettings::Format::IniFormat }; + settings.setFallbacksEnabled(false); + + settings.setValue("simple", "value1"); + settings.setValue("withQuotes", R"("value2" with quotes)"); + settings.setValue("withSpecialCharacters", "env mesa=true"); + settings.setValue("withSpecialCharacters2", "1,2,3,4"); + settings.setValue("withSpecialCharacters2", "1;2;3;4"); + settings.setValue("withAll", "val=\"$INST_JAVA\" -jar; ls "); + + settings.sync(); + + QCOMPARE(settings.status(), QSettings::Status::NoError); + + // load + INIFile f1; + f1.loadFile(fileName); + for (auto key : settings.allKeys()) + QCOMPARE(f1.get(key, "NOT SET").toString(), settings.value(key).toString()); + f1.saveFile(fileName); + INIFile f2; + f2.loadFile(fileName); + for (auto key : settings.allKeys()) + QCOMPARE(f2.get(key, "NOT SET").toString(), settings.value(key).toString()); + QCOMPARE(f2.get("ConfigVersion", "NOT SET").toString(), "1.2"); +#if defined(Q_OS_WIN) + FS::deletePath(fileName); +#endif + } + + void test_SaveAlreadyExistingFileWithSpecialCharsV1() + { + QString fileContent = R"(InstanceType=OneSix +ConfigVersion=1.1 +iconKey=vanillia_icon +name=Minecraft Vanillia +OverrideCommands=true +PreLaunchCommand=)"; + fileContent += "\"\\\"env mesa=true\\\"\"\n"; + +#if defined(Q_OS_WIN) + QString fileName = "test_SaveAlreadyExistingFileWithSpecialCharsV1.ini"; + QFile file(fileName); + QCOMPARE(file.open(QFile::WriteOnly | QFile::Text), true); +#else + QTemporaryFile file; + QCOMPARE(file.open(), true); + QCOMPARE(file.fileName().isEmpty(), false); + QString fileName = file.fileName(); +#endif + QTextStream stream(&file); + stream << fileContent; + file.close(); + + // load + INIFile f1; + f1.loadFile(fileName); + QCOMPARE(f1.get("PreLaunchCommand", "NOT SET").toString(), "env mesa=true"); + QCOMPARE(f1.get("ConfigVersion", "NOT SET").toString(), "1.2"); +#if defined(Q_OS_WIN) + FS::deletePath(fileName); +#endif } }; |