diff options
Diffstat (limited to 'launcher')
186 files changed, 2312 insertions, 1471 deletions
diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 7c7fc746..6194527c 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -136,11 +136,7 @@ #endif #if defined Q_OS_WIN32 -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include <stdio.h> -#include <windows.h> +#include "WindowsConsole.h" #endif #define STRINGIFY(x) #x @@ -172,22 +168,8 @@ void appDebugOutput(QtMsgType type, const QMessageLogContext& context, const QSt Application::Application(int& argc, char** argv) : QApplication(argc, argv) { #if defined Q_OS_WIN32 - // attach the parent console - if (AttachConsole(ATTACH_PARENT_PROCESS)) { - // if attach succeeds, reopen and sync all the i/o - if (freopen("CON", "w", stdout)) { - std::cout.sync_with_stdio(); - } - if (freopen("CON", "w", stderr)) { - std::cerr.sync_with_stdio(); - } - if (freopen("CON", "r", stdin)) { - std::cin.sync_with_stdio(); - } - auto out = GetStdHandle(STD_OUTPUT_HANDLE); - DWORD written; - const char* endline = "\n"; - WriteConsole(out, endline, strlen(endline), &written, NULL); + // attach the parent console if stdout not already captured + if (AttachWindowsConsole()) { consoleAttached = true; } #endif diff --git a/launcher/BaseInstance.h b/launcher/BaseInstance.h index 4357125f..38dc7c4a 100644 --- a/launcher/BaseInstance.h +++ b/launcher/BaseInstance.h @@ -86,7 +86,7 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns public: /// virtual destructor to make sure the destruction is COMPLETE - virtual ~BaseInstance(){}; + virtual ~BaseInstance() {} virtual void saveNow() = 0; @@ -146,7 +146,7 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns void copyManagedPack(BaseInstance& other); /// guess log level from a line of game log - virtual MessageLevel::Enum guessLevel([[maybe_unused]] const QString& line, MessageLevel::Enum level) { return level; }; + virtual MessageLevel::Enum guessLevel([[maybe_unused]] const QString& line, MessageLevel::Enum level) { return level; } virtual QStringList extraArguments(); @@ -267,7 +267,7 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns protected: void changeStatus(Status newStatus); - SettingsObjectPtr globalSettings() const { return m_global_settings.lock(); }; + SettingsObjectPtr globalSettings() const { return m_global_settings.lock(); } bool isSpecificSettingsLoaded() const { return m_specific_settings_loaded; } void setSpecificSettingsLoaded(bool loaded) { m_specific_settings_loaded = loaded; } diff --git a/launcher/BaseVersion.h b/launcher/BaseVersion.h index c7cedbe1..2837ff3a 100644 --- a/launcher/BaseVersion.h +++ b/launcher/BaseVersion.h @@ -43,9 +43,8 @@ class BaseVersion { * the kind of version this is (Stable, Beta, Snapshot, whatever) */ virtual QString typeString() const = 0; - - virtual bool operator<(BaseVersion& a) { return name() < a.name(); }; - virtual bool operator>(BaseVersion& a) { return name() > a.name(); }; + virtual bool operator<(BaseVersion& a) { return name() < a.name(); } + virtual bool operator>(BaseVersion& a) { return name() > a.name(); } }; Q_DECLARE_METATYPE(BaseVersion::Ptr) diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 824cf80e..84edab59 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -136,6 +136,15 @@ set(NET_SOURCES net/Validator.h net/Upload.cpp net/Upload.h + net/HeaderProxy.h + net/RawHeaderProxy.h + net/ApiHeaderProxy.h + net/ApiDownload.h + net/ApiDownload.cpp + net/ApiUpload.cpp + net/ApiUpload.h + net/NetRequest.cpp + net/NetRequest.h ) # Game launch logic @@ -566,6 +575,9 @@ set(ATLAUNCHER_SOURCES ) set(LINKEXE_SOURCES + WindowsConsole.cpp + WindowsConsole.h + filelink/FileLink.h filelink/FileLink.cpp FileSystem.h @@ -962,6 +974,8 @@ SET(LAUNCHER_SOURCES ui/dialogs/ChooseProviderDialog.cpp ui/dialogs/ModUpdateDialog.cpp ui/dialogs/ModUpdateDialog.h + ui/dialogs/InstallLoaderDialog.cpp + ui/dialogs/InstallLoaderDialog.h # GUI - widgets ui/widgets/Common.cpp @@ -1026,6 +1040,14 @@ SET(LAUNCHER_SOURCES ui/instanceview/VisualGroup.h ) +if(WIN32) + set(LAUNCHER_SOURCES + WindowsConsole.cpp + WindowsConsole.h + ${LAUNCHER_SOURCES} + ) +endif() + qt_wrap_ui(LAUNCHER_UI ui/MainWindow.ui ui/setupwizard/PasteWizardPage.ui @@ -1109,8 +1131,15 @@ if(WIN32) set(LAUNCHER_RCS ${CMAKE_CURRENT_BINARY_DIR}/../${Launcher_Branding_WindowsRC}) endif() +include(CompilerWarnings) + # Add executable add_library(Launcher_logic STATIC ${LOGIC_SOURCES} ${LAUNCHER_SOURCES} ${LAUNCHER_UI} ${LAUNCHER_RESOURCES}) +set_project_warnings(Launcher_logic + "${Launcher_MSVC_WARNINGS}" + "${Launcher_CLANG_WARNINGS}" + "${Launcher_GCC_WARNINGS}") +target_compile_definitions(Launcher_logic PUBLIC LAUNCHER_APPLICATION) target_include_directories(Launcher_logic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(Launcher_logic systeminfo @@ -1195,6 +1224,11 @@ install(TARGETS ${Launcher_Name} if(WIN32) add_library(filelink_logic STATIC ${LINKEXE_SOURCES}) + set_project_warnings(filelink_logic + "${Launcher_MSVC_WARNINGS}" + "${Launcher_CLANG_WARNINGS}" + "${Launcher_GCC_WARNINGS}") + target_include_directories(filelink_logic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(filelink_logic systeminfo diff --git a/launcher/DesktopServices.cpp b/launcher/DesktopServices.cpp index 71048734..6b738f2c 100644 --- a/launcher/DesktopServices.cpp +++ b/launcher/DesktopServices.cpp @@ -96,7 +96,7 @@ bool IndirectOpen(T callable, qint64* pid_forked = nullptr) #endif namespace DesktopServices { -bool openDirectory(const QString& path, bool ensureExists) +bool openDirectory(const QString& path, [[maybe_unused]] bool ensureExists) { qDebug() << "Opening directory" << path; QDir parentPath; diff --git a/launcher/FileSystem.h b/launcher/FileSystem.h index 85e2cbe0..bfed576c 100644 --- a/launcher/FileSystem.h +++ b/launcher/FileSystem.h @@ -112,8 +112,8 @@ class copy : public QObject { bool operator()(bool dryRun = false) { return operator()(QString(), dryRun); } - int totalCopied() { return m_copied; } - int totalFailed() { return m_failedPaths.length(); } + qsizetype totalCopied() { return m_copied; } + qsizetype totalFailed() { return m_failedPaths.length(); } QStringList failed() { return m_failedPaths; } signals: @@ -130,7 +130,7 @@ class copy : public QObject { bool m_whitelist = false; QDir m_src; QDir m_dst; - int m_copied; + qsizetype m_copied; QStringList m_failedPaths; }; @@ -474,8 +474,8 @@ class clone : public QObject { bool operator()(bool dryRun = false) { return operator()(QString(), dryRun); } - int totalCloned() { return m_cloned; } - int totalFailed() { return m_failedClones.length(); } + qsizetype totalCloned() { return m_cloned; } + qsizetype totalFailed() { return m_failedClones.length(); } QList<QPair<QString, QString>> failed() { return m_failedClones; } @@ -491,7 +491,7 @@ class clone : public QObject { bool m_whitelist = false; QDir m_src; QDir m_dst; - int m_cloned; + qsizetype m_cloned; QList<QPair<QString, QString>> m_failedClones; }; diff --git a/launcher/Filter.cpp b/launcher/Filter.cpp index 9d904473..fc1c4234 100644 --- a/launcher/Filter.cpp +++ b/launcher/Filter.cpp @@ -16,6 +16,12 @@ bool ExactFilter::accepts(const QString& value) return value == pattern; } +ExactIfPresentFilter::ExactIfPresentFilter(const QString& pattern) : pattern(pattern) {} +bool ExactIfPresentFilter::accepts(const QString& value) +{ + return value.isEmpty() || value == pattern; +} + RegexpFilter::RegexpFilter(const QString& regexp, bool invert) : invert(invert) { pattern.setPattern(regexp); diff --git a/launcher/Filter.h b/launcher/Filter.h index f58521cf..089c844d 100644 --- a/launcher/Filter.h +++ b/launcher/Filter.h @@ -29,6 +29,16 @@ class ExactFilter : public Filter { QString pattern; }; +class ExactIfPresentFilter : public Filter { + public: + ExactIfPresentFilter(const QString& pattern); + ~ExactIfPresentFilter() override = default; + bool accepts(const QString& value) override; + + private: + QString pattern; +}; + class RegexpFilter : public Filter { public: RegexpFilter(const QString& regexp, bool invert); diff --git a/launcher/InstanceImportTask.cpp b/launcher/InstanceImportTask.cpp index 97e106ba..3f948a33 100644 --- a/launcher/InstanceImportTask.cpp +++ b/launcher/InstanceImportTask.cpp @@ -51,6 +51,8 @@ #include "settings/INISettingsObject.h" +#include "net/ApiDownload.h" + #include <QtConcurrentRun> #include <algorithm> @@ -95,7 +97,7 @@ void InstanceImportTask::executeTask() m_archivePath = entry->getFullPath(); m_filesNetJob.reset(new NetJob(tr("Modpack download"), APPLICATION->network())); - m_filesNetJob->addNetAction(Net::Download::makeCached(m_sourceUrl, entry)); + m_filesNetJob->addNetAction(Net::ApiDownload::makeCached(m_sourceUrl, entry)); connect(m_filesNetJob.get(), &NetJob::succeeded, this, &InstanceImportTask::downloadSucceeded); connect(m_filesNetJob.get(), &NetJob::progress, this, &InstanceImportTask::downloadProgressChanged); diff --git a/launcher/InstanceList.cpp b/launcher/InstanceList.cpp index 02938409..856eee81 100644 --- a/launcher/InstanceList.cpp +++ b/launcher/InstanceList.cpp @@ -96,7 +96,11 @@ Qt::DropActions InstanceList::supportedDropActions() const return Qt::MoveAction; } -bool InstanceList::canDropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) const +bool InstanceList::canDropMimeData(const QMimeData* data, + [[maybe_unused]] Qt::DropAction action, + [[maybe_unused]] int row, + [[maybe_unused]] int column, + [[maybe_unused]] const QModelIndex& parent) const { if (data && data->hasFormat("application/x-instanceid")) { return true; @@ -104,7 +108,11 @@ bool InstanceList::canDropMimeData(const QMimeData* data, Qt::DropAction action, return false; } -bool InstanceList::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) +bool InstanceList::dropMimeData(const QMimeData* data, + [[maybe_unused]] Qt::DropAction action, + [[maybe_unused]] int row, + [[maybe_unused]] int column, + [[maybe_unused]] const QModelIndex& parent) { if (data && data->hasFormat("application/x-instanceid")) { return true; @@ -751,7 +759,7 @@ void InstanceList::instanceDirContentsChanged(const QString& path) emit instancesChanged(); } -void InstanceList::on_InstFolderChanged(const Setting& setting, QVariant value) +void InstanceList::on_InstFolderChanged([[maybe_unused]] const Setting& setting, QVariant value) { QString newInstDir = QDir(value.toString()).canonicalPath(); if (newInstDir != m_instDir) { @@ -789,7 +797,7 @@ class InstanceStaging : public Task { , m_groupName(std::move(groupName)) { m_child.reset(child); - connect(child, &Task::succeeded, this, &InstanceStaging::childSucceded); + connect(child, &Task::succeeded, this, &InstanceStaging::childSucceeded); connect(child, &Task::failed, this, &InstanceStaging::childFailed); connect(child, &Task::aborted, this, &InstanceStaging::childAborted); connect(child, &Task::abortStatusChanged, this, &InstanceStaging::setAbortable); @@ -797,7 +805,7 @@ class InstanceStaging : public Task { connect(child, &Task::details, this, &InstanceStaging::setDetails); connect(child, &Task::progress, this, &InstanceStaging::setProgress); connect(child, &Task::stepProgress, this, &InstanceStaging::propagateStepProgress); - connect(&m_backoffTimer, &QTimer::timeout, this, &InstanceStaging::childSucceded); + connect(&m_backoffTimer, &QTimer::timeout, this, &InstanceStaging::childSucceeded); } virtual ~InstanceStaging(){}; @@ -819,7 +827,7 @@ class InstanceStaging : public Task { QStringList warnings() const override { return m_child->warnings(); } private slots: - void childSucceded() + void childSucceeded() { unsigned sleepTime = backoff(); if (m_parent->commitStagedInstance(m_stagingPath, m_instance_name, m_groupName, *m_child.get())) { diff --git a/launcher/NullInstance.h b/launcher/NullInstance.h index a332d4c4..ff658c43 100644 --- a/launcher/NullInstance.h +++ b/launcher/NullInstance.h @@ -52,7 +52,7 @@ class NullInstance : public BaseInstance { QSet<QString> traits() const override { return {}; }; QString instanceConfigFolder() const override { return instanceRoot(); }; shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr, MinecraftServerTargetPtr) override { return nullptr; } - shared_qobject_ptr<Task> createUpdateTask(Net::Mode mode) override { return nullptr; } + shared_qobject_ptr<Task> createUpdateTask([[maybe_unused]] 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>(); } diff --git a/launcher/ProblemProvider.h b/launcher/ProblemProvider.h index 246a8b5c..9d1b0004 100644 --- a/launcher/ProblemProvider.h +++ b/launcher/ProblemProvider.h @@ -12,7 +12,7 @@ struct PatchProblem { class ProblemProvider { public: - virtual ~ProblemProvider(){}; + virtual ~ProblemProvider() {} virtual const QList<PatchProblem> getProblems() const = 0; virtual ProblemSeverity getProblemSeverity() const = 0; }; diff --git a/launcher/RecursiveFileSystemWatcher.cpp b/launcher/RecursiveFileSystemWatcher.cpp index f3be1bd8..8b28a03f 100644 --- a/launcher/RecursiveFileSystemWatcher.cpp +++ b/launcher/RecursiveFileSystemWatcher.cpp @@ -90,7 +90,7 @@ void RecursiveFileSystemWatcher::fileChange(const QString& path) { emit fileChanged(path); } -void RecursiveFileSystemWatcher::directoryChange(const QString& path) +void RecursiveFileSystemWatcher::directoryChange([[maybe_unused]] const QString& path) { setFiles(scanRecursive(m_root)); } diff --git a/launcher/ResourceDownloadTask.cpp b/launcher/ResourceDownloadTask.cpp index 8bb9b64e..a02151ca 100644 --- a/launcher/ResourceDownloadTask.cpp +++ b/launcher/ResourceDownloadTask.cpp @@ -24,6 +24,8 @@ #include "minecraft/mod/ModFolderModel.h" #include "minecraft/mod/ResourceFolderModel.h" +#include "net/ApiDownload.h" + ResourceDownloadTask::ResourceDownloadTask(ModPlatform::IndexedPack::Ptr pack, ModPlatform::IndexedVersion version, const std::shared_ptr<ResourceFolderModel> packs, @@ -51,7 +53,7 @@ ResourceDownloadTask::ResourceDownloadTask(ModPlatform::IndexedPack::Ptr pack, } } - m_filesNetJob->addNetAction(Net::Download::makeFile(m_pack_version.downloadUrl, dir.absoluteFilePath(getFilename()))); + m_filesNetJob->addNetAction(Net::ApiDownload::makeFile(m_pack_version.downloadUrl, dir.absoluteFilePath(getFilename()))); connect(m_filesNetJob.get(), &NetJob::succeeded, this, &ResourceDownloadTask::downloadSucceeded); connect(m_filesNetJob.get(), &NetJob::progress, this, &ResourceDownloadTask::downloadProgressChanged); connect(m_filesNetJob.get(), &NetJob::stepProgress, this, &ResourceDownloadTask::propagateStepProgress); diff --git a/launcher/Usable.h b/launcher/Usable.h index a75415aa..b0ecd401 100644 --- a/launcher/Usable.h +++ b/launcher/Usable.h @@ -16,6 +16,8 @@ class Usable { friend class UseLock; public: + virtual ~Usable() {} + std::size_t useCount() const { return m_useCount; } bool isInUse() const { return m_useCount > 0; } diff --git a/launcher/Version.h b/launcher/Version.h index 101a907c..92bff9ba 100644 --- a/launcher/Version.h +++ b/launcher/Version.h @@ -63,7 +63,7 @@ class Version { struct Section { explicit Section(QString fullString) : m_fullString(std::move(fullString)) { - int cutoff = m_fullString.size(); + qsizetype cutoff = m_fullString.size(); for (int i = 0; i < m_fullString.size(); i++) { if (!m_fullString[i].isDigit()) { cutoff = i; diff --git a/launcher/VersionProxyModel.cpp b/launcher/VersionProxyModel.cpp index 6e0333e4..0ab9ae2c 100644 --- a/launcher/VersionProxyModel.cpp +++ b/launcher/VersionProxyModel.cpp @@ -194,12 +194,12 @@ QVariant VersionProxyModel::data(const QModelIndex& index, int role) const switch (column) { case Name: { if (hasRecommended) { - auto value = sourceModel()->data(parentIndex, BaseVersionList::RecommendedRole); - if (value.toBool()) { + auto recommenced = sourceModel()->data(parentIndex, BaseVersionList::RecommendedRole); + if (recommenced.toBool()) { return APPLICATION->getThemedIcon("star"); } else if (hasLatest) { - auto value = sourceModel()->data(parentIndex, BaseVersionList::LatestRole); - if (value.toBool()) { + auto latest = sourceModel()->data(parentIndex, BaseVersionList::LatestRole); + if (latest.toBool()) { return APPLICATION->getThemedIcon("bug"); } } @@ -228,7 +228,7 @@ QVariant VersionProxyModel::data(const QModelIndex& index, int role) const } } -QModelIndex VersionProxyModel::parent(const QModelIndex& child) const +QModelIndex VersionProxyModel::parent([[maybe_unused]] const QModelIndex& child) const { return QModelIndex(); } @@ -408,7 +408,9 @@ void VersionProxyModel::sourceRowsAboutToBeInserted(const QModelIndex& parent, i beginInsertRows(parent, first, last); } -void VersionProxyModel::sourceRowsInserted(const QModelIndex& parent, int first, int last) +void VersionProxyModel::sourceRowsInserted([[maybe_unused]] const QModelIndex& parent, + [[maybe_unused]] int first, + [[maybe_unused]] int last) { endInsertRows(); } @@ -418,7 +420,7 @@ void VersionProxyModel::sourceRowsAboutToBeRemoved(const QModelIndex& parent, in beginRemoveRows(parent, first, last); } -void VersionProxyModel::sourceRowsRemoved(const QModelIndex& parent, int first, int last) +void VersionProxyModel::sourceRowsRemoved([[maybe_unused]] const QModelIndex& parent, [[maybe_unused]] int first, [[maybe_unused]] int last) { endRemoveRows(); } diff --git a/launcher/WindowsConsole.cpp b/launcher/WindowsConsole.cpp new file mode 100644 index 00000000..83cad5af --- /dev/null +++ b/launcher/WindowsConsole.cpp @@ -0,0 +1,128 @@ +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include <fcntl.h> +#include <io.h> +#include <stdio.h> +#include <windows.h> +#include <iostream> + +void RedirectHandle(DWORD handle, FILE* stream, const char* mode) +{ + HANDLE stdHandle = GetStdHandle(handle); + if (stdHandle != INVALID_HANDLE_VALUE) { + int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT); + if (fileDescriptor != -1) { + FILE* file = _fdopen(fileDescriptor, mode); + if (file != NULL) { + int dup2Result = _dup2(_fileno(file), _fileno(stream)); + if (dup2Result == 0) { + setvbuf(stream, NULL, _IONBF, 0); + } + } + } + } +} + +// taken from https://stackoverflow.com/a/25927081 +// getting a proper output to console with redirection support on windows is apparently hell +void BindCrtHandlesToStdHandles(bool bindStdIn, bool bindStdOut, bool bindStdErr) +{ + // Re-initialize the C runtime "FILE" handles with clean handles bound to "nul". We do this because it has been + // observed that the file number of our standard handle file objects can be assigned internally to a value of -2 + // when not bound to a valid target, which represents some kind of unknown internal invalid state. In this state our + // call to "_dup2" fails, as it specifically tests to ensure that the target file number isn't equal to this value + // before allowing the operation to continue. We can resolve this issue by first "re-opening" the target files to + // use the "nul" device, which will place them into a valid state, after which we can redirect them to our target + // using the "_dup2" function. + if (bindStdIn) { + FILE* dummyFile; + freopen_s(&dummyFile, "nul", "r", stdin); + } + if (bindStdOut) { + FILE* dummyFile; + freopen_s(&dummyFile, "nul", "w", stdout); + } + if (bindStdErr) { + FILE* dummyFile; + freopen_s(&dummyFile, "nul", "w", stderr); + } + + // Redirect unbuffered stdin from the current standard input handle + if (bindStdIn) { + RedirectHandle(STD_INPUT_HANDLE, stdin, "r"); + } + + // Redirect unbuffered stdout to the current standard output handle + if (bindStdOut) { + RedirectHandle(STD_OUTPUT_HANDLE, stdout, "w"); + } + + // Redirect unbuffered stderr to the current standard error handle + if (bindStdErr) { + RedirectHandle(STD_ERROR_HANDLE, stderr, "w"); + } + + // Clear the error state for each of the C++ standard stream objects. We need to do this, as attempts to access the + // standard streams before they refer to a valid target will cause the iostream objects to enter an error state. In + // versions of Visual Studio after 2005, this seems to always occur during startup regardless of whether anything + // has been read from or written to the targets or not. + if (bindStdIn) { + std::wcin.clear(); + std::cin.clear(); + } + if (bindStdOut) { + std::wcout.clear(); + std::cout.clear(); + } + if (bindStdErr) { + std::wcerr.clear(); + std::cerr.clear(); + } +} + +bool AttachWindowsConsole() +{ + auto stdinType = GetFileType(GetStdHandle(STD_INPUT_HANDLE)); + auto stdoutType = GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)); + auto stderrType = GetFileType(GetStdHandle(STD_ERROR_HANDLE)); + + bool bindStdIn = false; + bool bindStdOut = false; + bool bindStdErr = false; + + if (stdinType == FILE_TYPE_CHAR || stdinType == FILE_TYPE_UNKNOWN) { + bindStdIn = true; + } + if (stdoutType == FILE_TYPE_CHAR || stdoutType == FILE_TYPE_UNKNOWN) { + bindStdOut = true; + } + if (stderrType == FILE_TYPE_CHAR || stderrType == FILE_TYPE_UNKNOWN) { + bindStdErr = true; + } + + if (AttachConsole(ATTACH_PARENT_PROCESS)) { + BindCrtHandlesToStdHandles(bindStdIn, bindStdOut, bindStdErr); + return true; + } + + return false; +} diff --git a/launcher/WindowsConsole.h b/launcher/WindowsConsole.h new file mode 100644 index 00000000..ab53864b --- /dev/null +++ b/launcher/WindowsConsole.h @@ -0,0 +1,25 @@ +// +// SPDX-License-Identifier: GPL-3.0-only + +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#pragma once + +void BindCrtHandlesToStdHandles(bool bindStdIn, bool bindStdOut, bool bindStdErr); +bool AttachWindowsConsole(); diff --git a/launcher/filelink/FileLink.cpp b/launcher/filelink/FileLink.cpp index c9599b82..1ea0e382 100644 --- a/launcher/filelink/FileLink.cpp +++ b/launcher/filelink/FileLink.cpp @@ -37,11 +37,7 @@ #include <sys.h> #if defined Q_OS_WIN32 -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include <stdio.h> -#include <windows.h> +#include "WindowsConsole.h" #endif // Snippet from https://github.com/gulrak/filesystem#using-it-as-single-file-header @@ -67,21 +63,7 @@ FileLinkApp::FileLinkApp(int& argc, char** argv) : QCoreApplication(argc, argv), { #if defined Q_OS_WIN32 // attach the parent console - if (AttachConsole(ATTACH_PARENT_PROCESS)) { - // if attach succeeds, reopen and sync all the i/o - if (freopen("CON", "w", stdout)) { - std::cout.sync_with_stdio(); - } - if (freopen("CON", "w", stderr)) { - std::cerr.sync_with_stdio(); - } - if (freopen("CON", "r", stdin)) { - std::cin.sync_with_stdio(); - } - auto out = GetStdHandle(STD_OUTPUT_HANDLE); - DWORD written; - const char* endline = "\n"; - WriteConsole(out, endline, strlen(endline), &written, NULL); + if (AttachWindowsConsole()) { consoleAttached = true; } #endif @@ -188,7 +170,7 @@ void FileLinkApp::runLink() FS::LinkResult result = { src_path, dst_path, QString::fromStdString(os_err.message()), os_err.value() }; m_path_results.append(result); } else { - FS::LinkResult result = { src_path, dst_path }; + FS::LinkResult result = { src_path, dst_path, "", 0 }; m_path_results.append(result); } } @@ -248,7 +230,7 @@ void FileLinkApp::readPathPairs() in >> numLinks; qDebug() << "numLinks" << numLinks; - for (int i = 0; i < numLinks; i++) { + for (quint32 i = 0; i < numLinks; i++) { FS::LinkPair pair; in >> pair.src; in >> pair.dst; @@ -271,7 +253,6 @@ FileLinkApp::~FileLinkApp() fclose(stdout); fclose(stdin); fclose(stderr); - FreeConsole(); } #endif } diff --git a/launcher/icons/IconList.cpp b/launcher/icons/IconList.cpp index 30c51caf..5576b974 100644 --- a/launcher/icons/IconList.cpp +++ b/launcher/icons/IconList.cpp @@ -2,6 +2,7 @@ /* * Prism Launcher - Minecraft Launcher * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> + * Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -42,6 +43,7 @@ #include <QMimeData> #include <QSet> #include <QUrl> +#include "icons/IconUtils.h" #define MAX_SIZE 1024 @@ -128,7 +130,7 @@ void IconList::directoryChanged(const QString& path) QString suffix = rmfile.suffix(); // The icon doesnt have a suffix, but it can have other .s in the name, so we account for those as well - if (suffix != "jpeg" && suffix != "png" && suffix != "jpg" && suffix != "ico" && suffix != "svg" && suffix != "gif") + if (!IconUtils::isIconSuffix(suffix)) key = rmfile.fileName(); int idx = getIconIndex(key); @@ -155,7 +157,7 @@ void IconList::directoryChanged(const QString& path) QString suffix = addfile.suffix(); // The icon doesnt have a suffix, but it can have other .s in the name, so we account for those as well - if (suffix != "jpeg" && suffix != "png" && suffix != "jpg" && suffix != "ico" && suffix != "svg" && suffix != "gif") + if (!IconUtils::isIconSuffix(suffix)) key = addfile.fileName(); if (addIcon(key, QString(), addfile.filePath(), IconType::FileBased)) { @@ -255,10 +257,7 @@ bool IconList::dropMimeData(const QMimeData* data, Qt::ItemFlags IconList::flags(const QModelIndex& index) const { Qt::ItemFlags defaultFlags = QAbstractListModel::flags(index); - if (index.isValid()) - return Qt::ItemIsDropEnabled | defaultFlags; - else - return Qt::ItemIsDropEnabled | defaultFlags; + return Qt::ItemIsDropEnabled | defaultFlags; } QVariant IconList::data(const QModelIndex& index, int role) const @@ -290,19 +289,8 @@ int IconList::rowCount(const QModelIndex& parent) const void IconList::installIcons(const QStringList& iconFiles) { - for (QString file : iconFiles) { - QFileInfo fileinfo(file); - if (!fileinfo.isReadable() || !fileinfo.isFile()) - continue; - QString target = FS::PathCombine(getDirectory(), fileinfo.fileName()); - - QString suffix = fileinfo.suffix(); - if (suffix != "jpeg" && suffix != "png" && suffix != "jpg" && suffix != "ico" && suffix != "svg" && suffix != "gif") - continue; - - if (!QFile::copy(file, target)) - continue; - } + for (QString file : iconFiles) + installIcon(file, {}); } void IconList::installIcon(const QString& file, const QString& name) @@ -311,18 +299,17 @@ void IconList::installIcon(const QString& file, const QString& name) if (!fileinfo.isReadable() || !fileinfo.isFile()) return; - QString target = FS::PathCombine(getDirectory(), name); + if (!IconUtils::isIconSuffix(fileinfo.suffix())) + return; + QString target = FS::PathCombine(getDirectory(), name.isEmpty() ? fileinfo.fileName() : name); QFile::copy(file, target); } bool IconList::iconFileExists(const QString& key) const { auto iconEntry = icon(key); - if (!iconEntry) { - return false; - } - return iconEntry->has(IconType::FileBased); + return iconEntry && iconEntry->has(IconType::FileBased); } const MMCIcon* IconList::icon(const QString& key) const @@ -335,18 +322,12 @@ const MMCIcon* IconList::icon(const QString& key) const bool IconList::deleteIcon(const QString& key) { - if (!iconFileExists(key)) - return false; - - return QFile::remove(icon(key)->getFilePath()); + return iconFileExists(key) && QFile::remove(icon(key)->getFilePath()); } bool IconList::trashIcon(const QString& key) { - if (!iconFileExists(key)) - return false; - - return FS::trash(icon(key)->getFilePath(), nullptr); + return iconFileExists(key) && FS::trash(icon(key)->getFilePath(), nullptr); } bool IconList::addThemeIcon(const QString& key) @@ -357,20 +338,19 @@ bool IconList::addThemeIcon(const QString& key) oldOne.replace(Builtin, key); dataChanged(index(*iter), index(*iter)); return true; - } else { - // add a new icon - beginInsertRows(QModelIndex(), icons.size(), icons.size()); - { - MMCIcon mmc_icon; - mmc_icon.m_name = key; - mmc_icon.m_key = key; - mmc_icon.replace(Builtin, key); - icons.push_back(mmc_icon); - name_index[key] = icons.size() - 1; - } - endInsertRows(); - return true; } + // add a new icon + beginInsertRows(QModelIndex(), icons.size(), icons.size()); + { + MMCIcon mmc_icon; + mmc_icon.m_name = key; + mmc_icon.m_key = key; + mmc_icon.replace(Builtin, key); + icons.push_back(mmc_icon); + name_index[key] = icons.size() - 1; + } + endInsertRows(); + return true; } bool IconList::addIcon(const QString& key, const QString& name, const QString& path, const IconType type) @@ -385,20 +365,19 @@ bool IconList::addIcon(const QString& key, const QString& name, const QString& p oldOne.replace(type, icon, path); dataChanged(index(*iter), index(*iter)); return true; - } else { - // add a new icon - beginInsertRows(QModelIndex(), icons.size(), icons.size()); - { - MMCIcon mmc_icon; - mmc_icon.m_name = name; - mmc_icon.m_key = key; - mmc_icon.replace(type, icon, path); - icons.push_back(mmc_icon); - name_index[key] = icons.size() - 1; - } - endInsertRows(); - return true; } + // add a new icon + beginInsertRows(QModelIndex(), icons.size(), icons.size()); + { + MMCIcon mmc_icon; + mmc_icon.m_name = name; + mmc_icon.m_key = key; + mmc_icon.replace(type, icon, path); + icons.push_back(mmc_icon); + name_index[key] = icons.size() - 1; + } + endInsertRows(); + return true; } void IconList::saveIcon(const QString& key, const QString& path, const char* format) const @@ -446,5 +425,3 @@ QString IconList::getDirectory() const { return m_dir.absolutePath(); } - -//#include "IconList.moc" diff --git a/launcher/icons/IconList.h b/launcher/icons/IconList.h index bc1dd3b9..8afd0557 100644 --- a/launcher/icons/IconList.h +++ b/launcher/icons/IconList.h @@ -1,18 +1,37 @@ -/* Copyright 2013-2021 MultiMC Contributors +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com> * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - #pragma once #include <QAbstractListModel> diff --git a/launcher/icons/IconUtils.cpp b/launcher/icons/IconUtils.cpp index 0b06639e..99c38f47 100644 --- a/launcher/icons/IconUtils.cpp +++ b/launcher/icons/IconUtils.cpp @@ -1,19 +1,51 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include "IconUtils.h" #include <QDirIterator> #include "FileSystem.h" -#include <array> - namespace { -std::array<const char*, 6> validIconExtensions = { { "svg", "png", "ico", "gif", "jpg", "jpeg" } }; +static const QStringList validIconExtensions = { { "svg", "png", "ico", "gif", "jpg", "jpeg" } }; } namespace IconUtils { QString findBestIconIn(const QString& folder, const QString& iconKey) { - int best_found = validIconExtensions.size(); QString best_filename; QDirIterator it(folder, QDir::NoDotAndDotDot | QDir::Files, QDirIterator::NoIteratorFlags); @@ -21,36 +53,20 @@ QString findBestIconIn(const QString& folder, const QString& iconKey) it.next(); auto fileInfo = it.fileInfo(); - if (fileInfo.completeBaseName() != iconKey) - continue; - - auto extension = fileInfo.suffix(); - - for (int i = 0; i < best_found; i++) { - if (extension == validIconExtensions[i]) { - best_found = i; - qDebug() << i << " : " << fileInfo.fileName(); - best_filename = fileInfo.fileName(); - } - } + if (fileInfo.completeBaseName() == iconKey && isIconSuffix(fileInfo.suffix())) + return fileInfo.absoluteFilePath(); } - return FS::PathCombine(folder, best_filename); + return {}; } QString getIconFilter() { - QString out; - QTextStream stream(&out); - stream << '('; - for (size_t i = 0; i < validIconExtensions.size() - 1; i++) { - if (i > 0) { - stream << " "; - } - stream << "*." << validIconExtensions[i]; - } - stream << " *." << validIconExtensions[validIconExtensions.size() - 1]; - stream << ')'; - return out; + return "(*." + validIconExtensions.join(" *.") + ")"; +} + +bool isIconSuffix(QString suffix) +{ + return validIconExtensions.contains(suffix); } } // namespace IconUtils diff --git a/launcher/icons/IconUtils.h b/launcher/icons/IconUtils.h index 8c6f677d..90cdfe5a 100644 --- a/launcher/icons/IconUtils.h +++ b/launcher/icons/IconUtils.h @@ -1,3 +1,38 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #pragma once #include <QString> @@ -10,4 +45,5 @@ QString findBestIconIn(const QString& folder, const QString& iconKey); // Get icon file type filter for file browser dialogs QString getIconFilter(); +bool isIconSuffix(QString suffix); } // namespace IconUtils diff --git a/launcher/icons/MMCIcon.cpp b/launcher/icons/MMCIcon.cpp index 8301b1ba..991b470c 100644 --- a/launcher/icons/MMCIcon.cpp +++ b/launcher/icons/MMCIcon.cpp @@ -2,6 +2,7 @@ /* * Prism Launcher - Minecraft Launcher * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> + * Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -50,8 +51,8 @@ IconType operator--(IconType& t, int) case IconType::FileBased: t = IconType::Transient; break; - default: { - } + default: + break; } return temp; } diff --git a/launcher/icons/MMCIcon.h b/launcher/icons/MMCIcon.h index c968f306..a6e30566 100644 --- a/launcher/icons/MMCIcon.h +++ b/launcher/icons/MMCIcon.h @@ -1,18 +1,37 @@ -/* Copyright 2013-2021 MultiMC Contributors +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com> * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - #pragma once #include <QDateTime> #include <QIcon> diff --git a/launcher/java/JavaVersion.h b/launcher/java/JavaVersion.h index 69473203..7e66269c 100644 --- a/launcher/java/JavaVersion.h +++ b/launcher/java/JavaVersion.h @@ -14,7 +14,7 @@ class JavaVersion { friend class JavaVersionTest; public: - JavaVersion(){}; + JavaVersion() {} JavaVersion(const QString& rhs); JavaVersion& operator=(const QString& rhs); diff --git a/launcher/meta/BaseEntity.cpp b/launcher/meta/BaseEntity.cpp index d8003b55..5f9804e4 100644 --- a/launcher/meta/BaseEntity.cpp +++ b/launcher/meta/BaseEntity.cpp @@ -16,7 +16,7 @@ #include "BaseEntity.h" #include "Json.h" -#include "net/Download.h" +#include "net/ApiDownload.h" #include "net/HttpMetaCache.h" #include "net/NetJob.h" @@ -32,7 +32,7 @@ class ParsingValidator : public Net::Validator { bool init(QNetworkRequest&) override { return true; } bool write(QByteArray& data) override { - this->data.append(data); + this->m_data.append(data); return true; } bool abort() override { return true; } @@ -40,7 +40,7 @@ class ParsingValidator : public Net::Validator { { auto fname = m_entity->localFilename(); try { - auto doc = Json::requireDocument(data, fname); + auto doc = Json::requireDocument(m_data, fname); auto obj = Json::requireObject(doc, fname); m_entity->parse(obj); return true; @@ -51,7 +51,7 @@ class ParsingValidator : public Net::Validator { } private: /* data */ - QByteArray data; + QByteArray m_data; Meta::BaseEntity* m_entity; }; @@ -104,7 +104,7 @@ void Meta::BaseEntity::load(Net::Mode loadType) auto url = this->url(); auto entry = APPLICATION->metacache()->resolveEntry("meta", localFilename()); entry->setStale(true); - auto dl = Net::Download::makeCached(url, entry); + auto dl = Net::ApiDownload::makeCached(url, entry); /* * The validator parses the file and loads it into the object. * If that fails, the file is not written to storage. diff --git a/launcher/minecraft/AssetsUtils.cpp b/launcher/minecraft/AssetsUtils.cpp index 4923f0ef..4ef00707 100644 --- a/launcher/minecraft/AssetsUtils.cpp +++ b/launcher/minecraft/AssetsUtils.cpp @@ -46,8 +46,8 @@ #include "AssetsUtils.h" #include "BuildConfig.h" #include "FileSystem.h" +#include "net/ApiDownload.h" #include "net/ChecksumValidator.h" -#include "net/Download.h" #include "Application.h" @@ -279,7 +279,7 @@ NetAction::Ptr AssetObject::getDownloadAction() { QFileInfo objectFile(getLocalPath()); if ((!objectFile.isFile()) || (objectFile.size() != size)) { - auto objectDL = Net::Download::makeFile(getUrl(), objectFile.filePath()); + auto objectDL = Net::ApiDownload::makeFile(getUrl(), objectFile.filePath()); if (hash.size()) { auto rawHash = QByteArray::fromHex(hash.toLatin1()); objectDL->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawHash)); diff --git a/launcher/minecraft/Component.h b/launcher/minecraft/Component.h index 00a912d6..3474a22e 100644 --- a/launcher/minecraft/Component.h +++ b/launcher/minecraft/Component.h @@ -25,7 +25,8 @@ class Component : public QObject, public ProblemProvider { Component(PackProfile* parent, std::shared_ptr<Meta::Version> version); Component(PackProfile* parent, const QString& uid, std::shared_ptr<VersionFile> file); - virtual ~Component(){}; + virtual ~Component() {} + void applyTo(LaunchProfile* profile); bool isEnabled(); diff --git a/launcher/minecraft/LaunchProfile.h b/launcher/minecraft/LaunchProfile.h index 3acc1f19..12b31238 100644 --- a/launcher/minecraft/LaunchProfile.h +++ b/launcher/minecraft/LaunchProfile.h @@ -41,7 +41,7 @@ class LaunchProfile : public ProblemProvider { public: - virtual ~LaunchProfile(){}; + virtual ~LaunchProfile() {} public: /* application of profile variables from patches */ void applyMinecraftVersion(const QString& id); diff --git a/launcher/minecraft/Library.cpp b/launcher/minecraft/Library.cpp index a9c20845..0e8ddf03 100644 --- a/launcher/minecraft/Library.cpp +++ b/launcher/minecraft/Library.cpp @@ -38,8 +38,8 @@ #include <BuildConfig.h> #include <FileSystem.h> +#include <net/ApiDownload.h> #include <net/ChecksumValidator.h> -#include <net/Download.h> void Library::getApplicableFiles(const RuntimeContext& runtimeContext, QStringList& jar, @@ -115,12 +115,12 @@ QList<NetAction::Ptr> Library::getDownloads(const RuntimeContext& runtimeContext if (sha1.size()) { auto rawSha1 = QByteArray::fromHex(sha1.toLatin1()); - auto dl = Net::Download::makeCached(url, entry, options); + auto dl = Net::ApiDownload::makeCached(url, entry, options); dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawSha1)); qDebug() << "Checksummed Download for:" << rawName().serialize() << "storage:" << storage << "url:" << url; out.append(dl); } else { - out.append(Net::Download::makeCached(url, entry, options)); + out.append(Net::ApiDownload::makeCached(url, entry, options)); qDebug() << "Download for:" << rawName().serialize() << "storage:" << storage << "url:" << url; } return true; diff --git a/launcher/minecraft/MojangDownloadInfo.h b/launcher/minecraft/MojangDownloadInfo.h index b98a0168..855dbe00 100644 --- a/launcher/minecraft/MojangDownloadInfo.h +++ b/launcher/minecraft/MojangDownloadInfo.h @@ -19,8 +19,8 @@ struct MojangDownloadInfo { }; struct MojangLibraryDownloadInfo { - MojangLibraryDownloadInfo(MojangDownloadInfo::Ptr artifact) : artifact(artifact){}; - MojangLibraryDownloadInfo(){}; + MojangLibraryDownloadInfo(MojangDownloadInfo::Ptr artifact_) : artifact(artifact_) {} + MojangLibraryDownloadInfo() {} // types typedef std::shared_ptr<MojangLibraryDownloadInfo> Ptr; @@ -47,18 +47,18 @@ struct MojangAssetIndexInfo : public MojangDownloadInfo { // methods MojangAssetIndexInfo() {} - MojangAssetIndexInfo(QString id) + MojangAssetIndexInfo(QString id_) { - this->id = id; + this->id = id_; // HACK: ignore assets from other version files than Minecraft // workaround for stupid assets issue caused by amazon: // https://www.theregister.co.uk/2017/02/28/aws_is_awol_as_s3_goes_haywire/ - if (id == "legacy") { + if (id_ == "legacy") { url = "https://piston-meta.mojang.com/mc/assets/legacy/c0fd82e8ce9fbc93119e40d96d5a4e62cfa3f729/legacy.json"; } // HACK else { - url = "https://s3.amazonaws.com/Minecraft.Download/indexes/" + id + ".json"; + url = "https://s3.amazonaws.com/Minecraft.Download/indexes/" + id_ + ".json"; } known = false; } diff --git a/launcher/minecraft/OneSixVersionFormat.cpp b/launcher/minecraft/OneSixVersionFormat.cpp index e2455325..306c95a6 100644 --- a/launcher/minecraft/OneSixVersionFormat.cpp +++ b/launcher/minecraft/OneSixVersionFormat.cpp @@ -350,7 +350,7 @@ QJsonDocument OneSixVersionFormat::versionFileToJson(const VersionFilePtr& patch } } -LibraryPtr OneSixVersionFormat::plusJarModFromJson(ProblemContainer& problems, +LibraryPtr OneSixVersionFormat::plusJarModFromJson([[maybe_unused]] ProblemContainer& problems, const QJsonObject& libObj, const QString& filename, const QString& originalName) diff --git a/launcher/minecraft/PackProfile.cpp b/launcher/minecraft/PackProfile.cpp index 82fc779e..cf8270cd 100644 --- a/launcher/minecraft/PackProfile.cpp +++ b/launcher/minecraft/PackProfile.cpp @@ -204,10 +204,10 @@ static bool loadPackProfile(PackProfile* parent, } auto orderArray = Json::requireArray(obj.value("components")); for (auto item : orderArray) { - auto obj = Json::requireObject(item, "Component must be an object."); - container.append(componentFromJsonV1(parent, componentJsonPattern, obj)); + auto comp_obj = Json::requireObject(item, "Component must be an object."); + container.append(componentFromJsonV1(parent, componentJsonPattern, comp_obj)); } - } catch (const JSONValidationError& err) { + } catch ([[maybe_unused]] const JSONValidationError& err) { qCritical() << "Couldn't parse" << componentsFile.fileName() << ": bad file format"; container.clear(); return false; @@ -377,7 +377,7 @@ void PackProfile::insertComponent(size_t index, ComponentPtr component) qWarning() << "Attempt to add a component that is already present!"; return; } - beginInsertRows(QModelIndex(), index, index); + beginInsertRows(QModelIndex(), static_cast<int>(index), static_cast<int>(index)); d->components.insert(index, component); d->componentIndex[id] = component; endInsertRows(); @@ -389,7 +389,7 @@ void PackProfile::componentDataChanged() { auto objPtr = qobject_cast<Component*>(sender()); if (!objPtr) { - qWarning() << "PackProfile got dataChenged signal from a non-Component!"; + qWarning() << "PackProfile got dataChanged signal from a non-Component!"; return; } if (objPtr->getID() == "net.minecraft") { @@ -405,7 +405,7 @@ void PackProfile::componentDataChanged() } index++; } - qWarning() << "PackProfile got dataChenged signal from a Component which does not belong to it!"; + qWarning() << "PackProfile got dataChanged signal from a Component which does not belong to it!"; } bool PackProfile::remove(const int index) @@ -483,9 +483,9 @@ ComponentPtr PackProfile::getComponent(const QString& id) return (*iter); } -ComponentPtr PackProfile::getComponent(int index) +ComponentPtr PackProfile::getComponent(size_t index) { - if (index < 0 || index >= d->components.size()) { + if (index >= static_cast<size_t>(d->components.size())) { return nullptr; } return d->components[index]; @@ -547,7 +547,7 @@ QVariant PackProfile::data(const QModelIndex& index, int role) const return QVariant(); } -bool PackProfile::setData(const QModelIndex& index, const QVariant& value, int role) +bool PackProfile::setData(const QModelIndex& index, [[maybe_unused]] const QVariant& value, int role) { if (!index.isValid() || index.row() < 0 || index.row() >= rowCount(index.parent())) { return false; diff --git a/launcher/minecraft/PackProfile.h b/launcher/minecraft/PackProfile.h index a5e5cb1a..ce44fa58 100644 --- a/launcher/minecraft/PackProfile.h +++ b/launcher/minecraft/PackProfile.h @@ -140,7 +140,7 @@ class PackProfile : public QAbstractListModel { ComponentPtr getComponent(const QString& id); /// get the profile component by index - ComponentPtr getComponent(int index); + ComponentPtr getComponent(size_t index); /// Add the component to the internal list of patches // todo(merged): is this the best approach diff --git a/launcher/minecraft/ProfileUtils.cpp b/launcher/minecraft/ProfileUtils.cpp index 18a4b7d0..d56ed14b 100644 --- a/launcher/minecraft/ProfileUtils.cpp +++ b/launcher/minecraft/ProfileUtils.cpp @@ -82,7 +82,7 @@ bool readOverrideOrders(QString path, PatchOrder& order) for (auto item : orderArray) { order.append(Json::requireString(item)); } - } catch (const JSONValidationError& err) { + } catch ([[maybe_unused]] const JSONValidationError& err) { qCritical() << "Couldn't parse" << orderFile.fileName() << ": bad file format"; qWarning() << "Ignoring overriden order"; order.clear(); diff --git a/launcher/minecraft/Rule.h b/launcher/minecraft/Rule.h index 483cd936..c6cdbc43 100644 --- a/launcher/minecraft/Rule.h +++ b/launcher/minecraft/Rule.h @@ -55,7 +55,7 @@ class Rule { public: Rule(RuleAction result) : m_result(result) {} - virtual ~Rule(){}; + virtual ~Rule() {} virtual QJsonObject toJson() = 0; RuleAction apply(const Library* parent, const RuntimeContext& runtimeContext) { diff --git a/launcher/minecraft/World.cpp b/launcher/minecraft/World.cpp index 62e0279a..1a680ac5 100644 --- a/launcher/minecraft/World.cpp +++ b/launcher/minecraft/World.cpp @@ -368,11 +368,11 @@ optional<QString> read_string(nbt::value& parent, const char* name) } auto& tag_str = namedValue.as<nbt::tag_string>(); return QString::fromStdString(tag_str.get()); - } catch (const std::out_of_range& e) { + } catch ([[maybe_unused]] const std::out_of_range& e) { // fallback for old world formats qWarning() << "String NBT tag" << name << "could not be found."; return nullopt; - } catch (const std::bad_cast& e) { + } catch ([[maybe_unused]] const std::bad_cast& e) { // type mismatch qWarning() << "NBT tag" << name << "could not be converted to string."; return nullopt; @@ -388,11 +388,11 @@ optional<int64_t> read_long(nbt::value& parent, const char* name) } auto& tag_str = namedValue.as<nbt::tag_long>(); return tag_str.get(); - } catch (const std::out_of_range& e) { + } catch ([[maybe_unused]] const std::out_of_range& e) { // fallback for old world formats qWarning() << "Long NBT tag" << name << "could not be found."; return nullopt; - } catch (const std::bad_cast& e) { + } catch ([[maybe_unused]] const std::bad_cast& e) { // type mismatch qWarning() << "NBT tag" << name << "could not be converted to long."; return nullopt; @@ -408,11 +408,11 @@ optional<int> read_int(nbt::value& parent, const char* name) } auto& tag_str = namedValue.as<nbt::tag_int>(); return tag_str.get(); - } catch (const std::out_of_range& e) { + } catch ([[maybe_unused]] const std::out_of_range& e) { // fallback for old world formats qWarning() << "Int NBT tag" << name << "could not be found."; return nullopt; - } catch (const std::bad_cast& e) { + } catch ([[maybe_unused]] const std::bad_cast& e) { // type mismatch qWarning() << "NBT tag" << name << "could not be converted to int."; return nullopt; diff --git a/launcher/minecraft/WorldList.cpp b/launcher/minecraft/WorldList.cpp index a7348e57..812b13c7 100644 --- a/launcher/minecraft/WorldList.cpp +++ b/launcher/minecraft/WorldList.cpp @@ -255,7 +255,7 @@ QVariant WorldList::data(const QModelIndex& index, int role) const } } -QVariant WorldList::headerData(int section, Qt::Orientation orientation, int role) const +QVariant WorldList::headerData(int section, [[maybe_unused]] Qt::Orientation orientation, int role) const { switch (role) { case Qt::DisplayRole: @@ -294,7 +294,6 @@ QVariant WorldList::headerData(int section, Qt::Orientation orientation, int rol default: return QVariant(); } - return QVariant(); } QStringList WorldList::mimeTypes() const @@ -339,19 +338,19 @@ QMimeData* WorldList::mimeData(const QModelIndexList& indexes) const if (indexes.size() == 0) return new QMimeData(); - QList<World> worlds; + QList<World> worlds_; for (auto idx : indexes) { if (idx.column() != 0) continue; int row = idx.row(); if (row < 0 || row >= this->worlds.size()) continue; - worlds.append(this->worlds[row]); + worlds_.append(this->worlds[row]); } - if (!worlds.size()) { + if (!worlds_.size()) { return new QMimeData(); } - return new WorldMimeData(worlds); + return new WorldMimeData(worlds_); } Qt::ItemFlags WorldList::flags(const QModelIndex& index) const diff --git a/launcher/minecraft/auth/AccountData.cpp b/launcher/minecraft/auth/AccountData.cpp index b56f49cb..474bf7c6 100644 --- a/launcher/minecraft/auth/AccountData.cpp +++ b/launcher/minecraft/auth/AccountData.cpp @@ -311,7 +311,7 @@ bool AccountData::resumeStateFromV2(QJsonObject data) QJsonObject profileObject = profileVal.toObject(); QString id = profileObject.value("id").toString(""); QString name = profileObject.value("name").toString(""); - bool legacy = profileObject.value("legacy").toBool(false); + bool legacy_ = profileObject.value("legacy").toBool(false); if (id.isEmpty() || name.isEmpty()) { qWarning() << "Unable to load a profile" << name << "because it was missing an ID or a name."; continue; @@ -319,7 +319,7 @@ bool AccountData::resumeStateFromV2(QJsonObject data) if (id == currentProfile) { currentProfileIndex = index; } - profiles.append({ id, name, legacy }); + profiles.append({ id, name, legacy_ }); } auto& profile = profiles[currentProfileIndex]; diff --git a/launcher/minecraft/auth/AccountList.cpp b/launcher/minecraft/auth/AccountList.cpp index 317af714..c534ea3b 100644 --- a/launcher/minecraft/auth/AccountList.cpp +++ b/launcher/minecraft/auth/AccountList.cpp @@ -353,7 +353,7 @@ QVariant AccountList::data(const QModelIndex& index, int role) const } } -QVariant AccountList::headerData(int section, Qt::Orientation orientation, int role) const +QVariant AccountList::headerData(int section, [[maybe_unused]] Qt::Orientation orientation, int role) const { switch (role) { case Qt::DisplayRole: diff --git a/launcher/minecraft/auth/Parsers.cpp b/launcher/minecraft/auth/Parsers.cpp index 8dbe446a..f6179a93 100644 --- a/launcher/minecraft/auth/Parsers.cpp +++ b/launcher/minecraft/auth/Parsers.cpp @@ -113,16 +113,16 @@ bool parseXTokenResponse(QByteArray& data, Katabasis::Token& output, QString nam if (!item.isObject()) { continue; } - auto obj = item.toObject(); - if (obj.contains("uhs")) { + auto obj_ = item.toObject(); + if (obj_.contains("uhs")) { foundUHS = true; } else { continue; } // consume all 'display claims' ... whatever that means - for (auto iter = obj.begin(); iter != obj.end(); iter++) { + for (auto iter = obj_.begin(); iter != obj_.end(); iter++) { QString claim; - if (!getString(obj.value(iter.key()), claim)) { + if (!getString(obj_.value(iter.key()), claim)) { qWarning() << "display claim " << iter.key() << " is not a string..."; return false; } diff --git a/launcher/minecraft/auth/steps/EntitlementsStep.cpp b/launcher/minecraft/auth/steps/EntitlementsStep.cpp index e942db52..0573dcb6 100644 --- a/launcher/minecraft/auth/steps/EntitlementsStep.cpp +++ b/launcher/minecraft/auth/steps/EntitlementsStep.cpp @@ -36,7 +36,9 @@ void EntitlementsStep::rehydrate() // NOOP, for now. We only save bools and there's nothing to check. } -void EntitlementsStep::onRequestDone(QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers) +void EntitlementsStep::onRequestDone([[maybe_unused]] QNetworkReply::NetworkError error, + QByteArray data, + [[maybe_unused]] QList<QNetworkReply::RawHeaderPair> headers) { auto requestor = qobject_cast<AuthRequest*>(QObject::sender()); requestor->deleteLater(); diff --git a/launcher/minecraft/gameoptions/GameOptions.cpp b/launcher/minecraft/gameoptions/GameOptions.cpp index 443525ae..4f4fb99a 100644 --- a/launcher/minecraft/gameoptions/GameOptions.cpp +++ b/launcher/minecraft/gameoptions/GameOptions.cpp @@ -97,12 +97,11 @@ QVariant GameOptions::data(const QModelIndex& index, int role) const default: return QVariant(); } - return QVariant(); } int GameOptions::rowCount(const QModelIndex&) const { - return contents.size(); + return static_cast<int>(contents.size()); } int GameOptions::columnCount(const QModelIndex&) const diff --git a/launcher/minecraft/launch/LauncherPartLaunch.cpp b/launcher/minecraft/launch/LauncherPartLaunch.cpp index 05562ef2..44e5d0a6 100644 --- a/launcher/minecraft/launch/LauncherPartLaunch.cpp +++ b/launcher/minecraft/launch/LauncherPartLaunch.cpp @@ -53,7 +53,7 @@ LauncherPartLaunch::LauncherPartLaunch(LaunchTask* parent) : LaunchStep(parent) auto instance = parent->instance(); if (instance->settings()->get("CloseAfterLaunch").toBool()) { std::shared_ptr<QMetaObject::Connection> connection{ new QMetaObject::Connection }; - *connection = connect(&m_process, &LoggedProcess::log, this, [=](QStringList lines, MessageLevel::Enum level) { + *connection = connect(&m_process, &LoggedProcess::log, this, [=](QStringList lines, [[maybe_unused]] MessageLevel::Enum level) { qDebug() << lines; if (lines.filter(QRegularExpression(".*Setting user.+", QRegularExpression::CaseInsensitiveOption)).length() != 0) { APPLICATION->closeAllWindows(); diff --git a/launcher/minecraft/mod/Mod.h b/launcher/minecraft/mod/Mod.h index ca3ee11f..6dafecfc 100644 --- a/launcher/minecraft/mod/Mod.h +++ b/launcher/minecraft/mod/Mod.h @@ -72,7 +72,7 @@ class Mod : public Resource { auto metaurl() const -> QString; /** Get the intneral path to the mod's icon file*/ - QString iconPath() const { return m_local_details.icon_file; }; + QString iconPath() const { return m_local_details.icon_file; } /** Gets the icon of the mod, converted to a QPixmap for drawing, and scaled to size. */ [[nodiscard]] QPixmap icon(QSize size, Qt::AspectRatioMode mode = Qt::AspectRatioMode::IgnoreAspectRatio) const; /** Thread-safe. */ diff --git a/launcher/minecraft/mod/ModDetails.h b/launcher/minecraft/mod/ModDetails.h index 6a15219a..a00d5a24 100644 --- a/launcher/minecraft/mod/ModDetails.h +++ b/launcher/minecraft/mod/ModDetails.h @@ -60,17 +60,17 @@ struct ModLicense { ModLicense(const QString license) { - // FIXME: come up with a better license parseing. + // FIXME: come up with a better license parsing. // handle SPDX identifiers? https://spdx.org/licenses/ auto parts = license.split(' '); QStringList notNameParts = {}; for (auto part : parts) { - auto url = QUrl(part); + auto _url = QUrl(part); if (part.startsWith("(") && part.endsWith(")")) - url = QUrl(part.mid(1, part.size() - 2)); + _url = QUrl(part.mid(1, part.size() - 2)); - if (url.isValid() && !url.scheme().isEmpty() && !url.host().isEmpty()) { - this->url = url.toString(); + if (_url.isValid() && !_url.scheme().isEmpty() && !_url.host().isEmpty()) { + this->url = _url.toString(); notNameParts.append(part); continue; } @@ -89,13 +89,9 @@ struct ModLicense { } } - ModLicense(const QString name, const QString id, const QString url, const QString description) - { - this->name = name; - this->id = id; - this->url = url; - this->description = description; - } + ModLicense(const QString& name_, const QString& id_, const QString& url_, const QString& description_) + : name(name_), id(id_), url(url_), description(description_) + {} ModLicense(const ModLicense& other) : name(other.name), id(other.id), url(other.url), description(other.description) {} diff --git a/launcher/minecraft/mod/ModFolderModel.cpp b/launcher/minecraft/mod/ModFolderModel.cpp index 8dbe583d..280e70d7 100644 --- a/launcher/minecraft/mod/ModFolderModel.cpp +++ b/launcher/minecraft/mod/ModFolderModel.cpp @@ -62,6 +62,7 @@ ModFolderModel::ModFolderModel(const QString& dir, BaseInstance* instance, bool m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::NAME, SortType::VERSION, SortType::DATE, SortType::PROVIDER }; m_column_resize_modes = { QHeaderView::ResizeToContents, QHeaderView::Interactive, QHeaderView::Stretch, QHeaderView::ResizeToContents, QHeaderView::ResizeToContents, QHeaderView::ResizeToContents }; + m_columnsHideable = { false, true, false, true, true, true }; } QVariant ModFolderModel::data(const QModelIndex& index, int role) const @@ -137,7 +138,7 @@ QVariant ModFolderModel::data(const QModelIndex& index, int role) const } } -QVariant ModFolderModel::headerData(int section, Qt::Orientation orientation, int role) const +QVariant ModFolderModel::headerData(int section, [[maybe_unused]] Qt::Orientation orientation, int role) const { switch (role) { case Qt::DisplayRole: diff --git a/launcher/minecraft/mod/ResourceFolderModel.cpp b/launcher/minecraft/mod/ResourceFolderModel.cpp index 0106d5c9..d3237b34 100644 --- a/launcher/minecraft/mod/ResourceFolderModel.cpp +++ b/launcher/minecraft/mod/ResourceFolderModel.cpp @@ -447,7 +447,7 @@ QVariant ResourceFolderModel::data(const QModelIndex& index, int role) const } } -bool ResourceFolderModel::setData(const QModelIndex& index, const QVariant& value, int role) +bool ResourceFolderModel::setData(const QModelIndex& index, [[maybe_unused]] const QVariant& value, int role) { int row = index.row(); if (row < 0 || row >= rowCount(index.parent()) || !index.isValid()) @@ -471,7 +471,7 @@ bool ResourceFolderModel::setData(const QModelIndex& index, const QVariant& valu return false; } -QVariant ResourceFolderModel::headerData(int section, Qt::Orientation orientation, int role) const +QVariant ResourceFolderModel::headerData(int section, [[maybe_unused]] Qt::Orientation orientation, int role) const { switch (role) { case Qt::DisplayRole: @@ -551,6 +551,9 @@ QMenu* ResourceFolderModel::createHeaderContextMenu(QTreeView* tree) menu->addSeparator()->setText(tr("Show / Hide Columns")); for (int col = 0; col < columnCount(); ++col) { + // Skip creating actions for columns that should not be hidden + if (!m_columnsHideable.at(col)) + continue; auto act = new QAction(menu); setupHeaderAction(act, col); @@ -584,7 +587,8 @@ SortType ResourceFolderModel::columnToSortKey(size_t column) const } /* Standard Proxy Model for createFilterProxyModel */ -[[nodiscard]] bool ResourceFolderModel::ProxyModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const +[[nodiscard]] bool ResourceFolderModel::ProxyModel::filterAcceptsRow(int source_row, + [[maybe_unused]] const QModelIndex& source_parent) const { auto* model = qobject_cast<ResourceFolderModel*>(sourceModel()); if (!model) diff --git a/launcher/minecraft/mod/ResourceFolderModel.h b/launcher/minecraft/mod/ResourceFolderModel.h index 595b9762..80c31e45 100644 --- a/launcher/minecraft/mod/ResourceFolderModel.h +++ b/launcher/minecraft/mod/ResourceFolderModel.h @@ -49,8 +49,8 @@ class ResourceFolderModel : public QAbstractListModel { bool stopWatching(const QStringList paths); /* Helper methods for subclasses, using a predetermined list of paths. */ - virtual bool startWatching() { return startWatching({ m_dir.absolutePath() }); }; - virtual bool stopWatching() { return stopWatching({ m_dir.absolutePath() }); }; + virtual bool startWatching() { return startWatching({ m_dir.absolutePath() }); } + virtual bool stopWatching() { return stopWatching({ m_dir.absolutePath() }); } /** Given a path in the system, install that resource, moving it to its place in the * instance file hierarchy. @@ -78,7 +78,7 @@ class ResourceFolderModel : public QAbstractListModel { /** Creates a new parse task, if needed, for 'res' and start it.*/ virtual void resolveResource(Resource* res); - [[nodiscard]] size_t size() const { return m_resources.size(); }; + [[nodiscard]] qsizetype size() const { return m_resources.size(); } [[nodiscard]] bool empty() const { return size() == 0; } [[nodiscard]] Resource& at(int index) { return *m_resources.at(index); } [[nodiscard]] Resource const& at(int index) const { return *m_resources.at(index); } @@ -97,10 +97,10 @@ class ResourceFolderModel : public QAbstractListModel { /* Basic columns */ enum Columns { ACTIVE_COLUMN = 0, NAME_COLUMN, DATE_COLUMN, NUM_COLUMNS }; - QStringList columnNames(bool translated = true) const { return translated ? m_column_names_translated : m_column_names; }; + QStringList columnNames(bool translated = true) const { return translated ? m_column_names_translated : m_column_names; } [[nodiscard]] int rowCount(const QModelIndex& parent = {}) const override { return parent.isValid() ? 0 : static_cast<int>(size()); } - [[nodiscard]] int columnCount(const QModelIndex& parent = {}) const override { return parent.isValid() ? 0 : NUM_COLUMNS; }; + [[nodiscard]] int columnCount(const QModelIndex& parent = {}) const override { return parent.isValid() ? 0 : NUM_COLUMNS; } [[nodiscard]] Qt::DropActions supportedDropActions() const override; @@ -159,7 +159,7 @@ class ResourceFolderModel : public QAbstractListModel { * This task should load and parse all heavy info needed by a resource, such as parsing a manifest. It gets executed * in the background, so it slowly updates the UI as tasks get done. */ - [[nodiscard]] virtual Task* createParseTask(Resource&) { return nullptr; }; + [[nodiscard]] virtual Task* createParseTask(Resource&) { return nullptr; } /** Standard implementation of the model update logic. * @@ -203,6 +203,7 @@ class ResourceFolderModel : public QAbstractListModel { QStringList m_column_names_translated = { tr("Enable"), tr("Name"), tr("Last Modified") }; QList<QHeaderView::ResizeMode> m_column_resize_modes = { QHeaderView::ResizeToContents, QHeaderView::Stretch, QHeaderView::ResizeToContents }; + QList<bool> m_columnsHideable = { false, false, true }; QDir m_dir; BaseInstance* m_instance; @@ -224,15 +225,15 @@ class ResourceFolderModel : public QAbstractListModel { /* A macro to define useful functions to handle Resource* -> T* more easily on derived classes */ #define RESOURCE_HELPERS(T) \ - [[nodiscard]] T* operator[](size_t index) \ + [[nodiscard]] T* operator[](int index) \ { \ return static_cast<T*>(m_resources[index].get()); \ } \ - [[nodiscard]] T* at(size_t index) \ + [[nodiscard]] T* at(int index) \ { \ return static_cast<T*>(m_resources[index].get()); \ } \ - [[nodiscard]] const T* at(size_t index) const \ + [[nodiscard]] const T* at(int index) const \ { \ return static_cast<const T*>(m_resources.at(index).get()); \ } \ diff --git a/launcher/minecraft/mod/ResourcePackFolderModel.cpp b/launcher/minecraft/mod/ResourcePackFolderModel.cpp index 70206cb0..f2743157 100644 --- a/launcher/minecraft/mod/ResourcePackFolderModel.cpp +++ b/launcher/minecraft/mod/ResourcePackFolderModel.cpp @@ -54,6 +54,7 @@ ResourcePackFolderModel::ResourcePackFolderModel(const QString& dir, BaseInstanc m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::NAME, SortType::PACK_FORMAT, SortType::DATE }; m_column_resize_modes = { QHeaderView::ResizeToContents, QHeaderView::Interactive, QHeaderView::Stretch, QHeaderView::ResizeToContents, QHeaderView::ResizeToContents }; + m_columnsHideable = { false, true, false, true, true }; } QVariant ResourcePackFolderModel::data(const QModelIndex& index, int role) const @@ -128,7 +129,7 @@ QVariant ResourcePackFolderModel::data(const QModelIndex& index, int role) const } } -QVariant ResourcePackFolderModel::headerData(int section, Qt::Orientation orientation, int role) const +QVariant ResourcePackFolderModel::headerData(int section, [[maybe_unused]] Qt::Orientation orientation, int role) const { switch (role) { case Qt::DisplayRole: @@ -165,7 +166,6 @@ QVariant ResourcePackFolderModel::headerData(int section, Qt::Orientation orient default: return {}; } - return {}; } int ResourcePackFolderModel::columnCount(const QModelIndex& parent) const diff --git a/launcher/minecraft/mod/TexturePackFolderModel.cpp b/launcher/minecraft/mod/TexturePackFolderModel.cpp index 9a9910fa..5c5f2b7c 100644 --- a/launcher/minecraft/mod/TexturePackFolderModel.cpp +++ b/launcher/minecraft/mod/TexturePackFolderModel.cpp @@ -49,6 +49,7 @@ TexturePackFolderModel::TexturePackFolderModel(const QString& dir, BaseInstance* m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::NAME, SortType::DATE }; m_column_resize_modes = { QHeaderView::ResizeToContents, QHeaderView::Interactive, QHeaderView::Stretch, QHeaderView::ResizeToContents }; + m_columnsHideable = { false, true, false, true }; } Task* TexturePackFolderModel::createUpdateTask() @@ -113,7 +114,7 @@ QVariant TexturePackFolderModel::data(const QModelIndex& index, int role) const } } -QVariant TexturePackFolderModel::headerData(int section, Qt::Orientation orientation, int role) const +QVariant TexturePackFolderModel::headerData(int section, [[maybe_unused]] Qt::Orientation orientation, int role) const { switch (role) { case Qt::DisplayRole: diff --git a/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp b/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp index f8ecdb33..0a0f57bf 100644 --- a/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp +++ b/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp @@ -61,7 +61,7 @@ GetModDependenciesTask::GetModDependenciesTask(QObject* parent, if (auto meta = mod->metadata(); meta) m_mods.append(meta); prepare(); -}; +} void GetModDependenciesTask::prepare() { @@ -130,7 +130,7 @@ QList<ModPlatform::Dependency> GetModDependenciesTask::getDependenciesForVersion c_dependencies.append(getOverride(ver_dep, providerName)); } return c_dependencies; -}; +} Task::Ptr GetModDependenciesTask::getProjectInfoTask(std::shared_ptr<PackDependency> pDep) { @@ -181,7 +181,7 @@ Task::Ptr GetModDependenciesTask::prepareDependencyTask(const ModPlatform::Depen ResourceAPI::DependencySearchArgs args = { dep, m_version, m_loaderType }; ResourceAPI::DependencySearchCallbacks callbacks; - callbacks.on_succeed = [dep, provider, pDep, level, this](auto& doc, auto& pack) { + callbacks.on_succeed = [dep, provider, pDep, level, this](auto& doc, [[maybe_unused]] auto& pack) { try { QJsonArray arr; if (dep.version.length() != 0 && doc.isObject()) { @@ -215,27 +215,27 @@ Task::Ptr GetModDependenciesTask::prepareDependencyTask(const ModPlatform::Depen return; } if (level == 0) { - qWarning() << "Dependency cycle exeeded"; + qWarning() << "Dependency cycle exceeded"; return; } if (dep.addonId.toString().isEmpty() && !pDep->version.addonId.toString().isEmpty()) { pDep->pack->addonId = pDep->version.addonId; - auto dep = getOverride({ pDep->version.addonId, pDep->dependency.type }, provider.name); - if (dep.addonId != pDep->version.addonId) { + auto dep_ = getOverride({ pDep->version.addonId, pDep->dependency.type }, provider.name); + if (dep_.addonId != pDep->version.addonId) { removePack(pDep->version.addonId); - addTask(prepareDependencyTask(dep, provider.name, level)); + addTask(prepareDependencyTask(dep_, provider.name, level)); } else addTask(getProjectInfoTask(pDep)); } - for (auto dep : getDependenciesForVersion(pDep->version, provider.name)) { - addTask(prepareDependencyTask(dep, provider.name, level - 1)); + for (auto dep_ : getDependenciesForVersion(pDep->version, provider.name)) { + addTask(prepareDependencyTask(dep_, provider.name, level - 1)); } }; auto version = provider.api->getDependencyVersion(std::move(args), std::move(callbacks)); tasks->addTask(version); return tasks; -}; +} void GetModDependenciesTask::removePack(const QVariant addonId) { diff --git a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp index 75bb6d25..7ec00c0c 100644 --- a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp @@ -104,14 +104,15 @@ ModDetails ReadMCModTOML(QByteArray contents) #if TOML_EXCEPTIONS try { tomlData = toml::parse(contents.toStdString()); - } catch (const toml::parse_error& err) { + } catch ([[maybe_unused]] const toml::parse_error& err) { return {}; } #else - tomlData = toml::parse(contents.toStdString()); - if (!tomlData) { + toml::parse_result result = toml::parse(contents.toStdString()); + if (!result) { return {}; } + tomlData = result.table(); #endif // array defined by [[mods]] @@ -151,8 +152,8 @@ ModDetails ReadMCModTOML(QByteArray contents) QString authors = ""; if (auto authorsDatum = tomlData["authors"].as_string()) { authors = QString::fromStdString(authorsDatum->get()); - } else if (auto authorsDatum = (*modsTable)["authors"].as_string()) { - authors = QString::fromStdString(authorsDatum->get()); + } else if (auto authorsDatumMods = (*modsTable)["authors"].as_string()) { + authors = QString::fromStdString(authorsDatumMods->get()); } if (!authors.isEmpty()) { details.authors.append(authors); @@ -161,8 +162,8 @@ ModDetails ReadMCModTOML(QByteArray contents) QString homeurl = ""; if (auto homeurlDatum = tomlData["displayURL"].as_string()) { homeurl = QString::fromStdString(homeurlDatum->get()); - } else if (auto homeurlDatum = (*modsTable)["displayURL"].as_string()) { - homeurl = QString::fromStdString(homeurlDatum->get()); + } else if (auto homeurlDatumMods = (*modsTable)["displayURL"].as_string()) { + homeurl = QString::fromStdString(homeurlDatumMods->get()); } // fix up url. if (!homeurl.isEmpty() && !homeurl.startsWith("http://") && !homeurl.startsWith("https://") && !homeurl.startsWith("ftp://")) { @@ -173,16 +174,16 @@ ModDetails ReadMCModTOML(QByteArray contents) QString issueTrackerURL = ""; if (auto issueTrackerURLDatum = tomlData["issueTrackerURL"].as_string()) { issueTrackerURL = QString::fromStdString(issueTrackerURLDatum->get()); - } else if (auto issueTrackerURLDatum = (*modsTable)["issueTrackerURL"].as_string()) { - issueTrackerURL = QString::fromStdString(issueTrackerURLDatum->get()); + } else if (auto issueTrackerURLDatumMods = (*modsTable)["issueTrackerURL"].as_string()) { + issueTrackerURL = QString::fromStdString(issueTrackerURLDatumMods->get()); } details.issue_tracker = issueTrackerURL; QString license = ""; if (auto licenseDatum = tomlData["license"].as_string()) { license = QString::fromStdString(licenseDatum->get()); - } else if (auto licenseDatum = (*modsTable)["license"].as_string()) { - license = QString::fromStdString(licenseDatum->get()); + } else if (auto licenseDatumMods = (*modsTable)["license"].as_string()) { + license = QString::fromStdString(licenseDatumMods->get()); } if (!license.isEmpty()) details.licenses.append(ModLicense(license)); @@ -190,8 +191,8 @@ ModDetails ReadMCModTOML(QByteArray contents) QString logoFile = ""; if (auto logoFileDatum = tomlData["logoFile"].as_string()) { logoFile = QString::fromStdString(logoFileDatum->get()); - } else if (auto logoFileDatum = (*modsTable)["logoFile"].as_string()) { - logoFile = QString::fromStdString(logoFileDatum->get()); + } else if (auto logoFileDatumMods = (*modsTable)["logoFile"].as_string()) { + logoFile = QString::fromStdString(logoFileDatumMods->get()); } details.icon_file = logoFile; @@ -458,7 +459,7 @@ bool process(Mod& mod, ProcessingLevel level) } } -bool processZIP(Mod& mod, ProcessingLevel level) +bool processZIP(Mod& mod, [[maybe_unused]] ProcessingLevel level) { ModDetails details; @@ -591,7 +592,7 @@ bool processZIP(Mod& mod, ProcessingLevel level) return false; // no valid mod found in archive } -bool processFolder(Mod& mod, ProcessingLevel level) +bool processFolder(Mod& mod, [[maybe_unused]] ProcessingLevel level) { ModDetails details; @@ -612,7 +613,7 @@ bool processFolder(Mod& mod, ProcessingLevel level) return false; // no valid mcmod.info file found } -bool processLitemod(Mod& mod, ProcessingLevel level) +bool processLitemod(Mod& mod, [[maybe_unused]] ProcessingLevel level) { ModDetails details; diff --git a/launcher/minecraft/services/CapeChange.cpp b/launcher/minecraft/services/CapeChange.cpp index f87da13e..2ba38a6a 100644 --- a/launcher/minecraft/services/CapeChange.cpp +++ b/launcher/minecraft/services/CapeChange.cpp @@ -42,7 +42,7 @@ CapeChange::CapeChange(QObject* parent, QString token, QString cape) : Task(parent), m_capeId(cape), m_token(token) {} -void CapeChange::setCape(QString& cape) +void CapeChange::setCape([[maybe_unused]] QString& cape) { QNetworkRequest request(QUrl("https://api.minecraftservices.com/minecraft/profile/capes/active")); auto requestString = QString("{\"capeId\":\"%1\"}").arg(m_capeId); diff --git a/launcher/minecraft/update/AssetUpdateTask.cpp b/launcher/minecraft/update/AssetUpdateTask.cpp index 7043d987..8af01499 100644 --- a/launcher/minecraft/update/AssetUpdateTask.cpp +++ b/launcher/minecraft/update/AssetUpdateTask.cpp @@ -7,6 +7,8 @@ #include "Application.h" +#include "net/ApiDownload.h" + AssetUpdateTask::AssetUpdateTask(MinecraftInstance* inst) { m_inst = inst; @@ -29,7 +31,7 @@ void AssetUpdateTask::executeTask() entry->setStale(true); auto hexSha1 = assets->sha1.toLatin1(); qDebug() << "Asset index SHA1:" << hexSha1; - auto dl = Net::Download::makeCached(indexUrl, entry); + auto dl = Net::ApiDownload::makeCached(indexUrl, entry); auto rawSha1 = QByteArray::fromHex(assets->sha1.toLatin1()); dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawSha1)); job->addNetAction(dl); diff --git a/launcher/minecraft/update/FMLLibrariesTask.cpp b/launcher/minecraft/update/FMLLibrariesTask.cpp index a6ca2102..ce0c9a72 100644 --- a/launcher/minecraft/update/FMLLibrariesTask.cpp +++ b/launcher/minecraft/update/FMLLibrariesTask.cpp @@ -8,6 +8,8 @@ #include "Application.h" #include "BuildConfig.h" +#include "net/ApiDownload.h" + FMLLibrariesTask::FMLLibrariesTask(MinecraftInstance* inst) { m_inst = inst; @@ -62,7 +64,7 @@ void FMLLibrariesTask::executeTask() for (auto& lib : fmlLibsToProcess) { auto entry = metacache->resolveEntry("fmllibs", lib.filename); QString urlString = BuildConfig.FMLLIBS_BASE_URL + lib.filename; - dljob->addNetAction(Net::Download::makeCached(QUrl(urlString), entry, options)); + dljob->addNetAction(Net::ApiDownload::makeCached(QUrl(urlString), entry, options)); } connect(dljob.get(), &NetJob::succeeded, this, &FMLLibrariesTask::fmllibsFinished); diff --git a/launcher/modplatform/ModIndex.h b/launcher/modplatform/ModIndex.h index 2aa91602..cad21703 100644 --- a/launcher/modplatform/ModIndex.h +++ b/launcher/modplatform/ModIndex.h @@ -113,7 +113,7 @@ struct IndexedPack { ExtraPackData extraData; // For internal use, not provided by APIs - [[nodiscard]] bool isVersionSelected(size_t index) const + [[nodiscard]] bool isVersionSelected(int index) const { if (!versionsLoaded) return false; @@ -144,7 +144,8 @@ inline auto getOverrideDeps() -> QList<OverrideDep> { "qvIfYCYJ", "P7dR8mSH", "API", ModPlatform::ResourceProvider::MODRINTH }, { "lwVhp9o5", "Ha28R6CL", "KotlinLibraries", ModPlatform::ResourceProvider::MODRINTH } }; -}; +} + QString getMetaURL(ResourceProvider provider, QVariant projectID); } // namespace ModPlatform diff --git a/launcher/modplatform/ResourceAPI.h b/launcher/modplatform/ResourceAPI.h index ef220977..a92217a0 100644 --- a/launcher/modplatform/ResourceAPI.h +++ b/launcher/modplatform/ResourceAPI.h @@ -128,28 +128,30 @@ class ResourceAPI { public slots: [[nodiscard]] virtual Task::Ptr searchProjects(SearchArgs&&, SearchCallbacks&&) const { - qWarning() << "TODO"; + qWarning() << "TODO: ResourceAPI::searchProjects"; return nullptr; } - [[nodiscard]] virtual Task::Ptr getProject(QString addonId, std::shared_ptr<QByteArray> response) const + [[nodiscard]] virtual Task::Ptr getProject([[maybe_unused]] QString addonId, + [[maybe_unused]] std::shared_ptr<QByteArray> response) const { - qWarning() << "TODO"; + qWarning() << "TODO: ResourceAPI::getProject"; return nullptr; } - [[nodiscard]] virtual Task::Ptr getProjects(QStringList addonIds, std::shared_ptr<QByteArray> response) const + [[nodiscard]] virtual Task::Ptr getProjects([[maybe_unused]] QStringList addonIds, + [[maybe_unused]] std::shared_ptr<QByteArray> response) const { - qWarning() << "TODO"; + qWarning() << "TODO: ResourceAPI::getProjects"; return nullptr; } [[nodiscard]] virtual Task::Ptr getProjectInfo(ProjectInfoArgs&&, ProjectInfoCallbacks&&) const { - qWarning() << "TODO"; + qWarning() << "TODO: ResourceAPI::getProjectInfo"; return nullptr; } [[nodiscard]] virtual Task::Ptr getProjectVersions(VersionSearchArgs&&, VersionSearchCallbacks&&) const { - qWarning() << "TODO"; + qWarning() << "TODO: ResourceAPI::getProjectVersions"; return nullptr; } diff --git a/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp b/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp index f0198481..5d1a361d 100644 --- a/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp +++ b/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp @@ -53,6 +53,8 @@ #include "net/ChecksumValidator.h" #include "settings/INISettingsObject.h" +#include "net/ApiDownload.h" + #include "Application.h" #include "BuildConfig.h" @@ -83,7 +85,7 @@ void PackInstallTask::executeTask() NetJob::Ptr netJob{ new NetJob("ATLauncher::VersionFetch", APPLICATION->network()) }; auto searchUrl = QString(BuildConfig.ATL_DOWNLOAD_SERVER_URL + "packs/%1/versions/%2/Configs.json").arg(m_pack_safe_name).arg(m_version_name); - netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), response)); + netJob->addNetAction(Net::ApiDownload::makeByteArray(QUrl(searchUrl), response)); QObject::connect(netJob.get(), &NetJob::succeeded, this, &PackInstallTask::onDownloadSucceeded); QObject::connect(netJob.get(), &NetJob::failed, this, &PackInstallTask::onDownloadFailed); @@ -631,7 +633,7 @@ void PackInstallTask::installConfigs() auto entry = APPLICATION->metacache()->resolveEntry("ATLauncherPacks", path); entry->setStale(true); - auto dl = Net::Download::makeCached(url, entry); + auto dl = Net::ApiDownload::makeCached(url, entry); if (!m_version.configs.sha1.isEmpty()) { auto rawSha1 = QByteArray::fromHex(m_version.configs.sha1.toLatin1()); dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawSha1)); @@ -748,7 +750,7 @@ void PackInstallTask::downloadMods() entry->setStale(true); modsToExtract.insert(entry->getFullPath(), mod); - auto dl = Net::Download::makeCached(url, entry); + auto dl = Net::ApiDownload::makeCached(url, entry); if (!mod.md5.isEmpty()) { auto rawMd5 = QByteArray::fromHex(mod.md5.toLatin1()); dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Md5, rawMd5)); @@ -759,7 +761,7 @@ void PackInstallTask::downloadMods() entry->setStale(true); modsToDecomp.insert(entry->getFullPath(), mod); - auto dl = Net::Download::makeCached(url, entry); + auto dl = Net::ApiDownload::makeCached(url, entry); if (!mod.md5.isEmpty()) { auto rawMd5 = QByteArray::fromHex(mod.md5.toLatin1()); dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Md5, rawMd5)); @@ -773,7 +775,7 @@ void PackInstallTask::downloadMods() auto entry = APPLICATION->metacache()->resolveEntry("ATLauncherPacks", cacheName); entry->setStale(true); - auto dl = Net::Download::makeCached(url, entry); + auto dl = Net::ApiDownload::makeCached(url, entry); if (!mod.md5.isEmpty()) { auto rawMd5 = QByteArray::fromHex(mod.md5.toLatin1()); dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Md5, rawMd5)); diff --git a/launcher/modplatform/flame/FileResolvingTask.cpp b/launcher/modplatform/flame/FileResolvingTask.cpp index ae168bbd..860d7340 100644 --- a/launcher/modplatform/flame/FileResolvingTask.cpp +++ b/launcher/modplatform/flame/FileResolvingTask.cpp @@ -1,6 +1,8 @@ #include "FileResolvingTask.h" #include "Json.h" +#include "net/ApiDownload.h" +#include "net/ApiUpload.h" #include "net/Upload.h" #include "modplatform/modrinth/ModrinthPackIndex.h" @@ -38,7 +40,7 @@ void Flame::FileResolvingTask::executeTask() return l; })); QByteArray data = Json::toText(object); - auto dl = Net::Upload::makeByteArray(QUrl("https://api.curseforge.com/v1/mods/files"), result, data); + auto dl = Net::ApiUpload::makeByteArray(QUrl("https://api.curseforge.com/v1/mods/files"), result, data); m_dljob->addNetAction(dl); auto step_progress = std::make_shared<TaskStepProgress>(); @@ -93,13 +95,13 @@ void Flame::FileResolvingTask::netJobFinished() auto& out = m_toProcess.files[fileid]; try { out.parseFromObject(Json::requireObject(file)); - } catch (const JSONValidationError& e) { + } catch ([[maybe_unused]] const JSONValidationError& e) { qDebug() << "Blocked mod on curseforge" << out.fileName; auto hash = out.hash; if (!hash.isEmpty()) { auto url = QString("https://api.modrinth.com/v2/version_file/%1?algorithm=sha1").arg(hash); auto output = std::make_shared<QByteArray>(); - auto dl = Net::Download::makeByteArray(QUrl(url), output); + auto dl = Net::ApiDownload::makeByteArray(QUrl(url), output); QObject::connect(dl.get(), &Net::Download::succeeded, [&out]() { out.resolved = true; }); m_checkJob->addNetAction(dl); @@ -171,7 +173,7 @@ void Flame::FileResolvingTask::modrinthCheckFinished() auto projectId = mod->projectId; auto output = std::make_shared<QByteArray>(); auto url = QString("https://api.curseforge.com/v1/mods/%1").arg(projectId); - auto dl = Net::Download::makeByteArray(url, output); + auto dl = Net::ApiDownload::makeByteArray(url, output); qDebug() << "Fetching url slug for file:" << mod->fileName; QObject::connect(dl.get(), &Net::Download::succeeded, [block, index, output]() { auto mod = block->at(index); // use the shared_ptr so it is captured and only freed when we are done diff --git a/launcher/modplatform/flame/FlameAPI.cpp b/launcher/modplatform/flame/FlameAPI.cpp index 5b0b1d8b..73ed1011 100644 --- a/launcher/modplatform/flame/FlameAPI.cpp +++ b/launcher/modplatform/flame/FlameAPI.cpp @@ -8,6 +8,8 @@ #include "Application.h" #include "BuildConfig.h" #include "Json.h" +#include "net/ApiDownload.h" +#include "net/ApiUpload.h" #include "net/NetJob.h" #include "net/Upload.h" @@ -26,7 +28,7 @@ Task::Ptr FlameAPI::matchFingerprints(const QList<uint>& fingerprints, std::shar QJsonDocument body(body_obj); auto body_raw = body.toJson(); - netJob->addNetAction(Net::Upload::makeByteArray(QString("https://api.curseforge.com/v1/fingerprints"), response, body_raw)); + netJob->addNetAction(Net::ApiUpload::makeByteArray(QString("https://api.curseforge.com/v1/fingerprints"), response, body_raw)); return netJob; } @@ -38,7 +40,7 @@ auto FlameAPI::getModFileChangelog(int modId, int fileId) -> QString auto netJob = makeShared<NetJob>(QString("Flame::FileChangelog"), APPLICATION->network()); auto response = std::make_shared<QByteArray>(); - netJob->addNetAction(Net::Download::makeByteArray( + netJob->addNetAction(Net::ApiDownload::makeByteArray( QString("https://api.curseforge.com/v1/mods/%1/files/%2/changelog") .arg(QString::fromStdString(std::to_string(modId)), QString::fromStdString(std::to_string(fileId))), response)); @@ -73,8 +75,8 @@ auto FlameAPI::getModDescription(int modId) -> QString auto netJob = makeShared<NetJob>(QString("Flame::ModDescription"), APPLICATION->network()); auto response = std::make_shared<QByteArray>(); - netJob->addNetAction( - Net::Download::makeByteArray(QString("https://api.curseforge.com/v1/mods/%1/description").arg(QString::number(modId)), response)); + netJob->addNetAction(Net::ApiDownload::makeByteArray( + QString("https://api.curseforge.com/v1/mods/%1/description").arg(QString::number(modId)), response)); QObject::connect(netJob.get(), &NetJob::succeeded, [&netJob, response, &description] { QJsonParseError parse_error{}; @@ -113,7 +115,7 @@ auto FlameAPI::getLatestVersion(VersionSearchArgs&& args) -> ModPlatform::Indexe auto response = std::make_shared<QByteArray>(); ModPlatform::IndexedVersion ver; - netJob->addNetAction(Net::Download::makeByteArray(versions_url, response)); + netJob->addNetAction(Net::ApiDownload::makeByteArray(versions_url, response)); QObject::connect(netJob.get(), &NetJob::succeeded, [response, args, &ver] { QJsonParseError parse_error{}; @@ -173,7 +175,7 @@ Task::Ptr FlameAPI::getProjects(QStringList addonIds, std::shared_ptr<QByteArray QJsonDocument body(body_obj); auto body_raw = body.toJson(); - netJob->addNetAction(Net::Upload::makeByteArray(QString("https://api.curseforge.com/v1/mods"), response, body_raw)); + netJob->addNetAction(Net::ApiUpload::makeByteArray(QString("https://api.curseforge.com/v1/mods"), response, body_raw)); QObject::connect(netJob.get(), &NetJob::failed, [body_raw] { qDebug() << body_raw; }); @@ -195,7 +197,7 @@ Task::Ptr FlameAPI::getFiles(const QStringList& fileIds, std::shared_ptr<QByteAr QJsonDocument body(body_obj); auto body_raw = body.toJson(); - netJob->addNetAction(Net::Upload::makeByteArray(QString("https://api.curseforge.com/v1/mods/files"), response, body_raw)); + netJob->addNetAction(Net::ApiUpload::makeByteArray(QString("https://api.curseforge.com/v1/mods/files"), response, body_raw)); QObject::connect(netJob.get(), &NetJob::failed, [body_raw] { qDebug() << body_raw; }); diff --git a/launcher/modplatform/flame/FlameCheckUpdate.cpp b/launcher/modplatform/flame/FlameCheckUpdate.cpp index a2628e34..e10fedc3 100644 --- a/launcher/modplatform/flame/FlameCheckUpdate.cpp +++ b/launcher/modplatform/flame/FlameCheckUpdate.cpp @@ -13,6 +13,8 @@ #include "minecraft/mod/ModFolderModel.h" #include "minecraft/mod/ResourceFolderModel.h" +#include "net/ApiDownload.h" + static FlameAPI api; bool FlameCheckUpdate::abort() @@ -33,7 +35,7 @@ ModPlatform::IndexedPack getProjectInfo(ModPlatform::IndexedVersion& ver_info) auto response = std::make_shared<QByteArray>(); auto url = QString("https://api.curseforge.com/v1/mods/%1").arg(ver_info.addonId.toString()); - auto dl = Net::Download::makeByteArray(url, response); + auto dl = Net::ApiDownload::makeByteArray(url, response); get_project_job->addNetAction(dl); QObject::connect(get_project_job, &NetJob::succeeded, [response, &pack]() { @@ -77,7 +79,7 @@ ModPlatform::IndexedVersion getFileInfo(int addonId, int fileId) auto response = std::make_shared<QByteArray>(); auto url = QString("https://api.curseforge.com/v1/mods/%1/files/%2").arg(QString::number(addonId), QString::number(fileId)); - auto dl = Net::Download::makeByteArray(url, response); + auto dl = Net::ApiDownload::makeByteArray(url, response); get_file_info_job->addNetAction(dl); QObject::connect(get_file_info_job, &NetJob::succeeded, [response, &ver]() { diff --git a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp index e17cf1c2..9fe8d486 100644 --- a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp +++ b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp @@ -61,6 +61,7 @@ #include "meta/VersionList.h" #include "minecraft/World.h" #include "minecraft/mod/tasks/LocalResourceParse.h" +#include "net/ApiDownload.h" static const FlameAPI api; @@ -353,11 +354,11 @@ bool FlameCreationTask::createInstance() id.remove("forge-"); loaderType = "forge"; loaderUid = "net.minecraftforge"; - } else if (loaderType == "fabric") { + } else if (id.startsWith("fabric-")) { id.remove("fabric-"); loaderType = "fabric"; loaderUid = "net.fabricmc.fabric-loader"; - } else if (loaderType == "quilt") { + } else if (id.startsWith("quilt-")) { id.remove("quilt-"); loaderType = "quilt"; loaderUid = "org.quiltmc.quilt-loader"; @@ -523,7 +524,7 @@ void FlameCreationTask::setupDownloadJob(QEventLoop& loop) case Flame::File::Type::Mod: { if (!result.url.isEmpty()) { qDebug() << "Will download" << result.url << "to" << path; - auto dl = Net::Download::makeFile(result.url, path); + auto dl = Net::ApiDownload::makeFile(result.url, path); m_files_job->addNetAction(dl); } break; diff --git a/launcher/modplatform/flame/FlameModIndex.cpp b/launcher/modplatform/flame/FlameModIndex.cpp index 227ce489..19803cf6 100644 --- a/launcher/modplatform/flame/FlameModIndex.cpp +++ b/launcher/modplatform/flame/FlameModIndex.cpp @@ -54,7 +54,7 @@ void FlameMod::loadURLs(ModPlatform::IndexedPack& pack, QJsonObject& obj) pack.extraDataLoaded = true; } -void FlameMod::loadBody(ModPlatform::IndexedPack& pack, QJsonObject& obj) +void FlameMod::loadBody(ModPlatform::IndexedPack& pack, [[maybe_unused]] QJsonObject& obj) { pack.extraData.body = api.getModDescription(pack.addonId.toInt()); @@ -75,7 +75,7 @@ static QString enumToString(int hash_algorithm) void FlameMod::loadIndexedPackVersions(ModPlatform::IndexedPack& pack, QJsonArray& arr, - const shared_qobject_ptr<QNetworkAccessManager>& network, + [[maybe_unused]] const shared_qobject_ptr<QNetworkAccessManager>& network, const BaseInstance* inst) { QVector<ModPlatform::IndexedVersion> unsortedVersions; @@ -193,4 +193,4 @@ ModPlatform::IndexedVersion FlameMod::loadDependencyVersions(const ModPlatform:: }; std::sort(versions.begin(), versions.end(), orderSortPredicate); return versions.front(); -}; +} diff --git a/launcher/modplatform/helpers/NetworkResourceAPI.cpp b/launcher/modplatform/helpers/NetworkResourceAPI.cpp index c278f800..46b96662 100644 --- a/launcher/modplatform/helpers/NetworkResourceAPI.cpp +++ b/launcher/modplatform/helpers/NetworkResourceAPI.cpp @@ -10,6 +10,8 @@ #include "modplatform/ModIndex.h" +#include "net/ApiDownload.h" + Task::Ptr NetworkResourceAPI::searchProjects(SearchArgs&& args, SearchCallbacks&& callbacks) const { auto search_url_optional = getSearchURL(args); @@ -23,7 +25,7 @@ Task::Ptr NetworkResourceAPI::searchProjects(SearchArgs&& args, SearchCallbacks& auto response = std::make_shared<QByteArray>(); auto netJob = makeShared<NetJob>(QString("%1::Search").arg(debugName()), APPLICATION->network()); - netJob->addNetAction(Net::Download::makeByteArray(QUrl(search_url), response)); + netJob->addNetAction(Net::ApiDownload::makeByteArray(QUrl(search_url), response)); QObject::connect(netJob.get(), &NetJob::succeeded, [this, response, callbacks] { QJsonParseError parse_error{}; @@ -85,7 +87,7 @@ Task::Ptr NetworkResourceAPI::getProjectVersions(VersionSearchArgs&& args, Versi auto netJob = makeShared<NetJob>(QString("%1::Versions").arg(args.pack.name), APPLICATION->network()); auto response = std::make_shared<QByteArray>(); - netJob->addNetAction(Net::Download::makeByteArray(versions_url, response)); + netJob->addNetAction(Net::ApiDownload::makeByteArray(versions_url, response)); QObject::connect(netJob.get(), &NetJob::succeeded, [response, callbacks, args] { QJsonParseError parse_error{}; @@ -113,7 +115,7 @@ Task::Ptr NetworkResourceAPI::getProject(QString addonId, std::shared_ptr<QByteA auto netJob = makeShared<NetJob>(QString("%1::GetProject").arg(addonId), APPLICATION->network()); - netJob->addNetAction(Net::Download::makeByteArray(QUrl(project_url), response)); + netJob->addNetAction(Net::ApiDownload::makeByteArray(QUrl(project_url), response)); return netJob; } @@ -145,4 +147,4 @@ Task::Ptr NetworkResourceAPI::getDependencyVersion(DependencySearchArgs&& args, }); return netJob; -}; +} diff --git a/launcher/modplatform/legacy_ftb/PackFetchTask.cpp b/launcher/modplatform/legacy_ftb/PackFetchTask.cpp index 6d27357a..8f1a6e2f 100644 --- a/launcher/modplatform/legacy_ftb/PackFetchTask.cpp +++ b/launcher/modplatform/legacy_ftb/PackFetchTask.cpp @@ -40,6 +40,8 @@ #include "Application.h" #include "BuildConfig.h" +#include "net/ApiDownload.h" + namespace LegacyFTB { void PackFetchTask::fetch() @@ -51,7 +53,7 @@ void PackFetchTask::fetch() QUrl publicPacksUrl = QUrl(BuildConfig.LEGACY_FTB_CDN_BASE_URL + "static/modpacks.xml"); qDebug() << "Downloading public version info from" << publicPacksUrl.toString(); - jobPtr->addNetAction(Net::Download::makeByteArray(publicPacksUrl, publicModpacksXmlFileData)); + jobPtr->addNetAction(Net::ApiDownload::makeByteArray(publicPacksUrl, publicModpacksXmlFileData)); QUrl thirdPartyUrl = QUrl(BuildConfig.LEGACY_FTB_CDN_BASE_URL + "static/thirdparty.xml"); qDebug() << "Downloading thirdparty version info from" << thirdPartyUrl.toString(); @@ -71,7 +73,7 @@ void PackFetchTask::fetchPrivate(const QStringList& toFetch) for (auto& packCode : toFetch) { auto data = std::make_shared<QByteArray>(); NetJob* job = new NetJob("Fetching private pack", m_network); - job->addNetAction(Net::Download::makeByteArray(privatePackBaseUrl.arg(packCode), data)); + job->addNetAction(Net::ApiDownload::makeByteArray(privatePackBaseUrl.arg(packCode), data)); QObject::connect(job, &NetJob::succeeded, this, [this, job, data, packCode] { ModpackList packs; diff --git a/launcher/modplatform/legacy_ftb/PackInstallTask.cpp b/launcher/modplatform/legacy_ftb/PackInstallTask.cpp index 91c821f0..761f622b 100644 --- a/launcher/modplatform/legacy_ftb/PackInstallTask.cpp +++ b/launcher/modplatform/legacy_ftb/PackInstallTask.cpp @@ -48,6 +48,8 @@ #include "Application.h" #include "BuildConfig.h" +#include "net/ApiDownload.h" + namespace LegacyFTB { PackInstallTask::PackInstallTask(shared_qobject_ptr<QNetworkAccessManager> network, Modpack pack, QString version) @@ -77,7 +79,7 @@ void PackInstallTask::downloadPack() } else { url = QString(BuildConfig.LEGACY_FTB_CDN_BASE_URL + "modpacks/%1").arg(archivePath); } - netJobContainer->addNetAction(Net::Download::makeFile(url, archivePath)); + netJobContainer->addNetAction(Net::ApiDownload::makeFile(url, archivePath)); connect(netJobContainer.get(), &NetJob::succeeded, this, &PackInstallTask::unzip); connect(netJobContainer.get(), &NetJob::failed, this, &PackInstallTask::emitFailed); diff --git a/launcher/modplatform/modrinth/ModrinthAPI.cpp b/launcher/modplatform/modrinth/ModrinthAPI.cpp index 364cf3f3..466c5b10 100644 --- a/launcher/modplatform/modrinth/ModrinthAPI.cpp +++ b/launcher/modplatform/modrinth/ModrinthAPI.cpp @@ -6,6 +6,8 @@ #include "Application.h" #include "Json.h" +#include "net/ApiDownload.h" +#include "net/ApiUpload.h" #include "net/NetJob.h" #include "net/Upload.h" @@ -13,7 +15,7 @@ Task::Ptr ModrinthAPI::currentVersion(QString hash, QString hash_format, std::sh { auto netJob = makeShared<NetJob>(QString("Modrinth::GetCurrentVersion"), APPLICATION->network()); - netJob->addNetAction(Net::Download::makeByteArray( + netJob->addNetAction(Net::ApiDownload::makeByteArray( QString(BuildConfig.MODRINTH_PROD_URL + "/version_file/%1?algorithm=%2").arg(hash, hash_format), response)); return netJob; @@ -31,7 +33,7 @@ Task::Ptr ModrinthAPI::currentVersions(const QStringList& hashes, QString hash_f QJsonDocument body(body_obj); auto body_raw = body.toJson(); - netJob->addNetAction(Net::Upload::makeByteArray(QString(BuildConfig.MODRINTH_PROD_URL + "/version_files"), response, body_raw)); + netJob->addNetAction(Net::ApiUpload::makeByteArray(QString(BuildConfig.MODRINTH_PROD_URL + "/version_files"), response, body_raw)); return netJob; } @@ -60,7 +62,7 @@ Task::Ptr ModrinthAPI::latestVersion(QString hash, QJsonDocument body(body_obj); auto body_raw = body.toJson(); - netJob->addNetAction(Net::Upload::makeByteArray( + netJob->addNetAction(Net::ApiUpload::makeByteArray( QString(BuildConfig.MODRINTH_PROD_URL + "/version_file/%1/update?algorithm=%2").arg(hash, hash_format), response, body_raw)); return netJob; @@ -93,7 +95,8 @@ Task::Ptr ModrinthAPI::latestVersions(const QStringList& hashes, QJsonDocument body(body_obj); auto body_raw = body.toJson(); - netJob->addNetAction(Net::Upload::makeByteArray(QString(BuildConfig.MODRINTH_PROD_URL + "/version_files/update"), response, body_raw)); + netJob->addNetAction( + Net::ApiUpload::makeByteArray(QString(BuildConfig.MODRINTH_PROD_URL + "/version_files/update"), response, body_raw)); return netJob; } @@ -103,7 +106,7 @@ Task::Ptr ModrinthAPI::getProjects(QStringList addonIds, std::shared_ptr<QByteAr auto netJob = makeShared<NetJob>(QString("Modrinth::GetProjects"), APPLICATION->network()); auto searchUrl = getMultipleModInfoURL(addonIds); - netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), response)); + netJob->addNetAction(Net::ApiDownload::makeByteArray(QUrl(searchUrl), response)); return netJob; } diff --git a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp index 16e375cd..cdbbd42d 100644 --- a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp +++ b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp @@ -11,6 +11,7 @@ #include "net/ChecksumValidator.h" +#include "net/ApiDownload.h" #include "net/NetJob.h" #include "settings/INISettingsObject.h" @@ -238,7 +239,7 @@ bool ModrinthCreationTask::createInstance() } qDebug() << "Will try to download" << file.downloads.front() << "to" << file_path; - auto dl = Net::Download::makeFile(file.downloads.dequeue(), file_path); + auto dl = Net::ApiDownload::makeFile(file.downloads.dequeue(), file_path); dl->addValidator(new Net::ChecksumValidator(file.hashAlgorithm, file.hash)); m_files_job->addNetAction(dl); @@ -247,7 +248,7 @@ bool ModrinthCreationTask::createInstance() // MultipleOptionsTask's , once those exist :) auto param = dl.toWeakRef(); connect(dl.get(), &NetAction::failed, [this, &file, file_path, param] { - auto ndl = Net::Download::makeFile(file.downloads.dequeue(), file_path); + auto ndl = Net::ApiDownload::makeFile(file.downloads.dequeue(), file_path); ndl->addValidator(new Net::ChecksumValidator(file.hashAlgorithm, file.hash)); m_files_job->addNetAction(ndl); if (auto shared = param.lock()) diff --git a/launcher/modplatform/modrinth/ModrinthPackExportTask.cpp b/launcher/modplatform/modrinth/ModrinthPackExportTask.cpp index 7bf29639..64c06d1b 100644 --- a/launcher/modplatform/modrinth/ModrinthPackExportTask.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackExportTask.cpp @@ -174,10 +174,10 @@ void ModrinthPackExportTask::parseApiResponse(const std::shared_ptr<QByteArray> if (obj.isEmpty()) continue; - const QJsonArray files = obj["files"].toArray(); - if (auto fileIter = std::find_if(files.begin(), files.end(), + const QJsonArray files_array = obj["files"].toArray(); + if (auto fileIter = std::find_if(files_array.begin(), files_array.end(), [&iterator](const QJsonValue& file) { return file["hashes"]["sha512"] == iterator.value(); }); - fileIter != files.end()) { + fileIter != files_array.end()) { // map the file to the url resolvedFiles[iterator.key()] = ResolvedFile{ fileIter->toObject()["hashes"].toObject()["sha1"].toString(), iterator.value(), diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp index 96dafe70..85e66a91 100644 --- a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp @@ -95,7 +95,7 @@ void Modrinth::loadExtraPackData(ModPlatform::IndexedPack& pack, QJsonObject& ob void Modrinth::loadIndexedPackVersions(ModPlatform::IndexedPack& pack, QJsonArray& arr, - const shared_qobject_ptr<QNetworkAccessManager>& network, + [[maybe_unused]] const shared_qobject_ptr<QNetworkAccessManager>& network, const BaseInstance* inst) { QVector<ModPlatform::IndexedVersion> unsortedVersions; @@ -218,7 +218,7 @@ auto Modrinth::loadIndexedPackVersion(QJsonObject& obj, QString preferred_hash_t return {}; } -auto Modrinth::loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion +auto Modrinth::loadDependencyVersions([[maybe_unused]] const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion { QVector<ModPlatform::IndexedVersion> versions; @@ -235,4 +235,4 @@ auto Modrinth::loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArr }; std::sort(versions.begin(), versions.end(), orderSortPredicate); return versions.length() != 0 ? versions.front() : ModPlatform::IndexedVersion(); -}
\ No newline at end of file +} diff --git a/launcher/modplatform/packwiz/Packwiz.cpp b/launcher/modplatform/packwiz/Packwiz.cpp index 1be28378..71f66bf3 100644 --- a/launcher/modplatform/packwiz/Packwiz.cpp +++ b/launcher/modplatform/packwiz/Packwiz.cpp @@ -89,7 +89,8 @@ auto intEntry(toml::table table, QString entry_name) -> int return node.value_or(0); } -auto V1::createModFormat(QDir& index_dir, ModPlatform::IndexedPack& mod_pack, ModPlatform::IndexedVersion& mod_version) -> Mod +auto V1::createModFormat([[maybe_unused]] QDir& index_dir, ModPlatform::IndexedPack& mod_pack, ModPlatform::IndexedVersion& mod_version) + -> Mod { Mod mod; @@ -114,7 +115,7 @@ auto V1::createModFormat(QDir& index_dir, ModPlatform::IndexedPack& mod_pack, Mo return mod; } -auto V1::createModFormat(QDir& index_dir, ::Mod& internal_mod, QString slug) -> Mod +auto V1::createModFormat(QDir& index_dir, [[maybe_unused]] ::Mod& internal_mod, QString slug) -> Mod { // Try getting metadata if it exists Mod mod{ getIndexForMod(index_dir, slug) }; @@ -241,12 +242,13 @@ auto V1::getIndexForMod(QDir& index_dir, QString slug) -> Mod return {}; } #else - table = toml::parse_file(StringUtils::toStdString(index_dir.absoluteFilePath(real_fname))); - if (!table) { + toml::parse_result result = toml::parse_file(StringUtils::toStdString(index_dir.absoluteFilePath(real_fname))); + if (!result) { qWarning() << QString("Could not open file %1!").arg(normalized_fname); - qWarning() << "Reason: " << QString(table.error().what()); + qWarning() << "Reason: " << result.error().description(); return {}; } + table = result.table(); #endif // index_file.close(); diff --git a/launcher/modplatform/technic/SingleZipPackInstallTask.cpp b/launcher/modplatform/technic/SingleZipPackInstallTask.cpp index dd59e652..ad08d72d 100644 --- a/launcher/modplatform/technic/SingleZipPackInstallTask.cpp +++ b/launcher/modplatform/technic/SingleZipPackInstallTask.cpp @@ -23,6 +23,8 @@ #include "Application.h" +#include "net/ApiDownload.h" + Technic::SingleZipPackInstallTask::SingleZipPackInstallTask(const QUrl& sourceUrl, const QString& minecraftVersion) { m_sourceUrl = sourceUrl; @@ -45,7 +47,7 @@ void Technic::SingleZipPackInstallTask::executeTask() auto entry = APPLICATION->metacache()->resolveEntry("general", path); entry->setStale(true); m_filesNetJob.reset(new NetJob(tr("Modpack download"), APPLICATION->network())); - m_filesNetJob->addNetAction(Net::Download::makeCached(m_sourceUrl, entry)); + m_filesNetJob->addNetAction(Net::ApiDownload::makeCached(m_sourceUrl, entry)); m_archivePath = entry->getFullPath(); auto job = m_filesNetJob.get(); connect(job, &NetJob::succeeded, this, &Technic::SingleZipPackInstallTask::downloadSucceeded); diff --git a/launcher/modplatform/technic/SolderPackInstallTask.cpp b/launcher/modplatform/technic/SolderPackInstallTask.cpp index ad564de0..c162d625 100644 --- a/launcher/modplatform/technic/SolderPackInstallTask.cpp +++ b/launcher/modplatform/technic/SolderPackInstallTask.cpp @@ -42,6 +42,7 @@ #include "SolderPackManifest.h" #include "TechnicPackProcessor.h" +#include "net/ApiDownload.h" #include "net/ChecksumValidator.h" Technic::SolderPackInstallTask::SolderPackInstallTask(shared_qobject_ptr<QNetworkAccessManager> network, @@ -71,7 +72,7 @@ void Technic::SolderPackInstallTask::executeTask() m_filesNetJob.reset(new NetJob(tr("Resolving modpack files"), m_network)); auto sourceUrl = QString("%1/modpack/%2/%3").arg(m_solderUrl.toString(), m_pack, m_version); - m_filesNetJob->addNetAction(Net::Download::makeByteArray(sourceUrl, m_response)); + m_filesNetJob->addNetAction(Net::ApiDownload::makeByteArray(sourceUrl, m_response)); auto job = m_filesNetJob.get(); connect(job, &NetJob::succeeded, this, &Technic::SolderPackInstallTask::fileListSucceeded); @@ -111,7 +112,7 @@ void Technic::SolderPackInstallTask::fileListSucceeded() for (const auto& mod : build.mods) { auto path = FS::PathCombine(m_outputDir.path(), QString("%1").arg(i)); - auto dl = Net::Download::makeFile(mod.url, path); + auto dl = Net::ApiDownload::makeFile(mod.url, path); if (!mod.md5.isEmpty()) { auto rawMd5 = QByteArray::fromHex(mod.md5.toLatin1()); dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Md5, rawMd5)); diff --git a/launcher/modplatform/technic/TechnicPackProcessor.cpp b/launcher/modplatform/technic/TechnicPackProcessor.cpp index 778a6531..3b9424bf 100644 --- a/launcher/modplatform/technic/TechnicPackProcessor.cpp +++ b/launcher/modplatform/technic/TechnicPackProcessor.cpp @@ -31,7 +31,7 @@ void Technic::TechnicPackProcessor::run(SettingsObjectPtr globalSettings, const QString& instIcon, const QString& stagingPath, const QString& minecraftVersion, - const bool isSolder) + [[maybe_unused]] const bool isSolder) { QString minecraftPath = FS::PathCombine(stagingPath, ".minecraft"); QString configPath = FS::PathCombine(stagingPath, "instance.cfg"); @@ -138,15 +138,15 @@ void Technic::TechnicPackProcessor::run(SettingsObjectPtr globalSettings, try { QJsonDocument doc = Json::requireDocument(data); QJsonObject root = Json::requireObject(doc, "version.json"); - QString minecraftVersion = Json::ensureString(root, "inheritsFrom", QString(), ""); - if (minecraftVersion.isEmpty()) { + QString packMinecraftVersion = Json::ensureString(root, "inheritsFrom", QString(), ""); + if (packMinecraftVersion.isEmpty()) { if (fmlMinecraftVersion.isEmpty()) { emit failed(tr("Could not understand \"version.json\":\ninheritsFrom is missing")); return; } - minecraftVersion = fmlMinecraftVersion; + packMinecraftVersion = fmlMinecraftVersion; } - components->setComponentVersion("net.minecraft", minecraftVersion, true); + components->setComponentVersion("net.minecraft", packMinecraftVersion, true); for (auto library : Json::ensureArray(root, "libraries", {})) { if (!library.isObject()) { continue; diff --git a/launcher/net/ApiDownload.cpp b/launcher/net/ApiDownload.cpp new file mode 100644 index 00000000..aaa8ff65 --- /dev/null +++ b/launcher/net/ApiDownload.cpp @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2023 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include "net/ApiDownload.h" +#include "ByteArraySink.h" +#include "ChecksumValidator.h" +#include "MetaCacheSink.h" +#include "net/NetAction.h" + +namespace Net { + +auto ApiDownload::makeCached(QUrl url, MetaEntryPtr entry, Options options) -> Download::Ptr +{ + auto dl = makeShared<ApiDownload>(); + dl->m_url = url; + dl->setObjectName(QString("CACHE:") + url.toString()); + dl->m_options = options; + auto md5Node = new ChecksumValidator(QCryptographicHash::Md5); + auto cachedNode = new MetaCacheSink(entry, md5Node, options.testFlag(Option::MakeEternal)); + dl->m_sink.reset(cachedNode); + return dl; +} + +auto ApiDownload::makeByteArray(QUrl url, std::shared_ptr<QByteArray> output, Options options) -> Download::Ptr +{ + auto dl = makeShared<ApiDownload>(); + dl->m_url = url; + dl->setObjectName(QString("BYTES:") + url.toString()); + dl->m_options = options; + dl->m_sink.reset(new ByteArraySink(output)); + return dl; +} + +auto ApiDownload::makeFile(QUrl url, QString path, Options options) -> Download::Ptr +{ + auto dl = makeShared<ApiDownload>(); + dl->m_url = url; + dl->setObjectName(QString("FILE:") + url.toString()); + dl->m_options = options; + dl->m_sink.reset(new FileSink(path)); + return dl; +} + +void ApiDownload::init() +{ + qDebug() << "Setting up api download"; + auto api_headers = new ApiHeaderProxy(); + addHeaderProxy(api_headers); +} +} // namespace Net diff --git a/launcher/net/ApiDownload.h b/launcher/net/ApiDownload.h new file mode 100644 index 00000000..638c94e1 --- /dev/null +++ b/launcher/net/ApiDownload.h @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2023 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include "ApiHeaderProxy.h" +#include "Download.h" + +namespace Net { + +class ApiDownload : public Download { + public: + virtual ~ApiDownload() = default; + + static auto makeCached(QUrl url, MetaEntryPtr entry, Options options = Option::NoOptions) -> Download::Ptr; + static auto makeByteArray(QUrl url, std::shared_ptr<QByteArray> output, Options options = Option::NoOptions) -> Download::Ptr; + static auto makeFile(QUrl url, QString path, Options options = Option::NoOptions) -> Download::Ptr; + + void init() override; +}; + +} // namespace Net diff --git a/launcher/net/ApiHeaderProxy.h b/launcher/net/ApiHeaderProxy.h new file mode 100644 index 00000000..789a6fad --- /dev/null +++ b/launcher/net/ApiHeaderProxy.h @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2023 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include "Application.h" +#include "BuildConfig.h" +#include "net/HeaderProxy.h" + +namespace Net { + +class ApiHeaderProxy : public HeaderProxy { + public: + ApiHeaderProxy() : HeaderProxy() {} + virtual ~ApiHeaderProxy() = default; + + public: + virtual QList<HeaderPair> headers(const QNetworkRequest& request) const override + { + QList<HeaderPair> hdrs; + if (APPLICATION->capabilities() & Application::SupportsFlame && request.url().host() == QUrl(BuildConfig.FLAME_BASE_URL).host()) { + hdrs.append({ "x-api-key", APPLICATION->getFlameAPIKey().toUtf8() }); + } else if (request.url().host() == QUrl(BuildConfig.MODRINTH_PROD_URL).host() || + request.url().host() == QUrl(BuildConfig.MODRINTH_STAGING_URL).host()) { + QString token = APPLICATION->getModrinthAPIToken(); + if (!token.isNull()) + hdrs.append({ "Authorization", token.toUtf8() }); + } + return hdrs; + }; +}; + +} // namespace Net diff --git a/launcher/net/ApiUpload.cpp b/launcher/net/ApiUpload.cpp new file mode 100644 index 00000000..c1221b76 --- /dev/null +++ b/launcher/net/ApiUpload.cpp @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2023 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#include "net/ApiUpload.h" +#include "ByteArraySink.h" +#include "ChecksumValidator.h" +#include "MetaCacheSink.h" +#include "net/NetAction.h" + +namespace Net { + +Upload::Ptr ApiUpload::makeByteArray(QUrl url, std::shared_ptr<QByteArray> output, QByteArray m_post_data) +{ + auto up = makeShared<ApiUpload>(); + up->m_url = std::move(url); + up->m_sink.reset(new ByteArraySink(output)); + up->m_post_data = std::move(m_post_data); + return up; +} + +void ApiUpload::init() +{ + qDebug() << "Setting up api upload"; + auto api_headers = new ApiHeaderProxy(); + addHeaderProxy(api_headers); +} +} // namespace Net diff --git a/launcher/net/ApiUpload.h b/launcher/net/ApiUpload.h new file mode 100644 index 00000000..b12842b0 --- /dev/null +++ b/launcher/net/ApiUpload.h @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2023 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include "ApiHeaderProxy.h" +#include "Upload.h" + +namespace Net { + +class ApiUpload : public Upload { + public: + virtual ~ApiUpload() = default; + + static Upload::Ptr makeByteArray(QUrl url, std::shared_ptr<QByteArray> output, QByteArray m_post_data); + + void init() override; +}; + +} // namespace Net diff --git a/launcher/net/ByteArraySink.h b/launcher/net/ByteArraySink.h index d6b17d60..7b8f0f8a 100644 --- a/launcher/net/ByteArraySink.h +++ b/launcher/net/ByteArraySink.h @@ -42,8 +42,6 @@ namespace Net { /* * Sink object for downloads that uses an external QByteArray it doesn't own as a target. - * FIXME: It is possible that the QByteArray is freed while we're doing some operation on it, - * causing a segmentation fault. */ class ByteArraySink : public Sink { public: diff --git a/launcher/net/Download.cpp b/launcher/net/Download.cpp index 9ad49ded..d25447b2 100644 --- a/launcher/net/Download.cpp +++ b/launcher/net/Download.cpp @@ -47,17 +47,11 @@ #include "ChecksumValidator.h" #include "MetaCacheSink.h" -#include "Application.h" -#include "BuildConfig.h" - -#include "net/Logging.h" #include "net/NetAction.h" -#include "MMCTime.h" -#include "StringUtils.h" - namespace Net { +#if defined(LAUNCHER_APPLICATION) auto Download::makeCached(QUrl url, MetaEntryPtr entry, Options options) -> Download::Ptr { auto dl = makeShared<Download>(); @@ -69,6 +63,7 @@ auto Download::makeCached(QUrl url, MetaEntryPtr entry, Options options) -> Down dl->m_sink.reset(cachedNode); return dl; } +#endif auto Download::makeByteArray(QUrl url, std::shared_ptr<QByteArray> output, Options options) -> Download::Ptr { @@ -90,259 +85,8 @@ auto Download::makeFile(QUrl url, QString path, Options options) -> Download::Pt return dl; } -void Download::addValidator(Validator* v) -{ - m_sink->addValidator(v); -} - -void Download::executeTask() -{ - setStatus(tr("Downloading %1").arg(StringUtils::truncateUrlHumanFriendly(m_url, 80))); - - if (getState() == Task::State::AbortedByUser) { - qCWarning(taskDownloadLogC) << getUid().toString() << "Attempt to start an aborted Download:" << m_url.toString(); - emitAborted(); - return; - } - - QNetworkRequest request(m_url); - m_state = m_sink->init(request); - switch (m_state) { - case State::Succeeded: - emit succeeded(); - qCDebug(taskDownloadLogC) << getUid().toString() << "Download cache hit " << m_url.toString(); - return; - case State::Running: - qCDebug(taskDownloadLogC) << getUid().toString() << "Downloading " << m_url.toString(); - break; - case State::Inactive: - case State::Failed: - emitFailed(); - return; - case State::AbortedByUser: - emitAborted(); - return; - } - - request.setHeader(QNetworkRequest::UserAgentHeader, APPLICATION->getUserAgent().toUtf8()); - // TODO remove duplication - if (APPLICATION->capabilities() & Application::SupportsFlame && request.url().host() == QUrl(BuildConfig.FLAME_BASE_URL).host()) { - request.setRawHeader("x-api-key", APPLICATION->getFlameAPIKey().toUtf8()); - } else if (request.url().host() == QUrl(BuildConfig.MODRINTH_PROD_URL).host() || - request.url().host() == QUrl(BuildConfig.MODRINTH_STAGING_URL).host()) { - QString token = APPLICATION->getModrinthAPIToken(); - if (!token.isNull()) - request.setRawHeader("Authorization", token.toUtf8()); - } - -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) - request.setTransferTimeout(); -#endif - - m_last_progress_time = m_clock.now(); - m_last_progress_bytes = 0; - - QNetworkReply* rep = m_network->get(request); - m_reply.reset(rep); - connect(rep, &QNetworkReply::downloadProgress, this, &Download::downloadProgress); - connect(rep, &QNetworkReply::finished, this, &Download::downloadFinished); -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15 - connect(rep, &QNetworkReply::errorOccurred, this, &Download::downloadError); -#else - connect(rep, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), this, &Download::downloadError); -#endif - connect(rep, &QNetworkReply::sslErrors, this, &Download::sslErrors); - connect(rep, &QNetworkReply::readyRead, this, &Download::downloadReadyRead); -} - -void Download::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) -{ - auto now = m_clock.now(); - auto elapsed = now - m_last_progress_time; - - // use milliseconds for speed precision - auto elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed); - auto bytes_received_since = bytesReceived - m_last_progress_bytes; - auto dl_speed_bps = (double)bytes_received_since / elapsed_ms.count() * 1000; - auto remaing_time_s = (bytesTotal - bytesReceived) / dl_speed_bps; - - //: Current amount of bytes downloaded, out of the total amount of bytes in the download - QString dl_progress = - tr("%1 / %2").arg(StringUtils::humanReadableFileSize(bytesReceived)).arg(StringUtils::humanReadableFileSize(bytesTotal)); - - QString dl_speed_str; - if (elapsed_ms.count() > 0) { - auto str_eta = bytesTotal > 0 ? Time::humanReadableDuration(remaing_time_s) : tr("unknown"); - //: Download speed, in bytes per second (remaining download time in parenthesis) - dl_speed_str = tr("%1 /s (%2)").arg(StringUtils::humanReadableFileSize(dl_speed_bps)).arg(str_eta); - } else { - //: Download speed at 0 bytes per second - dl_speed_str = tr("0 B/s"); - } - - setDetails(dl_progress + "\n" + dl_speed_str); - - setProgress(bytesReceived, bytesTotal); -} - -void Download::downloadError(QNetworkReply::NetworkError error) -{ - if (error == QNetworkReply::OperationCanceledError) { - qCCritical(taskDownloadLogC) << getUid().toString() << "Aborted " << m_url.toString(); - m_state = State::AbortedByUser; - } else { - if (m_options & Option::AcceptLocalFiles) { - if (m_sink->hasLocalData()) { - m_state = State::Succeeded; - return; - } - } - // error happened during download. - qCCritical(taskDownloadLogC) << getUid().toString() << "Failed " << m_url.toString() << " with reason " << error; - m_state = State::Failed; - } -} - -void Download::sslErrors(const QList<QSslError>& errors) -{ - int i = 1; - for (auto error : errors) { - qCCritical(taskDownloadLogC) << getUid().toString() << "Download" << m_url.toString() << "SSL Error #" << i << " : " - << error.errorString(); - auto cert = error.certificate(); - qCCritical(taskDownloadLogC) << getUid().toString() << "Certificate in question:\n" << cert.toText(); - i++; - } -} - -auto Download::handleRedirect() -> bool -{ - QUrl redirect = m_reply->header(QNetworkRequest::LocationHeader).toUrl(); - if (!redirect.isValid()) { - if (!m_reply->hasRawHeader("Location")) { - // no redirect -> it's fine to continue - return false; - } - // there is a Location header, but it's not correct. we need to apply some workarounds... - QByteArray redirectBA = m_reply->rawHeader("Location"); - if (redirectBA.size() == 0) { - // empty, yet present redirect header? WTF? - return false; - } - QString redirectStr = QString::fromUtf8(redirectBA); - - if (redirectStr.startsWith("//")) { - /* - * IF the URL begins with //, we need to insert the URL scheme. - * See: https://bugreports.qt.io/browse/QTBUG-41061 - * See: http://tools.ietf.org/html/rfc3986#section-4.2 - */ - redirectStr = m_reply->url().scheme() + ":" + redirectStr; - } else if (redirectStr.startsWith("/")) { - /* - * IF the URL begins with /, we need to process it as a relative URL - */ - auto url = m_reply->url(); - url.setPath(redirectStr, QUrl::TolerantMode); - redirectStr = url.toString(); - } - - /* - * Next, make sure the URL is parsed in tolerant mode. Qt doesn't parse the location header in tolerant mode, which causes issues. - * FIXME: report Qt bug for this - */ - redirect = QUrl(redirectStr, QUrl::TolerantMode); - if (!redirect.isValid()) { - qCWarning(taskDownloadLogC) << getUid().toString() << "Failed to parse redirect URL:" << redirectStr; - downloadError(QNetworkReply::ProtocolFailure); - return false; - } - qCDebug(taskDownloadLogC) << getUid().toString() << "Fixed location header:" << redirect; - } else { - qCDebug(taskDownloadLogC) << getUid().toString() << "Location header:" << redirect; - } - - m_url = QUrl(redirect.toString()); - qCDebug(taskDownloadLogC) << getUid().toString() << "Following redirect to " << m_url.toString(); - startAction(m_network); - - return true; -} - -void Download::downloadFinished() -{ - // handle HTTP redirection first - if (handleRedirect()) { - qCDebug(taskDownloadLogC) << getUid().toString() << "Download redirected:" << m_url.toString(); - return; - } - - // if the download failed before this point ... - if (m_state == State::Succeeded) // pretend to succeed so we continue processing :) - { - qCDebug(taskDownloadLogC) << getUid().toString() << "Download failed but we are allowed to proceed:" << m_url.toString(); - m_sink->abort(); - m_reply.reset(); - emit succeeded(); - return; - } else if (m_state == State::Failed) { - qCDebug(taskDownloadLogC) << getUid().toString() << "Download failed in previous step:" << m_url.toString(); - m_sink->abort(); - m_reply.reset(); - emit failed(""); - return; - } else if (m_state == State::AbortedByUser) { - qCDebug(taskDownloadLogC) << getUid().toString() << "Download aborted in previous step:" << m_url.toString(); - m_sink->abort(); - m_reply.reset(); - emit aborted(); - return; - } - - // make sure we got all the remaining data, if any - auto data = m_reply->readAll(); - if (data.size()) { - qCDebug(taskDownloadLogC) << getUid().toString() << "Writing extra" << data.size() << "bytes"; - m_state = m_sink->write(data); - } - - // otherwise, finalize the whole graph - m_state = m_sink->finalize(*m_reply.get()); - if (m_state != State::Succeeded) { - qCDebug(taskDownloadLogC) << getUid().toString() << "Download failed to finalize:" << m_url.toString(); - m_sink->abort(); - m_reply.reset(); - emit failed(""); - return; - } - - m_reply.reset(); - qCDebug(taskDownloadLogC) << getUid().toString() << "Download succeeded:" << m_url.toString(); - emit succeeded(); -} - -void Download::downloadReadyRead() -{ - if (m_state == State::Running) { - auto data = m_reply->readAll(); - m_state = m_sink->write(data); - if (m_state == State::Failed) { - qCCritical(taskDownloadLogC) << getUid().toString() << "Failed to process response chunk"; - } - // qDebug() << "Download" << m_url.toString() << "gained" << data.size() << "bytes"; - } else { - qCCritical(taskDownloadLogC) << getUid().toString() << "Cannot write download data! illegal status " << m_status; - } -} - -} // namespace Net - -auto Net::Download::abort() -> bool +QNetworkReply* Download::getReply(QNetworkRequest& request) { - if (m_reply) { - m_reply->abort(); - } else { - m_state = State::AbortedByUser; - } - return true; + return m_network->get(request); } +} // namespace Net
\ No newline at end of file diff --git a/launcher/net/Download.h b/launcher/net/Download.h index 2e861732..5f6a5caf 100644 --- a/launcher/net/Download.h +++ b/launcher/net/Download.h @@ -38,57 +38,26 @@ #pragma once -#include <chrono> - #include "HttpMetaCache.h" -#include "NetAction.h" -#include "Sink.h" -#include "Validator.h" #include "QObjectPtr.h" +#include "net/NetRequest.h" namespace Net { -class Download : public NetAction { +class Download : public NetRequest { Q_OBJECT - public: using Ptr = shared_qobject_ptr<class Download>; - enum class Option { NoOptions = 0, AcceptLocalFiles = 1, MakeEternal = 2 }; - Q_DECLARE_FLAGS(Options, Option) - - public: - ~Download() override = default; + explicit Download() : NetRequest() { logCat = taskDownloadLogC; } +#if defined(LAUNCHER_APPLICATION) static auto makeCached(QUrl url, MetaEntryPtr entry, Options options = Option::NoOptions) -> Download::Ptr; +#endif + static auto makeByteArray(QUrl url, std::shared_ptr<QByteArray> output, Options options = Option::NoOptions) -> Download::Ptr; static auto makeFile(QUrl url, QString path, Options options = Option::NoOptions) -> Download::Ptr; - public: - void addValidator(Validator* v); - auto abort() -> bool override; - auto canAbort() const -> bool override { return true; }; - - private: - auto handleRedirect() -> bool; - - protected slots: - void downloadProgress(qint64 bytesReceived, qint64 bytesTotal) override; - void downloadError(QNetworkReply::NetworkError error) override; - void sslErrors(const QList<QSslError>& errors) override; - void downloadFinished() override; - void downloadReadyRead() override; - - public slots: - void executeTask() override; - - private: - std::unique_ptr<Sink> m_sink; - Options m_options; - - std::chrono::steady_clock m_clock; - std::chrono::time_point<std::chrono::steady_clock> m_last_progress_time; - qint64 m_last_progress_bytes; + protected: + virtual QNetworkReply* getReply(QNetworkRequest&) override; }; } // namespace Net - -Q_DECLARE_OPERATORS_FOR_FLAGS(Net::Download::Options) diff --git a/launcher/net/HeaderProxy.h b/launcher/net/HeaderProxy.h new file mode 100644 index 00000000..20362924 --- /dev/null +++ b/launcher/net/HeaderProxy.h @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2023 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include <QDebug> +#include <QNetworkRequest> + +namespace Net { + +struct HeaderPair { + QByteArray headerName; + QByteArray headerValue; +}; + +class HeaderProxy { + public: + HeaderProxy() {} + virtual ~HeaderProxy() {} + + public: + virtual QList<HeaderPair> headers(const QNetworkRequest& request) const = 0; + + public: + void writeHeaders(QNetworkRequest& request) + { + for (auto header : headers(request)) { + request.setRawHeader(header.headerName, header.headerValue); + } + } +}; + +} // namespace Net diff --git a/launcher/net/HttpMetaCache.h b/launcher/net/HttpMetaCache.h index 0dcb5668..036a8dd9 100644 --- a/launcher/net/HttpMetaCache.h +++ b/launcher/net/HttpMetaCache.h @@ -74,7 +74,7 @@ class MetaEntry { auto getMaximumAge() -> qint64 { return m_max_age; } void setMaximumAge(qint64 age) { m_max_age = age; } - bool isExpired(qint64 offset) { return !m_is_eternal && (m_current_age >= m_max_age - offset); }; + bool isExpired(qint64 offset) { return !m_is_eternal && (m_current_age >= m_max_age - offset); } protected: QString m_baseId; diff --git a/launcher/net/NetAction.h b/launcher/net/NetAction.h index 54eddc72..b66b9194 100644 --- a/launcher/net/NetAction.h +++ b/launcher/net/NetAction.h @@ -42,10 +42,12 @@ #include "QObjectPtr.h" #include "tasks/Task.h" +#include "HeaderProxy.h" + class NetAction : public Task { Q_OBJECT protected: - explicit NetAction() : Task(){}; + explicit NetAction() : Task() {} public: using Ptr = shared_qobject_ptr<NetAction>; @@ -56,6 +58,9 @@ class NetAction : public Task { void setNetwork(shared_qobject_ptr<QNetworkAccessManager> network) { m_network = network; } + void addHeaderProxy(Net::HeaderProxy* proxy) { m_headerProxies.push_back(std::shared_ptr<Net::HeaderProxy>(proxy)); } + virtual void init() = 0; + protected slots: virtual void downloadProgress(qint64 bytesReceived, qint64 bytesTotal) = 0; virtual void downloadError(QNetworkReply::NetworkError error) = 0; @@ -71,7 +76,7 @@ class NetAction : public Task { qCritical() << "Certificate in question:\n" << cert.toText(); i++; } - }; + } public slots: void startAction(shared_qobject_ptr<QNetworkAccessManager> network) @@ -81,7 +86,7 @@ class NetAction : public Task { } protected: - void executeTask() override{}; + void executeTask() override {} public: shared_qobject_ptr<QNetworkAccessManager> m_network; @@ -91,4 +96,5 @@ class NetAction : public Task { /// source URL QUrl m_url; + std::vector<std::shared_ptr<Net::HeaderProxy>> m_headerProxies; }; diff --git a/launcher/net/NetRequest.cpp b/launcher/net/NetRequest.cpp new file mode 100644 index 00000000..ff59da18 --- /dev/null +++ b/launcher/net/NetRequest.cpp @@ -0,0 +1,331 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2022 flowln <flowlnlnln@gmail.com> + * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> + * Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me> + * Copyright (C) 2023 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "NetRequest.h" +#include <QUrl> + +#include <QDateTime> +#include <QFileInfo> +#include <memory> + +#if defined(LAUNCHER_APPLICATION) +#include "Application.h" +#endif + +#include "net/NetAction.h" + +#include "MMCTime.h" +#include "StringUtils.h" + +namespace Net { + +void NetRequest::addValidator(Validator* v) +{ + m_sink->addValidator(v); +} + +void NetRequest::executeTask() +{ + init(); + + setStatus(tr("Requesting %1").arg(StringUtils::truncateUrlHumanFriendly(m_url, 80))); + + if (getState() == Task::State::AbortedByUser) { + qCWarning(logCat) << getUid().toString() << "Attempt to start an aborted Request:" << m_url.toString(); + emitAborted(); + return; + } + + QNetworkRequest request(m_url); + m_state = m_sink->init(request); + switch (m_state) { + case State::Succeeded: + qCDebug(logCat) << getUid().toString() << "Request cache hit " << m_url.toString(); + emit succeeded(); + emit finished(); + return; + case State::Running: + qCDebug(logCat) << getUid().toString() << "Runninng " << m_url.toString(); + break; + case State::Inactive: + case State::Failed: + emitFailed(); + return; + case State::AbortedByUser: + emitAborted(); + return; + } + +#if defined(LAUNCHER_APPLICATION) + auto user_agent = APPLICATION->getUserAgent(); +#else + auto user_agent = BuildConfig.USER_AGENT; +#endif + + request.setHeader(QNetworkRequest::UserAgentHeader, user_agent.toUtf8()); + for (auto& header_proxy : m_headerProxies) { + header_proxy->writeHeaders(request); + } + // TODO remove duplication + +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + request.setTransferTimeout(); +#endif + + m_last_progress_time = m_clock.now(); + m_last_progress_bytes = 0; + + QNetworkReply* rep = getReply(request); + m_reply.reset(rep); + connect(rep, &QNetworkReply::downloadProgress, this, &NetRequest::downloadProgress); + connect(rep, &QNetworkReply::finished, this, &NetRequest::downloadFinished); +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15 + connect(rep, &QNetworkReply::errorOccurred, this, &NetRequest::downloadError); +#else + connect(rep, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), this, &NetRequest::downloadError); +#endif + connect(rep, &QNetworkReply::sslErrors, this, &NetRequest::sslErrors); + connect(rep, &QNetworkReply::readyRead, this, &NetRequest::downloadReadyRead); +} + +void NetRequest::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) +{ + auto now = m_clock.now(); + auto elapsed = now - m_last_progress_time; + + // use milliseconds for speed precision + auto elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed); + auto bytes_received_since = bytesReceived - m_last_progress_bytes; + auto dl_speed_bps = (double)bytes_received_since / elapsed_ms.count() * 1000; + auto remaining_time_s = (bytesTotal - bytesReceived) / dl_speed_bps; + + //: Current amount of bytes downloaded, out of the total amount of bytes in the download + QString dl_progress = + tr("%1 / %2").arg(StringUtils::humanReadableFileSize(bytesReceived)).arg(StringUtils::humanReadableFileSize(bytesTotal)); + + QString dl_speed_str; + if (elapsed_ms.count() > 0) { + auto str_eta = bytesTotal > 0 ? Time::humanReadableDuration(remaining_time_s) : tr("unknown"); + //: Download speed, in bytes per second (remaining download time in parenthesis) + dl_speed_str = tr("%1 /s (%2)").arg(StringUtils::humanReadableFileSize(dl_speed_bps)).arg(str_eta); + } else { + //: Download speed at 0 bytes per second + dl_speed_str = tr("0 B/s"); + } + + setDetails(dl_progress + "\n" + dl_speed_str); + + setProgress(bytesReceived, bytesTotal); +} + +void NetRequest::downloadError(QNetworkReply::NetworkError error) +{ + if (error == QNetworkReply::OperationCanceledError) { + qCCritical(logCat) << getUid().toString() << "Aborted " << m_url.toString(); + m_state = State::Failed; + } else { + if (m_options & Option::AcceptLocalFiles) { + if (m_sink->hasLocalData()) { + m_state = State::Succeeded; + return; + } + } + // error happened during download. + qCCritical(logCat) << getUid().toString() << "Failed " << m_url.toString() << " with reason " << error; + m_state = State::Failed; + } +} + +void NetRequest::sslErrors(const QList<QSslError>& errors) +{ + int i = 1; + for (auto error : errors) { + qCCritical(logCat) << getUid().toString() << "Request" << m_url.toString() << "SSL Error #" << i << " : " << error.errorString(); + auto cert = error.certificate(); + qCCritical(logCat) << getUid().toString() << "Certificate in question:\n" << cert.toText(); + i++; + } +} + +auto NetRequest::handleRedirect() -> bool +{ + QUrl redirect = m_reply->header(QNetworkRequest::LocationHeader).toUrl(); + if (!redirect.isValid()) { + if (!m_reply->hasRawHeader("Location")) { + // no redirect -> it's fine to continue + return false; + } + // there is a Location header, but it's not correct. we need to apply some workarounds... + QByteArray redirectBA = m_reply->rawHeader("Location"); + if (redirectBA.size() == 0) { + // empty, yet present redirect header? WTF? + return false; + } + QString redirectStr = QString::fromUtf8(redirectBA); + + if (redirectStr.startsWith("//")) { + /* + * IF the URL begins with //, we need to insert the URL scheme. + * See: https://bugreports.qt.io/browse/QTBUG-41061 + * See: http://tools.ietf.org/html/rfc3986#section-4.2 + */ + redirectStr = m_reply->url().scheme() + ":" + redirectStr; + } else if (redirectStr.startsWith("/")) { + /* + * IF the URL begins with /, we need to process it as a relative URL + */ + auto url = m_reply->url(); + url.setPath(redirectStr, QUrl::TolerantMode); + redirectStr = url.toString(); + } + + /* + * Next, make sure the URL is parsed in tolerant mode. Qt doesn't parse the location header in tolerant mode, which causes issues. + * FIXME: report Qt bug for this + */ + redirect = QUrl(redirectStr, QUrl::TolerantMode); + if (!redirect.isValid()) { + qCWarning(logCat) << getUid().toString() << "Failed to parse redirect URL:" << redirectStr; + downloadError(QNetworkReply::ProtocolFailure); + return false; + } + qCDebug(logCat) << getUid().toString() << "Fixed location header:" << redirect; + } else { + qCDebug(logCat) << getUid().toString() << "Location header:" << redirect; + } + + m_url = QUrl(redirect.toString()); + qCDebug(logCat) << getUid().toString() << "Following redirect to " << m_url.toString(); + startAction(m_network); + + return true; +} + +void NetRequest::downloadFinished() +{ + // handle HTTP redirection first + if (handleRedirect()) { + qCDebug(logCat) << getUid().toString() << "Request redirected:" << m_url.toString(); + return; + } + + // if the download failed before this point ... + if (m_state == State::Succeeded) // pretend to succeed so we continue processing :) + { + qCDebug(logCat) << getUid().toString() << "Request failed but we are allowed to proceed:" << m_url.toString(); + m_sink->abort(); + m_reply.reset(); + emit succeeded(); + emit finished(); + return; + } else if (m_state == State::Failed) { + qCDebug(logCat) << getUid().toString() << "Request failed in previous step:" << m_url.toString(); + m_sink->abort(); + m_reply.reset(); + emit failed(""); + emit finished(); + return; + } else if (m_state == State::AbortedByUser) { + qCDebug(logCat) << getUid().toString() << "Request aborted in previous step:" << m_url.toString(); + m_sink->abort(); + m_reply.reset(); + emit aborted(); + emit finished(); + return; + } + + // make sure we got all the remaining data, if any + auto data = m_reply->readAll(); + if (data.size()) { + qCDebug(logCat) << getUid().toString() << "Writing extra" << data.size() << "bytes"; + m_state = m_sink->write(data); + if (m_state != State::Succeeded) { + qCDebug(logCat) << getUid().toString() << "Request failed to write:" << m_url.toString(); + m_sink->abort(); + emit failed(""); + emit finished(); + return; + } + } + + // otherwise, finalize the whole graph + m_state = m_sink->finalize(*m_reply.get()); + if (m_state != State::Succeeded) { + qCDebug(logCat) << getUid().toString() << "Request failed to finalize:" << m_url.toString(); + m_sink->abort(); + m_reply.reset(); + emit failed(""); + emit finished(); + return; + } + + m_reply.reset(); + qCDebug(logCat) << getUid().toString() << "Request succeeded:" << m_url.toString(); + emit succeeded(); + emit finished(); +} + +void NetRequest::downloadReadyRead() +{ + if (m_state == State::Running) { + auto data = m_reply->readAll(); + m_state = m_sink->write(data); + if (m_state == State::Failed) { + qCCritical(logCat) << getUid().toString() << "Failed to process response chunk"; + } + // qDebug() << "Request" << m_url.toString() << "gained" << data.size() << "bytes"; + } else { + qCCritical(logCat) << getUid().toString() << "Cannot write download data! illegal status " << m_status; + } +} + +auto NetRequest::abort() -> bool +{ + m_state = State::AbortedByUser; + if (m_reply) { +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15 + disconnect(m_reply.get(), &QNetworkReply::errorOccurred, nullptr, nullptr); +#else + disconnect(m_reply.get(), QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), nullptr, nullptr); +#endif + m_reply->abort(); + } + return true; +} + +} // namespace Net diff --git a/launcher/net/NetRequest.h b/launcher/net/NetRequest.h new file mode 100644 index 00000000..ee47ab2a --- /dev/null +++ b/launcher/net/NetRequest.h @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2022 flowln <flowlnlnln@gmail.com> + * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> + * Copyright (C) 2023 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <qloggingcategory.h> +#include <chrono> + +#include "NetAction.h" +#include "Sink.h" +#include "Validator.h" + +#include "QObjectPtr.h" +#include "net/Logging.h" + +namespace Net { +class NetRequest : public NetAction { + Q_OBJECT + protected: + explicit NetRequest() : NetAction() {} + + public: + using Ptr = shared_qobject_ptr<class NetRequest>; + enum class Option { NoOptions = 0, AcceptLocalFiles = 1, MakeEternal = 2 }; + Q_DECLARE_FLAGS(Options, Option) + + public: + ~NetRequest() override = default; + + void init() override {} + + public: + void addValidator(Validator* v); + auto abort() -> bool override; + auto canAbort() const -> bool override { return true; } + + private: + auto handleRedirect() -> bool; + virtual QNetworkReply* getReply(QNetworkRequest&) = 0; + + protected slots: + void downloadProgress(qint64 bytesReceived, qint64 bytesTotal) override; + void downloadError(QNetworkReply::NetworkError error) override; + void sslErrors(const QList<QSslError>& errors) override; + void downloadFinished() override; + void downloadReadyRead() override; + + public slots: + void executeTask() override; + + protected: + std::unique_ptr<Sink> m_sink; + Options m_options; + + typedef const QLoggingCategory& (*logCatFunc)(); + logCatFunc logCat = taskUploadLogC; + + std::chrono::steady_clock m_clock; + std::chrono::time_point<std::chrono::steady_clock> m_last_progress_time; + qint64 m_last_progress_bytes; +}; +} // namespace Net + +Q_DECLARE_OPERATORS_FOR_FLAGS(Net::NetRequest::Options) diff --git a/launcher/net/RawHeaderProxy.h b/launcher/net/RawHeaderProxy.h new file mode 100644 index 00000000..09b3d4d0 --- /dev/null +++ b/launcher/net/RawHeaderProxy.h @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2022 flowln <flowlnlnln@gmail.com> + * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> + * Copyright (C) 2023 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include "net/HeaderProxy.h" + +namespace Net { + +class RawHeaderProxy : public HeaderProxy { + public: + RawHeaderProxy() : HeaderProxy() {} + virtual ~RawHeaderProxy() = default; + + public: + virtual QList<HeaderPair> headers(const QNetworkRequest&) const override { return m_headers; }; + + void addHeader(const HeaderPair& header) { m_headers.append(header); } + void addHeader(const QByteArray& headerName, const QByteArray& headerValue) { m_headers.append({ headerName, headerValue }); } + void addHeaders(const QList<HeaderPair>& headers) { m_headers.append(headers); } + + private: + QList<HeaderPair> m_headers; +}; + +} // namespace Net diff --git a/launcher/net/Upload.cpp b/launcher/net/Upload.cpp index 3f6f5829..726572e5 100644 --- a/launcher/net/Upload.cpp +++ b/launcher/net/Upload.cpp @@ -38,219 +38,16 @@ #include "Upload.h" +#include <memory> #include <utility> -#include "Application.h" -#include "BuildConfig.h" #include "ByteArraySink.h" -#include "net/Logging.h" - namespace Net { -bool Upload::abort() -{ - if (m_reply) { - m_reply->abort(); - } else { - m_state = State::AbortedByUser; - } - return true; -} - -void Upload::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) -{ - setProgress(bytesReceived, bytesTotal); -} - -void Upload::downloadError(QNetworkReply::NetworkError error) -{ - if (error == QNetworkReply::OperationCanceledError) { - qCCritical(taskUploadLogC) << getUid().toString() << "Aborted " << m_url.toString(); - m_state = State::AbortedByUser; - } else { - // error happened during download. - qCCritical(taskUploadLogC) << getUid().toString() << "Failed " << m_url.toString() << " with reason " << error; - m_state = State::Failed; - } -} - -void Upload::sslErrors(const QList<QSslError>& errors) -{ - int i = 1; - for (const auto& error : errors) { - qCCritical(taskUploadLogC) << getUid().toString() << "Upload" << m_url.toString() << "SSL Error #" << i << " : " - << error.errorString(); - auto cert = error.certificate(); - qCCritical(taskUploadLogC) << getUid().toString() << "Certificate in question:\n" << cert.toText(); - i++; - } -} - -bool Upload::handleRedirect() -{ - QUrl redirect = m_reply->header(QNetworkRequest::LocationHeader).toUrl(); - if (!redirect.isValid()) { - if (!m_reply->hasRawHeader("Location")) { - // no redirect -> it's fine to continue - return false; - } - // there is a Location header, but it's not correct. we need to apply some workarounds... - QByteArray redirectBA = m_reply->rawHeader("Location"); - if (redirectBA.size() == 0) { - // empty, yet present redirect header? WTF? - return false; - } - QString redirectStr = QString::fromUtf8(redirectBA); - - if (redirectStr.startsWith("//")) { - /* - * IF the URL begins with //, we need to insert the URL scheme. - * See: https://bugreports.qt.io/browse/QTBUG-41061 - * See: http://tools.ietf.org/html/rfc3986#section-4.2 - */ - redirectStr = m_reply->url().scheme() + ":" + redirectStr; - } else if (redirectStr.startsWith("/")) { - /* - * IF the URL begins with /, we need to process it as a relative URL - */ - auto url = m_reply->url(); - url.setPath(redirectStr, QUrl::TolerantMode); - redirectStr = url.toString(); - } - - /* - * Next, make sure the URL is parsed in tolerant mode. Qt doesn't parse the location header in tolerant mode, which causes issues. - * FIXME: report Qt bug for this - */ - redirect = QUrl(redirectStr, QUrl::TolerantMode); - if (!redirect.isValid()) { - qCWarning(taskUploadLogC) << getUid().toString() << "Failed to parse redirect URL:" << redirectStr; - downloadError(QNetworkReply::ProtocolFailure); - return false; - } - qCDebug(taskUploadLogC) << getUid().toString() << "Fixed location header:" << redirect; - } else { - qCDebug(taskUploadLogC) << getUid().toString() << "Location header:" << redirect; - } - - m_url = QUrl(redirect.toString()); - qCDebug(taskUploadLogC) << getUid().toString() << "Following redirect to " << m_url.toString(); - startAction(m_network); - return true; -} - -void Upload::downloadFinished() -{ - // handle HTTP redirection first - // very unlikely for post requests, still can happen - if (handleRedirect()) { - qCDebug(taskUploadLogC) << getUid().toString() << "Upload redirected:" << m_url.toString(); - return; - } - - // if the download failed before this point ... - if (m_state == State::Succeeded) { - qCDebug(taskUploadLogC) << getUid().toString() << "Upload failed but we are allowed to proceed:" << m_url.toString(); - m_sink->abort(); - m_reply.reset(); - emit succeeded(); - return; - } else if (m_state == State::Failed) { - qCDebug(taskUploadLogC) << getUid().toString() << "Upload failed in previous step:" << m_url.toString(); - m_sink->abort(); - m_reply.reset(); - emit failed(""); - return; - } else if (m_state == State::AbortedByUser) { - qCDebug(taskUploadLogC) << getUid().toString() << "Upload aborted in previous step:" << m_url.toString(); - m_sink->abort(); - m_reply.reset(); - emit aborted(); - return; - } - - // make sure we got all the remaining data, if any - auto data = m_reply->readAll(); - if (data.size()) { - qCDebug(taskUploadLogC) << getUid().toString() << "Writing extra" << data.size() << "bytes"; - m_state = m_sink->write(data); - } - - // otherwise, finalize the whole graph - m_state = m_sink->finalize(*m_reply.get()); - if (m_state != State::Succeeded) { - qCDebug(taskUploadLogC) << getUid().toString() << "Upload failed to finalize:" << m_url.toString(); - m_sink->abort(); - m_reply.reset(); - emit failed(""); - return; - } - m_reply.reset(); - qCDebug(taskUploadLogC) << getUid().toString() << "Upload succeeded:" << m_url.toString(); - emit succeeded(); -} - -void Upload::downloadReadyRead() -{ - if (m_state == State::Running) { - auto data = m_reply->readAll(); - m_state = m_sink->write(data); - } -} - -void Upload::executeTask() +QNetworkReply* Upload::getReply(QNetworkRequest& request) { - setStatus(tr("Uploading %1").arg(m_url.toString())); - - if (m_state == State::AbortedByUser) { - qCWarning(taskUploadLogC) << getUid().toString() << "Attempt to start an aborted Upload:" << m_url.toString(); - emit aborted(); - return; - } - QNetworkRequest request(m_url); - m_state = m_sink->init(request); - switch (m_state) { - case State::Succeeded: - emitSucceeded(); - qCDebug(taskUploadLogC) << getUid().toString() << "Upload cache hit " << m_url.toString(); - return; - case State::Running: - qCDebug(taskUploadLogC) << getUid().toString() << "Uploading " << m_url.toString(); - break; - case State::Inactive: - case State::Failed: - emitFailed(""); - return; - case State::AbortedByUser: - emitAborted(); - return; - } - - request.setHeader(QNetworkRequest::UserAgentHeader, APPLICATION->getUserAgent().toUtf8()); - // TODO remove duplication - if (APPLICATION->capabilities() & Application::SupportsFlame && request.url().host() == QUrl(BuildConfig.FLAME_BASE_URL).host()) { - request.setRawHeader("x-api-key", APPLICATION->getFlameAPIKey().toUtf8()); - } else if (request.url().host() == QUrl(BuildConfig.MODRINTH_PROD_URL).host() || - request.url().host() == QUrl(BuildConfig.MODRINTH_STAGING_URL).host()) { - QString token = APPLICATION->getModrinthAPIToken(); - if (!token.isNull()) - request.setRawHeader("Authorization", token.toUtf8()); - } - - // TODO other types of post requests ? request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - QNetworkReply* rep = m_network->post(request, m_post_data); - - m_reply.reset(rep); - connect(rep, &QNetworkReply::downloadProgress, this, &Upload::downloadProgress); - connect(rep, &QNetworkReply::finished, this, &Upload::downloadFinished); -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15 - connect(rep, &QNetworkReply::errorOccurred, this, &Upload::downloadError); -#else - connect(rep, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), this, &Upload::downloadError); -#endif - connect(rep, &QNetworkReply::sslErrors, this, &Upload::sslErrors); - connect(rep, &QNetworkReply::readyRead, this, &Upload::downloadReadyRead); + return m_network->post(request, m_post_data); } Upload::Ptr Upload::makeByteArray(QUrl url, std::shared_ptr<QByteArray> output, QByteArray m_post_data) diff --git a/launcher/net/Upload.h b/launcher/net/Upload.h index 0b0c9497..f920e556 100644 --- a/launcher/net/Upload.h +++ b/launcher/net/Upload.h @@ -37,36 +37,21 @@ #pragma once -#include "NetAction.h" -#include "Sink.h" +#include "net/NetRequest.h" namespace Net { -class Upload : public NetAction { +class Upload : public NetRequest { Q_OBJECT - public: using Ptr = shared_qobject_ptr<Upload>; + explicit Upload() : NetRequest() { logCat = taskUploadLogC; }; static Upload::Ptr makeByteArray(QUrl url, std::shared_ptr<QByteArray> output, QByteArray m_post_data); - auto abort() -> bool override; - auto canAbort() const -> bool override { return true; }; - - protected slots: - void downloadProgress(qint64 bytesReceived, qint64 bytesTotal) override; - void downloadError(QNetworkReply::NetworkError error) override; - void sslErrors(const QList<QSslError>& errors) override; - void downloadFinished() override; - void downloadReadyRead() override; - public slots: - void executeTask() override; - - private: - std::unique_ptr<Sink> m_sink; + protected: + virtual QNetworkReply* getReply(QNetworkRequest&) override; QByteArray m_post_data; - - bool handleRedirect(); }; } // namespace Net diff --git a/launcher/net/Validator.h b/launcher/net/Validator.h index 33c4cfee..92ac6ea1 100644 --- a/launcher/net/Validator.h +++ b/launcher/net/Validator.h @@ -39,8 +39,8 @@ namespace Net { class Validator { public: /* con/des */ - Validator(){}; - virtual ~Validator(){}; + Validator() {} + virtual ~Validator() {} public: /* methods */ virtual bool init(QNetworkRequest& request) = 0; diff --git a/launcher/news/NewsEntry.cpp b/launcher/news/NewsEntry.cpp index cf6d3e46..ea25f2e5 100644 --- a/launcher/news/NewsEntry.cpp +++ b/launcher/news/NewsEntry.cpp @@ -39,14 +39,14 @@ inline QString childValue(const QDomElement& element, const QString& childName, { QDomNodeList nodes = element.elementsByTagName(childName); if (nodes.count() > 0) { - QDomElement element = nodes.at(0).toElement(); - return element.text(); + QDomElement elem = nodes.at(0).toElement(); + return elem.text(); } else { return defaultVal; } } -bool NewsEntry::fromXmlElement(const QDomElement& element, NewsEntry* entry, QString* errorMsg) +bool NewsEntry::fromXmlElement(const QDomElement& element, NewsEntry* entry, [[maybe_unused]] QString* errorMsg) { QString title = childValue(element, "title", tr("Untitled")); QString content = childValue(element, "content", tr("No content.")); diff --git a/launcher/pathmatcher/IPathMatcher.h b/launcher/pathmatcher/IPathMatcher.h index 8121de5c..cd612197 100644 --- a/launcher/pathmatcher/IPathMatcher.h +++ b/launcher/pathmatcher/IPathMatcher.h @@ -7,6 +7,6 @@ class IPathMatcher { typedef std::shared_ptr<IPathMatcher> Ptr; public: - virtual ~IPathMatcher(){}; + virtual ~IPathMatcher() {} virtual bool matches(const QString& string) const = 0; }; diff --git a/launcher/pathmatcher/RegexpMatcher.h b/launcher/pathmatcher/RegexpMatcher.h index fe4aee6a..a6a3e616 100644 --- a/launcher/pathmatcher/RegexpMatcher.h +++ b/launcher/pathmatcher/RegexpMatcher.h @@ -3,7 +3,7 @@ class RegexpMatcher : public IPathMatcher { public: - virtual ~RegexpMatcher(){}; + virtual ~RegexpMatcher() {} RegexpMatcher(const QString& regexp) { m_regexp.setPattern(regexp); diff --git a/launcher/resources/multimc/128x128/instances/forge.png b/launcher/resources/multimc/128x128/instances/forge.png Binary files differnew file mode 100644 index 00000000..d8ff79a5 --- /dev/null +++ b/launcher/resources/multimc/128x128/instances/forge.png diff --git a/launcher/resources/multimc/128x128/instances/liteloader.png b/launcher/resources/multimc/128x128/instances/liteloader.png Binary files differnew file mode 100644 index 00000000..646217de --- /dev/null +++ b/launcher/resources/multimc/128x128/instances/liteloader.png diff --git a/launcher/resources/multimc/multimc.qrc b/launcher/resources/multimc/multimc.qrc index 2c00f28f..8f079bb3 100644 --- a/launcher/resources/multimc/multimc.qrc +++ b/launcher/resources/multimc/multimc.qrc @@ -347,5 +347,10 @@ <file>scalable/export.svg</file> <file>scalable/launch.svg</file> <file>scalable/server.svg</file> + + <file>scalable/instances/quiltmc.svg</file> <!-- CC0 QuiltMC --> + <file>scalable/instances/fabricmc.svg</file> <!-- CC0 unascribed, https://github.com/FabricMC/community/blob/main/media/unascribed/README.md --> + <file>128x128/instances/forge.png</file> <!-- LGPL3 Forge Development LLC --> + <file>128x128/instances/liteloader.png</file> <!-- CC-BY-SA 4.0 LiteLoader --> </qresource> </RCC> diff --git a/launcher/resources/multimc/scalable/instances/fabricmc.svg b/launcher/resources/multimc/scalable/instances/fabricmc.svg new file mode 100644 index 00000000..7bfc7548 --- /dev/null +++ b/launcher/resources/multimc/scalable/instances/fabricmc.svg @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="128" + height="128" + version="1.1" + viewBox="0 0 33.867 33.867" + xml:space="preserve" + id="svg252" + sodipodi:docname="fabricmc.svg" + inkscape:version="1.2.2 (b0a8486541, 2022-12-01)" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"><defs + id="defs256" /><sodipodi:namedview + id="namedview254" + pagecolor="#ffffff" + bordercolor="#000000" + borderopacity="0.25" + inkscape:showpageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" + showgrid="false" + inkscape:zoom="2.8284271" + inkscape:cx="39.421203" + inkscape:cy="132.22897" + inkscape:window-width="2560" + inkscape:window-height="1386" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="g2166" /><g + id="g2166"><path + style="fill:#38342a;fill-opacity:1;stroke-width:0;stroke-linejoin:round" + d="m 16.9336,2.1165994 c 0.705567,0 1.411134,0 2.116701,0 0,0.7055667 0,1.4111333 0,2.1167 0.705566,0 1.411132,0 2.116698,0 0,0.7055665 0,1.4111331 0,2.1166996 0.705567,0 1.411134,0 2.116701,0 0,0.7055667 0,1.4111333 0,2.1167 0.705567,0 1.411133,0 2.1167,0 0,0.705567 0,1.411134 0,2.116701 0.705567,0 1.411133,0 2.1167,0 0,0.705567 0,1.411133 0,2.1167 0.705567,0 1.411133,0 2.1167,0 0,1.4111 0,2.8222 0,4.2333 -0.7056,-3.3e-5 -1.4112,-6.7e-5 -2.1168,-10e-5 0,0.705567 0,1.411133 0,2.1167 -1.4111,0 -2.8222,0 -4.2333,0 0,0.705567 0,1.411133 0,2.1167 -0.705567,0 -1.411134,0 -2.116701,0 0,0.705567 0,1.411133 0,2.1167 -0.705566,0 -1.411132,0 -2.116698,0 0,0.705567 0,1.411134 0,2.116701 -0.705567,0 -1.411134,0 -2.116701,0 -3.4e-5,1.411133 -6.7e-5,2.822266 -1.01e-4,4.233399 -0.705567,0 -1.411133,0 -2.1167,0 0,0.705567 0,1.411134 0,2.116701 -1.4111,0 -2.822199,0 -4.233299,0 3.4e-5,-0.705567 6.7e-5,-1.411134 1.01e-4,-2.116701 -0.705567,0 -1.411134,0 -2.116701,0 0,-0.705567 0,-1.411134 0,-2.116701 -0.705567,0 -1.411134,0 -2.116701,0 0,-0.705566 0,-1.411132 0,-2.116698 -0.705567,0 -1.411134,0 -2.116701,0 0,-0.705567 0,-1.411134 0,-2.116701 -0.705566,0 -1.411132,0 -2.116698,0 0,-1.4111 0,-2.8222 0,-4.2333 0.705566,0 1.411132,0 2.116698,0 0,-0.705567 0,-1.411133 0,-2.1167 0.705567,0 1.411134,0 2.116701,0 0,-0.705567 0,-1.411133 0,-2.1167 0.705567,0 1.411134,0 2.116701,0 0,-0.705567 0,-1.411133 0,-2.1167 0.705567,0 1.411134,0 2.116701,0 0,-0.705567 0,-1.411133 0,-2.1167 0.705566,0 1.411132,0 2.116698,0 0,-0.705567 0,-1.411134 0,-2.116701 0.705567,0 1.411134,0 2.116701,0 -3.4e-5,-1.4110999 -6.7e-5,-2.8221997 -1.01e-4,-4.2332996 0.705567,0 1.411134,0 2.116701,0 0,-0.7055667 0,-1.4111333 0,-2.1167 z" + id="path1587-0" /><rect + x="25.400299" + y="14.8166" + width="2.1166999" + height="2.1166999" + fill="#807a6d" + id="rect246-7" + style="stroke-width:0" /><path + id="path1670" + style="fill:#dbd0b4;fill-opacity:1;stroke-width:0;stroke-linejoin:round" + d="m 4.233501,21.166701 2.1167,-2.117 6.09e-4,-2.1165 2.1161,-10e-5 6.09e-4,-2.1166 2.116099,-10e-5 6.09e-4,-2.1166 h 2.115899 l 2.1168,-2.117 6.72e-4,-2.1164 2.1159,-10e-5 v 2.1167 l 2.1171,10e-5 -3.97e-4,2.1166 2.1171,1e-4 v 2.1167 l 2.1167,2.11665 -11.642055,11.642008" + sodipodi:nodetypes="cccccccccccccccccc" /><path + style="fill:#dbd0b4;fill-opacity:1;stroke-width:0;stroke-linejoin:round" + d="m 16.9336,4.2332985 c 0.705333,-6.65e-5 1.410667,-1.329e-4 2.116,-1.994e-4 0,0.7055666 0,1.4111333 0,2.1166999 0.7058,6.67e-5 1.411599,1.333e-4 2.117399,2e-4 -2.29e-4,0.7055 -4.59e-4,1.411 -6.88e-4,2.1165 0.7058,6.63e-5 1.4116,1.327e-4 2.1174,1.99e-4 -2.29e-4,0.7055003 -4.59e-4,1.4110007 -6.88e-4,2.116501 0.705567,0 1.411133,0 2.1167,0 -0.0492,0.747877 0.09844,1.542199 -0.07194,2.26148 -0.32867,0.65734 -0.65734,1.31468 -0.98601,1.97202 -0.429296,-0.748959 -0.696496,-1.614758 -1.230307,-2.288382 -2.059217,-2.059636 -4.118734,-4.1189729 -6.178143,-6.178418 9.3e-5,-0.7055335 1.87e-4,-1.411067 2.8e-4,-2.1166005 z" + id="path2115" /><path + d="m 12.700401,25.400025 h 2.1167 v 2.1167 h -2.1167 z m 2.1167,-4.2333 v 4.2333 h 2.1167 v -2.1167 h 2.1167 v -2.1167 c -1.411133,-1.9e-5 -2.822267,1.4e-5 -4.2334,10e-5 z m 6.35,-6.35 v 2.1167 h -2.1167 v 4.2333 h 2.1167 v -2.1167 h 2.1167 v -4.2333 z m 2.1167,-2.1167 h 2.1167 v 2.1167 h -2.1167 z m -2.1167,-2.1167 h 2.1167 v 2.1167 h -2.1167 z m -2.1167,-2.1167 h 2.1167 v 2.1167 h -2.1167 z m -2.1167,-2.1167 h 2.1167 v 2.1167 h -2.1167 z" + fill="#bcb29c" + id="path238-2" + style="stroke-width:0" + sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccc" /><path + d="m 10.583601,27.516801 c 0.705567,0 1.411133,0 2.1167,0 0,0.705567 0,1.411133 0,2.1167 -0.705567,0 -1.411133,0 -2.1167,0 0,-0.705567 0,-1.411133 0,-2.1167 z m -2.1167,-2.1167 c 0.7055667,0 1.4111333,0 2.1167,0 0,0.705567 0,1.411133 0,2.1167 -0.7055667,0 -1.4111333,0 -2.1167,0 0,-0.705567 0,-1.411133 0,-2.1167 z m -2.1167,-2.1167 c 0.7055667,0 1.4111333,0 2.1167,0 0,0.705567 0,1.411133 0,2.1167 -0.7055667,0 -1.4111333,0 -2.1167,0 0,-0.705567 0,-1.411133 0,-2.1167 z m -2.1167,-2.1167 c 0.7055667,0 1.4111333,0 2.1167,0 0,0.705567 0,1.411133 0,2.1167 -0.7055667,0 -1.4111333,0 -2.1167,0 0,-0.705567 0,-1.411133 0,-2.1167 z" + fill="#9a927e" + id="path240-6" + style="stroke-width:0" /><path + d="m 10.583701,25.400025 c 0.705567,0 1.411133,0 2.1167,0 0,0.705567 0,1.411133 0,2.1167 -0.705567,0 -1.411133,0 -2.1167,0 0,-0.705567 0,-1.411133 0,-2.1167 z m -2.1167,-2.1167 c 0.7055667,0 1.4111333,0 2.1167,0 0,0.705567 0,1.411133 0,2.1167 -0.7055667,0 -1.4111333,0 -2.1167,0 0,-0.705567 0,-1.411133 0,-2.1167 z m -2.1167,-2.1167 c 0.7055667,0 1.4111333,0 2.1167,0 0,0.705567 0,1.411133 0,2.1167 -0.7055667,0 -1.4111333,0 -2.1167,0 0,-0.705567 0,-1.411133 0,-2.1167 z m -2.1167,-2.1167 c 0.7055667,0 1.4111333,0 2.1167,0 0,0.705567 0,1.411133 0,2.1167 -0.7055667,0 -1.4111333,0 -2.1167,0 0,-0.705567 0,-1.411133 0,-2.1167 z" + fill="#aea694" + id="path244-1" + style="stroke-width:0" /><path + d="m 10.583751,16.933325 h 2.1167 v 2.1167 h -2.1167 z m 2.1167,2.1167 v 2.1167 h 4.2333 v -2.1167 z m 4.2333,-4.2333 v 2.1167 h 4.2333 v -2.1167 z m -2.1167,-2.1167 h 2.1167 v 2.1167 h -2.1167 z m -2.1167,-2.1167 h 2.1167 v 2.1167 h -2.1167 z" + fill="#c6bca5" + id="path248-8" + style="stroke-width:0" + sodipodi:nodetypes="ccccccccccccccccccccccccc" /></g></svg> diff --git a/launcher/resources/multimc/scalable/instances/quiltmc.svg b/launcher/resources/multimc/scalable/instances/quiltmc.svg new file mode 100644 index 00000000..a7aaca53 --- /dev/null +++ b/launcher/resources/multimc/scalable/instances/quiltmc.svg @@ -0,0 +1,98 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + id="Layer_1" + data-name="Layer 1" + viewBox="0 0 23.999999 23.999999" + version="1.1" + sodipodi:docname="quiltmc.svg" + width="24" + height="24" + inkscape:version="1.2.2 (b0a8486541, 2022-12-01)" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <sodipodi:namedview + id="namedview27" + pagecolor="#ffffff" + bordercolor="#000000" + borderopacity="0.25" + inkscape:showpageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" + showgrid="false" + inkscape:zoom="10.390684" + inkscape:cx="24.685575" + inkscape:cy="9.5277659" + inkscape:window-width="1499" + inkscape:window-height="749" + inkscape:window-x="100" + inkscape:window-y="118" + inkscape:window-maximized="0" + inkscape:current-layer="Layer_1" /> + <defs + id="defs4"> + <style + id="style2">.cls-1{fill:#1b112b;}.cls-2{fill:#9722ff;}.cls-3{fill:#dc29dd;}.cls-4{fill:#27a2fd;}.cls-5{fill:#34f;}</style> + </defs> + <rect + class="cls-1" + width="24" + height="24" + rx="5.9670944" + id="rect6" + x="0" + y="0" + style="stroke-width:0.0262717" /> + <path + class="cls-2" + d="M 8.53568,6.3874419 A 0.27217496,0.27217496 0 0 0 8.8075922,6.6593542 H 9.2699744 V 7.6928834 H 8.8075922 a 0.27191225,0.27191225 0 0 0 0,0.5438245 H 9.2699744 V 9.0293255 A 0.24091162,0.24091162 0 0 1 9.0290628,9.2702371 H 8.2364452 V 8.807855 a 0.27191225,0.27191225 0 0 0 -0.5438245,0 V 9.2702371 H 6.6590914 V 8.807855 a 0.27191224,0.27191224 0 0 0 -0.5438244,0 V 9.2702371 H 5.3226493 A 0.24117434,0.24117434 0 0 1 5.0817377,9.0293255 V 5.322912 A 0.24091162,0.24091162 0 0 1 5.3226493,5.0820004 H 9.0290628 A 0.2406489,0.2406489 0 0 1 9.2699744,5.322912 V 6.115267 H 8.8075922 A 0.27217496,0.27217496 0 0 0 8.53568,6.3874419 Z" + id="path8" + style="stroke-width:0.0262717" /> + <path + class="cls-3" + d="m 13.267216,6.3874419 a 0.27191224,0.27191224 0 0 0 0.271912,0.2719123 h 0.463696 v 1.0335292 h -0.462382 a 0.27191225,0.27191225 0 0 0 0,0.5438245 h 0.462382 V 9.0293255 A 0.24117434,0.24117434 0 0 1 13.761912,9.2702371 H 10.054973 A 0.24091162,0.24091162 0 0 1 9.8140616,9.0293255 V 8.2367079 h 0.4621194 a 0.27191225,0.27191225 0 1 0 0,-0.5438245 H 9.8140616 V 6.6593542 h 0.4621194 a 0.27217496,0.27217496 0 1 0 0,-0.5440872 H 9.8140616 V 5.322912 A 0.2406489,0.2406489 0 0 1 10.054973,5.0820004 h 3.706414 a 0.24091162,0.24091162 0 0 1 0.240911,0.2409116 v 0.792355 h -0.462382 a 0.27191224,0.27191224 0 0 0 -0.2727,0.2721749 z" + id="path10" + style="stroke-width:0.0262717" /> + <path + class="cls-4" + d="M 18.73436,5.322912 V 9.0293255 A 0.24091162,0.24091162 0 0 1 18.493448,9.2702371 H 17.70083 V 8.807855 a 0.27191224,0.27191224 0 0 0 -0.543824,0 V 9.2702371 H 16.123477 V 8.807855 a 0.27191251,0.27191251 0 0 0 -0.543825,0 V 9.2702371 H 14.787034 A 0.24117434,0.24117434 0 0 1 14.546123,9.0293255 V 8.2367079 h 0.462382 a 0.27191225,0.27191225 0 1 0 0,-0.5438245 H 14.546123 V 6.6593542 h 0.462382 a 0.27217496,0.27217496 0 0 0 0,-0.5440872 H 14.546123 V 5.322912 a 0.24091162,0.24091162 0 0 1 0.240911,-0.2409116 h 3.706414 A 0.2406489,0.2406489 0 0 1 18.73436,5.322912 Z" + id="path12" + style="stroke-width:0.0262717" /> + <path + class="cls-3" + d="m 9.2699744,10.054973 v 3.706414 A 0.2406489,0.2406489 0 0 1 9.0290628,14.002298 H 8.2364452 v -0.462382 a 0.27191225,0.27191225 0 1 0 -0.5438245,0 v 0.462908 H 6.6590914 v -0.462382 a 0.27191224,0.27191224 0 0 0 -0.5438244,0 v 0.462382 H 5.3226493 A 0.24091162,0.24091162 0 0 1 5.0817377,13.761912 V 10.054973 A 0.24117434,0.24117434 0 0 1 5.3226493,9.8140616 H 6.115267 v 0.4623824 a 0.27191224,0.27191224 0 0 0 0.5438244,0 V 9.8140616 h 1.0335293 v 0.4623824 a 0.27191225,0.27191225 0 1 0 0.5438245,0 V 9.8140616 h 0.7926176 a 0.24091162,0.24091162 0 0 1 0.2409116,0.2409114 z" + id="path14" + style="stroke-width:0.0262717" /> + <path + class="cls-4" + d="m 13.267216,11.119503 a 0.27191224,0.27191224 0 0 0 0.271912,0.271912 h 0.463696 v 1.03353 h -0.462382 a 0.27191224,0.27191224 0 0 0 0,0.543824 h 0.462382 v 0.792618 a 0.24091162,0.24091162 0 0 1 -0.240912,0.240911 h -0.793143 v -0.462382 a 0.27191224,0.27191224 0 1 0 -0.543824,0 v 0.462908 h -1.03353 v -0.462382 a 0.27217496,0.27217496 0 0 0 -0.544087,0 v 0.462382 H 10.054973 A 0.2406489,0.2406489 0 0 1 9.8140616,13.761912 V 10.054973 A 0.24091162,0.24091162 0 0 1 10.054973,9.8140616 h 3.706414 a 0.24117434,0.24117434 0 0 1 0.240911,0.2409114 v 0.792618 h -0.462382 a 0.27191224,0.27191224 0 0 0 -0.2727,0.271912 z" + id="path16" + style="stroke-width:0.0262717" /> + <path + class="cls-5" + d="m 18.73436,10.054973 v 3.706414 a 0.2406489,0.2406489 0 0 1 -0.240912,0.240911 h -3.706414 a 0.24091162,0.24091162 0 0 1 -0.240911,-0.240911 v -0.792618 h 0.462382 a 0.27191224,0.27191224 0 1 0 0,-0.543824 h -0.462382 v -1.03353 h 0.462382 a 0.27191224,0.27191224 0 0 0 0,-0.543824 h -0.462382 v -0.792618 a 0.24117434,0.24117434 0 0 1 0.240911,-0.2409114 h 0.792093 v 0.4623824 a 0.27191224,0.27191224 0 0 0 0.543824,0 V 9.8140616 h 1.033529 v 0.4623824 a 0.27191251,0.27191251 0 0 0 0.543825,0 V 9.8140616 h 0.792617 a 0.24091162,0.24091162 0 0 1 0.241438,0.2409114 z" + id="path18" + style="stroke-width:0.0262717" /> + <path + class="cls-2" + d="m 8.53568,15.851827 a 0.27217496,0.27217496 0 0 0 0.2719122,0.271912 h 0.4623822 v 1.033267 H 8.8075922 a 0.27217496,0.27217496 0 0 0 0,0.544087 h 0.4623822 v 0.792618 A 0.24091162,0.24091162 0 0 1 9.0290628,18.734622 H 5.3226493 A 0.24117434,0.24117434 0 0 1 5.0817377,18.493711 V 14.787297 A 0.24091162,0.24091162 0 0 1 5.3226493,14.546386 H 6.115267 v 0.462119 a 0.27191224,0.27191224 0 1 0 0.5438244,0 v -0.462119 h 1.0335293 v 0.462119 a 0.27191225,0.27191225 0 1 0 0.5438245,0 v -0.462119 h 0.7926176 a 0.2406489,0.2406489 0 0 1 0.2409116,0.240911 v 0.79183 H 8.8075922 a 0.27217496,0.27217496 0 0 0 -0.2719122,0.2727 z" + id="path20" + style="stroke-width:0.0262717" /> + <path + class="cls-5" + d="m 14.002824,14.787297 v 3.706414 a 0.24117434,0.24117434 0 0 1 -0.240912,0.240911 H 10.054973 A 0.24091162,0.24091162 0 0 1 9.8140616,18.493711 v -0.792618 h 0.4621194 a 0.27217496,0.27217496 0 1 0 0,-0.544087 H 9.8140616 v -1.033267 h 0.4621194 a 0.27217496,0.27217496 0 1 0 0,-0.544087 H 9.8140616 v -0.792355 a 0.2406489,0.2406489 0 0 1 0.2409114,-0.240911 h 0.792355 v 0.462119 a 0.27217496,0.27217496 0 1 0 0.544087,0 v -0.462119 h 1.03353 v 0.462119 a 0.27191224,0.27191224 0 1 0 0.543824,0 v -0.462119 h 0.792618 a 0.24091162,0.24091162 0 0 1 0.241437,0.240911 z" + id="path22" + style="stroke-width:0.0262717" /> + <rect + class="cls-2" + x="-2.0941913" + y="22.665482" + width="4.1882367" + height="4.1882367" + rx="0.24091162" + transform="rotate(-45)" + id="rect24" + style="stroke-width:0.0262717" /> +</svg> diff --git a/launcher/screenshots/ImgurAlbumCreation.cpp b/launcher/screenshots/ImgurAlbumCreation.cpp index d598d77e..d548c89a 100644 --- a/launcher/screenshots/ImgurAlbumCreation.cpp +++ b/launcher/screenshots/ImgurAlbumCreation.cpp @@ -81,7 +81,7 @@ void ImgurAlbumCreation::executeTask() connect(rep, &QNetworkReply::sslErrors, this, &ImgurAlbumCreation::sslErrors); } -void ImgurAlbumCreation::downloadError(QNetworkReply::NetworkError error) +void ImgurAlbumCreation::downloadError([[maybe_unused]] QNetworkReply::NetworkError error) { qDebug() << m_reply->errorString(); m_state = State::Failed; diff --git a/launcher/screenshots/ImgurAlbumCreation.h b/launcher/screenshots/ImgurAlbumCreation.h index 3a82a956..bb71bec2 100644 --- a/launcher/screenshots/ImgurAlbumCreation.h +++ b/launcher/screenshots/ImgurAlbumCreation.h @@ -50,6 +50,8 @@ class ImgurAlbumCreation : public NetAction { QString deleteHash() const { return m_deleteHash; } QString id() const { return m_id; } + void init() override{}; + protected slots: void downloadProgress(qint64 bytesReceived, qint64 bytesTotal) override; void downloadError(QNetworkReply::NetworkError error) override; diff --git a/launcher/screenshots/ImgurUpload.cpp b/launcher/screenshots/ImgurUpload.cpp index 706af7ba..29499a20 100644 --- a/launcher/screenshots/ImgurUpload.cpp +++ b/launcher/screenshots/ImgurUpload.cpp @@ -96,7 +96,7 @@ void ImgurUpload::executeTask() connect(rep, &QNetworkReply::sslErrors, this, &ImgurUpload::sslErrors); } -void ImgurUpload::downloadError(QNetworkReply::NetworkError error) +void ImgurUpload::downloadError([[maybe_unused]] QNetworkReply::NetworkError error) { qCritical() << "ImgurUpload failed with error" << m_reply->errorString() << "Server reply:\n" << m_reply->readAll(); if (finished) { diff --git a/launcher/screenshots/ImgurUpload.h b/launcher/screenshots/ImgurUpload.h index 8714e0c0..542255b2 100644 --- a/launcher/screenshots/ImgurUpload.h +++ b/launcher/screenshots/ImgurUpload.h @@ -44,6 +44,7 @@ class ImgurUpload : public NetAction { explicit ImgurUpload(ScreenShot::Ptr shot); static Ptr make(ScreenShot::Ptr shot) { return Ptr(new ImgurUpload(shot)); } + void init() override{}; protected slots: void downloadProgress(qint64 bytesReceived, qint64 bytesTotal) override; diff --git a/launcher/tasks/ConcurrentTask.cpp b/launcher/tasks/ConcurrentTask.cpp index efa16280..6cfd864c 100644 --- a/launcher/tasks/ConcurrentTask.cpp +++ b/launcher/tasks/ConcurrentTask.cpp @@ -173,7 +173,7 @@ void ConcurrentTask::subTaskSucceeded(Task::Ptr task) startNext(); } -void ConcurrentTask::subTaskFailed(Task::Ptr task, const QString& msg) +void ConcurrentTask::subTaskFailed(Task::Ptr task, [[maybe_unused]] const QString& msg) { m_done.insert(task.get(), task); m_failed.insert(task.get(), task); diff --git a/launcher/tasks/ConcurrentTask.h b/launcher/tasks/ConcurrentTask.h index 6325fc9e..8b696bf5 100644 --- a/launcher/tasks/ConcurrentTask.h +++ b/launcher/tasks/ConcurrentTask.h @@ -53,7 +53,7 @@ class ConcurrentTask : public Task { bool canAbort() const override { return true; } - inline auto isMultiStep() const -> bool override { return totalSize() > 1; }; + inline auto isMultiStep() const -> bool override { return totalSize() > 1; } auto getStepProgress() const -> TaskStepProgressList override; void addTask(Task::Ptr task); @@ -80,7 +80,7 @@ class ConcurrentTask : public Task { protected: // NOTE: This is not thread-safe. - [[nodiscard]] unsigned int totalSize() const { return m_queue.size() + m_doing.size() + m_done.size(); } + [[nodiscard]] unsigned int totalSize() const { return static_cast<unsigned int>(m_queue.size() + m_doing.size() + m_done.size()); } enum class Operation { ADDED, REMOVED, CHANGED }; void updateStepProgress(TaskStepProgress const& changed_progress, Operation); diff --git a/launcher/tasks/Task.h b/launcher/tasks/Task.h index 7e1defd8..94b4089f 100644 --- a/launcher/tasks/Task.h +++ b/launcher/tasks/Task.h @@ -59,16 +59,18 @@ struct TaskStepProgress { QString status = ""; QString details = ""; TaskStepState state = TaskStepState::Waiting; + TaskStepProgress() { this->uid = QUuid::createUuid(); } - TaskStepProgress(QUuid uid) { this->uid = uid; } + TaskStepProgress(QUuid uid_) : uid(uid_) {} + bool isDone() const { return (state == TaskStepState::Failed) || (state == TaskStepState::Succeeded); } - void update(qint64 current, qint64 total) + void update(qint64 new_current, qint64 new_total) { this->old_current = this->current; this->old_total = this->total; - this->current = current; - this->total = total; + this->current = new_current; + this->total = new_total; this->state = TaskStepState::Running; } }; @@ -150,7 +152,7 @@ class Task : public QObject, public QRunnable { if (canAbort()) emitAborted(); return canAbort(); - }; + } void setAbortable(bool can_abort) { diff --git a/launcher/tools/JProfiler.cpp b/launcher/tools/JProfiler.cpp index 3fa9e94e..7a532a3d 100644 --- a/launcher/tools/JProfiler.cpp +++ b/launcher/tools/JProfiler.cpp @@ -29,7 +29,7 @@ void JProfiler::profilerStarted() emit readyToLaunch(tr("Listening on port: %1").arg(listeningPort)); } -void JProfiler::profilerFinished(int exit, QProcess::ExitStatus status) +void JProfiler::profilerFinished([[maybe_unused]] int exit, QProcess::ExitStatus status) { if (status == QProcess::CrashExit) { emit abortLaunch(tr("Profiler aborted")); diff --git a/launcher/tools/JVisualVM.cpp b/launcher/tools/JVisualVM.cpp index 5f2762eb..4da4e1e5 100644 --- a/launcher/tools/JVisualVM.cpp +++ b/launcher/tools/JVisualVM.cpp @@ -27,7 +27,7 @@ void JVisualVM::profilerStarted() emit readyToLaunch(tr("JVisualVM started")); } -void JVisualVM::profilerFinished(int exit, QProcess::ExitStatus status) +void JVisualVM::profilerFinished([[maybe_unused]] int exit, QProcess::ExitStatus status) { if (status == QProcess::CrashExit) { emit abortLaunch(tr("Profiler aborted")); diff --git a/launcher/translations/POTranslator.cpp b/launcher/translations/POTranslator.cpp index 71d7878d..51ef4852 100644 --- a/launcher/translations/POTranslator.cpp +++ b/launcher/translations/POTranslator.cpp @@ -275,7 +275,7 @@ POTranslator::~POTranslator() delete d; } -QString POTranslator::translate(const char* context, const char* sourceText, const char* disambiguation, int n) const +QString POTranslator::translate(const char* context, const char* sourceText, const char* disambiguation, [[maybe_unused]] int n) const { if (disambiguation) { auto disambiguationKey = QByteArray(context) + "|" + QByteArray(sourceText) + "@" + QByteArray(disambiguation); diff --git a/launcher/translations/TranslationsModel.cpp b/launcher/translations/TranslationsModel.cpp index 06d5bfd8..933fe2d3 100644 --- a/launcher/translations/TranslationsModel.cpp +++ b/launcher/translations/TranslationsModel.cpp @@ -228,12 +228,11 @@ void readIndex(const QString& path, QMap<QString, Language>& languages) QByteArray data; try { data = FS::read(path); - } catch (const Exception& e) { + } catch ([[maybe_unused]] const Exception& e) { qCritical() << "Translations Download Failed: index file not readable"; return; } - int index = 1; try { auto toplevel_doc = Json::requireDocument(data); auto doc = Json::requireObject(toplevel_doc); @@ -259,9 +258,8 @@ void readIndex(const QString& path, QMap<QString, Language>& languages) lang.file_size = Json::requireInteger(langObj, "size"); languages.insert(lang.key, lang); - index++; } - } catch (Json::JsonException& e) { + } catch ([[maybe_unused]] Json::JsonException& e) { qCritical() << "Translations Download Failed: index file could not be parsed as json"; } } @@ -409,12 +407,12 @@ QVariant TranslationsModel::headerData(int section, Qt::Orientation orientation, return QAbstractListModel::headerData(section, orientation, role); } -int TranslationsModel::rowCount(const QModelIndex& parent) const +int TranslationsModel::rowCount([[maybe_unused]] const QModelIndex& parent) const { return d->m_languages.size(); } -int TranslationsModel::columnCount(const QModelIndex& parent) const +int TranslationsModel::columnCount([[maybe_unused]] const QModelIndex& parent) const { return 2; } diff --git a/launcher/ui/InstanceWindow.cpp b/launcher/ui/InstanceWindow.cpp index 9c7886fa..7025cb79 100644 --- a/launcher/ui/InstanceWindow.cpp +++ b/launcher/ui/InstanceWindow.cpp @@ -2,6 +2,7 @@ /* * Prism Launcher - Minecraft Launcher * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> + * Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -251,6 +252,11 @@ bool InstanceWindow::selectPage(QString pageId) return m_container->selectPage(pageId); } +BasePage* InstanceWindow::selectedPage() const +{ + return m_container->selectedPage(); +} + void InstanceWindow::refreshContainer() { m_container->refreshContainer(); diff --git a/launcher/ui/InstanceWindow.h b/launcher/ui/InstanceWindow.h index 508bcaa1..70f206f2 100644 --- a/launcher/ui/InstanceWindow.h +++ b/launcher/ui/InstanceWindow.h @@ -2,6 +2,7 @@ /* * Prism Launcher - Minecraft Launcher * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> + * Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -55,6 +56,7 @@ class InstanceWindow : public QMainWindow, public BasePageContainer { virtual ~InstanceWindow(); bool selectPage(QString pageId) override; + BasePage* selectedPage() const override; void refreshContainer() override; QString instanceId(); diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index e342e833..bb88d74e 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -515,9 +515,9 @@ void MainWindow::showInstanceContextMenu(const QPoint& pos) QAction* actionCreateInstance = new QAction(tr("Create instance"), this); actionCreateInstance->setToolTip(ui->actionAddInstance->toolTip()); if (!group.isNull()) { - QVariantMap data; - data["group"] = group; - actionCreateInstance->setData(data); + QVariantMap instance_action_data; + instance_action_data["group"] = group; + actionCreateInstance->setData(instance_action_data); } connect(actionCreateInstance, SIGNAL(triggered(bool)), SLOT(on_actionAddInstance_triggered())); @@ -527,9 +527,9 @@ void MainWindow::showInstanceContextMenu(const QPoint& pos) actions.append(actionCreateInstance); if (!group.isNull()) { QAction* actionDeleteGroup = new QAction(tr("Delete group '%1'").arg(group), this); - QVariantMap data; - data["group"] = group; - actionDeleteGroup->setData(data); + QVariantMap delete_group_action_data; + delete_group_action_data["group"] = group; + actionDeleteGroup->setData(delete_group_action_data); connect(actionDeleteGroup, SIGNAL(triggered(bool)), SLOT(deleteGroup())); actions.append(actionDeleteGroup); } @@ -744,9 +744,9 @@ void MainWindow::changeActiveAccount() if (sAction->data().type() != QVariant::Type::Int) return; - QVariant data = sAction->data(); + QVariant action_data = sAction->data(); bool valid = false; - int index = data.toInt(&valid); + int index = action_data.toInt(&valid); if (!valid) { index = -1; } @@ -1061,9 +1061,9 @@ void MainWindow::on_actionChangeInstIcon_triggered() void MainWindow::iconUpdated(QString icon) { if (icon == m_currentInstIcon) { - auto icon = APPLICATION->icons()->getIcon(m_currentInstIcon); - ui->actionChangeInstIcon->setIcon(icon); - changeIconButton->setIcon(icon); + auto new_icon = APPLICATION->icons()->getIcon(m_currentInstIcon); + ui->actionChangeInstIcon->setIcon(new_icon); + changeIconButton->setIcon(new_icon); } } @@ -1590,7 +1590,7 @@ void MainWindow::startTask(Task* task) task->start(); } -void MainWindow::instanceChanged(const QModelIndex& current, const QModelIndex& previous) +void MainWindow::instanceChanged(const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous) { if (!current.isValid()) { APPLICATION->settings()->set("SelectedInstance", QString()); @@ -1725,7 +1725,7 @@ void MainWindow::setInstanceActionsEnabled(bool enabled) ui->actionCreateInstanceShortcut->setEnabled(enabled); } -void MainWindow::refreshCurrentInstance(bool running) +void MainWindow::refreshCurrentInstance([[maybe_unused]] bool running) { auto current = view->selectionModel()->currentIndex(); instanceChanged(current, current); diff --git a/launcher/ui/dialogs/CopyInstanceDialog.cpp b/launcher/ui/dialogs/CopyInstanceDialog.cpp index 0e410027..8b2f5bb8 100644 --- a/launcher/ui/dialogs/CopyInstanceDialog.cpp +++ b/launcher/ui/dialogs/CopyInstanceDialog.cpp @@ -220,7 +220,7 @@ void CopyInstanceDialog::on_iconButton_clicked() } } -void CopyInstanceDialog::on_instNameTextBox_textChanged(const QString& arg1) +void CopyInstanceDialog::on_instNameTextBox_textChanged([[maybe_unused]] const QString& arg1) { updateDialogState(); } diff --git a/launcher/ui/dialogs/ExportInstanceDialog.cpp b/launcher/ui/dialogs/ExportInstanceDialog.cpp index d6a503cc..703736d6 100644 --- a/launcher/ui/dialogs/ExportInstanceDialog.cpp +++ b/launcher/ui/dialogs/ExportInstanceDialog.cpp @@ -195,8 +195,8 @@ void ExportInstanceDialog::loadPackIgnore() if (!ignoreFile.open(QIODevice::ReadOnly)) { return; } - auto data = ignoreFile.readAll(); - auto string = QString::fromUtf8(data); + auto ignoreData = ignoreFile.readAll(); + auto string = QString::fromUtf8(ignoreData); #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) proxyModel->setBlockedPaths(string.split('\n', Qt::SkipEmptyParts)); #else @@ -206,10 +206,10 @@ void ExportInstanceDialog::loadPackIgnore() void ExportInstanceDialog::savePackIgnore() { - auto data = proxyModel->blockedPaths().toStringList().join('\n').toUtf8(); + auto ignoreData = proxyModel->blockedPaths().toStringList().join('\n').toUtf8(); auto filename = ignoreFileName(); try { - FS::write(filename, data); + FS::write(filename, ignoreData); } catch (const Exception& e) { qWarning() << e.cause(); } diff --git a/launcher/ui/dialogs/InstallLoaderDialog.cpp b/launcher/ui/dialogs/InstallLoaderDialog.cpp new file mode 100644 index 00000000..840a328f --- /dev/null +++ b/launcher/ui/dialogs/InstallLoaderDialog.cpp @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "InstallLoaderDialog.h" + +#include <QDialogButtonBox> +#include <QPushButton> +#include <QVBoxLayout> +#include "Application.h" +#include "BuildConfig.h" +#include "DesktopServices.h" +#include "meta/Index.h" +#include "minecraft/MinecraftInstance.h" +#include "minecraft/PackProfile.h" +#include "ui/widgets/PageContainer.h" +#include "ui/widgets/VersionSelectWidget.h" + +class InstallLoaderPage : public VersionSelectWidget, public BasePage { + public: + InstallLoaderPage(const QString& id, + const QString& iconName, + const QString& name, + const Version& oldestVersion, + const std::shared_ptr<PackProfile> profile) + : VersionSelectWidget(nullptr), uid(id), iconName(iconName), name(name) + { + const QString minecraftVersion = profile->getComponentVersion("net.minecraft"); + setEmptyString(tr("No versions are currently available for Minecraft %1").arg(minecraftVersion)); + setExactIfPresentFilter(BaseVersionList::ParentVersionRole, minecraftVersion); + + if (oldestVersion != Version() && Version(minecraftVersion) < oldestVersion) + setExactFilter(BaseVersionList::ParentVersionRole, "AAA"); + + if (const QString currentVersion = profile->getComponentVersion(id); !currentVersion.isNull()) + setCurrentVersion(currentVersion); + } + + QString id() const override { return uid; } + QString displayName() const override { return name; } + QIcon icon() const override { return APPLICATION->getThemedIcon(iconName); } + + void openedImpl() override + { + if (loaded) + return; + + const auto versions = APPLICATION->metadataIndex()->get(uid); + if (!versions) + return; + + initialize(versions.get()); + loaded = true; + } + + void setParentContainer(BasePageContainer* container) override + { + auto dialog = dynamic_cast<QDialog*>(dynamic_cast<PageContainer*>(container)->parent()); + connect(view(), &QAbstractItemView::doubleClicked, dialog, &QDialog::accept); + } + + private: + const QString uid; + const QString iconName; + const QString name; + bool loaded = false; +}; + +static InstallLoaderPage* pageCast(BasePage* page) +{ + auto result = dynamic_cast<InstallLoaderPage*>(page); + Q_ASSERT(result != nullptr); + return result; +} + +InstallLoaderDialog::InstallLoaderDialog(std::shared_ptr<PackProfile> profile, const QString& uid, QWidget* parent) + : QDialog(parent), profile(std::move(profile)), container(new PageContainer(this, QString(), this)), buttons(new QDialogButtonBox(this)) +{ + auto layout = new QVBoxLayout(this); + + container->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); + layout->addWidget(container); + + auto buttonLayout = new QHBoxLayout(this); + + auto refreshButton = new QPushButton(tr("&Refresh"), this); + connect(refreshButton, &QPushButton::clicked, this, [this] { pageCast(container->selectedPage())->loadList(); }); + buttonLayout->addWidget(refreshButton); + + buttons->setOrientation(Qt::Horizontal); + buttons->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok); + connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); + buttonLayout->addWidget(buttons); + + layout->addLayout(buttonLayout); + + setWindowTitle(dialogTitle()); + setWindowModality(Qt::WindowModal); + resize(520, 347); + + for (BasePage* page : container->getPages()) { + if (page->id() == uid) + container->selectPage(page->id()); + + connect(pageCast(page), &VersionSelectWidget::selectedVersionChanged, this, [this, page] { + if (page->id() == container->selectedPage()->id()) + validate(container->selectedPage()); + }); + } + connect(container, &PageContainer::selectedPageChanged, this, [this](BasePage* previous, BasePage* current) { validate(current); }); + pageCast(container->selectedPage())->selectSearch(); + validate(container->selectedPage()); +} + +QList<BasePage*> InstallLoaderDialog::getPages() +{ + return { // Forge + new InstallLoaderPage("net.minecraftforge", "forge", tr("Forge"), {}, profile), + // Fabric + new InstallLoaderPage("net.fabricmc.fabric-loader", "fabricmc", tr("Fabric"), Version("1.14"), profile), + // Quilt + new InstallLoaderPage("org.quiltmc.quilt-loader", "quiltmc", tr("Quilt"), Version("1.14"), profile), + // LiteLoader + new InstallLoaderPage("com.mumfrey.liteloader", "liteloader", tr("LiteLoader"), {}, profile) + }; +} + +QString InstallLoaderDialog::dialogTitle() +{ + return tr("Install Loader"); +} + +void InstallLoaderDialog::validate(BasePage* page) +{ + buttons->button(QDialogButtonBox::Ok)->setEnabled(pageCast(page)->selectedVersion() != nullptr); +} + +void InstallLoaderDialog::done(int result) +{ + if (result == Accepted) { + auto* page = pageCast(container->selectedPage()); + if (page->selectedVersion()) { + profile->setComponentVersion(page->id(), page->selectedVersion()->descriptor()); + profile->resolve(Net::Mode::Online); + } + } + + QDialog::done(result); +} diff --git a/launcher/ui/dialogs/InstallLoaderDialog.h b/launcher/ui/dialogs/InstallLoaderDialog.h new file mode 100644 index 00000000..86cb3bdd --- /dev/null +++ b/launcher/ui/dialogs/InstallLoaderDialog.h @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <QDialog> +#include "ui/pages/BasePageProvider.h" + +class MinecraftInstance; +class PageContainer; +class PackProfile; +class QDialogButtonBox; + +class InstallLoaderDialog final : public QDialog, protected BasePageProvider { + Q_OBJECT + + public: + explicit InstallLoaderDialog(std::shared_ptr<PackProfile> instance, const QString& uid = QString(), QWidget* parent = nullptr); + + QList<BasePage*> getPages() override; + QString dialogTitle() override; + + void validate(BasePage* page); + void done(int result) override; + + private: + std::shared_ptr<PackProfile> profile; + PageContainer* container; + QDialogButtonBox* buttons; +}; diff --git a/launcher/ui/dialogs/NewInstanceDialog.cpp b/launcher/ui/dialogs/NewInstanceDialog.cpp index 6e5a41ef..1daaa3ce 100644 --- a/launcher/ui/dialogs/NewInstanceDialog.cpp +++ b/launcher/ui/dialogs/NewInstanceDialog.cpp @@ -290,7 +290,7 @@ void NewInstanceDialog::on_iconButton_clicked() } } -void NewInstanceDialog::on_instNameTextBox_textChanged(const QString& arg1) +void NewInstanceDialog::on_instNameTextBox_textChanged([[maybe_unused]] const QString& arg1) { updateDialogState(); } @@ -299,7 +299,7 @@ void NewInstanceDialog::importIconNow() { if (importIcon) { APPLICATION->icons()->installIcon(importIconPath, importIconName); - InstIconKey = importIconName; + InstIconKey = importIconName.mid(0, importIconName.lastIndexOf('.')); importIcon = false; } APPLICATION->settings()->set("NewInstanceGeometry", saveGeometry().toBase64()); diff --git a/launcher/ui/dialogs/ProfileSetupDialog.cpp b/launcher/ui/dialogs/ProfileSetupDialog.cpp index d7758d6d..4b0c5b76 100644 --- a/launcher/ui/dialogs/ProfileSetupDialog.cpp +++ b/launcher/ui/dialogs/ProfileSetupDialog.cpp @@ -163,13 +163,15 @@ void ProfileSetupDialog::checkName(const QString& name) requestor->get(request); } -void ProfileSetupDialog::checkFinished(QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers) +void ProfileSetupDialog::checkFinished(QNetworkReply::NetworkError error, + QByteArray profileData, + [[maybe_unused]] QList<QNetworkReply::RawHeaderPair> headers) { auto requestor = qobject_cast<AuthRequest*>(QObject::sender()); requestor->deleteLater(); if (error == QNetworkReply::NoError) { - auto doc = QJsonDocument::fromJson(data); + auto doc = QJsonDocument::fromJson(profileData); auto root = doc.object(); auto statusValue = root.value("status").toString("INVALID"); if (statusValue == "AVAILABLE") { @@ -202,11 +204,11 @@ void ProfileSetupDialog::setupProfile(const QString& profileName) request.setRawHeader("Authorization", QString("Bearer %1").arg(token).toUtf8()); QString payloadTemplate("{\"profileName\":\"%1\"}"); - auto data = payloadTemplate.arg(profileName).toUtf8(); + auto profileData = payloadTemplate.arg(profileName).toUtf8(); AuthRequest* requestor = new AuthRequest(this); connect(requestor, &AuthRequest::finished, this, &ProfileSetupDialog::setupProfileFinished); - requestor->post(request, data); + requestor->post(request, profileData); isWorking = true; auto button = ui->buttonBox->button(QDialogButtonBox::Cancel); @@ -243,8 +245,8 @@ struct MojangError { } // namespace void ProfileSetupDialog::setupProfileFinished(QNetworkReply::NetworkError error, - QByteArray data, - QList<QNetworkReply::RawHeaderPair> headers) + QByteArray errorData, + [[maybe_unused]] QList<QNetworkReply::RawHeaderPair> headers) { auto requestor = qobject_cast<AuthRequest*>(QObject::sender()); requestor->deleteLater(); @@ -257,7 +259,7 @@ void ProfileSetupDialog::setupProfileFinished(QNetworkReply::NetworkError error, */ accept(); } else { - auto parsedError = MojangError::fromJSON(data); + auto parsedError = MojangError::fromJSON(errorData); ui->errorLabel->setVisible(true); ui->errorLabel->setText(tr("The server returned the following error:") + "\n\n" + parsedError.errorMessage); qDebug() << parsedError.rawError; diff --git a/launcher/ui/dialogs/ProgressDialog.cpp b/launcher/ui/dialogs/ProgressDialog.cpp index ba22e334..0ca3a1bd 100644 --- a/launcher/ui/dialogs/ProgressDialog.cpp +++ b/launcher/ui/dialogs/ProgressDialog.cpp @@ -85,7 +85,7 @@ void ProgressDialog::on_skipButton_clicked(bool checked) { Q_UNUSED(checked); if (ui->skipButton->isEnabled()) // prevent other triggers from aborting - task->abort(); + m_task->abort(); } ProgressDialog::~ProgressDialog() @@ -127,7 +127,7 @@ void ProgressDialog::updateSize(bool recenterParent) int ProgressDialog::execWithTask(Task* task) { - this->task = task; + this->m_task = task; if (!task) { qDebug() << "Programmer error: Progress dialog created with null task."; @@ -179,8 +179,8 @@ int ProgressDialog::execWithTask(std::unique_ptr<Task>& task) bool ProgressDialog::handleImmediateResult(QDialog::DialogCode& result) { - if (task->isFinished()) { - if (task->wasSuccessful()) { + if (m_task->isFinished()) { + if (m_task->wasSuccessful()) { result = QDialog::Accepted; } else { result = QDialog::Rejected; @@ -192,12 +192,12 @@ bool ProgressDialog::handleImmediateResult(QDialog::DialogCode& result) Task* ProgressDialog::getTask() { - return task; + return m_task; } void ProgressDialog::onTaskStarted() {} -void ProgressDialog::onTaskFailed(QString failure) +void ProgressDialog::onTaskFailed([[maybe_unused]] QString failure) { reject(); hide(); @@ -209,11 +209,11 @@ void ProgressDialog::onTaskSucceeded() hide(); } -void ProgressDialog::changeStatus(const QString& status) +void ProgressDialog::changeStatus([[maybe_unused]] const QString& status) { - ui->globalStatusLabel->setText(task->getStatus()); + ui->globalStatusLabel->setText(m_task->getStatus()); ui->globalStatusLabel->adjustSize(); - ui->globalStatusDetailsLabel->setText(task->getDetails()); + ui->globalStatusDetailsLabel->setText(m_task->getDetails()); ui->globalStatusDetailsLabel->adjustSize(); updateSize(); @@ -279,7 +279,7 @@ void ProgressDialog::keyPressEvent(QKeyEvent* e) void ProgressDialog::closeEvent(QCloseEvent* e) { - if (task && task->isRunning()) { + if (m_task && m_task->isRunning()) { e->ignore(); } else { QDialog::closeEvent(e); diff --git a/launcher/ui/dialogs/ProgressDialog.h b/launcher/ui/dialogs/ProgressDialog.h index 82067271..15eadf4e 100644 --- a/launcher/ui/dialogs/ProgressDialog.h +++ b/launcher/ui/dialogs/ProgressDialog.h @@ -92,7 +92,7 @@ class ProgressDialog : public QDialog { private: Ui::ProgressDialog* ui; - Task* task; + Task* m_task; bool m_is_multi_step = false; QHash<QUuid, SubTaskProgressBar*> taskProgress; diff --git a/launcher/ui/dialogs/ResourceDownloadDialog.cpp b/launcher/ui/dialogs/ResourceDownloadDialog.cpp index b17eced3..4b82c0c5 100644 --- a/launcher/ui/dialogs/ResourceDownloadDialog.cpp +++ b/launcher/ui/dialogs/ResourceDownloadDialog.cpp @@ -2,7 +2,7 @@ /* * Prism Launcher - Minecraft Launcher * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> - * Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me> + * Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -209,15 +209,17 @@ bool ResourceDownloadDialog::selectPage(QString pageId) return m_container->selectPage(pageId); } -ResourcePage* ResourceDownloadDialog::getSelectedPage() +ResourcePage* ResourceDownloadDialog::selectedPage() { - return m_selectedPage; + ResourcePage* result = dynamic_cast<ResourcePage*>(m_container->selectedPage()); + Q_ASSERT(result != nullptr); + return result; } void ResourceDownloadDialog::addResource(ModPlatform::IndexedPack::Ptr pack, ModPlatform::IndexedVersion& ver) { removeResource(pack->name); - m_selectedPage->addResourceToPage(pack, ver, getBaseModel()); + selectedPage()->addResourceToPage(pack, ver, getBaseModel()); setButtonStatus(); } @@ -257,14 +259,8 @@ void ResourceDownloadDialog::selectedPageChanged(BasePage* previous, BasePage* s return; } - m_selectedPage = dynamic_cast<ResourcePage*>(selected); - if (!m_selectedPage) { - qCritical() << "Page '" << selected->displayName() << "' in ResourceDownloadDialog is not a ResourcePage!"; - return; - } - // Same effect as having a global search bar - m_selectedPage->setSearchTerm(prev_page->getSearchTerm()); + selectedPage()->setSearchTerm(prev_page->getSearchTerm()); } ModDownloadDialog::ModDownloadDialog(QWidget* parent, const std::shared_ptr<ModFolderModel>& mods, BaseInstance* instance) @@ -290,8 +286,6 @@ QList<BasePage*> ModDownloadDialog::getPages() if (APPLICATION->capabilities() & Application::SupportsFlame && FlameAPI::validateModLoaders(loaders)) pages.append(FlameModPage::create(this, *m_instance)); - m_selectedPage = dynamic_cast<ModPage*>(pages[0]); - return pages; } @@ -306,7 +300,7 @@ GetModDependenciesTask::Ptr ModDownloadDialog::getModDependenciesTask() return makeShared<GetModDependenciesTask>(this, m_instance, model, selectedVers); } return nullptr; -}; +} ResourcePackDownloadDialog::ResourcePackDownloadDialog(QWidget* parent, const std::shared_ptr<ResourcePackFolderModel>& resource_packs, @@ -330,8 +324,6 @@ QList<BasePage*> ResourcePackDownloadDialog::getPages() if (APPLICATION->capabilities() & Application::SupportsFlame) pages.append(FlameResourcePackPage::create(this, *m_instance)); - m_selectedPage = dynamic_cast<ResourcePackResourcePage*>(pages[0]); - return pages; } @@ -357,8 +349,6 @@ QList<BasePage*> TexturePackDownloadDialog::getPages() if (APPLICATION->capabilities() & Application::SupportsFlame) pages.append(FlameTexturePackPage::create(this, *m_instance)); - m_selectedPage = dynamic_cast<TexturePackResourcePage*>(pages[0]); - return pages; } @@ -379,11 +369,7 @@ ShaderPackDownloadDialog::ShaderPackDownloadDialog(QWidget* parent, QList<BasePage*> ShaderPackDownloadDialog::getPages() { QList<BasePage*> pages; - pages.append(ModrinthShaderPackPage::create(this, *m_instance)); - - m_selectedPage = dynamic_cast<ShaderPackResourcePage*>(pages[0]); - return pages; } diff --git a/launcher/ui/dialogs/ResourceDownloadDialog.h b/launcher/ui/dialogs/ResourceDownloadDialog.h index f65daaa3..e9d2cfbe 100644 --- a/launcher/ui/dialogs/ResourceDownloadDialog.h +++ b/launcher/ui/dialogs/ResourceDownloadDialog.h @@ -2,7 +2,7 @@ /* * Prism Launcher - Minecraft Launcher * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> - * Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me> + * Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -61,7 +61,7 @@ class ResourceDownloadDialog : public QDialog, public BasePageProvider { QString dialogTitle() override { return tr("Download %1").arg(resourcesString()); }; bool selectPage(QString pageId); - ResourcePage* getSelectedPage(); + ResourcePage* selectedPage(); void addResource(ModPlatform::IndexedPack::Ptr, ModPlatform::IndexedVersion&); void removeResource(const QString&); @@ -88,7 +88,6 @@ class ResourceDownloadDialog : public QDialog, public BasePageProvider { const std::shared_ptr<ResourceFolderModel> m_base_model; PageContainer* m_container = nullptr; - ResourcePage* m_selectedPage = nullptr; QDialogButtonBox m_buttons; QVBoxLayout m_vertical_layout; diff --git a/launcher/ui/dialogs/ReviewMessageBox.cpp b/launcher/ui/dialogs/ReviewMessageBox.cpp index 7b33765f..78c2542f 100644 --- a/launcher/ui/dialogs/ReviewMessageBox.cpp +++ b/launcher/ui/dialogs/ReviewMessageBox.cpp @@ -5,7 +5,7 @@ #include <QPushButton> -ReviewMessageBox::ReviewMessageBox(QWidget* parent, QString const& title, QString const& icon) +ReviewMessageBox::ReviewMessageBox(QWidget* parent, [[maybe_unused]] QString const& title, [[maybe_unused]] QString const& icon) : QDialog(parent), ui(new Ui::ReviewMessageBox) { ui->setupUi(this); diff --git a/launcher/ui/dialogs/SkinUploadDialog.cpp b/launcher/ui/dialogs/SkinUploadDialog.cpp index 8f0c8fa4..5b3ebfa2 100644 --- a/launcher/ui/dialogs/SkinUploadDialog.cpp +++ b/launcher/ui/dialogs/SkinUploadDialog.cpp @@ -133,15 +133,15 @@ SkinUploadDialog::SkinUploadDialog(MinecraftAccountPtr acct, QWidget* parent) : ui->setupUi(this); // FIXME: add a model for this, download/refresh the capes on demand - auto& data = *acct->accountData(); + auto& accountData = *acct->accountData(); int index = 0; ui->capeCombo->addItem(tr("No Cape"), QVariant()); - auto currentCape = data.minecraftProfile.currentCape; + auto currentCape = accountData.minecraftProfile.currentCape; if (currentCape.isEmpty()) { ui->capeCombo->setCurrentIndex(index); } - for (auto& cape : data.minecraftProfile.capes) { + for (auto& cape : accountData.minecraftProfile.capes) { index++; if (cape.data.size()) { QPixmap capeImage; diff --git a/launcher/ui/dialogs/SkinUploadDialog.ui b/launcher/ui/dialogs/SkinUploadDialog.ui index c7b16645..2c81a7fe 100644 --- a/launcher/ui/dialogs/SkinUploadDialog.ui +++ b/launcher/ui/dialogs/SkinUploadDialog.ui @@ -42,7 +42,7 @@ </size> </property> <property name="text"> - <string notr="true">...</string> + <string>Browse</string> </property> </widget> </item> diff --git a/launcher/ui/dialogs/VersionSelectDialog.cpp b/launcher/ui/dialogs/VersionSelectDialog.cpp index 61254c46..c61d1057 100644 --- a/launcher/ui/dialogs/VersionSelectDialog.cpp +++ b/launcher/ui/dialogs/VersionSelectDialog.cpp @@ -54,7 +54,7 @@ VersionSelectDialog::VersionSelectDialog(BaseVersionList* vlist, QString title, m_verticalLayout = new QVBoxLayout(this); m_verticalLayout->setObjectName(QStringLiteral("verticalLayout")); - m_versionWidget = new VersionSelectWidget(true, parent); + m_versionWidget = new VersionSelectWidget(parent); m_verticalLayout->addWidget(m_versionWidget); m_horizontalLayout = new QHBoxLayout(); @@ -74,8 +74,9 @@ VersionSelectDialog::VersionSelectDialog(BaseVersionList* vlist, QString title, retranslate(); - QObject::connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - QObject::connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(m_versionWidget->view(), &QAbstractItemView::doubleClicked, this, &QDialog::accept); + connect(m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); QMetaObject::connectSlotsByName(this); setWindowModality(Qt::WindowModal); @@ -121,6 +122,7 @@ int VersionSelectDialog::exec() { QDialog::open(); m_versionWidget->initialize(m_vlist); + m_versionWidget->selectSearch(); if (resizeOnColumn != -1) { m_versionWidget->setResizeOn(resizeOnColumn); } @@ -147,6 +149,11 @@ void VersionSelectDialog::setExactFilter(BaseVersionList::ModelRoles role, QStri m_versionWidget->setExactFilter(role, filter); } +void VersionSelectDialog::setExactIfPresentFilter(BaseVersionList::ModelRoles role, QString filter) +{ + m_versionWidget->setExactIfPresentFilter(role, filter); +} + void VersionSelectDialog::setFuzzyFilter(BaseVersionList::ModelRoles role, QString filter) { m_versionWidget->setFuzzyFilter(role, filter); diff --git a/launcher/ui/dialogs/VersionSelectDialog.h b/launcher/ui/dialogs/VersionSelectDialog.h index 701020fa..0ccd45e7 100644 --- a/launcher/ui/dialogs/VersionSelectDialog.h +++ b/launcher/ui/dialogs/VersionSelectDialog.h @@ -46,6 +46,7 @@ class VersionSelectDialog : public QDialog { void setCurrentVersion(const QString& version); void setFuzzyFilter(BaseVersionList::ModelRoles role, QString filter); void setExactFilter(BaseVersionList::ModelRoles role, QString filter); + void setExactIfPresentFilter(BaseVersionList::ModelRoles role, QString filter); void setEmptyString(QString emptyString); void setEmptyErrorString(QString emptyErrorString); void setResizeOn(int column); diff --git a/launcher/ui/instanceview/InstanceDelegate.cpp b/launcher/ui/instanceview/InstanceDelegate.cpp index 915b41d8..d947163b 100644 --- a/launcher/ui/instanceview/InstanceDelegate.cpp +++ b/launcher/ui/instanceview/InstanceDelegate.cpp @@ -367,7 +367,9 @@ class NoReturnTextEdit : public QTextEdit { void editingDone(); }; -void ListViewDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const +void ListViewDelegate::updateEditorGeometry(QWidget* editor, + const QStyleOptionViewItem& option, + [[maybe_unused]] const QModelIndex& index) const { const int iconSize = 48; QRect textRect = option.rect; @@ -379,17 +381,17 @@ void ListViewDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionV void ListViewDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const { auto text = index.data(Qt::EditRole).toString(); - QTextEdit* realeditor = qobject_cast<NoReturnTextEdit*>(editor); - realeditor->setAlignment(Qt::AlignHCenter | Qt::AlignTop); - realeditor->append(text); - realeditor->selectAll(); - realeditor->document()->clearUndoRedoStacks(); + QTextEdit* realEditor = qobject_cast<NoReturnTextEdit*>(editor); + realEditor->setAlignment(Qt::AlignHCenter | Qt::AlignTop); + realEditor->append(text); + realEditor->selectAll(); + realEditor->document()->clearUndoRedoStacks(); } void ListViewDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const { - QTextEdit* realeditor = qobject_cast<NoReturnTextEdit*>(editor); - QString text = realeditor->toPlainText(); + QTextEdit* realEditor = qobject_cast<NoReturnTextEdit*>(editor); + QString text = realEditor->toPlainText(); text.replace(QChar('\n'), QChar(' ')); text = text.trimmed(); // Prevent instance names longer than 128 chars @@ -399,7 +401,9 @@ void ListViewDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, } } -QWidget* ListViewDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const +QWidget* ListViewDelegate::createEditor(QWidget* parent, + [[maybe_unused]] const QStyleOptionViewItem& option, + [[maybe_unused]] const QModelIndex& index) const { auto editor = new NoReturnTextEdit(parent); connect(editor, &NoReturnTextEdit::editingDone, this, &ListViewDelegate::editingDone); diff --git a/launcher/ui/instanceview/InstanceView.cpp b/launcher/ui/instanceview/InstanceView.cpp index a9442546..607f3cad 100644 --- a/launcher/ui/instanceview/InstanceView.cpp +++ b/launcher/ui/instanceview/InstanceView.cpp @@ -86,16 +86,18 @@ void InstanceView::setModel(QAbstractItemModel* model) connect(model, &QAbstractItemModel::rowsRemoved, this, &InstanceView::rowsRemoved); } -void InstanceView::dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles) +void InstanceView::dataChanged([[maybe_unused]] const QModelIndex& topLeft, + [[maybe_unused]] const QModelIndex& bottomRight, + [[maybe_unused]] const QVector<int>& roles) { scheduleDelayedItemsLayout(); } -void InstanceView::rowsInserted(const QModelIndex& parent, int start, int end) +void InstanceView::rowsInserted([[maybe_unused]] const QModelIndex& parent, [[maybe_unused]] int start, [[maybe_unused]] int end) { scheduleDelayedItemsLayout(); } -void InstanceView::rowsAboutToBeRemoved(const QModelIndex& parent, int start, int end) +void InstanceView::rowsAboutToBeRemoved([[maybe_unused]] const QModelIndex& parent, [[maybe_unused]] int start, [[maybe_unused]] int end) { scheduleDelayedItemsLayout(); } @@ -239,9 +241,9 @@ QString InstanceView::groupNameAt(const QPoint& point) { executeDelayedItemsLayout(); - VisualGroup::HitResults hitresult; - auto group = categoryAt(point + offset(), hitresult); - if (group && (hitresult & (VisualGroup::HeaderHit | VisualGroup::BodyHit))) { + VisualGroup::HitResults hitResult; + auto group = categoryAt(point + offset(), hitResult); + if (group && (hitResult & (VisualGroup::HeaderHit | VisualGroup::BodyHit))) { return group->text; } return QString(); @@ -275,9 +277,9 @@ void InstanceView::mousePressEvent(QMouseEvent* event) m_pressedAlreadySelected = selectionModel()->isSelected(m_pressedIndex); m_pressedPosition = geometryPos; - VisualGroup::HitResults hitresult; - m_pressedCategory = categoryAt(geometryPos, hitresult); - if (m_pressedCategory && hitresult & VisualGroup::CheckboxHit) { + VisualGroup::HitResults hitResult; + m_pressedCategory = categoryAt(geometryPos, hitResult); + if (m_pressedCategory && hitResult & VisualGroup::CheckboxHit) { setState(m_pressedCategory->collapsed ? ExpandingState : CollapsingState); event->accept(); return; @@ -361,10 +363,10 @@ void InstanceView::mouseReleaseEvent(QMouseEvent* event) QPoint geometryPos = event->pos() + offset(); QPersistentModelIndex index = indexAt(visualPos); - VisualGroup::HitResults hitresult; + VisualGroup::HitResults hitResult; bool click = - (index == m_pressedIndex && index.isValid()) || (m_pressedCategory && m_pressedCategory == categoryAt(geometryPos, hitresult)); + (index == m_pressedIndex && index.isValid()) || (m_pressedCategory && m_pressedCategory == categoryAt(geometryPos, hitResult)); if (click && m_pressedCategory) { if (state() == ExpandingState) { @@ -449,7 +451,7 @@ void InstanceView::setPaintCat(bool visible) m_catPixmap = QPixmap(); } -void InstanceView::paintEvent(QPaintEvent* event) +void InstanceView::paintEvent([[maybe_unused]] QPaintEvent* event) { executeDelayedItemsLayout(); @@ -545,7 +547,7 @@ void InstanceView::paintEvent(QPaintEvent* event) #endif } -void InstanceView::resizeEvent(QResizeEvent* event) +void InstanceView::resizeEvent([[maybe_unused]] QResizeEvent* event) { int newItemsPerRow = calculateItemsPerRow(); if (newItemsPerRow != m_currentItemsPerRow) { @@ -581,7 +583,7 @@ void InstanceView::dragMoveEvent(QDragMoveEvent* event) event->accept(); } -void InstanceView::dragLeaveEvent(QDragLeaveEvent* event) +void InstanceView::dragLeaveEvent([[maybe_unused]] QDragLeaveEvent* event) { executeDelayedItemsLayout(); @@ -604,9 +606,9 @@ void InstanceView::dropEvent(QDropEvent* event) if (event->possibleActions() & Qt::MoveAction) { std::pair<VisualGroup*, VisualGroup::HitResults> dropPos = rowDropPos(event->pos()); const VisualGroup* group = dropPos.first; - auto hitresult = dropPos.second; + auto hitResult = dropPos.second; - if (hitresult == VisualGroup::HitResult::NoHit) { + if (hitResult == VisualGroup::HitResult::NoHit) { viewport()->update(); return; } @@ -643,15 +645,15 @@ void InstanceView::startDrag(Qt::DropActions supportedActions) if (indexes.count() == 0) return; - QMimeData* data = model()->mimeData(indexes); - if (!data) { + QMimeData* mimeData = model()->mimeData(indexes); + if (!mimeData) { return; } QRect rect; QPixmap pixmap = renderToPixmap(indexes, &rect); QDrag* drag = new QDrag(this); drag->setPixmap(pixmap); - drag->setMimeData(data); + drag->setMimeData(mimeData); drag->setHotSpot(m_pressedPosition - rect.topLeft()); Qt::DropAction defaultDropAction = Qt::IgnoreAction; if (this->defaultDropAction() != Qt::IgnoreAction && (supportedActions & this->defaultDropAction())) { @@ -767,16 +769,16 @@ QList<std::pair<QRect, QModelIndex>> InstanceView::draggablePaintPairs(const QMo return ret; } -bool InstanceView::isDragEventAccepted(QDropEvent* event) +bool InstanceView::isDragEventAccepted([[maybe_unused]] QDropEvent* event) { return true; } std::pair<VisualGroup*, VisualGroup::HitResults> InstanceView::rowDropPos(const QPoint& pos) { - VisualGroup::HitResults hitresult; - auto group = categoryAt(pos + offset(), hitresult); - return std::make_pair(group, hitresult); + VisualGroup::HitResults hitResult; + auto group = categoryAt(pos + offset(), hitResult); + return std::make_pair(group, hitResult); } QPoint InstanceView::offset() const @@ -802,7 +804,7 @@ QRegion InstanceView::visualRegionForSelection(const QItemSelection& selection) return region; } -QModelIndex InstanceView::moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers) +QModelIndex InstanceView::moveCursor(QAbstractItemView::CursorAction cursorAction, [[maybe_unused]] Qt::KeyboardModifiers modifiers) { auto current = currentIndex(); if (!current.isValid()) { @@ -822,20 +824,20 @@ QModelIndex InstanceView::moveCursor(QAbstractItemView::CursorAction cursorActio switch (cursorAction) { case MoveUp: { if (row == 0) { - int prevgroupindex = group_index - 1; - while (prevgroupindex >= 0) { - auto prevgroup = m_groups[prevgroupindex]; - if (prevgroup->collapsed) { - prevgroupindex--; + int prevGroupIndex = group_index - 1; + while (prevGroupIndex >= 0) { + auto prevGroup = m_groups[prevGroupIndex]; + if (prevGroup->collapsed) { + prevGroupIndex--; continue; } - int newRow = prevgroup->numRows() - 1; - int newRowSize = prevgroup->rows[newRow].size(); + int newRow = prevGroup->numRows() - 1; + int newRowSize = prevGroup->rows[newRow].size(); int newColumn = m_currentCursorColumn; if (m_currentCursorColumn >= newRowSize) { newColumn = newRowSize - 1; } - return prevgroup->rows[newRow][newColumn]; + return prevGroup->rows[newRow][newColumn]; } } else { int newRow = row - 1; @@ -850,19 +852,19 @@ QModelIndex InstanceView::moveCursor(QAbstractItemView::CursorAction cursorActio } case MoveDown: { if (row == cat->rows.size() - 1) { - int nextgroupindex = group_index + 1; - while (nextgroupindex < m_groups.size()) { - auto nextgroup = m_groups[nextgroupindex]; - if (nextgroup->collapsed) { - nextgroupindex++; + int nextGroupIndex = group_index + 1; + while (nextGroupIndex < m_groups.size()) { + auto nextGroup = m_groups[nextGroupIndex]; + if (nextGroup->collapsed) { + nextGroupIndex++; continue; } - int newRowSize = nextgroup->rows[0].size(); + int newRowSize = nextGroup->rows[0].size(); int newColumn = m_currentCursorColumn; if (m_currentCursorColumn >= newRowSize) { newColumn = newRowSize - 1; } - return nextgroup->rows[0][newColumn]; + return nextGroup->rows[0][newColumn]; } } else { int newRow = row + 1; @@ -936,7 +938,7 @@ void InstanceView::scrollTo(const QModelIndex& index, ScrollHint hint) verticalScrollBar()->setValue(verticalScrollToValue(index, rect, hint)); } -int InstanceView::verticalScrollToValue(const QModelIndex& index, const QRect& rect, QListView::ScrollHint hint) const +int InstanceView::verticalScrollToValue([[maybe_unused]] const QModelIndex& index, const QRect& rect, QListView::ScrollHint hint) const { const QRect area = viewport()->rect(); const bool above = (hint == QListView::EnsureVisible && rect.top() < area.top()); diff --git a/launcher/ui/pages/BasePageContainer.h b/launcher/ui/pages/BasePageContainer.h index b750e827..a497ef7b 100644 --- a/launcher/ui/pages/BasePageContainer.h +++ b/launcher/ui/pages/BasePageContainer.h @@ -6,6 +6,7 @@ class BasePageContainer { public: virtual ~BasePageContainer(){}; virtual bool selectPage(QString pageId) = 0; + virtual BasePage* selectedPage() const = 0; virtual BasePage* getPage(QString pageId) { return nullptr; }; virtual void refreshContainer() = 0; virtual bool requestClose() = 0; diff --git a/launcher/ui/pages/global/AccountListPage.cpp b/launcher/ui/pages/global/AccountListPage.cpp index 1d5ecb8d..5c6fb092 100644 --- a/launcher/ui/pages/global/AccountListPage.cpp +++ b/launcher/ui/pages/global/AccountListPage.cpp @@ -83,7 +83,7 @@ AccountListPage::AccountListPage(QWidget* parent) : QMainWindow(parent), ui(new QItemSelectionModel* selectionModel = ui->listView->selectionModel(); connect(selectionModel, &QItemSelectionModel::selectionChanged, - [this](const QItemSelection& sel, const QItemSelection& dsel) { updateButtonStates(); }); + [this]([[maybe_unused]] const QItemSelection& sel, [[maybe_unused]] const QItemSelection& dsel) { updateButtonStates(); }); connect(ui->listView, &VersionListView::customContextMenuRequested, this, &AccountListPage::ShowContextMenu); connect(m_accounts.get(), &AccountList::listChanged, this, &AccountListPage::listChanged); diff --git a/launcher/ui/pages/global/ExternalToolsPage.ui b/launcher/ui/pages/global/ExternalToolsPage.ui index 3643094d..47c77842 100644 --- a/launcher/ui/pages/global/ExternalToolsPage.ui +++ b/launcher/ui/pages/global/ExternalToolsPage.ui @@ -47,7 +47,7 @@ <item> <widget class="QPushButton" name="jprofilerPathBtn"> <property name="text"> - <string notr="true">...</string> + <string>Browse</string> </property> </widget> </item> @@ -84,7 +84,7 @@ <item> <widget class="QPushButton" name="jvisualvmPathBtn"> <property name="text"> - <string notr="true">...</string> + <string>Browse</string> </property> </widget> </item> @@ -121,7 +121,7 @@ <item> <widget class="QPushButton" name="mceditPathBtn"> <property name="text"> - <string notr="true">...</string> + <string>Browse</string> </property> </widget> </item> @@ -166,7 +166,7 @@ <item row="0" column="2"> <widget class="QToolButton" name="jsonEditorBrowseBtn"> <property name="text"> - <string notr="true">...</string> + <string>Browse</string> </property> </widget> </item> diff --git a/launcher/ui/pages/global/JavaPage.cpp b/launcher/ui/pages/global/JavaPage.cpp index a9ede8ed..45d8f018 100644 --- a/launcher/ui/pages/global/JavaPage.cpp +++ b/launcher/ui/pages/global/JavaPage.cpp @@ -166,7 +166,7 @@ void JavaPage::on_javaTestBtn_clicked() checker->run(); } -void JavaPage::on_maxMemSpinBox_valueChanged(int i) +void JavaPage::on_maxMemSpinBox_valueChanged([[maybe_unused]] int i) { updateThresholds(); } diff --git a/launcher/ui/pages/global/JavaPage.ui b/launcher/ui/pages/global/JavaPage.ui index 561cf79b..5a547637 100644 --- a/launcher/ui/pages/global/JavaPage.ui +++ b/launcher/ui/pages/global/JavaPage.ui @@ -160,37 +160,73 @@ <string>Java Runtime</string> </property> <layout class="QGridLayout" name="gridLayout_3"> - <item row="3" column="1"> - <widget class="QPushButton" name="javaDetectBtn"> + <item row="7" column="0" colspan="3"> + <widget class="QPlainTextEdit" name="jvmArgsTextBox"> + <property name="enabled"> + <bool>true</bool> + </property> <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="text"> - <string>&Auto-detect...</string> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>100</height> + </size> </property> </widget> </item> - <item row="2" column="0"> - <widget class="QLabel" name="labelJVMArgs"> + <item row="4" column="0"> + <widget class="QCheckBox" name="skipCompatibilityCheckbox"> <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="text"> - <string>JVM arguments:</string> + <property name="toolTip"> + <string>If enabled, the launcher will not check if an instance is compatible with the selected Java version.</string> </property> - <property name="alignment"> - <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> + <property name="text"> + <string>&Skip Java compatibility checks</string> </property> </widget> </item> - <item row="0" column="0"> - <widget class="QLabel" name="labelJavaPath"> + <item row="2" column="0" colspan="3"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QPushButton" name="javaDetectBtn"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Auto-detect...</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="javaTestBtn"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Test</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="6" column="0"> + <widget class="QLabel" name="labelJVMArgs"> <property name="sizePolicy"> <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> <horstretch>0</horstretch> @@ -198,69 +234,50 @@ </sizepolicy> </property> <property name="text"> - <string>&Java path:</string> - </property> - <property name="buddy"> - <cstring>javaPathTextBox</cstring> - </property> - </widget> - </item> - <item row="3" column="2"> - <widget class="QPushButton" name="javaTestBtn"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> + <string>JVM arguments:</string> </property> - <property name="text"> - <string>&Test</string> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="0" column="1" colspan="2"> + <item row="1" column="0" colspan="3"> <layout class="QHBoxLayout" name="horizontalLayout"> <item> + <widget class="QLabel" name="labelJavaPath"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Java path:</string> + </property> + <property name="buddy"> + <cstring>javaPathTextBox</cstring> + </property> + </widget> + </item> + <item> <widget class="QLineEdit" name="javaPathTextBox"/> </item> <item> <widget class="QPushButton" name="javaBrowseBtn"> <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="maximumSize"> - <size> - <width>28</width> - <height>16777215</height> - </size> - </property> <property name="text"> - <string notr="true">...</string> + <string>Browse</string> </property> </widget> </item> </layout> </item> - <item row="4" column="1"> - <widget class="QCheckBox" name="skipCompatibilityCheckbox"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>If enabled, the launcher will not check if an instance is compatible with the selected Java version.</string> - </property> - <property name="text"> - <string>&Skip Java compatibility checks</string> - </property> - </widget> - </item> - <item row="5" column="1"> + <item row="5" column="0"> <widget class="QCheckBox" name="skipJavaWizardCheckbox"> <property name="toolTip"> <string>If enabled, the launcher will not prompt you to choose a Java version if one isn't found.</string> @@ -270,25 +287,6 @@ </property> </widget> </item> - <item row="2" column="1" colspan="2"> - <widget class="QPlainTextEdit" name="jvmArgsTextBox"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="maximumSize"> - <size> - <width>16777215</width> - <height>100</height> - </size> - </property> - </widget> - </item> </layout> </widget> </item> @@ -317,8 +315,6 @@ <tabstop>permGenSpinBox</tabstop> <tabstop>javaBrowseBtn</tabstop> <tabstop>javaPathTextBox</tabstop> - <tabstop>javaDetectBtn</tabstop> - <tabstop>javaTestBtn</tabstop> <tabstop>tabWidget</tabstop> </tabstops> <resources/> diff --git a/launcher/ui/pages/global/LauncherPage.ui b/launcher/ui/pages/global/LauncherPage.ui index 26408f44..bc259a9b 100644 --- a/launcher/ui/pages/global/LauncherPage.ui +++ b/launcher/ui/pages/global/LauncherPage.ui @@ -99,7 +99,7 @@ <item row="3" column="2"> <widget class="QToolButton" name="downloadsDirBrowseBtn"> <property name="text"> - <string notr="true">...</string> + <string>Browse</string> </property> </widget> </item> @@ -109,7 +109,7 @@ <item row="1" column="2"> <widget class="QToolButton" name="modsDirBrowseBtn"> <property name="text"> - <string notr="true">...</string> + <string>Browse</string> </property> </widget> </item> @@ -126,14 +126,14 @@ <item row="0" column="2"> <widget class="QToolButton" name="instDirBrowseBtn"> <property name="text"> - <string notr="true">...</string> + <string>Browse</string> </property> </widget> </item> <item row="2" column="2"> <widget class="QToolButton" name="iconsDirBrowseBtn"> <property name="text"> - <string notr="true">...</string> + <string>Browse</string> </property> </widget> </item> diff --git a/launcher/ui/pages/global/ProxyPage.cpp b/launcher/ui/pages/global/ProxyPage.cpp index 19b2bcea..9caffcb3 100644 --- a/launcher/ui/pages/global/ProxyPage.cpp +++ b/launcher/ui/pages/global/ProxyPage.cpp @@ -71,7 +71,7 @@ void ProxyPage::updateCheckboxStuff() ui->proxyAuthBox->setEnabled(enableEditing); } -void ProxyPage::proxyGroupChanged(QAbstractButton* button) +void ProxyPage::proxyGroupChanged([[maybe_unused]] QAbstractButton* button) { updateCheckboxStuff(); } diff --git a/launcher/ui/pages/instance/ExternalResourcesPage.cpp b/launcher/ui/pages/instance/ExternalResourcesPage.cpp index 12038f88..719db879 100644 --- a/launcher/ui/pages/instance/ExternalResourcesPage.cpp +++ b/launcher/ui/pages/instance/ExternalResourcesPage.cpp @@ -305,7 +305,7 @@ bool ExternalResourcesPage::current(const QModelIndex& current, const QModelInde return onSelectionChanged(current, previous); } -bool ExternalResourcesPage::onSelectionChanged(const QModelIndex& current, const QModelIndex& previous) +bool ExternalResourcesPage::onSelectionChanged(const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous) { auto sourceCurrent = m_filterModel->mapToSource(current); int row = sourceCurrent.row(); diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.cpp b/launcher/ui/pages/instance/InstanceSettingsPage.cpp index 687b82d7..f7be9168 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.cpp +++ b/launcher/ui/pages/instance/InstanceSettingsPage.cpp @@ -440,7 +440,7 @@ void InstanceSettingsPage::changeInstanceAccount(int index) } } -void InstanceSettingsPage::on_maxMemSpinBox_valueChanged(int i) +void InstanceSettingsPage::on_maxMemSpinBox_valueChanged([[maybe_unused]] int i) { updateThresholds(); } diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.ui b/launcher/ui/pages/instance/InstanceSettingsPage.ui index 245433fe..380d8c88 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.ui +++ b/launcher/ui/pages/instance/InstanceSettingsPage.ui @@ -61,31 +61,7 @@ <bool>false</bool> </property> <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0" colspan="3"> - <widget class="QLineEdit" name="javaPathTextBox"/> - </item> - <item row="1" column="0"> - <widget class="QPushButton" name="javaDetectBtn"> - <property name="text"> - <string>Auto-detect...</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QPushButton" name="javaBrowseBtn"> - <property name="text"> - <string>Browse...</string> - </property> - </widget> - </item> - <item row="1" column="2"> - <widget class="QPushButton" name="javaTestBtn"> - <property name="text"> - <string>Test</string> - </property> - </widget> - </item> - <item row="2" column="0"> + <item row="4" column="0"> <widget class="QCheckBox" name="skipCompatibilityCheckbox"> <property name="toolTip"> <string>If enabled, the launcher will not check if an instance is compatible with the selected Java version.</string> @@ -95,6 +71,38 @@ </property> </widget> </item> + <item row="1" column="0"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLineEdit" name="javaPathTextBox"/> + </item> + <item> + <widget class="QPushButton" name="javaBrowseBtn"> + <property name="text"> + <string>Browse</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="2" column="0"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QPushButton" name="javaDetectBtn"> + <property name="text"> + <string>Auto-detect...</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="javaTestBtn"> + <property name="text"> + <string>Test</string> + </property> + </widget> + </item> + </layout> + </item> </layout> </widget> </item> @@ -699,10 +707,6 @@ <tabstop>openGlobalJavaSettingsButton</tabstop> <tabstop>settingsTabs</tabstop> <tabstop>javaSettingsGroupBox</tabstop> - <tabstop>javaPathTextBox</tabstop> - <tabstop>javaDetectBtn</tabstop> - <tabstop>javaBrowseBtn</tabstop> - <tabstop>javaTestBtn</tabstop> <tabstop>memoryGroupBox</tabstop> <tabstop>minMemSpinBox</tabstop> <tabstop>maxMemSpinBox</tabstop> diff --git a/launcher/ui/pages/instance/ManagedPackPage.cpp b/launcher/ui/pages/instance/ManagedPackPage.cpp index 0443baf1..8fdaf065 100644 --- a/launcher/ui/pages/instance/ManagedPackPage.cpp +++ b/launcher/ui/pages/instance/ManagedPackPage.cpp @@ -26,6 +26,8 @@ #include "ui/dialogs/CustomMessageBox.h" #include "ui/dialogs/ProgressDialog.h" +#include "net/ApiDownload.h" + /** This is just to override the combo box popup behavior so that the combo box doesn't take the whole screen. * ... thanks Qt. */ @@ -242,7 +244,7 @@ void ModrinthManagedPackPage::parseManagedPack() QString id = m_inst->getManagedPackID(); m_fetch_job->addNetAction( - Net::Download::makeByteArray(QString("%1/project/%2/version").arg(BuildConfig.MODRINTH_PROD_URL, id), response)); + Net::ApiDownload::makeByteArray(QString("%1/project/%2/version").arg(BuildConfig.MODRINTH_PROD_URL, id), response)); QObject::connect(m_fetch_job.get(), &NetJob::succeeded, this, [this, response, id] { QJsonParseError parse_error{}; @@ -392,7 +394,7 @@ void FlameManagedPackPage::parseManagedPack() QString id = m_inst->getManagedPackID(); - m_fetch_job->addNetAction(Net::Download::makeByteArray(QString("%1/mods/%2/files").arg(BuildConfig.FLAME_BASE_URL, id), response)); + m_fetch_job->addNetAction(Net::ApiDownload::makeByteArray(QString("%1/mods/%2/files").arg(BuildConfig.FLAME_BASE_URL, id), response)); QObject::connect(m_fetch_job.get(), &NetJob::succeeded, this, [this, response, id] { QJsonParseError parse_error{}; diff --git a/launcher/ui/pages/instance/ModFolderPage.cpp b/launcher/ui/pages/instance/ModFolderPage.cpp index cef292bd..0f5e29cb 100644 --- a/launcher/ui/pages/instance/ModFolderPage.cpp +++ b/launcher/ui/pages/instance/ModFolderPage.cpp @@ -127,7 +127,7 @@ bool ModFolderPage::shouldDisplay() const return true; } -bool ModFolderPage::onSelectionChanged(const QModelIndex& current, const QModelIndex& previous) +bool ModFolderPage::onSelectionChanged(const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous) { auto sourceCurrent = m_filterModel->mapToSource(current); int row = sourceCurrent.row(); diff --git a/launcher/ui/pages/instance/OtherLogsPage.cpp b/launcher/ui/pages/instance/OtherLogsPage.cpp index b80c08e1..ab5d9828 100644 --- a/launcher/ui/pages/instance/OtherLogsPage.cpp +++ b/launcher/ui/pages/instance/OtherLogsPage.cpp @@ -246,20 +246,20 @@ void OtherLogsPage::on_btnClean_clicked() } } if (!failed.empty()) { - QMessageBox* messageBox = new QMessageBox(this); - messageBox->setWindowTitle(tr("Error")); + QMessageBox* messageBoxFailure = new QMessageBox(this); + messageBoxFailure->setWindowTitle(tr("Error")); if (failed.size() > 5) { - messageBox->setText(tr("Couldn't delete some files!")); - messageBox->setDetailedText(failed.join('\n')); + messageBoxFailure->setText(tr("Couldn't delete some files!")); + messageBoxFailure->setDetailedText(failed.join('\n')); } else { - messageBox->setText(tr("Couldn't delete some files:\n%1").arg(failed.join('\n'))); + messageBoxFailure->setText(tr("Couldn't delete some files:\n%1").arg(failed.join('\n'))); } - messageBox->setStandardButtons(QMessageBox::Ok); - messageBox->setDefaultButton(QMessageBox::Ok); - messageBox->setTextInteractionFlags(Qt::TextSelectableByMouse); - messageBox->setIcon(QMessageBox::Critical); - messageBox->setTextInteractionFlags(Qt::TextBrowserInteraction); - messageBox->exec(); + messageBoxFailure->setStandardButtons(QMessageBox::Ok); + messageBoxFailure->setDefaultButton(QMessageBox::Ok); + messageBoxFailure->setTextInteractionFlags(Qt::TextSelectableByMouse); + messageBoxFailure->setIcon(QMessageBox::Critical); + messageBoxFailure->setTextInteractionFlags(Qt::TextBrowserInteraction); + messageBoxFailure->exec(); } } diff --git a/launcher/ui/pages/instance/ResourcePackPage.cpp b/launcher/ui/pages/instance/ResourcePackPage.cpp index 12b371df..26c14ca4 100644 --- a/launcher/ui/pages/instance/ResourcePackPage.cpp +++ b/launcher/ui/pages/instance/ResourcePackPage.cpp @@ -55,7 +55,7 @@ ResourcePackPage::ResourcePackPage(MinecraftInstance* instance, std::shared_ptr< ui->actionViewConfigs->setVisible(false); } -bool ResourcePackPage::onSelectionChanged(const QModelIndex& current, const QModelIndex& previous) +bool ResourcePackPage::onSelectionChanged(const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous) { auto sourceCurrent = m_filterModel->mapToSource(current); int row = sourceCurrent.row(); diff --git a/launcher/ui/pages/instance/ServersPage.cpp b/launcher/ui/pages/instance/ServersPage.cpp index 07daca21..da49f4a7 100644 --- a/launcher/ui/pages/instance/ServersPage.cpp +++ b/launcher/ui/pages/instance/ServersPage.cpp @@ -607,7 +607,7 @@ void ServersPage::runningStateChanged(bool running) updateState(); } -void ServersPage::currentChanged(const QModelIndex& current, const QModelIndex& previous) +void ServersPage::currentChanged(const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous) { int nextServer = -1; if (!current.isValid()) { @@ -620,7 +620,7 @@ void ServersPage::currentChanged(const QModelIndex& current, const QModelIndex& } // WARNING: this is here because currentChanged is not accurate when removing rows. the current item needs to be fixed up after removal. -void ServersPage::rowsRemoved(const QModelIndex& parent, int first, int last) +void ServersPage::rowsRemoved([[maybe_unused]] const QModelIndex& parent, int first, int last) { if (currentServer < first) { // current was before the removal diff --git a/launcher/ui/pages/instance/TexturePackPage.cpp b/launcher/ui/pages/instance/TexturePackPage.cpp index e477ceda..fa478a9a 100644 --- a/launcher/ui/pages/instance/TexturePackPage.cpp +++ b/launcher/ui/pages/instance/TexturePackPage.cpp @@ -57,7 +57,7 @@ TexturePackPage::TexturePackPage(MinecraftInstance* instance, std::shared_ptr<Te ui->actionViewConfigs->setVisible(false); } -bool TexturePackPage::onSelectionChanged(const QModelIndex& current, const QModelIndex& previous) +bool TexturePackPage::onSelectionChanged(const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous) { auto sourceCurrent = m_filterModel->mapToSource(current); int row = sourceCurrent.row(); diff --git a/launcher/ui/pages/instance/VersionPage.cpp b/launcher/ui/pages/instance/VersionPage.cpp index a180c804..ef029d1d 100644 --- a/launcher/ui/pages/instance/VersionPage.cpp +++ b/launcher/ui/pages/instance/VersionPage.cpp @@ -6,7 +6,7 @@ * Prism Launcher - Minecraft Launcher * Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org> * Copyright (C) 2022-2023 Sefa Eyeoglu <contact@scrumplex.net> - * Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me> + * Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -51,6 +51,7 @@ #include <QUrl> #include "VersionPage.h" +#include "ui/dialogs/InstallLoaderDialog.h" #include "ui_VersionPage.h" #include "ui/dialogs/CustomMessageBox.h" @@ -188,7 +189,7 @@ void VersionPage::showContextMenu(const QPoint& pos) delete menu; } -void VersionPage::packageCurrent(const QModelIndex& current, const QModelIndex& previous) +void VersionPage::packageCurrent(const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous) { if (!current.isValid()) { ui->frame->clear(); @@ -226,18 +227,6 @@ void VersionPage::packageCurrent(const QModelIndex& current, const QModelIndex& void VersionPage::updateVersionControls() { - // FIXME: this is a dirty hack - auto minecraftVersion = Version(m_profile->getComponentVersion("net.minecraft")); - - bool supportsFabric = minecraftVersion >= Version("1.14"); - ui->actionInstall_Fabric->setEnabled(supportsFabric); - - bool supportsQuilt = minecraftVersion >= Version("1.14"); - ui->actionInstall_Quilt->setEnabled(supportsQuilt); - - bool supportsLiteLoader = minecraftVersion <= Version("1.12.2"); - ui->actionInstall_LiteLoader->setEnabled(supportsLiteLoader); - updateButtons(); } @@ -389,20 +378,14 @@ void VersionPage::on_actionChange_version_triggered() return; } auto uid = list->uid(); - // FIXME: this is a horrible HACK. Get version filtering information from the actual metadata... - if (uid == "net.minecraftforge") { - on_actionInstall_Forge_triggered(); - return; - } else if (uid == "com.mumfrey.liteloader") { - on_actionInstall_LiteLoader_triggered(); - return; - } + VersionSelectDialog vselect(list.get(), tr("Change %1 version").arg(name), this); if (uid == "net.fabricmc.intermediary" || uid == "org.quiltmc.hashed") { vselect.setEmptyString(tr("No intermediary mappings versions are currently available.")); vselect.setEmptyErrorString(tr("Couldn't load or download the intermediary mappings version lists!")); - vselect.setExactFilter(BaseVersionList::ParentVersionRole, m_profile->getComponentVersion("net.minecraft")); } + vselect.setExactIfPresentFilter(BaseVersionList::ParentVersionRole, m_profile->getComponentVersion("net.minecraft")); + auto currentVersion = patch->getVersion(); if (!currentVersion.isEmpty()) { vselect.setCurrentVersion(currentVersion); @@ -443,79 +426,11 @@ void VersionPage::on_actionDownload_All_triggered() m_container->refreshContainer(); } -void VersionPage::on_actionInstall_Forge_triggered() -{ - auto vlist = APPLICATION->metadataIndex()->get("net.minecraftforge"); - if (!vlist) { - return; - } - VersionSelectDialog vselect(vlist.get(), tr("Select Forge version"), this); - vselect.setExactFilter(BaseVersionList::ParentVersionRole, m_profile->getComponentVersion("net.minecraft")); - vselect.setEmptyString(tr("No Forge versions are currently available for Minecraft ") + - m_profile->getComponentVersion("net.minecraft")); - vselect.setEmptyErrorString(tr("Couldn't load or download the Forge version lists!")); - - auto currentVersion = m_profile->getComponentVersion("net.minecraftforge"); - if (!currentVersion.isEmpty()) { - vselect.setCurrentVersion(currentVersion); - } - - if (vselect.exec() && vselect.selectedVersion()) { - auto vsn = vselect.selectedVersion(); - m_profile->setComponentVersion("net.minecraftforge", vsn->descriptor()); - m_profile->resolve(Net::Mode::Online); - // m_profile->installVersion(); - preselect(m_profile->rowCount(QModelIndex()) - 1); - m_container->refreshContainer(); - } -} - -void VersionPage::on_actionInstall_Fabric_triggered() +void VersionPage::on_actionInstall_Loader_triggered() { - auto vlist = APPLICATION->metadataIndex()->get("net.fabricmc.fabric-loader"); - if (!vlist) { - return; - } - VersionSelectDialog vselect(vlist.get(), tr("Select Fabric Loader version"), this); - vselect.setEmptyString(tr("No Fabric Loader versions are currently available.")); - vselect.setEmptyErrorString(tr("Couldn't load or download the Fabric Loader version lists!")); - - auto currentVersion = m_profile->getComponentVersion("net.fabricmc.fabric-loader"); - if (!currentVersion.isEmpty()) { - vselect.setCurrentVersion(currentVersion); - } - - if (vselect.exec() && vselect.selectedVersion()) { - auto vsn = vselect.selectedVersion(); - m_profile->setComponentVersion("net.fabricmc.fabric-loader", vsn->descriptor()); - m_profile->resolve(Net::Mode::Online); - preselect(m_profile->rowCount(QModelIndex()) - 1); - m_container->refreshContainer(); - } -} - -void VersionPage::on_actionInstall_Quilt_triggered() -{ - auto vlist = APPLICATION->metadataIndex()->get("org.quiltmc.quilt-loader"); - if (!vlist) { - return; - } - VersionSelectDialog vselect(vlist.get(), tr("Select Quilt Loader version"), this); - vselect.setEmptyString(tr("No Quilt Loader versions are currently available.")); - vselect.setEmptyErrorString(tr("Couldn't load or download the Quilt Loader version lists!")); - - auto currentVersion = m_profile->getComponentVersion("org.quiltmc.quilt-loader"); - if (!currentVersion.isEmpty()) { - vselect.setCurrentVersion(currentVersion); - } - - if (vselect.exec() && vselect.selectedVersion()) { - auto vsn = vselect.selectedVersion(); - m_profile->setComponentVersion("org.quiltmc.quilt-loader", vsn->descriptor()); - m_profile->resolve(Net::Mode::Online); - preselect(m_profile->rowCount(QModelIndex()) - 1); - m_container->refreshContainer(); - } + InstallLoaderDialog dialog(m_inst->getPackProfile(), QString(), this); + dialog.exec(); + m_container->refreshContainer(); } void VersionPage::on_actionAdd_Empty_triggered() @@ -534,33 +449,6 @@ void VersionPage::on_actionAdd_Empty_triggered() } } -void VersionPage::on_actionInstall_LiteLoader_triggered() -{ - auto vlist = APPLICATION->metadataIndex()->get("com.mumfrey.liteloader"); - if (!vlist) { - return; - } - VersionSelectDialog vselect(vlist.get(), tr("Select LiteLoader version"), this); - vselect.setExactFilter(BaseVersionList::ParentVersionRole, m_profile->getComponentVersion("net.minecraft")); - vselect.setEmptyString(tr("No LiteLoader versions are currently available for Minecraft ") + - m_profile->getComponentVersion("net.minecraft")); - vselect.setEmptyErrorString(tr("Couldn't load or download the LiteLoader version lists!")); - - auto currentVersion = m_profile->getComponentVersion("com.mumfrey.liteloader"); - if (!currentVersion.isEmpty()) { - vselect.setCurrentVersion(currentVersion); - } - - if (vselect.exec() && vselect.selectedVersion()) { - auto vsn = vselect.selectedVersion(); - m_profile->setComponentVersion("com.mumfrey.liteloader", vsn->descriptor()); - m_profile->resolve(Net::Mode::Online); - // m_profile->installVersion(vselect.selectedVersion()); - preselect(m_profile->rowCount(QModelIndex()) - 1); - m_container->refreshContainer(); - } -} - void VersionPage::on_actionLibrariesFolder_triggered() { DesktopServices::openDirectory(m_inst->getLocalLibraryPath(), true); @@ -571,7 +459,7 @@ void VersionPage::on_actionMinecraftFolder_triggered() DesktopServices::openDirectory(m_inst->gameRoot(), true); } -void VersionPage::versionCurrent(const QModelIndex& current, const QModelIndex& previous) +void VersionPage::versionCurrent(const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous) { currentIdx = current.row(); updateButtons(currentIdx); diff --git a/launcher/ui/pages/instance/VersionPage.h b/launcher/ui/pages/instance/VersionPage.h index 45d383f4..6915be88 100644 --- a/launcher/ui/pages/instance/VersionPage.h +++ b/launcher/ui/pages/instance/VersionPage.h @@ -68,11 +68,8 @@ class VersionPage : public QMainWindow, public BasePage { private slots: void on_actionChange_version_triggered(); - void on_actionInstall_Forge_triggered(); - void on_actionInstall_Fabric_triggered(); - void on_actionInstall_Quilt_triggered(); + void on_actionInstall_Loader_triggered(); void on_actionAdd_Empty_triggered(); - void on_actionInstall_LiteLoader_triggered(); void on_actionReload_triggered(); void on_actionRemove_triggered(); void on_actionMove_up_triggered(); diff --git a/launcher/ui/pages/instance/VersionPage.ui b/launcher/ui/pages/instance/VersionPage.ui index a73c42d6..9be21d49 100644 --- a/launcher/ui/pages/instance/VersionPage.ui +++ b/launcher/ui/pages/instance/VersionPage.ui @@ -98,11 +98,7 @@ <addaction name="actionEdit"/> <addaction name="actionRevert"/> <addaction name="separator"/> - <addaction name="actionInstall_Forge"/> - <addaction name="actionInstall_Fabric"/> - <addaction name="actionInstall_Quilt"/> - <addaction name="actionInstall_LiteLoader"/> - <addaction name="separator"/> + <addaction name="actionInstall_Loader"/> <addaction name="actionAdd_to_Minecraft_jar"/> <addaction name="actionReplace_Minecraft_jar"/> <addaction name="actionAdd_Agents"/> @@ -116,26 +112,26 @@ </widget> <action name="actionChange_version"> <property name="text"> - <string>Change version</string> + <string>Change Version</string> </property> <property name="toolTip"> - <string>Change version of the selected package.</string> + <string>Change version of the selected component.</string> </property> </action> <action name="actionMove_up"> <property name="text"> - <string>Move up</string> + <string>Move Up</string> </property> <property name="toolTip"> - <string>Make the selected package apply sooner.</string> + <string>Make the selected component apply sooner.</string> </property> </action> <action name="actionMove_down"> <property name="text"> - <string>Move down</string> + <string>Move Down</string> </property> <property name="toolTip"> - <string>Make the selected package apply later.</string> + <string>Make the selected component apply later.</string> </property> </action> <action name="actionRemove"> @@ -143,7 +139,7 @@ <string>Remove</string> </property> <property name="toolTip"> - <string>Remove selected package from the instance.</string> + <string>Remove selected component from the instance.</string> </property> </action> <action name="actionCustomize"> @@ -151,7 +147,7 @@ <string>Customize</string> </property> <property name="toolTip"> - <string>Customize selected package.</string> + <string>Customize selected component.</string> </property> </action> <action name="actionEdit"> @@ -159,7 +155,7 @@ <string>Edit</string> </property> <property name="toolTip"> - <string>Edit selected package.</string> + <string>Edit selected component.</string> </property> </action> <action name="actionRevert"> @@ -167,39 +163,15 @@ <string>Revert</string> </property> <property name="toolTip"> - <string>Revert the selected package to default.</string> - </property> - </action> - <action name="actionInstall_Forge"> - <property name="text"> - <string>Install Forge</string> - </property> - <property name="toolTip"> - <string>Install the Minecraft Forge package.</string> - </property> - </action> - <action name="actionInstall_Fabric"> - <property name="text"> - <string>Install Fabric</string> - </property> - <property name="toolTip"> - <string>Install the Fabric Loader package.</string> - </property> - </action> - <action name="actionInstall_Quilt"> - <property name="text"> - <string>Install Quilt</string> - </property> - <property name="toolTip"> - <string>Install the Quilt Loader package.</string> + <string>Revert the selected component to default.</string> </property> </action> - <action name="actionInstall_LiteLoader"> + <action name="actionInstall_Loader"> <property name="text"> - <string>Install LiteLoader</string> + <string>Install Loader</string> </property> <property name="toolTip"> - <string>Install the LiteLoader package.</string> + <string>Install a mod loader.</string> </property> </action> <action name="actionAdd_to_Minecraft_jar"> @@ -228,7 +200,7 @@ <string>Add Empty</string> </property> <property name="toolTip"> - <string>Add an empty custom package.</string> + <string>Add an empty custom component.</string> </property> </action> <action name="actionReload"> @@ -236,12 +208,12 @@ <string>Reload</string> </property> <property name="toolTip"> - <string>Reload all packages.</string> + <string>Reload all components.</string> </property> </action> <action name="actionDownload_All"> <property name="text"> - <string>Download All</string> + <string>Download all</string> </property> <property name="toolTip"> <string>Download the files needed to launch the instance now.</string> diff --git a/launcher/ui/pages/instance/WorldListPage.cpp b/launcher/ui/pages/instance/WorldListPage.cpp index fe477616..587bb6ce 100644 --- a/launcher/ui/pages/instance/WorldListPage.cpp +++ b/launcher/ui/pages/instance/WorldListPage.cpp @@ -327,7 +327,7 @@ void WorldListPage::mceditState(LoggedProcess::State state) } } -void WorldListPage::worldChanged(const QModelIndex& current, const QModelIndex& previous) +void WorldListPage::worldChanged([[maybe_unused]] const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous) { QModelIndex index = getSelectedWorld(); bool enable = index.isValid(); diff --git a/launcher/ui/pages/modplatform/ImportPage.cpp b/launcher/ui/pages/modplatform/ImportPage.cpp index ba53d033..ce2777b3 100644 --- a/launcher/ui/pages/modplatform/ImportPage.cpp +++ b/launcher/ui/pages/modplatform/ImportPage.cpp @@ -48,7 +48,7 @@ class UrlValidator : public QValidator { public: using QValidator::QValidator; - State validate(QString& in, int& pos) const + State validate(QString& in, [[maybe_unused]] int& pos) const { const QUrl url(in); if (url.isValid() && !url.isRelative() && !url.isEmpty()) { @@ -106,8 +106,8 @@ void ImportPage::updateState() bool isMRPack = fi.suffix() == "mrpack"; if (fi.exists() && (isZip || isMRPack)) { - QFileInfo fi(url.fileName()); - dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(url, this)); + QFileInfo file_info(url.fileName()); + dialog->setSuggestedPack(file_info.completeBaseName(), new InstanceImportTask(url, this)); dialog->setSuggestedIcon("default"); } } else { diff --git a/launcher/ui/pages/modplatform/ResourceModel.cpp b/launcher/ui/pages/modplatform/ResourceModel.cpp index 49405a02..0a7edb7b 100644 --- a/launcher/ui/pages/modplatform/ResourceModel.cpp +++ b/launcher/ui/pages/modplatform/ResourceModel.cpp @@ -17,7 +17,7 @@ #include "BuildConfig.h" #include "Json.h" -#include "net/Download.h" +#include "net/ApiDownload.h" #include "net/NetJob.h" #include "modplatform/ModIndex.h" @@ -102,7 +102,7 @@ QHash<int, QByteArray> ResourceModel::roleNames() const return roles; } -bool ResourceModel::setData(const QModelIndex& index, const QVariant& value, int role) +bool ResourceModel::setData(const QModelIndex& index, const QVariant& value, [[maybe_unused]] int role) { int pos = index.row(); if (pos >= m_packs.size() || pos < 0 || !index.isValid()) @@ -281,7 +281,7 @@ std::optional<QIcon> ResourceModel::getIcon(QModelIndex& index, const QUrl& url) auto cache_entry = APPLICATION->metacache()->resolveEntry( metaEntryBase(), QString("logos/%1").arg(QString(QCryptographicHash::hash(url.toEncoded(), QCryptographicHash::Algorithm::Sha1).toHex()))); - auto icon_fetch_action = Net::Download::makeCached(url, cache_entry); + auto icon_fetch_action = Net::ApiDownload::makeCached(url, cache_entry); auto full_file_path = cache_entry->getFullPath(); connect(icon_fetch_action.get(), &NetAction::succeeded, this, [=] { @@ -310,7 +310,7 @@ std::optional<QIcon> ResourceModel::getIcon(QModelIndex& index, const QUrl& url) #define NEED_FOR_CALLBACK_ASSERT(name) \ Q_ASSERT_X(0 != 0, #name, "You NEED to re-implement this if you intend on using the default callbacks.") -QJsonArray ResourceModel::documentToArray(QJsonDocument& doc) const +QJsonArray ResourceModel::documentToArray([[maybe_unused]] QJsonDocument& doc) const { NEED_FOR_CALLBACK_ASSERT("documentToArray"); return {}; @@ -372,7 +372,7 @@ void ResourceModel::searchRequestSucceeded(QJsonDocument& doc) endInsertRows(); } -void ResourceModel::searchRequestFailed(QString reason, int network_error_code) +void ResourceModel::searchRequestFailed([[maybe_unused]] QString reason, int network_error_code) { switch (network_error_code) { default: diff --git a/launcher/ui/pages/modplatform/ResourceModel.h b/launcher/ui/pages/modplatform/ResourceModel.h index 6533d9c6..cc813d6e 100644 --- a/launcher/ui/pages/modplatform/ResourceModel.h +++ b/launcher/ui/pages/modplatform/ResourceModel.h @@ -42,7 +42,10 @@ class ResourceModel : public QAbstractListModel { [[nodiscard]] virtual auto debugName() const -> QString; [[nodiscard]] virtual auto metaEntryBase() const -> QString = 0; - [[nodiscard]] inline int rowCount(const QModelIndex& parent) const override { return parent.isValid() ? 0 : m_packs.size(); } + [[nodiscard]] inline int rowCount(const QModelIndex& parent) const override + { + return parent.isValid() ? 0 : static_cast<int>(m_packs.size()); + } [[nodiscard]] inline int columnCount(const QModelIndex& parent) const override { return parent.isValid() ? 0 : 1; } [[nodiscard]] inline auto flags(const QModelIndex& index) const -> Qt::ItemFlags override { return QAbstractListModel::flags(index); } diff --git a/launcher/ui/pages/modplatform/ResourcePackModel.cpp b/launcher/ui/pages/modplatform/ResourcePackModel.cpp index 18c14bf8..d436f320 100644 --- a/launcher/ui/pages/modplatform/ResourcePackModel.cpp +++ b/launcher/ui/pages/modplatform/ResourcePackModel.cpp @@ -9,7 +9,8 @@ namespace ResourceDownload { ResourcePackResourceModel::ResourcePackResourceModel(BaseInstance const& base_inst, ResourceAPI* api) - : ResourceModel(api), m_base_instance(base_inst){}; + : ResourceModel(api), m_base_instance(base_inst) +{} /******** Make data requests ********/ diff --git a/launcher/ui/pages/modplatform/ResourcePage.cpp b/launcher/ui/pages/modplatform/ResourcePage.cpp index 48afbd90..c087e2be 100644 --- a/launcher/ui/pages/modplatform/ResourcePage.cpp +++ b/launcher/ui/pages/modplatform/ResourcePage.cpp @@ -4,7 +4,7 @@ /* * Prism Launcher - Minecraft Launcher * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> - * Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me> + * Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -280,7 +280,7 @@ void ResourcePage::updateVersionList() updateSelectionButton(); } -void ResourcePage::onSelectionChanged(QModelIndex curr, QModelIndex prev) +void ResourcePage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelIndex prev) { if (!curr.isValid()) { return; @@ -307,9 +307,9 @@ void ResourcePage::onSelectionChanged(QModelIndex curr, QModelIndex prev) updateUi(); } -void ResourcePage::onVersionSelectionChanged(QString data) +void ResourcePage::onVersionSelectionChanged(QString versionData) { - if (data.isNull() || data.isEmpty()) { + if (versionData.isNull() || versionData.isEmpty()) { m_selected_version_index = -1; return; } @@ -395,7 +395,7 @@ void ResourcePage::openUrl(const QUrl& url) if (auto current_pack = getCurrentPack(); current_pack && slug != current_pack->slug) { m_parent_dialog->selectPage(page); - auto newPage = m_parent_dialog->getSelectedPage(); + auto newPage = m_parent_dialog->selectedPage(); QLineEdit* searchEdit = newPage->m_ui->searchEdit; auto model = newPage->m_model; diff --git a/launcher/ui/pages/modplatform/ResourcePage.h b/launcher/ui/pages/modplatform/ResourcePage.h index b4a87f57..7bec0a37 100644 --- a/launcher/ui/pages/modplatform/ResourcePage.h +++ b/launcher/ui/pages/modplatform/ResourcePage.h @@ -97,7 +97,11 @@ class ResourcePage : public QWidget, public BasePage { virtual void openUrl(const QUrl&); /** Whether the version is opted out or not. Currently only makes sense in CF. */ - virtual bool optedOut(ModPlatform::IndexedVersion& ver) const { return false; }; + virtual bool optedOut(ModPlatform::IndexedVersion& ver) const + { + Q_UNUSED(ver); + return false; + }; public: BaseInstance& m_base_instance; diff --git a/launcher/ui/pages/modplatform/ShaderPackModel.cpp b/launcher/ui/pages/modplatform/ShaderPackModel.cpp index aabd3be6..8c913657 100644 --- a/launcher/ui/pages/modplatform/ShaderPackModel.cpp +++ b/launcher/ui/pages/modplatform/ShaderPackModel.cpp @@ -9,7 +9,8 @@ namespace ResourceDownload { ShaderPackResourceModel::ShaderPackResourceModel(BaseInstance const& base_inst, ResourceAPI* api) - : ResourceModel(api), m_base_instance(base_inst){}; + : ResourceModel(api), m_base_instance(base_inst) +{} /******** Make data requests ********/ diff --git a/launcher/ui/pages/modplatform/atlauncher/AtlListModel.cpp b/launcher/ui/pages/modplatform/atlauncher/AtlListModel.cpp index c6b087d6..39f4f346 100644 --- a/launcher/ui/pages/modplatform/atlauncher/AtlListModel.cpp +++ b/launcher/ui/pages/modplatform/atlauncher/AtlListModel.cpp @@ -20,6 +20,8 @@ #include <BuildConfig.h> #include <Json.h> +#include "net/ApiDownload.h" + namespace Atl { ListModel::ListModel(QObject* parent) : QAbstractListModel(parent) {} @@ -75,7 +77,7 @@ void ListModel::request() auto netJob = makeShared<NetJob>("Atl::Request", APPLICATION->network()); auto url = QString(BuildConfig.ATL_DOWNLOAD_SERVER_URL + "launcher/json/packsnew.json"); - netJob->addNetAction(Net::Download::makeByteArray(QUrl(url), response)); + netJob->addNetAction(Net::ApiDownload::makeByteArray(QUrl(url), response)); jobPtr = netJob; jobPtr->start(); @@ -137,8 +139,7 @@ void ListModel::requestFailed(QString reason) void ListModel::getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback) { if (m_logoMap.contains(logo)) { - callback( - APPLICATION->metacache()->resolveEntry("ATLauncherPacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath()); + callback(APPLICATION->metacache()->resolveEntry("ATLauncherPacks", QString("logos/%1").arg(logo))->getFullPath()); } else { requestLogo(logo, logoUrl); } @@ -168,9 +169,9 @@ void ListModel::requestLogo(QString file, QString url) return; } - MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("ATLauncherPacks", QString("logos/%1").arg(file.section(".", 0, 0))); + MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("ATLauncherPacks", QString("logos/%1").arg(file)); auto job = new NetJob(QString("ATLauncher Icon Download %1").arg(file), APPLICATION->network()); - job->addNetAction(Net::Download::makeCached(QUrl(url), entry)); + job->addNetAction(Net::ApiDownload::makeCached(QUrl(url), entry)); auto fullPath = entry->getFullPath(); QObject::connect(job, &NetJob::succeeded, this, [this, file, fullPath, job] { diff --git a/launcher/ui/pages/modplatform/atlauncher/AtlOptionalModDialog.cpp b/launcher/ui/pages/modplatform/atlauncher/AtlOptionalModDialog.cpp index 62e406d3..6fb86773 100644 --- a/launcher/ui/pages/modplatform/atlauncher/AtlOptionalModDialog.cpp +++ b/launcher/ui/pages/modplatform/atlauncher/AtlOptionalModDialog.cpp @@ -43,6 +43,8 @@ #include "Json.h" #include "modplatform/atlauncher/ATLShareCode.h" +#include "net/ApiDownload.h" + AtlOptionalModListModel::AtlOptionalModListModel(QWidget* parent, ATLauncher::PackVersion version, QVector<ATLauncher::VersionMod> mods) : QAbstractListModel(parent), m_version(version), m_mods(mods) { @@ -113,7 +115,7 @@ QVariant AtlOptionalModListModel::data(const QModelIndex& index, int role) const return {}; } -bool AtlOptionalModListModel::setData(const QModelIndex& index, const QVariant& value, int role) +bool AtlOptionalModListModel::setData(const QModelIndex& index, [[maybe_unused]] const QVariant& value, int role) { if (role == Qt::CheckStateRole) { auto row = index.row(); @@ -155,7 +157,7 @@ void AtlOptionalModListModel::useShareCode(const QString& code) { m_jobPtr.reset(new NetJob("Atl::Request", APPLICATION->network())); auto url = QString(BuildConfig.ATL_API_BASE_URL + "share-codes/" + code); - m_jobPtr->addNetAction(Net::Download::makeByteArray(QUrl(url), m_response)); + m_jobPtr->addNetAction(Net::ApiDownload::makeByteArray(QUrl(url), m_response)); connect(m_jobPtr.get(), &NetJob::succeeded, this, &AtlOptionalModListModel::shareCodeSuccess); connect(m_jobPtr.get(), &NetJob::failed, this, &AtlOptionalModListModel::shareCodeFailure); @@ -206,7 +208,7 @@ void AtlOptionalModListModel::shareCodeSuccess() emit dataChanged(AtlOptionalModListModel::index(0, EnabledColumn), AtlOptionalModListModel::index(m_mods.size() - 1, EnabledColumn)); } -void AtlOptionalModListModel::shareCodeFailure(const QString& reason) +void AtlOptionalModListModel::shareCodeFailure([[maybe_unused]] const QString& reason) { m_jobPtr.reset(); @@ -281,15 +283,15 @@ void AtlOptionalModListModel::setMod(ATLauncher::VersionMod mod, int index, bool // if the dependency is 'effectively hidden', then track which mods // depend on it - so we can efficiently disable it when no more dependents // depend on it. - auto dependants = m_dependants[dependencyName]; + auto dependents = m_dependents[dependencyName]; if (enable) { - dependants.append(mod.name); + dependents.append(mod.name); } else { - dependants.removeAll(mod.name); + dependents.removeAll(mod.name); // if there are no longer any dependents, let's disable the mod - if (dependencyMod.effectively_hidden && dependants.isEmpty()) { + if (dependencyMod.effectively_hidden && dependents.isEmpty()) { setMod(dependencyMod, dependencyIndex, false, shouldEmit); } } @@ -297,8 +299,8 @@ void AtlOptionalModListModel::setMod(ATLauncher::VersionMod mod, int index, bool // disable mods that depend on this one, if disabling if (!enable) { - auto dependants = m_dependants[mod.name]; - for (const auto& dependencyName : dependants) { + auto dependents = m_dependents[mod.name]; + for (const auto& dependencyName : dependents) { auto dependencyIndex = m_index[dependencyName]; auto dependencyMod = m_mods.at(dependencyIndex); diff --git a/launcher/ui/pages/modplatform/atlauncher/AtlOptionalModDialog.h b/launcher/ui/pages/modplatform/atlauncher/AtlOptionalModDialog.h index 72a946da..55903003 100644 --- a/launcher/ui/pages/modplatform/atlauncher/AtlOptionalModDialog.h +++ b/launcher/ui/pages/modplatform/atlauncher/AtlOptionalModDialog.h @@ -90,7 +90,7 @@ class AtlOptionalModListModel : public QAbstractListModel { QMap<QString, bool> m_selection; QMap<QString, int> m_index; - QMap<QString, QVector<QString>> m_dependants; + QMap<QString, QVector<QString>> m_dependents; }; class AtlOptionalModDialog : public QDialog { diff --git a/launcher/ui/pages/modplatform/atlauncher/AtlPage.cpp b/launcher/ui/pages/modplatform/atlauncher/AtlPage.cpp index 4c9dec58..5e3b9ecf 100644 --- a/launcher/ui/pages/modplatform/atlauncher/AtlPage.cpp +++ b/launcher/ui/pages/modplatform/atlauncher/AtlPage.cpp @@ -123,13 +123,13 @@ void AtlPage::triggerSearch() filterModel->setSearchTerm(ui->searchEdit->text()); } -void AtlPage::onSortingSelectionChanged(QString data) +void AtlPage::onSortingSelectionChanged(QString sort) { - auto toSet = filterModel->getAvailableSortings().value(data); + auto toSet = filterModel->getAvailableSortings().value(sort); filterModel->setSorting(toSet); } -void AtlPage::onSelectionChanged(QModelIndex first, QModelIndex second) +void AtlPage::onSelectionChanged(QModelIndex first, [[maybe_unused]] QModelIndex second) { ui->versionSelectionBox->clear(); @@ -151,13 +151,13 @@ void AtlPage::onSelectionChanged(QModelIndex first, QModelIndex second) suggestCurrent(); } -void AtlPage::onVersionSelectionChanged(QString data) +void AtlPage::onVersionSelectionChanged(QString version) { - if (data.isNull() || data.isEmpty()) { + if (version.isNull() || version.isEmpty()) { selectedVersion = ""; return; } - selectedVersion = data; + selectedVersion = version; suggestCurrent(); } diff --git a/launcher/ui/pages/modplatform/flame/FlameModel.cpp b/launcher/ui/pages/modplatform/flame/FlameModel.cpp index 83c1270b..ff21d010 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModel.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModel.cpp @@ -3,6 +3,8 @@ #include "Application.h" #include "ui/widgets/ProjectItem.h" +#include "net/ApiDownload.h" + #include <Version.h> #include <QtMath> @@ -70,7 +72,7 @@ QVariant ListModel::data(const QModelIndex& index, int role) const return QVariant(); } -bool ListModel::setData(const QModelIndex& index, const QVariant& value, int role) +bool ListModel::setData(const QModelIndex& index, const QVariant& value, [[maybe_unused]] int role) { int pos = index.row(); if (pos >= modpacks.size() || pos < 0 || !index.isValid()) @@ -104,9 +106,9 @@ void ListModel::requestLogo(QString logo, QString url) return; } - MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("FlamePacks", QString("logos/%1").arg(logo.section(".", 0, 0))); + MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("FlamePacks", QString("logos/%1").arg(logo)); auto job = new NetJob(QString("Flame Icon Download %1").arg(logo), APPLICATION->network()); - job->addNetAction(Net::Download::makeCached(QUrl(url), entry)); + job->addNetAction(Net::ApiDownload::makeCached(QUrl(url), entry)); auto fullPath = entry->getFullPath(); QObject::connect(job, &NetJob::succeeded, this, [this, logo, fullPath, job] { @@ -130,7 +132,7 @@ void ListModel::requestLogo(QString logo, QString url) void ListModel::getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback) { if (m_logoMap.contains(logo)) { - callback(APPLICATION->metacache()->resolveEntry("FlamePacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath()); + callback(APPLICATION->metacache()->resolveEntry("FlamePacks", QString("logos/%1").arg(logo))->getFullPath()); } else { requestLogo(logo, logoUrl); } @@ -141,7 +143,7 @@ Qt::ItemFlags ListModel::flags(const QModelIndex& index) const return QAbstractListModel::flags(index); } -bool ListModel::canFetchMore(const QModelIndex& parent) const +bool ListModel::canFetchMore([[maybe_unused]] const QModelIndex& parent) const { return searchState == CanPossiblyFetchMore; } @@ -173,7 +175,7 @@ void ListModel::performPaginatedSearch() .arg(currentSearchTerm) .arg(currentSort + 1); - netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), response)); + netJob->addNetAction(Net::ApiDownload::makeByteArray(QUrl(searchUrl), response)); jobPtr = netJob; jobPtr->start(); QObject::connect(netJob.get(), &NetJob::succeeded, this, &ListModel::searchRequestFinished); diff --git a/launcher/ui/pages/modplatform/flame/FlamePage.cpp b/launcher/ui/pages/modplatform/flame/FlamePage.cpp index b676cad9..183e16f9 100644 --- a/launcher/ui/pages/modplatform/flame/FlamePage.cpp +++ b/launcher/ui/pages/modplatform/flame/FlamePage.cpp @@ -46,6 +46,8 @@ #include "ui/dialogs/NewInstanceDialog.h" #include "ui/widgets/ProjectItem.h" +#include "net/ApiDownload.h" + static FlameAPI api; FlamePage::FlamePage(NewInstanceDialog* dialog, QWidget* parent) : QWidget(parent), ui(new Ui::FlamePage), dialog(dialog) @@ -114,7 +116,7 @@ void FlamePage::triggerSearch() listModel->searchWithTerm(ui->searchEdit->text(), ui->sortByBox->currentIndex()); } -void FlamePage::onSelectionChanged(QModelIndex curr, QModelIndex prev) +void FlamePage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelIndex prev) { ui->versionSelectionBox->clear(); @@ -132,7 +134,8 @@ void FlamePage::onSelectionChanged(QModelIndex curr, QModelIndex prev) auto netJob = new NetJob(QString("Flame::PackVersions(%1)").arg(current.name), APPLICATION->network()); auto response = std::make_shared<QByteArray>(); int addonId = current.addonId; - netJob->addNetAction(Net::Download::makeByteArray(QString("https://api.curseforge.com/v1/mods/%1/files").arg(addonId), response)); + netJob->addNetAction( + Net::ApiDownload::makeByteArray(QString("https://api.curseforge.com/v1/mods/%1/files").arg(addonId), response)); QObject::connect(netJob, &NetJob::succeeded, this, [this, response, addonId, curr] { if (addonId != current.addonId) { @@ -207,17 +210,17 @@ void FlamePage::suggestCurrent() dialog->setSuggestedPack(current.name, new InstanceImportTask(version.downloadUrl, this, std::move(extra_info))); QString editedLogoName; - editedLogoName = "curseforge_" + current.logoName.section(".", 0, 0); + editedLogoName = "curseforge_" + current.logoName; listModel->getLogo(current.logoName, current.logoUrl, [this, editedLogoName](QString logo) { dialog->setSuggestedIconFromFile(logo, editedLogoName); }); } -void FlamePage::onVersionSelectionChanged(QString data) +void FlamePage::onVersionSelectionChanged(QString version) { bool is_blocked = false; ui->versionSelectionBox->currentData().toInt(&is_blocked); - if (data.isNull() || data.isEmpty() || is_blocked) { + if (version.isNull() || version.isEmpty() || is_blocked) { m_selected_version_index = -1; return; } diff --git a/launcher/ui/pages/modplatform/flame/FlameResourceModels.cpp b/launcher/ui/pages/modplatform/flame/FlameResourceModels.cpp index 0fb67c50..2b020c48 100644 --- a/launcher/ui/pages/modplatform/flame/FlameResourceModels.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameResourceModels.cpp @@ -32,7 +32,7 @@ void FlameModModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonAr auto FlameModModel::loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion { return FlameMod::loadDependencyVersions(m, arr); -}; +} auto FlameModModel::documentToArray(QJsonDocument& obj) const -> QJsonArray { diff --git a/launcher/ui/pages/modplatform/legacy_ftb/ListModel.cpp b/launcher/ui/pages/modplatform/legacy_ftb/ListModel.cpp index 1731ff2c..356d919d 100644 --- a/launcher/ui/pages/modplatform/legacy_ftb/ListModel.cpp +++ b/launcher/ui/pages/modplatform/legacy_ftb/ListModel.cpp @@ -35,6 +35,7 @@ #include "ListModel.h" #include "Application.h" +#include "net/ApiDownload.h" #include "net/HttpMetaCache.h" #include "net/NetJob.h" @@ -76,7 +77,7 @@ bool FilterModel::lessThan(const QModelIndex& left, const QModelIndex& right) co return true; } -bool FilterModel::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const +bool FilterModel::filterAcceptsRow([[maybe_unused]] int sourceRow, [[maybe_unused]] const QModelIndex& sourceParent) const { return true; } @@ -173,10 +174,10 @@ QVariant ListModel::data(const QModelIndex& index, int role) const return QVariant(); } -void ListModel::fill(ModpackList modpacks) +void ListModel::fill(ModpackList modpacks_) { beginResetModel(); - this->modpacks = modpacks; + this->modpacks = modpacks_; endResetModel(); } @@ -229,9 +230,9 @@ void ListModel::requestLogo(QString file) return; } - MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("FTBPacks", QString("logos/%1").arg(file.section(".", 0, 0))); + MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("FTBPacks", QString("logos/%1").arg(file)); NetJob* job = new NetJob(QString("FTB Icon Download for %1").arg(file), APPLICATION->network()); - job->addNetAction(Net::Download::makeCached(QUrl(QString(BuildConfig.LEGACY_FTB_CDN_BASE_URL + "static/%1").arg(file)), entry)); + job->addNetAction(Net::ApiDownload::makeCached(QUrl(QString(BuildConfig.LEGACY_FTB_CDN_BASE_URL + "static/%1").arg(file)), entry)); auto fullPath = entry->getFullPath(); QObject::connect(job, &NetJob::finished, this, [this, file, fullPath, job] { @@ -255,7 +256,7 @@ void ListModel::requestLogo(QString file) void ListModel::getLogo(const QString& logo, LogoCallback callback) { if (m_logoMap.contains(logo)) { - callback(APPLICATION->metacache()->resolveEntry("FTBPacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath()); + callback(APPLICATION->metacache()->resolveEntry("FTBPacks", QString("logos/%1").arg(logo))->getFullPath()); } else { requestLogo(logo); } diff --git a/launcher/ui/pages/modplatform/legacy_ftb/Page.cpp b/launcher/ui/pages/modplatform/legacy_ftb/Page.cpp index ef8e9892..0103bbaa 100644 --- a/launcher/ui/pages/modplatform/legacy_ftb/Page.cpp +++ b/launcher/ui/pages/modplatform/legacy_ftb/Page.cpp @@ -215,7 +215,7 @@ void Page::ftbPrivatePackDataDownloadSuccessfully(Modpack pack) privateListModel->addPack(pack); } -void Page::ftbPrivatePackDataDownloadFailed(QString reason, QString packCode) +void Page::ftbPrivatePackDataDownloadFailed([[maybe_unused]] QString reason, QString packCode) { auto reply = QMessageBox::question(this, tr("FTB private packs"), tr("Failed to download pack information for code %1.\nShould it be removed now?").arg(packCode)); @@ -224,7 +224,7 @@ void Page::ftbPrivatePackDataDownloadFailed(QString reason, QString packCode) } } -void Page::onPublicPackSelectionChanged(QModelIndex now, QModelIndex prev) +void Page::onPublicPackSelectionChanged(QModelIndex now, [[maybe_unused]] QModelIndex prev) { if (!now.isValid()) { onPackSelectionChanged(); @@ -234,7 +234,7 @@ void Page::onPublicPackSelectionChanged(QModelIndex now, QModelIndex prev) onPackSelectionChanged(&selectedPack); } -void Page::onThirdPartyPackSelectionChanged(QModelIndex now, QModelIndex prev) +void Page::onThirdPartyPackSelectionChanged(QModelIndex now, [[maybe_unused]] QModelIndex prev) { if (!now.isValid()) { onPackSelectionChanged(); @@ -244,7 +244,7 @@ void Page::onThirdPartyPackSelectionChanged(QModelIndex now, QModelIndex prev) onPackSelectionChanged(&selectedPack); } -void Page::onPrivatePackSelectionChanged(QModelIndex now, QModelIndex prev) +void Page::onPrivatePackSelectionChanged(QModelIndex now, [[maybe_unused]] QModelIndex prev) { if (!now.isValid()) { onPackSelectionChanged(); @@ -284,20 +284,20 @@ void Page::onPackSelectionChanged(Modpack* pack) suggestCurrent(); } -void Page::onVersionSelectionItemChanged(QString data) +void Page::onVersionSelectionItemChanged(QString version) { - if (data.isNull() || data.isEmpty()) { + if (version.isNull() || version.isEmpty()) { selectedVersion = ""; return; } - selectedVersion = data; + selectedVersion = version; suggestCurrent(); } -void Page::onSortingSelectionChanged(QString data) +void Page::onSortingSelectionChanged(QString sort) { - FilterModel::Sorting toSet = publicFilterModel->getAvailableSortings().value(data); + FilterModel::Sorting toSet = publicFilterModel->getAvailableSortings().value(sort); publicFilterModel->setSorting(toSet); thirdPartyFilterModel->setSorting(toSet); privateFilterModel->setSorting(toSet); diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index 761e265d..ebc5556c 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -42,6 +42,8 @@ #include "minecraft/PackProfile.h" #include "ui/widgets/ProjectItem.h" +#include "net/ApiDownload.h" + #include <QMessageBox> namespace Modrinth { @@ -115,7 +117,7 @@ auto ModpackListModel::data(const QModelIndex& index, int role) const -> QVarian return {}; } -bool ModpackListModel::setData(const QModelIndex& index, const QVariant& value, int role) +bool ModpackListModel::setData(const QModelIndex& index, const QVariant& value, [[maybe_unused]] int role) { int pos = index.row(); if (pos >= modpacks.size() || pos < 0 || !index.isValid()) @@ -142,7 +144,7 @@ void ModpackListModel::performPaginatedSearch() .arg(currentSearchTerm) .arg(currentSort); - netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchAllUrl), m_all_response)); + netJob->addNetAction(Net::ApiDownload::makeByteArray(QUrl(searchAllUrl), m_all_response)); QObject::connect(netJob.get(), &NetJob::succeeded, this, [this] { QJsonParseError parse_error_all{}; @@ -194,8 +196,6 @@ static auto sortFromIndex(int index) -> QString case 4: return "updated"; } - - return {}; } void ModpackListModel::searchWithTerm(const QString& term, const int sort) @@ -218,9 +218,7 @@ void ModpackListModel::searchWithTerm(const QString& term, const int sort) void ModpackListModel::getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback) { if (m_logoMap.contains(logo)) { - callback(APPLICATION->metacache() - ->resolveEntry(m_parent->metaEntryBase(), QString("logos/%1").arg(logo.section(".", 0, 0))) - ->getFullPath()); + callback(APPLICATION->metacache()->resolveEntry(m_parent->metaEntryBase(), QString("logos/%1").arg(logo))->getFullPath()); } else { requestLogo(logo, logoUrl); } @@ -232,10 +230,9 @@ void ModpackListModel::requestLogo(QString logo, QString url) return; } - MetaEntryPtr entry = - APPLICATION->metacache()->resolveEntry(m_parent->metaEntryBase(), QString("logos/%1").arg(logo.section(".", 0, 0))); + MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry(m_parent->metaEntryBase(), QString("logos/%1").arg(logo)); auto job = new NetJob(QString("%1 Icon Download %2").arg(m_parent->debugName()).arg(logo), APPLICATION->network()); - job->addNetAction(Net::Download::makeCached(QUrl(url), entry)); + job->addNetAction(Net::ApiDownload::makeCached(QUrl(url), entry)); auto fullPath = entry->getFullPath(); QObject::connect(job, &NetJob::succeeded, this, [this, logo, fullPath, job] { diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index 31b05030..41fd5003 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -46,6 +46,8 @@ #include "ui/widgets/ProjectItem.h" +#include "net/ApiDownload.h" + #include <QComboBox> #include <QKeyEvent> #include <QPushButton> @@ -105,7 +107,7 @@ bool ModrinthPage::eventFilter(QObject* watched, QEvent* event) return QObject::eventFilter(watched, event); } -void ModrinthPage::onSelectionChanged(QModelIndex curr, QModelIndex prev) +void ModrinthPage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelIndex prev) { ui->versionSelectionBox->clear(); @@ -127,7 +129,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex curr, QModelIndex prev) QString id = current.id; - netJob->addNetAction(Net::Download::makeByteArray(QString("%1/project/%2").arg(BuildConfig.MODRINTH_PROD_URL, id), response)); + netJob->addNetAction(Net::ApiDownload::makeByteArray(QString("%1/project/%2").arg(BuildConfig.MODRINTH_PROD_URL, id), response)); QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id, curr] { if (id != current.id) { @@ -176,7 +178,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex curr, QModelIndex prev) QString id = current.id; netJob->addNetAction( - Net::Download::makeByteArray(QString("%1/project/%2/version").arg(BuildConfig.MODRINTH_PROD_URL, id), response)); + Net::ApiDownload::makeByteArray(QString("%1/project/%2/version").arg(BuildConfig.MODRINTH_PROD_URL, id), response)); QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id, curr] { if (id != current.id) { @@ -309,9 +311,9 @@ void ModrinthPage::triggerSearch() m_model->searchWithTerm(ui->searchEdit->text(), ui->sortByBox->currentIndex()); } -void ModrinthPage::onVersionSelectionChanged(QString data) +void ModrinthPage::onVersionSelectionChanged(QString version) { - if (data.isNull() || data.isEmpty()) { + if (version.isNull() || version.isEmpty()) { selectedVersion = ""; return; } diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthResourceModels.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthResourceModels.cpp index 00a0108a..ce7475b6 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthResourceModels.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthResourceModels.cpp @@ -45,7 +45,7 @@ void ModrinthModModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJso auto ModrinthModModel::loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion { return ::Modrinth::loadDependencyVersions(m, arr); -}; +} auto ModrinthModModel::documentToArray(QJsonDocument& obj) const -> QJsonArray { diff --git a/launcher/ui/pages/modplatform/technic/TechnicModel.cpp b/launcher/ui/pages/modplatform/technic/TechnicModel.cpp index 02d7fd5b..e8c5ac92 100644 --- a/launcher/ui/pages/modplatform/technic/TechnicModel.cpp +++ b/launcher/ui/pages/modplatform/technic/TechnicModel.cpp @@ -38,6 +38,8 @@ #include "BuildConfig.h" #include "Json.h" +#include "net/ApiDownload.h" + #include <QIcon> Technic::ListModel::ListModel(QObject* parent) : QAbstractListModel(parent) {} @@ -116,7 +118,7 @@ void Technic::ListModel::performSearch() QString("%1search?build=%2&q=%3").arg(BuildConfig.TECHNIC_API_BASE_URL, BuildConfig.TECHNIC_API_BUILD, currentSearchTerm); searchMode = List; } - netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), response)); + netJob->addNetAction(Net::ApiDownload::makeByteArray(QUrl(searchUrl), response)); jobPtr = netJob; jobPtr->start(); QObject::connect(netJob.get(), &NetJob::succeeded, this, &ListModel::searchRequestFinished); @@ -157,7 +159,7 @@ void Technic::ListModel::searchRequestFinished() pack.logoName = "null"; } else { pack.logoUrl = rawURL; - pack.logoName = rawURL.section(QLatin1Char('/'), -1).section(QLatin1Char('.'), 0, 0); + pack.logoName = rawURL.section(QLatin1Char('/'), -1); } pack.broken = false; newList.append(pack); @@ -179,7 +181,7 @@ void Technic::ListModel::searchRequestFinished() auto iconUrl = Json::requireString(iconObj, "url"); pack.logoUrl = iconUrl; - pack.logoName = iconUrl.section(QLatin1Char('/'), -1).section(QLatin1Char('.'), 0, 0); + pack.logoName = iconUrl.section(QLatin1Char('/'), -1); } else { pack.logoUrl = "null"; pack.logoName = "null"; @@ -254,7 +256,7 @@ void Technic::ListModel::requestLogo(QString logo, QString url) MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("TechnicPacks", QString("logos/%1").arg(logo)); auto job = new NetJob(QString("Technic Icon Download %1").arg(logo), APPLICATION->network()); - job->addNetAction(Net::Download::makeCached(QUrl(url), entry)); + job->addNetAction(Net::ApiDownload::makeCached(QUrl(url), entry)); auto fullPath = entry->getFullPath(); diff --git a/launcher/ui/pages/modplatform/technic/TechnicPage.cpp b/launcher/ui/pages/modplatform/technic/TechnicPage.cpp index 88132754..54b86feb 100644 --- a/launcher/ui/pages/modplatform/technic/TechnicPage.cpp +++ b/launcher/ui/pages/modplatform/technic/TechnicPage.cpp @@ -49,6 +49,8 @@ #include "Application.h" #include "modplatform/technic/SolderPackManifest.h" +#include "net/ApiDownload.h" + TechnicPage::TechnicPage(NewInstanceDialog* dialog, QWidget* parent) : QWidget(parent), ui(new Ui::TechnicPage), dialog(dialog) { ui->setupUi(this); @@ -100,7 +102,7 @@ void TechnicPage::triggerSearch() model->searchWithTerm(ui->searchEdit->text()); } -void TechnicPage::onSelectionChanged(QModelIndex first, QModelIndex second) +void TechnicPage::onSelectionChanged(QModelIndex first, [[maybe_unused]] QModelIndex second) { ui->versionSelectionBox->clear(); @@ -125,7 +127,7 @@ void TechnicPage::suggestCurrent() return; } - QString editedLogoName = "technic_" + current.logoName.section(".", 0, 0); + QString editedLogoName = "technic_" + current.logoName; model->getLogo(current.logoName, current.logoUrl, [this, editedLogoName](QString logo) { dialog->setSuggestedIconFromFile(logo, editedLogoName); }); @@ -136,7 +138,7 @@ void TechnicPage::suggestCurrent() auto netJob = makeShared<NetJob>(QString("Technic::PackMeta(%1)").arg(current.name), APPLICATION->network()); QString slug = current.slug; - netJob->addNetAction(Net::Download::makeByteArray( + netJob->addNetAction(Net::ApiDownload::makeByteArray( QString("%1modpack/%2?build=%3").arg(BuildConfig.TECHNIC_API_BASE_URL, slug, BuildConfig.TECHNIC_API_BUILD), response)); QObject::connect(netJob.get(), &NetJob::succeeded, this, [this, slug] { jobPtr.reset(); @@ -232,7 +234,7 @@ void TechnicPage::metadataLoaded() auto netJob = makeShared<NetJob>(QString("Technic::SolderMeta(%1)").arg(current.name), APPLICATION->network()); auto url = QString("%1/modpack/%2").arg(current.url, current.slug); - netJob->addNetAction(Net::Download::makeByteArray(QUrl(url), response)); + netJob->addNetAction(Net::ApiDownload::makeByteArray(QUrl(url), response)); QObject::connect(netJob.get(), &NetJob::succeeded, this, &TechnicPage::onSolderLoaded); @@ -304,13 +306,13 @@ void TechnicPage::onSolderLoaded() metadataLoaded(); } -void TechnicPage::onVersionSelectionChanged(QString data) +void TechnicPage::onVersionSelectionChanged(QString version) { - if (data.isNull() || data.isEmpty()) { + if (version.isNull() || version.isEmpty()) { selectedVersion = ""; return; } - selectedVersion = data; + selectedVersion = version; selectVersion(); } diff --git a/launcher/ui/themes/CatPack.h b/launcher/ui/themes/CatPack.h index b03a19f0..fdd117a7 100644 --- a/launcher/ui/themes/CatPack.h +++ b/launcher/ui/themes/CatPack.h @@ -52,8 +52,8 @@ class BasicCatPack : public CatPack { public: BasicCatPack(QString id, QString name) : m_id(id), m_name(name) {} BasicCatPack(QString id) : BasicCatPack(id, id) {} - virtual QString id() { return m_id; }; - virtual QString name() { return m_name; }; + virtual QString id() { return m_id; } + virtual QString name() { return m_name; } virtual QString path(); protected: diff --git a/launcher/ui/themes/CustomTheme.cpp b/launcher/ui/themes/CustomTheme.cpp index d1eaf157..29ecf625 100644 --- a/launcher/ui/themes/CustomTheme.cpp +++ b/launcher/ui/themes/CustomTheme.cpp @@ -148,7 +148,7 @@ static bool writeThemeJson(const QString& path, try { Json::write(rootObj, path); return true; - } catch (const Exception& e) { + } catch ([[maybe_unused]] const Exception& e) { themeWarningLog() << "Failed to write theme json to" << path; return false; } diff --git a/launcher/ui/widgets/InfoFrame.cpp b/launcher/ui/widgets/InfoFrame.cpp index a0fda952..1f03f9ea 100644 --- a/launcher/ui/widgets/InfoFrame.cpp +++ b/launcher/ui/widgets/InfoFrame.cpp @@ -348,7 +348,7 @@ void InfoFrame::setImage(QPixmap img) } } -void InfoFrame::descriptionEllipsisHandler(QString link) +void InfoFrame::descriptionEllipsisHandler([[maybe_unused]] QString link) { if (!m_current_box) { m_current_box = CustomMessageBox::selectable(this, "", m_description); @@ -359,7 +359,7 @@ void InfoFrame::descriptionEllipsisHandler(QString link) } } -void InfoFrame::licenseEllipsisHandler(QString link) +void InfoFrame::licenseEllipsisHandler([[maybe_unused]] QString link) { if (!m_current_box) { m_current_box = CustomMessageBox::selectable(this, "", m_license); @@ -370,7 +370,7 @@ void InfoFrame::licenseEllipsisHandler(QString link) } } -void InfoFrame::boxClosed(int result) +void InfoFrame::boxClosed([[maybe_unused]] int result) { m_current_box = nullptr; } diff --git a/launcher/ui/widgets/JavaSettingsWidget.cpp b/launcher/ui/widgets/JavaSettingsWidget.cpp index 8c4048ff..42279a66 100644 --- a/launcher/ui/widgets/JavaSettingsWidget.cpp +++ b/launcher/ui/widgets/JavaSettingsWidget.cpp @@ -46,7 +46,7 @@ void JavaSettingsWidget::setupUi() m_verticalLayout = new QVBoxLayout(this); m_verticalLayout->setObjectName(QStringLiteral("verticalLayout")); - m_versionWidget = new VersionSelectWidget(true, this); + m_versionWidget = new VersionSelectWidget(this); m_verticalLayout->addWidget(m_versionWidget); m_horizontalLayout = new QHBoxLayout(); @@ -126,6 +126,7 @@ void JavaSettingsWidget::setupUi() void JavaSettingsWidget::initialize() { m_versionWidget->initialize(APPLICATION->javalist().get()); + m_versionWidget->selectSearch(); m_versionWidget->setResizeOn(2); auto s = APPLICATION->settings(); // Memory diff --git a/launcher/ui/widgets/PageContainer.cpp b/launcher/ui/widgets/PageContainer.cpp index f132643a..514e1d25 100644 --- a/launcher/ui/widgets/PageContainer.cpp +++ b/launcher/ui/widgets/PageContainer.cpp @@ -3,6 +3,7 @@ * Prism Launcher - Minecraft Launcher * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> * Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org> + * Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -131,7 +132,12 @@ BasePage* PageContainer::getPage(QString pageId) return m_model->findPageEntryById(pageId); } -const QList<BasePage*> PageContainer::getPages() const +BasePage* PageContainer::selectedPage() const +{ + return m_currentPage; +} + +const QList<BasePage*>& PageContainer::getPages() const { return m_model->pages(); } diff --git a/launcher/ui/widgets/PageContainer.h b/launcher/ui/widgets/PageContainer.h index 43aa0e7c..05be1c3a 100644 --- a/launcher/ui/widgets/PageContainer.h +++ b/launcher/ui/widgets/PageContainer.h @@ -2,6 +2,7 @@ /* * Prism Launcher - Minecraft Launcher * Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org> + * Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -75,9 +76,10 @@ class PageContainer : public QWidget, public BasePageContainer { return false; } - virtual bool selectPage(QString pageId) override; + bool selectPage(QString pageId) override; + BasePage* selectedPage() const override; BasePage* getPage(QString pageId) override; - const QList<BasePage*> getPages() const; + const QList<BasePage*>& getPages() const; void refreshContainer() override; virtual void setParentContainer(BasePageContainer* container) { m_container = container; }; diff --git a/launcher/ui/widgets/PageContainer_p.h b/launcher/ui/widgets/PageContainer_p.h index 9a7651c7..e61f6e15 100644 --- a/launcher/ui/widgets/PageContainer_p.h +++ b/launcher/ui/widgets/PageContainer_p.h @@ -89,6 +89,8 @@ class PageView : public QListView { setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding); setItemDelegate(new PageViewDelegate(this)); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + // Adjust margins when using Breeze theme + setProperty("_kde_side_panel_view", true); } virtual QSize sizeHint() const diff --git a/launcher/ui/widgets/SubTaskProgressBar.cpp b/launcher/ui/widgets/SubTaskProgressBar.cpp index 39102197..b0e62e0f 100644 --- a/launcher/ui/widgets/SubTaskProgressBar.cpp +++ b/launcher/ui/widgets/SubTaskProgressBar.cpp @@ -26,7 +26,7 @@ unique_qobject_ptr<SubTaskProgressBar> SubTaskProgressBar::create(QWidget* paren return unique_qobject_ptr<SubTaskProgressBar>(progress_bar); } -SubTaskProgressBar::SubTaskProgressBar(QWidget* parent) : ui(new Ui::SubTaskProgressBar) +SubTaskProgressBar::SubTaskProgressBar(QWidget* parent) : QWidget(parent), ui(new Ui::SubTaskProgressBar) { ui->setupUi(this); } diff --git a/launcher/ui/widgets/VariableSizedImageObject.cpp b/launcher/ui/widgets/VariableSizedImageObject.cpp index 4daf513a..f655fc38 100644 --- a/launcher/ui/widgets/VariableSizedImageObject.cpp +++ b/launcher/ui/widgets/VariableSizedImageObject.cpp @@ -25,6 +25,7 @@ #include "Application.h" +#include "net/ApiDownload.h" #include "net/NetJob.h" enum FormatProperties { ImageData = QTextFormat::UserProperty + 1 }; @@ -97,7 +98,7 @@ void VariableSizedImageObject::loadImage(QTextDocument* doc, const QUrl& source, QString("images/%1").arg(QString(QCryptographicHash::hash(source.toEncoded(), QCryptographicHash::Algorithm::Sha1).toHex()))); auto job = new NetJob(QString("Load Image: %1").arg(source.fileName()), APPLICATION->network()); - job->addNetAction(Net::Download::makeCached(source, entry)); + job->addNetAction(Net::ApiDownload::makeCached(source, entry)); auto full_entry_path = entry->getFullPath(); auto source_url = source; diff --git a/launcher/ui/widgets/VersionSelectWidget.cpp b/launcher/ui/widgets/VersionSelectWidget.cpp index 9647dc79..a24630b3 100644 --- a/launcher/ui/widgets/VersionSelectWidget.cpp +++ b/launcher/ui/widgets/VersionSelectWidget.cpp @@ -11,9 +11,7 @@ #include "ui/dialogs/CustomMessageBox.h" -VersionSelectWidget::VersionSelectWidget(QWidget* parent) : VersionSelectWidget(false, parent) {} - -VersionSelectWidget::VersionSelectWidget(bool focusSearch, QWidget* parent) : QWidget(parent), focusSearch(focusSearch) +VersionSelectWidget::VersionSelectWidget(QWidget* parent) : QWidget(parent) { setObjectName(QStringLiteral("VersionSelectWidget")); verticalLayout = new QVBoxLayout(this); @@ -114,9 +112,6 @@ void VersionSelectWidget::initialize(BaseVersionList* vlist) listView->header()->setSectionResizeMode(QHeaderView::ResizeToContents); listView->header()->setSectionResizeMode(resizeOnColumn, QHeaderView::Stretch); - if (focusSearch) - search->setFocus(); - if (!m_vlist->isLoaded()) { loadList(); } else { @@ -199,6 +194,16 @@ void VersionSelectWidget::selectCurrent() } } +void VersionSelectWidget::selectSearch() +{ + search->setFocus(); +} + +VersionListView* VersionSelectWidget::view() +{ + return listView; +} + void VersionSelectWidget::selectRecommended() { auto idx = m_proxyModel->getRecommended(); @@ -221,14 +226,19 @@ BaseVersion::Ptr VersionSelectWidget::selectedVersion() const return variant.value<BaseVersion::Ptr>(); } +void VersionSelectWidget::setFuzzyFilter(BaseVersionList::ModelRoles role, QString filter) +{ + m_proxyModel->setFilter(role, new ContainsFilter(filter)); +} + void VersionSelectWidget::setExactFilter(BaseVersionList::ModelRoles role, QString filter) { m_proxyModel->setFilter(role, new ExactFilter(filter)); } -void VersionSelectWidget::setFuzzyFilter(BaseVersionList::ModelRoles role, QString filter) +void VersionSelectWidget::setExactIfPresentFilter(BaseVersionList::ModelRoles role, QString filter) { - m_proxyModel->setFilter(role, new ContainsFilter(filter)); + m_proxyModel->setFilter(role, new ExactIfPresentFilter(filter)); } void VersionSelectWidget::setFilter(BaseVersionList::ModelRoles role, Filter* filter) diff --git a/launcher/ui/widgets/VersionSelectWidget.h b/launcher/ui/widgets/VersionSelectWidget.h index b7f40101..99729fbd 100644 --- a/launcher/ui/widgets/VersionSelectWidget.h +++ b/launcher/ui/widgets/VersionSelectWidget.h @@ -51,7 +51,6 @@ class VersionSelectWidget : public QWidget { Q_OBJECT public: explicit VersionSelectWidget(QWidget* parent); - explicit VersionSelectWidget(bool focusSearch = false, QWidget* parent = 0); ~VersionSelectWidget(); //! loads the list if needed. @@ -64,15 +63,19 @@ class VersionSelectWidget : public QWidget { BaseVersion::Ptr selectedVersion() const; void selectRecommended(); void selectCurrent(); + void selectSearch(); + VersionListView* view(); void setCurrentVersion(const QString& version); void setFuzzyFilter(BaseVersionList::ModelRoles role, QString filter); void setExactFilter(BaseVersionList::ModelRoles role, QString filter); + void setExactIfPresentFilter(BaseVersionList::ModelRoles role, QString filter); void setFilter(BaseVersionList::ModelRoles role, Filter* filter); void setEmptyString(QString emptyString); void setEmptyErrorString(QString emptyErrorString); void setEmptyMode(VersionListView::EmptyMode mode); void setResizeOn(int column); + bool eventFilter(QObject* watched, QEvent* event) override; signals: @@ -97,7 +100,6 @@ class VersionSelectWidget : public QWidget { int resizeOnColumn = 0; Task* loadTask; bool preselectedAlready = false; - bool focusSearch; QVBoxLayout* verticalLayout = nullptr; VersionListView* listView = nullptr; diff --git a/launcher/ui/widgets/WideBar.cpp b/launcher/ui/widgets/WideBar.cpp index b793d84f..46caaaef 100644 --- a/launcher/ui/widgets/WideBar.cpp +++ b/launcher/ui/widgets/WideBar.cpp @@ -204,8 +204,10 @@ static void copyAction(QAction* from, QAction* to) void WideBar::showVisibilityMenu(QPoint const& position) { - if (!m_bar_menu) + if (!m_bar_menu) { m_bar_menu = std::make_unique<QMenu>(this); + m_bar_menu->setTearOffEnabled(true); + } if (m_menu_state == MenuState::Dirty) { for (auto* old_action : m_bar_menu->actions()) |