Merge branch 'develop' into icon-indexing
Signed-off-by: Tayou <31988415+TayouVR@users.noreply.github.com>
This commit is contained in:
		| @@ -1,16 +1,17 @@ | ||||
| --- | ||||
| Language:        Cpp | ||||
| BasedOnStyle:  Chromium | ||||
| BasedOnStyle: Chromium | ||||
| IndentWidth: 4 | ||||
| AlignConsecutiveMacros: false | ||||
| AlignConsecutiveAssignments: false | ||||
| AllowShortIfStatementsOnASingleLine: false | ||||
| ColumnLimit: 140 | ||||
| --- | ||||
| Language: Cpp | ||||
| AlignConsecutiveMacros: None | ||||
| AlignConsecutiveAssignments: None | ||||
| BraceWrapping: | ||||
|   AfterFunction:   true | ||||
|   AfterFunction: true | ||||
|   SplitEmptyFunction: false | ||||
|   SplitEmptyRecord: false | ||||
|   SplitEmptyNamespace: false | ||||
| BreakBeforeBraces: Custom | ||||
| BreakConstructorInitializers: BeforeComma | ||||
| ColumnLimit:     140 | ||||
| Cpp11BracedListStyle: false | ||||
|   | ||||
							
								
								
									
										6
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							| @@ -68,7 +68,7 @@ jobs: | ||||
|             qt_ver: 6 | ||||
|             qt_host: windows | ||||
|             qt_arch: '' | ||||
|             qt_version: '6.5.1' | ||||
|             qt_version: '6.5.2' | ||||
|             qt_modules: 'qt5compat qtimageformats' | ||||
|             qt_tools: '' | ||||
|  | ||||
| @@ -80,7 +80,7 @@ jobs: | ||||
|             qt_ver: 6 | ||||
|             qt_host: windows | ||||
|             qt_arch: 'win64_msvc2019_arm64' | ||||
|             qt_version: '6.5.1' | ||||
|             qt_version: '6.5.2' | ||||
|             qt_modules: 'qt5compat qtimageformats' | ||||
|             qt_tools: '' | ||||
|  | ||||
| @@ -90,7 +90,7 @@ jobs: | ||||
|             qt_ver: 6 | ||||
|             qt_host: mac | ||||
|             qt_arch: '' | ||||
|             qt_version: '6.5.0' | ||||
|             qt_version: '6.5.2' | ||||
|             qt_modules: 'qt5compat qtimageformats' | ||||
|             qt_tools: '' | ||||
|  | ||||
|   | ||||
| @@ -318,6 +318,8 @@ add_subdirectory(program_info) | ||||
|  | ||||
| ####################################### Install layout ####################################### | ||||
|  | ||||
| set(Launcher_ENABLE_UPDATER NO) | ||||
|  | ||||
| if(NOT (UNIX AND APPLE)) | ||||
|     # Install "portable.txt" if selected component is "portable" | ||||
|     install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_Portable_File}" DESTINATION "." COMPONENT portable EXCLUDE_FROM_ALL) | ||||
| @@ -342,9 +344,9 @@ if(UNIX AND APPLE) | ||||
|     set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_NAME}") | ||||
|     set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_NAME}") | ||||
|     set(MACOSX_BUNDLE_ICON_FILE ${Launcher_Name}.icns) | ||||
|     set(MACOSX_BUNDLE_COPYRIGHT "© 2022 ${Launcher_Copyright_Mac}") | ||||
|     set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "v55ZWWD6QlPoXGV6VLzOTZxZUggWeE51X8cRQyQh6vA=") | ||||
|     set(MACOSX_SPARKLE_UPDATE_FEED_URL "https://prismlauncher.org/feed/appcast.xml") | ||||
|     set(MACOSX_BUNDLE_COPYRIGHT "© 2022-2023 ${Launcher_Copyright_Mac}") | ||||
|     set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "v55ZWWD6QlPoXGV6VLzOTZxZUggWeE51X8cRQyQh6vA=" CACHE STRING "Public key for Sparkle update feed") | ||||
|     set(MACOSX_SPARKLE_UPDATE_FEED_URL "https://prismlauncher.org/feed/appcast.xml" CACHE STRING "URL for Sparkle update feed") | ||||
|  | ||||
|     set(MACOSX_SPARKLE_DOWNLOAD_URL "https://github.com/sparkle-project/Sparkle/releases/download/2.1.0/Sparkle-2.1.0.tar.xz" CACHE STRING "URL to Sparkle release archive") | ||||
|     set(MACOSX_SPARKLE_SHA256 "bf6ac1caa9f8d321d5784859c88da874f28412f37fb327bc21b7b14c5d61ef94" CACHE STRING "SHA256 checksum for Sparkle release archive") | ||||
| @@ -353,8 +355,12 @@ if(UNIX AND APPLE) | ||||
|     # directories to look for dependencies | ||||
|     set(DIRS ${QT_LIBS_DIR} ${QT_LIBEXECS_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${MACOSX_SPARKLE_DIR}) | ||||
|  | ||||
|     if(NOT MACOSX_SPARKLE_UPDATE_PUBLIC_KEY STREQUAL "" AND NOT MACOSX_SPARKLE_UPDATE_FEED_URL STREQUAL "") | ||||
|         set(Launcher_ENABLE_UPDATER YES) | ||||
|     endif() | ||||
|  | ||||
|     # install as bundle | ||||
|     set(INSTALL_BUNDLE "full") | ||||
|     set(INSTALL_BUNDLE "full" CACHE STRING "Use fixup_bundle to bundle dependencies") | ||||
|  | ||||
|     # Add the icon | ||||
|     install(FILES ${Launcher_Branding_ICNS} DESTINATION ${RESOURCES_DEST_DIR} RENAME ${Launcher_Name}.icns) | ||||
| @@ -367,7 +373,7 @@ elseif(UNIX) | ||||
|     set(JARS_DEST_DIR "share/${Launcher_Name}") | ||||
|  | ||||
|     # install as bundle with no dependencies included | ||||
|     set(INSTALL_BUNDLE "nodeps") | ||||
|     set(INSTALL_BUNDLE "nodeps" CACHE STRING "Use fixup_bundle to bundle dependencies") | ||||
|  | ||||
|     # Set RPATH | ||||
|     SET(Launcher_BINARY_RPATH "$ORIGIN/") | ||||
| @@ -401,7 +407,7 @@ elseif(WIN32) | ||||
|     set(DIRS ${QT_LIBS_DIR} ${QT_LIBEXECS_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) | ||||
|  | ||||
|     # install as bundle | ||||
|     set(INSTALL_BUNDLE "full") | ||||
|     set(INSTALL_BUNDLE "full" CACHE STRING "Use fixup_bundle to bundle dependencies") | ||||
| else() | ||||
|     message(FATAL_ERROR "Platform not supported") | ||||
| endif() | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
|   | ||||
| @@ -36,8 +36,8 @@ | ||||
|  */ | ||||
|  | ||||
| #pragma once | ||||
| #include <QString> | ||||
| #include <QList> | ||||
| #include <QString> | ||||
|  | ||||
| /** | ||||
|  * \brief The Config class holds all the build-time information passed from the build system. | ||||
| @@ -145,7 +145,7 @@ class Config { | ||||
|     QString AUTH_BASE = "https://authserver.mojang.com/"; | ||||
|     QString IMGUR_BASE_URL = "https://api.imgur.com/3/"; | ||||
|     QString FMLLIBS_BASE_URL = "https://files.prismlauncher.org/fmllibs/";  // FIXME: move into CMakeLists | ||||
|     QString TRANSLATIONS_BASE_URL = "https://i18n.prismlauncher.org/";  // FIXME: move into CMakeLists | ||||
|     QString TRANSLATIONS_BASE_URL = "https://i18n.prismlauncher.org/";      // FIXME: move into CMakeLists | ||||
|  | ||||
|     QString MODPACKSCH_API_BASE_URL = "https://api.modpacks.ch/"; | ||||
|  | ||||
| @@ -162,7 +162,7 @@ class Config { | ||||
|  | ||||
|     QString MODRINTH_STAGING_URL = "https://staging-api.modrinth.com/v2"; | ||||
|     QString MODRINTH_PROD_URL = "https://api.modrinth.com/v2"; | ||||
|     QStringList MODRINTH_MRPACK_HOSTS{"cdn.modrinth.com", "github.com", "raw.githubusercontent.com", "gitlab.com"}; | ||||
|     QStringList MODRINTH_MRPACK_HOSTS{ "cdn.modrinth.com", "github.com", "raw.githubusercontent.com", "gitlab.com" }; | ||||
|  | ||||
|     QString FLAME_BASE_URL = "https://api.curseforge.com/v1"; | ||||
|  | ||||
|   | ||||
							
								
								
									
										24
									
								
								flake.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										24
									
								
								flake.lock
									
									
									
										generated
									
									
									
								
							| @@ -21,11 +21,11 @@ | ||||
|         "nixpkgs-lib": "nixpkgs-lib" | ||||
|       }, | ||||
|       "locked": { | ||||
|         "lastModified": 1688466019, | ||||
|         "narHash": "sha256-VeM2akYrBYMsb4W/MmBo1zmaMfgbL4cH3Pu8PGyIwJ0=", | ||||
|         "lastModified": 1690933134, | ||||
|         "narHash": "sha256-ab989mN63fQZBFrkk4Q8bYxQCktuHmBIBqUG1jl6/FQ=", | ||||
|         "owner": "hercules-ci", | ||||
|         "repo": "flake-parts", | ||||
|         "rev": "8e8d955c22df93dbe24f19ea04f47a74adbdc5ec", | ||||
|         "rev": "59cf3f1447cfc75087e7273b04b31e689a8599fb", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
| @@ -91,11 +91,11 @@ | ||||
|     }, | ||||
|     "nixpkgs": { | ||||
|       "locked": { | ||||
|         "lastModified": 1690630721, | ||||
|         "narHash": "sha256-Y04onHyBQT4Erfr2fc82dbJTfXGYrf4V0ysLUYnPOP8=", | ||||
|         "lastModified": 1691218994, | ||||
|         "narHash": "sha256-46GJ5vLf9H+Oh7Jii2gJI9GATJHGbx2iQpon5nUSFPI=", | ||||
|         "owner": "nixos", | ||||
|         "repo": "nixpkgs", | ||||
|         "rev": "d2b52322f35597c62abf56de91b0236746b2a03d", | ||||
|         "rev": "0d2fb29f5071a12d7983319c2c2576be6a130582", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
| @@ -108,11 +108,11 @@ | ||||
|     "nixpkgs-lib": { | ||||
|       "locked": { | ||||
|         "dir": "lib", | ||||
|         "lastModified": 1688049487, | ||||
|         "narHash": "sha256-100g4iaKC9MalDjUW9iN6Jl/OocTDtXdeAj7pEGIRh4=", | ||||
|         "lastModified": 1690881714, | ||||
|         "narHash": "sha256-h/nXluEqdiQHs1oSgkOOWF+j8gcJMWhwnZ9PFabN6q0=", | ||||
|         "owner": "NixOS", | ||||
|         "repo": "nixpkgs", | ||||
|         "rev": "4bc72cae107788bf3f24f30db2e2f685c9298dc9", | ||||
|         "rev": "9e1960bc196baf6881340d53dccb203a951745a2", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
| @@ -138,11 +138,11 @@ | ||||
|         ] | ||||
|       }, | ||||
|       "locked": { | ||||
|         "lastModified": 1690628027, | ||||
|         "narHash": "sha256-OTSbA2hM6VmxyZ/4siYPANffMBzIsKu04GLjXcv8ST0=", | ||||
|         "lastModified": 1691256628, | ||||
|         "narHash": "sha256-M0YXHemR3zbyhM7PvJa5lzGhWVf6kM/fpZ4cWe/VIhI=", | ||||
|         "owner": "cachix", | ||||
|         "repo": "pre-commit-hooks.nix", | ||||
|         "rev": "1e2443dd3f669eb65433b2fc26a3065e05a7dc9c", | ||||
|         "rev": "3139c4d1f7732cab89f06492bdd4677b877e3785", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|   | ||||
| @@ -1,22 +1,22 @@ | ||||
| { | ||||
|   "name": "libdecor", | ||||
|   "buildsystem": "meson", | ||||
|   "config-opts": [ | ||||
|     "-Ddemo=false" | ||||
|   ], | ||||
|   "sources": [ | ||||
|     { | ||||
|       "type": "git", | ||||
|       "url": "https://gitlab.freedesktop.org/libdecor/libdecor.git", | ||||
|       "commit": "73260393a97291c887e1074ab7f318e031be0ac6" | ||||
|     }, | ||||
|     { | ||||
|       "type": "patch", | ||||
|       "path": "patches/weird_libdecor.patch" | ||||
|     } | ||||
|   ], | ||||
|   "cleanup": [ | ||||
|     "/include", | ||||
|     "/lib/pkgconfig" | ||||
|   ] | ||||
|     "name": "libdecor", | ||||
|     "buildsystem": "meson", | ||||
|     "config-opts": [ | ||||
|         "-Ddemo=false" | ||||
|     ], | ||||
|     "sources": [ | ||||
|         { | ||||
|             "type": "git", | ||||
|             "url": "https://gitlab.freedesktop.org/libdecor/libdecor.git", | ||||
|             "commit": "73260393a97291c887e1074ab7f318e031be0ac6" | ||||
|         }, | ||||
|         { | ||||
|             "type": "patch", | ||||
|             "path": "patches/weird_libdecor.patch" | ||||
|         } | ||||
|     ], | ||||
|     "cleanup": [ | ||||
|         "/include", | ||||
|         "/lib/pkgconfig" | ||||
|     ] | ||||
| } | ||||
|   | ||||
| @@ -18,6 +18,8 @@ finish-args: | ||||
|   - --filesystem=xdg-run/app/com.discordapp.Discord:create | ||||
|     # Mod drag&drop | ||||
|   - --filesystem=xdg-download:ro | ||||
|     # FTBApp import | ||||
|   - --filesystem=~/.ftba:ro | ||||
|  | ||||
| cleanup: | ||||
|   - /lib/libGLU* | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -38,12 +38,12 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <QApplication> | ||||
| #include <memory> | ||||
| #include <QDateTime> | ||||
| #include <QDebug> | ||||
| #include <QFlag> | ||||
| #include <QIcon> | ||||
| #include <QDateTime> | ||||
| #include <QUrl> | ||||
| #include <memory> | ||||
|  | ||||
| #include <BaseInstance.h> | ||||
|  | ||||
| @@ -74,25 +74,19 @@ class ThemeManager; | ||||
| class IconTheme; | ||||
|  | ||||
| namespace Meta { | ||||
|     class Index; | ||||
| class Index; | ||||
| } | ||||
|  | ||||
| #if defined(APPLICATION) | ||||
| #undef APPLICATION | ||||
| #endif | ||||
| #define APPLICATION (static_cast<Application *>(QCoreApplication::instance())) | ||||
| #define APPLICATION (static_cast<Application*>(QCoreApplication::instance())) | ||||
|  | ||||
| class Application : public QApplication | ||||
| { | ||||
| class Application : public QApplication { | ||||
|     // friends for the purpose of limiting access to deprecated stuff | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     enum Status { | ||||
|         StartingUp, | ||||
|         Failed, | ||||
|         Succeeded, | ||||
|         Initialized | ||||
|     }; | ||||
|    public: | ||||
|     enum Status { StartingUp, Failed, Succeeded, Initialized }; | ||||
|  | ||||
|     enum Capability { | ||||
|         None = 0, | ||||
| @@ -104,19 +98,15 @@ public: | ||||
|     }; | ||||
|     Q_DECLARE_FLAGS(Capabilities, Capability) | ||||
|  | ||||
| public: | ||||
|     Application(int &argc, char **argv); | ||||
|    public: | ||||
|     Application(int& argc, char** argv); | ||||
|     virtual ~Application(); | ||||
|  | ||||
|     bool event(QEvent* event) override; | ||||
|  | ||||
|     std::shared_ptr<SettingsObject> settings() const { | ||||
|         return m_settings; | ||||
|     } | ||||
|     std::shared_ptr<SettingsObject> settings() const { return m_settings; } | ||||
|  | ||||
|     qint64 timeSinceStart() const { | ||||
|         return startTime.msecsTo(QDateTime::currentDateTime()); | ||||
|     } | ||||
|     qint64 timeSinceStart() const { return startTime.msecsTo(QDateTime::currentDateTime()); } | ||||
|  | ||||
|     QIcon getThemedIcon(const QString& name); | ||||
|  | ||||
| @@ -130,29 +120,17 @@ public: | ||||
|  | ||||
|     std::shared_ptr<JavaInstallList> javalist(); | ||||
|  | ||||
|     std::shared_ptr<InstanceList> instances() const { | ||||
|         return m_instances; | ||||
|     } | ||||
|     std::shared_ptr<InstanceList> instances() const { return m_instances; } | ||||
|  | ||||
|     std::shared_ptr<IconList> icons() const { | ||||
|         return m_icons; | ||||
|     } | ||||
|     std::shared_ptr<IconList> icons() const { return m_icons; } | ||||
|  | ||||
|     MCEditTool *mcedit() const { | ||||
|         return m_mcedit.get(); | ||||
|     } | ||||
|     MCEditTool* mcedit() const { return m_mcedit.get(); } | ||||
|  | ||||
|     shared_qobject_ptr<AccountList> accounts() const { | ||||
|         return m_accounts; | ||||
|     } | ||||
|     shared_qobject_ptr<AccountList> accounts() const { return m_accounts; } | ||||
|  | ||||
|     Status status() const { | ||||
|         return m_status; | ||||
|     } | ||||
|     Status status() const { return m_status; } | ||||
|  | ||||
|     const QMap<QString, std::shared_ptr<BaseProfilerFactory>> &profilers() const { | ||||
|         return m_profilers; | ||||
|     } | ||||
|     const QMap<QString, std::shared_ptr<BaseProfilerFactory>>& profilers() const { return m_profilers; } | ||||
|  | ||||
|     void updateProxySettings(QString proxyTypeStr, QString addr, int port, QString user, QString password); | ||||
|  | ||||
| @@ -177,35 +155,29 @@ public: | ||||
|     QString getUserAgentUncached(); | ||||
|  | ||||
|     /// this is the root of the 'installation'. Used for automatic updates | ||||
|     const QString &root() { | ||||
|         return m_rootPath; | ||||
|     } | ||||
|     const QString& root() { return m_rootPath; } | ||||
|  | ||||
|     bool isPortable() { | ||||
|         return m_portable; | ||||
|     } | ||||
|     bool isPortable() { return m_portable; } | ||||
|  | ||||
|     const Capabilities capabilities() { | ||||
|         return m_capabilities; | ||||
|     } | ||||
|     const Capabilities capabilities() { return m_capabilities; } | ||||
|  | ||||
|     /*! | ||||
|      * Opens a json file using either a system default editor, or, if not empty, the editor | ||||
|      * specified in the settings | ||||
|      */ | ||||
|     bool openJsonEditor(const QString &filename); | ||||
|     bool openJsonEditor(const QString& filename); | ||||
|  | ||||
|     InstanceWindow *showInstanceWindow(InstancePtr instance, QString page = QString()); | ||||
|     MainWindow *showMainWindow(bool minimized = false); | ||||
|     InstanceWindow* showInstanceWindow(InstancePtr instance, QString page = QString()); | ||||
|     MainWindow* showMainWindow(bool minimized = false); | ||||
|  | ||||
|     void updateIsRunning(bool running); | ||||
|     bool updatesAreAllowed(); | ||||
|  | ||||
|     void ShowGlobalSettings(class QWidget * parent, QString open_page = QString()); | ||||
|     void ShowGlobalSettings(class QWidget* parent, QString open_page = QString()); | ||||
|  | ||||
|     int suitableMaxMem(); | ||||
|  | ||||
| signals: | ||||
|    signals: | ||||
|     void updateAllowedChanged(bool status); | ||||
|     void globalSettingsAboutToOpen(); | ||||
|     void globalSettingsClosed(); | ||||
| @@ -215,39 +187,37 @@ signals: | ||||
|     void clickedOnDock(); | ||||
| #endif | ||||
|  | ||||
| public slots: | ||||
|     bool launch( | ||||
|         InstancePtr instance, | ||||
|         bool online = true, | ||||
|         bool demo = false, | ||||
|         BaseProfilerFactory *profiler = nullptr, | ||||
|         MinecraftServerTargetPtr serverToJoin = nullptr, | ||||
|         MinecraftAccountPtr accountToUse = nullptr | ||||
|     ); | ||||
|    public slots: | ||||
|     bool launch(InstancePtr instance, | ||||
|                 bool online = true, | ||||
|                 bool demo = false, | ||||
|                 BaseProfilerFactory* profiler = nullptr, | ||||
|                 MinecraftServerTargetPtr serverToJoin = nullptr, | ||||
|                 MinecraftAccountPtr accountToUse = nullptr); | ||||
|     bool kill(InstancePtr instance); | ||||
|     void closeCurrentWindow(); | ||||
|  | ||||
| private slots: | ||||
|    private slots: | ||||
|     void on_windowClose(); | ||||
|     void messageReceived(const QByteArray & message); | ||||
|     void messageReceived(const QByteArray& message); | ||||
|     void controllerSucceeded(); | ||||
|     void controllerFailed(const QString & error); | ||||
|     void controllerFailed(const QString& error); | ||||
|     void setupWizardFinished(int status); | ||||
|  | ||||
| private: | ||||
|     bool handleDataMigration(const QString & currentData, const QString & oldData, const QString & name, const QString & configFile) const; | ||||
|    private: | ||||
|     bool handleDataMigration(const QString& currentData, const QString& oldData, const QString& name, const QString& configFile) const; | ||||
|     bool createSetupWizard(); | ||||
|     void performMainStartupAction(); | ||||
|  | ||||
|     // sets the fatal error message and m_status to Failed. | ||||
|     void showFatalErrorMessage(const QString & title, const QString & content); | ||||
|     void showFatalErrorMessage(const QString& title, const QString& content); | ||||
|  | ||||
| private: | ||||
|    private: | ||||
|     void addRunningInstance(); | ||||
|     void subRunningInstance(); | ||||
|     bool shouldExitNow() const; | ||||
|  | ||||
| private: | ||||
|    private: | ||||
|     QDateTime startTime; | ||||
|  | ||||
|     shared_qobject_ptr<QNetworkAccessManager> m_network; | ||||
| @@ -286,7 +256,7 @@ private: | ||||
|  | ||||
|     // FIXME: attach to instances instead. | ||||
|     struct InstanceXtras { | ||||
|         InstanceWindow * window = nullptr; | ||||
|         InstanceWindow* window = nullptr; | ||||
|         shared_qobject_ptr<LaunchController> controller; | ||||
|     }; | ||||
|     std::map<QString, InstanceXtras> m_instanceExtras; | ||||
| @@ -297,13 +267,14 @@ private: | ||||
|     bool m_updateRunning = false; | ||||
|  | ||||
|     // main window, if any | ||||
|     MainWindow * m_mainWindow = nullptr; | ||||
|     MainWindow* m_mainWindow = nullptr; | ||||
|  | ||||
|     // peer launcher instance connector - used to implement single instance launcher and signalling | ||||
|     LocalPeer * m_peerInstance = nullptr; | ||||
|     LocalPeer* m_peerInstance = nullptr; | ||||
|  | ||||
|     SetupWizard * m_setupWizard = nullptr; | ||||
| public: | ||||
|     SetupWizard* m_setupWizard = nullptr; | ||||
|  | ||||
|    public: | ||||
|     QString m_instanceIdToLaunch; | ||||
|     QString m_serverToJoin; | ||||
|     QString m_profileToUse; | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
| @@ -39,7 +39,8 @@ | ||||
| #include <QJsonObject> | ||||
| #include "Json.h" | ||||
|  | ||||
| void ApplicationMessage::parse(const QByteArray & input) { | ||||
| void ApplicationMessage::parse(const QByteArray& input) | ||||
| { | ||||
|     auto doc = Json::requireDocument(input, "ApplicationMessage"); | ||||
|     auto root = Json::requireObject(doc, "ApplicationMessage"); | ||||
|  | ||||
| @@ -47,12 +48,13 @@ void ApplicationMessage::parse(const QByteArray & input) { | ||||
|     args.clear(); | ||||
|  | ||||
|     auto parsedArgs = root.value("args").toObject(); | ||||
|     for(auto iter = parsedArgs.constBegin(); iter != parsedArgs.constEnd(); iter++) { | ||||
|     for (auto iter = parsedArgs.constBegin(); iter != parsedArgs.constEnd(); iter++) { | ||||
|         args.insert(iter.key(), iter.value().toString()); | ||||
|     } | ||||
| } | ||||
|  | ||||
| QByteArray ApplicationMessage::serialize() { | ||||
| QByteArray ApplicationMessage::serialize() | ||||
| { | ||||
|     QJsonObject root; | ||||
|     root.insert("command", command); | ||||
|     QJsonObject outArgs; | ||||
|   | ||||
| @@ -1,13 +1,13 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <QString> | ||||
| #include <QHash> | ||||
| #include <QByteArray> | ||||
| #include <QHash> | ||||
| #include <QString> | ||||
|  | ||||
| struct ApplicationMessage { | ||||
|     QString command; | ||||
|     QHash<QString, QString> args; | ||||
|  | ||||
|     QByteArray serialize(); | ||||
|     void parse(const QByteArray & input); | ||||
|     void parse(const QByteArray& input); | ||||
| }; | ||||
|   | ||||
| @@ -18,27 +18,21 @@ | ||||
| #include "BaseInstaller.h" | ||||
| #include "minecraft/MinecraftInstance.h" | ||||
|  | ||||
| BaseInstaller::BaseInstaller() | ||||
| { | ||||
| BaseInstaller::BaseInstaller() {} | ||||
|  | ||||
| } | ||||
|  | ||||
| bool BaseInstaller::isApplied(MinecraftInstance *on) | ||||
| bool BaseInstaller::isApplied(MinecraftInstance* on) | ||||
| { | ||||
|     return QFile::exists(filename(on->instanceRoot())); | ||||
| } | ||||
|  | ||||
| bool BaseInstaller::add(MinecraftInstance *to) | ||||
| bool BaseInstaller::add(MinecraftInstance* to) | ||||
| { | ||||
|     if (!patchesDir(to->instanceRoot()).exists()) | ||||
|     { | ||||
|     if (!patchesDir(to->instanceRoot()).exists()) { | ||||
|         QDir(to->instanceRoot()).mkdir("patches"); | ||||
|     } | ||||
|  | ||||
|     if (isApplied(to)) | ||||
|     { | ||||
|         if (!remove(to)) | ||||
|         { | ||||
|     if (isApplied(to)) { | ||||
|         if (!remove(to)) { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| @@ -46,16 +40,16 @@ bool BaseInstaller::add(MinecraftInstance *to) | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| bool BaseInstaller::remove(MinecraftInstance *from) | ||||
| bool BaseInstaller::remove(MinecraftInstance* from) | ||||
| { | ||||
|     return QFile::remove(filename(from->instanceRoot())); | ||||
| } | ||||
|  | ||||
| QString BaseInstaller::filename(const QString &root) const | ||||
| QString BaseInstaller::filename(const QString& root) const | ||||
| { | ||||
|     return patchesDir(root).absoluteFilePath(id() + ".json"); | ||||
| } | ||||
| QDir BaseInstaller::patchesDir(const QString &root) const | ||||
| QDir BaseInstaller::patchesDir(const QString& root) const | ||||
| { | ||||
|     return QDir(root + "/patches/"); | ||||
| } | ||||
|   | ||||
| @@ -26,20 +26,19 @@ class QObject; | ||||
| class Task; | ||||
| class BaseVersion; | ||||
|  | ||||
| class BaseInstaller | ||||
| { | ||||
| public: | ||||
| class BaseInstaller { | ||||
|    public: | ||||
|     BaseInstaller(); | ||||
|     virtual ~BaseInstaller(){}; | ||||
|     bool isApplied(MinecraftInstance *on); | ||||
|     bool isApplied(MinecraftInstance* on); | ||||
|  | ||||
|     virtual bool add(MinecraftInstance *to); | ||||
|     virtual bool remove(MinecraftInstance *from); | ||||
|     virtual bool add(MinecraftInstance* to); | ||||
|     virtual bool remove(MinecraftInstance* from); | ||||
|  | ||||
|     virtual Task *createInstallTask(MinecraftInstance *instance, BaseVersion::Ptr version, QObject *parent) = 0; | ||||
|     virtual Task* createInstallTask(MinecraftInstance* instance, BaseVersion::Ptr version, QObject* parent) = 0; | ||||
|  | ||||
| protected: | ||||
|    protected: | ||||
|     virtual QString id() const = 0; | ||||
|     QString filename(const QString &root) const; | ||||
|     QDir patchesDir(const QString &root) const; | ||||
|     QString filename(const QString& root) const; | ||||
|     QDir patchesDir(const QString& root) const; | ||||
| }; | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  *  Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org> | ||||
|  * | ||||
| @@ -36,23 +36,22 @@ | ||||
|  | ||||
| #include "BaseInstance.h" | ||||
|  | ||||
| #include <QFileInfo> | ||||
| #include <QDir> | ||||
| #include <QDebug> | ||||
| #include <QRegularExpression> | ||||
| #include <QDir> | ||||
| #include <QFileInfo> | ||||
| #include <QJsonDocument> | ||||
| #include <QJsonObject> | ||||
| #include <QRegularExpression> | ||||
|  | ||||
| #include "settings/INISettingsObject.h" | ||||
| #include "settings/Setting.h" | ||||
| #include "settings/OverrideSetting.h" | ||||
| #include "settings/Setting.h" | ||||
|  | ||||
| #include "FileSystem.h" | ||||
| #include "Commandline.h" | ||||
| #include "BuildConfig.h" | ||||
| #include "Commandline.h" | ||||
| #include "FileSystem.h" | ||||
|  | ||||
| BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir) | ||||
|     : QObject() | ||||
| BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString& rootDir) : QObject() | ||||
| { | ||||
|     m_settings = settings; | ||||
|     m_global_settings = globalSettings; | ||||
| @@ -79,7 +78,7 @@ BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr s | ||||
|         m_settings->registerSetting("InstanceType", ""); | ||||
|  | ||||
|     // Custom Commands | ||||
|     auto commandSetting = m_settings->registerSetting({"OverrideCommands","OverrideLaunchCmd"}, false); | ||||
|     auto commandSetting = m_settings->registerSetting({ "OverrideCommands", "OverrideLaunchCmd" }, false); | ||||
|     m_settings->registerOverride(globalSettings->getSetting("PreLaunchCommand"), commandSetting); | ||||
|     m_settings->registerOverride(globalSettings->getSetting("WrapperCommand"), commandSetting); | ||||
|     m_settings->registerOverride(globalSettings->getSetting("PostExitCommand"), commandSetting); | ||||
| @@ -148,7 +147,11 @@ QString BaseInstance::getManagedPackVersionName() const | ||||
|     return m_settings->get("ManagedPackVersionName").toString(); | ||||
| } | ||||
|  | ||||
| void BaseInstance::setManagedPack(const QString& type, const QString& id, const QString& name, const QString& versionId, const QString& version) | ||||
| void BaseInstance::setManagedPack(const QString& type, | ||||
|                                   const QString& id, | ||||
|                                   const QString& name, | ||||
|                                   const QString& versionId, | ||||
|                                   const QString& version) | ||||
| { | ||||
|     m_settings->set("ManagedPack", true); | ||||
|     m_settings->set("ManagedPackType", type); | ||||
| @@ -173,8 +176,7 @@ int BaseInstance::getConsoleMaxLines() const | ||||
|     auto lineSetting = m_settings->getSetting("ConsoleMaxLines"); | ||||
|     bool conversionOk = false; | ||||
|     int maxLines = lineSetting->get().toInt(&conversionOk); | ||||
|     if(!conversionOk) | ||||
|     { | ||||
|     if (!conversionOk) { | ||||
|         maxLines = lineSetting->defValue().toInt(); | ||||
|         qWarning() << "ConsoleMaxLines has nonsensical value, defaulting to" << maxLines; | ||||
|     } | ||||
| @@ -220,8 +222,7 @@ bool BaseInstance::isLinkedToInstanceId(const QString& id) const | ||||
|  | ||||
| void BaseInstance::iconUpdated(QString key) | ||||
| { | ||||
|     if(iconKey() == key) | ||||
|     { | ||||
|     if (iconKey() == key) { | ||||
|         emit propertiesChanged(this); | ||||
|     } | ||||
| } | ||||
| @@ -235,8 +236,7 @@ void BaseInstance::invalidate() | ||||
| void BaseInstance::changeStatus(BaseInstance::Status newStatus) | ||||
| { | ||||
|     Status status = currentStatus(); | ||||
|     if(status != newStatus) | ||||
|     { | ||||
|     if (status != newStatus) { | ||||
|         m_status = newStatus; | ||||
|         emit statusChanged(status, newStatus); | ||||
|     } | ||||
| @@ -259,23 +259,19 @@ bool BaseInstance::isRunning() const | ||||
|  | ||||
| void BaseInstance::setRunning(bool running) | ||||
| { | ||||
|     if(running == m_isRunning) | ||||
|     if (running == m_isRunning) | ||||
|         return; | ||||
|  | ||||
|     m_isRunning = running; | ||||
|  | ||||
|     if(!m_settings->get("RecordGameTime").toBool()) | ||||
|     { | ||||
|     if (!m_settings->get("RecordGameTime").toBool()) { | ||||
|         emit runningStatusChanged(running); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if(running) | ||||
|     { | ||||
|     if (running) { | ||||
|         m_timeStarted = QDateTime::currentDateTime(); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|     } else { | ||||
|         QDateTime timeEnded = QDateTime::currentDateTime(); | ||||
|  | ||||
|         qint64 current = settings()->get("totalTimePlayed").toLongLong(); | ||||
| @@ -291,8 +287,7 @@ void BaseInstance::setRunning(bool running) | ||||
| int64_t BaseInstance::totalTimePlayed() const | ||||
| { | ||||
|     qint64 current = m_settings->get("totalTimePlayed").toLongLong(); | ||||
|     if(m_isRunning) | ||||
|     { | ||||
|     if (m_isRunning) { | ||||
|         QDateTime timeNow = QDateTime::currentDateTime(); | ||||
|         return current + m_timeStarted.secsTo(timeNow); | ||||
|     } | ||||
| @@ -301,8 +296,7 @@ int64_t BaseInstance::totalTimePlayed() const | ||||
|  | ||||
| int64_t BaseInstance::lastTimePlayed() const | ||||
| { | ||||
|     if(m_isRunning) | ||||
|     { | ||||
|     if (m_isRunning) { | ||||
|         QDateTime timeNow = QDateTime::currentDateTime(); | ||||
|         return m_timeStarted.secsTo(timeNow); | ||||
|     } | ||||
| @@ -349,14 +343,14 @@ qint64 BaseInstance::lastLaunch() const | ||||
|  | ||||
| void BaseInstance::setLastLaunch(qint64 val) | ||||
| { | ||||
|     //FIXME: if no change, do not set. setting involves saving a file. | ||||
|     // FIXME: if no change, do not set. setting involves saving a file. | ||||
|     m_settings->set("lastLaunchTime", val); | ||||
|     emit propertiesChanged(this); | ||||
| } | ||||
|  | ||||
| void BaseInstance::setNotes(QString val) | ||||
| { | ||||
|     //FIXME: if no change, do not set. setting involves saving a file. | ||||
|     // FIXME: if no change, do not set. setting involves saving a file. | ||||
|     m_settings->set("notes", val); | ||||
| } | ||||
|  | ||||
| @@ -367,7 +361,7 @@ QString BaseInstance::notes() const | ||||
|  | ||||
| void BaseInstance::setIconKey(QString val) | ||||
| { | ||||
|     //FIXME: if no change, do not set. setting involves saving a file. | ||||
|     // FIXME: if no change, do not set. setting involves saving a file. | ||||
|     m_settings->set("iconKey", val); | ||||
|     emit propertiesChanged(this); | ||||
| } | ||||
| @@ -379,7 +373,7 @@ QString BaseInstance::iconKey() const | ||||
|  | ||||
| void BaseInstance::setName(QString val) | ||||
| { | ||||
|     //FIXME: if no change, do not set. setting involves saving a file. | ||||
|     // FIXME: if no change, do not set. setting involves saving a file. | ||||
|     m_settings->set("name", val); | ||||
|     emit propertiesChanged(this); | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  *  Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org> | ||||
|  * | ||||
| @@ -37,24 +37,24 @@ | ||||
| #pragma once | ||||
| #include <cassert> | ||||
|  | ||||
| #include <QObject> | ||||
| #include "QObjectPtr.h" | ||||
| #include <QDateTime> | ||||
| #include <QSet> | ||||
| #include <QObject> | ||||
| #include <QProcess> | ||||
| #include <QSet> | ||||
| #include "QObjectPtr.h" | ||||
|  | ||||
| #include "settings/SettingsObject.h" | ||||
|  | ||||
| #include "settings/INIFile.h" | ||||
| #include "BaseVersionList.h" | ||||
| #include "minecraft/auth/MinecraftAccount.h" | ||||
| #include "MessageLevel.h" | ||||
| #include "minecraft/auth/MinecraftAccount.h" | ||||
| #include "pathmatcher/IPathMatcher.h" | ||||
| #include "settings/INIFile.h" | ||||
|  | ||||
| #include "net/Mode.h" | ||||
|  | ||||
| #include "minecraft/launch/MinecraftServerTarget.h" | ||||
| #include "RuntimeContext.h" | ||||
| #include "minecraft/launch/MinecraftServerTarget.h" | ||||
|  | ||||
| class QDir; | ||||
| class Task; | ||||
| @@ -72,23 +72,21 @@ typedef std::shared_ptr<BaseInstance> InstancePtr; | ||||
|  * To create a new instance type, create a new class inheriting from this class | ||||
|  * and implement the pure virtual functions. | ||||
|  */ | ||||
| class BaseInstance : public QObject, public std::enable_shared_from_this<BaseInstance> | ||||
| { | ||||
| class BaseInstance : public QObject, public std::enable_shared_from_this<BaseInstance> { | ||||
|     Q_OBJECT | ||||
| protected: | ||||
|    protected: | ||||
|     /// no-touchy! | ||||
|     BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir); | ||||
|     BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString& rootDir); | ||||
|  | ||||
| public: /* types */ | ||||
|     enum class Status | ||||
|     { | ||||
|    public: /* types */ | ||||
|     enum class Status { | ||||
|         Present, | ||||
|         Gone // either nuked or invalidated | ||||
|         Gone  // either nuked or invalidated | ||||
|     }; | ||||
|  | ||||
| public: | ||||
|    public: | ||||
|     /// virtual destructor to make sure the destruction is COMPLETE | ||||
|     virtual ~BaseInstance() {}; | ||||
|     virtual ~BaseInstance(){}; | ||||
|  | ||||
|     virtual void saveNow() = 0; | ||||
|  | ||||
| @@ -117,10 +115,7 @@ public: | ||||
|     QString instanceRoot() const; | ||||
|  | ||||
|     /// Path to the instance's game root directory. | ||||
|     virtual QString gameRoot() const | ||||
|     { | ||||
|         return instanceRoot(); | ||||
|     } | ||||
|     virtual QString gameRoot() const { return instanceRoot(); } | ||||
|  | ||||
|     /// Path to the instance's mods directory. | ||||
|     virtual QString modsRoot() const = 0; | ||||
| @@ -151,15 +146,12 @@ public: | ||||
|     void copyManagedPack(BaseInstance& other); | ||||
|  | ||||
|     /// guess log level from a line of game log | ||||
|     virtual MessageLevel::Enum guessLevel([[maybe_unused]] const QString &line, MessageLevel::Enum level) | ||||
|     { | ||||
|         return level; | ||||
|     }; | ||||
|     virtual MessageLevel::Enum guessLevel([[maybe_unused]] const QString& line, MessageLevel::Enum level) { return level; }; | ||||
|  | ||||
|     virtual QStringList extraArguments(); | ||||
|  | ||||
|     /// Traits. Normally inside the version, depends on instance implementation. | ||||
|     virtual QSet <QString> traits() const = 0; | ||||
|     virtual QSet<QString> traits() const = 0; | ||||
|  | ||||
|     /** | ||||
|      * Gets the time that the instance was last launched. | ||||
| @@ -189,8 +181,7 @@ public: | ||||
|     virtual Task::Ptr createUpdateTask(Net::Mode mode) = 0; | ||||
|  | ||||
|     /// returns a valid launcher (task container) | ||||
|     virtual shared_qobject_ptr<LaunchTask> createLaunchTask( | ||||
|             AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) = 0; | ||||
|     virtual shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) = 0; | ||||
|  | ||||
|     /// returns the current launch task (if any) | ||||
|     shared_qobject_ptr<LaunchTask> getLaunchTask(); | ||||
| @@ -222,45 +213,30 @@ public: | ||||
|     virtual QString typeName() const = 0; | ||||
|  | ||||
|     void updateRuntimeContext(); | ||||
|     RuntimeContext runtimeContext() const | ||||
|     { | ||||
|         return m_runtimeContext; | ||||
|     } | ||||
|     RuntimeContext runtimeContext() const { return m_runtimeContext; } | ||||
|  | ||||
|     bool hasVersionBroken() const | ||||
|     { | ||||
|         return m_hasBrokenVersion; | ||||
|     } | ||||
|     bool hasVersionBroken() const { return m_hasBrokenVersion; } | ||||
|     void setVersionBroken(bool value) | ||||
|     { | ||||
|         if(m_hasBrokenVersion != value) | ||||
|         { | ||||
|         if (m_hasBrokenVersion != value) { | ||||
|             m_hasBrokenVersion = value; | ||||
|             emit propertiesChanged(this); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     bool hasUpdateAvailable() const | ||||
|     { | ||||
|         return m_hasUpdate; | ||||
|     } | ||||
|     bool hasUpdateAvailable() const { return m_hasUpdate; } | ||||
|     void setUpdateAvailable(bool value) | ||||
|     { | ||||
|         if(m_hasUpdate != value) | ||||
|         { | ||||
|         if (m_hasUpdate != value) { | ||||
|             m_hasUpdate = value; | ||||
|             emit propertiesChanged(this); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     bool hasCrashed() const | ||||
|     { | ||||
|         return m_crashed; | ||||
|     } | ||||
|     bool hasCrashed() const { return m_crashed; } | ||||
|     void setCrashed(bool value) | ||||
|     { | ||||
|         if(m_crashed != value) | ||||
|         { | ||||
|         if (m_crashed != value) { | ||||
|             m_crashed = value; | ||||
|             emit propertiesChanged(this); | ||||
|         } | ||||
| @@ -288,7 +264,7 @@ public: | ||||
|     bool removeLinkedInstanceId(const QString& id); | ||||
|     bool isLinkedToInstanceId(const QString& id) const; | ||||
|  | ||||
| protected: | ||||
|    protected: | ||||
|     void changeStatus(Status newStatus); | ||||
|  | ||||
|     SettingsObjectPtr globalSettings() const { return m_global_settings.lock(); }; | ||||
| @@ -296,11 +272,11 @@ protected: | ||||
|     bool isSpecificSettingsLoaded() const { return m_specific_settings_loaded; } | ||||
|     void setSpecificSettingsLoaded(bool loaded) { m_specific_settings_loaded = loaded; } | ||||
|  | ||||
| signals: | ||||
|    signals: | ||||
|     /*! | ||||
|      * \brief Signal emitted when properties relevant to the instance view change | ||||
|      */ | ||||
|     void propertiesChanged(BaseInstance *inst); | ||||
|     void propertiesChanged(BaseInstance* inst); | ||||
|  | ||||
|     void launchTaskChanged(shared_qobject_ptr<LaunchTask>); | ||||
|  | ||||
| @@ -308,10 +284,10 @@ signals: | ||||
|  | ||||
|     void statusChanged(Status from, Status to); | ||||
|  | ||||
| protected slots: | ||||
|    protected slots: | ||||
|     void iconUpdated(QString key); | ||||
|  | ||||
| protected: /* data */ | ||||
|    protected: /* data */ | ||||
|     QString m_rootDir; | ||||
|     SettingsObjectPtr m_settings; | ||||
|     // InstanceFlags m_flags; | ||||
| @@ -320,7 +296,7 @@ protected: /* data */ | ||||
|     QDateTime m_timeStarted; | ||||
|     RuntimeContext m_runtimeContext; | ||||
|  | ||||
| private: /* data */ | ||||
|    private: /* data */ | ||||
|     Status m_status = Status::Present; | ||||
|     bool m_crashed = false; | ||||
|     bool m_hasUpdate = false; | ||||
| @@ -328,9 +304,8 @@ private: /* data */ | ||||
|  | ||||
|     SettingsObjectWeakPtr m_global_settings; | ||||
|     bool m_specific_settings_loaded = false; | ||||
|  | ||||
| }; | ||||
|  | ||||
| Q_DECLARE_METATYPE(shared_qobject_ptr<BaseInstance>) | ||||
| //Q_DECLARE_METATYPE(BaseInstance::InstanceFlag) | ||||
| //Q_DECLARE_OPERATORS_FOR_FLAGS(BaseInstance::InstanceFlags) | ||||
| // Q_DECLARE_METATYPE(BaseInstance::InstanceFlag) | ||||
| // Q_DECLARE_OPERATORS_FOR_FLAGS(BaseInstance::InstanceFlags) | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
| @@ -36,14 +36,11 @@ | ||||
| #include "BaseVersionList.h" | ||||
| #include "BaseVersion.h" | ||||
|  | ||||
| BaseVersionList::BaseVersionList(QObject *parent) : QAbstractListModel(parent) | ||||
| { | ||||
| } | ||||
| BaseVersionList::BaseVersionList(QObject* parent) : QAbstractListModel(parent) {} | ||||
|  | ||||
| BaseVersion::Ptr BaseVersionList::findVersion(const QString &descriptor) | ||||
| BaseVersion::Ptr BaseVersionList::findVersion(const QString& descriptor) | ||||
| { | ||||
|     for (int i = 0; i < count(); i++) | ||||
|     { | ||||
|     for (int i = 0; i < count(); i++) { | ||||
|         if (at(i)->descriptor() == descriptor) | ||||
|             return at(i); | ||||
|     } | ||||
| @@ -58,7 +55,7 @@ BaseVersion::Ptr BaseVersionList::getRecommended() const | ||||
|         return at(0); | ||||
| } | ||||
|  | ||||
| QVariant BaseVersionList::data(const QModelIndex &index, int role) const | ||||
| QVariant BaseVersionList::data(const QModelIndex& index, int role) const | ||||
| { | ||||
|     if (!index.isValid()) | ||||
|         return QVariant(); | ||||
| @@ -68,37 +65,36 @@ QVariant BaseVersionList::data(const QModelIndex &index, int role) const | ||||
|  | ||||
|     BaseVersion::Ptr version = at(index.row()); | ||||
|  | ||||
|     switch (role) | ||||
|     { | ||||
|     case VersionPointerRole: | ||||
|         return QVariant::fromValue(version); | ||||
|     switch (role) { | ||||
|         case VersionPointerRole: | ||||
|             return QVariant::fromValue(version); | ||||
|  | ||||
|     case VersionRole: | ||||
|         return version->name(); | ||||
|         case VersionRole: | ||||
|             return version->name(); | ||||
|  | ||||
|     case VersionIdRole: | ||||
|         return version->descriptor(); | ||||
|         case VersionIdRole: | ||||
|             return version->descriptor(); | ||||
|  | ||||
|     case TypeRole: | ||||
|         return version->typeString(); | ||||
|         case TypeRole: | ||||
|             return version->typeString(); | ||||
|  | ||||
|     default: | ||||
|         return QVariant(); | ||||
|         default: | ||||
|             return QVariant(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| BaseVersionList::RoleList BaseVersionList::providesRoles() const | ||||
| { | ||||
|     return {VersionPointerRole, VersionRole, VersionIdRole, TypeRole}; | ||||
|     return { VersionPointerRole, VersionRole, VersionIdRole, TypeRole }; | ||||
| } | ||||
|  | ||||
| int BaseVersionList::rowCount(const QModelIndex &parent) const | ||||
| int BaseVersionList::rowCount(const QModelIndex& parent) const | ||||
| { | ||||
|     // Return count | ||||
|     return parent.isValid() ? 0 : count(); | ||||
| } | ||||
|  | ||||
| int BaseVersionList::columnCount(const QModelIndex &parent) const | ||||
| int BaseVersionList::columnCount(const QModelIndex& parent) const | ||||
| { | ||||
|     return parent.isValid() ? 0 : 1; | ||||
| } | ||||
|   | ||||
| @@ -15,13 +15,13 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <QAbstractListModel> | ||||
| #include <QObject> | ||||
| #include <QVariant> | ||||
| #include <QAbstractListModel> | ||||
|  | ||||
| #include "BaseVersion.h" | ||||
| #include "tasks/Task.h" | ||||
| #include "QObjectPtr.h" | ||||
| #include "tasks/Task.h" | ||||
|  | ||||
| /*! | ||||
|  * \brief Class that each instance type's version list derives from. | ||||
| @@ -35,12 +35,10 @@ | ||||
|  * all have a default implementation, but they can be overridden by plugins to | ||||
|  * change the behavior of the list. | ||||
|  */ | ||||
| class BaseVersionList : public QAbstractListModel | ||||
| { | ||||
| class BaseVersionList : public QAbstractListModel { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     enum ModelRoles | ||||
|     { | ||||
|    public: | ||||
|     enum ModelRoles { | ||||
|         VersionPointerRole = Qt::UserRole, | ||||
|         VersionRole, | ||||
|         VersionIdRole, | ||||
| @@ -55,7 +53,7 @@ public: | ||||
|     }; | ||||
|     typedef QList<int> RoleList; | ||||
|  | ||||
|     explicit BaseVersionList(QObject *parent = 0); | ||||
|     explicit BaseVersionList(QObject* parent = 0); | ||||
|  | ||||
|     /*! | ||||
|      * \brief Gets a task that will reload the version list. | ||||
| @@ -66,7 +64,7 @@ public: | ||||
|     virtual Task::Ptr getLoadTask() = 0; | ||||
|  | ||||
|     //! Checks whether or not the list is loaded. If this returns false, the list should be | ||||
|     //loaded. | ||||
|     // loaded. | ||||
|     virtual bool isLoaded() = 0; | ||||
|  | ||||
|     //! Gets the version at the given index. | ||||
| @@ -76,9 +74,9 @@ public: | ||||
|     virtual int count() const = 0; | ||||
|  | ||||
|     //////// List Model Functions //////// | ||||
|     QVariant data(const QModelIndex &index, int role) const override; | ||||
|     int rowCount(const QModelIndex &parent) const override; | ||||
|     int columnCount(const QModelIndex &parent) const override; | ||||
|     QVariant data(const QModelIndex& index, int role) const override; | ||||
|     int rowCount(const QModelIndex& parent) const override; | ||||
|     int columnCount(const QModelIndex& parent) const override; | ||||
|     QHash<int, QByteArray> roleNames() const override; | ||||
|  | ||||
|     //! which roles are provided by this version list? | ||||
| @@ -90,7 +88,7 @@ public: | ||||
|      * \return A const pointer to the version with the given descriptor. NULL if | ||||
|      * one doesn't exist. | ||||
|      */ | ||||
|     virtual BaseVersion::Ptr findVersion(const QString &descriptor); | ||||
|     virtual BaseVersion::Ptr findVersion(const QString& descriptor); | ||||
|  | ||||
|     /*! | ||||
|      * \brief Gets the recommended version from this list | ||||
| @@ -103,8 +101,7 @@ public: | ||||
|      */ | ||||
|     virtual void sortVersions() = 0; | ||||
|  | ||||
| protected | ||||
| slots: | ||||
|    protected slots: | ||||
|     /*! | ||||
|      * Updates this list with the given list of versions. | ||||
|      * This is done by copying each version in the given list and inserting it | ||||
|   | ||||
| @@ -262,8 +262,6 @@ set(MINECRAFT_SOURCES | ||||
|     minecraft/launch/CreateGameFolders.h | ||||
|     minecraft/launch/ModMinecraftJar.cpp | ||||
|     minecraft/launch/ModMinecraftJar.h | ||||
|     minecraft/launch/DirectJavaLaunch.cpp | ||||
|     minecraft/launch/DirectJavaLaunch.h | ||||
|     minecraft/launch/ExtractNatives.cpp | ||||
|     minecraft/launch/ExtractNatives.h | ||||
|     minecraft/launch/LauncherPartLaunch.cpp | ||||
| @@ -501,6 +499,11 @@ set(FTB_SOURCES | ||||
|     modplatform/legacy_ftb/PrivatePackManager.cpp | ||||
|  | ||||
|     modplatform/legacy_ftb/PackHelpers.h | ||||
|  | ||||
|     modplatform/import_ftb/PackInstallTask.h | ||||
|     modplatform/import_ftb/PackInstallTask.cpp | ||||
|     modplatform/import_ftb/PackHelpers.h | ||||
|     modplatform/import_ftb/PackHelpers.cpp | ||||
| ) | ||||
|  | ||||
| set(FLAME_SOURCES | ||||
| @@ -668,7 +671,7 @@ set(LOGIC_SOURCES | ||||
|     ${ATLAUNCHER_SOURCES} | ||||
| ) | ||||
|  | ||||
| if(APPLE) | ||||
| if(APPLE AND Launcher_ENABLE_UPDATER) | ||||
|     set (LOGIC_SOURCES ${LOGIC_SOURCES} ${MAC_UPDATE_SOURCES}) | ||||
| endif() | ||||
|  | ||||
| @@ -874,6 +877,11 @@ SET(LAUNCHER_SOURCES | ||||
|     ui/pages/modplatform/legacy_ftb/ListModel.h | ||||
|     ui/pages/modplatform/legacy_ftb/ListModel.cpp | ||||
|  | ||||
|     ui/pages/modplatform/import_ftb/ImportFTBPage.cpp | ||||
|     ui/pages/modplatform/import_ftb/ImportFTBPage.h | ||||
|     ui/pages/modplatform/import_ftb/ListModel.h | ||||
|     ui/pages/modplatform/import_ftb/ListModel.cpp | ||||
|  | ||||
|     ui/pages/modplatform/flame/FlameModel.cpp | ||||
|     ui/pages/modplatform/flame/FlameModel.h | ||||
|     ui/pages/modplatform/flame/FlamePage.cpp | ||||
| @@ -1048,6 +1056,7 @@ qt_wrap_ui(LAUNCHER_UI | ||||
|     ui/pages/modplatform/ResourcePage.ui | ||||
|     ui/pages/modplatform/flame/FlamePage.ui | ||||
|     ui/pages/modplatform/legacy_ftb/Page.ui | ||||
|     ui/pages/modplatform/import_ftb/ImportFTBPage.ui | ||||
|     ui/pages/modplatform/ImportPage.ui | ||||
|     ui/pages/modplatform/modrinth/ModrinthPage.ui | ||||
|     ui/pages/modplatform/technic/TechnicPage.ui | ||||
| @@ -1143,17 +1152,23 @@ 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) | ||||
|     if(Launcher_ENABLE_UPDATER) | ||||
|       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") | ||||
|       add_compile_definitions(SPARKLE_ENABLED) | ||||
|     endif() | ||||
|  | ||||
|     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}) | ||||
|     if(Launcher_ENABLE_UPDATER) | ||||
|       target_link_libraries(Launcher_logic ${SPARKLE_FRAMEWORK}) | ||||
|     endif() | ||||
| endif() | ||||
|  | ||||
| target_link_libraries(Launcher_logic) | ||||
| @@ -1215,7 +1230,7 @@ if(WIN32) | ||||
|     ) | ||||
| endif() | ||||
|  | ||||
| if (UNIX AND APPLE) | ||||
| if (UNIX AND APPLE AND Launcher_ENABLE_UPDATER) | ||||
|     # 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 | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
| @@ -41,8 +41,7 @@ | ||||
|  * @file libutil/src/cmdutils.cpp | ||||
|  */ | ||||
|  | ||||
| namespace Commandline | ||||
| { | ||||
| namespace Commandline { | ||||
|  | ||||
| // commandline splitter | ||||
| QStringList splitArgs(QString args) | ||||
| @@ -51,19 +50,15 @@ QStringList splitArgs(QString args) | ||||
|     QString current; | ||||
|     bool escape = false; | ||||
|     QChar inquotes; | ||||
|     for (int i = 0; i < args.length(); i++) | ||||
|     { | ||||
|     for (int i = 0; i < args.length(); i++) { | ||||
|         QChar cchar = args.at(i); | ||||
|  | ||||
|         // \ escaped | ||||
|         if (escape) | ||||
|         { | ||||
|         if (escape) { | ||||
|             current += cchar; | ||||
|             escape = false; | ||||
|             // in "quotes" | ||||
|         } | ||||
|         else if (!inquotes.isNull()) | ||||
|         { | ||||
|         } else if (!inquotes.isNull()) { | ||||
|             if (cchar == '\\') | ||||
|                 escape = true; | ||||
|             else if (cchar == inquotes) | ||||
| @@ -71,18 +66,13 @@ QStringList splitArgs(QString args) | ||||
|             else | ||||
|                 current += cchar; | ||||
|             // otherwise | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             if (cchar == ' ') | ||||
|             { | ||||
|                 if (!current.isEmpty()) | ||||
|                 { | ||||
|         } else { | ||||
|             if (cchar == ' ') { | ||||
|                 if (!current.isEmpty()) { | ||||
|                     argv << current; | ||||
|                     current.clear(); | ||||
|                 } | ||||
|             } | ||||
|             else if (cchar == '"' || cchar == '\'') | ||||
|             } else if (cchar == '"' || cchar == '\'') | ||||
|                 inquotes = cchar; | ||||
|             else | ||||
|                 current += cchar; | ||||
| @@ -92,4 +82,4 @@ QStringList splitArgs(QString args) | ||||
|         argv << current; | ||||
|     return argv; | ||||
| } | ||||
| } | ||||
| }  // namespace Commandline | ||||
|   | ||||
| @@ -25,8 +25,7 @@ | ||||
|  * @brief commandline parsing and processing utilities | ||||
|  */ | ||||
|  | ||||
| namespace Commandline | ||||
| { | ||||
| namespace Commandline { | ||||
|  | ||||
| /** | ||||
|  * @brief split a string into argv items like a shell would do | ||||
| @@ -34,4 +33,4 @@ namespace Commandline | ||||
|  * @return a QStringList containing all arguments | ||||
|  */ | ||||
| QStringList splitArgs(QString args); | ||||
| } | ||||
| }  // namespace Commandline | ||||
|   | ||||
| @@ -1,33 +1,21 @@ | ||||
| #pragma once | ||||
|  | ||||
| template <typename T> | ||||
| class DefaultVariable | ||||
| { | ||||
| public: | ||||
|     DefaultVariable(const T & value) | ||||
|     { | ||||
|         defaultValue = value; | ||||
|     } | ||||
|     DefaultVariable<T> & operator =(const T & value) | ||||
| class DefaultVariable { | ||||
|    public: | ||||
|     DefaultVariable(const T& value) { defaultValue = value; } | ||||
|     DefaultVariable<T>& operator=(const T& value) | ||||
|     { | ||||
|         currentValue = value; | ||||
|         is_default = currentValue == defaultValue; | ||||
|         is_explicit = true; | ||||
|         return *this; | ||||
|     } | ||||
|     operator const T &() const | ||||
|     { | ||||
|         return is_default ? defaultValue : currentValue; | ||||
|     } | ||||
|     bool isDefault() const | ||||
|     { | ||||
|         return is_default; | ||||
|     } | ||||
|     bool isExplicit() const | ||||
|     { | ||||
|         return is_explicit; | ||||
|     } | ||||
| private: | ||||
|     operator const T&() const { return is_default ? defaultValue : currentValue; } | ||||
|     bool isDefault() const { return is_default; } | ||||
|     bool isExplicit() const { return is_explicit; } | ||||
|  | ||||
|    private: | ||||
|     T currentValue; | ||||
|     T defaultValue; | ||||
|     bool is_default = true; | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 dada513 <dada513@protonmail.com> | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
| @@ -33,40 +33,37 @@ | ||||
|  *      limitations under the License. | ||||
|  */ | ||||
| #include "DesktopServices.h" | ||||
| #include <QDir> | ||||
| #include <QDesktopServices> | ||||
| #include <QProcess> | ||||
| #include <QDebug> | ||||
| #include <QDesktopServices> | ||||
| #include <QDir> | ||||
| #include <QProcess> | ||||
|  | ||||
| /** | ||||
|  * This shouldn't exist, but until QTBUG-9328 and other unreported bugs are fixed, it needs to be a thing. | ||||
|  */ | ||||
| #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) | ||||
|  | ||||
| #include <unistd.h> | ||||
| #include <errno.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/wait.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| template <typename T> | ||||
| bool IndirectOpen(T callable, qint64 *pid_forked = nullptr) | ||||
| bool IndirectOpen(T callable, qint64* pid_forked = nullptr) | ||||
| { | ||||
|     auto pid = fork(); | ||||
|     if(pid_forked) | ||||
|     { | ||||
|         if(pid > 0) | ||||
|     if (pid_forked) { | ||||
|         if (pid > 0) | ||||
|             *pid_forked = pid; | ||||
|         else | ||||
|             *pid_forked = 0; | ||||
|     } | ||||
|     if(pid == -1) | ||||
|     { | ||||
|     if (pid == -1) { | ||||
|         qWarning() << "IndirectOpen failed to fork: " << errno; | ||||
|         return false; | ||||
|     } | ||||
|     // child - do the stuff | ||||
|     if(pid == 0) | ||||
|     { | ||||
|     if (pid == 0) { | ||||
|         // unset all this garbage so it doesn't get passed to the child process | ||||
|         qunsetenv("LD_PRELOAD"); | ||||
|         qunsetenv("LD_LIBRARY_PATH"); | ||||
| @@ -82,19 +79,14 @@ bool IndirectOpen(T callable, qint64 *pid_forked = nullptr) | ||||
|  | ||||
|         // die. now. do not clean up anything, it would just hang forever. | ||||
|         _exit(status ? 0 : 1); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         //parent - assume it worked. | ||||
|     } else { | ||||
|         // parent - assume it worked. | ||||
|         int status; | ||||
|         while (waitpid(pid, &status, 0)) | ||||
|         { | ||||
|             if(WIFEXITED(status)) | ||||
|             { | ||||
|         while (waitpid(pid, &status, 0)) { | ||||
|             if (WIFEXITED(status)) { | ||||
|                 return WEXITSTATUS(status) == 0; | ||||
|             } | ||||
|             if(WIFSIGNALED(status)) | ||||
|             { | ||||
|             if (WIFSIGNALED(status)) { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| @@ -104,26 +96,19 @@ bool IndirectOpen(T callable, qint64 *pid_forked = nullptr) | ||||
| #endif | ||||
|  | ||||
| namespace DesktopServices { | ||||
| bool openDirectory(const QString &path, bool ensureExists) | ||||
| bool openDirectory(const QString& path, bool ensureExists) | ||||
| { | ||||
|     qDebug() << "Opening directory" << path; | ||||
|     QDir parentPath; | ||||
|     QDir dir(path); | ||||
|     if (ensureExists && !dir.exists()) | ||||
|     { | ||||
|     if (ensureExists && !dir.exists()) { | ||||
|         parentPath.mkpath(dir.absolutePath()); | ||||
|     } | ||||
|     auto f = [&]() | ||||
|     { | ||||
|         return QDesktopServices::openUrl(QUrl::fromLocalFile(dir.absolutePath())); | ||||
|     }; | ||||
|     auto f = [&]() { return QDesktopServices::openUrl(QUrl::fromLocalFile(dir.absolutePath())); }; | ||||
| #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) | ||||
|     if(!isFlatpak()) | ||||
|     { | ||||
|     if (!isSandbox()) { | ||||
|         return IndirectOpen(f); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|     } else { | ||||
|         return f(); | ||||
|     } | ||||
| #else | ||||
| @@ -131,20 +116,14 @@ bool openDirectory(const QString &path, bool ensureExists) | ||||
| #endif | ||||
| } | ||||
|  | ||||
| bool openFile(const QString &path) | ||||
| bool openFile(const QString& path) | ||||
| { | ||||
|     qDebug() << "Opening file" << path; | ||||
|     auto f = [&]() | ||||
|     { | ||||
|         return QDesktopServices::openUrl(QUrl::fromLocalFile(path)); | ||||
|     }; | ||||
|     auto f = [&]() { return QDesktopServices::openUrl(QUrl::fromLocalFile(path)); }; | ||||
| #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) | ||||
|     if(!isFlatpak()) | ||||
|     { | ||||
|     if (!isSandbox()) { | ||||
|         return IndirectOpen(f); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|     } else { | ||||
|         return f(); | ||||
|     } | ||||
| #else | ||||
| @@ -152,41 +131,29 @@ bool openFile(const QString &path) | ||||
| #endif | ||||
| } | ||||
|  | ||||
| bool openFile(const QString &application, const QString &path, const QString &workingDirectory, qint64 *pid) | ||||
| bool openFile(const QString& application, const QString& path, const QString& workingDirectory, qint64* pid) | ||||
| { | ||||
|     qDebug() << "Opening file" << path << "using" << application; | ||||
| #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) | ||||
|     // FIXME: the pid here is fake. So if something depends on it, it will likely misbehave | ||||
|     if(!isFlatpak()) | ||||
|     { | ||||
|         return IndirectOpen([&]() | ||||
|         { | ||||
|             return QProcess::startDetached(application, QStringList() << path, workingDirectory); | ||||
|         }, pid); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|       return QProcess::startDetached(application, QStringList() << path, workingDirectory, pid);   | ||||
|     if (!isSandbox()) { | ||||
|         return IndirectOpen([&]() { return QProcess::startDetached(application, QStringList() << path, workingDirectory); }, pid); | ||||
|     } else { | ||||
|         return QProcess::startDetached(application, QStringList() << path, workingDirectory, pid); | ||||
|     } | ||||
| #else | ||||
|     return QProcess::startDetached(application, QStringList() << path, workingDirectory, pid); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| bool run(const QString &application, const QStringList &args, const QString &workingDirectory, qint64 *pid) | ||||
| bool run(const QString& application, const QStringList& args, const QString& workingDirectory, qint64* pid) | ||||
| { | ||||
|     qDebug() << "Running" << application << "with args" << args.join(' '); | ||||
| #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) | ||||
|     if(!isFlatpak()) | ||||
|     { | ||||
|     // FIXME: the pid here is fake. So if something depends on it, it will likely misbehave | ||||
|     return IndirectOpen([&]() | ||||
|     { | ||||
|         return QProcess::startDetached(application, args, workingDirectory); | ||||
|     }, pid); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|     if (!isSandbox()) { | ||||
|         // FIXME: the pid here is fake. So if something depends on it, it will likely misbehave | ||||
|         return IndirectOpen([&]() { return QProcess::startDetached(application, args, workingDirectory); }, pid); | ||||
|     } else { | ||||
|         return QProcess::startDetached(application, args, workingDirectory, pid); | ||||
|     } | ||||
| #else | ||||
| @@ -194,20 +161,14 @@ bool run(const QString &application, const QStringList &args, const QString &wor | ||||
| #endif | ||||
| } | ||||
|  | ||||
| bool openUrl(const QUrl &url) | ||||
| bool openUrl(const QUrl& url) | ||||
| { | ||||
|     qDebug() << "Opening URL" << url.toString(); | ||||
|     auto f = [&]() | ||||
|     { | ||||
|         return QDesktopServices::openUrl(url); | ||||
|     }; | ||||
|     auto f = [&]() { return QDesktopServices::openUrl(url); }; | ||||
| #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) | ||||
|     if(!isFlatpak()) | ||||
|     { | ||||
|     if (!isSandbox()) { | ||||
|         return IndirectOpen(f); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|     } else { | ||||
|         return f(); | ||||
|     } | ||||
| #else | ||||
| @@ -224,4 +185,18 @@ bool isFlatpak() | ||||
| #endif | ||||
| } | ||||
|  | ||||
| bool isSnap() | ||||
| { | ||||
| #ifdef Q_OS_LINUX | ||||
|     return getenv("SNAP"); | ||||
| #else | ||||
|     return false; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| bool isSandbox() | ||||
| { | ||||
|     return isSnap() || isFlatpak(); | ||||
| } | ||||
|  | ||||
| }  // namespace DesktopServices | ||||
|   | ||||
| @@ -1,38 +1,50 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <QUrl> | ||||
| #include <QString> | ||||
| #include <QUrl> | ||||
|  | ||||
| /** | ||||
|  * This wraps around QDesktopServices and adds workarounds where needed | ||||
|  * Use this instead of QDesktopServices! | ||||
|  */ | ||||
| namespace DesktopServices | ||||
| { | ||||
|     /** | ||||
|      * Open a file in whatever application is applicable | ||||
|      */ | ||||
|     bool openFile(const QString &path); | ||||
| namespace DesktopServices { | ||||
| /** | ||||
|  * Open a file in whatever application is applicable | ||||
|  */ | ||||
| bool openFile(const QString& path); | ||||
|  | ||||
|     /** | ||||
|      * Open a file in the specified application | ||||
|      */ | ||||
|     bool openFile(const QString &application, const QString &path, const QString & workingDirectory = QString(), qint64 *pid = 0); | ||||
| /** | ||||
|  * Open a file in the specified application | ||||
|  */ | ||||
| bool openFile(const QString& application, const QString& path, const QString& workingDirectory = QString(), qint64* pid = 0); | ||||
|  | ||||
|     /** | ||||
|      * Run an application | ||||
|      */ | ||||
|     bool run(const QString &application,const QStringList &args, const QString & workingDirectory = QString(), qint64 *pid = 0); | ||||
| /** | ||||
|  * Run an application | ||||
|  */ | ||||
| bool run(const QString& application, const QStringList& args, const QString& workingDirectory = QString(), qint64* pid = 0); | ||||
|  | ||||
|     /** | ||||
|      * Open a directory | ||||
|      */ | ||||
|     bool openDirectory(const QString &path, bool ensureExists = false); | ||||
| /** | ||||
|  * Open a directory | ||||
|  */ | ||||
| bool openDirectory(const QString& path, bool ensureExists = false); | ||||
|  | ||||
|     /** | ||||
|      * Open the URL, most likely in a browser. Maybe. | ||||
|      */ | ||||
|     bool openUrl(const QUrl &url); | ||||
| /** | ||||
|  * Open the URL, most likely in a browser. Maybe. | ||||
|  */ | ||||
| bool openUrl(const QUrl& url); | ||||
|  | ||||
|     bool isFlatpak(); | ||||
| } | ||||
| /** | ||||
|  * Determine whether the launcher is running in a Flatpak environment | ||||
|  */ | ||||
| bool isFlatpak(); | ||||
|  | ||||
| /** | ||||
|  * Determine whether the launcher is running in a Snap environment | ||||
|  */ | ||||
| bool isSnap(); | ||||
|  | ||||
| /** | ||||
|  * Determine whether the launcher is running in a sandboxed (Flatpak or Snap) environment | ||||
|  */ | ||||
| bool isSandbox(); | ||||
| }  // namespace DesktopServices | ||||
|   | ||||
| @@ -2,31 +2,18 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <QString> | ||||
| #include <QDebug> | ||||
| #include <QString> | ||||
| #include <exception> | ||||
|  | ||||
| class Exception : public std::exception | ||||
| { | ||||
| public: | ||||
|     Exception(const QString &message) : std::exception(), m_message(message) | ||||
|     { | ||||
|         qCritical() << "Exception:" << message; | ||||
|     } | ||||
|     Exception(const Exception &other) | ||||
|         : std::exception(), m_message(other.cause()) | ||||
|     { | ||||
|     } | ||||
| class Exception : public std::exception { | ||||
|    public: | ||||
|     Exception(const QString& message) : std::exception(), m_message(message) { qCritical() << "Exception:" << message; } | ||||
|     Exception(const Exception& other) : std::exception(), m_message(other.cause()) {} | ||||
|     virtual ~Exception() noexcept {} | ||||
|     const char *what() const noexcept | ||||
|     { | ||||
|         return m_message.toLatin1().constData(); | ||||
|     } | ||||
|     QString cause() const | ||||
|     { | ||||
|         return m_message; | ||||
|     } | ||||
|     const char* what() const noexcept { return m_message.toLatin1().constData(); } | ||||
|     QString cause() const { return m_message; } | ||||
|  | ||||
| private: | ||||
|    private: | ||||
|     QString m_message; | ||||
| }; | ||||
|   | ||||
| @@ -4,31 +4,24 @@ | ||||
| template <typename T> | ||||
| inline void clamp(T& current, T min, T max) | ||||
| { | ||||
|     if (current < min) | ||||
|     { | ||||
|     if (current < min) { | ||||
|         current = min; | ||||
|     } | ||||
|     else if(current > max) | ||||
|     { | ||||
|     } else if (current > max) { | ||||
|         current = max; | ||||
|     } | ||||
| } | ||||
|  | ||||
| // List of numbers from min to max. Next is exponent times bigger than previous. | ||||
|  | ||||
| class ExponentialSeries | ||||
| { | ||||
| public: | ||||
| class ExponentialSeries { | ||||
|    public: | ||||
|     ExponentialSeries(unsigned min, unsigned max, unsigned exponent = 2) | ||||
|     { | ||||
|         m_current = m_min = min; | ||||
|         m_max = max; | ||||
|         m_exponent = exponent; | ||||
|     } | ||||
|     void reset() | ||||
|     { | ||||
|         m_current = m_min; | ||||
|     } | ||||
|     void reset() { m_current = m_min; } | ||||
|     unsigned operator()() | ||||
|     { | ||||
|         unsigned retval = m_current; | ||||
|   | ||||
| @@ -779,7 +779,8 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri | ||||
|     } | ||||
| #if defined(Q_OS_MACOS) | ||||
|     // Create the Application | ||||
|     QDir applicationDirectory = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + "/" + BuildConfig.LAUNCHER_NAME + " Instances/"; | ||||
|     QDir applicationDirectory = | ||||
|         QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + "/" + BuildConfig.LAUNCHER_NAME + " Instances/"; | ||||
|  | ||||
|     if (!applicationDirectory.mkpath(".")) { | ||||
|         qWarning() << "Couldn't create application directory"; | ||||
| @@ -843,7 +844,9 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri | ||||
|                   "    <key>CFBundleIconFile</key>\n" | ||||
|                   "    <string>Icon.icns</string>\n" | ||||
|                   "    <key>CFBundleName</key>\n" | ||||
|                   "    <string>" << name << "</string>\n"  // Name of the application | ||||
|                   "    <string>" | ||||
|                << name | ||||
|                << "</string>\n"  // Name of the application | ||||
|                   "    <key>CFBundlePackageType</key>\n" | ||||
|                   "    <string>APPL</string>\n" | ||||
|                   "    <key>CFBundleShortVersionString</key>\n" | ||||
|   | ||||
| @@ -43,10 +43,10 @@ | ||||
| #include <system_error> | ||||
|  | ||||
| #include <QDir> | ||||
| #include <QPair> | ||||
| #include <QFlags> | ||||
| #include <QLocalServer> | ||||
| #include <QObject> | ||||
| #include <QPair> | ||||
| #include <QThread> | ||||
|  | ||||
| namespace FS { | ||||
| @@ -365,25 +365,24 @@ enum class FilesystemType { | ||||
|  * QMap is ordered | ||||
|  * | ||||
|  */ | ||||
| static const QMap<FilesystemType, QStringList> s_filesystem_type_names = { | ||||
|     {FilesystemType::FAT,        { "FAT" }}, | ||||
|     {FilesystemType::NTFS,       { "NTFS" }}, | ||||
|     {FilesystemType::REFS,       { "REFS" }}, | ||||
|     {FilesystemType::EXT_2_OLD,  { "EXT_2_OLD", "EXT2_OLD" }}, | ||||
|     {FilesystemType::EXT_2_3_4,  { "EXT2/3/4", "EXT_2_3_4", "EXT2", "EXT3", "EXT4" }}, | ||||
|     {FilesystemType::EXT,        { "EXT" }}, | ||||
|     {FilesystemType::XFS,        { "XFS" }}, | ||||
|     {FilesystemType::BTRFS,      { "BTRFS" }}, | ||||
|     {FilesystemType::NFS,        { "NFS" }}, | ||||
|     {FilesystemType::ZFS,        { "ZFS" }}, | ||||
|     {FilesystemType::APFS,       { "APFS" }}, | ||||
|     {FilesystemType::HFS,        { "HFS" }}, | ||||
|     {FilesystemType::HFSPLUS,    { "HFSPLUS" }}, | ||||
|     {FilesystemType::HFSX,       { "HFSX" }}, | ||||
|     {FilesystemType::FUSEBLK,    { "FUSEBLK" }}, | ||||
|     {FilesystemType::F2FS,       { "F2FS" }}, | ||||
|     {FilesystemType::UNKNOWN,    { "UNKNOWN" }} | ||||
| }; | ||||
| static const QMap<FilesystemType, QStringList> s_filesystem_type_names = { { FilesystemType::FAT, { "FAT" } }, | ||||
|                                                                            { FilesystemType::NTFS, { "NTFS" } }, | ||||
|                                                                            { FilesystemType::REFS, { "REFS" } }, | ||||
|                                                                            { FilesystemType::EXT_2_OLD, { "EXT_2_OLD", "EXT2_OLD" } }, | ||||
|                                                                            { FilesystemType::EXT_2_3_4, | ||||
|                                                                              { "EXT2/3/4", "EXT_2_3_4", "EXT2", "EXT3", "EXT4" } }, | ||||
|                                                                            { FilesystemType::EXT, { "EXT" } }, | ||||
|                                                                            { FilesystemType::XFS, { "XFS" } }, | ||||
|                                                                            { FilesystemType::BTRFS, { "BTRFS" } }, | ||||
|                                                                            { FilesystemType::NFS, { "NFS" } }, | ||||
|                                                                            { FilesystemType::ZFS, { "ZFS" } }, | ||||
|                                                                            { FilesystemType::APFS, { "APFS" } }, | ||||
|                                                                            { FilesystemType::HFS, { "HFS" } }, | ||||
|                                                                            { FilesystemType::HFSPLUS, { "HFSPLUS" } }, | ||||
|                                                                            { FilesystemType::HFSX, { "HFSX" } }, | ||||
|                                                                            { FilesystemType::FUSEBLK, { "FUSEBLK" } }, | ||||
|                                                                            { FilesystemType::F2FS, { "F2FS" } }, | ||||
|                                                                            { FilesystemType::UNKNOWN, { "UNKNOWN" } } }; | ||||
|  | ||||
| /** | ||||
|  * @brief Get the string name of Filesystem enum object | ||||
|   | ||||
| @@ -1,28 +1,27 @@ | ||||
| #include "Filter.h" | ||||
|  | ||||
| Filter::~Filter(){} | ||||
| Filter::~Filter() {} | ||||
|  | ||||
| ContainsFilter::ContainsFilter(const QString& pattern) : pattern(pattern){} | ||||
| ContainsFilter::~ContainsFilter(){} | ||||
| ContainsFilter::ContainsFilter(const QString& pattern) : pattern(pattern) {} | ||||
| ContainsFilter::~ContainsFilter() {} | ||||
| bool ContainsFilter::accepts(const QString& value) | ||||
| { | ||||
|     return value.contains(pattern); | ||||
| } | ||||
|  | ||||
| ExactFilter::ExactFilter(const QString& pattern) : pattern(pattern){} | ||||
| ExactFilter::~ExactFilter(){} | ||||
| ExactFilter::ExactFilter(const QString& pattern) : pattern(pattern) {} | ||||
| ExactFilter::~ExactFilter() {} | ||||
| bool ExactFilter::accepts(const QString& value) | ||||
| { | ||||
|     return value == pattern; | ||||
| } | ||||
|  | ||||
| RegexpFilter::RegexpFilter(const QString& regexp, bool invert) | ||||
|     :invert(invert) | ||||
| RegexpFilter::RegexpFilter(const QString& regexp, bool invert) : invert(invert) | ||||
| { | ||||
|     pattern.setPattern(regexp); | ||||
|     pattern.optimize(); | ||||
| } | ||||
| RegexpFilter::~RegexpFilter(){} | ||||
| RegexpFilter::~RegexpFilter() {} | ||||
| bool RegexpFilter::accepts(const QString& value) | ||||
| { | ||||
|     auto match = pattern.match(value); | ||||
|   | ||||
| @@ -1,42 +1,41 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <QString> | ||||
| #include <QRegularExpression> | ||||
| #include <QString> | ||||
|  | ||||
| class Filter | ||||
| { | ||||
| public: | ||||
| class Filter { | ||||
|    public: | ||||
|     virtual ~Filter(); | ||||
|     virtual bool accepts(const QString & value) = 0; | ||||
|     virtual bool accepts(const QString& value) = 0; | ||||
| }; | ||||
|  | ||||
| class ContainsFilter: public Filter | ||||
| { | ||||
| public: | ||||
|     ContainsFilter(const QString &pattern); | ||||
| class ContainsFilter : public Filter { | ||||
|    public: | ||||
|     ContainsFilter(const QString& pattern); | ||||
|     virtual ~ContainsFilter(); | ||||
|     bool accepts(const QString & value) override; | ||||
| private: | ||||
|     bool accepts(const QString& value) override; | ||||
|  | ||||
|    private: | ||||
|     QString pattern; | ||||
| }; | ||||
|  | ||||
| class ExactFilter: public Filter | ||||
| { | ||||
| public: | ||||
|     ExactFilter(const QString &pattern); | ||||
| class ExactFilter : public Filter { | ||||
|    public: | ||||
|     ExactFilter(const QString& pattern); | ||||
|     virtual ~ExactFilter(); | ||||
|     bool accepts(const QString & value) override; | ||||
| private: | ||||
|     bool accepts(const QString& value) override; | ||||
|  | ||||
|    private: | ||||
|     QString pattern; | ||||
| }; | ||||
|  | ||||
| class RegexpFilter: public Filter | ||||
| { | ||||
| public: | ||||
|     RegexpFilter(const QString ®exp, bool invert); | ||||
| class RegexpFilter : public Filter { | ||||
|    public: | ||||
|     RegexpFilter(const QString& regexp, bool invert); | ||||
|     virtual ~RegexpFilter(); | ||||
|     bool accepts(const QString & value) override; | ||||
| private: | ||||
|     bool accepts(const QString& value) override; | ||||
|  | ||||
|    private: | ||||
|     QRegularExpression pattern; | ||||
|     bool invert = false; | ||||
| }; | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
| @@ -37,10 +37,9 @@ | ||||
| #include <zlib.h> | ||||
| #include <QByteArray> | ||||
|  | ||||
| bool GZip::unzip(const QByteArray &compressedBytes, QByteArray &uncompressedBytes) | ||||
| bool GZip::unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes) | ||||
| { | ||||
|     if (compressedBytes.size() == 0) | ||||
|     { | ||||
|     if (compressedBytes.size() == 0) { | ||||
|         uncompressedBytes = compressedBytes; | ||||
|         return true; | ||||
|     } | ||||
| @@ -51,42 +50,37 @@ bool GZip::unzip(const QByteArray &compressedBytes, QByteArray &uncompressedByte | ||||
|  | ||||
|     z_stream strm; | ||||
|     memset(&strm, 0, sizeof(strm)); | ||||
|     strm.next_in = (Bytef *)compressedBytes.data(); | ||||
|     strm.next_in = (Bytef*)compressedBytes.data(); | ||||
|     strm.avail_in = compressedBytes.size(); | ||||
|  | ||||
|     bool done = false; | ||||
|  | ||||
|     if (inflateInit2(&strm, (16 + MAX_WBITS)) != Z_OK) | ||||
|     { | ||||
|     if (inflateInit2(&strm, (16 + MAX_WBITS)) != Z_OK) { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     int err = Z_OK; | ||||
|  | ||||
|     while (!done) | ||||
|     { | ||||
|     while (!done) { | ||||
|         // If our output buffer is too small | ||||
|         if (strm.total_out >= uncompLength) | ||||
|         { | ||||
|         if (strm.total_out >= uncompLength) { | ||||
|             uncompressedBytes.resize(uncompLength * 2); | ||||
|             uncompLength *= 2; | ||||
|         } | ||||
|  | ||||
|         strm.next_out = reinterpret_cast<Bytef *>((uncompressedBytes.data() + strm.total_out)); | ||||
|         strm.next_out = reinterpret_cast<Bytef*>((uncompressedBytes.data() + strm.total_out)); | ||||
|         strm.avail_out = uncompLength - strm.total_out; | ||||
|  | ||||
|         // Inflate another chunk. | ||||
|         err = inflate(&strm, Z_SYNC_FLUSH); | ||||
|         if (err == Z_STREAM_END) | ||||
|             done = true; | ||||
|         else if (err != Z_OK) | ||||
|         { | ||||
|         else if (err != Z_OK) { | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (inflateEnd(&strm) != Z_OK || !done) | ||||
|     { | ||||
|     if (inflateEnd(&strm) != Z_OK || !done) { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
| @@ -94,10 +88,9 @@ bool GZip::unzip(const QByteArray &compressedBytes, QByteArray &uncompressedByte | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| bool GZip::zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes) | ||||
| bool GZip::zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes) | ||||
| { | ||||
|     if (uncompressedBytes.size() == 0) | ||||
|     { | ||||
|     if (uncompressedBytes.size() == 0) { | ||||
|         compressedBytes = uncompressedBytes; | ||||
|         return true; | ||||
|     } | ||||
| @@ -109,8 +102,7 @@ bool GZip::zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes) | ||||
|     z_stream zs; | ||||
|     memset(&zs, 0, sizeof(zs)); | ||||
|  | ||||
|     if (deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (16 + MAX_WBITS), 8, Z_DEFAULT_STRATEGY) != Z_OK) | ||||
|     { | ||||
|     if (deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (16 + MAX_WBITS), 8, Z_DEFAULT_STRATEGY) != Z_OK) { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
| @@ -122,11 +114,9 @@ bool GZip::zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes) | ||||
|  | ||||
|     unsigned offset = 0; | ||||
|     unsigned temp = 0; | ||||
|     do | ||||
|     { | ||||
|     do { | ||||
|         auto remaining = compressedBytes.size() - offset; | ||||
|         if(remaining < 1) | ||||
|         { | ||||
|         if (remaining < 1) { | ||||
|             compressedBytes.resize(compressedBytes.size() * 2); | ||||
|         } | ||||
|         zs.next_out = reinterpret_cast<Bytef*>((compressedBytes.data() + offset)); | ||||
| @@ -137,13 +127,11 @@ bool GZip::zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes) | ||||
|  | ||||
|     compressedBytes.resize(offset); | ||||
|  | ||||
|     if (deflateEnd(&zs) != Z_OK) | ||||
|     { | ||||
|     if (deflateEnd(&zs) != Z_OK) { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     if (ret != Z_STREAM_END) | ||||
|     { | ||||
|     if (ret != Z_STREAM_END) { | ||||
|         return false; | ||||
|     } | ||||
|     return true; | ||||
|   | ||||
| @@ -1,10 +1,8 @@ | ||||
| #pragma once | ||||
| #include <QByteArray> | ||||
|  | ||||
| class GZip | ||||
| { | ||||
| public: | ||||
|     static bool unzip(const QByteArray &compressedBytes, QByteArray &uncompressedBytes); | ||||
|     static bool zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes); | ||||
| class GZip { | ||||
|    public: | ||||
|     static bool unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes); | ||||
|     static bool zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes); | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -6,17 +6,10 @@ | ||||
|  | ||||
| bool InstanceCopyPrefs::allTrue() const | ||||
| { | ||||
|     return copySaves && | ||||
|         keepPlaytime && | ||||
|         copyGameOptions && | ||||
|         copyResourcePacks && | ||||
|         copyShaderPacks && | ||||
|         copyServers && | ||||
|         copyMods && | ||||
|         copyScreenshots; | ||||
|     return copySaves && keepPlaytime && copyGameOptions && copyResourcePacks && copyShaderPacks && copyServers && copyMods && | ||||
|            copyScreenshots; | ||||
| } | ||||
|  | ||||
|  | ||||
| // Returns a single RegEx string of the selected folders/files to filter out (ex: ".minecraft/saves|.minecraft/server.dat") | ||||
| QString InstanceCopyPrefs::getSelectedFiltersAsRegex() const | ||||
| { | ||||
| @@ -26,25 +19,30 @@ QString InstanceCopyPrefs::getSelectedFiltersAsRegex(const QStringList& addition | ||||
| { | ||||
|     QStringList filters; | ||||
|  | ||||
|     if(!copySaves) | ||||
|     if (!copySaves) | ||||
|         filters << "saves"; | ||||
|  | ||||
|     if(!copyGameOptions) | ||||
|     if (!copyGameOptions) | ||||
|         filters << "options.txt"; | ||||
|  | ||||
|     if(!copyResourcePacks) | ||||
|         filters << "resourcepacks" << "texturepacks"; | ||||
|     if (!copyResourcePacks) | ||||
|         filters << "resourcepacks" | ||||
|                 << "texturepacks"; | ||||
|  | ||||
|     if(!copyShaderPacks) | ||||
|     if (!copyShaderPacks) | ||||
|         filters << "shaderpacks"; | ||||
|  | ||||
|     if(!copyServers) | ||||
|         filters << "servers.dat" << "servers.dat_old" << "server-resource-packs"; | ||||
|     if (!copyServers) | ||||
|         filters << "servers.dat" | ||||
|                 << "servers.dat_old" | ||||
|                 << "server-resource-packs"; | ||||
|  | ||||
|     if(!copyMods) | ||||
|         filters << "coremods" << "mods" << "config"; | ||||
|     if (!copyMods) | ||||
|         filters << "coremods" | ||||
|                 << "mods" | ||||
|                 << "config"; | ||||
|  | ||||
|     if(!copyScreenshots) | ||||
|     if (!copyScreenshots) | ||||
|         filters << "screenshots"; | ||||
|  | ||||
|     for (auto filter : additionalFilters) { | ||||
|   | ||||
| @@ -40,7 +40,7 @@ struct InstanceCopyPrefs { | ||||
|     void enableDontLinkSaves(bool b); | ||||
|     void enableUseClone(bool b); | ||||
|  | ||||
|    protected: // data | ||||
|    protected:  // data | ||||
|     bool copySaves = true; | ||||
|     bool keepPlaytime = true; | ||||
|     bool copyGameOptions = true; | ||||
|   | ||||
| @@ -156,8 +156,9 @@ void InstanceCopyTask::copyFinished() | ||||
|         allowed_symlinks.append(m_origInstance->gameRoot().toUtf8()); | ||||
|         allowed_symlinks.append("\n"); | ||||
|         if (allowed_symlinks_file.isSymLink()) | ||||
|             FS::deletePath(allowed_symlinks_file | ||||
|                                .filePath());  // we dont want to modify the original. also make sure the resulting file is not itself a link. | ||||
|             FS::deletePath( | ||||
|                 allowed_symlinks_file | ||||
|                     .filePath());  // we dont want to modify the original. also make sure the resulting file is not itself a link. | ||||
|  | ||||
|         FS::write(allowed_symlinks_file.filePath(), allowed_symlinks); | ||||
|     } | ||||
|   | ||||
| @@ -11,19 +11,18 @@ | ||||
| #include "settings/SettingsObject.h" | ||||
| #include "tasks/Task.h" | ||||
|  | ||||
| class InstanceCopyTask : public InstanceTask | ||||
| { | ||||
| class InstanceCopyTask : public InstanceTask { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|    public: | ||||
|     explicit InstanceCopyTask(InstancePtr origInstance, const InstanceCopyPrefs& prefs); | ||||
|  | ||||
| protected: | ||||
|    protected: | ||||
|     //! Entry point for tasks. | ||||
|     virtual void executeTask() override; | ||||
|     void copyFinished(); | ||||
|     void copyAborted(); | ||||
|  | ||||
| private: | ||||
|    private: | ||||
|     /* data */ | ||||
|     InstancePtr m_origInstance; | ||||
|     QFuture<bool> m_copyFuture; | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  *  Copyright (c) 2022 flowln <flowlnlnln@gmail.com> | ||||
|  * | ||||
| @@ -45,9 +45,9 @@ | ||||
| #include "icons/IconList.h" | ||||
| #include "icons/IconUtils.h" | ||||
|  | ||||
| #include "modplatform/technic/TechnicPackProcessor.h" | ||||
| #include "modplatform/modrinth/ModrinthInstanceCreationTask.h" | ||||
| #include "modplatform/flame/FlameInstanceCreationTask.h" | ||||
| #include "modplatform/modrinth/ModrinthInstanceCreationTask.h" | ||||
| #include "modplatform/technic/TechnicPackProcessor.h" | ||||
|  | ||||
| #include "settings/INISettingsObject.h" | ||||
|  | ||||
| @@ -138,8 +138,7 @@ void InstanceImportTask::processZipPack() | ||||
|  | ||||
|     // open the zip and find relevant files in it | ||||
|     m_packZip.reset(new QuaZip(m_archivePath)); | ||||
|     if (!m_packZip->open(QuaZip::mdUnzip)) | ||||
|     { | ||||
|     if (!m_packZip->open(QuaZip::mdUnzip)) { | ||||
|         emitFailed(tr("Unable to open supplied modpack zip file.")); | ||||
|         return; | ||||
|     } | ||||
| @@ -153,44 +152,40 @@ void InstanceImportTask::processZipPack() | ||||
|  | ||||
|     // NOTE: Prioritize modpack platforms that aren't searched for recursively. | ||||
|     // Especially Flame has a very common filename for its manifest, which may appear inside overrides for example | ||||
|     if(modrinthFound) | ||||
|     { | ||||
|     if (modrinthFound) { | ||||
|         // process as Modrinth pack | ||||
|         qDebug() << "Modrinth:" << modrinthFound; | ||||
|         m_modpackType = ModpackType::Modrinth; | ||||
|     } | ||||
|     else if (technicFound) | ||||
|     { | ||||
|     } else if (technicFound) { | ||||
|         // process as Technic pack | ||||
|         qDebug() << "Technic:" << technicFound; | ||||
|         extractDir.mkpath(".minecraft"); | ||||
|         extractDir.cd(".minecraft"); | ||||
|         m_modpackType = ModpackType::Technic; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         QStringList paths_to_ignore { "overrides/" }; | ||||
|     } else { | ||||
|         QStringList paths_to_ignore{ "overrides/" }; | ||||
|  | ||||
|         if (QString mmcRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "instance.cfg", paths_to_ignore); !mmcRoot.isNull()) { | ||||
|             // process as MultiMC instance/pack | ||||
|             qDebug() << "MultiMC:" << mmcRoot; | ||||
|             root = mmcRoot; | ||||
|             m_modpackType = ModpackType::MultiMC; | ||||
|         } else if (QString flameRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "manifest.json", paths_to_ignore); !flameRoot.isNull()) { | ||||
|         } else if (QString flameRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "manifest.json", paths_to_ignore); | ||||
|                    !flameRoot.isNull()) { | ||||
|             // process as Flame pack | ||||
|             qDebug() << "Flame:" << flameRoot; | ||||
|             root = flameRoot; | ||||
|             m_modpackType = ModpackType::Flame; | ||||
|         } | ||||
|     } | ||||
|     if(m_modpackType == ModpackType::Unknown) | ||||
|     { | ||||
|     if (m_modpackType == ModpackType::Unknown) { | ||||
|         emitFailed(tr("Archive does not contain a recognized modpack type.")); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     // make sure we extract just the pack | ||||
|     m_extractFuture = QtConcurrent::run(QThreadPool::globalInstance(), MMCZip::extractSubDir, m_packZip.get(), root, extractDir.absolutePath()); | ||||
|     m_extractFuture = | ||||
|         QtConcurrent::run(QThreadPool::globalInstance(), MMCZip::extractSubDir, m_packZip.get(), root, extractDir.absolutePath()); | ||||
|     connect(&m_extractFutureWatcher, &QFutureWatcher<QStringList>::finished, this, &InstanceImportTask::extractFinished); | ||||
|     m_extractFutureWatcher.setFuture(m_extractFuture); | ||||
| } | ||||
| @@ -210,37 +205,28 @@ void InstanceImportTask::extractFinished() | ||||
|  | ||||
|     qDebug() << "Fixing permissions for extracted pack files..."; | ||||
|     QDirIterator it(extractDir, QDirIterator::Subdirectories); | ||||
|     while (it.hasNext()) | ||||
|     { | ||||
|     while (it.hasNext()) { | ||||
|         auto filepath = it.next(); | ||||
|         QFileInfo file(filepath); | ||||
|         auto permissions = QFile::permissions(filepath); | ||||
|         auto origPermissions = permissions; | ||||
|         if(file.isDir()) | ||||
|         { | ||||
|         if (file.isDir()) { | ||||
|             // Folder +rwx for current user | ||||
|             permissions |= QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser | QFileDevice::Permission::ExeUser; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|         } else { | ||||
|             // File +rw for current user | ||||
|             permissions |= QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser; | ||||
|         } | ||||
|         if(origPermissions != permissions) | ||||
|         { | ||||
|             if(!QFile::setPermissions(filepath, permissions)) | ||||
|             { | ||||
|         if (origPermissions != permissions) { | ||||
|             if (!QFile::setPermissions(filepath, permissions)) { | ||||
|                 logWarning(tr("Could not fix permissions for %1").arg(filepath)); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|             } else { | ||||
|                 qDebug() << "Fixed" << filepath; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     switch(m_modpackType) | ||||
|     { | ||||
|     switch (m_modpackType) { | ||||
|         case ModpackType::MultiMC: | ||||
|             processMultiMC(); | ||||
|             return; | ||||
| @@ -276,7 +262,8 @@ void InstanceImportTask::processFlame() | ||||
|         if (original_instance_id_it != m_extra_info.constEnd()) | ||||
|             original_instance_id = original_instance_id_it.value(); | ||||
|  | ||||
|         inst_creation_task = makeShared<FlameCreationTask>(m_stagingPath, m_globalSettings, m_parent, pack_id, pack_version_id, original_instance_id); | ||||
|         inst_creation_task = | ||||
|             makeShared<FlameCreationTask>(m_stagingPath, m_globalSettings, m_parent, pack_id, pack_version_id, original_instance_id); | ||||
|     } else { | ||||
|         // FIXME: Find a way to get IDs in directly imported ZIPs | ||||
|         inst_creation_task = makeShared<FlameCreationTask>(m_stagingPath, m_globalSettings, m_parent, QString(), QString()); | ||||
| @@ -362,7 +349,8 @@ void InstanceImportTask::processModrinth() | ||||
|         if (original_instance_id_it != m_extra_info.constEnd()) | ||||
|             original_instance_id = original_instance_id_it.value(); | ||||
|  | ||||
|         inst_creation_task = new ModrinthCreationTask(m_stagingPath, m_globalSettings, m_parent, pack_id, pack_version_id, original_instance_id); | ||||
|         inst_creation_task = | ||||
|             new ModrinthCreationTask(m_stagingPath, m_globalSettings, m_parent, pack_id, pack_version_id, original_instance_id); | ||||
|     } else { | ||||
|         QString pack_id; | ||||
|         if (!m_sourceUrl.isEmpty()) { | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
| @@ -35,54 +35,49 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "InstanceTask.h" | ||||
| #include "net/NetJob.h" | ||||
| #include <QUrl> | ||||
| #include <QFuture> | ||||
| #include <QFutureWatcher> | ||||
| #include "settings/SettingsObject.h" | ||||
| #include <QUrl> | ||||
| #include "InstanceTask.h" | ||||
| #include "QObjectPtr.h" | ||||
| #include "modplatform/flame/PackManifest.h" | ||||
| #include "net/NetJob.h" | ||||
| #include "settings/SettingsObject.h" | ||||
|  | ||||
| #include <optional> | ||||
|  | ||||
| class QuaZip; | ||||
| namespace Flame | ||||
| { | ||||
|     class FileResolvingTask; | ||||
| namespace Flame { | ||||
| class FileResolvingTask; | ||||
| } | ||||
|  | ||||
| class InstanceImportTask : public InstanceTask | ||||
| { | ||||
| class InstanceImportTask : public InstanceTask { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|    public: | ||||
|     explicit InstanceImportTask(const QUrl sourceUrl, QWidget* parent = nullptr, QMap<QString, QString>&& extra_info = {}); | ||||
|  | ||||
|     bool abort() override; | ||||
|     const QVector<Flame::File> &getBlockedFiles() const | ||||
|     { | ||||
|         return m_blockedMods; | ||||
|     } | ||||
|     const QVector<Flame::File>& getBlockedFiles() const { return m_blockedMods; } | ||||
|  | ||||
| protected: | ||||
|    protected: | ||||
|     //! Entry point for tasks. | ||||
|     virtual void executeTask() override; | ||||
|  | ||||
| private: | ||||
|    private: | ||||
|     void processZipPack(); | ||||
|     void processMultiMC(); | ||||
|     void processTechnic(); | ||||
|     void processFlame(); | ||||
|     void processModrinth(); | ||||
|  | ||||
| private slots: | ||||
|    private slots: | ||||
|     void downloadSucceeded(); | ||||
|     void downloadFailed(QString reason); | ||||
|     void downloadProgressChanged(qint64 current, qint64 total); | ||||
|     void downloadAborted(); | ||||
|     void extractFinished(); | ||||
|  | ||||
| private: /* data */ | ||||
|    private: /* data */ | ||||
|     NetJob::Ptr m_filesNetJob; | ||||
|     shared_qobject_ptr<Flame::FileResolvingTask> m_modIdResolver; | ||||
|     QUrl m_sourceUrl; | ||||
| @@ -92,7 +87,7 @@ private: /* data */ | ||||
|     QFuture<std::optional<QStringList>> m_extractFuture; | ||||
|     QFutureWatcher<std::optional<QStringList>> m_extractFutureWatcher; | ||||
|     QVector<Flame::File> m_blockedMods; | ||||
|     enum class ModpackType{ | ||||
|     enum class ModpackType { | ||||
|         Unknown, | ||||
|         MultiMC, | ||||
|         Technic, | ||||
| @@ -104,6 +99,6 @@ private: /* data */ | ||||
|     // the source URL / the resource it points to alone. | ||||
|     QMap<QString, QString> m_extra_info; | ||||
|  | ||||
|     //FIXME: nuke | ||||
|     // FIXME: nuke | ||||
|     QWidget* m_parent; | ||||
| }; | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
| @@ -41,9 +41,9 @@ | ||||
| #include <QJsonArray> | ||||
| #include <QJsonDocument> | ||||
| #include <QMimeData> | ||||
| #include <QPair> | ||||
| #include <QSet> | ||||
| #include <QStack> | ||||
| #include <QPair> | ||||
| #include <QTextStream> | ||||
| #include <QThread> | ||||
| #include <QTimer> | ||||
| @@ -129,7 +129,7 @@ QMimeData* InstanceList::mimeData(const QModelIndexList& indexes) const | ||||
|     return mimeData; | ||||
| } | ||||
|  | ||||
| QStringList InstanceList::getLinkedInstancesById(const QString &id) const | ||||
| QStringList InstanceList::getLinkedInstancesById(const QString& id) const | ||||
| { | ||||
|     QStringList linkedInstances; | ||||
|     for (auto inst : m_instances) { | ||||
| @@ -158,42 +158,34 @@ QVariant InstanceList::data(const QModelIndex& index, int role) const | ||||
|     if (!index.isValid()) { | ||||
|         return QVariant(); | ||||
|     } | ||||
|     BaseInstance *pdata = static_cast<BaseInstance *>(index.internalPointer()); | ||||
|     switch (role) | ||||
|     { | ||||
|     case InstancePointerRole: | ||||
|     { | ||||
|         QVariant v = QVariant::fromValue((void *)pdata); | ||||
|         return v; | ||||
|     } | ||||
|     case InstanceIDRole: | ||||
|     { | ||||
|         return pdata->id(); | ||||
|     } | ||||
|     case Qt::EditRole: | ||||
|     case Qt::DisplayRole: | ||||
|     { | ||||
|         return pdata->name(); | ||||
|     } | ||||
|     case Qt::AccessibleTextRole: | ||||
|     { | ||||
|         return tr("%1 Instance").arg(pdata->name()); | ||||
|     } | ||||
|     case Qt::ToolTipRole: | ||||
|     { | ||||
|         return pdata->instanceRoot(); | ||||
|     } | ||||
|     case Qt::DecorationRole: | ||||
|     { | ||||
|         return pdata->iconKey(); | ||||
|     } | ||||
|     // HACK: see InstanceView.h in gui! | ||||
|     case GroupRole: | ||||
|     { | ||||
|         return getInstanceGroup(pdata->id()); | ||||
|     } | ||||
|     default: | ||||
|         break; | ||||
|     BaseInstance* pdata = static_cast<BaseInstance*>(index.internalPointer()); | ||||
|     switch (role) { | ||||
|         case InstancePointerRole: { | ||||
|             QVariant v = QVariant::fromValue((void*)pdata); | ||||
|             return v; | ||||
|         } | ||||
|         case InstanceIDRole: { | ||||
|             return pdata->id(); | ||||
|         } | ||||
|         case Qt::EditRole: | ||||
|         case Qt::DisplayRole: { | ||||
|             return pdata->name(); | ||||
|         } | ||||
|         case Qt::AccessibleTextRole: { | ||||
|             return tr("%1 Instance").arg(pdata->name()); | ||||
|         } | ||||
|         case Qt::ToolTipRole: { | ||||
|             return pdata->instanceRoot(); | ||||
|         } | ||||
|         case Qt::DecorationRole: { | ||||
|             return pdata->iconKey(); | ||||
|         } | ||||
|         // HACK: see InstanceView.h in gui! | ||||
|         case GroupRole: { | ||||
|             return getInstanceGroup(pdata->id()); | ||||
|         } | ||||
|         default: | ||||
|             break; | ||||
|     } | ||||
|     return QVariant(); | ||||
| } | ||||
| @@ -320,16 +312,18 @@ bool InstanceList::trashInstance(const InstanceId& id) | ||||
|     } | ||||
|  | ||||
|     qDebug() << "Instance" << id << "has been trashed by the launcher."; | ||||
|     m_trashHistory.push({id, inst->instanceRoot(), trashedLoc, cachedGroupId}); | ||||
|     m_trashHistory.push({ id, inst->instanceRoot(), trashedLoc, cachedGroupId }); | ||||
|  | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| bool InstanceList::trashedSomething() { | ||||
| bool InstanceList::trashedSomething() | ||||
| { | ||||
|     return !m_trashHistory.empty(); | ||||
| } | ||||
|  | ||||
| void InstanceList::undoTrashInstance() { | ||||
| void InstanceList::undoTrashInstance() | ||||
| { | ||||
|     if (m_trashHistory.empty()) { | ||||
|         qWarning() << "Nothing to recover from trash."; | ||||
|         return; | ||||
| @@ -558,7 +552,7 @@ InstancePtr InstanceList::getInstanceByManagedName(const QString& managed_name) | ||||
|     return {}; | ||||
| } | ||||
|  | ||||
| QModelIndex InstanceList::getInstanceIndexById(const QString &id) const | ||||
| QModelIndex InstanceList::getInstanceIndexById(const QString& id) const | ||||
| { | ||||
|     return index(getInstIndex(getInstanceById(id).get())); | ||||
| } | ||||
| @@ -597,13 +591,11 @@ InstancePtr InstanceList::loadInstance(const InstanceId& id) | ||||
|  | ||||
|     QString inst_type = instanceSettings->get("InstanceType").toString(); | ||||
|  | ||||
|     // NOTE: Some PolyMC versions didn't save the InstanceType properly. We will just bank on the probability that this is probably a OneSix instance | ||||
|     if (inst_type == "OneSix" || inst_type.isEmpty()) | ||||
|     { | ||||
|     // NOTE: Some PolyMC versions didn't save the InstanceType properly. We will just bank on the probability that this is probably a OneSix | ||||
|     // instance | ||||
|     if (inst_type == "OneSix" || inst_type.isEmpty()) { | ||||
|         inst.reset(new MinecraftInstance(m_globalSettings, instanceSettings, instanceRoot)); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|     } else { | ||||
|         inst.reset(new NullInstance(m_globalSettings, instanceSettings, instanceRoot)); | ||||
|     } | ||||
|     qDebug() << "Loaded instance " << inst->name() << " from " << inst->instanceRoot(); | ||||
| @@ -787,9 +779,14 @@ class InstanceStaging : public Task { | ||||
|     Q_OBJECT | ||||
|     const unsigned minBackoff = 1; | ||||
|     const unsigned maxBackoff = 16; | ||||
|  | ||||
|    public: | ||||
|     InstanceStaging(InstanceList* parent, InstanceTask* child, QString stagingPath, InstanceName const& instanceName, QString groupName) | ||||
|         : m_parent(parent), backoff(minBackoff, maxBackoff), m_stagingPath(std::move(stagingPath)), m_instance_name(std::move(instanceName)), m_groupName(std::move(groupName)) | ||||
|         : m_parent(parent) | ||||
|         , backoff(minBackoff, maxBackoff) | ||||
|         , m_stagingPath(std::move(stagingPath)) | ||||
|         , m_instance_name(std::move(instanceName)) | ||||
|         , m_groupName(std::move(groupName)) | ||||
|     { | ||||
|         m_child.reset(child); | ||||
|         connect(child, &Task::succeeded, this, &InstanceStaging::childSucceded); | ||||
| @@ -815,10 +812,7 @@ class InstanceStaging : public Task { | ||||
|  | ||||
|         return Task::abort(); | ||||
|     } | ||||
|     bool canAbort() const override | ||||
|     { | ||||
|         return (m_child && m_child->canAbort()); | ||||
|     } | ||||
|     bool canAbort() const override { return (m_child && m_child->canAbort()); } | ||||
|  | ||||
|    protected: | ||||
|     virtual void executeTask() override { m_child->start(); } | ||||
| @@ -828,8 +822,7 @@ class InstanceStaging : public Task { | ||||
|     void childSucceded() | ||||
|     { | ||||
|         unsigned sleepTime = backoff(); | ||||
|         if (m_parent->commitStagedInstance(m_stagingPath, m_instance_name, m_groupName, *m_child.get())) | ||||
|         { | ||||
|         if (m_parent->commitStagedInstance(m_stagingPath, m_instance_name, m_groupName, *m_child.get())) { | ||||
|             emitSucceeded(); | ||||
|             return; | ||||
|         } | ||||
| @@ -847,13 +840,10 @@ class InstanceStaging : public Task { | ||||
|         emitFailed(reason); | ||||
|     } | ||||
|  | ||||
|     void childAborted() | ||||
|     { | ||||
|         emitAborted(); | ||||
|     } | ||||
|     void childAborted() { emitAborted(); } | ||||
|  | ||||
| private: | ||||
|     InstanceList * m_parent; | ||||
|    private: | ||||
|     InstanceList* m_parent; | ||||
|     /* | ||||
|      * WHY: the whole reason why this uses an exponential backoff retry scheme is antivirus on Windows. | ||||
|      * Basically, it starts messing things up while the launcher is extracting/creating instances | ||||
| @@ -892,7 +882,10 @@ QString InstanceList::getStagedInstancePath() | ||||
|     return path; | ||||
| } | ||||
|  | ||||
| bool InstanceList::commitStagedInstance(const QString& path, InstanceName const& instanceName, const QString& groupName, InstanceTask const& commiting) | ||||
| bool InstanceList::commitStagedInstance(const QString& path, | ||||
|                                         InstanceName const& instanceName, | ||||
|                                         const QString& groupName, | ||||
|                                         InstanceTask const& commiting) | ||||
| { | ||||
|     QDir dir; | ||||
|     QString instID; | ||||
|   | ||||
| @@ -15,12 +15,12 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <QObject> | ||||
| #include <QAbstractListModel> | ||||
| #include <QSet> | ||||
| #include <QList> | ||||
| #include <QStack> | ||||
| #include <QObject> | ||||
| #include <QPair> | ||||
| #include <QSet> | ||||
| #include <QStack> | ||||
|  | ||||
| #include "BaseInstance.h" | ||||
|  | ||||
| @@ -32,21 +32,9 @@ using InstanceId = QString; | ||||
| using GroupId = QString; | ||||
| using InstanceLocator = std::pair<InstancePtr, int>; | ||||
|  | ||||
| enum class InstCreateError | ||||
| { | ||||
|     NoCreateError = 0, | ||||
|     NoSuchVersion, | ||||
|     UnknownCreateError, | ||||
|     InstExists, | ||||
|     CantCreateDir | ||||
| }; | ||||
| enum class InstCreateError { NoCreateError = 0, NoSuchVersion, UnknownCreateError, InstExists, CantCreateDir }; | ||||
|  | ||||
| enum class GroupsState | ||||
| { | ||||
|     NotLoaded, | ||||
|     Steady, | ||||
|     Dirty | ||||
| }; | ||||
| enum class GroupsState { NotLoaded, Steady, Dirty }; | ||||
|  | ||||
| struct TrashHistoryItem { | ||||
|     QString id; | ||||
| @@ -55,48 +43,36 @@ struct TrashHistoryItem { | ||||
|     QString groupName; | ||||
| }; | ||||
|  | ||||
| class InstanceList : public QAbstractListModel | ||||
| { | ||||
| class InstanceList : public QAbstractListModel { | ||||
|     Q_OBJECT | ||||
|  | ||||
| public: | ||||
|     explicit InstanceList(SettingsObjectPtr settings, const QString & instDir, QObject *parent = 0); | ||||
|    public: | ||||
|     explicit InstanceList(SettingsObjectPtr settings, const QString& instDir, QObject* parent = 0); | ||||
|     virtual ~InstanceList(); | ||||
|  | ||||
| public: | ||||
|     QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const override; | ||||
|     int rowCount(const QModelIndex &parent = QModelIndex()) const override; | ||||
|     QVariant data(const QModelIndex &index, int role) const override; | ||||
|     Qt::ItemFlags flags(const QModelIndex &index) const override; | ||||
|    public: | ||||
|     QModelIndex index(int row, int column = 0, const QModelIndex& parent = QModelIndex()) const override; | ||||
|     int rowCount(const QModelIndex& parent = QModelIndex()) const override; | ||||
|     QVariant data(const QModelIndex& index, int role) const override; | ||||
|     Qt::ItemFlags flags(const QModelIndex& index) const override; | ||||
|  | ||||
|     bool setData(const QModelIndex & index, const QVariant & value, int role) override; | ||||
|     bool setData(const QModelIndex& index, const QVariant& value, int role) override; | ||||
|  | ||||
|     enum AdditionalRoles | ||||
|     { | ||||
|     enum AdditionalRoles { | ||||
|         GroupRole = Qt::UserRole, | ||||
|         InstancePointerRole = 0x34B1CB48, ///< Return pointer to real instance | ||||
|         InstanceIDRole = 0x34B1CB49 ///< Return id if the instance | ||||
|         InstancePointerRole = 0x34B1CB48,  ///< Return pointer to real instance | ||||
|         InstanceIDRole = 0x34B1CB49        ///< Return id if the instance | ||||
|     }; | ||||
|     /*! | ||||
|      * \brief Error codes returned by functions in the InstanceList class. | ||||
|      * NoError Indicates that no error occurred. | ||||
|      * UnknownError indicates that an unspecified error occurred. | ||||
|      */ | ||||
|     enum InstListError | ||||
|     { | ||||
|         NoError = 0, | ||||
|         UnknownError | ||||
|     }; | ||||
|     enum InstListError { NoError = 0, UnknownError }; | ||||
|  | ||||
|     InstancePtr at(int i) const | ||||
|     { | ||||
|         return m_instances.at(i); | ||||
|     } | ||||
|     InstancePtr at(int i) const { return m_instances.at(i); } | ||||
|  | ||||
|     int count() const | ||||
|     { | ||||
|         return m_instances.count(); | ||||
|     } | ||||
|     int count() const { return m_instances.count(); } | ||||
|  | ||||
|     InstListError loadList(); | ||||
|     void saveNow(); | ||||
| @@ -105,21 +81,21 @@ public: | ||||
|     InstancePtr getInstanceById(QString id) const; | ||||
|     /* O(n) */ | ||||
|     InstancePtr getInstanceByManagedName(const QString& managed_name) const; | ||||
|     QModelIndex getInstanceIndexById(const QString &id) const; | ||||
|     QModelIndex getInstanceIndexById(const QString& id) const; | ||||
|     QStringList getGroups(); | ||||
|     bool isGroupCollapsed(const QString &groupName); | ||||
|     bool isGroupCollapsed(const QString& groupName); | ||||
|  | ||||
|     GroupId getInstanceGroup(const InstanceId & id) const; | ||||
|     void setInstanceGroup(const InstanceId & id, const GroupId& name); | ||||
|     GroupId getInstanceGroup(const InstanceId& id) const; | ||||
|     void setInstanceGroup(const InstanceId& id, const GroupId& name); | ||||
|  | ||||
|     void deleteGroup(const GroupId & name); | ||||
|     bool trashInstance(const InstanceId &id); | ||||
|     void deleteGroup(const GroupId& name); | ||||
|     bool trashInstance(const InstanceId& id); | ||||
|     bool trashedSomething(); | ||||
|     void undoTrashInstance(); | ||||
|     void deleteInstance(const InstanceId & id); | ||||
|     void deleteInstance(const InstanceId& id); | ||||
|  | ||||
|     // Wrap an instance creation task in some more task machinery and make it ready to be used | ||||
|     Task * wrapInstanceTask(InstanceTask * task); | ||||
|     Task* wrapInstanceTask(InstanceTask* task); | ||||
|  | ||||
|     /** | ||||
|      * Create a new empty staging area for instance creation and @return a path/key top commit it later. | ||||
| @@ -139,7 +115,7 @@ public: | ||||
|      * Destroy a previously created staging area given by @keyPath - used when creation fails. | ||||
|      * Used by instance manipulation tasks. | ||||
|      */ | ||||
|     bool destroyStagingPath(const QString & keyPath); | ||||
|     bool destroyStagingPath(const QString& keyPath); | ||||
|  | ||||
|     int getTotalPlayTime(); | ||||
|  | ||||
| @@ -147,42 +123,42 @@ public: | ||||
|  | ||||
|     Qt::DropActions supportedDropActions() const override; | ||||
|  | ||||
|     bool canDropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent) const override; | ||||
|     bool canDropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) const override; | ||||
|  | ||||
|     bool dropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent) override; | ||||
|     bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) override; | ||||
|  | ||||
|     QStringList mimeTypes() const override; | ||||
|     QMimeData *mimeData(const QModelIndexList &indexes) const override; | ||||
|     QMimeData* mimeData(const QModelIndexList& indexes) const override; | ||||
|  | ||||
|     QStringList getLinkedInstancesById(const QString &id) const; | ||||
|     QStringList getLinkedInstancesById(const QString& id) const; | ||||
|  | ||||
| signals: | ||||
|    signals: | ||||
|     void dataIsInvalid(); | ||||
|     void instancesChanged(); | ||||
|     void instanceSelectRequest(QString instanceId); | ||||
|     void groupsChanged(QSet<QString> groups); | ||||
|  | ||||
| public slots: | ||||
|     void on_InstFolderChanged(const Setting &setting, QVariant value); | ||||
|     void on_GroupStateChanged(const QString &group, bool collapsed); | ||||
|    public slots: | ||||
|     void on_InstFolderChanged(const Setting& setting, QVariant value); | ||||
|     void on_GroupStateChanged(const QString& group, bool collapsed); | ||||
|  | ||||
| private slots: | ||||
|     void propertiesChanged(BaseInstance *inst); | ||||
|    private slots: | ||||
|     void propertiesChanged(BaseInstance* inst); | ||||
|     void providerUpdated(); | ||||
|     void instanceDirContentsChanged(const QString &path); | ||||
|     void instanceDirContentsChanged(const QString& path); | ||||
|  | ||||
| private: | ||||
|     int getInstIndex(BaseInstance *inst) const; | ||||
|    private: | ||||
|     int getInstIndex(BaseInstance* inst) const; | ||||
|     void updateTotalPlayTime(); | ||||
|     void suspendWatch(); | ||||
|     void resumeWatch(); | ||||
|     void add(const QList<InstancePtr> &list); | ||||
|     void add(const QList<InstancePtr>& list); | ||||
|     void loadGroupList(); | ||||
|     void saveGroupList(); | ||||
|     QList<InstanceId> discoverInstances(); | ||||
|     InstancePtr loadInstance(const InstanceId& id); | ||||
|  | ||||
| private: | ||||
|    private: | ||||
|     int m_watchLevel = 0; | ||||
|     int totalPlayTime = 0; | ||||
|     bool m_dirty = false; | ||||
| @@ -191,7 +167,7 @@ private: | ||||
|  | ||||
|     SettingsObjectPtr m_globalSettings; | ||||
|     QString m_instDir; | ||||
|     QFileSystemWatcher * m_watcher; | ||||
|     QFileSystemWatcher* m_watcher; | ||||
|     // FIXME: this is so inefficient that looking at it is almost painful. | ||||
|     QSet<QString> m_collapsedGroups; | ||||
|     QMap<InstanceId, GroupId> m_instanceGroupIndex; | ||||
|   | ||||
| @@ -1,36 +1,31 @@ | ||||
| #pragma once | ||||
| #include "minecraft/MinecraftInstance.h" | ||||
| #include <FileSystem.h> | ||||
| #include "minecraft/MinecraftInstance.h" | ||||
| #include "ui/pages/BasePage.h" | ||||
| #include "ui/pages/BasePageProvider.h" | ||||
| #include "ui/pages/instance/InstanceSettingsPage.h" | ||||
| #include "ui/pages/instance/LogPage.h" | ||||
| #include "ui/pages/instance/VersionPage.h" | ||||
| #include "ui/pages/instance/ManagedPackPage.h" | ||||
| #include "ui/pages/instance/ModFolderPage.h" | ||||
| #include "ui/pages/instance/ResourcePackPage.h" | ||||
| #include "ui/pages/instance/TexturePackPage.h" | ||||
| #include "ui/pages/instance/ShaderPackPage.h" | ||||
| #include "ui/pages/instance/NotesPage.h" | ||||
| #include "ui/pages/instance/ScreenshotsPage.h" | ||||
| #include "ui/pages/instance/InstanceSettingsPage.h" | ||||
| #include "ui/pages/instance/OtherLogsPage.h" | ||||
| #include "ui/pages/instance/WorldListPage.h" | ||||
| #include "ui/pages/instance/ResourcePackPage.h" | ||||
| #include "ui/pages/instance/ScreenshotsPage.h" | ||||
| #include "ui/pages/instance/ServersPage.h" | ||||
| #include "ui/pages/instance/GameOptionsPage.h" | ||||
| #include "ui/pages/instance/ShaderPackPage.h" | ||||
| #include "ui/pages/instance/TexturePackPage.h" | ||||
| #include "ui/pages/instance/VersionPage.h" | ||||
| #include "ui/pages/instance/WorldListPage.h" | ||||
|  | ||||
| class InstancePageProvider : public QObject, public BasePageProvider | ||||
| { | ||||
| class InstancePageProvider : protected QObject, public BasePageProvider { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     explicit InstancePageProvider(InstancePtr parent) | ||||
|     { | ||||
|         inst = parent; | ||||
|     } | ||||
|    public: | ||||
|     explicit InstancePageProvider(InstancePtr parent) { inst = parent; } | ||||
|  | ||||
|     virtual ~InstancePageProvider() {}; | ||||
|     virtual QList<BasePage *> getPages() override | ||||
|     virtual ~InstancePageProvider(){}; | ||||
|     virtual QList<BasePage*> getPages() override | ||||
|     { | ||||
|         QList<BasePage *> values; | ||||
|         QList<BasePage*> values; | ||||
|         values.append(new LogPage(inst)); | ||||
|         std::shared_ptr<MinecraftInstance> onesix = std::dynamic_pointer_cast<MinecraftInstance>(inst); | ||||
|         values.append(new VersionPage(onesix.get())); | ||||
| @@ -50,18 +45,14 @@ public: | ||||
|         values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots"))); | ||||
|         values.append(new InstanceSettingsPage(onesix.get())); | ||||
|         auto logMatcher = inst->getLogFileMatcher(); | ||||
|         if(logMatcher) | ||||
|         { | ||||
|         if (logMatcher) { | ||||
|             values.append(new OtherLogsPage(inst->getLogFileRoot(), logMatcher)); | ||||
|         } | ||||
|         return values; | ||||
|     } | ||||
|  | ||||
|     virtual QString dialogTitle() override | ||||
|     { | ||||
|         return tr("Edit Instance (%1)").arg(inst->name()); | ||||
|     } | ||||
| protected: | ||||
|     virtual QString dialogTitle() override { return tr("Edit Instance (%1)").arg(inst->name()); } | ||||
|  | ||||
|    protected: | ||||
|     InstancePtr inst; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -18,13 +18,14 @@ InstanceNameChange askForChangingInstanceName(QWidget* parent, const QString& ol | ||||
|     return InstanceNameChange::ShouldKeep; | ||||
| } | ||||
|  | ||||
| ShouldUpdate askIfShouldUpdate(QWidget *parent, QString original_version_name) | ||||
| ShouldUpdate askIfShouldUpdate(QWidget* parent, QString original_version_name) | ||||
| { | ||||
|     auto info = CustomMessageBox::selectable( | ||||
|         parent, QObject::tr("Similar modpack was found!"), | ||||
|         QObject::tr("One or more of your instances are from this same modpack%1. Do you want to create a " | ||||
|            "separate instance, or update the existing one?\n\nNOTE: Make sure you made a backup of your important instance data before " | ||||
|            "updating, as worlds can be corrupted and some configuration may be lost (due to pack overrides).") | ||||
|         QObject::tr( | ||||
|             "One or more of your instances are from this same modpack%1. Do you want to create a " | ||||
|             "separate instance, or update the existing one?\n\nNOTE: Make sure you made a backup of your important instance data before " | ||||
|             "updating, as worlds can be corrupted and some configuration may be lost (due to pack overrides).") | ||||
|             .arg(original_version_name), | ||||
|         QMessageBox::Information, QMessageBox::Ok | QMessageBox::Reset | QMessageBox::Abort); | ||||
|     info->setButtonText(QMessageBox::Ok, QObject::tr("Update existing instance")); | ||||
| @@ -38,7 +39,6 @@ ShouldUpdate askIfShouldUpdate(QWidget *parent, QString original_version_name) | ||||
|     if (info->clickedButton() == info->button(QMessageBox::Abort)) | ||||
|         return ShouldUpdate::SkipUpdating; | ||||
|     return ShouldUpdate::Cancel; | ||||
|  | ||||
| } | ||||
|  | ||||
| QString InstanceName::name() const | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
| @@ -39,43 +39,39 @@ | ||||
|  | ||||
| #include <QRegularExpression> | ||||
|  | ||||
| bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget *parent) | ||||
| bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget* parent) | ||||
| { | ||||
|     if (jvmargs.contains("-XX:PermSize=") || jvmargs.contains(QRegularExpression("-Xm[sx]")) | ||||
|         || jvmargs.contains("-XX-MaxHeapSize") || jvmargs.contains("-XX:InitialHeapSize")) | ||||
|     { | ||||
|     if (jvmargs.contains("-XX:PermSize=") || jvmargs.contains(QRegularExpression("-Xm[sx]")) || jvmargs.contains("-XX-MaxHeapSize") || | ||||
|         jvmargs.contains("-XX:InitialHeapSize")) { | ||||
|         auto warnStr = QObject::tr( | ||||
|             "You tried to manually set a JVM memory option (using \"-XX:PermSize\", \"-XX-MaxHeapSize\", \"-XX:InitialHeapSize\", \"-Xmx\" or \"-Xms\").\n" | ||||
|             "You tried to manually set a JVM memory option (using \"-XX:PermSize\", \"-XX-MaxHeapSize\", \"-XX:InitialHeapSize\", \"-Xmx\" " | ||||
|             "or \"-Xms\").\n" | ||||
|             "There are dedicated boxes for these in the settings (Java tab, in the Memory group at the top).\n" | ||||
|             "This message will be displayed until you remove them from the JVM arguments."); | ||||
|         CustomMessageBox::selectable( | ||||
|             parent, QObject::tr("JVM arguments warning"), | ||||
|             warnStr, | ||||
|             QMessageBox::Warning)->exec(); | ||||
|         CustomMessageBox::selectable(parent, QObject::tr("JVM arguments warning"), warnStr, QMessageBox::Warning)->exec(); | ||||
|         return false; | ||||
|     } | ||||
|     // block lunacy with passing required version to the JVM | ||||
|     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" | ||||
|             "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."); | ||||
|         CustomMessageBox::selectable( | ||||
|             parent, QObject::tr("JVM arguments warning"), | ||||
|             warnStr, | ||||
|             QMessageBox::Warning)->exec(); | ||||
|         CustomMessageBox::selectable(parent, QObject::tr("JVM arguments warning"), warnStr, QMessageBox::Warning)->exec(); | ||||
|         return false; | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| void JavaCommon::javaWasOk(QWidget *parent, JavaCheckResult result) | ||||
| void JavaCommon::javaWasOk(QWidget* parent, const JavaCheckResult& result) | ||||
| { | ||||
|     QString text; | ||||
|     text += QObject::tr("Java test succeeded!<br />Platform reported: %1<br />Java version " | ||||
|         "reported: %2<br />Java vendor " | ||||
|         "reported: %3<br />").arg(result.realPlatform, result.javaVersion.toString(), result.javaVendor); | ||||
|     if (result.errorLog.size()) | ||||
|     { | ||||
|     text += QObject::tr( | ||||
|                 "Java test succeeded!<br />Platform reported: %1<br />Java version " | ||||
|                 "reported: %2<br />Java vendor " | ||||
|                 "reported: %3<br />") | ||||
|                 .arg(result.realPlatform, result.javaVersion.toString(), result.javaVendor); | ||||
|     if (result.errorLog.size()) { | ||||
|         auto htmlError = result.errorLog; | ||||
|         htmlError.replace('\n', "<br />"); | ||||
|         text += QObject::tr("<br />Warnings:<br /><font color=\"orange\">%1</font>").arg(htmlError); | ||||
| @@ -83,7 +79,7 @@ void JavaCommon::javaWasOk(QWidget *parent, JavaCheckResult result) | ||||
|     CustomMessageBox::selectable(parent, QObject::tr("Java test success"), text, QMessageBox::Information)->show(); | ||||
| } | ||||
|  | ||||
| void JavaCommon::javaArgsWereBad(QWidget *parent, JavaCheckResult result) | ||||
| void JavaCommon::javaArgsWereBad(QWidget* parent, const JavaCheckResult& result) | ||||
| { | ||||
|     auto htmlError = result.errorLog; | ||||
|     QString text; | ||||
| @@ -93,7 +89,7 @@ void JavaCommon::javaArgsWereBad(QWidget *parent, JavaCheckResult result) | ||||
|     CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show(); | ||||
| } | ||||
|  | ||||
| void JavaCommon::javaBinaryWasBad(QWidget *parent, JavaCheckResult result) | ||||
| void JavaCommon::javaBinaryWasBad(QWidget* parent, const JavaCheckResult& result) | ||||
| { | ||||
|     QString text; | ||||
|     text += QObject::tr( | ||||
| @@ -102,7 +98,7 @@ void JavaCommon::javaBinaryWasBad(QWidget *parent, JavaCheckResult result) | ||||
|     CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show(); | ||||
| } | ||||
|  | ||||
| void JavaCommon::javaCheckNotFound(QWidget *parent) | ||||
| void JavaCommon::javaCheckNotFound(QWidget* parent) | ||||
| { | ||||
|     QString text; | ||||
|     text += QObject::tr("Java checker library could not be found. Please check your installation."); | ||||
| @@ -111,8 +107,7 @@ void JavaCommon::javaCheckNotFound(QWidget *parent) | ||||
|  | ||||
| void JavaCommon::TestCheck::run() | ||||
| { | ||||
|     if (!JavaCommon::checkJVMArgs(m_args, m_parent)) | ||||
|     { | ||||
|     if (!JavaCommon::checkJVMArgs(m_args, m_parent)) { | ||||
|         emit finished(); | ||||
|         return; | ||||
|     } | ||||
| @@ -129,8 +124,7 @@ void JavaCommon::TestCheck::run() | ||||
|  | ||||
| void JavaCommon::TestCheck::checkFinished(JavaCheckResult result) | ||||
| { | ||||
|     if (result.validity != JavaCheckResult::Validity::Valid) | ||||
|     { | ||||
|     if (result.validity != JavaCheckResult::Validity::Valid) { | ||||
|         javaBinaryWasBad(m_parent, result); | ||||
|         emit finished(); | ||||
|         return; | ||||
| @@ -141,8 +135,7 @@ void JavaCommon::TestCheck::checkFinished(JavaCheckResult result) | ||||
|     checker->m_args = m_args; | ||||
|     checker->m_minMem = m_minMem; | ||||
|     checker->m_maxMem = m_maxMem; | ||||
|     if (result.javaVersion.requiresPermGen()) | ||||
|     { | ||||
|     if (result.javaVersion.requiresPermGen()) { | ||||
|         checker->m_permGen = m_permGen; | ||||
|     } | ||||
|     checker->performCheck(); | ||||
| @@ -150,8 +143,7 @@ void JavaCommon::TestCheck::checkFinished(JavaCheckResult result) | ||||
|  | ||||
| void JavaCommon::TestCheck::checkFinishedWithArgs(JavaCheckResult result) | ||||
| { | ||||
|     if (result.validity == JavaCheckResult::Validity::Valid) | ||||
|     { | ||||
|     if (result.validity == JavaCheckResult::Validity::Valid) { | ||||
|         javaWasOk(m_parent, result); | ||||
|         emit finished(); | ||||
|         return; | ||||
| @@ -159,4 +151,3 @@ void JavaCommon::TestCheck::checkFinishedWithArgs(JavaCheckResult result) | ||||
|     javaArgsWereBad(m_parent, result); | ||||
|     emit finished(); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -6,45 +6,42 @@ class QWidget; | ||||
| /** | ||||
|  * Common UI bits for the java pages to use. | ||||
|  */ | ||||
| namespace JavaCommon | ||||
| { | ||||
|     bool checkJVMArgs(QString args, QWidget *parent); | ||||
| namespace JavaCommon { | ||||
| bool checkJVMArgs(QString args, QWidget* parent); | ||||
|  | ||||
|     // 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); | ||||
| // Show a dialog saying that the Java binary was usable | ||||
| void javaWasOk(QWidget* parent, const JavaCheckResult& result); | ||||
| // Show a dialog saying that the Java binary was not usable because of bad options | ||||
| void javaArgsWereBad(QWidget* parent, const JavaCheckResult& result); | ||||
| // Show a dialog saying that the Java binary was not usable | ||||
| void javaBinaryWasBad(QWidget* parent, const JavaCheckResult& result); | ||||
| // Show a dialog if we couldn't find Java Checker | ||||
| void javaCheckNotFound(QWidget* parent); | ||||
|  | ||||
|     class TestCheck : public QObject | ||||
|     { | ||||
|         Q_OBJECT | ||||
|     public: | ||||
|         TestCheck(QWidget *parent, QString path, QString args, int minMem, int maxMem, int permGen) | ||||
|             :m_parent(parent), m_path(path), m_args(args), m_minMem(minMem), m_maxMem(maxMem), m_permGen(permGen) | ||||
|         { | ||||
|         } | ||||
|         virtual ~TestCheck() {}; | ||||
| class TestCheck : public QObject { | ||||
|     Q_OBJECT | ||||
|    public: | ||||
|     TestCheck(QWidget* parent, QString path, QString args, int minMem, int maxMem, int permGen) | ||||
|         : m_parent(parent), m_path(path), m_args(args), m_minMem(minMem), m_maxMem(maxMem), m_permGen(permGen) | ||||
|     {} | ||||
|     virtual ~TestCheck(){}; | ||||
|  | ||||
|         void run(); | ||||
|     void run(); | ||||
|  | ||||
|     signals: | ||||
|         void finished(); | ||||
|    signals: | ||||
|     void finished(); | ||||
|  | ||||
|     private slots: | ||||
|         void checkFinished(JavaCheckResult result); | ||||
|         void checkFinishedWithArgs(JavaCheckResult result); | ||||
|    private slots: | ||||
|     void checkFinished(JavaCheckResult result); | ||||
|     void checkFinishedWithArgs(JavaCheckResult result); | ||||
|  | ||||
|     private: | ||||
|         std::shared_ptr<JavaChecker> checker; | ||||
|         QWidget *m_parent = nullptr; | ||||
|         QString m_path; | ||||
|         QString m_args; | ||||
|         int m_minMem = 0; | ||||
|         int m_maxMem = 0; | ||||
|         int m_permGen = 64; | ||||
|     }; | ||||
| } | ||||
|    private: | ||||
|     std::shared_ptr<JavaChecker> checker; | ||||
|     QWidget* m_parent = nullptr; | ||||
|     QString m_path; | ||||
|     QString m_args; | ||||
|     int m_minMem = 0; | ||||
|     int m_maxMem = 0; | ||||
|     int m_permGen = 64; | ||||
| }; | ||||
| }  // namespace JavaCommon | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
| @@ -37,257 +37,246 @@ | ||||
|  | ||||
| #include <QFile> | ||||
|  | ||||
| #include "FileSystem.h" | ||||
| #include <math.h> | ||||
| #include "FileSystem.h" | ||||
|  | ||||
| namespace Json | ||||
| { | ||||
| void write(const QJsonDocument &doc, const QString &filename) | ||||
| namespace Json { | ||||
| void write(const QJsonDocument& doc, const QString& filename) | ||||
| { | ||||
|     FS::write(filename, doc.toJson()); | ||||
| } | ||||
| void write(const QJsonObject &object, const QString &filename) | ||||
| void write(const QJsonObject& object, const QString& filename) | ||||
| { | ||||
|     write(QJsonDocument(object), filename); | ||||
| } | ||||
| void write(const QJsonArray &array, const QString &filename) | ||||
| void write(const QJsonArray& array, const QString& filename) | ||||
| { | ||||
|     write(QJsonDocument(array), filename); | ||||
| } | ||||
|  | ||||
| QByteArray toText(const QJsonObject &obj) | ||||
| QByteArray toText(const QJsonObject& obj) | ||||
| { | ||||
|     return QJsonDocument(obj).toJson(QJsonDocument::Compact); | ||||
| } | ||||
| QByteArray toText(const QJsonArray &array) | ||||
| QByteArray toText(const QJsonArray& array) | ||||
| { | ||||
|     return QJsonDocument(array).toJson(QJsonDocument::Compact); | ||||
| } | ||||
|  | ||||
| static bool isBinaryJson(const QByteArray &data) | ||||
| static bool isBinaryJson(const QByteArray& data) | ||||
| { | ||||
|     decltype(QJsonDocument::BinaryFormatTag) tag = QJsonDocument::BinaryFormatTag; | ||||
|     return memcmp(data.constData(), &tag, sizeof(QJsonDocument::BinaryFormatTag)) == 0; | ||||
| } | ||||
| QJsonDocument requireDocument(const QByteArray &data, const QString &what) | ||||
| QJsonDocument requireDocument(const QByteArray& data, const QString& what) | ||||
| { | ||||
|     if (isBinaryJson(data)) | ||||
|     { | ||||
|     if (isBinaryJson(data)) { | ||||
|         // FIXME: Is this needed? | ||||
|         throw JsonException(what + ": Invalid JSON. Binary JSON unsupported"); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|     } else { | ||||
|         QJsonParseError error; | ||||
|         QJsonDocument doc = QJsonDocument::fromJson(data, &error); | ||||
|         if (error.error != QJsonParseError::NoError) | ||||
|         { | ||||
|         if (error.error != QJsonParseError::NoError) { | ||||
|             throw JsonException(what + ": Error parsing JSON: " + error.errorString()); | ||||
|         } | ||||
|         return doc; | ||||
|     } | ||||
| } | ||||
| QJsonDocument requireDocument(const QString &filename, const QString &what) | ||||
| QJsonDocument requireDocument(const QString& filename, const QString& what) | ||||
| { | ||||
|     return requireDocument(FS::read(filename), what); | ||||
| } | ||||
| QJsonObject requireObject(const QJsonDocument &doc, const QString &what) | ||||
| QJsonObject requireObject(const QJsonDocument& doc, const QString& what) | ||||
| { | ||||
|     if (!doc.isObject()) | ||||
|     { | ||||
|     if (!doc.isObject()) { | ||||
|         throw JsonException(what + " is not an object"); | ||||
|     } | ||||
|     return doc.object(); | ||||
| } | ||||
| QJsonArray requireArray(const QJsonDocument &doc, const QString &what) | ||||
| QJsonArray requireArray(const QJsonDocument& doc, const QString& what) | ||||
| { | ||||
|     if (!doc.isArray()) | ||||
|     { | ||||
|     if (!doc.isArray()) { | ||||
|         throw JsonException(what + " is not an array"); | ||||
|     } | ||||
|     return doc.array(); | ||||
| } | ||||
|  | ||||
| void writeString(QJsonObject &to, const QString &key, const QString &value) | ||||
| void writeString(QJsonObject& to, const QString& key, const QString& value) | ||||
| { | ||||
|     if (!value.isEmpty()) | ||||
|     { | ||||
|     if (!value.isEmpty()) { | ||||
|         to.insert(key, value); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void writeStringList(QJsonObject &to, const QString &key, const QStringList &values) | ||||
| void writeStringList(QJsonObject& to, const QString& key, const QStringList& values) | ||||
| { | ||||
|     if (!values.isEmpty()) | ||||
|     { | ||||
|     if (!values.isEmpty()) { | ||||
|         QJsonArray array; | ||||
|         for(auto value: values) | ||||
|         { | ||||
|         for (auto value : values) { | ||||
|             array.append(value); | ||||
|         } | ||||
|         to.insert(key, array); | ||||
|     } | ||||
| } | ||||
|  | ||||
| template<> | ||||
| QJsonValue toJson<QUrl>(const QUrl &url) | ||||
| template <> | ||||
| QJsonValue toJson<QUrl>(const QUrl& url) | ||||
| { | ||||
|     return QJsonValue(url.toString(QUrl::FullyEncoded)); | ||||
| } | ||||
| template<> | ||||
| QJsonValue toJson<QByteArray>(const QByteArray &data) | ||||
| template <> | ||||
| QJsonValue toJson<QByteArray>(const QByteArray& data) | ||||
| { | ||||
|     return QJsonValue(QString::fromLatin1(data.toHex())); | ||||
| } | ||||
| template<> | ||||
| QJsonValue toJson<QDateTime>(const QDateTime &datetime) | ||||
| template <> | ||||
| QJsonValue toJson<QDateTime>(const QDateTime& datetime) | ||||
| { | ||||
|     return QJsonValue(datetime.toString(Qt::ISODate)); | ||||
| } | ||||
| template<> | ||||
| QJsonValue toJson<QDir>(const QDir &dir) | ||||
| template <> | ||||
| QJsonValue toJson<QDir>(const QDir& dir) | ||||
| { | ||||
|     return QDir::current().relativeFilePath(dir.absolutePath()); | ||||
| } | ||||
| template<> | ||||
| QJsonValue toJson<QUuid>(const QUuid &uuid) | ||||
| template <> | ||||
| QJsonValue toJson<QUuid>(const QUuid& uuid) | ||||
| { | ||||
|     return uuid.toString(); | ||||
| } | ||||
| template<> | ||||
| QJsonValue toJson<QVariant>(const QVariant &variant) | ||||
| template <> | ||||
| QJsonValue toJson<QVariant>(const QVariant& variant) | ||||
| { | ||||
|     return QJsonValue::fromVariant(variant); | ||||
| } | ||||
|  | ||||
|  | ||||
| template<> QByteArray requireIsType<QByteArray>(const QJsonValue &value, const QString &what) | ||||
| template <> | ||||
| QByteArray requireIsType<QByteArray>(const QJsonValue& value, const QString& what) | ||||
| { | ||||
|     const QString string = ensureIsType<QString>(value, what); | ||||
|     // ensure that the string can be safely cast to Latin1 | ||||
|     if (string != QString::fromLatin1(string.toLatin1())) | ||||
|     { | ||||
|     if (string != QString::fromLatin1(string.toLatin1())) { | ||||
|         throw JsonException(what + " is not encodable as Latin1"); | ||||
|     } | ||||
|     return QByteArray::fromHex(string.toLatin1()); | ||||
| } | ||||
|  | ||||
| template<> QJsonArray requireIsType<QJsonArray>(const QJsonValue &value, const QString &what) | ||||
| template <> | ||||
| QJsonArray requireIsType<QJsonArray>(const QJsonValue& value, const QString& what) | ||||
| { | ||||
|     if (!value.isArray()) | ||||
|     { | ||||
|     if (!value.isArray()) { | ||||
|         throw JsonException(what + " is not an array"); | ||||
|     } | ||||
|     return value.toArray(); | ||||
| } | ||||
|  | ||||
|  | ||||
| template<> QString requireIsType<QString>(const QJsonValue &value, const QString &what) | ||||
| template <> | ||||
| QString requireIsType<QString>(const QJsonValue& value, const QString& what) | ||||
| { | ||||
|     if (!value.isString()) | ||||
|     { | ||||
|     if (!value.isString()) { | ||||
|         throw JsonException(what + " is not a string"); | ||||
|     } | ||||
|     return value.toString(); | ||||
| } | ||||
|  | ||||
| template<> bool requireIsType<bool>(const QJsonValue &value, const QString &what) | ||||
| template <> | ||||
| bool requireIsType<bool>(const QJsonValue& value, const QString& what) | ||||
| { | ||||
|     if (!value.isBool()) | ||||
|     { | ||||
|     if (!value.isBool()) { | ||||
|         throw JsonException(what + " is not a bool"); | ||||
|     } | ||||
|     return value.toBool(); | ||||
| } | ||||
|  | ||||
| template<> double requireIsType<double>(const QJsonValue &value, const QString &what) | ||||
| template <> | ||||
| double requireIsType<double>(const QJsonValue& value, const QString& what) | ||||
| { | ||||
|     if (!value.isDouble()) | ||||
|     { | ||||
|     if (!value.isDouble()) { | ||||
|         throw JsonException(what + " is not a double"); | ||||
|     } | ||||
|     return value.toDouble(); | ||||
| } | ||||
|  | ||||
| template<> int requireIsType<int>(const QJsonValue &value, const QString &what) | ||||
| template <> | ||||
| int requireIsType<int>(const QJsonValue& value, const QString& what) | ||||
| { | ||||
|     const double doubl = requireIsType<double>(value, what); | ||||
|     if (fmod(doubl, 1) != 0) | ||||
|     { | ||||
|     if (fmod(doubl, 1) != 0) { | ||||
|         throw JsonException(what + " is not an integer"); | ||||
|     } | ||||
|     return int(doubl); | ||||
| } | ||||
|  | ||||
| template<> QDateTime requireIsType<QDateTime>(const QJsonValue &value, const QString &what) | ||||
| template <> | ||||
| QDateTime requireIsType<QDateTime>(const QJsonValue& value, const QString& what) | ||||
| { | ||||
|     const QString string = requireIsType<QString>(value, what); | ||||
|     const QDateTime datetime = QDateTime::fromString(string, Qt::ISODate); | ||||
|     if (!datetime.isValid()) | ||||
|     { | ||||
|     if (!datetime.isValid()) { | ||||
|         throw JsonException(what + " is not a ISO formatted date/time value"); | ||||
|     } | ||||
|     return datetime; | ||||
| } | ||||
|  | ||||
| template<> QUrl requireIsType<QUrl>(const QJsonValue &value, const QString &what) | ||||
| template <> | ||||
| QUrl requireIsType<QUrl>(const QJsonValue& value, const QString& what) | ||||
| { | ||||
|     const QString string = ensureIsType<QString>(value, what); | ||||
|     if (string.isEmpty()) | ||||
|     { | ||||
|     if (string.isEmpty()) { | ||||
|         return QUrl(); | ||||
|     } | ||||
|     const QUrl url = QUrl(string, QUrl::StrictMode); | ||||
|     if (!url.isValid()) | ||||
|     { | ||||
|     if (!url.isValid()) { | ||||
|         throw JsonException(what + " is not a correctly formatted URL"); | ||||
|     } | ||||
|     return url; | ||||
| } | ||||
|  | ||||
| template<> QDir requireIsType<QDir>(const QJsonValue &value, const QString &what) | ||||
| template <> | ||||
| QDir requireIsType<QDir>(const QJsonValue& value, const QString& what) | ||||
| { | ||||
|     const QString string = requireIsType<QString>(value, what); | ||||
|     // FIXME: does not handle invalid characters! | ||||
|     return QDir::current().absoluteFilePath(string); | ||||
| } | ||||
|  | ||||
| template<> QUuid requireIsType<QUuid>(const QJsonValue &value, const QString &what) | ||||
| template <> | ||||
| QUuid requireIsType<QUuid>(const QJsonValue& value, const QString& what) | ||||
| { | ||||
|     const QString string = requireIsType<QString>(value, what); | ||||
|     const QUuid uuid = QUuid(string); | ||||
|     if (uuid.toString() != string) // converts back => valid | ||||
|     if (uuid.toString() != string)  // converts back => valid | ||||
|     { | ||||
|         throw JsonException(what + " is not a valid UUID"); | ||||
|     } | ||||
|     return uuid; | ||||
| } | ||||
|  | ||||
| template<> QJsonObject requireIsType<QJsonObject>(const QJsonValue &value, const QString &what) | ||||
| template <> | ||||
| QJsonObject requireIsType<QJsonObject>(const QJsonValue& value, const QString& what) | ||||
| { | ||||
|     if (!value.isObject()) | ||||
|     { | ||||
|     if (!value.isObject()) { | ||||
|         throw JsonException(what + " is not an object"); | ||||
|     } | ||||
|     return value.toObject(); | ||||
| } | ||||
|  | ||||
| template<> QVariant requireIsType<QVariant>(const QJsonValue &value, const QString &what) | ||||
| template <> | ||||
| QVariant requireIsType<QVariant>(const QJsonValue& value, const QString& what) | ||||
| { | ||||
|     if (value.isNull() || value.isUndefined()) | ||||
|     { | ||||
|     if (value.isNull() || value.isUndefined()) { | ||||
|         throw JsonException(what + " is null or undefined"); | ||||
|     } | ||||
|     return value.toVariant(); | ||||
| } | ||||
|  | ||||
| template<> QJsonValue requireIsType<QJsonValue>(const QJsonValue &value, const QString &what) | ||||
| template <> | ||||
| QJsonValue requireIsType<QJsonValue>(const QJsonValue& value, const QString& what) | ||||
| { | ||||
|     if (value.isNull() || value.isUndefined()) | ||||
|     { | ||||
|     if (value.isNull() || value.isUndefined()) { | ||||
|         throw JsonException(what + " is null or undefined"); | ||||
|     } | ||||
|     return value; | ||||
| } | ||||
|  | ||||
| } | ||||
| }  // namespace Json | ||||
|   | ||||
							
								
								
									
										204
									
								
								launcher/Json.h
									
									
									
									
									
								
							
							
						
						
									
										204
									
								
								launcher/Json.h
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
| @@ -35,74 +35,71 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <QJsonDocument> | ||||
| #include <QJsonArray> | ||||
| #include <QJsonObject> | ||||
| #include <QDateTime> | ||||
| #include <QUrl> | ||||
| #include <QDir> | ||||
| #include <QJsonArray> | ||||
| #include <QJsonDocument> | ||||
| #include <QJsonObject> | ||||
| #include <QUrl> | ||||
| #include <QUuid> | ||||
| #include <QVariant> | ||||
| #include <memory> | ||||
|  | ||||
| #include "Exception.h" | ||||
|  | ||||
| namespace Json | ||||
| { | ||||
| class JsonException : public ::Exception | ||||
| { | ||||
| public: | ||||
|     JsonException(const QString &message) : Exception(message) {} | ||||
| namespace Json { | ||||
| class JsonException : public ::Exception { | ||||
|    public: | ||||
|     JsonException(const QString& message) : Exception(message) {} | ||||
| }; | ||||
|  | ||||
| /// @throw FileSystemException | ||||
| void write(const QJsonDocument &doc, const QString &filename); | ||||
| void write(const QJsonDocument& doc, const QString& filename); | ||||
| /// @throw FileSystemException | ||||
| void write(const QJsonObject &object, const QString &filename); | ||||
| void write(const QJsonObject& object, const QString& filename); | ||||
| /// @throw FileSystemException | ||||
| void write(const QJsonArray &array, const QString &filename); | ||||
| void write(const QJsonArray& array, const QString& filename); | ||||
|  | ||||
| QByteArray toText(const QJsonObject &obj); | ||||
| QByteArray toText(const QJsonArray &array); | ||||
| QByteArray toText(const QJsonObject& obj); | ||||
| QByteArray toText(const QJsonArray& array); | ||||
|  | ||||
| /// @throw JsonException | ||||
| QJsonDocument requireDocument(const QByteArray &data, const QString &what = "Document"); | ||||
| QJsonDocument requireDocument(const QByteArray& data, const QString& what = "Document"); | ||||
| /// @throw JsonException | ||||
| QJsonDocument requireDocument(const QString &filename, const QString &what = "Document"); | ||||
| QJsonDocument requireDocument(const QString& filename, const QString& what = "Document"); | ||||
| /// @throw JsonException | ||||
| QJsonObject requireObject(const QJsonDocument &doc, const QString &what = "Document"); | ||||
| QJsonObject requireObject(const QJsonDocument& doc, const QString& what = "Document"); | ||||
| /// @throw JsonException | ||||
| QJsonArray requireArray(const QJsonDocument &doc, const QString &what = "Document"); | ||||
| QJsonArray requireArray(const QJsonDocument& doc, const QString& what = "Document"); | ||||
|  | ||||
| /////////////////// WRITING //////////////////// | ||||
|  | ||||
| void writeString(QJsonObject & to, const QString &key, const QString &value); | ||||
| void writeStringList(QJsonObject & to, const QString &key, const QStringList &values); | ||||
| void writeString(QJsonObject& to, const QString& key, const QString& value); | ||||
| void writeStringList(QJsonObject& to, const QString& key, const QStringList& values); | ||||
|  | ||||
| template<typename T> | ||||
| QJsonValue toJson(const T &t) | ||||
| template <typename T> | ||||
| QJsonValue toJson(const T& t) | ||||
| { | ||||
|     return QJsonValue(t); | ||||
| } | ||||
| template<> | ||||
| QJsonValue toJson<QUrl>(const QUrl &url); | ||||
| template<> | ||||
| QJsonValue toJson<QByteArray>(const QByteArray &data); | ||||
| template<> | ||||
| QJsonValue toJson<QDateTime>(const QDateTime &datetime); | ||||
| template<> | ||||
| QJsonValue toJson<QDir>(const QDir &dir); | ||||
| template<> | ||||
| QJsonValue toJson<QUuid>(const QUuid &uuid); | ||||
| template<> | ||||
| QJsonValue toJson<QVariant>(const QVariant &variant); | ||||
| template <> | ||||
| QJsonValue toJson<QUrl>(const QUrl& url); | ||||
| template <> | ||||
| QJsonValue toJson<QByteArray>(const QByteArray& data); | ||||
| template <> | ||||
| QJsonValue toJson<QDateTime>(const QDateTime& datetime); | ||||
| template <> | ||||
| QJsonValue toJson<QDir>(const QDir& dir); | ||||
| template <> | ||||
| QJsonValue toJson<QUuid>(const QUuid& uuid); | ||||
| template <> | ||||
| QJsonValue toJson<QVariant>(const QVariant& variant); | ||||
|  | ||||
| template<typename T> | ||||
| QJsonArray toJsonArray(const QList<T> &container) | ||||
| template <typename T> | ||||
| QJsonArray toJsonArray(const QList<T>& container) | ||||
| { | ||||
|     QJsonArray array; | ||||
|     for (const T item : container) | ||||
|     { | ||||
|     for (const T item : container) { | ||||
|         array.append(toJson<T>(item)); | ||||
|     } | ||||
|     return array; | ||||
| @@ -112,106 +109,110 @@ QJsonArray toJsonArray(const QList<T> &container) | ||||
|  | ||||
| /// @throw JsonException | ||||
| template <typename T> | ||||
| T requireIsType(const QJsonValue &value, const QString &what = "Value"); | ||||
| T requireIsType(const QJsonValue& value, const QString& what = "Value"); | ||||
|  | ||||
| /// @throw JsonException | ||||
| template<> double requireIsType<double>(const QJsonValue &value, const QString &what); | ||||
| template <> | ||||
| double requireIsType<double>(const QJsonValue& value, const QString& what); | ||||
| /// @throw JsonException | ||||
| template<> bool requireIsType<bool>(const QJsonValue &value, const QString &what); | ||||
| template <> | ||||
| bool requireIsType<bool>(const QJsonValue& value, const QString& what); | ||||
| /// @throw JsonException | ||||
| template<> int requireIsType<int>(const QJsonValue &value, const QString &what); | ||||
| template <> | ||||
| int requireIsType<int>(const QJsonValue& value, const QString& what); | ||||
| /// @throw JsonException | ||||
| template<> QJsonObject requireIsType<QJsonObject>(const QJsonValue &value, const QString &what); | ||||
| template <> | ||||
| QJsonObject requireIsType<QJsonObject>(const QJsonValue& value, const QString& what); | ||||
| /// @throw JsonException | ||||
| template<> QJsonArray requireIsType<QJsonArray>(const QJsonValue &value, const QString &what); | ||||
| template <> | ||||
| QJsonArray requireIsType<QJsonArray>(const QJsonValue& value, const QString& what); | ||||
| /// @throw JsonException | ||||
| template<> QJsonValue requireIsType<QJsonValue>(const QJsonValue &value, const QString &what); | ||||
| template <> | ||||
| QJsonValue requireIsType<QJsonValue>(const QJsonValue& value, const QString& what); | ||||
| /// @throw JsonException | ||||
| template<> QByteArray requireIsType<QByteArray>(const QJsonValue &value, const QString &what); | ||||
| template <> | ||||
| QByteArray requireIsType<QByteArray>(const QJsonValue& value, const QString& what); | ||||
| /// @throw JsonException | ||||
| template<> QDateTime requireIsType<QDateTime>(const QJsonValue &value, const QString &what); | ||||
| template <> | ||||
| QDateTime requireIsType<QDateTime>(const QJsonValue& value, const QString& what); | ||||
| /// @throw JsonException | ||||
| template<> QVariant requireIsType<QVariant>(const QJsonValue &value, const QString &what); | ||||
| template <> | ||||
| QVariant requireIsType<QVariant>(const QJsonValue& value, const QString& what); | ||||
| /// @throw JsonException | ||||
| template<> QString requireIsType<QString>(const QJsonValue &value, const QString &what); | ||||
| template <> | ||||
| QString requireIsType<QString>(const QJsonValue& value, const QString& what); | ||||
| /// @throw JsonException | ||||
| template<> QUuid requireIsType<QUuid>(const QJsonValue &value, const QString &what); | ||||
| template <> | ||||
| QUuid requireIsType<QUuid>(const QJsonValue& value, const QString& what); | ||||
| /// @throw JsonException | ||||
| template<> QDir requireIsType<QDir>(const QJsonValue &value, const QString &what); | ||||
| template <> | ||||
| QDir requireIsType<QDir>(const QJsonValue& value, const QString& what); | ||||
| /// @throw JsonException | ||||
| template<> QUrl requireIsType<QUrl>(const QJsonValue &value, const QString &what); | ||||
| template <> | ||||
| QUrl requireIsType<QUrl>(const QJsonValue& value, const QString& what); | ||||
|  | ||||
| // the following functions are higher level functions, that make use of the above functions for | ||||
| // type conversion | ||||
| template <typename T> | ||||
| T ensureIsType(const QJsonValue &value, const T default_ = T(), const QString &what = "Value") | ||||
| T ensureIsType(const QJsonValue& value, const T default_ = T(), const QString& what = "Value") | ||||
| { | ||||
|     if (value.isUndefined() || value.isNull()) | ||||
|     { | ||||
|     if (value.isUndefined() || value.isNull()) { | ||||
|         return default_; | ||||
|     } | ||||
|     try | ||||
|     { | ||||
|     try { | ||||
|         return requireIsType<T>(value, what); | ||||
|     } | ||||
|     catch (const JsonException &) | ||||
|     { | ||||
|     } catch (const JsonException&) { | ||||
|         return default_; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// @throw JsonException | ||||
| template <typename T> | ||||
| T requireIsType(const QJsonObject &parent, const QString &key, const QString &what = "__placeholder__") | ||||
| T requireIsType(const QJsonObject& parent, const QString& key, const QString& what = "__placeholder__") | ||||
| { | ||||
|     const QString localWhat = QString(what).replace("__placeholder__", '\'' + key + '\''); | ||||
|     if (!parent.contains(key)) | ||||
|     { | ||||
|     if (!parent.contains(key)) { | ||||
|         throw JsonException(localWhat + "s parent does not contain " + localWhat); | ||||
|     } | ||||
|     return requireIsType<T>(parent.value(key), localWhat); | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| T ensureIsType(const QJsonObject &parent, const QString &key, const T default_ = T(), const QString &what = "__placeholder__") | ||||
| T ensureIsType(const QJsonObject& parent, const QString& key, const T default_ = T(), const QString& what = "__placeholder__") | ||||
| { | ||||
|     const QString localWhat = QString(what).replace("__placeholder__", '\'' + key + '\''); | ||||
|     if (!parent.contains(key)) | ||||
|     { | ||||
|     if (!parent.contains(key)) { | ||||
|         return default_; | ||||
|     } | ||||
|     return ensureIsType<T>(parent.value(key), default_, localWhat); | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| QVector<T> requireIsArrayOf(const QJsonDocument &doc) | ||||
| QVector<T> requireIsArrayOf(const QJsonDocument& doc) | ||||
| { | ||||
|     const QJsonArray array = requireArray(doc); | ||||
|     QVector<T> out; | ||||
|     for (const QJsonValue val : array) | ||||
|     { | ||||
|     for (const QJsonValue val : array) { | ||||
|         out.append(requireIsType<T>(val, "Document")); | ||||
|     } | ||||
|     return out; | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| QVector<T> ensureIsArrayOf(const QJsonValue &value, const QString &what = "Value") | ||||
| QVector<T> ensureIsArrayOf(const QJsonValue& value, const QString& what = "Value") | ||||
| { | ||||
|     const QJsonArray array = ensureIsType<QJsonArray>(value, QJsonArray(), what); | ||||
|     QVector<T> out; | ||||
|     for (const QJsonValue val : array) | ||||
|     { | ||||
|     for (const QJsonValue val : array) { | ||||
|         out.append(requireIsType<T>(val, what)); | ||||
|     } | ||||
|     return out; | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| QVector<T> ensureIsArrayOf(const QJsonValue &value, const QVector<T> default_, const QString &what = "Value") | ||||
| QVector<T> ensureIsArrayOf(const QJsonValue& value, const QVector<T> default_, const QString& what = "Value") | ||||
| { | ||||
|     if (value.isUndefined()) | ||||
|     { | ||||
|     if (value.isUndefined()) { | ||||
|         return default_; | ||||
|     } | ||||
|     return ensureIsArrayOf<T>(value, what); | ||||
| @@ -219,45 +220,46 @@ QVector<T> ensureIsArrayOf(const QJsonValue &value, const QVector<T> default_, c | ||||
|  | ||||
| /// @throw JsonException | ||||
| template <typename T> | ||||
| QVector<T> requireIsArrayOf(const QJsonObject &parent, const QString &key, const QString &what = "__placeholder__") | ||||
| QVector<T> requireIsArrayOf(const QJsonObject& parent, const QString& key, const QString& what = "__placeholder__") | ||||
| { | ||||
|     const QString localWhat = QString(what).replace("__placeholder__", '\'' + key + '\''); | ||||
|     if (!parent.contains(key)) | ||||
|     { | ||||
|     if (!parent.contains(key)) { | ||||
|         throw JsonException(localWhat + "s parent does not contain " + localWhat); | ||||
|     } | ||||
|     return ensureIsArrayOf<T>(parent.value(key), localWhat); | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| QVector<T> ensureIsArrayOf(const QJsonObject &parent, const QString &key, | ||||
|                          const QVector<T> &default_ = QVector<T>(), const QString &what = "__placeholder__") | ||||
| QVector<T> ensureIsArrayOf(const QJsonObject& parent, | ||||
|                            const QString& key, | ||||
|                            const QVector<T>& default_ = QVector<T>(), | ||||
|                            const QString& what = "__placeholder__") | ||||
| { | ||||
|     const QString localWhat = QString(what).replace("__placeholder__", '\'' + key + '\''); | ||||
|     if (!parent.contains(key)) | ||||
|     { | ||||
|     if (!parent.contains(key)) { | ||||
|         return default_; | ||||
|     } | ||||
|     return ensureIsArrayOf<T>(parent.value(key), default_, localWhat); | ||||
| } | ||||
|  | ||||
| // this macro part could be replaced by variadic functions that just pass on their arguments, but that wouldn't work well with IDE helpers | ||||
| #define JSON_HELPERFUNCTIONS(NAME, TYPE) \ | ||||
|     inline TYPE require##NAME(const QJsonValue &value, const QString &what = "Value") \ | ||||
|     { \ | ||||
|         return requireIsType<TYPE>(value, what); \ | ||||
|     } \ | ||||
|     inline TYPE ensure##NAME(const QJsonValue &value, const TYPE default_ = TYPE(), const QString &what = "Value") \ | ||||
|     { \ | ||||
|         return ensureIsType<TYPE>(value, default_, what); \ | ||||
|     } \ | ||||
|     inline TYPE require##NAME(const QJsonObject &parent, const QString &key, const QString &what = "__placeholder__") \ | ||||
|     { \ | ||||
|         return requireIsType<TYPE>(parent, key, what); \ | ||||
|     } \ | ||||
|     inline TYPE ensure##NAME(const QJsonObject &parent, const QString &key, const TYPE default_ = TYPE(), const QString &what = "__placeholder") \ | ||||
|     { \ | ||||
|         return ensureIsType<TYPE>(parent, key, default_, what); \ | ||||
| #define JSON_HELPERFUNCTIONS(NAME, TYPE)                                                                              \ | ||||
|     inline TYPE require##NAME(const QJsonValue& value, const QString& what = "Value")                                 \ | ||||
|     {                                                                                                                 \ | ||||
|         return requireIsType<TYPE>(value, what);                                                                      \ | ||||
|     }                                                                                                                 \ | ||||
|     inline TYPE ensure##NAME(const QJsonValue& value, const TYPE default_ = TYPE(), const QString& what = "Value")    \ | ||||
|     {                                                                                                                 \ | ||||
|         return ensureIsType<TYPE>(value, default_, what);                                                             \ | ||||
|     }                                                                                                                 \ | ||||
|     inline TYPE require##NAME(const QJsonObject& parent, const QString& key, const QString& what = "__placeholder__") \ | ||||
|     {                                                                                                                 \ | ||||
|         return requireIsType<TYPE>(parent, key, what);                                                                \ | ||||
|     }                                                                                                                 \ | ||||
|     inline TYPE ensure##NAME(const QJsonObject& parent, const QString& key, const TYPE default_ = TYPE(),             \ | ||||
|                              const QString& what = "__placeholder")                                                   \ | ||||
|     {                                                                                                                 \ | ||||
|         return ensureIsType<TYPE>(parent, key, default_, what);                                                       \ | ||||
|     } | ||||
|  | ||||
| JSON_HELPERFUNCTIONS(Array, QJsonArray) | ||||
| @@ -276,5 +278,5 @@ JSON_HELPERFUNCTIONS(Variant, QVariant) | ||||
|  | ||||
| #undef JSON_HELPERFUNCTIONS | ||||
|  | ||||
| } | ||||
| }  // namespace Json | ||||
| using JSONValidationError = Json::JsonException; | ||||
|   | ||||
| @@ -1,42 +1,26 @@ | ||||
| #include "KonamiCode.h" | ||||
|  | ||||
| #include <array> | ||||
| #include <QDebug> | ||||
| #include <array> | ||||
|  | ||||
| namespace { | ||||
| const std::array<Qt::Key, 10> konamiCode = | ||||
| { | ||||
|     { | ||||
|         Qt::Key_Up, Qt::Key_Up, | ||||
|         Qt::Key_Down, Qt::Key_Down, | ||||
|         Qt::Key_Left, Qt::Key_Right, | ||||
|         Qt::Key_Left, Qt::Key_Right, | ||||
|         Qt::Key_B, Qt::Key_A | ||||
|     } | ||||
| }; | ||||
| } | ||||
|  | ||||
| KonamiCode::KonamiCode(QObject* parent) : QObject(parent) | ||||
| { | ||||
| const std::array<Qt::Key, 10> konamiCode = { { Qt::Key_Up, Qt::Key_Up, Qt::Key_Down, Qt::Key_Down, Qt::Key_Left, Qt::Key_Right, | ||||
|                                                Qt::Key_Left, Qt::Key_Right, Qt::Key_B, Qt::Key_A } }; | ||||
| } | ||||
|  | ||||
| KonamiCode::KonamiCode(QObject* parent) : QObject(parent) {} | ||||
|  | ||||
| void KonamiCode::input(QEvent* event) | ||||
| { | ||||
|     if( event->type() == QEvent::KeyPress ) | ||||
|     { | ||||
|         QKeyEvent *keyEvent = static_cast<QKeyEvent*>( event ); | ||||
|     if (event->type() == QEvent::KeyPress) { | ||||
|         QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event); | ||||
|         auto key = Qt::Key(keyEvent->key()); | ||||
|         if(key == konamiCode[m_progress]) | ||||
|         { | ||||
|             m_progress ++; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|         if (key == konamiCode[m_progress]) { | ||||
|             m_progress++; | ||||
|         } else { | ||||
|             m_progress = 0; | ||||
|         } | ||||
|         if(m_progress == static_cast<int>(konamiCode.size())) | ||||
|         { | ||||
|         if (m_progress == static_cast<int>(konamiCode.size())) { | ||||
|             m_progress = 0; | ||||
|             emit triggered(); | ||||
|         } | ||||
|   | ||||
| @@ -2,16 +2,15 @@ | ||||
|  | ||||
| #include <QKeyEvent> | ||||
|  | ||||
| class KonamiCode : public QObject | ||||
| { | ||||
| class KonamiCode : public QObject { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     KonamiCode(QObject *parent = 0); | ||||
|     void input(QEvent *event); | ||||
|    public: | ||||
|     KonamiCode(QObject* parent = 0); | ||||
|     void input(QEvent* event); | ||||
|  | ||||
| signals: | ||||
|    signals: | ||||
|     void triggered(); | ||||
|  | ||||
| private: | ||||
|    private: | ||||
|     int m_progress = 0; | ||||
| }; | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
| @@ -34,44 +34,41 @@ | ||||
|  */ | ||||
|  | ||||
| #include "LaunchController.h" | ||||
| #include "minecraft/auth/AccountList.h" | ||||
| #include "Application.h" | ||||
| #include "minecraft/auth/AccountList.h" | ||||
|  | ||||
| #include "ui/MainWindow.h" | ||||
| #include "ui/InstanceWindow.h" | ||||
| #include "ui/MainWindow.h" | ||||
| #include "ui/dialogs/CustomMessageBox.h" | ||||
| #include "ui/dialogs/ProfileSelectDialog.h" | ||||
| #include "ui/dialogs/ProgressDialog.h" | ||||
| #include "ui/dialogs/EditAccountDialog.h" | ||||
| #include "ui/dialogs/ProfileSelectDialog.h" | ||||
| #include "ui/dialogs/ProfileSetupDialog.h" | ||||
| #include "ui/dialogs/ProgressDialog.h" | ||||
|  | ||||
| #include <QLineEdit> | ||||
| #include <QInputDialog> | ||||
| #include <QStringList> | ||||
| #include <QHostInfo> | ||||
| #include <QList> | ||||
| #include <QHostAddress> | ||||
| #include <QHostInfo> | ||||
| #include <QInputDialog> | ||||
| #include <QLineEdit> | ||||
| #include <QList> | ||||
| #include <QPushButton> | ||||
| #include <QStringList> | ||||
|  | ||||
| #include "BuildConfig.h" | ||||
| #include "JavaCommon.h" | ||||
| #include "tasks/Task.h" | ||||
| #include "minecraft/auth/AccountTask.h" | ||||
| #include "launch/steps/TextPrint.h" | ||||
| #include "minecraft/auth/AccountTask.h" | ||||
| #include "tasks/Task.h" | ||||
|  | ||||
| LaunchController::LaunchController(QObject *parent) : Task(parent) | ||||
| { | ||||
| } | ||||
| LaunchController::LaunchController(QObject* parent) : Task(parent) {} | ||||
|  | ||||
| void LaunchController::executeTask() | ||||
| { | ||||
|     if (!m_instance) | ||||
|     { | ||||
|     if (!m_instance) { | ||||
|         emitFailed(tr("No instance specified!")); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if(!JavaCommon::checkJVMArgs(m_instance->settings()->get("JvmArgs").toString(), m_parentWidget)) { | ||||
|     if (!JavaCommon::checkJVMArgs(m_instance->settings()->get("JvmArgs").toString(), m_parentWidget)) { | ||||
|         emitFailed(tr("Invalid Java arguments specified. Please fix this first.")); | ||||
|         return; | ||||
|     } | ||||
| @@ -81,32 +78,25 @@ void LaunchController::executeTask() | ||||
|  | ||||
| void LaunchController::decideAccount() | ||||
| { | ||||
|     if(m_accountToUse) { | ||||
|     if (m_accountToUse) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     // Find an account to use. | ||||
|     auto accounts = APPLICATION->accounts(); | ||||
|     if (accounts->count() <= 0) | ||||
|     { | ||||
|     if (accounts->count() <= 0) { | ||||
|         // Tell the user they need to log in at least one account in order to play. | ||||
|         auto reply = CustomMessageBox::selectable( | ||||
|             m_parentWidget, | ||||
|             tr("No Accounts"), | ||||
|             tr("In order to play Minecraft, you must have at least one Microsoft or Mojang " | ||||
|                "account logged in. Mojang accounts can only be used offline. " | ||||
|                "Would you like to open the account manager to add an account now?"), | ||||
|             QMessageBox::Information, | ||||
|             QMessageBox::Yes | QMessageBox::No | ||||
|         )->exec(); | ||||
|         auto reply = CustomMessageBox::selectable(m_parentWidget, tr("No Accounts"), | ||||
|                                                   tr("In order to play Minecraft, you must have at least one Microsoft or Mojang " | ||||
|                                                      "account logged in. Mojang accounts can only be used offline. " | ||||
|                                                      "Would you like to open the account manager to add an account now?"), | ||||
|                                                   QMessageBox::Information, QMessageBox::Yes | QMessageBox::No) | ||||
|                          ->exec(); | ||||
|  | ||||
|         if (reply == QMessageBox::Yes) | ||||
|         { | ||||
|         if (reply == QMessageBox::Yes) { | ||||
|             // Open the account manager. | ||||
|             APPLICATION->ShowGlobalSettings(m_parentWidget, "accounts"); | ||||
|         } | ||||
|         else if (reply == QMessageBox::No) | ||||
|         { | ||||
|         } else if (reply == QMessageBox::No) { | ||||
|             // Do not open "profile select" dialog. | ||||
|             return; | ||||
|         } | ||||
| @@ -121,14 +111,10 @@ void LaunchController::decideAccount() | ||||
|         m_accountToUse = accounts->at(instanceAccountIndex); | ||||
|     } | ||||
|  | ||||
|     if (!m_accountToUse) | ||||
|     { | ||||
|     if (!m_accountToUse) { | ||||
|         // If no default account is set, ask the user which one to use. | ||||
|         ProfileSelectDialog selectDialog( | ||||
|             tr("Which account would you like to use?"), | ||||
|             ProfileSelectDialog::GlobalDefaultCheckbox, | ||||
|             m_parentWidget | ||||
|         ); | ||||
|         ProfileSelectDialog selectDialog(tr("Which account would you like to use?"), ProfileSelectDialog::GlobalDefaultCheckbox, | ||||
|                                          m_parentWidget); | ||||
|  | ||||
|         selectDialog.exec(); | ||||
|  | ||||
| @@ -142,13 +128,12 @@ void LaunchController::decideAccount() | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| void LaunchController::login() { | ||||
| void LaunchController::login() | ||||
| { | ||||
|     decideAccount(); | ||||
|  | ||||
|     // if no account is selected, we bail | ||||
|     if (!m_accountToUse) | ||||
|     { | ||||
|     if (!m_accountToUse) { | ||||
|         emitFailed(tr("No account selected for launch.")); | ||||
|         return; | ||||
|     } | ||||
| @@ -157,15 +142,11 @@ void LaunchController::login() { | ||||
|     bool tryagain = true; | ||||
|     unsigned int tries = 0; | ||||
|  | ||||
|     while (tryagain) | ||||
|     { | ||||
|     while (tryagain) { | ||||
|         if (tries > 0 && tries % 3 == 0) { | ||||
|             auto result = QMessageBox::question( | ||||
|                 m_parentWidget, | ||||
|                 tr("Continue launch?"), | ||||
|                 tr("It looks like we couldn't launch after %1 tries. Do you want to continue trying?") | ||||
|                     .arg(tries) | ||||
|             ); | ||||
|             auto result = | ||||
|                 QMessageBox::question(m_parentWidget, tr("Continue launch?"), | ||||
|                                       tr("It looks like we couldn't launch after %1 tries. Do you want to continue trying?").arg(tries)); | ||||
|  | ||||
|             if (result == QMessageBox::No) { | ||||
|                 emitAborted(); | ||||
| @@ -179,60 +160,48 @@ void LaunchController::login() { | ||||
|         m_accountToUse->fillSession(m_session); | ||||
|  | ||||
|         // Launch immediately in true offline mode | ||||
|         if(m_accountToUse->isOffline()) { | ||||
|         if (m_accountToUse->isOffline()) { | ||||
|             launchInstance(); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         switch(m_accountToUse->accountState()) { | ||||
|         switch (m_accountToUse->accountState()) { | ||||
|             case AccountState::Offline: { | ||||
|                 m_session->wants_online = false; | ||||
|             } | ||||
|             /* fallthrough */ | ||||
|             case AccountState::Online: { | ||||
|                 if(!m_session->wants_online) { | ||||
|                 if (!m_session->wants_online) { | ||||
|                     // we ask the user for a player name | ||||
|                     bool ok = false; | ||||
|  | ||||
|                     QString message = tr("Choose your offline mode player name."); | ||||
|                     if(m_session->demo) { | ||||
|                     if (m_session->demo) { | ||||
|                         message = tr("Choose your demo mode player name."); | ||||
|                     } | ||||
|  | ||||
|                     QString lastOfflinePlayerName = APPLICATION->settings()->get("LastOfflinePlayerName").toString(); | ||||
|                     QString usedname = lastOfflinePlayerName.isEmpty() ? m_session->player_name : lastOfflinePlayerName; | ||||
|                     QString name = QInputDialog::getText( | ||||
|                         m_parentWidget, | ||||
|                         tr("Player name"), | ||||
|                         message, | ||||
|                         QLineEdit::Normal, | ||||
|                         usedname, | ||||
|                         &ok | ||||
|                     ); | ||||
|                     if (!ok) | ||||
|                     { | ||||
|                     QString name = QInputDialog::getText(m_parentWidget, tr("Player name"), message, QLineEdit::Normal, usedname, &ok); | ||||
|                     if (!ok) { | ||||
|                         tryagain = false; | ||||
|                         break; | ||||
|                     } | ||||
|                     if (name.length()) | ||||
|                     { | ||||
|                     if (name.length()) { | ||||
|                         usedname = name; | ||||
|                         APPLICATION->settings()->set("LastOfflinePlayerName", usedname); | ||||
|                     } | ||||
|                     m_session->MakeOffline(usedname); | ||||
|                     // offline flavored game from here :3 | ||||
|                 } | ||||
|                 if(m_accountToUse->ownsMinecraft()) { | ||||
|                     if(!m_accountToUse->hasProfile()) { | ||||
|                 if (m_accountToUse->ownsMinecraft()) { | ||||
|                     if (!m_accountToUse->hasProfile()) { | ||||
|                         // Now handle setting up a profile name here... | ||||
|                         ProfileSetupDialog dialog(m_accountToUse, m_parentWidget); | ||||
|                         if (dialog.exec() == QDialog::Accepted) | ||||
|                         { | ||||
|                         if (dialog.exec() == QDialog::Accepted) { | ||||
|                             tryagain = true; | ||||
|                             continue; | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                         } else { | ||||
|                             emitFailed(tr("Received undetermined session status during login.")); | ||||
|                             return; | ||||
|                         } | ||||
| @@ -240,24 +209,24 @@ void LaunchController::login() { | ||||
|                     // we own Minecraft, there is a profile, it's all ready to go! | ||||
|                     launchInstance(); | ||||
|                     return; | ||||
|                 } | ||||
|                 else { | ||||
|                 } else { | ||||
|                     // play demo ? | ||||
|                     QMessageBox box(m_parentWidget); | ||||
|                     box.setWindowTitle(tr("Play demo?")); | ||||
|                     box.setText(tr("This account does not own Minecraft.\nYou need to purchase the game first to play it.\n\nDo you want to play the demo?")); | ||||
|                     box.setText( | ||||
|                         tr("This account does not own Minecraft.\nYou need to purchase the game first to play it.\n\nDo you want to play " | ||||
|                            "the demo?")); | ||||
|                     box.setIcon(QMessageBox::Warning); | ||||
|                     auto demoButton = box.addButton(tr("Play Demo"), QMessageBox::ButtonRole::YesRole); | ||||
|                     auto cancelButton = box.addButton(tr("Cancel"), QMessageBox::ButtonRole::NoRole); | ||||
|                     box.setDefaultButton(cancelButton); | ||||
|  | ||||
|                     box.exec(); | ||||
|                     if(box.clickedButton() == demoButton) { | ||||
|                     if (box.clickedButton() == demoButton) { | ||||
|                         // play demo here | ||||
|                         m_session->MakeDemo(); | ||||
|                         launchInstance(); | ||||
|                     } | ||||
|                     else { | ||||
|                     } else { | ||||
|                         emitFailed(tr("Launch cancelled - account does not own Minecraft.")); | ||||
|                     } | ||||
|                 } | ||||
| @@ -272,8 +241,7 @@ void LaunchController::login() { | ||||
|             case AccountState::Working: { | ||||
|                 // refresh is in progress, we need to wait for it to finish to proceed. | ||||
|                 ProgressDialog progDialog(m_parentWidget); | ||||
|                 if (m_online) | ||||
|                 { | ||||
|                 if (m_online) { | ||||
|                     progDialog.setSkipButton(true, tr("Play Offline")); | ||||
|                 } | ||||
|                 auto task = m_accountToUse->currentTask(); | ||||
| @@ -288,37 +256,24 @@ void LaunchController::login() { | ||||
|             */ | ||||
|             case AccountState::Expired: { | ||||
|                 auto errorString = tr("The account has expired and needs to be logged into manually again."); | ||||
|                 QMessageBox::warning( | ||||
|                     m_parentWidget, | ||||
|                     tr("Account refresh failed"), | ||||
|                     errorString, | ||||
|                     QMessageBox::StandardButton::Ok, | ||||
|                     QMessageBox::StandardButton::Ok | ||||
|                 ); | ||||
|                 QMessageBox::warning(m_parentWidget, tr("Account refresh failed"), errorString, QMessageBox::StandardButton::Ok, | ||||
|                                      QMessageBox::StandardButton::Ok); | ||||
|                 emitFailed(errorString); | ||||
|                 return; | ||||
|             } | ||||
|             case AccountState::Disabled: { | ||||
|                 auto errorString = tr("The launcher's client identification has changed. Please remove this account and add it again."); | ||||
|                 QMessageBox::warning( | ||||
|                         m_parentWidget, | ||||
|                         tr("Client identification changed"), | ||||
|                         errorString, | ||||
|                         QMessageBox::StandardButton::Ok, | ||||
|                         QMessageBox::StandardButton::Ok | ||||
|                 ); | ||||
|                 QMessageBox::warning(m_parentWidget, tr("Client identification changed"), errorString, QMessageBox::StandardButton::Ok, | ||||
|                                      QMessageBox::StandardButton::Ok); | ||||
|                 emitFailed(errorString); | ||||
|                 return; | ||||
|             } | ||||
|             case AccountState::Gone: { | ||||
|                 auto errorString = tr("The account no longer exists on the servers. It may have been migrated, in which case please add the new account you migrated this one to."); | ||||
|                 QMessageBox::warning( | ||||
|                     m_parentWidget, | ||||
|                     tr("Account gone"), | ||||
|                     errorString, | ||||
|                     QMessageBox::StandardButton::Ok, | ||||
|                     QMessageBox::StandardButton::Ok | ||||
|                 ); | ||||
|                 auto errorString = | ||||
|                     tr("The account no longer exists on the servers. It may have been migrated, in which case please add the new account " | ||||
|                        "you migrated this one to."); | ||||
|                 QMessageBox::warning(m_parentWidget, tr("Account gone"), errorString, QMessageBox::StandardButton::Ok, | ||||
|                                      QMessageBox::StandardButton::Ok); | ||||
|                 emitFailed(errorString); | ||||
|                 return; | ||||
|             } | ||||
| @@ -332,48 +287,45 @@ void LaunchController::launchInstance() | ||||
|     Q_ASSERT_X(m_instance != NULL, "launchInstance", "instance is NULL"); | ||||
|     Q_ASSERT_X(m_session.get() != nullptr, "launchInstance", "session is NULL"); | ||||
|  | ||||
|     if(!m_instance->reloadSettings()) | ||||
|     { | ||||
|     if (!m_instance->reloadSettings()) { | ||||
|         QMessageBox::critical(m_parentWidget, tr("Error!"), tr("Couldn't load the instance profile.")); | ||||
|         emitFailed(tr("Couldn't load the instance profile.")); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     m_launcher = m_instance->createLaunchTask(m_session, m_serverToJoin); | ||||
|     if (!m_launcher) | ||||
|     { | ||||
|     if (!m_launcher) { | ||||
|         emitFailed(tr("Couldn't instantiate a launcher.")); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     auto console = qobject_cast<InstanceWindow *>(m_parentWidget); | ||||
|     auto console = qobject_cast<InstanceWindow*>(m_parentWidget); | ||||
|     auto showConsole = m_instance->settings()->get("ShowConsole").toBool(); | ||||
|     if(!console && showConsole) | ||||
|     { | ||||
|     if (!console && showConsole) { | ||||
|         APPLICATION->showInstanceWindow(m_instance); | ||||
|     } | ||||
|     connect(m_launcher.get(), &LaunchTask::readyForLaunch, this, &LaunchController::readyForLaunch); | ||||
|     connect(m_launcher.get(), &LaunchTask::succeeded, this, &LaunchController::onSucceeded); | ||||
|     connect(m_launcher.get(), &LaunchTask::failed, this,  &LaunchController::onFailed); | ||||
|     connect(m_launcher.get(), &LaunchTask::failed, this, &LaunchController::onFailed); | ||||
|     connect(m_launcher.get(), &LaunchTask::requestProgress, this, &LaunchController::onProgressRequested); | ||||
|  | ||||
|     // Prepend Online and Auth Status | ||||
|     QString online_mode; | ||||
|     if(m_session->wants_online) { | ||||
|     if (m_session->wants_online) { | ||||
|         online_mode = "online"; | ||||
|  | ||||
|         // Prepend Server Status | ||||
|         QStringList servers = {"authserver.mojang.com", "session.minecraft.net", "textures.minecraft.net", "api.mojang.com"}; | ||||
|         QStringList servers = { "authserver.mojang.com", "session.minecraft.net", "textures.minecraft.net", "api.mojang.com" }; | ||||
|         QString resolved_servers = ""; | ||||
|         QHostInfo host_info; | ||||
|  | ||||
|         for(QString server : servers) { | ||||
|         for (QString server : servers) { | ||||
|             host_info = QHostInfo::fromName(server); | ||||
|             resolved_servers = resolved_servers + server + " resolves to:\n    ["; | ||||
|             if(!host_info.addresses().isEmpty()) { | ||||
|                 for(QHostAddress address : host_info.addresses()) { | ||||
|             if (!host_info.addresses().isEmpty()) { | ||||
|                 for (QHostAddress address : host_info.addresses()) { | ||||
|                     resolved_servers = resolved_servers + address.toString(); | ||||
|                     if(!host_info.addresses().endsWith(address)) { | ||||
|                     if (!host_info.addresses().endsWith(address)) { | ||||
|                         resolved_servers = resolved_servers + ", "; | ||||
|                     } | ||||
|                 } | ||||
| @@ -387,11 +339,13 @@ void LaunchController::launchInstance() | ||||
|         online_mode = m_demo ? "demo" : "offline"; | ||||
|     } | ||||
|  | ||||
|     m_launcher->prependStep(makeShared<TextPrint>(m_launcher.get(), "Launched instance in " + online_mode + " mode\n", MessageLevel::Launcher)); | ||||
|     m_launcher->prependStep( | ||||
|         makeShared<TextPrint>(m_launcher.get(), "Launched instance in " + online_mode + " mode\n", MessageLevel::Launcher)); | ||||
|  | ||||
|     // Prepend Version | ||||
|     { | ||||
|         auto versionString = QString("%1 version: %2 (%3)").arg(BuildConfig.LAUNCHER_DISPLAYNAME, BuildConfig.printableVersionString(), BuildConfig.BUILD_PLATFORM); | ||||
|         auto versionString = QString("%1 version: %2 (%3)") | ||||
|                                  .arg(BuildConfig.LAUNCHER_DISPLAYNAME, BuildConfig.printableVersionString(), BuildConfig.BUILD_PLATFORM); | ||||
|         m_launcher->prependStep(makeShared<TextPrint>(m_launcher.get(), versionString + "\n\n", MessageLevel::Launcher)); | ||||
|     } | ||||
|     m_launcher->start(); | ||||
| @@ -399,28 +353,26 @@ void LaunchController::launchInstance() | ||||
|  | ||||
| void LaunchController::readyForLaunch() | ||||
| { | ||||
|     if (!m_profiler) | ||||
|     { | ||||
|     if (!m_profiler) { | ||||
|         m_launcher->proceed(); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     QString error; | ||||
|     if (!m_profiler->check(&error)) | ||||
|     { | ||||
|     if (!m_profiler->check(&error)) { | ||||
|         m_launcher->abort(); | ||||
|         QMessageBox::critical(m_parentWidget, tr("Error!"), tr("Couldn't start profiler: %1").arg(error)); | ||||
|         emitFailed("Profiler startup failed!"); | ||||
|         return; | ||||
|     } | ||||
|     BaseProfiler *profilerInstance = m_profiler->createProfiler(m_launcher->instance(), this); | ||||
|     BaseProfiler* profilerInstance = m_profiler->createProfiler(m_launcher->instance(), this); | ||||
|  | ||||
|     connect(profilerInstance, &BaseProfiler::readyToLaunch, [this](const QString & message) | ||||
|     { | ||||
|     connect(profilerInstance, &BaseProfiler::readyToLaunch, [this](const QString& message) { | ||||
|         QMessageBox msg; | ||||
|         msg.setText(tr("The game launch is delayed until you press the " | ||||
|                         "button. This is the right time to setup the profiler, as the " | ||||
|                         "profiler server is running now.\n\n%1").arg(message)); | ||||
|                        "button. This is the right time to setup the profiler, as the " | ||||
|                        "profiler server is running now.\n\n%1") | ||||
|                         .arg(message)); | ||||
|         msg.setWindowTitle(tr("Waiting.")); | ||||
|         msg.setIcon(QMessageBox::Information); | ||||
|         msg.addButton(tr("Launch"), QMessageBox::AcceptRole); | ||||
| @@ -428,8 +380,7 @@ void LaunchController::readyForLaunch() | ||||
|         msg.exec(); | ||||
|         m_launcher->proceed(); | ||||
|     }); | ||||
|     connect(profilerInstance, &BaseProfiler::abortLaunch, [this](const QString & message) | ||||
|     { | ||||
|     connect(profilerInstance, &BaseProfiler::abortLaunch, [this](const QString& message) { | ||||
|         QMessageBox msg; | ||||
|         msg.setText(tr("Couldn't start the profiler: %1").arg(message)); | ||||
|         msg.setWindowTitle(tr("Error")); | ||||
| @@ -450,8 +401,7 @@ void LaunchController::onSucceeded() | ||||
|  | ||||
| void LaunchController::onFailed(QString reason) | ||||
| { | ||||
|     if(m_instance->settings()->get("ShowConsoleOnError").toBool()) | ||||
|     { | ||||
|     if (m_instance->settings()->get("ShowConsoleOnError").toBool()) { | ||||
|         APPLICATION->showInstanceWindow(m_instance, "console"); | ||||
|     } | ||||
|     emitFailed(reason); | ||||
| @@ -467,21 +417,18 @@ void LaunchController::onProgressRequested(Task* task) | ||||
|  | ||||
| bool LaunchController::abort() | ||||
| { | ||||
|     if(!m_launcher) | ||||
|     { | ||||
|     if (!m_launcher) { | ||||
|         return true; | ||||
|     } | ||||
|     if(!m_launcher->canAbort()) | ||||
|     { | ||||
|     if (!m_launcher->canAbort()) { | ||||
|         return false; | ||||
|     } | ||||
|     auto response = CustomMessageBox::selectable( | ||||
|             m_parentWidget, tr("Kill Minecraft?"), | ||||
|             tr("This can cause the instance to get corrupted and should only be used if Minecraft " | ||||
|             "is frozen for some reason"), | ||||
|             QMessageBox::Question, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)->exec(); | ||||
|     if (response == QMessageBox::Yes) | ||||
|     { | ||||
|     auto response = CustomMessageBox::selectable(m_parentWidget, tr("Kill Minecraft?"), | ||||
|                                                  tr("This can cause the instance to get corrupted and should only be used if Minecraft " | ||||
|                                                     "is frozen for some reason"), | ||||
|                                                  QMessageBox::Question, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) | ||||
|                         ->exec(); | ||||
|     if (response == QMessageBox::Yes) { | ||||
|         return m_launcher->abort(); | ||||
|     } | ||||
|     return false; | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
| @@ -34,81 +34,61 @@ | ||||
|  */ | ||||
|  | ||||
| #pragma once | ||||
| #include <QObject> | ||||
| #include <BaseInstance.h> | ||||
| #include <tools/BaseProfiler.h> | ||||
| #include <QObject> | ||||
|  | ||||
| #include "minecraft/launch/MinecraftServerTarget.h" | ||||
| #include "minecraft/auth/MinecraftAccount.h" | ||||
| #include "minecraft/launch/MinecraftServerTarget.h" | ||||
|  | ||||
| class InstanceWindow; | ||||
| class LaunchController: public Task | ||||
| { | ||||
| class LaunchController : public Task { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|    public: | ||||
|     void executeTask() override; | ||||
|  | ||||
|     LaunchController(QObject * parent = nullptr); | ||||
|     LaunchController(QObject* parent = nullptr); | ||||
|     virtual ~LaunchController(){}; | ||||
|  | ||||
|     void setInstance(InstancePtr instance) { | ||||
|         m_instance = instance; | ||||
|     } | ||||
|     void setInstance(InstancePtr instance) { m_instance = instance; } | ||||
|  | ||||
|     InstancePtr instance() { | ||||
|         return m_instance; | ||||
|     } | ||||
|     InstancePtr instance() { return m_instance; } | ||||
|  | ||||
|     void setOnline(bool online) { | ||||
|         m_online = online; | ||||
|     } | ||||
|     void setOnline(bool online) { m_online = online; } | ||||
|  | ||||
|     void setDemo(bool demo) { | ||||
|         m_demo = demo; | ||||
|     } | ||||
|     void setDemo(bool demo) { m_demo = demo; } | ||||
|  | ||||
|     void setProfiler(BaseProfilerFactory *profiler) { | ||||
|         m_profiler = profiler; | ||||
|     } | ||||
|     void setProfiler(BaseProfilerFactory* profiler) { m_profiler = profiler; } | ||||
|  | ||||
|     void setParentWidget(QWidget * widget) { | ||||
|         m_parentWidget = widget; | ||||
|     } | ||||
|     void setParentWidget(QWidget* widget) { m_parentWidget = widget; } | ||||
|  | ||||
|     void setServerToJoin(MinecraftServerTargetPtr serverToJoin) { | ||||
|         m_serverToJoin = std::move(serverToJoin); | ||||
|     } | ||||
|     void setServerToJoin(MinecraftServerTargetPtr serverToJoin) { m_serverToJoin = std::move(serverToJoin); } | ||||
|  | ||||
|     void setAccountToUse(MinecraftAccountPtr accountToUse) { | ||||
|         m_accountToUse = std::move(accountToUse); | ||||
|     } | ||||
|     void setAccountToUse(MinecraftAccountPtr accountToUse) { m_accountToUse = std::move(accountToUse); } | ||||
|  | ||||
|     QString id() | ||||
|     { | ||||
|         return m_instance->id(); | ||||
|     } | ||||
|     QString id() { return m_instance->id(); } | ||||
|  | ||||
|     bool abort() override; | ||||
|  | ||||
| private: | ||||
|    private: | ||||
|     void login(); | ||||
|     void launchInstance(); | ||||
|     void decideAccount(); | ||||
|  | ||||
| private slots: | ||||
|    private slots: | ||||
|     void readyForLaunch(); | ||||
|  | ||||
|     void onSucceeded(); | ||||
|     void onFailed(QString reason); | ||||
|     void onProgressRequested(Task *task); | ||||
|     void onProgressRequested(Task* task); | ||||
|  | ||||
| private: | ||||
|     BaseProfilerFactory *m_profiler = nullptr; | ||||
|    private: | ||||
|     BaseProfilerFactory* m_profiler = nullptr; | ||||
|     bool m_online = true; | ||||
|     bool m_demo = false; | ||||
|     InstancePtr m_instance; | ||||
|     QWidget * m_parentWidget = nullptr; | ||||
|     InstanceWindow *m_console = nullptr; | ||||
|     QWidget* m_parentWidget = nullptr; | ||||
|     InstanceWindow* m_console = nullptr; | ||||
|     MinecraftAccountPtr m_accountToUse = nullptr; | ||||
|     AuthSessionPtr m_session; | ||||
|     shared_qobject_ptr<LaunchTask> m_launcher; | ||||
|   | ||||
| @@ -39,7 +39,7 @@ | ||||
| #include <QTextDecoder> | ||||
| #include "MessageLevel.h" | ||||
|  | ||||
| LoggedProcess::LoggedProcess(QObject *parent) : QProcess(parent) | ||||
| LoggedProcess::LoggedProcess(QObject* parent) : QProcess(parent) | ||||
| { | ||||
|     // QProcess has a strange interface... let's map a lot of those into a few. | ||||
|     connect(this, &QProcess::readyReadStandardOutput, this, &LoggedProcess::on_stdOut); | ||||
| @@ -51,8 +51,7 @@ LoggedProcess::LoggedProcess(QObject *parent) : QProcess(parent) | ||||
|  | ||||
| LoggedProcess::~LoggedProcess() | ||||
| { | ||||
|     if(m_is_detachable) | ||||
|     { | ||||
|     if (m_is_detachable) { | ||||
|         setProcessState(QProcess::NotRunning); | ||||
|     } | ||||
| } | ||||
| @@ -95,39 +94,31 @@ void LoggedProcess::on_exit(int exit_code, QProcess::ExitStatus status) | ||||
|     m_exit_code = exit_code; | ||||
|  | ||||
|     // based on state, send signals | ||||
|     if (!m_is_aborting) | ||||
|     { | ||||
|         if (status == QProcess::NormalExit) | ||||
|         { | ||||
|     if (!m_is_aborting) { | ||||
|         if (status == QProcess::NormalExit) { | ||||
|             //: Message displayed on instance exit | ||||
|             emit log({tr("Process exited with code %1.").arg(exit_code)}, MessageLevel::Launcher); | ||||
|             emit log({ tr("Process exited with code %1.").arg(exit_code) }, MessageLevel::Launcher); | ||||
|             changeState(LoggedProcess::Finished); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|         } else { | ||||
|             //: Message displayed on instance crashed | ||||
|             if(exit_code == -1) | ||||
|                 emit log({tr("Process crashed.")}, MessageLevel::Launcher); | ||||
|             if (exit_code == -1) | ||||
|                 emit log({ tr("Process crashed.") }, MessageLevel::Launcher); | ||||
|             else | ||||
|                 emit log({tr("Process crashed with exitcode %1.").arg(exit_code)}, MessageLevel::Launcher); | ||||
|                 emit log({ tr("Process crashed with exitcode %1.").arg(exit_code) }, MessageLevel::Launcher); | ||||
|             changeState(LoggedProcess::Crashed); | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|     } else { | ||||
|         //: Message displayed after the instance exits due to kill request | ||||
|         emit log({tr("Process was killed by user.")}, MessageLevel::Error); | ||||
|         emit log({ tr("Process was killed by user.") }, MessageLevel::Error); | ||||
|         changeState(LoggedProcess::Aborted); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void LoggedProcess::on_error(QProcess::ProcessError error) | ||||
| { | ||||
|     switch(error) | ||||
|     { | ||||
|         case QProcess::FailedToStart: | ||||
|         { | ||||
|             emit log({tr("The process failed to start.")}, MessageLevel::Fatal); | ||||
|     switch (error) { | ||||
|         case QProcess::FailedToStart: { | ||||
|             emit log({ tr("The process failed to start.") }, MessageLevel::Fatal); | ||||
|             changeState(LoggedProcess::FailedToStart); | ||||
|             break; | ||||
|         } | ||||
| @@ -154,7 +145,7 @@ int LoggedProcess::exitCode() const | ||||
|  | ||||
| void LoggedProcess::changeState(LoggedProcess::State state) | ||||
| { | ||||
|     if(state == m_state) | ||||
|     if (state == m_state) | ||||
|         return; | ||||
|     m_state = state; | ||||
|     emit stateChanged(m_state); | ||||
| @@ -167,24 +158,19 @@ LoggedProcess::State LoggedProcess::state() const | ||||
|  | ||||
| void LoggedProcess::on_stateChange(QProcess::ProcessState state) | ||||
| { | ||||
|     switch(state) | ||||
|     { | ||||
|     switch (state) { | ||||
|         case QProcess::NotRunning: | ||||
|             break; // let's not - there are too many that handle this already. | ||||
|         case QProcess::Starting: | ||||
|         { | ||||
|             if(m_state != LoggedProcess::NotRunning) | ||||
|             { | ||||
|                 qWarning() << "Wrong state change for process from state" << m_state << "to" << (int) LoggedProcess::Starting; | ||||
|             break;  // let's not - there are too many that handle this already. | ||||
|         case QProcess::Starting: { | ||||
|             if (m_state != LoggedProcess::NotRunning) { | ||||
|                 qWarning() << "Wrong state change for process from state" << m_state << "to" << (int)LoggedProcess::Starting; | ||||
|             } | ||||
|             changeState(LoggedProcess::Starting); | ||||
|             return; | ||||
|         } | ||||
|         case QProcess::Running: | ||||
|         { | ||||
|             if(m_state != LoggedProcess::Starting) | ||||
|             { | ||||
|                 qWarning() << "Wrong state change for process from state" << m_state << "to" << (int) LoggedProcess::Running; | ||||
|         case QProcess::Running: { | ||||
|             if (m_state != LoggedProcess::Starting) { | ||||
|                 qWarning() << "Wrong state change for process from state" << m_state << "to" << (int)LoggedProcess::Running; | ||||
|             } | ||||
|             changeState(LoggedProcess::Running); | ||||
|             return; | ||||
|   | ||||
| @@ -43,22 +43,12 @@ | ||||
|  * This is a basic process. | ||||
|  * It has line-based logging support and hides some of the nasty bits. | ||||
|  */ | ||||
| class LoggedProcess : public QProcess | ||||
| { | ||||
| Q_OBJECT | ||||
| public: | ||||
|     enum State | ||||
|     { | ||||
|         NotRunning, | ||||
|         Starting, | ||||
|         FailedToStart, | ||||
|         Running, | ||||
|         Finished, | ||||
|         Crashed, | ||||
|         Aborted | ||||
|     }; | ||||
| class LoggedProcess : public QProcess { | ||||
|     Q_OBJECT | ||||
|    public: | ||||
|     enum State { NotRunning, Starting, FailedToStart, Running, Finished, Crashed, Aborted }; | ||||
|  | ||||
| public: | ||||
|    public: | ||||
|     explicit LoggedProcess(QObject* parent = 0); | ||||
|     virtual ~LoggedProcess(); | ||||
|  | ||||
| @@ -67,30 +57,29 @@ public: | ||||
|  | ||||
|     void setDetachable(bool detachable); | ||||
|  | ||||
| signals: | ||||
|    signals: | ||||
|     void log(QStringList lines, MessageLevel::Enum level); | ||||
|     void stateChanged(LoggedProcess::State state); | ||||
|  | ||||
| public slots: | ||||
|    public slots: | ||||
|     /** | ||||
|      * @brief kill the process - equivalent to kill -9 | ||||
|      */ | ||||
|     void kill(); | ||||
|  | ||||
|  | ||||
| private slots: | ||||
|    private slots: | ||||
|     void on_stdErr(); | ||||
|     void on_stdOut(); | ||||
|     void on_exit(int exit_code, QProcess::ExitStatus status); | ||||
|     void on_error(QProcess::ProcessError error); | ||||
|     void on_stateChange(QProcess::ProcessState); | ||||
|  | ||||
| private: | ||||
|    private: | ||||
|     void changeState(LoggedProcess::State state); | ||||
|  | ||||
|     QStringList reprocess(const QByteArray& data, QTextDecoder& decoder); | ||||
|  | ||||
| private: | ||||
|    private: | ||||
|     QTextDecoder m_err_decoder = QTextDecoder(QTextCodec::codecForLocale()); | ||||
|     QTextDecoder m_out_decoder = QTextDecoder(QTextCodec::codecForLocale()); | ||||
|     QString m_leftover_line; | ||||
|   | ||||
| @@ -17,30 +17,29 @@ | ||||
|  | ||||
| #include <MMCTime.h> | ||||
|  | ||||
| #include <QObject> | ||||
| #include <QDateTime> | ||||
| #include <QObject> | ||||
| #include <QTextStream> | ||||
|  | ||||
| QString Time::prettifyDuration(int64_t duration) { | ||||
|     int seconds = (int) (duration % 60); | ||||
| QString Time::prettifyDuration(int64_t duration) | ||||
| { | ||||
|     int seconds = (int)(duration % 60); | ||||
|     duration /= 60; | ||||
|     int minutes = (int) (duration % 60); | ||||
|     int minutes = (int)(duration % 60); | ||||
|     duration /= 60; | ||||
|     int hours = (int) (duration % 24); | ||||
|     int days = (int) (duration / 24); | ||||
|     if((hours == 0)&&(days == 0)) | ||||
|     { | ||||
|     int hours = (int)(duration % 24); | ||||
|     int days = (int)(duration / 24); | ||||
|     if ((hours == 0) && (days == 0)) { | ||||
|         return QObject::tr("%1min %2s").arg(minutes).arg(seconds); | ||||
|     } | ||||
|     if (days == 0) | ||||
|     { | ||||
|     if (days == 0) { | ||||
|         return QObject::tr("%1h %2min").arg(hours).arg(minutes); | ||||
|     } | ||||
|     return QObject::tr("%1d %2h %3min").arg(days).arg(hours).arg(minutes); | ||||
| } | ||||
|  | ||||
| QString Time::humanReadableDuration(double duration, int precision) { | ||||
|  | ||||
| QString Time::humanReadableDuration(double duration, int precision) | ||||
| { | ||||
|     using days = std::chrono::duration<int, std::ratio<86400>>; | ||||
|  | ||||
|     QString outStr; | ||||
| @@ -48,8 +47,8 @@ QString Time::humanReadableDuration(double duration, int precision) { | ||||
|  | ||||
|     bool neg = false; | ||||
|     if (duration < 0) { | ||||
|         neg = true; // flag | ||||
|         duration  *= -1; // invert | ||||
|         neg = true;      // flag | ||||
|         duration *= -1;  // invert | ||||
|     } | ||||
|  | ||||
|     auto std_duration = std::chrono::duration<double>(duration); | ||||
| @@ -78,22 +77,22 @@ QString Time::humanReadableDuration(double duration, int precision) { | ||||
|     if (hc) { | ||||
|         if (dc) | ||||
|             os << " "; | ||||
|         os << qSetFieldWidth(2) << hc << QObject::tr("h"); // hours | ||||
|         os << qSetFieldWidth(2) << hc << QObject::tr("h");  // hours | ||||
|     } | ||||
|     if (mc) { | ||||
|         if (dc || hc) | ||||
|             os << " "; | ||||
|         os << qSetFieldWidth(2) << mc << QObject::tr("m"); // minutes | ||||
|         os << qSetFieldWidth(2) << mc << QObject::tr("m");  // minutes | ||||
|     } | ||||
|     if (dc || hc || mc || sc) { | ||||
|         if (dc || hc || mc) | ||||
|             os << " "; | ||||
|         os << qSetFieldWidth(2) << sc << QObject::tr("s"); // seconds | ||||
|         os << qSetFieldWidth(2) << sc << QObject::tr("s");  // seconds | ||||
|     } | ||||
|     if ((msc && (precision > 0)) || !(dc || hc || mc || sc)) { | ||||
|         if (dc || hc || mc || sc) | ||||
|             os << " "; | ||||
|         os << qSetFieldWidth(0) << qSetRealNumberPrecision(precision) << msc << QObject::tr("ms"); // miliseconds | ||||
|         os << qSetFieldWidth(0) << qSetRealNumberPrecision(precision) << msc << QObject::tr("ms");  // miliseconds | ||||
|     } | ||||
|  | ||||
|     os.flush(); | ||||
|   | ||||
| @@ -31,4 +31,4 @@ QString prettifyDuration(int64_t duration); | ||||
|  * @return QString | ||||
|  */ | ||||
| QString humanReadableDuration(double duration, int precision = 0); | ||||
| } | ||||
| }  // namespace Time | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <QCoreApplication> | ||||
| #include <QDebug> | ||||
| #include <QPixmapCache> | ||||
| #include <QThread> | ||||
| #include <QTime> | ||||
| #include <QDebug> | ||||
|  | ||||
| #define GET_TYPE()                                                          \ | ||||
|     Qt::ConnectionType type;                                                \ | ||||
|   | ||||
| @@ -16,15 +16,15 @@ | ||||
|  *  along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| #include <QStringList> | ||||
| #include <QDir> | ||||
| #include <QString> | ||||
| #include <QStringList> | ||||
| #include <QSysInfo> | ||||
| #include <QtGlobal> | ||||
|  | ||||
| #include "MangoHud.h" | ||||
| #include "FileSystem.h" | ||||
| #include "Json.h" | ||||
| #include "MangoHud.h" | ||||
|  | ||||
| namespace MangoHud { | ||||
|  | ||||
|   | ||||
| @@ -18,7 +18,7 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <QString> | ||||
| #include <cmark.h> | ||||
| #include <QString> | ||||
|  | ||||
| QString markdownToHTML(const QString& markdown); | ||||
| @@ -22,12 +22,11 @@ MessageLevel::Enum MessageLevel::getLevel(const QString& levelName) | ||||
|         return MessageLevel::Unknown; | ||||
| } | ||||
|  | ||||
| MessageLevel::Enum MessageLevel::fromLine(QString &line) | ||||
| MessageLevel::Enum MessageLevel::fromLine(QString& line) | ||||
| { | ||||
|     // Level prefix | ||||
|     int endmark = line.indexOf("]!"); | ||||
|     if (line.startsWith("!![") && endmark != -1) | ||||
|     { | ||||
|     if (line.startsWith("!![") && endmark != -1) { | ||||
|         auto level = MessageLevel::getLevel(line.left(endmark).mid(3)); | ||||
|         line = line.mid(endmark + 2); | ||||
|         return level; | ||||
|   | ||||
| @@ -6,23 +6,21 @@ | ||||
|  * @brief the MessageLevel Enum | ||||
|  * defines what level a log message is | ||||
|  */ | ||||
| namespace MessageLevel | ||||
| { | ||||
| enum Enum | ||||
| { | ||||
|     Unknown, /**< No idea what this is or where it came from */ | ||||
|     StdOut,  /**< Undetermined stderr messages */ | ||||
|     StdErr,  /**< Undetermined stdout messages */ | ||||
| namespace MessageLevel { | ||||
| enum Enum { | ||||
|     Unknown,  /**< No idea what this is or where it came from */ | ||||
|     StdOut,   /**< Undetermined stderr messages */ | ||||
|     StdErr,   /**< Undetermined stdout messages */ | ||||
|     Launcher, /**< Launcher Messages */ | ||||
|     Debug,   /**< Debug Messages */ | ||||
|     Info,    /**< Info Messages */ | ||||
|     Message, /**< Standard Messages */ | ||||
|     Warning, /**< Warnings */ | ||||
|     Error,   /**< Errors */ | ||||
|     Fatal,   /**< Fatal Errors */ | ||||
|     Debug,    /**< Debug Messages */ | ||||
|     Info,     /**< Info Messages */ | ||||
|     Message,  /**< Standard Messages */ | ||||
|     Warning,  /**< Warnings */ | ||||
|     Error,    /**< Errors */ | ||||
|     Fatal,    /**< Fatal Errors */ | ||||
| }; | ||||
| MessageLevel::Enum getLevel(const QString &levelName); | ||||
| MessageLevel::Enum getLevel(const QString& levelName); | ||||
|  | ||||
| /* Get message level from a line. Line is modified if it was successful. */ | ||||
| MessageLevel::Enum fromLine(QString &line); | ||||
| } | ||||
| MessageLevel::Enum fromLine(QString& line); | ||||
| }  // namespace MessageLevel | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
| @@ -37,88 +37,38 @@ | ||||
| #include "BaseInstance.h" | ||||
| #include "launch/LaunchTask.h" | ||||
|  | ||||
| class NullInstance: public BaseInstance | ||||
| { | ||||
| class NullInstance : public BaseInstance { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|    public: | ||||
|     NullInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString& rootDir) | ||||
|     :BaseInstance(globalSettings, settings, rootDir) | ||||
|         : BaseInstance(globalSettings, settings, rootDir) | ||||
|     { | ||||
|         setVersionBroken(true); | ||||
|     } | ||||
|     virtual ~NullInstance() {}; | ||||
|     void saveNow() override | ||||
|     { | ||||
|     } | ||||
|     void loadSpecificSettings() override | ||||
|     { | ||||
|         setSpecificSettingsLoaded(true); | ||||
|     } | ||||
|     QString getStatusbarDescription() override | ||||
|     { | ||||
|         return tr("Unknown instance type"); | ||||
|     }; | ||||
|     QSet< QString > traits() const override | ||||
|     { | ||||
|         return {}; | ||||
|     }; | ||||
|     QString instanceConfigFolder() const override | ||||
|     { | ||||
|         return instanceRoot(); | ||||
|     }; | ||||
|     shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr, MinecraftServerTargetPtr) override | ||||
|     { | ||||
|         return nullptr; | ||||
|     } | ||||
|     shared_qobject_ptr< Task > createUpdateTask(Net::Mode mode) override | ||||
|     { | ||||
|         return nullptr; | ||||
|     } | ||||
|     QProcessEnvironment createEnvironment() override | ||||
|     { | ||||
|         return QProcessEnvironment(); | ||||
|     } | ||||
|     QProcessEnvironment createLaunchEnvironment() override | ||||
|     { | ||||
|         return QProcessEnvironment(); | ||||
|     } | ||||
|     QMap<QString, QString> getVariables() override | ||||
|     { | ||||
|         return QMap<QString, QString>(); | ||||
|     } | ||||
|     IPathMatcher::Ptr getLogFileMatcher() override | ||||
|     { | ||||
|         return nullptr; | ||||
|     } | ||||
|     QString getLogFileRoot() override | ||||
|     { | ||||
|         return instanceRoot(); | ||||
|     } | ||||
|     QString typeName() const override | ||||
|     { | ||||
|         return "Null"; | ||||
|     } | ||||
|     bool canExport() const override | ||||
|     { | ||||
|         return false; | ||||
|     } | ||||
|     bool canEdit() const override | ||||
|     { | ||||
|         return false; | ||||
|     } | ||||
|     bool canLaunch() const override | ||||
|     { | ||||
|         return false; | ||||
|     } | ||||
|     virtual ~NullInstance(){}; | ||||
|     void saveNow() override {} | ||||
|     void loadSpecificSettings() override { setSpecificSettingsLoaded(true); } | ||||
|     QString getStatusbarDescription() override { return tr("Unknown instance type"); }; | ||||
|     QSet<QString> traits() const override { return {}; }; | ||||
|     QString instanceConfigFolder() const override { return instanceRoot(); }; | ||||
|     shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr, MinecraftServerTargetPtr) override { return nullptr; } | ||||
|     shared_qobject_ptr<Task> createUpdateTask(Net::Mode mode) override { return nullptr; } | ||||
|     QProcessEnvironment createEnvironment() override { return QProcessEnvironment(); } | ||||
|     QProcessEnvironment createLaunchEnvironment() override { return QProcessEnvironment(); } | ||||
|     QMap<QString, QString> getVariables() override { return QMap<QString, QString>(); } | ||||
|     IPathMatcher::Ptr getLogFileMatcher() override { return nullptr; } | ||||
|     QString getLogFileRoot() override { return instanceRoot(); } | ||||
|     QString typeName() const override { return "Null"; } | ||||
|     bool canExport() const override { return false; } | ||||
|     bool canEdit() const override { return false; } | ||||
|     bool canLaunch() const override { return false; } | ||||
|     QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override | ||||
|     { | ||||
|         QStringList out; | ||||
|         out << "Null instance - placeholder."; | ||||
|         return out; | ||||
|     } | ||||
|     QString modsRoot() const override { | ||||
|         return QString(); | ||||
|     } | ||||
|     QString modsRoot() const override { return QString(); } | ||||
|     void updateRuntimeContext() | ||||
|     { | ||||
|         // NOOP | ||||
|   | ||||
| @@ -1,47 +1,35 @@ | ||||
| #pragma once | ||||
|  | ||||
| enum class ProblemSeverity | ||||
| { | ||||
|     None, | ||||
|     Warning, | ||||
|     Error | ||||
| }; | ||||
| #include <QList> | ||||
| #include <QString> | ||||
|  | ||||
| struct PatchProblem | ||||
| { | ||||
| enum class ProblemSeverity { None, Warning, Error }; | ||||
|  | ||||
| struct PatchProblem { | ||||
|     ProblemSeverity m_severity; | ||||
|     QString m_description; | ||||
| }; | ||||
|  | ||||
| class ProblemProvider | ||||
| { | ||||
| public: | ||||
|     virtual ~ProblemProvider() {}; | ||||
| class ProblemProvider { | ||||
|    public: | ||||
|     virtual ~ProblemProvider(){}; | ||||
|     virtual const QList<PatchProblem> getProblems() const = 0; | ||||
|     virtual ProblemSeverity getProblemSeverity() const = 0; | ||||
| }; | ||||
|  | ||||
| class ProblemContainer : public ProblemProvider | ||||
| { | ||||
| public: | ||||
|     const QList<PatchProblem> getProblems() const override | ||||
| class ProblemContainer : public ProblemProvider { | ||||
|    public: | ||||
|     const QList<PatchProblem> getProblems() const override { return m_problems; } | ||||
|     ProblemSeverity getProblemSeverity() const override { return m_problemSeverity; } | ||||
|     virtual void addProblem(ProblemSeverity severity, const QString& description) | ||||
|     { | ||||
|         return m_problems; | ||||
|     } | ||||
|     ProblemSeverity getProblemSeverity() const override | ||||
|     { | ||||
|         return m_problemSeverity; | ||||
|     } | ||||
|     virtual void addProblem(ProblemSeverity severity, const QString &description) | ||||
|     { | ||||
|         if(severity > m_problemSeverity) | ||||
|         { | ||||
|         if (severity > m_problemSeverity) { | ||||
|             m_problemSeverity = severity; | ||||
|         } | ||||
|         m_problems.append({severity, description}); | ||||
|         m_problems.append({ severity, description }); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|    private: | ||||
|     QList<PatchProblem> m_problems; | ||||
|     ProblemSeverity m_problemSeverity = ProblemSeverity::None; | ||||
| }; | ||||
|   | ||||
| @@ -36,35 +36,34 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
|  | ||||
| #include <QVariant> | ||||
| #include <QList> | ||||
| #include <QVariant> | ||||
|  | ||||
| namespace QVariantUtils { | ||||
|  | ||||
| template <typename T> | ||||
| inline QList<T> toList(QVariant src) { | ||||
| inline QList<T> toList(QVariant src) | ||||
| { | ||||
|     QVariantList variantList = src.toList(); | ||||
|  | ||||
|     QList<T> list_t; | ||||
|     list_t.reserve(variantList.size()); | ||||
|     for (const QVariant& v : variantList) | ||||
|     { | ||||
|     for (const QVariant& v : variantList) { | ||||
|         list_t.append(v.value<T>()); | ||||
|     } | ||||
|     return list_t; | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| inline QVariant fromList(QList<T> val) { | ||||
| inline QVariant fromList(QList<T> val) | ||||
| { | ||||
|     QVariantList variantList; | ||||
|     variantList.reserve(val.size()); | ||||
|     for (const T& v : val) | ||||
|     { | ||||
|     for (const T& v : val) { | ||||
|         variantList.append(v); | ||||
|     } | ||||
|  | ||||
|     return variantList; | ||||
| } | ||||
|  | ||||
| } | ||||
| }  // namespace QVariantUtils | ||||
| @@ -1,13 +1,12 @@ | ||||
| #pragma once | ||||
| #include <QWriteLocker> | ||||
| #include <QReadLocker> | ||||
| #include <QMap> | ||||
| #include <QReadLocker> | ||||
| #include <QSet> | ||||
| #include <QWriteLocker> | ||||
|  | ||||
| template <typename K, typename V> | ||||
| class RWStorage | ||||
| { | ||||
| public: | ||||
| class RWStorage { | ||||
|    public: | ||||
|     void add(K key, V value) | ||||
|     { | ||||
|         QWriteLocker l(&lock); | ||||
| @@ -17,21 +16,19 @@ public: | ||||
|     V get(K key) | ||||
|     { | ||||
|         QReadLocker l(&lock); | ||||
|         if(cache.contains(key)) | ||||
|         { | ||||
|         if (cache.contains(key)) { | ||||
|             return cache[key]; | ||||
|         } | ||||
|         else return V(); | ||||
|         } else | ||||
|             return V(); | ||||
|     } | ||||
|     bool get(K key, V& value) | ||||
|     { | ||||
|         QReadLocker l(&lock); | ||||
|         if(cache.contains(key)) | ||||
|         { | ||||
|         if (cache.contains(key)) { | ||||
|             value = cache[key]; | ||||
|             return true; | ||||
|         } | ||||
|         else return false; | ||||
|         } else | ||||
|             return false; | ||||
|     } | ||||
|     bool has(K key) | ||||
|     { | ||||
| @@ -41,15 +38,14 @@ public: | ||||
|     bool stale(K key) | ||||
|     { | ||||
|         QReadLocker l(&lock); | ||||
|         if(!cache.contains(key)) | ||||
|         if (!cache.contains(key)) | ||||
|             return true; | ||||
|         return stale_entries.contains(key); | ||||
|     } | ||||
|     void setStale(K key) | ||||
|     { | ||||
|         QWriteLocker l(&lock); | ||||
|         if(cache.contains(key)) | ||||
|         { | ||||
|         if (cache.contains(key)) { | ||||
|             stale_entries.insert(key); | ||||
|         } | ||||
|     } | ||||
| @@ -59,7 +55,8 @@ public: | ||||
|         cache.clear(); | ||||
|         stale_entries.clear(); | ||||
|     } | ||||
| private: | ||||
|  | ||||
|    private: | ||||
|     QReadWriteLock lock; | ||||
|     QMap<K, V> cache; | ||||
|     QSet<K> stale_entries; | ||||
|   | ||||
| @@ -1,25 +1,21 @@ | ||||
| #include "RecursiveFileSystemWatcher.h" | ||||
|  | ||||
| #include <QRegularExpression> | ||||
| #include <QDebug> | ||||
| #include <QRegularExpression> | ||||
|  | ||||
| RecursiveFileSystemWatcher::RecursiveFileSystemWatcher(QObject *parent) | ||||
|     : QObject(parent), m_watcher(new QFileSystemWatcher(this)) | ||||
| RecursiveFileSystemWatcher::RecursiveFileSystemWatcher(QObject* parent) : QObject(parent), m_watcher(new QFileSystemWatcher(this)) | ||||
| { | ||||
|     connect(m_watcher, &QFileSystemWatcher::fileChanged, this, | ||||
|             &RecursiveFileSystemWatcher::fileChange); | ||||
|     connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, | ||||
|             &RecursiveFileSystemWatcher::directoryChange); | ||||
|     connect(m_watcher, &QFileSystemWatcher::fileChanged, this, &RecursiveFileSystemWatcher::fileChange); | ||||
|     connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, &RecursiveFileSystemWatcher::directoryChange); | ||||
| } | ||||
|  | ||||
| void RecursiveFileSystemWatcher::setRootDir(const QDir &root) | ||||
| void RecursiveFileSystemWatcher::setRootDir(const QDir& root) | ||||
| { | ||||
|     bool wasEnabled = m_isEnabled; | ||||
|     disable(); | ||||
|     m_root = root; | ||||
|     setFiles(scanRecursive(m_root)); | ||||
|     if (wasEnabled) | ||||
|     { | ||||
|     if (wasEnabled) { | ||||
|         enable(); | ||||
|     } | ||||
| } | ||||
| @@ -28,16 +24,14 @@ void RecursiveFileSystemWatcher::setWatchFiles(const bool watchFiles) | ||||
|     bool wasEnabled = m_isEnabled; | ||||
|     disable(); | ||||
|     m_watchFiles = watchFiles; | ||||
|     if (wasEnabled) | ||||
|     { | ||||
|     if (wasEnabled) { | ||||
|         enable(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void RecursiveFileSystemWatcher::enable() | ||||
| { | ||||
|     if (m_isEnabled) | ||||
|     { | ||||
|     if (m_isEnabled) { | ||||
|         return; | ||||
|     } | ||||
|     Q_ASSERT(m_root != QDir::root()); | ||||
| @@ -46,8 +40,7 @@ void RecursiveFileSystemWatcher::enable() | ||||
| } | ||||
| void RecursiveFileSystemWatcher::disable() | ||||
| { | ||||
|     if (!m_isEnabled) | ||||
|     { | ||||
|     if (!m_isEnabled) { | ||||
|         return; | ||||
|     } | ||||
|     m_isEnabled = false; | ||||
| @@ -55,57 +48,49 @@ void RecursiveFileSystemWatcher::disable() | ||||
|     m_watcher->removePaths(m_watcher->directories()); | ||||
| } | ||||
|  | ||||
| void RecursiveFileSystemWatcher::setFiles(const QStringList &files) | ||||
| void RecursiveFileSystemWatcher::setFiles(const QStringList& files) | ||||
| { | ||||
|     if (files != m_files) | ||||
|     { | ||||
|     if (files != m_files) { | ||||
|         m_files = files; | ||||
|         emit filesChanged(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void RecursiveFileSystemWatcher::addFilesToWatcherRecursive(const QDir &dir) | ||||
| void RecursiveFileSystemWatcher::addFilesToWatcherRecursive(const QDir& dir) | ||||
| { | ||||
|     m_watcher->addPath(dir.absolutePath()); | ||||
|     for (const QString &directory : dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) | ||||
|     { | ||||
|     for (const QString& directory : dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { | ||||
|         addFilesToWatcherRecursive(dir.absoluteFilePath(directory)); | ||||
|     } | ||||
|     if (m_watchFiles) | ||||
|     { | ||||
|         for (const QFileInfo &info : dir.entryInfoList(QDir::Files)) | ||||
|         { | ||||
|     if (m_watchFiles) { | ||||
|         for (const QFileInfo& info : dir.entryInfoList(QDir::Files)) { | ||||
|             m_watcher->addPath(info.absoluteFilePath()); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| QStringList RecursiveFileSystemWatcher::scanRecursive(const QDir &directory) | ||||
| QStringList RecursiveFileSystemWatcher::scanRecursive(const QDir& directory) | ||||
| { | ||||
|     QStringList ret; | ||||
|     if(!m_matcher) | ||||
|     { | ||||
|     if (!m_matcher) { | ||||
|         return {}; | ||||
|     } | ||||
|     for (const QString &dir : directory.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden)) | ||||
|     { | ||||
|     for (const QString& dir : directory.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden)) { | ||||
|         ret.append(scanRecursive(directory.absoluteFilePath(dir))); | ||||
|     } | ||||
|     for (const QString &file : directory.entryList(QDir::Files | QDir::Hidden)) | ||||
|     { | ||||
|     for (const QString& file : directory.entryList(QDir::Files | QDir::Hidden)) { | ||||
|         auto relPath = m_root.relativeFilePath(directory.absoluteFilePath(file)); | ||||
|         if (m_matcher->matches(relPath)) | ||||
|         { | ||||
|         if (m_matcher->matches(relPath)) { | ||||
|             ret.append(relPath); | ||||
|         } | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| void RecursiveFileSystemWatcher::fileChange(const QString &path) | ||||
| void RecursiveFileSystemWatcher::fileChange(const QString& path) | ||||
| { | ||||
|     emit fileChanged(path); | ||||
| } | ||||
| void RecursiveFileSystemWatcher::directoryChange(const QString &path) | ||||
| void RecursiveFileSystemWatcher::directoryChange(const QString& path) | ||||
| { | ||||
|     setFiles(scanRecursive(m_root)); | ||||
| } | ||||
|   | ||||
| @@ -1,61 +1,48 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <QFileSystemWatcher> | ||||
| #include <QDir> | ||||
| #include <QFileSystemWatcher> | ||||
| #include "pathmatcher/IPathMatcher.h" | ||||
|  | ||||
| class RecursiveFileSystemWatcher : public QObject | ||||
| { | ||||
| class RecursiveFileSystemWatcher : public QObject { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     RecursiveFileSystemWatcher(QObject *parent); | ||||
|    public: | ||||
|     RecursiveFileSystemWatcher(QObject* parent); | ||||
|  | ||||
|     void setRootDir(const QDir &root); | ||||
|     QDir rootDir() const | ||||
|     { | ||||
|         return m_root; | ||||
|     } | ||||
|     void setRootDir(const QDir& root); | ||||
|     QDir rootDir() const { return m_root; } | ||||
|  | ||||
|     // WARNING: setting this to true may be bad for performance | ||||
|     void setWatchFiles(const bool watchFiles); | ||||
|     bool watchFiles() const | ||||
|     { | ||||
|         return m_watchFiles; | ||||
|     } | ||||
|     bool watchFiles() const { return m_watchFiles; } | ||||
|  | ||||
|     void setMatcher(IPathMatcher::Ptr matcher) | ||||
|     { | ||||
|         m_matcher = matcher; | ||||
|     } | ||||
|     void setMatcher(IPathMatcher::Ptr matcher) { m_matcher = matcher; } | ||||
|  | ||||
|     QStringList files() const | ||||
|     { | ||||
|         return m_files; | ||||
|     } | ||||
|     QStringList files() const { return m_files; } | ||||
|  | ||||
| signals: | ||||
|    signals: | ||||
|     void filesChanged(); | ||||
|     void fileChanged(const QString &path); | ||||
|     void fileChanged(const QString& path); | ||||
|  | ||||
| public slots: | ||||
|    public slots: | ||||
|     void enable(); | ||||
|     void disable(); | ||||
|  | ||||
| private: | ||||
|    private: | ||||
|     QDir m_root; | ||||
|     bool m_watchFiles = false; | ||||
|     bool m_isEnabled = false; | ||||
|     IPathMatcher::Ptr m_matcher; | ||||
|  | ||||
|     QFileSystemWatcher *m_watcher; | ||||
|     QFileSystemWatcher* m_watcher; | ||||
|  | ||||
|     QStringList m_files; | ||||
|     void setFiles(const QStringList &files); | ||||
|     void setFiles(const QStringList& files); | ||||
|  | ||||
|     void addFilesToWatcherRecursive(const QDir &dir); | ||||
|     QStringList scanRecursive(const QDir &dir); | ||||
|     void addFilesToWatcherRecursive(const QDir& dir); | ||||
|     QStringList scanRecursive(const QDir& dir); | ||||
|  | ||||
| private slots: | ||||
|     void fileChange(const QString &path); | ||||
|     void directoryChange(const QString &path); | ||||
|    private slots: | ||||
|     void fileChange(const QString& path); | ||||
|     void directoryChange(const QString& path); | ||||
| }; | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
|   | ||||
| @@ -1,44 +1,32 @@ | ||||
| #pragma once | ||||
| #include <QString> | ||||
| #include <QMap> | ||||
| #include <QString> | ||||
| #include <QStringList> | ||||
|  | ||||
| template <char Tseparator> | ||||
| class SeparatorPrefixTree | ||||
| { | ||||
| public: | ||||
|     SeparatorPrefixTree(QStringList paths) | ||||
|     { | ||||
|         insert(paths); | ||||
|     } | ||||
| class SeparatorPrefixTree { | ||||
|    public: | ||||
|     SeparatorPrefixTree(QStringList paths) { insert(paths); } | ||||
|  | ||||
|     SeparatorPrefixTree(bool contained = false) | ||||
|     { | ||||
|         m_contained = contained; | ||||
|     } | ||||
|     SeparatorPrefixTree(bool contained = false) { m_contained = contained; } | ||||
|  | ||||
|     void insert(QStringList paths) | ||||
|     { | ||||
|         for(auto &path: paths) | ||||
|         { | ||||
|         for (auto& path : paths) { | ||||
|             insert(path); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// insert an exact path into the tree | ||||
|     SeparatorPrefixTree & insert(QString path) | ||||
|     SeparatorPrefixTree& insert(QString path) | ||||
|     { | ||||
|         auto sepIndex = path.indexOf(Tseparator); | ||||
|         if(sepIndex == -1) | ||||
|         { | ||||
|         if (sepIndex == -1) { | ||||
|             children[path] = SeparatorPrefixTree(true); | ||||
|             return children[path]; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|         } else { | ||||
|             auto prefix = path.left(sepIndex); | ||||
|             if(!children.contains(prefix)) | ||||
|             { | ||||
|             if (!children.contains(prefix)) { | ||||
|                 children[prefix] = SeparatorPrefixTree(false); | ||||
|             } | ||||
|             return children[prefix].insert(path.mid(sepIndex + 1)); | ||||
| @@ -56,26 +44,20 @@ public: | ||||
|     bool covers(QString path) const | ||||
|     { | ||||
|         // if we found some valid node, it's good enough. the tree covers the path | ||||
|         if(m_contained) | ||||
|         { | ||||
|         if (m_contained) { | ||||
|             return true; | ||||
|         } | ||||
|         auto sepIndex = path.indexOf(Tseparator); | ||||
|         if(sepIndex == -1) | ||||
|         { | ||||
|         if (sepIndex == -1) { | ||||
|             auto found = children.find(path); | ||||
|             if(found == children.end()) | ||||
|             { | ||||
|             if (found == children.end()) { | ||||
|                 return false; | ||||
|             } | ||||
|             return (*found).covers(QString()); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|         } else { | ||||
|             auto prefix = path.left(sepIndex); | ||||
|             auto found = children.find(prefix); | ||||
|             if(found == children.end()) | ||||
|             { | ||||
|             if (found == children.end()) { | ||||
|                 return false; | ||||
|             } | ||||
|             return (*found).covers(path.mid(sepIndex + 1)); | ||||
| @@ -86,41 +68,33 @@ public: | ||||
|     QString cover(QString path) const | ||||
|     { | ||||
|         // if we found some valid node, it's good enough. the tree covers the path | ||||
|         if(m_contained) | ||||
|         { | ||||
|         if (m_contained) { | ||||
|             return QString(""); | ||||
|         } | ||||
|         auto sepIndex = path.indexOf(Tseparator); | ||||
|         if(sepIndex == -1) | ||||
|         { | ||||
|         if (sepIndex == -1) { | ||||
|             auto found = children.find(path); | ||||
|             if(found == children.end()) | ||||
|             { | ||||
|             if (found == children.end()) { | ||||
|                 return QString(); | ||||
|             } | ||||
|             auto nested = (*found).cover(QString()); | ||||
|             if(nested.isNull()) | ||||
|             { | ||||
|             if (nested.isNull()) { | ||||
|                 return nested; | ||||
|             } | ||||
|             if(nested.isEmpty()) | ||||
|             if (nested.isEmpty()) | ||||
|                 return path; | ||||
|             return path + Tseparator + nested; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|         } else { | ||||
|             auto prefix = path.left(sepIndex); | ||||
|             auto found = children.find(prefix); | ||||
|             if(found == children.end()) | ||||
|             { | ||||
|             if (found == children.end()) { | ||||
|                 return QString(); | ||||
|             } | ||||
|             auto nested = (*found).cover(path.mid(sepIndex + 1)); | ||||
|             if(nested.isNull()) | ||||
|             { | ||||
|             if (nested.isNull()) { | ||||
|                 return nested; | ||||
|             } | ||||
|             if(nested.isEmpty()) | ||||
|             if (nested.isEmpty()) | ||||
|                 return prefix; | ||||
|             return prefix + Tseparator + nested; | ||||
|         } | ||||
| @@ -130,21 +104,16 @@ public: | ||||
|     bool exists(QString path) const | ||||
|     { | ||||
|         auto sepIndex = path.indexOf(Tseparator); | ||||
|         if(sepIndex == -1) | ||||
|         { | ||||
|         if (sepIndex == -1) { | ||||
|             auto found = children.find(path); | ||||
|             if(found == children.end()) | ||||
|             { | ||||
|             if (found == children.end()) { | ||||
|                 return false; | ||||
|             } | ||||
|             return true; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|         } else { | ||||
|             auto prefix = path.left(sepIndex); | ||||
|             auto found = children.find(prefix); | ||||
|             if(found == children.end()) | ||||
|             { | ||||
|             if (found == children.end()) { | ||||
|                 return false; | ||||
|             } | ||||
|             return (*found).exists(path.mid(sepIndex + 1)); | ||||
| @@ -152,24 +121,19 @@ public: | ||||
|     } | ||||
|  | ||||
|     /// find a node in the tree by name | ||||
|     const SeparatorPrefixTree * find(QString path) const | ||||
|     const SeparatorPrefixTree* find(QString path) const | ||||
|     { | ||||
|         auto sepIndex = path.indexOf(Tseparator); | ||||
|         if(sepIndex == -1) | ||||
|         { | ||||
|         if (sepIndex == -1) { | ||||
|             auto found = children.find(path); | ||||
|             if(found == children.end()) | ||||
|             { | ||||
|             if (found == children.end()) { | ||||
|                 return nullptr; | ||||
|             } | ||||
|             return &(*found); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|         } else { | ||||
|             auto prefix = path.left(sepIndex); | ||||
|             auto found = children.find(prefix); | ||||
|             if(found == children.end()) | ||||
|             { | ||||
|             if (found == children.end()) { | ||||
|                 return nullptr; | ||||
|             } | ||||
|             return (*found).find(path.mid(sepIndex + 1)); | ||||
| @@ -177,70 +141,48 @@ public: | ||||
|     } | ||||
|  | ||||
|     /// is this a leaf node? | ||||
|     bool leaf() const | ||||
|     { | ||||
|         return children.isEmpty(); | ||||
|     } | ||||
|     bool leaf() const { return children.isEmpty(); } | ||||
|  | ||||
|     /// is this node actually contained in the tree, or is it purely structural? | ||||
|     bool contained() const | ||||
|     { | ||||
|         return m_contained; | ||||
|     } | ||||
|     bool contained() const { return m_contained; } | ||||
|  | ||||
|     /// Remove a path from the tree | ||||
|     bool remove(QString path) | ||||
|     { | ||||
|         return removeInternal(path) != Failed; | ||||
|     } | ||||
|     bool remove(QString path) { return removeInternal(path) != Failed; } | ||||
|  | ||||
|     /// Clear all children of this node tree node | ||||
|     void clear() | ||||
|     { | ||||
|         children.clear(); | ||||
|     } | ||||
|     void clear() { children.clear(); } | ||||
|  | ||||
|     QStringList toStringList() const | ||||
|     { | ||||
|         QStringList collected; | ||||
|         // collecting these is more expensive. | ||||
|         auto iter = children.begin(); | ||||
|         while(iter != children.end()) | ||||
|         { | ||||
|         while (iter != children.end()) { | ||||
|             QStringList list = iter.value().toStringList(); | ||||
|             for(int i = 0; i < list.size(); i++) | ||||
|             { | ||||
|             for (int i = 0; i < list.size(); i++) { | ||||
|                 list[i] = iter.key() + Tseparator + list[i]; | ||||
|             } | ||||
|             collected.append(list); | ||||
|             if((*iter).m_contained) | ||||
|             { | ||||
|             if ((*iter).m_contained) { | ||||
|                 collected.append(iter.key()); | ||||
|             } | ||||
|             iter++; | ||||
|         } | ||||
|         return collected; | ||||
|     } | ||||
| private: | ||||
|     enum Removal | ||||
|     { | ||||
|         Failed, | ||||
|         Succeeded, | ||||
|         HasChildren | ||||
|     }; | ||||
|  | ||||
|    private: | ||||
|     enum Removal { Failed, Succeeded, HasChildren }; | ||||
|     Removal removeInternal(QString path = QString()) | ||||
|     { | ||||
|         if(path.isEmpty()) | ||||
|         { | ||||
|             if(!m_contained) | ||||
|             { | ||||
|         if (path.isEmpty()) { | ||||
|             if (!m_contained) { | ||||
|                 // remove all children - we are removing a prefix | ||||
|                 clear(); | ||||
|                 return Succeeded; | ||||
|             } | ||||
|             m_contained = false; | ||||
|             if(children.size()) | ||||
|             { | ||||
|             if (children.size()) { | ||||
|                 return HasChildren; | ||||
|             } | ||||
|             return Succeeded; | ||||
| @@ -248,42 +190,32 @@ private: | ||||
|         Removal remStatus = Failed; | ||||
|         QString childToRemove; | ||||
|         auto sepIndex = path.indexOf(Tseparator); | ||||
|         if(sepIndex == -1) | ||||
|         { | ||||
|         if (sepIndex == -1) { | ||||
|             childToRemove = path; | ||||
|             auto found = children.find(childToRemove); | ||||
|             if(found == children.end()) | ||||
|             { | ||||
|             if (found == children.end()) { | ||||
|                 return Failed; | ||||
|             } | ||||
|             remStatus = (*found).removeInternal(); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|         } else { | ||||
|             childToRemove = path.left(sepIndex); | ||||
|             auto found = children.find(childToRemove); | ||||
|             if(found == children.end()) | ||||
|             { | ||||
|             if (found == children.end()) { | ||||
|                 return Failed; | ||||
|             } | ||||
|             remStatus = (*found).removeInternal(path.mid(sepIndex + 1)); | ||||
|         } | ||||
|         switch (remStatus) | ||||
|         { | ||||
|         switch (remStatus) { | ||||
|             case Failed: | ||||
|             case HasChildren: | ||||
|             { | ||||
|             case HasChildren: { | ||||
|                 return remStatus; | ||||
|             } | ||||
|             case Succeeded: | ||||
|             { | ||||
|             case Succeeded: { | ||||
|                 children.remove(childToRemove); | ||||
|                 if(m_contained) | ||||
|                 { | ||||
|                 if (m_contained) { | ||||
|                     return HasChildren; | ||||
|                 } | ||||
|                 if(children.size()) | ||||
|                 { | ||||
|                 if (children.size()) { | ||||
|                     return HasChildren; | ||||
|                 } | ||||
|                 return Succeeded; | ||||
| @@ -292,7 +224,7 @@ private: | ||||
|         return Failed; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     QMap<QString,SeparatorPrefixTree<Tseparator>> children; | ||||
|    private: | ||||
|     QMap<QString, SeparatorPrefixTree<Tseparator>> children; | ||||
|     bool m_contained = false; | ||||
| }; | ||||
|   | ||||
| @@ -14,17 +14,16 @@ | ||||
|  */ | ||||
|  | ||||
| #include "SkinUtils.h" | ||||
| #include "net/HttpMetaCache.h" | ||||
| #include "Application.h" | ||||
| #include "net/HttpMetaCache.h" | ||||
|  | ||||
| #include <QFile> | ||||
| #include <QPainter> | ||||
| #include <QJsonArray> | ||||
| #include <QJsonDocument> | ||||
| #include <QJsonObject> | ||||
| #include <QJsonArray> | ||||
| #include <QPainter> | ||||
|  | ||||
| namespace SkinUtils | ||||
| { | ||||
| namespace SkinUtils { | ||||
| /* | ||||
|  * Given a username, return a pixmap of the cached skin (if it exists), QPixmap() otherwise | ||||
|  */ | ||||
| @@ -32,11 +31,9 @@ QPixmap getFaceFromCache(QString username, int height, int width) | ||||
| { | ||||
|     QFile fskin(APPLICATION->metacache()->resolveEntry("skins", username + ".png")->getFullPath()); | ||||
|  | ||||
|     if (fskin.exists()) | ||||
|     { | ||||
|     if (fskin.exists()) { | ||||
|         QPixmap skinTexture(fskin.fileName()); | ||||
|         if(!skinTexture.isNull()) | ||||
|         { | ||||
|         if (!skinTexture.isNull()) { | ||||
|             QPixmap skin = QPixmap(8, 8); | ||||
|             QPainter painter(&skin); | ||||
|             painter.drawPixmap(0, 0, skinTexture.copy(8, 8, 8, 8)); | ||||
| @@ -47,4 +44,4 @@ QPixmap getFaceFromCache(QString username, int height, int width) | ||||
|  | ||||
|     return QPixmap(); | ||||
| } | ||||
| } | ||||
| }  // namespace SkinUtils | ||||
|   | ||||
| @@ -17,7 +17,6 @@ | ||||
|  | ||||
| #include <QPixmap> | ||||
|  | ||||
| namespace SkinUtils | ||||
| { | ||||
| namespace SkinUtils { | ||||
| QPixmap getFaceFromCache(QString id, int height = 64, int width = 64); | ||||
| } | ||||
|   | ||||
| @@ -73,10 +73,9 @@ int naturalCompare(const QString& s1, const QString& s2, Qt::CaseSensitivity cs) | ||||
|  * @param max_len max lenght of url in charaters | ||||
|  * @param hard_limit if truncating the path can't get the url short enough, truncate it normaly. | ||||
|  */ | ||||
| QString truncateUrlHumanFriendly(QUrl &url, int max_len, bool hard_limit = false); | ||||
| QString truncateUrlHumanFriendly(QUrl& url, int max_len, bool hard_limit = false); | ||||
|  | ||||
| QString humanReadableFileSize(double bytes, bool use_si = false, int decimal_points = 1); | ||||
|  | ||||
|  | ||||
| QString getRandomAlphaNumeric(); | ||||
| }  // namespace StringUtils | ||||
|   | ||||
| @@ -12,28 +12,18 @@ class Usable; | ||||
|  * | ||||
|  * @see UseLock | ||||
|  */ | ||||
| class Usable | ||||
| { | ||||
| class Usable { | ||||
|     friend class UseLock; | ||||
| public: | ||||
|     std::size_t useCount() const | ||||
|     { | ||||
|         return m_useCount; | ||||
|     } | ||||
|     bool isInUse() const | ||||
|     { | ||||
|         return m_useCount > 0; | ||||
|     } | ||||
| protected: | ||||
|     virtual void decrementUses() | ||||
|     { | ||||
|         m_useCount--; | ||||
|     } | ||||
|     virtual void incrementUses() | ||||
|     { | ||||
|         m_useCount++; | ||||
|     } | ||||
| private: | ||||
|  | ||||
|    public: | ||||
|     std::size_t useCount() const { return m_useCount; } | ||||
|     bool isInUse() const { return m_useCount > 0; } | ||||
|  | ||||
|    protected: | ||||
|     virtual void decrementUses() { m_useCount--; } | ||||
|     virtual void incrementUses() { m_useCount++; } | ||||
|  | ||||
|    private: | ||||
|     std::size_t m_useCount = 0; | ||||
| }; | ||||
|  | ||||
| @@ -42,19 +32,15 @@ private: | ||||
|  * | ||||
|  * @see Usable | ||||
|  */ | ||||
| class UseLock | ||||
| { | ||||
| public: | ||||
|     UseLock(shared_qobject_ptr<Usable> usable) | ||||
|         : m_usable(usable) | ||||
| class UseLock { | ||||
|    public: | ||||
|     UseLock(shared_qobject_ptr<Usable> usable) : m_usable(usable) | ||||
|     { | ||||
|         // this doesn't use shared pointer use count, because that wouldn't be correct. this count is separate. | ||||
|         m_usable->incrementUses(); | ||||
|     } | ||||
|     ~UseLock() | ||||
|     { | ||||
|         m_usable->decrementUses(); | ||||
|     } | ||||
| private: | ||||
|     ~UseLock() { m_usable->decrementUses(); } | ||||
|  | ||||
|    private: | ||||
|     shared_qobject_ptr<Usable> m_usable; | ||||
| }; | ||||
|   | ||||
| @@ -117,12 +117,14 @@ QDebug operator<<(QDebug debug, const Version& v) | ||||
|  | ||||
|     bool first = true; | ||||
|     for (auto s : v.m_sections) { | ||||
|         if (!first) debug.nospace() << ", "; | ||||
|         if (!first) | ||||
|             debug.nospace() << ", "; | ||||
|         debug.nospace() << s.m_fullString; | ||||
|         first = false; | ||||
|     } | ||||
|  | ||||
|     debug.nospace() << " ]" << " }"; | ||||
|     debug.nospace() << " ]" | ||||
|                     << " }"; | ||||
|  | ||||
|     return debug; | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2023 flowln <flowlnlnln@gmail.com> | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  * | ||||
| @@ -48,12 +48,12 @@ class Version { | ||||
|     Version(QString str); | ||||
|     Version() = default; | ||||
|  | ||||
|     bool operator<(const Version &other) const; | ||||
|     bool operator<=(const Version &other) const; | ||||
|     bool operator>(const Version &other) const; | ||||
|     bool operator>=(const Version &other) const; | ||||
|     bool operator==(const Version &other) const; | ||||
|     bool operator!=(const Version &other) const; | ||||
|     bool operator<(const Version& other) const; | ||||
|     bool operator<=(const Version& other) const; | ||||
|     bool operator>(const Version& other) const; | ||||
|     bool operator>=(const Version& other) const; | ||||
|     bool operator==(const Version& other) const; | ||||
|     bool operator!=(const Version& other) const; | ||||
|  | ||||
|     QString toString() const { return m_string; } | ||||
|  | ||||
| @@ -72,7 +72,7 @@ class Version { | ||||
|             } | ||||
|  | ||||
| #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) | ||||
|             auto numPart = QStringView{m_fullString}.left(cutoff); | ||||
|             auto numPart = QStringView{ m_fullString }.left(cutoff); | ||||
| #else | ||||
|             auto numPart = m_fullString.leftRef(cutoff); | ||||
| #endif | ||||
| @@ -83,7 +83,7 @@ class Version { | ||||
|             } | ||||
|  | ||||
| #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) | ||||
|             auto stringPart = QStringView{m_fullString}.mid(cutoff); | ||||
|             auto stringPart = QStringView{ m_fullString }.mid(cutoff); | ||||
| #else | ||||
|             auto stringPart = m_fullString.midRef(cutoff); | ||||
| #endif | ||||
| @@ -103,8 +103,14 @@ class Version { | ||||
|  | ||||
|         QString m_fullString; | ||||
|  | ||||
|         [[nodiscard]] inline bool isAppendix() const { return m_stringPart.startsWith('+'); } | ||||
|         [[nodiscard]] inline bool isPreRelease() const { return m_stringPart.startsWith('-') && m_stringPart.length() > 1; } | ||||
|         [[nodiscard]] inline bool isAppendix() const | ||||
|         { | ||||
|             return m_stringPart.startsWith('+'); | ||||
|         } | ||||
|         [[nodiscard]] inline bool isPreRelease() const | ||||
|         { | ||||
|             return m_stringPart.startsWith('-') && m_stringPart.length() > 1; | ||||
|         } | ||||
|  | ||||
|         inline bool operator==(const Section& other) const | ||||
|         { | ||||
| @@ -154,7 +160,7 @@ class Version { | ||||
|         { | ||||
|             return !(*this == other); | ||||
|         } | ||||
|         inline bool operator>(const Section &other) const | ||||
|         inline bool operator>(const Section& other) const | ||||
|         { | ||||
|             return !(*this < other || *this == other); | ||||
|         } | ||||
| @@ -166,5 +172,3 @@ class Version { | ||||
|  | ||||
|     void parse(); | ||||
| }; | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -35,53 +35,48 @@ | ||||
|  */ | ||||
|  | ||||
| #include "VersionProxyModel.h" | ||||
| #include "Application.h" | ||||
| #include <QSortFilterProxyModel> | ||||
| #include <QPixmapCache> | ||||
| #include <Version.h> | ||||
| #include <meta/VersionList.h> | ||||
| #include <QPixmapCache> | ||||
| #include <QSortFilterProxyModel> | ||||
| #include "Application.h" | ||||
|  | ||||
| class VersionFilterModel : public QSortFilterProxyModel | ||||
| { | ||||
| class VersionFilterModel : public QSortFilterProxyModel { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     VersionFilterModel(VersionProxyModel *parent) : QSortFilterProxyModel(parent) | ||||
|    public: | ||||
|     VersionFilterModel(VersionProxyModel* parent) : QSortFilterProxyModel(parent) | ||||
|     { | ||||
|         m_parent = parent; | ||||
|         setSortRole(BaseVersionList::SortRole); | ||||
|         sort(0, Qt::DescendingOrder); | ||||
|     } | ||||
|  | ||||
|     bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const | ||||
|     bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const | ||||
|     { | ||||
|         const auto &filters = m_parent->filters(); | ||||
|         const QString &search = m_parent->search(); | ||||
|         const auto& filters = m_parent->filters(); | ||||
|         const QString& search = m_parent->search(); | ||||
|         const QModelIndex idx = sourceModel()->index(source_row, 0, source_parent); | ||||
|  | ||||
|         if (!search.isEmpty() && !sourceModel()->data(idx, BaseVersionList::VersionRole).toString().contains(search, Qt::CaseInsensitive)) | ||||
|             return false; | ||||
|  | ||||
|         for (auto it = filters.begin(); it != filters.end(); ++it) | ||||
|         { | ||||
|         for (auto it = filters.begin(); it != filters.end(); ++it) { | ||||
|             auto data = sourceModel()->data(idx, it.key()); | ||||
|             auto match = data.toString(); | ||||
|             if(!it.value()->accepts(match)) | ||||
|             { | ||||
|             if (!it.value()->accepts(match)) { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     void filterChanged() | ||||
|     { | ||||
|         invalidateFilter(); | ||||
|     } | ||||
| private: | ||||
|     VersionProxyModel *m_parent; | ||||
|     void filterChanged() { invalidateFilter(); } | ||||
|  | ||||
|    private: | ||||
|     VersionProxyModel* m_parent; | ||||
| }; | ||||
|  | ||||
| VersionProxyModel::VersionProxyModel(QObject *parent) : QAbstractProxyModel(parent) | ||||
| VersionProxyModel::VersionProxyModel(QObject* parent) : QAbstractProxyModel(parent) | ||||
| { | ||||
|     filterModel = new VersionFilterModel(this); | ||||
|     connect(filterModel, &QAbstractItemModel::dataChanged, this, &VersionProxyModel::sourceDataChanged); | ||||
| @@ -104,19 +99,17 @@ VersionProxyModel::VersionProxyModel(QObject *parent) : QAbstractProxyModel(pare | ||||
|  | ||||
| QVariant VersionProxyModel::headerData(int section, Qt::Orientation orientation, int role) const | ||||
| { | ||||
|     if(section < 0 || section >= m_columns.size()) | ||||
|     if (section < 0 || section >= m_columns.size()) | ||||
|         return QVariant(); | ||||
|     if(orientation != Qt::Horizontal) | ||||
|     if (orientation != Qt::Horizontal) | ||||
|         return QVariant(); | ||||
|     auto column = m_columns[section]; | ||||
|     if(role == Qt::DisplayRole) | ||||
|     { | ||||
|         switch(column) | ||||
|         { | ||||
|     if (role == Qt::DisplayRole) { | ||||
|         switch (column) { | ||||
|             case Name: | ||||
|                 return tr("Version"); | ||||
|             case ParentVersion: | ||||
|                 return tr("Minecraft"); //FIXME: this should come from metadata | ||||
|                 return tr("Minecraft");  // FIXME: this should come from metadata | ||||
|             case Branch: | ||||
|                 return tr("Branch"); | ||||
|             case Type: | ||||
| @@ -128,15 +121,12 @@ QVariant VersionProxyModel::headerData(int section, Qt::Orientation orientation, | ||||
|             case Time: | ||||
|                 return tr("Released"); | ||||
|         } | ||||
|     } | ||||
|     else if(role == Qt::ToolTipRole) | ||||
|     { | ||||
|         switch(column) | ||||
|         { | ||||
|     } else if (role == Qt::ToolTipRole) { | ||||
|         switch (column) { | ||||
|             case Name: | ||||
|                 return tr("The name of the version."); | ||||
|             case ParentVersion: | ||||
|                 return tr("Minecraft version"); //FIXME: this should come from metadata | ||||
|                 return tr("Minecraft version");  // FIXME: this should come from metadata | ||||
|             case Branch: | ||||
|                 return tr("The version's branch"); | ||||
|             case Type: | ||||
| @@ -152,25 +142,19 @@ QVariant VersionProxyModel::headerData(int section, Qt::Orientation orientation, | ||||
|     return QVariant(); | ||||
| } | ||||
|  | ||||
| QVariant VersionProxyModel::data(const QModelIndex &index, int role) const | ||||
| QVariant VersionProxyModel::data(const QModelIndex& index, int role) const | ||||
| { | ||||
|     if(!index.isValid()) | ||||
|     { | ||||
|     if (!index.isValid()) { | ||||
|         return QVariant(); | ||||
|     } | ||||
|     auto column = m_columns[index.column()]; | ||||
|     auto parentIndex = mapToSource(index); | ||||
|     switch(role) | ||||
|     { | ||||
|         case Qt::DisplayRole: | ||||
|         { | ||||
|             switch(column) | ||||
|             { | ||||
|                 case Name: | ||||
|                 { | ||||
|     switch (role) { | ||||
|         case Qt::DisplayRole: { | ||||
|             switch (column) { | ||||
|                 case Name: { | ||||
|                     QString version = sourceModel()->data(parentIndex, BaseVersionList::VersionRole).toString(); | ||||
|                     if(version == m_currentVersion) | ||||
|                     { | ||||
|                     if (version == m_currentVersion) { | ||||
|                         return tr("%1 (installed)").arg(version); | ||||
|                     } | ||||
|                     return version; | ||||
| @@ -191,18 +175,14 @@ QVariant VersionProxyModel::data(const QModelIndex &index, int role) const | ||||
|                     return QVariant(); | ||||
|             } | ||||
|         } | ||||
|         case Qt::ToolTipRole: | ||||
|         { | ||||
|             if(column == Name && hasRecommended)  | ||||
|             { | ||||
|         case Qt::ToolTipRole: { | ||||
|             if (column == Name && hasRecommended) { | ||||
|                 auto value = sourceModel()->data(parentIndex, BaseVersionList::RecommendedRole); | ||||
|                 if(value.toBool()) | ||||
|                 { | ||||
|                 if (value.toBool()) { | ||||
|                     return tr("Recommended"); | ||||
|                 } else if(hasLatest) { | ||||
|                 } else if (hasLatest) { | ||||
|                     auto value = sourceModel()->data(parentIndex, BaseVersionList::LatestRole); | ||||
|                     if(value.toBool()) | ||||
|                     { | ||||
|                     if (value.toBool()) { | ||||
|                         return tr("Latest"); | ||||
|                     } | ||||
|                 } | ||||
| @@ -210,32 +190,23 @@ QVariant VersionProxyModel::data(const QModelIndex &index, int role) const | ||||
|                 return sourceModel()->data(parentIndex, BaseVersionList::VersionIdRole); | ||||
|             } | ||||
|         } | ||||
|         case Qt::DecorationRole: | ||||
|         { | ||||
|             switch(column) | ||||
|             { | ||||
|                 case Name: | ||||
|                 { | ||||
|                     if(hasRecommended) | ||||
|                     { | ||||
|         case Qt::DecorationRole: { | ||||
|             switch (column) { | ||||
|                 case Name: { | ||||
|                     if (hasRecommended) { | ||||
|                         auto value = sourceModel()->data(parentIndex, BaseVersionList::RecommendedRole); | ||||
|                         if(value.toBool()) | ||||
|                         { | ||||
|                         if (value.toBool()) { | ||||
|                             return APPLICATION->getThemedIcon("star"); | ||||
|                         } | ||||
|                         else if(hasLatest) | ||||
|                         { | ||||
|                         } else if (hasLatest) { | ||||
|                             auto value = sourceModel()->data(parentIndex, BaseVersionList::LatestRole); | ||||
|                             if(value.toBool()) | ||||
|                             { | ||||
|                             if (value.toBool()) { | ||||
|                                 return APPLICATION->getThemedIcon("bug"); | ||||
|                             } | ||||
|                         } | ||||
|                         QPixmap pixmap; | ||||
|                         QPixmapCache::find("placeholder", &pixmap); | ||||
|                         if(!pixmap) | ||||
|                         { | ||||
|                             QPixmap px(16,16); | ||||
|                         if (!pixmap) { | ||||
|                             QPixmap px(16, 16); | ||||
|                             px.fill(Qt::transparent); | ||||
|                             QPixmapCache::insert("placeholder", px); | ||||
|                             return px; | ||||
| @@ -243,16 +214,13 @@ QVariant VersionProxyModel::data(const QModelIndex &index, int role) const | ||||
|                         return pixmap; | ||||
|                     } | ||||
|                 } | ||||
|                 default: | ||||
|                 { | ||||
|                 default: { | ||||
|                     return QVariant(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         default: | ||||
|         { | ||||
|             if(roles.contains((BaseVersionList::ModelRoles)role)) | ||||
|             { | ||||
|         default: { | ||||
|             if (roles.contains((BaseVersionList::ModelRoles)role)) { | ||||
|                 return sourceModel()->data(parentIndex, role); | ||||
|             } | ||||
|             return QVariant(); | ||||
| @@ -260,61 +228,56 @@ QVariant VersionProxyModel::data(const QModelIndex &index, int role) const | ||||
|     } | ||||
| } | ||||
|  | ||||
| QModelIndex VersionProxyModel::parent(const QModelIndex &child) const | ||||
| QModelIndex VersionProxyModel::parent(const QModelIndex& child) const | ||||
| { | ||||
|     return QModelIndex(); | ||||
| } | ||||
|  | ||||
| QModelIndex VersionProxyModel::mapFromSource(const QModelIndex &sourceIndex) const | ||||
| QModelIndex VersionProxyModel::mapFromSource(const QModelIndex& sourceIndex) const | ||||
| { | ||||
|     if(sourceIndex.isValid()) | ||||
|     { | ||||
|     if (sourceIndex.isValid()) { | ||||
|         return index(sourceIndex.row(), 0); | ||||
|     } | ||||
|     return QModelIndex(); | ||||
| } | ||||
|  | ||||
| QModelIndex VersionProxyModel::mapToSource(const QModelIndex &proxyIndex) const | ||||
| QModelIndex VersionProxyModel::mapToSource(const QModelIndex& proxyIndex) const | ||||
| { | ||||
|     if(proxyIndex.isValid()) | ||||
|     { | ||||
|     if (proxyIndex.isValid()) { | ||||
|         return sourceModel()->index(proxyIndex.row(), 0); | ||||
|     } | ||||
|     return QModelIndex(); | ||||
| } | ||||
|  | ||||
| QModelIndex VersionProxyModel::index(int row, int column, const QModelIndex &parent) const | ||||
| QModelIndex VersionProxyModel::index(int row, int column, const QModelIndex& parent) const | ||||
| { | ||||
|     // no trees here... shoo | ||||
|     if(parent.isValid()) | ||||
|     { | ||||
|     if (parent.isValid()) { | ||||
|         return QModelIndex(); | ||||
|     } | ||||
|     if(row < 0 || row >= sourceModel()->rowCount()) | ||||
|     if (row < 0 || row >= sourceModel()->rowCount()) | ||||
|         return QModelIndex(); | ||||
|     if(column < 0 || column >= columnCount()) | ||||
|     if (column < 0 || column >= columnCount()) | ||||
|         return QModelIndex(); | ||||
|     return QAbstractItemModel::createIndex(row, column); | ||||
| } | ||||
|  | ||||
| int VersionProxyModel::columnCount(const QModelIndex &parent) const | ||||
| int VersionProxyModel::columnCount(const QModelIndex& parent) const | ||||
| { | ||||
|     return parent.isValid() ? 0 : m_columns.size(); | ||||
| } | ||||
|  | ||||
| int VersionProxyModel::rowCount(const QModelIndex &parent) const | ||||
| int VersionProxyModel::rowCount(const QModelIndex& parent) const | ||||
| { | ||||
|     if(sourceModel()) | ||||
|     { | ||||
|     if (sourceModel()) { | ||||
|         return sourceModel()->rowCount(parent); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| void VersionProxyModel::sourceDataChanged(const QModelIndex &source_top_left, | ||||
|                                           const QModelIndex &source_bottom_right) | ||||
| void VersionProxyModel::sourceDataChanged(const QModelIndex& source_top_left, const QModelIndex& source_bottom_right) | ||||
| { | ||||
|     if(source_top_left.parent() != source_bottom_right.parent()) | ||||
|     if (source_top_left.parent() != source_bottom_right.parent()) | ||||
|         return; | ||||
|  | ||||
|     // whole row is getting changed | ||||
| @@ -323,22 +286,20 @@ void VersionProxyModel::sourceDataChanged(const QModelIndex &source_top_left, | ||||
|     emit dataChanged(topLeft, bottomRight); | ||||
| } | ||||
|  | ||||
| void VersionProxyModel::setSourceModel(QAbstractItemModel *replacingRaw) | ||||
| void VersionProxyModel::setSourceModel(QAbstractItemModel* replacingRaw) | ||||
| { | ||||
|     auto replacing = dynamic_cast<BaseVersionList *>(replacingRaw); | ||||
|     auto replacing = dynamic_cast<BaseVersionList*>(replacingRaw); | ||||
|     beginResetModel(); | ||||
|  | ||||
|     m_columns.clear(); | ||||
|     if(!replacing) | ||||
|     { | ||||
|     if (!replacing) { | ||||
|         roles.clear(); | ||||
|         filterModel->setSourceModel(replacing); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     roles = replacing->providesRoles(); | ||||
|     if(roles.contains(BaseVersionList::VersionRole)) | ||||
|     { | ||||
|     if (roles.contains(BaseVersionList::VersionRole)) { | ||||
|         m_columns.push_back(Name); | ||||
|     } | ||||
|     /* | ||||
| @@ -347,32 +308,25 @@ void VersionProxyModel::setSourceModel(QAbstractItemModel *replacingRaw) | ||||
|         m_columns.push_back(ParentVersion); | ||||
|     } | ||||
|     */ | ||||
|     if(roles.contains(BaseVersionList::ArchitectureRole)) | ||||
|     { | ||||
|     if (roles.contains(BaseVersionList::ArchitectureRole)) { | ||||
|         m_columns.push_back(Architecture); | ||||
|     } | ||||
|     if(roles.contains(BaseVersionList::PathRole)) | ||||
|     { | ||||
|     if (roles.contains(BaseVersionList::PathRole)) { | ||||
|         m_columns.push_back(Path); | ||||
|     } | ||||
|     if(roles.contains(Meta::VersionList::TimeRole)) | ||||
|     { | ||||
|     if (roles.contains(Meta::VersionList::TimeRole)) { | ||||
|         m_columns.push_back(Time); | ||||
|     } | ||||
|     if(roles.contains(BaseVersionList::BranchRole)) | ||||
|     { | ||||
|     if (roles.contains(BaseVersionList::BranchRole)) { | ||||
|         m_columns.push_back(Branch); | ||||
|     } | ||||
|     if(roles.contains(BaseVersionList::TypeRole)) | ||||
|     { | ||||
|     if (roles.contains(BaseVersionList::TypeRole)) { | ||||
|         m_columns.push_back(Type); | ||||
|     } | ||||
|     if(roles.contains(BaseVersionList::RecommendedRole)) | ||||
|     { | ||||
|     if (roles.contains(BaseVersionList::RecommendedRole)) { | ||||
|         hasRecommended = true; | ||||
|     } | ||||
|     if(roles.contains(BaseVersionList::LatestRole)) | ||||
|     { | ||||
|     if (roles.contains(BaseVersionList::LatestRole)) { | ||||
|         hasLatest = true; | ||||
|     } | ||||
|     filterModel->setSourceModel(replacing); | ||||
| @@ -382,16 +336,13 @@ void VersionProxyModel::setSourceModel(QAbstractItemModel *replacingRaw) | ||||
|  | ||||
| QModelIndex VersionProxyModel::getRecommended() const | ||||
| { | ||||
|     if(!roles.contains(BaseVersionList::RecommendedRole)) | ||||
|     { | ||||
|     if (!roles.contains(BaseVersionList::RecommendedRole)) { | ||||
|         return index(0, 0); | ||||
|     } | ||||
|     int recommended = 0; | ||||
|     for (int i = 0; i < rowCount(); i++) | ||||
|     { | ||||
|     for (int i = 0; i < rowCount(); i++) { | ||||
|         auto value = sourceModel()->data(mapToSource(index(i, 0)), BaseVersionList::RecommendedRole); | ||||
|         if (value.toBool()) | ||||
|         { | ||||
|         if (value.toBool()) { | ||||
|             recommended = i; | ||||
|         } | ||||
|     } | ||||
| @@ -401,16 +352,13 @@ QModelIndex VersionProxyModel::getRecommended() const | ||||
| QModelIndex VersionProxyModel::getVersion(const QString& version) const | ||||
| { | ||||
|     int found = -1; | ||||
|     for (int i = 0; i < rowCount(); i++) | ||||
|     { | ||||
|     for (int i = 0; i < rowCount(); i++) { | ||||
|         auto value = sourceModel()->data(mapToSource(index(i, 0)), BaseVersionList::VersionRole); | ||||
|         if (value.toString() == version) | ||||
|         { | ||||
|         if (value.toString() == version) { | ||||
|             found = i; | ||||
|         } | ||||
|     } | ||||
|     if(found == -1) | ||||
|     { | ||||
|     if (found == -1) { | ||||
|         return QModelIndex(); | ||||
|     } | ||||
|     return index(found, 0); | ||||
| @@ -423,23 +371,24 @@ void VersionProxyModel::clearFilters() | ||||
|     filterModel->filterChanged(); | ||||
| } | ||||
|  | ||||
| void VersionProxyModel::setFilter(const BaseVersionList::ModelRoles column, Filter * f) | ||||
| void VersionProxyModel::setFilter(const BaseVersionList::ModelRoles column, Filter* f) | ||||
| { | ||||
|     m_filters[column].reset(f); | ||||
|     filterModel->filterChanged(); | ||||
| } | ||||
|  | ||||
| void VersionProxyModel::setSearch(const QString &search) { | ||||
| void VersionProxyModel::setSearch(const QString& search) | ||||
| { | ||||
|     m_search = search; | ||||
|     filterModel->filterChanged(); | ||||
| } | ||||
|  | ||||
| const VersionProxyModel::FilterMap &VersionProxyModel::filters() const | ||||
| const VersionProxyModel::FilterMap& VersionProxyModel::filters() const | ||||
| { | ||||
|     return m_filters; | ||||
| } | ||||
|  | ||||
| const QString &VersionProxyModel::search() const | ||||
| const QString& VersionProxyModel::search() const | ||||
| { | ||||
|     return m_search; | ||||
| } | ||||
| @@ -474,7 +423,7 @@ void VersionProxyModel::sourceRowsRemoved(const QModelIndex& parent, int first, | ||||
|     endRemoveRows(); | ||||
| } | ||||
|  | ||||
| void VersionProxyModel::setCurrentVersion(const QString &version) | ||||
| void VersionProxyModel::setCurrentVersion(const QString& version) | ||||
| { | ||||
|     m_currentVersion = version; | ||||
| } | ||||
|   | ||||
| @@ -6,64 +6,53 @@ | ||||
|  | ||||
| class VersionFilterModel; | ||||
|  | ||||
| class VersionProxyModel: public QAbstractProxyModel | ||||
| { | ||||
| class VersionProxyModel : public QAbstractProxyModel { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|  | ||||
|     enum Column | ||||
|     { | ||||
|         Name, | ||||
|         ParentVersion, | ||||
|         Branch, | ||||
|         Type, | ||||
|         Architecture, | ||||
|         Path, | ||||
|         Time | ||||
|     }; | ||||
|    public: | ||||
|     enum Column { Name, ParentVersion, Branch, Type, Architecture, Path, Time }; | ||||
|     typedef QHash<BaseVersionList::ModelRoles, std::shared_ptr<Filter>> FilterMap; | ||||
|  | ||||
| public: | ||||
|     VersionProxyModel ( QObject* parent = 0 ); | ||||
|     virtual ~VersionProxyModel() {}; | ||||
|    public: | ||||
|     VersionProxyModel(QObject* parent = 0); | ||||
|     virtual ~VersionProxyModel(){}; | ||||
|  | ||||
|     virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override; | ||||
|     virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; | ||||
|     virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override; | ||||
|     virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const override; | ||||
|     virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; | ||||
|     virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; | ||||
|     virtual int columnCount(const QModelIndex& parent = QModelIndex()) const override; | ||||
|     virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override; | ||||
|     virtual QModelIndex mapFromSource(const QModelIndex& sourceIndex) const override; | ||||
|     virtual QModelIndex mapToSource(const QModelIndex& proxyIndex) const override; | ||||
|     virtual QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; | ||||
|     virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; | ||||
|     virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; | ||||
|     virtual QModelIndex parent(const QModelIndex &child) const override; | ||||
|     virtual void setSourceModel(QAbstractItemModel *sourceModel) override; | ||||
|     virtual QModelIndex parent(const QModelIndex& child) const override; | ||||
|     virtual void setSourceModel(QAbstractItemModel* sourceModel) override; | ||||
|  | ||||
|     const FilterMap &filters() const; | ||||
|     const QString &search() const; | ||||
|     void setFilter(const BaseVersionList::ModelRoles column, Filter * filter); | ||||
|     void setSearch(const QString &search); | ||||
|     const FilterMap& filters() const; | ||||
|     const QString& search() const; | ||||
|     void setFilter(const BaseVersionList::ModelRoles column, Filter* filter); | ||||
|     void setSearch(const QString& search); | ||||
|     void clearFilters(); | ||||
|     QModelIndex getRecommended() const; | ||||
|     QModelIndex getVersion(const QString & version) const; | ||||
|     void setCurrentVersion(const QString &version); | ||||
| private slots: | ||||
|     QModelIndex getVersion(const QString& version) const; | ||||
|     void setCurrentVersion(const QString& version); | ||||
|    private slots: | ||||
|  | ||||
|     void sourceDataChanged(const QModelIndex &source_top_left,const QModelIndex &source_bottom_right); | ||||
|     void sourceDataChanged(const QModelIndex& source_top_left, const QModelIndex& source_bottom_right); | ||||
|  | ||||
|     void sourceAboutToBeReset(); | ||||
|     void sourceReset(); | ||||
|  | ||||
|     void sourceRowsAboutToBeInserted(const QModelIndex &parent, int first, int last); | ||||
|     void sourceRowsInserted(const QModelIndex &parent, int first, int last); | ||||
|     void sourceRowsAboutToBeInserted(const QModelIndex& parent, int first, int last); | ||||
|     void sourceRowsInserted(const QModelIndex& parent, int first, int last); | ||||
|  | ||||
|     void sourceRowsAboutToBeRemoved(const QModelIndex &parent, int first, int last); | ||||
|     void sourceRowsRemoved(const QModelIndex &parent, int first, int last); | ||||
|     void sourceRowsAboutToBeRemoved(const QModelIndex& parent, int first, int last); | ||||
|     void sourceRowsRemoved(const QModelIndex& parent, int first, int last); | ||||
|  | ||||
| private: | ||||
|    private: | ||||
|     QList<Column> m_columns; | ||||
|     FilterMap m_filters; | ||||
|     QString m_search; | ||||
|     BaseVersionList::RoleList roles; | ||||
|     VersionFilterModel * filterModel; | ||||
|     VersionFilterModel* filterModel; | ||||
|     bool hasRecommended = false; | ||||
|     bool hasLatest = false; | ||||
|     QString m_currentVersion; | ||||
|   | ||||
| @@ -1,20 +1,15 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <QString> | ||||
| #include <QFileSystemWatcher> | ||||
| #include <QString> | ||||
|  | ||||
| struct WatchLock | ||||
| { | ||||
|     WatchLock(QFileSystemWatcher * watcher, const QString& directory) | ||||
|         : m_watcher(watcher), m_directory(directory) | ||||
| struct WatchLock { | ||||
|     WatchLock(QFileSystemWatcher* watcher, const QString& directory) : m_watcher(watcher), m_directory(directory) | ||||
|     { | ||||
|         m_watcher->removePath(m_directory); | ||||
|     } | ||||
|     ~WatchLock() | ||||
|     { | ||||
|         m_watcher->addPath(m_directory); | ||||
|     } | ||||
|     QFileSystemWatcher * m_watcher; | ||||
|     ~WatchLock() { m_watcher->addPath(m_directory); } | ||||
|     QFileSystemWatcher* m_watcher; | ||||
|     QString m_directory; | ||||
| }; | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
| @@ -35,32 +35,29 @@ | ||||
|  | ||||
| #include "IconList.h" | ||||
| #include <FileSystem.h> | ||||
| #include <QMap> | ||||
| #include <QEventLoop> | ||||
| #include <QMimeData> | ||||
| #include <QUrl> | ||||
| #include <QFileSystemWatcher> | ||||
| #include <QSet> | ||||
| #include <QDebug> | ||||
| #include <QEventLoop> | ||||
| #include <QFileSystemWatcher> | ||||
| #include <QMap> | ||||
| #include <QMimeData> | ||||
| #include <QSet> | ||||
| #include <QUrl> | ||||
|  | ||||
| #define MAX_SIZE 1024 | ||||
|  | ||||
| IconList::IconList(const QStringList &builtinPaths, QString path, QObject *parent) : QAbstractListModel(parent) | ||||
| IconList::IconList(const QStringList& builtinPaths, QString path, QObject* parent) : QAbstractListModel(parent) | ||||
| { | ||||
|     QSet<QString> builtinNames; | ||||
|  | ||||
|     // add builtin icons | ||||
|     for(auto & builtinPath: builtinPaths) | ||||
|     { | ||||
|     for (auto& builtinPath : builtinPaths) { | ||||
|         QDir instance_icons(builtinPath); | ||||
|         auto file_info_list = instance_icons.entryInfoList(QDir::Files, QDir::Name); | ||||
|         for (auto file_info : file_info_list) | ||||
|         { | ||||
|         for (auto file_info : file_info_list) { | ||||
|             builtinNames.insert(file_info.completeBaseName()); | ||||
|         } | ||||
|     } | ||||
|     for(auto & builtinName : builtinNames) | ||||
|     { | ||||
|     for (auto& builtinName : builtinNames) { | ||||
|         addThemeIcon(builtinName); | ||||
|     } | ||||
|  | ||||
| @@ -78,31 +75,27 @@ IconList::IconList(const QStringList &builtinPaths, QString path, QObject *paren | ||||
| void IconList::sortIconList() | ||||
| { | ||||
|     qDebug() << "Sorting icon list..."; | ||||
|     std::sort(icons.begin(), icons.end(), [](const MMCIcon& a, const MMCIcon& b) { | ||||
|         return a.m_key.localeAwareCompare(b.m_key) < 0; | ||||
|     }); | ||||
|     std::sort(icons.begin(), icons.end(), [](const MMCIcon& a, const MMCIcon& b) { return a.m_key.localeAwareCompare(b.m_key) < 0; }); | ||||
|     reindex(); | ||||
| } | ||||
|  | ||||
| void IconList::directoryChanged(const QString &path) | ||||
| void IconList::directoryChanged(const QString& path) | ||||
| { | ||||
|     QDir new_dir (path); | ||||
|     if(m_dir.absolutePath() != new_dir.absolutePath()) | ||||
|     { | ||||
|     QDir new_dir(path); | ||||
|     if (m_dir.absolutePath() != new_dir.absolutePath()) { | ||||
|         m_dir.setPath(path); | ||||
|         m_dir.refresh(); | ||||
|         if(is_watching) | ||||
|         if (is_watching) | ||||
|             stopWatching(); | ||||
|         startWatching(); | ||||
|     } | ||||
|     if(!m_dir.exists()) | ||||
|         if(!FS::ensureFolderPathExists(m_dir.absolutePath())) | ||||
|     if (!m_dir.exists()) | ||||
|         if (!FS::ensureFolderPathExists(m_dir.absolutePath())) | ||||
|             return; | ||||
|     m_dir.refresh(); | ||||
|     auto new_list = m_dir.entryList(QDir::Files, QDir::Name); | ||||
|     for (auto it = new_list.begin(); it != new_list.end(); it++) | ||||
|     { | ||||
|         QString &foo = (*it); | ||||
|     for (auto it = new_list.begin(); it != new_list.end(); it++) { | ||||
|         QString& foo = (*it); | ||||
|         foo = m_dir.filePath(foo); | ||||
|     } | ||||
| #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) | ||||
| @@ -111,8 +104,7 @@ void IconList::directoryChanged(const QString &path) | ||||
|     auto new_set = new_list.toSet(); | ||||
| #endif | ||||
|     QList<QString> current_list; | ||||
|     for (auto &it : icons) | ||||
|     { | ||||
|     for (auto& it : icons) { | ||||
|         if (!it.has(IconType::FileBased)) | ||||
|             continue; | ||||
|         current_list.push_back(it.m_images[IconType::FileBased].filename); | ||||
| @@ -129,8 +121,7 @@ void IconList::directoryChanged(const QString &path) | ||||
|     QSet<QString> to_add = new_set; | ||||
|     to_add -= current_set; | ||||
|  | ||||
|     for (auto remove : to_remove) | ||||
|     { | ||||
|     for (auto remove : to_remove) { | ||||
|         qDebug() << "Removing " << remove; | ||||
|         QFileInfo rmfile(remove); | ||||
|         QString key = rmfile.completeBaseName(); | ||||
| @@ -144,23 +135,19 @@ void IconList::directoryChanged(const QString &path) | ||||
|         if (idx == -1) | ||||
|             continue; | ||||
|         icons[idx].remove(IconType::FileBased); | ||||
|         if (icons[idx].type() == IconType::ToBeDeleted) | ||||
|         { | ||||
|         if (icons[idx].type() == IconType::ToBeDeleted) { | ||||
|             beginRemoveRows(QModelIndex(), idx, idx); | ||||
|             icons.remove(idx); | ||||
|             reindex(); | ||||
|             endRemoveRows(); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|         } else { | ||||
|             dataChanged(index(idx), index(idx)); | ||||
|         } | ||||
|         m_watcher->removePath(remove); | ||||
|         emit iconUpdated(key); | ||||
|     } | ||||
|  | ||||
|     for (auto add : to_add) | ||||
|     { | ||||
|     for (auto add : to_add) { | ||||
|         qDebug() << "Adding " << add; | ||||
|  | ||||
|         QFileInfo addfile(add); | ||||
| @@ -171,8 +158,7 @@ void IconList::directoryChanged(const QString &path) | ||||
|         if (suffix != "jpeg" && suffix != "png" && suffix != "jpg" && suffix != "ico" && suffix != "svg" && suffix != "gif") | ||||
|             key = addfile.fileName(); | ||||
|  | ||||
|         if (addIcon(key, QString(), addfile.filePath(), IconType::FileBased)) | ||||
|         { | ||||
|         if (addIcon(key, QString(), addfile.filePath(), IconType::FileBased)) { | ||||
|             m_watcher->addPath(add); | ||||
|             emit iconUpdated(key); | ||||
|         } | ||||
| @@ -181,7 +167,7 @@ void IconList::directoryChanged(const QString &path) | ||||
|     sortIconList(); | ||||
| } | ||||
|  | ||||
| void IconList::fileChanged(const QString &path) | ||||
| void IconList::fileChanged(const QString& path) | ||||
| { | ||||
|     qDebug() << "Checking " << path; | ||||
|     QFileInfo checkfile(path); | ||||
| @@ -200,9 +186,9 @@ void IconList::fileChanged(const QString &path) | ||||
|     emit iconUpdated(key); | ||||
| } | ||||
|  | ||||
| void IconList::SettingChanged(const Setting &setting, QVariant value) | ||||
| void IconList::SettingChanged(const Setting& setting, QVariant value) | ||||
| { | ||||
|     if(setting.id() != "IconsDir") | ||||
|     if (setting.id() != "IconsDir") | ||||
|         return; | ||||
|  | ||||
|     directoryChanged(value.toString()); | ||||
| @@ -213,12 +199,9 @@ void IconList::startWatching() | ||||
|     auto abs_path = m_dir.absolutePath(); | ||||
|     FS::ensureFolderPathExists(abs_path); | ||||
|     is_watching = m_watcher->addPath(abs_path); | ||||
|     if (is_watching) | ||||
|     { | ||||
|     if (is_watching) { | ||||
|         qDebug() << "Started watching " << abs_path; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|     } else { | ||||
|         qDebug() << "Failed to start watching " << abs_path; | ||||
|     } | ||||
| } | ||||
| @@ -241,7 +224,11 @@ Qt::DropActions IconList::supportedDropActions() const | ||||
|     return Qt::CopyAction; | ||||
| } | ||||
|  | ||||
| bool IconList::dropMimeData(const QMimeData *data, Qt::DropAction action, [[maybe_unused]] int row, [[maybe_unused]] int column, [[maybe_unused]] const QModelIndex &parent) | ||||
| bool IconList::dropMimeData(const QMimeData* data, | ||||
|                             Qt::DropAction action, | ||||
|                             [[maybe_unused]] int row, | ||||
|                             [[maybe_unused]] int column, | ||||
|                             [[maybe_unused]] const QModelIndex& parent) | ||||
| { | ||||
|     if (action == Qt::IgnoreAction) | ||||
|         return true; | ||||
| @@ -250,12 +237,10 @@ bool IconList::dropMimeData(const QMimeData *data, Qt::DropAction action, [[mayb | ||||
|         return false; | ||||
|  | ||||
|     // files dropped from outside? | ||||
|     if (data->hasUrls()) | ||||
|     { | ||||
|     if (data->hasUrls()) { | ||||
|         auto urls = data->urls(); | ||||
|         QStringList iconFiles; | ||||
|         for (auto url : urls) | ||||
|         { | ||||
|         for (auto url : urls) { | ||||
|             // only local files may be dropped... | ||||
|             if (!url.isLocalFile()) | ||||
|                 continue; | ||||
| @@ -267,7 +252,7 @@ bool IconList::dropMimeData(const QMimeData *data, Qt::DropAction action, [[mayb | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| Qt::ItemFlags IconList::flags(const QModelIndex &index) const | ||||
| Qt::ItemFlags IconList::flags(const QModelIndex& index) const | ||||
| { | ||||
|     Qt::ItemFlags defaultFlags = QAbstractListModel::flags(index); | ||||
|     if (index.isValid()) | ||||
| @@ -276,7 +261,7 @@ Qt::ItemFlags IconList::flags(const QModelIndex &index) const | ||||
|         return Qt::ItemIsDropEnabled | defaultFlags; | ||||
| } | ||||
|  | ||||
| QVariant IconList::data(const QModelIndex &index, int role) const | ||||
| QVariant IconList::data(const QModelIndex& index, int role) const | ||||
| { | ||||
|     if (!index.isValid()) | ||||
|         return QVariant(); | ||||
| @@ -286,28 +271,26 @@ QVariant IconList::data(const QModelIndex &index, int role) const | ||||
|     if (row < 0 || row >= icons.size()) | ||||
|         return QVariant(); | ||||
|  | ||||
|     switch (role) | ||||
|     { | ||||
|     case Qt::DecorationRole: | ||||
|         return icons[row].icon(); | ||||
|     case Qt::DisplayRole: | ||||
|         return icons[row].name(); | ||||
|     case Qt::UserRole: | ||||
|         return icons[row].m_key; | ||||
|     default: | ||||
|         return QVariant(); | ||||
|     switch (role) { | ||||
|         case Qt::DecorationRole: | ||||
|             return icons[row].icon(); | ||||
|         case Qt::DisplayRole: | ||||
|             return icons[row].name(); | ||||
|         case Qt::UserRole: | ||||
|             return icons[row].m_key; | ||||
|         default: | ||||
|             return QVariant(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| int IconList::rowCount(const QModelIndex &parent) const | ||||
| int IconList::rowCount(const QModelIndex& parent) const | ||||
| { | ||||
|     return parent.isValid() ? 0 : icons.size(); | ||||
| } | ||||
|  | ||||
| void IconList::installIcons(const QStringList &iconFiles) | ||||
| void IconList::installIcons(const QStringList& iconFiles) | ||||
| { | ||||
|     for (QString file : iconFiles) | ||||
|     { | ||||
|     for (QString file : iconFiles) { | ||||
|         QFileInfo fileinfo(file); | ||||
|         if (!fileinfo.isReadable() || !fileinfo.isFile()) | ||||
|             continue; | ||||
| @@ -322,10 +305,10 @@ void IconList::installIcons(const QStringList &iconFiles) | ||||
|     } | ||||
| } | ||||
|  | ||||
| void IconList::installIcon(const QString &file, const QString &name) | ||||
| void IconList::installIcon(const QString& file, const QString& name) | ||||
| { | ||||
|     QFileInfo fileinfo(file); | ||||
|     if(!fileinfo.isReadable() || !fileinfo.isFile()) | ||||
|     if (!fileinfo.isReadable() || !fileinfo.isFile()) | ||||
|         return; | ||||
|  | ||||
|     QString target = FS::PathCombine(getDirectory(), name); | ||||
| @@ -333,17 +316,16 @@ void IconList::installIcon(const QString &file, const QString &name) | ||||
|     QFile::copy(file, target); | ||||
| } | ||||
|  | ||||
| bool IconList::iconFileExists(const QString &key) const | ||||
| bool IconList::iconFileExists(const QString& key) const | ||||
| { | ||||
|     auto iconEntry = icon(key); | ||||
|     if(!iconEntry) | ||||
|     { | ||||
|     if (!iconEntry) { | ||||
|         return false; | ||||
|     } | ||||
|     return iconEntry->has(IconType::FileBased); | ||||
| } | ||||
|  | ||||
| const MMCIcon *IconList::icon(const QString &key) const | ||||
| const MMCIcon* IconList::icon(const QString& key) const | ||||
| { | ||||
|     int iconIdx = getIconIndex(key); | ||||
|     if (iconIdx == -1) | ||||
| @@ -351,7 +333,7 @@ const MMCIcon *IconList::icon(const QString &key) const | ||||
|     return &icons[iconIdx]; | ||||
| } | ||||
|  | ||||
| bool IconList::deleteIcon(const QString &key) | ||||
| bool IconList::deleteIcon(const QString& key) | ||||
| { | ||||
|     if (!iconFileExists(key)) | ||||
|         return false; | ||||
| @@ -359,7 +341,7 @@ bool IconList::deleteIcon(const QString &key) | ||||
|     return QFile::remove(icon(key)->getFilePath()); | ||||
| } | ||||
|  | ||||
| bool IconList::trashIcon(const QString &key) | ||||
| bool IconList::trashIcon(const QString& key) | ||||
| { | ||||
|     if (!iconFileExists(key)) | ||||
|         return false; | ||||
| @@ -370,15 +352,12 @@ bool IconList::trashIcon(const QString &key) | ||||
| bool IconList::addThemeIcon(const QString& key) | ||||
| { | ||||
|     auto iter = name_index.find(key); | ||||
|     if (iter != name_index.end()) | ||||
|     { | ||||
|         auto &oldOne = icons[*iter]; | ||||
|     if (iter != name_index.end()) { | ||||
|         auto& oldOne = icons[*iter]; | ||||
|         oldOne.replace(Builtin, key); | ||||
|         dataChanged(index(*iter), index(*iter)); | ||||
|         return true; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|     } else { | ||||
|         // add a new icon | ||||
|         beginInsertRows(QModelIndex(), icons.size(), icons.size()); | ||||
|         { | ||||
| @@ -394,22 +373,19 @@ bool IconList::addThemeIcon(const QString& key) | ||||
|     } | ||||
| } | ||||
|  | ||||
| bool IconList::addIcon(const QString &key, const QString &name, const QString &path, const IconType type) | ||||
| bool IconList::addIcon(const QString& key, const QString& name, const QString& path, const IconType type) | ||||
| { | ||||
|     // replace the icon even? is the input valid? | ||||
|     QIcon icon(path); | ||||
|     if (icon.isNull()) | ||||
|         return false; | ||||
|     auto iter = name_index.find(key); | ||||
|     if (iter != name_index.end()) | ||||
|     { | ||||
|         auto &oldOne = icons[*iter]; | ||||
|     if (iter != name_index.end()) { | ||||
|         auto& oldOne = icons[*iter]; | ||||
|         oldOne.replace(type, icon, path); | ||||
|         dataChanged(index(*iter), index(*iter)); | ||||
|         return true; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|     } else { | ||||
|         // add a new icon | ||||
|         beginInsertRows(QModelIndex(), icons.size(), icons.size()); | ||||
|         { | ||||
| @@ -425,26 +401,24 @@ bool IconList::addIcon(const QString &key, const QString &name, const QString &p | ||||
|     } | ||||
| } | ||||
|  | ||||
| void IconList::saveIcon(const QString &key, const QString &path, const char * format) const | ||||
| void IconList::saveIcon(const QString& key, const QString& path, const char* format) const | ||||
| { | ||||
|     auto icon = getIcon(key); | ||||
|     auto pixmap = icon.pixmap(128, 128); | ||||
|     pixmap.save(path, format); | ||||
| } | ||||
|  | ||||
|  | ||||
| void IconList::reindex() | ||||
| { | ||||
|     name_index.clear(); | ||||
|     int i = 0; | ||||
|     for (auto &iter : icons) | ||||
|     { | ||||
|     for (auto& iter : icons) { | ||||
|         name_index[iter.m_key] = i; | ||||
|         i++; | ||||
|     } | ||||
| } | ||||
|  | ||||
| QIcon IconList::getIcon(const QString &key) const | ||||
| QIcon IconList::getIcon(const QString& key) const | ||||
| { | ||||
|     int icon_index = getIconIndex(key); | ||||
|  | ||||
| @@ -459,7 +433,7 @@ QIcon IconList::getIcon(const QString &key) const | ||||
|     return QIcon(); | ||||
| } | ||||
|  | ||||
| int IconList::getIconIndex(const QString &key) const | ||||
| int IconList::getIconIndex(const QString& key) const | ||||
| { | ||||
|     auto iter = name_index.find(key == "default" ? "grass" : key); | ||||
|     if (iter != name_index.end()) | ||||
|   | ||||
| @@ -15,10 +15,10 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <QMutex> | ||||
| #include <QAbstractListModel> | ||||
| #include <QFile> | ||||
| #include <QDir> | ||||
| #include <QFile> | ||||
| #include <QMutex> | ||||
| #include <QtGui/QIcon> | ||||
| #include <memory> | ||||
|  | ||||
| @@ -29,58 +29,58 @@ | ||||
|  | ||||
| class QFileSystemWatcher; | ||||
|  | ||||
| class IconList : public QAbstractListModel | ||||
| { | ||||
| class IconList : public QAbstractListModel { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     explicit IconList(const QStringList &builtinPaths, QString path, QObject *parent = 0); | ||||
|     virtual ~IconList() {}; | ||||
|    public: | ||||
|     explicit IconList(const QStringList& builtinPaths, QString path, QObject* parent = 0); | ||||
|     virtual ~IconList(){}; | ||||
|  | ||||
|     QIcon getIcon(const QString &key) const; | ||||
|     int getIconIndex(const QString &key) const; | ||||
|     QIcon getIcon(const QString& key) const; | ||||
|     int getIconIndex(const QString& key) const; | ||||
|     QString getDirectory() const; | ||||
|  | ||||
|     virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; | ||||
|     virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; | ||||
|     virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; | ||||
|     virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override; | ||||
|  | ||||
|     virtual QStringList mimeTypes() const override; | ||||
|     virtual Qt::DropActions supportedDropActions() const override; | ||||
|     virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; | ||||
|     virtual Qt::ItemFlags flags(const QModelIndex &index) const override; | ||||
|     virtual bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) override; | ||||
|     virtual Qt::ItemFlags flags(const QModelIndex& index) const override; | ||||
|  | ||||
|     bool addThemeIcon(const QString &key); | ||||
|     bool addIcon(const QString &key, const QString &name, const QString &path, const IconType type); | ||||
|     void saveIcon(const QString &key, const QString &path, const char * format) const; | ||||
|     bool deleteIcon(const QString &key); | ||||
|     bool trashIcon(const QString &key); | ||||
|     bool iconFileExists(const QString &key) const; | ||||
|     bool addThemeIcon(const QString& key); | ||||
|     bool addIcon(const QString& key, const QString& name, const QString& path, const IconType type); | ||||
|     void saveIcon(const QString& key, const QString& path, const char* format) const; | ||||
|     bool deleteIcon(const QString& key); | ||||
|     bool trashIcon(const QString& key); | ||||
|     bool iconFileExists(const QString& key) const; | ||||
|  | ||||
|     void installIcons(const QStringList &iconFiles); | ||||
|     void installIcon(const QString &file, const QString &name); | ||||
|     void installIcons(const QStringList& iconFiles); | ||||
|     void installIcon(const QString& file, const QString& name); | ||||
|  | ||||
|     const MMCIcon * icon(const QString &key) const; | ||||
|     const MMCIcon* icon(const QString& key) const; | ||||
|  | ||||
|     void startWatching(); | ||||
|     void stopWatching(); | ||||
|  | ||||
| signals: | ||||
|    signals: | ||||
|     void iconUpdated(QString key); | ||||
|  | ||||
| private: | ||||
|    private: | ||||
|     // hide copy constructor | ||||
|     IconList(const IconList &) = delete; | ||||
|     IconList(const IconList&) = delete; | ||||
|     // hide assign op | ||||
|     IconList &operator=(const IconList &) = delete; | ||||
|     IconList& operator=(const IconList&) = delete; | ||||
|     void reindex(); | ||||
|     void sortIconList(); | ||||
|  | ||||
| public slots: | ||||
|     void directoryChanged(const QString &path); | ||||
|    public slots: | ||||
|     void directoryChanged(const QString& path); | ||||
|  | ||||
| protected slots: | ||||
|     void fileChanged(const QString &path); | ||||
|     void SettingChanged(const Setting & setting, QVariant value); | ||||
| private: | ||||
|    protected slots: | ||||
|     void fileChanged(const QString& path); | ||||
|     void SettingChanged(const Setting& setting, QVariant value); | ||||
|  | ||||
|    private: | ||||
|     shared_qobject_ptr<QFileSystemWatcher> m_watcher; | ||||
|     bool is_watching; | ||||
|     QMap<QString, int> name_index; | ||||
|   | ||||
| @@ -1,24 +1,18 @@ | ||||
| #include "IconUtils.h" | ||||
|  | ||||
| #include "FileSystem.h" | ||||
| #include <QDirIterator> | ||||
| #include "FileSystem.h" | ||||
|  | ||||
| #include <array> | ||||
|  | ||||
| namespace { | ||||
| std::array<const char *, 6> validIconExtensions = {{ | ||||
|     "svg", | ||||
|     "png", | ||||
|     "ico", | ||||
|     "gif", | ||||
|     "jpg", | ||||
|     "jpeg" | ||||
| }}; | ||||
| std::array<const char*, 6> validIconExtensions = { { "svg", "png", "ico", "gif", "jpg", "jpeg" } }; | ||||
| } | ||||
|  | ||||
| namespace IconUtils{ | ||||
| namespace IconUtils { | ||||
|  | ||||
| QString findBestIconIn(const QString &folder, const QString & iconKey) { | ||||
| QString findBestIconIn(const QString& folder, const QString& iconKey) | ||||
| { | ||||
|     int best_found = validIconExtensions.size(); | ||||
|     QString best_filename; | ||||
|  | ||||
| @@ -27,13 +21,13 @@ QString findBestIconIn(const QString &folder, const QString & iconKey) { | ||||
|         it.next(); | ||||
|         auto fileInfo = it.fileInfo(); | ||||
|  | ||||
|         if(fileInfo.completeBaseName() != iconKey) | ||||
|         if (fileInfo.completeBaseName() != iconKey) | ||||
|             continue; | ||||
|  | ||||
|         auto extension = fileInfo.suffix(); | ||||
|  | ||||
|         for(int i = 0; i < best_found; i++) { | ||||
|             if(extension == validIconExtensions[i]) { | ||||
|         for (int i = 0; i < best_found; i++) { | ||||
|             if (extension == validIconExtensions[i]) { | ||||
|                 best_found = i; | ||||
|                 qDebug() << i << " : " << fileInfo.fileName(); | ||||
|                 best_filename = fileInfo.fileName(); | ||||
| @@ -43,12 +37,13 @@ QString findBestIconIn(const QString &folder, const QString & iconKey) { | ||||
|     return FS::PathCombine(folder, best_filename); | ||||
| } | ||||
|  | ||||
| QString getIconFilter() { | ||||
| QString getIconFilter() | ||||
| { | ||||
|     QString out; | ||||
|     QTextStream stream(&out); | ||||
|     stream << '('; | ||||
|     for(size_t i = 0; i < validIconExtensions.size() - 1; i++) { | ||||
|         if(i > 0) { | ||||
|     for (size_t i = 0; i < validIconExtensions.size() - 1; i++) { | ||||
|         if (i > 0) { | ||||
|             stream << " "; | ||||
|         } | ||||
|         stream << "*." << validIconExtensions[i]; | ||||
| @@ -58,5 +53,4 @@ QString getIconFilter() { | ||||
|     return out; | ||||
| } | ||||
|  | ||||
| } | ||||
|  | ||||
| }  // namespace IconUtils | ||||
|   | ||||
| @@ -5,9 +5,9 @@ | ||||
| namespace IconUtils { | ||||
|  | ||||
| // Given a folder and an icon key, find 'best' of the icons with the given key in there and return its path | ||||
| QString findBestIconIn(const QString &folder, const QString & iconKey); | ||||
| QString findBestIconIn(const QString& folder, const QString& iconKey); | ||||
|  | ||||
| // Get icon file type filter for file browser dialogs | ||||
| QString getIconFilter(); | ||||
|  | ||||
| } | ||||
| }  // namespace IconUtils | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
| @@ -37,23 +37,21 @@ | ||||
| #include <QFileInfo> | ||||
| #include <QIcon> | ||||
|  | ||||
| IconType operator--(IconType &t, int) | ||||
| IconType operator--(IconType& t, int) | ||||
| { | ||||
|     IconType temp = t; | ||||
|     switch (t) | ||||
|     { | ||||
|     case IconType::Builtin: | ||||
|         t = IconType::ToBeDeleted; | ||||
|         break; | ||||
|     case IconType::Transient: | ||||
|         t = IconType::Builtin; | ||||
|         break; | ||||
|     case IconType::FileBased: | ||||
|         t = IconType::Transient; | ||||
|         break; | ||||
|     default: | ||||
|     { | ||||
|     } | ||||
|     switch (t) { | ||||
|         case IconType::Builtin: | ||||
|             t = IconType::ToBeDeleted; | ||||
|             break; | ||||
|         case IconType::Transient: | ||||
|             t = IconType::Builtin; | ||||
|             break; | ||||
|         case IconType::FileBased: | ||||
|             t = IconType::Transient; | ||||
|             break; | ||||
|         default: { | ||||
|         } | ||||
|     } | ||||
|     return temp; | ||||
| } | ||||
| @@ -79,8 +77,8 @@ QIcon MMCIcon::icon() const | ||||
| { | ||||
|     if (m_current_type == IconType::ToBeDeleted) | ||||
|         return QIcon(); | ||||
|     auto & icon = m_images[m_current_type].icon; | ||||
|     if(!icon.isNull()) | ||||
|     auto& icon = m_images[m_current_type].icon; | ||||
|     if (!icon.isNull()) | ||||
|         return icon; | ||||
|     // FIXME: inject this. | ||||
|     return QIcon::fromTheme(m_images[m_current_type].key); | ||||
| @@ -90,10 +88,8 @@ void MMCIcon::remove(IconType rm_type) | ||||
| { | ||||
|     m_images[rm_type].filename = QString(); | ||||
|     m_images[rm_type].icon = QIcon(); | ||||
|     for (auto iter = rm_type; iter != IconType::ToBeDeleted; iter--) | ||||
|     { | ||||
|         if (m_images[iter].present()) | ||||
|         { | ||||
|     for (auto iter = rm_type; iter != IconType::ToBeDeleted; iter--) { | ||||
|         if (m_images[iter].present()) { | ||||
|             m_current_type = iter; | ||||
|             return; | ||||
|         } | ||||
| @@ -103,8 +99,7 @@ void MMCIcon::remove(IconType rm_type) | ||||
|  | ||||
| void MMCIcon::replace(IconType new_type, QIcon icon, QString path) | ||||
| { | ||||
|     if (new_type > m_current_type || m_current_type == IconType::ToBeDeleted) | ||||
|     { | ||||
|     if (new_type > m_current_type || m_current_type == IconType::ToBeDeleted) { | ||||
|         m_current_type = new_type; | ||||
|     } | ||||
|     m_images[new_type].icon = icon; | ||||
| @@ -114,8 +109,7 @@ void MMCIcon::replace(IconType new_type, QIcon icon, QString path) | ||||
|  | ||||
| void MMCIcon::replace(IconType new_type, const QString& key) | ||||
| { | ||||
|     if (new_type > m_current_type || m_current_type == IconType::ToBeDeleted) | ||||
|     { | ||||
|     if (new_type > m_current_type || m_current_type == IconType::ToBeDeleted) { | ||||
|         m_current_type = new_type; | ||||
|     } | ||||
|     m_images[new_type].icon = QIcon(); | ||||
| @@ -125,13 +119,12 @@ void MMCIcon::replace(IconType new_type, const QString& key) | ||||
|  | ||||
| QString MMCIcon::getFilePath() const | ||||
| { | ||||
|     if(m_current_type == IconType::ToBeDeleted){ | ||||
|     if (m_current_type == IconType::ToBeDeleted) { | ||||
|         return QString(); | ||||
|     } | ||||
|     return m_images[m_current_type].filename; | ||||
| } | ||||
|  | ||||
|  | ||||
| bool MMCIcon::isBuiltIn() const | ||||
| { | ||||
|     return m_current_type == IconType::Builtin; | ||||
|   | ||||
| @@ -14,32 +14,20 @@ | ||||
|  */ | ||||
|  | ||||
| #pragma once | ||||
| #include <QString> | ||||
| #include <QDateTime> | ||||
| #include <QIcon> | ||||
| #include <QString> | ||||
|  | ||||
| enum IconType : unsigned | ||||
| { | ||||
|     Builtin, | ||||
|     Transient, | ||||
|     FileBased, | ||||
|     ICONS_TOTAL, | ||||
|     ToBeDeleted | ||||
| }; | ||||
| enum IconType : unsigned { Builtin, Transient, FileBased, ICONS_TOTAL, ToBeDeleted }; | ||||
|  | ||||
| struct MMCImage | ||||
| { | ||||
| struct MMCImage { | ||||
|     QIcon icon; | ||||
|     QString key; | ||||
|     QString filename; | ||||
|     bool present() const | ||||
|     { | ||||
|         return !icon.isNull() || !key.isEmpty(); | ||||
|     } | ||||
|     bool present() const { return !icon.isNull() || !key.isEmpty(); } | ||||
| }; | ||||
|  | ||||
| struct MMCIcon | ||||
| { | ||||
| struct MMCIcon { | ||||
|     QString m_key; | ||||
|     QString m_name; | ||||
|     MMCImage m_images[ICONS_TOTAL]; | ||||
| @@ -51,7 +39,7 @@ struct MMCIcon | ||||
|     QIcon icon() const; | ||||
|     void remove(IconType rm_type); | ||||
|     void replace(IconType new_type, QIcon icon, QString path = QString()); | ||||
|     void replace(IconType new_type, const QString &key); | ||||
|     void replace(IconType new_type, const QString& key); | ||||
|     bool isBuiltIn() const; | ||||
|     QString getFilePath() const; | ||||
| }; | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
| @@ -35,26 +35,23 @@ | ||||
|  | ||||
| #include "JavaChecker.h" | ||||
|  | ||||
| #include <QFile> | ||||
| #include <QProcess> | ||||
| #include <QMap> | ||||
| #include <QDebug> | ||||
| #include <QFile> | ||||
| #include <QMap> | ||||
| #include <QProcess> | ||||
|  | ||||
| #include "JavaUtils.h" | ||||
| #include "FileSystem.h" | ||||
| #include "Commandline.h" | ||||
| #include "Application.h" | ||||
| #include "Commandline.h" | ||||
| #include "FileSystem.h" | ||||
| #include "JavaUtils.h" | ||||
|  | ||||
| JavaChecker::JavaChecker(QObject *parent) : QObject(parent) | ||||
| { | ||||
| } | ||||
| JavaChecker::JavaChecker(QObject* parent) : QObject(parent) {} | ||||
|  | ||||
| void JavaChecker::performCheck() | ||||
| { | ||||
|     QString checkerJar = JavaUtils::getJavaCheckPath(); | ||||
|  | ||||
|     if (checkerJar.isEmpty()) | ||||
|     { | ||||
|     if (checkerJar.isEmpty()) { | ||||
|         qDebug() << "Java checker library could not be found. Please check your installation."; | ||||
|         return; | ||||
|     } | ||||
| @@ -62,25 +59,21 @@ void JavaChecker::performCheck() | ||||
|     QStringList args; | ||||
|  | ||||
|     process.reset(new QProcess()); | ||||
|     if(m_args.size()) | ||||
|     { | ||||
|     if (m_args.size()) { | ||||
|         auto extraArgs = Commandline::splitArgs(m_args); | ||||
|         args.append(extraArgs); | ||||
|     } | ||||
|     if(m_minMem != 0) | ||||
|     { | ||||
|     if (m_minMem != 0) { | ||||
|         args << QString("-Xms%1m").arg(m_minMem); | ||||
|     } | ||||
|     if(m_maxMem != 0) | ||||
|     { | ||||
|     if (m_maxMem != 0) { | ||||
|         args << QString("-Xmx%1m").arg(m_maxMem); | ||||
|     } | ||||
|     if(m_permGen != 64) | ||||
|     { | ||||
|     if (m_permGen != 64) { | ||||
|         args << QString("-XX:PermSize=%1m").arg(m_permGen); | ||||
|     } | ||||
|  | ||||
|     args.append({"-jar", checkerJar}); | ||||
|     args.append({ "-jar", checkerJar }); | ||||
|     process->setArguments(args); | ||||
|     process->setProgram(m_path); | ||||
|     process->setProcessChannelMode(QProcess::SeparateChannels); | ||||
| @@ -130,8 +123,7 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status) | ||||
|     qWarning() << "STDERR" << m_stderr; | ||||
|     qDebug() << "Java checker finished with status" << status << "exit code" << exitcode; | ||||
|  | ||||
|     if (status == QProcess::CrashExit || exitcode == 1) | ||||
|     { | ||||
|     if (status == QProcess::CrashExit || exitcode == 1) { | ||||
|         result.validity = JavaCheckResult::Validity::Errored; | ||||
|         emit checkFinished(result); | ||||
|         return; | ||||
| @@ -146,8 +138,7 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status) | ||||
| #else | ||||
|     QStringList lines = m_stdout.split("\n", QString::SkipEmptyParts); | ||||
| #endif | ||||
|     for(QString line : lines) | ||||
|     { | ||||
|     for (QString line : lines) { | ||||
|         line = line.trimmed(); | ||||
|         // NOTE: workaround for GH-4125, where garbage is getting printed into stdout on bedrock linux | ||||
|         if (line.contains("/bedrock/strata")) { | ||||
| @@ -159,18 +150,14 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status) | ||||
| #else | ||||
|         auto parts = line.split('=', QString::SkipEmptyParts); | ||||
| #endif | ||||
|         if(parts.size() != 2 || parts[0].isEmpty() || parts[1].isEmpty()) | ||||
|         { | ||||
|         if (parts.size() != 2 || parts[0].isEmpty() || parts[1].isEmpty()) { | ||||
|             continue; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|         } else { | ||||
|             results.insert(parts[0], parts[1]); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if(!results.contains("os.arch") || !results.contains("java.version") || !results.contains("java.vendor") || !success) | ||||
|     { | ||||
|     if (!results.contains("os.arch") || !results.contains("java.version") || !results.contains("java.vendor") || !success) { | ||||
|         result.validity = JavaCheckResult::Validity::ReturnedInvalidData; | ||||
|         emit checkFinished(result); | ||||
|         return; | ||||
| @@ -181,7 +168,6 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status) | ||||
|     auto java_vendor = results["java.vendor"]; | ||||
|     bool is_64 = os_arch == "x86_64" || os_arch == "amd64" || os_arch == "aarch64" || os_arch == "arm64"; | ||||
|  | ||||
|  | ||||
|     result.validity = JavaCheckResult::Validity::Valid; | ||||
|     result.is_64bit = is_64; | ||||
|     result.mojangPlatform = is_64 ? "64" : "32"; | ||||
| @@ -194,8 +180,7 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status) | ||||
|  | ||||
| void JavaChecker::error(QProcess::ProcessError err) | ||||
| { | ||||
|     if(err == QProcess::FailedToStart) | ||||
|     { | ||||
|     if (err == QProcess::FailedToStart) { | ||||
|         qDebug() << "Java checker has failed to start."; | ||||
|         qDebug() << "Process environment:"; | ||||
|         qDebug() << process->environment(); | ||||
| @@ -216,8 +201,7 @@ void JavaChecker::error(QProcess::ProcessError err) | ||||
| void JavaChecker::timeout() | ||||
| { | ||||
|     // NO MERCY. NO ABUSE. | ||||
|     if(process) | ||||
|     { | ||||
|     if (process) { | ||||
|         qDebug() << "Java checker has been killed by timeout."; | ||||
|         process->kill(); | ||||
|     } | ||||
|   | ||||
| @@ -9,8 +9,7 @@ | ||||
|  | ||||
| class JavaChecker; | ||||
|  | ||||
| struct JavaCheckResult | ||||
| { | ||||
| struct JavaCheckResult { | ||||
|     QString path; | ||||
|     QString mojangPlatform; | ||||
|     QString realPlatform; | ||||
| @@ -20,21 +19,15 @@ struct JavaCheckResult | ||||
|     QString errorLog; | ||||
|     bool is_64bit = false; | ||||
|     int id; | ||||
|     enum class Validity | ||||
|     { | ||||
|         Errored, | ||||
|         ReturnedInvalidData, | ||||
|         Valid | ||||
|     } validity = Validity::Errored; | ||||
|     enum class Validity { Errored, ReturnedInvalidData, Valid } validity = Validity::Errored; | ||||
| }; | ||||
|  | ||||
| typedef shared_qobject_ptr<QProcess> QProcessPtr; | ||||
| typedef shared_qobject_ptr<JavaChecker> JavaCheckerPtr; | ||||
| class JavaChecker : public QObject | ||||
| { | ||||
| class JavaChecker : public QObject { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     explicit JavaChecker(QObject *parent = 0); | ||||
|    public: | ||||
|     explicit JavaChecker(QObject* parent = 0); | ||||
|     void performCheck(); | ||||
|  | ||||
|     QString m_path; | ||||
| @@ -44,15 +37,15 @@ public: | ||||
|     int m_maxMem = 0; | ||||
|     int m_permGen = 64; | ||||
|  | ||||
| signals: | ||||
|    signals: | ||||
|     void checkFinished(JavaCheckResult result); | ||||
| private: | ||||
|  | ||||
|    private: | ||||
|     QProcessPtr process; | ||||
|     QTimer killTimer; | ||||
|     QString m_stdout; | ||||
|     QString m_stderr; | ||||
| public | ||||
| slots: | ||||
|    public slots: | ||||
|     void timeout(); | ||||
|     void finished(int exitcode, QProcess::ExitStatus); | ||||
|     void error(QProcess::ProcessError); | ||||
|   | ||||
| @@ -20,14 +20,12 @@ | ||||
| void JavaCheckerJob::partFinished(JavaCheckResult result) | ||||
| { | ||||
|     num_finished++; | ||||
|     qDebug() << m_job_name.toLocal8Bit() << "progress:" << num_finished << "/" | ||||
|                 << javacheckers.size(); | ||||
|     qDebug() << m_job_name.toLocal8Bit() << "progress:" << num_finished << "/" << javacheckers.size(); | ||||
|     setProgress(num_finished, javacheckers.size()); | ||||
|  | ||||
|     javaresults.replace(result.id, result); | ||||
|  | ||||
|     if (num_finished == javacheckers.size()) | ||||
|     { | ||||
|     if (num_finished == javacheckers.size()) { | ||||
|         emitSucceeded(); | ||||
|     } | ||||
| } | ||||
| @@ -35,8 +33,7 @@ void JavaCheckerJob::partFinished(JavaCheckResult result) | ||||
| void JavaCheckerJob::executeTask() | ||||
| { | ||||
|     qDebug() << m_job_name.toLocal8Bit() << " started."; | ||||
|     for (auto iter : javacheckers) | ||||
|     { | ||||
|     for (auto iter : javacheckers) { | ||||
|         javaresults.append(JavaCheckResult()); | ||||
|         connect(iter.get(), &JavaChecker::checkFinished, this, &JavaCheckerJob::partFinished); | ||||
|         iter->performCheck(); | ||||
|   | ||||
| @@ -23,37 +23,32 @@ class JavaCheckerJob; | ||||
| typedef shared_qobject_ptr<JavaCheckerJob> JavaCheckerJobPtr; | ||||
|  | ||||
| // FIXME: this just seems horribly redundant | ||||
| class JavaCheckerJob : public Task | ||||
| { | ||||
| class JavaCheckerJob : public Task { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     explicit JavaCheckerJob(QString job_name) : Task(), m_job_name(job_name) {}; | ||||
|     virtual ~JavaCheckerJob() {}; | ||||
|    public: | ||||
|     explicit JavaCheckerJob(QString job_name) : Task(), m_job_name(job_name){}; | ||||
|     virtual ~JavaCheckerJob(){}; | ||||
|  | ||||
|     bool addJavaCheckerAction(JavaCheckerPtr base) | ||||
|     { | ||||
|         javacheckers.append(base); | ||||
|         // if this is already running, the action needs to be started right away! | ||||
|         if (isRunning()) | ||||
|         { | ||||
|         if (isRunning()) { | ||||
|             setProgress(num_finished, javacheckers.size()); | ||||
|             connect(base.get(), &JavaChecker::checkFinished, this, &JavaCheckerJob::partFinished); | ||||
|             base->performCheck(); | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|     QList<JavaCheckResult> getResults() | ||||
|     { | ||||
|         return javaresults; | ||||
|     } | ||||
|     QList<JavaCheckResult> getResults() { return javaresults; } | ||||
|  | ||||
| private slots: | ||||
|    private slots: | ||||
|     void partFinished(JavaCheckResult result); | ||||
|  | ||||
| protected: | ||||
|    protected: | ||||
|     virtual void executeTask() override; | ||||
|  | ||||
| private: | ||||
|    private: | ||||
|     QString m_job_name; | ||||
|     QList<JavaCheckerPtr> javacheckers; | ||||
|     QList<JavaCheckResult> javaresults; | ||||
|   | ||||
| @@ -39,14 +39,12 @@ | ||||
|  | ||||
| #include <QDebug> | ||||
|  | ||||
| #include "java/JavaInstallList.h" | ||||
| #include "java/JavaCheckerJob.h" | ||||
| #include "java/JavaInstallList.h" | ||||
| #include "java/JavaUtils.h" | ||||
| #include "minecraft/VersionFilterData.h" | ||||
|  | ||||
| JavaInstallList::JavaInstallList(QObject *parent) : BaseVersionList(parent) | ||||
| { | ||||
| } | ||||
| JavaInstallList::JavaInstallList(QObject* parent) : BaseVersionList(parent) {} | ||||
|  | ||||
| Task::Ptr JavaInstallList::getLoadTask() | ||||
| { | ||||
| @@ -56,8 +54,7 @@ Task::Ptr JavaInstallList::getLoadTask() | ||||
|  | ||||
| Task::Ptr JavaInstallList::getCurrentTask() | ||||
| { | ||||
|     if(m_status == Status::InProgress) | ||||
|     { | ||||
|     if (m_status == Status::InProgress) { | ||||
|         return m_loadTask; | ||||
|     } | ||||
|     return nullptr; | ||||
| @@ -65,8 +62,7 @@ Task::Ptr JavaInstallList::getCurrentTask() | ||||
|  | ||||
| void JavaInstallList::load() | ||||
| { | ||||
|     if(m_status != Status::InProgress) | ||||
|     { | ||||
|     if (m_status != Status::InProgress) { | ||||
|         m_status = Status::InProgress; | ||||
|         m_loadTask.reset(new JavaListLoadTask(this)); | ||||
|         m_loadTask->start(); | ||||
| @@ -88,7 +84,7 @@ int JavaInstallList::count() const | ||||
|     return m_vlist.count(); | ||||
| } | ||||
|  | ||||
| QVariant JavaInstallList::data(const QModelIndex &index, int role) const | ||||
| QVariant JavaInstallList::data(const QModelIndex& index, int role) const | ||||
| { | ||||
|     if (!index.isValid()) | ||||
|         return QVariant(); | ||||
| @@ -97,8 +93,7 @@ QVariant JavaInstallList::data(const QModelIndex &index, int role) const | ||||
|         return QVariant(); | ||||
|  | ||||
|     auto version = std::dynamic_pointer_cast<JavaInstall>(m_vlist[index.row()]); | ||||
|     switch (role) | ||||
|     { | ||||
|     switch (role) { | ||||
|         case SortRole: | ||||
|             return -index.row(); | ||||
|         case VersionPointerRole: | ||||
| @@ -120,17 +115,15 @@ QVariant JavaInstallList::data(const QModelIndex &index, int role) const | ||||
|  | ||||
| BaseVersionList::RoleList JavaInstallList::providesRoles() const | ||||
| { | ||||
|     return {VersionPointerRole, VersionIdRole, VersionRole, RecommendedRole, PathRole, ArchitectureRole}; | ||||
|     return { VersionPointerRole, VersionIdRole, VersionRole, RecommendedRole, PathRole, ArchitectureRole }; | ||||
| } | ||||
|  | ||||
|  | ||||
| void JavaInstallList::updateListData(QList<BaseVersion::Ptr> versions) | ||||
| { | ||||
|     beginResetModel(); | ||||
|     m_vlist = versions; | ||||
|     sortVersions(); | ||||
|     if(m_vlist.size()) | ||||
|     { | ||||
|     if (m_vlist.size()) { | ||||
|         auto best = std::dynamic_pointer_cast<JavaInstall>(m_vlist[0]); | ||||
|         best->recommended = true; | ||||
|     } | ||||
| @@ -153,15 +146,13 @@ void JavaInstallList::sortVersions() | ||||
|     endResetModel(); | ||||
| } | ||||
|  | ||||
| JavaListLoadTask::JavaListLoadTask(JavaInstallList *vlist) : Task() | ||||
| JavaListLoadTask::JavaListLoadTask(JavaInstallList* vlist) : Task() | ||||
| { | ||||
|     m_list = vlist; | ||||
|     m_currentRecommended = NULL; | ||||
| } | ||||
|  | ||||
| JavaListLoadTask::~JavaListLoadTask() | ||||
| { | ||||
| } | ||||
| JavaListLoadTask::~JavaListLoadTask() {} | ||||
|  | ||||
| void JavaListLoadTask::executeTask() | ||||
| { | ||||
| @@ -176,8 +167,7 @@ void JavaListLoadTask::executeTask() | ||||
|  | ||||
|     qDebug() << "Probing the following Java paths: "; | ||||
|     int id = 0; | ||||
|     for(QString candidate : candidate_paths) | ||||
|     { | ||||
|     for (QString candidate : candidate_paths) { | ||||
|         qDebug() << " " << candidate; | ||||
|  | ||||
|         auto candidate_checker = new JavaChecker(); | ||||
| @@ -197,10 +187,8 @@ void JavaListLoadTask::javaCheckerFinished() | ||||
|     auto results = m_job->getResults(); | ||||
|  | ||||
|     qDebug() << "Found the following valid Java installations:"; | ||||
|     for(JavaCheckResult result : results) | ||||
|     { | ||||
|         if(result.validity == JavaCheckResult::Validity::Valid) | ||||
|         { | ||||
|     for (JavaCheckResult result : results) { | ||||
|         if (result.validity == JavaCheckResult::Validity::Valid) { | ||||
|             JavaInstallPtr javaVersion(new JavaInstall()); | ||||
|  | ||||
|             javaVersion->id = result.javaVersion; | ||||
| @@ -213,13 +201,11 @@ void JavaListLoadTask::javaCheckerFinished() | ||||
|     } | ||||
|  | ||||
|     QList<BaseVersion::Ptr> javas_bvp; | ||||
|     for (auto java : candidates) | ||||
|     { | ||||
|         //qDebug() << java->id << java->arch << " at " << java->path; | ||||
|     for (auto java : candidates) { | ||||
|         // qDebug() << java->id << java->arch << " at " << java->path; | ||||
|         BaseVersion::Ptr bp_java = std::dynamic_pointer_cast<BaseVersion>(java); | ||||
|  | ||||
|         if (bp_java) | ||||
|         { | ||||
|         if (bp_java) { | ||||
|             javas_bvp.append(java); | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -15,8 +15,8 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <QObject> | ||||
| #include <QAbstractListModel> | ||||
| #include <QObject> | ||||
|  | ||||
| #include "BaseVersionList.h" | ||||
| #include "tasks/Task.h" | ||||
| @@ -28,17 +28,12 @@ | ||||
|  | ||||
| class JavaListLoadTask; | ||||
|  | ||||
| class JavaInstallList : public BaseVersionList | ||||
| { | ||||
| class JavaInstallList : public BaseVersionList { | ||||
|     Q_OBJECT | ||||
|     enum class Status | ||||
|     { | ||||
|         NotDone, | ||||
|         InProgress, | ||||
|         Done | ||||
|     }; | ||||
| public: | ||||
|     explicit JavaInstallList(QObject *parent = 0); | ||||
|     enum class Status { NotDone, InProgress, Done }; | ||||
|  | ||||
|    public: | ||||
|     explicit JavaInstallList(QObject* parent = 0); | ||||
|  | ||||
|     Task::Ptr getLoadTask() override; | ||||
|     bool isLoaded() override; | ||||
| @@ -46,36 +41,35 @@ public: | ||||
|     int count() const override; | ||||
|     void sortVersions() override; | ||||
|  | ||||
|     QVariant data(const QModelIndex &index, int role) const override; | ||||
|     QVariant data(const QModelIndex& index, int role) const override; | ||||
|     RoleList providesRoles() const override; | ||||
|  | ||||
| public slots: | ||||
|    public slots: | ||||
|     void updateListData(QList<BaseVersion::Ptr> versions) override; | ||||
|  | ||||
| protected: | ||||
|    protected: | ||||
|     void load(); | ||||
|     Task::Ptr getCurrentTask(); | ||||
|  | ||||
| protected: | ||||
|    protected: | ||||
|     Status m_status = Status::NotDone; | ||||
|     shared_qobject_ptr<JavaListLoadTask> m_loadTask; | ||||
|     QList<BaseVersion::Ptr> m_vlist; | ||||
| }; | ||||
|  | ||||
| class JavaListLoadTask : public Task | ||||
| { | ||||
| class JavaListLoadTask : public Task { | ||||
|     Q_OBJECT | ||||
|  | ||||
| public: | ||||
|     explicit JavaListLoadTask(JavaInstallList *vlist); | ||||
|    public: | ||||
|     explicit JavaListLoadTask(JavaInstallList* vlist); | ||||
|     virtual ~JavaListLoadTask(); | ||||
|  | ||||
|     void executeTask() override; | ||||
| public slots: | ||||
|    public slots: | ||||
|     void javaCheckerFinished(); | ||||
|  | ||||
| protected: | ||||
|    protected: | ||||
|     shared_qobject_ptr<JavaCheckerJob> m_job; | ||||
|     JavaInstallList *m_list; | ||||
|     JavaInstall *m_currentRecommended; | ||||
|     JavaInstallList* m_list; | ||||
|     JavaInstall* m_currentRecommended; | ||||
| }; | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
| @@ -33,24 +33,21 @@ | ||||
|  *      limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #include <QStringList> | ||||
| #include <QString> | ||||
| #include <QDir> | ||||
| #include <QString> | ||||
| #include <QStringList> | ||||
|  | ||||
| #include <settings/Setting.h> | ||||
|  | ||||
| #include <QDebug> | ||||
| #include "java/JavaUtils.h" | ||||
| #include "java/JavaInstallList.h" | ||||
| #include "FileSystem.h" | ||||
| #include "Application.h" | ||||
| #include "FileSystem.h" | ||||
| #include "java/JavaInstallList.h" | ||||
| #include "java/JavaUtils.h" | ||||
|  | ||||
| #define IBUS "@im=ibus" | ||||
|  | ||||
| JavaUtils::JavaUtils() | ||||
| { | ||||
| } | ||||
| JavaUtils::JavaUtils() {} | ||||
|  | ||||
| QString stripVariableEntries(QString name, QString target, QString remove) | ||||
| { | ||||
| @@ -65,8 +62,7 @@ QString stripVariableEntries(QString name, QString target, QString remove) | ||||
|     for (QString item : toRemove) { | ||||
|         bool removed = targetItems.removeOne(item); | ||||
|         if (!removed) | ||||
|             qWarning() << "Entry" << item | ||||
|                 << "could not be stripped from variable" << name; | ||||
|             qWarning() << "Entry" << item << "could not be stripped from variable" << name; | ||||
|     } | ||||
|     return targetItems.join(delimiter); | ||||
| } | ||||
| @@ -77,20 +73,10 @@ QProcessEnvironment CleanEnviroment() | ||||
|     QProcessEnvironment rawenv = QProcessEnvironment::systemEnvironment(); | ||||
|     QProcessEnvironment env; | ||||
|  | ||||
|     QStringList ignored = | ||||
|     { | ||||
|         "JAVA_ARGS", | ||||
|         "CLASSPATH", | ||||
|         "CONFIGPATH", | ||||
|         "JAVA_HOME", | ||||
|         "JRE_HOME", | ||||
|         "_JAVA_OPTIONS", | ||||
|         "JAVA_OPTIONS", | ||||
|         "JAVA_TOOL_OPTIONS" | ||||
|     }; | ||||
|     QStringList ignored = { "JAVA_ARGS", "CLASSPATH",     "CONFIGPATH",   "JAVA_HOME", | ||||
|                             "JRE_HOME",  "_JAVA_OPTIONS", "JAVA_OPTIONS", "JAVA_TOOL_OPTIONS" }; | ||||
|  | ||||
|     QStringList stripped = | ||||
|     { | ||||
|     QStringList stripped = { | ||||
| #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) | ||||
|         "LD_LIBRARY_PATH", | ||||
|         "LD_PRELOAD", | ||||
| @@ -98,12 +84,10 @@ QProcessEnvironment CleanEnviroment() | ||||
|         "QT_PLUGIN_PATH", | ||||
|         "QT_FONTPATH" | ||||
|     }; | ||||
|     for(auto key: rawenv.keys()) | ||||
|     { | ||||
|     for (auto key : rawenv.keys()) { | ||||
|         auto value = rawenv.value(key); | ||||
|         // filter out dangerous java crap | ||||
|         if(ignored.contains(key)) | ||||
|         { | ||||
|         if (ignored.contains(key)) { | ||||
|             qDebug() << "Env: ignoring" << key << value; | ||||
|             continue; | ||||
|         } | ||||
| @@ -111,13 +95,11 @@ QProcessEnvironment CleanEnviroment() | ||||
|         // These are used to strip the original variables | ||||
|         // If there is "LD_LIBRARY_PATH" and "LAUNCHER_LD_LIBRARY_PATH", we want to | ||||
|         // remove all values in "LAUNCHER_LD_LIBRARY_PATH" from "LD_LIBRARY_PATH" | ||||
|         if(key.startsWith("LAUNCHER_")) | ||||
|         { | ||||
|         if (key.startsWith("LAUNCHER_")) { | ||||
|             qDebug() << "Env: ignoring" << key << value; | ||||
|             continue; | ||||
|         } | ||||
|         if(stripped.contains(key)) | ||||
|         { | ||||
|         if (stripped.contains(key)) { | ||||
|             QString newValue = stripVariableEntries(key, value, rawenv.value("LAUNCHER_" + key)); | ||||
|  | ||||
|             qDebug() << "Env: stripped" << key << value << "to" << newValue; | ||||
| @@ -125,8 +107,7 @@ QProcessEnvironment CleanEnviroment() | ||||
| #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) | ||||
|         // Strip IBus | ||||
|         // IBus is a Linux IME framework. For some reason, it breaks MC? | ||||
|         if (key == "XMODIFIERS" && value.contains(IBUS)) | ||||
|         { | ||||
|         if (key == "XMODIFIERS" && value.contains(IBUS)) { | ||||
|             QString save = value; | ||||
|             value.replace(IBUS, ""); | ||||
|             qDebug() << "Env: stripped" << IBUS << "from" << save << ":" << value; | ||||
| @@ -137,8 +118,7 @@ QProcessEnvironment CleanEnviroment() | ||||
|     } | ||||
| #ifdef Q_OS_LINUX | ||||
|     // HACK: Workaround for QTBUG-42500 | ||||
|     if(!env.contains("LD_LIBRARY_PATH")) | ||||
|     { | ||||
|     if (!env.contains("LD_LIBRARY_PATH")) { | ||||
|         env.insert("LD_LIBRARY_PATH", ""); | ||||
|     } | ||||
| #endif | ||||
| @@ -186,8 +166,7 @@ QStringList addJavasFromEnv(QList<QString> javas) | ||||
| #else | ||||
|     QList<QString> javaPaths = env.split(QLatin1String(":")); | ||||
| #endif | ||||
|     for(QString i : javaPaths) | ||||
|     { | ||||
|     for (QString i : javaPaths) { | ||||
|         javas.append(i); | ||||
|     }; | ||||
|     return javas; | ||||
| @@ -205,9 +184,8 @@ QList<JavaInstallPtr> JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString | ||||
|         archType = "32"; | ||||
|  | ||||
|     HKEY jreKey; | ||||
|     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyName.toStdWString().c_str(), 0, | ||||
|                       KEY_READ | keyType | KEY_ENUMERATE_SUB_KEYS, &jreKey) == ERROR_SUCCESS) | ||||
|     { | ||||
|     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. | ||||
|  | ||||
| @@ -215,46 +193,36 @@ QList<JavaInstallPtr> JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString | ||||
|         DWORD subKeyNameSize, numSubKeys, retCode; | ||||
|  | ||||
|         // Get the number of subkeys | ||||
|         RegQueryInfoKeyW(jreKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL, | ||||
|                         NULL, NULL); | ||||
|         RegQueryInfoKeyW(jreKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL); | ||||
|  | ||||
|         // Iterate until RegEnumKeyEx fails | ||||
|         if (numSubKeys > 0) | ||||
|         { | ||||
|             for (DWORD i = 0; i < numSubKeys; i++) | ||||
|             { | ||||
|         if (numSubKeys > 0) { | ||||
|             for (DWORD i = 0; i < numSubKeys; i++) { | ||||
|                 subKeyNameSize = 255; | ||||
|                 retCode = RegEnumKeyExW(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) | ||||
|                 { | ||||
|                 if (retCode == ERROR_SUCCESS) { | ||||
|                     // Now open the registry key for the version that we just got. | ||||
|                     QString newKeyName = keyName + "\\" + newSubkeyName + subkeySuffix; | ||||
|  | ||||
|                     HKEY newKey; | ||||
|                     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, newKeyName.toStdWString().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. | ||||
|                         DWORD valueSz = 0; | ||||
|                         if (RegQueryValueExW(newKey, keyJavaDir.toStdWString().c_str(), NULL, NULL, NULL, | ||||
|                                              &valueSz) == ERROR_SUCCESS) | ||||
|                         { | ||||
|                             WCHAR *value = new WCHAR[valueSz]; | ||||
|                             RegQueryValueExW(newKey, keyJavaDir.toStdWString().c_str(), NULL, NULL, (BYTE *)value, | ||||
|                                              &valueSz); | ||||
|                         if (RegQueryValueExW(newKey, keyJavaDir.toStdWString().c_str(), NULL, NULL, NULL, &valueSz) == ERROR_SUCCESS) { | ||||
|                             WCHAR* value = new WCHAR[valueSz]; | ||||
|                             RegQueryValueExW(newKey, keyJavaDir.toStdWString().c_str(), NULL, NULL, (BYTE*)value, &valueSz); | ||||
|  | ||||
|                             QString newValue = QString::fromWCharArray(value); | ||||
|                             delete [] value; | ||||
|                             delete[] value; | ||||
|  | ||||
|                             // Now, we construct the version object and add it to the list. | ||||
|                             JavaInstallPtr javaVersion(new JavaInstall()); | ||||
|  | ||||
|                             javaVersion->id = newSubkeyName; | ||||
|                             javaVersion->arch = archType; | ||||
|                             javaVersion->path = | ||||
|                                 QDir(FS::PathCombine(newValue, "bin")).absoluteFilePath("javaw.exe"); | ||||
|                             javaVersion->path = QDir(FS::PathCombine(newValue, "bin")).absoluteFilePath("javaw.exe"); | ||||
|                             javas.append(javaVersion); | ||||
|                         } | ||||
|  | ||||
| @@ -275,66 +243,56 @@ QList<QString> JavaUtils::FindJavaPaths() | ||||
|     QList<JavaInstallPtr> java_candidates; | ||||
|  | ||||
|     // Oracle | ||||
|     QList<JavaInstallPtr> JRE64s = this->FindJavaFromRegistryKey( | ||||
|         KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment", "JavaHome"); | ||||
|     QList<JavaInstallPtr> JDK64s = this->FindJavaFromRegistryKey( | ||||
|         KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Development Kit", "JavaHome"); | ||||
|     QList<JavaInstallPtr> JRE32s = this->FindJavaFromRegistryKey( | ||||
|         KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment", "JavaHome"); | ||||
|     QList<JavaInstallPtr> JDK32s = this->FindJavaFromRegistryKey( | ||||
|         KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\Java Development Kit", "JavaHome"); | ||||
|     QList<JavaInstallPtr> JRE64s = | ||||
|         this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment", "JavaHome"); | ||||
|     QList<JavaInstallPtr> JDK64s = this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Development Kit", "JavaHome"); | ||||
|     QList<JavaInstallPtr> JRE32s = | ||||
|         this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment", "JavaHome"); | ||||
|     QList<JavaInstallPtr> JDK32s = this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\Java Development Kit", "JavaHome"); | ||||
|  | ||||
|     // Oracle for Java 9 and newer | ||||
|     QList<JavaInstallPtr> NEWJRE64s = this->FindJavaFromRegistryKey( | ||||
|         KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\JRE", "JavaHome"); | ||||
|     QList<JavaInstallPtr> NEWJDK64s = this->FindJavaFromRegistryKey( | ||||
|         KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\JDK", "JavaHome"); | ||||
|     QList<JavaInstallPtr> NEWJRE32s = this->FindJavaFromRegistryKey( | ||||
|         KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\JRE", "JavaHome"); | ||||
|     QList<JavaInstallPtr> NEWJDK32s = this->FindJavaFromRegistryKey( | ||||
|         KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\JDK", "JavaHome"); | ||||
|     QList<JavaInstallPtr> NEWJRE64s = this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\JRE", "JavaHome"); | ||||
|     QList<JavaInstallPtr> NEWJDK64s = this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\JDK", "JavaHome"); | ||||
|     QList<JavaInstallPtr> NEWJRE32s = this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\JRE", "JavaHome"); | ||||
|     QList<JavaInstallPtr> NEWJDK32s = this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\JDK", "JavaHome"); | ||||
|  | ||||
|     // AdoptOpenJDK | ||||
|     QList<JavaInstallPtr> ADOPTOPENJRE32s = this->FindJavaFromRegistryKey( | ||||
|         KEY_WOW64_32KEY, "SOFTWARE\\AdoptOpenJDK\\JRE", "Path", "\\hotspot\\MSI"); | ||||
|     QList<JavaInstallPtr> ADOPTOPENJRE64s = this->FindJavaFromRegistryKey( | ||||
|         KEY_WOW64_64KEY, "SOFTWARE\\AdoptOpenJDK\\JRE", "Path", "\\hotspot\\MSI"); | ||||
|     QList<JavaInstallPtr> ADOPTOPENJDK32s = this->FindJavaFromRegistryKey( | ||||
|         KEY_WOW64_32KEY, "SOFTWARE\\AdoptOpenJDK\\JDK", "Path", "\\hotspot\\MSI"); | ||||
|     QList<JavaInstallPtr> ADOPTOPENJDK64s = this->FindJavaFromRegistryKey( | ||||
|         KEY_WOW64_64KEY, "SOFTWARE\\AdoptOpenJDK\\JDK", "Path", "\\hotspot\\MSI"); | ||||
|     QList<JavaInstallPtr> ADOPTOPENJRE32s = | ||||
|         this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\AdoptOpenJDK\\JRE", "Path", "\\hotspot\\MSI"); | ||||
|     QList<JavaInstallPtr> ADOPTOPENJRE64s = | ||||
|         this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\AdoptOpenJDK\\JRE", "Path", "\\hotspot\\MSI"); | ||||
|     QList<JavaInstallPtr> ADOPTOPENJDK32s = | ||||
|         this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\AdoptOpenJDK\\JDK", "Path", "\\hotspot\\MSI"); | ||||
|     QList<JavaInstallPtr> ADOPTOPENJDK64s = | ||||
|         this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\AdoptOpenJDK\\JDK", "Path", "\\hotspot\\MSI"); | ||||
|  | ||||
|     // Eclipse Foundation | ||||
|     QList<JavaInstallPtr> FOUNDATIONJDK32s = this->FindJavaFromRegistryKey( | ||||
|         KEY_WOW64_32KEY, "SOFTWARE\\Eclipse Foundation\\JDK", "Path", "\\hotspot\\MSI"); | ||||
|     QList<JavaInstallPtr> FOUNDATIONJDK64s = this->FindJavaFromRegistryKey( | ||||
|         KEY_WOW64_64KEY, "SOFTWARE\\Eclipse Foundation\\JDK", "Path", "\\hotspot\\MSI"); | ||||
|     QList<JavaInstallPtr> FOUNDATIONJDK32s = | ||||
|         this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\Eclipse Foundation\\JDK", "Path", "\\hotspot\\MSI"); | ||||
|     QList<JavaInstallPtr> FOUNDATIONJDK64s = | ||||
|         this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\Eclipse Foundation\\JDK", "Path", "\\hotspot\\MSI"); | ||||
|  | ||||
|     // Eclipse Adoptium | ||||
|     QList<JavaInstallPtr> ADOPTIUMJRE32s = this->FindJavaFromRegistryKey( | ||||
|         KEY_WOW64_32KEY, "SOFTWARE\\Eclipse Adoptium\\JRE", "Path", "\\hotspot\\MSI"); | ||||
|     QList<JavaInstallPtr> ADOPTIUMJRE64s = this->FindJavaFromRegistryKey( | ||||
|         KEY_WOW64_64KEY, "SOFTWARE\\Eclipse Adoptium\\JRE", "Path", "\\hotspot\\MSI"); | ||||
|     QList<JavaInstallPtr> ADOPTIUMJDK32s = this->FindJavaFromRegistryKey( | ||||
|         KEY_WOW64_32KEY, "SOFTWARE\\Eclipse Adoptium\\JDK", "Path", "\\hotspot\\MSI"); | ||||
|     QList<JavaInstallPtr> ADOPTIUMJDK64s = this->FindJavaFromRegistryKey( | ||||
|         KEY_WOW64_64KEY, "SOFTWARE\\Eclipse Adoptium\\JDK", "Path", "\\hotspot\\MSI"); | ||||
|     QList<JavaInstallPtr> ADOPTIUMJRE32s = | ||||
|         this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\Eclipse Adoptium\\JRE", "Path", "\\hotspot\\MSI"); | ||||
|     QList<JavaInstallPtr> ADOPTIUMJRE64s = | ||||
|         this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\Eclipse Adoptium\\JRE", "Path", "\\hotspot\\MSI"); | ||||
|     QList<JavaInstallPtr> ADOPTIUMJDK32s = | ||||
|         this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\Eclipse Adoptium\\JDK", "Path", "\\hotspot\\MSI"); | ||||
|     QList<JavaInstallPtr> ADOPTIUMJDK64s = | ||||
|         this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\Eclipse Adoptium\\JDK", "Path", "\\hotspot\\MSI"); | ||||
|  | ||||
|     // Microsoft | ||||
|     QList<JavaInstallPtr> MICROSOFTJDK64s = this->FindJavaFromRegistryKey( | ||||
|         KEY_WOW64_64KEY, "SOFTWARE\\Microsoft\\JDK", "Path", "\\hotspot\\MSI"); | ||||
|     QList<JavaInstallPtr> MICROSOFTJDK64s = | ||||
|         this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\Microsoft\\JDK", "Path", "\\hotspot\\MSI"); | ||||
|  | ||||
|     // Azul Zulu | ||||
|     QList<JavaInstallPtr> ZULU64s = this->FindJavaFromRegistryKey( | ||||
|         KEY_WOW64_64KEY, "SOFTWARE\\Azul Systems\\Zulu", "InstallationPath"); | ||||
|     QList<JavaInstallPtr> ZULU32s = this->FindJavaFromRegistryKey( | ||||
|         KEY_WOW64_32KEY, "SOFTWARE\\Azul Systems\\Zulu", "InstallationPath"); | ||||
|     QList<JavaInstallPtr> ZULU64s = this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\Azul Systems\\Zulu", "InstallationPath"); | ||||
|     QList<JavaInstallPtr> ZULU32s = this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\Azul Systems\\Zulu", "InstallationPath"); | ||||
|  | ||||
|     // BellSoft Liberica | ||||
|     QList<JavaInstallPtr> LIBERICA64s = this->FindJavaFromRegistryKey( | ||||
|         KEY_WOW64_64KEY, "SOFTWARE\\BellSoft\\Liberica", "InstallationPath"); | ||||
|     QList<JavaInstallPtr> LIBERICA32s = this->FindJavaFromRegistryKey( | ||||
|         KEY_WOW64_32KEY, "SOFTWARE\\BellSoft\\Liberica", "InstallationPath"); | ||||
|     QList<JavaInstallPtr> LIBERICA64s = this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\BellSoft\\Liberica", "InstallationPath"); | ||||
|     QList<JavaInstallPtr> LIBERICA32s = this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\BellSoft\\Liberica", "InstallationPath"); | ||||
|  | ||||
|     // List x64 before x86 | ||||
|     java_candidates.append(JRE64s); | ||||
| @@ -371,10 +329,8 @@ QList<QString> JavaUtils::FindJavaPaths() | ||||
|     java_candidates.append(MakeJavaPtr(this->GetDefaultJava()->path)); | ||||
|  | ||||
|     QList<QString> candidates; | ||||
|     for(JavaInstallPtr java_candidate : java_candidates) | ||||
|     { | ||||
|         if(!candidates.contains(java_candidate->path)) | ||||
|         { | ||||
|     for (JavaInstallPtr java_candidate : java_candidates) { | ||||
|         if (!candidates.contains(java_candidate->path)) { | ||||
|             candidates.append(java_candidate->path); | ||||
|         } | ||||
|     } | ||||
| @@ -394,13 +350,13 @@ QList<QString> JavaUtils::FindJavaPaths() | ||||
|     javas.append("/System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands/java"); | ||||
|     QDir libraryJVMDir("/Library/Java/JavaVirtualMachines/"); | ||||
|     QStringList libraryJVMJavas = libraryJVMDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); | ||||
|     foreach (const QString &java, libraryJVMJavas) { | ||||
|     foreach (const QString& java, libraryJVMJavas) { | ||||
|         javas.append(libraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/bin/java"); | ||||
|         javas.append(libraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/jre/bin/java"); | ||||
|     } | ||||
|     QDir systemLibraryJVMDir("/System/Library/Java/JavaVirtualMachines/"); | ||||
|     QStringList systemLibraryJVMJavas = systemLibraryJVMDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); | ||||
|     foreach (const QString &java, systemLibraryJVMJavas) { | ||||
|     foreach (const QString& java, systemLibraryJVMJavas) { | ||||
|         javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/bin/java"); | ||||
|         javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Commands/java"); | ||||
|     } | ||||
| @@ -414,14 +370,12 @@ QList<QString> JavaUtils::FindJavaPaths() | ||||
| { | ||||
|     QList<QString> javas; | ||||
|     javas.append(this->GetDefaultJava()->path); | ||||
|     auto scanJavaDir = [&](const QString & dirPath) | ||||
|     { | ||||
|     auto scanJavaDir = [&](const QString& dirPath) { | ||||
|         QDir dir(dirPath); | ||||
|         if(!dir.exists()) | ||||
|         if (!dir.exists()) | ||||
|             return; | ||||
|         auto entries = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); | ||||
|         for(auto & entry: entries) | ||||
|         { | ||||
|         for (auto& entry : entries) { | ||||
|             QString prefix; | ||||
|             prefix = entry.canonicalFilePath(); | ||||
|             javas.append(FS::PathCombine(prefix, "jre/bin/java")); | ||||
| @@ -430,8 +384,7 @@ QList<QString> JavaUtils::FindJavaPaths() | ||||
|     }; | ||||
|     // java installed in a snap is installed in the standard directory, but underneath $SNAP | ||||
|     auto snap = qEnvironmentVariable("SNAP"); | ||||
|     auto scanJavaDirs = [&](const QString & dirPath) | ||||
|     { | ||||
|     auto scanJavaDirs = [&](const QString& dirPath) { | ||||
|         scanJavaDir(dirPath); | ||||
|         if (!snap.isNull()) { | ||||
|             scanJavaDir(snap + dirPath); | ||||
|   | ||||
| @@ -27,10 +27,9 @@ | ||||
| QString stripVariableEntries(QString name, QString target, QString remove); | ||||
| QProcessEnvironment CleanEnviroment(); | ||||
|  | ||||
| class JavaUtils : public QObject | ||||
| { | ||||
| class JavaUtils : public QObject { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|    public: | ||||
|     JavaUtils(); | ||||
|  | ||||
|     JavaInstallPtr MakeJavaPtr(QString path, QString id = "unknown", QString arch = "unknown"); | ||||
|   | ||||
| @@ -5,27 +5,22 @@ | ||||
| #include <QRegularExpression> | ||||
| #include <QString> | ||||
|  | ||||
| JavaVersion & JavaVersion::operator=(const QString & javaVersionString) | ||||
| JavaVersion& JavaVersion::operator=(const QString& javaVersionString) | ||||
| { | ||||
|     m_string = javaVersionString; | ||||
|  | ||||
|     auto getCapturedInteger = [](const QRegularExpressionMatch & match, const QString &what) -> int | ||||
|     { | ||||
|     auto getCapturedInteger = [](const QRegularExpressionMatch& match, const QString& what) -> int { | ||||
|         auto str = match.captured(what); | ||||
|         if(str.isEmpty()) | ||||
|         { | ||||
|         if (str.isEmpty()) { | ||||
|             return 0; | ||||
|         } | ||||
|         return str.toInt(); | ||||
|     }; | ||||
|  | ||||
|     QRegularExpression pattern; | ||||
|     if(javaVersionString.startsWith("1.")) | ||||
|     { | ||||
|         pattern = QRegularExpression ("1[.](?<major>[0-9]+)([.](?<minor>[0-9]+))?(_(?<security>[0-9]+)?)?(-(?<prerelease>[a-zA-Z0-9]+))?"); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|     if (javaVersionString.startsWith("1.")) { | ||||
|         pattern = QRegularExpression("1[.](?<major>[0-9]+)([.](?<minor>[0-9]+))?(_(?<security>[0-9]+)?)?(-(?<prerelease>[a-zA-Z0-9]+))?"); | ||||
|     } else { | ||||
|         pattern = QRegularExpression("(?<major>[0-9]+)([.](?<minor>[0-9]+))?([.](?<security>[0-9]+))?(-(?<prerelease>[a-zA-Z0-9]+))?"); | ||||
|     } | ||||
|  | ||||
| @@ -38,85 +33,77 @@ JavaVersion & JavaVersion::operator=(const QString & javaVersionString) | ||||
|     return *this; | ||||
| } | ||||
|  | ||||
| JavaVersion::JavaVersion(const QString &rhs) | ||||
| JavaVersion::JavaVersion(const QString& rhs) | ||||
| { | ||||
|     operator=(rhs); | ||||
| } | ||||
|  | ||||
| QString JavaVersion::toString() | ||||
| QString JavaVersion::toString() const | ||||
| { | ||||
|     return m_string; | ||||
| } | ||||
|  | ||||
| bool JavaVersion::requiresPermGen() | ||||
| { | ||||
|     if(m_parseable) | ||||
|     { | ||||
|     if (m_parseable) { | ||||
|         return m_major < 8; | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| bool JavaVersion::operator<(const JavaVersion &rhs) | ||||
| bool JavaVersion::operator<(const JavaVersion& rhs) | ||||
| { | ||||
|     if(m_parseable && rhs.m_parseable) | ||||
|     { | ||||
|     if (m_parseable && rhs.m_parseable) { | ||||
|         auto major = m_major; | ||||
|         auto rmajor = rhs.m_major; | ||||
|  | ||||
|         // HACK: discourage using java 9 | ||||
|         if(major > 8) | ||||
|         if (major > 8) | ||||
|             major = -major; | ||||
|         if(rmajor > 8) | ||||
|         if (rmajor > 8) | ||||
|             rmajor = -rmajor; | ||||
|  | ||||
|         if(major < rmajor) | ||||
|         if (major < rmajor) | ||||
|             return true; | ||||
|         if(major > rmajor) | ||||
|         if (major > rmajor) | ||||
|             return false; | ||||
|         if(m_minor < rhs.m_minor) | ||||
|         if (m_minor < rhs.m_minor) | ||||
|             return true; | ||||
|         if(m_minor > rhs.m_minor) | ||||
|         if (m_minor > rhs.m_minor) | ||||
|             return false; | ||||
|         if(m_security < rhs.m_security) | ||||
|         if (m_security < rhs.m_security) | ||||
|             return true; | ||||
|         if(m_security > rhs.m_security) | ||||
|         if (m_security > rhs.m_security) | ||||
|             return false; | ||||
|  | ||||
|         // everything else being equal, consider prerelease status | ||||
|         bool thisPre = !m_prerelease.isEmpty(); | ||||
|         bool rhsPre = !rhs.m_prerelease.isEmpty(); | ||||
|         if(thisPre && !rhsPre) | ||||
|         { | ||||
|         if (thisPre && !rhsPre) { | ||||
|             // this is a prerelease and the other one isn't -> lesser | ||||
|             return true; | ||||
|         } | ||||
|         else if(!thisPre && rhsPre) | ||||
|         { | ||||
|         } else if (!thisPre && rhsPre) { | ||||
|             // this isn't a prerelease and the other one is -> greater | ||||
|             return false; | ||||
|         } | ||||
|         else if(thisPre && rhsPre) | ||||
|         { | ||||
|         } else if (thisPre && rhsPre) { | ||||
|             // both are prereleases - use natural compare... | ||||
|             return StringUtils::naturalCompare(m_prerelease, rhs.m_prerelease, Qt::CaseSensitive) < 0; | ||||
|         } | ||||
|         // neither is prerelease, so they are the same -> this cannot be less than rhs | ||||
|         return false; | ||||
|     } | ||||
|     else return StringUtils::naturalCompare(m_string, rhs.m_string, Qt::CaseSensitive) < 0; | ||||
|     } else | ||||
|         return StringUtils::naturalCompare(m_string, rhs.m_string, Qt::CaseSensitive) < 0; | ||||
| } | ||||
|  | ||||
| bool JavaVersion::operator==(const JavaVersion &rhs) | ||||
| bool JavaVersion::operator==(const JavaVersion& rhs) | ||||
| { | ||||
|     if(m_parseable && rhs.m_parseable) | ||||
|     { | ||||
|     if (m_parseable && rhs.m_parseable) { | ||||
|         return m_major == rhs.m_major && m_minor == rhs.m_minor && m_security == rhs.m_security && m_prerelease == rhs.m_prerelease; | ||||
|     } | ||||
|     return m_string == rhs.m_string; | ||||
| } | ||||
|  | ||||
| bool JavaVersion::operator>(const JavaVersion &rhs) | ||||
| bool JavaVersion::operator>(const JavaVersion& rhs) | ||||
| { | ||||
|     return (!operator<(rhs)) && (!operator==(rhs)); | ||||
| } | ||||
|   | ||||
| @@ -4,42 +4,34 @@ | ||||
|  | ||||
| // NOTE: apparently the GNU C library pollutes the global namespace with these... undef them. | ||||
| #ifdef major | ||||
|     #undef major | ||||
| #undef major | ||||
| #endif | ||||
| #ifdef minor | ||||
|     #undef minor | ||||
| #undef minor | ||||
| #endif | ||||
|  | ||||
| class JavaVersion | ||||
| { | ||||
| class JavaVersion { | ||||
|     friend class JavaVersionTest; | ||||
| public: | ||||
|     JavaVersion() {}; | ||||
|     JavaVersion(const QString & rhs); | ||||
|  | ||||
|     JavaVersion & operator=(const QString & rhs); | ||||
|    public: | ||||
|     JavaVersion(){}; | ||||
|     JavaVersion(const QString& rhs); | ||||
|  | ||||
|     bool operator<(const JavaVersion & rhs); | ||||
|     bool operator==(const JavaVersion & rhs); | ||||
|     bool operator>(const JavaVersion & rhs); | ||||
|     JavaVersion& operator=(const QString& rhs); | ||||
|  | ||||
|     bool operator<(const JavaVersion& rhs); | ||||
|     bool operator==(const JavaVersion& rhs); | ||||
|     bool operator>(const JavaVersion& rhs); | ||||
|  | ||||
|     bool requiresPermGen(); | ||||
|  | ||||
|     QString toString(); | ||||
|     QString toString() const; | ||||
|  | ||||
|     int major() | ||||
|     { | ||||
|         return m_major; | ||||
|     } | ||||
|     int minor() | ||||
|     { | ||||
|         return m_minor; | ||||
|     } | ||||
|     int security() | ||||
|     { | ||||
|         return m_security; | ||||
|     } | ||||
| private: | ||||
|     int major() { return m_major; } | ||||
|     int minor() { return m_minor; } | ||||
|     int security() { return m_security; } | ||||
|  | ||||
|    private: | ||||
|     QString m_string; | ||||
|     int m_major = 0; | ||||
|     int m_minor = 0; | ||||
|   | ||||
| @@ -16,7 +16,7 @@ | ||||
| #include "LaunchStep.h" | ||||
| #include "LaunchTask.h" | ||||
|  | ||||
| void LaunchStep::bind(LaunchTask *parent) | ||||
| void LaunchStep::bind(LaunchTask* parent) | ||||
| { | ||||
|     m_parent = parent; | ||||
|     connect(this, &LaunchStep::readyForLaunch, parent, &LaunchTask::onReadyForLaunch); | ||||
|   | ||||
| @@ -15,36 +15,32 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "tasks/Task.h" | ||||
| #include "MessageLevel.h" | ||||
| #include "tasks/Task.h" | ||||
|  | ||||
| #include <QStringList> | ||||
|  | ||||
| class LaunchTask; | ||||
| class LaunchStep: public Task | ||||
| { | ||||
| class LaunchStep : public Task { | ||||
|     Q_OBJECT | ||||
| public: /* methods */ | ||||
|     explicit LaunchStep(LaunchTask *parent):Task(nullptr), m_parent(parent) | ||||
|     { | ||||
|         bind(parent); | ||||
|     }; | ||||
|     virtual ~LaunchStep() {}; | ||||
|    public: /* methods */ | ||||
|     explicit LaunchStep(LaunchTask* parent) : Task(nullptr), m_parent(parent) { bind(parent); }; | ||||
|     virtual ~LaunchStep(){}; | ||||
|  | ||||
| private: /* methods */ | ||||
|     void bind(LaunchTask *parent); | ||||
|    private: /* methods */ | ||||
|     void bind(LaunchTask* parent); | ||||
|  | ||||
| signals: | ||||
|    signals: | ||||
|     void logLines(QStringList lines, MessageLevel::Enum level); | ||||
|     void logLine(QString line, MessageLevel::Enum level); | ||||
|     void readyForLaunch(); | ||||
|     void progressReportingRequest(); | ||||
|  | ||||
| public slots: | ||||
|     virtual void proceed() {}; | ||||
|    public slots: | ||||
|     virtual void proceed(){}; | ||||
|     // called in the opposite order than the Task launch(), used to clean up or otherwise undo things after the launch ends | ||||
|     virtual void finalize() {}; | ||||
|     virtual void finalize(){}; | ||||
|  | ||||
| protected: /* data */ | ||||
|     LaunchTask *m_parent; | ||||
|    protected: /* data */ | ||||
|     LaunchTask* m_parent; | ||||
| }; | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
| @@ -36,16 +36,16 @@ | ||||
|  */ | ||||
|  | ||||
| #include "launch/LaunchTask.h" | ||||
| #include "MessageLevel.h" | ||||
| #include "java/JavaChecker.h" | ||||
| #include "tasks/Task.h" | ||||
| #include <assert.h> | ||||
| #include <QCoreApplication> | ||||
| #include <QDebug> | ||||
| #include <QDir> | ||||
| #include <QEventLoop> | ||||
| #include <QRegularExpression> | ||||
| #include <QCoreApplication> | ||||
| #include <QStandardPaths> | ||||
| #include <assert.h> | ||||
| #include "MessageLevel.h" | ||||
| #include "java/JavaChecker.h" | ||||
| #include "tasks/Task.h" | ||||
|  | ||||
| void LaunchTask::init() | ||||
| { | ||||
| @@ -59,9 +59,7 @@ shared_qobject_ptr<LaunchTask> LaunchTask::create(InstancePtr inst) | ||||
|     return proc; | ||||
| } | ||||
|  | ||||
| LaunchTask::LaunchTask(InstancePtr instance): m_instance(instance) | ||||
| { | ||||
| } | ||||
| LaunchTask::LaunchTask(InstancePtr instance) : m_instance(instance) {} | ||||
|  | ||||
| void LaunchTask::appendStep(shared_qobject_ptr<LaunchStep> step) | ||||
| { | ||||
| @@ -76,8 +74,7 @@ void LaunchTask::prependStep(shared_qobject_ptr<LaunchStep> step) | ||||
| void LaunchTask::executeTask() | ||||
| { | ||||
|     m_instance->setCrashed(false); | ||||
|     if(!m_steps.size()) | ||||
|     { | ||||
|     if (!m_steps.size()) { | ||||
|         state = LaunchTask::Finished; | ||||
|         emitSucceeded(); | ||||
|     } | ||||
| @@ -94,46 +91,35 @@ void LaunchTask::onReadyForLaunch() | ||||
| void LaunchTask::onStepFinished() | ||||
| { | ||||
|     // initial -> just start the first step | ||||
|     if(currentStep == -1) | ||||
|     { | ||||
|         currentStep ++; | ||||
|     if (currentStep == -1) { | ||||
|         currentStep++; | ||||
|         m_steps[currentStep]->start(); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     auto step = m_steps[currentStep]; | ||||
|     if(step->wasSuccessful()) | ||||
|     { | ||||
|     if (step->wasSuccessful()) { | ||||
|         // end? | ||||
|         if(currentStep == m_steps.size() - 1) | ||||
|         { | ||||
|         if (currentStep == m_steps.size() - 1) { | ||||
|             finalizeSteps(true, QString()); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             currentStep ++; | ||||
|         } else { | ||||
|             currentStep++; | ||||
|             step = m_steps[currentStep]; | ||||
|             step->start(); | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|     } else { | ||||
|         finalizeSteps(false, step->failReason()); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void LaunchTask::finalizeSteps(bool successful, const QString& error) | ||||
| { | ||||
|     for(auto step = currentStep; step >= 0; step--) | ||||
|     { | ||||
|     for (auto step = currentStep; step >= 0; step--) { | ||||
|         m_steps[step]->finalize(); | ||||
|     } | ||||
|     if(successful) | ||||
|     { | ||||
|     if (successful) { | ||||
|         emitSucceeded(); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|     } else { | ||||
|         emitFailed(error); | ||||
|     } | ||||
| } | ||||
| @@ -152,8 +138,7 @@ void LaunchTask::setCensorFilter(QMap<QString, QString> filter) | ||||
| QString LaunchTask::censorPrivateInfo(QString in) | ||||
| { | ||||
|     auto iter = m_censorFilter.begin(); | ||||
|     while (iter != m_censorFilter.end()) | ||||
|     { | ||||
|     while (iter != m_censorFilter.end()) { | ||||
|         in.replace(iter.key(), iter.value()); | ||||
|         iter++; | ||||
|     } | ||||
| @@ -162,8 +147,7 @@ QString LaunchTask::censorPrivateInfo(QString in) | ||||
|  | ||||
| void LaunchTask::proceed() | ||||
| { | ||||
|     if(state != LaunchTask::Waiting) | ||||
|     { | ||||
|     if (state != LaunchTask::Waiting) { | ||||
|         return; | ||||
|     } | ||||
|     m_steps[currentStep]->proceed(); | ||||
| @@ -171,8 +155,7 @@ void LaunchTask::proceed() | ||||
|  | ||||
| bool LaunchTask::canAbort() const | ||||
| { | ||||
|     switch(state) | ||||
|     { | ||||
|     switch (state) { | ||||
|         case LaunchTask::Aborted: | ||||
|         case LaunchTask::Failed: | ||||
|         case LaunchTask::Finished: | ||||
| @@ -180,8 +163,7 @@ bool LaunchTask::canAbort() const | ||||
|         case LaunchTask::NotStarted: | ||||
|             return true; | ||||
|         case LaunchTask::Running: | ||||
|         case LaunchTask::Waiting: | ||||
|         { | ||||
|         case LaunchTask::Waiting: { | ||||
|             auto step = m_steps[currentStep]; | ||||
|             return step->canAbort(); | ||||
|         } | ||||
| @@ -191,28 +173,23 @@ bool LaunchTask::canAbort() const | ||||
|  | ||||
| bool LaunchTask::abort() | ||||
| { | ||||
|     switch(state) | ||||
|     { | ||||
|     switch (state) { | ||||
|         case LaunchTask::Aborted: | ||||
|         case LaunchTask::Failed: | ||||
|         case LaunchTask::Finished: | ||||
|             return true; | ||||
|         case LaunchTask::NotStarted: | ||||
|         { | ||||
|         case LaunchTask::NotStarted: { | ||||
|             state = LaunchTask::Aborted; | ||||
|             emitFailed("Aborted"); | ||||
|             return true; | ||||
|         } | ||||
|         case LaunchTask::Running: | ||||
|         case LaunchTask::Waiting: | ||||
|         { | ||||
|         case LaunchTask::Waiting: { | ||||
|             auto step = m_steps[currentStep]; | ||||
|             if(!step->canAbort()) | ||||
|             { | ||||
|             if (!step->canAbort()) { | ||||
|                 return false; | ||||
|             } | ||||
|             if(step->abort()) | ||||
|             { | ||||
|             if (step->abort()) { | ||||
|                 state = LaunchTask::Aborted; | ||||
|                 return true; | ||||
|             } | ||||
| @@ -225,23 +202,22 @@ bool LaunchTask::abort() | ||||
|  | ||||
| shared_qobject_ptr<LogModel> LaunchTask::getLogModel() | ||||
| { | ||||
|     if(!m_logModel) | ||||
|     { | ||||
|     if (!m_logModel) { | ||||
|         m_logModel.reset(new LogModel()); | ||||
|         m_logModel->setMaxLines(m_instance->getConsoleMaxLines()); | ||||
|         m_logModel->setStopOnOverflow(m_instance->shouldStopOnConsoleOverflow()); | ||||
|         // FIXME: should this really be here? | ||||
|         m_logModel->setOverflowMessage(tr("Stopped watching the game log because the log length surpassed %1 lines.\n" | ||||
|             "You may have to fix your mods because the game is still logging to files and" | ||||
|             " likely wasting harddrive space at an alarming rate!").arg(m_logModel->getMaxLines())); | ||||
|                                           "You may have to fix your mods because the game is still logging to files and" | ||||
|                                           " likely wasting harddrive space at an alarming rate!") | ||||
|                                            .arg(m_logModel->getMaxLines())); | ||||
|     } | ||||
|     return m_logModel; | ||||
| } | ||||
|  | ||||
| void LaunchTask::onLogLines(const QStringList &lines, MessageLevel::Enum defaultLevel) | ||||
| void LaunchTask::onLogLines(const QStringList& lines, MessageLevel::Enum defaultLevel) | ||||
| { | ||||
|     for (auto & line: lines) | ||||
|     { | ||||
|     for (auto& line : lines) { | ||||
|         onLogLine(line, defaultLevel); | ||||
|     } | ||||
| } | ||||
| @@ -250,21 +226,19 @@ void LaunchTask::onLogLine(QString line, MessageLevel::Enum level) | ||||
| { | ||||
|     // if the launcher part set a log level, use it | ||||
|     auto innerLevel = MessageLevel::fromLine(line); | ||||
|     if(innerLevel != MessageLevel::Unknown) | ||||
|     { | ||||
|     if (innerLevel != MessageLevel::Unknown) { | ||||
|         level = innerLevel; | ||||
|     } | ||||
|  | ||||
|     // If the level is still undetermined, guess level | ||||
|     if (level == MessageLevel::StdErr || level == MessageLevel::StdOut || level == MessageLevel::Unknown) | ||||
|     { | ||||
|     if (level == MessageLevel::StdErr || level == MessageLevel::StdOut || level == MessageLevel::Unknown) { | ||||
|         level = m_instance->guessLevel(line, level); | ||||
|     } | ||||
|  | ||||
|     // censor private user info | ||||
|     line = censorPrivateInfo(line); | ||||
|  | ||||
|     auto &model = *getLogModel(); | ||||
|     auto& model = *getLogModel(); | ||||
|     model.append(level, line); | ||||
| } | ||||
|  | ||||
| @@ -281,22 +255,20 @@ void LaunchTask::emitFailed(QString reason) | ||||
|     Task::emitFailed(reason); | ||||
| } | ||||
|  | ||||
| void LaunchTask::substituteVariables(QStringList &args) const | ||||
| void LaunchTask::substituteVariables(QStringList& args) const | ||||
| { | ||||
|     auto env = m_instance->createEnvironment(); | ||||
|  | ||||
|     for (auto key : env.keys()) | ||||
|     { | ||||
|     for (auto key : env.keys()) { | ||||
|         args.replaceInStrings("$" + key, env.value(key)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void LaunchTask::substituteVariables(QString &cmd) const | ||||
| void LaunchTask::substituteVariables(QString& cmd) const | ||||
| { | ||||
|     auto env = m_instance->createEnvironment(); | ||||
|  | ||||
|     for (auto key : env.keys()) | ||||
|     { | ||||
|     for (auto key : env.keys()) { | ||||
|         cmd.replace("$" + key, env.value(key)); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
| @@ -36,54 +36,36 @@ | ||||
|  */ | ||||
|  | ||||
| #pragma once | ||||
| #include <QProcess> | ||||
| #include <QObjectPtr.h> | ||||
| #include "LogModel.h" | ||||
| #include <QProcess> | ||||
| #include "BaseInstance.h" | ||||
| #include "MessageLevel.h" | ||||
| #include "LoggedProcess.h" | ||||
| #include "LaunchStep.h" | ||||
| #include "LogModel.h" | ||||
| #include "LoggedProcess.h" | ||||
| #include "MessageLevel.h" | ||||
|  | ||||
| class LaunchTask: public Task | ||||
| { | ||||
| class LaunchTask : public Task { | ||||
|     Q_OBJECT | ||||
| protected: | ||||
|    protected: | ||||
|     explicit LaunchTask(InstancePtr instance); | ||||
|     void init(); | ||||
|  | ||||
| public: | ||||
|     enum State | ||||
|     { | ||||
|         NotStarted, | ||||
|         Running, | ||||
|         Waiting, | ||||
|         Failed, | ||||
|         Aborted, | ||||
|         Finished | ||||
|     }; | ||||
|    public: | ||||
|     enum State { NotStarted, Running, Waiting, Failed, Aborted, Finished }; | ||||
|  | ||||
| public: /* methods */ | ||||
|    public: /* methods */ | ||||
|     static shared_qobject_ptr<LaunchTask> create(InstancePtr inst); | ||||
|     virtual ~LaunchTask() {}; | ||||
|     virtual ~LaunchTask(){}; | ||||
|  | ||||
|     void appendStep(shared_qobject_ptr<LaunchStep> step); | ||||
|     void prependStep(shared_qobject_ptr<LaunchStep> step); | ||||
|     void setCensorFilter(QMap<QString, QString> filter); | ||||
|  | ||||
|     InstancePtr instance() | ||||
|     { | ||||
|         return m_instance; | ||||
|     } | ||||
|     InstancePtr instance() { return m_instance; } | ||||
|  | ||||
|     void setPid(qint64 pid) | ||||
|     { | ||||
|         m_pid = pid; | ||||
|     } | ||||
|     void setPid(qint64 pid) { m_pid = pid; } | ||||
|  | ||||
|     qint64 pid() | ||||
|     { | ||||
|         return m_pid; | ||||
|     } | ||||
|     qint64 pid() { return m_pid; } | ||||
|  | ||||
|     /** | ||||
|      * @brief prepare the process for launch (for multi-stage launch) | ||||
| @@ -104,39 +86,39 @@ public: /* methods */ | ||||
|  | ||||
|     shared_qobject_ptr<LogModel> getLogModel(); | ||||
|  | ||||
| public: | ||||
|     void substituteVariables(QStringList &args) const; | ||||
|     void substituteVariables(QString &cmd) const; | ||||
|    public: | ||||
|     void substituteVariables(QStringList& args) const; | ||||
|     void substituteVariables(QString& cmd) const; | ||||
|     QString censorPrivateInfo(QString in); | ||||
|  | ||||
| protected: /* methods */ | ||||
|    protected: /* methods */ | ||||
|     virtual void emitFailed(QString reason) override; | ||||
|     virtual void emitSucceeded() override; | ||||
|  | ||||
| signals: | ||||
|    signals: | ||||
|     /** | ||||
|      * @brief emitted when the launch preparations are done | ||||
|      */ | ||||
|     void readyForLaunch(); | ||||
|  | ||||
|     void requestProgress(Task *task); | ||||
|     void requestProgress(Task* task); | ||||
|  | ||||
|     void requestLogging(); | ||||
|  | ||||
| public slots: | ||||
|    public slots: | ||||
|     void onLogLines(const QStringList& lines, MessageLevel::Enum defaultLevel = MessageLevel::Launcher); | ||||
|     void onLogLine(QString line, MessageLevel::Enum defaultLevel = MessageLevel::Launcher); | ||||
|     void onReadyForLaunch(); | ||||
|     void onStepFinished(); | ||||
|     void onProgressReportingRequested(); | ||||
|  | ||||
| private: /*methods */ | ||||
|     void finalizeSteps(bool successful, const QString & error); | ||||
|    private: /*methods */ | ||||
|     void finalizeSteps(bool successful, const QString& error); | ||||
|  | ||||
| protected: /* data */ | ||||
|    protected: /* data */ | ||||
|     InstancePtr m_instance; | ||||
|     shared_qobject_ptr<LogModel> m_logModel; | ||||
|     QList <shared_qobject_ptr<LaunchStep>> m_steps; | ||||
|     QList<shared_qobject_ptr<LaunchStep>> m_steps; | ||||
|     QMap<QString, QString> m_censorFilter; | ||||
|     int currentStep = -1; | ||||
|     State state = NotStarted; | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| #include "LogModel.h" | ||||
|  | ||||
| LogModel::LogModel(QObject *parent):QAbstractListModel(parent) | ||||
| LogModel::LogModel(QObject* parent) : QAbstractListModel(parent) | ||||
| { | ||||
|     m_content.resize(m_maxLines); | ||||
| } | ||||
|  | ||||
| int LogModel::rowCount(const QModelIndex &parent) const | ||||
| int LogModel::rowCount(const QModelIndex& parent) const | ||||
| { | ||||
|     if (parent.isValid()) | ||||
|         return 0; | ||||
| @@ -13,19 +13,17 @@ int LogModel::rowCount(const QModelIndex &parent) const | ||||
|     return m_numLines; | ||||
| } | ||||
|  | ||||
| QVariant LogModel::data(const QModelIndex &index, int role) const | ||||
| QVariant LogModel::data(const QModelIndex& index, int role) const | ||||
| { | ||||
|     if (index.row() < 0 || index.row() >= m_numLines) | ||||
|         return QVariant(); | ||||
|  | ||||
|     auto row = index.row(); | ||||
|     auto realRow = (row + m_firstLine) % m_maxLines; | ||||
|     if (role == Qt::DisplayRole || role == Qt::EditRole) | ||||
|     { | ||||
|     if (role == Qt::DisplayRole || role == Qt::EditRole) { | ||||
|         return m_content[realRow].line; | ||||
|     } | ||||
|     if(role == LevelRole) | ||||
|     { | ||||
|     if (role == LevelRole) { | ||||
|         return m_content[realRow].level; | ||||
|     } | ||||
|  | ||||
| @@ -34,31 +32,26 @@ QVariant LogModel::data(const QModelIndex &index, int role) const | ||||
|  | ||||
| void LogModel::append(MessageLevel::Enum level, QString line) | ||||
| { | ||||
|     if(m_suspended) | ||||
|     { | ||||
|     if (m_suspended) { | ||||
|         return; | ||||
|     } | ||||
|     int lineNum = (m_firstLine + m_numLines) % m_maxLines; | ||||
|     // overflow | ||||
|     if(m_numLines == m_maxLines) | ||||
|     { | ||||
|         if(m_stopOnOverflow) | ||||
|         { | ||||
|     if (m_numLines == m_maxLines) { | ||||
|         if (m_stopOnOverflow) { | ||||
|             // nothing more to do, the buffer is full | ||||
|             return; | ||||
|         } | ||||
|         beginRemoveRows(QModelIndex(), 0, 0); | ||||
|         m_firstLine = (m_firstLine + 1) % m_maxLines; | ||||
|         m_numLines --; | ||||
|         m_numLines--; | ||||
|         endRemoveRows(); | ||||
|     } | ||||
|     else if (m_numLines == m_maxLines - 1 && m_stopOnOverflow) | ||||
|     { | ||||
|     } else if (m_numLines == m_maxLines - 1 && m_stopOnOverflow) { | ||||
|         level = MessageLevel::Fatal; | ||||
|         line = m_overflowMessage; | ||||
|     } | ||||
|     beginInsertRows(QModelIndex(), m_numLines, m_numLines); | ||||
|     m_numLines ++; | ||||
|     m_numLines++; | ||||
|     m_content[lineNum].level = level; | ||||
|     m_content[lineNum].line = line; | ||||
|     endInsertRows(); | ||||
| @@ -86,9 +79,8 @@ QString LogModel::toPlainText() | ||||
| { | ||||
|     QString out; | ||||
|     out.reserve(m_numLines * 80); | ||||
|     for(int i = 0; i < m_numLines; i++) | ||||
|     { | ||||
|         QString & line = m_content[(m_firstLine + i) % m_maxLines].line; | ||||
|     for (int i = 0; i < m_numLines; i++) { | ||||
|         QString& line = m_content[(m_firstLine + i) % m_maxLines].line; | ||||
|         out.append(line + '\n'); | ||||
|     } | ||||
|     out.squeeze(); | ||||
| @@ -98,13 +90,11 @@ QString LogModel::toPlainText() | ||||
| void LogModel::setMaxLines(int maxLines) | ||||
| { | ||||
|     // no-op | ||||
|     if(maxLines == m_maxLines) | ||||
|     { | ||||
|     if (maxLines == m_maxLines) { | ||||
|         return; | ||||
|     } | ||||
|     // if it all still fits in the buffer, just resize it | ||||
|     if(m_firstLine + m_numLines < m_maxLines) | ||||
|     { | ||||
|     if (m_firstLine + m_numLines < m_maxLines) { | ||||
|         m_maxLines = maxLines; | ||||
|         m_content.resize(maxLines); | ||||
|         return; | ||||
| @@ -112,22 +102,17 @@ void LogModel::setMaxLines(int maxLines) | ||||
|     // otherwise, we need to reorganize the data because it crosses the wrap boundary | ||||
|     QVector<entry> newContent; | ||||
|     newContent.resize(maxLines); | ||||
|     if(m_numLines <= maxLines) | ||||
|     { | ||||
|     if (m_numLines <= maxLines) { | ||||
|         // if it all fits in the new buffer, just copy it over | ||||
|         for(int i = 0; i < m_numLines; i++) | ||||
|         { | ||||
|         for (int i = 0; i < m_numLines; i++) { | ||||
|             newContent[i] = m_content[(m_firstLine + i) % m_maxLines]; | ||||
|         } | ||||
|         m_content.swap(newContent); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|     } else { | ||||
|         // if it doesn't fit, part of the data needs to be thrown away (the oldest log messages) | ||||
|         int lead = m_numLines - maxLines; | ||||
|         beginRemoveRows(QModelIndex(), 0, lead - 1); | ||||
|         for(int i = 0; i < maxLines; i++) | ||||
|         { | ||||
|         for (int i = 0; i < maxLines; i++) { | ||||
|             newContent[i] = m_content[(m_firstLine + lead + i) % m_maxLines]; | ||||
|         } | ||||
|         m_numLines = m_maxLines; | ||||
| @@ -155,8 +140,7 @@ void LogModel::setOverflowMessage(const QString& overflowMessage) | ||||
|  | ||||
| void LogModel::setLineWrap(bool state) | ||||
| { | ||||
|     if(m_lineWrap != state) | ||||
|     { | ||||
|     if (m_lineWrap != state) { | ||||
|         m_lineWrap = state; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -4,14 +4,13 @@ | ||||
| #include <QString> | ||||
| #include "MessageLevel.h" | ||||
|  | ||||
| class LogModel : public QAbstractListModel | ||||
| { | ||||
| class LogModel : public QAbstractListModel { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     explicit LogModel(QObject *parent = 0); | ||||
|    public: | ||||
|     explicit LogModel(QObject* parent = 0); | ||||
|  | ||||
|     int rowCount(const QModelIndex &parent = QModelIndex()) const; | ||||
|     QVariant data(const QModelIndex &index, int role) const; | ||||
|     int rowCount(const QModelIndex& parent = QModelIndex()) const; | ||||
|     QVariant data(const QModelIndex& index, int role) const; | ||||
|  | ||||
|     void append(MessageLevel::Enum, QString line); | ||||
|     void clear(); | ||||
| @@ -24,25 +23,21 @@ public: | ||||
|     int getMaxLines(); | ||||
|     void setMaxLines(int maxLines); | ||||
|     void setStopOnOverflow(bool stop); | ||||
|     void setOverflowMessage(const QString & overflowMessage); | ||||
|     void setOverflowMessage(const QString& overflowMessage); | ||||
|  | ||||
|     void setLineWrap(bool state); | ||||
|     bool wrapLines() const; | ||||
|  | ||||
|     enum Roles | ||||
|     { | ||||
|         LevelRole = Qt::UserRole | ||||
|     }; | ||||
|     enum Roles { LevelRole = Qt::UserRole }; | ||||
|  | ||||
| private /* types */: | ||||
|     struct entry | ||||
|     { | ||||
|     private /* types */: | ||||
|     struct entry { | ||||
|         MessageLevel::Enum level; | ||||
|         QString line; | ||||
|     }; | ||||
|  | ||||
| private: /* data */ | ||||
|     QVector <entry> m_content; | ||||
|    private: /* data */ | ||||
|     QVector<entry> m_content; | ||||
|     int m_maxLines = 1000; | ||||
|     // first line in the circular buffer | ||||
|     int m_firstLine = 0; | ||||
| @@ -53,6 +48,6 @@ private: /* data */ | ||||
|     bool m_suspended = false; | ||||
|     bool m_lineWrap = true; | ||||
|  | ||||
| private: | ||||
|    private: | ||||
|     Q_DISABLE_COPY(LogModel) | ||||
| }; | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Prism Launcher - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
| @@ -34,12 +34,12 @@ | ||||
|  */ | ||||
|  | ||||
| #include "CheckJava.h" | ||||
| #include "java/JavaUtils.h" | ||||
| #include <launch/LaunchTask.h> | ||||
| #include <FileSystem.h> | ||||
| #include <QStandardPaths> | ||||
| #include <QFileInfo> | ||||
| #include <launch/LaunchTask.h> | ||||
| #include <sys.h> | ||||
| #include <QFileInfo> | ||||
| #include <QStandardPaths> | ||||
| #include "java/JavaUtils.h" | ||||
|  | ||||
| void CheckJava::executeTask() | ||||
| { | ||||
| @@ -49,32 +49,26 @@ void CheckJava::executeTask() | ||||
|     bool perInstance = settings->get("OverrideJava").toBool() || settings->get("OverrideJavaLocation").toBool(); | ||||
|  | ||||
|     auto realJavaPath = QStandardPaths::findExecutable(m_javaPath); | ||||
|     if (realJavaPath.isEmpty()) | ||||
|     { | ||||
|         if (perInstance) | ||||
|         { | ||||
|             emit logLine( | ||||
|                 QString("The java binary \"%1\" couldn't be found. Please fix the java path " | ||||
|                    "override in the instance's settings or disable it.").arg(m_javaPath), | ||||
|                 MessageLevel::Warning); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|     if (realJavaPath.isEmpty()) { | ||||
|         if (perInstance) { | ||||
|             emit logLine(QString("The java binary \"%1\" couldn't be found. Please fix the java path " | ||||
|                                  "override in the instance's settings or disable it.") | ||||
|                              .arg(m_javaPath), | ||||
|                          MessageLevel::Warning); | ||||
|         } else { | ||||
|             emit logLine(QString("The java binary \"%1\" couldn't be found. Please set up java in " | ||||
|                             "the settings.").arg(m_javaPath), | ||||
|                                  "the settings.") | ||||
|                              .arg(m_javaPath), | ||||
|                          MessageLevel::Warning); | ||||
|         } | ||||
|         emitFailed(QString("Java path is not valid.")); | ||||
|         return; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|     } else { | ||||
|         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."); | ||||
|     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; | ||||
| @@ -94,19 +88,15 @@ void CheckJava::executeTask() | ||||
|     m_javaSignature = hash.result().toHex(); | ||||
|  | ||||
|     // if timestamps are not the same, or something is missing, check! | ||||
|     if (m_javaSignature != storedSignature || storedVersion.size() == 0 | ||||
|         || storedArchitecture.size() == 0 || storedRealArchitecture.size() == 0 | ||||
|         || storedVendor.size() == 0) | ||||
|     { | ||||
|     if (m_javaSignature != storedSignature || storedVersion.size() == 0 || storedArchitecture.size() == 0 || | ||||
|         storedRealArchitecture.size() == 0 || storedVendor.size() == 0) { | ||||
|         m_JavaChecker.reset(new JavaChecker); | ||||
|         emit logLine(QString("Checking Java version..."), MessageLevel::Launcher); | ||||
|         connect(m_JavaChecker.get(), &JavaChecker::checkFinished, this, &CheckJava::checkJavaFinished); | ||||
|         m_JavaChecker->m_path = realJavaPath; | ||||
|         m_JavaChecker->performCheck(); | ||||
|         return; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|     } else { | ||||
|         auto verString = instance->settings()->get("JavaVersion").toString(); | ||||
|         auto archString = instance->settings()->get("JavaArchitecture").toString(); | ||||
|         auto realArchString = settings->get("JavaRealArchitecture").toString(); | ||||
| @@ -118,10 +108,8 @@ void CheckJava::executeTask() | ||||
|  | ||||
| void CheckJava::checkJavaFinished(JavaCheckResult result) | ||||
| { | ||||
|     switch (result.validity) | ||||
|     { | ||||
|         case JavaCheckResult::Validity::Errored: | ||||
|         { | ||||
|     switch (result.validity) { | ||||
|         case JavaCheckResult::Validity::Errored: { | ||||
|             // Error message displayed if java can't start | ||||
|             emit logLine(QString("Could not start java:"), MessageLevel::Error); | ||||
|             emit logLines(result.errorLog.split('\n'), MessageLevel::Error); | ||||
| @@ -129,16 +117,14 @@ void CheckJava::checkJavaFinished(JavaCheckResult result) | ||||
|             emitFailed(QString("Could not start java!")); | ||||
|             return; | ||||
|         } | ||||
|         case JavaCheckResult::Validity::ReturnedInvalidData: | ||||
|         { | ||||
|         case JavaCheckResult::Validity::ReturnedInvalidData: { | ||||
|             emit logLine(QString("Java checker returned some invalid data we don't understand:"), MessageLevel::Error); | ||||
|             emit logLines(result.outLog.split('\n'), MessageLevel::Warning); | ||||
|             emit logLine("\nMinecraft might not start properly.", MessageLevel::Launcher); | ||||
|             emitSucceeded(); | ||||
|             return; | ||||
|         } | ||||
|         case JavaCheckResult::Validity::Valid: | ||||
|         { | ||||
|         case JavaCheckResult::Validity::Valid: { | ||||
|             auto instance = m_parent->instance(); | ||||
|             printJavaInfo(result.javaVersion.toString(), result.mojangPlatform, result.realPlatform, result.javaVendor); | ||||
|             instance->settings()->set("JavaVersion", result.javaVersion.toString()); | ||||
| @@ -152,8 +138,9 @@ void CheckJava::checkJavaFinished(JavaCheckResult result) | ||||
|     } | ||||
| } | ||||
|  | ||||
| void CheckJava::printJavaInfo(const QString& version, const QString& architecture, const QString& realArchitecture, const QString & vendor) | ||||
| void CheckJava::printJavaInfo(const QString& version, const QString& architecture, const QString& realArchitecture, const QString& vendor) | ||||
| { | ||||
|     emit logLine(QString("Java is version %1, using %2 (%3) architecture, from %4.\n\n") | ||||
|                     .arg(version, architecture, realArchitecture, vendor), MessageLevel::Launcher); | ||||
|     emit logLine( | ||||
|         QString("Java is version %1, using %2 (%3) architecture, from %4.\n\n").arg(version, architecture, realArchitecture, vendor), | ||||
|         MessageLevel::Launcher); | ||||
| } | ||||
|   | ||||
| @@ -15,30 +15,26 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <launch/LaunchStep.h> | ||||
| #include <LoggedProcess.h> | ||||
| #include <java/JavaChecker.h> | ||||
| #include <launch/LaunchStep.h> | ||||
|  | ||||
| class CheckJava: public LaunchStep | ||||
| { | ||||
| class CheckJava : public LaunchStep { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     explicit CheckJava(LaunchTask *parent) :LaunchStep(parent){}; | ||||
|     virtual ~CheckJava() {}; | ||||
|    public: | ||||
|     explicit CheckJava(LaunchTask* parent) : LaunchStep(parent){}; | ||||
|     virtual ~CheckJava(){}; | ||||
|  | ||||
|     virtual void executeTask(); | ||||
|     virtual bool canAbort() const | ||||
|     { | ||||
|         return false; | ||||
|     } | ||||
| private slots: | ||||
|     virtual bool canAbort() const { return false; } | ||||
|    private slots: | ||||
|     void checkJavaFinished(JavaCheckResult result); | ||||
|  | ||||
| private: | ||||
|     void printJavaInfo(const QString & version, const QString & architecture, const QString & realArchitecture, const QString & vendor); | ||||
|    private: | ||||
|     void printJavaInfo(const QString& version, const QString& architecture, const QString& realArchitecture, const QString& vendor); | ||||
|     void printSystemInfo(bool javaIsKnown, bool javaIs64bit); | ||||
|  | ||||
| private: | ||||
|    private: | ||||
|     QString m_javaPath; | ||||
|     QString m_javaSignature; | ||||
|     JavaCheckerPtr m_JavaChecker; | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user