Merge branch 'develop' of https://github.com/PrismLauncher/PrismLauncher into welcome_background

Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
This commit is contained in:
Trial97 2023-08-05 19:04:15 +03:00
commit d936b25868
No known key found for this signature in database
GPG Key ID: 55EF5DA53DB36318
661 changed files with 17194 additions and 17319 deletions

View File

@ -1,10 +1,12 @@
---
Language: Cpp
BasedOnStyle: Chromium
IndentWidth: 4
AlignConsecutiveMacros: false
AlignConsecutiveAssignments: false
AllowShortIfStatementsOnASingleLine: false
ColumnLimit: 140
---
Language: Cpp
AlignConsecutiveMacros: None
AlignConsecutiveAssignments: None
BraceWrapping:
AfterFunction: true
SplitEmptyFunction: false
@ -12,5 +14,4 @@ BraceWrapping:
SplitEmptyNamespace: false
BreakBeforeBraces: Custom
BreakConstructorInitializers: BeforeComma
ColumnLimit: 140
Cpp11BracedListStyle: false

View File

@ -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: ''
@ -586,33 +586,3 @@ jobs:
with:
bundle: "Prism Launcher.flatpak"
manifest-path: flatpak/org.prismlauncher.PrismLauncher.yml
nix:
runs-on: ubuntu-latest
strategy:
matrix:
package:
- prismlauncher
- prismlauncher-qt5
steps:
- name: Clone repository
if: inputs.build_type == 'Debug'
uses: actions/checkout@v3
with:
submodules: 'true'
- name: Install nix
if: inputs.build_type == 'Debug'
uses: cachix/install-nix-action@v22
with:
install_url: https://nixos.org/nix/install
extra_nix_config: |
auto-optimise-store = true
experimental-features = nix-command flakes
- uses: cachix/cachix-action@v12
if: inputs.build_type == 'Debug'
with:
name: prismlauncher
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
- name: Build
if: inputs.build_type == 'Debug'
run: nix build .#${{ matrix.package }} --print-build-logs

View File

@ -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()

View File

@ -19,7 +19,7 @@ In an effort to ensure that the code you contribute is actually compatible with
This can be done by appending `-s` to your `git commit` call, or by manually appending the following text to your commit message:
```
```text
<commit message>
Signed-off-by: Author name <Author email>
@ -27,7 +27,7 @@ Signed-off-by: Author name <Author email>
By signing off your work, you agree to the terms below:
```
```text
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
@ -62,7 +62,6 @@ As a bonus, you can also [cryptographically sign your commits][gh-signing-commit
[gh-signing-commits]: https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits
[gh-vigilant-mode]: https://docs.github.com/en/authentication/managing-commit-signature-verification/displaying-verification-statuses-for-all-of-your-commits
## Backporting to Release Branches
We use [automated backports](https://github.com/PrismLauncher/PrismLauncher/blob/develop/.github/workflows/backport.yml) to merge specific contributions from develop into `release` branches.

View File

@ -42,7 +42,7 @@ Feel free to create a GitHub issue if you find a bug or want to suggest a new fe
- **Our Matrix space:**
[![PrismLauncher Space](https://img.shields.io/matrix/prismlauncher:matrix.org?style=for-the-badge&label=Matrix%20Space&logo=matrix&color=purple)](https://prismlauncher.org/matrix)
[![Prism Launcher Space](https://img.shields.io/matrix/prismlauncher:matrix.org?style=for-the-badge&label=Matrix%20Space&logo=matrix&color=purple)](https://prismlauncher.org/matrix)
- **Our Subreddit:**
@ -50,7 +50,7 @@ Feel free to create a GitHub issue if you find a bug or want to suggest a new fe
## Translations
The translation effort for PrismLauncher is hosted on [Weblate](https://hosted.weblate.org/projects/prismlauncher/launcher/) and information about translating Prism Launcher is available at <https://github.com/PrismLauncher/Translations>
The translation effort for Prism Launcher is hosted on [Weblate](https://hosted.weblate.org/projects/prismlauncher/launcher/) and information about translating Prism Launcher is available at <https://github.com/PrismLauncher/Translations>
## Building
@ -82,14 +82,16 @@ Thanks to the awesome people over at [MacStadium](https://www.macstadium.com/),
## Forking/Redistributing/Custom builds policy
We don't care what you do with your fork/custom build as long as you follow the terms of the [license](LICENSE) (this is a legal responsibility), and if you made code changes rather than just packaging a custom build, please do the following as a basic courtesy:
You are free to fork, redistribute and provide custom builds as long as you follow the terms of the [license](LICENSE) (this is a legal responsibility), and if you made code changes rather than just packaging a custom build, please do the following as a basic courtesy:
- Make it clear that your fork is not PrismLauncher and is not endorsed by or affiliated with the PrismLauncher project (<https://prismlauncher.org>).
- Go through [CMakeLists.txt](CMakeLists.txt) and change PrismLauncher's API keys to your own or set them to empty strings (`""`) to disable them (this way the program will still compile but the functionality requiring those keys will be disabled).
- Make it clear that your fork is not Prism Launcher and is not endorsed by or affiliated with the Prism Launcher project (<https://prismlauncher.org>).
- Go through [CMakeLists.txt](CMakeLists.txt) and change Prism Launcher's API keys to your own or set them to empty strings (`""`) to disable them (this way the program will still compile but the functionality requiring those keys will be disabled).
If you have any questions or want any clarification on the above conditions please make an issue and ask us.
Be aware that if you build this software without removing the provided API keys in [CMakeLists.txt](CMakeLists.txt) you are accepting the following terms and conditions:
If you are just building Prism Launcher for your distribution, please make sure to set the `Launcher_BUILD_PLATFORM` to a slug representing your distribution. Examples are `archlinux`, `fedora` and `nixpkgs`.
Note that if you build this software without removing the provided API keys in [CMakeLists.txt](CMakeLists.txt) you are accepting the following terms and conditions:
- [Microsoft Identity Platform Terms of Use](https://docs.microsoft.com/en-us/legal/microsoft-identity-platform/terms-of-use)
- [CurseForge 3rd Party API Terms and Conditions](https://support.curseforge.com/en/support/solutions/articles/9000207405-curse-forge-3rd-party-api-terms-and-conditions)

View File

@ -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

View File

@ -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.
@ -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";

18
flake.lock generated
View File

@ -76,11 +76,11 @@
"libnbtplusplus": {
"flake": false,
"locked": {
"lastModified": 1650031308,
"narHash": "sha256-TvVOjkUobYJD9itQYueELJX3wmecvEdCbJ0FinW2mL4=",
"lastModified": 1690036783,
"narHash": "sha256-A5kTgICnx+Qdq3Fir/bKTfdTt/T1NQP2SC+nhN1ENug=",
"owner": "PrismLauncher",
"repo": "libnbtplusplus",
"rev": "2203af7eeb48c45398139b583615134efd8d407f",
"rev": "a5e8fd52b8bf4ab5d5bcc042b2a247867589985f",
"type": "github"
},
"original": {
@ -91,11 +91,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1689413807,
"narHash": "sha256-exuzOvOhGAEKWQKwDuZAL4N8a1I837hH5eocaTcIbLc=",
"lastModified": 1690630721,
"narHash": "sha256-Y04onHyBQT4Erfr2fc82dbJTfXGYrf4V0ysLUYnPOP8=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "46ed466081b9cad1125b11f11a2af5cc40b942c7",
"rev": "d2b52322f35597c62abf56de91b0236746b2a03d",
"type": "github"
},
"original": {
@ -138,11 +138,11 @@
]
},
"locked": {
"lastModified": 1689328505,
"narHash": "sha256-9B3+OeUn1a/CvzE3GW6nWNwS5J7PDHTyHGlpL3wV5oA=",
"lastModified": 1690628027,
"narHash": "sha256-OTSbA2hM6VmxyZ/4siYPANffMBzIsKu04GLjXcv8ST0=",
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "5e28316db471d1ac234beb70031b635437421dd6",
"rev": "1e2443dd3f669eb65433b2fc26a3065e05a7dc9c",
"type": "github"
},
"original": {

View File

@ -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*

6
garnix.yaml Normal file
View File

@ -0,0 +1,6 @@
builds:
exclude: []
include:
- "checks.x86_64-linux.*"
- "devShells.*.*"
- "packages.*.*"

File diff suppressed because it is too large Load Diff

View File

@ -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>
@ -73,25 +73,19 @@ class MCEditTool;
class ThemeManager;
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,
@ -103,19 +97,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);
@ -139,29 +129,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);
@ -186,35 +164,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();
@ -224,39 +196,37 @@ signals:
void clickedOnDock();
#endif
public slots:
bool launch(
InstancePtr instance,
public slots:
bool launch(InstancePtr instance,
bool online = true,
bool demo = false,
BaseProfilerFactory *profiler = nullptr,
BaseProfilerFactory* profiler = nullptr,
MinecraftServerTargetPtr serverToJoin = nullptr,
MinecraftAccountPtr accountToUse = 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;
@ -295,7 +265,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;
@ -306,13 +276,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;

View File

@ -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;

View File

@ -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);
};

View File

@ -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/");
}

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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
};
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)

View File

@ -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,8 +65,7 @@ QVariant BaseVersionList::data(const QModelIndex &index, int role) const
BaseVersion::Ptr version = at(index.row());
switch (role)
{
switch (role) {
case VersionPointerRole:
return QVariant::fromValue(version);
@ -89,16 +85,16 @@ QVariant BaseVersionList::data(const QModelIndex &index, int role) const
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;
}

View File

@ -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

View File

@ -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()
@ -872,6 +875,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
@ -1046,6 +1054,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
@ -1141,17 +1150,23 @@ if(APPLE)
set(CMAKE_MACOSX_RPATH 1)
set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks/")
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()
target_link_libraries(Launcher_logic
"-framework AppKit"
"-framework Carbon"
"-framework Foundation"
"-framework ApplicationServices"
)
if(Launcher_ENABLE_UPDATER)
target_link_libraries(Launcher_logic ${SPARKLE_FRAMEWORK})
endif()
endif()
target_link_libraries(Launcher_logic)
@ -1213,7 +1228,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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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 (!dir.exists())
{
if (!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,20 +131,14 @@ 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
{
if (!isSandbox()) {
return IndirectOpen([&]() { return QProcess::startDetached(application, QStringList() << path, workingDirectory); }, pid);
} else {
return QProcess::startDetached(application, QStringList() << path, workingDirectory, pid);
}
#else
@ -173,20 +146,14 @@ bool openFile(const QString &application, const QString &path, const QString &wo
#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())
{
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 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

View File

@ -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
{
/**
namespace DesktopServices {
/**
* Open a file in whatever application is applicable
*/
bool openFile(const QString &path);
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);
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);
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);
bool openDirectory(const QString& path, bool ensureExists = false);
/**
/**
* Open the URL, most likely in a browser. Maybe.
*/
bool openUrl(const QUrl &url);
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

View File

@ -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;
};

View File

@ -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;

View File

@ -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"

View File

@ -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

View File

@ -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);

View File

@ -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 &regexp, 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;
};

View File

@ -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;

View File

@ -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);
};

View File

@ -6,17 +6,10 @@
bool InstanceCopyPrefs::allTrue() const
{
return copySaves &&
keepPlaytime &&
copyGameOptions &&
copyResourcePacks &&
copyShaderPacks &&
copyServers &&
copyMods &&
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) {

View File

@ -156,7 +156,8 @@ void InstanceCopyTask::copyFinished()
allowed_symlinks.append(m_origInstance->gameRoot().toUtf8());
allowed_symlinks.append("\n");
if (allowed_symlinks_file.isSymLink())
FS::deletePath(allowed_symlinks_file
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);

View File

@ -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;

View File

@ -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"
@ -99,7 +99,7 @@ void InstanceImportTask::executeTask()
connect(m_filesNetJob.get(), &NetJob::succeeded, this, &InstanceImportTask::downloadSucceeded);
connect(m_filesNetJob.get(), &NetJob::progress, this, &InstanceImportTask::downloadProgressChanged);
connect(m_filesNetJob.get(), &NetJob::stepProgress, this, &InstanceImportTask::propogateStepProgress);
connect(m_filesNetJob.get(), &NetJob::stepProgress, this, &InstanceImportTask::propagateStepProgress);
connect(m_filesNetJob.get(), &NetJob::failed, this, &InstanceImportTask::downloadFailed);
connect(m_filesNetJob.get(), &NetJob::aborted, this, &InstanceImportTask::downloadAborted);
@ -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());
@ -293,7 +280,7 @@ void InstanceImportTask::processFlame()
});
connect(inst_creation_task.get(), &Task::failed, this, &InstanceImportTask::emitFailed);
connect(inst_creation_task.get(), &Task::progress, this, &InstanceImportTask::setProgress);
connect(inst_creation_task.get(), &Task::stepProgress, this, &InstanceImportTask::propogateStepProgress);
connect(inst_creation_task.get(), &Task::stepProgress, this, &InstanceImportTask::propagateStepProgress);
connect(inst_creation_task.get(), &Task::status, this, &InstanceImportTask::setStatus);
connect(inst_creation_task.get(), &Task::details, this, &InstanceImportTask::setDetails);
@ -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()) {
@ -385,7 +373,7 @@ void InstanceImportTask::processModrinth()
});
connect(inst_creation_task, &Task::failed, this, &InstanceImportTask::emitFailed);
connect(inst_creation_task, &Task::progress, this, &InstanceImportTask::setProgress);
connect(inst_creation_task, &Task::stepProgress, this, &InstanceImportTask::propogateStepProgress);
connect(inst_creation_task, &Task::stepProgress, this, &InstanceImportTask::propagateStepProgress);
connect(inst_creation_task, &Task::status, this, &InstanceImportTask::setStatus);
connect(inst_creation_task, &Task::details, this, &InstanceImportTask::setDetails);
connect(inst_creation_task, &Task::finished, inst_creation_task, &InstanceCreationTask::deleteLater);

View File

@ -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;
};

View File

@ -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,38 +158,30 @@ 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);
BaseInstance* pdata = static_cast<BaseInstance*>(index.internalPointer());
switch (role) {
case InstancePointerRole: {
QVariant v = QVariant::fromValue((void*)pdata);
return v;
}
case InstanceIDRole:
{
case InstanceIDRole: {
return pdata->id();
}
case Qt::EditRole:
case Qt::DisplayRole:
{
case Qt::DisplayRole: {
return pdata->name();
}
case Qt::AccessibleTextRole:
{
case Qt::AccessibleTextRole: {
return tr("%1 Instance").arg(pdata->name());
}
case Qt::ToolTipRole:
{
case Qt::ToolTipRole: {
return pdata->instanceRoot();
}
case Qt::DecorationRole:
{
case Qt::DecorationRole: {
return pdata->iconKey();
}
// HACK: see InstanceView.h in gui!
case GroupRole:
{
case GroupRole: {
return getInstanceGroup(pdata->id());
}
default:
@ -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);
@ -799,7 +796,7 @@ class InstanceStaging : public Task {
connect(child, &Task::status, this, &InstanceStaging::setStatus);
connect(child, &Task::details, this, &InstanceStaging::setDetails);
connect(child, &Task::progress, this, &InstanceStaging::setProgress);
connect(child, &Task::stepProgress, this, &InstanceStaging::propogateStepProgress);
connect(child, &Task::stepProgress, this, &InstanceStaging::propagateStepProgress);
connect(&m_backoffTimer, &QTimer::timeout, 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;

View File

@ -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,24 +43,22 @@ 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
@ -82,21 +68,11 @@ public:
* 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;

View File

@ -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;
};

View File

@ -18,11 +18,12 @@ 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 "
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),
@ -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

View File

@ -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 "
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())
{
"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();
}

View File

@ -6,28 +6,25 @@ 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
{
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() {};
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();
@ -40,11 +37,11 @@ namespace JavaCommon
private:
std::shared_ptr<JavaChecker> checker;
QWidget *m_parent = nullptr;
QWidget* m_parent = nullptr;
QString m_path;
QString m_args;
int m_minMem = 0;
int m_maxMem = 0;
int m_permGen = 64;
};
}
};
} // namespace JavaCommon

View File

@ -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,222 +37,211 @@
#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);
@ -263,31 +252,31 @@ template<> QUuid requireIsType<QUuid>(const QJsonValue &value, const QString &wh
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

View File

@ -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,23 +220,23 @@ 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);
@ -243,19 +244,20 @@ QVector<T> ensureIsArrayOf(const QJsonObject &parent, const QString &key,
// 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") \
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") \
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__") \
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") \
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); \
}
@ -276,5 +278,5 @@ JSON_HELPERFUNCTIONS(Variant, QVariant)
#undef JSON_HELPERFUNCTIONS
}
} // namespace Json
using JSONValidationError = Json::JsonException;

View File

@ -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();
}

View File

@ -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;
};

View File

@ -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"),
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();
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,24 +287,21 @@ 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);
@ -359,21 +311,21 @@ void LaunchController::launchInstance()
// 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));
"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?"),
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)
{
QMessageBox::Question, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)
->exec();
if (response == QMessageBox::Yes) {
return m_launcher->abort();
}
return false;

View File

@ -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;

View File

@ -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;
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;

View File

@ -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;

View File

@ -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;

View File

@ -31,4 +31,4 @@ QString prettifyDuration(int64_t duration);
* @return QString
*/
QString humanReadableDuration(double duration, int precision = 0);
}
} // namespace Time

View File

@ -1,10 +1,10 @@
#pragma once
#include <QCoreApplication>
#include <QDebug>
#include <QPixmapCache>
#include <QThread>
#include <QTime>
#include <QDebug>
#define GET_TYPE() \
Qt::ConnectionType type; \

View File

@ -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 {

View File

@ -18,7 +18,7 @@
#pragma once
#include <QString>
#include <cmark.h>
#include <QString>
QString markdownToHTML(const QString& markdown);

View File

@ -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;

View File

@ -6,10 +6,8 @@
* @brief the MessageLevel Enum
* defines what level a log message is
*/
namespace MessageLevel
{
enum Enum
{
namespace MessageLevel {
enum Enum {
Unknown, /**< No idea what this is or where it came from */
StdOut, /**< Undetermined stderr messages */
StdErr, /**< Undetermined stdout messages */
@ -21,8 +19,8 @@ enum Enum
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

View File

@ -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

View File

@ -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
{
return m_problems;
}
ProblemSeverity getProblemSeverity() const override
{
return m_problemSeverity;
}
virtual void addProblem(ProblemSeverity severity, const QString &description)
{
if(severity > m_problemSeverity)
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)
{
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;
};

View File

@ -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

View File

@ -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;

View File

@ -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));
}

View File

@ -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);
};

View File

@ -54,7 +54,7 @@ ResourceDownloadTask::ResourceDownloadTask(ModPlatform::IndexedPack::Ptr pack,
m_filesNetJob->addNetAction(Net::Download::makeFile(m_pack_version.downloadUrl, dir.absoluteFilePath(getFilename())));
connect(m_filesNetJob.get(), &NetJob::succeeded, this, &ResourceDownloadTask::downloadSucceeded);
connect(m_filesNetJob.get(), &NetJob::progress, this, &ResourceDownloadTask::downloadProgressChanged);
connect(m_filesNetJob.get(), &NetJob::stepProgress, this, &ResourceDownloadTask::propogateStepProgress);
connect(m_filesNetJob.get(), &NetJob::stepProgress, this, &ResourceDownloadTask::propagateStepProgress);
connect(m_filesNetJob.get(), &NetJob::failed, this, &ResourceDownloadTask::downloadFailed);
addTask(m_filesNetJob);

View File

@ -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

View File

@ -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;
};

View File

@ -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

View File

@ -17,7 +17,6 @@
#include <QPixmap>
namespace SkinUtils
{
namespace SkinUtils {
QPixmap getFaceFromCache(QString id, int height = 64, int width = 64);
}

View File

@ -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

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
};

View File

@ -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,8 +271,7 @@ QVariant IconList::data(const QModelIndex &index, int role) const
if (row < 0 || row >= icons.size())
return QVariant();
switch (role)
{
switch (role) {
case Qt::DecorationRole:
return icons[row].icon();
case Qt::DisplayRole:
@ -299,15 +283,14 @@ QVariant IconList::data(const QModelIndex &index, int role) const
}
}
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())

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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,11 +37,10 @@
#include <QFileInfo>
#include <QIcon>
IconType operator--(IconType &t, int)
IconType operator--(IconType& t, int)
{
IconType temp = t;
switch (t)
{
switch (t) {
case IconType::Builtin:
t = IconType::ToBeDeleted;
break;
@ -51,8 +50,7 @@ IconType operator--(IconType &t, int)
case IconType::FileBased:
t = IconType::Transient;
break;
default:
{
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;

View File

@ -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;
};

View File

@ -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();
}

View File

@ -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);

View File

@ -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();

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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;
};

View File

@ -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);

View File

@ -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");

View File

@ -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));
}

View File

@ -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;

View File

@ -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);

View File

@ -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;
};

View File

@ -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()));
" 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));
}
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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)
};

Some files were not shown because too many files have changed in this diff Show More