aboutsummaryrefslogtreecommitdiff
path: root/launcher
diff options
context:
space:
mode:
Diffstat (limited to 'launcher')
-rw-r--r--launcher/Application.cpp41
-rw-r--r--launcher/Application.h10
-rw-r--r--launcher/ApplicationMessage.cpp44
-rw-r--r--launcher/BaseInstance.cpp3
-rw-r--r--launcher/BaseInstance.h1
-rw-r--r--launcher/BaseVersionList.cpp42
-rw-r--r--launcher/CMakeLists.txt201
-rw-r--r--launcher/Commandline.cpp46
-rw-r--r--launcher/FileSystem.cpp39
-rw-r--r--launcher/FileSystem.h44
-rw-r--r--launcher/FileSystem_test.cpp44
-rw-r--r--launcher/GZip.cpp39
-rw-r--r--launcher/GZip_test.cpp1
-rw-r--r--launcher/InstanceImportTask.cpp23
-rw-r--r--launcher/InstanceList.cpp48
-rw-r--r--launcher/InstancePageProvider.h4
-rw-r--r--launcher/JavaCommon.cpp53
-rw-r--r--launcher/JavaCommon.h10
-rw-r--r--launcher/Json.cpp51
-rw-r--r--launcher/Json.h37
-rw-r--r--launcher/LoggedProcess.cpp52
-rw-r--r--launcher/LoggedProcess.h41
-rw-r--r--launcher/MMCZip.cpp2
-rw-r--r--launcher/NullInstance.h4
-rw-r--r--launcher/Version.h44
-rw-r--r--launcher/VersionProxyModel.cpp40
-rw-r--r--launcher/icons/IconList.cpp48
-rw-r--r--launcher/icons/MMCIcon.cpp44
-rw-r--r--launcher/java/JavaChecker.cpp56
-rw-r--r--launcher/java/JavaInstallList.cpp43
-rw-r--r--launcher/java/JavaUtils.cpp75
-rw-r--r--launcher/java/JavaUtils.h2
-rw-r--r--launcher/java/JavaVersion_test.cpp1
-rw-r--r--launcher/launch/LaunchTask.cpp17
-rw-r--r--launcher/launch/LaunchTask.h43
-rw-r--r--launcher/launch/steps/CheckJava.cpp9
-rw-r--r--launcher/launch/steps/PostLaunchCommand.cpp50
-rw-r--r--launcher/launch/steps/PreLaunchCommand.cpp49
-rw-r--r--launcher/main.cpp37
-rw-r--r--launcher/meta/Index_test.cpp1
-rw-r--r--launcher/minecraft/ComponentUpdateTask.cpp8
-rw-r--r--launcher/minecraft/GradleSpecifier.h55
-rw-r--r--launcher/minecraft/GradleSpecifier_test.cpp1
-rw-r--r--launcher/minecraft/Library_test.cpp44
-rw-r--r--launcher/minecraft/MinecraftInstance.cpp74
-rw-r--r--launcher/minecraft/MinecraftInstance.h1
-rw-r--r--launcher/minecraft/MinecraftLoadAndCheck.cpp1
-rw-r--r--launcher/minecraft/MinecraftUpdate.cpp2
-rw-r--r--launcher/minecraft/MinecraftUpdate.h2
-rw-r--r--launcher/minecraft/MojangVersionFormat_test.cpp8
-rw-r--r--launcher/minecraft/OneSixVersionFormat.cpp37
-rw-r--r--launcher/minecraft/PackProfile.cpp45
-rw-r--r--launcher/minecraft/ParseUtils_test.cpp2
-rw-r--r--launcher/minecraft/ProfileUtils.cpp53
-rw-r--r--launcher/minecraft/ProfileUtils.h38
-rw-r--r--launcher/minecraft/VersionFile.cpp11
-rw-r--r--launcher/minecraft/World.cpp43
-rw-r--r--launcher/minecraft/WorldList.cpp50
-rw-r--r--launcher/minecraft/auth/AccountData.cpp5
-rw-r--r--launcher/minecraft/auth/AccountList.cpp22
-rw-r--r--launcher/minecraft/auth/AccountList.h4
-rw-r--r--launcher/minecraft/auth/AccountTask.cpp2
-rw-r--r--launcher/minecraft/auth/AuthRequest.cpp43
-rw-r--r--launcher/minecraft/auth/MinecraftAccount.cpp14
-rw-r--r--launcher/minecraft/auth/steps/YggdrasilStep.cpp1
-rw-r--r--launcher/minecraft/launch/DirectJavaLaunch.cpp22
-rw-r--r--launcher/minecraft/launch/LauncherPartLaunch.cpp31
-rw-r--r--launcher/minecraft/mod/ModFolderModel.cpp28
-rw-r--r--launcher/minecraft/mod/ModFolderModel_test.cpp3
-rw-r--r--launcher/minecraft/mod/testdata/test_folder/assets/minecraft/textures/blah.txt1
-rw-r--r--launcher/minecraft/mod/testdata/test_folder/pack.mcmeta6
-rw-r--r--launcher/minecraft/mod/testdata/test_folder/pack.nfo1
-rw-r--r--launcher/minecraft/services/CapeChange.cpp39
-rw-r--r--launcher/minecraft/services/SkinDelete.cpp39
-rw-r--r--launcher/minecraft/services/SkinUpload.cpp39
-rw-r--r--launcher/minecraft/update/AssetUpdateTask.cpp2
-rw-r--r--launcher/minecraft/update/FMLLibrariesTask.cpp1
-rw-r--r--launcher/minecraft/update/LibrariesTask.cpp1
-rw-r--r--launcher/modplatform/ModAPI.h36
-rw-r--r--launcher/modplatform/atlauncher/ATLPackInstallTask.cpp16
-rw-r--r--launcher/modplatform/flame/FileResolvingTask.cpp4
-rw-r--r--launcher/modplatform/flame/FlameAPI.h2
-rw-r--r--launcher/modplatform/flame/PackManifest.h37
-rw-r--r--launcher/modplatform/legacy_ftb/PackFetchTask.cpp37
-rw-r--r--launcher/modplatform/legacy_ftb/PackInstallTask.cpp39
-rw-r--r--launcher/modplatform/legacy_ftb/PrivatePackManager.cpp43
-rw-r--r--launcher/modplatform/modpacksch/FTBPackInstallTask.cpp4
-rw-r--r--launcher/modplatform/packwiz/Packwiz_test.cpp1
-rw-r--r--launcher/modplatform/technic/TechnicPackProcessor.cpp14
-rw-r--r--launcher/mojang/PackageManifest_test.cpp1
-rw-r--r--launcher/net/Download.cpp5
-rw-r--r--launcher/net/NetJob.cpp8
-rw-r--r--launcher/net/PasteUpload.cpp13
-rw-r--r--launcher/news/NewsChecker.cpp42
-rw-r--r--launcher/news/NewsEntry.cpp2
-rw-r--r--launcher/screenshots/ImgurAlbumCreation.cpp5
-rw-r--r--launcher/screenshots/ImgurUpload.cpp8
-rw-r--r--launcher/settings/INIFile.cpp48
-rw-r--r--launcher/settings/INIFile_test.cpp1
-rw-r--r--launcher/tasks/ConcurrentTask.cpp144
-rw-r--r--launcher/tasks/ConcurrentTask.h58
-rw-r--r--launcher/tasks/Task_test.cpp1
-rw-r--r--launcher/translations/POTranslator.cpp5
-rw-r--r--launcher/translations/POTranslator.h1
-rw-r--r--launcher/translations/TranslationsModel.cpp7
-rw-r--r--launcher/ui/GuiUtil.cpp1
-rw-r--r--launcher/ui/InstanceWindow.cpp50
-rw-r--r--launcher/ui/InstanceWindow.h44
-rw-r--r--launcher/ui/MainWindow.cpp219
-rw-r--r--launcher/ui/MainWindow.h14
-rw-r--r--launcher/ui/dialogs/AboutDialog.cpp2
-rw-r--r--launcher/ui/dialogs/CopyInstanceDialog.cpp46
-rw-r--r--launcher/ui/dialogs/ExportInstanceDialog.cpp4
-rw-r--r--launcher/ui/dialogs/NewComponentDialog.cpp41
-rw-r--r--launcher/ui/dialogs/NewInstanceDialog.cpp46
-rw-r--r--launcher/ui/dialogs/NewsDialog.cpp49
-rw-r--r--launcher/ui/dialogs/NewsDialog.h30
-rw-r--r--launcher/ui/dialogs/NewsDialog.ui113
-rw-r--r--launcher/ui/dialogs/ProfileSetupDialog.cpp46
-rw-r--r--launcher/ui/dialogs/SkinUploadDialog.cpp39
-rw-r--r--launcher/ui/dialogs/UpdateDialog.cpp37
-rw-r--r--launcher/ui/instanceview/InstanceDelegate.cpp46
-rw-r--r--launcher/ui/instanceview/InstanceView.cpp90
-rw-r--r--launcher/ui/instanceview/InstanceView.h44
-rw-r--r--launcher/ui/instanceview/VisualGroup.cpp49
-rw-r--r--launcher/ui/pages/global/AccountListPage.cpp18
-rw-r--r--launcher/ui/pages/global/CustomCommandsPage.cpp2
-rw-r--r--launcher/ui/pages/global/JavaPage.cpp5
-rw-r--r--launcher/ui/pages/global/LauncherPage.cpp38
-rw-r--r--launcher/ui/pages/global/LauncherPage.h5
-rw-r--r--launcher/ui/pages/global/LauncherPage.ui5
-rw-r--r--launcher/ui/pages/global/MinecraftPage.cpp13
-rw-r--r--launcher/ui/pages/global/MinecraftPage.ui60
-rw-r--r--launcher/ui/pages/global/ProxyPage.cpp16
-rw-r--r--launcher/ui/pages/global/ProxyPage.h9
-rw-r--r--launcher/ui/pages/instance/ExternalResourcesPage.cpp297
-rw-r--r--launcher/ui/pages/instance/ExternalResourcesPage.h73
-rw-r--r--launcher/ui/pages/instance/ExternalResourcesPage.ui (renamed from launcher/ui/pages/instance/ModFolderPage.ui)49
-rw-r--r--launcher/ui/pages/instance/InstanceSettingsPage.cpp34
-rw-r--r--launcher/ui/pages/instance/InstanceSettingsPage.ui68
-rw-r--r--launcher/ui/pages/instance/LogPage.cpp3
-rw-r--r--launcher/ui/pages/instance/ModFolderPage.cpp381
-rw-r--r--launcher/ui/pages/instance/ModFolderPage.h113
-rw-r--r--launcher/ui/pages/instance/ResourcePackPage.h20
-rw-r--r--launcher/ui/pages/instance/ScreenshotsPage.cpp5
-rw-r--r--launcher/ui/pages/instance/ScreenshotsPage.h1
-rw-r--r--launcher/ui/pages/instance/ServersPage.cpp13
-rw-r--r--launcher/ui/pages/instance/ServersPage.h3
-rw-r--r--launcher/ui/pages/instance/ShaderPackPage.h16
-rw-r--r--launcher/ui/pages/instance/TexturePackPage.h18
-rw-r--r--launcher/ui/pages/instance/VersionPage.cpp2
-rw-r--r--launcher/ui/pages/instance/WorldListPage.cpp1
-rw-r--r--launcher/ui/pages/modplatform/ImportPage.cpp2
-rw-r--r--launcher/ui/pages/modplatform/ModModel.cpp10
-rw-r--r--launcher/ui/pages/modplatform/flame/FlameModPage.cpp2
-rw-r--r--launcher/ui/pages/modplatform/flame/FlameModPage.h2
-rw-r--r--launcher/ui/pages/modplatform/flame/FlameModel.cpp16
-rw-r--r--launcher/ui/pages/modplatform/flame/FlameModel.h1
-rw-r--r--launcher/ui/pages/modplatform/flame/FlamePage.cpp25
-rw-r--r--launcher/ui/pages/modplatform/flame/FlamePage.ui2
-rw-r--r--launcher/ui/pages/modplatform/legacy_ftb/ListModel.cpp4
-rw-r--r--launcher/ui/pages/modplatform/legacy_ftb/Page.cpp3
-rw-r--r--launcher/ui/pages/modplatform/legacy_ftb/Page.ui6
-rw-r--r--launcher/ui/pages/modplatform/modrinth/ModrinthModPage.cpp2
-rw-r--r--launcher/ui/pages/modplatform/modrinth/ModrinthModPage.h2
-rw-r--r--launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp26
-rw-r--r--launcher/ui/pages/modplatform/modrinth/ModrinthModel.h2
-rw-r--r--launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp35
-rw-r--r--launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui3
-rw-r--r--launcher/ui/pages/modplatform/technic/TechnicModel.cpp5
-rw-r--r--launcher/ui/widgets/CustomCommands.cpp2
-rw-r--r--launcher/ui/widgets/CustomCommands.h2
-rw-r--r--launcher/ui/widgets/JavaSettingsWidget.cpp5
-rw-r--r--launcher/ui/widgets/LabeledToolButton.cpp44
-rw-r--r--launcher/ui/widgets/LogView.cpp37
-rw-r--r--launcher/ui/widgets/PageContainer.cpp4
-rw-r--r--launcher/ui/widgets/VersionListView.cpp42
-rw-r--r--launcher/updater/DownloadTask_test.cpp196
-rw-r--r--launcher/updater/ExternalUpdater.h87
-rw-r--r--launcher/updater/MacSparkleUpdater.h126
-rw-r--r--launcher/updater/MacSparkleUpdater.mm222
-rw-r--r--launcher/updater/UpdateChecker.cpp131
-rw-r--r--launcher/updater/UpdateChecker.h21
-rw-r--r--launcher/updater/UpdateChecker_test.cpp149
-rw-r--r--launcher/updater/testdata/1.json43
-rw-r--r--launcher/updater/testdata/2.json31
-rw-r--r--launcher/updater/testdata/channels.json23
-rw-r--r--launcher/updater/testdata/errorChannels.json23
-rw-r--r--launcher/updater/testdata/fileOneA1
-rw-r--r--launcher/updater/testdata/fileOneB3
-rw-r--r--launcher/updater/testdata/fileThree1
-rw-r--r--launcher/updater/testdata/fileTwo1
-rw-r--r--launcher/updater/testdata/garbageChannels.json22
-rw-r--r--launcher/updater/testdata/index.json9
-rw-r--r--launcher/updater/testdata/noChannels.json5
-rw-r--r--launcher/updater/testdata/oneChannel.json11
-rw-r--r--launcher/updater/testdata/tst_DownloadTask-test_writeInstallScript.xml17
197 files changed, 4451 insertions, 2033 deletions
diff --git a/launcher/Application.cpp b/launcher/Application.cpp
index 85b0d788..f8c93259 100644
--- a/launcher/Application.cpp
+++ b/launcher/Application.cpp
@@ -84,6 +84,7 @@
#include <QDebug>
#include <QStyleFactory>
#include <QWindow>
+#include <QIcon>
#include "InstanceList.h"
@@ -99,7 +100,6 @@
#include "tools/JVisualVM.h"
#include "tools/MCEditTool.h"
-#include <xdgicon.h>
#include "settings/INISettingsObject.h"
#include "settings/Setting.h"
@@ -154,7 +154,6 @@ void appDebugOutput(QtMsgType type, const QMessageLogContext &context, const QSt
fflush(stderr);
}
-#ifdef LAUNCHER_WITH_UPDATER
QString getIdealPlatform(QString currentPlatform) {
auto info = Sys::getKernelInfo();
switch(info.kernelType) {
@@ -193,7 +192,6 @@ QString getIdealPlatform(QString currentPlatform) {
}
return currentPlatform;
}
-#endif
}
@@ -226,7 +224,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
setOrganizationName(BuildConfig.LAUNCHER_NAME);
setOrganizationDomain(BuildConfig.LAUNCHER_DOMAIN);
setApplicationName(BuildConfig.LAUNCHER_NAME);
- setApplicationDisplayName(BuildConfig.LAUNCHER_DISPLAYNAME);
+ setApplicationDisplayName(QString("%1 %2").arg(BuildConfig.LAUNCHER_DISPLAYNAME, BuildConfig.printableVersionString()));
setApplicationVersion(BuildConfig.printableVersionString());
setDesktopFileName(BuildConfig.LAUNCHER_DESKTOPFILENAME);
startTime = QDateTime::currentDateTime();
@@ -334,10 +332,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
// on macOS, touch the root to force Finder to reload the .app metadata (and fix any icon change issues)
FS::updateTimestamp(m_rootPath);
#endif
-
-#ifdef LAUNCHER_JARS_LOCATION
- m_jarsPath = TOSTRING(LAUNCHER_JARS_LOCATION);
-#endif
}
QString adjustedBy;
@@ -549,6 +543,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
{
m_settings.reset(new INISettingsObject(BuildConfig.LAUNCHER_CONFIGFILE, this));
// Updates
+ // Multiple channels are separated by spaces
m_settings->registerSetting("UpdateChannel", BuildConfig.VERSION_CHANNEL);
m_settings->registerSetting("AutoUpdate", true);
@@ -638,6 +633,11 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
m_settings->registerSetting("UseNativeOpenAL", false);
m_settings->registerSetting("UseNativeGLFW", false);
+ // Peformance related options
+ m_settings->registerSetting("EnableFeralGamemode", false);
+ m_settings->registerSetting("EnableMangoHud", false);
+ m_settings->registerSetting("UseDiscreteGpu", false);
+
// Game time
m_settings->registerSetting("ShowGameTime", true);
m_settings->registerSetting("ShowGlobalGameTime", true);
@@ -757,7 +757,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
qDebug() << "<> Translations loaded.";
}
-#ifdef LAUNCHER_WITH_UPDATER
// initialize the updater
if(BuildConfig.UPDATER_ENABLED)
{
@@ -767,7 +766,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
m_updateChecker.reset(new UpdateChecker(m_network, channelUrl, BuildConfig.VERSION_CHANNEL, BuildConfig.VERSION_BUILD));
qDebug() << "<> Updater started.";
}
-#endif
// Instance icons
{
@@ -1185,7 +1183,7 @@ void Application::setApplicationTheme(const QString& name, bool initial)
void Application::setIconTheme(const QString& name)
{
- XdgIcon::setThemeName(name);
+ QIcon::setThemeName(name);
}
QIcon Application::getThemedIcon(const QString& name)
@@ -1193,7 +1191,7 @@ QIcon Application::getThemedIcon(const QString& name)
if(name == "logo") {
return QIcon(":/org.polymc.PolyMC.svg");
}
- return XdgIcon::fromTheme(name);
+ return QIcon::fromTheme(name);
}
bool Application::openJsonEditor(const QString &filename)
@@ -1413,9 +1411,7 @@ MainWindow* Application::showMainWindow(bool minimized)
}
m_mainWindow->checkInstancePathForProblems();
-#ifdef LAUNCHER_WITH_UPDATER
connect(this, &Application::updateAllowedChanged, m_mainWindow, &MainWindow::updatesAllowedChanged);
-#endif
connect(m_mainWindow, &MainWindow::isClosing, this, &Application::on_windowClose);
m_openWindows++;
}
@@ -1557,13 +1553,22 @@ shared_qobject_ptr<Meta::Index> Application::metadataIndex()
return m_metadataIndex;
}
-QString Application::getJarsPath()
+QString Application::getJarPath(QString jarFile)
{
- if(m_jarsPath.isEmpty())
+ QStringList potentialPaths = {
+#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
+ FS::PathCombine(m_rootPath, "share/jars"),
+#endif
+ FS::PathCombine(m_rootPath, "jars"),
+ FS::PathCombine(applicationDirPath(), "jars")
+ };
+ for(QString p : potentialPaths)
{
- return FS::PathCombine(QCoreApplication::applicationDirPath(), "jars");
+ QString jarPath = FS::PathCombine(p, jarFile);
+ if (QFileInfo(jarPath).isFile())
+ return jarPath;
}
- return FS::PathCombine(m_rootPath, m_jarsPath);
+ return {};
}
QString Application::getMSAClientID()
diff --git a/launcher/Application.h b/launcher/Application.h
index 09007160..e3b4fced 100644
--- a/launcher/Application.h
+++ b/launcher/Application.h
@@ -42,10 +42,7 @@
#include <QIcon>
#include <QDateTime>
#include <QUrl>
-
-#ifdef LAUNCHER_WITH_UPDATER
#include <updater/GoUpdate.h>
-#endif
#include <BaseInstance.h>
@@ -157,7 +154,11 @@ public:
shared_qobject_ptr<Meta::Index> metadataIndex();
- QString getJarsPath();
+ /*!
+ * Finds and returns the full path to a jar file.
+ * Returns a null-string if it could not be found.
+ */
+ QString getJarPath(QString jarFile);
QString getMSAClientID();
QString getCurseKey();
@@ -241,7 +242,6 @@ private:
std::shared_ptr<GenericPageProvider> m_globalSettingsProvider;
std::map<QString, std::unique_ptr<ITheme>> m_themes;
std::unique_ptr<MCEditTool> m_mcedit;
- QString m_jarsPath;
QSet<QString> m_features;
QMap<QString, std::shared_ptr<BaseProfilerFactory>> m_profilers;
diff --git a/launcher/ApplicationMessage.cpp b/launcher/ApplicationMessage.cpp
index e22bf13c..ca276b89 100644
--- a/launcher/ApplicationMessage.cpp
+++ b/launcher/ApplicationMessage.cpp
@@ -1,11 +1,47 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 "ApplicationMessage.h"
#include <QJsonDocument>
#include <QJsonObject>
+#include "Json.h"
void ApplicationMessage::parse(const QByteArray & input) {
- auto doc = QJsonDocument::fromBinaryData(input);
- auto root = doc.object();
+ auto doc = Json::requireDocument(input, "ApplicationMessage");
+ auto root = Json::requireObject(doc, "ApplicationMessage");
command = root.value("command").toString();
args.clear();
@@ -25,7 +61,5 @@ QByteArray ApplicationMessage::serialize() {
}
root.insert("args", outArgs);
- QJsonDocument out;
- out.setObject(root);
- return out.toBinaryData();
+ return Json::toText(root);
}
diff --git a/launcher/BaseInstance.cpp b/launcher/BaseInstance.cpp
index 0efbdddc..5a84a931 100644
--- a/launcher/BaseInstance.cpp
+++ b/launcher/BaseInstance.cpp
@@ -39,6 +39,7 @@
#include <QFileInfo>
#include <QDir>
#include <QDebug>
+#include <QRegularExpression>
#include "settings/INISettingsObject.h"
#include "settings/Setting.h"
@@ -335,7 +336,7 @@ QString BaseInstance::name() const
QString BaseInstance::windowTitle() const
{
- return BuildConfig.LAUNCHER_NAME + ": " + name().replace(QRegExp("[ \n\r\t]+"), " ");
+ return BuildConfig.LAUNCHER_NAME + ": " + name().replace(QRegularExpression("\\s+"), " ");
}
// FIXME: why is this here? move it to MinecraftInstance!!!
diff --git a/launcher/BaseInstance.h b/launcher/BaseInstance.h
index 66177614..2a94dcc6 100644
--- a/launcher/BaseInstance.h
+++ b/launcher/BaseInstance.h
@@ -188,6 +188,7 @@ public:
* Create envrironment variables for running the instance
*/
virtual QProcessEnvironment createEnvironment() = 0;
+ virtual QProcessEnvironment createLaunchEnvironment() = 0;
/*!
* Returns a matcher that can maps relative paths within the instance to whether they are 'log files'
diff --git a/launcher/BaseVersionList.cpp b/launcher/BaseVersionList.cpp
index aa9cb6cf..b4a7d6dd 100644
--- a/launcher/BaseVersionList.cpp
+++ b/launcher/BaseVersionList.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * 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 "BaseVersionList.h"
@@ -51,7 +71,7 @@ QVariant BaseVersionList::data(const QModelIndex &index, int role) const
switch (role)
{
case VersionPointerRole:
- return qVariantFromValue(version);
+ return QVariant::fromValue(version);
case VersionRole:
return version->name();
diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt
index b8db803b..ecdeaac0 100644
--- a/launcher/CMakeLists.txt
+++ b/launcher/CMakeLists.txt
@@ -4,8 +4,6 @@ project(application)
######## Sources and headers ########
-include (UnitTest)
-
set(CORE_SOURCES
# LOGIC - Base classes and infrastructure
BaseInstaller.h
@@ -90,16 +88,11 @@ set(CORE_SOURCES
MMCTime.cpp
)
-add_unit_test(FileSystem
- SOURCES FileSystem_test.cpp
- LIBS Launcher_logic
- DATA testdata
- )
+ecm_add_test(FileSystem_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
+ TEST_NAME FileSystem) # TODO: needs testdata
-add_unit_test(GZip
- SOURCES GZip_test.cpp
- LIBS Launcher_logic
- )
+ecm_add_test(GZip_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
+ TEST_NAME GZip)
set(PATHMATCHER_SOURCES
# Path matchers
@@ -156,29 +149,21 @@ set(LAUNCH_SOURCES
launch/LogModel.h
)
-if (Launcher_UPDATER_BASE)
- set(Launcher_APP_BINARY_DEFS "-DLAUNCHER_WITH_UPDATER ${Launcher_APP_BINARY_DEFS}")
- # Old update system
- set(UPDATE_SOURCES
- updater/GoUpdate.h
- updater/GoUpdate.cpp
- updater/UpdateChecker.h
- updater/UpdateChecker.cpp
- updater/DownloadTask.h
- updater/DownloadTask.cpp
- )
+# Old update system
+set(UPDATE_SOURCES
+ updater/GoUpdate.h
+ updater/GoUpdate.cpp
+ updater/UpdateChecker.h
+ updater/UpdateChecker.cpp
+ updater/DownloadTask.h
+ updater/DownloadTask.cpp
+ updater/ExternalUpdater.h
+)
- add_unit_test(UpdateChecker
- SOURCES updater/UpdateChecker_test.cpp
- LIBS Launcher_logic
- DATA updater/testdata
- )
- add_unit_test(DownloadTask
- SOURCES updater/DownloadTask_test.cpp
- LIBS Launcher_logic
- DATA updater/testdata
- )
-endif()
+set(MAC_UPDATE_SOURCES
+ updater/MacSparkleUpdater.h
+ updater/MacSparkleUpdater.mm
+)
# Backend for the news bar... there's usually no news.
set(NEWS_SOURCES
@@ -359,10 +344,8 @@ set(MINECRAFT_SOURCES
mojang/PackageManifest.cpp
minecraft/Agent.h)
-add_unit_test(GradleSpecifier
- SOURCES minecraft/GradleSpecifier_test.cpp
- LIBS Launcher_logic
- )
+ecm_add_test(minecraft/GradleSpecifier_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
+ TEST_NAME GradleSpecifier)
if(BUILD_TESTING)
add_executable(PackageManifest
@@ -370,7 +353,7 @@ if(BUILD_TESTING)
)
target_link_libraries(PackageManifest
Launcher_logic
- Qt5::Test
+ Qt${QT_VERSION_MAJOR}::Test
)
target_include_directories(PackageManifest
PRIVATE ../cmake/UnitTest/
@@ -382,28 +365,20 @@ if(BUILD_TESTING)
)
endif()
-add_unit_test(MojangVersionFormat
- SOURCES minecraft/MojangVersionFormat_test.cpp
- LIBS Launcher_logic
- DATA minecraft/testdata
- )
+# TODO: needs minecraft/testdata
+ecm_add_test(minecraft/MojangVersionFormat_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
+ TEST_NAME MojangVersionFormat)
-add_unit_test(Library
- SOURCES minecraft/Library_test.cpp
- LIBS Launcher_logic
- )
+ecm_add_test(minecraft/Library_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
+ TEST_NAME Library)
# FIXME: shares data with FileSystem test
-add_unit_test(ModFolderModel
- SOURCES minecraft/mod/ModFolderModel_test.cpp
- DATA testdata
- LIBS Launcher_logic
- )
+# TODO: needs testdata
+ecm_add_test(minecraft/mod/ModFolderModel_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
+ TEST_NAME ModFolderModel)
-add_unit_test(ParseUtils
- SOURCES minecraft/ParseUtils_test.cpp
- LIBS Launcher_logic
- )
+ecm_add_test(minecraft/ParseUtils_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
+ TEST_NAME ParseUtils)
# the screenshots feature
set(SCREENSHOTS_SOURCES
@@ -418,14 +393,14 @@ set(TASKS_SOURCES
# Tasks
tasks/Task.h
tasks/Task.cpp
+ tasks/ConcurrentTask.h
+ tasks/ConcurrentTask.cpp
tasks/SequentialTask.h
tasks/SequentialTask.cpp
)
-add_unit_test(Task
- SOURCES tasks/Task_test.cpp
- LIBS Launcher_logic
- )
+ecm_add_test(tasks/Task_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
+ TEST_NAME Task)
set(SETTINGS_SOURCES
# Settings
@@ -443,10 +418,8 @@ set(SETTINGS_SOURCES
settings/SettingsObject.h
)
-add_unit_test(INIFile
- SOURCES settings/INIFile_test.cpp
- LIBS Launcher_logic
- )
+ecm_add_test(settings/INIFile_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
+ TEST_NAME INIFile)
set(JAVA_SOURCES
java/JavaChecker.h
@@ -463,10 +436,8 @@ set(JAVA_SOURCES
java/JavaVersion.cpp
)
-add_unit_test(JavaVersion
- SOURCES java/JavaVersion_test.cpp
- LIBS Launcher_logic
- )
+ecm_add_test(java/JavaVersion_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
+ TEST_NAME JavaVersion)
set(TRANSLATIONS_SOURCES
translations/TranslationsModel.h
@@ -511,7 +482,7 @@ set(API_SOURCES
modplatform/flame/FlameAPI.h
modplatform/modrinth/ModrinthAPI.h
-
+
modplatform/helpers/NetworkModAPI.h
modplatform/helpers/NetworkModAPI.cpp
)
@@ -558,11 +529,9 @@ set(PACKWIZ_SOURCES
modplatform/packwiz/Packwiz.cpp
)
-add_unit_test(Packwiz
- SOURCES modplatform/packwiz/Packwiz_test.cpp
- DATA modplatform/packwiz/testdata
- LIBS Launcher_logic
- )
+# TODO: needs modplatform/packwiz/testdata
+ecm_add_test(modplatform/packwiz/Packwiz_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
+ TEST_NAME Packwiz)
set(TECHNIC_SOURCES
modplatform/technic/SingleZipPackInstallTask.h
@@ -586,10 +555,8 @@ set(ATLAUNCHER_SOURCES
modplatform/atlauncher/ATLShareCode.h
)
-add_unit_test(Index
- SOURCES meta/Index_test.cpp
- LIBS Launcher_logic
- )
+ecm_add_test(meta/Index_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
+ TEST_NAME Index)
################################ COMPILE ################################
@@ -622,6 +589,10 @@ set(LOGIC_SOURCES
${ATLAUNCHER_SOURCES}
)
+if(APPLE)
+ set (LOGIC_SOURCES ${LOGIC_SOURCES} ${MAC_UPDATE_SOURCES})
+endif()
+
SET(LAUNCHER_SOURCES
# Application base
Application.h
@@ -717,6 +688,8 @@ SET(LAUNCHER_SOURCES
ui/pages/BasePageProvider.h
# GUI - instance pages
+ ui/pages/instance/ExternalResourcesPage.cpp
+ ui/pages/instance/ExternalResourcesPage.h
ui/pages/instance/GameOptionsPage.cpp
ui/pages/instance/GameOptionsPage.h
ui/pages/instance/VersionPage.cpp
@@ -845,6 +818,8 @@ SET(LAUNCHER_SOURCES
ui/dialogs/NewComponentDialog.h
ui/dialogs/NewInstanceDialog.cpp
ui/dialogs/NewInstanceDialog.h
+ ui/dialogs/NewsDialog.cpp
+ ui/dialogs/NewsDialog.h
ui/pagedialog/PageDialog.cpp
ui/pagedialog/PageDialog.h
ui/dialogs/ProgressDialog.cpp
@@ -915,7 +890,7 @@ SET(LAUNCHER_SOURCES
ui/instanceview/VisualGroup.h
)
-qt5_wrap_ui(LAUNCHER_UI
+qt_wrap_ui(LAUNCHER_UI
ui/setupwizard/PasteWizardPage.ui
ui/pages/global/AccountListPage.ui
ui/pages/global/JavaPage.ui
@@ -924,7 +899,7 @@ qt5_wrap_ui(LAUNCHER_UI
ui/pages/global/ProxyPage.ui
ui/pages/global/MinecraftPage.ui
ui/pages/global/ExternalToolsPage.ui
- ui/pages/instance/ModFolderPage.ui
+ ui/pages/instance/ExternalResourcesPage.ui
ui/pages/instance/NotesPage.ui
ui/pages/instance/LogPage.ui
ui/pages/instance/ServersPage.ui
@@ -954,6 +929,7 @@ qt5_wrap_ui(LAUNCHER_UI
ui/dialogs/NewInstanceDialog.ui
ui/dialogs/UpdateDialog.ui
ui/dialogs/NewComponentDialog.ui
+ ui/dialogs/NewsDialog.ui
ui/dialogs/ProfileSelectDialog.ui
ui/dialogs/SkinUploadDialog.ui
ui/dialogs/ExportInstanceDialog.ui
@@ -967,7 +943,7 @@ qt5_wrap_ui(LAUNCHER_UI
ui/dialogs/ScrollMessageBox.ui
)
-qt5_add_resources(LAUNCHER_RESOURCES
+qt_add_resources(LAUNCHER_RESOURCES
resources/backgrounds/backgrounds.qrc
resources/multimc/multimc.qrc
resources/pe_dark/pe_dark.qrc
@@ -997,21 +973,46 @@ target_link_libraries(Launcher_logic
tomlc99
BuildConfig
Katabasis
+ Qt${QT_VERSION_MAJOR}::Widgets
)
+
+if (UNIX AND NOT CYGWIN AND NOT APPLE)
+ target_link_libraries(Launcher_logic
+ gamemode
+ )
+endif()
+
target_link_libraries(Launcher_logic
- Qt5::Core
- Qt5::Xml
- Qt5::Network
- Qt5::Concurrent
- Qt5::Gui
+ Qt${QT_VERSION_MAJOR}::Core
+ Qt${QT_VERSION_MAJOR}::Xml
+ Qt${QT_VERSION_MAJOR}::Network
+ Qt${QT_VERSION_MAJOR}::Concurrent
+ Qt${QT_VERSION_MAJOR}::Gui
+ Qt${QT_VERSION_MAJOR}::Widgets
+ ${Launcher_QT_LIBS}
)
target_link_libraries(Launcher_logic
- Launcher_iconfix
QuaZip::QuaZip
hoedown
LocalPeer
Launcher_rainbow
)
+if(APPLE)
+ set(CMAKE_MACOSX_RPATH 1)
+ set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks/")
+
+ file(DOWNLOAD ${MACOSX_SPARKLE_DOWNLOAD_URL} ${CMAKE_BINARY_DIR}/Sparkle.tar.xz EXPECTED_HASH SHA256=${MACOSX_SPARKLE_SHA256})
+ file(ARCHIVE_EXTRACT INPUT ${CMAKE_BINARY_DIR}/Sparkle.tar.xz DESTINATION ${CMAKE_BINARY_DIR}/frameworks/Sparkle)
+
+ find_library(SPARKLE_FRAMEWORK Sparkle "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
+ target_link_libraries(Launcher_logic
+ "-framework AppKit"
+ "-framework Carbon"
+ "-framework Foundation"
+ "-framework ApplicationServices"
+ )
+ target_link_libraries(Launcher_logic ${SPARKLE_FRAMEWORK})
+endif()
target_link_libraries(Launcher_logic)
@@ -1034,8 +1035,16 @@ install(TARGETS ${Launcher_Name}
BUNDLE DESTINATION "." COMPONENT Runtime
LIBRARY DESTINATION ${LIBRARY_DEST_DIR} COMPONENT Runtime
RUNTIME DESTINATION ${BINARY_DEST_DIR} COMPONENT Runtime
+ FRAMEWORK DESTINATION ${FRAMEWORK_DEST_DIR} COMPONENT Runtime
)
+if (UNIX AND APPLE)
+ # Add Sparkle updater
+ # It has to be copied here instead of just allowing fixup_bundle to install it, otherwise essential parts of
+ # the framework aren't installed
+ install(DIRECTORY ${MACOSX_SPARKLE_DIR}/Sparkle.framework DESTINATION ${FRAMEWORK_DEST_DIR} USE_SOURCE_PERMISSIONS)
+endif()
+
#### The bundle mess! ####
# Bundle utilities are used to complete the portable packages - they add all the libraries that would otherwise be missing on the target system.
# NOTE: it seems that this absolutely has to be here, and nowhere else.
@@ -1076,6 +1085,14 @@ if(INSTALL_BUNDLE STREQUAL "full")
COMPONENT Runtime
)
endif()
+ # TLS plugins (Qt 6 only)
+ if(EXISTS "${QT_PLUGINS_DIR}/tls")
+ install(
+ DIRECTORY "${QT_PLUGINS_DIR}/tls"
+ DESTINATION ${PLUGIN_DEST_DIR}
+ COMPONENT Runtime
+ )
+ endif()
else()
# Image formats
install(
@@ -1118,6 +1135,16 @@ if(INSTALL_BUNDLE STREQUAL "full")
REGEX "\\.dSYM" EXCLUDE
)
endif()
+ # TLS plugins (Qt 6 only)
+ if(EXISTS "${QT_PLUGINS_DIR}/tls")
+ install(
+ DIRECTORY "${QT_PLUGINS_DIR}/tls"
+ DESTINATION ${PLUGIN_DEST_DIR}
+ COMPONENT Runtime
+ REGEX "_debug\\." EXCLUDE
+ REGEX "\\.dSYM" EXCLUDE
+ )
+ endif()
endif()
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/install_prereqs.cmake.in"
diff --git a/launcher/Commandline.cpp b/launcher/Commandline.cpp
index 2c0fde64..8e7356bb 100644
--- a/launcher/Commandline.cpp
+++ b/launcher/Commandline.cpp
@@ -1,18 +1,38 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
*
- * Authors: Orochimarufan <orochimarufan.x3@gmail.com>
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
*
- * 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
+ * Copyright 2013-2021 MultiMC Contributors
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Authors: Orochimarufan <orochimarufan.x3@gmail.com>
*
- * 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.
+ * 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 "Commandline.h"
@@ -47,7 +67,7 @@ QStringList splitArgs(QString args)
if (cchar == '\\')
escape = true;
else if (cchar == inquotes)
- inquotes = 0;
+ inquotes = QChar::Null;
else
current += cchar;
// otherwise
@@ -480,4 +500,4 @@ void Parser::getPrefix(QString &opt, QString &flag)
ParsingError::ParsingError(const QString &what) : std::runtime_error(what.toStdString())
{
}
-} \ No newline at end of file
+}
diff --git a/launcher/FileSystem.cpp b/launcher/FileSystem.cpp
index 3837d75f..ebb4460d 100644
--- a/launcher/FileSystem.cpp
+++ b/launcher/FileSystem.cpp
@@ -1,4 +1,37 @@
-// Licensed under the Apache-2.0 license. See README.md for details.
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 "FileSystem.h"
@@ -346,7 +379,7 @@ bool checkProblemticPathJava(QDir folder)
}
// Win32 crap
-#if defined Q_OS_WIN
+#ifdef Q_OS_WIN
bool called_coinit = false;
@@ -366,7 +399,7 @@ HRESULT CreateLink(LPCSTR linkPath, LPCSTR targetPath, LPCSTR args)
}
}
- IShellLink *link;
+ IShellLinkA *link;
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink,
(LPVOID *)&link);
diff --git a/launcher/FileSystem.h b/launcher/FileSystem.h
index bc942ab3..fd305b01 100644
--- a/launcher/FileSystem.h
+++ b/launcher/FileSystem.h
@@ -1,4 +1,37 @@
-// Licensed under the Apache-2.0 license. See README.md for details.
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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
@@ -49,8 +82,8 @@ class copy
public:
copy(const QString & src, const QString & dst)
{
- m_src = src;
- m_dst = dst;
+ m_src.setPath(src);
+ m_dst.setPath(dst);
}
copy & followSymlinks(const bool follow)
{
@@ -120,11 +153,6 @@ bool checkProblemticPathJava(QDir folder);
// Get the Directory representing the User's Desktop
QString getDesktopDir();
-// Create a shortcut at *location*, pointing to *dest* called with the arguments *args*
-// call it *name* and assign it the icon *icon*
-// return true if operation succeeded
-bool createShortCut(QString location, QString dest, QStringList args, QString name, QString iconLocation);
-
// Overrides one folder with the contents of another, preserving items exclusive to the first folder
// Equivalent to doing QDir::rename, but allowing for overrides
bool overrideFolder(QString overwritten_path, QString override_path);
diff --git a/launcher/FileSystem_test.cpp b/launcher/FileSystem_test.cpp
index 90ddc499..99ae9269 100644
--- a/launcher/FileSystem_test.cpp
+++ b/launcher/FileSystem_test.cpp
@@ -1,7 +1,6 @@
#include <QTest>
#include <QTemporaryDir>
#include <QStandardPaths>
-#include "TestUtil.h"
#include "FileSystem.h"
@@ -81,7 +80,7 @@ slots:
void test_copy()
{
- QString folder = QFINDTESTDATA("data/test_folder");
+ QString folder = QFINDTESTDATA("testdata/test_folder");
auto f = [&folder]()
{
QTemporaryDir tempDir;
@@ -116,47 +115,6 @@ slots:
{
QCOMPARE(FS::getDesktopDir(), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation));
}
-
-// this is only valid on linux
-// FIXME: implement on windows, OSX, then test.
-#if defined(Q_OS_LINUX)
- void test_createShortcut_data()
- {
- QTest::addColumn<QString>("location");
- QTest::addColumn<QString>("dest");
- QTest::addColumn<QStringList>("args");
- QTest::addColumn<QString>("name");
- QTest::addColumn<QString>("iconLocation");
- QTest::addColumn<QByteArray>("result");
-
- QTest::newRow("unix") << QDir::currentPath()
- << "asdfDest"
- << (QStringList() << "arg1" << "arg2")
- << "asdf"
- << QString()
- #if defined(Q_OS_LINUX)
- << GET_TEST_FILE("data/FileSystem-test_createShortcut-unix")
- #elif defined(Q_OS_WIN)
- << QByteArray()
- #endif
- ;
- }
-
- void test_createShortcut()
- {
- QFETCH(QString, location);
- QFETCH(QString, dest);
- QFETCH(QStringList, args);
- QFETCH(QString, name);
- QFETCH(QString, iconLocation);
- QFETCH(QByteArray, result);
-
- QVERIFY(FS::createShortCut(location, dest, args, name, iconLocation));
- QCOMPARE(QString::fromLocal8Bit(TestsInternal::readFile(location + QDir::separator() + name + ".desktop")), QString::fromLocal8Bit(result));
-
- //QDir().remove(location);
- }
-#endif
};
QTEST_GUILESS_MAIN(FileSystemTest)
diff --git a/launcher/GZip.cpp b/launcher/GZip.cpp
index 0368c32d..067104cf 100644
--- a/launcher/GZip.cpp
+++ b/launcher/GZip.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 "GZip.h"
#include <zlib.h>
#include <QByteArray>
@@ -67,7 +102,7 @@ bool GZip::zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes)
return true;
}
- unsigned compLength = std::min(uncompressedBytes.size(), 16);
+ unsigned compLength = qMin(uncompressedBytes.size(), 16);
compressedBytes.clear();
compressedBytes.resize(compLength);
@@ -112,4 +147,4 @@ bool GZip::zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes)
return false;
}
return true;
-} \ No newline at end of file
+}
diff --git a/launcher/GZip_test.cpp b/launcher/GZip_test.cpp
index 3f4d181c..73859fbc 100644
--- a/launcher/GZip_test.cpp
+++ b/launcher/GZip_test.cpp
@@ -1,5 +1,4 @@
#include <QTest>
-#include "TestUtil.h"
#include "GZip.h"
#include <random>
diff --git a/launcher/InstanceImportTask.cpp b/launcher/InstanceImportTask.cpp
index d5684805..14e1cd47 100644
--- a/launcher/InstanceImportTask.cpp
+++ b/launcher/InstanceImportTask.cpp
@@ -325,7 +325,7 @@ void InstanceImportTask::processFlame()
// Hack to correct some 'special sauce'...
if(mcVersion.endsWith('.'))
{
- mcVersion.remove(QRegExp("[.]+$"));
+ mcVersion.remove(QRegularExpression("[.]+$"));
logWarning(tr("Mysterious trailing dots removed from Minecraft version while importing pack."));
}
auto components = instance.getPackProfile();
@@ -412,12 +412,8 @@ void InstanceImportTask::processFlame()
"You will need to manually download them and add them to the modpack"),
text);
message_dialog->setModal(true);
- message_dialog->show();
- connect(message_dialog, &QDialog::rejected, [&]() {
- m_modIdResolver.reset();
- emitFailed("Canceled");
- });
- connect(message_dialog, &QDialog::accepted, [&]() {
+
+ if (message_dialog->exec()) {
m_filesNetJob = new NetJob(tr("Mod download"), APPLICATION->network());
for (const auto &result: m_modIdResolver->getResults().files) {
QString filename = result.fileName;
@@ -469,8 +465,11 @@ void InstanceImportTask::processFlame()
});
setStatus(tr("Downloading mods..."));
m_filesNetJob->start();
- });
- }else{
+ } else {
+ m_modIdResolver.reset();
+ emitFailed("Canceled");
+ }
+ } else {
//TODO extract to function ?
m_filesNetJob = new NetJob(tr("Mod download"), APPLICATION->network());
for (const auto &result: m_modIdResolver->getResults().files) {
@@ -723,11 +722,11 @@ void InstanceImportTask::processModrinth()
components->buildingFromScratch();
components->setComponentVersion("net.minecraft", minecraftVersion, true);
if (!fabricVersion.isEmpty())
- components->setComponentVersion("net.fabricmc.fabric-loader", fabricVersion, true);
+ components->setComponentVersion("net.fabricmc.fabric-loader", fabricVersion);
if (!quiltVersion.isEmpty())
- components->setComponentVersion("org.quiltmc.quilt-loader", quiltVersion, true);
+ components->setComponentVersion("org.quiltmc.quilt-loader", quiltVersion);
if (!forgeVersion.isEmpty())
- components->setComponentVersion("net.minecraftforge", forgeVersion, true);
+ components->setComponentVersion("net.minecraftforge", forgeVersion);
if (m_instIcon != "default")
{
instance.setIconKey(m_instIcon);
diff --git a/launcher/InstanceList.cpp b/launcher/InstanceList.cpp
index 3e3c81f7..fb7103dd 100644
--- a/launcher/InstanceList.cpp
+++ b/launcher/InstanceList.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * 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 <QDir>
@@ -136,7 +156,7 @@ QVariant InstanceList::data(const QModelIndex &index, int role) const
{
case InstancePointerRole:
{
- QVariant v = qVariantFromValue((void *)pdata);
+ QVariant v = QVariant::fromValue((void *)pdata);
return v;
}
case InstanceIDRole:
@@ -252,7 +272,7 @@ void InstanceList::setInstanceGroup(const InstanceId& id, const GroupId& name)
QStringList InstanceList::getGroups()
{
- return m_groupNameCache.toList();
+ return m_groupNameCache.values();
}
void InstanceList::deleteGroup(const QString& name)
@@ -353,7 +373,11 @@ QList< InstanceId > InstanceList::discoverInstances()
out.append(id);
qDebug() << "Found instance ID" << id;
}
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+ instanceSet = QSet<QString>(out.begin(), out.end());
+#else
instanceSet = out.toSet();
+#endif
m_instancesProbed = true;
return out;
}
diff --git a/launcher/InstancePageProvider.h b/launcher/InstancePageProvider.h
index 357157d0..78fb7016 100644
--- a/launcher/InstancePageProvider.h
+++ b/launcher/InstancePageProvider.h
@@ -33,10 +33,10 @@ public:
values.append(new LogPage(inst));
std::shared_ptr<MinecraftInstance> onesix = std::dynamic_pointer_cast<MinecraftInstance>(inst);
values.append(new VersionPage(onesix.get()));
- auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList(), "mods", "loadermods", tr("Mods"), "Loader-mods");
+ auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList());
modsPage->setFilter("%1 (*.zip *.jar *.litemod)");
values.append(modsPage);
- values.append(new CoreModFolderPage(onesix.get(), onesix->coreModList(), "coremods", "coremods", tr("Core mods"), "Core-mods"));
+ values.append(new CoreModFolderPage(onesix.get(), onesix->coreModList()));
values.append(new ResourcePackPage(onesix.get()));
values.append(new TexturePackPage(onesix.get()));
values.append(new ShaderPackPage(onesix.get()));
diff --git a/launcher/JavaCommon.cpp b/launcher/JavaCommon.cpp
index 17278d86..4ba319b8 100644
--- a/launcher/JavaCommon.cpp
+++ b/launcher/JavaCommon.cpp
@@ -1,10 +1,47 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 "JavaCommon.h"
+#include "java/JavaUtils.h"
#include "ui/dialogs/CustomMessageBox.h"
#include <MMCStrings.h>
+#include <QRegularExpression>
bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget *parent)
{
- if (jvmargs.contains("-XX:PermSize=") || jvmargs.contains(QRegExp("-Xm[sx]"))
+ if (jvmargs.contains("-XX:PermSize=") || jvmargs.contains(QRegularExpression("-Xm[sx]"))
|| jvmargs.contains("-XX-MaxHeapSize") || jvmargs.contains("-XX:InitialHeapSize"))
{
auto warnStr = QObject::tr(
@@ -18,7 +55,7 @@ bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget *parent)
return false;
}
// block lunacy with passing required version to the JVM
- if (jvmargs.contains(QRegExp("-version:.*"))) {
+ if (jvmargs.contains(QRegularExpression("-version:.*"))) {
auto warnStr = QObject::tr(
"You tried to pass required Java version argument to the JVM (using \"-version:xxx\"). This is not safe and will not be allowed.\n"
"This message will be displayed until you remove this from the JVM arguments.");
@@ -65,6 +102,13 @@ void JavaCommon::javaBinaryWasBad(QWidget *parent, JavaCheckResult result)
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
}
+void JavaCommon::javaCheckNotFound(QWidget *parent)
+{
+ QString text;
+ text += QObject::tr("Java checker library could not be found. Please check your installation");
+ CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
+}
+
void JavaCommon::TestCheck::run()
{
if (!JavaCommon::checkJVMArgs(m_args, m_parent))
@@ -72,6 +116,11 @@ void JavaCommon::TestCheck::run()
emit finished();
return;
}
+ if (JavaUtils::getJavaCheckPath().isEmpty()) {
+ javaCheckNotFound(m_parent);
+ emit finished();
+ return;
+ }
checker.reset(new JavaChecker());
connect(checker.get(), SIGNAL(checkFinished(JavaCheckResult)), this,
SLOT(checkFinished(JavaCheckResult)));
diff --git a/launcher/JavaCommon.h b/launcher/JavaCommon.h
index ca98145c..59cb7a67 100644
--- a/launcher/JavaCommon.h
+++ b/launcher/JavaCommon.h
@@ -10,12 +10,14 @@ namespace JavaCommon
{
bool checkJVMArgs(QString args, QWidget *parent);
- // Show a dialog saying that the Java binary was not usable
- void javaBinaryWasBad(QWidget *parent, JavaCheckResult result);
- // Show a dialog saying that the Java binary was not usable because of bad options
- void javaArgsWereBad(QWidget *parent, JavaCheckResult result);
// Show a dialog saying that the Java binary was usable
void javaWasOk(QWidget *parent, JavaCheckResult result);
+ // Show a dialog saying that the Java binary was not usable because of bad options
+ void javaArgsWereBad(QWidget *parent, JavaCheckResult result);
+ // Show a dialog saying that the Java binary was not usable
+ void javaBinaryWasBad(QWidget *parent, JavaCheckResult result);
+ // Show a dialog if we couldn't find Java Checker
+ void javaCheckNotFound(QWidget *parent);
class TestCheck : public QObject
{
diff --git a/launcher/Json.cpp b/launcher/Json.cpp
index 37ada1aa..06b3d3bd 100644
--- a/launcher/Json.cpp
+++ b/launcher/Json.cpp
@@ -1,4 +1,37 @@
-// Licensed under the Apache-2.0 license. See README.md for details.
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 "Json.h"
@@ -22,14 +55,6 @@ void write(const QJsonArray &array, const QString &filename)
write(QJsonDocument(array), filename);
}
-QByteArray toBinary(const QJsonObject &obj)
-{
- return QJsonDocument(obj).toBinaryData();
-}
-QByteArray toBinary(const QJsonArray &array)
-{
- return QJsonDocument(array).toBinaryData();
-}
QByteArray toText(const QJsonObject &obj)
{
return QJsonDocument(obj).toJson(QJsonDocument::Compact);
@@ -48,12 +73,8 @@ QJsonDocument requireDocument(const QByteArray &data, const QString &what)
{
if (isBinaryJson(data))
{
- QJsonDocument doc = QJsonDocument::fromBinaryData(data);
- if (doc.isNull())
- {
- throw JsonException(what + ": Invalid JSON (binary JSON detected)");
- }
- return doc;
+ // FIXME: Is this needed?
+ throw JsonException(what + ": Invalid JSON. Binary JSON unsupported");
}
else
{
diff --git a/launcher/Json.h b/launcher/Json.h
index f2e68f0c..b11a356c 100644
--- a/launcher/Json.h
+++ b/launcher/Json.h
@@ -1,4 +1,37 @@
-// Licensed under the Apache-2.0 license. See README.md for details.
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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
@@ -29,8 +62,6 @@ void write(const QJsonObject &object, const QString &filename);
/// @throw FileSystemException
void write(const QJsonArray &array, const QString &filename);
-QByteArray toBinary(const QJsonObject &obj);
-QByteArray toBinary(const QJsonArray &array);
QByteArray toText(const QJsonObject &obj);
QByteArray toText(const QJsonArray &array);
diff --git a/launcher/LoggedProcess.cpp b/launcher/LoggedProcess.cpp
index 2479f4ff..fbdeed8f 100644
--- a/launcher/LoggedProcess.cpp
+++ b/launcher/LoggedProcess.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 "LoggedProcess.h"
#include "MessageLevel.h"
#include <QDebug>
@@ -8,7 +43,11 @@ LoggedProcess::LoggedProcess(QObject *parent) : QProcess(parent)
connect(this, &QProcess::readyReadStandardOutput, this, &LoggedProcess::on_stdOut);
connect(this, &QProcess::readyReadStandardError, this, &LoggedProcess::on_stdErr);
connect(this, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(on_exit(int,QProcess::ExitStatus)));
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ connect(this, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(on_error(QProcess::ProcessError)));
+#else
connect(this, SIGNAL(error(QProcess::ProcessError)), this, SLOT(on_error(QProcess::ProcessError)));
+#endif
connect(this, &QProcess::stateChanged, this, &LoggedProcess::on_stateChange);
}
@@ -157,19 +196,6 @@ void LoggedProcess::on_stateChange(QProcess::ProcessState state)
}
}
-#if defined Q_OS_WIN32
-#include <windows.h>
-#endif
-
-qint64 LoggedProcess::processId() const
-{
-#ifdef Q_OS_WIN
- return pid() ? pid()->dwProcessId : 0;
-#else
- return pid();
-#endif
-}
-
void LoggedProcess::setDetachable(bool detachable)
{
m_is_detachable = detachable;
diff --git a/launcher/LoggedProcess.h b/launcher/LoggedProcess.h
index e52b8a7b..61e74bd9 100644
--- a/launcher/LoggedProcess.h
+++ b/launcher/LoggedProcess.h
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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
+ * 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
+ * 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.
+ * 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
@@ -43,7 +63,6 @@ public:
State state() const;
int exitCode() const;
- qint64 processId() const;
void setDetachable(bool detachable);
diff --git a/launcher/MMCZip.cpp b/launcher/MMCZip.cpp
index d7ad4428..f20d6dff 100644
--- a/launcher/MMCZip.cpp
+++ b/launcher/MMCZip.cpp
@@ -421,7 +421,7 @@ bool MMCZip::collectFileListRecursively(const QString& rootDir, const QString& s
continue;
}
- files->append(e.filePath()); // we want the original paths for MMCZip::compressDirFiles
+ files->append(e); // we want the original paths for MMCZip::compressDirFiles
}
return true;
}
diff --git a/launcher/NullInstance.h b/launcher/NullInstance.h
index ed421433..9b0a9331 100644
--- a/launcher/NullInstance.h
+++ b/launcher/NullInstance.h
@@ -39,6 +39,10 @@ public:
{
return QProcessEnvironment();
}
+ QProcessEnvironment createLaunchEnvironment() override
+ {
+ return QProcessEnvironment();
+ }
QMap<QString, QString> getVariables() const override
{
return QMap<QString, QString>();
diff --git a/launcher/Version.h b/launcher/Version.h
index 9fe12d6d..aceb7a07 100644
--- a/launcher/Version.h
+++ b/launcher/Version.h
@@ -1,6 +1,42 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 <QString>
+#include <QStringView>
#include <QList>
class QUrl;
@@ -39,13 +75,21 @@ private:
break;
}
}
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ auto numPart = QStringView{m_fullString}.left(cutoff);
+#else
auto numPart = m_fullString.leftRef(cutoff);
+#endif
if(numPart.size())
{
numValid = true;
m_numPart = numPart.toInt();
}
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ auto stringPart = QStringView{m_fullString}.mid(cutoff);
+#else
auto stringPart = m_fullString.midRef(cutoff);
+#endif
if(stringPart.size())
{
m_stringPart = stringPart.toString();
diff --git a/launcher/VersionProxyModel.cpp b/launcher/VersionProxyModel.cpp
index b9a87c9c..032f21f9 100644
--- a/launcher/VersionProxyModel.cpp
+++ b/launcher/VersionProxyModel.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 "VersionProxyModel.h"
#include "Application.h"
#include <QSortFilterProxyModel>
@@ -208,7 +243,8 @@ QVariant VersionProxyModel::data(const QModelIndex &index, int role) const
{
return APPLICATION->getThemedIcon("bug");
}
- auto pixmap = QPixmapCache::find("placeholder");
+ QPixmap pixmap;
+ QPixmapCache::find("placeholder", &pixmap);
if(!pixmap)
{
QPixmap px(16,16);
@@ -216,7 +252,7 @@ QVariant VersionProxyModel::data(const QModelIndex &index, int role) const
QPixmapCache::insert("placeholder", px);
return px;
}
- return *pixmap;
+ return pixmap;
}
}
default:
diff --git a/launcher/icons/IconList.cpp b/launcher/icons/IconList.cpp
index d426aa80..3a223d1b 100644
--- a/launcher/icons/IconList.cpp
+++ b/launcher/icons/IconList.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * 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 "IconList.h"
@@ -86,7 +106,11 @@ void IconList::directoryChanged(const QString &path)
QString &foo = (*it);
foo = m_dir.filePath(foo);
}
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+ QSet<QString> new_set(new_list.begin(), new_list.end());
+#else
auto new_set = new_list.toSet();
+#endif
QList<QString> current_list;
for (auto &it : icons)
{
@@ -94,7 +118,11 @@ void IconList::directoryChanged(const QString &path)
continue;
current_list.push_back(it.m_images[IconType::FileBased].filename);
}
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+ QSet<QString> current_set(current_list.begin(), current_list.end());
+#else
QSet<QString> current_set = current_list.toSet();
+#endif
QSet<QString> to_remove = current_set;
to_remove -= new_set;
diff --git a/launcher/icons/MMCIcon.cpp b/launcher/icons/MMCIcon.cpp
index f0b82ec9..436ef75f 100644
--- a/launcher/icons/MMCIcon.cpp
+++ b/launcher/icons/MMCIcon.cpp
@@ -1,21 +1,41 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * 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 "MMCIcon.h"
#include <QFileInfo>
-#include <xdgicon.h>
+#include <QIcon>
IconType operator--(IconType &t, int)
{
@@ -63,7 +83,7 @@ QIcon MMCIcon::icon() const
if(!icon.isNull())
return icon;
// FIXME: inject this.
- return XdgIcon::fromTheme(m_images[m_current_type].key);
+ return QIcon::fromTheme(m_images[m_current_type].key);
}
void MMCIcon::remove(IconType rm_type)
diff --git a/launcher/java/JavaChecker.cpp b/launcher/java/JavaChecker.cpp
index 946599c5..041583d1 100644
--- a/launcher/java/JavaChecker.cpp
+++ b/launcher/java/JavaChecker.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 "JavaChecker.h"
#include <QFile>
@@ -16,7 +51,13 @@ JavaChecker::JavaChecker(QObject *parent) : QObject(parent)
void JavaChecker::performCheck()
{
- QString checkerJar = FS::PathCombine(APPLICATION->getJarsPath(), "JavaCheck.jar");
+ QString checkerJar = JavaUtils::getJavaCheckPath();
+
+ if (checkerJar.isEmpty())
+ {
+ qDebug() << "Java checker library could not be found. Please check your installation.";
+ return;
+ }
QStringList args;
@@ -47,7 +88,11 @@ void JavaChecker::performCheck()
qDebug() << "Running java checker: " + m_path + args.join(" ");;
connect(process.get(), SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(finished(int, QProcess::ExitStatus)));
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ connect(process.get(), SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(error(QProcess::ProcessError)));
+#else
connect(process.get(), SIGNAL(error(QProcess::ProcessError)), this, SLOT(error(QProcess::ProcessError)));
+#endif
connect(process.get(), SIGNAL(readyReadStandardOutput()), this, SLOT(stdoutReady()));
connect(process.get(), SIGNAL(readyReadStandardError()), this, SLOT(stderrReady()));
connect(&killTimer, SIGNAL(timeout()), SLOT(timeout()));
@@ -99,7 +144,12 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
bool success = true;
QMap<QString, QString> results;
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+ QStringList lines = m_stdout.split("\n", Qt::SkipEmptyParts);
+#else
QStringList lines = m_stdout.split("\n", QString::SkipEmptyParts);
+#endif
for(QString line : lines)
{
line = line.trimmed();
@@ -108,7 +158,11 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
continue;
}
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+ auto parts = line.split('=', Qt::SkipEmptyParts);
+#else
auto parts = line.split('=', QString::SkipEmptyParts);
+#endif
if(parts.size() != 2 || parts[0].isEmpty() || parts[1].isEmpty())
{
continue;
diff --git a/launcher/java/JavaInstallList.cpp b/launcher/java/JavaInstallList.cpp
index 9b745095..0249bd22 100644
--- a/launcher/java/JavaInstallList.cpp
+++ b/launcher/java/JavaInstallList.cpp
@@ -1,21 +1,40 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * 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 <QtNetwork>
#include <QtXml>
-#include <QRegExp>
#include <QDebug>
@@ -81,7 +100,7 @@ QVariant JavaInstallList::data(const QModelIndex &index, int role) const
switch (role)
{
case VersionPointerRole:
- return qVariantFromValue(m_vlist[index.row()]);
+ return QVariant::fromValue(m_vlist[index.row()]);
case VersionIdRole:
return version->descriptor();
case VersionRole:
diff --git a/launcher/java/JavaUtils.cpp b/launcher/java/JavaUtils.cpp
index 65a8b1db..c2b776ae 100644
--- a/launcher/java/JavaUtils.cpp
+++ b/launcher/java/JavaUtils.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * 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 <QStringList>
@@ -24,6 +44,7 @@
#include "java/JavaUtils.h"
#include "java/JavaInstallList.h"
#include "FileSystem.h"
+#include "Application.h"
#define IBUS "@im=ibus"
@@ -176,25 +197,25 @@ QList<JavaInstallPtr> JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString
archType = "32";
HKEY jreKey;
- if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, keyName.toStdString().c_str(), 0,
+ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyName.toStdWString().c_str(), 0,
KEY_READ | keyType | KEY_ENUMERATE_SUB_KEYS, &jreKey) == ERROR_SUCCESS)
{
// Read the current type version from the registry.
// This will be used to find any key that contains the JavaHome value.
char *value = new char[0];
DWORD valueSz = 0;
- if (RegQueryValueExA(jreKey, "CurrentVersion", NULL, NULL, (BYTE *)value, &valueSz) ==
+ if (RegQueryValueExW(jreKey, L"CurrentVersion", NULL, NULL, (BYTE *)value, &valueSz) ==
ERROR_MORE_DATA)
{
value = new char[valueSz];
- RegQueryValueExA(jreKey, "CurrentVersion", NULL, NULL, (BYTE *)value, &valueSz);
+ RegQueryValueExW(jreKey, L"CurrentVersion", NULL, NULL, (BYTE *)value, &valueSz);
}
TCHAR subKeyName[255];
DWORD subKeyNameSize, numSubKeys, retCode;
// Get the number of subkeys
- RegQueryInfoKey(jreKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL,
+ RegQueryInfoKeyW(jreKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL,
NULL, NULL);
// Iterate until RegEnumKeyEx fails
@@ -203,31 +224,32 @@ QList<JavaInstallPtr> JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString
for (DWORD i = 0; i < numSubKeys; i++)
{
subKeyNameSize = 255;
- retCode = RegEnumKeyEx(jreKey, i, subKeyName, &subKeyNameSize, NULL, NULL, NULL,
- NULL);
+ retCode = RegEnumKeyExW(jreKey, i, subKeyName, &subKeyNameSize, NULL, NULL, NULL,
+ NULL);
+ QString newSubkeyName = QString::fromWCharArray(subKeyName);
if (retCode == ERROR_SUCCESS)
{
// Now open the registry key for the version that we just got.
- QString newKeyName = keyName + "\\" + subKeyName + subkeySuffix;
+ QString newKeyName = keyName + "\\" + newSubkeyName + subkeySuffix;
HKEY newKey;
- if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, newKeyName.toStdString().c_str(), 0,
- KEY_READ | KEY_WOW64_64KEY, &newKey) == ERROR_SUCCESS)
+ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, newKeyName.toStdWString().c_str(), 0,
+ KEY_READ | KEY_WOW64_64KEY, &newKey) == ERROR_SUCCESS)
{
// Read the JavaHome value to find where Java is installed.
value = new char[0];
valueSz = 0;
- if (RegQueryValueEx(newKey, keyJavaDir.toStdString().c_str(), NULL, NULL, (BYTE *)value,
- &valueSz) == ERROR_MORE_DATA)
+ if (RegQueryValueExW(newKey, keyJavaDir.toStdWString().c_str(), NULL, NULL, (BYTE *)value,
+ &valueSz) == ERROR_MORE_DATA)
{
value = new char[valueSz];
- RegQueryValueEx(newKey, keyJavaDir.toStdString().c_str(), NULL, NULL, (BYTE *)value,
- &valueSz);
+ RegQueryValueExW(newKey, keyJavaDir.toStdWString().c_str(), NULL, NULL, (BYTE *)value,
+ &valueSz);
// Now, we construct the version object and add it to the list.
JavaInstallPtr javaVersion(new JavaInstall());
- javaVersion->id = subKeyName;
+ javaVersion->id = newSubkeyName;
javaVersion->arch = archType;
javaVersion->path =
QDir(FS::PathCombine(value, "bin")).absoluteFilePath("javaw.exe");
@@ -437,3 +459,8 @@ QList<QString> JavaUtils::FindJavaPaths()
return addJavasFromEnv(javas);
}
#endif
+
+QString JavaUtils::getJavaCheckPath()
+{
+ return APPLICATION->getJarPath("JavaCheck.jar");
+}
diff --git a/launcher/java/JavaUtils.h b/launcher/java/JavaUtils.h
index 3152d143..26d8003b 100644
--- a/launcher/java/JavaUtils.h
+++ b/launcher/java/JavaUtils.h
@@ -39,4 +39,6 @@ public:
#ifdef Q_OS_WIN
QList<JavaInstallPtr> FindJavaFromRegistryKey(DWORD keyType, QString keyName, QString keyJavaDir, QString subkeySuffix = "");
#endif
+
+ static QString getJavaCheckPath();
};
diff --git a/launcher/java/JavaVersion_test.cpp b/launcher/java/JavaVersion_test.cpp
index 10ae13a7..545947ef 100644
--- a/launcher/java/JavaVersion_test.cpp
+++ b/launcher/java/JavaVersion_test.cpp
@@ -1,5 +1,4 @@
#include <QTest>
-#include "TestUtil.h"
#include "java/JavaVersion.h"
diff --git a/launcher/launch/LaunchTask.cpp b/launcher/launch/LaunchTask.cpp
index d5442a2b..3aa95052 100644
--- a/launcher/launch/LaunchTask.cpp
+++ b/launcher/launch/LaunchTask.cpp
@@ -282,6 +282,23 @@ void LaunchTask::emitFailed(QString reason)
Task::emitFailed(reason);
}
+void LaunchTask::substituteVariables(const QStringList &args) const
+{
+ auto variables = m_instance->getVariables();
+ auto envVariables = QProcessEnvironment::systemEnvironment();
+
+ for (auto arg : args) {
+ for (auto key : variables)
+ {
+ arg.replace("$" + key, variables.value(key));
+ }
+ for (auto env : envVariables.keys())
+ {
+ arg.replace("$" + env, envVariables.value(env));
+ }
+ }
+}
+
QString LaunchTask::substituteVariables(const QString &cmd) const
{
QString out = cmd;
diff --git a/launcher/launch/LaunchTask.h b/launcher/launch/LaunchTask.h
index a1e891ac..2efe1fa2 100644
--- a/launcher/launch/LaunchTask.h
+++ b/launcher/launch/LaunchTask.h
@@ -1,18 +1,38 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * Authors: Orochimarufan <orochimarufan.x3@gmail.com>
+ * 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.
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*
- * 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.
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Authors: Orochimarufan <orochimarufan.x3@gmail.com>
+ *
+ * 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
@@ -85,6 +105,7 @@ public: /* methods */
shared_qobject_ptr<LogModel> getLogModel();
public:
+ void substituteVariables(const QStringList &args) const;
QString substituteVariables(const QString &cmd) const;
QString censorPrivateInfo(QString in);
diff --git a/launcher/launch/steps/CheckJava.cpp b/launcher/launch/steps/CheckJava.cpp
index ef5db2c9..db56b652 100644
--- a/launcher/launch/steps/CheckJava.cpp
+++ b/launcher/launch/steps/CheckJava.cpp
@@ -34,6 +34,7 @@
*/
#include "CheckJava.h"
+#include "java/JavaUtils.h"
#include <launch/LaunchTask.h>
#include <FileSystem.h>
#include <QStandardPaths>
@@ -71,6 +72,14 @@ void CheckJava::executeTask()
emit logLine("Java path is:\n" + m_javaPath + "\n\n", MessageLevel::Launcher);
}
+ if (JavaUtils::getJavaCheckPath().isEmpty())
+ {
+ const char *reason = QT_TR_NOOP("Java checker library could not be found. Please check your installation.");
+ emit logLine(tr(reason), MessageLevel::Fatal);
+ emitFailed(tr(reason));
+ return;
+ }
+
QFileInfo javaInfo(realJavaPath);
qlonglong javaUnixTime = javaInfo.lastModified().toMSecsSinceEpoch();
auto storedUnixTime = settings->get("JavaTimestamp").toLongLong();
diff --git a/launcher/launch/steps/PostLaunchCommand.cpp b/launcher/launch/steps/PostLaunchCommand.cpp
index 143eb441..cf765bc0 100644
--- a/launcher/launch/steps/PostLaunchCommand.cpp
+++ b/launcher/launch/steps/PostLaunchCommand.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * 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 "PostLaunchCommand.h"
@@ -27,9 +47,19 @@ PostLaunchCommand::PostLaunchCommand(LaunchTask *parent) : LaunchStep(parent)
void PostLaunchCommand::executeTask()
{
+ //FIXME: where to put this?
+#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
+ auto args = QProcess::splitCommand(m_command);
+ m_parent->substituteVariables(args);
+
+ emit logLine(tr("Running Post-Launch command: %1").arg(args.join(' ')), MessageLevel::Launcher);
+ const QString program = args.takeFirst();
+ m_process.start(program, args);
+#else
QString postlaunch_cmd = m_parent->substituteVariables(m_command);
emit logLine(tr("Running Post-Launch command: %1").arg(postlaunch_cmd), MessageLevel::Launcher);
m_process.start(postlaunch_cmd);
+#endif
}
void PostLaunchCommand::on_state(LoggedProcess::State state)
diff --git a/launcher/launch/steps/PreLaunchCommand.cpp b/launcher/launch/steps/PreLaunchCommand.cpp
index 1a0889c8..bf7d27eb 100644
--- a/launcher/launch/steps/PreLaunchCommand.cpp
+++ b/launcher/launch/steps/PreLaunchCommand.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * 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 "PreLaunchCommand.h"
@@ -28,9 +48,18 @@ PreLaunchCommand::PreLaunchCommand(LaunchTask *parent) : LaunchStep(parent)
void PreLaunchCommand::executeTask()
{
//FIXME: where to put this?
+#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
+ auto args = QProcess::splitCommand(m_command);
+ m_parent->substituteVariables(args);
+
+ emit logLine(tr("Running Pre-Launch command: %1").arg(args.join(' ')), MessageLevel::Launcher);
+ const QString program = args.takeFirst();
+ m_process.start(program, args);
+#else
QString prelaunch_cmd = m_parent->substituteVariables(m_command);
emit logLine(tr("Running Pre-Launch command: %1").arg(prelaunch_cmd), MessageLevel::Launcher);
m_process.start(prelaunch_cmd);
+#endif
}
void PreLaunchCommand::on_state(LoggedProcess::State state)
diff --git a/launcher/main.cpp b/launcher/main.cpp
index 3d25b4ff..85fe1260 100644
--- a/launcher/main.cpp
+++ b/launcher/main.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 "Application.h"
// #define BREAK_INFINITE_LOOP
@@ -24,8 +59,10 @@ int main(int argc, char *argv[])
return 42;
#endif
+#if QT_VERSION <= QT_VERSION_CHECK(6, 0, 0)
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
+#endif
// initialize Qt
Application app(argc, argv);
diff --git a/launcher/meta/Index_test.cpp b/launcher/meta/Index_test.cpp
index 5d3ddc50..261858c4 100644
--- a/launcher/meta/Index_test.cpp
+++ b/launcher/meta/Index_test.cpp
@@ -1,5 +1,4 @@
#include <QTest>
-#include "TestUtil.h"
#include "meta/Index.h"
#include "meta/VersionList.h"
diff --git a/launcher/minecraft/ComponentUpdateTask.cpp b/launcher/minecraft/ComponentUpdateTask.cpp
index ff7ed0af..6db21622 100644
--- a/launcher/minecraft/ComponentUpdateTask.cpp
+++ b/launcher/minecraft/ComponentUpdateTask.cpp
@@ -197,6 +197,10 @@ void ComponentUpdateTask::loadComponents()
{
remoteLoadFailed(taskIndex, error);
});
+ connect(indexLoadTask.get(), &Task::aborted, [=]()
+ {
+ remoteLoadFailed(taskIndex, tr("Aborted"));
+ });
taskIndex++;
}
}
@@ -243,6 +247,10 @@ void ComponentUpdateTask::loadComponents()
{
remoteLoadFailed(taskIndex, error);
});
+ connect(loadTask.get(), &Task::aborted, [=]()
+ {
+ remoteLoadFailed(taskIndex, tr("Aborted"));
+ });
RemoteLoadStatus status;
status.type = loadType;
status.PackProfileIndex = componentIndex;
diff --git a/launcher/minecraft/GradleSpecifier.h b/launcher/minecraft/GradleSpecifier.h
index d9bb0207..27514ab9 100644
--- a/launcher/minecraft/GradleSpecifier.h
+++ b/launcher/minecraft/GradleSpecifier.h
@@ -1,7 +1,43 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 <QString>
#include <QStringList>
+#include <QRegularExpression>
#include "DefaultVariable.h"
struct GradleSpecifier
@@ -25,20 +61,21 @@ struct GradleSpecifier
4 "jdk15"
5 "jar"
*/
- QRegExp matcher("([^:@]+):([^:@]+):([^:@]+)" "(?::([^:@]+))?" "(?:@([^:@]+))?");
- m_valid = matcher.exactMatch(value);
+ QRegularExpression matcher(QRegularExpression::anchoredPattern("([^:@]+):([^:@]+):([^:@]+)" "(?::([^:@]+))?" "(?:@([^:@]+))?"));
+ QRegularExpressionMatch match = matcher.match(value);
+ m_valid = match.hasMatch();
if(!m_valid) {
m_invalidValue = value;
return *this;
}
- auto elements = matcher.capturedTexts();
- m_groupId = elements[1];
- m_artifactId = elements[2];
- m_version = elements[3];
- m_classifier = elements[4];
- if(!elements[5].isEmpty())
+ auto elements = match.captured();
+ m_groupId = match.captured(1);
+ m_artifactId = match.captured(2);
+ m_version = match.captured(3);
+ m_classifier = match.captured(4);
+ if(match.lastCapturedIndex() >= 5)
{
- m_extension = elements[5];
+ m_extension = match.captured(5);
}
return *this;
}
diff --git a/launcher/minecraft/GradleSpecifier_test.cpp b/launcher/minecraft/GradleSpecifier_test.cpp
index 0900c9d8..a062dfac 100644
--- a/launcher/minecraft/GradleSpecifier_test.cpp
+++ b/launcher/minecraft/GradleSpecifier_test.cpp
@@ -1,5 +1,4 @@
#include <QTest>
-#include "TestUtil.h"
#include "minecraft/GradleSpecifier.h"
diff --git a/launcher/minecraft/Library_test.cpp b/launcher/minecraft/Library_test.cpp
index 47531ad6..834dd558 100644
--- a/launcher/minecraft/Library_test.cpp
+++ b/launcher/minecraft/Library_test.cpp
@@ -1,5 +1,4 @@
#include <QTest>
-#include "TestUtil.h"
#include "minecraft/MojangVersionFormat.h"
#include "minecraft/OneSixVersionFormat.h"
@@ -11,15 +10,14 @@ class LibraryTest : public QObject
{
Q_OBJECT
private:
- LibraryPtr readMojangJson(const char *file)
+ LibraryPtr readMojangJson(const QString path)
{
- auto path = QFINDTESTDATA(file);
QFile jsonFile(path);
jsonFile.open(QIODevice::ReadOnly);
auto data = jsonFile.readAll();
jsonFile.close();
ProblemContainer problems;
- return MojangVersionFormat::libraryFromJson(problems, QJsonDocument::fromJson(data).object(), file);
+ return MojangVersionFormat::libraryFromJson(problems, QJsonDocument::fromJson(data).object(), path);
}
// get absolute path to expected storage, assuming default cache prefix
QStringList getStorage(QString relative)
@@ -32,7 +30,7 @@ slots:
{
cache.reset(new HttpMetaCache());
cache->addBase("libraries", QDir("libraries").absolutePath());
- dataDir = QDir("data").absolutePath();
+ dataDir = QDir(QFINDTESTDATA("testdata")).absolutePath();
}
void test_legacy()
{
@@ -74,14 +72,14 @@ slots:
QCOMPARE(test.isNative(), false);
QStringList failedFiles;
test.setHint("local");
- auto downloads = test.getDownloads(currentSystem, cache.get(), failedFiles, QString("data"));
+ auto downloads = test.getDownloads(currentSystem, cache.get(), failedFiles, QFINDTESTDATA("testdata"));
QCOMPARE(downloads.size(), 0);
qDebug() << failedFiles;
QCOMPARE(failedFiles.size(), 0);
QStringList jar, native, native32, native64;
- test.getApplicableFiles(currentSystem, jar, native, native32, native64, QString("data"));
- QCOMPARE(jar, {QFileInfo("data/codecwav-20101023.jar").absoluteFilePath()});
+ test.getApplicableFiles(currentSystem, jar, native, native32, native64, QFINDTESTDATA("testdata"));
+ QCOMPARE(jar, {QFileInfo(QFINDTESTDATA("testdata/codecwav-20101023.jar")).absoluteFilePath()});
QCOMPARE(native, {});
QCOMPARE(native32, {});
QCOMPARE(native64, {});
@@ -167,20 +165,20 @@ slots:
test.setRepositoryURL("file://foo/bar");
{
QStringList jar, native, native32, native64;
- test.getApplicableFiles(Os_Linux, jar, native, native32, native64, QString("data"));
+ test.getApplicableFiles(Os_Linux, jar, native, native32, native64, QFINDTESTDATA("testdata"));
QCOMPARE(jar, {});
QCOMPARE(native, {});
- QCOMPARE(native32, {QFileInfo("data/testname-testversion-linux-32.jar").absoluteFilePath()});
- QCOMPARE(native64, {QFileInfo("data/testname-testversion-linux-64.jar").absoluteFilePath()});
+ QCOMPARE(native32, {QFileInfo(QFINDTESTDATA("testdata/testname-testversion-linux-32.jar")).absoluteFilePath()});
+ QCOMPARE(native64, {QFileInfo(QFINDTESTDATA("testdata") + "/testname-testversion-linux-64.jar").absoluteFilePath()});
QStringList failedFiles;
- auto dls = test.getDownloads(Os_Linux, cache.get(), failedFiles, QString("data"));
+ auto dls = test.getDownloads(Os_Linux, cache.get(), failedFiles, QFINDTESTDATA("testdata"));
QCOMPARE(dls.size(), 0);
- QCOMPARE(failedFiles, {"data/testname-testversion-linux-64.jar"});
+ QCOMPARE(failedFiles, {QFileInfo(QFINDTESTDATA("testdata") + "/testname-testversion-linux-64.jar").absoluteFilePath()});
}
}
void test_onenine()
{
- auto test = readMojangJson("data/lib-simple.json");
+ auto test = readMojangJson(QFINDTESTDATA("testdata/lib-simple.json"));
{
QStringList jar, native, native32, native64;
test->getApplicableFiles(Os_OSX, jar, native, native32, native64, QString());
@@ -199,41 +197,41 @@ slots:
test->setHint("local");
{
QStringList jar, native, native32, native64;
- test->getApplicableFiles(Os_OSX, jar, native, native32, native64, QString("data"));
- QCOMPARE(jar, {QFileInfo("data/codecwav-20101023.jar").absoluteFilePath()});
+ test->getApplicableFiles(Os_OSX, jar, native, native32, native64, QFINDTESTDATA("testdata"));
+ QCOMPARE(jar, {QFileInfo(QFINDTESTDATA("testdata/codecwav-20101023.jar")).absoluteFilePath()});
QCOMPARE(native, {});
QCOMPARE(native32, {});
QCOMPARE(native64, {});
}
{
QStringList failedFiles;
- auto dls = test->getDownloads(Os_Linux, cache.get(), failedFiles, QString("data"));
+ auto dls = test->getDownloads(Os_Linux, cache.get(), failedFiles, QFINDTESTDATA("testdata"));
QCOMPARE(dls.size(), 0);
QCOMPARE(failedFiles, {});
}
}
void test_onenine_local_override()
{
- auto test = readMojangJson("data/lib-simple.json");
+ auto test = readMojangJson(QFINDTESTDATA("testdata/lib-simple.json"));
test->setHint("local");
{
QStringList jar, native, native32, native64;
- test->getApplicableFiles(Os_OSX, jar, native, native32, native64, QString("data"));
- QCOMPARE(jar, {QFileInfo("data/codecwav-20101023.jar").absoluteFilePath()});
+ test->getApplicableFiles(Os_OSX, jar, native, native32, native64, QFINDTESTDATA("testdata"));
+ QCOMPARE(jar, {QFileInfo(QFINDTESTDATA("testdata/codecwav-20101023.jar")).absoluteFilePath()});
QCOMPARE(native, {});
QCOMPARE(native32, {});
QCOMPARE(native64, {});
}
{
QStringList failedFiles;
- auto dls = test->getDownloads(Os_Linux, cache.get(), failedFiles, QString("data"));
+ auto dls = test->getDownloads(Os_Linux, cache.get(), failedFiles, QFINDTESTDATA("testdata"));
QCOMPARE(dls.size(), 0);
QCOMPARE(failedFiles, {});
}
}
void test_onenine_native()
{
- auto test = readMojangJson("data/lib-native.json");
+ auto test = readMojangJson(QFINDTESTDATA("testdata/lib-native.json"));
QStringList jar, native, native32, native64;
test->getApplicableFiles(Os_OSX, jar, native, native32, native64, QString());
QCOMPARE(jar, QStringList());
@@ -248,7 +246,7 @@ slots:
}
void test_onenine_native_arch()
{
- auto test = readMojangJson("data/lib-native-arch.json");
+ auto test = readMojangJson(QFINDTESTDATA("testdata/lib-native-arch.json"));
QStringList jar, native, native32, native64;
test->getApplicableFiles(Os_Windows, jar, native, native32, native64, QString());
QCOMPARE(jar, {});
diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp
index 7e72601f..abc022b6 100644
--- a/launcher/minecraft/MinecraftInstance.cpp
+++ b/launcher/minecraft/MinecraftInstance.cpp
@@ -154,6 +154,12 @@ MinecraftInstance::MinecraftInstance(SettingsObjectPtr globalSettings, SettingsO
m_settings->registerOverride(globalSettings->getSetting("UseNativeOpenAL"), nativeLibraryWorkaroundsOverride);
m_settings->registerOverride(globalSettings->getSetting("UseNativeGLFW"), nativeLibraryWorkaroundsOverride);
+ // Peformance related options
+ auto performanceOverride = m_settings->registerSetting("OverridePerformance", false);
+ m_settings->registerOverride(globalSettings->getSetting("EnableFeralGamemode"), performanceOverride);
+ m_settings->registerOverride(globalSettings->getSetting("EnableMangoHud"), performanceOverride);
+ m_settings->registerOverride(globalSettings->getSetting("UseDiscreteGpu"), performanceOverride);
+
// Game time
auto gameTimeOverride = m_settings->registerSetting("OverrideGameTime", false);
m_settings->registerOverride(globalSettings->getSetting("ShowGameTime"), gameTimeOverride);
@@ -435,27 +441,57 @@ QProcessEnvironment MinecraftInstance::createEnvironment()
return env;
}
+QProcessEnvironment MinecraftInstance::createLaunchEnvironment()
+{
+ // prepare the process environment
+ QProcessEnvironment env = createEnvironment();
+
+#ifdef Q_OS_LINUX
+ if (settings()->get("EnableMangoHud").toBool())
+ {
+ auto preload = env.value("LD_PRELOAD", "") + ":libMangoHud_dlsym.so:libMangoHud.so";
+ auto lib_path = env.value("LD_LIBRARY_PATH", "") + ":/usr/local/$LIB/mangohud/:/usr/$LIB/mangohud/";
+
+ env.insert("LD_PRELOAD", preload);
+ env.insert("LD_LIBRARY_PATH", lib_path);
+ env.insert("MANGOHUD", "1");
+ }
+
+ if (settings()->get("UseDiscreteGpu").toBool())
+ {
+ // Open Source Drivers
+ env.insert("DRI_PRIME", "1");
+ // Proprietary Nvidia Drivers
+ env.insert("__NV_PRIME_RENDER_OFFLOAD", "1");
+ env.insert("__VK_LAYER_NV_optimus", "NVIDIA_only");
+ env.insert("__GLX_VENDOR_LIBRARY_NAME", "nvidia");
+ }
+#endif
+
+ return env;
+}
+
static QString replaceTokensIn(QString text, QMap<QString, QString> with)
{
+ // TODO: does this still work??
QString result;
- QRegExp token_regexp("\\$\\{(.+)\\}");
- token_regexp.setMinimal(true);
+ QRegularExpression token_regexp("\\$\\{(.+)\\}", QRegularExpression::InvertedGreedinessOption);
QStringList list;
- int tail = 0;
- int head = 0;
- while ((head = token_regexp.indexIn(text, head)) != -1)
+ QRegularExpressionMatchIterator i = token_regexp.globalMatch(text);
+ int lastCapturedEnd = 0;
+ while (i.hasNext())
{
- result.append(text.mid(tail, head - tail));
- QString key = token_regexp.cap(1);
+ QRegularExpressionMatch match = i.next();
+ result.append(text.mid(lastCapturedEnd, match.capturedStart()));
+ QString key = match.captured(1);
auto iter = with.find(key);
if (iter != with.end())
{
result.append(*iter);
}
- head += token_regexp.matchedLength();
- tail = head;
+ lastCapturedEnd = match.capturedEnd();
}
- result.append(text.mid(tail));
+ result.append(text.mid(lastCapturedEnd));
return result;
}
@@ -504,7 +540,11 @@ QStringList MinecraftInstance::processMinecraftArgs(
token_mapping["assets_root"] = absAssetsDir;
token_mapping["assets_index_name"] = assets->id;
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+ QStringList parts = args_pattern.split(' ', Qt::SkipEmptyParts);
+#else
QStringList parts = args_pattern.split(' ', QString::SkipEmptyParts);
+#endif
for (int i = 0; i < parts.length(); i++)
{
parts[i] = replaceTokensIn(parts[i], token_mapping);
@@ -747,7 +787,9 @@ QMap<QString, QString> MinecraftInstance::createCensorFilterFromSession(AuthSess
{
addToFilter(sessionRef.session, tr("<SESSION ID>"));
}
- addToFilter(sessionRef.access_token, tr("<ACCESS TOKEN>"));
+ if (sessionRef.access_token != "offline") {
+ addToFilter(sessionRef.access_token, tr("<ACCESS TOKEN>"));
+ }
if(sessionRef.client_token.size()) {
addToFilter(sessionRef.client_token, tr("<CLIENT TOKEN>"));
}
@@ -826,8 +868,16 @@ QString MinecraftInstance::getStatusbarDescription()
traits.append(tr("broken"));
}
+ QString mcVersion = m_components->getComponentVersion("net.minecraft");
+ if (mcVersion.isEmpty())
+ {
+ // Load component info if needed
+ m_components->reload(Net::Mode::Offline);
+ mcVersion = m_components->getComponentVersion("net.minecraft");
+ }
+
QString description;
- description.append(tr("Minecraft %1 (%2)").arg(m_components->getComponentVersion("net.minecraft")).arg(typeName()));
+ description.append(tr("Minecraft %1").arg(mcVersion));
if(m_settings->get("ShowGameTime").toBool())
{
if (lastTimePlayed() > 0) {
diff --git a/launcher/minecraft/MinecraftInstance.h b/launcher/minecraft/MinecraftInstance.h
index fda58aa7..05450d41 100644
--- a/launcher/minecraft/MinecraftInstance.h
+++ b/launcher/minecraft/MinecraftInstance.h
@@ -91,6 +91,7 @@ public:
/// create an environment for launching processes
QProcessEnvironment createEnvironment() override;
+ QProcessEnvironment createLaunchEnvironment() override;
/// guess log level from a line of minecraft log
MessageLevel::Enum guessLevel(const QString &line, MessageLevel::Enum level) override;
diff --git a/launcher/minecraft/MinecraftLoadAndCheck.cpp b/launcher/minecraft/MinecraftLoadAndCheck.cpp
index 79b0c484..d72bc7be 100644
--- a/launcher/minecraft/MinecraftLoadAndCheck.cpp
+++ b/launcher/minecraft/MinecraftLoadAndCheck.cpp
@@ -20,6 +20,7 @@ void MinecraftLoadAndCheck::executeTask()
}
connect(m_task.get(), &Task::succeeded, this, &MinecraftLoadAndCheck::subtaskSucceeded);
connect(m_task.get(), &Task::failed, this, &MinecraftLoadAndCheck::subtaskFailed);
+ connect(m_task.get(), &Task::aborted, this, [this]{ subtaskFailed(tr("Aborted")); });
connect(m_task.get(), &Task::progress, this, &MinecraftLoadAndCheck::progress);
connect(m_task.get(), &Task::status, this, &MinecraftLoadAndCheck::setStatus);
}
diff --git a/launcher/minecraft/MinecraftUpdate.cpp b/launcher/minecraft/MinecraftUpdate.cpp
index 32e9cbb6..0ce0c347 100644
--- a/launcher/minecraft/MinecraftUpdate.cpp
+++ b/launcher/minecraft/MinecraftUpdate.cpp
@@ -98,6 +98,7 @@ void MinecraftUpdate::next()
auto task = m_tasks[m_currentTask - 1];
disconnect(task.get(), &Task::succeeded, this, &MinecraftUpdate::subtaskSucceeded);
disconnect(task.get(), &Task::failed, this, &MinecraftUpdate::subtaskFailed);
+ disconnect(task.get(), &Task::aborted, this, &Task::abort);
disconnect(task.get(), &Task::progress, this, &MinecraftUpdate::progress);
disconnect(task.get(), &Task::status, this, &MinecraftUpdate::setStatus);
}
@@ -115,6 +116,7 @@ void MinecraftUpdate::next()
}
connect(task.get(), &Task::succeeded, this, &MinecraftUpdate::subtaskSucceeded);
connect(task.get(), &Task::failed, this, &MinecraftUpdate::subtaskFailed);
+ connect(task.get(), &Task::aborted, this, &Task::abort);
connect(task.get(), &Task::progress, this, &MinecraftUpdate::progress);
connect(task.get(), &Task::status, this, &MinecraftUpdate::setStatus);
// if the task is already running, do not start it again
diff --git a/launcher/minecraft/MinecraftUpdate.h b/launcher/minecraft/MinecraftUpdate.h
index 9ebef656..acf2eb86 100644
--- a/launcher/minecraft/MinecraftUpdate.h
+++ b/launcher/minecraft/MinecraftUpdate.h
@@ -27,6 +27,8 @@
class MinecraftVersion;
class MinecraftInstance;
+// FIXME: This looks very similar to a SequentialTask. Maybe we can reduce code duplications? :^)
+
class MinecraftUpdate : public Task
{
Q_OBJECT
diff --git a/launcher/minecraft/MojangVersionFormat_test.cpp b/launcher/minecraft/MojangVersionFormat_test.cpp
index 9d095340..71df784b 100644
--- a/launcher/minecraft/MojangVersionFormat_test.cpp
+++ b/launcher/minecraft/MojangVersionFormat_test.cpp
@@ -1,6 +1,5 @@
#include <QTest>
#include <QDebug>
-#include "TestUtil.h"
#include "minecraft/MojangVersionFormat.h"
@@ -8,9 +7,8 @@ class MojangVersionFormatTest : public QObject
{
Q_OBJECT
- static QJsonDocument readJson(const char *file)
+ static QJsonDocument readJson(const QString path)
{
- auto path = QFINDTESTDATA(file);
QFile jsonFile(path);
jsonFile.open(QIODevice::ReadOnly);
auto data = jsonFile.readAll();
@@ -31,7 +29,7 @@ private
slots:
void test_Through_Simple()
{
- QJsonDocument doc = readJson("data/1.9-simple.json");
+ QJsonDocument doc = readJson(QFINDTESTDATA("testdata/1.9-simple.json"));
auto vfile = MojangVersionFormat::versionFileFromJson(doc, "1.9-simple.json");
auto doc2 = MojangVersionFormat::versionFileToJson(vfile);
writeJson("1.9-simple-passthorugh.json", doc2);
@@ -41,7 +39,7 @@ slots:
void test_Through()
{
- QJsonDocument doc = readJson("data/1.9.json");
+ QJsonDocument doc = readJson(QFINDTESTDATA("testdata/1.9.json"));
auto vfile = MojangVersionFormat::versionFileFromJson(doc, "1.9.json");
auto doc2 = MojangVersionFormat::versionFileToJson(vfile);
writeJson("1.9-passthorugh.json", doc2);
diff --git a/launcher/minecraft/OneSixVersionFormat.cpp b/launcher/minecraft/OneSixVersionFormat.cpp
index 879f18c1..cec4a55b 100644
--- a/launcher/minecraft/OneSixVersionFormat.cpp
+++ b/launcher/minecraft/OneSixVersionFormat.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 "OneSixVersionFormat.h"
#include <Json.h>
#include "minecraft/Agent.h"
@@ -296,7 +331,7 @@ QJsonDocument OneSixVersionFormat::versionFileToJson(const VersionFilePtr &patch
}
writeString(root, "appletClass", patch->appletClass);
writeStringList(root, "+tweakers", patch->addTweakers);
- writeStringList(root, "+traits", patch->traits.toList());
+ writeStringList(root, "+traits", patch->traits.values());
if (!patch->libraries.isEmpty())
{
QJsonArray array;
diff --git a/launcher/minecraft/PackProfile.cpp b/launcher/minecraft/PackProfile.cpp
index 125048f0..5e76b892 100644
--- a/launcher/minecraft/PackProfile.cpp
+++ b/launcher/minecraft/PackProfile.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * 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 <QFile>
@@ -346,6 +366,7 @@ void PackProfile::resolve(Net::Mode netmode)
d->m_updateTask.reset(updateTask);
connect(updateTask, &ComponentUpdateTask::succeeded, this, &PackProfile::updateSucceeded);
connect(updateTask, &ComponentUpdateTask::failed, this, &PackProfile::updateFailed);
+ connect(updateTask, &ComponentUpdateTask::aborted, this, [this]{ updateFailed(tr("Aborted")); });
d->m_updateTask->start();
}
@@ -687,7 +708,11 @@ void PackProfile::move(const int index, const MoveDirection direction)
return;
}
beginMoveRows(QModelIndex(), index, index, QModelIndex(), togap);
+#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
+ d->components.swapItemsAt(index, theirIndex);
+#else
d->components.swap(index, theirIndex);
+#endif
endMoveRows();
invalidateLaunchProfile();
scheduleSave();
diff --git a/launcher/minecraft/ParseUtils_test.cpp b/launcher/minecraft/ParseUtils_test.cpp
index fcc137e5..7721a46d 100644
--- a/launcher/minecraft/ParseUtils_test.cpp
+++ b/launcher/minecraft/ParseUtils_test.cpp
@@ -1,5 +1,4 @@
#include <QTest>
-#include "TestUtil.h"
#include "minecraft/ParseUtils.h"
@@ -42,4 +41,3 @@ slots:
QTEST_GUILESS_MAIN(ParseUtilsTest)
#include "ParseUtils_test.moc"
-
diff --git a/launcher/minecraft/ProfileUtils.cpp b/launcher/minecraft/ProfileUtils.cpp
index 8ca24cc8..03f8c198 100644
--- a/launcher/minecraft/ProfileUtils.cpp
+++ b/launcher/minecraft/ProfileUtils.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 "ProfileUtils.h"
#include "minecraft/VersionFilterData.h"
#include "minecraft/OneSixVersionFormat.h"
@@ -141,24 +176,6 @@ bool saveJsonFile(const QJsonDocument doc, const QString & filename)
return true;
}
-VersionFilePtr parseBinaryJsonFile(const QFileInfo &fileInfo)
-{
- QFile file(fileInfo.absoluteFilePath());
- if (!file.open(QFile::ReadOnly))
- {
- auto errorStr = QObject::tr("Unable to open the version file %1: %2.").arg(fileInfo.fileName(), file.errorString());
- return createErrorVersionFile(fileInfo.completeBaseName(), fileInfo.absoluteFilePath(), errorStr);
- }
- QJsonDocument doc = QJsonDocument::fromBinaryData(file.readAll());
- file.close();
- if (doc.isNull())
- {
- file.remove();
- throw JSONValidationError(QObject::tr("Unable to process the version file %1.").arg(fileInfo.fileName()));
- }
- return guardedParseJson(doc, fileInfo.completeBaseName(), fileInfo.absoluteFilePath(), false);
-}
-
void removeLwjglFromPatch(VersionFilePtr patch)
{
auto filter = [](QList<LibraryPtr>& libs)
diff --git a/launcher/minecraft/ProfileUtils.h b/launcher/minecraft/ProfileUtils.h
index 351c36cb..5b938784 100644
--- a/launcher/minecraft/ProfileUtils.h
+++ b/launcher/minecraft/ProfileUtils.h
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 "Library.h"
#include "VersionFile.h"
@@ -19,9 +54,6 @@ VersionFilePtr parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder)
/// Save a JSON file (in any format)
bool saveJsonFile(const QJsonDocument doc, const QString & filename);
-/// Parse a version file in binary JSON format
-VersionFilePtr parseBinaryJsonFile(const QFileInfo &fileInfo);
-
/// Remove LWJGL from a patch file. This is applied to all Mojang-like profile files.
void removeLwjglFromPatch(VersionFilePtr patch);
diff --git a/launcher/minecraft/VersionFile.cpp b/launcher/minecraft/VersionFile.cpp
index f242fbe7..a9a0f7f4 100644
--- a/launcher/minecraft/VersionFile.cpp
+++ b/launcher/minecraft/VersionFile.cpp
@@ -89,14 +89,3 @@ void VersionFile::applyTo(LaunchProfile *profile)
}
profile->applyProblemSeverity(getProblemSeverity());
}
-
-/*
- auto theirVersion = profile->getMinecraftVersion();
- if (!theirVersion.isNull() && !dependsOnMinecraftVersion.isNull())
- {
- if (QRegExp(dependsOnMinecraftVersion, Qt::CaseInsensitive, QRegExp::Wildcard).indexIn(theirVersion) == -1)
- {
- throw MinecraftVersionMismatch(uid, dependsOnMinecraftVersion, theirVersion);
- }
- }
-*/
diff --git a/launcher/minecraft/World.cpp b/launcher/minecraft/World.cpp
index dc756e06..dfcb43d8 100644
--- a/launcher/minecraft/World.cpp
+++ b/launcher/minecraft/World.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2015-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * 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 <QDir>
@@ -321,7 +341,8 @@ bool World::install(const QString &to, const QString &name)
if(ok && !name.isEmpty() && m_actualName != name)
{
- World newWorld(finalPath);
+ QFileInfo finalPathInfo(finalPath);
+ World newWorld(finalPathInfo);
if(newWorld.isValid())
{
newWorld.rename(name);
diff --git a/launcher/minecraft/WorldList.cpp b/launcher/minecraft/WorldList.cpp
index 955609bf..aee7be35 100644
--- a/launcher/minecraft/WorldList.cpp
+++ b/launcher/minecraft/WorldList.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2015-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * 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 "WorldList.h"
@@ -195,7 +215,7 @@ QVariant WorldList::data(const QModelIndex &index, int role) const
switch (column)
{
case SizeColumn:
- return qVariantFromValue<qlonglong>(world.bytes());
+ return QVariant::fromValue<qlonglong>(world.bytes());
default:
return data(index, Qt::DisplayRole);
@@ -215,7 +235,7 @@ QVariant WorldList::data(const QModelIndex &index, int role) const
}
case SeedRole:
{
- return qVariantFromValue<qlonglong>(world.seed());
+ return QVariant::fromValue<qlonglong>(world.seed());
}
case NameRole:
{
@@ -227,7 +247,7 @@ QVariant WorldList::data(const QModelIndex &index, int role) const
}
case SizeRole:
{
- return qVariantFromValue<qlonglong>(world.bytes());
+ return QVariant::fromValue<qlonglong>(world.bytes());
}
case IconFileRole:
{
@@ -301,7 +321,11 @@ public:
}
protected:
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ QVariant retrieveData(const QString &mimetype, QMetaType type) const
+#else
QVariant retrieveData(const QString &mimetype, QVariant::Type type) const
+#endif
{
QList<QUrl> urls;
for(auto &world: m_worlds)
diff --git a/launcher/minecraft/auth/AccountData.cpp b/launcher/minecraft/auth/AccountData.cpp
index dd9c3f8f..44f7e256 100644
--- a/launcher/minecraft/auth/AccountData.cpp
+++ b/launcher/minecraft/auth/AccountData.cpp
@@ -39,6 +39,7 @@
#include <QJsonArray>
#include <QDebug>
#include <QUuid>
+#include <QRegularExpression>
namespace {
void tokenToJSONV3(QJsonObject &parent, Katabasis::Token t, const char * tokenName) {
@@ -451,7 +452,7 @@ void AccountData::invalidateClientToken() {
if(type != AccountType::Mojang) {
return;
}
- yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegExp("[{-}]"));
+ yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegularExpression("[{-}]"));
}
QString AccountData::profileId() const {
@@ -473,7 +474,7 @@ QString AccountData::accountDisplayString() const {
return userName();
}
case AccountType::Offline: {
- return userName();
+ return QObject::tr("<Offline>");
}
case AccountType::MSA: {
if(xboxApiToken.extra.contains("gtg")) {
diff --git a/launcher/minecraft/auth/AccountList.cpp b/launcher/minecraft/auth/AccountList.cpp
index 3422df7c..2b851e18 100644
--- a/launcher/minecraft/auth/AccountList.cpp
+++ b/launcher/minecraft/auth/AccountList.cpp
@@ -282,6 +282,10 @@ QVariant AccountList::data(const QModelIndex &index, int role) const
case Qt::DisplayRole:
switch (index.column())
{
+ case ProfileNameColumn: {
+ return account->profileName();
+ }
+
case NameColumn:
return account->accountDisplayString();
@@ -300,7 +304,7 @@ QVariant AccountList::data(const QModelIndex &index, int role) const
return tr("Offline", "Account status");
}
case AccountState::Online: {
- return tr("Online", "Account status");
+ return tr("Ready", "Account status");
}
case AccountState::Working: {
return tr("Working", "Account status");
@@ -320,10 +324,6 @@ QVariant AccountList::data(const QModelIndex &index, int role) const
}
}
- case ProfileNameColumn: {
- return account->profileName();
- }
-
case MigrationColumn: {
if(account->isMSA() || account->isOffline()) {
return tr("N/A", "Can Migrate?");
@@ -349,7 +349,7 @@ QVariant AccountList::data(const QModelIndex &index, int role) const
case Qt::CheckStateRole:
switch (index.column())
{
- case NameColumn:
+ case ProfileNameColumn:
return account == m_defaultAccount ? Qt::Checked : Qt::Unchecked;
}
@@ -365,6 +365,8 @@ QVariant AccountList::headerData(int section, Qt::Orientation orientation, int r
case Qt::DisplayRole:
switch (section)
{
+ case ProfileNameColumn:
+ return tr("Username");
case NameColumn:
return tr("Account");
case TypeColumn:
@@ -373,8 +375,6 @@ QVariant AccountList::headerData(int section, Qt::Orientation orientation, int r
return tr("Status");
case MigrationColumn:
return tr("Can Migrate?");
- case ProfileNameColumn:
- return tr("Profile");
default:
return QVariant();
}
@@ -382,6 +382,8 @@ QVariant AccountList::headerData(int section, Qt::Orientation orientation, int r
case Qt::ToolTipRole:
switch (section)
{
+ case ProfileNameColumn:
+ return tr("Minecraft username associated with the account.");
case NameColumn:
return tr("User name of the account.");
case TypeColumn:
@@ -389,9 +391,7 @@ QVariant AccountList::headerData(int section, Qt::Orientation orientation, int r
case StatusColumn:
return tr("Current status of the account.");
case MigrationColumn:
- return tr("Can this account migrate to Microsoft account?");
- case ProfileNameColumn:
- return tr("Name of the Minecraft profile associated with the account.");
+ return tr("Can this account migrate to a Microsoft account?");
default:
return QVariant();
}
diff --git a/launcher/minecraft/auth/AccountList.h b/launcher/minecraft/auth/AccountList.h
index baaf7414..8136a92e 100644
--- a/launcher/minecraft/auth/AccountList.h
+++ b/launcher/minecraft/auth/AccountList.h
@@ -58,8 +58,8 @@ public:
enum VListColumns
{
// TODO: Add icon column.
- NameColumn = 0,
- ProfileNameColumn,
+ ProfileNameColumn = 0,
+ NameColumn,
MigrationColumn,
TypeColumn,
StatusColumn,
diff --git a/launcher/minecraft/auth/AccountTask.cpp b/launcher/minecraft/auth/AccountTask.cpp
index 49b6e46f..4118c3c5 100644
--- a/launcher/minecraft/auth/AccountTask.cpp
+++ b/launcher/minecraft/auth/AccountTask.cpp
@@ -79,6 +79,8 @@ QString AccountTask::getStateMessage() const
bool AccountTask::changeState(AccountTaskState newState, QString reason)
{
m_taskState = newState;
+ // FIXME: virtual method invoked in constructor.
+ // We want that behavior, but maybe make it less weird?
setStatus(getStateMessage());
switch(newState) {
case AccountTaskState::STATE_CREATED: {
diff --git a/launcher/minecraft/auth/AuthRequest.cpp b/launcher/minecraft/auth/AuthRequest.cpp
index feface80..bb82e1e2 100644
--- a/launcher/minecraft/auth/AuthRequest.cpp
+++ b/launcher/minecraft/auth/AuthRequest.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 <cassert>
#include <QDebug>
@@ -20,7 +55,11 @@ void AuthRequest::get(const QNetworkRequest &req, int timeout/* = 60*1000*/) {
reply_ = APPLICATION->network()->get(request_);
status_ = Requesting;
timedReplies_.add(new Katabasis::Reply(reply_, timeout));
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ connect(reply_, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)));
+#else
connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)));
+#endif
connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()));
connect(reply_, &QNetworkReply::sslErrors, this, &AuthRequest::onSslErrors);
}
@@ -31,7 +70,11 @@ void AuthRequest::post(const QNetworkRequest &req, const QByteArray &data, int t
status_ = Requesting;
reply_ = APPLICATION->network()->post(request_, data_);
timedReplies_.add(new Katabasis::Reply(reply_, timeout));
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ connect(reply_, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)));
+#else
connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)));
+#endif
connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()));
connect(reply_, &QNetworkReply::sslErrors, this, &AuthRequest::onSslErrors);
connect(reply_, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(onUploadProgress(qint64,qint64)));
diff --git a/launcher/minecraft/auth/MinecraftAccount.cpp b/launcher/minecraft/auth/MinecraftAccount.cpp
index ec86fa5c..a5c6f542 100644
--- a/launcher/minecraft/auth/MinecraftAccount.cpp
+++ b/launcher/minecraft/auth/MinecraftAccount.cpp
@@ -40,7 +40,7 @@
#include <QUuid>
#include <QJsonObject>
#include <QJsonArray>
-#include <QRegExp>
+#include <QRegularExpression>
#include <QStringList>
#include <QJsonDocument>
@@ -53,7 +53,7 @@
#include "flows/Offline.h"
MinecraftAccount::MinecraftAccount(QObject* parent) : QObject(parent) {
- data.internalId = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
+ data.internalId = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]"));
}
@@ -78,7 +78,7 @@ MinecraftAccountPtr MinecraftAccount::createFromUsername(const QString &username
MinecraftAccountPtr account = new MinecraftAccount();
account->data.type = AccountType::Mojang;
account->data.yggdrasilToken.extra["userName"] = username;
- account->data.yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
+ account->data.yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]"));
return account;
}
@@ -97,10 +97,10 @@ MinecraftAccountPtr MinecraftAccount::createOffline(const QString &username)
account->data.yggdrasilToken.validity = Katabasis::Validity::Certain;
account->data.yggdrasilToken.issueInstant = QDateTime::currentDateTimeUtc();
account->data.yggdrasilToken.extra["userName"] = username;
- account->data.yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
+ account->data.yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]"));
account->data.minecraftEntitlement.ownsMinecraft = true;
account->data.minecraftEntitlement.canPlayMinecraft = true;
- account->data.minecraftProfile.id = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
+ account->data.minecraftProfile.id = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]"));
account->data.minecraftProfile.name = username;
account->data.minecraftProfile.validity = Katabasis::Validity::Certain;
return account;
@@ -135,6 +135,7 @@ shared_qobject_ptr<AccountTask> MinecraftAccount::login(QString password) {
m_currentTask.reset(new MojangLogin(&data, password));
connect(m_currentTask.get(), SIGNAL(succeeded()), SLOT(authSucceeded()));
connect(m_currentTask.get(), SIGNAL(failed(QString)), SLOT(authFailed(QString)));
+ connect(m_currentTask.get(), &Task::aborted, this, [this]{ authFailed(tr("Aborted")); });
emit activityChanged(true);
return m_currentTask;
}
@@ -145,6 +146,7 @@ shared_qobject_ptr<AccountTask> MinecraftAccount::loginMSA() {
m_currentTask.reset(new MSAInteractive(&data));
connect(m_currentTask.get(), SIGNAL(succeeded()), SLOT(authSucceeded()));
connect(m_currentTask.get(), SIGNAL(failed(QString)), SLOT(authFailed(QString)));
+ connect(m_currentTask.get(), &Task::aborted, this, [this]{ authFailed(tr("Aborted")); });
emit activityChanged(true);
return m_currentTask;
}
@@ -155,6 +157,7 @@ shared_qobject_ptr<AccountTask> MinecraftAccount::loginOffline() {
m_currentTask.reset(new OfflineLogin(&data));
connect(m_currentTask.get(), SIGNAL(succeeded()), SLOT(authSucceeded()));
connect(m_currentTask.get(), SIGNAL(failed(QString)), SLOT(authFailed(QString)));
+ connect(m_currentTask.get(), &Task::aborted, this, [this]{ authFailed(tr("Aborted")); });
emit activityChanged(true);
return m_currentTask;
}
@@ -176,6 +179,7 @@ shared_qobject_ptr<AccountTask> MinecraftAccount::refresh() {
connect(m_currentTask.get(), SIGNAL(succeeded()), SLOT(authSucceeded()));
connect(m_currentTask.get(), SIGNAL(failed(QString)), SLOT(authFailed(QString)));
+ connect(m_currentTask.get(), &Task::aborted, this, [this]{ authFailed(tr("Aborted")); });
emit activityChanged(true);
return m_currentTask;
}
diff --git a/launcher/minecraft/auth/steps/YggdrasilStep.cpp b/launcher/minecraft/auth/steps/YggdrasilStep.cpp
index 4c6b1624..e1d33172 100644
--- a/launcher/minecraft/auth/steps/YggdrasilStep.cpp
+++ b/launcher/minecraft/auth/steps/YggdrasilStep.cpp
@@ -9,6 +9,7 @@ YggdrasilStep::YggdrasilStep(AccountData* data, QString password) : AuthStep(dat
connect(m_yggdrasil, &Task::failed, this, &YggdrasilStep::onAuthFailed);
connect(m_yggdrasil, &Task::succeeded, this, &YggdrasilStep::onAuthSucceeded);
+ connect(m_yggdrasil, &Task::aborted, this, &YggdrasilStep::onAuthFailed);
}
YggdrasilStep::~YggdrasilStep() noexcept = default;
diff --git a/launcher/minecraft/launch/DirectJavaLaunch.cpp b/launcher/minecraft/launch/DirectJavaLaunch.cpp
index 742170fa..152485b3 100644
--- a/launcher/minecraft/launch/DirectJavaLaunch.cpp
+++ b/launcher/minecraft/launch/DirectJavaLaunch.cpp
@@ -12,13 +12,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#include "DirectJavaLaunch.h"
+
+#include <QStandardPaths>
+
#include <launch/LaunchTask.h>
#include <minecraft/MinecraftInstance.h>
#include <FileSystem.h>
#include <Commandline.h>
-#include <QStandardPaths>
+
+#ifdef Q_OS_LINUX
+#include "gamemode_client.h"
+#endif
DirectJavaLaunch::DirectJavaLaunch(LaunchTask *parent) : LaunchStep(parent)
{
@@ -50,7 +55,7 @@ void DirectJavaLaunch::executeTask()
auto javaPath = FS::ResolveExecutable(instance->settings()->get("JavaPath").toString());
- m_process.setProcessEnvironment(instance->createEnvironment());
+ m_process.setProcessEnvironment(instance->createLaunchEnvironment());
// make detachable - this will keep the process running even if the object is destroyed
m_process.setDetachable(true);
@@ -79,6 +84,17 @@ void DirectJavaLaunch::executeTask()
{
m_process.start(javaPath, args);
}
+
+#ifdef Q_OS_LINUX
+ if (instance->settings()->get("EnableFeralGamemode").toBool())
+ {
+ auto pid = m_process.processId();
+ if (pid)
+ {
+ gamemode_request_start_for(pid);
+ }
+ }
+#endif
}
void DirectJavaLaunch::on_state(LoggedProcess::State state)
diff --git a/launcher/minecraft/launch/LauncherPartLaunch.cpp b/launcher/minecraft/launch/LauncherPartLaunch.cpp
index 427bc32b..63e4d90f 100644
--- a/launcher/minecraft/launch/LauncherPartLaunch.cpp
+++ b/launcher/minecraft/launch/LauncherPartLaunch.cpp
@@ -36,7 +36,6 @@
#include "LauncherPartLaunch.h"
#include <QStandardPaths>
-#include <QRegularExpression>
#include "launch/LaunchTask.h"
#include "minecraft/MinecraftInstance.h"
@@ -44,6 +43,10 @@
#include "Commandline.h"
#include "Application.h"
+#ifdef Q_OS_LINUX
+#include "gamemode_client.h"
+#endif
+
LauncherPartLaunch::LauncherPartLaunch(LaunchTask *parent) : LaunchStep(parent)
{
auto instance = parent->instance();
@@ -92,6 +95,15 @@ bool fitsInLocal8bit(const QString & string)
void LauncherPartLaunch::executeTask()
{
+ QString jarPath = APPLICATION->getJarPath("NewLaunch.jar");
+ if (jarPath.isEmpty())
+ {
+ const char *reason = QT_TR_NOOP("Launcher library could not be found. Please check your installation.");
+ emit logLine(tr(reason), MessageLevel::Fatal);
+ emitFailed(tr(reason));
+ return;
+ }
+
auto instance = m_parent->instance();
std::shared_ptr<MinecraftInstance> minecraftInstance = std::dynamic_pointer_cast<MinecraftInstance>(instance);
@@ -102,13 +114,13 @@ void LauncherPartLaunch::executeTask()
auto javaPath = FS::ResolveExecutable(instance->settings()->get("JavaPath").toString());
- m_process.setProcessEnvironment(instance->createEnvironment());
+ m_process.setProcessEnvironment(instance->createLaunchEnvironment());
// make detachable - this will keep the process running even if the object is destroyed
m_process.setDetachable(true);
auto classPath = minecraftInstance->getClassPath();
- classPath.prepend(FS::PathCombine(APPLICATION->getJarsPath(), "NewLaunch.jar"));
+ classPath.prepend(jarPath);
auto natPath = minecraftInstance->getNativePath();
#ifdef Q_OS_WIN
@@ -142,7 +154,7 @@ void LauncherPartLaunch::executeTask()
#else
args << classPath.join(':');
#endif
- args << "org.multimc.EntryPoint";
+ args << "org.polymc.EntryPoint";
qDebug() << args.join(' ');
@@ -167,6 +179,17 @@ void LauncherPartLaunch::executeTask()
{
m_process.start(javaPath, args);
}
+
+#ifdef Q_OS_LINUX
+ if (instance->settings()->get("EnableFeralGamemode").toBool())
+ {
+ auto pid = m_process.processId();
+ if (pid)
+ {
+ gamemode_request_start_for(pid);
+ }
+ }
+#endif
}
void LauncherPartLaunch::on_state(LoggedProcess::State state)
diff --git a/launcher/minecraft/mod/ModFolderModel.cpp b/launcher/minecraft/mod/ModFolderModel.cpp
index ded2d3a2..5ee08cbf 100644
--- a/launcher/minecraft/mod/ModFolderModel.cpp
+++ b/launcher/minecraft/mod/ModFolderModel.cpp
@@ -116,9 +116,17 @@ bool ModFolderModel::update()
void ModFolderModel::finishUpdate()
{
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+ auto currentList = modsIndex.keys();
+ QSet<QString> currentSet(currentList.begin(), currentList.end());
+ auto & newMods = m_update->mods;
+ auto newList = newMods.keys();
+ QSet<QString> newSet(newList.begin(), newList.end());
+#else
QSet<QString> currentSet = modsIndex.keys().toSet();
auto & newMods = m_update->mods;
QSet<QString> newSet = newMods.keys().toSet();
+#endif
// see if the kept mods changed in some way
{
@@ -167,12 +175,16 @@ void ModFolderModel::finishUpdate()
{
QSet<QString> added = newSet;
added.subtract(currentSet);
- beginInsertRows(QModelIndex(), mods.size(), mods.size() + added.size() - 1);
- for(auto & addedMod: added) {
- mods.append(newMods[addedMod]);
- resolveMod(mods.last());
+
+ // When you have a Qt build with assertions turned on, proceeding here will abort the application
+ if (added.size() > 0) {
+ beginInsertRows(QModelIndex(), mods.size(), mods.size() + added.size() - 1);
+ for (auto& addedMod : added) {
+ mods.append(newMods[addedMod]);
+ resolveMod(mods.last());
+ }
+ endInsertRows();
}
- endInsertRows();
}
// update index
@@ -305,7 +317,8 @@ bool ModFolderModel::installMod(const QString &filename)
return false;
}
FS::updateTimestamp(newpath);
- installedMod.repath(newpath);
+ QFileInfo newpathInfo(newpath);
+ installedMod.repath(newpathInfo);
update();
return true;
}
@@ -323,7 +336,8 @@ bool ModFolderModel::installMod(const QString &filename)
qWarning() << "Copy of folder from" << originalPath << "to" << newpath << "has (potentially partially) failed.";
return false;
}
- installedMod.repath(newpath);
+ QFileInfo newpathInfo(newpath);
+ installedMod.repath(newpathInfo);
update();
return true;
}
diff --git a/launcher/minecraft/mod/ModFolderModel_test.cpp b/launcher/minecraft/mod/ModFolderModel_test.cpp
index 34a3b83a..b4d37ce5 100644
--- a/launcher/minecraft/mod/ModFolderModel_test.cpp
+++ b/launcher/minecraft/mod/ModFolderModel_test.cpp
@@ -35,7 +35,6 @@
#include <QTest>
#include <QTemporaryDir>
-#include "TestUtil.h"
#include "FileSystem.h"
#include "minecraft/mod/ModFolderModel.h"
@@ -50,7 +49,7 @@ slots:
void test_1178()
{
// source
- QString source = QFINDTESTDATA("data/test_folder");
+ QString source = QFINDTESTDATA("testdata/test_folder");
// sanity check
QVERIFY(!source.endsWith('/'));
diff --git a/launcher/minecraft/mod/testdata/test_folder/assets/minecraft/textures/blah.txt b/launcher/minecraft/mod/testdata/test_folder/assets/minecraft/textures/blah.txt
new file mode 100644
index 00000000..8d1c8b69
--- /dev/null
+++ b/launcher/minecraft/mod/testdata/test_folder/assets/minecraft/textures/blah.txt
@@ -0,0 +1 @@
+
diff --git a/launcher/minecraft/mod/testdata/test_folder/pack.mcmeta b/launcher/minecraft/mod/testdata/test_folder/pack.mcmeta
new file mode 100644
index 00000000..67ee0434
--- /dev/null
+++ b/launcher/minecraft/mod/testdata/test_folder/pack.mcmeta
@@ -0,0 +1,6 @@
+{
+ "pack": {
+ "pack_format": 1,
+ "description": "Some resource pack maybe"
+ }
+}
diff --git a/launcher/minecraft/mod/testdata/test_folder/pack.nfo b/launcher/minecraft/mod/testdata/test_folder/pack.nfo
new file mode 100644
index 00000000..8d1c8b69
--- /dev/null
+++ b/launcher/minecraft/mod/testdata/test_folder/pack.nfo
@@ -0,0 +1 @@
+
diff --git a/launcher/minecraft/services/CapeChange.cpp b/launcher/minecraft/services/CapeChange.cpp
index e49c166a..c73a11b6 100644
--- a/launcher/minecraft/services/CapeChange.cpp
+++ b/launcher/minecraft/services/CapeChange.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 "CapeChange.h"
#include <QNetworkRequest>
@@ -34,7 +69,11 @@ void CapeChange::clearCape() {
m_reply = shared_qobject_ptr<QNetworkReply>(rep);
connect(rep, &QNetworkReply::uploadProgress, this, &Task::setProgress);
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ connect(rep, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(downloadError(QNetworkReply::NetworkError)));
+#else
connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(downloadError(QNetworkReply::NetworkError)));
+#endif
connect(rep, SIGNAL(finished()), this, SLOT(downloadFinished()));
}
diff --git a/launcher/minecraft/services/SkinDelete.cpp b/launcher/minecraft/services/SkinDelete.cpp
index cce8364e..921bd094 100644
--- a/launcher/minecraft/services/SkinDelete.cpp
+++ b/launcher/minecraft/services/SkinDelete.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 "SkinDelete.h"
#include <QNetworkRequest>
@@ -19,7 +54,11 @@ void SkinDelete::executeTask()
setStatus(tr("Deleting skin"));
connect(rep, &QNetworkReply::uploadProgress, this, &Task::setProgress);
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ connect(rep, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(downloadError(QNetworkReply::NetworkError)));
+#else
connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(downloadError(QNetworkReply::NetworkError)));
+#endif
connect(rep, SIGNAL(finished()), this, SLOT(downloadFinished()));
}
diff --git a/launcher/minecraft/services/SkinUpload.cpp b/launcher/minecraft/services/SkinUpload.cpp
index 7c2e8337..c7987875 100644
--- a/launcher/minecraft/services/SkinUpload.cpp
+++ b/launcher/minecraft/services/SkinUpload.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 "SkinUpload.h"
#include <QNetworkRequest>
@@ -44,7 +79,11 @@ void SkinUpload::executeTask()
setStatus(tr("Uploading skin"));
connect(rep, &QNetworkReply::uploadProgress, this, &Task::setProgress);
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ connect(rep, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(downloadError(QNetworkReply::NetworkError)));
+#else
connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(downloadError(QNetworkReply::NetworkError)));
+#endif
connect(rep, SIGNAL(finished()), this, SLOT(downloadFinished()));
}
diff --git a/launcher/minecraft/update/AssetUpdateTask.cpp b/launcher/minecraft/update/AssetUpdateTask.cpp
index c4bddb08..dd246665 100644
--- a/launcher/minecraft/update/AssetUpdateTask.cpp
+++ b/launcher/minecraft/update/AssetUpdateTask.cpp
@@ -43,6 +43,7 @@ void AssetUpdateTask::executeTask()
connect(downloadJob.get(), &NetJob::succeeded, this, &AssetUpdateTask::assetIndexFinished);
connect(downloadJob.get(), &NetJob::failed, this, &AssetUpdateTask::assetIndexFailed);
+ connect(downloadJob.get(), &NetJob::aborted, this, [this]{ emitFailed(tr("Aborted")); });
connect(downloadJob.get(), &NetJob::progress, this, &AssetUpdateTask::progress);
qDebug() << m_inst->name() << ": Starting asset index download";
@@ -80,6 +81,7 @@ void AssetUpdateTask::assetIndexFinished()
downloadJob = job;
connect(downloadJob.get(), &NetJob::succeeded, this, &AssetUpdateTask::emitSucceeded);
connect(downloadJob.get(), &NetJob::failed, this, &AssetUpdateTask::assetsFailed);
+ connect(downloadJob.get(), &NetJob::aborted, this, [this]{ emitFailed(tr("Aborted")); });
connect(downloadJob.get(), &NetJob::progress, this, &AssetUpdateTask::progress);
downloadJob->start();
return;
diff --git a/launcher/minecraft/update/FMLLibrariesTask.cpp b/launcher/minecraft/update/FMLLibrariesTask.cpp
index 58141991..b6238ce9 100644
--- a/launcher/minecraft/update/FMLLibrariesTask.cpp
+++ b/launcher/minecraft/update/FMLLibrariesTask.cpp
@@ -72,6 +72,7 @@ void FMLLibrariesTask::executeTask()
connect(dljob, &NetJob::succeeded, this, &FMLLibrariesTask::fmllibsFinished);
connect(dljob, &NetJob::failed, this, &FMLLibrariesTask::fmllibsFailed);
+ connect(dljob, &NetJob::aborted, this, [this]{ emitFailed(tr("Aborted")); });
connect(dljob, &NetJob::progress, this, &FMLLibrariesTask::progress);
downloadJob.reset(dljob);
downloadJob->start();
diff --git a/launcher/minecraft/update/LibrariesTask.cpp b/launcher/minecraft/update/LibrariesTask.cpp
index 26679110..aa2bf407 100644
--- a/launcher/minecraft/update/LibrariesTask.cpp
+++ b/launcher/minecraft/update/LibrariesTask.cpp
@@ -68,6 +68,7 @@ void LibrariesTask::executeTask()
connect(downloadJob.get(), &NetJob::succeeded, this, &LibrariesTask::emitSucceeded);
connect(downloadJob.get(), &NetJob::failed, this, &LibrariesTask::jarlibFailed);
+ connect(downloadJob.get(), &NetJob::aborted, this, [this]{ emitFailed(tr("Aborted")); });
connect(downloadJob.get(), &NetJob::progress, this, &LibrariesTask::progress);
downloadJob->start();
}
diff --git a/launcher/modplatform/ModAPI.h b/launcher/modplatform/ModAPI.h
index 91b760df..cf116353 100644
--- a/launcher/modplatform/ModAPI.h
+++ b/launcher/modplatform/ModAPI.h
@@ -1,7 +1,43 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 <QString>
#include <QList>
+#include <list>
#include "Version.h"
diff --git a/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp b/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp
index b4936bd8..0ed0ad29 100644
--- a/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp
+++ b/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp
@@ -36,7 +36,7 @@
#include "ATLPackInstallTask.h"
-#include <QtConcurrent/QtConcurrent>
+#include <QtConcurrent>
#include <quazip/quazip.h>
@@ -557,7 +557,11 @@ void PackInstallTask::extractConfigs()
return;
}
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ m_extractFuture = QtConcurrent::run(QThreadPool::globalInstance(), QOverload<QString, QString>::of(MMCZip::extractDir), archivePath, extractDir.absolutePath() + "/minecraft");
+#else
m_extractFuture = QtConcurrent::run(QThreadPool::globalInstance(), MMCZip::extractDir, archivePath, extractDir.absolutePath() + "/minecraft");
+#endif
connect(&m_extractFutureWatcher, &QFutureWatcher<QStringList>::finished, this, [&]()
{
downloadMods();
@@ -702,7 +706,11 @@ void PackInstallTask::onModsDownloaded() {
jobPtr.reset();
if(!modsToExtract.empty() || !modsToDecomp.empty() || !modsToCopy.empty()) {
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ m_modExtractFuture = QtConcurrent::run(QThreadPool::globalInstance(), &PackInstallTask::extractMods, this, modsToExtract, modsToDecomp, modsToCopy);
+#else
m_modExtractFuture = QtConcurrent::run(QThreadPool::globalInstance(), this, &PackInstallTask::extractMods, modsToExtract, modsToDecomp, modsToCopy);
+#endif
connect(&m_modExtractFutureWatcher, &QFutureWatcher<QStringList>::finished, this, &PackInstallTask::onModsExtracted);
connect(&m_modExtractFutureWatcher, &QFutureWatcher<QStringList>::canceled, this, [&]()
{
@@ -754,7 +762,7 @@ bool PackInstallTask::extractMods(
QString folderToExtract = "";
if(mod.type == ModType::Extract) {
folderToExtract = mod.extractFolder;
- folderToExtract.remove(QRegExp("^/"));
+ folderToExtract.remove(QRegularExpression("^/"));
}
qDebug() << "Extracting " + mod.file + " to " + extractToDir;
@@ -830,14 +838,14 @@ void PackInstallTask::install()
auto version = getVersionForLoader("net.minecraftforge");
if(version == Q_NULLPTR) return;
- components->setComponentVersion("net.minecraftforge", version, true);
+ components->setComponentVersion("net.minecraftforge", version);
}
else if(m_version.loader.type == QString("fabric"))
{
auto version = getVersionForLoader("net.fabricmc.fabric-loader");
if(version == Q_NULLPTR) return;
- components->setComponentVersion("net.fabricmc.fabric-loader", version, true);
+ components->setComponentVersion("net.fabricmc.fabric-loader", version);
}
else if(m_version.loader.type != QString())
{
diff --git a/launcher/modplatform/flame/FileResolvingTask.cpp b/launcher/modplatform/flame/FileResolvingTask.cpp
index a790ab9c..c1f56658 100644
--- a/launcher/modplatform/flame/FileResolvingTask.cpp
+++ b/launcher/modplatform/flame/FileResolvingTask.cpp
@@ -10,7 +10,7 @@ Flame::FileResolvingTask::FileResolvingTask(const shared_qobject_ptr<QNetworkAcc
void Flame::FileResolvingTask::executeTask()
{
setStatus(tr("Resolving mod IDs..."));
- setProgress(0, m_toProcess.files.size());
+ setProgress(0, 3);
m_dljob = new NetJob("Mod id resolver", m_network);
result.reset(new QByteArray());
//build json data to send
@@ -29,6 +29,7 @@ void Flame::FileResolvingTask::executeTask()
void Flame::FileResolvingTask::netJobFinished()
{
+ setProgress(1, 3);
int index = 0;
// job to check modrinth for blocked projects
auto job = new NetJob("Modrinth check", m_network);
@@ -63,6 +64,7 @@ void Flame::FileResolvingTask::netJobFinished()
}
void Flame::FileResolvingTask::modrinthCheckFinished() {
+ setProgress(2, 3);
qDebug() << "Finished with blocked mods : " << blockedProjects.size();
for (auto it = blockedProjects.keyBegin(); it != blockedProjects.keyEnd(); it++) {
diff --git a/launcher/modplatform/flame/FlameAPI.h b/launcher/modplatform/flame/FlameAPI.h
index 424153d2..aea76ff1 100644
--- a/launcher/modplatform/flame/FlameAPI.h
+++ b/launcher/modplatform/flame/FlameAPI.h
@@ -59,7 +59,7 @@ class FlameAPI : public NetworkModAPI {
};
public:
- static auto getMappedModLoader(const ModLoaderTypes loaders) -> const int
+ static auto getMappedModLoader(const ModLoaderTypes loaders) -> int
{
// https://docs.curseforge.com/?http#tocS_ModLoaderType
if (loaders & Forge)
diff --git a/launcher/modplatform/flame/PackManifest.h b/launcher/modplatform/flame/PackManifest.h
index 26a48d1c..677db1c3 100644
--- a/launcher/modplatform/flame/PackManifest.h
+++ b/launcher/modplatform/flame/PackManifest.h
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 <QString>
@@ -25,7 +60,7 @@ struct File
bool resolved = false;
QString fileName;
QUrl url;
- QString targetFolder = QLatin1Literal("mods");
+ QString targetFolder = QStringLiteral("mods");
enum class Type
{
Unknown,
diff --git a/launcher/modplatform/legacy_ftb/PackFetchTask.cpp b/launcher/modplatform/legacy_ftb/PackFetchTask.cpp
index 961fe868..4da6a866 100644
--- a/launcher/modplatform/legacy_ftb/PackFetchTask.cpp
+++ b/launcher/modplatform/legacy_ftb/PackFetchTask.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 "PackFetchTask.h"
#include "PrivatePackManager.h"
@@ -103,7 +138,7 @@ bool PackFetchTask::parseAndAddPacks(QByteArray &data, PackType packType, Modpac
if(!doc.setContent(data, false, &errorMsg, &errorLine, &errorCol))
{
- auto fullErrMsg = QString("Failed to fetch modpack data: %1 %2:3d!").arg(errorMsg, errorLine, errorCol);
+ auto fullErrMsg = QString("Failed to fetch modpack data: %1 %2:%3!").arg(errorMsg).arg(errorLine).arg(errorCol);
qWarning() << fullErrMsg;
data.clear();
return false;
diff --git a/launcher/modplatform/legacy_ftb/PackInstallTask.cpp b/launcher/modplatform/legacy_ftb/PackInstallTask.cpp
index c63a9f1e..83e14969 100644
--- a/launcher/modplatform/legacy_ftb/PackInstallTask.cpp
+++ b/launcher/modplatform/legacy_ftb/PackInstallTask.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 "PackInstallTask.h"
#include <QtConcurrent>
@@ -88,7 +123,11 @@ void PackInstallTask::unzip()
return;
}
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ m_extractFuture = QtConcurrent::run(QThreadPool::globalInstance(), QOverload<QString, QString>::of(MMCZip::extractDir), archivePath, extractDir.absolutePath() + "/unzip");
+#else
m_extractFuture = QtConcurrent::run(QThreadPool::globalInstance(), MMCZip::extractDir, archivePath, extractDir.absolutePath() + "/unzip");
+#endif
connect(&m_extractFutureWatcher, &QFutureWatcher<QStringList>::finished, this, &PackInstallTask::onUnzipFinished);
connect(&m_extractFutureWatcher, &QFutureWatcher<QStringList>::canceled, this, &PackInstallTask::onUnzipCanceled);
m_extractFutureWatcher.setFuture(m_extractFuture);
diff --git a/launcher/modplatform/legacy_ftb/PrivatePackManager.cpp b/launcher/modplatform/legacy_ftb/PrivatePackManager.cpp
index 501e6003..1a81f026 100644
--- a/launcher/modplatform/legacy_ftb/PrivatePackManager.cpp
+++ b/launcher/modplatform/legacy_ftb/PrivatePackManager.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 "PrivatePackManager.h"
#include <QDebug>
@@ -10,7 +45,13 @@ void PrivatePackManager::load()
{
try
{
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+ auto foo = QString::fromUtf8(FS::read(m_filename)).split('\n', Qt::SkipEmptyParts);
+ currentPacks = QSet<QString>(foo.begin(), foo.end());
+#else
currentPacks = QString::fromUtf8(FS::read(m_filename)).split('\n', QString::SkipEmptyParts).toSet();
+#endif
+
dirty = false;
}
catch(...)
@@ -28,7 +69,7 @@ void PrivatePackManager::save() const
}
try
{
- QStringList list = currentPacks.toList();
+ QStringList list = currentPacks.values();
FS::write(m_filename, list.join('\n').toUtf8());
dirty = false;
}
diff --git a/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp b/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp
index c324ffda..cac432cd 100644
--- a/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp
+++ b/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp
@@ -216,10 +216,10 @@ void PackInstallTask::install()
if(target.type != "modloader") continue;
if(target.name == "forge") {
- components->setComponentVersion("net.minecraftforge", target.version, true);
+ components->setComponentVersion("net.minecraftforge", target.version);
}
else if(target.name == "fabric") {
- components->setComponentVersion("net.fabricmc.fabric-loader", target.version, true);
+ components->setComponentVersion("net.fabricmc.fabric-loader", target.version);
}
}
diff --git a/launcher/modplatform/packwiz/Packwiz_test.cpp b/launcher/modplatform/packwiz/Packwiz_test.cpp
index 3d47f9f7..d6251148 100644
--- a/launcher/modplatform/packwiz/Packwiz_test.cpp
+++ b/launcher/modplatform/packwiz/Packwiz_test.cpp
@@ -21,7 +21,6 @@
#include <QTest>
#include "Packwiz.h"
-#include "TestUtil.h"
class PackwizTest : public QObject {
Q_OBJECT
diff --git a/launcher/modplatform/technic/TechnicPackProcessor.cpp b/launcher/modplatform/technic/TechnicPackProcessor.cpp
index 471b4a2f..95feb4b2 100644
--- a/launcher/modplatform/technic/TechnicPackProcessor.cpp
+++ b/launcher/modplatform/technic/TechnicPackProcessor.cpp
@@ -187,17 +187,17 @@ void Technic::TechnicPackProcessor::run(SettingsObjectPtr globalSettings, const
}
else
{
- static QStringList possibleLoaders{
- "net.minecraftforge:minecraftforge:",
- "net.fabricmc:fabric-loader:",
- "org.quiltmc:quilt-loader:"
+ // <Technic library name prefix> -> <our component name>
+ static QMap<QString, QString> loaderMap {
+ {"net.minecraftforge:minecraftforge:", "net.minecraftforge"},
+ {"net.fabricmc:fabric-loader:", "net.fabricmc.fabric-loader"},
+ {"org.quiltmc:quilt-loader:", "org.quiltmc.quilt-loader"}
};
- for (const auto& loader : possibleLoaders)
+ for (const auto& loader : loaderMap.keys())
{
if (libraryName.startsWith(loader))
{
- auto loaderComponent = loader.chopped(1).replace(":", ".");
- components->setComponentVersion(loaderComponent, libraryName.section(':', 2));
+ components->setComponentVersion(loaderMap.value(loader), libraryName.section(':', 2));
break;
}
}
diff --git a/launcher/mojang/PackageManifest_test.cpp b/launcher/mojang/PackageManifest_test.cpp
index d4c55c5a..e8da4266 100644
--- a/launcher/mojang/PackageManifest_test.cpp
+++ b/launcher/mojang/PackageManifest_test.cpp
@@ -1,6 +1,5 @@
#include <QTest>
#include <QDebug>
-#include "TestUtil.h"
#include "mojang/PackageManifest.h"
diff --git a/launcher/net/Download.cpp b/launcher/net/Download.cpp
index d93eb088..3061e32e 100644
--- a/launcher/net/Download.cpp
+++ b/launcher/net/Download.cpp
@@ -2,6 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* 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
@@ -126,7 +127,11 @@ void Download::executeTask()
m_reply.reset(rep);
connect(rep, &QNetworkReply::downloadProgress, this, &Download::downloadProgress);
connect(rep, &QNetworkReply::finished, this, &Download::downloadFinished);
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ connect(rep, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), SLOT(downloadError(QNetworkReply::NetworkError)));
+#else
connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(downloadError(QNetworkReply::NetworkError)));
+#endif
connect(rep, &QNetworkReply::sslErrors, this, &Download::sslErrors);
connect(rep, &QNetworkReply::readyRead, this, &Download::downloadReadyRead);
}
diff --git a/launcher/net/NetJob.cpp b/launcher/net/NetJob.cpp
index df899178..bab35fa5 100644
--- a/launcher/net/NetJob.cpp
+++ b/launcher/net/NetJob.cpp
@@ -2,6 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* 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
@@ -97,11 +98,16 @@ auto NetJob::abort() -> bool
bool fullyAborted = true;
// fail all downloads on the queue
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+ QSet<int> todoSet(m_todo.begin(), m_todo.end());
+ m_failed.unite(todoSet);
+#else
m_failed.unite(m_todo.toSet());
+#endif
m_todo.clear();
// abort active downloads
- auto toKill = m_doing.toList();
+ auto toKill = m_doing.values();
for (auto index : toKill) {
auto part = m_downloads[index];
fullyAborted &= part->abort();
diff --git a/launcher/net/PasteUpload.cpp b/launcher/net/PasteUpload.cpp
index 7438e1a1..76b86743 100644
--- a/launcher/net/PasteUpload.cpp
+++ b/launcher/net/PasteUpload.cpp
@@ -44,8 +44,6 @@
#include <QJsonArray>
#include <QJsonDocument>
#include <QFile>
-#include <QHttpPart>
-#include <QUrlQuery>
std::array<PasteUpload::PasteTypeInfo, 4> PasteUpload::PasteTypes = {
{{"0x0.st", "https://0x0.st", ""},
@@ -131,10 +129,13 @@ void PasteUpload::executeTask()
connect(rep, &QNetworkReply::uploadProgress, this, &Task::setProgress);
connect(rep, &QNetworkReply::finished, this, &PasteUpload::downloadFinished);
- // This function call would be a lot shorter if we were using the latest Qt
- connect(rep,
- static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error),
- this, &PasteUpload::downloadError);
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
+ connect(rep, &QNetworkReply::errorOccurred, this, &PasteUpload::downloadError);
+#else
+ connect(rep, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), this, &PasteUpload::downloadError);
+#endif
+
m_reply = std::shared_ptr<QNetworkReply>(rep);
diff --git a/launcher/news/NewsChecker.cpp b/launcher/news/NewsChecker.cpp
index 6724950f..3b969732 100644
--- a/launcher/news/NewsChecker.cpp
+++ b/launcher/news/NewsChecker.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * 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 "NewsChecker.h"
@@ -61,7 +81,7 @@ void NewsChecker::rssDownloadFinished()
// Parse the XML.
if (!doc.setContent(newsData, false, &errorMsg, &errorLine, &errorCol))
{
- QString fullErrorMsg = QString("Error parsing RSS feed XML. %s at %d:%d.").arg(errorMsg, errorLine, errorCol);
+ QString fullErrorMsg = QString("Error parsing RSS feed XML. %1 at %2:%3.").arg(errorMsg).arg(errorLine).arg(errorCol);
fail(fullErrorMsg);
newsData.clear();
return;
diff --git a/launcher/news/NewsEntry.cpp b/launcher/news/NewsEntry.cpp
index 137703d1..cfe07e86 100644
--- a/launcher/news/NewsEntry.cpp
+++ b/launcher/news/NewsEntry.cpp
@@ -54,7 +54,7 @@ inline QString childValue(const QDomElement& element, const QString& childName,
bool NewsEntry::fromXmlElement(const QDomElement& element, NewsEntry* entry, QString* errorMsg)
{
QString title = childValue(element, "title", tr("Untitled"));
- QString content = childValue(element, "description", tr("No content."));
+ QString content = childValue(element, "content", tr("No content."));
QString link = childValue(element, "id");
entry->title = title;
diff --git a/launcher/screenshots/ImgurAlbumCreation.cpp b/launcher/screenshots/ImgurAlbumCreation.cpp
index 04e26ea2..a72c32d3 100644
--- a/launcher/screenshots/ImgurAlbumCreation.cpp
+++ b/launcher/screenshots/ImgurAlbumCreation.cpp
@@ -2,6 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* 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
@@ -73,7 +74,11 @@ void ImgurAlbumCreation::executeTask()
m_reply.reset(rep);
connect(rep, &QNetworkReply::uploadProgress, this, &ImgurAlbumCreation::downloadProgress);
connect(rep, &QNetworkReply::finished, this, &ImgurAlbumCreation::downloadFinished);
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ connect(rep, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), SLOT(downloadError(QNetworkReply::NetworkError)));
+#else
connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(downloadError(QNetworkReply::NetworkError)));
+#endif
}
void ImgurAlbumCreation::downloadError(QNetworkReply::NetworkError error)
{
diff --git a/launcher/screenshots/ImgurUpload.cpp b/launcher/screenshots/ImgurUpload.cpp
index 9aeb6fb8..f8ac9bc2 100644
--- a/launcher/screenshots/ImgurUpload.cpp
+++ b/launcher/screenshots/ImgurUpload.cpp
@@ -2,6 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* 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
@@ -88,8 +89,11 @@ void ImgurUpload::executeTask()
m_reply.reset(rep);
connect(rep, &QNetworkReply::uploadProgress, this, &ImgurUpload::downloadProgress);
connect(rep, &QNetworkReply::finished, this, &ImgurUpload::downloadFinished);
- connect(rep, SIGNAL(error(QNetworkReply::NetworkError)),
- SLOT(downloadError(QNetworkReply::NetworkError)));
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ connect(rep, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), SLOT(downloadError(QNetworkReply::NetworkError)));
+#else
+ connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(downloadError(QNetworkReply::NetworkError)));
+#endif
}
void ImgurUpload::downloadError(QNetworkReply::NetworkError error)
{
diff --git a/launcher/settings/INIFile.cpp b/launcher/settings/INIFile.cpp
index 6a3c801d..733cd444 100644
--- a/launcher/settings/INIFile.cpp
+++ b/launcher/settings/INIFile.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * 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 "settings/INIFile.h"
@@ -29,7 +49,7 @@ INIFile::INIFile()
QString INIFile::unescape(QString orig)
{
QString out;
- QChar prev = 0;
+ QChar prev = QChar::Null;
for(auto c: orig)
{
if(prev == '\\')
@@ -42,7 +62,7 @@ QString INIFile::unescape(QString orig)
out += '#';
else
out += c;
- prev = 0;
+ prev = QChar::Null;
}
else
{
@@ -52,7 +72,7 @@ QString INIFile::unescape(QString orig)
continue;
}
out += c;
- prev = 0;
+ prev = QChar::Null;
}
}
return out;
@@ -117,7 +137,9 @@ bool INIFile::loadFile(QString fileName)
bool INIFile::loadFile(QByteArray file)
{
QTextStream in(file);
+#if QT_VERSION <= QT_VERSION_CHECK(6, 0, 0)
in.setCodec("UTF-8");
+#endif
QStringList lines = in.readAll().split('\n');
for (int i = 0; i < lines.count(); i++)
diff --git a/launcher/settings/INIFile_test.cpp b/launcher/settings/INIFile_test.cpp
index 08c2155e..d23f9fdf 100644
--- a/launcher/settings/INIFile_test.cpp
+++ b/launcher/settings/INIFile_test.cpp
@@ -1,5 +1,4 @@
#include <QTest>
-#include "TestUtil.h"
#include "settings/INIFile.h"
diff --git a/launcher/tasks/ConcurrentTask.cpp b/launcher/tasks/ConcurrentTask.cpp
new file mode 100644
index 00000000..b88cfb13
--- /dev/null
+++ b/launcher/tasks/ConcurrentTask.cpp
@@ -0,0 +1,144 @@
+#include "ConcurrentTask.h"
+
+#include <QDebug>
+
+ConcurrentTask::ConcurrentTask(QObject* parent, QString task_name, int max_concurrent)
+ : Task(parent), m_name(task_name), m_total_max_size(max_concurrent)
+{}
+
+ConcurrentTask::~ConcurrentTask()
+{
+ for (auto task : m_queue) {
+ if (task)
+ task->deleteLater();
+ }
+}
+
+auto ConcurrentTask::getStepProgress() const -> qint64
+{
+ return m_stepProgress;
+}
+
+auto ConcurrentTask::getStepTotalProgress() const -> qint64
+{
+ return m_stepTotalProgress;
+}
+
+void ConcurrentTask::addTask(Task::Ptr task)
+{
+ if (!isRunning())
+ m_queue.append(task);
+ else
+ qWarning() << "Tried to add a task to a running concurrent task!";
+}
+
+void ConcurrentTask::executeTask()
+{
+ m_total_size = m_queue.size();
+
+ for (int i = 0; i < m_total_max_size; i++)
+ startNext();
+}
+
+bool ConcurrentTask::abort()
+{
+ if (m_doing.isEmpty()) {
+ // Don't call emitAborted() here, we want to bypass the 'is the task running' check
+ emit aborted();
+ emit finished();
+
+ m_aborted = true;
+ return true;
+ }
+
+ m_queue.clear();
+
+ m_aborted = true;
+ for (auto task : m_doing)
+ m_aborted &= task->abort();
+
+ if (m_aborted)
+ emitAborted();
+
+ return m_aborted;
+}
+
+void ConcurrentTask::startNext()
+{
+ if (m_aborted || m_doing.count() > m_total_max_size)
+ return;
+
+ if (m_queue.isEmpty() && m_doing.isEmpty()) {
+ emitSucceeded();
+ return;
+ }
+
+ if (m_queue.isEmpty())
+ return;
+
+ Task::Ptr next = m_queue.dequeue();
+
+ connect(next.get(), &Task::succeeded, this, [this, next] { subTaskSucceeded(next); });
+ connect(next.get(), &Task::failed, this, [this, next](QString msg) { subTaskFailed(next, msg); });
+
+ connect(next.get(), &Task::status, this, &ConcurrentTask::subTaskStatus);
+ connect(next.get(), &Task::stepStatus, this, &ConcurrentTask::subTaskStatus);
+
+ connect(next.get(), &Task::progress, this, &ConcurrentTask::subTaskProgress);
+
+ m_doing.insert(next.get(), next);
+
+ setStepStatus(next->isMultiStep() ? next->getStepStatus() : next->getStatus());
+ updateState();
+
+ next->start();
+}
+
+void ConcurrentTask::subTaskSucceeded(Task::Ptr task)
+{
+ m_done.insert(task.get(), task);
+ m_doing.remove(task.get());
+
+ disconnect(task.get(), 0, this, 0);
+
+ updateState();
+
+ startNext();
+}
+
+void ConcurrentTask::subTaskFailed(Task::Ptr task, const QString& msg)
+{
+ m_done.insert(task.get(), task);
+ m_failed.insert(task.get(), task);
+
+ m_doing.remove(task.get());
+
+ disconnect(task.get(), 0, this, 0);
+
+ updateState();
+
+ startNext();
+}
+
+void ConcurrentTask::subTaskStatus(const QString& msg)
+{
+ setStepStatus(msg);
+}
+
+void ConcurrentTask::subTaskProgress(qint64 current, qint64 total)
+{
+ if (total == 0) {
+ setProgress(0, 100);
+ return;
+ }
+
+ m_stepProgress = current;
+ m_stepTotalProgress = total;
+}
+
+void ConcurrentTask::updateState()
+{
+ setProgress(m_done.count(), m_total_size);
+ setStatus(tr("Executing %1 task(s) (%2 out of %3 are done)")
+ .arg(QString::number(m_doing.count()), QString::number(m_done.count()), QString::number(m_total_size)));
+}
diff --git a/launcher/tasks/ConcurrentTask.h b/launcher/tasks/ConcurrentTask.h
new file mode 100644
index 00000000..5898899d
--- /dev/null
+++ b/launcher/tasks/ConcurrentTask.h
@@ -0,0 +1,58 @@
+#pragma once
+
+#include <QQueue>
+#include <QSet>
+
+#include "tasks/Task.h"
+
+class ConcurrentTask : public Task {
+ Q_OBJECT
+public:
+ explicit ConcurrentTask(QObject* parent = nullptr, QString task_name = "", int max_concurrent = 6);
+ virtual ~ConcurrentTask();
+
+ inline auto isMultiStep() const -> bool override { return m_queue.size() > 1; };
+ auto getStepProgress() const -> qint64 override;
+ auto getStepTotalProgress() const -> qint64 override;
+
+ inline auto getStepStatus() const -> QString override { return m_step_status; }
+
+ void addTask(Task::Ptr task);
+
+public slots:
+ bool abort() override;
+
+protected
+slots:
+ void executeTask() override;
+
+ virtual void startNext();
+
+ void subTaskSucceeded(Task::Ptr);
+ void subTaskFailed(Task::Ptr, const QString &msg);
+ void subTaskStatus(const QString &msg);
+ void subTaskProgress(qint64 current, qint64 total);
+
+protected:
+ void setStepStatus(QString status) { m_step_status = status; emit stepStatus(status); };
+
+ virtual void updateState();
+
+protected:
+ QString m_name;
+ QString m_step_status;
+
+ QQueue<Task::Ptr> m_queue;
+
+ QHash<Task*, Task::Ptr> m_doing;
+ QHash<Task*, Task::Ptr> m_done;
+ QHash<Task*, Task::Ptr> m_failed;
+
+ int m_total_max_size;
+ int m_total_size;
+
+ qint64 m_stepProgress = 0;
+ qint64 m_stepTotalProgress = 100;
+
+ bool m_aborted = false;
+};
diff --git a/launcher/tasks/Task_test.cpp b/launcher/tasks/Task_test.cpp
index 9b6cc2e5..ef153a6a 100644
--- a/launcher/tasks/Task_test.cpp
+++ b/launcher/tasks/Task_test.cpp
@@ -1,5 +1,4 @@
#include <QTest>
-#include "TestUtil.h"
#include "Task.h"
diff --git a/launcher/translations/POTranslator.cpp b/launcher/translations/POTranslator.cpp
index 1ffcb9a4..c77ae45d 100644
--- a/launcher/translations/POTranslator.cpp
+++ b/launcher/translations/POTranslator.cpp
@@ -329,6 +329,11 @@ POTranslator::POTranslator(const QString& filename, QObject* parent) : QTranslat
d->reload();
}
+POTranslator::~POTranslator()
+{
+ delete d;
+}
+
QString POTranslator::translate(const char* context, const char* sourceText, const char* disambiguation, int n) const
{
if(disambiguation)
diff --git a/launcher/translations/POTranslator.h b/launcher/translations/POTranslator.h
index 6d518560..1634018c 100644
--- a/launcher/translations/POTranslator.h
+++ b/launcher/translations/POTranslator.h
@@ -9,6 +9,7 @@ class POTranslator : public QTranslator
Q_OBJECT
public:
explicit POTranslator(const QString& filename, QObject * parent = nullptr);
+ virtual ~POTranslator();
QString translate(const char * context, const char * sourceText, const char * disambiguation, int n) const override;
bool isEmpty() const override;
private:
diff --git a/launcher/translations/TranslationsModel.cpp b/launcher/translations/TranslationsModel.cpp
index 53722d69..848b4d19 100644
--- a/launcher/translations/TranslationsModel.cpp
+++ b/launcher/translations/TranslationsModel.cpp
@@ -2,6 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* 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
@@ -52,7 +53,7 @@
#include "Application.h"
-const static QLatin1Literal defaultLangCode("en_US");
+const static QLatin1String defaultLangCode("en_US");
enum class FileType
{
@@ -431,9 +432,7 @@ QVariant TranslationsModel::data(const QModelIndex& index, int role) const
}
case Column::Completeness:
{
- QString text;
- text.sprintf("%3.1f %%", lang.percentTranslated());
- return text;
+ return QString("%1%").arg(lang.percentTranslated(), 3, 'f', 1);
}
}
}
diff --git a/launcher/ui/GuiUtil.cpp b/launcher/ui/GuiUtil.cpp
index b1ea5ee9..5a62e4d0 100644
--- a/launcher/ui/GuiUtil.cpp
+++ b/launcher/ui/GuiUtil.cpp
@@ -39,7 +39,6 @@
#include <QClipboard>
#include <QApplication>
#include <QFileDialog>
-#include <QStandardPaths>
#include "ui/dialogs/ProgressDialog.h"
#include "ui/dialogs/CustomMessageBox.h"
diff --git a/launcher/ui/InstanceWindow.cpp b/launcher/ui/InstanceWindow.cpp
index ae765c3c..0ad8c594 100644
--- a/launcher/ui/InstanceWindow.cpp
+++ b/launcher/ui/InstanceWindow.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * 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 "InstanceWindow.h"
@@ -97,9 +117,9 @@ InstanceWindow::InstanceWindow(InstancePtr instance, QWidget *parent)
// set up instance and launch process recognition
{
auto launchTask = m_instance->getLaunchTask();
- on_InstanceLaunchTask_changed(launchTask);
- connect(m_instance.get(), &BaseInstance::launchTaskChanged, this, &InstanceWindow::on_InstanceLaunchTask_changed);
- connect(m_instance.get(), &BaseInstance::runningStatusChanged, this, &InstanceWindow::on_RunningState_changed);
+ instanceLaunchTaskChanged(launchTask);
+ connect(m_instance.get(), &BaseInstance::launchTaskChanged, this, &InstanceWindow::instanceLaunchTaskChanged);
+ connect(m_instance.get(), &BaseInstance::runningStatusChanged, this, &InstanceWindow::runningStateChanged);
}
// set up instance destruction detection
@@ -152,12 +172,12 @@ void InstanceWindow::on_btnLaunchMinecraftOffline_clicked()
APPLICATION->launch(m_instance, false, nullptr);
}
-void InstanceWindow::on_InstanceLaunchTask_changed(shared_qobject_ptr<LaunchTask> proc)
+void InstanceWindow::instanceLaunchTaskChanged(shared_qobject_ptr<LaunchTask> proc)
{
m_proc = proc;
}
-void InstanceWindow::on_RunningState_changed(bool running)
+void InstanceWindow::runningStateChanged(bool running)
{
updateLaunchButtons();
m_container->refreshContainer();
diff --git a/launcher/ui/InstanceWindow.h b/launcher/ui/InstanceWindow.h
index 1acf684e..aec07868 100644
--- a/launcher/ui/InstanceWindow.h
+++ b/launcher/ui/InstanceWindow.h
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * 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
@@ -55,8 +75,8 @@ slots:
void on_btnKillMinecraft_clicked();
void on_btnLaunchMinecraftOffline_clicked();
- void on_InstanceLaunchTask_changed(shared_qobject_ptr<LaunchTask> proc);
- void on_RunningState_changed(bool running);
+ void instanceLaunchTaskChanged(shared_qobject_ptr<LaunchTask> proc);
+ void runningStateChanged(bool running);
void on_instanceStatusChanged(BaseInstance::Status, BaseInstance::Status newStatus);
protected:
diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp
index 210442df..d58f158e 100644
--- a/launcher/ui/MainWindow.cpp
+++ b/launcher/ui/MainWindow.cpp
@@ -42,31 +42,31 @@
#include "MainWindow.h"
-#include <QtCore/QVariant>
-#include <QtCore/QUrl>
-#include <QtCore/QDir>
-#include <QtCore/QFileInfo>
-
-#include <QtGui/QKeyEvent>
-
-#include <QtWidgets/QAction>
-#include <QtWidgets/QApplication>
-#include <QtWidgets/QButtonGroup>
-#include <QtWidgets/QHBoxLayout>
-#include <QtWidgets/QHeaderView>
-#include <QtWidgets/QMainWindow>
-#include <QtWidgets/QStatusBar>
-#include <QtWidgets/QToolBar>
-#include <QtWidgets/QWidget>
-#include <QtWidgets/QMenu>
-#include <QtWidgets/QMenuBar>
-#include <QtWidgets/QMessageBox>
-#include <QtWidgets/QInputDialog>
-#include <QtWidgets/QLabel>
-#include <QtWidgets/QToolButton>
-#include <QtWidgets/QWidgetAction>
-#include <QtWidgets/QProgressDialog>
-#include <QtWidgets/QShortcut>
+#include <QVariant>
+#include <QUrl>
+#include <QDir>
+#include <QFileInfo>
+
+#include <QKeyEvent>
+#include <QAction>
+
+#include <QApplication>
+#include <QButtonGroup>
+#include <QHBoxLayout>
+#include <QHeaderView>
+#include <QMainWindow>
+#include <QStatusBar>
+#include <QToolBar>
+#include <QWidget>
+#include <QMenu>
+#include <QMenuBar>
+#include <QMessageBox>
+#include <QInputDialog>
+#include <QLabel>
+#include <QToolButton>
+#include <QWidgetAction>
+#include <QProgressDialog>
+#include <QShortcut>
#include <BaseInstance.h>
#include <InstanceList.h>
@@ -95,6 +95,7 @@
#include "ui/instanceview/InstanceDelegate.h"
#include "ui/widgets/LabeledToolButton.h"
#include "ui/dialogs/NewInstanceDialog.h"
+#include "ui/dialogs/NewsDialog.h"
#include "ui/dialogs/ProgressDialog.h"
#include "ui/dialogs/AboutDialog.h"
#include "ui/dialogs/VersionSelectDialog.h"
@@ -224,6 +225,7 @@ public:
TranslatedAction actionMoreNews;
TranslatedAction actionManageAccounts;
TranslatedAction actionLaunchInstance;
+ TranslatedAction actionKillInstance;
TranslatedAction actionRenameInstance;
TranslatedAction actionChangeInstGroup;
TranslatedAction actionChangeInstIcon;
@@ -233,7 +235,6 @@ public:
TranslatedAction actionMods;
TranslatedAction actionViewSelectedInstFolder;
TranslatedAction actionViewSelectedMCFolder;
- TranslatedAction actionViewSelectedModsFolder;
TranslatedAction actionDeleteInstance;
TranslatedAction actionConfig_Folder;
TranslatedAction actionCAT;
@@ -282,29 +283,8 @@ public:
TranslatedToolbar instanceToolBar;
TranslatedToolbar newsToolBar;
QVector<TranslatedToolbar *> all_toolbars;
- bool m_kill = false;
- void updateLaunchAction()
- {
- if(m_kill)
- {
- actionLaunchInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "&Kill"));
- actionLaunchInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Kill the running instance"));
- }
- else
- {
- actionLaunchInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "&Launch"));
- actionLaunchInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Launch the selected instance."));
- }
- actionLaunchInstance.retranslate();
- }
- void setLaunchAction(bool kill)
- {
- m_kill = kill;
- updateLaunchAction();
- }
-
- void createMainToolbarActions(QMainWindow *MainWindow)
+ void createMainToolbarActions(MainWindow *MainWindow)
{
actionAddInstance = TranslatedAction(MainWindow);
actionAddInstance->setObjectName(QStringLiteral("actionAddInstance"));
@@ -503,9 +483,12 @@ public:
menuBar->setVisible(APPLICATION->settings()->get("MenuBarInsteadOfToolBar").toBool());
fileMenu = menuBar->addMenu(tr("&File"));
+ // Workaround for QTBUG-94802 (https://bugreports.qt.io/browse/QTBUG-94802); also present for other menus
+ fileMenu->setSeparatorsCollapsible(false);
fileMenu->addAction(actionAddInstance);
fileMenu->addAction(actionLaunchInstance);
fileMenu->addAction(actionLaunchInstanceOffline);
+ fileMenu->addAction(actionKillInstance);
fileMenu->addAction(actionCloseWindow);
fileMenu->addSeparator();
fileMenu->addAction(actionEditInstance);
@@ -526,15 +509,18 @@ public:
fileMenu->addAction(actionSettings);
viewMenu = menuBar->addMenu(tr("&View"));
+ viewMenu->setSeparatorsCollapsible(false);
viewMenu->addAction(actionCAT);
viewMenu->addSeparator();
menuBar->addMenu(foldersMenu);
profileMenu = menuBar->addMenu(tr("&Profiles"));
+ profileMenu->setSeparatorsCollapsible(false);
profileMenu->addAction(actionManageAccounts);
helpMenu = menuBar->addMenu(tr("&Help"));
+ helpMenu->setSeparatorsCollapsible(false);
helpMenu->addAction(actionAbout);
helpMenu->addAction(actionOpenWiki);
helpMenu->addAction(actionNewsMenuBar);
@@ -580,10 +566,9 @@ public:
}
// "Instance actions" are actions that require an instance to be selected (i.e. "new instance" is not here)
+ // Actions that also require other conditions (e.g. a running instance) won't be changed.
void setInstanceActionsEnabled(bool enabled)
{
- actionLaunchInstance->setEnabled(enabled);
- actionLaunchInstanceOffline->setEnabled(enabled);
actionEditInstance->setEnabled(enabled);
actionEditInstNotes->setEnabled(enabled);
actionMods->setEnabled(enabled);
@@ -670,6 +655,14 @@ public:
actionLaunchInstanceOffline.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Launch the selected instance in offline mode."));
all_actions.append(&actionLaunchInstanceOffline);
+ actionKillInstance = TranslatedAction(MainWindow);
+ actionKillInstance->setObjectName(QStringLiteral("actionKillInstance"));
+ actionKillInstance->setDisabled(true);
+ actionKillInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "&Kill"));
+ actionKillInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Kill the running instance"));
+ actionKillInstance->setShortcut(QKeySequence(tr("Ctrl+K")));
+ all_actions.append(&actionKillInstance);
+
actionEditInstance = TranslatedAction(MainWindow);
actionEditInstance->setObjectName(QStringLiteral("actionEditInstance"));
actionEditInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Edit Inst&ance..."));
@@ -715,14 +708,6 @@ public:
actionViewSelectedMCFolder->setShortcut(QKeySequence(tr("Ctrl+M")));
all_actions.append(&actionViewSelectedMCFolder);
- /*
- actionViewSelectedModsFolder = TranslatedAction(MainWindow);
- actionViewSelectedModsFolder->setObjectName(QStringLiteral("actionViewSelectedModsFolder"));
- actionViewSelectedModsFolder.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Mods Folder"));
- actionViewSelectedModsFolder.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the selected instance's mods folder in a file browser."));
- all_actions.append(&actionViewSelectedModsFolder);
- */
-
actionConfig_Folder = TranslatedAction(MainWindow);
actionConfig_Folder->setObjectName(QStringLiteral("actionConfig_Folder"));
actionConfig_Folder.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Confi&g Folder"));
@@ -785,6 +770,7 @@ public:
instanceToolBar->addAction(actionLaunchInstance);
instanceToolBar->addAction(actionLaunchInstanceOffline);
+ instanceToolBar->addAction(actionKillInstance);
instanceToolBar->addSeparator();
@@ -798,9 +784,6 @@ public:
instanceToolBar->addSeparator();
instanceToolBar->addAction(actionViewSelectedMCFolder);
- /*
- instanceToolBar->addAction(actionViewSelectedModsFolder);
- */
instanceToolBar->addAction(actionConfig_Folder);
instanceToolBar->addAction(actionViewSelectedInstFolder);
@@ -822,7 +805,7 @@ public:
}
MainWindow->resize(800, 600);
MainWindow->setWindowIcon(APPLICATION->getThemedIcon("logo"));
- MainWindow->setWindowTitle(BuildConfig.LAUNCHER_DISPLAYNAME);
+ MainWindow->setWindowTitle(APPLICATION->applicationDisplayName());
#ifndef QT_NO_ACCESSIBILITY
MainWindow->setAccessibleName(BuildConfig.LAUNCHER_NAME);
#endif
@@ -857,8 +840,6 @@ public:
void retranslateUi(MainWindow *MainWindow)
{
- QString winTitle = tr("%1 - Version %2", "Launcher - Version X").arg(BuildConfig.LAUNCHER_DISPLAYNAME, BuildConfig.printableVersionString());
- MainWindow->setWindowTitle(winTitle);
// all the actions
for(auto * item: all_actions)
{
@@ -1031,7 +1012,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
}
-#ifdef LAUNCHER_WITH_UPDATER
if(BuildConfig.UPDATER_ENABLED)
{
bool updatesAllowed = APPLICATION->updatesAreAllowed();
@@ -1049,8 +1029,15 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
{
updater->checkForUpdate(APPLICATION->settings()->get("UpdateChannel").toString(), false);
}
+
+ if (APPLICATION->updateChecker()->getExternalUpdater())
+ {
+ connect(APPLICATION->updateChecker()->getExternalUpdater(),
+ &ExternalUpdater::canCheckForUpdatesChanged,
+ this,
+ &MainWindow::updatesAllowedChanged);
+ }
}
-#endif
setSelectedInstanceById(APPLICATION->settings()->get("SelectedInstance").toString());
@@ -1184,14 +1171,10 @@ void MainWindow::updateToolsMenu()
QToolButton *launchButton = dynamic_cast<QToolButton*>(ui->instanceToolBar->widgetForAction(ui->actionLaunchInstance));
QToolButton *launchOfflineButton = dynamic_cast<QToolButton*>(ui->instanceToolBar->widgetForAction(ui->actionLaunchInstanceOffline));
- if(m_selectedInstance && m_selectedInstance->isRunning())
- {
- ui->actionLaunchInstance->setMenu(nullptr);
- ui->actionLaunchInstanceOffline->setMenu(nullptr);
- launchButton->setPopupMode(QToolButton::InstantPopup);
- launchOfflineButton->setPopupMode(QToolButton::InstantPopup);
- return;
- }
+ bool currentInstanceRunning = m_selectedInstance && m_selectedInstance->isRunning();
+
+ ui->actionLaunchInstance->setDisabled(!m_selectedInstance || currentInstanceRunning);
+ ui->actionLaunchInstanceOffline->setDisabled(!m_selectedInstance || currentInstanceRunning);
QMenu *launchMenu = ui->actionLaunchInstance->menu();
QMenu *launchOfflineMenu = ui->actionLaunchInstanceOffline->menu();
@@ -1219,6 +1202,9 @@ void MainWindow::updateToolsMenu()
normalLaunchOffline->setShortcut(QKeySequence(tr("Ctrl+Shift+O")));
if (m_selectedInstance)
{
+ normalLaunch->setEnabled(m_selectedInstance->canLaunch());
+ normalLaunchOffline->setEnabled(m_selectedInstance->canLaunch());
+
connect(normalLaunch, &QAction::triggered, [this]() {
APPLICATION->launch(m_selectedInstance, true);
});
@@ -1249,6 +1235,9 @@ void MainWindow::updateToolsMenu()
}
else if (m_selectedInstance)
{
+ profilerAction->setEnabled(m_selectedInstance->canLaunch());
+ profilerOfflineAction->setEnabled(m_selectedInstance->canLaunch());
+
connect(profilerAction, &QAction::triggered, [this, profiler]()
{
APPLICATION->launch(m_selectedInstance, true, profiler.get());
@@ -1360,7 +1349,6 @@ void MainWindow::repopulateAccountsMenu()
ui->profileMenu->addAction(ui->actionManageAccounts);
}
-#ifdef LAUNCHER_WITH_UPDATER
void MainWindow::updatesAllowedChanged(bool allowed)
{
if(!BuildConfig.UPDATER_ENABLED)
@@ -1369,7 +1357,6 @@ void MainWindow::updatesAllowedChanged(bool allowed)
}
ui->actionCheckUpdate->setEnabled(allowed);
}
-#endif
/*
* Assumes the sender is a QAction
@@ -1475,7 +1462,6 @@ void MainWindow::updateNewsLabel()
}
}
-#ifdef LAUNCHER_WITH_UPDATER
void MainWindow::updateAvailable(GoUpdate::Status status)
{
if(!APPLICATION->updatesAreAllowed())
@@ -1501,11 +1487,14 @@ void MainWindow::updateNotAvailable()
UpdateDialog dlg(false, this);
dlg.exec();
}
-#endif
QList<int> stringToIntList(const QString &string)
{
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+ QStringList split = string.split(',', Qt::SkipEmptyParts);
+#else
QStringList split = string.split(',', QString::SkipEmptyParts);
+#endif
QList<int> out;
for (int i = 0; i < split.size(); ++i)
{
@@ -1523,7 +1512,6 @@ QString intListToString(const QList<int> &list)
return slist.join(',');
}
-#ifdef LAUNCHER_WITH_UPDATER
void MainWindow::downloadUpdates(GoUpdate::Status status)
{
if(!APPLICATION->updatesAreAllowed())
@@ -1557,7 +1545,6 @@ void MainWindow::downloadUpdates(GoUpdate::Status status)
CustomMessageBox::selectable(this, tr("Error"), updateTask.failReason(), QMessageBox::Warning)->show();
}
}
-#endif
void MainWindow::onCatToggled(bool state)
{
@@ -1870,7 +1857,6 @@ void MainWindow::on_actionConfig_Folder_triggered()
}
}
-#ifdef LAUNCHER_WITH_UPDATER
void MainWindow::checkForUpdates()
{
if(BuildConfig.UPDATER_ENABLED)
@@ -1883,7 +1869,6 @@ void MainWindow::checkForUpdates()
qWarning() << "Updater not set up. Cannot check for updates.";
}
}
-#endif
void MainWindow::on_actionSettings_triggered()
{
@@ -1905,11 +1890,6 @@ void MainWindow::globalSettingsClosed()
update();
}
-void MainWindow::on_actionInstanceSettings_triggered()
-{
- APPLICATION->showInstanceWindow(m_selectedInstance, "settings");
-}
-
void MainWindow::on_actionEditInstNotes_triggered()
{
APPLICATION->showInstanceWindow(m_selectedInstance, "notes");
@@ -1952,20 +1932,17 @@ void MainWindow::on_actionOpenWiki_triggered()
void MainWindow::on_actionMoreNews_triggered()
{
- DesktopServices::openUrl(QUrl(BuildConfig.NEWS_OPEN_URL));
+ auto entries = m_newsChecker->getNewsEntries();
+ NewsDialog news_dialog(entries, this);
+ news_dialog.exec();
}
void MainWindow::newsButtonClicked()
{
- QList<NewsEntryPtr> entries = m_newsChecker->getNewsEntries();
- if (entries.count() > 0)
- {
- DesktopServices::openUrl(QUrl(entries[0]->link));
- }
- else
- {
- DesktopServices::openUrl(QUrl(BuildConfig.NEWS_OPEN_URL));
- }
+ auto entries = m_newsChecker->getNewsEntries();
+ NewsDialog news_dialog(entries, this);
+ news_dialog.toggleArticleList();
+ news_dialog.exec();
}
void MainWindow::on_actionAbout_triggered()
@@ -2035,20 +2012,6 @@ void MainWindow::on_actionViewSelectedMCFolder_triggered()
}
}
-void MainWindow::on_actionViewSelectedModsFolder_triggered()
-{
- if (m_selectedInstance)
- {
- QString str = m_selectedInstance->modsRoot();
- if (!FS::ensureFilePathExists(str))
- {
- // TODO: report error
- return;
- }
- DesktopServices::openDirectory(QDir(str).absolutePath());
- }
-}
-
void MainWindow::closeEvent(QCloseEvent *event)
{
// Save the window state and geometry.
@@ -2081,15 +2044,7 @@ void MainWindow::instanceActivated(QModelIndex index)
void MainWindow::on_actionLaunchInstance_triggered()
{
- if (!m_selectedInstance)
- {
- return;
- }
- if(m_selectedInstance->isRunning())
- {
- APPLICATION->kill(m_selectedInstance);
- }
- else
+ if(m_selectedInstance && !m_selectedInstance->isRunning())
{
APPLICATION->launch(m_selectedInstance);
}
@@ -2108,6 +2063,14 @@ void MainWindow::on_actionLaunchInstanceOffline_triggered()
}
}
+void MainWindow::on_actionKillInstance_triggered()
+{
+ if(m_selectedInstance && m_selectedInstance->isRunning())
+ {
+ APPLICATION->kill(m_selectedInstance);
+ }
+}
+
void MainWindow::taskEnd()
{
QObject *sender = QObject::sender();
@@ -2141,17 +2104,9 @@ void MainWindow::instanceChanged(const QModelIndex &current, const QModelIndex &
{
ui->instanceToolBar->setEnabled(true);
ui->setInstanceActionsEnabled(true);
- if(m_selectedInstance->isRunning())
- {
- ui->actionLaunchInstance->setEnabled(true);
- ui->setLaunchAction(true);
- }
- else
- {
- ui->actionLaunchInstance->setEnabled(m_selectedInstance->canLaunch());
- ui->setLaunchAction(false);
- }
+ ui->actionLaunchInstance->setEnabled(m_selectedInstance->canLaunch());
ui->actionLaunchInstanceOffline->setEnabled(m_selectedInstance->canLaunch());
+ ui->actionKillInstance->setEnabled(m_selectedInstance->isRunning());
ui->actionExportInstance->setEnabled(m_selectedInstance->canExport());
ui->renameButton->setText(m_selectedInstance->name());
m_statusLeft->setText(m_selectedInstance->getStatusbarDescription());
@@ -2168,6 +2123,9 @@ void MainWindow::instanceChanged(const QModelIndex &current, const QModelIndex &
{
ui->instanceToolBar->setEnabled(false);
ui->setInstanceActionsEnabled(false);
+ ui->actionLaunchInstance->setEnabled(false);
+ ui->actionLaunchInstanceOffline->setEnabled(false);
+ ui->actionKillInstance->setEnabled(false);
APPLICATION->settings()->set("SelectedInstance", QString());
selectionBad();
return;
@@ -2197,6 +2155,7 @@ void MainWindow::selectionBad()
statusBar()->clearMessage();
ui->instanceToolBar->setEnabled(false);
ui->setInstanceActionsEnabled(false);
+ updateToolsMenu();
ui->renameButton->setText(tr("Rename Instance"));
updateInstanceToolIcon("grass");
diff --git a/launcher/ui/MainWindow.h b/launcher/ui/MainWindow.h
index 6c64756f..d7930b5a 100644
--- a/launcher/ui/MainWindow.h
+++ b/launcher/ui/MainWindow.h
@@ -78,9 +78,7 @@ public:
void checkInstancePathForProblems();
-#ifdef LAUNCHER_WITH_UPDATER
void updatesAllowedChanged(bool allowed);
-#endif
void droppedURLs(QList<QUrl> urls);
signals:
@@ -120,20 +118,14 @@ private slots:
void on_actionViewSelectedMCFolder_triggered();
- void on_actionViewSelectedModsFolder_triggered();
-
void refreshInstances();
void on_actionViewCentralModsFolder_triggered();
-#ifdef LAUNCHER_WITH_UPDATER
void checkForUpdates();
-#endif
void on_actionSettings_triggered();
- void on_actionInstanceSettings_triggered();
-
void on_actionManageAccounts_triggered();
void on_actionReportBug_triggered();
@@ -148,6 +140,8 @@ private slots:
void on_actionLaunchInstanceOffline_triggered();
+ void on_actionKillInstance_triggered();
+
void on_actionDeleteInstance_triggered();
void deleteGroup();
@@ -195,11 +189,9 @@ private slots:
void startTask(Task *task);
-#ifdef LAUNCHER_WITH_UPDATER
void updateAvailable(GoUpdate::Status status);
void updateNotAvailable();
-#endif
void defaultAccountChanged();
@@ -209,12 +201,10 @@ private slots:
void updateNewsLabel();
-#ifdef LAUNCHER_WITH_UPDATER
/*!
* Runs the DownloadTask and installs updates.
*/
void downloadUpdates(GoUpdate::Status status);
-#endif
void konamiTriggered();
diff --git a/launcher/ui/dialogs/AboutDialog.cpp b/launcher/ui/dialogs/AboutDialog.cpp
index 8dadb755..c5367d5b 100644
--- a/launcher/ui/dialogs/AboutDialog.cpp
+++ b/launcher/ui/dialogs/AboutDialog.cpp
@@ -64,7 +64,9 @@ QString getCreditsHtml()
{
QString output;
QTextStream stream(&output);
+#if QT_VERSION <= QT_VERSION_CHECK(6, 0, 0)
stream.setCodec(QTextCodec::codecForName("UTF-8"));
+#endif
stream << "<center>\n";
//: %1 is the name of the launcher, determined at build time, e.g. "PolyMC Developers"
diff --git a/launcher/ui/dialogs/CopyInstanceDialog.cpp b/launcher/ui/dialogs/CopyInstanceDialog.cpp
index e5113981..9ec341bc 100644
--- a/launcher/ui/dialogs/CopyInstanceDialog.cpp
+++ b/launcher/ui/dialogs/CopyInstanceDialog.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * 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 <QLayout>
@@ -39,8 +59,14 @@ CopyInstanceDialog::CopyInstanceDialog(InstancePtr original, QWidget *parent)
ui->iconButton->setIcon(APPLICATION->icons()->getIcon(InstIconKey));
ui->instNameTextBox->setText(original->name());
ui->instNameTextBox->setFocus();
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+ auto groupList = APPLICATION->instances()->getGroups();
+ QSet<QString> groups(groupList.begin(), groupList.end());
+ groupList = QStringList(groups.values());
+#else
auto groups = APPLICATION->instances()->getGroups().toSet();
auto groupList = QStringList(groups.toList());
+#endif
groupList.sort(Qt::CaseInsensitive);
groupList.removeOne("");
groupList.push_front("");
diff --git a/launcher/ui/dialogs/ExportInstanceDialog.cpp b/launcher/ui/dialogs/ExportInstanceDialog.cpp
index 8631edf6..9f32dd8e 100644
--- a/launcher/ui/dialogs/ExportInstanceDialog.cpp
+++ b/launcher/ui/dialogs/ExportInstanceDialog.cpp
@@ -488,7 +488,11 @@ void ExportInstanceDialog::loadPackIgnore()
}
auto data = ignoreFile.readAll();
auto string = QString::fromUtf8(data);
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+ proxyModel->setBlockedPaths(string.split('\n', Qt::SkipEmptyParts));
+#else
proxyModel->setBlockedPaths(string.split('\n', QString::SkipEmptyParts));
+#endif
}
void ExportInstanceDialog::savePackIgnore()
diff --git a/launcher/ui/dialogs/NewComponentDialog.cpp b/launcher/ui/dialogs/NewComponentDialog.cpp
index 1bbafb0c..ea790e8c 100644
--- a/launcher/ui/dialogs/NewComponentDialog.cpp
+++ b/launcher/ui/dialogs/NewComponentDialog.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * 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 "Application.h"
@@ -46,7 +66,6 @@ NewComponentDialog::NewComponentDialog(const QString & initialName, const QStrin
connect(ui->nameTextBox, &QLineEdit::textChanged, this, &NewComponentDialog::updateDialogState);
connect(ui->uidTextBox, &QLineEdit::textChanged, this, &NewComponentDialog::updateDialogState);
- auto groups = APPLICATION->instances()->getGroups().toSet();
ui->nameTextBox->setFocus();
originalPlaceholderText = ui->uidTextBox->placeholderText();
diff --git a/launcher/ui/dialogs/NewInstanceDialog.cpp b/launcher/ui/dialogs/NewInstanceDialog.cpp
index 05ea091d..5b8ecc5b 100644
--- a/launcher/ui/dialogs/NewInstanceDialog.cpp
+++ b/launcher/ui/dialogs/NewInstanceDialog.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * 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 "Application.h"
@@ -54,8 +74,14 @@ NewInstanceDialog::NewInstanceDialog(const QString & initialGroup, const QString
InstIconKey = "default";
ui->iconButton->setIcon(APPLICATION->icons()->getIcon(InstIconKey));
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+ auto groupList = APPLICATION->instances()->getGroups();
+ auto groups = QSet<QString>(groupList.begin(), groupList.end());
+ groupList = groups.values();
+#else
auto groups = APPLICATION->instances()->getGroups().toSet();
auto groupList = QStringList(groups.toList());
+#endif
groupList.sort(Qt::CaseInsensitive);
groupList.removeOne("");
groupList.push_front(initialGroup);
diff --git a/launcher/ui/dialogs/NewsDialog.cpp b/launcher/ui/dialogs/NewsDialog.cpp
new file mode 100644
index 00000000..d3b21627
--- /dev/null
+++ b/launcher/ui/dialogs/NewsDialog.cpp
@@ -0,0 +1,49 @@
+#include "NewsDialog.h"
+#include "ui_NewsDialog.h"
+
+NewsDialog::NewsDialog(QList<NewsEntryPtr> entries, QWidget* parent) : QDialog(parent), ui(new Ui::NewsDialog())
+{
+ ui->setupUi(this);
+
+ for (auto entry : entries) {
+ ui->articleListWidget->addItem(entry->title);
+ m_entries.insert(entry->title, entry);
+ }
+
+ connect(ui->articleListWidget, &QListWidget::currentTextChanged, this, &NewsDialog::selectedArticleChanged);
+ connect(ui->toggleListButton, &QPushButton::clicked, this, &NewsDialog::toggleArticleList);
+
+ m_article_list_hidden = ui->articleListWidget->isHidden();
+
+ auto first_item = ui->articleListWidget->item(0);
+ first_item->setSelected(true);
+
+ auto article_entry = m_entries.constFind(first_item->text()).value();
+ ui->articleTitleLabel->setText(QString("<a href='%1'>%2</a>").arg(article_entry->link, first_item->text()));
+ ui->currentArticleContentBrowser->setText(article_entry->content);
+}
+
+NewsDialog::~NewsDialog()
+{
+ delete ui;
+}
+
+void NewsDialog::selectedArticleChanged(const QString& new_title)
+{
+ auto const& article_entry = m_entries.constFind(new_title).value();
+
+ ui->articleTitleLabel->setText(QString("<a href='%1'>%2</a>").arg(article_entry->link, new_title));
+ ui->currentArticleContentBrowser->setText(article_entry->content);
+}
+
+void NewsDialog::toggleArticleList()
+{
+ m_article_list_hidden = !m_article_list_hidden;
+
+ ui->articleListWidget->setHidden(m_article_list_hidden);
+
+ if (m_article_list_hidden)
+ ui->toggleListButton->setText(tr("Show article list"));
+ else
+ ui->toggleListButton->setText(tr("Hide article list"));
+}
diff --git a/launcher/ui/dialogs/NewsDialog.h b/launcher/ui/dialogs/NewsDialog.h
new file mode 100644
index 00000000..add6b8dd
--- /dev/null
+++ b/launcher/ui/dialogs/NewsDialog.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <QDialog>
+#include <QHash>
+
+#include "news/NewsEntry.h"
+
+namespace Ui {
+class NewsDialog;
+}
+
+class NewsDialog : public QDialog {
+ Q_OBJECT
+
+ public:
+ NewsDialog(QList<NewsEntryPtr> entries, QWidget* parent = nullptr);
+ ~NewsDialog();
+
+ public slots:
+ void toggleArticleList();
+
+ private slots:
+ void selectedArticleChanged(const QString& new_title);
+
+ private:
+ Ui::NewsDialog* ui;
+
+ QHash<QString, NewsEntryPtr> m_entries;
+ bool m_article_list_hidden = false;
+};
diff --git a/launcher/ui/dialogs/NewsDialog.ui b/launcher/ui/dialogs/NewsDialog.ui
new file mode 100644
index 00000000..2aaa08f1
--- /dev/null
+++ b/launcher/ui/dialogs/NewsDialog.ui
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>NewsDialog</class>
+ <widget class="QDialog" name="NewsDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>500</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>News</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="leftVerticalLayout">
+ <item>
+ <widget class="QListWidget" name="articleListWidget">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="rightVerticalLayout">
+ <item>
+ <widget class="QLabel" name="articleTitleLabel">
+ <property name="text">
+ <string notr="true">Placeholder</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTextBrowser" name="currentArticleContentBrowser">
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ <property name="openLinks">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="1">
+ <widget class="QPushButton" name="closeButton">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>10</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QPushButton" name="toggleListButton">
+ <property name="text">
+ <string>Hide article list</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>closeButton</sender>
+ <signal>clicked()</signal>
+ <receiver>NewsDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>199</x>
+ <y>277</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>199</x>
+ <y>149</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/launcher/ui/dialogs/ProfileSetupDialog.cpp b/launcher/ui/dialogs/ProfileSetupDialog.cpp
index 76b6af49..64c0b924 100644
--- a/launcher/ui/dialogs/ProfileSetupDialog.cpp
+++ b/launcher/ui/dialogs/ProfileSetupDialog.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * 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 "ProfileSetupDialog.h"
@@ -18,7 +38,7 @@
#include <QPushButton>
#include <QAction>
-#include <QRegExpValidator>
+#include <QRegularExpressionValidator>
#include <QJsonDocument>
#include <QDebug>
@@ -39,9 +59,9 @@ ProfileSetupDialog::ProfileSetupDialog(MinecraftAccountPtr accountToSetup, QWidg
yellowIcon = APPLICATION->getThemedIcon("status-yellow");
badIcon = APPLICATION->getThemedIcon("status-bad");
- QRegExp permittedNames("[a-zA-Z0-9_]{3,16}");
+ QRegularExpression permittedNames("[a-zA-Z0-9_]{3,16}");
auto nameEdit = ui->nameEdit;
- nameEdit->setValidator(new QRegExpValidator(permittedNames));
+ nameEdit->setValidator(new QRegularExpressionValidator(permittedNames));
nameEdit->setClearButtonEnabled(true);
validityAction = nameEdit->addAction(yellowIcon, QLineEdit::LeadingPosition);
connect(nameEdit, &QLineEdit::textEdited, this, &ProfileSetupDialog::nameEdited);
diff --git a/launcher/ui/dialogs/SkinUploadDialog.cpp b/launcher/ui/dialogs/SkinUploadDialog.cpp
index 8d137afc..b5b78690 100644
--- a/launcher/ui/dialogs/SkinUploadDialog.cpp
+++ b/launcher/ui/dialogs/SkinUploadDialog.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 <QFileInfo>
#include <QFileDialog>
#include <QPainter>
@@ -22,10 +57,10 @@ void SkinUploadDialog::on_buttonBox_accepted()
{
QString fileName;
QString input = ui->skinPathTextBox->text();
- QRegExp urlPrefixMatcher("^([a-z]+)://.+$");
+ QRegularExpression urlPrefixMatcher(QRegularExpression::anchoredPattern("^([a-z]+)://.+$"));
bool isLocalFile = false;
// it has an URL prefix -> it is an URL
- if(urlPrefixMatcher.exactMatch(input))
+ if(urlPrefixMatcher.match(input).hasMatch())
{
QUrl fileURL = input;
if(fileURL.isValid())
diff --git a/launcher/ui/dialogs/UpdateDialog.cpp b/launcher/ui/dialogs/UpdateDialog.cpp
index ec77d146..e0c5a495 100644
--- a/launcher/ui/dialogs/UpdateDialog.cpp
+++ b/launcher/ui/dialogs/UpdateDialog.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 "UpdateDialog.h"
#include "ui_UpdateDialog.h"
#include <QDebug>
@@ -58,7 +93,7 @@ QString reprocessMarkdown(QByteArray markdown)
QString output = hoedown.process(markdown);
// HACK: easier than customizing hoedown
- output.replace(QRegExp("GH-([0-9]+)"), "<a href=\"https://github.com/PolyMC/PolyMC/issues/\\1\">GH-\\1</a>");
+ output.replace(QRegularExpression("GH-([0-9]+)"), "<a href=\"https://github.com/PolyMC/PolyMC/issues/\\1\">GH-\\1</a>");
qDebug() << output;
return output;
}
diff --git a/launcher/ui/instanceview/InstanceDelegate.cpp b/launcher/ui/instanceview/InstanceDelegate.cpp
index b446e39d..137cc8d5 100644
--- a/launcher/ui/instanceview/InstanceDelegate.cpp
+++ b/launcher/ui/instanceview/InstanceDelegate.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * 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 "InstanceDelegate.h"
@@ -24,7 +44,7 @@
#include "InstanceView.h"
#include "BaseInstance.h"
#include "InstanceList.h"
-#include <xdgicon.h>
+#include <QIcon>
#include <QTextEdit>
// Origin: Qt
@@ -61,7 +81,7 @@ void drawSelectionRect(QPainter *painter, const QStyleOptionViewItem &option,
painter->fillRect(rect, option.palette.brush(QPalette::Highlight));
else
{
- QColor backgroundColor = option.palette.color(QPalette::Background);
+ QColor backgroundColor = option.palette.color(QPalette::Window);
backgroundColor.setAlpha(160);
painter->fillRect(rect, QBrush(backgroundColor));
}
@@ -142,7 +162,7 @@ void drawBadges(QPainter *painter, const QStyleOptionViewItem &option, BaseInsta
return;
}
// FIXME: inject this.
- auto icon = XdgIcon::fromTheme(it.next());
+ auto icon = QIcon::fromTheme(it.next());
// opt.icon.paint(painter, iconbox, Qt::AlignCenter, mode, state);
const QPixmap pixmap;
// itemSide
diff --git a/launcher/ui/instanceview/InstanceView.cpp b/launcher/ui/instanceview/InstanceView.cpp
index 25aec1ab..fbeffe35 100644
--- a/launcher/ui/instanceview/InstanceView.cpp
+++ b/launcher/ui/instanceview/InstanceView.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * 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 "InstanceView.h"
@@ -425,7 +445,12 @@ void InstanceView::mouseReleaseEvent(QMouseEvent *event)
{
emit clicked(index);
}
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ QStyleOptionViewItem option;
+ initViewItemOption(&option);
+#else
QStyleOptionViewItem option = viewOptions();
+#endif
if (m_pressedAlreadySelected)
{
option.state |= QStyle::State_Selected;
@@ -461,7 +486,12 @@ void InstanceView::mouseDoubleClickEvent(QMouseEvent *event)
QPersistentModelIndex persistent = index;
emit doubleClicked(persistent);
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ QStyleOptionViewItem option;
+ initViewItemOption(&option);
+#else
QStyleOptionViewItem option = viewOptions();
+#endif
if ((model()->flags(index) & Qt::ItemIsEnabled) && !style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, &option, this))
{
emit activated(index);
@@ -474,7 +504,12 @@ void InstanceView::paintEvent(QPaintEvent *event)
QPainter painter(this->viewport());
- QStyleOptionViewItem option(viewOptions());
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ QStyleOptionViewItem option;
+ initViewItemOption(&option);
+#else
+ QStyleOptionViewItem option = viewOptions();
+#endif
option.widget = this;
int wpWidth = viewport()->width();
@@ -528,9 +563,9 @@ void InstanceView::paintEvent(QPaintEvent *event)
#if 0
if (!m_lastDragPosition.isNull())
{
- QPair<Group *, int> pair = rowDropPos(m_lastDragPosition);
- Group *category = pair.first;
- int row = pair.second;
+ std::pair<VisualGroup *, VisualGroup::HitResults> pair = rowDropPos(m_lastDragPosition);
+ VisualGroup *category = pair.first;
+ VisualGroup::HitResults row = pair.second;
if (category)
{
int internalRow = row - category->firstItemIndex;
@@ -618,7 +653,7 @@ void InstanceView::dropEvent(QDropEvent *event)
{
if(event->possibleActions() & Qt::MoveAction)
{
- QPair<VisualGroup *, VisualGroup::HitResults> dropPos = rowDropPos(event->pos());
+ std::pair<VisualGroup *, VisualGroup::HitResults> dropPos = rowDropPos(event->pos());
const VisualGroup *group = dropPos.first;
auto hitresult = dropPos.second;
@@ -709,10 +744,18 @@ QRect InstanceView::geometryRect(const QModelIndex &index) const
int x = pos.first;
// int y = pos.second;
+
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ QStyleOptionViewItem option;
+ initViewItemOption(&option);
+#else
+ QStyleOptionViewItem option = viewOptions();
+#endif
+
QRect out;
out.setTop(cat->verticalPosition() + cat->headerHeight() + 5 + cat->rowTopOf(index));
out.setLeft(m_spacing + x * (itemWidth() + m_spacing));
- out.setSize(itemDelegate()->sizeHint(viewOptions(), index));
+ out.setSize(itemDelegate()->sizeHint(option, index));
geometryCache.insert(row, new QRect(out));
return out;
}
@@ -759,7 +802,12 @@ QPixmap InstanceView::renderToPixmap(const QModelIndexList &indices, QRect *r) c
QPixmap pixmap(r->size());
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ QStyleOptionViewItem option;
+ initViewItemOption(&option);
+#else
QStyleOptionViewItem option = viewOptions();
+#endif
option.state |= QStyle::State_Selected;
for (int j = 0; j < paintPairs.count(); ++j)
{
@@ -770,16 +818,16 @@ QPixmap InstanceView::renderToPixmap(const QModelIndexList &indices, QRect *r) c
return pixmap;
}
-QList<QPair<QRect, QModelIndex>> InstanceView::draggablePaintPairs(const QModelIndexList &indices, QRect *r) const
+QList<std::pair<QRect, QModelIndex>> InstanceView::draggablePaintPairs(const QModelIndexList &indices, QRect *r) const
{
Q_ASSERT(r);
QRect &rect = *r;
- QList<QPair<QRect, QModelIndex>> ret;
+ QList<std::pair<QRect, QModelIndex>> ret;
for (int i = 0; i < indices.count(); ++i)
{
const QModelIndex &index = indices.at(i);
const QRect current = geometryRect(index);
- ret += qMakePair(current, index);
+ ret += std::make_pair(current, index);
rect |= current;
}
return ret;
@@ -790,11 +838,11 @@ bool InstanceView::isDragEventAccepted(QDropEvent *event)
return true;
}
-QPair<VisualGroup *, VisualGroup::HitResults> InstanceView::rowDropPos(const QPoint &pos)
+std::pair<VisualGroup *, VisualGroup::HitResults> InstanceView::rowDropPos(const QPoint &pos)
{
VisualGroup::HitResults hitresult;
auto group = categoryAt(pos + offset(), hitresult);
- return qMakePair<VisualGroup*, int>(group, hitresult);
+ return std::make_pair(group, hitresult);
}
QPoint InstanceView::offset() const
diff --git a/launcher/ui/instanceview/InstanceView.h b/launcher/ui/instanceview/InstanceView.h
index 406362e6..ac338274 100644
--- a/launcher/ui/instanceview/InstanceView.h
+++ b/launcher/ui/instanceview/InstanceView.h
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * 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
@@ -143,11 +163,11 @@ private: /* methods */
int calculateItemsPerRow() const;
int verticalScrollToValue(const QModelIndex &index, const QRect &rect, QListView::ScrollHint hint) const;
QPixmap renderToPixmap(const QModelIndexList &indices, QRect *r) const;
- QList<QPair<QRect, QModelIndex>> draggablePaintPairs(const QModelIndexList &indices, QRect *r) const;
+ QList<std::pair<QRect, QModelIndex>> draggablePaintPairs(const QModelIndexList &indices, QRect *r) const;
bool isDragEventAccepted(QDropEvent *event);
- QPair<VisualGroup *, VisualGroup::HitResults> rowDropPos(const QPoint &pos);
+ std::pair<VisualGroup *, VisualGroup::HitResults> rowDropPos(const QPoint &pos);
QPoint offset() const;
};
diff --git a/launcher/ui/instanceview/VisualGroup.cpp b/launcher/ui/instanceview/VisualGroup.cpp
index 8991fb2d..e6bca17d 100644
--- a/launcher/ui/instanceview/VisualGroup.cpp
+++ b/launcher/ui/instanceview/VisualGroup.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * 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 "VisualGroup.h"
@@ -55,7 +75,14 @@ void VisualGroup::update()
positionInRow = 0;
maxRowHeight = 0;
}
- auto itemHeight = view->itemDelegate()->sizeHint(view->viewOptions(), item).height();
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ QStyleOptionViewItem viewItemOption;
+ view->initViewItemOption(&viewItemOption);
+#else
+ QStyleOptionViewItem viewItemOption = view->viewOptions();
+#endif
+
+ auto itemHeight = view->itemDelegate()->sizeHint(viewItemOption, item).height();
if(itemHeight > maxRowHeight)
{
maxRowHeight = itemHeight;
diff --git a/launcher/ui/pages/global/AccountListPage.cpp b/launcher/ui/pages/global/AccountListPage.cpp
index 6e1e2183..a608771e 100644
--- a/launcher/ui/pages/global/AccountListPage.cpp
+++ b/launcher/ui/pages/global/AccountListPage.cpp
@@ -73,9 +73,11 @@ AccountListPage::AccountListPage(QWidget *parent)
m_accounts = APPLICATION->accounts();
ui->listView->setModel(m_accounts.get());
- ui->listView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
- ui->listView->header()->setSectionResizeMode(1, QHeaderView::Stretch);
- ui->listView->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
+ ui->listView->header()->setSectionResizeMode(AccountList::VListColumns::ProfileNameColumn, QHeaderView::Stretch);
+ ui->listView->header()->setSectionResizeMode(AccountList::VListColumns::NameColumn, QHeaderView::Stretch);
+ ui->listView->header()->setSectionResizeMode(AccountList::VListColumns::MigrationColumn, QHeaderView::ResizeToContents);
+ ui->listView->header()->setSectionResizeMode(AccountList::VListColumns::TypeColumn, QHeaderView::ResizeToContents);
+ ui->listView->header()->setSectionResizeMode(AccountList::VListColumns::StatusColumn, QHeaderView::ResizeToContents);
ui->listView->setSelectionMode(QAbstractItemView::SingleSelection);
// Expand the account column
@@ -253,19 +255,21 @@ void AccountListPage::updateButtonStates()
{
// If there is no selection, disable buttons that require something selected.
QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
- bool hasSelection = selection.size() > 0;
+ bool hasSelection = !selection.empty();
bool accountIsReady = false;
+ bool accountIsOnline = false;
if (hasSelection)
{
QModelIndex selected = selection.first();
MinecraftAccountPtr account = selected.data(AccountList::PointerRole).value<MinecraftAccountPtr>();
accountIsReady = !account->isActive();
+ accountIsOnline = !account->isOffline();
}
ui->actionRemove->setEnabled(accountIsReady);
ui->actionSetDefault->setEnabled(accountIsReady);
- ui->actionUploadSkin->setEnabled(accountIsReady);
- ui->actionDeleteSkin->setEnabled(accountIsReady);
- ui->actionRefresh->setEnabled(accountIsReady);
+ ui->actionUploadSkin->setEnabled(accountIsReady && accountIsOnline);
+ ui->actionDeleteSkin->setEnabled(accountIsReady && accountIsOnline);
+ ui->actionRefresh->setEnabled(accountIsReady && accountIsOnline);
if(m_accounts->defaultAccount().get() == nullptr) {
ui->actionNoDefault->setEnabled(false);
diff --git a/launcher/ui/pages/global/CustomCommandsPage.cpp b/launcher/ui/pages/global/CustomCommandsPage.cpp
index 436d766e..df1420ca 100644
--- a/launcher/ui/pages/global/CustomCommandsPage.cpp
+++ b/launcher/ui/pages/global/CustomCommandsPage.cpp
@@ -2,7 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
- * Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* 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/ui/pages/global/JavaPage.cpp b/launcher/ui/pages/global/JavaPage.cpp
index 025771e8..2cee15bf 100644
--- a/launcher/ui/pages/global/JavaPage.cpp
+++ b/launcher/ui/pages/global/JavaPage.cpp
@@ -127,6 +127,11 @@ void JavaPage::loadSettings()
void JavaPage::on_javaDetectBtn_clicked()
{
+ if (JavaUtils::getJavaCheckPath().isEmpty()) {
+ JavaCommon::javaCheckNotFound(this);
+ return;
+ }
+
JavaInstallPtr java;
VersionSelectDialog vselect(APPLICATION->javalist().get(), tr("Select a Java version"), this, true);
diff --git a/launcher/ui/pages/global/LauncherPage.cpp b/launcher/ui/pages/global/LauncherPage.cpp
index edbf609f..73ef0024 100644
--- a/launcher/ui/pages/global/LauncherPage.cpp
+++ b/launcher/ui/pages/global/LauncherPage.cpp
@@ -78,7 +78,6 @@ LauncherPage::LauncherPage(QWidget *parent) : QWidget(parent), ui(new Ui::Launch
m_languageModel = APPLICATION->translations();
loadSettings();
-#ifdef LAUNCHER_WITH_UPDATER
if(BuildConfig.UPDATER_ENABLED)
{
QObject::connect(APPLICATION->updateChecker().get(), &UpdateChecker::channelListLoaded, this, &LauncherPage::refreshUpdateChannelList);
@@ -91,9 +90,18 @@ LauncherPage::LauncherPage(QWidget *parent) : QWidget(parent), ui(new Ui::Launch
{
APPLICATION->updateChecker()->updateChanList(false);
}
- ui->updateSettingsBox->setHidden(false);
+
+ if (APPLICATION->updateChecker()->getExternalUpdater())
+ {
+ ui->updateChannelComboBox->setVisible(false);
+ ui->updateChannelDescLabel->setVisible(false);
+ ui->updateChannelLabel->setVisible(false);
+ }
+ }
+ else
+ {
+ ui->updateSettingsBox->setHidden(true);
}
-#endif
connect(ui->fontSizeBox, SIGNAL(valueChanged(int)), SLOT(refreshFontPreview()));
connect(ui->consoleFont, SIGNAL(currentFontChanged(QFont)), SLOT(refreshFontPreview()));
}
@@ -188,7 +196,6 @@ void LauncherPage::on_metadataDisableBtn_clicked()
ui->metadataWarningLabel->setHidden(!ui->metadataDisableBtn->isChecked());
}
-#ifdef LAUNCHER_WITH_UPDATER
void LauncherPage::refreshUpdateChannelList()
{
// Stop listening for selection changes. It's going to change a lot while we update it and
@@ -260,14 +267,22 @@ void LauncherPage::refreshUpdateChannelDesc()
m_currentUpdateChannel = selected.id;
}
}
-#endif
void LauncherPage::applySettings()
{
auto s = APPLICATION->settings();
// Updates
- s->set("AutoUpdate", ui->autoUpdateCheckBox->isChecked());
+ if (BuildConfig.UPDATER_ENABLED && APPLICATION->updateChecker()->getExternalUpdater())
+ {
+ APPLICATION->updateChecker()->getExternalUpdater()->setAutomaticallyChecksForUpdates(
+ ui->autoUpdateCheckBox->isChecked());
+ }
+ else
+ {
+ s->set("AutoUpdate", ui->autoUpdateCheckBox->isChecked());
+ }
+
s->set("UpdateChannel", m_currentUpdateChannel);
auto original = s->get("IconTheme").toString();
//FIXME: make generic
@@ -352,7 +367,16 @@ void LauncherPage::loadSettings()
{
auto s = APPLICATION->settings();
// Updates
- ui->autoUpdateCheckBox->setChecked(s->get("AutoUpdate").toBool());
+ if (BuildConfig.UPDATER_ENABLED && APPLICATION->updateChecker()->getExternalUpdater())
+ {
+ ui->autoUpdateCheckBox->setChecked(
+ APPLICATION->updateChecker()->getExternalUpdater()->getAutomaticallyChecksForUpdates());
+ }
+ else
+ {
+ ui->autoUpdateCheckBox->setChecked(s->get("AutoUpdate").toBool());
+ }
+
m_currentUpdateChannel = s->get("UpdateChannel").toString();
//FIXME: make generic
auto theme = s->get("IconTheme").toString();
diff --git a/launcher/ui/pages/global/LauncherPage.h b/launcher/ui/pages/global/LauncherPage.h
index ccfd7e9e..f38c922e 100644
--- a/launcher/ui/pages/global/LauncherPage.h
+++ b/launcher/ui/pages/global/LauncherPage.h
@@ -90,7 +90,6 @@ slots:
void on_iconsDirBrowseBtn_clicked();
void on_metadataDisableBtn_clicked();
-#ifdef LAUNCHER_WITH_UPDATER
/*!
* Updates the list of update channels in the combo box.
*/
@@ -101,13 +100,13 @@ slots:
*/
void refreshUpdateChannelDesc();
- void updateChannelSelectionChanged(int index);
-#endif
/*!
* Updates the font preview
*/
void refreshFontPreview();
+ void updateChannelSelectionChanged(int index);
+
private:
Ui::LauncherPage *ui;
diff --git a/launcher/ui/pages/global/LauncherPage.ui b/launcher/ui/pages/global/LauncherPage.ui
index ceb68c5b..645f7ef6 100644
--- a/launcher/ui/pages/global/LauncherPage.ui
+++ b/launcher/ui/pages/global/LauncherPage.ui
@@ -50,14 +50,11 @@
<property name="title">
<string>Update Settings</string>
</property>
- <property name="visible">
- <bool>false</bool>
- </property>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<widget class="QCheckBox" name="autoUpdateCheckBox">
<property name="text">
- <string>Check for updates on start?</string>
+ <string>Check for updates automatically</string>
</property>
</widget>
</item>
diff --git a/launcher/ui/pages/global/MinecraftPage.cpp b/launcher/ui/pages/global/MinecraftPage.cpp
index f49f5a92..e3ac7e7c 100644
--- a/launcher/ui/pages/global/MinecraftPage.cpp
+++ b/launcher/ui/pages/global/MinecraftPage.cpp
@@ -87,6 +87,11 @@ void MinecraftPage::applySettings()
s->set("UseNativeOpenAL", ui->useNativeOpenALCheck->isChecked());
s->set("UseNativeGLFW", ui->useNativeGLFWCheck->isChecked());
+ // Peformance related options
+ s->set("EnableFeralGamemode", ui->enableFeralGamemodeCheck->isChecked());
+ s->set("EnableMangoHud", ui->enableMangoHud->isChecked());
+ s->set("UseDiscreteGpu", ui->useDiscreteGpuCheck->isChecked());
+
// Game time
s->set("ShowGameTime", ui->showGameTime->isChecked());
s->set("ShowGlobalGameTime", ui->showGlobalGameTime->isChecked());
@@ -109,6 +114,14 @@ void MinecraftPage::loadSettings()
ui->useNativeOpenALCheck->setChecked(s->get("UseNativeOpenAL").toBool());
ui->useNativeGLFWCheck->setChecked(s->get("UseNativeGLFW").toBool());
+ ui->enableFeralGamemodeCheck->setChecked(s->get("EnableFeralGamemode").toBool());
+ ui->enableMangoHud->setChecked(s->get("EnableMangoHud").toBool());
+ ui->useDiscreteGpuCheck->setChecked(s->get("UseDiscreteGpu").toBool());
+
+#if !defined(Q_OS_LINUX)
+ ui->perfomanceGroupBox->setVisible(false);
+#endif
+
ui->showGameTime->setChecked(s->get("ShowGameTime").toBool());
ui->showGlobalGameTime->setChecked(s->get("ShowGlobalGameTime").toBool());
ui->recordGameTime->setChecked(s->get("RecordGameTime").toBool());
diff --git a/launcher/ui/pages/global/MinecraftPage.ui b/launcher/ui/pages/global/MinecraftPage.ui
index 353390bd..640f436d 100644
--- a/launcher/ui/pages/global/MinecraftPage.ui
+++ b/launcher/ui/pages/global/MinecraftPage.ui
@@ -135,6 +135,45 @@
</widget>
</item>
<item>
+ <widget class="QGroupBox" name="perfomanceGroupBox">
+ <property name="title">
+ <string>Performance</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QCheckBox" name="enableFeralGamemodeCheck">
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable Feral Interactive's GameMode, to potentially improve gaming performance.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>Enable Feral GameMode</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="enableMangoHud">
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable MangoHud's advanced performance overlay.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>Enable MangoHud</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="useDiscreteGpuCheck">
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use the discrete GPU instead of the primary GPU.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>Use discrete GPU</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
<widget class="QGroupBox" name="gameTimeGroupBox">
<property name="title">
<string>Game time</string>
@@ -181,15 +220,15 @@
</widget>
</item>
<item>
- <widget class="QCheckBox" name="quitAfterGameStopCheck">
- <property name="toolTip">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The launcher will automatically quit after the game exits or crashes.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
- </property>
- <property name="text">
- <string>&amp;Quit the launcher after game window closes</string>
- </property>
- </widget>
- </item>
+ <widget class="QCheckBox" name="quitAfterGameStopCheck">
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The launcher will automatically quit after the game exits or crashes.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>&amp;Quit the launcher after game window closes</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>
@@ -218,6 +257,9 @@
<tabstop>windowHeightSpinBox</tabstop>
<tabstop>useNativeGLFWCheck</tabstop>
<tabstop>useNativeOpenALCheck</tabstop>
+ <tabstop>enableFeralGamemodeCheck</tabstop>
+ <tabstop>enableMangoHud</tabstop>
+ <tabstop>useDiscreteGpuCheck</tabstop>
</tabstops>
<resources/>
<connections/>
diff --git a/launcher/ui/pages/global/ProxyPage.cpp b/launcher/ui/pages/global/ProxyPage.cpp
index aefd1e74..ffff8456 100644
--- a/launcher/ui/pages/global/ProxyPage.cpp
+++ b/launcher/ui/pages/global/ProxyPage.cpp
@@ -2,6 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* 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
@@ -36,11 +37,11 @@
#include "ProxyPage.h"
#include "ui_ProxyPage.h"
+#include <QButtonGroup>
#include <QTabBar>
#include "settings/SettingsObject.h"
#include "Application.h"
-#include "Application.h"
ProxyPage::ProxyPage(QWidget *parent) : QWidget(parent), ui(new Ui::ProxyPage)
{
@@ -49,7 +50,8 @@ ProxyPage::ProxyPage(QWidget *parent) : QWidget(parent), ui(new Ui::ProxyPage)
loadSettings();
updateCheckboxStuff();
- connect(ui->proxyGroup, SIGNAL(buttonClicked(int)), SLOT(proxyChanged(int)));
+ connect(ui->proxyGroup, QOverload<QAbstractButton *>::of(&QButtonGroup::buttonClicked),
+ this, &ProxyPage::proxyGroupChanged);
}
ProxyPage::~ProxyPage()
@@ -65,13 +67,13 @@ bool ProxyPage::apply()
void ProxyPage::updateCheckboxStuff()
{
- ui->proxyAddrBox->setEnabled(!ui->proxyNoneBtn->isChecked() &&
- !ui->proxyDefaultBtn->isChecked());
- ui->proxyAuthBox->setEnabled(!ui->proxyNoneBtn->isChecked() &&
- !ui->proxyDefaultBtn->isChecked());
+ bool enableEditing = ui->proxyHTTPBtn->isChecked()
+ || ui->proxySOCKS5Btn->isChecked();
+ ui->proxyAddrBox->setEnabled(enableEditing);
+ ui->proxyAuthBox->setEnabled(enableEditing);
}
-void ProxyPage::proxyChanged(int)
+void ProxyPage::proxyGroupChanged(QAbstractButton *button)
{
updateCheckboxStuff();
}
diff --git a/launcher/ui/pages/global/ProxyPage.h b/launcher/ui/pages/global/ProxyPage.h
index e3677774..279a9029 100644
--- a/launcher/ui/pages/global/ProxyPage.h
+++ b/launcher/ui/pages/global/ProxyPage.h
@@ -2,6 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* 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
@@ -36,6 +37,7 @@
#pragma once
#include <memory>
+#include <QAbstractButton>
#include <QDialog>
#include "ui/pages/BasePage.h"
@@ -73,15 +75,14 @@ public:
bool apply() override;
void retranslate() override;
+private slots:
+ void proxyGroupChanged(QAbstractButton *button);
+
private:
void updateCheckboxStuff();
void applySettings();
void loadSettings();
-private
-slots:
- void proxyChanged(int);
-
private:
Ui::ProxyPage *ui;
};
diff --git a/launcher/ui/pages/instance/ExternalResourcesPage.cpp b/launcher/ui/pages/instance/ExternalResourcesPage.cpp
new file mode 100644
index 00000000..d06f412b
--- /dev/null
+++ b/launcher/ui/pages/instance/ExternalResourcesPage.cpp
@@ -0,0 +1,297 @@
+#include "ExternalResourcesPage.h"
+#include "ui_ExternalResourcesPage.h"
+
+#include "DesktopServices.h"
+#include "Version.h"
+#include "minecraft/mod/ModFolderModel.h"
+#include "ui/GuiUtil.h"
+
+#include <QKeyEvent>
+#include <QMenu>
+
+namespace {
+// FIXME: wasteful
+void RemoveThePrefix(QString& string)
+{
+ QRegularExpression regex(QStringLiteral("^(?:the|teh) +"), QRegularExpression::CaseInsensitiveOption);
+ string.remove(regex);
+ string = string.trimmed();
+}
+} // namespace
+
+class SortProxy : public QSortFilterProxyModel {
+ public:
+ explicit SortProxy(QObject* parent = nullptr) : QSortFilterProxyModel(parent) {}
+
+ protected:
+ bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override
+ {
+ ModFolderModel* model = qobject_cast<ModFolderModel*>(sourceModel());
+ if (!model)
+ return false;
+
+ const auto& mod = model->at(source_row);
+
+ if (mod.name().contains(filterRegularExpression()))
+ return true;
+ if (mod.description().contains(filterRegularExpression()))
+ return true;
+
+ for (auto& author : mod.authors()) {
+ if (author.contains(filterRegularExpression())) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ bool lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const override
+ {
+ ModFolderModel* model = qobject_cast<ModFolderModel*>(sourceModel());
+ if (!model || !source_left.isValid() || !source_right.isValid() || source_left.column() != source_right.column()) {
+ return QSortFilterProxyModel::lessThan(source_left, source_right);
+ }
+
+ // we are now guaranteed to have two valid indexes in the same column... we love the provided invariants unconditionally and
+ // proceed.
+
+ auto column = (ModFolderModel::Columns) source_left.column();
+ bool invert = false;
+ switch (column) {
+ // GH-2550 - sort by enabled/disabled
+ case ModFolderModel::ActiveColumn: {
+ auto dataL = source_left.data(Qt::CheckStateRole).toBool();
+ auto dataR = source_right.data(Qt::CheckStateRole).toBool();
+ if (dataL != dataR)
+ return dataL > dataR;
+
+ // fallthrough
+ invert = sortOrder() == Qt::DescendingOrder;
+ }
+ // GH-2722 - sort mod names in a way that discards "The" prefixes
+ case ModFolderModel::NameColumn: {
+ auto dataL = model->data(model->index(source_left.row(), ModFolderModel::NameColumn)).toString();
+ RemoveThePrefix(dataL);
+ auto dataR = model->data(model->index(source_right.row(), ModFolderModel::NameColumn)).toString();
+ RemoveThePrefix(dataR);
+
+ auto less = dataL.compare(dataR, sortCaseSensitivity());
+ if (less != 0)
+ return invert ? (less > 0) : (less < 0);
+
+ // fallthrough
+ invert = sortOrder() == Qt::DescendingOrder;
+ }
+ // GH-2762 - sort versions by parsing them as versions
+ case ModFolderModel::VersionColumn: {
+ auto dataL = Version(model->data(model->index(source_left.row(), ModFolderModel::VersionColumn)).toString());
+ auto dataR = Version(model->data(model->index(source_right.row(), ModFolderModel::VersionColumn)).toString());
+ return invert ? (dataL > dataR) : (dataL < dataR);
+ }
+ default: {
+ return QSortFilterProxyModel::lessThan(source_left, source_right);
+ }
+ }
+ }
+};
+
+ExternalResourcesPage::ExternalResourcesPage(BaseInstance* instance, std::shared_ptr<ModFolderModel> model, QWidget* parent)
+ : QMainWindow(parent), m_instance(instance), ui(new Ui::ExternalResourcesPage), m_model(model)
+{
+ ui->setupUi(this);
+
+ runningStateChanged(m_instance && m_instance->isRunning());
+
+ ui->actionsToolbar->insertSpacer(ui->actionViewConfigs);
+
+ m_filterModel = new SortProxy(this);
+ m_filterModel->setDynamicSortFilter(true);
+ m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
+ m_filterModel->setSortCaseSensitivity(Qt::CaseInsensitive);
+ m_filterModel->setSourceModel(m_model.get());
+ m_filterModel->setFilterKeyColumn(-1);
+ ui->treeView->setModel(m_filterModel);
+
+ ui->treeView->installEventFilter(this);
+ ui->treeView->sortByColumn(1, Qt::AscendingOrder);
+ ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
+
+ // The default function names by Qt are pretty ugly, so let's just connect the actions manually,
+ // to make it easier to read :)
+ connect(ui->actionAddItem, &QAction::triggered, this, &ExternalResourcesPage::addItem);
+ connect(ui->actionRemoveItem, &QAction::triggered, this, &ExternalResourcesPage::removeItem);
+ connect(ui->actionEnableItem, &QAction::triggered, this, &ExternalResourcesPage::enableItem);
+ connect(ui->actionDisableItem, &QAction::triggered, this, &ExternalResourcesPage::disableItem);
+ connect(ui->actionViewConfigs, &QAction::triggered, this, &ExternalResourcesPage::viewConfigs);
+ connect(ui->actionViewFolder, &QAction::triggered, this, &ExternalResourcesPage::viewFolder);
+
+ connect(ui->treeView, &ModListView::customContextMenuRequested, this, &ExternalResourcesPage::ShowContextMenu);
+ connect(ui->treeView, &ModListView::activated, this, &ExternalResourcesPage::itemActivated);
+
+ auto selection_model = ui->treeView->selectionModel();
+ connect(selection_model, &QItemSelectionModel::currentChanged, this, &ExternalResourcesPage::current);
+ connect(ui->filterEdit, &QLineEdit::textChanged, this, &ExternalResourcesPage::filterTextChanged);
+ connect(m_instance, &BaseInstance::runningStatusChanged, this, &ExternalResourcesPage::runningStateChanged);
+}
+
+ExternalResourcesPage::~ExternalResourcesPage()
+{
+ m_model->stopWatching();
+ delete ui;
+}
+
+void ExternalResourcesPage::itemActivated(const QModelIndex&)
+{
+ if (!m_controlsEnabled)
+ return;
+
+ auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
+ m_model->setModStatus(selection.indexes(), ModFolderModel::Toggle);
+}
+
+QMenu* ExternalResourcesPage::createPopupMenu()
+{
+ QMenu* filteredMenu = QMainWindow::createPopupMenu();
+ filteredMenu->removeAction(ui->actionsToolbar->toggleViewAction());
+ return filteredMenu;
+}
+
+void ExternalResourcesPage::ShowContextMenu(const QPoint& pos)
+{
+ auto menu = ui->actionsToolbar->createContextMenu(this, tr("Context menu"));
+ menu->exec(ui->treeView->mapToGlobal(pos));
+ delete menu;
+}
+
+void ExternalResourcesPage::openedImpl()
+{
+ m_model->startWatching();
+}
+
+void ExternalResourcesPage::closedImpl()
+{
+ m_model->stopWatching();
+}
+
+void ExternalResourcesPage::retranslate()
+{
+ ui->retranslateUi(this);
+}
+
+void ExternalResourcesPage::filterTextChanged(const QString& newContents)
+{
+ m_viewFilter = newContents;
+ m_filterModel->setFilterFixedString(m_viewFilter);
+}
+
+void ExternalResourcesPage::runningStateChanged(bool running)
+{
+ if (m_controlsEnabled == !running)
+ return;
+
+ m_controlsEnabled = !running;
+ ui->actionAddItem->setEnabled(m_controlsEnabled);
+ ui->actionDisableItem->setEnabled(m_controlsEnabled);
+ ui->actionEnableItem->setEnabled(m_controlsEnabled);
+ ui->actionRemoveItem->setEnabled(m_controlsEnabled);
+}
+
+bool ExternalResourcesPage::shouldDisplay() const
+{
+ return true;
+}
+
+bool ExternalResourcesPage::listFilter(QKeyEvent* keyEvent)
+{
+ switch (keyEvent->key()) {
+ case Qt::Key_Delete:
+ removeItem();
+ return true;
+ case Qt::Key_Plus:
+ addItem();
+ return true;
+ default:
+ break;
+ }
+ return QWidget::eventFilter(ui->treeView, keyEvent);
+}
+
+bool ExternalResourcesPage::eventFilter(QObject* obj, QEvent* ev)
+{
+ if (ev->type() != QEvent::KeyPress)
+ return QWidget::eventFilter(obj, ev);
+
+ QKeyEvent* keyEvent = static_cast<QKeyEvent*>(ev);
+ if (obj == ui->treeView)
+ return listFilter(keyEvent);
+
+ return QWidget::eventFilter(obj, ev);
+}
+
+void ExternalResourcesPage::addItem()
+{
+ if (!m_controlsEnabled)
+ return;
+
+
+ auto list = GuiUtil::BrowseForFiles(
+ helpPage(), tr("Select %1", "Select whatever type of files the page contains. Example: 'Loader Mods'").arg(displayName()),
+ m_fileSelectionFilter.arg(displayName()), APPLICATION->settings()->get("CentralModsDir").toString(), this->parentWidget());
+
+ if (!list.isEmpty()) {
+ for (auto filename : list) {
+ m_model->installMod(filename);
+ }
+ }
+}
+
+void ExternalResourcesPage::removeItem()
+{
+ if (!m_controlsEnabled)
+ return;
+
+ auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
+ m_model->deleteMods(selection.indexes());
+}
+
+void ExternalResourcesPage::enableItem()
+{
+ if (!m_controlsEnabled)
+ return;
+
+ auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
+ m_model->setModStatus(selection.indexes(), ModFolderModel::Enable);
+}
+
+void ExternalResourcesPage::disableItem()
+{
+ if (!m_controlsEnabled)
+ return;
+
+ auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
+ m_model->setModStatus(selection.indexes(), ModFolderModel::Disable);
+}
+
+void ExternalResourcesPage::viewConfigs()
+{
+ DesktopServices::openDirectory(m_instance->instanceConfigFolder(), true);
+}
+
+void ExternalResourcesPage::viewFolder()
+{
+ DesktopServices::openDirectory(m_model->dir().absolutePath(), true);
+}
+
+void ExternalResourcesPage::current(const QModelIndex& current, const QModelIndex& previous)
+{
+ if (!current.isValid()) {
+ ui->frame->clear();
+ return;
+ }
+
+ auto sourceCurrent = m_filterModel->mapToSource(current);
+ int row = sourceCurrent.row();
+ Mod& m = m_model->operator[](row);
+ ui->frame->updateWithMod(m);
+}
diff --git a/launcher/ui/pages/instance/ExternalResourcesPage.h b/launcher/ui/pages/instance/ExternalResourcesPage.h
new file mode 100644
index 00000000..41237139
--- /dev/null
+++ b/launcher/ui/pages/instance/ExternalResourcesPage.h
@@ -0,0 +1,73 @@
+#pragma once
+
+#include <QMainWindow>
+#include <QSortFilterProxyModel>
+
+#include "Application.h"
+#include "minecraft/MinecraftInstance.h"
+#include "ui/pages/BasePage.h"
+
+class ModFolderModel;
+
+namespace Ui {
+class ExternalResourcesPage;
+}
+
+/* This page is used as a base for pages in which the user can manage external resources
+ * related to the game, such as mods, shaders or resource packs. */
+class ExternalResourcesPage : public QMainWindow, public BasePage {
+ Q_OBJECT
+
+ public:
+ // FIXME: Switch to different model (or change the name of this one)
+ explicit ExternalResourcesPage(BaseInstance* instance, std::shared_ptr<ModFolderModel> model, QWidget* parent = nullptr);
+ virtual ~ExternalResourcesPage();
+
+ virtual QString displayName() const override = 0;
+ virtual QIcon icon() const override = 0;
+ virtual QString id() const override = 0;
+ virtual QString helpPage() const override = 0;
+
+ virtual bool shouldDisplay() const override = 0;
+
+ void openedImpl() override;
+ void closedImpl() override;
+
+ void retranslate() override;
+
+ protected:
+ bool eventFilter(QObject* obj, QEvent* ev) override;
+ bool listFilter(QKeyEvent* ev);
+ QMenu* createPopupMenu() override;
+
+ public slots:
+ void current(const QModelIndex& current, const QModelIndex& previous);
+
+ protected slots:
+ void itemActivated(const QModelIndex& index);
+ void filterTextChanged(const QString& newContents);
+ void runningStateChanged(bool running);
+
+ virtual void addItem();
+ virtual void removeItem();
+
+ virtual void enableItem();
+ virtual void disableItem();
+
+ virtual void viewFolder();
+ virtual void viewConfigs();
+
+ void ShowContextMenu(const QPoint& pos);
+
+ protected:
+ BaseInstance* m_instance = nullptr;
+
+ Ui::ExternalResourcesPage* ui = nullptr;
+ std::shared_ptr<ModFolderModel> m_model;
+ QSortFilterProxyModel* m_filterModel = nullptr;
+
+ QString m_fileSelectionFilter;
+ QString m_viewFilter;
+
+ bool m_controlsEnabled = true;
+};
diff --git a/launcher/ui/pages/instance/ModFolderPage.ui b/launcher/ui/pages/instance/ExternalResourcesPage.ui
index ab59b0df..17bf455a 100644
--- a/launcher/ui/pages/instance/ModFolderPage.ui
+++ b/launcher/ui/pages/instance/ExternalResourcesPage.ui
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
- <class>ModFolderPage</class>
- <widget class="QMainWindow" name="ModFolderPage">
+ <class>ExternalResourcesPage</class>
+ <widget class="QMainWindow" name="ExternalResourcesPage">
<property name="geometry">
<rect>
<x>0</x>
@@ -53,7 +53,7 @@
</widget>
</item>
<item row="1" column="1" colspan="3">
- <widget class="ModListView" name="modTreeView">
+ <widget class="ModListView" name="treeView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
@@ -83,15 +83,15 @@
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
- <addaction name="actionAdd"/>
+ <addaction name="actionAddItem"/>
<addaction name="separator"/>
- <addaction name="actionRemove"/>
- <addaction name="actionEnable"/>
- <addaction name="actionDisable"/>
- <addaction name="actionView_configs"/>
- <addaction name="actionView_Folder"/>
+ <addaction name="actionRemoveItem"/>
+ <addaction name="actionEnableItem"/>
+ <addaction name="actionDisableItem"/>
+ <addaction name="actionViewConfigs"/>
+ <addaction name="actionViewFolder"/>
</widget>
- <action name="actionAdd">
+ <action name="actionAddItem">
<property name="text">
<string>&amp;Add</string>
</property>
@@ -99,31 +99,31 @@
<string>Add</string>
</property>
</action>
- <action name="actionRemove">
+ <action name="actionRemoveItem">
<property name="text">
<string>&amp;Remove</string>
</property>
<property name="toolTip">
- <string>Remove selected mods</string>
+ <string>Remove selected item</string>
</property>
</action>
- <action name="actionEnable">
+ <action name="actionEnableItem">
<property name="text">
<string>&amp;Enable</string>
</property>
<property name="toolTip">
- <string>Enable selected mods</string>
+ <string>Enable selected item</string>
</property>
</action>
- <action name="actionDisable">
+ <action name="actionDisableItem">
<property name="text">
<string>&amp;Disable</string>
</property>
<property name="toolTip">
- <string>Disable selected mods</string>
+ <string>Disable selected item</string>
</property>
</action>
- <action name="actionView_configs">
+ <action name="actionViewConfigs">
<property name="text">
<string>View &amp;Configs</string>
</property>
@@ -131,11 +131,22 @@
<string>Open the 'config' folder in the system file manager.</string>
</property>
</action>
- <action name="actionView_Folder">
+ <action name="actionViewFolder">
<property name="text">
<string>View &amp;Folder</string>
</property>
</action>
+ <action name="actionDownloadItem">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Download</string>
+ </property>
+ <property name="toolTip">
+ <string>Download a new resource</string>
+ </property>
+ </action>
</widget>
<customwidgets>
<customwidget>
@@ -156,7 +167,7 @@
</customwidget>
</customwidgets>
<tabstops>
- <tabstop>modTreeView</tabstop>
+ <tabstop>treeView</tabstop>
<tabstop>filterEdit</tabstop>
</tabstops>
<resources/>
diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.cpp b/launcher/ui/pages/instance/InstanceSettingsPage.cpp
index b4562843..fcc110de 100644
--- a/launcher/ui/pages/instance/InstanceSettingsPage.cpp
+++ b/launcher/ui/pages/instance/InstanceSettingsPage.cpp
@@ -2,7 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
- * Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* 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
@@ -50,6 +50,7 @@
#include "Application.h"
#include "java/JavaInstallList.h"
+#include "java/JavaUtils.h"
#include "FileSystem.h"
@@ -232,6 +233,22 @@ void InstanceSettingsPage::applySettings()
m_settings->reset("UseNativeGLFW");
}
+ // Performance
+ bool performance = ui->perfomanceGroupBox->isChecked();
+ m_settings->set("OverridePerformance", performance);
+ if(performance)
+ {
+ m_settings->set("EnableFeralGamemode", ui->enableFeralGamemodeCheck->isChecked());
+ m_settings->set("EnableMangoHud", ui->enableMangoHud->isChecked());
+ m_settings->set("UseDiscreteGpu", ui->useDiscreteGpuCheck->isChecked());
+ }
+ else
+ {
+ m_settings->reset("EnableFeralGamemode");
+ m_settings->reset("EnableMangoHud");
+ m_settings->reset("UseDiscreteGpu");
+ }
+
// Game time
bool gameTime = ui->gameTimeGroupBox->isChecked();
m_settings->set("OverrideGameTime", gameTime);
@@ -325,6 +342,16 @@ void InstanceSettingsPage::loadSettings()
ui->useNativeGLFWCheck->setChecked(m_settings->get("UseNativeGLFW").toBool());
ui->useNativeOpenALCheck->setChecked(m_settings->get("UseNativeOpenAL").toBool());
+ // Performance
+ ui->perfomanceGroupBox->setChecked(m_settings->get("OverridePerformance").toBool());
+ ui->enableFeralGamemodeCheck->setChecked(m_settings->get("EnableFeralGamemode").toBool());
+ ui->enableMangoHud->setChecked(m_settings->get("EnableMangoHud").toBool());
+ ui->useDiscreteGpuCheck->setChecked(m_settings->get("UseDiscreteGpu").toBool());
+
+ #if !defined(Q_OS_LINUX)
+ ui->perfomanceGroupBox->setVisible(false);
+ #endif
+
// Miscellanous
ui->gameTimeGroupBox->setChecked(m_settings->get("OverrideGameTime").toBool());
ui->showGameTime->setChecked(m_settings->get("ShowGameTime").toBool());
@@ -336,6 +363,11 @@ void InstanceSettingsPage::loadSettings()
void InstanceSettingsPage::on_javaDetectBtn_clicked()
{
+ if (JavaUtils::getJavaCheckPath().isEmpty()) {
+ JavaCommon::javaCheckNotFound(this);
+ return;
+ }
+
JavaInstallPtr java;
VersionSelectDialog vselect(APPLICATION->javalist().get(), tr("Select a Java version"), this, true);
diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.ui b/launcher/ui/pages/instance/InstanceSettingsPage.ui
index cb66b3ce..8b3c3370 100644
--- a/launcher/ui/pages/instance/InstanceSettingsPage.ui
+++ b/launcher/ui/pages/instance/InstanceSettingsPage.ui
@@ -455,6 +455,74 @@
</item>
</layout>
</widget>
+ <widget class="QWidget" name="performancePage">
+ <attribute name="title">
+ <string>Performance</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_14">
+ <item>
+ <widget class="QGroupBox" name="perfomanceGroupBox">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string>Performance</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_13">
+ <item>
+ <widget class="QCheckBox" name="enableFeralGamemodeCheck">
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable Feral Interactive's GameMode, to potentially improve gaming performance.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>Enable Feral GameMode</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="enableMangoHud">
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable MangoHud's advanced performance overlay.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>Enable MangoHud</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="useDiscreteGpuCheck">
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use the discrete GPU instead of the primary GPU.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>Use discrete GPU</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
<widget class="QWidget" name="miscellaneousPage">
<attribute name="title">
<string>Miscellaneous</string>
diff --git a/launcher/ui/pages/instance/LogPage.cpp b/launcher/ui/pages/instance/LogPage.cpp
index a6c98c08..3d9fb025 100644
--- a/launcher/ui/pages/instance/LogPage.cpp
+++ b/launcher/ui/pages/instance/LogPage.cpp
@@ -40,7 +40,6 @@
#include "Application.h"
#include <QIcon>
-#include <QIdentityProxyModel>
#include <QScrollBar>
#include <QShortcut>
@@ -64,7 +63,7 @@ public:
{
case Qt::FontRole:
return m_font;
- case Qt::TextColorRole:
+ case Qt::ForegroundRole:
{
MessageLevel::Enum level = (MessageLevel::Enum) QIdentityProxyModel::data(index, LogModel::LevelRole).toInt();
return m_colors->getFront(level);
diff --git a/launcher/ui/pages/instance/ModFolderPage.cpp b/launcher/ui/pages/instance/ModFolderPage.cpp
index d929a0ea..4432ccc8 100644
--- a/launcher/ui/pages/instance/ModFolderPage.cpp
+++ b/launcher/ui/pages/instance/ModFolderPage.cpp
@@ -35,370 +35,99 @@
*/
#include "ModFolderPage.h"
-#include "ui_ModFolderPage.h"
+#include "ui_ExternalResourcesPage.h"
-#include <QMessageBox>
+#include <QAbstractItemModel>
#include <QEvent>
#include <QKeyEvent>
-#include <QAbstractItemModel>
#include <QMenu>
+#include <QMessageBox>
#include <QSortFilterProxyModel>
#include "Application.h"
+#include "ui/GuiUtil.h"
#include "ui/dialogs/CustomMessageBox.h"
#include "ui/dialogs/ModDownloadDialog.h"
-#include "ui/GuiUtil.h"
#include "DesktopServices.h"
-#include "minecraft/mod/ModFolderModel.h"
-#include "minecraft/mod/Mod.h"
-#include "minecraft/VersionFilterData.h"
#include "minecraft/PackProfile.h"
+#include "minecraft/VersionFilterData.h"
+#include "minecraft/mod/Mod.h"
+#include "minecraft/mod/ModFolderModel.h"
#include "modplatform/ModAPI.h"
#include "Version.h"
+#include "tasks/ConcurrentTask.h"
#include "ui/dialogs/ProgressDialog.h"
-#include "tasks/SequentialTask.h"
-
-namespace {
- // FIXME: wasteful
- void RemoveThePrefix(QString & string) {
- QRegularExpression regex(QStringLiteral("^(([Tt][Hh][eE])|([Tt][eE][Hh])) +"));
- string.remove(regex);
- string = string.trimmed();
- }
-}
-
-class ModSortProxy : public QSortFilterProxyModel
-{
-public:
- explicit ModSortProxy(QObject *parent = 0) : QSortFilterProxyModel(parent)
- {
- }
-
-protected:
- bool filterAcceptsRow(int source_row, const QModelIndex & source_parent) const override {
- ModFolderModel *model = qobject_cast<ModFolderModel *>(sourceModel());
- if(!model) {
- return false;
- }
- const auto &mod = model->at(source_row);
- if(mod.name().contains(filterRegExp())) {
- return true;
- }
- if(mod.description().contains(filterRegExp())) {
- return true;
- }
- for(auto & author: mod.authors()) {
- if (author.contains(filterRegExp())) {
- return true;
- }
- }
- return false;
- }
-
- bool lessThan(const QModelIndex & source_left, const QModelIndex & source_right) const override
- {
- ModFolderModel *model = qobject_cast<ModFolderModel *>(sourceModel());
- if(
- !model ||
- !source_left.isValid() ||
- !source_right.isValid() ||
- source_left.column() != source_right.column()
- ) {
- return QSortFilterProxyModel::lessThan(source_left, source_right);
- }
-
- // we are now guaranteed to have two valid indexes in the same column... we love the provided invariants unconditionally and proceed.
- auto column = (ModFolderModel::Columns) source_left.column();
- bool invert = false;
- switch(column) {
- // GH-2550 - sort by enabled/disabled
- case ModFolderModel::ActiveColumn: {
- auto dataL = source_left.data(Qt::CheckStateRole).toBool();
- auto dataR = source_right.data(Qt::CheckStateRole).toBool();
- if(dataL != dataR) {
- return dataL > dataR;
- }
- // fallthrough
- invert = sortOrder() == Qt::DescendingOrder;
- }
- // GH-2722 - sort mod names in a way that discards "The" prefixes
- case ModFolderModel::NameColumn: {
- auto dataL = model->data(model->index(source_left.row(), ModFolderModel::NameColumn)).toString();
- RemoveThePrefix(dataL);
- auto dataR = model->data(model->index(source_right.row(), ModFolderModel::NameColumn)).toString();
- RemoveThePrefix(dataR);
-
- auto less = dataL.compare(dataR, sortCaseSensitivity());
- if(less != 0) {
- return invert ? (less > 0) : (less < 0);
- }
- // fallthrough
- invert = sortOrder() == Qt::DescendingOrder;
- }
- // GH-2762 - sort versions by parsing them as versions
- case ModFolderModel::VersionColumn: {
- auto dataL = Version(model->data(model->index(source_left.row(), ModFolderModel::VersionColumn)).toString());
- auto dataR = Version(model->data(model->index(source_right.row(), ModFolderModel::VersionColumn)).toString());
- return invert ? (dataL > dataR) : (dataL < dataR);
- }
- default: {
- return QSortFilterProxyModel::lessThan(source_left, source_right);
- }
- }
- }
-};
-
-ModFolderPage::ModFolderPage(
- BaseInstance *inst,
- std::shared_ptr<ModFolderModel> mods,
- QString id,
- QString iconName,
- QString displayName,
- QString helpPage,
- QWidget *parent
-) :
- QMainWindow(parent),
- ui(new Ui::ModFolderPage)
+ModFolderPage::ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent)
+ : ExternalResourcesPage(inst, mods, parent)
{
- ui->setupUi(this);
-
// This is structured like that so that these changes
- // do not affect the Resouce pack and Shader pack tabs
- if(id == "mods") {
- auto act = new QAction(tr("Download mods"), this);
- act->setToolTip(tr("Download mods from online mod platforms"));
- ui->actionsToolbar->insertActionBefore(ui->actionAdd, act);
- connect(act, &QAction::triggered, this, &ModFolderPage::on_actionInstall_mods_triggered);
-
- ui->actionAdd->setText(tr("Add .jar"));
- ui->actionAdd->setToolTip(tr("Add mods via local file"));
- }
-
- ui->actionsToolbar->insertSpacer(ui->actionView_configs);
-
- m_inst = inst;
- on_RunningState_changed(m_inst && m_inst->isRunning());
- m_mods = mods;
- m_id = id;
- m_displayName = displayName;
- m_iconName = iconName;
- m_helpName = helpPage;
- m_fileSelectionFilter = "%1 (*.zip *.jar)";
- m_filterModel = new ModSortProxy(this);
- m_filterModel->setDynamicSortFilter(true);
- m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
- m_filterModel->setSortCaseSensitivity(Qt::CaseInsensitive);
- m_filterModel->setSourceModel(m_mods.get());
- m_filterModel->setFilterKeyColumn(-1);
- ui->modTreeView->setModel(m_filterModel);
- ui->modTreeView->installEventFilter(this);
- ui->modTreeView->sortByColumn(1, Qt::AscendingOrder);
- ui->modTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
- connect(ui->modTreeView, &ModListView::customContextMenuRequested, this, &ModFolderPage::ShowContextMenu);
- connect(ui->modTreeView, &ModListView::activated, this, &ModFolderPage::modItemActivated);
+ // do not affect the Resource pack and Shader pack tabs
+ {
+ ui->actionDownloadItem->setText(tr("Download mods"));
+ ui->actionDownloadItem->setToolTip(tr("Download mods from online mod platforms"));
+ ui->actionDownloadItem->setEnabled(true);
+ ui->actionAddItem->setText(tr("Add file"));
+ ui->actionAddItem->setToolTip(tr("Add a locally downloaded file"));
- auto smodel = ui->modTreeView->selectionModel();
- connect(smodel, &QItemSelectionModel::currentChanged, this, &ModFolderPage::modCurrent);
- connect(ui->filterEdit, &QLineEdit::textChanged, this, &ModFolderPage::on_filterTextChanged);
- connect(m_inst, &BaseInstance::runningStatusChanged, this, &ModFolderPage::on_RunningState_changed);
-}
+ ui->actionsToolbar->insertActionBefore(ui->actionAddItem, ui->actionDownloadItem);
-void ModFolderPage::modItemActivated(const QModelIndex&)
-{
- if(!m_controlsEnabled) {
- return;
+ connect(ui->actionDownloadItem, &QAction::triggered, this, &ModFolderPage::installMods);
}
- auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
- m_mods->setModStatus(selection.indexes(), ModFolderModel::Toggle);
-}
-
-QMenu * ModFolderPage::createPopupMenu()
-{
- QMenu* filteredMenu = QMainWindow::createPopupMenu();
- filteredMenu->removeAction(ui->actionsToolbar->toggleViewAction() );
- return filteredMenu;
}
-void ModFolderPage::ShowContextMenu(const QPoint& pos)
-{
- auto menu = ui->actionsToolbar->createContextMenu(this, tr("Context menu"));
- menu->exec(ui->modTreeView->mapToGlobal(pos));
- delete menu;
-}
-
-void ModFolderPage::openedImpl()
-{
- m_mods->startWatching();
-}
-
-void ModFolderPage::closedImpl()
-{
- m_mods->stopWatching();
-}
-
-void ModFolderPage::on_filterTextChanged(const QString& newContents)
-{
- m_viewFilter = newContents;
- m_filterModel->setFilterFixedString(m_viewFilter);
-}
-
-
-CoreModFolderPage::CoreModFolderPage(BaseInstance *inst, std::shared_ptr<ModFolderModel> mods,
- QString id, QString iconName, QString displayName,
- QString helpPage, QWidget *parent)
- : ModFolderPage(inst, mods, id, iconName, displayName, helpPage, parent)
-{
-}
-
-ModFolderPage::~ModFolderPage()
-{
- m_mods->stopWatching();
- delete ui;
-}
-
-void ModFolderPage::on_RunningState_changed(bool running)
-{
- if(m_controlsEnabled == !running) {
- return;
- }
- m_controlsEnabled = !running;
- ui->actionsToolbar->setEnabled(m_controlsEnabled);
-}
+CoreModFolderPage::CoreModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent)
+ : ModFolderPage(inst, mods, parent)
+{}
bool ModFolderPage::shouldDisplay() const
{
return true;
}
-void ModFolderPage::retranslate()
-{
- ui->retranslateUi(this);
-}
-
bool CoreModFolderPage::shouldDisplay() const
{
- if (ModFolderPage::shouldDisplay())
- {
- auto inst = dynamic_cast<MinecraftInstance *>(m_inst);
+ if (ModFolderPage::shouldDisplay()) {
+ auto inst = dynamic_cast<MinecraftInstance*>(m_instance);
if (!inst)
return true;
+
auto version = inst->getPackProfile();
+
if (!version)
return true;
- if(!version->getComponent("net.minecraftforge"))
- {
+ if (!version->getComponent("net.minecraftforge"))
return false;
- }
- if(!version->getComponent("net.minecraft"))
- {
+ if (!version->getComponent("net.minecraft"))
return false;
- }
- if(version->getComponent("net.minecraft")->getReleaseDateTime() < g_VersionFilterData.legacyCutoffDate)
- {
+ if (version->getComponent("net.minecraft")->getReleaseDateTime() < g_VersionFilterData.legacyCutoffDate)
return true;
- }
+
}
return false;
}
-bool ModFolderPage::modListFilter(QKeyEvent *keyEvent)
+void ModFolderPage::installMods()
{
- switch (keyEvent->key())
- {
- case Qt::Key_Delete:
- on_actionRemove_triggered();
- return true;
- case Qt::Key_Plus:
- on_actionAdd_triggered();
- return true;
- default:
- break;
- }
- return QWidget::eventFilter(ui->modTreeView, keyEvent);
-}
-
-bool ModFolderPage::eventFilter(QObject *obj, QEvent *ev)
-{
- if (ev->type() != QEvent::KeyPress)
- {
- return QWidget::eventFilter(obj, ev);
- }
- QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev);
- if (obj == ui->modTreeView)
- return modListFilter(keyEvent);
- return QWidget::eventFilter(obj, ev);
-}
-
-void ModFolderPage::on_actionAdd_triggered()
-{
- if(!m_controlsEnabled) {
+ if (!m_controlsEnabled)
return;
- }
- auto list = GuiUtil::BrowseForFiles(
- m_helpName,
- tr("Select %1",
- "Select whatever type of files the page contains. Example: 'Loader Mods'")
- .arg(m_displayName),
- m_fileSelectionFilter.arg(m_displayName), APPLICATION->settings()->get("CentralModsDir").toString(),
- this->parentWidget());
- if (!list.empty())
- {
- for (auto filename : list)
- {
- m_mods->installMod(filename);
- }
- }
-}
-
-void ModFolderPage::on_actionEnable_triggered()
-{
- if(!m_controlsEnabled) {
- return;
- }
- auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
- m_mods->setModStatus(selection.indexes(), ModFolderModel::Enable);
-}
-
-void ModFolderPage::on_actionDisable_triggered()
-{
- if(!m_controlsEnabled) {
- return;
- }
- auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
- m_mods->setModStatus(selection.indexes(), ModFolderModel::Disable);
-}
-
-void ModFolderPage::on_actionRemove_triggered()
-{
- if(!m_controlsEnabled) {
- return;
- }
- auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
- m_mods->deleteMods(selection.indexes());
-}
-
-void ModFolderPage::on_actionInstall_mods_triggered()
-{
- if(!m_controlsEnabled) {
- return;
- }
- if(m_inst->typeName() != "Minecraft"){
- return; //this is a null instance or a legacy instance
- }
- auto profile = ((MinecraftInstance *)m_inst)->getPackProfile();
+ if (m_instance->typeName() != "Minecraft")
+ return; // this is a null instance or a legacy instance
+
+ auto profile = static_cast<MinecraftInstance*>(m_instance)->getPackProfile();
if (profile->getModLoaders() == ModAPI::Unspecified) {
- QMessageBox::critical(this,tr("Error"),tr("Please install a mod loader first!"));
+ QMessageBox::critical(this, tr("Error"), tr("Please install a mod loader first!"));
return;
}
- ModDownloadDialog mdownload(m_mods, this, m_inst);
+
+ ModDownloadDialog mdownload(m_model, this, m_instance);
if (mdownload.exec()) {
- SequentialTask* tasks = new SequentialTask(this);
+ ConcurrentTask* tasks = new ConcurrentTask(this);
connect(tasks, &Task::failed, [this, tasks](QString reason) {
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show();
tasks->deleteLater();
@@ -409,40 +138,20 @@ void ModFolderPage::on_actionInstall_mods_triggered()
});
connect(tasks, &Task::succeeded, [this, tasks]() {
QStringList warnings = tasks->warnings();
- if (warnings.count()) { CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show(); }
+ if (warnings.count())
+ CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show();
+
tasks->deleteLater();
});
- for (auto task : mdownload.getTasks()) {
+ for (auto& task : mdownload.getTasks()) {
tasks->addTask(task);
}
ProgressDialog loadDialog(this);
loadDialog.setSkipButton(true, tr("Abort"));
loadDialog.execWithTask(tasks);
- m_mods->update();
- }
-}
-void ModFolderPage::on_actionView_configs_triggered()
-{
- DesktopServices::openDirectory(m_inst->instanceConfigFolder(), true);
-}
-
-void ModFolderPage::on_actionView_Folder_triggered()
-{
- DesktopServices::openDirectory(m_mods->dir().absolutePath(), true);
-}
-
-void ModFolderPage::modCurrent(const QModelIndex &current, const QModelIndex &previous)
-{
- if (!current.isValid())
- {
- ui->frame->clear();
- return;
+ m_model->update();
}
- auto sourceCurrent = m_filterModel->mapToSource(current);
- int row = sourceCurrent.row();
- Mod &m = m_mods->operator[](row);
- ui->frame->updateWithMod(m);
}
diff --git a/launcher/ui/pages/instance/ModFolderPage.h b/launcher/ui/pages/instance/ModFolderPage.h
index 2dd44e85..19caa732 100644
--- a/launcher/ui/pages/instance/ModFolderPage.h
+++ b/launcher/ui/pages/instance/ModFolderPage.h
@@ -2,6 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* 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
@@ -35,109 +36,31 @@
#pragma once
-#include <QMainWindow>
+#include "ExternalResourcesPage.h"
-#include "minecraft/MinecraftInstance.h"
-#include "ui/pages/BasePage.h"
-
-#include <Application.h>
-#include <QSortFilterProxyModel>
-
-class ModFolderModel;
-namespace Ui
-{
-class ModFolderPage;
-}
-
-class ModFolderPage : public QMainWindow, public BasePage
-{
+class ModFolderPage : public ExternalResourcesPage {
Q_OBJECT
-public:
- explicit ModFolderPage(
- BaseInstance *inst,
- std::shared_ptr<ModFolderModel> mods,
- QString id,
- QString iconName,
- QString displayName,
- QString helpPage = "",
- QWidget *parent = 0
- );
- virtual ~ModFolderPage();
-
- void setFilter(const QString & filter)
- {
- m_fileSelectionFilter = filter;
- }
+ public:
+ explicit ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent = nullptr);
+ virtual ~ModFolderPage() = default;
- virtual QString displayName() const override
- {
- return m_displayName;
- }
- virtual QIcon icon() const override
- {
- return APPLICATION->getThemedIcon(m_iconName);
- }
- virtual QString id() const override
- {
- return m_id;
- }
- virtual QString helpPage() const override
- {
- return m_helpName;
- }
- virtual bool shouldDisplay() const override;
- void retranslate() override;
-
- virtual void openedImpl() override;
- virtual void closedImpl() override;
-protected:
- bool eventFilter(QObject *obj, QEvent *ev) override;
- bool modListFilter(QKeyEvent *ev);
- QMenu * createPopupMenu() override;
+ void setFilter(const QString& filter) { m_fileSelectionFilter = filter; }
-protected:
- BaseInstance *m_inst = nullptr;
+ virtual QString displayName() const override { return tr("Mods"); }
+ virtual QIcon icon() const override { return APPLICATION->getThemedIcon("loadermods"); }
+ virtual QString id() const override { return "mods"; }
+ virtual QString helpPage() const override { return "Loader-mods"; }
-protected:
- Ui::ModFolderPage *ui = nullptr;
- std::shared_ptr<ModFolderModel> m_mods;
- QSortFilterProxyModel *m_filterModel = nullptr;
- QString m_iconName;
- QString m_id;
- QString m_displayName;
- QString m_helpName;
- QString m_fileSelectionFilter;
- QString m_viewFilter;
- bool m_controlsEnabled = true;
-
-public
-slots:
- void modCurrent(const QModelIndex &current, const QModelIndex &previous);
+ virtual bool shouldDisplay() const override;
-private
-slots:
- void modItemActivated(const QModelIndex &index);
- void on_filterTextChanged(const QString & newContents);
- void on_RunningState_changed(bool running);
- void on_actionAdd_triggered();
- void on_actionRemove_triggered();
- void on_actionEnable_triggered();
- void on_actionDisable_triggered();
- void on_actionInstall_mods_triggered();
- void on_actionView_Folder_triggered();
- void on_actionView_configs_triggered();
- void ShowContextMenu(const QPoint &pos);
+ private slots:
+ void installMods();
};
-class CoreModFolderPage : public ModFolderPage
-{
-public:
- explicit CoreModFolderPage(BaseInstance *inst, std::shared_ptr<ModFolderModel> mods, QString id,
- QString iconName, QString displayName, QString helpPage = "",
- QWidget *parent = 0);
- virtual ~CoreModFolderPage()
- {
- }
+class CoreModFolderPage : public ModFolderPage {
+ public:
+ explicit CoreModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent = 0);
+ virtual ~CoreModFolderPage() = default;
virtual bool shouldDisplay() const;
};
diff --git a/launcher/ui/pages/instance/ResourcePackPage.h b/launcher/ui/pages/instance/ResourcePackPage.h
index 8054926c..a6c9fdd3 100644
--- a/launcher/ui/pages/instance/ResourcePackPage.h
+++ b/launcher/ui/pages/instance/ResourcePackPage.h
@@ -35,24 +35,28 @@
#pragma once
-#include "ModFolderPage.h"
-#include "ui_ModFolderPage.h"
+#include "ExternalResourcesPage.h"
+#include "ui_ExternalResourcesPage.h"
-class ResourcePackPage : public ModFolderPage
+class ResourcePackPage : public ExternalResourcesPage
{
Q_OBJECT
public:
explicit ResourcePackPage(MinecraftInstance *instance, QWidget *parent = 0)
- : ModFolderPage(instance, instance->resourcePackList(), "resourcepacks",
- "resourcepacks", tr("Resource packs"), "Resource-packs", parent)
+ : ExternalResourcesPage(instance, instance->resourcePackList(), parent)
{
- ui->actionView_configs->setVisible(false);
+ ui->actionViewConfigs->setVisible(false);
}
virtual ~ResourcePackPage() {}
+ QString displayName() const override { return tr("Resource packs"); }
+ QIcon icon() const override { return APPLICATION->getThemedIcon("resourcepacks"); }
+ QString id() const override { return "resourcepacks"; }
+ QString helpPage() const override { return "Resource-packs"; }
+
virtual bool shouldDisplay() const override
{
- return !m_inst->traits().contains("no-texturepacks") &&
- !m_inst->traits().contains("texturepacks");
+ return !m_instance->traits().contains("no-texturepacks") &&
+ !m_instance->traits().contains("texturepacks");
}
};
diff --git a/launcher/ui/pages/instance/ScreenshotsPage.cpp b/launcher/ui/pages/instance/ScreenshotsPage.cpp
index 51163e28..c97253e4 100644
--- a/launcher/ui/pages/instance/ScreenshotsPage.cpp
+++ b/launcher/ui/pages/instance/ScreenshotsPage.cpp
@@ -50,6 +50,7 @@
#include <QClipboard>
#include <QKeyEvent>
#include <QMenu>
+#include <QRegularExpression>
#include <Application.h>
@@ -154,7 +155,7 @@ public:
if (role == Qt::DisplayRole || role == Qt::EditRole)
{
QVariant result = sourceModel()->data(mapToSource(proxyIndex), role);
- return result.toString().remove(QRegExp("\\.png$"));
+ return result.toString().remove(QRegularExpression("\\.png$"));
}
if (role == Qt::DecorationRole)
{
@@ -270,7 +271,7 @@ ScreenshotsPage::ScreenshotsPage(QString path, QWidget *parent)
ui->listView->setViewMode(QListView::IconMode);
ui->listView->setResizeMode(QListView::Adjust);
ui->listView->installEventFilter(this);
- ui->listView->setEditTriggers(0);
+ ui->listView->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->listView->setItemDelegate(new CenteredEditingDelegate(this));
ui->listView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->listView, &QListView::customContextMenuRequested, this, &ScreenshotsPage::ShowContextMenu);
diff --git a/launcher/ui/pages/instance/ScreenshotsPage.h b/launcher/ui/pages/instance/ScreenshotsPage.h
index c34c9755..c22706af 100644
--- a/launcher/ui/pages/instance/ScreenshotsPage.h
+++ b/launcher/ui/pages/instance/ScreenshotsPage.h
@@ -35,7 +35,6 @@
#pragma once
-#include <QItemSelection>
#include <QMainWindow>
#include "ui/pages/BasePage.h"
diff --git a/launcher/ui/pages/instance/ServersPage.cpp b/launcher/ui/pages/instance/ServersPage.cpp
index c3bde612..e5cce96c 100644
--- a/launcher/ui/pages/instance/ServersPage.cpp
+++ b/launcher/ui/pages/instance/ServersPage.cpp
@@ -48,7 +48,6 @@
#include <QFileSystemWatcher>
#include <QMenu>
-#include <QTimer>
static const int COLUMN_COUNT = 2; // 3 , TBD: latency and other nice things.
@@ -289,7 +288,11 @@ public:
return false;
}
beginMoveRows(QModelIndex(), row, row, QModelIndex(), row - 1);
+#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
+ m_servers.swapItemsAt(row-1, row);
+#else
m_servers.swap(row-1, row);
+#endif
endMoveRows();
scheduleSave();
return true;
@@ -307,7 +310,11 @@ public:
return false;
}
beginMoveRows(QModelIndex(), row, row, QModelIndex(), row + 2);
+#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
+ m_servers.swapItemsAt(row+1, row);
+#else
m_servers.swap(row+1, row);
+#endif
endMoveRows();
scheduleSave();
return true;
@@ -616,7 +623,7 @@ ServersPage::ServersPage(InstancePtr inst, QWidget* parent)
auto selectionModel = ui->serversView->selectionModel();
connect(selectionModel, &QItemSelectionModel::currentChanged, this, &ServersPage::currentChanged);
- connect(m_inst.get(), &MinecraftInstance::runningStatusChanged, this, &ServersPage::on_RunningState_changed);
+ connect(m_inst.get(), &MinecraftInstance::runningStatusChanged, this, &ServersPage::runningStateChanged);
connect(ui->nameLine, &QLineEdit::textEdited, this, &ServersPage::nameEdited);
connect(ui->addressLine, &QLineEdit::textEdited, this, &ServersPage::addressEdited);
connect(ui->resourceComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(resourceIndexChanged(int)));
@@ -656,7 +663,7 @@ QMenu * ServersPage::createPopupMenu()
return filteredMenu;
}
-void ServersPage::on_RunningState_changed(bool running)
+void ServersPage::runningStateChanged(bool running)
{
if(m_locked == running)
{
diff --git a/launcher/ui/pages/instance/ServersPage.h b/launcher/ui/pages/instance/ServersPage.h
index 5173712c..37399d49 100644
--- a/launcher/ui/pages/instance/ServersPage.h
+++ b/launcher/ui/pages/instance/ServersPage.h
@@ -2,6 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* 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
@@ -97,7 +98,7 @@ private slots:
void on_actionMove_Down_triggered();
void on_actionJoin_triggered();
- void on_RunningState_changed(bool running);
+ void runningStateChanged(bool running);
void nameEdited(const QString & name);
void addressEdited(const QString & address);
diff --git a/launcher/ui/pages/instance/ShaderPackPage.h b/launcher/ui/pages/instance/ShaderPackPage.h
index 7d4f5074..2cc056c8 100644
--- a/launcher/ui/pages/instance/ShaderPackPage.h
+++ b/launcher/ui/pages/instance/ShaderPackPage.h
@@ -35,21 +35,25 @@
#pragma once
-#include "ModFolderPage.h"
-#include "ui_ModFolderPage.h"
+#include "ExternalResourcesPage.h"
+#include "ui_ExternalResourcesPage.h"
-class ShaderPackPage : public ModFolderPage
+class ShaderPackPage : public ExternalResourcesPage
{
Q_OBJECT
public:
explicit ShaderPackPage(MinecraftInstance *instance, QWidget *parent = 0)
- : ModFolderPage(instance, instance->shaderPackList(), "shaderpacks",
- "shaderpacks", tr("Shader packs"), "Resource-packs", parent)
+ : ExternalResourcesPage(instance, instance->shaderPackList(), parent)
{
- ui->actionView_configs->setVisible(false);
+ ui->actionViewConfigs->setVisible(false);
}
virtual ~ShaderPackPage() {}
+ QString displayName() const override { return tr("Shader packs"); }
+ QIcon icon() const override { return APPLICATION->getThemedIcon("shaderpacks"); }
+ QString id() const override { return "shaderpacks"; }
+ QString helpPage() const override { return "Resource-packs"; }
+
virtual bool shouldDisplay() const override
{
return true;
diff --git a/launcher/ui/pages/instance/TexturePackPage.h b/launcher/ui/pages/instance/TexturePackPage.h
index e8cefe6e..f550a5bc 100644
--- a/launcher/ui/pages/instance/TexturePackPage.h
+++ b/launcher/ui/pages/instance/TexturePackPage.h
@@ -35,23 +35,27 @@
#pragma once
-#include "ModFolderPage.h"
-#include "ui_ModFolderPage.h"
+#include "ExternalResourcesPage.h"
+#include "ui_ExternalResourcesPage.h"
-class TexturePackPage : public ModFolderPage
+class TexturePackPage : public ExternalResourcesPage
{
Q_OBJECT
public:
explicit TexturePackPage(MinecraftInstance *instance, QWidget *parent = 0)
- : ModFolderPage(instance, instance->texturePackList(), "texturepacks", "resourcepacks",
- tr("Texture packs"), "Texture-packs", parent)
+ : ExternalResourcesPage(instance, instance->texturePackList(), parent)
{
- ui->actionView_configs->setVisible(false);
+ ui->actionViewConfigs->setVisible(false);
}
virtual ~TexturePackPage() {}
+ QString displayName() const override { return tr("Texture packs"); }
+ QIcon icon() const override { return APPLICATION->getThemedIcon("resourcepacks"); }
+ QString id() const override { return "texturepacks"; }
+ QString helpPage() const override { return "Texture-packs"; }
+
virtual bool shouldDisplay() const override
{
- return m_inst->traits().contains("texturepacks");
+ return m_instance->traits().contains("texturepacks");
}
};
diff --git a/launcher/ui/pages/instance/VersionPage.cpp b/launcher/ui/pages/instance/VersionPage.cpp
index 23e2367b..468ff35c 100644
--- a/launcher/ui/pages/instance/VersionPage.cpp
+++ b/launcher/ui/pages/instance/VersionPage.cpp
@@ -2,7 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
- * Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* 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/ui/pages/instance/WorldListPage.cpp b/launcher/ui/pages/instance/WorldListPage.cpp
index ff30dd82..647b04a7 100644
--- a/launcher/ui/pages/instance/WorldListPage.cpp
+++ b/launcher/ui/pages/instance/WorldListPage.cpp
@@ -47,7 +47,6 @@
#include <QInputDialog>
#include <QProcess>
#include <Qt>
-#include <QSortFilterProxyModel>
#include "tools/MCEditTool.h"
#include "FileSystem.h"
diff --git a/launcher/ui/pages/modplatform/ImportPage.cpp b/launcher/ui/pages/modplatform/ImportPage.cpp
index 0b8577b1..30196aad 100644
--- a/launcher/ui/pages/modplatform/ImportPage.cpp
+++ b/launcher/ui/pages/modplatform/ImportPage.cpp
@@ -2,7 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
- * Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* 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/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp
index 98eec31c..94b1f099 100644
--- a/launcher/ui/pages/modplatform/ModModel.cpp
+++ b/launcher/ui/pages/modplatform/ModModel.cpp
@@ -53,7 +53,11 @@ auto ListModel::data(const QModelIndex& index, int role) const -> QVariant
}
case Qt::DecorationRole: {
if (m_logoMap.contains(pack.logoName)) {
- return (m_logoMap.value(pack.logoName));
+ auto icon = m_logoMap.value(pack.logoName);
+ // FIXME: This doesn't really belong here, but Qt doesn't offer a good way right now ;(
+ auto icon_scaled = QIcon(icon.pixmap(48, 48).scaledToWidth(48));
+
+ return icon_scaled;
}
QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder");
// un-const-ify this
@@ -215,6 +219,10 @@ void ListModel::searchRequestFinished(QJsonDocument& doc)
searchState = CanPossiblyFetchMore;
}
+ // When you have a Qt build with assertions turned on, proceeding here will abort the application
+ if (newList.size() == 0)
+ return;
+
beginInsertRows(QModelIndex(), modpacks.size(), modpacks.size() + newList.size() - 1);
modpacks.append(newList);
endInsertRows();
diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.cpp b/launcher/ui/pages/modplatform/flame/FlameModPage.cpp
index 1c160fd4..10d34218 100644
--- a/launcher/ui/pages/modplatform/flame/FlameModPage.cpp
+++ b/launcher/ui/pages/modplatform/flame/FlameModPage.cpp
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
- * Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* 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/ui/pages/modplatform/flame/FlameModPage.h b/launcher/ui/pages/modplatform/flame/FlameModPage.h
index 86e1a17b..445d0368 100644
--- a/launcher/ui/pages/modplatform/flame/FlameModPage.h
+++ b/launcher/ui/pages/modplatform/flame/FlameModPage.h
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
- * Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* 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/ui/pages/modplatform/flame/FlameModel.cpp b/launcher/ui/pages/modplatform/flame/FlameModel.cpp
index f97536e8..b9804681 100644
--- a/launcher/ui/pages/modplatform/flame/FlameModel.cpp
+++ b/launcher/ui/pages/modplatform/flame/FlameModel.cpp
@@ -57,6 +57,17 @@ QVariant ListModel::data(const QModelIndex& index, int role) const
return QVariant();
}
+bool ListModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ int pos = index.row();
+ if (pos >= modpacks.size() || pos < 0 || !index.isValid())
+ return false;
+
+ modpacks[pos] = value.value<Flame::IndexedPack>();
+
+ return true;
+}
+
void ListModel::logoLoaded(QString logo, QIcon out)
{
m_loadingLogos.removeAll(logo);
@@ -210,6 +221,11 @@ void Flame::ListModel::searchRequestFinished()
nextSearchOffset += 25;
searchState = CanPossiblyFetchMore;
}
+
+ // When you have a Qt build with assertions turned on, proceeding here will abort the application
+ if (newList.size() == 0)
+ return;
+
beginInsertRows(QModelIndex(), modpacks.size(), modpacks.size() + newList.size() - 1);
modpacks.append(newList);
endInsertRows();
diff --git a/launcher/ui/pages/modplatform/flame/FlameModel.h b/launcher/ui/pages/modplatform/flame/FlameModel.h
index 536f6add..cab666cc 100644
--- a/launcher/ui/pages/modplatform/flame/FlameModel.h
+++ b/launcher/ui/pages/modplatform/flame/FlameModel.h
@@ -34,6 +34,7 @@ public:
int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
+ bool setData(const QModelIndex &index, const QVariant &value, int role) override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
bool canFetchMore(const QModelIndex & parent) const override;
void fetchMore(const QModelIndex & parent) override;
diff --git a/launcher/ui/pages/modplatform/flame/FlamePage.cpp b/launcher/ui/pages/modplatform/flame/FlamePage.cpp
index b65ace6b..7d2ba2e2 100644
--- a/launcher/ui/pages/modplatform/flame/FlamePage.cpp
+++ b/launcher/ui/pages/modplatform/flame/FlamePage.cpp
@@ -107,18 +107,18 @@ void FlamePage::triggerSearch()
listModel->searchWithTerm(ui->searchEdit->text(), ui->sortByBox->currentIndex());
}
-void FlamePage::onSelectionChanged(QModelIndex first, QModelIndex second)
+void FlamePage::onSelectionChanged(QModelIndex curr, QModelIndex prev)
{
ui->versionSelectionBox->clear();
- if (!first.isValid()) {
+ if (!curr.isValid()) {
if (isOpened) {
dialog->setSuggestedPack();
}
return;
}
- current = listModel->data(first, Qt::UserRole).value<Flame::IndexedPack>();
+ current = listModel->data(curr, Qt::UserRole).value<Flame::IndexedPack>();
if (current.versionsLoaded == false) {
qDebug() << "Loading flame modpack versions";
@@ -127,7 +127,7 @@ void FlamePage::onSelectionChanged(QModelIndex first, QModelIndex second)
int addonId = current.addonId;
netJob->addNetAction(Net::Download::makeByteArray(QString("https://api.curseforge.com/v1/mods/%1/files").arg(addonId), response));
- QObject::connect(netJob, &NetJob::succeeded, this, [this, response, addonId] {
+ QObject::connect(netJob, &NetJob::succeeded, this, [this, response, addonId, curr] {
if (addonId != current.addonId) {
return; // wrong request
}
@@ -151,6 +151,16 @@ void FlamePage::onSelectionChanged(QModelIndex first, QModelIndex second)
ui->versionSelectionBox->addItem(version.version, QVariant(version.downloadUrl));
}
+ QVariant current_updated;
+ current_updated.setValue(current);
+
+ if (!listModel->setData(curr, current_updated, Qt::UserRole))
+ qWarning() << "Failed to cache versions for the current pack!";
+
+ // TODO: Check whether it's a connection issue or the project disabled 3rd-party distribution.
+ if (current.versionsLoaded && ui->versionSelectionBox->count() < 1) {
+ ui->versionSelectionBox->addItem(tr("No version is available!"), -1);
+ }
suggestCurrent();
});
QObject::connect(netJob, &NetJob::finished, this, [response, netJob] {
@@ -166,6 +176,11 @@ void FlamePage::onSelectionChanged(QModelIndex first, QModelIndex second)
suggestCurrent();
}
+ // TODO: Check whether it's a connection issue or the project disabled 3rd-party distribution.
+ if (current.versionsLoaded && ui->versionSelectionBox->count() < 1) {
+ ui->versionSelectionBox->addItem(tr("No version is available!"), -1);
+ }
+
updateUi();
}
@@ -175,7 +190,7 @@ void FlamePage::suggestCurrent()
return;
}
- if (selectedVersion.isEmpty()) {
+ if (selectedVersion.isEmpty() || selectedVersion == "-1") {
dialog->setSuggestedPack();
return;
}
diff --git a/launcher/ui/pages/modplatform/flame/FlamePage.ui b/launcher/ui/pages/modplatform/flame/FlamePage.ui
index 9fab9773..aab16421 100644
--- a/launcher/ui/pages/modplatform/flame/FlamePage.ui
+++ b/launcher/ui/pages/modplatform/flame/FlamePage.ui
@@ -19,7 +19,7 @@
</font>
</property>
<property name="text">
- <string>Note: CurseForge's API is very unreliable. CurseForge and some mod authors have disallowed downloading mods in third-party applications like PolyMC. As such, you may need to manually download some mods to be able to install a modpack.</string>
+ <string>Note: CurseForge allows creators to block access to third-party tools like PolyMC. As such, you may need to manually download some mods to be able to install a modpack.</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
diff --git a/launcher/ui/pages/modplatform/legacy_ftb/ListModel.cpp b/launcher/ui/pages/modplatform/legacy_ftb/ListModel.cpp
index 06e9db4f..2d135e59 100644
--- a/launcher/ui/pages/modplatform/legacy_ftb/ListModel.cpp
+++ b/launcher/ui/pages/modplatform/legacy_ftb/ListModel.cpp
@@ -46,8 +46,6 @@
#include <BuildConfig.h>
-#include <net/NetJob.h>
-
namespace LegacyFTB {
FilterModel::FilterModel(QObject *parent) : QSortFilterProxyModel(parent)
@@ -170,7 +168,7 @@ QVariant ListModel::data(const QModelIndex &index, int role) const
((ListModel *)this)->requestLogo(pack.logo);
return icon;
}
- else if(role == Qt::TextColorRole)
+ else if(role == Qt::ForegroundRole)
{
if(pack.broken)
{
diff --git a/launcher/ui/pages/modplatform/legacy_ftb/Page.cpp b/launcher/ui/pages/modplatform/legacy_ftb/Page.cpp
index 7667d169..6ffbd312 100644
--- a/launcher/ui/pages/modplatform/legacy_ftb/Page.cpp
+++ b/launcher/ui/pages/modplatform/legacy_ftb/Page.cpp
@@ -2,6 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* 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
@@ -151,7 +152,7 @@ void Page::openedImpl()
ftbFetchTask->fetch();
ftbPrivatePacks->load();
- ftbFetchTask->fetchPrivate(ftbPrivatePacks->getCurrentPackCodes().toList());
+ ftbFetchTask->fetchPrivate(ftbPrivatePacks->getCurrentPackCodes().values());
initialized = true;
}
suggestCurrent();
diff --git a/launcher/ui/pages/modplatform/legacy_ftb/Page.ui b/launcher/ui/pages/modplatform/legacy_ftb/Page.ui
index 15e5d432..f4231d8d 100644
--- a/launcher/ui/pages/modplatform/legacy_ftb/Page.ui
+++ b/launcher/ui/pages/modplatform/legacy_ftb/Page.ui
@@ -25,7 +25,7 @@
<widget class="QTreeView" name="publicPackList">
<property name="maximumSize">
<size>
- <width>250</width>
+ <width>16777215</width>
<height>16777215</height>
</size>
</property>
@@ -51,7 +51,7 @@
<widget class="QTreeView" name="thirdPartyPackList">
<property name="maximumSize">
<size>
- <width>250</width>
+ <width>16777215</width>
<height>16777215</height>
</size>
</property>
@@ -71,7 +71,7 @@
<widget class="QTreeView" name="privatePackList">
<property name="maximumSize">
<size>
- <width>250</width>
+ <width>16777215</width>
<height>16777215</height>
</size>
</property>
diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.cpp
index 0b81ea93..5fa00b9b 100644
--- a/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.cpp
+++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.cpp
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
- * Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* 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/ui/pages/modplatform/modrinth/ModrinthModPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.h
index c39acaa0..94985f63 100644
--- a/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.h
+++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.h
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
- * Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* 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/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp
index 07d1687c..3633d575 100644
--- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp
+++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp
@@ -87,6 +87,7 @@ auto ModpackListModel::data(const QModelIndex& index, int role) const -> QVarian
} else if (role == Qt::DecorationRole) {
if (m_logoMap.contains(pack.iconName)) {
auto icon = m_logoMap.value(pack.iconName);
+ // FIXME: This doesn't really belong here, but Qt doesn't offer a good way right now ;(
auto icon_scaled = QIcon(icon.pixmap(48, 48).scaledToWidth(48));
return icon_scaled;
@@ -103,6 +104,17 @@ auto ModpackListModel::data(const QModelIndex& index, int role) const -> QVarian
return {};
}
+bool ModpackListModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ int pos = index.row();
+ if (pos >= modpacks.size() || pos < 0 || !index.isValid())
+ return false;
+
+ modpacks[pos] = value.value<Modrinth::Modpack>();
+
+ return true;
+}
+
void ModpackListModel::performPaginatedSearch()
{
// TODO: Move to standalone API
@@ -160,15 +172,15 @@ static auto sortFromIndex(int index) -> QString
{
switch(index){
default:
- case 1:
+ case 0:
return "relevance";
- case 2:
+ case 1:
return "downloads";
- case 3:
+ case 2:
return "follows";
- case 4:
+ case 3:
return "newest";
- case 5:
+ case 4:
return "updated";
}
@@ -278,6 +290,10 @@ void ModpackListModel::searchRequestFinished(QJsonDocument& doc_all)
searchState = CanPossiblyFetchMore;
}
+ // When you have a Qt build with assertions turned on, proceeding here will abort the application
+ if (newList.size() == 0)
+ return;
+
beginInsertRows(QModelIndex(), modpacks.size(), modpacks.size() + newList.size() - 1);
modpacks.append(newList);
endInsertRows();
diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h
index 1b4d8da4..6f33e11e 100644
--- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h
+++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h
@@ -39,7 +39,6 @@
#include "modplatform/modrinth/ModrinthPackManifest.h"
#include "ui/pages/modplatform/modrinth/ModrinthPage.h"
-#include "net/NetJob.h"
class ModPage;
class Version;
@@ -64,6 +63,7 @@ class ModpackListModel : public QAbstractListModel {
/* Retrieve information from the model at a given index with the given role */
auto data(const QModelIndex& index, int role) const -> QVariant override;
+ bool setData(const QModelIndex &index, const QVariant &value, int role) override;
inline void setActiveJob(NetJob::Ptr ptr) { jobPtr = ptr; }
diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp
index d8500674..df29c0c3 100644
--- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp
+++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp
@@ -101,18 +101,18 @@ bool ModrinthPage::eventFilter(QObject* watched, QEvent* event)
return QObject::eventFilter(watched, event);
}
-void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second)
+void ModrinthPage::onSelectionChanged(QModelIndex curr, QModelIndex prev)
{
ui->versionSelectionBox->clear();
- if (!first.isValid()) {
+ if (!curr.isValid()) {
if (isOpened) {
dialog->setSuggestedPack();
}
return;
}
- current = m_model->data(first, Qt::UserRole).value<Modrinth::Modpack>();
+ current = m_model->data(curr, Qt::UserRole).value<Modrinth::Modpack>();
auto name = current.name;
if (!current.extraInfoLoaded) {
@@ -125,7 +125,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second)
netJob->addNetAction(Net::Download::makeByteArray(QString("%1/project/%2").arg(BuildConfig.MODRINTH_PROD_URL, id), response));
- QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id] {
+ QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id, curr] {
if (id != current.id) {
return; // wrong request?
}
@@ -149,6 +149,13 @@ void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second)
}
updateUI();
+
+ QVariant current_updated;
+ current_updated.setValue(current);
+
+ if (!m_model->setData(curr, current_updated, Qt::UserRole))
+ qWarning() << "Failed to cache extra info for the current pack!";
+
suggestCurrent();
});
QObject::connect(netJob, &NetJob::finished, this, [response, netJob] {
@@ -170,7 +177,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second)
netJob->addNetAction(
Net::Download::makeByteArray(QString("%1/project/%2/version").arg(BuildConfig.MODRINTH_PROD_URL, id), response));
- QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id] {
+ QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id, curr] {
if (id != current.id) {
return; // wrong request?
}
@@ -192,9 +199,18 @@ void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second)
}
for (auto version : current.versions) {
- ui->versionSelectionBox->addItem(version.version, QVariant(version.id));
+ if (!version.name.contains(version.version))
+ ui->versionSelectionBox->addItem(QString("%1 — %2").arg(version.name, version.version), QVariant(version.id));
+ else
+ ui->versionSelectionBox->addItem(version.name, QVariant(version.id));
}
+ QVariant current_updated;
+ current_updated.setValue(current);
+
+ if (!m_model->setData(curr, current_updated, Qt::UserRole))
+ qWarning() << "Failed to cache versions for the current pack!";
+
suggestCurrent();
});
QObject::connect(netJob, &NetJob::finished, this, [response, netJob] {
@@ -205,7 +221,10 @@ void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second)
} else {
for (auto version : current.versions) {
- ui->versionSelectionBox->addItem(QString("%1 - %2").arg(version.name, version.version), QVariant(version.id));
+ if (!version.name.contains(version.version))
+ ui->versionSelectionBox->addItem(QString("%1 - %2").arg(version.name, version.version), QVariant(version.id));
+ else
+ ui->versionSelectionBox->addItem(version.name, QVariant(version.id));
}
suggestCurrent();
@@ -224,7 +243,7 @@ void ModrinthPage::updateUI()
// TODO: Implement multiple authors with links
text += "<br>" + tr(" by ") + QString("<a href=%1>%2</a>").arg(std::get<1>(current.author).toString(), std::get<0>(current.author));
- if(current.extraInfoLoaded) {
+ if (current.extraInfoLoaded) {
if (!current.extra.donate.isEmpty()) {
text += "<br><br>" + tr("Donate information: ");
auto donateToStr = [](Modrinth::DonationData& donate) -> QString {
diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui
index ae9556ed..6a34701d 100644
--- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui
+++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui
@@ -63,9 +63,6 @@
<height>48</height>
</size>
</property>
- <property name="uniformItemSizes">
- <bool>true</bool>
- </property>
</widget>
</item>
<item>
diff --git a/launcher/ui/pages/modplatform/technic/TechnicModel.cpp b/launcher/ui/pages/modplatform/technic/TechnicModel.cpp
index 9c9d1e75..742f4f2a 100644
--- a/launcher/ui/pages/modplatform/technic/TechnicModel.cpp
+++ b/launcher/ui/pages/modplatform/technic/TechnicModel.cpp
@@ -217,6 +217,11 @@ void Technic::ListModel::searchRequestFinished()
return;
}
searchState = Finished;
+
+ // When you have a Qt build with assertions turned on, proceeding here will abort the application
+ if (newList.size() == 0)
+ return;
+
beginInsertRows(QModelIndex(), modpacks.size(), modpacks.size() + newList.size() - 1);
modpacks.append(newList);
endInsertRows();
diff --git a/launcher/ui/widgets/CustomCommands.cpp b/launcher/ui/widgets/CustomCommands.cpp
index 5a718b54..5ab90395 100644
--- a/launcher/ui/widgets/CustomCommands.cpp
+++ b/launcher/ui/widgets/CustomCommands.cpp
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
- * Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* 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/ui/widgets/CustomCommands.h b/launcher/ui/widgets/CustomCommands.h
index 4a7a17ef..ed10ba95 100644
--- a/launcher/ui/widgets/CustomCommands.h
+++ b/launcher/ui/widgets/CustomCommands.h
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
- * Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* 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/ui/widgets/JavaSettingsWidget.cpp b/launcher/ui/widgets/JavaSettingsWidget.cpp
index 340518b1..f0765909 100644
--- a/launcher/ui/widgets/JavaSettingsWidget.cpp
+++ b/launcher/ui/widgets/JavaSettingsWidget.cpp
@@ -11,6 +11,7 @@
#include <sys.h>
+#include "JavaCommon.h"
#include "java/JavaInstall.h"
#include "java/JavaUtils.h"
#include "FileSystem.h"
@@ -133,6 +134,10 @@ void JavaSettingsWidget::initialize()
void JavaSettingsWidget::refresh()
{
+ if (JavaUtils::getJavaCheckPath().isEmpty()) {
+ JavaCommon::javaCheckNotFound(this);
+ return;
+ }
m_versionWidget->loadList();
}
diff --git a/launcher/ui/widgets/LabeledToolButton.cpp b/launcher/ui/widgets/LabeledToolButton.cpp
index ab2d3278..f52e49c9 100644
--- a/launcher/ui/widgets/LabeledToolButton.cpp
+++ b/launcher/ui/widgets/LabeledToolButton.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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
+ * 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
+ * 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.
+ * 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 <QLabel>
@@ -80,9 +100,7 @@ QSize LabeledToolButton::sizeHint() const
if (popupMode() == MenuButtonPopup)
w += style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &opt, this);
- QSize rawSize = style()->sizeFromContents(QStyle::CT_ToolButton, &opt, QSize(w, h), this);
- QSize sizeHint = rawSize.expandedTo(QApplication::globalStrut());
- return sizeHint;
+ return style()->sizeFromContents(QStyle::CT_ToolButton, &opt, QSize(w, h), this);
}
diff --git a/launcher/ui/widgets/LogView.cpp b/launcher/ui/widgets/LogView.cpp
index 26a2a527..9c46438d 100644
--- a/launcher/ui/widgets/LogView.cpp
+++ b/launcher/ui/widgets/LogView.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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 "LogView.h"
#include <QTextBlock>
#include <QScrollBar>
@@ -102,7 +137,7 @@ void LogView::rowsInserted(const QModelIndex& parent, int first, int last)
{
format.setFont(font.value<QFont>());
}
- auto fg = m_model->data(idx, Qt::TextColorRole);
+ auto fg = m_model->data(idx, Qt::ForegroundRole);
if(fg.isValid())
{
format.setForeground(fg.value<QColor>());
diff --git a/launcher/ui/widgets/PageContainer.cpp b/launcher/ui/widgets/PageContainer.cpp
index 2af7d731..419ccb66 100644
--- a/launcher/ui/widgets/PageContainer.cpp
+++ b/launcher/ui/widgets/PageContainer.cpp
@@ -66,7 +66,7 @@ public:
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
- const QString pattern = filterRegExp().pattern();
+ const QString pattern = filterRegularExpression().pattern();
const auto model = static_cast<PageModel *>(sourceModel());
const auto page = model->pages().at(sourceRow);
if (!page->shouldDisplay())
@@ -171,7 +171,7 @@ void PageContainer::createUI()
headerHLayout->addSpacerItem(new QSpacerItem(rightMargin, 0, QSizePolicy::Fixed, QSizePolicy::Ignored));
headerHLayout->setContentsMargins(0, 6, 0, 0);
- m_pageStack->setMargin(0);
+ m_pageStack->setContentsMargins(0, 0, 0, 0);
m_pageStack->addWidget(new QWidget(this));
m_layout = new QGridLayout;
diff --git a/launcher/ui/widgets/VersionListView.cpp b/launcher/ui/widgets/VersionListView.cpp
index aba0b1a1..0e126c65 100644
--- a/launcher/ui/widgets/VersionListView.cpp
+++ b/launcher/ui/widgets/VersionListView.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * 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 <QHeaderView>
@@ -136,7 +156,7 @@ void VersionListView::paintInfoLabel(QPaintEvent *event) const
auto innerBounds = bounds;
innerBounds.adjust(10, 10, -10, -10);
- QColor background = QApplication::palette().color(QPalette::Foreground);
+ QColor background = QApplication::palette().color(QPalette::WindowText);
QColor foreground = QApplication::palette().color(QPalette::Base);
foreground.setAlpha(190);
painter.setFont(font);
diff --git a/launcher/updater/DownloadTask_test.cpp b/launcher/updater/DownloadTask_test.cpp
deleted file mode 100644
index 8e823a63..00000000
--- a/launcher/updater/DownloadTask_test.cpp
+++ /dev/null
@@ -1,196 +0,0 @@
-#include <QTest>
-#include <QSignalSpy>
-
-#include "TestUtil.h"
-
-#include "updater/GoUpdate.h"
-#include "updater/DownloadTask.h"
-#include "updater/UpdateChecker.h"
-#include <FileSystem.h>
-
-using namespace GoUpdate;
-
-FileSourceList encodeBaseFile(const char *suffix)
-{
- auto base = QDir::currentPath();
- QUrl localFile = QUrl::fromLocalFile(base + suffix);
- QString localUrlString = localFile.toString(QUrl::FullyEncoded);
- auto item = FileSource("http", localUrlString);
- return FileSourceList({item});
-}
-
-Q_DECLARE_METATYPE(VersionFileList)
-Q_DECLARE_METATYPE(Operation)
-
-QDebug operator<<(QDebug dbg, const FileSource &f)
-{
- dbg.nospace() << "FileSource(type=" << f.type << " url=" << f.url
- << " comp=" << f.compressionType << ")";
- return dbg.maybeSpace();
-}
-
-QDebug operator<<(QDebug dbg, const VersionFileEntry &v)
-{
- dbg.nospace() << "VersionFileEntry(path=" << v.path << " mode=" << v.mode
- << " md5=" << v.md5 << " sources=" << v.sources << ")";
- return dbg.maybeSpace();
-}
-
-QDebug operator<<(QDebug dbg, const Operation::Type &t)
-{
- switch (t)
- {
- case Operation::OP_REPLACE:
- dbg << "OP_COPY";
- break;
- case Operation::OP_DELETE:
- dbg << "OP_DELETE";
- break;
- }
- return dbg.maybeSpace();
-}
-
-QDebug operator<<(QDebug dbg, const Operation &u)
-{
- dbg.nospace() << "Operation(type=" << u.type << " file=" << u.source
- << " dest=" << u.destination << " mode=" << u.destinationMode << ")";
- return dbg.maybeSpace();
-}
-
-class DownloadTaskTest : public QObject
-{
- Q_OBJECT
-private
-slots:
- void initTestCase()
- {
- }
- void cleanupTestCase()
- {
- }
-
- void test_parseVersionInfo_data()
- {
- QTest::addColumn<QByteArray>("data");
- QTest::addColumn<VersionFileList>("list");
- QTest::addColumn<QString>("error");
- QTest::addColumn<bool>("ret");
-
- QTest::newRow("one")
- << GET_TEST_FILE("data/1.json")
- << (VersionFileList()
- << VersionFileEntry{"fileOne",
- 493,
- encodeBaseFile("/data/fileOneA"),
- "9eb84090956c484e32cb6c08455a667b"}
- << VersionFileEntry{"fileTwo",
- 644,
- encodeBaseFile("/data/fileTwo"),
- "38f94f54fa3eb72b0ea836538c10b043"}
- << VersionFileEntry{"fileThree",
- 750,
- encodeBaseFile("/data/fileThree"),
- "f12df554b21e320be6471d7154130e70"})
- << QString() << true;
- QTest::newRow("two")
- << GET_TEST_FILE("data/2.json")
- << (VersionFileList()
- << VersionFileEntry{"fileOne",
- 493,
- encodeBaseFile("/data/fileOneB"),
- "42915a71277c9016668cce7b82c6b577"}
- << VersionFileEntry{"fileTwo",
- 644,
- encodeBaseFile("/data/fileTwo"),
- "38f94f54fa3eb72b0ea836538c10b043"})
- << QString() << true;
- }
- void test_parseVersionInfo()
- {
- QFETCH(QByteArray, data);
- QFETCH(VersionFileList, list);
- QFETCH(QString, error);
- QFETCH(bool, ret);
-
- VersionFileList outList;
- QString outError;
- bool outRet = parseVersionInfo(data, outList, outError);
- QCOMPARE(outRet, ret);
- QCOMPARE(outList, list);
- QCOMPARE(outError, error);
- }
-
- void test_processFileLists_data()
- {
- QTest::addColumn<QString>("tempFolder");
- QTest::addColumn<VersionFileList>("currentVersion");
- QTest::addColumn<VersionFileList>("newVersion");
- QTest::addColumn<OperationList>("expectedOperations");
-
- QTemporaryDir tempFolderObj;
- QString tempFolder = tempFolderObj.path();
- // update fileOne, keep fileTwo, remove fileThree
- QTest::newRow("test 1")
- << tempFolder << (VersionFileList()
- << VersionFileEntry{
- "data/fileOne", 493,
- FileSourceList()
- << FileSource(
- "http", "http://host/path/fileOne-1"),
- "9eb84090956c484e32cb6c08455a667b"}
- << VersionFileEntry{
- "data/fileTwo", 644,
- FileSourceList()
- << FileSource(
- "http", "http://host/path/fileTwo-1"),
- "38f94f54fa3eb72b0ea836538c10b043"}
- << VersionFileEntry{
- "data/fileThree", 420,
- FileSourceList()
- << FileSource(
- "http", "http://host/path/fileThree-1"),
- "f12df554b21e320be6471d7154130e70"})
- << (VersionFileList()
- << VersionFileEntry{
- "data/fileOne", 493,
- FileSourceList()
- << FileSource("http",
- "http://host/path/fileOne-2"),
- "42915a71277c9016668cce7b82c6b577"}
- << VersionFileEntry{
- "data/fileTwo", 644,
- FileSourceList()
- << FileSource("http",
- "http://host/path/fileTwo-2"),
- "38f94f54fa3eb72b0ea836538c10b043"})
- << (OperationList()
- << Operation::DeleteOp("data/fileThree")
- << Operation::CopyOp(
- FS::PathCombine(tempFolder,
- QString("data/fileOne").replace("/", "_")),
- "data/fileOne", 493));
- }
- void test_processFileLists()
- {
- QFETCH(QString, tempFolder);
- QFETCH(VersionFileList, currentVersion);
- QFETCH(VersionFileList, newVersion);
- QFETCH(OperationList, expectedOperations);
-
- OperationList operations;
-
- shared_qobject_ptr<QNetworkAccessManager> network = new QNetworkAccessManager();
- processFileLists(currentVersion, newVersion, QDir::currentPath(), tempFolder, new NetJob("Dummy", network), operations);
- qDebug() << (operations == expectedOperations);
- qDebug() << operations;
- qDebug() << expectedOperations;
- QCOMPARE(operations, expectedOperations);
- }
-};
-
-extern "C"
-{
- QTEST_GUILESS_MAIN(DownloadTaskTest)
-}
-
-#include "DownloadTask_test.moc"
diff --git a/launcher/updater/ExternalUpdater.h b/launcher/updater/ExternalUpdater.h
new file mode 100644
index 00000000..a053e081
--- /dev/null
+++ b/launcher/updater/ExternalUpdater.h
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Kenneth Chew <kenneth.c0@protonmail.com>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef LAUNCHER_EXTERNALUPDATER_H
+#define LAUNCHER_EXTERNALUPDATER_H
+
+#include <QObject>
+
+/*!
+ * A base class for an updater that uses an external library.
+ * This class contains basic functions to control the updater.
+ *
+ * To implement the updater on a new platform, create a new class that inherits from this class and
+ * implement the pure virtual functions.
+ *
+ * The initializer of the new class should have the side effect of starting the automatic updater. That is,
+ * once the class is initialized, the program should automatically check for updates if necessary.
+ */
+class ExternalUpdater : public QObject
+{
+ Q_OBJECT
+
+public:
+ /*!
+ * Check for updates manually, showing the user a progress bar and an alert if no updates are found.
+ */
+ virtual void checkForUpdates() = 0;
+
+ /*!
+ * Indicates whether or not to check for updates automatically.
+ */
+ virtual bool getAutomaticallyChecksForUpdates() = 0;
+
+ /*!
+ * Indicates the current automatic update check interval in seconds.
+ */
+ virtual double getUpdateCheckInterval() = 0;
+
+ /*!
+ * Indicates whether or not beta updates should be checked for in addition to regular releases.
+ */
+ virtual bool getBetaAllowed() = 0;
+
+ /*!
+ * Set whether or not to check for updates automatically.
+ */
+ virtual void setAutomaticallyChecksForUpdates(bool check) = 0;
+
+ /*!
+ * Set the current automatic update check interval in seconds.
+ */
+ virtual void setUpdateCheckInterval(double seconds) = 0;
+
+ /*!
+ * Set whether or not beta updates should be checked for in addition to regular releases.
+ */
+ virtual void setBetaAllowed(bool allowed) = 0;
+
+signals:
+ /*!
+ * Emits whenever the user's ability to check for updates changes.
+ *
+ * As per Sparkle documentation, "An update check can be made by the user when an update session isn’t in progress,
+ * or when an update or its progress is being shown to the user. A user cannot check for updates when data (such
+ * as the feed or an update) is still being downloaded automatically in the background.
+ *
+ * This property is suitable to use for menu item validation for seeing if checkForUpdates can be invoked."
+ */
+ void canCheckForUpdatesChanged(bool canCheck);
+};
+
+#endif //LAUNCHER_EXTERNALUPDATER_H
diff --git a/launcher/updater/MacSparkleUpdater.h b/launcher/updater/MacSparkleUpdater.h
new file mode 100644
index 00000000..d50dbd68
--- /dev/null
+++ b/launcher/updater/MacSparkleUpdater.h
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Kenneth Chew <kenneth.c0@protonmail.com>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef LAUNCHER_MACSPARKLEUPDATER_H
+#define LAUNCHER_MACSPARKLEUPDATER_H
+
+#include <QObject>
+#include <QSet>
+#include "ExternalUpdater.h"
+
+/*!
+ * An implementation for the updater on macOS that uses the Sparkle framework.
+ */
+class MacSparkleUpdater : public ExternalUpdater
+{
+ Q_OBJECT
+
+public:
+ /*!
+ * Start the Sparkle updater, which automatically checks for updates if necessary.
+ */
+ MacSparkleUpdater();
+ ~MacSparkleUpdater() override;
+
+ /*!
+ * Check for updates manually, showing the user a progress bar and an alert if no updates are found.
+ */
+ void checkForUpdates() override;
+
+ /*!
+ * Indicates whether or not to check for updates automatically.
+ */
+ bool getAutomaticallyChecksForUpdates() override;
+
+ /*!
+ * Indicates the current automatic update check interval in seconds.
+ */
+ double getUpdateCheckInterval() override;
+
+ /*!
+ * Indicates the set of Sparkle channels the updater is allowed to find new updates from.
+ */
+ QSet<QString> getAllowedChannels();
+
+ /*!
+ * Indicates whether or not beta updates should be checked for in addition to regular releases.
+ */
+ bool getBetaAllowed() override;
+
+ /*!
+ * Set whether or not to check for updates automatically.
+ *
+ * As per Sparkle documentation, "By default, Sparkle asks users on second launch for permission if they want
+ * automatic update checks enabled and sets this property based on their response. If SUEnableAutomaticChecks is
+ * set in the Info.plist, this permission request is not performed however.
+ *
+ * Setting this property will persist in the host bundle’s user defaults. Only set this property if you need
+ * dynamic behavior (e.g. user preferences).
+ *
+ * The update schedule cycle will be reset in a short delay after the property’s new value is set. This is to allow
+ * reverting this property without kicking off a schedule change immediately."
+ */
+ void setAutomaticallyChecksForUpdates(bool check) override;
+
+ /*!
+ * Set the current automatic update check interval in seconds.
+ *
+ * As per Sparkle documentation, "Setting this property will persist in the host bundle’s user defaults. For this
+ * reason, only set this property if you need dynamic behavior (eg user preferences). Otherwise prefer to set
+ * SUScheduledCheckInterval directly in your Info.plist.
+ *
+ * The update schedule cycle will be reset in a short delay after the property’s new value is set. This is to allow
+ * reverting this property without kicking off a schedule change immediately."
+ */
+ void setUpdateCheckInterval(double seconds) override;
+
+ /*!
+ * Clears all allowed Sparkle channels, returning to the default updater channel behavior.
+ */
+ void clearAllowedChannels();
+
+ /*!
+ * Set a single Sparkle channel the updater is allowed to find new updates from.
+ *
+ * Items in the default channel can always be found, regardless of this setting. If an empty string is passed,
+ * return to the default behavior.
+ */
+ void setAllowedChannel(const QString& channel);
+
+ /*!
+ * Set a set of Sparkle channels the updater is allowed to find new updates from.
+ *
+ * Items in the default channel can always be found, regardless of this setting. If an empty set is passed,
+ * return to the default behavior.
+ */
+ void setAllowedChannels(const QSet<QString>& channels);
+
+ /*!
+ * Set whether or not beta updates should be checked for in addition to regular releases.
+ */
+ void setBetaAllowed(bool allowed) override;
+
+private:
+ class Private;
+
+ Private *priv;
+
+ void loadChannelsFromSettings();
+};
+
+#endif //LAUNCHER_MACSPARKLEUPDATER_H
diff --git a/launcher/updater/MacSparkleUpdater.mm b/launcher/updater/MacSparkleUpdater.mm
new file mode 100644
index 00000000..ca6da55a
--- /dev/null
+++ b/launcher/updater/MacSparkleUpdater.mm
@@ -0,0 +1,222 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Kenneth Chew <kenneth.c0@protonmail.com>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+
+#include "MacSparkleUpdater.h"
+
+#include "Application.h"
+
+#include <Cocoa/Cocoa.h>
+#include <Sparkle/Sparkle.h>
+
+@interface UpdaterObserver : NSObject
+
+@property(nonatomic, readonly) SPUUpdater* updater;
+
+/// A callback to run when the state of `canCheckForUpdates` for the `updater` changes.
+@property(nonatomic, copy) void (^callback) (bool);
+
+- (id)initWithUpdater:(SPUUpdater*)updater;
+
+@end
+
+@implementation UpdaterObserver
+
+- (id)initWithUpdater:(SPUUpdater*)updater
+{
+ self = [super init];
+ _updater = updater;
+ [self addObserver:self forKeyPath:@"updater.canCheckForUpdates" options:NSKeyValueObservingOptionNew context:nil];
+
+ return self;
+}
+
+- (void)observeValueForKeyPath:(NSString *)keyPath
+ ofObject:(id)object
+ change:(NSDictionary<NSKeyValueChangeKey, id> *)change
+ context:(void *)context
+{
+ if ([keyPath isEqualToString:@"updater.canCheckForUpdates"])
+ {
+ bool canCheck = [change[NSKeyValueChangeNewKey] boolValue];
+ self.callback(canCheck);
+ }
+}
+
+@end
+
+
+@interface UpdaterDelegate : NSObject <SPUUpdaterDelegate>
+
+@property(nonatomic, copy) NSSet<NSString *> *allowedChannels;
+
+@end
+
+@implementation UpdaterDelegate
+
+- (NSSet<NSString *> *)allowedChannelsForUpdater:(SPUUpdater *)updater
+{
+ return _allowedChannels;
+}
+
+@end
+
+
+class MacSparkleUpdater::Private
+{
+public:
+ SPUStandardUpdaterController *updaterController;
+ UpdaterObserver *updaterObserver;
+ UpdaterDelegate *updaterDelegate;
+ NSAutoreleasePool *autoReleasePool;
+};
+
+MacSparkleUpdater::MacSparkleUpdater()
+{
+ priv = new MacSparkleUpdater::Private();
+
+ // Enable Cocoa's memory management.
+ NSApplicationLoad();
+ priv->autoReleasePool = [[NSAutoreleasePool alloc] init];
+
+ // Delegate is used for setting/getting allowed update channels.
+ priv->updaterDelegate = [[UpdaterDelegate alloc] init];
+
+ // Controller is the interface for actually doing the updates.
+ priv->updaterController = [[SPUStandardUpdaterController alloc] initWithStartingUpdater:true
+ updaterDelegate:priv->updaterDelegate
+ userDriverDelegate:nil];
+
+ priv->updaterObserver = [[UpdaterObserver alloc] initWithUpdater:priv->updaterController.updater];
+ // Use KVO to run a callback that emits a Qt signal when `canCheckForUpdates` changes, so the UI can respond accordingly.
+ priv->updaterObserver.callback = ^(bool canCheck) {
+ emit canCheckForUpdatesChanged(canCheck);
+ };
+
+ loadChannelsFromSettings();
+}
+
+MacSparkleUpdater::~MacSparkleUpdater()
+{
+ [priv->updaterObserver removeObserver:priv->updaterObserver forKeyPath:@"updater.canCheckForUpdates"];
+
+ [priv->updaterController release];
+ [priv->updaterObserver release];
+ [priv->updaterDelegate release];
+ [priv->autoReleasePool release];
+ delete priv;
+}
+
+void MacSparkleUpdater::checkForUpdates()
+{
+ [priv->updaterController checkForUpdates:nil];
+}
+
+bool MacSparkleUpdater::getAutomaticallyChecksForUpdates()
+{
+ return priv->updaterController.updater.automaticallyChecksForUpdates;
+}
+
+double MacSparkleUpdater::getUpdateCheckInterval()
+{
+ return priv->updaterController.updater.updateCheckInterval;
+}
+
+QSet<QString> MacSparkleUpdater::getAllowedChannels()
+{
+ // Convert NSSet<NSString> -> QSet<QString>
+ __block QSet<QString> channels;
+ [priv->updaterDelegate.allowedChannels enumerateObjectsUsingBlock:^(NSString *channel, BOOL *stop)
+ {
+ channels.insert(QString::fromNSString(channel));
+ }];
+ return channels;
+}
+
+bool MacSparkleUpdater::getBetaAllowed()
+{
+ return getAllowedChannels().contains("beta");
+}
+
+void MacSparkleUpdater::setAutomaticallyChecksForUpdates(bool check)
+{
+ priv->updaterController.updater.automaticallyChecksForUpdates = check ? YES : NO; // make clang-tidy happy
+}
+
+void MacSparkleUpdater::setUpdateCheckInterval(double seconds)
+{
+ priv->updaterController.updater.updateCheckInterval = seconds;
+}
+
+void MacSparkleUpdater::clearAllowedChannels()
+{
+ priv->updaterDelegate.allowedChannels = [NSSet set];
+ APPLICATION->settings()->set("UpdateChannel", "");
+}
+
+void MacSparkleUpdater::setAllowedChannel(const QString &channel)
+{
+ if (channel.isEmpty())
+ {
+ clearAllowedChannels();
+ return;
+ }
+
+ NSSet<NSString *> *nsChannels = [NSSet setWithObject:channel.toNSString()];
+ priv->updaterDelegate.allowedChannels = nsChannels;
+ APPLICATION->settings()->set("UpdateChannel", channel);
+}
+
+void MacSparkleUpdater::setAllowedChannels(const QSet<QString> &channels)
+{
+ if (channels.isEmpty())
+ {
+ clearAllowedChannels();
+ return;
+ }
+
+ QString channelsConfig = "";
+ // Convert QSet<QString> -> NSSet<NSString>
+ NSMutableSet<NSString *> *nsChannels = [NSMutableSet setWithCapacity:channels.count()];
+ foreach (const QString channel, channels)
+ {
+ [nsChannels addObject:channel.toNSString()];
+ channelsConfig += channel + " ";
+ }
+
+ priv->updaterDelegate.allowedChannels = nsChannels;
+ APPLICATION->settings()->set("UpdateChannel", channelsConfig.trimmed());
+}
+
+void MacSparkleUpdater::setBetaAllowed(bool allowed)
+{
+ if (allowed)
+ {
+ setAllowedChannel("beta");
+ }
+ else
+ {
+ clearAllowedChannels();
+ }
+}
+
+void MacSparkleUpdater::loadChannelsFromSettings()
+{
+ QStringList channelList = APPLICATION->settings()->get("UpdateChannel").toString().split(" ");
+ QSet<QString> channels(channelList.begin(), channelList.end());
+ setAllowedChannels(channels);
+}
diff --git a/launcher/updater/UpdateChecker.cpp b/launcher/updater/UpdateChecker.cpp
index efdb6093..fa6e5a97 100644
--- a/launcher/updater/UpdateChecker.cpp
+++ b/launcher/updater/UpdateChecker.cpp
@@ -24,7 +24,6 @@
#define CHANLIST_FORMAT 0
#include "BuildConfig.h"
-#include "sys.h"
UpdateChecker::UpdateChecker(shared_qobject_ptr<QNetworkAccessManager> nam, QString channelUrl, QString currentChannel, int currentBuild)
{
@@ -32,6 +31,10 @@ UpdateChecker::UpdateChecker(shared_qobject_ptr<QNetworkAccessManager> nam, QStr
m_channelUrl = channelUrl;
m_currentChannel = currentChannel;
m_currentBuild = currentBuild;
+
+#ifdef Q_OS_MAC
+ m_externalUpdater = new MacSparkleUpdater();
+#endif
}
QList<UpdateChecker::ChannelListEntry> UpdateChecker::getChannelList() const
@@ -44,71 +47,95 @@ bool UpdateChecker::hasChannels() const
return !m_channels.isEmpty();
}
-void UpdateChecker::checkForUpdate(QString updateChannel, bool notifyNoUpdate)
+ExternalUpdater* UpdateChecker::getExternalUpdater()
{
- qDebug() << "Checking for updates.";
-
- // If the channel list hasn't loaded yet, load it and defer checking for updates until
- // later.
- if (!m_chanListLoaded)
- {
- qDebug() << "Channel list isn't loaded yet. Loading channel list and deferring update check.";
- m_checkUpdateWaiting = true;
- m_deferredUpdateChannel = updateChannel;
- updateChanList(notifyNoUpdate);
- return;
- }
+ return m_externalUpdater;
+}
- if (m_updateChecking)
+void UpdateChecker::checkForUpdate(const QString& updateChannel, bool notifyNoUpdate)
+{
+ if (m_externalUpdater)
{
- qDebug() << "Ignoring update check request. Already checking for updates.";
- return;
+ m_externalUpdater->setBetaAllowed(updateChannel == "beta");
+ if (notifyNoUpdate)
+ {
+ qDebug() << "Checking for updates.";
+ m_externalUpdater->checkForUpdates();
+ } else
+ {
+ // The updater library already handles automatic update checks.
+ return;
+ }
}
-
- // Find the desired channel within the channel list and get its repo URL. If if cannot be
- // found, error.
- QString stableUrl;
- m_newRepoUrl = "";
- for (ChannelListEntry entry : m_channels)
+ else
{
- qDebug() << "channelEntry = " << entry.id;
- if(entry.id == "stable") {
- stableUrl = entry.url;
+ qDebug() << "Checking for updates.";
+ // If the channel list hasn't loaded yet, load it and defer checking for updates until
+ // later.
+ if (!m_chanListLoaded)
+ {
+ qDebug() << "Channel list isn't loaded yet. Loading channel list and deferring update check.";
+ m_checkUpdateWaiting = true;
+ m_deferredUpdateChannel = updateChannel;
+ updateChanList(notifyNoUpdate);
+ return;
}
- if (entry.id == updateChannel) {
- m_newRepoUrl = entry.url;
- qDebug() << "is intended update channel: " << entry.id;
+
+ if (m_updateChecking)
+ {
+ qDebug() << "Ignoring update check request. Already checking for updates.";
+ return;
}
- if (entry.id == m_currentChannel) {
- m_currentRepoUrl = entry.url;
- qDebug() << "is current update channel: " << entry.id;
+
+ // Find the desired channel within the channel list and get its repo URL. If if cannot be
+ // found, error.
+ QString stableUrl;
+ m_newRepoUrl = "";
+ for (ChannelListEntry entry: m_channels)
+ {
+ qDebug() << "channelEntry = " << entry.id;
+ if (entry.id == "stable")
+ {
+ stableUrl = entry.url;
+ }
+ if (entry.id == updateChannel)
+ {
+ m_newRepoUrl = entry.url;
+ qDebug() << "is intended update channel: " << entry.id;
+ }
+ if (entry.id == m_currentChannel)
+ {
+ m_currentRepoUrl = entry.url;
+ qDebug() << "is current update channel: " << entry.id;
+ }
}
- }
- qDebug() << "m_repoUrl = " << m_newRepoUrl;
+ qDebug() << "m_repoUrl = " << m_newRepoUrl;
- if (m_newRepoUrl.isEmpty()) {
- qWarning() << "m_repoUrl was empty. defaulting to 'stable': " << stableUrl;
- m_newRepoUrl = stableUrl;
- }
+ if (m_newRepoUrl.isEmpty())
+ {
+ qWarning() << "m_repoUrl was empty. defaulting to 'stable': " << stableUrl;
+ m_newRepoUrl = stableUrl;
+ }
- // If nothing applies, error
- if (m_newRepoUrl.isEmpty())
- {
- qCritical() << "failed to select any update repository for: " << updateChannel;
- emit updateCheckFailed();
- return;
- }
+ // If nothing applies, error
+ if (m_newRepoUrl.isEmpty())
+ {
+ qCritical() << "failed to select any update repository for: " << updateChannel;
+ emit updateCheckFailed();
+ return;
+ }
- m_updateChecking = true;
+ m_updateChecking = true;
- QUrl indexUrl = QUrl(m_newRepoUrl).resolved(QUrl("index.json"));
+ QUrl indexUrl = QUrl(m_newRepoUrl).resolved(QUrl("index.json"));
- indexJob = new NetJob("GoUpdate Repository Index", m_network);
- indexJob->addNetAction(Net::Download::makeByteArray(indexUrl, &indexData));
- connect(indexJob.get(), &NetJob::succeeded, [this, notifyNoUpdate](){ updateCheckFinished(notifyNoUpdate); });
- connect(indexJob.get(), &NetJob::failed, this, &UpdateChecker::updateCheckFailed);
- indexJob->start();
+ indexJob = new NetJob("GoUpdate Repository Index", m_network);
+ indexJob->addNetAction(Net::Download::makeByteArray(indexUrl, &indexData));
+ connect(indexJob.get(), &NetJob::succeeded, [this, notifyNoUpdate]() { updateCheckFinished(notifyNoUpdate); });
+ connect(indexJob.get(), &NetJob::failed, this, &UpdateChecker::updateCheckFailed);
+ indexJob->start();
+ }
}
void UpdateChecker::updateCheckFinished(bool notifyNoUpdate)
diff --git a/launcher/updater/UpdateChecker.h b/launcher/updater/UpdateChecker.h
index 13ee4efd..94e4312b 100644
--- a/launcher/updater/UpdateChecker.h
+++ b/launcher/updater/UpdateChecker.h
@@ -17,6 +17,11 @@
#include "net/NetJob.h"
#include "GoUpdate.h"
+#include "ExternalUpdater.h"
+
+#ifdef Q_OS_MAC
+#include "MacSparkleUpdater.h"
+#endif
class UpdateChecker : public QObject
{
@@ -24,7 +29,7 @@ class UpdateChecker : public QObject
public:
UpdateChecker(shared_qobject_ptr<QNetworkAccessManager> nam, QString channelUrl, QString currentChannel, int currentBuild);
- void checkForUpdate(QString updateChannel, bool notifyNoUpdate);
+ void checkForUpdate(const QString& updateChannel, bool notifyNoUpdate);
/*!
* Causes the update checker to download the channel list from the URL specified in config.h (generated by CMake).
@@ -54,6 +59,11 @@ public:
*/
bool hasChannels() const;
+ /*!
+ * Returns a pointer to an object that controls the external updater, or nullptr if an external updater is not used.
+ */
+ ExternalUpdater *getExternalUpdater();
+
signals:
//! Signal emitted when an update is available. Passes the URL for the repo and the ID and name for the version.
void updateAvailable(GoUpdate::Status status);
@@ -117,5 +127,14 @@ private:
QString m_currentRepoUrl;
QString m_newRepoUrl;
+
+ /*!
+ * If not a nullptr, then the updater here will be used instead of the old updater that uses GoUpdate when
+ * checking for updates.
+ *
+ * As a result, signals from this class won't be emitted, and most of the functions in this class other
+ * than checkForUpdate are not useful. Call functions from this external updater object instead.
+ */
+ ExternalUpdater *m_externalUpdater = nullptr;
};
diff --git a/launcher/updater/UpdateChecker_test.cpp b/launcher/updater/UpdateChecker_test.cpp
deleted file mode 100644
index ec55a40e..00000000
--- a/launcher/updater/UpdateChecker_test.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-#include <QTest>
-#include <QSignalSpy>
-
-#include "TestUtil.h"
-#include "updater/UpdateChecker.h"
-
-Q_DECLARE_METATYPE(UpdateChecker::ChannelListEntry)
-
-bool operator==(const UpdateChecker::ChannelListEntry &e1, const UpdateChecker::ChannelListEntry &e2)
-{
- qDebug() << e1.url << "vs" << e2.url;
- return e1.id == e2.id &&
- e1.name == e2.name &&
- e1.description == e2.description &&
- e1.url == e2.url;
-}
-
-QDebug operator<<(QDebug dbg, const UpdateChecker::ChannelListEntry &c)
-{
- dbg.nospace() << "ChannelListEntry(id=" << c.id << " name=" << c.name << " description=" << c.description << " url=" << c.url << ")";
- return dbg.maybeSpace();
-}
-
-QString findTestDataUrl(const char *file)
-{
- return QUrl::fromLocalFile(QFINDTESTDATA(file)).toString();
-}
-
-class UpdateCheckerTest : public QObject
-{
- Q_OBJECT
-private
-slots:
- void initTestCase()
- {
-
- }
- void cleanupTestCase()
- {
-
- }
-
- void tst_ChannelListParsing_data()
- {
- QTest::addColumn<QString>("channel");
- QTest::addColumn<QString>("channelUrl");
- QTest::addColumn<bool>("hasChannels");
- QTest::addColumn<bool>("valid");
- QTest::addColumn<QList<UpdateChecker::ChannelListEntry> >("result");
-
- QTest::newRow("garbage")
- << QString()
- << findTestDataUrl("data/garbageChannels.json")
- << false
- << false
- << QList<UpdateChecker::ChannelListEntry>();
- QTest::newRow("errors")
- << QString()
- << findTestDataUrl("data/errorChannels.json")
- << false
- << true
- << QList<UpdateChecker::ChannelListEntry>();
- QTest::newRow("no channels")
- << QString()
- << findTestDataUrl("data/noChannels.json")
- << false
- << true
- << QList<UpdateChecker::ChannelListEntry>();
- QTest::newRow("one channel")
- << QString("develop")
- << findTestDataUrl("data/oneChannel.json")
- << true
- << true
- << (QList<UpdateChecker::ChannelListEntry>() << UpdateChecker::ChannelListEntry{"develop", "Develop", "The channel called \"develop\"", "http://example.org/stuff"});
- QTest::newRow("several channels")
- << QString("develop")
- << findTestDataUrl("data/channels.json")
- << true
- << true
- << (QList<UpdateChecker::ChannelListEntry>()
- << UpdateChecker::ChannelListEntry{"develop", "Develop", "The channel called \"develop\"", findTestDataUrl("data")}
- << UpdateChecker::ChannelListEntry{"stable", "Stable", "It's stable at least", findTestDataUrl("data")}
- << UpdateChecker::ChannelListEntry{"42", "The Channel", "This is the channel that is going to answer all of your questions", "https://dent.me/tea"});
- }
- void tst_ChannelListParsing()
- {
-
- QFETCH(QString, channel);
- QFETCH(QString, channelUrl);
- QFETCH(bool, hasChannels);
- QFETCH(bool, valid);
- QFETCH(QList<UpdateChecker::ChannelListEntry>, result);
-
- shared_qobject_ptr<QNetworkAccessManager> nam = new QNetworkAccessManager();
- UpdateChecker checker(nam, channelUrl, channel, 0);
-
- QSignalSpy channelListLoadedSpy(&checker, SIGNAL(channelListLoaded()));
- QVERIFY(channelListLoadedSpy.isValid());
-
- checker.updateChanList(false);
-
- if (valid)
- {
- QVERIFY(channelListLoadedSpy.wait());
- QCOMPARE(channelListLoadedSpy.size(), 1);
- }
- else
- {
- channelListLoadedSpy.wait();
- QCOMPARE(channelListLoadedSpy.size(), 0);
- }
-
- QCOMPARE(checker.hasChannels(), hasChannels);
- QCOMPARE(checker.getChannelList(), result);
- }
-
- void tst_UpdateChecking()
- {
- QString channel = "develop";
- QString channelUrl = findTestDataUrl("data/channels.json");
- int currentBuild = 2;
-
- shared_qobject_ptr<QNetworkAccessManager> nam = new QNetworkAccessManager();
- UpdateChecker checker(nam, channelUrl, channel, currentBuild);
-
- QSignalSpy updateAvailableSpy(&checker, SIGNAL(updateAvailable(GoUpdate::Status)));
- QVERIFY(updateAvailableSpy.isValid());
- QSignalSpy channelListLoadedSpy(&checker, SIGNAL(channelListLoaded()));
- QVERIFY(channelListLoadedSpy.isValid());
-
- checker.updateChanList(false);
- QVERIFY(channelListLoadedSpy.wait());
-
- qDebug() << "CWD:" << QDir::current().absolutePath();
- checker.m_channels[0].url = findTestDataUrl("data/");
- checker.checkForUpdate(channel, false);
-
- QVERIFY(updateAvailableSpy.wait());
-
- auto status = updateAvailableSpy.first().first().value<GoUpdate::Status>();
- QCOMPARE(checker.m_channels[0].url, status.newRepoUrl);
- QCOMPARE(3, status.newVersionId);
- QCOMPARE(currentBuild, status.currentVersionId);
- }
-};
-
-QTEST_GUILESS_MAIN(UpdateCheckerTest)
-
-#include "UpdateChecker_test.moc"
diff --git a/launcher/updater/testdata/1.json b/launcher/updater/testdata/1.json
deleted file mode 100644
index 7af7e52d..00000000
--- a/launcher/updater/testdata/1.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "ApiVersion": 0,
- "Id": 1,
- "Name": "1.0.1",
- "Files": [
- {
- "Path": "fileOne",
- "Sources": [
- {
- "SourceType": "http",
- "Url": "@TEST_DATA_URL@/fileOneA"
- }
- ],
- "Executable": true,
- "Perms": 493,
- "MD5": "9eb84090956c484e32cb6c08455a667b"
- },
- {
- "Path": "fileTwo",
- "Sources": [
- {
- "SourceType": "http",
- "Url": "@TEST_DATA_URL@/fileTwo"
- }
- ],
- "Executable": false,
- "Perms": 644,
- "MD5": "38f94f54fa3eb72b0ea836538c10b043"
- },
- {
- "Path": "fileThree",
- "Sources": [
- {
- "SourceType": "http",
- "Url": "@TEST_DATA_URL@/fileThree"
- }
- ],
- "Executable": false,
- "Perms": "750",
- "MD5": "f12df554b21e320be6471d7154130e70"
- }
- ]
-}
diff --git a/launcher/updater/testdata/2.json b/launcher/updater/testdata/2.json
deleted file mode 100644
index 96d430d5..00000000
--- a/launcher/updater/testdata/2.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "ApiVersion": 0,
- "Id": 1,
- "Name": "1.0.1",
- "Files": [
- {
- "Path": "fileOne",
- "Sources": [
- {
- "SourceType": "http",
- "Url": "@TEST_DATA_URL@/fileOneB"
- }
- ],
- "Executable": true,
- "Perms": 493,
- "MD5": "42915a71277c9016668cce7b82c6b577"
- },
- {
- "Path": "fileTwo",
- "Sources": [
- {
- "SourceType": "http",
- "Url": "@TEST_DATA_URL@/fileTwo"
- }
- ],
- "Executable": false,
- "Perms": 644,
- "MD5": "38f94f54fa3eb72b0ea836538c10b043"
- }
- ]
-}
diff --git a/launcher/updater/testdata/channels.json b/launcher/updater/testdata/channels.json
deleted file mode 100644
index 5c6e42cb..00000000
--- a/launcher/updater/testdata/channels.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "format_version": 0,
- "channels": [
- {
- "id": "develop",
- "name": "Develop",
- "description": "The channel called \"develop\"",
- "url": "@TEST_DATA_URL@"
- },
- {
- "id": "stable",
- "name": "Stable",
- "description": "It's stable at least",
- "url": "@TEST_DATA_URL@"
- },
- {
- "id": "42",
- "name": "The Channel",
- "description": "This is the channel that is going to answer all of your questions",
- "url": "https://dent.me/tea"
- }
- ]
-}
diff --git a/launcher/updater/testdata/errorChannels.json b/launcher/updater/testdata/errorChannels.json
deleted file mode 100644
index a2cb2165..00000000
--- a/launcher/updater/testdata/errorChannels.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "format_version": 0,
- "channels": [
- {
- "id": "",
- "name": "Develop",
- "description": "The channel called \"develop\"",
- "url": "http://example.org/stuff"
- },
- {
- "id": "stable",
- "name": "",
- "description": "It's stable at least",
- "url": "ftp://username@host/path/to/stuff"
- },
- {
- "id": "42",
- "name": "The Channel",
- "description": "This is the channel that is going to answer all of your questions",
- "url": ""
- }
- ]
-}
diff --git a/launcher/updater/testdata/fileOneA b/launcher/updater/testdata/fileOneA
deleted file mode 100644
index f2e41136..00000000
--- a/launcher/updater/testdata/fileOneA
+++ /dev/null
@@ -1 +0,0 @@
-stuff
diff --git a/launcher/updater/testdata/fileOneB b/launcher/updater/testdata/fileOneB
deleted file mode 100644
index f9aba922..00000000
--- a/launcher/updater/testdata/fileOneB
+++ /dev/null
@@ -1,3 +0,0 @@
-stuff
-
-more stuff that came in the new version
diff --git a/launcher/updater/testdata/fileThree b/launcher/updater/testdata/fileThree
deleted file mode 100644
index 6353ff16..00000000
--- a/launcher/updater/testdata/fileThree
+++ /dev/null
@@ -1 +0,0 @@
-this is yet another file
diff --git a/launcher/updater/testdata/fileTwo b/launcher/updater/testdata/fileTwo
deleted file mode 100644
index aad9a93a..00000000
--- a/launcher/updater/testdata/fileTwo
+++ /dev/null
@@ -1 +0,0 @@
-some other stuff
diff --git a/launcher/updater/testdata/garbageChannels.json b/launcher/updater/testdata/garbageChannels.json
deleted file mode 100644
index 34437451..00000000
--- a/launcher/updater/testdata/garbageChannels.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "format_version": 0,
- "channels": [
- {
- "id": "develop",
- "name": "Develop",
- "description": "The channel called \"develop\"",
-aa "url": "http://example.org/stuff"
- },
-a "id": "stable",
- "name": "Stable",
- "description": "It's stable at least",
- "url": "ftp://username@host/path/to/stuff"
- },
- {
- "id": "42"f
- "name": "The Channel",
- "description": "This is the channel that is going to answer all of your questions",
- "url": "https://dent.me/tea"
- }
- ]
-}
diff --git a/launcher/updater/testdata/index.json b/launcher/updater/testdata/index.json
deleted file mode 100644
index 867bdcfb..00000000
--- a/launcher/updater/testdata/index.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "ApiVersion": 0,
- "Versions": [
- { "Id": 0, "Name": "1.0.0" },
- { "Id": 1, "Name": "1.0.1" },
- { "Id": 2, "Name": "1.0.2" },
- { "Id": 3, "Name": "1.0.3" }
- ]
-}
diff --git a/launcher/updater/testdata/noChannels.json b/launcher/updater/testdata/noChannels.json
deleted file mode 100644
index 76988982..00000000
--- a/launcher/updater/testdata/noChannels.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "format_version": 0,
- "channels": [
- ]
-}
diff --git a/launcher/updater/testdata/oneChannel.json b/launcher/updater/testdata/oneChannel.json
deleted file mode 100644
index cc8ed255..00000000
--- a/launcher/updater/testdata/oneChannel.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "format_version": 0,
- "channels": [
- {
- "id": "develop",
- "name": "Develop",
- "description": "The channel called \"develop\"",
- "url": "http://example.org/stuff"
- }
- ]
-}
diff --git a/launcher/updater/testdata/tst_DownloadTask-test_writeInstallScript.xml b/launcher/updater/testdata/tst_DownloadTask-test_writeInstallScript.xml
deleted file mode 100644
index 38ecc809..00000000
--- a/launcher/updater/testdata/tst_DownloadTask-test_writeInstallScript.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<update version="3">
- <install>
- <file>
- <source>sourceOne</source>
- <dest>destOne</dest>
- <mode>0777</mode>
- </file>
- <file>
- <source>PolyMC.exe</source>
- <dest>P/o/l/y/M/C/e/x/e</dest>
- <mode>0644</mode>
- </file>
- </install>
- <uninstall>
- <file>toDelete.abc</file>
- </uninstall>
-</update>