diff options
| author | Sefa Eyeoglu <contact@scrumplex.net> | 2023-05-12 09:47:19 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-05-12 09:47:19 +0200 |
| commit | c5aff7cc1ef43a1326bd3ce0c83e29669e2ff43f (patch) | |
| tree | b261ced954e5cccc7dd0f27d880689174a692d3b /launcher | |
| parent | ce5bb29c442cee3654c5f4287a999d5d6593032f (diff) | |
| parent | b16829b0f9a24dba9d4c9582f82affb30a416f1b (diff) | |
| download | PrismLauncher-c5aff7cc1ef43a1326bd3ce0c83e29669e2ff43f.tar.gz PrismLauncher-c5aff7cc1ef43a1326bd3ce0c83e29669e2ff43f.tar.bz2 PrismLauncher-c5aff7cc1ef43a1326bd3ce0c83e29669e2ff43f.zip | |
Merge pull request #961 from Ryex/better-tasks
Diffstat (limited to 'launcher')
55 files changed, 1422 insertions, 234 deletions
diff --git a/launcher/Application.cpp b/launcher/Application.cpp index a7c97aa7..1659eb44 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -8,6 +8,7 @@ * Copyright (C) 2022 Lenny McLennington <lenny@sneed.church> * Copyright (C) 2022 Tayou <tayou@gmx.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 @@ -46,6 +47,7 @@ #include "net/PasteUpload.h" #include "pathmatcher/MultiMatcher.h" #include "pathmatcher/SimplePrefixMatcher.h" +#include "settings/INIFile.h" #include "ui/MainWindow.h" #include "ui/InstanceWindow.h" @@ -286,6 +288,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) if (QFile::exists(FS::PathCombine(m_rootPath, "portable.txt"))) { dataPath = m_rootPath; adjustedBy = "Portable data path"; + m_portable = true; } #endif } @@ -410,6 +413,47 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) " " "|" " " "%{if-category}[%{category}]: %{endif}" "%{message}"); + + bool foundLoggingRules = false; + + auto logRulesFile = QStringLiteral("qtlogging.ini"); + auto logRulesPath = FS::PathCombine(dataPath, logRulesFile); + + qDebug() << "Testing" << logRulesPath << "..."; + foundLoggingRules = QFile::exists(logRulesPath); + + // search the dataPath() + // seach app data standard path + if(!foundLoggingRules && !isPortable() && dirParam.isEmpty()) { + logRulesPath = QStandardPaths::locate(QStandardPaths::AppDataLocation, FS::PathCombine("..", logRulesFile)); + if(!logRulesPath.isEmpty()) { + qDebug() << "Found" << logRulesPath << "..."; + foundLoggingRules = true; + } + } + // seach root path + if(!foundLoggingRules) { + logRulesPath = FS::PathCombine(m_rootPath, logRulesFile); + qDebug() << "Testing" << logRulesPath << "..."; + foundLoggingRules = QFile::exists(logRulesPath); + } + + if(foundLoggingRules) { + // load and set logging rules + qDebug() << "Loading logging rules from:" << logRulesPath; + QSettings loggingRules(logRulesPath, QSettings::IniFormat); + loggingRules.beginGroup("Rules"); + QStringList rule_names = loggingRules.childKeys(); + QStringList rules; + qDebug() << "Setting log rules:"; + for (auto rule_name : rule_names) { + auto rule = QString("%1=%2").arg(rule_name).arg(loggingRules.value(rule_name).toString()); + rules.append(rule); + qDebug() << " " << rule; + } + auto rules_str = rules.join("\n"); + QLoggingCategory::setFilterRules(rules_str); + } qDebug() << "<> Log initialized."; } diff --git a/launcher/Application.h b/launcher/Application.h index 0d24a4e9..ced0af17 100644 --- a/launcher/Application.h +++ b/launcher/Application.h @@ -187,6 +187,10 @@ public: return m_rootPath; } + bool isPortable() { + return m_portable; + } + const Capabilities capabilities() { return m_capabilities; } @@ -275,6 +279,7 @@ private: QString m_rootPath; Status m_status = Application::StartingUp; Capabilities m_capabilities; + bool m_portable = false; #ifdef Q_OS_MACOS Qt::ApplicationState m_prevAppState = Qt::ApplicationInactive; diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 6eec9b3a..273b5449 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -124,6 +124,8 @@ set(NET_SOURCES net/HttpMetaCache.h net/MetaCacheSink.cpp net/MetaCacheSink.h + net/Logging.h + net/Logging.cpp net/NetAction.h net/NetJob.cpp net/NetJob.h @@ -576,6 +578,55 @@ ecm_qt_declare_logging_category(CORE_SOURCES EXPORT "${Launcher_Name}" ) +ecm_qt_export_logging_category( + IDENTIFIER taskLogC + CATEGORY_NAME "launcher.task" + DEFAULT_SEVERITY Debug + DESCRIPTION "Task actions" + EXPORT "${Launcher_Name}" +) + +ecm_qt_export_logging_category( + IDENTIFIER taskNetLogC + CATEGORY_NAME "launcher.task.net" + DEFAULT_SEVERITY Debug + DESCRIPTION "task network action" + EXPORT "${Launcher_Name}" +) + +ecm_qt_export_logging_category( + IDENTIFIER taskDownloadLogC + CATEGORY_NAME "launcher.task.net.download" + DEFAULT_SEVERITY Debug + DESCRIPTION "task network download actions" + EXPORT "${Launcher_Name}" +) +ecm_qt_export_logging_category( + IDENTIFIER taskUploadLogC + CATEGORY_NAME "launcher.task.net.upload" + DEFAULT_SEVERITY Debug + DESCRIPTION "task network upload actions" + EXPORT "${Launcher_Name}" +) + +ecm_qt_export_logging_category( + IDENTIFIER taskMetaCacheLogC + CATEGORY_NAME "launcher.task.net.metacache" + DEFAULT_SEVERITY Debug + DESCRIPTION "task network meta-cache actions" + EXPORT "${Launcher_Name}" +) + +ecm_qt_export_logging_category( + IDENTIFIER taskHttpMetaCacheLogC + CATEGORY_NAME "launcher.task.net.metacache.http" + DEFAULT_SEVERITY Debug + DESCRIPTION "task network http meta-cache actions" + EXPORT "${Launcher_Name}" +) + + + if(KDE_INSTALL_LOGGINGCATEGORIESDIR) # only install if there is a standard path for this ecm_qt_install_logging_categories( EXPORT "${Launcher_Name}" @@ -922,6 +973,8 @@ SET(LAUNCHER_SOURCES ui/widgets/VariableSizedImageObject.cpp ui/widgets/ProjectItem.h ui/widgets/ProjectItem.cpp + ui/widgets/SubTaskProgressBar.h + ui/widgets/SubTaskProgressBar.cpp ui/widgets/VersionListView.cpp ui/widgets/VersionListView.h ui/widgets/VersionSelectWidget.cpp @@ -982,6 +1035,7 @@ qt_wrap_ui(LAUNCHER_UI ui/widgets/CustomCommands.ui ui/widgets/InfoFrame.ui ui/widgets/ModFilterWidget.ui + ui/widgets/SubTaskProgressBar.ui ui/widgets/ThemeCustomizationWidget.ui ui/dialogs/CopyInstanceDialog.ui ui/dialogs/ProfileSetupDialog.ui @@ -1155,6 +1209,12 @@ if(INSTALL_BUNDLE STREQUAL "full") CODE "file(WRITE \"\${CMAKE_INSTALL_PREFIX}/${RESOURCES_DEST_DIR}/qt.conf\" \" \")" COMPONENT Runtime ) + # add qtlogging.ini as a config file + install( + FILES "qtlogging.ini" + DESTINATION ${CMAKE_INSTALL_PREFIX}/${RESOURCES_DEST_DIR} + COMPONENT Runtime + ) # Bundle plugins # Image formats install( diff --git a/launcher/InstanceImportTask.cpp b/launcher/InstanceImportTask.cpp index 080828a8..8a48873e 100644 --- a/launcher/InstanceImportTask.cpp +++ b/launcher/InstanceImportTask.cpp @@ -98,6 +98,7 @@ void InstanceImportTask::executeTask() connect(m_filesNetJob.get(), &NetJob::succeeded, this, &InstanceImportTask::downloadSucceeded); connect(m_filesNetJob.get(), &NetJob::progress, this, &InstanceImportTask::downloadProgressChanged); + connect(m_filesNetJob.get(), &NetJob::stepProgress, this, &InstanceImportTask::propogateStepProgress); connect(m_filesNetJob.get(), &NetJob::failed, this, &InstanceImportTask::downloadFailed); connect(m_filesNetJob.get(), &NetJob::aborted, this, &InstanceImportTask::downloadAborted); @@ -291,7 +292,9 @@ void InstanceImportTask::processFlame() }); connect(inst_creation_task, &Task::failed, this, &InstanceImportTask::emitFailed); connect(inst_creation_task, &Task::progress, this, &InstanceImportTask::setProgress); + connect(inst_creation_task, &Task::stepProgress, this, &InstanceImportTask::propogateStepProgress); connect(inst_creation_task, &Task::status, this, &InstanceImportTask::setStatus); + connect(inst_creation_task, &Task::details, this, &InstanceImportTask::setDetails); connect(inst_creation_task, &Task::finished, inst_creation_task, &InstanceCreationTask::deleteLater); connect(this, &Task::aborted, inst_creation_task, &InstanceCreationTask::abort); @@ -382,7 +385,9 @@ void InstanceImportTask::processModrinth() }); connect(inst_creation_task, &Task::failed, this, &InstanceImportTask::emitFailed); connect(inst_creation_task, &Task::progress, this, &InstanceImportTask::setProgress); + connect(inst_creation_task, &Task::stepProgress, this, &InstanceImportTask::propogateStepProgress); connect(inst_creation_task, &Task::status, this, &InstanceImportTask::setStatus); + connect(inst_creation_task, &Task::details, this, &InstanceImportTask::setDetails); connect(inst_creation_task, &Task::finished, inst_creation_task, &InstanceCreationTask::deleteLater); connect(this, &Task::aborted, inst_creation_task, &InstanceCreationTask::abort); diff --git a/launcher/InstanceList.cpp b/launcher/InstanceList.cpp index 5b33d678..b4c520cd 100644 --- a/launcher/InstanceList.cpp +++ b/launcher/InstanceList.cpp @@ -797,7 +797,9 @@ class InstanceStaging : public Task { connect(child, &Task::aborted, this, &InstanceStaging::childAborted); connect(child, &Task::abortStatusChanged, this, &InstanceStaging::setAbortable); connect(child, &Task::status, this, &InstanceStaging::setStatus); + connect(child, &Task::details, this, &InstanceStaging::setDetails); connect(child, &Task::progress, this, &InstanceStaging::setProgress); + connect(child, &Task::stepProgress, this, &InstanceStaging::propogateStepProgress); connect(&m_backoffTimer, &QTimer::timeout, this, &InstanceStaging::childSucceded); } diff --git a/launcher/MMCTime.cpp b/launcher/MMCTime.cpp index 70bc4135..1702ec06 100644 --- a/launcher/MMCTime.cpp +++ b/launcher/MMCTime.cpp @@ -18,6 +18,8 @@ #include <MMCTime.h> #include <QObject> +#include <QDateTime> +#include <QTextStream> QString Time::prettifyDuration(int64_t duration) { int seconds = (int) (duration % 60); @@ -36,3 +38,65 @@ QString Time::prettifyDuration(int64_t duration) { } return QObject::tr("%1d %2h %3min").arg(days).arg(hours).arg(minutes); } + +QString Time::humanReadableDuration(double duration, int precision) { + + using days = std::chrono::duration<int, std::ratio<86400>>; + + QString outStr; + QTextStream os(&outStr); + + bool neg = false; + if (duration < 0) { + neg = true; // flag + duration *= -1; // invert + } + + auto std_duration = std::chrono::duration<double>(duration); + auto d = std::chrono::duration_cast<days>(std_duration); + std_duration -= d; + auto h = std::chrono::duration_cast<std::chrono::hours>(std_duration); + std_duration -= h; + auto m = std::chrono::duration_cast<std::chrono::minutes>(std_duration); + std_duration -= m; + auto s = std::chrono::duration_cast<std::chrono::seconds>(std_duration); + std_duration -= s; + auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(std_duration); + + auto dc = d.count(); + auto hc = h.count(); + auto mc = m.count(); + auto sc = s.count(); + auto msc = ms.count(); + + if (neg) { + os << '-'; + } + if (dc) { + os << dc << QObject::tr("days"); + } + if (hc) { + if (dc) + os << " "; + os << qSetFieldWidth(2) << hc << QObject::tr("h"); // hours + } + if (mc) { + if (dc || hc) + os << " "; + os << qSetFieldWidth(2) << mc << QObject::tr("m"); // minutes + } + if (dc || hc || mc || sc) { + if (dc || hc || mc) + os << " "; + os << qSetFieldWidth(2) << sc << QObject::tr("s"); // seconds + } + if ((msc && (precision > 0)) || !(dc || hc || mc || sc)) { + if (dc || hc || mc || sc) + os << " "; + os << qSetFieldWidth(0) << qSetRealNumberPrecision(precision) << msc << QObject::tr("ms"); // miliseconds + } + + os.flush(); + + return outStr; +}
\ No newline at end of file diff --git a/launcher/MMCTime.h b/launcher/MMCTime.h index 10ff2ffe..6a5780b4 100644 --- a/launcher/MMCTime.h +++ b/launcher/MMCTime.h @@ -22,4 +22,13 @@ namespace Time { QString prettifyDuration(int64_t duration); +/** + * @brief Returns a string with short form time duration ie. `2days 1h3m4s56.0ms`. + * miliseconds are only included if `precision` is greater than 0. + * + * @param duration a number of seconds as floating point + * @param precision number of decmial points to display on fractons of a second, defualts to 0. + * @return QString + */ +QString humanReadableDuration(double duration, int precision = 0); } diff --git a/launcher/ResourceDownloadTask.cpp b/launcher/ResourceDownloadTask.cpp index 98bcf259..61b918aa 100644 --- a/launcher/ResourceDownloadTask.cpp +++ b/launcher/ResourceDownloadTask.cpp @@ -53,6 +53,7 @@ ResourceDownloadTask::ResourceDownloadTask(ModPlatform::IndexedPack pack, m_filesNetJob->addNetAction(Net::Download::makeFile(m_pack_version.downloadUrl, dir.absoluteFilePath(getFilename()))); connect(m_filesNetJob.get(), &NetJob::succeeded, this, &ResourceDownloadTask::downloadSucceeded); connect(m_filesNetJob.get(), &NetJob::progress, this, &ResourceDownloadTask::downloadProgressChanged); + connect(m_filesNetJob.get(), &NetJob::stepProgress, this, &ResourceDownloadTask::propogateStepProgress); connect(m_filesNetJob.get(), &NetJob::failed, this, &ResourceDownloadTask::downloadFailed); addTask(m_filesNetJob); diff --git a/launcher/StringUtils.cpp b/launcher/StringUtils.cpp index d109d63d..e08e6fdc 100644 --- a/launcher/StringUtils.cpp +++ b/launcher/StringUtils.cpp @@ -33,10 +33,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - + #include "StringUtils.h" +#include <QRegularExpression> #include <QUuid> +#include <cmath> /// If you're wondering where these came from exactly, then know you're not the only one =D @@ -113,6 +115,69 @@ int StringUtils::naturalCompare(const QString& s1, const QString& s2, Qt::CaseSe return QString::compare(s1, s2, cs); } +QString StringUtils::truncateUrlHumanFriendly(QUrl& url, int max_len, bool hard_limit) +{ + auto display_options = QUrl::RemoveUserInfo | QUrl::RemoveFragment | QUrl::NormalizePathSegments; + auto str_url = url.toDisplayString(display_options); + + if (str_url.length() <= max_len) + return str_url; + + auto url_path_parts = url.path().split('/'); + QString last_path_segment = url_path_parts.takeLast(); + + if (url_path_parts.size() >= 1 && url_path_parts.first().isEmpty()) + url_path_parts.removeFirst(); // drop empty first segment (from leading / ) + + if (url_path_parts.size() >= 1) + url_path_parts.removeLast(); // drop the next to last path segment + + auto url_template = QStringLiteral("%1://%2/%3%4"); + + auto url_compact = url_path_parts.isEmpty() + ? url_template.arg(url.scheme(), url.host(), QStringList({ "...", last_path_segment }).join('/'), url.query()) + : url_template.arg(url.scheme(), url.host(), + QStringList({ url_path_parts.join('/'), "...", last_path_segment }).join('/'), url.query()); + + // remove url parts one by one if it's still too long + while (url_compact.length() > max_len && url_path_parts.size() >= 1) { + url_path_parts.removeLast(); // drop the next to last path segment + url_compact = url_path_parts.isEmpty() + ? url_template.arg(url.scheme(), url.host(), QStringList({ "...", last_path_segment }).join('/'), url.query()) + : url_template.arg(url.scheme(), url.host(), + QStringList({ url_path_parts.join('/'), "...", last_path_segment }).join('/'), url.query()); + } + + if ((url_compact.length() >= max_len) && hard_limit) { + // still too long, truncate normaly + url_compact = QString(str_url); + auto to_remove = url_compact.length() - max_len + 3; + url_compact.remove(url_compact.length() - to_remove - 1, to_remove); + url_compact.append("..."); + } + + return url_compact; +} + +static const QStringList s_units_si{ "KB", "MB", "GB", "TB" }; +static const QStringList s_units_kibi{ "KiB", "MiB", "GiB", "TiB" }; + +QString StringUtils::humanReadableFileSize(double bytes, bool use_si, int decimal_points) +{ + const QStringList units = use_si ? s_units_si : s_units_kibi; + const int scale = use_si ? 1000 : 1024; + + int u = -1; + double r = pow(10, decimal_points); + + do { + bytes /= scale; + u++; + } while (round(abs(bytes) * r) / r >= scale && u < units.length() - 1); + + return QString::number(bytes, 'f', 2) + " " + units[u]; +} + QString StringUtils::getRandomAlphaNumeric() { return QUuid::createUuid().toString(QUuid::Id128); diff --git a/launcher/StringUtils.h b/launcher/StringUtils.h index 36c8cf8f..f90a6ac7 100644 --- a/launcher/StringUtils.h +++ b/launcher/StringUtils.h @@ -37,6 +37,7 @@ #pragma once #include <QString> +#include <QUrl> namespace StringUtils { @@ -66,5 +67,16 @@ inline QString fromStdString(string s) int naturalCompare(const QString& s1, const QString& s2, Qt::CaseSensitivity cs); +/** + * @brief Truncate a url while keeping its readability py placing the `...` in the middle of the path + * @param url Url to truncate + * @param max_len max lenght of url in charaters + * @param hard_limit if truncating the path can't get the url short enough, truncate it normaly. + */ +QString truncateUrlHumanFriendly(QUrl &url, int max_len, bool hard_limit = false); + +QString humanReadableFileSize(double bytes, bool use_si = false, int decimal_points = 1); + + QString getRandomAlphaNumeric(); } // namespace StringUtils diff --git a/launcher/launch/steps/Update.cpp b/launcher/launch/steps/Update.cpp index 28bd153d..c8e576a5 100644 --- a/launcher/launch/steps/Update.cpp +++ b/launcher/launch/steps/Update.cpp @@ -27,8 +27,10 @@ void Update::executeTask() if(m_updateTask) { connect(m_updateTask.get(), SIGNAL(finished()), this, SLOT(updateFinished())); - connect(m_updateTask.get(), &Task::progress, this, &Task::setProgress); - connect(m_updateTask.get(), &Task::status, this, &Task::setStatus); + connect(m_updateTask.get(), &Task::progress, this, &Update::setProgress); + connect(m_updateTask.get(), &Task::stepProgress, this, &Update::propogateStepProgress); + connect(m_updateTask.get(), &Task::status, this, &Update::setStatus); + connect(m_updateTask.get(), &Task::details, this, &Update::setDetails); emit progressReportingRequest(); return; } diff --git a/launcher/minecraft/MinecraftLoadAndCheck.cpp b/launcher/minecraft/MinecraftLoadAndCheck.cpp index d72bc7be..1c3f6fb7 100644 --- a/launcher/minecraft/MinecraftLoadAndCheck.cpp +++ b/launcher/minecraft/MinecraftLoadAndCheck.cpp @@ -22,6 +22,7 @@ void MinecraftLoadAndCheck::executeTask() connect(m_task.get(), &Task::failed, this, &MinecraftLoadAndCheck::subtaskFailed); connect(m_task.get(), &Task::aborted, this, [this]{ subtaskFailed(tr("Aborted")); }); connect(m_task.get(), &Task::progress, this, &MinecraftLoadAndCheck::progress); + connect(m_task.get(), &Task::stepProgress, this, &MinecraftLoadAndCheck::propogateStepProgress); connect(m_task.get(), &Task::status, this, &MinecraftLoadAndCheck::setStatus); } diff --git a/launcher/minecraft/MinecraftUpdate.cpp b/launcher/minecraft/MinecraftUpdate.cpp index 07ad4882..35430bb0 100644 --- a/launcher/minecraft/MinecraftUpdate.cpp +++ b/launcher/minecraft/MinecraftUpdate.cpp @@ -100,7 +100,9 @@ void MinecraftUpda |
