Merge branch 'develop' of https://github.com/PrismLauncher/PrismLauncher into refactor/NetActions
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
This commit is contained in:
commit
1d3f2674d1
@ -1,16 +1,17 @@
|
|||||||
---
|
---
|
||||||
Language: Cpp
|
BasedOnStyle: Chromium
|
||||||
BasedOnStyle: Chromium
|
|
||||||
IndentWidth: 4
|
IndentWidth: 4
|
||||||
AlignConsecutiveMacros: false
|
|
||||||
AlignConsecutiveAssignments: false
|
|
||||||
AllowShortIfStatementsOnASingleLine: false
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
ColumnLimit: 140
|
||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
AlignConsecutiveMacros: None
|
||||||
|
AlignConsecutiveAssignments: None
|
||||||
BraceWrapping:
|
BraceWrapping:
|
||||||
AfterFunction: true
|
AfterFunction: true
|
||||||
SplitEmptyFunction: false
|
SplitEmptyFunction: false
|
||||||
SplitEmptyRecord: false
|
SplitEmptyRecord: false
|
||||||
SplitEmptyNamespace: false
|
SplitEmptyNamespace: false
|
||||||
BreakBeforeBraces: Custom
|
BreakBeforeBraces: Custom
|
||||||
BreakConstructorInitializers: BeforeComma
|
BreakConstructorInitializers: BeforeComma
|
||||||
ColumnLimit: 140
|
|
||||||
Cpp11BracedListStyle: false
|
Cpp11BracedListStyle: false
|
||||||
|
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@ -68,7 +68,7 @@ jobs:
|
|||||||
qt_ver: 6
|
qt_ver: 6
|
||||||
qt_host: windows
|
qt_host: windows
|
||||||
qt_arch: ''
|
qt_arch: ''
|
||||||
qt_version: '6.5.1'
|
qt_version: '6.5.2'
|
||||||
qt_modules: 'qt5compat qtimageformats'
|
qt_modules: 'qt5compat qtimageformats'
|
||||||
qt_tools: ''
|
qt_tools: ''
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ jobs:
|
|||||||
qt_ver: 6
|
qt_ver: 6
|
||||||
qt_host: windows
|
qt_host: windows
|
||||||
qt_arch: 'win64_msvc2019_arm64'
|
qt_arch: 'win64_msvc2019_arm64'
|
||||||
qt_version: '6.5.1'
|
qt_version: '6.5.2'
|
||||||
qt_modules: 'qt5compat qtimageformats'
|
qt_modules: 'qt5compat qtimageformats'
|
||||||
qt_tools: ''
|
qt_tools: ''
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ jobs:
|
|||||||
qt_ver: 6
|
qt_ver: 6
|
||||||
qt_host: mac
|
qt_host: mac
|
||||||
qt_arch: ''
|
qt_arch: ''
|
||||||
qt_version: '6.5.0'
|
qt_version: '6.5.2'
|
||||||
qt_modules: 'qt5compat qtimageformats'
|
qt_modules: 'qt5compat qtimageformats'
|
||||||
qt_tools: ''
|
qt_tools: ''
|
||||||
|
|
||||||
|
@ -318,6 +318,8 @@ add_subdirectory(program_info)
|
|||||||
|
|
||||||
####################################### Install layout #######################################
|
####################################### Install layout #######################################
|
||||||
|
|
||||||
|
set(Launcher_ENABLE_UPDATER NO)
|
||||||
|
|
||||||
if(NOT (UNIX AND APPLE))
|
if(NOT (UNIX AND APPLE))
|
||||||
# Install "portable.txt" if selected component is "portable"
|
# Install "portable.txt" if selected component is "portable"
|
||||||
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_Portable_File}" DESTINATION "." COMPONENT portable EXCLUDE_FROM_ALL)
|
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_SHORT_VERSION_STRING "${Launcher_VERSION_NAME}")
|
||||||
set(MACOSX_BUNDLE_LONG_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_ICON_FILE ${Launcher_Name}.icns)
|
||||||
set(MACOSX_BUNDLE_COPYRIGHT "© 2022 ${Launcher_Copyright_Mac}")
|
set(MACOSX_BUNDLE_COPYRIGHT "© 2022-2023 ${Launcher_Copyright_Mac}")
|
||||||
set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "v55ZWWD6QlPoXGV6VLzOTZxZUggWeE51X8cRQyQh6vA=")
|
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")
|
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_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")
|
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
|
# directories to look for dependencies
|
||||||
set(DIRS ${QT_LIBS_DIR} ${QT_LIBEXECS_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${MACOSX_SPARKLE_DIR})
|
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
|
# install as bundle
|
||||||
set(INSTALL_BUNDLE "full")
|
set(INSTALL_BUNDLE "full" CACHE STRING "Use fixup_bundle to bundle dependencies")
|
||||||
|
|
||||||
# Add the icon
|
# Add the icon
|
||||||
install(FILES ${Launcher_Branding_ICNS} DESTINATION ${RESOURCES_DEST_DIR} RENAME ${Launcher_Name}.icns)
|
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}")
|
set(JARS_DEST_DIR "share/${Launcher_Name}")
|
||||||
|
|
||||||
# install as bundle with no dependencies included
|
# 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 RPATH
|
||||||
SET(Launcher_BINARY_RPATH "$ORIGIN/")
|
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})
|
set(DIRS ${QT_LIBS_DIR} ${QT_LIBEXECS_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
|
||||||
|
|
||||||
# install as bundle
|
# install as bundle
|
||||||
set(INSTALL_BUNDLE "full")
|
set(INSTALL_BUNDLE "full" CACHE STRING "Use fixup_bundle to bundle dependencies")
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "Platform not supported")
|
message(FATAL_ERROR "Platform not supported")
|
||||||
endif()
|
endif()
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// 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 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
@ -36,8 +36,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <QString>
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief The Config class holds all the build-time information passed from the build system.
|
* \brief The Config class holds all the build-time information passed from the build system.
|
||||||
@ -145,7 +145,7 @@ class Config {
|
|||||||
QString AUTH_BASE = "https://authserver.mojang.com/";
|
QString AUTH_BASE = "https://authserver.mojang.com/";
|
||||||
QString IMGUR_BASE_URL = "https://api.imgur.com/3/";
|
QString IMGUR_BASE_URL = "https://api.imgur.com/3/";
|
||||||
QString FMLLIBS_BASE_URL = "https://files.prismlauncher.org/fmllibs/"; // FIXME: move into CMakeLists
|
QString FMLLIBS_BASE_URL = "https://files.prismlauncher.org/fmllibs/"; // FIXME: move into CMakeLists
|
||||||
QString TRANSLATIONS_BASE_URL = "https://i18n.prismlauncher.org/"; // FIXME: move into CMakeLists
|
QString TRANSLATIONS_BASE_URL = "https://i18n.prismlauncher.org/"; // FIXME: move into CMakeLists
|
||||||
|
|
||||||
QString MODPACKSCH_API_BASE_URL = "https://api.modpacks.ch/";
|
QString MODPACKSCH_API_BASE_URL = "https://api.modpacks.ch/";
|
||||||
|
|
||||||
@ -162,7 +162,7 @@ class Config {
|
|||||||
|
|
||||||
QString MODRINTH_STAGING_URL = "https://staging-api.modrinth.com/v2";
|
QString MODRINTH_STAGING_URL = "https://staging-api.modrinth.com/v2";
|
||||||
QString MODRINTH_PROD_URL = "https://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";
|
QString FLAME_BASE_URL = "https://api.curseforge.com/v1";
|
||||||
|
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
{
|
{
|
||||||
"name": "libdecor",
|
"name": "libdecor",
|
||||||
"buildsystem": "meson",
|
"buildsystem": "meson",
|
||||||
"config-opts": [
|
"config-opts": [
|
||||||
"-Ddemo=false"
|
"-Ddemo=false"
|
||||||
],
|
],
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://gitlab.freedesktop.org/libdecor/libdecor.git",
|
"url": "https://gitlab.freedesktop.org/libdecor/libdecor.git",
|
||||||
"commit": "73260393a97291c887e1074ab7f318e031be0ac6"
|
"commit": "73260393a97291c887e1074ab7f318e031be0ac6"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "patch",
|
"type": "patch",
|
||||||
"path": "patches/weird_libdecor.patch"
|
"path": "patches/weird_libdecor.patch"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"cleanup": [
|
"cleanup": [
|
||||||
"/include",
|
"/include",
|
||||||
"/lib/pkgconfig"
|
"/lib/pkgconfig"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,8 @@ finish-args:
|
|||||||
- --filesystem=xdg-run/app/com.discordapp.Discord:create
|
- --filesystem=xdg-run/app/com.discordapp.Discord:create
|
||||||
# Mod drag&drop
|
# Mod drag&drop
|
||||||
- --filesystem=xdg-download:ro
|
- --filesystem=xdg-download:ro
|
||||||
|
# FTBApp import
|
||||||
|
- --filesystem=~/.ftba:ro
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
- /lib/libGLU*
|
- /lib/libGLU*
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -38,12 +38,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <memory>
|
#include <QDateTime>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QFlag>
|
#include <QFlag>
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <QDateTime>
|
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <BaseInstance.h>
|
#include <BaseInstance.h>
|
||||||
|
|
||||||
@ -73,25 +73,19 @@ class MCEditTool;
|
|||||||
class ThemeManager;
|
class ThemeManager;
|
||||||
|
|
||||||
namespace Meta {
|
namespace Meta {
|
||||||
class Index;
|
class Index;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(APPLICATION)
|
#if defined(APPLICATION)
|
||||||
#undef APPLICATION
|
#undef APPLICATION
|
||||||
#endif
|
#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
|
// friends for the purpose of limiting access to deprecated stuff
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
enum Status {
|
enum Status { StartingUp, Failed, Succeeded, Initialized };
|
||||||
StartingUp,
|
|
||||||
Failed,
|
|
||||||
Succeeded,
|
|
||||||
Initialized
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Capability {
|
enum Capability {
|
||||||
None = 0,
|
None = 0,
|
||||||
@ -103,19 +97,15 @@ public:
|
|||||||
};
|
};
|
||||||
Q_DECLARE_FLAGS(Capabilities, Capability)
|
Q_DECLARE_FLAGS(Capabilities, Capability)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Application(int &argc, char **argv);
|
Application(int& argc, char** argv);
|
||||||
virtual ~Application();
|
virtual ~Application();
|
||||||
|
|
||||||
bool event(QEvent* event) override;
|
bool event(QEvent* event) override;
|
||||||
|
|
||||||
std::shared_ptr<SettingsObject> settings() const {
|
std::shared_ptr<SettingsObject> settings() const { return m_settings; }
|
||||||
return m_settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
qint64 timeSinceStart() const {
|
qint64 timeSinceStart() const { return startTime.msecsTo(QDateTime::currentDateTime()); }
|
||||||
return startTime.msecsTo(QDateTime::currentDateTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
QIcon getThemedIcon(const QString& name);
|
QIcon getThemedIcon(const QString& name);
|
||||||
|
|
||||||
@ -139,29 +129,17 @@ public:
|
|||||||
|
|
||||||
std::shared_ptr<JavaInstallList> javalist();
|
std::shared_ptr<JavaInstallList> javalist();
|
||||||
|
|
||||||
std::shared_ptr<InstanceList> instances() const {
|
std::shared_ptr<InstanceList> instances() const { return m_instances; }
|
||||||
return m_instances;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<IconList> icons() const {
|
std::shared_ptr<IconList> icons() const { return m_icons; }
|
||||||
return m_icons;
|
|
||||||
}
|
|
||||||
|
|
||||||
MCEditTool *mcedit() const {
|
MCEditTool* mcedit() const { return m_mcedit.get(); }
|
||||||
return m_mcedit.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
shared_qobject_ptr<AccountList> accounts() const {
|
shared_qobject_ptr<AccountList> accounts() const { return m_accounts; }
|
||||||
return m_accounts;
|
|
||||||
}
|
|
||||||
|
|
||||||
Status status() const {
|
Status status() const { return m_status; }
|
||||||
return m_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QMap<QString, std::shared_ptr<BaseProfilerFactory>> &profilers() const {
|
const QMap<QString, std::shared_ptr<BaseProfilerFactory>>& profilers() const { return m_profilers; }
|
||||||
return m_profilers;
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateProxySettings(QString proxyTypeStr, QString addr, int port, QString user, QString password);
|
void updateProxySettings(QString proxyTypeStr, QString addr, int port, QString user, QString password);
|
||||||
|
|
||||||
@ -186,35 +164,29 @@ public:
|
|||||||
QString getUserAgentUncached();
|
QString getUserAgentUncached();
|
||||||
|
|
||||||
/// this is the root of the 'installation'. Used for automatic updates
|
/// this is the root of the 'installation'. Used for automatic updates
|
||||||
const QString &root() {
|
const QString& root() { return m_rootPath; }
|
||||||
return m_rootPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isPortable() {
|
bool isPortable() { return m_portable; }
|
||||||
return m_portable;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Capabilities capabilities() {
|
const Capabilities capabilities() { return m_capabilities; }
|
||||||
return m_capabilities;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Opens a json file using either a system default editor, or, if not empty, the editor
|
* Opens a json file using either a system default editor, or, if not empty, the editor
|
||||||
* specified in the settings
|
* specified in the settings
|
||||||
*/
|
*/
|
||||||
bool openJsonEditor(const QString &filename);
|
bool openJsonEditor(const QString& filename);
|
||||||
|
|
||||||
InstanceWindow *showInstanceWindow(InstancePtr instance, QString page = QString());
|
InstanceWindow* showInstanceWindow(InstancePtr instance, QString page = QString());
|
||||||
MainWindow *showMainWindow(bool minimized = false);
|
MainWindow* showMainWindow(bool minimized = false);
|
||||||
|
|
||||||
void updateIsRunning(bool running);
|
void updateIsRunning(bool running);
|
||||||
bool updatesAreAllowed();
|
bool updatesAreAllowed();
|
||||||
|
|
||||||
void ShowGlobalSettings(class QWidget * parent, QString open_page = QString());
|
void ShowGlobalSettings(class QWidget* parent, QString open_page = QString());
|
||||||
|
|
||||||
int suitableMaxMem();
|
int suitableMaxMem();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void updateAllowedChanged(bool status);
|
void updateAllowedChanged(bool status);
|
||||||
void globalSettingsAboutToOpen();
|
void globalSettingsAboutToOpen();
|
||||||
void globalSettingsClosed();
|
void globalSettingsClosed();
|
||||||
@ -224,39 +196,37 @@ signals:
|
|||||||
void clickedOnDock();
|
void clickedOnDock();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
bool launch(
|
bool launch(InstancePtr instance,
|
||||||
InstancePtr instance,
|
bool online = true,
|
||||||
bool online = true,
|
bool demo = false,
|
||||||
bool demo = false,
|
BaseProfilerFactory* profiler = nullptr,
|
||||||
BaseProfilerFactory *profiler = nullptr,
|
MinecraftServerTargetPtr serverToJoin = nullptr,
|
||||||
MinecraftServerTargetPtr serverToJoin = nullptr,
|
MinecraftAccountPtr accountToUse = nullptr);
|
||||||
MinecraftAccountPtr accountToUse = nullptr
|
|
||||||
);
|
|
||||||
bool kill(InstancePtr instance);
|
bool kill(InstancePtr instance);
|
||||||
void closeCurrentWindow();
|
void closeCurrentWindow();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_windowClose();
|
void on_windowClose();
|
||||||
void messageReceived(const QByteArray & message);
|
void messageReceived(const QByteArray& message);
|
||||||
void controllerSucceeded();
|
void controllerSucceeded();
|
||||||
void controllerFailed(const QString & error);
|
void controllerFailed(const QString& error);
|
||||||
void setupWizardFinished(int status);
|
void setupWizardFinished(int status);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool handleDataMigration(const QString & currentData, const QString & oldData, const QString & name, const QString & configFile) const;
|
bool handleDataMigration(const QString& currentData, const QString& oldData, const QString& name, const QString& configFile) const;
|
||||||
bool createSetupWizard();
|
bool createSetupWizard();
|
||||||
void performMainStartupAction();
|
void performMainStartupAction();
|
||||||
|
|
||||||
// sets the fatal error message and m_status to Failed.
|
// 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 addRunningInstance();
|
||||||
void subRunningInstance();
|
void subRunningInstance();
|
||||||
bool shouldExitNow() const;
|
bool shouldExitNow() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QDateTime startTime;
|
QDateTime startTime;
|
||||||
|
|
||||||
shared_qobject_ptr<QNetworkAccessManager> m_network;
|
shared_qobject_ptr<QNetworkAccessManager> m_network;
|
||||||
@ -295,7 +265,7 @@ private:
|
|||||||
|
|
||||||
// FIXME: attach to instances instead.
|
// FIXME: attach to instances instead.
|
||||||
struct InstanceXtras {
|
struct InstanceXtras {
|
||||||
InstanceWindow * window = nullptr;
|
InstanceWindow* window = nullptr;
|
||||||
shared_qobject_ptr<LaunchController> controller;
|
shared_qobject_ptr<LaunchController> controller;
|
||||||
};
|
};
|
||||||
std::map<QString, InstanceXtras> m_instanceExtras;
|
std::map<QString, InstanceXtras> m_instanceExtras;
|
||||||
@ -306,13 +276,14 @@ private:
|
|||||||
bool m_updateRunning = false;
|
bool m_updateRunning = false;
|
||||||
|
|
||||||
// main window, if any
|
// main window, if any
|
||||||
MainWindow * m_mainWindow = nullptr;
|
MainWindow* m_mainWindow = nullptr;
|
||||||
|
|
||||||
// peer launcher instance connector - used to implement single instance launcher and signalling
|
// peer launcher instance connector - used to implement single instance launcher and signalling
|
||||||
LocalPeer * m_peerInstance = nullptr;
|
LocalPeer* m_peerInstance = nullptr;
|
||||||
|
|
||||||
SetupWizard * m_setupWizard = nullptr;
|
SetupWizard* m_setupWizard = nullptr;
|
||||||
public:
|
|
||||||
|
public:
|
||||||
QString m_instanceIdToLaunch;
|
QString m_instanceIdToLaunch;
|
||||||
QString m_serverToJoin;
|
QString m_serverToJoin;
|
||||||
QString m_profileToUse;
|
QString m_profileToUse;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// 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 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -39,7 +39,8 @@
|
|||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include "Json.h"
|
#include "Json.h"
|
||||||
|
|
||||||
void ApplicationMessage::parse(const QByteArray & input) {
|
void ApplicationMessage::parse(const QByteArray& input)
|
||||||
|
{
|
||||||
auto doc = Json::requireDocument(input, "ApplicationMessage");
|
auto doc = Json::requireDocument(input, "ApplicationMessage");
|
||||||
auto root = Json::requireObject(doc, "ApplicationMessage");
|
auto root = Json::requireObject(doc, "ApplicationMessage");
|
||||||
|
|
||||||
@ -47,12 +48,13 @@ void ApplicationMessage::parse(const QByteArray & input) {
|
|||||||
args.clear();
|
args.clear();
|
||||||
|
|
||||||
auto parsedArgs = root.value("args").toObject();
|
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());
|
args.insert(iter.key(), iter.value().toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray ApplicationMessage::serialize() {
|
QByteArray ApplicationMessage::serialize()
|
||||||
|
{
|
||||||
QJsonObject root;
|
QJsonObject root;
|
||||||
root.insert("command", command);
|
root.insert("command", command);
|
||||||
QJsonObject outArgs;
|
QJsonObject outArgs;
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
#include <QHash>
|
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
struct ApplicationMessage {
|
struct ApplicationMessage {
|
||||||
QString command;
|
QString command;
|
||||||
QHash<QString, QString> args;
|
QHash<QString, QString> args;
|
||||||
|
|
||||||
QByteArray serialize();
|
QByteArray serialize();
|
||||||
void parse(const QByteArray & input);
|
void parse(const QByteArray& input);
|
||||||
};
|
};
|
||||||
|
@ -18,27 +18,21 @@
|
|||||||
#include "BaseInstaller.h"
|
#include "BaseInstaller.h"
|
||||||
#include "minecraft/MinecraftInstance.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()));
|
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");
|
QDir(to->instanceRoot()).mkdir("patches");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isApplied(to))
|
if (isApplied(to)) {
|
||||||
{
|
if (!remove(to)) {
|
||||||
if (!remove(to))
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -46,16 +40,16 @@ bool BaseInstaller::add(MinecraftInstance *to)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseInstaller::remove(MinecraftInstance *from)
|
bool BaseInstaller::remove(MinecraftInstance* from)
|
||||||
{
|
{
|
||||||
return QFile::remove(filename(from->instanceRoot()));
|
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");
|
return patchesDir(root).absoluteFilePath(id() + ".json");
|
||||||
}
|
}
|
||||||
QDir BaseInstaller::patchesDir(const QString &root) const
|
QDir BaseInstaller::patchesDir(const QString& root) const
|
||||||
{
|
{
|
||||||
return QDir(root + "/patches/");
|
return QDir(root + "/patches/");
|
||||||
}
|
}
|
||||||
|
@ -26,20 +26,19 @@ class QObject;
|
|||||||
class Task;
|
class Task;
|
||||||
class BaseVersion;
|
class BaseVersion;
|
||||||
|
|
||||||
class BaseInstaller
|
class BaseInstaller {
|
||||||
{
|
public:
|
||||||
public:
|
|
||||||
BaseInstaller();
|
BaseInstaller();
|
||||||
virtual ~BaseInstaller(){};
|
virtual ~BaseInstaller(){};
|
||||||
bool isApplied(MinecraftInstance *on);
|
bool isApplied(MinecraftInstance* on);
|
||||||
|
|
||||||
virtual bool add(MinecraftInstance *to);
|
virtual bool add(MinecraftInstance* to);
|
||||||
virtual bool remove(MinecraftInstance *from);
|
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;
|
virtual QString id() const = 0;
|
||||||
QString filename(const QString &root) const;
|
QString filename(const QString& root) const;
|
||||||
QDir patchesDir(const QString &root) const;
|
QDir patchesDir(const QString& root) const;
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// 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 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||||
*
|
*
|
||||||
@ -36,23 +36,22 @@
|
|||||||
|
|
||||||
#include "BaseInstance.h"
|
#include "BaseInstance.h"
|
||||||
|
|
||||||
#include <QFileInfo>
|
|
||||||
#include <QDir>
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QRegularExpression>
|
#include <QDir>
|
||||||
|
#include <QFileInfo>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
#include "settings/INISettingsObject.h"
|
#include "settings/INISettingsObject.h"
|
||||||
#include "settings/Setting.h"
|
|
||||||
#include "settings/OverrideSetting.h"
|
#include "settings/OverrideSetting.h"
|
||||||
|
#include "settings/Setting.h"
|
||||||
|
|
||||||
#include "FileSystem.h"
|
|
||||||
#include "Commandline.h"
|
|
||||||
#include "BuildConfig.h"
|
#include "BuildConfig.h"
|
||||||
|
#include "Commandline.h"
|
||||||
|
#include "FileSystem.h"
|
||||||
|
|
||||||
BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir)
|
BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString& rootDir) : QObject()
|
||||||
: QObject()
|
|
||||||
{
|
{
|
||||||
m_settings = settings;
|
m_settings = settings;
|
||||||
m_global_settings = globalSettings;
|
m_global_settings = globalSettings;
|
||||||
@ -79,7 +78,7 @@ BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr s
|
|||||||
m_settings->registerSetting("InstanceType", "");
|
m_settings->registerSetting("InstanceType", "");
|
||||||
|
|
||||||
// Custom Commands
|
// 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("PreLaunchCommand"), commandSetting);
|
||||||
m_settings->registerOverride(globalSettings->getSetting("WrapperCommand"), commandSetting);
|
m_settings->registerOverride(globalSettings->getSetting("WrapperCommand"), commandSetting);
|
||||||
m_settings->registerOverride(globalSettings->getSetting("PostExitCommand"), commandSetting);
|
m_settings->registerOverride(globalSettings->getSetting("PostExitCommand"), commandSetting);
|
||||||
@ -148,7 +147,11 @@ QString BaseInstance::getManagedPackVersionName() const
|
|||||||
return m_settings->get("ManagedPackVersionName").toString();
|
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("ManagedPack", true);
|
||||||
m_settings->set("ManagedPackType", type);
|
m_settings->set("ManagedPackType", type);
|
||||||
@ -173,8 +176,7 @@ int BaseInstance::getConsoleMaxLines() const
|
|||||||
auto lineSetting = m_settings->getSetting("ConsoleMaxLines");
|
auto lineSetting = m_settings->getSetting("ConsoleMaxLines");
|
||||||
bool conversionOk = false;
|
bool conversionOk = false;
|
||||||
int maxLines = lineSetting->get().toInt(&conversionOk);
|
int maxLines = lineSetting->get().toInt(&conversionOk);
|
||||||
if(!conversionOk)
|
if (!conversionOk) {
|
||||||
{
|
|
||||||
maxLines = lineSetting->defValue().toInt();
|
maxLines = lineSetting->defValue().toInt();
|
||||||
qWarning() << "ConsoleMaxLines has nonsensical value, defaulting to" << maxLines;
|
qWarning() << "ConsoleMaxLines has nonsensical value, defaulting to" << maxLines;
|
||||||
}
|
}
|
||||||
@ -220,8 +222,7 @@ bool BaseInstance::isLinkedToInstanceId(const QString& id) const
|
|||||||
|
|
||||||
void BaseInstance::iconUpdated(QString key)
|
void BaseInstance::iconUpdated(QString key)
|
||||||
{
|
{
|
||||||
if(iconKey() == key)
|
if (iconKey() == key) {
|
||||||
{
|
|
||||||
emit propertiesChanged(this);
|
emit propertiesChanged(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -235,8 +236,7 @@ void BaseInstance::invalidate()
|
|||||||
void BaseInstance::changeStatus(BaseInstance::Status newStatus)
|
void BaseInstance::changeStatus(BaseInstance::Status newStatus)
|
||||||
{
|
{
|
||||||
Status status = currentStatus();
|
Status status = currentStatus();
|
||||||
if(status != newStatus)
|
if (status != newStatus) {
|
||||||
{
|
|
||||||
m_status = newStatus;
|
m_status = newStatus;
|
||||||
emit statusChanged(status, newStatus);
|
emit statusChanged(status, newStatus);
|
||||||
}
|
}
|
||||||
@ -259,23 +259,19 @@ bool BaseInstance::isRunning() const
|
|||||||
|
|
||||||
void BaseInstance::setRunning(bool running)
|
void BaseInstance::setRunning(bool running)
|
||||||
{
|
{
|
||||||
if(running == m_isRunning)
|
if (running == m_isRunning)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_isRunning = running;
|
m_isRunning = running;
|
||||||
|
|
||||||
if(!m_settings->get("RecordGameTime").toBool())
|
if (!m_settings->get("RecordGameTime").toBool()) {
|
||||||
{
|
|
||||||
emit runningStatusChanged(running);
|
emit runningStatusChanged(running);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(running)
|
if (running) {
|
||||||
{
|
|
||||||
m_timeStarted = QDateTime::currentDateTime();
|
m_timeStarted = QDateTime::currentDateTime();
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
QDateTime timeEnded = QDateTime::currentDateTime();
|
QDateTime timeEnded = QDateTime::currentDateTime();
|
||||||
|
|
||||||
qint64 current = settings()->get("totalTimePlayed").toLongLong();
|
qint64 current = settings()->get("totalTimePlayed").toLongLong();
|
||||||
@ -291,8 +287,7 @@ void BaseInstance::setRunning(bool running)
|
|||||||
int64_t BaseInstance::totalTimePlayed() const
|
int64_t BaseInstance::totalTimePlayed() const
|
||||||
{
|
{
|
||||||
qint64 current = m_settings->get("totalTimePlayed").toLongLong();
|
qint64 current = m_settings->get("totalTimePlayed").toLongLong();
|
||||||
if(m_isRunning)
|
if (m_isRunning) {
|
||||||
{
|
|
||||||
QDateTime timeNow = QDateTime::currentDateTime();
|
QDateTime timeNow = QDateTime::currentDateTime();
|
||||||
return current + m_timeStarted.secsTo(timeNow);
|
return current + m_timeStarted.secsTo(timeNow);
|
||||||
}
|
}
|
||||||
@ -301,8 +296,7 @@ int64_t BaseInstance::totalTimePlayed() const
|
|||||||
|
|
||||||
int64_t BaseInstance::lastTimePlayed() const
|
int64_t BaseInstance::lastTimePlayed() const
|
||||||
{
|
{
|
||||||
if(m_isRunning)
|
if (m_isRunning) {
|
||||||
{
|
|
||||||
QDateTime timeNow = QDateTime::currentDateTime();
|
QDateTime timeNow = QDateTime::currentDateTime();
|
||||||
return m_timeStarted.secsTo(timeNow);
|
return m_timeStarted.secsTo(timeNow);
|
||||||
}
|
}
|
||||||
@ -349,14 +343,14 @@ qint64 BaseInstance::lastLaunch() const
|
|||||||
|
|
||||||
void BaseInstance::setLastLaunch(qint64 val)
|
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);
|
m_settings->set("lastLaunchTime", val);
|
||||||
emit propertiesChanged(this);
|
emit propertiesChanged(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseInstance::setNotes(QString val)
|
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);
|
m_settings->set("notes", val);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,7 +361,7 @@ QString BaseInstance::notes() const
|
|||||||
|
|
||||||
void BaseInstance::setIconKey(QString val)
|
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);
|
m_settings->set("iconKey", val);
|
||||||
emit propertiesChanged(this);
|
emit propertiesChanged(this);
|
||||||
}
|
}
|
||||||
@ -379,7 +373,7 @@ QString BaseInstance::iconKey() const
|
|||||||
|
|
||||||
void BaseInstance::setName(QString val)
|
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);
|
m_settings->set("name", val);
|
||||||
emit propertiesChanged(this);
|
emit propertiesChanged(this);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// 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 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||||
*
|
*
|
||||||
@ -37,24 +37,24 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include "QObjectPtr.h"
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QSet>
|
#include <QObject>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
#include <QSet>
|
||||||
|
#include "QObjectPtr.h"
|
||||||
|
|
||||||
#include "settings/SettingsObject.h"
|
#include "settings/SettingsObject.h"
|
||||||
|
|
||||||
#include "settings/INIFile.h"
|
|
||||||
#include "BaseVersionList.h"
|
#include "BaseVersionList.h"
|
||||||
#include "minecraft/auth/MinecraftAccount.h"
|
|
||||||
#include "MessageLevel.h"
|
#include "MessageLevel.h"
|
||||||
|
#include "minecraft/auth/MinecraftAccount.h"
|
||||||
#include "pathmatcher/IPathMatcher.h"
|
#include "pathmatcher/IPathMatcher.h"
|
||||||
|
#include "settings/INIFile.h"
|
||||||
|
|
||||||
#include "net/Mode.h"
|
#include "net/Mode.h"
|
||||||
|
|
||||||
#include "minecraft/launch/MinecraftServerTarget.h"
|
|
||||||
#include "RuntimeContext.h"
|
#include "RuntimeContext.h"
|
||||||
|
#include "minecraft/launch/MinecraftServerTarget.h"
|
||||||
|
|
||||||
class QDir;
|
class QDir;
|
||||||
class Task;
|
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
|
* To create a new instance type, create a new class inheriting from this class
|
||||||
* and implement the pure virtual functions.
|
* 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
|
Q_OBJECT
|
||||||
protected:
|
protected:
|
||||||
/// no-touchy!
|
/// no-touchy!
|
||||||
BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir);
|
BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString& rootDir);
|
||||||
|
|
||||||
public: /* types */
|
public: /* types */
|
||||||
enum class Status
|
enum class Status {
|
||||||
{
|
|
||||||
Present,
|
Present,
|
||||||
Gone // either nuked or invalidated
|
Gone // either nuked or invalidated
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// virtual destructor to make sure the destruction is COMPLETE
|
/// virtual destructor to make sure the destruction is COMPLETE
|
||||||
virtual ~BaseInstance() {};
|
virtual ~BaseInstance(){};
|
||||||
|
|
||||||
virtual void saveNow() = 0;
|
virtual void saveNow() = 0;
|
||||||
|
|
||||||
@ -117,10 +115,7 @@ public:
|
|||||||
QString instanceRoot() const;
|
QString instanceRoot() const;
|
||||||
|
|
||||||
/// Path to the instance's game root directory.
|
/// Path to the instance's game root directory.
|
||||||
virtual QString gameRoot() const
|
virtual QString gameRoot() const { return instanceRoot(); }
|
||||||
{
|
|
||||||
return instanceRoot();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Path to the instance's mods directory.
|
/// Path to the instance's mods directory.
|
||||||
virtual QString modsRoot() const = 0;
|
virtual QString modsRoot() const = 0;
|
||||||
@ -151,15 +146,12 @@ public:
|
|||||||
void copyManagedPack(BaseInstance& other);
|
void copyManagedPack(BaseInstance& other);
|
||||||
|
|
||||||
/// guess log level from a line of game log
|
/// guess log level from a line of game log
|
||||||
virtual MessageLevel::Enum guessLevel([[maybe_unused]] const QString &line, MessageLevel::Enum level)
|
virtual MessageLevel::Enum guessLevel([[maybe_unused]] const QString& line, MessageLevel::Enum level) { return level; };
|
||||||
{
|
|
||||||
return level;
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual QStringList extraArguments();
|
virtual QStringList extraArguments();
|
||||||
|
|
||||||
/// Traits. Normally inside the version, depends on instance implementation.
|
/// 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.
|
* Gets the time that the instance was last launched.
|
||||||
@ -189,8 +181,7 @@ public:
|
|||||||
virtual Task::Ptr createUpdateTask(Net::Mode mode) = 0;
|
virtual Task::Ptr createUpdateTask(Net::Mode mode) = 0;
|
||||||
|
|
||||||
/// returns a valid launcher (task container)
|
/// returns a valid launcher (task container)
|
||||||
virtual shared_qobject_ptr<LaunchTask> createLaunchTask(
|
virtual shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) = 0;
|
||||||
AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) = 0;
|
|
||||||
|
|
||||||
/// returns the current launch task (if any)
|
/// returns the current launch task (if any)
|
||||||
shared_qobject_ptr<LaunchTask> getLaunchTask();
|
shared_qobject_ptr<LaunchTask> getLaunchTask();
|
||||||
@ -222,45 +213,30 @@ public:
|
|||||||
virtual QString typeName() const = 0;
|
virtual QString typeName() const = 0;
|
||||||
|
|
||||||
void updateRuntimeContext();
|
void updateRuntimeContext();
|
||||||
RuntimeContext runtimeContext() const
|
RuntimeContext runtimeContext() const { return m_runtimeContext; }
|
||||||
{
|
|
||||||
return m_runtimeContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasVersionBroken() const
|
bool hasVersionBroken() const { return m_hasBrokenVersion; }
|
||||||
{
|
|
||||||
return m_hasBrokenVersion;
|
|
||||||
}
|
|
||||||
void setVersionBroken(bool value)
|
void setVersionBroken(bool value)
|
||||||
{
|
{
|
||||||
if(m_hasBrokenVersion != value)
|
if (m_hasBrokenVersion != value) {
|
||||||
{
|
|
||||||
m_hasBrokenVersion = value;
|
m_hasBrokenVersion = value;
|
||||||
emit propertiesChanged(this);
|
emit propertiesChanged(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasUpdateAvailable() const
|
bool hasUpdateAvailable() const { return m_hasUpdate; }
|
||||||
{
|
|
||||||
return m_hasUpdate;
|
|
||||||
}
|
|
||||||
void setUpdateAvailable(bool value)
|
void setUpdateAvailable(bool value)
|
||||||
{
|
{
|
||||||
if(m_hasUpdate != value)
|
if (m_hasUpdate != value) {
|
||||||
{
|
|
||||||
m_hasUpdate = value;
|
m_hasUpdate = value;
|
||||||
emit propertiesChanged(this);
|
emit propertiesChanged(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasCrashed() const
|
bool hasCrashed() const { return m_crashed; }
|
||||||
{
|
|
||||||
return m_crashed;
|
|
||||||
}
|
|
||||||
void setCrashed(bool value)
|
void setCrashed(bool value)
|
||||||
{
|
{
|
||||||
if(m_crashed != value)
|
if (m_crashed != value) {
|
||||||
{
|
|
||||||
m_crashed = value;
|
m_crashed = value;
|
||||||
emit propertiesChanged(this);
|
emit propertiesChanged(this);
|
||||||
}
|
}
|
||||||
@ -288,7 +264,7 @@ public:
|
|||||||
bool removeLinkedInstanceId(const QString& id);
|
bool removeLinkedInstanceId(const QString& id);
|
||||||
bool isLinkedToInstanceId(const QString& id) const;
|
bool isLinkedToInstanceId(const QString& id) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void changeStatus(Status newStatus);
|
void changeStatus(Status newStatus);
|
||||||
|
|
||||||
SettingsObjectPtr globalSettings() const { return m_global_settings.lock(); };
|
SettingsObjectPtr globalSettings() const { return m_global_settings.lock(); };
|
||||||
@ -296,11 +272,11 @@ protected:
|
|||||||
bool isSpecificSettingsLoaded() const { return m_specific_settings_loaded; }
|
bool isSpecificSettingsLoaded() const { return m_specific_settings_loaded; }
|
||||||
void setSpecificSettingsLoaded(bool loaded) { m_specific_settings_loaded = loaded; }
|
void setSpecificSettingsLoaded(bool loaded) { m_specific_settings_loaded = loaded; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/*!
|
/*!
|
||||||
* \brief Signal emitted when properties relevant to the instance view change
|
* \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>);
|
void launchTaskChanged(shared_qobject_ptr<LaunchTask>);
|
||||||
|
|
||||||
@ -308,10 +284,10 @@ signals:
|
|||||||
|
|
||||||
void statusChanged(Status from, Status to);
|
void statusChanged(Status from, Status to);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void iconUpdated(QString key);
|
void iconUpdated(QString key);
|
||||||
|
|
||||||
protected: /* data */
|
protected: /* data */
|
||||||
QString m_rootDir;
|
QString m_rootDir;
|
||||||
SettingsObjectPtr m_settings;
|
SettingsObjectPtr m_settings;
|
||||||
// InstanceFlags m_flags;
|
// InstanceFlags m_flags;
|
||||||
@ -320,7 +296,7 @@ protected: /* data */
|
|||||||
QDateTime m_timeStarted;
|
QDateTime m_timeStarted;
|
||||||
RuntimeContext m_runtimeContext;
|
RuntimeContext m_runtimeContext;
|
||||||
|
|
||||||
private: /* data */
|
private: /* data */
|
||||||
Status m_status = Status::Present;
|
Status m_status = Status::Present;
|
||||||
bool m_crashed = false;
|
bool m_crashed = false;
|
||||||
bool m_hasUpdate = false;
|
bool m_hasUpdate = false;
|
||||||
@ -328,9 +304,8 @@ private: /* data */
|
|||||||
|
|
||||||
SettingsObjectWeakPtr m_global_settings;
|
SettingsObjectWeakPtr m_global_settings;
|
||||||
bool m_specific_settings_loaded = false;
|
bool m_specific_settings_loaded = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(shared_qobject_ptr<BaseInstance>)
|
Q_DECLARE_METATYPE(shared_qobject_ptr<BaseInstance>)
|
||||||
//Q_DECLARE_METATYPE(BaseInstance::InstanceFlag)
|
// Q_DECLARE_METATYPE(BaseInstance::InstanceFlag)
|
||||||
//Q_DECLARE_OPERATORS_FOR_FLAGS(BaseInstance::InstanceFlags)
|
// Q_DECLARE_OPERATORS_FOR_FLAGS(BaseInstance::InstanceFlags)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// 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 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -36,14 +36,11 @@
|
|||||||
#include "BaseVersionList.h"
|
#include "BaseVersionList.h"
|
||||||
#include "BaseVersion.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)
|
if (at(i)->descriptor() == descriptor)
|
||||||
return at(i);
|
return at(i);
|
||||||
}
|
}
|
||||||
@ -58,7 +55,7 @@ BaseVersion::Ptr BaseVersionList::getRecommended() const
|
|||||||
return at(0);
|
return at(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant BaseVersionList::data(const QModelIndex &index, int role) const
|
QVariant BaseVersionList::data(const QModelIndex& index, int role) const
|
||||||
{
|
{
|
||||||
if (!index.isValid())
|
if (!index.isValid())
|
||||||
return QVariant();
|
return QVariant();
|
||||||
@ -68,37 +65,36 @@ QVariant BaseVersionList::data(const QModelIndex &index, int role) const
|
|||||||
|
|
||||||
BaseVersion::Ptr version = at(index.row());
|
BaseVersion::Ptr version = at(index.row());
|
||||||
|
|
||||||
switch (role)
|
switch (role) {
|
||||||
{
|
case VersionPointerRole:
|
||||||
case VersionPointerRole:
|
return QVariant::fromValue(version);
|
||||||
return QVariant::fromValue(version);
|
|
||||||
|
|
||||||
case VersionRole:
|
case VersionRole:
|
||||||
return version->name();
|
return version->name();
|
||||||
|
|
||||||
case VersionIdRole:
|
case VersionIdRole:
|
||||||
return version->descriptor();
|
return version->descriptor();
|
||||||
|
|
||||||
case TypeRole:
|
case TypeRole:
|
||||||
return version->typeString();
|
return version->typeString();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseVersionList::RoleList BaseVersionList::providesRoles() 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 count
|
||||||
return parent.isValid() ? 0 : 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;
|
return parent.isValid() ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
@ -15,13 +15,13 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <QAbstractListModel>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <QAbstractListModel>
|
|
||||||
|
|
||||||
#include "BaseVersion.h"
|
#include "BaseVersion.h"
|
||||||
#include "tasks/Task.h"
|
|
||||||
#include "QObjectPtr.h"
|
#include "QObjectPtr.h"
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Class that each instance type's version list derives from.
|
* \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
|
* all have a default implementation, but they can be overridden by plugins to
|
||||||
* change the behavior of the list.
|
* change the behavior of the list.
|
||||||
*/
|
*/
|
||||||
class BaseVersionList : public QAbstractListModel
|
class BaseVersionList : public QAbstractListModel {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
enum ModelRoles
|
enum ModelRoles {
|
||||||
{
|
|
||||||
VersionPointerRole = Qt::UserRole,
|
VersionPointerRole = Qt::UserRole,
|
||||||
VersionRole,
|
VersionRole,
|
||||||
VersionIdRole,
|
VersionIdRole,
|
||||||
@ -55,7 +53,7 @@ public:
|
|||||||
};
|
};
|
||||||
typedef QList<int> RoleList;
|
typedef QList<int> RoleList;
|
||||||
|
|
||||||
explicit BaseVersionList(QObject *parent = 0);
|
explicit BaseVersionList(QObject* parent = 0);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Gets a task that will reload the version list.
|
* \brief Gets a task that will reload the version list.
|
||||||
@ -66,7 +64,7 @@ public:
|
|||||||
virtual Task::Ptr getLoadTask() = 0;
|
virtual Task::Ptr getLoadTask() = 0;
|
||||||
|
|
||||||
//! Checks whether or not the list is loaded. If this returns false, the list should be
|
//! Checks whether or not the list is loaded. If this returns false, the list should be
|
||||||
//loaded.
|
// loaded.
|
||||||
virtual bool isLoaded() = 0;
|
virtual bool isLoaded() = 0;
|
||||||
|
|
||||||
//! Gets the version at the given index.
|
//! Gets the version at the given index.
|
||||||
@ -76,9 +74,9 @@ public:
|
|||||||
virtual int count() const = 0;
|
virtual int count() const = 0;
|
||||||
|
|
||||||
//////// List Model Functions ////////
|
//////// List Model Functions ////////
|
||||||
QVariant data(const QModelIndex &index, int role) const override;
|
QVariant data(const QModelIndex& index, int role) const override;
|
||||||
int rowCount(const QModelIndex &parent) const override;
|
int rowCount(const QModelIndex& parent) const override;
|
||||||
int columnCount(const QModelIndex &parent) const override;
|
int columnCount(const QModelIndex& parent) const override;
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
//! which roles are provided by this version list?
|
//! 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
|
* \return A const pointer to the version with the given descriptor. NULL if
|
||||||
* one doesn't exist.
|
* 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
|
* \brief Gets the recommended version from this list
|
||||||
@ -103,8 +101,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual void sortVersions() = 0;
|
virtual void sortVersions() = 0;
|
||||||
|
|
||||||
protected
|
protected slots:
|
||||||
slots:
|
|
||||||
/*!
|
/*!
|
||||||
* Updates this list with the given list of versions.
|
* Updates this list with the given list of versions.
|
||||||
* This is done by copying each version in the given list and inserting it
|
* This is done by copying each version in the given list and inserting it
|
||||||
|
@ -272,8 +272,6 @@ set(MINECRAFT_SOURCES
|
|||||||
minecraft/launch/CreateGameFolders.h
|
minecraft/launch/CreateGameFolders.h
|
||||||
minecraft/launch/ModMinecraftJar.cpp
|
minecraft/launch/ModMinecraftJar.cpp
|
||||||
minecraft/launch/ModMinecraftJar.h
|
minecraft/launch/ModMinecraftJar.h
|
||||||
minecraft/launch/DirectJavaLaunch.cpp
|
|
||||||
minecraft/launch/DirectJavaLaunch.h
|
|
||||||
minecraft/launch/ExtractNatives.cpp
|
minecraft/launch/ExtractNatives.cpp
|
||||||
minecraft/launch/ExtractNatives.h
|
minecraft/launch/ExtractNatives.h
|
||||||
minecraft/launch/LauncherPartLaunch.cpp
|
minecraft/launch/LauncherPartLaunch.cpp
|
||||||
@ -511,6 +509,11 @@ set(FTB_SOURCES
|
|||||||
modplatform/legacy_ftb/PrivatePackManager.cpp
|
modplatform/legacy_ftb/PrivatePackManager.cpp
|
||||||
|
|
||||||
modplatform/legacy_ftb/PackHelpers.h
|
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
|
set(FLAME_SOURCES
|
||||||
@ -678,7 +681,7 @@ set(LOGIC_SOURCES
|
|||||||
${ATLAUNCHER_SOURCES}
|
${ATLAUNCHER_SOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE AND Launcher_ENABLE_UPDATER)
|
||||||
set (LOGIC_SOURCES ${LOGIC_SOURCES} ${MAC_UPDATE_SOURCES})
|
set (LOGIC_SOURCES ${LOGIC_SOURCES} ${MAC_UPDATE_SOURCES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -882,6 +885,11 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/pages/modplatform/legacy_ftb/ListModel.h
|
ui/pages/modplatform/legacy_ftb/ListModel.h
|
||||||
ui/pages/modplatform/legacy_ftb/ListModel.cpp
|
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.cpp
|
||||||
ui/pages/modplatform/flame/FlameModel.h
|
ui/pages/modplatform/flame/FlameModel.h
|
||||||
ui/pages/modplatform/flame/FlamePage.cpp
|
ui/pages/modplatform/flame/FlamePage.cpp
|
||||||
@ -1056,6 +1064,7 @@ qt_wrap_ui(LAUNCHER_UI
|
|||||||
ui/pages/modplatform/ResourcePage.ui
|
ui/pages/modplatform/ResourcePage.ui
|
||||||
ui/pages/modplatform/flame/FlamePage.ui
|
ui/pages/modplatform/flame/FlamePage.ui
|
||||||
ui/pages/modplatform/legacy_ftb/Page.ui
|
ui/pages/modplatform/legacy_ftb/Page.ui
|
||||||
|
ui/pages/modplatform/import_ftb/ImportFTBPage.ui
|
||||||
ui/pages/modplatform/ImportPage.ui
|
ui/pages/modplatform/ImportPage.ui
|
||||||
ui/pages/modplatform/modrinth/ModrinthPage.ui
|
ui/pages/modplatform/modrinth/ModrinthPage.ui
|
||||||
ui/pages/modplatform/technic/TechnicPage.ui
|
ui/pages/modplatform/technic/TechnicPage.ui
|
||||||
@ -1152,17 +1161,23 @@ if(APPLE)
|
|||||||
set(CMAKE_MACOSX_RPATH 1)
|
set(CMAKE_MACOSX_RPATH 1)
|
||||||
set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks/")
|
set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks/")
|
||||||
|
|
||||||
file(DOWNLOAD ${MACOSX_SPARKLE_DOWNLOAD_URL} ${CMAKE_BINARY_DIR}/Sparkle.tar.xz EXPECTED_HASH SHA256=${MACOSX_SPARKLE_SHA256})
|
if(Launcher_ENABLE_UPDATER)
|
||||||
file(ARCHIVE_EXTRACT INPUT ${CMAKE_BINARY_DIR}/Sparkle.tar.xz DESTINATION ${CMAKE_BINARY_DIR}/frameworks/Sparkle)
|
file(DOWNLOAD ${MACOSX_SPARKLE_DOWNLOAD_URL} ${CMAKE_BINARY_DIR}/Sparkle.tar.xz EXPECTED_HASH SHA256=${MACOSX_SPARKLE_SHA256})
|
||||||
|
file(ARCHIVE_EXTRACT INPUT ${CMAKE_BINARY_DIR}/Sparkle.tar.xz DESTINATION ${CMAKE_BINARY_DIR}/frameworks/Sparkle)
|
||||||
|
|
||||||
|
find_library(SPARKLE_FRAMEWORK Sparkle "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
|
||||||
|
add_compile_definitions(SPARKLE_ENABLED)
|
||||||
|
endif()
|
||||||
|
|
||||||
find_library(SPARKLE_FRAMEWORK Sparkle "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
|
|
||||||
target_link_libraries(Launcher_logic
|
target_link_libraries(Launcher_logic
|
||||||
"-framework AppKit"
|
"-framework AppKit"
|
||||||
"-framework Carbon"
|
"-framework Carbon"
|
||||||
"-framework Foundation"
|
"-framework Foundation"
|
||||||
"-framework ApplicationServices"
|
"-framework ApplicationServices"
|
||||||
)
|
)
|
||||||
target_link_libraries(Launcher_logic ${SPARKLE_FRAMEWORK})
|
if(Launcher_ENABLE_UPDATER)
|
||||||
|
target_link_libraries(Launcher_logic ${SPARKLE_FRAMEWORK})
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(Launcher_logic)
|
target_link_libraries(Launcher_logic)
|
||||||
@ -1224,7 +1239,7 @@ if(WIN32)
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (UNIX AND APPLE)
|
if (UNIX AND APPLE AND Launcher_ENABLE_UPDATER)
|
||||||
# Add Sparkle updater
|
# Add Sparkle updater
|
||||||
# It has to be copied here instead of just allowing fixup_bundle to install it, otherwise essential parts of
|
# It has to be copied here instead of just allowing fixup_bundle to install it, otherwise essential parts of
|
||||||
# the framework aren't installed
|
# the framework aren't installed
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// 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 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -41,8 +41,7 @@
|
|||||||
* @file libutil/src/cmdutils.cpp
|
* @file libutil/src/cmdutils.cpp
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Commandline
|
namespace Commandline {
|
||||||
{
|
|
||||||
|
|
||||||
// commandline splitter
|
// commandline splitter
|
||||||
QStringList splitArgs(QString args)
|
QStringList splitArgs(QString args)
|
||||||
@ -51,19 +50,15 @@ QStringList splitArgs(QString args)
|
|||||||
QString current;
|
QString current;
|
||||||
bool escape = false;
|
bool escape = false;
|
||||||
QChar inquotes;
|
QChar inquotes;
|
||||||
for (int i = 0; i < args.length(); i++)
|
for (int i = 0; i < args.length(); i++) {
|
||||||
{
|
|
||||||
QChar cchar = args.at(i);
|
QChar cchar = args.at(i);
|
||||||
|
|
||||||
// \ escaped
|
// \ escaped
|
||||||
if (escape)
|
if (escape) {
|
||||||
{
|
|
||||||
current += cchar;
|
current += cchar;
|
||||||
escape = false;
|
escape = false;
|
||||||
// in "quotes"
|
// in "quotes"
|
||||||
}
|
} else if (!inquotes.isNull()) {
|
||||||
else if (!inquotes.isNull())
|
|
||||||
{
|
|
||||||
if (cchar == '\\')
|
if (cchar == '\\')
|
||||||
escape = true;
|
escape = true;
|
||||||
else if (cchar == inquotes)
|
else if (cchar == inquotes)
|
||||||
@ -71,18 +66,13 @@ QStringList splitArgs(QString args)
|
|||||||
else
|
else
|
||||||
current += cchar;
|
current += cchar;
|
||||||
// otherwise
|
// otherwise
|
||||||
}
|
} else {
|
||||||
else
|
if (cchar == ' ') {
|
||||||
{
|
if (!current.isEmpty()) {
|
||||||
if (cchar == ' ')
|
|
||||||
{
|
|
||||||
if (!current.isEmpty())
|
|
||||||
{
|
|
||||||
argv << current;
|
argv << current;
|
||||||
current.clear();
|
current.clear();
|
||||||
}
|
}
|
||||||
}
|
} else if (cchar == '"' || cchar == '\'')
|
||||||
else if (cchar == '"' || cchar == '\'')
|
|
||||||
inquotes = cchar;
|
inquotes = cchar;
|
||||||
else
|
else
|
||||||
current += cchar;
|
current += cchar;
|
||||||
@ -92,4 +82,4 @@ QStringList splitArgs(QString args)
|
|||||||
argv << current;
|
argv << current;
|
||||||
return argv;
|
return argv;
|
||||||
}
|
}
|
||||||
}
|
} // namespace Commandline
|
||||||
|
@ -25,8 +25,7 @@
|
|||||||
* @brief commandline parsing and processing utilities
|
* @brief commandline parsing and processing utilities
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Commandline
|
namespace Commandline {
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief split a string into argv items like a shell would do
|
* @brief split a string into argv items like a shell would do
|
||||||
@ -34,4 +33,4 @@ namespace Commandline
|
|||||||
* @return a QStringList containing all arguments
|
* @return a QStringList containing all arguments
|
||||||
*/
|
*/
|
||||||
QStringList splitArgs(QString args);
|
QStringList splitArgs(QString args);
|
||||||
}
|
} // namespace Commandline
|
||||||
|
@ -1,33 +1,21 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class DefaultVariable
|
class DefaultVariable {
|
||||||
{
|
public:
|
||||||
public:
|
DefaultVariable(const T& value) { defaultValue = value; }
|
||||||
DefaultVariable(const T & value)
|
DefaultVariable<T>& operator=(const T& value)
|
||||||
{
|
|
||||||
defaultValue = value;
|
|
||||||
}
|
|
||||||
DefaultVariable<T> & operator =(const T & value)
|
|
||||||
{
|
{
|
||||||
currentValue = value;
|
currentValue = value;
|
||||||
is_default = currentValue == defaultValue;
|
is_default = currentValue == defaultValue;
|
||||||
is_explicit = true;
|
is_explicit = true;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
operator const T &() const
|
operator const T&() const { return is_default ? defaultValue : currentValue; }
|
||||||
{
|
bool isDefault() const { return is_default; }
|
||||||
return is_default ? defaultValue : currentValue;
|
bool isExplicit() const { return is_explicit; }
|
||||||
}
|
|
||||||
bool isDefault() const
|
private:
|
||||||
{
|
|
||||||
return is_default;
|
|
||||||
}
|
|
||||||
bool isExplicit() const
|
|
||||||
{
|
|
||||||
return is_explicit;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
T currentValue;
|
T currentValue;
|
||||||
T defaultValue;
|
T defaultValue;
|
||||||
bool is_default = true;
|
bool is_default = true;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
/*
|
/*
|
||||||
* PolyMC - Minecraft Launcher
|
* Prism Launcher - Minecraft Launcher
|
||||||
* Copyright (C) 2022 dada513 <dada513@protonmail.com>
|
* Copyright (C) 2022 dada513 <dada513@protonmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -33,40 +33,37 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
#include "DesktopServices.h"
|
#include "DesktopServices.h"
|
||||||
#include <QDir>
|
|
||||||
#include <QDesktopServices>
|
|
||||||
#include <QProcess>
|
|
||||||
#include <QDebug>
|
#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.
|
* 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)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool IndirectOpen(T callable, qint64 *pid_forked = nullptr)
|
bool IndirectOpen(T callable, qint64* pid_forked = nullptr)
|
||||||
{
|
{
|
||||||
auto pid = fork();
|
auto pid = fork();
|
||||||
if(pid_forked)
|
if (pid_forked) {
|
||||||
{
|
if (pid > 0)
|
||||||
if(pid > 0)
|
|
||||||
*pid_forked = pid;
|
*pid_forked = pid;
|
||||||
else
|
else
|
||||||
*pid_forked = 0;
|
*pid_forked = 0;
|
||||||
}
|
}
|
||||||
if(pid == -1)
|
if (pid == -1) {
|
||||||
{
|
|
||||||
qWarning() << "IndirectOpen failed to fork: " << errno;
|
qWarning() << "IndirectOpen failed to fork: " << errno;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// child - do the stuff
|
// child - do the stuff
|
||||||
if(pid == 0)
|
if (pid == 0) {
|
||||||
{
|
|
||||||
// unset all this garbage so it doesn't get passed to the child process
|
// unset all this garbage so it doesn't get passed to the child process
|
||||||
qunsetenv("LD_PRELOAD");
|
qunsetenv("LD_PRELOAD");
|
||||||
qunsetenv("LD_LIBRARY_PATH");
|
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.
|
// die. now. do not clean up anything, it would just hang forever.
|
||||||
_exit(status ? 0 : 1);
|
_exit(status ? 0 : 1);
|
||||||
}
|
} else {
|
||||||
else
|
// parent - assume it worked.
|
||||||
{
|
|
||||||
//parent - assume it worked.
|
|
||||||
int status;
|
int status;
|
||||||
while (waitpid(pid, &status, 0))
|
while (waitpid(pid, &status, 0)) {
|
||||||
{
|
if (WIFEXITED(status)) {
|
||||||
if(WIFEXITED(status))
|
|
||||||
{
|
|
||||||
return WEXITSTATUS(status) == 0;
|
return WEXITSTATUS(status) == 0;
|
||||||
}
|
}
|
||||||
if(WIFSIGNALED(status))
|
if (WIFSIGNALED(status)) {
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,26 +96,19 @@ bool IndirectOpen(T callable, qint64 *pid_forked = nullptr)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace DesktopServices {
|
namespace DesktopServices {
|
||||||
bool openDirectory(const QString &path, bool ensureExists)
|
bool openDirectory(const QString& path, bool ensureExists)
|
||||||
{
|
{
|
||||||
qDebug() << "Opening directory" << path;
|
qDebug() << "Opening directory" << path;
|
||||||
QDir parentPath;
|
QDir parentPath;
|
||||||
QDir dir(path);
|
QDir dir(path);
|
||||||
if (!dir.exists())
|
if (!dir.exists()) {
|
||||||
{
|
|
||||||
parentPath.mkpath(dir.absolutePath());
|
parentPath.mkpath(dir.absolutePath());
|
||||||
}
|
}
|
||||||
auto f = [&]()
|
auto f = [&]() { return QDesktopServices::openUrl(QUrl::fromLocalFile(dir.absolutePath())); };
|
||||||
{
|
|
||||||
return QDesktopServices::openUrl(QUrl::fromLocalFile(dir.absolutePath()));
|
|
||||||
};
|
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||||
if(!isFlatpak())
|
if (!isSandbox()) {
|
||||||
{
|
|
||||||
return IndirectOpen(f);
|
return IndirectOpen(f);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return f();
|
return f();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -131,20 +116,14 @@ bool openDirectory(const QString &path, bool ensureExists)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool openFile(const QString &path)
|
bool openFile(const QString& path)
|
||||||
{
|
{
|
||||||
qDebug() << "Opening file" << path;
|
qDebug() << "Opening file" << path;
|
||||||
auto f = [&]()
|
auto f = [&]() { return QDesktopServices::openUrl(QUrl::fromLocalFile(path)); };
|
||||||
{
|
|
||||||
return QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
|
||||||
};
|
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||||
if(!isFlatpak())
|
if (!isSandbox()) {
|
||||||
{
|
|
||||||
return IndirectOpen(f);
|
return IndirectOpen(f);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return f();
|
return f();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -152,41 +131,29 @@ bool openFile(const QString &path)
|
|||||||
#endif
|
#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;
|
qDebug() << "Opening file" << path << "using" << application;
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
#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
|
// FIXME: the pid here is fake. So if something depends on it, it will likely misbehave
|
||||||
if(!isFlatpak())
|
if (!isSandbox()) {
|
||||||
{
|
return IndirectOpen([&]() { return QProcess::startDetached(application, QStringList() << path, workingDirectory); }, pid);
|
||||||
return IndirectOpen([&]()
|
} else {
|
||||||
{
|
return QProcess::startDetached(application, QStringList() << path, workingDirectory, pid);
|
||||||
return QProcess::startDetached(application, QStringList() << path, workingDirectory);
|
|
||||||
}, pid);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return QProcess::startDetached(application, QStringList() << path, workingDirectory, pid);
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
return QProcess::startDetached(application, QStringList() << path, workingDirectory, pid);
|
return QProcess::startDetached(application, QStringList() << path, workingDirectory, pid);
|
||||||
#endif
|
#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(' ');
|
qDebug() << "Running" << application << "with args" << args.join(' ');
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
#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
|
||||||
// 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);
|
||||||
return IndirectOpen([&]()
|
} else {
|
||||||
{
|
|
||||||
return QProcess::startDetached(application, args, workingDirectory);
|
|
||||||
}, pid);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return QProcess::startDetached(application, args, workingDirectory, pid);
|
return QProcess::startDetached(application, args, workingDirectory, pid);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -194,20 +161,14 @@ bool run(const QString &application, const QStringList &args, const QString &wor
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool openUrl(const QUrl &url)
|
bool openUrl(const QUrl& url)
|
||||||
{
|
{
|
||||||
qDebug() << "Opening URL" << url.toString();
|
qDebug() << "Opening URL" << url.toString();
|
||||||
auto f = [&]()
|
auto f = [&]() { return QDesktopServices::openUrl(url); };
|
||||||
{
|
|
||||||
return QDesktopServices::openUrl(url);
|
|
||||||
};
|
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||||
if(!isFlatpak())
|
if (!isSandbox()) {
|
||||||
{
|
|
||||||
return IndirectOpen(f);
|
return IndirectOpen(f);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return f();
|
return f();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -224,4 +185,18 @@ bool isFlatpak()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isSnap()
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
return getenv("SNAP");
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isSandbox()
|
||||||
|
{
|
||||||
|
return isSnap() || isFlatpak();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace DesktopServices
|
||||||
|
@ -1,38 +1,50 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QUrl>
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This wraps around QDesktopServices and adds workarounds where needed
|
* This wraps around QDesktopServices and adds workarounds where needed
|
||||||
* Use this instead of QDesktopServices!
|
* Use this instead of QDesktopServices!
|
||||||
*/
|
*/
|
||||||
namespace DesktopServices
|
namespace DesktopServices {
|
||||||
{
|
/**
|
||||||
/**
|
* Open a file in whatever application is applicable
|
||||||
* 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
|
* 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
|
* 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
|
* 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.
|
* 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
|
||||||
|
@ -2,31 +2,18 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QString>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
|
||||||
class Exception : public std::exception
|
class Exception : public std::exception {
|
||||||
{
|
public:
|
||||||
public:
|
Exception(const QString& message) : std::exception(), m_message(message) { qCritical() << "Exception:" << message; }
|
||||||
Exception(const QString &message) : std::exception(), m_message(message)
|
Exception(const Exception& other) : std::exception(), m_message(other.cause()) {}
|
||||||
{
|
|
||||||
qCritical() << "Exception:" << message;
|
|
||||||
}
|
|
||||||
Exception(const Exception &other)
|
|
||||||
: std::exception(), m_message(other.cause())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
virtual ~Exception() noexcept {}
|
virtual ~Exception() noexcept {}
|
||||||
const char *what() const noexcept
|
const char* what() const noexcept { return m_message.toLatin1().constData(); }
|
||||||
{
|
QString cause() const { return m_message; }
|
||||||
return m_message.toLatin1().constData();
|
|
||||||
}
|
|
||||||
QString cause() const
|
|
||||||
{
|
|
||||||
return m_message;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_message;
|
QString m_message;
|
||||||
};
|
};
|
||||||
|
@ -4,31 +4,24 @@
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
inline void clamp(T& current, T min, T max)
|
inline void clamp(T& current, T min, T max)
|
||||||
{
|
{
|
||||||
if (current < min)
|
if (current < min) {
|
||||||
{
|
|
||||||
current = min;
|
current = min;
|
||||||
}
|
} else if (current > max) {
|
||||||
else if(current > max)
|
|
||||||
{
|
|
||||||
current = max;
|
current = max;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// List of numbers from min to max. Next is exponent times bigger than previous.
|
// List of numbers from min to max. Next is exponent times bigger than previous.
|
||||||
|
|
||||||
class ExponentialSeries
|
class ExponentialSeries {
|
||||||
{
|
public:
|
||||||
public:
|
|
||||||
ExponentialSeries(unsigned min, unsigned max, unsigned exponent = 2)
|
ExponentialSeries(unsigned min, unsigned max, unsigned exponent = 2)
|
||||||
{
|
{
|
||||||
m_current = m_min = min;
|
m_current = m_min = min;
|
||||||
m_max = max;
|
m_max = max;
|
||||||
m_exponent = exponent;
|
m_exponent = exponent;
|
||||||
}
|
}
|
||||||
void reset()
|
void reset() { m_current = m_min; }
|
||||||
{
|
|
||||||
m_current = m_min;
|
|
||||||
}
|
|
||||||
unsigned operator()()
|
unsigned operator()()
|
||||||
{
|
{
|
||||||
unsigned retval = m_current;
|
unsigned retval = m_current;
|
||||||
|
@ -779,7 +779,8 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
|
|||||||
}
|
}
|
||||||
#if defined(Q_OS_MACOS)
|
#if defined(Q_OS_MACOS)
|
||||||
// Create the Application
|
// 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(".")) {
|
if (!applicationDirectory.mkpath(".")) {
|
||||||
qWarning() << "Couldn't create application directory";
|
qWarning() << "Couldn't create application directory";
|
||||||
@ -843,7 +844,9 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
|
|||||||
" <key>CFBundleIconFile</key>\n"
|
" <key>CFBundleIconFile</key>\n"
|
||||||
" <string>Icon.icns</string>\n"
|
" <string>Icon.icns</string>\n"
|
||||||
" <key>CFBundleName</key>\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"
|
" <key>CFBundlePackageType</key>\n"
|
||||||
" <string>APPL</string>\n"
|
" <string>APPL</string>\n"
|
||||||
" <key>CFBundleShortVersionString</key>\n"
|
" <key>CFBundleShortVersionString</key>\n"
|
||||||
|
@ -43,10 +43,10 @@
|
|||||||
#include <system_error>
|
#include <system_error>
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QPair>
|
|
||||||
#include <QFlags>
|
#include <QFlags>
|
||||||
#include <QLocalServer>
|
#include <QLocalServer>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QPair>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
|
||||||
namespace FS {
|
namespace FS {
|
||||||
@ -365,25 +365,24 @@ enum class FilesystemType {
|
|||||||
* QMap is ordered
|
* QMap is ordered
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static const QMap<FilesystemType, QStringList> s_filesystem_type_names = {
|
static const QMap<FilesystemType, QStringList> s_filesystem_type_names = { { FilesystemType::FAT, { "FAT" } },
|
||||||
{FilesystemType::FAT, { "FAT" }},
|
{ FilesystemType::NTFS, { "NTFS" } },
|
||||||
{FilesystemType::NTFS, { "NTFS" }},
|
{ FilesystemType::REFS, { "REFS" } },
|
||||||
{FilesystemType::REFS, { "REFS" }},
|
{ FilesystemType::EXT_2_OLD, { "EXT_2_OLD", "EXT2_OLD" } },
|
||||||
{FilesystemType::EXT_2_OLD, { "EXT_2_OLD", "EXT2_OLD" }},
|
{ FilesystemType::EXT_2_3_4,
|
||||||
{FilesystemType::EXT_2_3_4, { "EXT2/3/4", "EXT_2_3_4", "EXT2", "EXT3", "EXT4" }},
|
{ "EXT2/3/4", "EXT_2_3_4", "EXT2", "EXT3", "EXT4" } },
|
||||||
{FilesystemType::EXT, { "EXT" }},
|
{ FilesystemType::EXT, { "EXT" } },
|
||||||
{FilesystemType::XFS, { "XFS" }},
|
{ FilesystemType::XFS, { "XFS" } },
|
||||||
{FilesystemType::BTRFS, { "BTRFS" }},
|
{ FilesystemType::BTRFS, { "BTRFS" } },
|
||||||
{FilesystemType::NFS, { "NFS" }},
|
{ FilesystemType::NFS, { "NFS" } },
|
||||||
{FilesystemType::ZFS, { "ZFS" }},
|
{ FilesystemType::ZFS, { "ZFS" } },
|
||||||
{FilesystemType::APFS, { "APFS" }},
|
{ FilesystemType::APFS, { "APFS" } },
|
||||||
{FilesystemType::HFS, { "HFS" }},
|
{ FilesystemType::HFS, { "HFS" } },
|
||||||
{FilesystemType::HFSPLUS, { "HFSPLUS" }},
|
{ FilesystemType::HFSPLUS, { "HFSPLUS" } },
|
||||||
{FilesystemType::HFSX, { "HFSX" }},
|
{ FilesystemType::HFSX, { "HFSX" } },
|
||||||
{FilesystemType::FUSEBLK, { "FUSEBLK" }},
|
{ FilesystemType::FUSEBLK, { "FUSEBLK" } },
|
||||||
{FilesystemType::F2FS, { "F2FS" }},
|
{ FilesystemType::F2FS, { "F2FS" } },
|
||||||
{FilesystemType::UNKNOWN, { "UNKNOWN" }}
|
{ FilesystemType::UNKNOWN, { "UNKNOWN" } } };
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the string name of Filesystem enum object
|
* @brief Get the string name of Filesystem enum object
|
||||||
|
@ -1,28 +1,27 @@
|
|||||||
#include "Filter.h"
|
#include "Filter.h"
|
||||||
|
|
||||||
Filter::~Filter(){}
|
Filter::~Filter() {}
|
||||||
|
|
||||||
ContainsFilter::ContainsFilter(const QString& pattern) : pattern(pattern){}
|
ContainsFilter::ContainsFilter(const QString& pattern) : pattern(pattern) {}
|
||||||
ContainsFilter::~ContainsFilter(){}
|
ContainsFilter::~ContainsFilter() {}
|
||||||
bool ContainsFilter::accepts(const QString& value)
|
bool ContainsFilter::accepts(const QString& value)
|
||||||
{
|
{
|
||||||
return value.contains(pattern);
|
return value.contains(pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactFilter::ExactFilter(const QString& pattern) : pattern(pattern){}
|
ExactFilter::ExactFilter(const QString& pattern) : pattern(pattern) {}
|
||||||
ExactFilter::~ExactFilter(){}
|
ExactFilter::~ExactFilter() {}
|
||||||
bool ExactFilter::accepts(const QString& value)
|
bool ExactFilter::accepts(const QString& value)
|
||||||
{
|
{
|
||||||
return value == pattern;
|
return value == pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegexpFilter::RegexpFilter(const QString& regexp, bool invert)
|
RegexpFilter::RegexpFilter(const QString& regexp, bool invert) : invert(invert)
|
||||||
:invert(invert)
|
|
||||||
{
|
{
|
||||||
pattern.setPattern(regexp);
|
pattern.setPattern(regexp);
|
||||||
pattern.optimize();
|
pattern.optimize();
|
||||||
}
|
}
|
||||||
RegexpFilter::~RegexpFilter(){}
|
RegexpFilter::~RegexpFilter() {}
|
||||||
bool RegexpFilter::accepts(const QString& value)
|
bool RegexpFilter::accepts(const QString& value)
|
||||||
{
|
{
|
||||||
auto match = pattern.match(value);
|
auto match = pattern.match(value);
|
||||||
|
@ -1,42 +1,41 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
class Filter
|
class Filter {
|
||||||
{
|
public:
|
||||||
public:
|
|
||||||
virtual ~Filter();
|
virtual ~Filter();
|
||||||
virtual bool accepts(const QString & value) = 0;
|
virtual bool accepts(const QString& value) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ContainsFilter: public Filter
|
class ContainsFilter : public Filter {
|
||||||
{
|
public:
|
||||||
public:
|
ContainsFilter(const QString& pattern);
|
||||||
ContainsFilter(const QString &pattern);
|
|
||||||
virtual ~ContainsFilter();
|
virtual ~ContainsFilter();
|
||||||
bool accepts(const QString & value) override;
|
bool accepts(const QString& value) override;
|
||||||
private:
|
|
||||||
|
private:
|
||||||
QString pattern;
|
QString pattern;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExactFilter: public Filter
|
class ExactFilter : public Filter {
|
||||||
{
|
public:
|
||||||
public:
|
ExactFilter(const QString& pattern);
|
||||||
ExactFilter(const QString &pattern);
|
|
||||||
virtual ~ExactFilter();
|
virtual ~ExactFilter();
|
||||||
bool accepts(const QString & value) override;
|
bool accepts(const QString& value) override;
|
||||||
private:
|
|
||||||
|
private:
|
||||||
QString pattern;
|
QString pattern;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RegexpFilter: public Filter
|
class RegexpFilter : public Filter {
|
||||||
{
|
public:
|
||||||
public:
|
RegexpFilter(const QString& regexp, bool invert);
|
||||||
RegexpFilter(const QString ®exp, bool invert);
|
|
||||||
virtual ~RegexpFilter();
|
virtual ~RegexpFilter();
|
||||||
bool accepts(const QString & value) override;
|
bool accepts(const QString& value) override;
|
||||||
private:
|
|
||||||
|
private:
|
||||||
QRegularExpression pattern;
|
QRegularExpression pattern;
|
||||||
bool invert = false;
|
bool invert = false;
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// 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 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -37,10 +37,9 @@
|
|||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include <QByteArray>
|
#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;
|
uncompressedBytes = compressedBytes;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -51,42 +50,37 @@ bool GZip::unzip(const QByteArray &compressedBytes, QByteArray &uncompressedByte
|
|||||||
|
|
||||||
z_stream strm;
|
z_stream strm;
|
||||||
memset(&strm, 0, sizeof(strm));
|
memset(&strm, 0, sizeof(strm));
|
||||||
strm.next_in = (Bytef *)compressedBytes.data();
|
strm.next_in = (Bytef*)compressedBytes.data();
|
||||||
strm.avail_in = compressedBytes.size();
|
strm.avail_in = compressedBytes.size();
|
||||||
|
|
||||||
bool done = false;
|
bool done = false;
|
||||||
|
|
||||||
if (inflateInit2(&strm, (16 + MAX_WBITS)) != Z_OK)
|
if (inflateInit2(&strm, (16 + MAX_WBITS)) != Z_OK) {
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int err = Z_OK;
|
int err = Z_OK;
|
||||||
|
|
||||||
while (!done)
|
while (!done) {
|
||||||
{
|
|
||||||
// If our output buffer is too small
|
// If our output buffer is too small
|
||||||
if (strm.total_out >= uncompLength)
|
if (strm.total_out >= uncompLength) {
|
||||||
{
|
|
||||||
uncompressedBytes.resize(uncompLength * 2);
|
uncompressedBytes.resize(uncompLength * 2);
|
||||||
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;
|
strm.avail_out = uncompLength - strm.total_out;
|
||||||
|
|
||||||
// Inflate another chunk.
|
// Inflate another chunk.
|
||||||
err = inflate(&strm, Z_SYNC_FLUSH);
|
err = inflate(&strm, Z_SYNC_FLUSH);
|
||||||
if (err == Z_STREAM_END)
|
if (err == Z_STREAM_END)
|
||||||
done = true;
|
done = true;
|
||||||
else if (err != Z_OK)
|
else if (err != Z_OK) {
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inflateEnd(&strm) != Z_OK || !done)
|
if (inflateEnd(&strm) != Z_OK || !done) {
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,10 +88,9 @@ bool GZip::unzip(const QByteArray &compressedBytes, QByteArray &uncompressedByte
|
|||||||
return true;
|
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;
|
compressedBytes = uncompressedBytes;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -109,8 +102,7 @@ bool GZip::zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes)
|
|||||||
z_stream zs;
|
z_stream zs;
|
||||||
memset(&zs, 0, sizeof(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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,11 +114,9 @@ bool GZip::zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes)
|
|||||||
|
|
||||||
unsigned offset = 0;
|
unsigned offset = 0;
|
||||||
unsigned temp = 0;
|
unsigned temp = 0;
|
||||||
do
|
do {
|
||||||
{
|
|
||||||
auto remaining = compressedBytes.size() - offset;
|
auto remaining = compressedBytes.size() - offset;
|
||||||
if(remaining < 1)
|
if (remaining < 1) {
|
||||||
{
|
|
||||||
compressedBytes.resize(compressedBytes.size() * 2);
|
compressedBytes.resize(compressedBytes.size() * 2);
|
||||||
}
|
}
|
||||||
zs.next_out = reinterpret_cast<Bytef*>((compressedBytes.data() + offset));
|
zs.next_out = reinterpret_cast<Bytef*>((compressedBytes.data() + offset));
|
||||||
@ -137,13 +127,11 @@ bool GZip::zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes)
|
|||||||
|
|
||||||
compressedBytes.resize(offset);
|
compressedBytes.resize(offset);
|
||||||
|
|
||||||
if (deflateEnd(&zs) != Z_OK)
|
if (deflateEnd(&zs) != Z_OK) {
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret != Z_STREAM_END)
|
if (ret != Z_STREAM_END) {
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
|
|
||||||
class GZip
|
class GZip {
|
||||||
{
|
public:
|
||||||
public:
|
static bool unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes);
|
||||||
static bool unzip(const QByteArray &compressedBytes, QByteArray &uncompressedBytes);
|
static bool zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes);
|
||||||
static bool zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6,17 +6,10 @@
|
|||||||
|
|
||||||
bool InstanceCopyPrefs::allTrue() const
|
bool InstanceCopyPrefs::allTrue() const
|
||||||
{
|
{
|
||||||
return copySaves &&
|
return copySaves && keepPlaytime && copyGameOptions && copyResourcePacks && copyShaderPacks && copyServers && copyMods &&
|
||||||
keepPlaytime &&
|
copyScreenshots;
|
||||||
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")
|
// Returns a single RegEx string of the selected folders/files to filter out (ex: ".minecraft/saves|.minecraft/server.dat")
|
||||||
QString InstanceCopyPrefs::getSelectedFiltersAsRegex() const
|
QString InstanceCopyPrefs::getSelectedFiltersAsRegex() const
|
||||||
{
|
{
|
||||||
@ -26,25 +19,30 @@ QString InstanceCopyPrefs::getSelectedFiltersAsRegex(const QStringList& addition
|
|||||||
{
|
{
|
||||||
QStringList filters;
|
QStringList filters;
|
||||||
|
|
||||||
if(!copySaves)
|
if (!copySaves)
|
||||||
filters << "saves";
|
filters << "saves";
|
||||||
|
|
||||||
if(!copyGameOptions)
|
if (!copyGameOptions)
|
||||||
filters << "options.txt";
|
filters << "options.txt";
|
||||||
|
|
||||||
if(!copyResourcePacks)
|
if (!copyResourcePacks)
|
||||||
filters << "resourcepacks" << "texturepacks";
|
filters << "resourcepacks"
|
||||||
|
<< "texturepacks";
|
||||||
|
|
||||||
if(!copyShaderPacks)
|
if (!copyShaderPacks)
|
||||||
filters << "shaderpacks";
|
filters << "shaderpacks";
|
||||||
|
|
||||||
if(!copyServers)
|
if (!copyServers)
|
||||||
filters << "servers.dat" << "servers.dat_old" << "server-resource-packs";
|
filters << "servers.dat"
|
||||||
|
<< "servers.dat_old"
|
||||||
|
<< "server-resource-packs";
|
||||||
|
|
||||||
if(!copyMods)
|
if (!copyMods)
|
||||||
filters << "coremods" << "mods" << "config";
|
filters << "coremods"
|
||||||
|
<< "mods"
|
||||||
|
<< "config";
|
||||||
|
|
||||||
if(!copyScreenshots)
|
if (!copyScreenshots)
|
||||||
filters << "screenshots";
|
filters << "screenshots";
|
||||||
|
|
||||||
for (auto filter : additionalFilters) {
|
for (auto filter : additionalFilters) {
|
||||||
|
@ -40,7 +40,7 @@ struct InstanceCopyPrefs {
|
|||||||
void enableDontLinkSaves(bool b);
|
void enableDontLinkSaves(bool b);
|
||||||
void enableUseClone(bool b);
|
void enableUseClone(bool b);
|
||||||
|
|
||||||
protected: // data
|
protected: // data
|
||||||
bool copySaves = true;
|
bool copySaves = true;
|
||||||
bool keepPlaytime = true;
|
bool keepPlaytime = true;
|
||||||
bool copyGameOptions = true;
|
bool copyGameOptions = true;
|
||||||
|
@ -156,8 +156,9 @@ void InstanceCopyTask::copyFinished()
|
|||||||
allowed_symlinks.append(m_origInstance->gameRoot().toUtf8());
|
allowed_symlinks.append(m_origInstance->gameRoot().toUtf8());
|
||||||
allowed_symlinks.append("\n");
|
allowed_symlinks.append("\n");
|
||||||
if (allowed_symlinks_file.isSymLink())
|
if (allowed_symlinks_file.isSymLink())
|
||||||
FS::deletePath(allowed_symlinks_file
|
FS::deletePath(
|
||||||
.filePath()); // we dont want to modify the original. also make sure the resulting file is not itself a link.
|
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);
|
FS::write(allowed_symlinks_file.filePath(), allowed_symlinks);
|
||||||
}
|
}
|
||||||
|
@ -11,19 +11,18 @@
|
|||||||
#include "settings/SettingsObject.h"
|
#include "settings/SettingsObject.h"
|
||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
class InstanceCopyTask : public InstanceTask
|
class InstanceCopyTask : public InstanceTask {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit InstanceCopyTask(InstancePtr origInstance, const InstanceCopyPrefs& prefs);
|
explicit InstanceCopyTask(InstancePtr origInstance, const InstanceCopyPrefs& prefs);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//! Entry point for tasks.
|
//! Entry point for tasks.
|
||||||
virtual void executeTask() override;
|
virtual void executeTask() override;
|
||||||
void copyFinished();
|
void copyFinished();
|
||||||
void copyAborted();
|
void copyAborted();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* data */
|
/* data */
|
||||||
InstancePtr m_origInstance;
|
InstancePtr m_origInstance;
|
||||||
QFuture<bool> m_copyFuture;
|
QFuture<bool> m_copyFuture;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// 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 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
|
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
|
||||||
*
|
*
|
||||||
@ -45,9 +45,9 @@
|
|||||||
#include "icons/IconList.h"
|
#include "icons/IconList.h"
|
||||||
#include "icons/IconUtils.h"
|
#include "icons/IconUtils.h"
|
||||||
|
|
||||||
#include "modplatform/technic/TechnicPackProcessor.h"
|
|
||||||
#include "modplatform/modrinth/ModrinthInstanceCreationTask.h"
|
|
||||||
#include "modplatform/flame/FlameInstanceCreationTask.h"
|
#include "modplatform/flame/FlameInstanceCreationTask.h"
|
||||||
|
#include "modplatform/modrinth/ModrinthInstanceCreationTask.h"
|
||||||
|
#include "modplatform/technic/TechnicPackProcessor.h"
|
||||||
|
|
||||||
#include "settings/INISettingsObject.h"
|
#include "settings/INISettingsObject.h"
|
||||||
|
|
||||||
@ -140,8 +140,7 @@ void InstanceImportTask::processZipPack()
|
|||||||
|
|
||||||
// open the zip and find relevant files in it
|
// open the zip and find relevant files in it
|
||||||
m_packZip.reset(new QuaZip(m_archivePath));
|
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."));
|
emitFailed(tr("Unable to open supplied modpack zip file."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -155,44 +154,40 @@ void InstanceImportTask::processZipPack()
|
|||||||
|
|
||||||
// NOTE: Prioritize modpack platforms that aren't searched for recursively.
|
// 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
|
// 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
|
// process as Modrinth pack
|
||||||
qDebug() << "Modrinth:" << modrinthFound;
|
qDebug() << "Modrinth:" << modrinthFound;
|
||||||
m_modpackType = ModpackType::Modrinth;
|
m_modpackType = ModpackType::Modrinth;
|
||||||
}
|
} else if (technicFound) {
|
||||||
else if (technicFound)
|
|
||||||
{
|
|
||||||
// process as Technic pack
|
// process as Technic pack
|
||||||
qDebug() << "Technic:" << technicFound;
|
qDebug() << "Technic:" << technicFound;
|
||||||
extractDir.mkpath(".minecraft");
|
extractDir.mkpath(".minecraft");
|
||||||
extractDir.cd(".minecraft");
|
extractDir.cd(".minecraft");
|
||||||
m_modpackType = ModpackType::Technic;
|
m_modpackType = ModpackType::Technic;
|
||||||
}
|
} else {
|
||||||
else
|
QStringList paths_to_ignore{ "overrides/" };
|
||||||
{
|
|
||||||
QStringList paths_to_ignore { "overrides/" };
|
|
||||||
|
|
||||||
if (QString mmcRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "instance.cfg", paths_to_ignore); !mmcRoot.isNull()) {
|
if (QString mmcRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "instance.cfg", paths_to_ignore); !mmcRoot.isNull()) {
|
||||||
// process as MultiMC instance/pack
|
// process as MultiMC instance/pack
|
||||||
qDebug() << "MultiMC:" << mmcRoot;
|
qDebug() << "MultiMC:" << mmcRoot;
|
||||||
root = mmcRoot;
|
root = mmcRoot;
|
||||||
m_modpackType = ModpackType::MultiMC;
|
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
|
// process as Flame pack
|
||||||
qDebug() << "Flame:" << flameRoot;
|
qDebug() << "Flame:" << flameRoot;
|
||||||
root = flameRoot;
|
root = flameRoot;
|
||||||
m_modpackType = ModpackType::Flame;
|
m_modpackType = ModpackType::Flame;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(m_modpackType == ModpackType::Unknown)
|
if (m_modpackType == ModpackType::Unknown) {
|
||||||
{
|
|
||||||
emitFailed(tr("Archive does not contain a recognized modpack type."));
|
emitFailed(tr("Archive does not contain a recognized modpack type."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure we extract just the pack
|
// 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);
|
connect(&m_extractFutureWatcher, &QFutureWatcher<QStringList>::finished, this, &InstanceImportTask::extractFinished);
|
||||||
m_extractFutureWatcher.setFuture(m_extractFuture);
|
m_extractFutureWatcher.setFuture(m_extractFuture);
|
||||||
}
|
}
|
||||||
@ -212,37 +207,28 @@ void InstanceImportTask::extractFinished()
|
|||||||
|
|
||||||
qDebug() << "Fixing permissions for extracted pack files...";
|
qDebug() << "Fixing permissions for extracted pack files...";
|
||||||
QDirIterator it(extractDir, QDirIterator::Subdirectories);
|
QDirIterator it(extractDir, QDirIterator::Subdirectories);
|
||||||
while (it.hasNext())
|
while (it.hasNext()) {
|
||||||
{
|
|
||||||
auto filepath = it.next();
|
auto filepath = it.next();
|
||||||
QFileInfo file(filepath);
|
QFileInfo file(filepath);
|
||||||
auto permissions = QFile::permissions(filepath);
|
auto permissions = QFile::permissions(filepath);
|
||||||
auto origPermissions = permissions;
|
auto origPermissions = permissions;
|
||||||
if(file.isDir())
|
if (file.isDir()) {
|
||||||
{
|
|
||||||
// Folder +rwx for current user
|
// Folder +rwx for current user
|
||||||
permissions |= QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser | QFileDevice::Permission::ExeUser;
|
permissions |= QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser | QFileDevice::Permission::ExeUser;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// File +rw for current user
|
// File +rw for current user
|
||||||
permissions |= QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser;
|
permissions |= QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser;
|
||||||
}
|
}
|
||||||
if(origPermissions != permissions)
|
if (origPermissions != permissions) {
|
||||||
{
|
if (!QFile::setPermissions(filepath, permissions)) {
|
||||||
if(!QFile::setPermissions(filepath, permissions))
|
|
||||||
{
|
|
||||||
logWarning(tr("Could not fix permissions for %1").arg(filepath));
|
logWarning(tr("Could not fix permissions for %1").arg(filepath));
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
qDebug() << "Fixed" << filepath;
|
qDebug() << "Fixed" << filepath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(m_modpackType)
|
switch (m_modpackType) {
|
||||||
{
|
|
||||||
case ModpackType::MultiMC:
|
case ModpackType::MultiMC:
|
||||||
processMultiMC();
|
processMultiMC();
|
||||||
return;
|
return;
|
||||||
@ -278,7 +264,8 @@ void InstanceImportTask::processFlame()
|
|||||||
if (original_instance_id_it != m_extra_info.constEnd())
|
if (original_instance_id_it != m_extra_info.constEnd())
|
||||||
original_instance_id = original_instance_id_it.value();
|
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 {
|
} else {
|
||||||
// FIXME: Find a way to get IDs in directly imported ZIPs
|
// FIXME: Find a way to get IDs in directly imported ZIPs
|
||||||
inst_creation_task = makeShared<FlameCreationTask>(m_stagingPath, m_globalSettings, m_parent, QString(), QString());
|
inst_creation_task = makeShared<FlameCreationTask>(m_stagingPath, m_globalSettings, m_parent, QString(), QString());
|
||||||
@ -364,7 +351,8 @@ void InstanceImportTask::processModrinth()
|
|||||||
if (original_instance_id_it != m_extra_info.constEnd())
|
if (original_instance_id_it != m_extra_info.constEnd())
|
||||||
original_instance_id = original_instance_id_it.value();
|
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 {
|
} else {
|
||||||
QString pack_id;
|
QString pack_id;
|
||||||
if (!m_sourceUrl.isEmpty()) {
|
if (!m_sourceUrl.isEmpty()) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// 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 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -35,54 +35,49 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "InstanceTask.h"
|
|
||||||
#include "net/NetJob.h"
|
|
||||||
#include <QUrl>
|
|
||||||
#include <QFuture>
|
#include <QFuture>
|
||||||
#include <QFutureWatcher>
|
#include <QFutureWatcher>
|
||||||
#include "settings/SettingsObject.h"
|
#include <QUrl>
|
||||||
|
#include "InstanceTask.h"
|
||||||
#include "QObjectPtr.h"
|
#include "QObjectPtr.h"
|
||||||
#include "modplatform/flame/PackManifest.h"
|
#include "modplatform/flame/PackManifest.h"
|
||||||
|
#include "net/NetJob.h"
|
||||||
|
#include "settings/SettingsObject.h"
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
class QuaZip;
|
class QuaZip;
|
||||||
namespace Flame
|
namespace Flame {
|
||||||
{
|
class FileResolvingTask;
|
||||||
class FileResolvingTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class InstanceImportTask : public InstanceTask
|
class InstanceImportTask : public InstanceTask {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit InstanceImportTask(const QUrl sourceUrl, QWidget* parent = nullptr, QMap<QString, QString>&& extra_info = {});
|
explicit InstanceImportTask(const QUrl sourceUrl, QWidget* parent = nullptr, QMap<QString, QString>&& extra_info = {});
|
||||||
|
|
||||||
bool abort() override;
|
bool abort() override;
|
||||||
const QVector<Flame::File> &getBlockedFiles() const
|
const QVector<Flame::File>& getBlockedFiles() const { return m_blockedMods; }
|
||||||
{
|
|
||||||
return m_blockedMods;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//! Entry point for tasks.
|
//! Entry point for tasks.
|
||||||
virtual void executeTask() override;
|
virtual void executeTask() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void processZipPack();
|
void processZipPack();
|
||||||
void processMultiMC();
|
void processMultiMC();
|
||||||
void processTechnic();
|
void processTechnic();
|
||||||
void processFlame();
|
void processFlame();
|
||||||
void processModrinth();
|
void processModrinth();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void downloadSucceeded();
|
void downloadSucceeded();
|
||||||
void downloadFailed(QString reason);
|
void downloadFailed(QString reason);
|
||||||
void downloadProgressChanged(qint64 current, qint64 total);
|
void downloadProgressChanged(qint64 current, qint64 total);
|
||||||
void downloadAborted();
|
void downloadAborted();
|
||||||
void extractFinished();
|
void extractFinished();
|
||||||
|
|
||||||
private: /* data */
|
private: /* data */
|
||||||
NetJob::Ptr m_filesNetJob;
|
NetJob::Ptr m_filesNetJob;
|
||||||
shared_qobject_ptr<Flame::FileResolvingTask> m_modIdResolver;
|
shared_qobject_ptr<Flame::FileResolvingTask> m_modIdResolver;
|
||||||
QUrl m_sourceUrl;
|
QUrl m_sourceUrl;
|
||||||
@ -92,7 +87,7 @@ private: /* data */
|
|||||||
QFuture<std::optional<QStringList>> m_extractFuture;
|
QFuture<std::optional<QStringList>> m_extractFuture;
|
||||||
QFutureWatcher<std::optional<QStringList>> m_extractFutureWatcher;
|
QFutureWatcher<std::optional<QStringList>> m_extractFutureWatcher;
|
||||||
QVector<Flame::File> m_blockedMods;
|
QVector<Flame::File> m_blockedMods;
|
||||||
enum class ModpackType{
|
enum class ModpackType {
|
||||||
Unknown,
|
Unknown,
|
||||||
MultiMC,
|
MultiMC,
|
||||||
Technic,
|
Technic,
|
||||||
@ -104,6 +99,6 @@ private: /* data */
|
|||||||
// the source URL / the resource it points to alone.
|
// the source URL / the resource it points to alone.
|
||||||
QMap<QString, QString> m_extra_info;
|
QMap<QString, QString> m_extra_info;
|
||||||
|
|
||||||
//FIXME: nuke
|
// FIXME: nuke
|
||||||
QWidget* m_parent;
|
QWidget* m_parent;
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// 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 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -41,9 +41,9 @@
|
|||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QMimeData>
|
#include <QMimeData>
|
||||||
|
#include <QPair>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QStack>
|
#include <QStack>
|
||||||
#include <QPair>
|
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
@ -129,7 +129,7 @@ QMimeData* InstanceList::mimeData(const QModelIndexList& indexes) const
|
|||||||
return mimeData;
|
return mimeData;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList InstanceList::getLinkedInstancesById(const QString &id) const
|
QStringList InstanceList::getLinkedInstancesById(const QString& id) const
|
||||||
{
|
{
|
||||||
QStringList linkedInstances;
|
QStringList linkedInstances;
|
||||||
for (auto inst : m_instances) {
|
for (auto inst : m_instances) {
|
||||||
@ -158,42 +158,34 @@ QVariant InstanceList::data(const QModelIndex& index, int role) const
|
|||||||
if (!index.isValid()) {
|
if (!index.isValid()) {
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
BaseInstance *pdata = static_cast<BaseInstance *>(index.internalPointer());
|
BaseInstance* pdata = static_cast<BaseInstance*>(index.internalPointer());
|
||||||
switch (role)
|
switch (role) {
|
||||||
{
|
case InstancePointerRole: {
|
||||||
case InstancePointerRole:
|
QVariant v = QVariant::fromValue((void*)pdata);
|
||||||
{
|
return v;
|
||||||
QVariant v = QVariant::fromValue((void *)pdata);
|
}
|
||||||
return v;
|
case InstanceIDRole: {
|
||||||
}
|
return pdata->id();
|
||||||
case InstanceIDRole:
|
}
|
||||||
{
|
case Qt::EditRole:
|
||||||
return pdata->id();
|
case Qt::DisplayRole: {
|
||||||
}
|
return pdata->name();
|
||||||
case Qt::EditRole:
|
}
|
||||||
case Qt::DisplayRole:
|
case Qt::AccessibleTextRole: {
|
||||||
{
|
return tr("%1 Instance").arg(pdata->name());
|
||||||
return pdata->name();
|
}
|
||||||
}
|
case Qt::ToolTipRole: {
|
||||||
case Qt::AccessibleTextRole:
|
return pdata->instanceRoot();
|
||||||
{
|
}
|
||||||
return tr("%1 Instance").arg(pdata->name());
|
case Qt::DecorationRole: {
|
||||||
}
|
return pdata->iconKey();
|
||||||
case Qt::ToolTipRole:
|
}
|
||||||
{
|
// HACK: see InstanceView.h in gui!
|
||||||
return pdata->instanceRoot();
|
case GroupRole: {
|
||||||
}
|
return getInstanceGroup(pdata->id());
|
||||||
case Qt::DecorationRole:
|
}
|
||||||
{
|
default:
|
||||||
return pdata->iconKey();
|
break;
|
||||||
}
|
|
||||||
// HACK: see InstanceView.h in gui!
|
|
||||||
case GroupRole:
|
|
||||||
{
|
|
||||||
return getInstanceGroup(pdata->id());
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
@ -320,16 +312,18 @@ bool InstanceList::trashInstance(const InstanceId& id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "Instance" << id << "has been trashed by the launcher.";
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InstanceList::trashedSomething() {
|
bool InstanceList::trashedSomething()
|
||||||
|
{
|
||||||
return !m_trashHistory.empty();
|
return !m_trashHistory.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceList::undoTrashInstance() {
|
void InstanceList::undoTrashInstance()
|
||||||
|
{
|
||||||
if (m_trashHistory.empty()) {
|
if (m_trashHistory.empty()) {
|
||||||
qWarning() << "Nothing to recover from trash.";
|
qWarning() << "Nothing to recover from trash.";
|
||||||
return;
|
return;
|
||||||
@ -558,7 +552,7 @@ InstancePtr InstanceList::getInstanceByManagedName(const QString& managed_name)
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex InstanceList::getInstanceIndexById(const QString &id) const
|
QModelIndex InstanceList::getInstanceIndexById(const QString& id) const
|
||||||
{
|
{
|
||||||
return index(getInstIndex(getInstanceById(id).get()));
|
return index(getInstIndex(getInstanceById(id).get()));
|
||||||
}
|
}
|
||||||
@ -597,13 +591,11 @@ InstancePtr InstanceList::loadInstance(const InstanceId& id)
|
|||||||
|
|
||||||
QString inst_type = instanceSettings->get("InstanceType").toString();
|
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
|
// NOTE: Some PolyMC versions didn't save the InstanceType properly. We will just bank on the probability that this is probably a OneSix
|
||||||
if (inst_type == "OneSix" || inst_type.isEmpty())
|
// instance
|
||||||
{
|
if (inst_type == "OneSix" || inst_type.isEmpty()) {
|
||||||
inst.reset(new MinecraftInstance(m_globalSettings, instanceSettings, instanceRoot));
|
inst.reset(new MinecraftInstance(m_globalSettings, instanceSettings, instanceRoot));
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
inst.reset(new NullInstance(m_globalSettings, instanceSettings, instanceRoot));
|
inst.reset(new NullInstance(m_globalSettings, instanceSettings, instanceRoot));
|
||||||
}
|
}
|
||||||
qDebug() << "Loaded instance " << inst->name() << " from " << inst->instanceRoot();
|
qDebug() << "Loaded instance " << inst->name() << " from " << inst->instanceRoot();
|
||||||
@ -787,9 +779,14 @@ class InstanceStaging : public Task {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
const unsigned minBackoff = 1;
|
const unsigned minBackoff = 1;
|
||||||
const unsigned maxBackoff = 16;
|
const unsigned maxBackoff = 16;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
InstanceStaging(InstanceList* parent, InstanceTask* child, QString stagingPath, InstanceName const& instanceName, QString groupName)
|
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);
|
m_child.reset(child);
|
||||||
connect(child, &Task::succeeded, this, &InstanceStaging::childSucceded);
|
connect(child, &Task::succeeded, this, &InstanceStaging::childSucceded);
|
||||||
@ -815,10 +812,7 @@ class InstanceStaging : public Task {
|
|||||||
|
|
||||||
return Task::abort();
|
return Task::abort();
|
||||||
}
|
}
|
||||||
bool canAbort() const override
|
bool canAbort() const override { return (m_child && m_child->canAbort()); }
|
||||||
{
|
|
||||||
return (m_child && m_child->canAbort());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void executeTask() override { m_child->start(); }
|
virtual void executeTask() override { m_child->start(); }
|
||||||
@ -828,8 +822,7 @@ class InstanceStaging : public Task {
|
|||||||
void childSucceded()
|
void childSucceded()
|
||||||
{
|
{
|
||||||
unsigned sleepTime = backoff();
|
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();
|
emitSucceeded();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -847,13 +840,10 @@ class InstanceStaging : public Task {
|
|||||||
emitFailed(reason);
|
emitFailed(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
void childAborted()
|
void childAborted() { emitAborted(); }
|
||||||
{
|
|
||||||
emitAborted();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
InstanceList * m_parent;
|
InstanceList* m_parent;
|
||||||
/*
|
/*
|
||||||
* WHY: the whole reason why this uses an exponential backoff retry scheme is antivirus on Windows.
|
* 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
|
* Basically, it starts messing things up while the launcher is extracting/creating instances
|
||||||
@ -892,7 +882,10 @@ QString InstanceList::getStagedInstancePath()
|
|||||||
return path;
|
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;
|
QDir dir;
|
||||||
QString instID;
|
QString instID;
|
||||||
|
@ -15,12 +15,12 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <QSet>
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QStack>
|
#include <QObject>
|
||||||
#include <QPair>
|
#include <QPair>
|
||||||
|
#include <QSet>
|
||||||
|
#include <QStack>
|
||||||
|
|
||||||
#include "BaseInstance.h"
|
#include "BaseInstance.h"
|
||||||
|
|
||||||
@ -32,21 +32,9 @@ using InstanceId = QString;
|
|||||||
using GroupId = QString;
|
using GroupId = QString;
|
||||||
using InstanceLocator = std::pair<InstancePtr, int>;
|
using InstanceLocator = std::pair<InstancePtr, int>;
|
||||||
|
|
||||||
enum class InstCreateError
|
enum class InstCreateError { NoCreateError = 0, NoSuchVersion, UnknownCreateError, InstExists, CantCreateDir };
|
||||||
{
|
|
||||||
NoCreateError = 0,
|
|
||||||
NoSuchVersion,
|
|
||||||
UnknownCreateError,
|
|
||||||
InstExists,
|
|
||||||
CantCreateDir
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class GroupsState
|
enum class GroupsState { NotLoaded, Steady, Dirty };
|
||||||
{
|
|
||||||
NotLoaded,
|
|
||||||
Steady,
|
|
||||||
Dirty
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TrashHistoryItem {
|
struct TrashHistoryItem {
|
||||||
QString id;
|
QString id;
|
||||||
@ -55,48 +43,36 @@ struct TrashHistoryItem {
|
|||||||
QString groupName;
|
QString groupName;
|
||||||
};
|
};
|
||||||
|
|
||||||
class InstanceList : public QAbstractListModel
|
class InstanceList : public QAbstractListModel {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit InstanceList(SettingsObjectPtr settings, const QString & instDir, QObject *parent = 0);
|
explicit InstanceList(SettingsObjectPtr settings, const QString& instDir, QObject* parent = 0);
|
||||||
virtual ~InstanceList();
|
virtual ~InstanceList();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const override;
|
QModelIndex index(int row, int column = 0, const QModelIndex& parent = QModelIndex()) const override;
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||||
QVariant data(const QModelIndex &index, int role) const override;
|
QVariant data(const QModelIndex& index, int role) const override;
|
||||||
Qt::ItemFlags flags(const QModelIndex &index) 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,
|
GroupRole = Qt::UserRole,
|
||||||
InstancePointerRole = 0x34B1CB48, ///< Return pointer to real instance
|
InstancePointerRole = 0x34B1CB48, ///< Return pointer to real instance
|
||||||
InstanceIDRole = 0x34B1CB49 ///< Return id if the instance
|
InstanceIDRole = 0x34B1CB49 ///< Return id if the instance
|
||||||
};
|
};
|
||||||
/*!
|
/*!
|
||||||
* \brief Error codes returned by functions in the InstanceList class.
|
* \brief Error codes returned by functions in the InstanceList class.
|
||||||
* NoError Indicates that no error occurred.
|
* NoError Indicates that no error occurred.
|
||||||
* UnknownError indicates that an unspecified error occurred.
|
* UnknownError indicates that an unspecified error occurred.
|
||||||
*/
|
*/
|
||||||
enum InstListError
|
enum InstListError { NoError = 0, UnknownError };
|
||||||
{
|
|
||||||
NoError = 0,
|
|
||||||
UnknownError
|
|
||||||
};
|
|
||||||
|
|
||||||
InstancePtr at(int i) const
|
InstancePtr at(int i) const { return m_instances.at(i); }
|
||||||
{
|
|
||||||
return m_instances.at(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
int count() const
|
int count() const { return m_instances.count(); }
|
||||||
{
|
|
||||||
return m_instances.count();
|
|
||||||
}
|
|
||||||
|
|
||||||
InstListError loadList();
|
InstListError loadList();
|
||||||
void saveNow();
|
void saveNow();
|
||||||
@ -105,21 +81,21 @@ public:
|
|||||||
InstancePtr getInstanceById(QString id) const;
|
InstancePtr getInstanceById(QString id) const;
|
||||||
/* O(n) */
|
/* O(n) */
|
||||||
InstancePtr getInstanceByManagedName(const QString& managed_name) const;
|
InstancePtr getInstanceByManagedName(const QString& managed_name) const;
|
||||||
QModelIndex getInstanceIndexById(const QString &id) const;
|
QModelIndex getInstanceIndexById(const QString& id) const;
|
||||||
QStringList getGroups();
|
QStringList getGroups();
|
||||||
bool isGroupCollapsed(const QString &groupName);
|
bool isGroupCollapsed(const QString& groupName);
|
||||||
|
|
||||||
GroupId getInstanceGroup(const InstanceId & id) const;
|
GroupId getInstanceGroup(const InstanceId& id) const;
|
||||||
void setInstanceGroup(const InstanceId & id, const GroupId& name);
|
void setInstanceGroup(const InstanceId& id, const GroupId& name);
|
||||||
|
|
||||||
void deleteGroup(const GroupId & name);
|
void deleteGroup(const GroupId& name);
|
||||||
bool trashInstance(const InstanceId &id);
|
bool trashInstance(const InstanceId& id);
|
||||||
bool trashedSomething();
|
bool trashedSomething();
|
||||||
void undoTrashInstance();
|
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
|
// 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.
|
* 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.
|
* Destroy a previously created staging area given by @keyPath - used when creation fails.
|
||||||
* Used by instance manipulation tasks.
|
* Used by instance manipulation tasks.
|
||||||
*/
|
*/
|
||||||
bool destroyStagingPath(const QString & keyPath);
|
bool destroyStagingPath(const QString& keyPath);
|
||||||
|
|
||||||
int getTotalPlayTime();
|
int getTotalPlayTime();
|
||||||
|
|
||||||
@ -147,42 +123,42 @@ public:
|
|||||||
|
|
||||||
Qt::DropActions supportedDropActions() const override;
|
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;
|
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 dataIsInvalid();
|
||||||
void instancesChanged();
|
void instancesChanged();
|
||||||
void instanceSelectRequest(QString instanceId);
|
void instanceSelectRequest(QString instanceId);
|
||||||
void groupsChanged(QSet<QString> groups);
|
void groupsChanged(QSet<QString> groups);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void on_InstFolderChanged(const Setting &setting, QVariant value);
|
void on_InstFolderChanged(const Setting& setting, QVariant value);
|
||||||
void on_GroupStateChanged(const QString &group, bool collapsed);
|
void on_GroupStateChanged(const QString& group, bool collapsed);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void propertiesChanged(BaseInstance *inst);
|
void propertiesChanged(BaseInstance* inst);
|
||||||
void providerUpdated();
|
void providerUpdated();
|
||||||
void instanceDirContentsChanged(const QString &path);
|
void instanceDirContentsChanged(const QString& path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int getInstIndex(BaseInstance *inst) const;
|
int getInstIndex(BaseInstance* inst) const;
|
||||||
void updateTotalPlayTime();
|
void updateTotalPlayTime();
|
||||||
void suspendWatch();
|
void suspendWatch();
|
||||||
void resumeWatch();
|
void resumeWatch();
|
||||||
void add(const QList<InstancePtr> &list);
|
void add(const QList<InstancePtr>& list);
|
||||||
void loadGroupList();
|
void loadGroupList();
|
||||||
void saveGroupList();
|
void saveGroupList();
|
||||||
QList<InstanceId> discoverInstances();
|
QList<InstanceId> discoverInstances();
|
||||||
InstancePtr loadInstance(const InstanceId& id);
|
InstancePtr loadInstance(const InstanceId& id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_watchLevel = 0;
|
int m_watchLevel = 0;
|
||||||
int totalPlayTime = 0;
|
int totalPlayTime = 0;
|
||||||
bool m_dirty = false;
|
bool m_dirty = false;
|
||||||
@ -191,7 +167,7 @@ private:
|
|||||||
|
|
||||||
SettingsObjectPtr m_globalSettings;
|
SettingsObjectPtr m_globalSettings;
|
||||||
QString m_instDir;
|
QString m_instDir;
|
||||||
QFileSystemWatcher * m_watcher;
|
QFileSystemWatcher* m_watcher;
|
||||||
// FIXME: this is so inefficient that looking at it is almost painful.
|
// FIXME: this is so inefficient that looking at it is almost painful.
|
||||||
QSet<QString> m_collapsedGroups;
|
QSet<QString> m_collapsedGroups;
|
||||||
QMap<InstanceId, GroupId> m_instanceGroupIndex;
|
QMap<InstanceId, GroupId> m_instanceGroupIndex;
|
||||||
|
@ -1,36 +1,31 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "minecraft/MinecraftInstance.h"
|
|
||||||
#include <FileSystem.h>
|
#include <FileSystem.h>
|
||||||
|
#include "minecraft/MinecraftInstance.h"
|
||||||
#include "ui/pages/BasePage.h"
|
#include "ui/pages/BasePage.h"
|
||||||
#include "ui/pages/BasePageProvider.h"
|
#include "ui/pages/BasePageProvider.h"
|
||||||
|
#include "ui/pages/instance/InstanceSettingsPage.h"
|
||||||
#include "ui/pages/instance/LogPage.h"
|
#include "ui/pages/instance/LogPage.h"
|
||||||
#include "ui/pages/instance/VersionPage.h"
|
|
||||||
#include "ui/pages/instance/ManagedPackPage.h"
|
#include "ui/pages/instance/ManagedPackPage.h"
|
||||||
#include "ui/pages/instance/ModFolderPage.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/NotesPage.h"
|
||||||
#include "ui/pages/instance/ScreenshotsPage.h"
|
|
||||||
#include "ui/pages/instance/InstanceSettingsPage.h"
|
|
||||||
#include "ui/pages/instance/OtherLogsPage.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/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
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit InstancePageProvider(InstancePtr parent)
|
explicit InstancePageProvider(InstancePtr parent) { inst = parent; }
|
||||||
{
|
|
||||||
inst = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~InstancePageProvider() {};
|
virtual ~InstancePageProvider(){};
|
||||||
virtual QList<BasePage *> getPages() override
|
virtual QList<BasePage*> getPages() override
|
||||||
{
|
{
|
||||||
QList<BasePage *> values;
|
QList<BasePage*> values;
|
||||||
values.append(new LogPage(inst));
|
values.append(new LogPage(inst));
|
||||||
std::shared_ptr<MinecraftInstance> onesix = std::dynamic_pointer_cast<MinecraftInstance>(inst);
|
std::shared_ptr<MinecraftInstance> onesix = std::dynamic_pointer_cast<MinecraftInstance>(inst);
|
||||||
values.append(new VersionPage(onesix.get()));
|
values.append(new VersionPage(onesix.get()));
|
||||||
@ -50,18 +45,14 @@ public:
|
|||||||
values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots")));
|
values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots")));
|
||||||
values.append(new InstanceSettingsPage(onesix.get()));
|
values.append(new InstanceSettingsPage(onesix.get()));
|
||||||
auto logMatcher = inst->getLogFileMatcher();
|
auto logMatcher = inst->getLogFileMatcher();
|
||||||
if(logMatcher)
|
if (logMatcher) {
|
||||||
{
|
|
||||||
values.append(new OtherLogsPage(inst->getLogFileRoot(), logMatcher));
|
values.append(new OtherLogsPage(inst->getLogFileRoot(), logMatcher));
|
||||||
}
|
}
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual QString dialogTitle() override
|
virtual QString dialogTitle() override { return tr("Edit Instance (%1)").arg(inst->name()); }
|
||||||
{
|
|
||||||
return tr("Edit Instance (%1)").arg(inst->name());
|
protected:
|
||||||
}
|
|
||||||
protected:
|
|
||||||
InstancePtr inst;
|
InstancePtr inst;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,13 +18,14 @@ InstanceNameChange askForChangingInstanceName(QWidget* parent, const QString& ol
|
|||||||
return InstanceNameChange::ShouldKeep;
|
return InstanceNameChange::ShouldKeep;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShouldUpdate askIfShouldUpdate(QWidget *parent, QString original_version_name)
|
ShouldUpdate askIfShouldUpdate(QWidget* parent, QString original_version_name)
|
||||||
{
|
{
|
||||||
auto info = CustomMessageBox::selectable(
|
auto info = CustomMessageBox::selectable(
|
||||||
parent, QObject::tr("Similar modpack was found!"),
|
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(
|
||||||
"separate instance, or update the existing one?\n\nNOTE: Make sure you made a backup of your important instance data before "
|
"One or more of your instances are from this same modpack%1. Do you want to create a "
|
||||||
"updating, as worlds can be corrupted and some configuration may be lost (due to pack overrides).")
|
"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),
|
.arg(original_version_name),
|
||||||
QMessageBox::Information, QMessageBox::Ok | QMessageBox::Reset | QMessageBox::Abort);
|
QMessageBox::Information, QMessageBox::Ok | QMessageBox::Reset | QMessageBox::Abort);
|
||||||
info->setButtonText(QMessageBox::Ok, QObject::tr("Update existing instance"));
|
info->setButtonText(QMessageBox::Ok, QObject::tr("Update existing instance"));
|
||||||
@ -38,7 +39,6 @@ ShouldUpdate askIfShouldUpdate(QWidget *parent, QString original_version_name)
|
|||||||
if (info->clickedButton() == info->button(QMessageBox::Abort))
|
if (info->clickedButton() == info->button(QMessageBox::Abort))
|
||||||
return ShouldUpdate::SkipUpdating;
|
return ShouldUpdate::SkipUpdating;
|
||||||
return ShouldUpdate::Cancel;
|
return ShouldUpdate::Cancel;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString InstanceName::name() const
|
QString InstanceName::name() const
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// 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 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -39,43 +39,39 @@
|
|||||||
|
|
||||||
#include <QRegularExpression>
|
#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]"))
|
if (jvmargs.contains("-XX:PermSize=") || jvmargs.contains(QRegularExpression("-Xm[sx]")) || jvmargs.contains("-XX-MaxHeapSize") ||
|
||||||
|| jvmargs.contains("-XX-MaxHeapSize") || jvmargs.contains("-XX:InitialHeapSize"))
|
jvmargs.contains("-XX:InitialHeapSize")) {
|
||||||
{
|
|
||||||
auto warnStr = QObject::tr(
|
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"
|
"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.");
|
"This message will be displayed until you remove them from the JVM arguments.");
|
||||||
CustomMessageBox::selectable(
|
CustomMessageBox::selectable(parent, QObject::tr("JVM arguments warning"), warnStr, QMessageBox::Warning)->exec();
|
||||||
parent, QObject::tr("JVM arguments warning"),
|
|
||||||
warnStr,
|
|
||||||
QMessageBox::Warning)->exec();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// block lunacy with passing required version to the JVM
|
// block lunacy with passing required version to the JVM
|
||||||
if (jvmargs.contains(QRegularExpression("-version:.*"))) {
|
if (jvmargs.contains(QRegularExpression("-version:.*"))) {
|
||||||
auto warnStr = QObject::tr(
|
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.");
|
"This message will be displayed until you remove this from the JVM arguments.");
|
||||||
CustomMessageBox::selectable(
|
CustomMessageBox::selectable(parent, QObject::tr("JVM arguments warning"), warnStr, QMessageBox::Warning)->exec();
|
||||||
parent, QObject::tr("JVM arguments warning"),
|
|
||||||
warnStr,
|
|
||||||
QMessageBox::Warning)->exec();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaCommon::javaWasOk(QWidget *parent, JavaCheckResult result)
|
void JavaCommon::javaWasOk(QWidget* parent, const JavaCheckResult& result)
|
||||||
{
|
{
|
||||||
QString text;
|
QString text;
|
||||||
text += QObject::tr("Java test succeeded!<br />Platform reported: %1<br />Java version "
|
text += QObject::tr(
|
||||||
"reported: %2<br />Java vendor "
|
"Java test succeeded!<br />Platform reported: %1<br />Java version "
|
||||||
"reported: %3<br />").arg(result.realPlatform, result.javaVersion.toString(), result.javaVendor);
|
"reported: %2<br />Java vendor "
|
||||||
if (result.errorLog.size())
|
"reported: %3<br />")
|
||||||
{
|
.arg(result.realPlatform, result.javaVersion.toString(), result.javaVendor);
|
||||||
|
if (result.errorLog.size()) {
|
||||||
auto htmlError = result.errorLog;
|
auto htmlError = result.errorLog;
|
||||||
htmlError.replace('\n', "<br />");
|
htmlError.replace('\n', "<br />");
|
||||||
text += QObject::tr("<br />Warnings:<br /><font color=\"orange\">%1</font>").arg(htmlError);
|
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();
|
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;
|
auto htmlError = result.errorLog;
|
||||||
QString text;
|
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();
|
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;
|
QString text;
|
||||||
text += QObject::tr(
|
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();
|
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaCommon::javaCheckNotFound(QWidget *parent)
|
void JavaCommon::javaCheckNotFound(QWidget* parent)
|
||||||
{
|
{
|
||||||
QString text;
|
QString text;
|
||||||
text += QObject::tr("Java checker library could not be found. Please check your installation.");
|
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()
|
void JavaCommon::TestCheck::run()
|
||||||
{
|
{
|
||||||
if (!JavaCommon::checkJVMArgs(m_args, m_parent))
|
if (!JavaCommon::checkJVMArgs(m_args, m_parent)) {
|
||||||
{
|
|
||||||
emit finished();
|
emit finished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -129,8 +124,7 @@ void JavaCommon::TestCheck::run()
|
|||||||
|
|
||||||
void JavaCommon::TestCheck::checkFinished(JavaCheckResult result)
|
void JavaCommon::TestCheck::checkFinished(JavaCheckResult result)
|
||||||
{
|
{
|
||||||
if (result.validity != JavaCheckResult::Validity::Valid)
|
if (result.validity != JavaCheckResult::Validity::Valid) {
|
||||||
{
|
|
||||||
javaBinaryWasBad(m_parent, result);
|
javaBinaryWasBad(m_parent, result);
|
||||||
emit finished();
|
emit finished();
|
||||||
return;
|
return;
|
||||||
@ -141,8 +135,7 @@ void JavaCommon::TestCheck::checkFinished(JavaCheckResult result)
|
|||||||
checker->m_args = m_args;
|
checker->m_args = m_args;
|
||||||
checker->m_minMem = m_minMem;
|
checker->m_minMem = m_minMem;
|
||||||
checker->m_maxMem = m_maxMem;
|
checker->m_maxMem = m_maxMem;
|
||||||
if (result.javaVersion.requiresPermGen())
|
if (result.javaVersion.requiresPermGen()) {
|
||||||
{
|
|
||||||
checker->m_permGen = m_permGen;
|
checker->m_permGen = m_permGen;
|
||||||
}
|
}
|
||||||
checker->performCheck();
|
checker->performCheck();
|
||||||
@ -150,8 +143,7 @@ void JavaCommon::TestCheck::checkFinished(JavaCheckResult result)
|
|||||||
|
|
||||||
void JavaCommon::TestCheck::checkFinishedWithArgs(JavaCheckResult result)
|
void JavaCommon::TestCheck::checkFinishedWithArgs(JavaCheckResult result)
|
||||||
{
|
{
|
||||||
if (result.validity == JavaCheckResult::Validity::Valid)
|
if (result.validity == JavaCheckResult::Validity::Valid) {
|
||||||
{
|
|
||||||
javaWasOk(m_parent, result);
|
javaWasOk(m_parent, result);
|
||||||
emit finished();
|
emit finished();
|
||||||
return;
|
return;
|
||||||
@ -159,4 +151,3 @@ void JavaCommon::TestCheck::checkFinishedWithArgs(JavaCheckResult result)
|
|||||||
javaArgsWereBad(m_parent, result);
|
javaArgsWereBad(m_parent, result);
|
||||||
emit finished();
|
emit finished();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,45 +6,42 @@ class QWidget;
|
|||||||
/**
|
/**
|
||||||
* Common UI bits for the java pages to use.
|
* Common UI bits for the java pages to use.
|
||||||
*/
|
*/
|
||||||
namespace JavaCommon
|
namespace JavaCommon {
|
||||||
{
|
bool checkJVMArgs(QString args, QWidget* parent);
|
||||||
bool checkJVMArgs(QString args, QWidget *parent);
|
|
||||||
|
|
||||||
// Show a dialog saying that the Java binary was usable
|
// Show a dialog saying that the Java binary was usable
|
||||||
void javaWasOk(QWidget *parent, JavaCheckResult result);
|
void javaWasOk(QWidget* parent, const JavaCheckResult& result);
|
||||||
// Show a dialog saying that the Java binary was not usable because of bad options
|
// Show a dialog saying that the Java binary was not usable because of bad options
|
||||||
void javaArgsWereBad(QWidget *parent, JavaCheckResult result);
|
void javaArgsWereBad(QWidget* parent, const JavaCheckResult& result);
|
||||||
// Show a dialog saying that the Java binary was not usable
|
// Show a dialog saying that the Java binary was not usable
|
||||||
void javaBinaryWasBad(QWidget *parent, JavaCheckResult result);
|
void javaBinaryWasBad(QWidget* parent, const JavaCheckResult& result);
|
||||||
// Show a dialog if we couldn't find Java Checker
|
// Show a dialog if we couldn't find Java Checker
|
||||||
void javaCheckNotFound(QWidget *parent);
|
void javaCheckNotFound(QWidget* parent);
|
||||||
|
|
||||||
class TestCheck : public QObject
|
class TestCheck : public QObject {
|
||||||
{
|
Q_OBJECT
|
||||||
Q_OBJECT
|
public:
|
||||||
public:
|
TestCheck(QWidget* parent, QString path, QString args, int minMem, int maxMem, int permGen)
|
||||||
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)
|
||||||
:m_parent(parent), m_path(path), m_args(args), m_minMem(minMem), m_maxMem(maxMem), m_permGen(permGen)
|
{}
|
||||||
{
|
virtual ~TestCheck(){};
|
||||||
}
|
|
||||||
virtual ~TestCheck() {};
|
|
||||||
|
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void finished();
|
void finished();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void checkFinished(JavaCheckResult result);
|
void checkFinished(JavaCheckResult result);
|
||||||
void checkFinishedWithArgs(JavaCheckResult result);
|
void checkFinishedWithArgs(JavaCheckResult result);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<JavaChecker> checker;
|
std::shared_ptr<JavaChecker> checker;
|
||||||
QWidget *m_parent = nullptr;
|
QWidget* m_parent = nullptr;
|
||||||
QString m_path;
|
QString m_path;
|
||||||
QString m_args;
|
QString m_args;
|
||||||
int m_minMem = 0;
|
int m_minMem = 0;
|
||||||
int m_maxMem = 0;
|
int m_maxMem = 0;
|
||||||
int m_permGen = 64;
|
int m_permGen = 64;
|
||||||
};
|
};
|
||||||
}
|
} // namespace JavaCommon
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// 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 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -37,257 +37,246 @@
|
|||||||
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
|
||||||
#include "FileSystem.h"
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include "FileSystem.h"
|
||||||
|
|
||||||
namespace Json
|
namespace Json {
|
||||||
{
|
void write(const QJsonDocument& doc, const QString& filename)
|
||||||
void write(const QJsonDocument &doc, const QString &filename)
|
|
||||||
{
|
{
|
||||||
FS::write(filename, doc.toJson());
|
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);
|
write(QJsonDocument(object), filename);
|
||||||
}
|
}
|
||||||
void write(const QJsonArray &array, const QString &filename)
|
void write(const QJsonArray& array, const QString& filename)
|
||||||
{
|
{
|
||||||
write(QJsonDocument(array), filename);
|
write(QJsonDocument(array), filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray toText(const QJsonObject &obj)
|
QByteArray toText(const QJsonObject& obj)
|
||||||
{
|
{
|
||||||
return QJsonDocument(obj).toJson(QJsonDocument::Compact);
|
return QJsonDocument(obj).toJson(QJsonDocument::Compact);
|
||||||
}
|
}
|
||||||
QByteArray toText(const QJsonArray &array)
|
QByteArray toText(const QJsonArray& array)
|
||||||
{
|
{
|
||||||
return QJsonDocument(array).toJson(QJsonDocument::Compact);
|
return QJsonDocument(array).toJson(QJsonDocument::Compact);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isBinaryJson(const QByteArray &data)
|
static bool isBinaryJson(const QByteArray& data)
|
||||||
{
|
{
|
||||||
decltype(QJsonDocument::BinaryFormatTag) tag = QJsonDocument::BinaryFormatTag;
|
decltype(QJsonDocument::BinaryFormatTag) tag = QJsonDocument::BinaryFormatTag;
|
||||||
return memcmp(data.constData(), &tag, sizeof(QJsonDocument::BinaryFormatTag)) == 0;
|
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?
|
// FIXME: Is this needed?
|
||||||
throw JsonException(what + ": Invalid JSON. Binary JSON unsupported");
|
throw JsonException(what + ": Invalid JSON. Binary JSON unsupported");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
QJsonParseError error;
|
QJsonParseError error;
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(data, &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());
|
throw JsonException(what + ": Error parsing JSON: " + error.errorString());
|
||||||
}
|
}
|
||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QJsonDocument requireDocument(const QString &filename, const QString &what)
|
QJsonDocument requireDocument(const QString& filename, const QString& what)
|
||||||
{
|
{
|
||||||
return requireDocument(FS::read(filename), 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");
|
throw JsonException(what + " is not an object");
|
||||||
}
|
}
|
||||||
return doc.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");
|
throw JsonException(what + " is not an array");
|
||||||
}
|
}
|
||||||
return doc.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);
|
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;
|
QJsonArray array;
|
||||||
for(auto value: values)
|
for (auto value : values) {
|
||||||
{
|
|
||||||
array.append(value);
|
array.append(value);
|
||||||
}
|
}
|
||||||
to.insert(key, array);
|
to.insert(key, array);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
QJsonValue toJson<QUrl>(const QUrl &url)
|
QJsonValue toJson<QUrl>(const QUrl& url)
|
||||||
{
|
{
|
||||||
return QJsonValue(url.toString(QUrl::FullyEncoded));
|
return QJsonValue(url.toString(QUrl::FullyEncoded));
|
||||||
}
|
}
|
||||||
template<>
|
template <>
|
||||||
QJsonValue toJson<QByteArray>(const QByteArray &data)
|
QJsonValue toJson<QByteArray>(const QByteArray& data)
|
||||||
{
|
{
|
||||||
return QJsonValue(QString::fromLatin1(data.toHex()));
|
return QJsonValue(QString::fromLatin1(data.toHex()));
|
||||||
}
|
}
|
||||||
template<>
|
template <>
|
||||||
QJsonValue toJson<QDateTime>(const QDateTime &datetime)
|
QJsonValue toJson<QDateTime>(const QDateTime& datetime)
|
||||||
{
|
{
|
||||||
return QJsonValue(datetime.toString(Qt::ISODate));
|
return QJsonValue(datetime.toString(Qt::ISODate));
|
||||||
}
|
}
|
||||||
template<>
|
template <>
|
||||||
QJsonValue toJson<QDir>(const QDir &dir)
|
QJsonValue toJson<QDir>(const QDir& dir)
|
||||||
{
|
{
|
||||||
return QDir::current().relativeFilePath(dir.absolutePath());
|
return QDir::current().relativeFilePath(dir.absolutePath());
|
||||||
}
|
}
|
||||||
template<>
|
template <>
|
||||||
QJsonValue toJson<QUuid>(const QUuid &uuid)
|
QJsonValue toJson<QUuid>(const QUuid& uuid)
|
||||||
{
|
{
|
||||||
return uuid.toString();
|
return uuid.toString();
|
||||||
}
|
}
|
||||||
template<>
|
template <>
|
||||||
QJsonValue toJson<QVariant>(const QVariant &variant)
|
QJsonValue toJson<QVariant>(const QVariant& variant)
|
||||||
{
|
{
|
||||||
return QJsonValue::fromVariant(variant);
|
return QJsonValue::fromVariant(variant);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
template<> QByteArray requireIsType<QByteArray>(const QJsonValue &value, const QString &what)
|
QByteArray requireIsType<QByteArray>(const QJsonValue& value, const QString& what)
|
||||||
{
|
{
|
||||||
const QString string = ensureIsType<QString>(value, what);
|
const QString string = ensureIsType<QString>(value, what);
|
||||||
// ensure that the string can be safely cast to Latin1
|
// 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");
|
throw JsonException(what + " is not encodable as Latin1");
|
||||||
}
|
}
|
||||||
return QByteArray::fromHex(string.toLatin1());
|
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");
|
throw JsonException(what + " is not an array");
|
||||||
}
|
}
|
||||||
return value.toArray();
|
return value.toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
template<> QString requireIsType<QString>(const QJsonValue &value, const QString &what)
|
QString requireIsType<QString>(const QJsonValue& value, const QString& what)
|
||||||
{
|
{
|
||||||
if (!value.isString())
|
if (!value.isString()) {
|
||||||
{
|
|
||||||
throw JsonException(what + " is not a string");
|
throw JsonException(what + " is not a string");
|
||||||
}
|
}
|
||||||
return value.toString();
|
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");
|
throw JsonException(what + " is not a bool");
|
||||||
}
|
}
|
||||||
return value.toBool();
|
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");
|
throw JsonException(what + " is not a double");
|
||||||
}
|
}
|
||||||
return value.toDouble();
|
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);
|
const double doubl = requireIsType<double>(value, what);
|
||||||
if (fmod(doubl, 1) != 0)
|
if (fmod(doubl, 1) != 0) {
|
||||||
{
|
|
||||||
throw JsonException(what + " is not an integer");
|
throw JsonException(what + " is not an integer");
|
||||||
}
|
}
|
||||||
return int(doubl);
|
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 QString string = requireIsType<QString>(value, what);
|
||||||
const QDateTime datetime = QDateTime::fromString(string, Qt::ISODate);
|
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");
|
throw JsonException(what + " is not a ISO formatted date/time value");
|
||||||
}
|
}
|
||||||
return datetime;
|
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);
|
const QString string = ensureIsType<QString>(value, what);
|
||||||
if (string.isEmpty())
|
if (string.isEmpty()) {
|
||||||
{
|
|
||||||
return QUrl();
|
return QUrl();
|
||||||
}
|
}
|
||||||
const QUrl url = QUrl(string, QUrl::StrictMode);
|
const QUrl url = QUrl(string, QUrl::StrictMode);
|
||||||
if (!url.isValid())
|
if (!url.isValid()) {
|
||||||
{
|
|
||||||
throw JsonException(what + " is not a correctly formatted URL");
|
throw JsonException(what + " is not a correctly formatted URL");
|
||||||
}
|
}
|
||||||
return 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);
|
const QString string = requireIsType<QString>(value, what);
|
||||||
// FIXME: does not handle invalid characters!
|
// FIXME: does not handle invalid characters!
|
||||||
return QDir::current().absoluteFilePath(string);
|
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 QString string = requireIsType<QString>(value, what);
|
||||||
const QUuid uuid = QUuid(string);
|
const QUuid uuid = QUuid(string);
|
||||||
if (uuid.toString() != string) // converts back => valid
|
if (uuid.toString() != string) // converts back => valid
|
||||||
{
|
{
|
||||||
throw JsonException(what + " is not a valid UUID");
|
throw JsonException(what + " is not a valid UUID");
|
||||||
}
|
}
|
||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> QJsonObject requireIsType<QJsonObject>(const QJsonValue &value, const QString &what)
|
template <>
|
||||||
|
QJsonObject requireIsType<QJsonObject>(const QJsonValue& value, const QString& what)
|
||||||
{
|
{
|
||||||
if (!value.isObject())
|
if (!value.isObject()) {
|
||||||
{
|
|
||||||
throw JsonException(what + " is not an object");
|
throw JsonException(what + " is not an object");
|
||||||
}
|
}
|
||||||
return value.toObject();
|
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");
|
throw JsonException(what + " is null or undefined");
|
||||||
}
|
}
|
||||||
return value.toVariant();
|
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");
|
throw JsonException(what + " is null or undefined");
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace Json
|
||||||
|
204
launcher/Json.h
204
launcher/Json.h
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// 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 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -35,74 +35,71 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QUrl>
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QUrl>
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "Exception.h"
|
#include "Exception.h"
|
||||||
|
|
||||||
namespace Json
|
namespace Json {
|
||||||
{
|
class JsonException : public ::Exception {
|
||||||
class JsonException : public ::Exception
|
public:
|
||||||
{
|
JsonException(const QString& message) : Exception(message) {}
|
||||||
public:
|
|
||||||
JsonException(const QString &message) : Exception(message) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @throw FileSystemException
|
/// @throw FileSystemException
|
||||||
void write(const QJsonDocument &doc, const QString &filename);
|
void write(const QJsonDocument& doc, const QString& filename);
|
||||||
/// @throw FileSystemException
|
/// @throw FileSystemException
|
||||||
void write(const QJsonObject &object, const QString &filename);
|
void write(const QJsonObject& object, const QString& filename);
|
||||||
/// @throw FileSystemException
|
/// @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 QJsonObject& obj);
|
||||||
QByteArray toText(const QJsonArray &array);
|
QByteArray toText(const QJsonArray& array);
|
||||||
|
|
||||||
/// @throw JsonException
|
/// @throw JsonException
|
||||||
QJsonDocument requireDocument(const QByteArray &data, const QString &what = "Document");
|
QJsonDocument requireDocument(const QByteArray& data, const QString& what = "Document");
|
||||||
/// @throw JsonException
|
/// @throw JsonException
|
||||||
QJsonDocument requireDocument(const QString &filename, const QString &what = "Document");
|
QJsonDocument requireDocument(const QString& filename, const QString& what = "Document");
|
||||||
/// @throw JsonException
|
/// @throw JsonException
|
||||||
QJsonObject requireObject(const QJsonDocument &doc, const QString &what = "Document");
|
QJsonObject requireObject(const QJsonDocument& doc, const QString& what = "Document");
|
||||||
/// @throw JsonException
|
/// @throw JsonException
|
||||||
QJsonArray requireArray(const QJsonDocument &doc, const QString &what = "Document");
|
QJsonArray requireArray(const QJsonDocument& doc, const QString& what = "Document");
|
||||||
|
|
||||||
/////////////////// WRITING ////////////////////
|
/////////////////// WRITING ////////////////////
|
||||||
|
|
||||||
void writeString(QJsonObject & to, const QString &key, const QString &value);
|
void writeString(QJsonObject& to, const QString& key, const QString& value);
|
||||||
void writeStringList(QJsonObject & to, const QString &key, const QStringList &values);
|
void writeStringList(QJsonObject& to, const QString& key, const QStringList& values);
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
QJsonValue toJson(const T &t)
|
QJsonValue toJson(const T& t)
|
||||||
{
|
{
|
||||||
return QJsonValue(t);
|
return QJsonValue(t);
|
||||||
}
|
}
|
||||||
template<>
|
template <>
|
||||||
QJsonValue toJson<QUrl>(const QUrl &url);
|
QJsonValue toJson<QUrl>(const QUrl& url);
|
||||||
template<>
|
template <>
|
||||||
QJsonValue toJson<QByteArray>(const QByteArray &data);
|
QJsonValue toJson<QByteArray>(const QByteArray& data);
|
||||||
template<>
|
template <>
|
||||||
QJsonValue toJson<QDateTime>(const QDateTime &datetime);
|
QJsonValue toJson<QDateTime>(const QDateTime& datetime);
|
||||||
template<>
|
template <>
|
||||||
QJsonValue toJson<QDir>(const QDir &dir);
|
QJsonValue toJson<QDir>(const QDir& dir);
|
||||||
template<>
|
template <>
|
||||||
QJsonValue toJson<QUuid>(const QUuid &uuid);
|
QJsonValue toJson<QUuid>(const QUuid& uuid);
|
||||||
template<>
|
template <>
|
||||||
QJsonValue toJson<QVariant>(const QVariant &variant);
|
QJsonValue toJson<QVariant>(const QVariant& variant);
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
QJsonArray toJsonArray(const QList<T> &container)
|
QJsonArray toJsonArray(const QList<T>& container)
|
||||||
{
|
{
|
||||||
QJsonArray array;
|
QJsonArray array;
|
||||||
for (const T item : container)
|
for (const T item : container) {
|
||||||
{
|
|
||||||
array.append(toJson<T>(item));
|
array.append(toJson<T>(item));
|
||||||
}
|
}
|
||||||
return array;
|
return array;
|
||||||
@ -112,106 +109,110 @@ QJsonArray toJsonArray(const QList<T> &container)
|
|||||||
|
|
||||||
/// @throw JsonException
|
/// @throw JsonException
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T requireIsType(const QJsonValue &value, const QString &what = "Value");
|
T requireIsType(const QJsonValue& value, const QString& what = "Value");
|
||||||
|
|
||||||
/// @throw JsonException
|
/// @throw JsonException
|
||||||
template<> double requireIsType<double>(const QJsonValue &value, const QString &what);
|
template <>
|
||||||
|
double requireIsType<double>(const QJsonValue& value, const QString& what);
|
||||||
/// @throw JsonException
|
/// @throw JsonException
|
||||||
template<> bool requireIsType<bool>(const QJsonValue &value, const QString &what);
|
template <>
|
||||||
|
bool requireIsType<bool>(const QJsonValue& value, const QString& what);
|
||||||
/// @throw JsonException
|
/// @throw JsonException
|
||||||
template<> int requireIsType<int>(const QJsonValue &value, const QString &what);
|
template <>
|
||||||
|
int requireIsType<int>(const QJsonValue& value, const QString& what);
|
||||||
/// @throw JsonException
|
/// @throw JsonException
|
||||||
template<> QJsonObject requireIsType<QJsonObject>(const QJsonValue &value, const QString &what);
|
template <>
|
||||||
|
QJsonObject requireIsType<QJsonObject>(const QJsonValue& value, const QString& what);
|
||||||
/// @throw JsonException
|
/// @throw JsonException
|
||||||
template<> QJsonArray requireIsType<QJsonArray>(const QJsonValue &value, const QString &what);
|
template <>
|
||||||
|
QJsonArray requireIsType<QJsonArray>(const QJsonValue& value, const QString& what);
|
||||||
/// @throw JsonException
|
/// @throw JsonException
|
||||||
template<> QJsonValue requireIsType<QJsonValue>(const QJsonValue &value, const QString &what);
|
template <>
|
||||||
|
QJsonValue requireIsType<QJsonValue>(const QJsonValue& value, const QString& what);
|
||||||
/// @throw JsonException
|
/// @throw JsonException
|
||||||
template<> QByteArray requireIsType<QByteArray>(const QJsonValue &value, const QString &what);
|
template <>
|
||||||
|
QByteArray requireIsType<QByteArray>(const QJsonValue& value, const QString& what);
|
||||||
/// @throw JsonException
|
/// @throw JsonException
|
||||||
template<> QDateTime requireIsType<QDateTime>(const QJsonValue &value, const QString &what);
|
template <>
|
||||||
|
QDateTime requireIsType<QDateTime>(const QJsonValue& value, const QString& what);
|
||||||
/// @throw JsonException
|
/// @throw JsonException
|
||||||
template<> QVariant requireIsType<QVariant>(const QJsonValue &value, const QString &what);
|
template <>
|
||||||
|
QVariant requireIsType<QVariant>(const QJsonValue& value, const QString& what);
|
||||||
/// @throw JsonException
|
/// @throw JsonException
|
||||||
template<> QString requireIsType<QString>(const QJsonValue &value, const QString &what);
|
template <>
|
||||||
|
QString requireIsType<QString>(const QJsonValue& value, const QString& what);
|
||||||
/// @throw JsonException
|
/// @throw JsonException
|
||||||
template<> QUuid requireIsType<QUuid>(const QJsonValue &value, const QString &what);
|
template <>
|
||||||
|
QUuid requireIsType<QUuid>(const QJsonValue& value, const QString& what);
|
||||||
/// @throw JsonException
|
/// @throw JsonException
|
||||||
template<> QDir requireIsType<QDir>(const QJsonValue &value, const QString &what);
|
template <>
|
||||||
|
QDir requireIsType<QDir>(const QJsonValue& value, const QString& what);
|
||||||
/// @throw JsonException
|
/// @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
|
// the following functions are higher level functions, that make use of the above functions for
|
||||||
// type conversion
|
// type conversion
|
||||||
template <typename T>
|
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_;
|
return default_;
|
||||||
}
|
}
|
||||||
try
|
try {
|
||||||
{
|
|
||||||
return requireIsType<T>(value, what);
|
return requireIsType<T>(value, what);
|
||||||
}
|
} catch (const JsonException&) {
|
||||||
catch (const JsonException &)
|
|
||||||
{
|
|
||||||
return default_;
|
return default_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @throw JsonException
|
/// @throw JsonException
|
||||||
template <typename T>
|
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 + '\'');
|
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);
|
throw JsonException(localWhat + "s parent does not contain " + localWhat);
|
||||||
}
|
}
|
||||||
return requireIsType<T>(parent.value(key), localWhat);
|
return requireIsType<T>(parent.value(key), localWhat);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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 + '\'');
|
const QString localWhat = QString(what).replace("__placeholder__", '\'' + key + '\'');
|
||||||
if (!parent.contains(key))
|
if (!parent.contains(key)) {
|
||||||
{
|
|
||||||
return default_;
|
return default_;
|
||||||
}
|
}
|
||||||
return ensureIsType<T>(parent.value(key), default_, localWhat);
|
return ensureIsType<T>(parent.value(key), default_, localWhat);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
QVector<T> requireIsArrayOf(const QJsonDocument &doc)
|
QVector<T> requireIsArrayOf(const QJsonDocument& doc)
|
||||||
{
|
{
|
||||||
const QJsonArray array = requireArray(doc);
|
const QJsonArray array = requireArray(doc);
|
||||||
QVector<T> out;
|
QVector<T> out;
|
||||||
for (const QJsonValue val : array)
|
for (const QJsonValue val : array) {
|
||||||
{
|
|
||||||
out.append(requireIsType<T>(val, "Document"));
|
out.append(requireIsType<T>(val, "Document"));
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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);
|
const QJsonArray array = ensureIsType<QJsonArray>(value, QJsonArray(), what);
|
||||||
QVector<T> out;
|
QVector<T> out;
|
||||||
for (const QJsonValue val : array)
|
for (const QJsonValue val : array) {
|
||||||
{
|
|
||||||
out.append(requireIsType<T>(val, what));
|
out.append(requireIsType<T>(val, what));
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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 default_;
|
||||||
}
|
}
|
||||||
return ensureIsArrayOf<T>(value, what);
|
return ensureIsArrayOf<T>(value, what);
|
||||||
@ -219,45 +220,46 @@ QVector<T> ensureIsArrayOf(const QJsonValue &value, const QVector<T> default_, c
|
|||||||
|
|
||||||
/// @throw JsonException
|
/// @throw JsonException
|
||||||
template <typename T>
|
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 + '\'');
|
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);
|
throw JsonException(localWhat + "s parent does not contain " + localWhat);
|
||||||
}
|
}
|
||||||
return ensureIsArrayOf<T>(parent.value(key), localWhat);
|
return ensureIsArrayOf<T>(parent.value(key), localWhat);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
QVector<T> ensureIsArrayOf(const QJsonObject &parent, const QString &key,
|
QVector<T> ensureIsArrayOf(const QJsonObject& parent,
|
||||||
const QVector<T> &default_ = QVector<T>(), const QString &what = "__placeholder__")
|
const QString& key,
|
||||||
|
const QVector<T>& default_ = QVector<T>(),
|
||||||
|
const QString& what = "__placeholder__")
|
||||||
{
|
{
|
||||||
const QString localWhat = QString(what).replace("__placeholder__", '\'' + key + '\'');
|
const QString localWhat = QString(what).replace("__placeholder__", '\'' + key + '\'');
|
||||||
if (!parent.contains(key))
|
if (!parent.contains(key)) {
|
||||||
{
|
|
||||||
return default_;
|
return default_;
|
||||||
}
|
}
|
||||||
return ensureIsArrayOf<T>(parent.value(key), default_, localWhat);
|
return ensureIsArrayOf<T>(parent.value(key), default_, localWhat);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this macro part could be replaced by variadic functions that just pass on their arguments, but that wouldn't work well with IDE helpers
|
// 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) \
|
#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); \
|
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); \
|
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); \
|
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); \
|
{ \
|
||||||
|
return ensureIsType<TYPE>(parent, key, default_, what); \
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_HELPERFUNCTIONS(Array, QJsonArray)
|
JSON_HELPERFUNCTIONS(Array, QJsonArray)
|
||||||
@ -276,5 +278,5 @@ JSON_HELPERFUNCTIONS(Variant, QVariant)
|
|||||||
|
|
||||||
#undef JSON_HELPERFUNCTIONS
|
#undef JSON_HELPERFUNCTIONS
|
||||||
|
|
||||||
}
|
} // namespace Json
|
||||||
using JSONValidationError = Json::JsonException;
|
using JSONValidationError = Json::JsonException;
|
||||||
|
@ -1,42 +1,26 @@
|
|||||||
#include "KonamiCode.h"
|
#include "KonamiCode.h"
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const std::array<Qt::Key, 10> konamiCode =
|
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 } };
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KonamiCode::KonamiCode(QObject* parent) : QObject(parent) {}
|
||||||
|
|
||||||
void KonamiCode::input(QEvent* event)
|
void KonamiCode::input(QEvent* event)
|
||||||
{
|
{
|
||||||
if( event->type() == QEvent::KeyPress )
|
if (event->type() == QEvent::KeyPress) {
|
||||||
{
|
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
||||||
QKeyEvent *keyEvent = static_cast<QKeyEvent*>( event );
|
|
||||||
auto key = Qt::Key(keyEvent->key());
|
auto key = Qt::Key(keyEvent->key());
|
||||||
if(key == konamiCode[m_progress])
|
if (key == konamiCode[m_progress]) {
|
||||||
{
|
m_progress++;
|
||||||
m_progress ++;
|
} else {
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_progress = 0;
|
m_progress = 0;
|
||||||
}
|
}
|
||||||
if(m_progress == static_cast<int>(konamiCode.size()))
|
if (m_progress == static_cast<int>(konamiCode.size())) {
|
||||||
{
|
|
||||||
m_progress = 0;
|
m_progress = 0;
|
||||||
emit triggered();
|
emit triggered();
|
||||||
}
|
}
|
||||||
|
@ -2,16 +2,15 @@
|
|||||||
|
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
|
|
||||||
class KonamiCode : public QObject
|
class KonamiCode : public QObject {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
KonamiCode(QObject *parent = 0);
|
KonamiCode(QObject* parent = 0);
|
||||||
void input(QEvent *event);
|
void input(QEvent* event);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void triggered();
|
void triggered();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_progress = 0;
|
int m_progress = 0;
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// 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 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -34,44 +34,41 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "LaunchController.h"
|
#include "LaunchController.h"
|
||||||
#include "minecraft/auth/AccountList.h"
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
#include "minecraft/auth/AccountList.h"
|
||||||
|
|
||||||
#include "ui/MainWindow.h"
|
|
||||||
#include "ui/InstanceWindow.h"
|
#include "ui/InstanceWindow.h"
|
||||||
|
#include "ui/MainWindow.h"
|
||||||
#include "ui/dialogs/CustomMessageBox.h"
|
#include "ui/dialogs/CustomMessageBox.h"
|
||||||
#include "ui/dialogs/ProfileSelectDialog.h"
|
|
||||||
#include "ui/dialogs/ProgressDialog.h"
|
|
||||||
#include "ui/dialogs/EditAccountDialog.h"
|
#include "ui/dialogs/EditAccountDialog.h"
|
||||||
|
#include "ui/dialogs/ProfileSelectDialog.h"
|
||||||
#include "ui/dialogs/ProfileSetupDialog.h"
|
#include "ui/dialogs/ProfileSetupDialog.h"
|
||||||
|
#include "ui/dialogs/ProgressDialog.h"
|
||||||
|
|
||||||
#include <QLineEdit>
|
|
||||||
#include <QInputDialog>
|
|
||||||
#include <QStringList>
|
|
||||||
#include <QHostInfo>
|
|
||||||
#include <QList>
|
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
|
#include <QHostInfo>
|
||||||
|
#include <QInputDialog>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QList>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
#include "BuildConfig.h"
|
#include "BuildConfig.h"
|
||||||
#include "JavaCommon.h"
|
#include "JavaCommon.h"
|
||||||
#include "tasks/Task.h"
|
|
||||||
#include "minecraft/auth/AccountTask.h"
|
|
||||||
#include "launch/steps/TextPrint.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()
|
void LaunchController::executeTask()
|
||||||
{
|
{
|
||||||
if (!m_instance)
|
if (!m_instance) {
|
||||||
{
|
|
||||||
emitFailed(tr("No instance specified!"));
|
emitFailed(tr("No instance specified!"));
|
||||||
return;
|
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."));
|
emitFailed(tr("Invalid Java arguments specified. Please fix this first."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -81,32 +78,25 @@ void LaunchController::executeTask()
|
|||||||
|
|
||||||
void LaunchController::decideAccount()
|
void LaunchController::decideAccount()
|
||||||
{
|
{
|
||||||
if(m_accountToUse) {
|
if (m_accountToUse) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find an account to use.
|
// Find an account to use.
|
||||||
auto accounts = APPLICATION->accounts();
|
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.
|
// Tell the user they need to log in at least one account in order to play.
|
||||||
auto reply = CustomMessageBox::selectable(
|
auto reply = CustomMessageBox::selectable(m_parentWidget, tr("No Accounts"),
|
||||||
m_parentWidget,
|
tr("In order to play Minecraft, you must have at least one Microsoft or Mojang "
|
||||||
tr("No Accounts"),
|
"account logged in. Mojang accounts can only be used offline. "
|
||||||
tr("In order to play Minecraft, you must have at least one Microsoft or Mojang "
|
"Would you like to open the account manager to add an account now?"),
|
||||||
"account logged in. Mojang accounts can only be used offline. "
|
QMessageBox::Information, QMessageBox::Yes | QMessageBox::No)
|
||||||
"Would you like to open the account manager to add an account now?"),
|
->exec();
|
||||||
QMessageBox::Information,
|
|
||||||
QMessageBox::Yes | QMessageBox::No
|
|
||||||
)->exec();
|
|
||||||
|
|
||||||
if (reply == QMessageBox::Yes)
|
if (reply == QMessageBox::Yes) {
|
||||||
{
|
|
||||||
// Open the account manager.
|
// Open the account manager.
|
||||||
APPLICATION->ShowGlobalSettings(m_parentWidget, "accounts");
|
APPLICATION->ShowGlobalSettings(m_parentWidget, "accounts");
|
||||||
}
|
} else if (reply == QMessageBox::No) {
|
||||||
else if (reply == QMessageBox::No)
|
|
||||||
{
|
|
||||||
// Do not open "profile select" dialog.
|
// Do not open "profile select" dialog.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -121,14 +111,10 @@ void LaunchController::decideAccount()
|
|||||||
m_accountToUse = accounts->at(instanceAccountIndex);
|
m_accountToUse = accounts->at(instanceAccountIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_accountToUse)
|
if (!m_accountToUse) {
|
||||||
{
|
|
||||||
// If no default account is set, ask the user which one to use.
|
// If no default account is set, ask the user which one to use.
|
||||||
ProfileSelectDialog selectDialog(
|
ProfileSelectDialog selectDialog(tr("Which account would you like to use?"), ProfileSelectDialog::GlobalDefaultCheckbox,
|
||||||
tr("Which account would you like to use?"),
|
m_parentWidget);
|
||||||
ProfileSelectDialog::GlobalDefaultCheckbox,
|
|
||||||
m_parentWidget
|
|
||||||
);
|
|
||||||
|
|
||||||
selectDialog.exec();
|
selectDialog.exec();
|
||||||
|
|
||||||
@ -142,13 +128,12 @@ void LaunchController::decideAccount()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LaunchController::login()
|
||||||
void LaunchController::login() {
|
{
|
||||||
decideAccount();
|
decideAccount();
|
||||||
|
|
||||||
// if no account is selected, we bail
|
// if no account is selected, we bail
|
||||||
if (!m_accountToUse)
|
if (!m_accountToUse) {
|
||||||
{
|
|
||||||
emitFailed(tr("No account selected for launch."));
|
emitFailed(tr("No account selected for launch."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -157,15 +142,11 @@ void LaunchController::login() {
|
|||||||
bool tryagain = true;
|
bool tryagain = true;
|
||||||
unsigned int tries = 0;
|
unsigned int tries = 0;
|
||||||
|
|
||||||
while (tryagain)
|
while (tryagain) {
|
||||||
{
|
|
||||||
if (tries > 0 && tries % 3 == 0) {
|
if (tries > 0 && tries % 3 == 0) {
|
||||||
auto result = QMessageBox::question(
|
auto result =
|
||||||
m_parentWidget,
|
QMessageBox::question(m_parentWidget, tr("Continue launch?"),
|
||||||
tr("Continue launch?"),
|
tr("It looks like we couldn't launch after %1 tries. Do you want to continue trying?").arg(tries));
|
||||||
tr("It looks like we couldn't launch after %1 tries. Do you want to continue trying?")
|
|
||||||
.arg(tries)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result == QMessageBox::No) {
|
if (result == QMessageBox::No) {
|
||||||
emitAborted();
|
emitAborted();
|
||||||
@ -179,60 +160,48 @@ void LaunchController::login() {
|
|||||||
m_accountToUse->fillSession(m_session);
|
m_accountToUse->fillSession(m_session);
|
||||||
|
|
||||||
// Launch immediately in true offline mode
|
// Launch immediately in true offline mode
|
||||||
if(m_accountToUse->isOffline()) {
|
if (m_accountToUse->isOffline()) {
|
||||||
launchInstance();
|
launchInstance();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(m_accountToUse->accountState()) {
|
switch (m_accountToUse->accountState()) {
|
||||||
case AccountState::Offline: {
|
case AccountState::Offline: {
|
||||||
m_session->wants_online = false;
|
m_session->wants_online = false;
|
||||||
}
|
}
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case AccountState::Online: {
|
case AccountState::Online: {
|
||||||
if(!m_session->wants_online) {
|
if (!m_session->wants_online) {
|
||||||
// we ask the user for a player name
|
// we ask the user for a player name
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
|
|
||||||
QString message = tr("Choose your offline mode player name.");
|
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.");
|
message = tr("Choose your demo mode player name.");
|
||||||
}
|
}
|
||||||
|
|
||||||
QString lastOfflinePlayerName = APPLICATION->settings()->get("LastOfflinePlayerName").toString();
|
QString lastOfflinePlayerName = APPLICATION->settings()->get("LastOfflinePlayerName").toString();
|
||||||
QString usedname = lastOfflinePlayerName.isEmpty() ? m_session->player_name : lastOfflinePlayerName;
|
QString usedname = lastOfflinePlayerName.isEmpty() ? m_session->player_name : lastOfflinePlayerName;
|
||||||
QString name = QInputDialog::getText(
|
QString name = QInputDialog::getText(m_parentWidget, tr("Player name"), message, QLineEdit::Normal, usedname, &ok);
|
||||||
m_parentWidget,
|
if (!ok) {
|
||||||
tr("Player name"),
|
|
||||||
message,
|
|
||||||
QLineEdit::Normal,
|
|
||||||
usedname,
|
|
||||||
&ok
|
|
||||||
);
|
|
||||||
if (!ok)
|
|
||||||
{
|
|
||||||
tryagain = false;
|
tryagain = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (name.length())
|
if (name.length()) {
|
||||||
{
|
|
||||||
usedname = name;
|
usedname = name;
|
||||||
APPLICATION->settings()->set("LastOfflinePlayerName", usedname);
|
APPLICATION->settings()->set("LastOfflinePlayerName", usedname);
|
||||||
}
|
}
|
||||||
m_session->MakeOffline(usedname);
|
m_session->MakeOffline(usedname);
|
||||||
// offline flavored game from here :3
|
// offline flavored game from here :3
|
||||||
}
|
}
|
||||||
if(m_accountToUse->ownsMinecraft()) {
|
if (m_accountToUse->ownsMinecraft()) {
|
||||||
if(!m_accountToUse->hasProfile()) {
|
if (!m_accountToUse->hasProfile()) {
|
||||||
// Now handle setting up a profile name here...
|
// Now handle setting up a profile name here...
|
||||||
ProfileSetupDialog dialog(m_accountToUse, m_parentWidget);
|
ProfileSetupDialog dialog(m_accountToUse, m_parentWidget);
|
||||||
if (dialog.exec() == QDialog::Accepted)
|
if (dialog.exec() == QDialog::Accepted) {
|
||||||
{
|
|
||||||
tryagain = true;
|
tryagain = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
emitFailed(tr("Received undetermined session status during login."));
|
emitFailed(tr("Received undetermined session status during login."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -240,24 +209,24 @@ void LaunchController::login() {
|
|||||||
// we own Minecraft, there is a profile, it's all ready to go!
|
// we own Minecraft, there is a profile, it's all ready to go!
|
||||||
launchInstance();
|
launchInstance();
|
||||||
return;
|
return;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// play demo ?
|
// play demo ?
|
||||||
QMessageBox box(m_parentWidget);
|
QMessageBox box(m_parentWidget);
|
||||||
box.setWindowTitle(tr("Play demo?"));
|
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);
|
box.setIcon(QMessageBox::Warning);
|
||||||
auto demoButton = box.addButton(tr("Play Demo"), QMessageBox::ButtonRole::YesRole);
|
auto demoButton = box.addButton(tr("Play Demo"), QMessageBox::ButtonRole::YesRole);
|
||||||
auto cancelButton = box.addButton(tr("Cancel"), QMessageBox::ButtonRole::NoRole);
|
auto cancelButton = box.addButton(tr("Cancel"), QMessageBox::ButtonRole::NoRole);
|
||||||
box.setDefaultButton(cancelButton);
|
box.setDefaultButton(cancelButton);
|
||||||
|
|
||||||
box.exec();
|
box.exec();
|
||||||
if(box.clickedButton() == demoButton) {
|
if (box.clickedButton() == demoButton) {
|
||||||
// play demo here
|
// play demo here
|
||||||
m_session->MakeDemo();
|
m_session->MakeDemo();
|
||||||
launchInstance();
|
launchInstance();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
emitFailed(tr("Launch cancelled - account does not own Minecraft."));
|
emitFailed(tr("Launch cancelled - account does not own Minecraft."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -272,8 +241,7 @@ void LaunchController::login() {
|
|||||||
case AccountState::Working: {
|
case AccountState::Working: {
|
||||||
// refresh is in progress, we need to wait for it to finish to proceed.
|
// refresh is in progress, we need to wait for it to finish to proceed.
|
||||||
ProgressDialog progDialog(m_parentWidget);
|
ProgressDialog progDialog(m_parentWidget);
|
||||||
if (m_online)
|
if (m_online) {
|
||||||
{
|
|
||||||
progDialog.setSkipButton(true, tr("Play Offline"));
|
progDialog.setSkipButton(true, tr("Play Offline"));
|
||||||
}
|
}
|
||||||
auto task = m_accountToUse->currentTask();
|
auto task = m_accountToUse->currentTask();
|
||||||
@ -288,37 +256,24 @@ void LaunchController::login() {
|
|||||||
*/
|
*/
|
||||||
case AccountState::Expired: {
|
case AccountState::Expired: {
|
||||||
auto errorString = tr("The account has expired and needs to be logged into manually again.");
|
auto errorString = tr("The account has expired and needs to be logged into manually again.");
|
||||||
QMessageBox::warning(
|
QMessageBox::warning(m_parentWidget, tr("Account refresh failed"), errorString, QMessageBox::StandardButton::Ok,
|
||||||
m_parentWidget,
|
QMessageBox::StandardButton::Ok);
|
||||||
tr("Account refresh failed"),
|
|
||||||
errorString,
|
|
||||||
QMessageBox::StandardButton::Ok,
|
|
||||||
QMessageBox::StandardButton::Ok
|
|
||||||
);
|
|
||||||
emitFailed(errorString);
|
emitFailed(errorString);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case AccountState::Disabled: {
|
case AccountState::Disabled: {
|
||||||
auto errorString = tr("The launcher's client identification has changed. Please remove this account and add it again.");
|
auto errorString = tr("The launcher's client identification has changed. Please remove this account and add it again.");
|
||||||
QMessageBox::warning(
|
QMessageBox::warning(m_parentWidget, tr("Client identification changed"), errorString, QMessageBox::StandardButton::Ok,
|
||||||
m_parentWidget,
|
QMessageBox::StandardButton::Ok);
|
||||||
tr("Client identification changed"),
|
|
||||||
errorString,
|
|
||||||
QMessageBox::StandardButton::Ok,
|
|
||||||
QMessageBox::StandardButton::Ok
|
|
||||||
);
|
|
||||||
emitFailed(errorString);
|
emitFailed(errorString);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case AccountState::Gone: {
|
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.");
|
auto errorString =
|
||||||
QMessageBox::warning(
|
tr("The account no longer exists on the servers. It may have been migrated, in which case please add the new account "
|
||||||
m_parentWidget,
|
"you migrated this one to.");
|
||||||
tr("Account gone"),
|
QMessageBox::warning(m_parentWidget, tr("Account gone"), errorString, QMessageBox::StandardButton::Ok,
|
||||||
errorString,
|
QMessageBox::StandardButton::Ok);
|
||||||
QMessageBox::StandardButton::Ok,
|
|
||||||
QMessageBox::StandardButton::Ok
|
|
||||||
);
|
|
||||||
emitFailed(errorString);
|
emitFailed(errorString);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -332,48 +287,45 @@ void LaunchController::launchInstance()
|
|||||||
Q_ASSERT_X(m_instance != NULL, "launchInstance", "instance is NULL");
|
Q_ASSERT_X(m_instance != NULL, "launchInstance", "instance is NULL");
|
||||||
Q_ASSERT_X(m_session.get() != nullptr, "launchInstance", "session 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."));
|
QMessageBox::critical(m_parentWidget, tr("Error!"), tr("Couldn't load the instance profile."));
|
||||||
emitFailed(tr("Couldn't load the instance profile."));
|
emitFailed(tr("Couldn't load the instance profile."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_launcher = m_instance->createLaunchTask(m_session, m_serverToJoin);
|
m_launcher = m_instance->createLaunchTask(m_session, m_serverToJoin);
|
||||||
if (!m_launcher)
|
if (!m_launcher) {
|
||||||
{
|
|
||||||
emitFailed(tr("Couldn't instantiate a launcher."));
|
emitFailed(tr("Couldn't instantiate a launcher."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto console = qobject_cast<InstanceWindow *>(m_parentWidget);
|
auto console = qobject_cast<InstanceWindow*>(m_parentWidget);
|
||||||
auto showConsole = m_instance->settings()->get("ShowConsole").toBool();
|
auto showConsole = m_instance->settings()->get("ShowConsole").toBool();
|
||||||
if(!console && showConsole)
|
if (!console && showConsole) {
|
||||||
{
|
|
||||||
APPLICATION->showInstanceWindow(m_instance);
|
APPLICATION->showInstanceWindow(m_instance);
|
||||||
}
|
}
|
||||||
connect(m_launcher.get(), &LaunchTask::readyForLaunch, this, &LaunchController::readyForLaunch);
|
connect(m_launcher.get(), &LaunchTask::readyForLaunch, this, &LaunchController::readyForLaunch);
|
||||||
connect(m_launcher.get(), &LaunchTask::succeeded, this, &LaunchController::onSucceeded);
|
connect(m_launcher.get(), &LaunchTask::succeeded, this, &LaunchController::onSucceeded);
|
||||||
connect(m_launcher.get(), &LaunchTask::failed, this, &LaunchController::onFailed);
|
connect(m_launcher.get(), &LaunchTask::failed, this, &LaunchController::onFailed);
|
||||||
connect(m_launcher.get(), &LaunchTask::requestProgress, this, &LaunchController::onProgressRequested);
|
connect(m_launcher.get(), &LaunchTask::requestProgress, this, &LaunchController::onProgressRequested);
|
||||||
|
|
||||||
// Prepend Online and Auth Status
|
// Prepend Online and Auth Status
|
||||||
QString online_mode;
|
QString online_mode;
|
||||||
if(m_session->wants_online) {
|
if (m_session->wants_online) {
|
||||||
online_mode = "online";
|
online_mode = "online";
|
||||||
|
|
||||||
// Prepend Server Status
|
// 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 = "";
|
QString resolved_servers = "";
|
||||||
QHostInfo host_info;
|
QHostInfo host_info;
|
||||||
|
|
||||||
for(QString server : servers) {
|
for (QString server : servers) {
|
||||||
host_info = QHostInfo::fromName(server);
|
host_info = QHostInfo::fromName(server);
|
||||||
resolved_servers = resolved_servers + server + " resolves to:\n [";
|
resolved_servers = resolved_servers + server + " resolves to:\n [";
|
||||||
if(!host_info.addresses().isEmpty()) {
|
if (!host_info.addresses().isEmpty()) {
|
||||||
for(QHostAddress address : host_info.addresses()) {
|
for (QHostAddress address : host_info.addresses()) {
|
||||||
resolved_servers = resolved_servers + address.toString();
|
resolved_servers = resolved_servers + address.toString();
|
||||||
if(!host_info.addresses().endsWith(address)) {
|
if (!host_info.addresses().endsWith(address)) {
|
||||||
resolved_servers = resolved_servers + ", ";
|
resolved_servers = resolved_servers + ", ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -387,11 +339,13 @@ void LaunchController::launchInstance()
|
|||||||
online_mode = m_demo ? "demo" : "offline";
|
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
|
// 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->prependStep(makeShared<TextPrint>(m_launcher.get(), versionString + "\n\n", MessageLevel::Launcher));
|
||||||
}
|
}
|
||||||
m_launcher->start();
|
m_launcher->start();
|
||||||
@ -399,28 +353,26 @@ void LaunchController::launchInstance()
|
|||||||
|
|
||||||
void LaunchController::readyForLaunch()
|
void LaunchController::readyForLaunch()
|
||||||
{
|
{
|
||||||
if (!m_profiler)
|
if (!m_profiler) {
|
||||||
{
|
|
||||||
m_launcher->proceed();
|
m_launcher->proceed();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString error;
|
QString error;
|
||||||
if (!m_profiler->check(&error))
|
if (!m_profiler->check(&error)) {
|
||||||
{
|
|
||||||
m_launcher->abort();
|
m_launcher->abort();
|
||||||
QMessageBox::critical(m_parentWidget, tr("Error!"), tr("Couldn't start profiler: %1").arg(error));
|
QMessageBox::critical(m_parentWidget, tr("Error!"), tr("Couldn't start profiler: %1").arg(error));
|
||||||
emitFailed("Profiler startup failed!");
|
emitFailed("Profiler startup failed!");
|
||||||
return;
|
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;
|
QMessageBox msg;
|
||||||
msg.setText(tr("The game launch is delayed until you press the "
|
msg.setText(tr("The game launch is delayed until you press the "
|
||||||
"button. This is the right time to setup the profiler, as 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.setWindowTitle(tr("Waiting."));
|
||||||
msg.setIcon(QMessageBox::Information);
|
msg.setIcon(QMessageBox::Information);
|
||||||
msg.addButton(tr("Launch"), QMessageBox::AcceptRole);
|
msg.addButton(tr("Launch"), QMessageBox::AcceptRole);
|
||||||
@ -428,8 +380,7 @@ void LaunchController::readyForLaunch()
|
|||||||
msg.exec();
|
msg.exec();
|
||||||
m_launcher->proceed();
|
m_launcher->proceed();
|
||||||
});
|
});
|
||||||
connect(profilerInstance, &BaseProfiler::abortLaunch, [this](const QString & message)
|
connect(profilerInstance, &BaseProfiler::abortLaunch, [this](const QString& message) {
|
||||||
{
|
|
||||||
QMessageBox msg;
|
QMessageBox msg;
|
||||||
msg.setText(tr("Couldn't start the profiler: %1").arg(message));
|
msg.setText(tr("Couldn't start the profiler: %1").arg(message));
|
||||||
msg.setWindowTitle(tr("Error"));
|
msg.setWindowTitle(tr("Error"));
|
||||||
@ -450,8 +401,7 @@ void LaunchController::onSucceeded()
|
|||||||
|
|
||||||
void LaunchController::onFailed(QString reason)
|
void LaunchController::onFailed(QString reason)
|
||||||
{
|
{
|
||||||
if(m_instance->settings()->get("ShowConsoleOnError").toBool())
|
if (m_instance->settings()->get("ShowConsoleOnError").toBool()) {
|
||||||
{
|
|
||||||
APPLICATION->showInstanceWindow(m_instance, "console");
|
APPLICATION->showInstanceWindow(m_instance, "console");
|
||||||
}
|
}
|
||||||
emitFailed(reason);
|
emitFailed(reason);
|
||||||
@ -467,21 +417,18 @@ void LaunchController::onProgressRequested(Task* task)
|
|||||||
|
|
||||||
bool LaunchController::abort()
|
bool LaunchController::abort()
|
||||||
{
|
{
|
||||||
if(!m_launcher)
|
if (!m_launcher) {
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(!m_launcher->canAbort())
|
if (!m_launcher->canAbort()) {
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto response = CustomMessageBox::selectable(
|
auto response = CustomMessageBox::selectable(m_parentWidget, tr("Kill Minecraft?"),
|
||||||
m_parentWidget, tr("Kill Minecraft?"),
|
tr("This can cause the instance to get corrupted and should only be used if Minecraft "
|
||||||
tr("This can cause the instance to get corrupted and should only be used if Minecraft "
|
"is frozen for some reason"),
|
||||||
"is frozen for some reason"),
|
QMessageBox::Question, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)
|
||||||
QMessageBox::Question, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)->exec();
|
->exec();
|
||||||
if (response == QMessageBox::Yes)
|
if (response == QMessageBox::Yes) {
|
||||||
{
|
|
||||||
return m_launcher->abort();
|
return m_launcher->abort();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// 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 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -34,81 +34,61 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <QObject>
|
|
||||||
#include <BaseInstance.h>
|
#include <BaseInstance.h>
|
||||||
#include <tools/BaseProfiler.h>
|
#include <tools/BaseProfiler.h>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
#include "minecraft/launch/MinecraftServerTarget.h"
|
|
||||||
#include "minecraft/auth/MinecraftAccount.h"
|
#include "minecraft/auth/MinecraftAccount.h"
|
||||||
|
#include "minecraft/launch/MinecraftServerTarget.h"
|
||||||
|
|
||||||
class InstanceWindow;
|
class InstanceWindow;
|
||||||
class LaunchController: public Task
|
class LaunchController : public Task {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
void executeTask() override;
|
void executeTask() override;
|
||||||
|
|
||||||
LaunchController(QObject * parent = nullptr);
|
LaunchController(QObject* parent = nullptr);
|
||||||
virtual ~LaunchController(){};
|
virtual ~LaunchController(){};
|
||||||
|
|
||||||
void setInstance(InstancePtr instance) {
|
void setInstance(InstancePtr instance) { m_instance = instance; }
|
||||||
m_instance = instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstancePtr instance() {
|
InstancePtr instance() { return m_instance; }
|
||||||
return m_instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setOnline(bool online) {
|
void setOnline(bool online) { m_online = online; }
|
||||||
m_online = online;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setDemo(bool demo) {
|
void setDemo(bool demo) { m_demo = demo; }
|
||||||
m_demo = demo;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setProfiler(BaseProfilerFactory *profiler) {
|
void setProfiler(BaseProfilerFactory* profiler) { m_profiler = profiler; }
|
||||||
m_profiler = profiler;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setParentWidget(QWidget * widget) {
|
void setParentWidget(QWidget* widget) { m_parentWidget = widget; }
|
||||||
m_parentWidget = widget;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setServerToJoin(MinecraftServerTargetPtr serverToJoin) {
|
void setServerToJoin(MinecraftServerTargetPtr serverToJoin) { m_serverToJoin = std::move(serverToJoin); }
|
||||||
m_serverToJoin = std::move(serverToJoin);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setAccountToUse(MinecraftAccountPtr accountToUse) {
|
void setAccountToUse(MinecraftAccountPtr accountToUse) { m_accountToUse = std::move(accountToUse); }
|
||||||
m_accountToUse = std::move(accountToUse);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString id()
|
QString id() { return m_instance->id(); }
|
||||||
{
|
|
||||||
return m_instance->id();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool abort() override;
|
bool abort() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void login();
|
void login();
|
||||||
void launchInstance();
|
void launchInstance();
|
||||||
void decideAccount();
|
void decideAccount();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void readyForLaunch();
|
void readyForLaunch();
|
||||||
|
|
||||||
void onSucceeded();
|
void onSucceeded();
|
||||||
void onFailed(QString reason);
|
void onFailed(QString reason);
|
||||||
void onProgressRequested(Task *task);
|
void onProgressRequested(Task* task);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BaseProfilerFactory *m_profiler = nullptr;
|
BaseProfilerFactory* m_profiler = nullptr;
|
||||||
bool m_online = true;
|
bool m_online = true;
|
||||||
bool m_demo = false;
|
bool m_demo = false;
|
||||||
InstancePtr m_instance;
|
InstancePtr m_instance;
|
||||||
QWidget * m_parentWidget = nullptr;
|
QWidget* m_parentWidget = nullptr;
|
||||||
InstanceWindow *m_console = nullptr;
|
InstanceWindow* m_console = nullptr;
|
||||||
MinecraftAccountPtr m_accountToUse = nullptr;
|
MinecraftAccountPtr m_accountToUse = nullptr;
|
||||||
AuthSessionPtr m_session;
|
AuthSessionPtr m_session;
|
||||||
shared_qobject_ptr<LaunchTask> m_launcher;
|
shared_qobject_ptr<LaunchTask> m_launcher;
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
#include <QTextDecoder>
|
#include <QTextDecoder>
|
||||||
#include "MessageLevel.h"
|
#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.
|
// QProcess has a strange interface... let's map a lot of those into a few.
|
||||||
connect(this, &QProcess::readyReadStandardOutput, this, &LoggedProcess::on_stdOut);
|
connect(this, &QProcess::readyReadStandardOutput, this, &LoggedProcess::on_stdOut);
|
||||||
@ -51,8 +51,7 @@ LoggedProcess::LoggedProcess(QObject *parent) : QProcess(parent)
|
|||||||
|
|
||||||
LoggedProcess::~LoggedProcess()
|
LoggedProcess::~LoggedProcess()
|
||||||
{
|
{
|
||||||
if(m_is_detachable)
|
if (m_is_detachable) {
|
||||||
{
|
|
||||||
setProcessState(QProcess::NotRunning);
|
setProcessState(QProcess::NotRunning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,39 +94,31 @@ void LoggedProcess::on_exit(int exit_code, QProcess::ExitStatus status)
|
|||||||
m_exit_code = exit_code;
|
m_exit_code = exit_code;
|
||||||
|
|
||||||
// based on state, send signals
|
// based on state, send signals
|
||||||
if (!m_is_aborting)
|
if (!m_is_aborting) {
|
||||||
{
|
if (status == QProcess::NormalExit) {
|
||||||
if (status == QProcess::NormalExit)
|
|
||||||
{
|
|
||||||
//: Message displayed on instance exit
|
//: 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);
|
changeState(LoggedProcess::Finished);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
//: Message displayed on instance crashed
|
//: Message displayed on instance crashed
|
||||||
if(exit_code == -1)
|
if (exit_code == -1)
|
||||||
emit log({tr("Process crashed.")}, MessageLevel::Launcher);
|
emit log({ tr("Process crashed.") }, MessageLevel::Launcher);
|
||||||
else
|
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);
|
changeState(LoggedProcess::Crashed);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
//: Message displayed after the instance exits due to kill request
|
//: 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);
|
changeState(LoggedProcess::Aborted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoggedProcess::on_error(QProcess::ProcessError error)
|
void LoggedProcess::on_error(QProcess::ProcessError error)
|
||||||
{
|
{
|
||||||
switch(error)
|
switch (error) {
|
||||||
{
|
case QProcess::FailedToStart: {
|
||||||
case QProcess::FailedToStart:
|
emit log({ tr("The process failed to start.") }, MessageLevel::Fatal);
|
||||||
{
|
|
||||||
emit log({tr("The process failed to start.")}, MessageLevel::Fatal);
|
|
||||||
changeState(LoggedProcess::FailedToStart);
|
changeState(LoggedProcess::FailedToStart);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -154,7 +145,7 @@ int LoggedProcess::exitCode() const
|
|||||||
|
|
||||||
void LoggedProcess::changeState(LoggedProcess::State state)
|
void LoggedProcess::changeState(LoggedProcess::State state)
|
||||||
{
|
{
|
||||||
if(state == m_state)
|
if (state == m_state)
|
||||||
return;
|
return;
|
||||||
m_state = state;
|
m_state = state;
|
||||||
emit stateChanged(m_state);
|
emit stateChanged(m_state);
|
||||||
@ -167,24 +158,19 @@ LoggedProcess::State LoggedProcess::state() const
|
|||||||
|
|
||||||
void LoggedProcess::on_stateChange(QProcess::ProcessState state)
|
void LoggedProcess::on_stateChange(QProcess::ProcessState state)
|
||||||
{
|
{
|
||||||
switch(state)
|
switch (state) {
|
||||||
{
|
|
||||||
case QProcess::NotRunning:
|
case QProcess::NotRunning:
|
||||||
break; // let's not - there are too many that handle this already.
|
break; // let's not - there are too many that handle this already.
|
||||||
case QProcess::Starting:
|
case QProcess::Starting: {
|
||||||
{
|
if (m_state != LoggedProcess::NotRunning) {
|
||||||
if(m_state != LoggedProcess::NotRunning)
|
qWarning() << "Wrong state change for process from state" << m_state << "to" << (int)LoggedProcess::Starting;
|
||||||
{
|
|
||||||
qWarning() << "Wrong state change for process from state" << m_state << "to" << (int) LoggedProcess::Starting;
|
|
||||||
}
|
}
|
||||||
changeState(LoggedProcess::Starting);
|
changeState(LoggedProcess::Starting);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case QProcess::Running:
|
case QProcess::Running: {
|
||||||
{
|
if (m_state != LoggedProcess::Starting) {
|
||||||
if(m_state != LoggedProcess::Starting)
|
qWarning() << "Wrong state change for process from state" << m_state << "to" << (int)LoggedProcess::Running;
|
||||||
{
|
|
||||||
qWarning() << "Wrong state change for process from state" << m_state << "to" << (int) LoggedProcess::Running;
|
|
||||||
}
|
}
|
||||||
changeState(LoggedProcess::Running);
|
changeState(LoggedProcess::Running);
|
||||||
return;
|
return;
|
||||||
|
@ -43,22 +43,12 @@
|
|||||||
* This is a basic process.
|
* This is a basic process.
|
||||||
* It has line-based logging support and hides some of the nasty bits.
|
* It has line-based logging support and hides some of the nasty bits.
|
||||||
*/
|
*/
|
||||||
class LoggedProcess : public QProcess
|
class LoggedProcess : public QProcess {
|
||||||
{
|
Q_OBJECT
|
||||||
Q_OBJECT
|
public:
|
||||||
public:
|
enum State { NotRunning, Starting, FailedToStart, Running, Finished, Crashed, Aborted };
|
||||||
enum State
|
|
||||||
{
|
|
||||||
NotRunning,
|
|
||||||
Starting,
|
|
||||||
FailedToStart,
|
|
||||||
Running,
|
|
||||||
Finished,
|
|
||||||
Crashed,
|
|
||||||
Aborted
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit LoggedProcess(QObject* parent = 0);
|
explicit LoggedProcess(QObject* parent = 0);
|
||||||
virtual ~LoggedProcess();
|
virtual ~LoggedProcess();
|
||||||
|
|
||||||
@ -67,30 +57,29 @@ public:
|
|||||||
|
|
||||||
void setDetachable(bool detachable);
|
void setDetachable(bool detachable);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void log(QStringList lines, MessageLevel::Enum level);
|
void log(QStringList lines, MessageLevel::Enum level);
|
||||||
void stateChanged(LoggedProcess::State state);
|
void stateChanged(LoggedProcess::State state);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
/**
|
/**
|
||||||
* @brief kill the process - equivalent to kill -9
|
* @brief kill the process - equivalent to kill -9
|
||||||
*/
|
*/
|
||||||
void kill();
|
void kill();
|
||||||
|
|
||||||
|
private slots:
|
||||||
private slots:
|
|
||||||
void on_stdErr();
|
void on_stdErr();
|
||||||
void on_stdOut();
|
void on_stdOut();
|
||||||
void on_exit(int exit_code, QProcess::ExitStatus status);
|
void on_exit(int exit_code, QProcess::ExitStatus status);
|
||||||
void on_error(QProcess::ProcessError error);
|
void on_error(QProcess::ProcessError error);
|
||||||
void on_stateChange(QProcess::ProcessState);
|
void on_stateChange(QProcess::ProcessState);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void changeState(LoggedProcess::State state);
|
void changeState(LoggedProcess::State state);
|
||||||
|
|
||||||
QStringList reprocess(const QByteArray& data, QTextDecoder& decoder);
|
QStringList reprocess(const QByteArray& data, QTextDecoder& decoder);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QTextDecoder m_err_decoder = QTextDecoder(QTextCodec::codecForLocale());
|
QTextDecoder m_err_decoder = QTextDecoder(QTextCodec::codecForLocale());
|
||||||
QTextDecoder m_out_decoder = QTextDecoder(QTextCodec::codecForLocale());
|
QTextDecoder m_out_decoder = QTextDecoder(QTextCodec::codecForLocale());
|
||||||
QString m_leftover_line;
|
QString m_leftover_line;
|
||||||
|
@ -17,30 +17,29 @@
|
|||||||
|
|
||||||
#include <MMCTime.h>
|
#include <MMCTime.h>
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
#include <QObject>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
|
|
||||||
QString Time::prettifyDuration(int64_t duration) {
|
QString Time::prettifyDuration(int64_t duration)
|
||||||
int seconds = (int) (duration % 60);
|
{
|
||||||
|
int seconds = (int)(duration % 60);
|
||||||
duration /= 60;
|
duration /= 60;
|
||||||
int minutes = (int) (duration % 60);
|
int minutes = (int)(duration % 60);
|
||||||
duration /= 60;
|
duration /= 60;
|
||||||
int hours = (int) (duration % 24);
|
int hours = (int)(duration % 24);
|
||||||
int days = (int) (duration / 24);
|
int days = (int)(duration / 24);
|
||||||
if((hours == 0)&&(days == 0))
|
if ((hours == 0) && (days == 0)) {
|
||||||
{
|
|
||||||
return QObject::tr("%1min %2s").arg(minutes).arg(seconds);
|
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("%1h %2min").arg(hours).arg(minutes);
|
||||||
}
|
}
|
||||||
return QObject::tr("%1d %2h %3min").arg(days).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>>;
|
using days = std::chrono::duration<int, std::ratio<86400>>;
|
||||||
|
|
||||||
QString outStr;
|
QString outStr;
|
||||||
@ -48,8 +47,8 @@ QString Time::humanReadableDuration(double duration, int precision) {
|
|||||||
|
|
||||||
bool neg = false;
|
bool neg = false;
|
||||||
if (duration < 0) {
|
if (duration < 0) {
|
||||||
neg = true; // flag
|
neg = true; // flag
|
||||||
duration *= -1; // invert
|
duration *= -1; // invert
|
||||||
}
|
}
|
||||||
|
|
||||||
auto std_duration = std::chrono::duration<double>(duration);
|
auto std_duration = std::chrono::duration<double>(duration);
|
||||||
@ -78,22 +77,22 @@ QString Time::humanReadableDuration(double duration, int precision) {
|
|||||||
if (hc) {
|
if (hc) {
|
||||||
if (dc)
|
if (dc)
|
||||||
os << " ";
|
os << " ";
|
||||||
os << qSetFieldWidth(2) << hc << QObject::tr("h"); // hours
|
os << qSetFieldWidth(2) << hc << QObject::tr("h"); // hours
|
||||||
}
|
}
|
||||||
if (mc) {
|
if (mc) {
|
||||||
if (dc || hc)
|
if (dc || hc)
|
||||||
os << " ";
|
os << " ";
|
||||||
os << qSetFieldWidth(2) << mc << QObject::tr("m"); // minutes
|
os << qSetFieldWidth(2) << mc << QObject::tr("m"); // minutes
|
||||||
}
|
}
|
||||||
if (dc || hc || mc || sc) {
|
if (dc || hc || mc || sc) {
|
||||||
if (dc || hc || mc)
|
if (dc || hc || mc)
|
||||||
os << " ";
|
os << " ";
|
||||||
os << qSetFieldWidth(2) << sc << QObject::tr("s"); // seconds
|
os << qSetFieldWidth(2) << sc << QObject::tr("s"); // seconds
|
||||||
}
|
}
|
||||||
if ((msc && (precision > 0)) || !(dc || hc || mc || sc)) {
|
if ((msc && (precision > 0)) || !(dc || hc || mc || sc)) {
|
||||||
if (dc || hc || mc || sc)
|
if (dc || hc || mc || sc)
|
||||||
os << " ";
|
os << " ";
|
||||||
os << qSetFieldWidth(0) << qSetRealNumberPrecision(precision) << msc << QObject::tr("ms"); // miliseconds
|
os << qSetFieldWidth(0) << qSetRealNumberPrecision(precision) << msc << QObject::tr("ms"); // miliseconds
|
||||||
}
|
}
|
||||||
|
|
||||||
os.flush();
|
os.flush();
|
||||||
|
@ -31,4 +31,4 @@ QString prettifyDuration(int64_t duration);
|
|||||||
* @return QString
|
* @return QString
|
||||||
*/
|
*/
|
||||||
QString humanReadableDuration(double duration, int precision = 0);
|
QString humanReadableDuration(double duration, int precision = 0);
|
||||||
}
|
} // namespace Time
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
|
#include <QDebug>
|
||||||
#include <QPixmapCache>
|
#include <QPixmapCache>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
#define GET_TYPE() \
|
#define GET_TYPE() \
|
||||||
Qt::ConnectionType type; \
|
Qt::ConnectionType type; \
|
||||||
|
@ -16,15 +16,15 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QStringList>
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
#include <QSysInfo>
|
#include <QSysInfo>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
|
|
||||||
#include "MangoHud.h"
|
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "Json.h"
|
#include "Json.h"
|
||||||
|
#include "MangoHud.h"
|
||||||
|
|
||||||
namespace MangoHud {
|
namespace MangoHud {
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
#include <cmark.h>
|
#include <cmark.h>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
QString markdownToHTML(const QString& markdown);
|
QString markdownToHTML(const QString& markdown);
|
@ -22,12 +22,11 @@ MessageLevel::Enum MessageLevel::getLevel(const QString& levelName)
|
|||||||
return MessageLevel::Unknown;
|
return MessageLevel::Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageLevel::Enum MessageLevel::fromLine(QString &line)
|
MessageLevel::Enum MessageLevel::fromLine(QString& line)
|
||||||
{
|
{
|
||||||
// Level prefix
|
// Level prefix
|
||||||
int endmark = line.indexOf("]!");
|
int endmark = line.indexOf("]!");
|
||||||
if (line.startsWith("!![") && endmark != -1)
|
if (line.startsWith("!![") && endmark != -1) {
|
||||||
{
|
|
||||||
auto level = MessageLevel::getLevel(line.left(endmark).mid(3));
|
auto level = MessageLevel::getLevel(line.left(endmark).mid(3));
|
||||||
line = line.mid(endmark + 2);
|
line = line.mid(endmark + 2);
|
||||||
return level;
|
return level;
|
||||||
|
@ -6,23 +6,21 @@
|
|||||||
* @brief the MessageLevel Enum
|
* @brief the MessageLevel Enum
|
||||||
* defines what level a log message is
|
* defines what level a log message is
|
||||||
*/
|
*/
|
||||||
namespace MessageLevel
|
namespace MessageLevel {
|
||||||
{
|
enum Enum {
|
||||||
enum Enum
|
Unknown, /**< No idea what this is or where it came from */
|
||||||
{
|
StdOut, /**< Undetermined stderr messages */
|
||||||
Unknown, /**< No idea what this is or where it came from */
|
StdErr, /**< Undetermined stdout messages */
|
||||||
StdOut, /**< Undetermined stderr messages */
|
|
||||||
StdErr, /**< Undetermined stdout messages */
|
|
||||||
Launcher, /**< Launcher Messages */
|
Launcher, /**< Launcher Messages */
|
||||||
Debug, /**< Debug Messages */
|
Debug, /**< Debug Messages */
|
||||||
Info, /**< Info Messages */
|
Info, /**< Info Messages */
|
||||||
Message, /**< Standard Messages */
|
Message, /**< Standard Messages */
|
||||||
Warning, /**< Warnings */
|
Warning, /**< Warnings */
|
||||||
Error, /**< Errors */
|
Error, /**< Errors */
|
||||||
Fatal, /**< Fatal 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. */
|
/* Get message level from a line. Line is modified if it was successful. */
|
||||||
MessageLevel::Enum fromLine(QString &line);
|
MessageLevel::Enum fromLine(QString& line);
|
||||||
}
|
} // namespace MessageLevel
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// 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 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -37,88 +37,38 @@
|
|||||||
#include "BaseInstance.h"
|
#include "BaseInstance.h"
|
||||||
#include "launch/LaunchTask.h"
|
#include "launch/LaunchTask.h"
|
||||||
|
|
||||||
class NullInstance: public BaseInstance
|
class NullInstance : public BaseInstance {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
NullInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString& rootDir)
|
NullInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString& rootDir)
|
||||||
:BaseInstance(globalSettings, settings, rootDir)
|
: BaseInstance(globalSettings, settings, rootDir)
|
||||||
{
|
{
|
||||||
setVersionBroken(true);
|
setVersionBroken(true);
|
||||||
}
|
}
|
||||||
virtual ~NullInstance() {};
|
virtual ~NullInstance(){};
|
||||||
void saveNow() override
|
void saveNow() override {}
|
||||||
{
|
void loadSpecificSettings() override { setSpecificSettingsLoaded(true); }
|
||||||
}
|
QString getStatusbarDescription() override { return tr("Unknown instance type"); };
|
||||||
void loadSpecificSettings() override
|
QSet<QString> traits() const override { return {}; };
|
||||||
{
|
QString instanceConfigFolder() const override { return instanceRoot(); };
|
||||||
setSpecificSettingsLoaded(true);
|
shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr, MinecraftServerTargetPtr) override { return nullptr; }
|
||||||
}
|
shared_qobject_ptr<Task> createUpdateTask(Net::Mode mode) override { return nullptr; }
|
||||||
QString getStatusbarDescription() override
|
QProcessEnvironment createEnvironment() override { return QProcessEnvironment(); }
|
||||||
{
|
QProcessEnvironment createLaunchEnvironment() override { return QProcessEnvironment(); }
|
||||||
return tr("Unknown instance type");
|
QMap<QString, QString> getVariables() override { return QMap<QString, QString>(); }
|
||||||
};
|
IPathMatcher::Ptr getLogFileMatcher() override { return nullptr; }
|
||||||
QSet< QString > traits() const override
|
QString getLogFileRoot() override { return instanceRoot(); }
|
||||||
{
|
QString typeName() const override { return "Null"; }
|
||||||
return {};
|
bool canExport() const override { return false; }
|
||||||
};
|
bool canEdit() const override { return false; }
|
||||||
QString instanceConfigFolder() const override
|
bool canLaunch() const override { return false; }
|
||||||
{
|
|
||||||
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 verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override
|
||||||
{
|
{
|
||||||
QStringList out;
|
QStringList out;
|
||||||
out << "Null instance - placeholder.";
|
out << "Null instance - placeholder.";
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
QString modsRoot() const override {
|
QString modsRoot() const override { return QString(); }
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
void updateRuntimeContext()
|
void updateRuntimeContext()
|
||||||
{
|
{
|
||||||
// NOOP
|
// NOOP
|
||||||
|
@ -1,47 +1,35 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
enum class ProblemSeverity
|
#include <QList>
|
||||||
{
|
#include <QString>
|
||||||
None,
|
|
||||||
Warning,
|
|
||||||
Error
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PatchProblem
|
enum class ProblemSeverity { None, Warning, Error };
|
||||||
{
|
|
||||||
|
struct PatchProblem {
|
||||||
ProblemSeverity m_severity;
|
ProblemSeverity m_severity;
|
||||||
QString m_description;
|
QString m_description;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ProblemProvider
|
class ProblemProvider {
|
||||||
{
|
public:
|
||||||
public:
|
virtual ~ProblemProvider(){};
|
||||||
virtual ~ProblemProvider() {};
|
|
||||||
virtual const QList<PatchProblem> getProblems() const = 0;
|
virtual const QList<PatchProblem> getProblems() const = 0;
|
||||||
virtual ProblemSeverity getProblemSeverity() const = 0;
|
virtual ProblemSeverity getProblemSeverity() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ProblemContainer : public ProblemProvider
|
class ProblemContainer : public ProblemProvider {
|
||||||
{
|
public:
|
||||||
public:
|
const QList<PatchProblem> getProblems() const override { return m_problems; }
|
||||||
const QList<PatchProblem> getProblems() const override
|
ProblemSeverity getProblemSeverity() const override { return m_problemSeverity; }
|
||||||
|
virtual void addProblem(ProblemSeverity severity, const QString& description)
|
||||||
{
|
{
|
||||||
return m_problems;
|
if (severity > m_problemSeverity) {
|
||||||
}
|
|
||||||
ProblemSeverity getProblemSeverity() const override
|
|
||||||
{
|
|
||||||
return m_problemSeverity;
|
|
||||||
}
|
|
||||||
virtual void addProblem(ProblemSeverity severity, const QString &description)
|
|
||||||
{
|
|
||||||
if(severity > m_problemSeverity)
|
|
||||||
{
|
|
||||||
m_problemSeverity = severity;
|
m_problemSeverity = severity;
|
||||||
}
|
}
|
||||||
m_problems.append({severity, description});
|
m_problems.append({ severity, description });
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<PatchProblem> m_problems;
|
QList<PatchProblem> m_problems;
|
||||||
ProblemSeverity m_problemSeverity = ProblemSeverity::None;
|
ProblemSeverity m_problemSeverity = ProblemSeverity::None;
|
||||||
};
|
};
|
||||||
|
@ -36,35 +36,34 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
#include <QVariant>
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
namespace QVariantUtils {
|
namespace QVariantUtils {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline QList<T> toList(QVariant src) {
|
inline QList<T> toList(QVariant src)
|
||||||
|
{
|
||||||
QVariantList variantList = src.toList();
|
QVariantList variantList = src.toList();
|
||||||
|
|
||||||
QList<T> list_t;
|
QList<T> list_t;
|
||||||
list_t.reserve(variantList.size());
|
list_t.reserve(variantList.size());
|
||||||
for (const QVariant& v : variantList)
|
for (const QVariant& v : variantList) {
|
||||||
{
|
|
||||||
list_t.append(v.value<T>());
|
list_t.append(v.value<T>());
|
||||||
}
|
}
|
||||||
return list_t;
|
return list_t;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline QVariant fromList(QList<T> val) {
|
inline QVariant fromList(QList<T> val)
|
||||||
|
{
|
||||||
QVariantList variantList;
|
QVariantList variantList;
|
||||||
variantList.reserve(val.size());
|
variantList.reserve(val.size());
|
||||||
for (const T& v : val)
|
for (const T& v : val) {
|
||||||
{
|
|
||||||
variantList.append(v);
|
variantList.append(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
return variantList;
|
return variantList;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace QVariantUtils
|
@ -1,13 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <QWriteLocker>
|
|
||||||
#include <QReadLocker>
|
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
#include <QReadLocker>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
#include <QWriteLocker>
|
||||||
|
|
||||||
template <typename K, typename V>
|
template <typename K, typename V>
|
||||||
class RWStorage
|
class RWStorage {
|
||||||
{
|
public:
|
||||||
public:
|
|
||||||
void add(K key, V value)
|
void add(K key, V value)
|
||||||
{
|
{
|
||||||
QWriteLocker l(&lock);
|
QWriteLocker l(&lock);
|
||||||
@ -17,21 +16,19 @@ public:
|
|||||||
V get(K key)
|
V get(K key)
|
||||||
{
|
{
|
||||||
QReadLocker l(&lock);
|
QReadLocker l(&lock);
|
||||||
if(cache.contains(key))
|
if (cache.contains(key)) {
|
||||||
{
|
|
||||||
return cache[key];
|
return cache[key];
|
||||||
}
|
} else
|
||||||
else return V();
|
return V();
|
||||||
}
|
}
|
||||||
bool get(K key, V& value)
|
bool get(K key, V& value)
|
||||||
{
|
{
|
||||||
QReadLocker l(&lock);
|
QReadLocker l(&lock);
|
||||||
if(cache.contains(key))
|
if (cache.contains(key)) {
|
||||||
{
|
|
||||||
value = cache[key];
|
value = cache[key];
|
||||||
return true;
|
return true;
|
||||||
}
|
} else
|
||||||
else return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool has(K key)
|
bool has(K key)
|
||||||
{
|
{
|
||||||
@ -41,15 +38,14 @@ public:
|
|||||||
bool stale(K key)
|
bool stale(K key)
|
||||||
{
|
{
|
||||||
QReadLocker l(&lock);
|
QReadLocker l(&lock);
|
||||||
if(!cache.contains(key))
|
if (!cache.contains(key))
|
||||||
return true;
|
return true;
|
||||||
return stale_entries.contains(key);
|
return stale_entries.contains(key);
|
||||||
}
|
}
|
||||||
void setStale(K key)
|
void setStale(K key)
|
||||||
{
|
{
|
||||||
QWriteLocker l(&lock);
|
QWriteLocker l(&lock);
|
||||||
if(cache.contains(key))
|
if (cache.contains(key)) {
|
||||||
{
|
|
||||||
stale_entries.insert(key);
|
stale_entries.insert(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,7 +55,8 @@ public:
|
|||||||
cache.clear();
|
cache.clear();
|
||||||
stale_entries.clear();
|
stale_entries.clear();
|
||||||
}
|
}
|
||||||
private:
|
|
||||||
|
private:
|
||||||
QReadWriteLock lock;
|
QReadWriteLock lock;
|
||||||
QMap<K, V> cache;
|
QMap<K, V> cache;
|
||||||
QSet<K> stale_entries;
|
QSet<K> stale_entries;
|
||||||
|
@ -1,25 +1,21 @@
|
|||||||
#include "RecursiveFileSystemWatcher.h"
|
#include "RecursiveFileSystemWatcher.h"
|
||||||
|
|
||||||
#include <QRegularExpression>
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
RecursiveFileSystemWatcher::RecursiveFileSystemWatcher(QObject *parent)
|
RecursiveFileSystemWatcher::RecursiveFileSystemWatcher(QObject* parent) : QObject(parent), m_watcher(new QFileSystemWatcher(this))
|
||||||
: QObject(parent), m_watcher(new QFileSystemWatcher(this))
|
|
||||||
{
|
{
|
||||||
connect(m_watcher, &QFileSystemWatcher::fileChanged, this,
|
connect(m_watcher, &QFileSystemWatcher::fileChanged, this, &RecursiveFileSystemWatcher::fileChange);
|
||||||
&RecursiveFileSystemWatcher::fileChange);
|
connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, &RecursiveFileSystemWatcher::directoryChange);
|
||||||
connect(m_watcher, &QFileSystemWatcher::directoryChanged, this,
|
|
||||||
&RecursiveFileSystemWatcher::directoryChange);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecursiveFileSystemWatcher::setRootDir(const QDir &root)
|
void RecursiveFileSystemWatcher::setRootDir(const QDir& root)
|
||||||
{
|
{
|
||||||
bool wasEnabled = m_isEnabled;
|
bool wasEnabled = m_isEnabled;
|
||||||
disable();
|
disable();
|
||||||
m_root = root;
|
m_root = root;
|
||||||
setFiles(scanRecursive(m_root));
|
setFiles(scanRecursive(m_root));
|
||||||
if (wasEnabled)
|
if (wasEnabled) {
|
||||||
{
|
|
||||||
enable();
|
enable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -28,16 +24,14 @@ void RecursiveFileSystemWatcher::setWatchFiles(const bool watchFiles)
|
|||||||
bool wasEnabled = m_isEnabled;
|
bool wasEnabled = m_isEnabled;
|
||||||
disable();
|
disable();
|
||||||
m_watchFiles = watchFiles;
|
m_watchFiles = watchFiles;
|
||||||
if (wasEnabled)
|
if (wasEnabled) {
|
||||||
{
|
|
||||||
enable();
|
enable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecursiveFileSystemWatcher::enable()
|
void RecursiveFileSystemWatcher::enable()
|
||||||
{
|
{
|
||||||
if (m_isEnabled)
|
if (m_isEnabled) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Q_ASSERT(m_root != QDir::root());
|
Q_ASSERT(m_root != QDir::root());
|
||||||
@ -46,8 +40,7 @@ void RecursiveFileSystemWatcher::enable()
|
|||||||
}
|
}
|
||||||
void RecursiveFileSystemWatcher::disable()
|
void RecursiveFileSystemWatcher::disable()
|
||||||
{
|
{
|
||||||
if (!m_isEnabled)
|
if (!m_isEnabled) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_isEnabled = false;
|
m_isEnabled = false;
|
||||||
@ -55,57 +48,49 @@ void RecursiveFileSystemWatcher::disable()
|
|||||||
m_watcher->removePaths(m_watcher->directories());
|
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;
|
m_files = files;
|
||||||
emit filesChanged();
|
emit filesChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecursiveFileSystemWatcher::addFilesToWatcherRecursive(const QDir &dir)
|
void RecursiveFileSystemWatcher::addFilesToWatcherRecursive(const QDir& dir)
|
||||||
{
|
{
|
||||||
m_watcher->addPath(dir.absolutePath());
|
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));
|
addFilesToWatcherRecursive(dir.absoluteFilePath(directory));
|
||||||
}
|
}
|
||||||
if (m_watchFiles)
|
if (m_watchFiles) {
|
||||||
{
|
for (const QFileInfo& info : dir.entryInfoList(QDir::Files)) {
|
||||||
for (const QFileInfo &info : dir.entryInfoList(QDir::Files))
|
|
||||||
{
|
|
||||||
m_watcher->addPath(info.absoluteFilePath());
|
m_watcher->addPath(info.absoluteFilePath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QStringList RecursiveFileSystemWatcher::scanRecursive(const QDir &directory)
|
QStringList RecursiveFileSystemWatcher::scanRecursive(const QDir& directory)
|
||||||
{
|
{
|
||||||
QStringList ret;
|
QStringList ret;
|
||||||
if(!m_matcher)
|
if (!m_matcher) {
|
||||||
{
|
|
||||||
return {};
|
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)));
|
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));
|
auto relPath = m_root.relativeFilePath(directory.absoluteFilePath(file));
|
||||||
if (m_matcher->matches(relPath))
|
if (m_matcher->matches(relPath)) {
|
||||||
{
|
|
||||||
ret.append(relPath);
|
ret.append(relPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecursiveFileSystemWatcher::fileChange(const QString &path)
|
void RecursiveFileSystemWatcher::fileChange(const QString& path)
|
||||||
{
|
{
|
||||||
emit fileChanged(path);
|
emit fileChanged(path);
|
||||||
}
|
}
|
||||||
void RecursiveFileSystemWatcher::directoryChange(const QString &path)
|
void RecursiveFileSystemWatcher::directoryChange(const QString& path)
|
||||||
{
|
{
|
||||||
setFiles(scanRecursive(m_root));
|
setFiles(scanRecursive(m_root));
|
||||||
}
|
}
|
||||||
|
@ -1,61 +1,48 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QFileSystemWatcher>
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QFileSystemWatcher>
|
||||||
#include "pathmatcher/IPathMatcher.h"
|
#include "pathmatcher/IPathMatcher.h"
|
||||||
|
|
||||||
class RecursiveFileSystemWatcher : public QObject
|
class RecursiveFileSystemWatcher : public QObject {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
RecursiveFileSystemWatcher(QObject *parent);
|
RecursiveFileSystemWatcher(QObject* parent);
|
||||||
|
|
||||||
void setRootDir(const QDir &root);
|
void setRootDir(const QDir& root);
|
||||||
QDir rootDir() const
|
QDir rootDir() const { return m_root; }
|
||||||
{
|
|
||||||
return m_root;
|
|
||||||
}
|
|
||||||
|
|
||||||
// WARNING: setting this to true may be bad for performance
|
// WARNING: setting this to true may be bad for performance
|
||||||
void setWatchFiles(const bool watchFiles);
|
void setWatchFiles(const bool watchFiles);
|
||||||
bool watchFiles() const
|
bool watchFiles() const { return m_watchFiles; }
|
||||||
{
|
|
||||||
return m_watchFiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setMatcher(IPathMatcher::Ptr matcher)
|
void setMatcher(IPathMatcher::Ptr matcher) { m_matcher = matcher; }
|
||||||
{
|
|
||||||
m_matcher = matcher;
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList files() const
|
QStringList files() const { return m_files; }
|
||||||
{
|
|
||||||
return m_files;
|
|
||||||
}
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void filesChanged();
|
void filesChanged();
|
||||||
void fileChanged(const QString &path);
|
void fileChanged(const QString& path);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void enable();
|
void enable();
|
||||||
void disable();
|
void disable();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QDir m_root;
|
QDir m_root;
|
||||||
bool m_watchFiles = false;
|
bool m_watchFiles = false;
|
||||||
bool m_isEnabled = false;
|
bool m_isEnabled = false;
|
||||||
IPathMatcher::Ptr m_matcher;
|
IPathMatcher::Ptr m_matcher;
|
||||||
|
|
||||||
QFileSystemWatcher *m_watcher;
|
QFileSystemWatcher* m_watcher;
|
||||||
|
|
||||||
QStringList m_files;
|
QStringList m_files;
|
||||||
void setFiles(const QStringList &files);
|
void setFiles(const QStringList& files);
|
||||||
|
|
||||||
void addFilesToWatcherRecursive(const QDir &dir);
|
void addFilesToWatcherRecursive(const QDir& dir);
|
||||||
QStringList scanRecursive(const QDir &dir);
|
QStringList scanRecursive(const QDir& dir);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void fileChange(const QString &path);
|
void fileChange(const QString& path);
|
||||||
void directoryChange(const QString &path);
|
void directoryChange(const QString& path);
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// 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 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
@ -1,44 +1,32 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <QString>
|
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
template <char Tseparator>
|
template <char Tseparator>
|
||||||
class SeparatorPrefixTree
|
class SeparatorPrefixTree {
|
||||||
{
|
public:
|
||||||
public:
|
SeparatorPrefixTree(QStringList paths) { insert(paths); }
|
||||||
SeparatorPrefixTree(QStringList paths)
|
|
||||||
{
|
|
||||||
insert(paths);
|
|
||||||
}
|
|
||||||
|
|
||||||
SeparatorPrefixTree(bool contained = false)
|
SeparatorPrefixTree(bool contained = false) { m_contained = contained; }
|
||||||
{
|
|
||||||
m_contained = contained;
|
|
||||||
}
|
|
||||||
|
|
||||||
void insert(QStringList paths)
|
void insert(QStringList paths)
|
||||||
{
|
{
|
||||||
for(auto &path: paths)
|
for (auto& path : paths) {
|
||||||
{
|
|
||||||
insert(path);
|
insert(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// insert an exact path into the tree
|
/// insert an exact path into the tree
|
||||||
SeparatorPrefixTree & insert(QString path)
|
SeparatorPrefixTree& insert(QString path)
|
||||||
{
|
{
|
||||||
auto sepIndex = path.indexOf(Tseparator);
|
auto sepIndex = path.indexOf(Tseparator);
|
||||||
if(sepIndex == -1)
|
if (sepIndex == -1) {
|
||||||
{
|
|
||||||
children[path] = SeparatorPrefixTree(true);
|
children[path] = SeparatorPrefixTree(true);
|
||||||
return children[path];
|
return children[path];
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
auto prefix = path.left(sepIndex);
|
auto prefix = path.left(sepIndex);
|
||||||
if(!children.contains(prefix))
|
if (!children.contains(prefix)) {
|
||||||
{
|
|
||||||
children[prefix] = SeparatorPrefixTree(false);
|
children[prefix] = SeparatorPrefixTree(false);
|
||||||
}
|
}
|
||||||
return children[prefix].insert(path.mid(sepIndex + 1));
|
return children[prefix].insert(path.mid(sepIndex + 1));
|
||||||
@ -56,26 +44,20 @@ public:
|
|||||||
bool covers(QString path) const
|
bool covers(QString path) const
|
||||||
{
|
{
|
||||||
// if we found some valid node, it's good enough. the tree covers the path
|
// if we found some valid node, it's good enough. the tree covers the path
|
||||||
if(m_contained)
|
if (m_contained) {
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
auto sepIndex = path.indexOf(Tseparator);
|
auto sepIndex = path.indexOf(Tseparator);
|
||||||
if(sepIndex == -1)
|
if (sepIndex == -1) {
|
||||||
{
|
|
||||||
auto found = children.find(path);
|
auto found = children.find(path);
|
||||||
if(found == children.end())
|
if (found == children.end()) {
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return (*found).covers(QString());
|
return (*found).covers(QString());
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
auto prefix = path.left(sepIndex);
|
auto prefix = path.left(sepIndex);
|
||||||
auto found = children.find(prefix);
|
auto found = children.find(prefix);
|
||||||
if(found == children.end())
|
if (found == children.end()) {
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return (*found).covers(path.mid(sepIndex + 1));
|
return (*found).covers(path.mid(sepIndex + 1));
|
||||||
@ -86,41 +68,33 @@ public:
|
|||||||
QString cover(QString path) const
|
QString cover(QString path) const
|
||||||
{
|
{
|
||||||
// if we found some valid node, it's good enough. the tree covers the path
|
// if we found some valid node, it's good enough. the tree covers the path
|
||||||
if(m_contained)
|
if (m_contained) {
|
||||||
{
|
|
||||||
return QString("");
|
return QString("");
|
||||||
}
|
}
|
||||||
auto sepIndex = path.indexOf(Tseparator);
|
auto sepIndex = path.indexOf(Tseparator);
|
||||||
if(sepIndex == -1)
|
if (sepIndex == -1) {
|
||||||
{
|
|
||||||
auto found = children.find(path);
|
auto found = children.find(path);
|
||||||
if(found == children.end())
|
if (found == children.end()) {
|
||||||
{
|
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
auto nested = (*found).cover(QString());
|
auto nested = (*found).cover(QString());
|
||||||
if(nested.isNull())
|
if (nested.isNull()) {
|
||||||
{
|
|
||||||
return nested;
|
return nested;
|
||||||
}
|
}
|
||||||
if(nested.isEmpty())
|
if (nested.isEmpty())
|
||||||
return path;
|
return path;
|
||||||
return path + Tseparator + nested;
|
return path + Tseparator + nested;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
auto prefix = path.left(sepIndex);
|
auto prefix = path.left(sepIndex);
|
||||||
auto found = children.find(prefix);
|
auto found = children.find(prefix);
|
||||||
if(found == children.end())
|
if (found == children.end()) {
|
||||||
{
|
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
auto nested = (*found).cover(path.mid(sepIndex + 1));
|
auto nested = (*found).cover(path.mid(sepIndex + 1));
|
||||||
if(nested.isNull())
|
if (nested.isNull()) {
|
||||||
{
|
|
||||||
return nested;
|
return nested;
|
||||||
}
|
}
|
||||||
if(nested.isEmpty())
|
if (nested.isEmpty())
|
||||||
return prefix;
|
return prefix;
|
||||||
return prefix + Tseparator + nested;
|
return prefix + Tseparator + nested;
|
||||||
}
|
}
|
||||||
@ -130,21 +104,16 @@ public:
|
|||||||
bool exists(QString path) const
|
bool exists(QString path) const
|
||||||
{
|
{
|
||||||
auto sepIndex = path.indexOf(Tseparator);
|
auto sepIndex = path.indexOf(Tseparator);
|
||||||
if(sepIndex == -1)
|
if (sepIndex == -1) {
|
||||||
{
|
|
||||||
auto found = children.find(path);
|
auto found = children.find(path);
|
||||||
if(found == children.end())
|
if (found == children.end()) {
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
auto prefix = path.left(sepIndex);
|
auto prefix = path.left(sepIndex);
|
||||||
auto found = children.find(prefix);
|
auto found = children.find(prefix);
|
||||||
if(found == children.end())
|
if (found == children.end()) {
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return (*found).exists(path.mid(sepIndex + 1));
|
return (*found).exists(path.mid(sepIndex + 1));
|
||||||
@ -152,24 +121,19 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// find a node in the tree by name
|
/// 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);
|
auto sepIndex = path.indexOf(Tseparator);
|
||||||
if(sepIndex == -1)
|
if (sepIndex == -1) {
|
||||||
{
|
|
||||||
auto found = children.find(path);
|
auto found = children.find(path);
|
||||||
if(found == children.end())
|
if (found == children.end()) {
|
||||||
{
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return &(*found);
|
return &(*found);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
auto prefix = path.left(sepIndex);
|
auto prefix = path.left(sepIndex);
|
||||||
auto found = children.find(prefix);
|
auto found = children.find(prefix);
|
||||||
if(found == children.end())
|
if (found == children.end()) {
|
||||||
{
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return (*found).find(path.mid(sepIndex + 1));
|
return (*found).find(path.mid(sepIndex + 1));
|
||||||
@ -177,70 +141,48 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// is this a leaf node?
|
/// is this a leaf node?
|
||||||
bool leaf() const
|
bool leaf() const { return children.isEmpty(); }
|
||||||
{
|
|
||||||
return children.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// is this node actually contained in the tree, or is it purely structural?
|
/// is this node actually contained in the tree, or is it purely structural?
|
||||||
bool contained() const
|
bool contained() const { return m_contained; }
|
||||||
{
|
|
||||||
return m_contained;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Remove a path from the tree
|
/// Remove a path from the tree
|
||||||
bool remove(QString path)
|
bool remove(QString path) { return removeInternal(path) != Failed; }
|
||||||
{
|
|
||||||
return removeInternal(path) != Failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clear all children of this node tree node
|
/// Clear all children of this node tree node
|
||||||
void clear()
|
void clear() { children.clear(); }
|
||||||
{
|
|
||||||
children.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList toStringList() const
|
QStringList toStringList() const
|
||||||
{
|
{
|
||||||
QStringList collected;
|
QStringList collected;
|
||||||
// collecting these is more expensive.
|
// collecting these is more expensive.
|
||||||
auto iter = children.begin();
|
auto iter = children.begin();
|
||||||
while(iter != children.end())
|
while (iter != children.end()) {
|
||||||
{
|
|
||||||
QStringList list = iter.value().toStringList();
|
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];
|
list[i] = iter.key() + Tseparator + list[i];
|
||||||
}
|
}
|
||||||
collected.append(list);
|
collected.append(list);
|
||||||
if((*iter).m_contained)
|
if ((*iter).m_contained) {
|
||||||
{
|
|
||||||
collected.append(iter.key());
|
collected.append(iter.key());
|
||||||
}
|
}
|
||||||
iter++;
|
iter++;
|
||||||
}
|
}
|
||||||
return collected;
|
return collected;
|
||||||
}
|
}
|
||||||
private:
|
|
||||||
enum Removal
|
private:
|
||||||
{
|
enum Removal { Failed, Succeeded, HasChildren };
|
||||||
Failed,
|
|
||||||
Succeeded,
|
|
||||||
HasChildren
|
|
||||||
};
|
|
||||||
Removal removeInternal(QString path = QString())
|
Removal removeInternal(QString path = QString())
|
||||||
{
|
{
|
||||||
if(path.isEmpty())
|
if (path.isEmpty()) {
|
||||||
{
|
if (!m_contained) {
|
||||||
if(!m_contained)
|
|
||||||
{
|
|
||||||
// remove all children - we are removing a prefix
|
// remove all children - we are removing a prefix
|
||||||
clear();
|
clear();
|
||||||
return Succeeded;
|
return Succeeded;
|
||||||
}
|
}
|
||||||
m_contained = false;
|
m_contained = false;
|
||||||
if(children.size())
|
if (children.size()) {
|
||||||
{
|
|
||||||
return HasChildren;
|
return HasChildren;
|
||||||
}
|
}
|
||||||
return Succeeded;
|
return Succeeded;
|
||||||
@ -248,42 +190,32 @@ private:
|
|||||||
Removal remStatus = Failed;
|
Removal remStatus = Failed;
|
||||||
QString childToRemove;
|
QString childToRemove;
|
||||||
auto sepIndex = path.indexOf(Tseparator);
|
auto sepIndex = path.indexOf(Tseparator);
|
||||||
if(sepIndex == -1)
|
if (sepIndex == -1) {
|
||||||
{
|
|
||||||
childToRemove = path;
|
childToRemove = path;
|
||||||
auto found = children.find(childToRemove);
|
auto found = children.find(childToRemove);
|
||||||
if(found == children.end())
|
if (found == children.end()) {
|
||||||
{
|
|
||||||
return Failed;
|
return Failed;
|
||||||
}
|
}
|
||||||
remStatus = (*found).removeInternal();
|
remStatus = (*found).removeInternal();
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
childToRemove = path.left(sepIndex);
|
childToRemove = path.left(sepIndex);
|
||||||
auto found = children.find(childToRemove);
|
auto found = children.find(childToRemove);
|
||||||
if(found == children.end())
|
if (found == children.end()) {
|
||||||
{
|
|
||||||
return Failed;
|
return Failed;
|
||||||
}
|
}
|
||||||
remStatus = (*found).removeInternal(path.mid(sepIndex + 1));
|
remStatus = (*found).removeInternal(path.mid(sepIndex + 1));
|
||||||
}
|
}
|
||||||
switch (remStatus)
|
switch (remStatus) {
|
||||||
{
|
|
||||||
case Failed:
|
case Failed:
|
||||||
case HasChildren:
|
case HasChildren: {
|
||||||
{
|
|
||||||
return remStatus;
|
return remStatus;
|
||||||
}
|
}
|
||||||
case Succeeded:
|
case Succeeded: {
|
||||||
{
|
|
||||||
children.remove(childToRemove);
|
children.remove(childToRemove);
|
||||||
if(m_contained)
|
if (m_contained) {
|
||||||
{
|
|
||||||
return HasChildren;
|
return HasChildren;
|
||||||
}
|
}
|
||||||
if(children.size())
|
if (children.size()) {
|
||||||
{
|
|
||||||
return HasChildren;
|
return HasChildren;
|
||||||
}
|
}
|
||||||
return Succeeded;
|
return Succeeded;
|
||||||
@ -292,7 +224,7 @@ private:
|
|||||||
return Failed;
|
return Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QMap<QString,SeparatorPrefixTree<Tseparator>> children;
|
QMap<QString, SeparatorPrefixTree<Tseparator>> children;
|
||||||
bool m_contained = false;
|
bool m_contained = false;
|
||||||
};
|
};
|
||||||
|
@ -14,17 +14,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "SkinUtils.h"
|
#include "SkinUtils.h"
|
||||||
#include "net/HttpMetaCache.h"
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
#include "net/HttpMetaCache.h"
|
||||||
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QPainter>
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#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
|
* 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());
|
QFile fskin(APPLICATION->metacache()->resolveEntry("skins", username + ".png")->getFullPath());
|
||||||
|
|
||||||
if (fskin.exists())
|
if (fskin.exists()) {
|
||||||
{
|
|
||||||
QPixmap skinTexture(fskin.fileName());
|
QPixmap skinTexture(fskin.fileName());
|
||||||
if(!skinTexture.isNull())
|
if (!skinTexture.isNull()) {
|
||||||
{
|
|
||||||
QPixmap skin = QPixmap(8, 8);
|
QPixmap skin = QPixmap(8, 8);
|
||||||
QPainter painter(&skin);
|
QPainter painter(&skin);
|
||||||
painter.drawPixmap(0, 0, skinTexture.copy(8, 8, 8, 8));
|
painter.drawPixmap(0, 0, skinTexture.copy(8, 8, 8, 8));
|
||||||
@ -47,4 +44,4 @@ QPixmap getFaceFromCache(QString username, int height, int width)
|
|||||||
|
|
||||||
return QPixmap();
|
return QPixmap();
|
||||||
}
|
}
|
||||||
}
|
} // namespace SkinUtils
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
|
|
||||||
namespace SkinUtils
|
namespace SkinUtils {
|
||||||
{
|
|
||||||
QPixmap getFaceFromCache(QString id, int height = 64, int width = 64);
|
QPixmap getFaceFromCache(QString id, int height = 64, int width = 64);
|
||||||
}
|
}
|
||||||
|
@ -73,10 +73,9 @@ int naturalCompare(const QString& s1, const QString& s2, Qt::CaseSensitivity cs)
|
|||||||
* @param max_len max lenght of url in charaters
|
* @param 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.
|
* @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 humanReadableFileSize(double bytes, bool use_si = false, int decimal_points = 1);
|
||||||
|
|
||||||
|
|
||||||
QString getRandomAlphaNumeric();
|
QString getRandomAlphaNumeric();
|
||||||
} // namespace StringUtils
|
} // namespace StringUtils
|
||||||
|
@ -12,28 +12,18 @@ class Usable;
|
|||||||
*
|
*
|
||||||
* @see UseLock
|
* @see UseLock
|
||||||
*/
|
*/
|
||||||
class Usable
|
class Usable {
|
||||||
{
|
|
||||||
friend class UseLock;
|
friend class UseLock;
|
||||||
public:
|
|
||||||
std::size_t useCount() const
|
public:
|
||||||
{
|
std::size_t useCount() const { return m_useCount; }
|
||||||
return m_useCount;
|
bool isInUse() const { return m_useCount > 0; }
|
||||||
}
|
|
||||||
bool isInUse() const
|
protected:
|
||||||
{
|
virtual void decrementUses() { m_useCount--; }
|
||||||
return m_useCount > 0;
|
virtual void incrementUses() { m_useCount++; }
|
||||||
}
|
|
||||||
protected:
|
private:
|
||||||
virtual void decrementUses()
|
|
||||||
{
|
|
||||||
m_useCount--;
|
|
||||||
}
|
|
||||||
virtual void incrementUses()
|
|
||||||
{
|
|
||||||
m_useCount++;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
std::size_t m_useCount = 0;
|
std::size_t m_useCount = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -42,19 +32,15 @@ private:
|
|||||||
*
|
*
|
||||||
* @see Usable
|
* @see Usable
|
||||||
*/
|
*/
|
||||||
class UseLock
|
class UseLock {
|
||||||
{
|
public:
|
||||||
public:
|
UseLock(shared_qobject_ptr<Usable> usable) : m_usable(usable)
|
||||||
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.
|
// this doesn't use shared pointer use count, because that wouldn't be correct. this count is separate.
|
||||||
m_usable->incrementUses();
|
m_usable->incrementUses();
|
||||||
}
|
}
|
||||||
~UseLock()
|
~UseLock() { m_usable->decrementUses(); }
|
||||||
{
|
|
||||||
m_usable->decrementUses();
|
private:
|
||||||
}
|
|
||||||
private:
|
|
||||||
shared_qobject_ptr<Usable> m_usable;
|
shared_qobject_ptr<Usable> m_usable;
|
||||||
};
|
};
|
||||||
|
@ -117,12 +117,14 @@ QDebug operator<<(QDebug debug, const Version& v)
|
|||||||
|
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (auto s : v.m_sections) {
|
for (auto s : v.m_sections) {
|
||||||
if (!first) debug.nospace() << ", ";
|
if (!first)
|
||||||
|
debug.nospace() << ", ";
|
||||||
debug.nospace() << s.m_fullString;
|
debug.nospace() << s.m_fullString;
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug.nospace() << " ]" << " }";
|
debug.nospace() << " ]"
|
||||||
|
<< " }";
|
||||||
|
|
||||||
return debug;
|
return debug;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
/*
|
/*
|
||||||
* PolyMC - Minecraft Launcher
|
* Prism Launcher - Minecraft Launcher
|
||||||
* Copyright (C) 2023 flowln <flowlnlnln@gmail.com>
|
* Copyright (C) 2023 flowln <flowlnlnln@gmail.com>
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
@ -48,12 +48,12 @@ class Version {
|
|||||||
Version(QString str);
|
Version(QString str);
|
||||||
Version() = default;
|
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; }
|
QString toString() const { return m_string; }
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ class Version {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
auto numPart = QStringView{m_fullString}.left(cutoff);
|
auto numPart = QStringView{ m_fullString }.left(cutoff);
|
||||||
#else
|
#else
|
||||||
auto numPart = m_fullString.leftRef(cutoff);
|
auto numPart = m_fullString.leftRef(cutoff);
|
||||||
#endif
|
#endif
|
||||||
@ -83,7 +83,7 @@ class Version {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
auto stringPart = QStringView{m_fullString}.mid(cutoff);
|
auto stringPart = QStringView{ m_fullString }.mid(cutoff);
|
||||||
#else
|
#else
|
||||||
auto stringPart = m_fullString.midRef(cutoff);
|
auto stringPart = m_fullString.midRef(cutoff);
|
||||||
#endif
|
#endif
|
||||||
@ -103,8 +103,14 @@ class Version {
|
|||||||
|
|
||||||
QString m_fullString;
|
QString m_fullString;
|
||||||
|
|
||||||
[[nodiscard]] inline bool isAppendix() const { return m_stringPart.startsWith('+'); }
|
[[nodiscard]] inline bool isAppendix() const
|
||||||
[[nodiscard]] inline bool isPreRelease() const { return m_stringPart.startsWith('-') && m_stringPart.length() > 1; }
|
{
|
||||||
|
return m_stringPart.startsWith('+');
|
||||||
|
}
|
||||||
|
[[nodiscard]] inline bool isPreRelease() const
|
||||||
|
{
|
||||||
|
return m_stringPart.startsWith('-') && m_stringPart.length() > 1;
|
||||||
|
}
|
||||||
|
|
||||||
inline bool operator==(const Section& other) const
|
inline bool operator==(const Section& other) const
|
||||||
{
|
{
|
||||||
@ -154,7 +160,7 @@ class Version {
|
|||||||
{
|
{
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
inline bool operator>(const Section &other) const
|
inline bool operator>(const Section& other) const
|
||||||
{
|
{
|
||||||
return !(*this < other || *this == other);
|
return !(*this < other || *this == other);
|
||||||
}
|
}
|
||||||
@ -166,5 +172,3 @@ class Version {
|
|||||||
|
|
||||||
void parse();
|
void parse();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,53 +35,48 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "VersionProxyModel.h"
|
#include "VersionProxyModel.h"
|
||||||
#include "Application.h"
|
|
||||||
#include <QSortFilterProxyModel>
|
|
||||||
#include <QPixmapCache>
|
|
||||||
#include <Version.h>
|
#include <Version.h>
|
||||||
#include <meta/VersionList.h>
|
#include <meta/VersionList.h>
|
||||||
|
#include <QPixmapCache>
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
#include "Application.h"
|
||||||
|
|
||||||
class VersionFilterModel : public QSortFilterProxyModel
|
class VersionFilterModel : public QSortFilterProxyModel {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
VersionFilterModel(VersionProxyModel *parent) : QSortFilterProxyModel(parent)
|
VersionFilterModel(VersionProxyModel* parent) : QSortFilterProxyModel(parent)
|
||||||
{
|
{
|
||||||
m_parent = parent;
|
m_parent = parent;
|
||||||
setSortRole(BaseVersionList::SortRole);
|
setSortRole(BaseVersionList::SortRole);
|
||||||
sort(0, Qt::DescendingOrder);
|
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 auto& filters = m_parent->filters();
|
||||||
const QString &search = m_parent->search();
|
const QString& search = m_parent->search();
|
||||||
const QModelIndex idx = sourceModel()->index(source_row, 0, source_parent);
|
const QModelIndex idx = sourceModel()->index(source_row, 0, source_parent);
|
||||||
|
|
||||||
if (!search.isEmpty() && !sourceModel()->data(idx, BaseVersionList::VersionRole).toString().contains(search, Qt::CaseInsensitive))
|
if (!search.isEmpty() && !sourceModel()->data(idx, BaseVersionList::VersionRole).toString().contains(search, Qt::CaseInsensitive))
|
||||||
return false;
|
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 data = sourceModel()->data(idx, it.key());
|
||||||
auto match = data.toString();
|
auto match = data.toString();
|
||||||
if(!it.value()->accepts(match))
|
if (!it.value()->accepts(match)) {
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void filterChanged()
|
void filterChanged() { invalidateFilter(); }
|
||||||
{
|
|
||||||
invalidateFilter();
|
private:
|
||||||
}
|
VersionProxyModel* m_parent;
|
||||||
private:
|
|
||||||
VersionProxyModel *m_parent;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
VersionProxyModel::VersionProxyModel(QObject *parent) : QAbstractProxyModel(parent)
|
VersionProxyModel::VersionProxyModel(QObject* parent) : QAbstractProxyModel(parent)
|
||||||
{
|
{
|
||||||
filterModel = new VersionFilterModel(this);
|
filterModel = new VersionFilterModel(this);
|
||||||
connect(filterModel, &QAbstractItemModel::dataChanged, this, &VersionProxyModel::sourceDataChanged);
|
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
|
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();
|
return QVariant();
|
||||||
if(orientation != Qt::Horizontal)
|
if (orientation != Qt::Horizontal)
|
||||||
return QVariant();
|
return QVariant();
|
||||||
auto column = m_columns[section];
|
auto column = m_columns[section];
|
||||||
if(role == Qt::DisplayRole)
|
if (role == Qt::DisplayRole) {
|
||||||
{
|
switch (column) {
|
||||||
switch(column)
|
|
||||||
{
|
|
||||||
case Name:
|
case Name:
|
||||||
return tr("Version");
|
return tr("Version");
|
||||||
case ParentVersion:
|
case ParentVersion:
|
||||||
return tr("Minecraft"); //FIXME: this should come from metadata
|
return tr("Minecraft"); // FIXME: this should come from metadata
|
||||||
case Branch:
|
case Branch:
|
||||||
return tr("Branch");
|
return tr("Branch");
|
||||||
case Type:
|
case Type:
|
||||||
@ -128,15 +121,12 @@ QVariant VersionProxyModel::headerData(int section, Qt::Orientation orientation,
|
|||||||
case Time:
|
case Time:
|
||||||
return tr("Released");
|
return tr("Released");
|
||||||
}
|
}
|
||||||
}
|
} else if (role == Qt::ToolTipRole) {
|
||||||
else if(role == Qt::ToolTipRole)
|
switch (column) {
|
||||||
{
|
|
||||||
switch(column)
|
|
||||||
{
|
|
||||||
case Name:
|
case Name:
|
||||||
return tr("The name of the version.");
|
return tr("The name of the version.");
|
||||||
case ParentVersion:
|
case ParentVersion:
|
||||||
return tr("Minecraft version"); //FIXME: this should come from metadata
|
return tr("Minecraft version"); // FIXME: this should come from metadata
|
||||||
case Branch:
|
case Branch:
|
||||||
return tr("The version's branch");
|
return tr("The version's branch");
|
||||||
case Type:
|
case Type:
|
||||||
@ -152,25 +142,19 @@ QVariant VersionProxyModel::headerData(int section, Qt::Orientation orientation,
|
|||||||
return QVariant();
|
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();
|
return QVariant();
|
||||||
}
|
}
|
||||||
auto column = m_columns[index.column()];
|
auto column = m_columns[index.column()];
|
||||||
auto parentIndex = mapToSource(index);
|
auto parentIndex = mapToSource(index);
|
||||||
switch(role)
|
switch (role) {
|
||||||
{
|
case Qt::DisplayRole: {
|
||||||
case Qt::DisplayRole:
|
switch (column) {
|
||||||
{
|
case Name: {
|
||||||
switch(column)
|
|
||||||
{
|
|
||||||
case Name:
|
|
||||||
{
|
|
||||||
QString version = sourceModel()->data(parentIndex, BaseVersionList::VersionRole).toString();
|
QString version = sourceModel()->data(parentIndex, BaseVersionList::VersionRole).toString();
|
||||||
if(version == m_currentVersion)
|
if (version == m_currentVersion) {
|
||||||
{
|
|
||||||
return tr("%1 (installed)").arg(version);
|
return tr("%1 (installed)").arg(version);
|
||||||
}
|
}
|
||||||
return version;
|
return version;
|
||||||
@ -191,18 +175,14 @@ QVariant VersionProxyModel::data(const QModelIndex &index, int role) const
|
|||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case Qt::ToolTipRole:
|
case Qt::ToolTipRole: {
|
||||||
{
|
if (column == Name && hasRecommended) {
|
||||||
if(column == Name && hasRecommended)
|
|
||||||
{
|
|
||||||
auto value = sourceModel()->data(parentIndex, BaseVersionList::RecommendedRole);
|
auto value = sourceModel()->data(parentIndex, BaseVersionList::RecommendedRole);
|
||||||
if(value.toBool())
|
if (value.toBool()) {
|
||||||
{
|
|
||||||
return tr("Recommended");
|
return tr("Recommended");
|
||||||
} else if(hasLatest) {
|
} else if (hasLatest) {
|
||||||
auto value = sourceModel()->data(parentIndex, BaseVersionList::LatestRole);
|
auto value = sourceModel()->data(parentIndex, BaseVersionList::LatestRole);
|
||||||
if(value.toBool())
|
if (value.toBool()) {
|
||||||
{
|
|
||||||
return tr("Latest");
|
return tr("Latest");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -210,32 +190,23 @@ QVariant VersionProxyModel::data(const QModelIndex &index, int role) const
|
|||||||
return sourceModel()->data(parentIndex, BaseVersionList::VersionIdRole);
|
return sourceModel()->data(parentIndex, BaseVersionList::VersionIdRole);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case Qt::DecorationRole:
|
case Qt::DecorationRole: {
|
||||||
{
|
switch (column) {
|
||||||
switch(column)
|
case Name: {
|
||||||
{
|
if (hasRecommended) {
|
||||||
case Name:
|
|
||||||
{
|
|
||||||
if(hasRecommended)
|
|
||||||
{
|
|
||||||
auto value = sourceModel()->data(parentIndex, BaseVersionList::RecommendedRole);
|
auto value = sourceModel()->data(parentIndex, BaseVersionList::RecommendedRole);
|
||||||
if(value.toBool())
|
if (value.toBool()) {
|
||||||
{
|
|
||||||
return APPLICATION->getThemedIcon("star");
|
return APPLICATION->getThemedIcon("star");
|
||||||
}
|
} else if (hasLatest) {
|
||||||
else if(hasLatest)
|
|
||||||
{
|
|
||||||
auto value = sourceModel()->data(parentIndex, BaseVersionList::LatestRole);
|
auto value = sourceModel()->data(parentIndex, BaseVersionList::LatestRole);
|
||||||
if(value.toBool())
|
if (value.toBool()) {
|
||||||
{
|
|
||||||
return APPLICATION->getThemedIcon("bug");
|
return APPLICATION->getThemedIcon("bug");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QPixmap pixmap;
|
QPixmap pixmap;
|
||||||
QPixmapCache::find("placeholder", &pixmap);
|
QPixmapCache::find("placeholder", &pixmap);
|
||||||
if(!pixmap)
|
if (!pixmap) {
|
||||||
{
|
QPixmap px(16, 16);
|
||||||
QPixmap px(16,16);
|
|
||||||
px.fill(Qt::transparent);
|
px.fill(Qt::transparent);
|
||||||
QPixmapCache::insert("placeholder", px);
|
QPixmapCache::insert("placeholder", px);
|
||||||
return px;
|
return px;
|
||||||
@ -243,16 +214,13 @@ QVariant VersionProxyModel::data(const QModelIndex &index, int role) const
|
|||||||
return pixmap;
|
return pixmap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default: {
|
||||||
{
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default: {
|
||||||
{
|
if (roles.contains((BaseVersionList::ModelRoles)role)) {
|
||||||
if(roles.contains((BaseVersionList::ModelRoles)role))
|
|
||||||
{
|
|
||||||
return sourceModel()->data(parentIndex, role);
|
return sourceModel()->data(parentIndex, role);
|
||||||
}
|
}
|
||||||
return QVariant();
|
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();
|
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 index(sourceIndex.row(), 0);
|
||||||
}
|
}
|
||||||
return QModelIndex();
|
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 sourceModel()->index(proxyIndex.row(), 0);
|
||||||
}
|
}
|
||||||
return QModelIndex();
|
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
|
// no trees here... shoo
|
||||||
if(parent.isValid())
|
if (parent.isValid()) {
|
||||||
{
|
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
}
|
}
|
||||||
if(row < 0 || row >= sourceModel()->rowCount())
|
if (row < 0 || row >= sourceModel()->rowCount())
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
if(column < 0 || column >= columnCount())
|
if (column < 0 || column >= columnCount())
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
return QAbstractItemModel::createIndex(row, column);
|
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();
|
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 sourceModel()->rowCount(parent);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VersionProxyModel::sourceDataChanged(const QModelIndex &source_top_left,
|
void VersionProxyModel::sourceDataChanged(const QModelIndex& source_top_left, const QModelIndex& source_bottom_right)
|
||||||
const QModelIndex &source_bottom_right)
|
|
||||||
{
|
{
|
||||||
if(source_top_left.parent() != source_bottom_right.parent())
|
if (source_top_left.parent() != source_bottom_right.parent())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// whole row is getting changed
|
// whole row is getting changed
|
||||||
@ -323,22 +286,20 @@ void VersionProxyModel::sourceDataChanged(const QModelIndex &source_top_left,
|
|||||||
emit dataChanged(topLeft, bottomRight);
|
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();
|
beginResetModel();
|
||||||
|
|
||||||
m_columns.clear();
|
m_columns.clear();
|
||||||
if(!replacing)
|
if (!replacing) {
|
||||||
{
|
|
||||||
roles.clear();
|
roles.clear();
|
||||||
filterModel->setSourceModel(replacing);
|
filterModel->setSourceModel(replacing);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
roles = replacing->providesRoles();
|
roles = replacing->providesRoles();
|
||||||
if(roles.contains(BaseVersionList::VersionRole))
|
if (roles.contains(BaseVersionList::VersionRole)) {
|
||||||
{
|
|
||||||
m_columns.push_back(Name);
|
m_columns.push_back(Name);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -347,32 +308,25 @@ void VersionProxyModel::setSourceModel(QAbstractItemModel *replacingRaw)
|
|||||||
m_columns.push_back(ParentVersion);
|
m_columns.push_back(ParentVersion);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if(roles.contains(BaseVersionList::ArchitectureRole))
|
if (roles.contains(BaseVersionList::ArchitectureRole)) {
|
||||||
{
|
|
||||||
m_columns.push_back(Architecture);
|
m_columns.push_back(Architecture);
|
||||||
}
|
}
|
||||||
if(roles.contains(BaseVersionList::PathRole))
|
if (roles.contains(BaseVersionList::PathRole)) {
|
||||||
{
|
|
||||||
m_columns.push_back(Path);
|
m_columns.push_back(Path);
|
||||||
}
|
}
|
||||||
if(roles.contains(Meta::VersionList::TimeRole))
|
if (roles.contains(Meta::VersionList::TimeRole)) {
|
||||||
{
|
|
||||||
m_columns.push_back(Time);
|
m_columns.push_back(Time);
|
||||||
}
|
}
|
||||||
if(roles.contains(BaseVersionList::BranchRole))
|
if (roles.contains(BaseVersionList::BranchRole)) {
|
||||||
{
|
|
||||||
m_columns.push_back(Branch);
|
m_columns.push_back(Branch);
|
||||||
}
|
}
|
||||||
if(roles.contains(BaseVersionList::TypeRole))
|
if (roles.contains(BaseVersionList::TypeRole)) {
|
||||||
{
|
|
||||||
m_columns.push_back(Type);
|
m_columns.push_back(Type);
|
||||||
}
|
}
|
||||||
if(roles.contains(BaseVersionList::RecommendedRole))
|
if (roles.contains(BaseVersionList::RecommendedRole)) {
|
||||||
{
|
|
||||||
hasRecommended = true;
|
hasRecommended = true;
|
||||||
}
|
}
|
||||||
if(roles.contains(BaseVersionList::LatestRole))
|
if (roles.contains(BaseVersionList::LatestRole)) {
|
||||||
{
|
|
||||||
hasLatest = true;
|
hasLatest = true;
|
||||||
}
|
}
|
||||||
filterModel->setSourceModel(replacing);
|
filterModel->setSourceModel(replacing);
|
||||||
@ -382,16 +336,13 @@ void VersionProxyModel::setSourceModel(QAbstractItemModel *replacingRaw)
|
|||||||
|
|
||||||
QModelIndex VersionProxyModel::getRecommended() const
|
QModelIndex VersionProxyModel::getRecommended() const
|
||||||
{
|
{
|
||||||
if(!roles.contains(BaseVersionList::RecommendedRole))
|
if (!roles.contains(BaseVersionList::RecommendedRole)) {
|
||||||
{
|
|
||||||
return index(0, 0);
|
return index(0, 0);
|
||||||
}
|
}
|
||||||
int recommended = 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);
|
auto value = sourceModel()->data(mapToSource(index(i, 0)), BaseVersionList::RecommendedRole);
|
||||||
if (value.toBool())
|
if (value.toBool()) {
|
||||||
{
|
|
||||||
recommended = i;
|
recommended = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -401,16 +352,13 @@ QModelIndex VersionProxyModel::getRecommended() const
|
|||||||
QModelIndex VersionProxyModel::getVersion(const QString& version) const
|
QModelIndex VersionProxyModel::getVersion(const QString& version) const
|
||||||
{
|
{
|
||||||
int found = -1;
|
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);
|
auto value = sourceModel()->data(mapToSource(index(i, 0)), BaseVersionList::VersionRole);
|
||||||
if (value.toString() == version)
|
if (value.toString() == version) {
|
||||||
{
|
|
||||||
found = i;
|
found = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(found == -1)
|
if (found == -1) {
|
||||||
{
|
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
}
|
}
|
||||||
return index(found, 0);
|
return index(found, 0);
|
||||||
@ -423,23 +371,24 @@ void VersionProxyModel::clearFilters()
|
|||||||
filterModel->filterChanged();
|
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);
|
m_filters[column].reset(f);
|
||||||
filterModel->filterChanged();
|
filterModel->filterChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VersionProxyModel::setSearch(const QString &search) {
|
void VersionProxyModel::setSearch(const QString& search)
|
||||||
|
{
|
||||||
m_search = search;
|
m_search = search;
|
||||||
filterModel->filterChanged();
|
filterModel->filterChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
const VersionProxyModel::FilterMap &VersionProxyModel::filters() const
|
const VersionProxyModel::FilterMap& VersionProxyModel::filters() const
|
||||||
{
|
{
|
||||||
return m_filters;
|
return m_filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString &VersionProxyModel::search() const
|
const QString& VersionProxyModel::search() const
|
||||||
{
|
{
|
||||||
return m_search;
|
return m_search;
|
||||||
}
|
}
|
||||||
@ -474,7 +423,7 @@ void VersionProxyModel::sourceRowsRemoved(const QModelIndex& parent, int first,
|
|||||||
endRemoveRows();
|
endRemoveRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VersionProxyModel::setCurrentVersion(const QString &version)
|
void VersionProxyModel::setCurrentVersion(const QString& version)
|
||||||
{
|
{
|
||||||
m_currentVersion = version;
|
m_currentVersion = version;
|
||||||
}
|
}
|
||||||
|
@ -6,64 +6,53 @@
|
|||||||
|
|
||||||
class VersionFilterModel;
|
class VersionFilterModel;
|
||||||
|
|
||||||
class VersionProxyModel: public QAbstractProxyModel
|
class VersionProxyModel : public QAbstractProxyModel {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
enum Column { Name, ParentVersion, Branch, Type, Architecture, Path, Time };
|
||||||
enum Column
|
|
||||||
{
|
|
||||||
Name,
|
|
||||||
ParentVersion,
|
|
||||||
Branch,
|
|
||||||
Type,
|
|
||||||
Architecture,
|
|
||||||
Path,
|
|
||||||
Time
|
|
||||||
};
|
|
||||||
typedef QHash<BaseVersionList::ModelRoles, std::shared_ptr<Filter>> FilterMap;
|
typedef QHash<BaseVersionList::ModelRoles, std::shared_ptr<Filter>> FilterMap;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VersionProxyModel ( QObject* parent = 0 );
|
VersionProxyModel(QObject* parent = 0);
|
||||||
virtual ~VersionProxyModel() {};
|
virtual ~VersionProxyModel(){};
|
||||||
|
|
||||||
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
virtual int columnCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||||
virtual int rowCount(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 mapFromSource(const QModelIndex& sourceIndex) const override;
|
||||||
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const override;
|
virtual QModelIndex mapToSource(const QModelIndex& proxyIndex) const override;
|
||||||
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) 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 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 QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||||
virtual QModelIndex parent(const QModelIndex &child) const override;
|
virtual QModelIndex parent(const QModelIndex& child) const override;
|
||||||
virtual void setSourceModel(QAbstractItemModel *sourceModel) override;
|
virtual void setSourceModel(QAbstractItemModel* sourceModel) override;
|
||||||
|
|
||||||
const FilterMap &filters() const;
|
const FilterMap& filters() const;
|
||||||
const QString &search() const;
|
const QString& search() const;
|
||||||
void setFilter(const BaseVersionList::ModelRoles column, Filter * filter);
|
void setFilter(const BaseVersionList::ModelRoles column, Filter* filter);
|
||||||
void setSearch(const QString &search);
|
void setSearch(const QString& search);
|
||||||
void clearFilters();
|
void clearFilters();
|
||||||
QModelIndex getRecommended() const;
|
QModelIndex getRecommended() const;
|
||||||
QModelIndex getVersion(const QString & version) const;
|
QModelIndex getVersion(const QString& version) const;
|
||||||
void setCurrentVersion(const QString &version);
|
void setCurrentVersion(const QString& version);
|
||||||
private slots:
|
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 sourceAboutToBeReset();
|
||||||
void sourceReset();
|
void sourceReset();
|
||||||
|
|
||||||
void sourceRowsAboutToBeInserted(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 sourceRowsInserted(const QModelIndex& parent, int first, int last);
|
||||||
|
|
||||||
void sourceRowsAboutToBeRemoved(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 sourceRowsRemoved(const QModelIndex& parent, int first, int last);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<Column> m_columns;
|
QList<Column> m_columns;
|
||||||
FilterMap m_filters;
|
FilterMap m_filters;
|
||||||
QString m_search;
|
QString m_search;
|
||||||
BaseVersionList::RoleList roles;
|
BaseVersionList::RoleList roles;
|
||||||
VersionFilterModel * filterModel;
|
VersionFilterModel* filterModel;
|
||||||
bool hasRecommended = false;
|
bool hasRecommended = false;
|
||||||
bool hasLatest = false;
|
bool hasLatest = false;
|
||||||
QString m_currentVersion;
|
QString m_currentVersion;
|
||||||
|
@ -1,20 +1,15 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
#include <QFileSystemWatcher>
|
#include <QFileSystemWatcher>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
struct WatchLock
|
struct WatchLock {
|
||||||
{
|
WatchLock(QFileSystemWatcher* watcher, const QString& directory) : m_watcher(watcher), m_directory(directory)
|
||||||
WatchLock(QFileSystemWatcher * watcher, const QString& directory)
|
|
||||||
: m_watcher(watcher), m_directory(directory)
|
|
||||||
{
|
{
|
||||||
m_watcher->removePath(m_directory);
|
m_watcher->removePath(m_directory);
|
||||||
}
|
}
|
||||||
~WatchLock()
|
~WatchLock() { m_watcher->addPath(m_directory); }
|
||||||
{
|
QFileSystemWatcher* m_watcher;
|
||||||
m_watcher->addPath(m_directory);
|
|
||||||
}
|
|
||||||
QFileSystemWatcher * m_watcher;
|
|
||||||
QString m_directory;
|
QString m_directory;
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// 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 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -35,32 +35,29 @@
|
|||||||
|
|
||||||
#include "IconList.h"
|
#include "IconList.h"
|
||||||
#include <FileSystem.h>
|
#include <FileSystem.h>
|
||||||
#include <QMap>
|
|
||||||
#include <QEventLoop>
|
|
||||||
#include <QMimeData>
|
|
||||||
#include <QUrl>
|
|
||||||
#include <QFileSystemWatcher>
|
|
||||||
#include <QSet>
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include <QFileSystemWatcher>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QMimeData>
|
||||||
|
#include <QSet>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
#define MAX_SIZE 1024
|
#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;
|
QSet<QString> builtinNames;
|
||||||
|
|
||||||
// add builtin icons
|
// add builtin icons
|
||||||
for(auto & builtinPath: builtinPaths)
|
for (auto& builtinPath : builtinPaths) {
|
||||||
{
|
|
||||||
QDir instance_icons(builtinPath);
|
QDir instance_icons(builtinPath);
|
||||||
auto file_info_list = instance_icons.entryInfoList(QDir::Files, QDir::Name);
|
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());
|
builtinNames.insert(file_info.completeBaseName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(auto & builtinName : builtinNames)
|
for (auto& builtinName : builtinNames) {
|
||||||
{
|
|
||||||
addThemeIcon(builtinName);
|
addThemeIcon(builtinName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,31 +75,27 @@ IconList::IconList(const QStringList &builtinPaths, QString path, QObject *paren
|
|||||||
void IconList::sortIconList()
|
void IconList::sortIconList()
|
||||||
{
|
{
|
||||||
qDebug() << "Sorting icon list...";
|
qDebug() << "Sorting icon list...";
|
||||||
std::sort(icons.begin(), icons.end(), [](const MMCIcon& a, const MMCIcon& b) {
|
std::sort(icons.begin(), icons.end(), [](const MMCIcon& a, const MMCIcon& b) { return a.m_key.localeAwareCompare(b.m_key) < 0; });
|
||||||
return a.m_key.localeAwareCompare(b.m_key) < 0;
|
|
||||||
});
|
|
||||||
reindex();
|
reindex();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IconList::directoryChanged(const QString &path)
|
void IconList::directoryChanged(const QString& path)
|
||||||
{
|
{
|
||||||
QDir new_dir (path);
|
QDir new_dir(path);
|
||||||
if(m_dir.absolutePath() != new_dir.absolutePath())
|
if (m_dir.absolutePath() != new_dir.absolutePath()) {
|
||||||
{
|
|
||||||
m_dir.setPath(path);
|
m_dir.setPath(path);
|
||||||
m_dir.refresh();
|
m_dir.refresh();
|
||||||
if(is_watching)
|
if (is_watching)
|
||||||
stopWatching();
|
stopWatching();
|
||||||
startWatching();
|
startWatching();
|
||||||
}
|
}
|
||||||
if(!m_dir.exists())
|
if (!m_dir.exists())
|
||||||
if(!FS::ensureFolderPathExists(m_dir.absolutePath()))
|
if (!FS::ensureFolderPathExists(m_dir.absolutePath()))
|
||||||
return;
|
return;
|
||||||
m_dir.refresh();
|
m_dir.refresh();
|
||||||
auto new_list = m_dir.entryList(QDir::Files, QDir::Name);
|
auto new_list = m_dir.entryList(QDir::Files, QDir::Name);
|
||||||
for (auto it = new_list.begin(); it != new_list.end(); it++)
|
for (auto it = new_list.begin(); it != new_list.end(); it++) {
|
||||||
{
|
QString& foo = (*it);
|
||||||
QString &foo = (*it);
|
|
||||||
foo = m_dir.filePath(foo);
|
foo = m_dir.filePath(foo);
|
||||||
}
|
}
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
#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();
|
auto new_set = new_list.toSet();
|
||||||
#endif
|
#endif
|
||||||
QList<QString> current_list;
|
QList<QString> current_list;
|
||||||
for (auto &it : icons)
|
for (auto& it : icons) {
|
||||||
{
|
|
||||||
if (!it.has(IconType::FileBased))
|
if (!it.has(IconType::FileBased))
|
||||||
continue;
|
continue;
|
||||||
current_list.push_back(it.m_images[IconType::FileBased].filename);
|
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;
|
QSet<QString> to_add = new_set;
|
||||||
to_add -= current_set;
|
to_add -= current_set;
|
||||||
|
|
||||||
for (auto remove : to_remove)
|
for (auto remove : to_remove) {
|
||||||
{
|
|
||||||
qDebug() << "Removing " << remove;
|
qDebug() << "Removing " << remove;
|
||||||
QFileInfo rmfile(remove);
|
QFileInfo rmfile(remove);
|
||||||
QString key = rmfile.completeBaseName();
|
QString key = rmfile.completeBaseName();
|
||||||
@ -144,23 +135,19 @@ void IconList::directoryChanged(const QString &path)
|
|||||||
if (idx == -1)
|
if (idx == -1)
|
||||||
continue;
|
continue;
|
||||||
icons[idx].remove(IconType::FileBased);
|
icons[idx].remove(IconType::FileBased);
|
||||||
if (icons[idx].type() == IconType::ToBeDeleted)
|
if (icons[idx].type() == IconType::ToBeDeleted) {
|
||||||
{
|
|
||||||
beginRemoveRows(QModelIndex(), idx, idx);
|
beginRemoveRows(QModelIndex(), idx, idx);
|
||||||
icons.remove(idx);
|
icons.remove(idx);
|
||||||
reindex();
|
reindex();
|
||||||
endRemoveRows();
|
endRemoveRows();
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
dataChanged(index(idx), index(idx));
|
dataChanged(index(idx), index(idx));
|
||||||
}
|
}
|
||||||
m_watcher->removePath(remove);
|
m_watcher->removePath(remove);
|
||||||
emit iconUpdated(key);
|
emit iconUpdated(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto add : to_add)
|
for (auto add : to_add) {
|
||||||
{
|
|
||||||
qDebug() << "Adding " << add;
|
qDebug() << "Adding " << add;
|
||||||
|
|
||||||
QFileInfo addfile(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")
|
if (suffix != "jpeg" && suffix != "png" && suffix != "jpg" && suffix != "ico" && suffix != "svg" && suffix != "gif")
|
||||||
key = addfile.fileName();
|
key = addfile.fileName();
|
||||||
|
|
||||||
if (addIcon(key, QString(), addfile.filePath(), IconType::FileBased))
|
if (addIcon(key, QString(), addfile.filePath(), IconType::FileBased)) {
|
||||||
{
|
|
||||||
m_watcher->addPath(add);
|
m_watcher->addPath(add);
|
||||||
emit iconUpdated(key);
|
emit iconUpdated(key);
|
||||||
}
|
}
|
||||||
@ -181,7 +167,7 @@ void IconList::directoryChanged(const QString &path)
|
|||||||
sortIconList();
|
sortIconList();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IconList::fileChanged(const QString &path)
|
void IconList::fileChanged(const QString& path)
|
||||||
{
|
{
|
||||||
qDebug() << "Checking " << path;
|
qDebug() << "Checking " << path;
|
||||||
QFileInfo checkfile(path);
|
QFileInfo checkfile(path);
|
||||||
@ -200,9 +186,9 @@ void IconList::fileChanged(const QString &path)
|
|||||||
emit iconUpdated(key);
|
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;
|
return;
|
||||||
|
|
||||||
directoryChanged(value.toString());
|
directoryChanged(value.toString());
|
||||||
@ -213,12 +199,9 @@ void IconList::startWatching()
|
|||||||
auto abs_path = m_dir.absolutePath();
|
auto abs_path = m_dir.absolutePath();
|
||||||
FS::ensureFolderPathExists(abs_path);
|
FS::ensureFolderPathExists(abs_path);
|
||||||
is_watching = m_watcher->addPath(abs_path);
|
is_watching = m_watcher->addPath(abs_path);
|
||||||
if (is_watching)
|
if (is_watching) {
|
||||||
{
|
|
||||||
qDebug() << "Started watching " << abs_path;
|
qDebug() << "Started watching " << abs_path;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
qDebug() << "Failed to start watching " << abs_path;
|
qDebug() << "Failed to start watching " << abs_path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -241,7 +224,11 @@ Qt::DropActions IconList::supportedDropActions() const
|
|||||||
return Qt::CopyAction;
|
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)
|
if (action == Qt::IgnoreAction)
|
||||||
return true;
|
return true;
|
||||||
@ -250,12 +237,10 @@ bool IconList::dropMimeData(const QMimeData *data, Qt::DropAction action, [[mayb
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// files dropped from outside?
|
// files dropped from outside?
|
||||||
if (data->hasUrls())
|
if (data->hasUrls()) {
|
||||||
{
|
|
||||||
auto urls = data->urls();
|
auto urls = data->urls();
|
||||||
QStringList iconFiles;
|
QStringList iconFiles;
|
||||||
for (auto url : urls)
|
for (auto url : urls) {
|
||||||
{
|
|
||||||
// only local files may be dropped...
|
// only local files may be dropped...
|
||||||
if (!url.isLocalFile())
|
if (!url.isLocalFile())
|
||||||
continue;
|
continue;
|
||||||
@ -267,7 +252,7 @@ bool IconList::dropMimeData(const QMimeData *data, Qt::DropAction action, [[mayb
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Qt::ItemFlags IconList::flags(const QModelIndex &index) const
|
Qt::ItemFlags IconList::flags(const QModelIndex& index) const
|
||||||
{
|
{
|
||||||
Qt::ItemFlags defaultFlags = QAbstractListModel::flags(index);
|
Qt::ItemFlags defaultFlags = QAbstractListModel::flags(index);
|
||||||
if (index.isValid())
|
if (index.isValid())
|
||||||
@ -276,7 +261,7 @@ Qt::ItemFlags IconList::flags(const QModelIndex &index) const
|
|||||||
return Qt::ItemIsDropEnabled | defaultFlags;
|
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())
|
if (!index.isValid())
|
||||||
return QVariant();
|
return QVariant();
|
||||||
@ -286,28 +271,26 @@ QVariant IconList::data(const QModelIndex &index, int role) const
|
|||||||
if (row < 0 || row >= icons.size())
|
if (row < 0 || row >= icons.size())
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
switch (role)
|
switch (role) {
|
||||||
{
|
case Qt::DecorationRole:
|
||||||
case Qt::DecorationRole:
|
return icons[row].icon();
|
||||||
return icons[row].icon();
|
case Qt::DisplayRole:
|
||||||
case Qt::DisplayRole:
|
return icons[row].name();
|
||||||
return icons[row].name();
|
case Qt::UserRole:
|
||||||
case Qt::UserRole:
|
return icons[row].m_key;
|
||||||
return icons[row].m_key;
|
default:
|
||||||
default:
|
return QVariant();
|
||||||
return QVariant();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int IconList::rowCount(const QModelIndex &parent) const
|
int IconList::rowCount(const QModelIndex& parent) const
|
||||||
{
|
{
|
||||||
return parent.isValid() ? 0 : icons.size();
|
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);
|
QFileInfo fileinfo(file);
|
||||||
if (!fileinfo.isReadable() || !fileinfo.isFile())
|
if (!fileinfo.isReadable() || !fileinfo.isFile())
|
||||||
continue;
|
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);
|
QFileInfo fileinfo(file);
|
||||||
if(!fileinfo.isReadable() || !fileinfo.isFile())
|
if (!fileinfo.isReadable() || !fileinfo.isFile())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QString target = FS::PathCombine(getDirectory(), name);
|
QString target = FS::PathCombine(getDirectory(), name);
|
||||||
@ -333,17 +316,16 @@ void IconList::installIcon(const QString &file, const QString &name)
|
|||||||
QFile::copy(file, target);
|
QFile::copy(file, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IconList::iconFileExists(const QString &key) const
|
bool IconList::iconFileExists(const QString& key) const
|
||||||
{
|
{
|
||||||
auto iconEntry = icon(key);
|
auto iconEntry = icon(key);
|
||||||
if(!iconEntry)
|
if (!iconEntry) {
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return iconEntry->has(IconType::FileBased);
|
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);
|
int iconIdx = getIconIndex(key);
|
||||||
if (iconIdx == -1)
|
if (iconIdx == -1)
|
||||||
@ -351,7 +333,7 @@ const MMCIcon *IconList::icon(const QString &key) const
|
|||||||
return &icons[iconIdx];
|
return &icons[iconIdx];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IconList::deleteIcon(const QString &key)
|
bool IconList::deleteIcon(const QString& key)
|
||||||
{
|
{
|
||||||
if (!iconFileExists(key))
|
if (!iconFileExists(key))
|
||||||
return false;
|
return false;
|
||||||
@ -359,7 +341,7 @@ bool IconList::deleteIcon(const QString &key)
|
|||||||
return QFile::remove(icon(key)->getFilePath());
|
return QFile::remove(icon(key)->getFilePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IconList::trashIcon(const QString &key)
|
bool IconList::trashIcon(const QString& key)
|
||||||
{
|
{
|
||||||
if (!iconFileExists(key))
|
if (!iconFileExists(key))
|
||||||
return false;
|
return false;
|
||||||
@ -370,15 +352,12 @@ bool IconList::trashIcon(const QString &key)
|
|||||||
bool IconList::addThemeIcon(const QString& key)
|
bool IconList::addThemeIcon(const QString& key)
|
||||||
{
|
{
|
||||||
auto iter = name_index.find(key);
|
auto iter = name_index.find(key);
|
||||||
if (iter != name_index.end())
|
if (iter != name_index.end()) {
|
||||||
{
|
auto& oldOne = icons[*iter];
|
||||||
auto &oldOne = icons[*iter];
|
|
||||||
oldOne.replace(Builtin, key);
|
oldOne.replace(Builtin, key);
|
||||||
dataChanged(index(*iter), index(*iter));
|
dataChanged(index(*iter), index(*iter));
|
||||||
return true;
|
return true;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// add a new icon
|
// add a new icon
|
||||||
beginInsertRows(QModelIndex(), icons.size(), icons.size());
|
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?
|
// replace the icon even? is the input valid?
|
||||||
QIcon icon(path);
|
QIcon icon(path);
|
||||||
if (icon.isNull())
|
if (icon.isNull())
|
||||||
return false;
|
return false;
|
||||||
auto iter = name_index.find(key);
|
auto iter = name_index.find(key);
|
||||||
if (iter != name_index.end())
|
if (iter != name_index.end()) {
|
||||||
{
|
auto& oldOne = icons[*iter];
|
||||||
auto &oldOne = icons[*iter];
|
|
||||||
oldOne.replace(type, icon, path);
|
oldOne.replace(type, icon, path);
|
||||||
dataChanged(index(*iter), index(*iter));
|
dataChanged(index(*iter), index(*iter));
|
||||||
return true;
|
return true;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// add a new icon
|
// add a new icon
|
||||||
beginInsertRows(QModelIndex(), icons.size(), icons.size());
|
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 icon = getIcon(key);
|
||||||
auto pixmap = icon.pixmap(128, 128);
|
auto pixmap = icon.pixmap(128, 128);
|
||||||
pixmap.save(path, format);
|
pixmap.save(path, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void IconList::reindex()
|
void IconList::reindex()
|
||||||
{
|
{
|
||||||
name_index.clear();
|
name_index.clear();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (auto &iter : icons)
|
for (auto& iter : icons) {
|
||||||
{
|
|
||||||
name_index[iter.m_key] = i;
|
name_index[iter.m_key] = i;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QIcon IconList::getIcon(const QString &key) const
|
QIcon IconList::getIcon(const QString& key) const
|
||||||
{
|
{
|
||||||
int icon_index = getIconIndex(key);
|
int icon_index = getIconIndex(key);
|
||||||
|
|
||||||
@ -459,7 +433,7 @@ QIcon IconList::getIcon(const QString &key) const
|
|||||||
return QIcon();
|
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);
|
auto iter = name_index.find(key == "default" ? "grass" : key);
|
||||||
if (iter != name_index.end())
|
if (iter != name_index.end())
|
||||||
|
@ -15,10 +15,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QMutex>
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <QFile>
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QMutex>
|
||||||
#include <QtGui/QIcon>
|
#include <QtGui/QIcon>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@ -29,58 +29,58 @@
|
|||||||
|
|
||||||
class QFileSystemWatcher;
|
class QFileSystemWatcher;
|
||||||
|
|
||||||
class IconList : public QAbstractListModel
|
class IconList : public QAbstractListModel {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit IconList(const QStringList &builtinPaths, QString path, QObject *parent = 0);
|
explicit IconList(const QStringList& builtinPaths, QString path, QObject* parent = 0);
|
||||||
virtual ~IconList() {};
|
virtual ~IconList(){};
|
||||||
|
|
||||||
QIcon getIcon(const QString &key) const;
|
QIcon getIcon(const QString& key) const;
|
||||||
int getIconIndex(const QString &key) const;
|
int getIconIndex(const QString& key) const;
|
||||||
QString getDirectory() const;
|
QString getDirectory() const;
|
||||||
|
|
||||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||||
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||||
|
|
||||||
virtual QStringList mimeTypes() const override;
|
virtual QStringList mimeTypes() const override;
|
||||||
virtual Qt::DropActions supportedDropActions() 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 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 Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||||
|
|
||||||
bool addThemeIcon(const QString &key);
|
bool addThemeIcon(const QString& key);
|
||||||
bool addIcon(const QString &key, const QString &name, const QString &path, const IconType type);
|
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;
|
void saveIcon(const QString& key, const QString& path, const char* format) const;
|
||||||
bool deleteIcon(const QString &key);
|
bool deleteIcon(const QString& key);
|
||||||
bool trashIcon(const QString &key);
|
bool trashIcon(const QString& key);
|
||||||
bool iconFileExists(const QString &key) const;
|
bool iconFileExists(const QString& key) const;
|
||||||
|
|
||||||
void installIcons(const QStringList &iconFiles);
|
void installIcons(const QStringList& iconFiles);
|
||||||
void installIcon(const QString &file, const QString &name);
|
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 startWatching();
|
||||||
void stopWatching();
|
void stopWatching();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void iconUpdated(QString key);
|
void iconUpdated(QString key);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// hide copy constructor
|
// hide copy constructor
|
||||||
IconList(const IconList &) = delete;
|
IconList(const IconList&) = delete;
|
||||||
// hide assign op
|
// hide assign op
|
||||||
IconList &operator=(const IconList &) = delete;
|
IconList& operator=(const IconList&) = delete;
|
||||||
void reindex();
|
void reindex();
|
||||||
void sortIconList();
|
void sortIconList();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void directoryChanged(const QString &path);
|
void directoryChanged(const QString& path);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void fileChanged(const QString &path);
|
void fileChanged(const QString& path);
|
||||||
void SettingChanged(const Setting & setting, QVariant value);
|
void SettingChanged(const Setting& setting, QVariant value);
|
||||||
private:
|
|
||||||
|
private:
|
||||||
shared_qobject_ptr<QFileSystemWatcher> m_watcher;
|
shared_qobject_ptr<QFileSystemWatcher> m_watcher;
|
||||||
bool is_watching;
|
bool is_watching;
|
||||||
QMap<QString, int> name_index;
|
QMap<QString, int> name_index;
|
||||||
|
@ -1,24 +1,18 @@
|
|||||||
#include "IconUtils.h"
|
#include "IconUtils.h"
|
||||||
|
|
||||||
#include "FileSystem.h"
|
|
||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
|
#include "FileSystem.h"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
std::array<const char *, 6> validIconExtensions = {{
|
std::array<const char*, 6> validIconExtensions = { { "svg", "png", "ico", "gif", "jpg", "jpeg" } };
|
||||||
"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();
|
int best_found = validIconExtensions.size();
|
||||||
QString best_filename;
|
QString best_filename;
|
||||||
|
|
||||||
@ -27,13 +21,13 @@ QString findBestIconIn(const QString &folder, const QString & iconKey) {
|
|||||||
it.next();
|
it.next();
|
||||||
auto fileInfo = it.fileInfo();
|
auto fileInfo = it.fileInfo();
|
||||||
|
|
||||||
if(fileInfo.completeBaseName() != iconKey)
|
if (fileInfo.completeBaseName() != iconKey)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto extension = fileInfo.suffix();
|
auto extension = fileInfo.suffix();
|
||||||
|
|
||||||
for(int i = 0; i < best_found; i++) {
|
for (int i = 0; i < best_found; i++) {
|
||||||
if(extension == validIconExtensions[i]) {
|
if (extension == validIconExtensions[i]) {
|
||||||
best_found = i;
|
best_found = i;
|
||||||
qDebug() << i << " : " << fileInfo.fileName();
|
qDebug() << i << " : " << fileInfo.fileName();
|
||||||
best_filename = fileInfo.fileName();
|
best_filename = fileInfo.fileName();
|
||||||
@ -43,12 +37,13 @@ QString findBestIconIn(const QString &folder, const QString & iconKey) {
|
|||||||
return FS::PathCombine(folder, best_filename);
|
return FS::PathCombine(folder, best_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString getIconFilter() {
|
QString getIconFilter()
|
||||||
|
{
|
||||||
QString out;
|
QString out;
|
||||||
QTextStream stream(&out);
|
QTextStream stream(&out);
|
||||||
stream << '(';
|
stream << '(';
|
||||||
for(size_t i = 0; i < validIconExtensions.size() - 1; i++) {
|
for (size_t i = 0; i < validIconExtensions.size() - 1; i++) {
|
||||||
if(i > 0) {
|
if (i > 0) {
|
||||||
stream << " ";
|
stream << " ";
|
||||||
}
|
}
|
||||||
stream << "*." << validIconExtensions[i];
|
stream << "*." << validIconExtensions[i];
|
||||||
@ -58,5 +53,4 @@ QString getIconFilter() {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace IconUtils
|
||||||
|
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
namespace IconUtils {
|
namespace IconUtils {
|
||||||
|
|
||||||
// Given a folder and an icon key, find 'best' of the icons with the given key in there and return its path
|
// 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
|
// Get icon file type filter for file browser dialogs
|
||||||
QString getIconFilter();
|
QString getIconFilter();
|
||||||
|
|
||||||
}
|
} // namespace IconUtils
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// 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 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -37,23 +37,21 @@
|
|||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
|
|
||||||
IconType operator--(IconType &t, int)
|
IconType operator--(IconType& t, int)
|
||||||
{
|
{
|
||||||
IconType temp = t;
|
IconType temp = t;
|
||||||
switch (t)
|
switch (t) {
|
||||||
{
|
case IconType::Builtin:
|
||||||
case IconType::Builtin:
|
t = IconType::ToBeDeleted;
|
||||||
t = IconType::ToBeDeleted;
|
break;
|
||||||
break;
|
case IconType::Transient:
|
||||||
case IconType::Transient:
|
t = IconType::Builtin;
|
||||||
t = IconType::Builtin;
|
break;
|
||||||
break;
|
case IconType::FileBased:
|
||||||
case IconType::FileBased:
|
t = IconType::Transient;
|
||||||
t = IconType::Transient;
|
break;
|
||||||
break;
|
default: {
|
||||||
default:
|
}
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
@ -79,8 +77,8 @@ QIcon MMCIcon::icon() const
|
|||||||
{
|
{
|
||||||
if (m_current_type == IconType::ToBeDeleted)
|
if (m_current_type == IconType::ToBeDeleted)
|
||||||
return QIcon();
|
return QIcon();
|
||||||
auto & icon = m_images[m_current_type].icon;
|
auto& icon = m_images[m_current_type].icon;
|
||||||
if(!icon.isNull())
|
if (!icon.isNull())
|
||||||
return icon;
|
return icon;
|
||||||
// FIXME: inject this.
|
// FIXME: inject this.
|
||||||
return QIcon::fromTheme(m_images[m_current_type].key);
|
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].filename = QString();
|
||||||
m_images[rm_type].icon = QIcon();
|
m_images[rm_type].icon = QIcon();
|
||||||
for (auto iter = rm_type; iter != IconType::ToBeDeleted; iter--)
|
for (auto iter = rm_type; iter != IconType::ToBeDeleted; iter--) {
|
||||||
{
|
if (m_images[iter].present()) {
|
||||||
if (m_images[iter].present())
|
|
||||||
{
|
|
||||||
m_current_type = iter;
|
m_current_type = iter;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -103,8 +99,7 @@ void MMCIcon::remove(IconType rm_type)
|
|||||||
|
|
||||||
void MMCIcon::replace(IconType new_type, QIcon icon, QString path)
|
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_current_type = new_type;
|
||||||
}
|
}
|
||||||
m_images[new_type].icon = icon;
|
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)
|
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_current_type = new_type;
|
||||||
}
|
}
|
||||||
m_images[new_type].icon = QIcon();
|
m_images[new_type].icon = QIcon();
|
||||||
@ -125,13 +119,12 @@ void MMCIcon::replace(IconType new_type, const QString& key)
|
|||||||
|
|
||||||
QString MMCIcon::getFilePath() const
|
QString MMCIcon::getFilePath() const
|
||||||
{
|
{
|
||||||
if(m_current_type == IconType::ToBeDeleted){
|
if (m_current_type == IconType::ToBeDeleted) {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
return m_images[m_current_type].filename;
|
return m_images[m_current_type].filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool MMCIcon::isBuiltIn() const
|
bool MMCIcon::isBuiltIn() const
|
||||||
{
|
{
|
||||||
return m_current_type == IconType::Builtin;
|
return m_current_type == IconType::Builtin;
|
||||||
|
@ -14,32 +14,20 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <QString>
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
enum IconType : unsigned
|
enum IconType : unsigned { Builtin, Transient, FileBased, ICONS_TOTAL, ToBeDeleted };
|
||||||
{
|
|
||||||
Builtin,
|
|
||||||
Transient,
|
|
||||||
FileBased,
|
|
||||||
ICONS_TOTAL,
|
|
||||||
ToBeDeleted
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MMCImage
|
struct MMCImage {
|
||||||
{
|
|
||||||
QIcon icon;
|
QIcon icon;
|
||||||
QString key;
|
QString key;
|
||||||
QString filename;
|
QString filename;
|
||||||
bool present() const
|
bool present() const { return !icon.isNull() || !key.isEmpty(); }
|
||||||
{
|
|
||||||
return !icon.isNull() || !key.isEmpty();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MMCIcon
|
struct MMCIcon {
|
||||||
{
|
|
||||||
QString m_key;
|
QString m_key;
|
||||||
QString m_name;
|
QString m_name;
|
||||||
MMCImage m_images[ICONS_TOTAL];
|
MMCImage m_images[ICONS_TOTAL];
|
||||||
@ -51,7 +39,7 @@ struct MMCIcon
|
|||||||
QIcon icon() const;
|
QIcon icon() const;
|
||||||
void remove(IconType rm_type);
|
void remove(IconType rm_type);
|
||||||
void replace(IconType new_type, QIcon icon, QString path = QString());
|
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;
|
bool isBuiltIn() const;
|
||||||
QString getFilePath() const;
|
QString getFilePath() const;
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// 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 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -35,26 +35,23 @@
|
|||||||
|
|
||||||
#include "JavaChecker.h"
|
#include "JavaChecker.h"
|
||||||
|
|
||||||
#include <QFile>
|
|
||||||
#include <QProcess>
|
|
||||||
#include <QMap>
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QProcess>
|
||||||
|
|
||||||
#include "JavaUtils.h"
|
|
||||||
#include "FileSystem.h"
|
|
||||||
#include "Commandline.h"
|
|
||||||
#include "Application.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()
|
void JavaChecker::performCheck()
|
||||||
{
|
{
|
||||||
QString checkerJar = JavaUtils::getJavaCheckPath();
|
QString checkerJar = JavaUtils::getJavaCheckPath();
|
||||||
|
|
||||||
if (checkerJar.isEmpty())
|
if (checkerJar.isEmpty()) {
|
||||||
{
|
|
||||||
qDebug() << "Java checker library could not be found. Please check your installation.";
|
qDebug() << "Java checker library could not be found. Please check your installation.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -62,25 +59,21 @@ void JavaChecker::performCheck()
|
|||||||
QStringList args;
|
QStringList args;
|
||||||
|
|
||||||
process.reset(new QProcess());
|
process.reset(new QProcess());
|
||||||
if(m_args.size())
|
if (m_args.size()) {
|
||||||
{
|
|
||||||
auto extraArgs = Commandline::splitArgs(m_args);
|
auto extraArgs = Commandline::splitArgs(m_args);
|
||||||
args.append(extraArgs);
|
args.append(extraArgs);
|
||||||
}
|
}
|
||||||
if(m_minMem != 0)
|
if (m_minMem != 0) {
|
||||||
{
|
|
||||||
args << QString("-Xms%1m").arg(m_minMem);
|
args << QString("-Xms%1m").arg(m_minMem);
|
||||||
}
|
}
|
||||||
if(m_maxMem != 0)
|
if (m_maxMem != 0) {
|
||||||
{
|
|
||||||
args << QString("-Xmx%1m").arg(m_maxMem);
|
args << QString("-Xmx%1m").arg(m_maxMem);
|
||||||
}
|
}
|
||||||
if(m_permGen != 64)
|
if (m_permGen != 64) {
|
||||||
{
|
|
||||||
args << QString("-XX:PermSize=%1m").arg(m_permGen);
|
args << QString("-XX:PermSize=%1m").arg(m_permGen);
|
||||||
}
|
}
|
||||||
|
|
||||||
args.append({"-jar", checkerJar});
|
args.append({ "-jar", checkerJar });
|
||||||
process->setArguments(args);
|
process->setArguments(args);
|
||||||
process->setProgram(m_path);
|
process->setProgram(m_path);
|
||||||
process->setProcessChannelMode(QProcess::SeparateChannels);
|
process->setProcessChannelMode(QProcess::SeparateChannels);
|
||||||
@ -130,8 +123,7 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
|
|||||||
qWarning() << "STDERR" << m_stderr;
|
qWarning() << "STDERR" << m_stderr;
|
||||||
qDebug() << "Java checker finished with status" << status << "exit code" << exitcode;
|
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;
|
result.validity = JavaCheckResult::Validity::Errored;
|
||||||
emit checkFinished(result);
|
emit checkFinished(result);
|
||||||
return;
|
return;
|
||||||
@ -146,8 +138,7 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
|
|||||||
#else
|
#else
|
||||||
QStringList lines = m_stdout.split("\n", QString::SkipEmptyParts);
|
QStringList lines = m_stdout.split("\n", QString::SkipEmptyParts);
|
||||||
#endif
|
#endif
|
||||||
for(QString line : lines)
|
for (QString line : lines) {
|
||||||
{
|
|
||||||
line = line.trimmed();
|
line = line.trimmed();
|
||||||
// NOTE: workaround for GH-4125, where garbage is getting printed into stdout on bedrock linux
|
// NOTE: workaround for GH-4125, where garbage is getting printed into stdout on bedrock linux
|
||||||
if (line.contains("/bedrock/strata")) {
|
if (line.contains("/bedrock/strata")) {
|
||||||
@ -159,18 +150,14 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
|
|||||||
#else
|
#else
|
||||||
auto parts = line.split('=', QString::SkipEmptyParts);
|
auto parts = line.split('=', QString::SkipEmptyParts);
|
||||||
#endif
|
#endif
|
||||||
if(parts.size() != 2 || parts[0].isEmpty() || parts[1].isEmpty())
|
if (parts.size() != 2 || parts[0].isEmpty() || parts[1].isEmpty()) {
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
results.insert(parts[0], parts[1]);
|
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;
|
result.validity = JavaCheckResult::Validity::ReturnedInvalidData;
|
||||||
emit checkFinished(result);
|
emit checkFinished(result);
|
||||||
return;
|
return;
|
||||||
@ -181,7 +168,6 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
|
|||||||
auto java_vendor = results["java.vendor"];
|
auto java_vendor = results["java.vendor"];
|
||||||
bool is_64 = os_arch == "x86_64" || os_arch == "amd64" || os_arch == "aarch64" || os_arch == "arm64";
|
bool is_64 = os_arch == "x86_64" || os_arch == "amd64" || os_arch == "aarch64" || os_arch == "arm64";
|
||||||
|
|
||||||
|
|
||||||
result.validity = JavaCheckResult::Validity::Valid;
|
result.validity = JavaCheckResult::Validity::Valid;
|
||||||
result.is_64bit = is_64;
|
result.is_64bit = is_64;
|
||||||
result.mojangPlatform = is_64 ? "64" : "32";
|
result.mojangPlatform = is_64 ? "64" : "32";
|
||||||
@ -194,8 +180,7 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
|
|||||||
|
|
||||||
void JavaChecker::error(QProcess::ProcessError err)
|
void JavaChecker::error(QProcess::ProcessError err)
|
||||||
{
|
{
|
||||||
if(err == QProcess::FailedToStart)
|
if (err == QProcess::FailedToStart) {
|
||||||
{
|
|
||||||
qDebug() << "Java checker has failed to start.";
|
qDebug() << "Java checker has failed to start.";
|
||||||
qDebug() << "Process environment:";
|
qDebug() << "Process environment:";
|
||||||
qDebug() << process->environment();
|
qDebug() << process->environment();
|
||||||
@ -216,8 +201,7 @@ void JavaChecker::error(QProcess::ProcessError err)
|
|||||||
void JavaChecker::timeout()
|
void JavaChecker::timeout()
|
||||||
{
|
{
|
||||||
// NO MERCY. NO ABUSE.
|
// NO MERCY. NO ABUSE.
|
||||||
if(process)
|
if (process) {
|
||||||
{
|
|
||||||
qDebug() << "Java checker has been killed by timeout.";
|
qDebug() << "Java checker has been killed by timeout.";
|
||||||
process->kill();
|
process->kill();
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,7 @@
|
|||||||
|
|
||||||
class JavaChecker;
|
class JavaChecker;
|
||||||
|
|
||||||
struct JavaCheckResult
|
struct JavaCheckResult {
|
||||||
{
|
|
||||||
QString path;
|
QString path;
|
||||||
QString mojangPlatform;
|
QString mojangPlatform;
|
||||||
QString realPlatform;
|
QString realPlatform;
|
||||||
@ -20,21 +19,15 @@ struct JavaCheckResult
|
|||||||
QString errorLog;
|
QString errorLog;
|
||||||
bool is_64bit = false;
|
bool is_64bit = false;
|
||||||
int id;
|
int id;
|
||||||
enum class Validity
|
enum class Validity { Errored, ReturnedInvalidData, Valid } validity = Validity::Errored;
|
||||||
{
|
|
||||||
Errored,
|
|
||||||
ReturnedInvalidData,
|
|
||||||
Valid
|
|
||||||
} validity = Validity::Errored;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef shared_qobject_ptr<QProcess> QProcessPtr;
|
typedef shared_qobject_ptr<QProcess> QProcessPtr;
|
||||||
typedef shared_qobject_ptr<JavaChecker> JavaCheckerPtr;
|
typedef shared_qobject_ptr<JavaChecker> JavaCheckerPtr;
|
||||||
class JavaChecker : public QObject
|
class JavaChecker : public QObject {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit JavaChecker(QObject *parent = 0);
|
explicit JavaChecker(QObject* parent = 0);
|
||||||
void performCheck();
|
void performCheck();
|
||||||
|
|
||||||
QString m_path;
|
QString m_path;
|
||||||
@ -44,15 +37,15 @@ public:
|
|||||||
int m_maxMem = 0;
|
int m_maxMem = 0;
|
||||||
int m_permGen = 64;
|
int m_permGen = 64;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void checkFinished(JavaCheckResult result);
|
void checkFinished(JavaCheckResult result);
|
||||||
private:
|
|
||||||
|
private:
|
||||||
QProcessPtr process;
|
QProcessPtr process;
|
||||||
QTimer killTimer;
|
QTimer killTimer;
|
||||||
QString m_stdout;
|
QString m_stdout;
|
||||||
QString m_stderr;
|
QString m_stderr;
|
||||||
public
|
public slots:
|
||||||
slots:
|
|
||||||
void timeout();
|
void timeout();
|
||||||
void finished(int exitcode, QProcess::ExitStatus);
|
void finished(int exitcode, QProcess::ExitStatus);
|
||||||
void error(QProcess::ProcessError);
|
void error(QProcess::ProcessError);
|
||||||
|
@ -20,14 +20,12 @@
|
|||||||
void JavaCheckerJob::partFinished(JavaCheckResult result)
|
void JavaCheckerJob::partFinished(JavaCheckResult result)
|
||||||
{
|
{
|
||||||
num_finished++;
|
num_finished++;
|
||||||
qDebug() << m_job_name.toLocal8Bit() << "progress:" << num_finished << "/"
|
qDebug() << m_job_name.toLocal8Bit() << "progress:" << num_finished << "/" << javacheckers.size();
|
||||||
<< javacheckers.size();
|
|
||||||
setProgress(num_finished, javacheckers.size());
|
setProgress(num_finished, javacheckers.size());
|
||||||
|
|
||||||
javaresults.replace(result.id, result);
|
javaresults.replace(result.id, result);
|
||||||
|
|
||||||
if (num_finished == javacheckers.size())
|
if (num_finished == javacheckers.size()) {
|
||||||
{
|
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -35,8 +33,7 @@ void JavaCheckerJob::partFinished(JavaCheckResult result)
|
|||||||
void JavaCheckerJob::executeTask()
|
void JavaCheckerJob::executeTask()
|
||||||
{
|
{
|
||||||
qDebug() << m_job_name.toLocal8Bit() << " started.";
|
qDebug() << m_job_name.toLocal8Bit() << " started.";
|
||||||
for (auto iter : javacheckers)
|
for (auto iter : javacheckers) {
|
||||||
{
|
|
||||||
javaresults.append(JavaCheckResult());
|
javaresults.append(JavaCheckResult());
|
||||||
connect(iter.get(), &JavaChecker::checkFinished, this, &JavaCheckerJob::partFinished);
|
connect(iter.get(), &JavaChecker::checkFinished, this, &JavaCheckerJob::partFinished);
|
||||||
iter->performCheck();
|
iter->performCheck();
|
||||||
|
@ -23,37 +23,32 @@ class JavaCheckerJob;
|
|||||||
typedef shared_qobject_ptr<JavaCheckerJob> JavaCheckerJobPtr;
|
typedef shared_qobject_ptr<JavaCheckerJob> JavaCheckerJobPtr;
|
||||||
|
|
||||||
// FIXME: this just seems horribly redundant
|
// FIXME: this just seems horribly redundant
|
||||||
class JavaCheckerJob : public Task
|
class JavaCheckerJob : public Task {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit JavaCheckerJob(QString job_name) : Task(), m_job_name(job_name) {};
|
explicit JavaCheckerJob(QString job_name) : Task(), m_job_name(job_name){};
|
||||||
virtual ~JavaCheckerJob() {};
|
virtual ~JavaCheckerJob(){};
|
||||||
|
|
||||||
bool addJavaCheckerAction(JavaCheckerPtr base)
|
bool addJavaCheckerAction(JavaCheckerPtr base)
|
||||||
{
|
{
|
||||||
javacheckers.append(base);
|
javacheckers.append(base);
|
||||||
// if this is already running, the action needs to be started right away!
|
// if this is already running, the action needs to be started right away!
|
||||||
if (isRunning())
|
if (isRunning()) {
|
||||||
{
|
|
||||||
setProgress(num_finished, javacheckers.size());
|
setProgress(num_finished, javacheckers.size());
|
||||||
connect(base.get(), &JavaChecker::checkFinished, this, &JavaCheckerJob::partFinished);
|
connect(base.get(), &JavaChecker::checkFinished, this, &JavaCheckerJob::partFinished);
|
||||||
base->performCheck();
|
base->performCheck();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
QList<JavaCheckResult> getResults()
|
QList<JavaCheckResult> getResults() { return javaresults; }
|
||||||
{
|
|
||||||
return javaresults;
|
|
||||||
}
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void partFinished(JavaCheckResult result);
|
void partFinished(JavaCheckResult result);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void executeTask() override;
|
virtual void executeTask() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_job_name;
|
QString m_job_name;
|
||||||
QList<JavaCheckerPtr> javacheckers;
|
QList<JavaCheckerPtr> javacheckers;
|
||||||
QList<JavaCheckResult> javaresults;
|
QList<JavaCheckResult> javaresults;
|
||||||
|
@ -39,14 +39,12 @@
|
|||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
#include "java/JavaInstallList.h"
|
|
||||||
#include "java/JavaCheckerJob.h"
|
#include "java/JavaCheckerJob.h"
|
||||||
|
#include "java/JavaInstallList.h"
|
||||||
#include "java/JavaUtils.h"
|
#include "java/JavaUtils.h"
|
||||||
#include "minecraft/VersionFilterData.h"
|
#include "minecraft/VersionFilterData.h"
|
||||||
|
|
||||||
JavaInstallList::JavaInstallList(QObject *parent) : BaseVersionList(parent)
|
JavaInstallList::JavaInstallList(QObject* parent) : BaseVersionList(parent) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Task::Ptr JavaInstallList::getLoadTask()
|
Task::Ptr JavaInstallList::getLoadTask()
|
||||||
{
|
{
|
||||||
@ -56,8 +54,7 @@ Task::Ptr JavaInstallList::getLoadTask()
|
|||||||
|
|
||||||
Task::Ptr JavaInstallList::getCurrentTask()
|
Task::Ptr JavaInstallList::getCurrentTask()
|
||||||
{
|
{
|
||||||
if(m_status == Status::InProgress)
|
if (m_status == Status::InProgress) {
|
||||||
{
|
|
||||||
return m_loadTask;
|
return m_loadTask;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -65,8 +62,7 @@ Task::Ptr JavaInstallList::getCurrentTask()
|
|||||||
|
|
||||||
void JavaInstallList::load()
|
void JavaInstallList::load()
|
||||||
{
|
{
|
||||||
if(m_status != Status::InProgress)
|
if (m_status != Status::InProgress) {
|
||||||
{
|
|
||||||
m_status = Status::InProgress;
|
m_status = Status::InProgress;
|
||||||
m_loadTask.reset(new JavaListLoadTask(this));
|
m_loadTask.reset(new JavaListLoadTask(this));
|
||||||
m_loadTask->start();
|
m_loadTask->start();
|
||||||
@ -88,7 +84,7 @@ int JavaInstallList::count() const
|
|||||||
return m_vlist.count();
|
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())
|
if (!index.isValid())
|
||||||
return QVariant();
|
return QVariant();
|
||||||
@ -97,8 +93,7 @@ QVariant JavaInstallList::data(const QModelIndex &index, int role) const
|
|||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
auto version = std::dynamic_pointer_cast<JavaInstall>(m_vlist[index.row()]);
|
auto version = std::dynamic_pointer_cast<JavaInstall>(m_vlist[index.row()]);
|
||||||
switch (role)
|
switch (role) {
|
||||||
{
|
|
||||||
case SortRole:
|
case SortRole:
|
||||||
return -index.row();
|
return -index.row();
|
||||||
case VersionPointerRole:
|
case VersionPointerRole:
|
||||||
@ -120,17 +115,15 @@ QVariant JavaInstallList::data(const QModelIndex &index, int role) const
|
|||||||
|
|
||||||
BaseVersionList::RoleList JavaInstallList::providesRoles() 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)
|
void JavaInstallList::updateListData(QList<BaseVersion::Ptr> versions)
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
m_vlist = versions;
|
m_vlist = versions;
|
||||||
sortVersions();
|
sortVersions();
|
||||||
if(m_vlist.size())
|
if (m_vlist.size()) {
|
||||||
{
|
|
||||||
auto best = std::dynamic_pointer_cast<JavaInstall>(m_vlist[0]);
|
auto best = std::dynamic_pointer_cast<JavaInstall>(m_vlist[0]);
|
||||||
best->recommended = true;
|
best->recommended = true;
|
||||||
}
|
}
|
||||||
@ -153,15 +146,13 @@ void JavaInstallList::sortVersions()
|
|||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
JavaListLoadTask::JavaListLoadTask(JavaInstallList *vlist) : Task()
|
JavaListLoadTask::JavaListLoadTask(JavaInstallList* vlist) : Task()
|
||||||
{
|
{
|
||||||
m_list = vlist;
|
m_list = vlist;
|
||||||
m_currentRecommended = NULL;
|
m_currentRecommended = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
JavaListLoadTask::~JavaListLoadTask()
|
JavaListLoadTask::~JavaListLoadTask() {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void JavaListLoadTask::executeTask()
|
void JavaListLoadTask::executeTask()
|
||||||
{
|
{
|
||||||
@ -176,8 +167,7 @@ void JavaListLoadTask::executeTask()
|
|||||||
|
|
||||||
qDebug() << "Probing the following Java paths: ";
|
qDebug() << "Probing the following Java paths: ";
|
||||||
int id = 0;
|
int id = 0;
|
||||||
for(QString candidate : candidate_paths)
|
for (QString candidate : candidate_paths) {
|
||||||
{
|
|
||||||
qDebug() << " " << candidate;
|
qDebug() << " " << candidate;
|
||||||
|
|
||||||
auto candidate_checker = new JavaChecker();
|
auto candidate_checker = new JavaChecker();
|
||||||
@ -197,10 +187,8 @@ void JavaListLoadTask::javaCheckerFinished()
|
|||||||
auto results = m_job->getResults();
|
auto results = m_job->getResults();
|
||||||
|
|
||||||
qDebug() << "Found the following valid Java installations:";
|
qDebug() << "Found the following valid Java installations:";
|
||||||
for(JavaCheckResult result : results)
|
for (JavaCheckResult result : results) {
|
||||||
{
|
if (result.validity == JavaCheckResult::Validity::Valid) {
|
||||||
if(result.validity == JavaCheckResult::Validity::Valid)
|
|
||||||
{
|
|
||||||
JavaInstallPtr javaVersion(new JavaInstall());
|
JavaInstallPtr javaVersion(new JavaInstall());
|
||||||
|
|
||||||
javaVersion->id = result.javaVersion;
|
javaVersion->id = result.javaVersion;
|
||||||
@ -213,13 +201,11 @@ void JavaListLoadTask::javaCheckerFinished()
|
|||||||
}
|
}
|
||||||
|
|
||||||
QList<BaseVersion::Ptr> javas_bvp;
|
QList<BaseVersion::Ptr> javas_bvp;
|
||||||
for (auto java : candidates)
|
for (auto java : candidates) {
|
||||||
{
|
// qDebug() << java->id << java->arch << " at " << java->path;
|
||||||
//qDebug() << java->id << java->arch << " at " << java->path;
|
|
||||||
BaseVersion::Ptr bp_java = std::dynamic_pointer_cast<BaseVersion>(java);
|
BaseVersion::Ptr bp_java = std::dynamic_pointer_cast<BaseVersion>(java);
|
||||||
|
|
||||||
if (bp_java)
|
if (bp_java) {
|
||||||
{
|
|
||||||
javas_bvp.append(java);
|
javas_bvp.append(java);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
#include "BaseVersionList.h"
|
#include "BaseVersionList.h"
|
||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
@ -28,17 +28,12 @@
|
|||||||
|
|
||||||
class JavaListLoadTask;
|
class JavaListLoadTask;
|
||||||
|
|
||||||
class JavaInstallList : public BaseVersionList
|
class JavaInstallList : public BaseVersionList {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
enum class Status
|
enum class Status { NotDone, InProgress, Done };
|
||||||
{
|
|
||||||
NotDone,
|
public:
|
||||||
InProgress,
|
explicit JavaInstallList(QObject* parent = 0);
|
||||||
Done
|
|
||||||
};
|
|
||||||
public:
|
|
||||||
explicit JavaInstallList(QObject *parent = 0);
|
|
||||||
|
|
||||||
Task::Ptr getLoadTask() override;
|
Task::Ptr getLoadTask() override;
|
||||||
bool isLoaded() override;
|
bool isLoaded() override;
|
||||||
@ -46,36 +41,35 @@ public:
|
|||||||
int count() const override;
|
int count() const override;
|
||||||
void sortVersions() 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;
|
RoleList providesRoles() const override;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void updateListData(QList<BaseVersion::Ptr> versions) override;
|
void updateListData(QList<BaseVersion::Ptr> versions) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void load();
|
void load();
|
||||||
Task::Ptr getCurrentTask();
|
Task::Ptr getCurrentTask();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Status m_status = Status::NotDone;
|
Status m_status = Status::NotDone;
|
||||||
shared_qobject_ptr<JavaListLoadTask> m_loadTask;
|
shared_qobject_ptr<JavaListLoadTask> m_loadTask;
|
||||||
QList<BaseVersion::Ptr> m_vlist;
|
QList<BaseVersion::Ptr> m_vlist;
|
||||||
};
|
};
|
||||||
|
|
||||||
class JavaListLoadTask : public Task
|
class JavaListLoadTask : public Task {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit JavaListLoadTask(JavaInstallList *vlist);
|
explicit JavaListLoadTask(JavaInstallList* vlist);
|
||||||
virtual ~JavaListLoadTask();
|
virtual ~JavaListLoadTask();
|
||||||
|
|
||||||
void executeTask() override;
|
void executeTask() override;
|
||||||
public slots:
|
public slots:
|
||||||
void javaCheckerFinished();
|
void javaCheckerFinished();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
shared_qobject_ptr<JavaCheckerJob> m_job;
|
shared_qobject_ptr<JavaCheckerJob> m_job;
|
||||||
JavaInstallList *m_list;
|
JavaInstallList* m_list;
|
||||||
JavaInstall *m_currentRecommended;
|
JavaInstall* m_currentRecommended;
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// 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 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -33,24 +33,21 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QStringList>
|
|
||||||
#include <QString>
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
#include <settings/Setting.h>
|
#include <settings/Setting.h>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include "java/JavaUtils.h"
|
|
||||||
#include "java/JavaInstallList.h"
|
|
||||||
#include "FileSystem.h"
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
#include "FileSystem.h"
|
||||||
|
#include "java/JavaInstallList.h"
|
||||||
|
#include "java/JavaUtils.h"
|
||||||
|
|
||||||
#define IBUS "@im=ibus"
|
#define IBUS "@im=ibus"
|
||||||
|
|
||||||
JavaUtils::JavaUtils()
|
JavaUtils::JavaUtils() {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QString stripVariableEntries(QString name, QString target, QString remove)
|
QString stripVariableEntries(QString name, QString target, QString remove)
|
||||||
{
|
{
|
||||||
@ -65,8 +62,7 @@ QString stripVariableEntries(QString name, QString target, QString remove)
|
|||||||
for (QString item : toRemove) {
|
for (QString item : toRemove) {
|
||||||
bool removed = targetItems.removeOne(item);
|
bool removed = targetItems.removeOne(item);
|
||||||
if (!removed)
|
if (!removed)
|
||||||
qWarning() << "Entry" << item
|
qWarning() << "Entry" << item << "could not be stripped from variable" << name;
|
||||||
<< "could not be stripped from variable" << name;
|
|
||||||
}
|
}
|
||||||
return targetItems.join(delimiter);
|
return targetItems.join(delimiter);
|
||||||
}
|
}
|
||||||
@ -77,20 +73,10 @@ QProcessEnvironment CleanEnviroment()
|
|||||||
QProcessEnvironment rawenv = QProcessEnvironment::systemEnvironment();
|
QProcessEnvironment rawenv = QProcessEnvironment::systemEnvironment();
|
||||||
QProcessEnvironment env;
|
QProcessEnvironment env;
|
||||||
|
|
||||||
QStringList ignored =
|
QStringList ignored = { "JAVA_ARGS", "CLASSPATH", "CONFIGPATH", "JAVA_HOME",
|
||||||
{
|
"JRE_HOME", "_JAVA_OPTIONS", "JAVA_OPTIONS", "JAVA_TOOL_OPTIONS" };
|
||||||
"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)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
||||||
"LD_LIBRARY_PATH",
|
"LD_LIBRARY_PATH",
|
||||||
"LD_PRELOAD",
|
"LD_PRELOAD",
|
||||||
@ -98,12 +84,10 @@ QProcessEnvironment CleanEnviroment()
|
|||||||
"QT_PLUGIN_PATH",
|
"QT_PLUGIN_PATH",
|
||||||
"QT_FONTPATH"
|
"QT_FONTPATH"
|
||||||
};
|
};
|
||||||
for(auto key: rawenv.keys())
|
for (auto key : rawenv.keys()) {
|
||||||
{
|
|
||||||
auto value = rawenv.value(key);
|
auto value = rawenv.value(key);
|
||||||
// filter out dangerous java crap
|
// filter out dangerous java crap
|
||||||
if(ignored.contains(key))
|
if (ignored.contains(key)) {
|
||||||
{
|
|
||||||
qDebug() << "Env: ignoring" << key << value;
|
qDebug() << "Env: ignoring" << key << value;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -111,13 +95,11 @@ QProcessEnvironment CleanEnviroment()
|
|||||||
// These are used to strip the original variables
|
// These are used to strip the original variables
|
||||||
// If there is "LD_LIBRARY_PATH" and "LAUNCHER_LD_LIBRARY_PATH", we want to
|
// 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"
|
// 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;
|
qDebug() << "Env: ignoring" << key << value;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(stripped.contains(key))
|
if (stripped.contains(key)) {
|
||||||
{
|
|
||||||
QString newValue = stripVariableEntries(key, value, rawenv.value("LAUNCHER_" + key));
|
QString newValue = stripVariableEntries(key, value, rawenv.value("LAUNCHER_" + key));
|
||||||
|
|
||||||
qDebug() << "Env: stripped" << key << value << "to" << newValue;
|
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)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
||||||
// Strip IBus
|
// Strip IBus
|
||||||
// IBus is a Linux IME framework. For some reason, it breaks MC?
|
// 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;
|
QString save = value;
|
||||||
value.replace(IBUS, "");
|
value.replace(IBUS, "");
|
||||||
qDebug() << "Env: stripped" << IBUS << "from" << save << ":" << value;
|
qDebug() << "Env: stripped" << IBUS << "from" << save << ":" << value;
|
||||||
@ -137,8 +118,7 @@ QProcessEnvironment CleanEnviroment()
|
|||||||
}
|
}
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
// HACK: Workaround for QTBUG-42500
|
// HACK: Workaround for QTBUG-42500
|
||||||
if(!env.contains("LD_LIBRARY_PATH"))
|
if (!env.contains("LD_LIBRARY_PATH")) {
|
||||||
{
|
|
||||||
env.insert("LD_LIBRARY_PATH", "");
|
env.insert("LD_LIBRARY_PATH", "");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -186,8 +166,7 @@ QStringList addJavasFromEnv(QList<QString> javas)
|
|||||||
#else
|
#else
|
||||||
QList<QString> javaPaths = env.split(QLatin1String(":"));
|
QList<QString> javaPaths = env.split(QLatin1String(":"));
|
||||||
#endif
|
#endif
|
||||||
for(QString i : javaPaths)
|
for (QString i : javaPaths) {
|
||||||
{
|
|
||||||
javas.append(i);
|
javas.append(i);
|
||||||
};
|
};
|
||||||
return javas;
|
return javas;
|
||||||
@ -205,9 +184,8 @@ QList<JavaInstallPtr> JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString
|
|||||||
archType = "32";
|
archType = "32";
|
||||||
|
|
||||||
HKEY jreKey;
|
HKEY jreKey;
|
||||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyName.toStdWString().c_str(), 0,
|
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyName.toStdWString().c_str(), 0, KEY_READ | keyType | KEY_ENUMERATE_SUB_KEYS, &jreKey) ==
|
||||||
KEY_READ | keyType | KEY_ENUMERATE_SUB_KEYS, &jreKey) == ERROR_SUCCESS)
|
ERROR_SUCCESS) {
|
||||||
{
|
|
||||||
// Read the current type version from the registry.
|
// Read the current type version from the registry.
|
||||||
// This will be used to find any key that contains the JavaHome value.
|
// 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;
|
DWORD subKeyNameSize, numSubKeys, retCode;
|
||||||
|
|
||||||
// Get the number of subkeys
|
// Get the number of subkeys
|
||||||
RegQueryInfoKeyW(jreKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL,
|
RegQueryInfoKeyW(jreKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||||
NULL, NULL);
|
|
||||||
|
|
||||||
// Iterate until RegEnumKeyEx fails
|
// Iterate until RegEnumKeyEx fails
|
||||||
if (numSubKeys > 0)
|
if (numSubKeys > 0) {
|
||||||
{
|
for (DWORD i = 0; i < numSubKeys; i++) {
|
||||||
for (DWORD i = 0; i < numSubKeys; i++)
|
|
||||||
{
|
|
||||||
subKeyNameSize = 255;
|
subKeyNameSize = 255;
|
||||||
retCode = RegEnumKeyExW(jreKey, i, subKeyName, &subKeyNameSize, NULL, NULL, NULL,
|
retCode = RegEnumKeyExW(jreKey, i, subKeyName, &subKeyNameSize, NULL, NULL, NULL, NULL);
|
||||||
NULL);
|
|
||||||
QString newSubkeyName = QString::fromWCharArray(subKeyName);
|
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.
|
// Now open the registry key for the version that we just got.
|
||||||
QString newKeyName = keyName + "\\" + newSubkeyName + subkeySuffix;
|
QString newKeyName = keyName + "\\" + newSubkeyName + subkeySuffix;
|
||||||
|
|
||||||
HKEY newKey;
|
HKEY newKey;
|
||||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, newKeyName.toStdWString().c_str(), 0,
|
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, newKeyName.toStdWString().c_str(), 0, KEY_READ | KEY_WOW64_64KEY, &newKey) ==
|
||||||
KEY_READ | KEY_WOW64_64KEY, &newKey) == ERROR_SUCCESS)
|
ERROR_SUCCESS) {
|
||||||
{
|
|
||||||
// Read the JavaHome value to find where Java is installed.
|
// Read the JavaHome value to find where Java is installed.
|
||||||
DWORD valueSz = 0;
|
DWORD valueSz = 0;
|
||||||
if (RegQueryValueExW(newKey, keyJavaDir.toStdWString().c_str(), NULL, NULL, NULL,
|
if (RegQueryValueExW(newKey, keyJavaDir.toStdWString().c_str(), NULL, NULL, NULL, &valueSz) == ERROR_SUCCESS) {
|
||||||
&valueSz) == ERROR_SUCCESS)
|
WCHAR* value = new WCHAR[valueSz];
|
||||||
{
|
RegQueryValueExW(newKey, keyJavaDir.toStdWString().c_str(), NULL, NULL, (BYTE*)value, &valueSz);
|
||||||
WCHAR *value = new WCHAR[valueSz];
|
|
||||||
RegQueryValueExW(newKey, keyJavaDir.toStdWString().c_str(), NULL, NULL, (BYTE *)value,
|
|
||||||
&valueSz);
|
|
||||||
|
|
||||||
QString newValue = QString::fromWCharArray(value);
|
QString newValue = QString::fromWCharArray(value);
|
||||||
delete [] value;
|
delete[] value;
|
||||||
|
|
||||||
// Now, we construct the version object and add it to the list.
|
// Now, we construct the version object and add it to the list.
|
||||||
JavaInstallPtr javaVersion(new JavaInstall());
|
JavaInstallPtr javaVersion(new JavaInstall());
|
||||||
|
|
||||||
javaVersion->id = newSubkeyName;
|
javaVersion->id = newSubkeyName;
|
||||||
javaVersion->arch = archType;
|
javaVersion->arch = archType;
|
||||||
javaVersion->path =
|
javaVersion->path = QDir(FS::PathCombine(newValue, "bin")).absoluteFilePath("javaw.exe");
|
||||||
QDir(FS::PathCombine(newValue, "bin")).absoluteFilePath("javaw.exe");
|
|
||||||
javas.append(javaVersion);
|
javas.append(javaVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,66 +243,56 @@ QList<QString> JavaUtils::FindJavaPaths()
|
|||||||
QList<JavaInstallPtr> java_candidates;
|
QList<JavaInstallPtr> java_candidates;
|
||||||
|
|
||||||
// Oracle
|
// Oracle
|
||||||
QList<JavaInstallPtr> JRE64s = this->FindJavaFromRegistryKey(
|
QList<JavaInstallPtr> JRE64s =
|
||||||
KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment", "JavaHome");
|
this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment", "JavaHome");
|
||||||
QList<JavaInstallPtr> JDK64s = this->FindJavaFromRegistryKey(
|
QList<JavaInstallPtr> JDK64s = this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Development Kit", "JavaHome");
|
||||||
KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Development Kit", "JavaHome");
|
QList<JavaInstallPtr> JRE32s =
|
||||||
QList<JavaInstallPtr> JRE32s = this->FindJavaFromRegistryKey(
|
this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment", "JavaHome");
|
||||||
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> JDK32s = this->FindJavaFromRegistryKey(
|
|
||||||
KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\Java Development Kit", "JavaHome");
|
|
||||||
|
|
||||||
// Oracle for Java 9 and newer
|
// Oracle for Java 9 and newer
|
||||||
QList<JavaInstallPtr> NEWJRE64s = this->FindJavaFromRegistryKey(
|
QList<JavaInstallPtr> NEWJRE64s = this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\JRE", "JavaHome");
|
||||||
KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\JRE", "JavaHome");
|
QList<JavaInstallPtr> NEWJDK64s = this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\JDK", "JavaHome");
|
||||||
QList<JavaInstallPtr> NEWJDK64s = this->FindJavaFromRegistryKey(
|
QList<JavaInstallPtr> NEWJRE32s = this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\JRE", "JavaHome");
|
||||||
KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\JDK", "JavaHome");
|
QList<JavaInstallPtr> NEWJDK32s = this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "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
|
// AdoptOpenJDK
|
||||||
QList<JavaInstallPtr> ADOPTOPENJRE32s = this->FindJavaFromRegistryKey(
|
QList<JavaInstallPtr> ADOPTOPENJRE32s =
|
||||||
KEY_WOW64_32KEY, "SOFTWARE\\AdoptOpenJDK\\JRE", "Path", "\\hotspot\\MSI");
|
this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\AdoptOpenJDK\\JRE", "Path", "\\hotspot\\MSI");
|
||||||
QList<JavaInstallPtr> ADOPTOPENJRE64s = this->FindJavaFromRegistryKey(
|
QList<JavaInstallPtr> ADOPTOPENJRE64s =
|
||||||
KEY_WOW64_64KEY, "SOFTWARE\\AdoptOpenJDK\\JRE", "Path", "\\hotspot\\MSI");
|
this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\AdoptOpenJDK\\JRE", "Path", "\\hotspot\\MSI");
|
||||||
QList<JavaInstallPtr> ADOPTOPENJDK32s = this->FindJavaFromRegistryKey(
|
QList<JavaInstallPtr> ADOPTOPENJDK32s =
|
||||||
KEY_WOW64_32KEY, "SOFTWARE\\AdoptOpenJDK\\JDK", "Path", "\\hotspot\\MSI");
|
this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\AdoptOpenJDK\\JDK", "Path", "\\hotspot\\MSI");
|
||||||
QList<JavaInstallPtr> ADOPTOPENJDK64s = this->FindJavaFromRegistryKey(
|
QList<JavaInstallPtr> ADOPTOPENJDK64s =
|
||||||
KEY_WOW64_64KEY, "SOFTWARE\\AdoptOpenJDK\\JDK", "Path", "\\hotspot\\MSI");
|
this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\AdoptOpenJDK\\JDK", "Path", "\\hotspot\\MSI");
|
||||||
|
|
||||||
// Eclipse Foundation
|
// Eclipse Foundation
|
||||||
QList<JavaInstallPtr> FOUNDATIONJDK32s = this->FindJavaFromRegistryKey(
|
QList<JavaInstallPtr> FOUNDATIONJDK32s =
|
||||||
KEY_WOW64_32KEY, "SOFTWARE\\Eclipse Foundation\\JDK", "Path", "\\hotspot\\MSI");
|
this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\Eclipse Foundation\\JDK", "Path", "\\hotspot\\MSI");
|
||||||
QList<JavaInstallPtr> FOUNDATIONJDK64s = this->FindJavaFromRegistryKey(
|
QList<JavaInstallPtr> FOUNDATIONJDK64s =
|
||||||
KEY_WOW64_64KEY, "SOFTWARE\\Eclipse Foundation\\JDK", "Path", "\\hotspot\\MSI");
|
this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\Eclipse Foundation\\JDK", "Path", "\\hotspot\\MSI");
|
||||||
|
|
||||||
// Eclipse Adoptium
|
// Eclipse Adoptium
|
||||||
QList<JavaInstallPtr> ADOPTIUMJRE32s = this->FindJavaFromRegistryKey(
|
QList<JavaInstallPtr> ADOPTIUMJRE32s =
|
||||||
KEY_WOW64_32KEY, "SOFTWARE\\Eclipse Adoptium\\JRE", "Path", "\\hotspot\\MSI");
|
this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\Eclipse Adoptium\\JRE", "Path", "\\hotspot\\MSI");
|
||||||
QList<JavaInstallPtr> ADOPTIUMJRE64s = this->FindJavaFromRegistryKey(
|
QList<JavaInstallPtr> ADOPTIUMJRE64s =
|
||||||
KEY_WOW64_64KEY, "SOFTWARE\\Eclipse Adoptium\\JRE", "Path", "\\hotspot\\MSI");
|
this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\Eclipse Adoptium\\JRE", "Path", "\\hotspot\\MSI");
|
||||||
QList<JavaInstallPtr> ADOPTIUMJDK32s = this->FindJavaFromRegistryKey(
|
QList<JavaInstallPtr> ADOPTIUMJDK32s =
|
||||||
KEY_WOW64_32KEY, "SOFTWARE\\Eclipse Adoptium\\JDK", "Path", "\\hotspot\\MSI");
|
this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\Eclipse Adoptium\\JDK", "Path", "\\hotspot\\MSI");
|
||||||
QList<JavaInstallPtr> ADOPTIUMJDK64s = this->FindJavaFromRegistryKey(
|
QList<JavaInstallPtr> ADOPTIUMJDK64s =
|
||||||
KEY_WOW64_64KEY, "SOFTWARE\\Eclipse Adoptium\\JDK", "Path", "\\hotspot\\MSI");
|
this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\Eclipse Adoptium\\JDK", "Path", "\\hotspot\\MSI");
|
||||||
|
|
||||||
// Microsoft
|
// Microsoft
|
||||||
QList<JavaInstallPtr> MICROSOFTJDK64s = this->FindJavaFromRegistryKey(
|
QList<JavaInstallPtr> MICROSOFTJDK64s =
|
||||||
KEY_WOW64_64KEY, "SOFTWARE\\Microsoft\\JDK", "Path", "\\hotspot\\MSI");
|
this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\Microsoft\\JDK", "Path", "\\hotspot\\MSI");
|
||||||
|
|
||||||
// Azul Zulu
|
// Azul Zulu
|
||||||
QList<JavaInstallPtr> ZULU64s = this->FindJavaFromRegistryKey(
|
QList<JavaInstallPtr> ZULU64s = this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\Azul Systems\\Zulu", "InstallationPath");
|
||||||
KEY_WOW64_64KEY, "SOFTWARE\\Azul Systems\\Zulu", "InstallationPath");
|
QList<JavaInstallPtr> ZULU32s = this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\Azul Systems\\Zulu", "InstallationPath");
|
||||||
QList<JavaInstallPtr> ZULU32s = this->FindJavaFromRegistryKey(
|
|
||||||
KEY_WOW64_32KEY, "SOFTWARE\\Azul Systems\\Zulu", "InstallationPath");
|
|
||||||
|
|
||||||
// BellSoft Liberica
|
// BellSoft Liberica
|
||||||
QList<JavaInstallPtr> LIBERICA64s = this->FindJavaFromRegistryKey(
|
QList<JavaInstallPtr> LIBERICA64s = this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\BellSoft\\Liberica", "InstallationPath");
|
||||||
KEY_WOW64_64KEY, "SOFTWARE\\BellSoft\\Liberica", "InstallationPath");
|
QList<JavaInstallPtr> LIBERICA32s = this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\BellSoft\\Liberica", "InstallationPath");
|
||||||
QList<JavaInstallPtr> LIBERICA32s = this->FindJavaFromRegistryKey(
|
|
||||||
KEY_WOW64_32KEY, "SOFTWARE\\BellSoft\\Liberica", "InstallationPath");
|
|
||||||
|
|
||||||
// List x64 before x86
|
// List x64 before x86
|
||||||
java_candidates.append(JRE64s);
|
java_candidates.append(JRE64s);
|
||||||
@ -371,10 +329,8 @@ QList<QString> JavaUtils::FindJavaPaths()
|
|||||||
java_candidates.append(MakeJavaPtr(this->GetDefaultJava()->path));
|
java_candidates.append(MakeJavaPtr(this->GetDefaultJava()->path));
|
||||||
|
|
||||||
QList<QString> candidates;
|
QList<QString> candidates;
|
||||||
for(JavaInstallPtr java_candidate : java_candidates)
|
for (JavaInstallPtr java_candidate : java_candidates) {
|
||||||
{
|
if (!candidates.contains(java_candidate->path)) {
|
||||||
if(!candidates.contains(java_candidate->path))
|
|
||||||
{
|
|
||||||
candidates.append(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");
|
javas.append("/System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands/java");
|
||||||
QDir libraryJVMDir("/Library/Java/JavaVirtualMachines/");
|
QDir libraryJVMDir("/Library/Java/JavaVirtualMachines/");
|
||||||
QStringList libraryJVMJavas = libraryJVMDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
|
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/bin/java");
|
||||||
javas.append(libraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/jre/bin/java");
|
javas.append(libraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/jre/bin/java");
|
||||||
}
|
}
|
||||||
QDir systemLibraryJVMDir("/System/Library/Java/JavaVirtualMachines/");
|
QDir systemLibraryJVMDir("/System/Library/Java/JavaVirtualMachines/");
|
||||||
QStringList systemLibraryJVMJavas = systemLibraryJVMDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
|
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/Home/bin/java");
|
||||||
javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Commands/java");
|
javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Commands/java");
|
||||||
}
|
}
|
||||||
@ -414,14 +370,12 @@ QList<QString> JavaUtils::FindJavaPaths()
|
|||||||
{
|
{
|
||||||
QList<QString> javas;
|
QList<QString> javas;
|
||||||
javas.append(this->GetDefaultJava()->path);
|
javas.append(this->GetDefaultJava()->path);
|
||||||
auto scanJavaDir = [&](const QString & dirPath)
|
auto scanJavaDir = [&](const QString& dirPath) {
|
||||||
{
|
|
||||||
QDir dir(dirPath);
|
QDir dir(dirPath);
|
||||||
if(!dir.exists())
|
if (!dir.exists())
|
||||||
return;
|
return;
|
||||||
auto entries = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
auto entries = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
for(auto & entry: entries)
|
for (auto& entry : entries) {
|
||||||
{
|
|
||||||
QString prefix;
|
QString prefix;
|
||||||
prefix = entry.canonicalFilePath();
|
prefix = entry.canonicalFilePath();
|
||||||
javas.append(FS::PathCombine(prefix, "jre/bin/java"));
|
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
|
// java installed in a snap is installed in the standard directory, but underneath $SNAP
|
||||||
auto snap = qEnvironmentVariable("SNAP");
|
auto snap = qEnvironmentVariable("SNAP");
|
||||||
auto scanJavaDirs = [&](const QString & dirPath)
|
auto scanJavaDirs = [&](const QString& dirPath) {
|
||||||
{
|
|
||||||
scanJavaDir(dirPath);
|
scanJavaDir(dirPath);
|
||||||
if (!snap.isNull()) {
|
if (!snap.isNull()) {
|
||||||
scanJavaDir(snap + dirPath);
|
scanJavaDir(snap + dirPath);
|
||||||
|
@ -27,10 +27,9 @@
|
|||||||
QString stripVariableEntries(QString name, QString target, QString remove);
|
QString stripVariableEntries(QString name, QString target, QString remove);
|
||||||
QProcessEnvironment CleanEnviroment();
|
QProcessEnvironment CleanEnviroment();
|
||||||
|
|
||||||
class JavaUtils : public QObject
|
class JavaUtils : public QObject {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
JavaUtils();
|
JavaUtils();
|
||||||
|
|
||||||
JavaInstallPtr MakeJavaPtr(QString path, QString id = "unknown", QString arch = "unknown");
|
JavaInstallPtr MakeJavaPtr(QString path, QString id = "unknown", QString arch = "unknown");
|
||||||
|
@ -5,27 +5,22 @@
|
|||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
JavaVersion & JavaVersion::operator=(const QString & javaVersionString)
|
JavaVersion& JavaVersion::operator=(const QString& javaVersionString)
|
||||||
{
|
{
|
||||||
m_string = 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);
|
auto str = match.captured(what);
|
||||||
if(str.isEmpty())
|
if (str.isEmpty()) {
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return str.toInt();
|
return str.toInt();
|
||||||
};
|
};
|
||||||
|
|
||||||
QRegularExpression pattern;
|
QRegularExpression pattern;
|
||||||
if(javaVersionString.startsWith("1."))
|
if (javaVersionString.startsWith("1.")) {
|
||||||
{
|
pattern = QRegularExpression("1[.](?<major>[0-9]+)([.](?<minor>[0-9]+))?(_(?<security>[0-9]+)?)?(-(?<prerelease>[a-zA-Z0-9]+))?");
|
||||||
pattern = QRegularExpression ("1[.](?<major>[0-9]+)([.](?<minor>[0-9]+))?(_(?<security>[0-9]+)?)?(-(?<prerelease>[a-zA-Z0-9]+))?");
|
} else {
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pattern = QRegularExpression("(?<major>[0-9]+)([.](?<minor>[0-9]+))?([.](?<security>[0-9]+))?(-(?<prerelease>[a-zA-Z0-9]+))?");
|
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;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
JavaVersion::JavaVersion(const QString &rhs)
|
JavaVersion::JavaVersion(const QString& rhs)
|
||||||
{
|
{
|
||||||
operator=(rhs);
|
operator=(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString JavaVersion::toString()
|
QString JavaVersion::toString() const
|
||||||
{
|
{
|
||||||
return m_string;
|
return m_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JavaVersion::requiresPermGen()
|
bool JavaVersion::requiresPermGen()
|
||||||
{
|
{
|
||||||
if(m_parseable)
|
if (m_parseable) {
|
||||||
{
|
|
||||||
return m_major < 8;
|
return m_major < 8;
|
||||||
}
|
}
|
||||||
return true;
|
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 major = m_major;
|
||||||
auto rmajor = rhs.m_major;
|
auto rmajor = rhs.m_major;
|
||||||
|
|
||||||
// HACK: discourage using java 9
|
// HACK: discourage using java 9
|
||||||
if(major > 8)
|
if (major > 8)
|
||||||
major = -major;
|
major = -major;
|
||||||
if(rmajor > 8)
|
if (rmajor > 8)
|
||||||
rmajor = -rmajor;
|
rmajor = -rmajor;
|
||||||
|
|
||||||
if(major < rmajor)
|
if (major < rmajor)
|
||||||
return true;
|
return true;
|
||||||
if(major > rmajor)
|
if (major > rmajor)
|
||||||
return false;
|
return false;
|
||||||
if(m_minor < rhs.m_minor)
|
if (m_minor < rhs.m_minor)
|
||||||
return true;
|
return true;
|
||||||
if(m_minor > rhs.m_minor)
|
if (m_minor > rhs.m_minor)
|
||||||
return false;
|
return false;
|
||||||
if(m_security < rhs.m_security)
|
if (m_security < rhs.m_security)
|
||||||
return true;
|
return true;
|
||||||
if(m_security > rhs.m_security)
|
if (m_security > rhs.m_security)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// everything else being equal, consider prerelease status
|
// everything else being equal, consider prerelease status
|
||||||
bool thisPre = !m_prerelease.isEmpty();
|
bool thisPre = !m_prerelease.isEmpty();
|
||||||
bool rhsPre = !rhs.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
|
// this is a prerelease and the other one isn't -> lesser
|
||||||
return true;
|
return true;
|
||||||
}
|
} else if (!thisPre && rhsPre) {
|
||||||
else if(!thisPre && rhsPre)
|
|
||||||
{
|
|
||||||
// this isn't a prerelease and the other one is -> greater
|
// this isn't a prerelease and the other one is -> greater
|
||||||
return false;
|
return false;
|
||||||
}
|
} else if (thisPre && rhsPre) {
|
||||||
else if(thisPre && rhsPre)
|
|
||||||
{
|
|
||||||
// both are prereleases - use natural compare...
|
// both are prereleases - use natural compare...
|
||||||
return StringUtils::naturalCompare(m_prerelease, rhs.m_prerelease, Qt::CaseSensitive) < 0;
|
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
|
// neither is prerelease, so they are the same -> this cannot be less than rhs
|
||||||
return false;
|
return false;
|
||||||
}
|
} else
|
||||||
else return StringUtils::naturalCompare(m_string, rhs.m_string, Qt::CaseSensitive) < 0;
|
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_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;
|
return m_string == rhs.m_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JavaVersion::operator>(const JavaVersion &rhs)
|
bool JavaVersion::operator>(const JavaVersion& rhs)
|
||||||
{
|
{
|
||||||
return (!operator<(rhs)) && (!operator==(rhs));
|
return (!operator<(rhs)) && (!operator==(rhs));
|
||||||
}
|
}
|
||||||
|
@ -4,42 +4,34 @@
|
|||||||
|
|
||||||
// NOTE: apparently the GNU C library pollutes the global namespace with these... undef them.
|
// NOTE: apparently the GNU C library pollutes the global namespace with these... undef them.
|
||||||
#ifdef major
|
#ifdef major
|
||||||
#undef major
|
#undef major
|
||||||
#endif
|
#endif
|
||||||
#ifdef minor
|
#ifdef minor
|
||||||
#undef minor
|
#undef minor
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class JavaVersion
|
class JavaVersion {
|
||||||
{
|
|
||||||
friend class JavaVersionTest;
|
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);
|
JavaVersion& operator=(const QString& rhs);
|
||||||
bool operator==(const JavaVersion & rhs);
|
|
||||||
bool operator>(const JavaVersion & rhs);
|
bool operator<(const JavaVersion& rhs);
|
||||||
|
bool operator==(const JavaVersion& rhs);
|
||||||
|
bool operator>(const JavaVersion& rhs);
|
||||||
|
|
||||||
bool requiresPermGen();
|
bool requiresPermGen();
|
||||||
|
|
||||||
QString toString();
|
QString toString() const;
|
||||||
|
|
||||||
int major()
|
int major() { return m_major; }
|
||||||
{
|
int minor() { return m_minor; }
|
||||||
return m_major;
|
int security() { return m_security; }
|
||||||
}
|
|
||||||
int minor()
|
private:
|
||||||
{
|
|
||||||
return m_minor;
|
|
||||||
}
|
|
||||||
int security()
|
|
||||||
{
|
|
||||||
return m_security;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
QString m_string;
|
QString m_string;
|
||||||
int m_major = 0;
|
int m_major = 0;
|
||||||
int m_minor = 0;
|
int m_minor = 0;
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
#include "LaunchStep.h"
|
#include "LaunchStep.h"
|
||||||
#include "LaunchTask.h"
|
#include "LaunchTask.h"
|
||||||
|
|
||||||
void LaunchStep::bind(LaunchTask *parent)
|
void LaunchStep::bind(LaunchTask* parent)
|
||||||
{
|
{
|
||||||
m_parent = parent;
|
m_parent = parent;
|
||||||
connect(this, &LaunchStep::readyForLaunch, parent, &LaunchTask::onReadyForLaunch);
|
connect(this, &LaunchStep::readyForLaunch, parent, &LaunchTask::onReadyForLaunch);
|
||||||
|
@ -15,36 +15,32 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "tasks/Task.h"
|
|
||||||
#include "MessageLevel.h"
|
#include "MessageLevel.h"
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
class LaunchTask;
|
class LaunchTask;
|
||||||
class LaunchStep: public Task
|
class LaunchStep : public Task {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public: /* methods */
|
public: /* methods */
|
||||||
explicit LaunchStep(LaunchTask *parent):Task(nullptr), m_parent(parent)
|
explicit LaunchStep(LaunchTask* parent) : Task(nullptr), m_parent(parent) { bind(parent); };
|
||||||
{
|
virtual ~LaunchStep(){};
|
||||||
bind(parent);
|
|
||||||
};
|
|
||||||
virtual ~LaunchStep() {};
|
|
||||||
|
|
||||||
private: /* methods */
|
private: /* methods */
|
||||||
void bind(LaunchTask *parent);
|
void bind(LaunchTask* parent);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void logLines(QStringList lines, MessageLevel::Enum level);
|
void logLines(QStringList lines, MessageLevel::Enum level);
|
||||||
void logLine(QString line, MessageLevel::Enum level);
|
void logLine(QString line, MessageLevel::Enum level);
|
||||||
void readyForLaunch();
|
void readyForLaunch();
|
||||||
void progressReportingRequest();
|
void progressReportingRequest();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
virtual void proceed() {};
|
virtual void proceed(){};
|
||||||
// called in the opposite order than the Task launch(), used to clean up or otherwise undo things after the launch ends
|
// 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 */
|
protected: /* data */
|
||||||
LaunchTask *m_parent;
|
LaunchTask* m_parent;
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// 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 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -36,16 +36,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "launch/LaunchTask.h"
|
#include "launch/LaunchTask.h"
|
||||||
#include "MessageLevel.h"
|
#include <assert.h>
|
||||||
#include "java/JavaChecker.h"
|
#include <QCoreApplication>
|
||||||
#include "tasks/Task.h"
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QEventLoop>
|
#include <QEventLoop>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <assert.h>
|
#include "MessageLevel.h"
|
||||||
|
#include "java/JavaChecker.h"
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
void LaunchTask::init()
|
void LaunchTask::init()
|
||||||
{
|
{
|
||||||
@ -59,9 +59,7 @@ shared_qobject_ptr<LaunchTask> LaunchTask::create(InstancePtr inst)
|
|||||||
return proc;
|
return proc;
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchTask::LaunchTask(InstancePtr instance): m_instance(instance)
|
LaunchTask::LaunchTask(InstancePtr instance) : m_instance(instance) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void LaunchTask::appendStep(shared_qobject_ptr<LaunchStep> step)
|
void LaunchTask::appendStep(shared_qobject_ptr<LaunchStep> step)
|
||||||
{
|
{
|
||||||
@ -76,8 +74,7 @@ void LaunchTask::prependStep(shared_qobject_ptr<LaunchStep> step)
|
|||||||
void LaunchTask::executeTask()
|
void LaunchTask::executeTask()
|
||||||
{
|
{
|
||||||
m_instance->setCrashed(false);
|
m_instance->setCrashed(false);
|
||||||
if(!m_steps.size())
|
if (!m_steps.size()) {
|
||||||
{
|
|
||||||
state = LaunchTask::Finished;
|
state = LaunchTask::Finished;
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
}
|
}
|
||||||
@ -94,46 +91,35 @@ void LaunchTask::onReadyForLaunch()
|
|||||||
void LaunchTask::onStepFinished()
|
void LaunchTask::onStepFinished()
|
||||||
{
|
{
|
||||||
// initial -> just start the first step
|
// initial -> just start the first step
|
||||||
if(currentStep == -1)
|
if (currentStep == -1) {
|
||||||
{
|
currentStep++;
|
||||||
currentStep ++;
|
|
||||||
m_steps[currentStep]->start();
|
m_steps[currentStep]->start();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto step = m_steps[currentStep];
|
auto step = m_steps[currentStep];
|
||||||
if(step->wasSuccessful())
|
if (step->wasSuccessful()) {
|
||||||
{
|
|
||||||
// end?
|
// end?
|
||||||
if(currentStep == m_steps.size() - 1)
|
if (currentStep == m_steps.size() - 1) {
|
||||||
{
|
|
||||||
finalizeSteps(true, QString());
|
finalizeSteps(true, QString());
|
||||||
}
|
} else {
|
||||||
else
|
currentStep++;
|
||||||
{
|
|
||||||
currentStep ++;
|
|
||||||
step = m_steps[currentStep];
|
step = m_steps[currentStep];
|
||||||
step->start();
|
step->start();
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
finalizeSteps(false, step->failReason());
|
finalizeSteps(false, step->failReason());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaunchTask::finalizeSteps(bool successful, const QString& error)
|
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();
|
m_steps[step]->finalize();
|
||||||
}
|
}
|
||||||
if(successful)
|
if (successful) {
|
||||||
{
|
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
emitFailed(error);
|
emitFailed(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,8 +138,7 @@ void LaunchTask::setCensorFilter(QMap<QString, QString> filter)
|
|||||||
QString LaunchTask::censorPrivateInfo(QString in)
|
QString LaunchTask::censorPrivateInfo(QString in)
|
||||||
{
|
{
|
||||||
auto iter = m_censorFilter.begin();
|
auto iter = m_censorFilter.begin();
|
||||||
while (iter != m_censorFilter.end())
|
while (iter != m_censorFilter.end()) {
|
||||||
{
|
|
||||||
in.replace(iter.key(), iter.value());
|
in.replace(iter.key(), iter.value());
|
||||||
iter++;
|
iter++;
|
||||||
}
|
}
|
||||||
@ -162,8 +147,7 @@ QString LaunchTask::censorPrivateInfo(QString in)
|
|||||||
|
|
||||||
void LaunchTask::proceed()
|
void LaunchTask::proceed()
|
||||||
{
|
{
|
||||||
if(state != LaunchTask::Waiting)
|
if (state != LaunchTask::Waiting) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_steps[currentStep]->proceed();
|
m_steps[currentStep]->proceed();
|
||||||
@ -171,8 +155,7 @@ void LaunchTask::proceed()
|
|||||||
|
|
||||||
bool LaunchTask::canAbort() const
|
bool LaunchTask::canAbort() const
|
||||||
{
|
{
|
||||||
switch(state)
|
switch (state) {
|
||||||
{
|
|
||||||
case LaunchTask::Aborted:
|
case LaunchTask::Aborted:
|
||||||
case LaunchTask::Failed:
|
case LaunchTask::Failed:
|
||||||
case LaunchTask::Finished:
|
case LaunchTask::Finished:
|
||||||
@ -180,8 +163,7 @@ bool LaunchTask::canAbort() const
|
|||||||
case LaunchTask::NotStarted:
|
case LaunchTask::NotStarted:
|
||||||
return true;
|
return true;
|
||||||
case LaunchTask::Running:
|
case LaunchTask::Running:
|
||||||
case LaunchTask::Waiting:
|
case LaunchTask::Waiting: {
|
||||||
{
|
|
||||||
auto step = m_steps[currentStep];
|
auto step = m_steps[currentStep];
|
||||||
return step->canAbort();
|
return step->canAbort();
|
||||||
}
|
}
|
||||||
@ -191,28 +173,23 @@ bool LaunchTask::canAbort() const
|
|||||||
|
|
||||||
bool LaunchTask::abort()
|
bool LaunchTask::abort()
|
||||||
{
|
{
|
||||||
switch(state)
|
switch (state) {
|
||||||
{
|
|
||||||
case LaunchTask::Aborted:
|
case LaunchTask::Aborted:
|
||||||
case LaunchTask::Failed:
|
case LaunchTask::Failed:
|
||||||
case LaunchTask::Finished:
|
case LaunchTask::Finished:
|
||||||
return true;
|
return true;
|
||||||
case LaunchTask::NotStarted:
|
case LaunchTask::NotStarted: {
|
||||||
{
|
|
||||||
state = LaunchTask::Aborted;
|
state = LaunchTask::Aborted;
|
||||||
emitFailed("Aborted");
|
emitFailed("Aborted");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case LaunchTask::Running:
|
case LaunchTask::Running:
|
||||||
case LaunchTask::Waiting:
|
case LaunchTask::Waiting: {
|
||||||
{
|
|
||||||
auto step = m_steps[currentStep];
|
auto step = m_steps[currentStep];
|
||||||
if(!step->canAbort())
|
if (!step->canAbort()) {
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(step->abort())
|
if (step->abort()) {
|
||||||
{
|
|
||||||
state = LaunchTask::Aborted;
|
state = LaunchTask::Aborted;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -225,23 +202,22 @@ bool LaunchTask::abort()
|
|||||||
|
|
||||||
shared_qobject_ptr<LogModel> LaunchTask::getLogModel()
|
shared_qobject_ptr<LogModel> LaunchTask::getLogModel()
|
||||||
{
|
{
|
||||||
if(!m_logModel)
|
if (!m_logModel) {
|
||||||
{
|
|
||||||
m_logModel.reset(new LogModel());
|
m_logModel.reset(new LogModel());
|
||||||
m_logModel->setMaxLines(m_instance->getConsoleMaxLines());
|
m_logModel->setMaxLines(m_instance->getConsoleMaxLines());
|
||||||
m_logModel->setStopOnOverflow(m_instance->shouldStopOnConsoleOverflow());
|
m_logModel->setStopOnOverflow(m_instance->shouldStopOnConsoleOverflow());
|
||||||
// FIXME: should this really be here?
|
// FIXME: should this really be here?
|
||||||
m_logModel->setOverflowMessage(tr("Stopped watching the game log because the log length surpassed %1 lines.\n"
|
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"
|
"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;
|
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);
|
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
|
// if the launcher part set a log level, use it
|
||||||
auto innerLevel = MessageLevel::fromLine(line);
|
auto innerLevel = MessageLevel::fromLine(line);
|
||||||
if(innerLevel != MessageLevel::Unknown)
|
if (innerLevel != MessageLevel::Unknown) {
|
||||||
{
|
|
||||||
level = innerLevel;
|
level = innerLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the level is still undetermined, guess level
|
// 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);
|
level = m_instance->guessLevel(line, level);
|
||||||
}
|
}
|
||||||
|
|
||||||
// censor private user info
|
// censor private user info
|
||||||
line = censorPrivateInfo(line);
|
line = censorPrivateInfo(line);
|
||||||
|
|
||||||
auto &model = *getLogModel();
|
auto& model = *getLogModel();
|
||||||
model.append(level, line);
|
model.append(level, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,22 +255,20 @@ void LaunchTask::emitFailed(QString reason)
|
|||||||
Task::emitFailed(reason);
|
Task::emitFailed(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaunchTask::substituteVariables(QStringList &args) const
|
void LaunchTask::substituteVariables(QStringList& args) const
|
||||||
{
|
{
|
||||||
auto env = m_instance->createEnvironment();
|
auto env = m_instance->createEnvironment();
|
||||||
|
|
||||||
for (auto key : env.keys())
|
for (auto key : env.keys()) {
|
||||||
{
|
|
||||||
args.replaceInStrings("$" + key, env.value(key));
|
args.replaceInStrings("$" + key, env.value(key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaunchTask::substituteVariables(QString &cmd) const
|
void LaunchTask::substituteVariables(QString& cmd) const
|
||||||
{
|
{
|
||||||
auto env = m_instance->createEnvironment();
|
auto env = m_instance->createEnvironment();
|
||||||
|
|
||||||
for (auto key : env.keys())
|
for (auto key : env.keys()) {
|
||||||
{
|
|
||||||
cmd.replace("$" + key, env.value(key));
|
cmd.replace("$" + key, env.value(key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// 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 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -36,54 +36,36 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <QProcess>
|
|
||||||
#include <QObjectPtr.h>
|
#include <QObjectPtr.h>
|
||||||
#include "LogModel.h"
|
#include <QProcess>
|
||||||
#include "BaseInstance.h"
|
#include "BaseInstance.h"
|
||||||
#include "MessageLevel.h"
|
|
||||||
#include "LoggedProcess.h"
|
|
||||||
#include "LaunchStep.h"
|
#include "LaunchStep.h"
|
||||||
|
#include "LogModel.h"
|
||||||
|
#include "LoggedProcess.h"
|
||||||
|
#include "MessageLevel.h"
|
||||||
|
|
||||||
class LaunchTask: public Task
|
class LaunchTask : public Task {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
protected:
|
protected:
|
||||||
explicit LaunchTask(InstancePtr instance);
|
explicit LaunchTask(InstancePtr instance);
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum State
|
enum State { NotStarted, Running, Waiting, Failed, Aborted, Finished };
|
||||||
{
|
|
||||||
NotStarted,
|
|
||||||
Running,
|
|
||||||
Waiting,
|
|
||||||
Failed,
|
|
||||||
Aborted,
|
|
||||||
Finished
|
|
||||||
};
|
|
||||||
|
|
||||||
public: /* methods */
|
public: /* methods */
|
||||||
static shared_qobject_ptr<LaunchTask> create(InstancePtr inst);
|
static shared_qobject_ptr<LaunchTask> create(InstancePtr inst);
|
||||||
virtual ~LaunchTask() {};
|
virtual ~LaunchTask(){};
|
||||||
|
|
||||||
void appendStep(shared_qobject_ptr<LaunchStep> step);
|
void appendStep(shared_qobject_ptr<LaunchStep> step);
|
||||||
void prependStep(shared_qobject_ptr<LaunchStep> step);
|
void prependStep(shared_qobject_ptr<LaunchStep> step);
|
||||||
void setCensorFilter(QMap<QString, QString> filter);
|
void setCensorFilter(QMap<QString, QString> filter);
|
||||||
|
|
||||||
InstancePtr instance()
|
InstancePtr instance() { return m_instance; }
|
||||||
{
|
|
||||||
return m_instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setPid(qint64 pid)
|
void setPid(qint64 pid) { m_pid = pid; }
|
||||||
{
|
|
||||||
m_pid = pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
qint64 pid()
|
qint64 pid() { return m_pid; }
|
||||||
{
|
|
||||||
return m_pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief prepare the process for launch (for multi-stage launch)
|
* @brief prepare the process for launch (for multi-stage launch)
|
||||||
@ -104,39 +86,39 @@ public: /* methods */
|
|||||||
|
|
||||||
shared_qobject_ptr<LogModel> getLogModel();
|
shared_qobject_ptr<LogModel> getLogModel();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void substituteVariables(QStringList &args) const;
|
void substituteVariables(QStringList& args) const;
|
||||||
void substituteVariables(QString &cmd) const;
|
void substituteVariables(QString& cmd) const;
|
||||||
QString censorPrivateInfo(QString in);
|
QString censorPrivateInfo(QString in);
|
||||||
|
|
||||||
protected: /* methods */
|
protected: /* methods */
|
||||||
virtual void emitFailed(QString reason) override;
|
virtual void emitFailed(QString reason) override;
|
||||||
virtual void emitSucceeded() override;
|
virtual void emitSucceeded() override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/**
|
/**
|
||||||
* @brief emitted when the launch preparations are done
|
* @brief emitted when the launch preparations are done
|
||||||
*/
|
*/
|
||||||
void readyForLaunch();
|
void readyForLaunch();
|
||||||
|
|
||||||
void requestProgress(Task *task);
|
void requestProgress(Task* task);
|
||||||
|
|
||||||
void requestLogging();
|
void requestLogging();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onLogLines(const QStringList& lines, MessageLevel::Enum defaultLevel = MessageLevel::Launcher);
|
void onLogLines(const QStringList& lines, MessageLevel::Enum defaultLevel = MessageLevel::Launcher);
|
||||||
void onLogLine(QString line, MessageLevel::Enum defaultLevel = MessageLevel::Launcher);
|
void onLogLine(QString line, MessageLevel::Enum defaultLevel = MessageLevel::Launcher);
|
||||||
void onReadyForLaunch();
|
void onReadyForLaunch();
|
||||||
void onStepFinished();
|
void onStepFinished();
|
||||||
void onProgressReportingRequested();
|
void onProgressReportingRequested();
|
||||||
|
|
||||||
private: /*methods */
|
private: /*methods */
|
||||||
void finalizeSteps(bool successful, const QString & error);
|
void finalizeSteps(bool successful, const QString& error);
|
||||||
|
|
||||||
protected: /* data */
|
protected: /* data */
|
||||||
InstancePtr m_instance;
|
InstancePtr m_instance;
|
||||||
shared_qobject_ptr<LogModel> m_logModel;
|
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;
|
QMap<QString, QString> m_censorFilter;
|
||||||
int currentStep = -1;
|
int currentStep = -1;
|
||||||
State state = NotStarted;
|
State state = NotStarted;
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
#include "LogModel.h"
|
#include "LogModel.h"
|
||||||
|
|
||||||
LogModel::LogModel(QObject *parent):QAbstractListModel(parent)
|
LogModel::LogModel(QObject* parent) : QAbstractListModel(parent)
|
||||||
{
|
{
|
||||||
m_content.resize(m_maxLines);
|
m_content.resize(m_maxLines);
|
||||||
}
|
}
|
||||||
|
|
||||||
int LogModel::rowCount(const QModelIndex &parent) const
|
int LogModel::rowCount(const QModelIndex& parent) const
|
||||||
{
|
{
|
||||||
if (parent.isValid())
|
if (parent.isValid())
|
||||||
return 0;
|
return 0;
|
||||||
@ -13,19 +13,17 @@ int LogModel::rowCount(const QModelIndex &parent) const
|
|||||||
return m_numLines;
|
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)
|
if (index.row() < 0 || index.row() >= m_numLines)
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
auto row = index.row();
|
auto row = index.row();
|
||||||
auto realRow = (row + m_firstLine) % m_maxLines;
|
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;
|
return m_content[realRow].line;
|
||||||
}
|
}
|
||||||
if(role == LevelRole)
|
if (role == LevelRole) {
|
||||||
{
|
|
||||||
return m_content[realRow].level;
|
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)
|
void LogModel::append(MessageLevel::Enum level, QString line)
|
||||||
{
|
{
|
||||||
if(m_suspended)
|
if (m_suspended) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int lineNum = (m_firstLine + m_numLines) % m_maxLines;
|
int lineNum = (m_firstLine + m_numLines) % m_maxLines;
|
||||||
// overflow
|
// overflow
|
||||||
if(m_numLines == m_maxLines)
|
if (m_numLines == m_maxLines) {
|
||||||
{
|
if (m_stopOnOverflow) {
|
||||||
if(m_stopOnOverflow)
|
|
||||||
{
|
|
||||||
// nothing more to do, the buffer is full
|
// nothing more to do, the buffer is full
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
beginRemoveRows(QModelIndex(), 0, 0);
|
beginRemoveRows(QModelIndex(), 0, 0);
|
||||||
m_firstLine = (m_firstLine + 1) % m_maxLines;
|
m_firstLine = (m_firstLine + 1) % m_maxLines;
|
||||||
m_numLines --;
|
m_numLines--;
|
||||||
endRemoveRows();
|
endRemoveRows();
|
||||||
}
|
} else if (m_numLines == m_maxLines - 1 && m_stopOnOverflow) {
|
||||||
else if (m_numLines == m_maxLines - 1 && m_stopOnOverflow)
|
|
||||||
{
|
|
||||||
level = MessageLevel::Fatal;
|
level = MessageLevel::Fatal;
|
||||||
line = m_overflowMessage;
|
line = m_overflowMessage;
|
||||||
}
|
}
|
||||||
beginInsertRows(QModelIndex(), m_numLines, m_numLines);
|
beginInsertRows(QModelIndex(), m_numLines, m_numLines);
|
||||||
m_numLines ++;
|
m_numLines++;
|
||||||
m_content[lineNum].level = level;
|
m_content[lineNum].level = level;
|
||||||
m_content[lineNum].line = line;
|
m_content[lineNum].line = line;
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
@ -86,9 +79,8 @@ QString LogModel::toPlainText()
|
|||||||
{
|
{
|
||||||
QString out;
|
QString out;
|
||||||
out.reserve(m_numLines * 80);
|
out.reserve(m_numLines * 80);
|
||||||
for(int i = 0; i < m_numLines; i++)
|
for (int i = 0; i < m_numLines; i++) {
|
||||||
{
|
QString& line = m_content[(m_firstLine + i) % m_maxLines].line;
|
||||||
QString & line = m_content[(m_firstLine + i) % m_maxLines].line;
|
|
||||||
out.append(line + '\n');
|
out.append(line + '\n');
|
||||||
}
|
}
|
||||||
out.squeeze();
|
out.squeeze();
|
||||||
@ -98,13 +90,11 @@ QString LogModel::toPlainText()
|
|||||||
void LogModel::setMaxLines(int maxLines)
|
void LogModel::setMaxLines(int maxLines)
|
||||||
{
|
{
|
||||||
// no-op
|
// no-op
|
||||||
if(maxLines == m_maxLines)
|
if (maxLines == m_maxLines) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// if it all still fits in the buffer, just resize it
|
// 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_maxLines = maxLines;
|
||||||
m_content.resize(maxLines);
|
m_content.resize(maxLines);
|
||||||
return;
|
return;
|
||||||
@ -112,22 +102,17 @@ void LogModel::setMaxLines(int maxLines)
|
|||||||
// otherwise, we need to reorganize the data because it crosses the wrap boundary
|
// otherwise, we need to reorganize the data because it crosses the wrap boundary
|
||||||
QVector<entry> newContent;
|
QVector<entry> newContent;
|
||||||
newContent.resize(maxLines);
|
newContent.resize(maxLines);
|
||||||
if(m_numLines <= maxLines)
|
if (m_numLines <= maxLines) {
|
||||||
{
|
|
||||||
// if it all fits in the new buffer, just copy it over
|
// 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];
|
newContent[i] = m_content[(m_firstLine + i) % m_maxLines];
|
||||||
}
|
}
|
||||||
m_content.swap(newContent);
|
m_content.swap(newContent);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// if it doesn't fit, part of the data needs to be thrown away (the oldest log messages)
|
// if it doesn't fit, part of the data needs to be thrown away (the oldest log messages)
|
||||||
int lead = m_numLines - maxLines;
|
int lead = m_numLines - maxLines;
|
||||||
beginRemoveRows(QModelIndex(), 0, lead - 1);
|
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];
|
newContent[i] = m_content[(m_firstLine + lead + i) % m_maxLines];
|
||||||
}
|
}
|
||||||
m_numLines = m_maxLines;
|
m_numLines = m_maxLines;
|
||||||
@ -155,8 +140,7 @@ void LogModel::setOverflowMessage(const QString& overflowMessage)
|
|||||||
|
|
||||||
void LogModel::setLineWrap(bool state)
|
void LogModel::setLineWrap(bool state)
|
||||||
{
|
{
|
||||||
if(m_lineWrap != state)
|
if (m_lineWrap != state) {
|
||||||
{
|
|
||||||
m_lineWrap = state;
|
m_lineWrap = state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,14 +4,13 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include "MessageLevel.h"
|
#include "MessageLevel.h"
|
||||||
|
|
||||||
class LogModel : public QAbstractListModel
|
class LogModel : public QAbstractListModel {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit LogModel(QObject *parent = 0);
|
explicit LogModel(QObject* parent = 0);
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
int rowCount(const QModelIndex& parent = QModelIndex()) const;
|
||||||
QVariant data(const QModelIndex &index, int role) const;
|
QVariant data(const QModelIndex& index, int role) const;
|
||||||
|
|
||||||
void append(MessageLevel::Enum, QString line);
|
void append(MessageLevel::Enum, QString line);
|
||||||
void clear();
|
void clear();
|
||||||
@ -24,25 +23,21 @@ public:
|
|||||||
int getMaxLines();
|
int getMaxLines();
|
||||||
void setMaxLines(int maxLines);
|
void setMaxLines(int maxLines);
|
||||||
void setStopOnOverflow(bool stop);
|
void setStopOnOverflow(bool stop);
|
||||||
void setOverflowMessage(const QString & overflowMessage);
|
void setOverflowMessage(const QString& overflowMessage);
|
||||||
|
|
||||||
void setLineWrap(bool state);
|
void setLineWrap(bool state);
|
||||||
bool wrapLines() const;
|
bool wrapLines() const;
|
||||||
|
|
||||||
enum Roles
|
enum Roles { LevelRole = Qt::UserRole };
|
||||||
{
|
|
||||||
LevelRole = Qt::UserRole
|
|
||||||
};
|
|
||||||
|
|
||||||
private /* types */:
|
private /* types */:
|
||||||
struct entry
|
struct entry {
|
||||||
{
|
|
||||||
MessageLevel::Enum level;
|
MessageLevel::Enum level;
|
||||||
QString line;
|
QString line;
|
||||||
};
|
};
|
||||||
|
|
||||||
private: /* data */
|
private: /* data */
|
||||||
QVector <entry> m_content;
|
QVector<entry> m_content;
|
||||||
int m_maxLines = 1000;
|
int m_maxLines = 1000;
|
||||||
// first line in the circular buffer
|
// first line in the circular buffer
|
||||||
int m_firstLine = 0;
|
int m_firstLine = 0;
|
||||||
@ -53,6 +48,6 @@ private: /* data */
|
|||||||
bool m_suspended = false;
|
bool m_suspended = false;
|
||||||
bool m_lineWrap = true;
|
bool m_lineWrap = true;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Q_DISABLE_COPY(LogModel)
|
Q_DISABLE_COPY(LogModel)
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// 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 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -34,12 +34,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CheckJava.h"
|
#include "CheckJava.h"
|
||||||
#include "java/JavaUtils.h"
|
|
||||||
#include <launch/LaunchTask.h>
|
|
||||||
#include <FileSystem.h>
|
#include <FileSystem.h>
|
||||||
#include <QStandardPaths>
|
#include <launch/LaunchTask.h>
|
||||||
#include <QFileInfo>
|
|
||||||
#include <sys.h>
|
#include <sys.h>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include "java/JavaUtils.h"
|
||||||
|
|
||||||
void CheckJava::executeTask()
|
void CheckJava::executeTask()
|
||||||
{
|
{
|
||||||
@ -49,32 +49,26 @@ void CheckJava::executeTask()
|
|||||||
bool perInstance = settings->get("OverrideJava").toBool() || settings->get("OverrideJavaLocation").toBool();
|
bool perInstance = settings->get("OverrideJava").toBool() || settings->get("OverrideJavaLocation").toBool();
|
||||||
|
|
||||||
auto realJavaPath = QStandardPaths::findExecutable(m_javaPath);
|
auto realJavaPath = QStandardPaths::findExecutable(m_javaPath);
|
||||||
if (realJavaPath.isEmpty())
|
if (realJavaPath.isEmpty()) {
|
||||||
{
|
if (perInstance) {
|
||||||
if (perInstance)
|
emit logLine(QString("The java binary \"%1\" couldn't be found. Please fix the java path "
|
||||||
{
|
"override in the instance's settings or disable it.")
|
||||||
emit logLine(
|
.arg(m_javaPath),
|
||||||
QString("The java binary \"%1\" couldn't be found. Please fix the java path "
|
MessageLevel::Warning);
|
||||||
"override in the instance's settings or disable it.").arg(m_javaPath),
|
} else {
|
||||||
MessageLevel::Warning);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
emit logLine(QString("The java binary \"%1\" couldn't be found. Please set up java in "
|
emit logLine(QString("The java binary \"%1\" couldn't be found. Please set up java in "
|
||||||
"the settings.").arg(m_javaPath),
|
"the settings.")
|
||||||
|
.arg(m_javaPath),
|
||||||
MessageLevel::Warning);
|
MessageLevel::Warning);
|
||||||
}
|
}
|
||||||
emitFailed(QString("Java path is not valid."));
|
emitFailed(QString("Java path is not valid."));
|
||||||
return;
|
return;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
emit logLine("Java path is:\n" + m_javaPath + "\n\n", MessageLevel::Launcher);
|
emit logLine("Java path is:\n" + m_javaPath + "\n\n", MessageLevel::Launcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JavaUtils::getJavaCheckPath().isEmpty())
|
if (JavaUtils::getJavaCheckPath().isEmpty()) {
|
||||||
{
|
const char* reason = QT_TR_NOOP("Java checker library could not be found. Please check your installation.");
|
||||||
const char *reason = QT_TR_NOOP("Java checker library could not be found. Please check your installation.");
|
|
||||||
emit logLine(tr(reason), MessageLevel::Fatal);
|
emit logLine(tr(reason), MessageLevel::Fatal);
|
||||||
emitFailed(tr(reason));
|
emitFailed(tr(reason));
|
||||||
return;
|
return;
|
||||||
@ -94,19 +88,15 @@ void CheckJava::executeTask()
|
|||||||
m_javaSignature = hash.result().toHex();
|
m_javaSignature = hash.result().toHex();
|
||||||
|
|
||||||
// if timestamps are not the same, or something is missing, check!
|
// if timestamps are not the same, or something is missing, check!
|
||||||
if (m_javaSignature != storedSignature || storedVersion.size() == 0
|
if (m_javaSignature != storedSignature || storedVersion.size() == 0 || storedArchitecture.size() == 0 ||
|
||||||
|| storedArchitecture.size() == 0 || storedRealArchitecture.size() == 0
|
storedRealArchitecture.size() == 0 || storedVendor.size() == 0) {
|
||||||
|| storedVendor.size() == 0)
|
|
||||||
{
|
|
||||||
m_JavaChecker.reset(new JavaChecker);
|
m_JavaChecker.reset(new JavaChecker);
|
||||||
emit logLine(QString("Checking Java version..."), MessageLevel::Launcher);
|
emit logLine(QString("Checking Java version..."), MessageLevel::Launcher);
|
||||||
connect(m_JavaChecker.get(), &JavaChecker::checkFinished, this, &CheckJava::checkJavaFinished);
|
connect(m_JavaChecker.get(), &JavaChecker::checkFinished, this, &CheckJava::checkJavaFinished);
|
||||||
m_JavaChecker->m_path = realJavaPath;
|
m_JavaChecker->m_path = realJavaPath;
|
||||||
m_JavaChecker->performCheck();
|
m_JavaChecker->performCheck();
|
||||||
return;
|
return;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
auto verString = instance->settings()->get("JavaVersion").toString();
|
auto verString = instance->settings()->get("JavaVersion").toString();
|
||||||
auto archString = instance->settings()->get("JavaArchitecture").toString();
|
auto archString = instance->settings()->get("JavaArchitecture").toString();
|
||||||
auto realArchString = settings->get("JavaRealArchitecture").toString();
|
auto realArchString = settings->get("JavaRealArchitecture").toString();
|
||||||
@ -118,10 +108,8 @@ void CheckJava::executeTask()
|
|||||||
|
|
||||||
void CheckJava::checkJavaFinished(JavaCheckResult result)
|
void CheckJava::checkJavaFinished(JavaCheckResult result)
|
||||||
{
|
{
|
||||||
switch (result.validity)
|
switch (result.validity) {
|
||||||
{
|
case JavaCheckResult::Validity::Errored: {
|
||||||
case JavaCheckResult::Validity::Errored:
|
|
||||||
{
|
|
||||||
// Error message displayed if java can't start
|
// Error message displayed if java can't start
|
||||||
emit logLine(QString("Could not start java:"), MessageLevel::Error);
|
emit logLine(QString("Could not start java:"), MessageLevel::Error);
|
||||||
emit logLines(result.errorLog.split('\n'), MessageLevel::Error);
|
emit logLines(result.errorLog.split('\n'), MessageLevel::Error);
|
||||||
@ -129,16 +117,14 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
|
|||||||
emitFailed(QString("Could not start java!"));
|
emitFailed(QString("Could not start java!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case JavaCheckResult::Validity::ReturnedInvalidData:
|
case JavaCheckResult::Validity::ReturnedInvalidData: {
|
||||||
{
|
|
||||||
emit logLine(QString("Java checker returned some invalid data we don't understand:"), MessageLevel::Error);
|
emit logLine(QString("Java checker returned some invalid data we don't understand:"), MessageLevel::Error);
|
||||||
emit logLines(result.outLog.split('\n'), MessageLevel::Warning);
|
emit logLines(result.outLog.split('\n'), MessageLevel::Warning);
|
||||||
emit logLine("\nMinecraft might not start properly.", MessageLevel::Launcher);
|
emit logLine("\nMinecraft might not start properly.", MessageLevel::Launcher);
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case JavaCheckResult::Validity::Valid:
|
case JavaCheckResult::Validity::Valid: {
|
||||||
{
|
|
||||||
auto instance = m_parent->instance();
|
auto instance = m_parent->instance();
|
||||||
printJavaInfo(result.javaVersion.toString(), result.mojangPlatform, result.realPlatform, result.javaVendor);
|
printJavaInfo(result.javaVersion.toString(), result.mojangPlatform, result.realPlatform, result.javaVendor);
|
||||||
instance->settings()->set("JavaVersion", result.javaVersion.toString());
|
instance->settings()->set("JavaVersion", result.javaVersion.toString());
|
||||||
@ -152,8 +138,9 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckJava::printJavaInfo(const QString& version, const QString& architecture, const QString& realArchitecture, const QString & vendor)
|
void CheckJava::printJavaInfo(const QString& version, const QString& architecture, const QString& realArchitecture, const QString& vendor)
|
||||||
{
|
{
|
||||||
emit logLine(QString("Java is version %1, using %2 (%3) architecture, from %4.\n\n")
|
emit logLine(
|
||||||
.arg(version, architecture, realArchitecture, vendor), MessageLevel::Launcher);
|
QString("Java is version %1, using %2 (%3) architecture, from %4.\n\n").arg(version, architecture, realArchitecture, vendor),
|
||||||
|
MessageLevel::Launcher);
|
||||||
}
|
}
|
||||||
|
@ -15,30 +15,26 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <launch/LaunchStep.h>
|
|
||||||
#include <LoggedProcess.h>
|
#include <LoggedProcess.h>
|
||||||
#include <java/JavaChecker.h>
|
#include <java/JavaChecker.h>
|
||||||
|
#include <launch/LaunchStep.h>
|
||||||
|
|
||||||
class CheckJava: public LaunchStep
|
class CheckJava : public LaunchStep {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit CheckJava(LaunchTask *parent) :LaunchStep(parent){};
|
explicit CheckJava(LaunchTask* parent) : LaunchStep(parent){};
|
||||||
virtual ~CheckJava() {};
|
virtual ~CheckJava(){};
|
||||||
|
|
||||||
virtual void executeTask();
|
virtual void executeTask();
|
||||||
virtual bool canAbort() const
|
virtual bool canAbort() const { return false; }
|
||||||
{
|
private slots:
|
||||||
return false;
|
|
||||||
}
|
|
||||||
private slots:
|
|
||||||
void checkJavaFinished(JavaCheckResult result);
|
void checkJavaFinished(JavaCheckResult result);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void printJavaInfo(const QString & version, const QString & architecture, const QString & realArchitecture, const QString & vendor);
|
void printJavaInfo(const QString& version, const QString& architecture, const QString& realArchitecture, const QString& vendor);
|
||||||
void printSystemInfo(bool javaIsKnown, bool javaIs64bit);
|
void printSystemInfo(bool javaIsKnown, bool javaIs64bit);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_javaPath;
|
QString m_javaPath;
|
||||||
QString m_javaSignature;
|
QString m_javaSignature;
|
||||||
JavaCheckerPtr m_JavaChecker;
|
JavaCheckerPtr m_JavaChecker;
|
||||||
|
@ -13,20 +13,18 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "LookupServerAddress.h"
|
#include "LookupServerAddress.h"
|
||||||
|
|
||||||
#include <launch/LaunchTask.h>
|
#include <launch/LaunchTask.h>
|
||||||
|
|
||||||
LookupServerAddress::LookupServerAddress(LaunchTask *parent) :
|
LookupServerAddress::LookupServerAddress(LaunchTask* parent) : LaunchStep(parent), m_dnsLookup(new QDnsLookup(this))
|
||||||
LaunchStep(parent), m_dnsLookup(new QDnsLookup(this))
|
|
||||||
{
|
{
|
||||||
connect(m_dnsLookup, &QDnsLookup::finished, this, &LookupServerAddress::on_dnsLookupFinished);
|
connect(m_dnsLookup, &QDnsLookup::finished, this, &LookupServerAddress::on_dnsLookupFinished);
|
||||||
|
|
||||||
m_dnsLookup->setType(QDnsLookup::SRV);
|
m_dnsLookup->setType(QDnsLookup::SRV);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LookupServerAddress::setLookupAddress(const QString &lookupAddress)
|
void LookupServerAddress::setLookupAddress(const QString& lookupAddress)
|
||||||
{
|
{
|
||||||
m_lookupAddress = lookupAddress;
|
m_lookupAddress = lookupAddress;
|
||||||
m_dnsLookup->setName(QString("_minecraft._tcp.%1").arg(lookupAddress));
|
m_dnsLookup->setName(QString("_minecraft._tcp.%1").arg(lookupAddress));
|
||||||
@ -51,41 +49,40 @@ void LookupServerAddress::executeTask()
|
|||||||
|
|
||||||
void LookupServerAddress::on_dnsLookupFinished()
|
void LookupServerAddress::on_dnsLookupFinished()
|
||||||
{
|
{
|
||||||
if (isFinished())
|
if (isFinished()) {
|
||||||
{
|
|
||||||
// Aborted
|
// Aborted
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_dnsLookup->error() != QDnsLookup::NoError)
|
if (m_dnsLookup->error() != QDnsLookup::NoError) {
|
||||||
{
|
|
||||||
emit logLine(QString("Failed to resolve server address (this is NOT an error!) %1: %2\n")
|
emit logLine(QString("Failed to resolve server address (this is NOT an error!) %1: %2\n")
|
||||||
.arg(m_dnsLookup->name(), m_dnsLookup->errorString()), MessageLevel::Launcher);
|
.arg(m_dnsLookup->name(), m_dnsLookup->errorString()),
|
||||||
resolve(m_lookupAddress, 25565); // Technically the task failed, however, we don't abort the launch
|
MessageLevel::Launcher);
|
||||||
// and leave it up to minecraft to fail (or maybe not) when connecting
|
resolve(m_lookupAddress, 25565); // Technically the task failed, however, we don't abort the launch
|
||||||
|
// and leave it up to minecraft to fail (or maybe not) when connecting
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto records = m_dnsLookup->serviceRecords();
|
const auto records = m_dnsLookup->serviceRecords();
|
||||||
if (records.empty())
|
if (records.empty()) {
|
||||||
{
|
emit logLine(QString("Failed to resolve server address %1: the DNS lookup succeeded, but no records were returned.\n")
|
||||||
emit logLine(
|
.arg(m_dnsLookup->name()),
|
||||||
QString("Failed to resolve server address %1: the DNS lookup succeeded, but no records were returned.\n")
|
MessageLevel::Warning);
|
||||||
.arg(m_dnsLookup->name()), MessageLevel::Warning);
|
resolve(m_lookupAddress, 25565); // Technically the task failed, however, we don't abort the launch
|
||||||
resolve(m_lookupAddress, 25565); // Technically the task failed, however, we don't abort the launch
|
// and leave it up to minecraft to fail (or maybe not) when connecting
|
||||||
// and leave it up to minecraft to fail (or maybe not) when connecting
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &firstRecord = records.at(0);
|
const auto& firstRecord = records.at(0);
|
||||||
quint16 port = firstRecord.port();
|
quint16 port = firstRecord.port();
|
||||||
|
|
||||||
emit logLine(QString("Resolved server address %1 to %2 with port %3\n").arg(
|
emit logLine(
|
||||||
m_dnsLookup->name(), firstRecord.target(), QString::number(port)),MessageLevel::Launcher);
|
QString("Resolved server address %1 to %2 with port %3\n").arg(m_dnsLookup->name(), firstRecord.target(), QString::number(port)),
|
||||||
|
MessageLevel::Launcher);
|
||||||
resolve(firstRecord.target(), port);
|
resolve(firstRecord.target(), port);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LookupServerAddress::resolve(const QString &address, quint16 port)
|
void LookupServerAddress::resolve(const QString& address, quint16 port)
|
||||||
{
|
{
|
||||||
m_output->address = address;
|
m_output->address = address;
|
||||||
m_output->port = port;
|
m_output->port = port;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user