From 5909af9878d67f2900c92e8d1dd3eec7a53a840a Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Fri, 11 Nov 2022 14:10:45 -0700 Subject: [PATCH 1/7] drag&drop + add folder to watch Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- .../flame/FlameInstanceCreationTask.cpp | 8 +- .../modpacksch/FTBPackInstallTask.cpp | 6 +- launcher/ui/dialogs/BlockedModsDialog.cpp | 82 +++++++++++++++++-- launcher/ui/dialogs/BlockedModsDialog.h | 8 ++ 4 files changed, 92 insertions(+), 12 deletions(-) diff --git a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp index f0fbdc96..eff729eb 100644 --- a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp +++ b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp @@ -393,8 +393,12 @@ void FlameCreationTask::idResolverSucceeded(QEventLoop& loop) qWarning() << "Blocked mods found, displaying mod list"; auto message_dialog = new BlockedModsDialog(m_parent, tr("Blocked mods found"), - tr("The following mods were blocked on third party launchers.
" - "You will need to manually download them and add them to the modpack"), + tr("The following files are not available for download in third party launchers.
" + "You will need to manually download them and add them to the instance.

" + "Your configured global mods folder and default downloads folder
" + "are automatically checked for the downloaded mods.
" + "Optionally, you may drag and drop the downloaded mods onto this dialog or add a folder to watch
" + "if you did not download the mods to a default location."), blocked_mods); message_dialog->setModal(true); diff --git a/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp b/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp index 40aee82b..d74faf08 100644 --- a/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp +++ b/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp @@ -212,7 +212,11 @@ void PackInstallTask::onResolveModsSucceeded() auto message_dialog = new BlockedModsDialog(m_parent, tr("Blocked files found"), tr("The following files are not available for download in third party launchers.
" - "You will need to manually download them and add them to the instance."), + "You will need to manually download them and add them to the instance.

" + "Your configured global mods folder and default downloads folder
" + "are automatically checked for the downloaded mods.
" + "Optionally, you may drag and drop the downloaded mods onto this dialog or add a folder to watch
" + "if you did not download the mods to a default location."), m_blocked_mods); if (message_dialog->exec() == QDialog::Accepted) { diff --git a/launcher/ui/dialogs/BlockedModsDialog.cpp b/launcher/ui/dialogs/BlockedModsDialog.cpp index 2cf94250..ca757cbc 100644 --- a/launcher/ui/dialogs/BlockedModsDialog.cpp +++ b/launcher/ui/dialogs/BlockedModsDialog.cpp @@ -5,20 +5,29 @@ #include "Application.h" #include "ui_BlockedModsDialog.h" + #include #include +#include +#include +#include BlockedModsDialog::BlockedModsDialog(QWidget* parent, const QString& title, const QString& text, QList& mods) : QDialog(parent), ui(new Ui::BlockedModsDialog), mods(mods) { + hashing_task = shared_qobject_ptr(new ConcurrentTask(this, "MakeHashesTask", 10)); + ui->setupUi(this); auto openAllButton = ui->buttonBox->addButton(tr("Open All"), QDialogButtonBox::ActionRole); connect(openAllButton, &QPushButton::clicked, this, &BlockedModsDialog::openAll); + auto downloadFolderButton = ui->buttonBox->addButton(tr("Add Download Folder"), QDialogButtonBox::ActionRole); + connect(downloadFolderButton, &QPushButton::clicked, this, &BlockedModsDialog::addDownloadFolder); + connect(&watcher, &QFileSystemWatcher::directoryChanged, this, &BlockedModsDialog::directoryChanged); - hashing_task = shared_qobject_ptr(new ConcurrentTask(this, "MakeHashesTask", 10)); + qDebug() << "Mods List: " << mods; @@ -28,6 +37,9 @@ BlockedModsDialog::BlockedModsDialog(QWidget* parent, const QString& title, cons this->setWindowTitle(title); ui->label->setText(text); ui->labelModsFound->setText(tr("Please download the missing mods.")); + + setAcceptDrops(true); + update(); } @@ -36,6 +48,22 @@ BlockedModsDialog::~BlockedModsDialog() delete ui; } +void BlockedModsDialog::dragEnterEvent(QDragEnterEvent *e) { + if (e->mimeData()->hasUrls()) { + e->acceptProposedAction(); + } +} + +void BlockedModsDialog::dropEvent(QDropEvent *e) +{ + foreach (const QUrl &url, e->mimeData()->urls()) { + QString file = url.toLocalFile(); + qDebug() << "Dropped file:" << file; + addHashTask(file); + } + hashing_task->start(); +} + void BlockedModsDialog::openAll() { for (auto& mod : mods) { @@ -43,6 +71,16 @@ void BlockedModsDialog::openAll() } } +void BlockedModsDialog::addDownloadFolder() { + QString dir = QFileDialog::getExistingDirectory( + this, + tr("Select directory where you downloaded the mods"), + QStandardPaths::writableLocation(QStandardPaths::DownloadLocation), + QFileDialog::ShowDirsOnly); + watcher.addPath(dir); + scanPath(dir); +} + /// @brief update UI with current status of the blocked mod detection void BlockedModsDialog::update() { @@ -74,6 +112,7 @@ void BlockedModsDialog::update() void BlockedModsDialog::directoryChanged(QString path) { qDebug() << "Directory changed: " << path; + validateMatchedMods(); scanPath(path); } @@ -108,19 +147,26 @@ void BlockedModsDialog::scanPath(QString path) continue; } - auto hash_task = Hashing::createBlockedModHasher(file, ModPlatform::Provider::FLAME, "sha1"); - - qDebug() << "Creating Hash task for path: " << file; - - connect(hash_task.get(), &Task::succeeded, [this, hash_task, file] { checkMatchHash(hash_task->getResult(), file); }); - connect(hash_task.get(), &Task::failed, [file] { qDebug() << "Failed to hash path: " << file; }); - - hashing_task->addTask(hash_task); + addHashTask(file); } hashing_task->start(); } +/// @brief add a hashing task for the file located at path and connect it to check that hash against +/// our blocked mods list +/// @param path the path to the local file being hashed +void BlockedModsDialog::addHashTask(QString path) { + auto hash_task = Hashing::createBlockedModHasher(path, ModPlatform::Provider::FLAME, "sha1"); + + qDebug() << "Creating Hash task for path: " << path; + + connect(hash_task.get(), &Task::succeeded, [this, hash_task, path] { checkMatchHash(hash_task->getResult(), path); }); + connect(hash_task.get(), &Task::failed, [path] { qDebug() << "Failed to hash path: " << path; }); + + hashing_task->addTask(hash_task); +} + /// @brief check if the computed hash for the provided path matches a blocked /// mod we are looking for /// @param hash the computed hash for the provided path @@ -174,6 +220,24 @@ bool BlockedModsDialog::allModsMatched() return std::all_of(mods.begin(), mods.end(), [](auto const& mod) { return mod.matched; }); } +/// @brief ensure matched file paths still exist +void BlockedModsDialog::validateMatchedMods() { + bool changed = false; + for (auto& mod : mods) { + if (mod.matched) { + QFileInfo file = QFileInfo(mod.localPath); + if (!file.exists() || !file.isFile()) { + mod.localPath = ""; + mod.matched = false; + changed = true; + } + } + } + if (changed) { + update(); + } +} + /// qDebug print support for the BlockedMod struct QDebug operator<<(QDebug debug, const BlockedMod& m) { diff --git a/launcher/ui/dialogs/BlockedModsDialog.h b/launcher/ui/dialogs/BlockedModsDialog.h index 0a5c90db..d683c54d 100644 --- a/launcher/ui/dialogs/BlockedModsDialog.h +++ b/launcher/ui/dialogs/BlockedModsDialog.h @@ -31,6 +31,11 @@ public: ~BlockedModsDialog() override; +protected: + void dragEnterEvent(QDragEnterEvent *event) override; + // void dragMoveEvent(QDragMoveEvent *event) override; + // void dragLeaveEvent(QDragLeaveEvent *event) override; + void dropEvent(QDropEvent *event) override; private: Ui::BlockedModsDialog *ui; @@ -39,12 +44,15 @@ private: shared_qobject_ptr hashing_task; void openAll(); + void addDownloadFolder(); void update(); void directoryChanged(QString path); void setupWatch(); void scanPaths(); void scanPath(QString path); + void addHashTask(QString path); void checkMatchHash(QString hash, QString path); + void validateMatchedMods(); bool checkValidPath(QString path); bool allModsMatched(); From 3f6cc178188a28e551755219bfa0a441ad8cfdcf Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Fri, 11 Nov 2022 15:45:40 -0700 Subject: [PATCH 2/7] properly handle a currently running hashing task Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- .../flame/FlameInstanceCreationTask.cpp | 2 +- .../modpacksch/FTBPackInstallTask.cpp | 2 +- launcher/ui/dialogs/BlockedModsDialog.cpp | 113 +++++++++++++----- launcher/ui/dialogs/BlockedModsDialog.h | 13 +- 4 files changed, 94 insertions(+), 36 deletions(-) diff --git a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp index eff729eb..4b9e7b86 100644 --- a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp +++ b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp @@ -396,7 +396,7 @@ void FlameCreationTask::idResolverSucceeded(QEventLoop& loop) tr("The following files are not available for download in third party launchers.
" "You will need to manually download them and add them to the instance.

" "Your configured global mods folder and default downloads folder
" - "are automatically checked for the downloaded mods.
" + "are automatically checked for the downloaded mods and they will be copied to the instance if found.
" "Optionally, you may drag and drop the downloaded mods onto this dialog or add a folder to watch
" "if you did not download the mods to a default location."), blocked_mods); diff --git a/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp b/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp index d74faf08..26d0c5a1 100644 --- a/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp +++ b/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp @@ -214,7 +214,7 @@ void PackInstallTask::onResolveModsSucceeded() tr("The following files are not available for download in third party launchers.
" "You will need to manually download them and add them to the instance.

" "Your configured global mods folder and default downloads folder
" - "are automatically checked for the downloaded mods.
" + "are automatically checked for the downloaded mods and they will be copied to the instance if found.
" "Optionally, you may drag and drop the downloaded mods onto this dialog or add a folder to watch
" "if you did not download the mods to a default location."), m_blocked_mods); diff --git a/launcher/ui/dialogs/BlockedModsDialog.cpp b/launcher/ui/dialogs/BlockedModsDialog.cpp index ca757cbc..a1941cb8 100644 --- a/launcher/ui/dialogs/BlockedModsDialog.cpp +++ b/launcher/ui/dialogs/BlockedModsDialog.cpp @@ -1,4 +1,5 @@ #include "BlockedModsDialog.h" +#include #include #include #include @@ -13,9 +14,10 @@ #include BlockedModsDialog::BlockedModsDialog(QWidget* parent, const QString& title, const QString& text, QList& mods) - : QDialog(parent), ui(new Ui::BlockedModsDialog), mods(mods) + : QDialog(parent), ui(new Ui::BlockedModsDialog), m_mods(mods) { - hashing_task = shared_qobject_ptr(new ConcurrentTask(this, "MakeHashesTask", 10)); + m_hashing_task = shared_qobject_ptr(new ConcurrentTask(this, "MakeHashesTask", 10)); + connect(m_hashing_task.get(), &Task::finished, this, &BlockedModsDialog::hashTaskFinished); ui->setupUi(this); @@ -25,11 +27,11 @@ BlockedModsDialog::BlockedModsDialog(QWidget* parent, const QString& title, cons auto downloadFolderButton = ui->buttonBox->addButton(tr("Add Download Folder"), QDialogButtonBox::ActionRole); connect(downloadFolderButton, &QPushButton::clicked, this, &BlockedModsDialog::addDownloadFolder); - connect(&watcher, &QFileSystemWatcher::directoryChanged, this, &BlockedModsDialog::directoryChanged); + connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &BlockedModsDialog::directoryChanged); - qDebug() << "Mods List: " << mods; + qDebug() << "[Blocked Mods Dialog] Mods List: " << mods; setupWatch(); scanPaths(); @@ -57,16 +59,23 @@ void BlockedModsDialog::dragEnterEvent(QDragEnterEvent *e) { void BlockedModsDialog::dropEvent(QDropEvent *e) { foreach (const QUrl &url, e->mimeData()->urls()) { - QString file = url.toLocalFile(); - qDebug() << "Dropped file:" << file; - addHashTask(file); + QString filePath = url.toLocalFile(); + qDebug() << "[Blocked Mods Dialog] Dropped file:" << filePath; + addHashTask(filePath); + + // watch for changes + QFileInfo file = QFileInfo(filePath); + QString path = file.dir().absolutePath(); + qDebug() << "[Blocked Mods Dialog] Adding watch path:" << path; + m_watcher.addPath(path); } - hashing_task->start(); + scanPaths(); + update(); } void BlockedModsDialog::openAll() { - for (auto& mod : mods) { + for (auto& mod : m_mods) { QDesktopServices::openUrl(mod.websiteUrl); } } @@ -77,8 +86,10 @@ void BlockedModsDialog::addDownloadFolder() { tr("Select directory where you downloaded the mods"), QStandardPaths::writableLocation(QStandardPaths::DownloadLocation), QFileDialog::ShowDirsOnly); - watcher.addPath(dir); - scanPath(dir); + qDebug() << "[Blocked Mods Dialog] Adding watch path:" << dir; + m_watcher.addPath(dir); + scanPath(dir, true); + update(); } /// @brief update UI with current status of the blocked mod detection @@ -87,7 +98,7 @@ void BlockedModsDialog::update() QString text; QString span; - for (auto& mod : mods) { + for (auto& mod : m_mods) { if (mod.matched) { // ✔ -> html for HEAVY CHECK MARK : ✔ span = QString(tr(" ✔ Found at %1 ")).arg(mod.localPath); @@ -111,9 +122,9 @@ void BlockedModsDialog::update() /// @param path the path to the changed directory void BlockedModsDialog::directoryChanged(QString path) { - qDebug() << "Directory changed: " << path; + qDebug() << "[Blocked Mods Dialog] Directory changed: " << path; validateMatchedMods(); - scanPath(path); + scanPath(path, true); } /// @brief add the user downloads folder and the global mods folder to the filesystem watcher @@ -121,22 +132,23 @@ void BlockedModsDialog::setupWatch() { const QString downloadsFolder = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); const QString modsFolder = APPLICATION->settings()->get("CentralModsDir").toString(); - watcher.addPath(downloadsFolder); - watcher.addPath(modsFolder); + m_watcher.addPath(downloadsFolder); + m_watcher.addPath(modsFolder); } /// @brief scan all watched folder void BlockedModsDialog::scanPaths() { - for (auto& dir : watcher.directories()) { - scanPath(dir); + for (auto& dir : m_watcher.directories()) { + scanPath(dir, false); } + runHashTask(); } /// @brief Scan the directory at path, skip paths that do not contain a file name /// of a blocked mod we are looking for /// @param path the directory to scan -void BlockedModsDialog::scanPath(QString path) +void BlockedModsDialog::scanPath(QString path, bool start_task) { QDir scan_dir(path); QDirIterator scan_it(path, QDir::Filter::Files | QDir::Filter::Hidden, QDirIterator::NoIteratorFlags); @@ -150,21 +162,35 @@ void BlockedModsDialog::scanPath(QString path) addHashTask(file); } - hashing_task->start(); + if (start_task) { + runHashTask(); + } + +} + +/// @brief add a hashing task for the file located at path, add the path to the pending set if the hasing task is already running +/// @param path the path to the local file being hashed +void BlockedModsDialog::addHashTask(QString path) { + if (m_hashing_task->isRunning()) { + qDebug() << "[Blocked Mods Dialog] adding a Hash task for" << path << "to the pending set."; + m_pending_hash_paths.insert(path); + } else { + buildHashTask(path); + } } /// @brief add a hashing task for the file located at path and connect it to check that hash against /// our blocked mods list /// @param path the path to the local file being hashed -void BlockedModsDialog::addHashTask(QString path) { +void BlockedModsDialog::buildHashTask(QString path) { auto hash_task = Hashing::createBlockedModHasher(path, ModPlatform::Provider::FLAME, "sha1"); - qDebug() << "Creating Hash task for path: " << path; + qDebug() << "[Blocked Mods Dialog] Creating Hash task for path: " << path; connect(hash_task.get(), &Task::succeeded, [this, hash_task, path] { checkMatchHash(hash_task->getResult(), path); }); connect(hash_task.get(), &Task::failed, [path] { qDebug() << "Failed to hash path: " << path; }); - hashing_task->addTask(hash_task); + m_hashing_task->addTask(hash_task); } /// @brief check if the computed hash for the provided path matches a blocked @@ -175,9 +201,9 @@ void BlockedModsDialog::checkMatchHash(QString hash, QString path) { bool match = false; - qDebug() << "Checking for match on hash: " << hash << "| From path:" << path; + qDebug() << "[Blocked Mods Dialog] Checking for match on hash: " << hash << "| From path:" << path; - for (auto& mod : mods) { + for (auto& mod : m_mods) { if (mod.matched) { continue; } @@ -186,7 +212,7 @@ void BlockedModsDialog::checkMatchHash(QString hash, QString path) mod.localPath = path; match = true; - qDebug() << "Hash match found:" << mod.name << hash << "| From path:" << path; + qDebug() << "[Blocked Mods Dialog] Hash match found:" << mod.name << hash << "| From path:" << path; break; } @@ -205,9 +231,9 @@ bool BlockedModsDialog::checkValidPath(QString path) QFileInfo file = QFileInfo(path); QString filename = file.fileName(); - for (auto& mod : mods) { + for (auto& mod : m_mods) { if (mod.name.compare(filename, Qt::CaseInsensitive) == 0) { - qDebug() << "Name match found:" << mod.name << "| From path:" << path; + qDebug() << "[Blocked Mods Dialog] Name match found:" << mod.name << "| From path:" << path; return true; } } @@ -217,13 +243,13 @@ bool BlockedModsDialog::checkValidPath(QString path) bool BlockedModsDialog::allModsMatched() { - return std::all_of(mods.begin(), mods.end(), [](auto const& mod) { return mod.matched; }); + return std::all_of(m_mods.begin(), m_mods.end(), [](auto const& mod) { return mod.matched; }); } /// @brief ensure matched file paths still exist void BlockedModsDialog::validateMatchedMods() { bool changed = false; - for (auto& mod : mods) { + for (auto& mod : m_mods) { if (mod.matched) { QFileInfo file = QFileInfo(mod.localPath); if (!file.exists() || !file.isFile()) { @@ -238,6 +264,33 @@ void BlockedModsDialog::validateMatchedMods() { } } +/// @brief run hast task or mark a pending run if it is already runing +void BlockedModsDialog::runHashTask() { + if (!m_hashing_task->isRunning()) { + m_rehash_pending = false; + m_hashing_task->start(); + } else { + qDebug() << "[Blocked Mods Dialog] queueing another run of the hashing task"; + qDebug() << "[Blocked Mods Dialog] pending hash tasks:" << m_pending_hash_paths; + m_rehash_pending = true; + } +} + +void BlockedModsDialog::hashTaskFinished() { + qDebug() << "[Blocked Mods Dialog] All hash tasks finished"; + if (m_rehash_pending) { + qDebug() << "[Blocked Mods Dialog] there was a pending rehash, building and running tasks"; + + auto path = m_pending_hash_paths.begin(); + while (path != m_pending_hash_paths.end()) { + buildHashTask(*path); + path = m_pending_hash_paths.erase(path); + } + + runHashTask(); + } +} + /// qDebug print support for the BlockedMod struct QDebug operator<<(QDebug debug, const BlockedMod& m) { diff --git a/launcher/ui/dialogs/BlockedModsDialog.h b/launcher/ui/dialogs/BlockedModsDialog.h index d683c54d..ee1e6a09 100644 --- a/launcher/ui/dialogs/BlockedModsDialog.h +++ b/launcher/ui/dialogs/BlockedModsDialog.h @@ -39,9 +39,11 @@ protected: private: Ui::BlockedModsDialog *ui; - QList &mods; - QFileSystemWatcher watcher; - shared_qobject_ptr hashing_task; + QList &m_mods; + QFileSystemWatcher m_watcher; + shared_qobject_ptr m_hashing_task; + QSet m_pending_hash_paths; + bool m_rehash_pending; void openAll(); void addDownloadFolder(); @@ -49,10 +51,13 @@ private: void directoryChanged(QString path); void setupWatch(); void scanPaths(); - void scanPath(QString path); + void scanPath(QString path, bool start_task); void addHashTask(QString path); + void buildHashTask(QString path); void checkMatchHash(QString hash, QString path); void validateMatchedMods(); + void runHashTask(); + void hashTaskFinished(); bool checkValidPath(QString path); bool allModsMatched(); From b9e2c3524ce39769396d1b4d6a2bf1b50a9f0996 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Fri, 11 Nov 2022 16:07:57 -0700 Subject: [PATCH 3/7] chore: clang format & cleanup Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/ui/dialogs/BlockedModsDialog.cpp | 45 ++++++++++++----------- launcher/ui/dialogs/BlockedModsDialog.h | 2 - 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/launcher/ui/dialogs/BlockedModsDialog.cpp b/launcher/ui/dialogs/BlockedModsDialog.cpp index a1941cb8..04d37963 100644 --- a/launcher/ui/dialogs/BlockedModsDialog.cpp +++ b/launcher/ui/dialogs/BlockedModsDialog.cpp @@ -6,19 +6,18 @@ #include "Application.h" #include "ui_BlockedModsDialog.h" - #include -#include #include #include #include +#include BlockedModsDialog::BlockedModsDialog(QWidget* parent, const QString& title, const QString& text, QList& mods) : QDialog(parent), ui(new Ui::BlockedModsDialog), m_mods(mods) { m_hashing_task = shared_qobject_ptr(new ConcurrentTask(this, "MakeHashesTask", 10)); connect(m_hashing_task.get(), &Task::finished, this, &BlockedModsDialog::hashTaskFinished); - + ui->setupUi(this); auto openAllButton = ui->buttonBox->addButton(tr("Open All"), QDialogButtonBox::ActionRole); @@ -29,8 +28,6 @@ BlockedModsDialog::BlockedModsDialog(QWidget* parent, const QString& title, cons connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &BlockedModsDialog::directoryChanged); - - qDebug() << "[Blocked Mods Dialog] Mods List: " << mods; setupWatch(); @@ -50,15 +47,16 @@ BlockedModsDialog::~BlockedModsDialog() delete ui; } -void BlockedModsDialog::dragEnterEvent(QDragEnterEvent *e) { +void BlockedModsDialog::dragEnterEvent(QDragEnterEvent* e) +{ if (e->mimeData()->hasUrls()) { e->acceptProposedAction(); } } -void BlockedModsDialog::dropEvent(QDropEvent *e) +void BlockedModsDialog::dropEvent(QDropEvent* e) { - foreach (const QUrl &url, e->mimeData()->urls()) { + foreach (const QUrl& url, e->mimeData()->urls()) { QString filePath = url.toLocalFile(); qDebug() << "[Blocked Mods Dialog] Dropped file:" << filePath; addHashTask(filePath); @@ -80,12 +78,11 @@ void BlockedModsDialog::openAll() } } -void BlockedModsDialog::addDownloadFolder() { - QString dir = QFileDialog::getExistingDirectory( - this, - tr("Select directory where you downloaded the mods"), - QStandardPaths::writableLocation(QStandardPaths::DownloadLocation), - QFileDialog::ShowDirsOnly); +void BlockedModsDialog::addDownloadFolder() +{ + QString dir = + QFileDialog::getExistingDirectory(this, tr("Select directory where you downloaded the mods"), + QStandardPaths::writableLocation(QStandardPaths::DownloadLocation), QFileDialog::ShowDirsOnly); qDebug() << "[Blocked Mods Dialog] Adding watch path:" << dir; m_watcher.addPath(dir); scanPath(dir, true); @@ -165,12 +162,12 @@ void BlockedModsDialog::scanPath(QString path, bool start_task) if (start_task) { runHashTask(); } - } /// @brief add a hashing task for the file located at path, add the path to the pending set if the hasing task is already running /// @param path the path to the local file being hashed -void BlockedModsDialog::addHashTask(QString path) { +void BlockedModsDialog::addHashTask(QString path) +{ if (m_hashing_task->isRunning()) { qDebug() << "[Blocked Mods Dialog] adding a Hash task for" << path << "to the pending set."; m_pending_hash_paths.insert(path); @@ -179,10 +176,11 @@ void BlockedModsDialog::addHashTask(QString path) { } } -/// @brief add a hashing task for the file located at path and connect it to check that hash against +/// @brief add a hashing task for the file located at path and connect it to check that hash against /// our blocked mods list /// @param path the path to the local file being hashed -void BlockedModsDialog::buildHashTask(QString path) { +void BlockedModsDialog::buildHashTask(QString path) +{ auto hash_task = Hashing::createBlockedModHasher(path, ModPlatform::Provider::FLAME, "sha1"); qDebug() << "[Blocked Mods Dialog] Creating Hash task for path: " << path; @@ -247,7 +245,8 @@ bool BlockedModsDialog::allModsMatched() } /// @brief ensure matched file paths still exist -void BlockedModsDialog::validateMatchedMods() { +void BlockedModsDialog::validateMatchedMods() +{ bool changed = false; for (auto& mod : m_mods) { if (mod.matched) { @@ -264,8 +263,9 @@ void BlockedModsDialog::validateMatchedMods() { } } -/// @brief run hast task or mark a pending run if it is already runing -void BlockedModsDialog::runHashTask() { +/// @brief run hash task or mark a pending run if it is already runing +void BlockedModsDialog::runHashTask() +{ if (!m_hashing_task->isRunning()) { m_rehash_pending = false; m_hashing_task->start(); @@ -276,7 +276,8 @@ void BlockedModsDialog::runHashTask() { } } -void BlockedModsDialog::hashTaskFinished() { +void BlockedModsDialog::hashTaskFinished() +{ qDebug() << "[Blocked Mods Dialog] All hash tasks finished"; if (m_rehash_pending) { qDebug() << "[Blocked Mods Dialog] there was a pending rehash, building and running tasks"; diff --git a/launcher/ui/dialogs/BlockedModsDialog.h b/launcher/ui/dialogs/BlockedModsDialog.h index ee1e6a09..dac43cba 100644 --- a/launcher/ui/dialogs/BlockedModsDialog.h +++ b/launcher/ui/dialogs/BlockedModsDialog.h @@ -33,8 +33,6 @@ public: protected: void dragEnterEvent(QDragEnterEvent *event) override; - // void dragMoveEvent(QDragMoveEvent *event) override; - // void dragLeaveEvent(QDragLeaveEvent *event) override; void dropEvent(QDropEvent *event) override; private: From 51c27e2748cca3d772cdd9656325b748a819f3c9 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Fri, 11 Nov 2022 16:33:52 -0700 Subject: [PATCH 4/7] always use the pending path set to avoid task duplication. Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/ui/dialogs/BlockedModsDialog.cpp | 32 ++++++++++++----------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/launcher/ui/dialogs/BlockedModsDialog.cpp b/launcher/ui/dialogs/BlockedModsDialog.cpp index 04d37963..ff331617 100644 --- a/launcher/ui/dialogs/BlockedModsDialog.cpp +++ b/launcher/ui/dialogs/BlockedModsDialog.cpp @@ -168,12 +168,8 @@ void BlockedModsDialog::scanPath(QString path, bool start_task) /// @param path the path to the local file being hashed void BlockedModsDialog::addHashTask(QString path) { - if (m_hashing_task->isRunning()) { - qDebug() << "[Blocked Mods Dialog] adding a Hash task for" << path << "to the pending set."; - m_pending_hash_paths.insert(path); - } else { - buildHashTask(path); - } + qDebug() << "[Blocked Mods Dialog] adding a Hash task for" << path << "to the pending set."; + m_pending_hash_paths.insert(path); } /// @brief add a hashing task for the file located at path and connect it to check that hash against @@ -252,6 +248,8 @@ void BlockedModsDialog::validateMatchedMods() if (mod.matched) { QFileInfo file = QFileInfo(mod.localPath); if (!file.exists() || !file.isFile()) { + qDebug() << "[Blocked Mods Dialog] File" << mod.localPath << "for mod" << mod.name + << "has vanshed! marking as not matched."; mod.localPath = ""; mod.matched = false; changed = true; @@ -268,7 +266,18 @@ void BlockedModsDialog::runHashTask() { if (!m_hashing_task->isRunning()) { m_rehash_pending = false; - m_hashing_task->start(); + + if (!m_pending_hash_paths.isEmpty()) { + qDebug() << "[Blocked Mods Dialog] there are pending hash tasks, building and running tasks"; + + auto path = m_pending_hash_paths.begin(); + while (path != m_pending_hash_paths.end()) { + buildHashTask(*path); + path = m_pending_hash_paths.erase(path); + } + + m_hashing_task->start(); + } } else { qDebug() << "[Blocked Mods Dialog] queueing another run of the hashing task"; qDebug() << "[Blocked Mods Dialog] pending hash tasks:" << m_pending_hash_paths; @@ -280,14 +289,7 @@ void BlockedModsDialog::hashTaskFinished() { qDebug() << "[Blocked Mods Dialog] All hash tasks finished"; if (m_rehash_pending) { - qDebug() << "[Blocked Mods Dialog] there was a pending rehash, building and running tasks"; - - auto path = m_pending_hash_paths.begin(); - while (path != m_pending_hash_paths.end()) { - buildHashTask(*path); - path = m_pending_hash_paths.erase(path); - } - + qDebug() << "[Blocked Mods Dialog] task finished with a rehash pending, rerunning"; runHashTask(); } } From 9af1b00df52d974a53925345efcd5c047b7d041c Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Fri, 11 Nov 2022 18:05:19 -0700 Subject: [PATCH 5/7] feat: add list of watched folders move explanation text into dialog class and it's own label Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- .../flame/FlameInstanceCreationTask.cpp | 11 ++-- .../modpacksch/FTBPackInstallTask.cpp | 15 ++--- launcher/ui/dialogs/BlockedModsDialog.cpp | 27 +++++++-- launcher/ui/dialogs/BlockedModsDialog.ui | 58 ++++++++++++++++++- 4 files changed, 86 insertions(+), 25 deletions(-) diff --git a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp index 4b9e7b86..91554b58 100644 --- a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp +++ b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp @@ -393,13 +393,10 @@ void FlameCreationTask::idResolverSucceeded(QEventLoop& loop) qWarning() << "Blocked mods found, displaying mod list"; auto message_dialog = new BlockedModsDialog(m_parent, tr("Blocked mods found"), - tr("The following files are not available for download in third party launchers.
" - "You will need to manually download them and add them to the instance.

" - "Your configured global mods folder and default downloads folder
" - "are automatically checked for the downloaded mods and they will be copied to the instance if found.
" - "Optionally, you may drag and drop the downloaded mods onto this dialog or add a folder to watch
" - "if you did not download the mods to a default location."), - blocked_mods); + tr("The following files are not available for download in third party launchers.
" + "You will need to manually download them and add them to the instance."), + blocked_mods); + message_dialog->setModal(true); if (message_dialog->exec()) { diff --git a/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp b/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp index 26d0c5a1..4c7b7a4f 100644 --- a/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp +++ b/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp @@ -211,22 +211,17 @@ void PackInstallTask::onResolveModsSucceeded() qDebug() << "Blocked files found, displaying file list"; auto message_dialog = new BlockedModsDialog(m_parent, tr("Blocked files found"), - tr("The following files are not available for download in third party launchers.
" - "You will need to manually download them and add them to the instance.

" - "Your configured global mods folder and default downloads folder
" - "are automatically checked for the downloaded mods and they will be copied to the instance if found.
" - "Optionally, you may drag and drop the downloaded mods onto this dialog or add a folder to watch
" - "if you did not download the mods to a default location."), - m_blocked_mods); + tr("The following files are not available for download in third party launchers.
" + "You will need to manually download them and add them to the instance."), + m_blocked_mods); if (message_dialog->exec() == QDialog::Accepted) { qDebug() << "Post dialog blocked mods list: " << m_blocked_mods; createInstance(); - } - else { + } else { abort(); } - + } else { createInstance(); } diff --git a/launcher/ui/dialogs/BlockedModsDialog.cpp b/launcher/ui/dialogs/BlockedModsDialog.cpp index ff331617..7f6b377b 100644 --- a/launcher/ui/dialogs/BlockedModsDialog.cpp +++ b/launcher/ui/dialogs/BlockedModsDialog.cpp @@ -1,5 +1,4 @@ #include "BlockedModsDialog.h" -#include #include #include #include @@ -34,7 +33,16 @@ BlockedModsDialog::BlockedModsDialog(QWidget* parent, const QString& title, cons scanPaths(); this->setWindowTitle(title); - ui->label->setText(text); + ui->labelDescription->setText(text); + ui->labelExplain->setText( + QString(tr("Your configured global mods folder and default downloads folder " + "are automatically checked for the downloaded mods and they will be copied to the instance if found.
" + "Optionally, you may drag and drop the downloaded mods onto this dialog or add a folder to watch " + "if you did not download the mods to a default location.

" + "Global Mods Folder: %1
" + "Default Downloads Folder: %2")) + .arg(APPLICATION->settings()->get("CentralModsDir").toString(), + QStandardPaths::writableLocation(QStandardPaths::DownloadLocation))); ui->labelModsFound->setText(tr("Please download the missing mods.")); setAcceptDrops(true); @@ -56,7 +64,7 @@ void BlockedModsDialog::dragEnterEvent(QDragEnterEvent* e) void BlockedModsDialog::dropEvent(QDropEvent* e) { - foreach (const QUrl& url, e->mimeData()->urls()) { + for (const QUrl& url : e->mimeData()->urls()) { QString filePath = url.toLocalFile(); qDebug() << "[Blocked Mods Dialog] Dropped file:" << filePath; addHashTask(filePath); @@ -106,7 +114,14 @@ void BlockedModsDialog::update() text += QString(tr("%1: %2

Hash: %3 %4


")).arg(mod.name, mod.websiteUrl, mod.hash, span); } - ui->textBrowser->setText(text); + ui->textBrowserModsListing->setText(text); + + QString watching; + for (auto& dir : m_watcher.directories()) { + watching += QString("%1
").arg(dir); + } + + ui->textBrowserWatched->setText(watching); if (allModsMatched()) { ui->labelModsFound->setText(tr("All mods found ✔")); @@ -181,8 +196,8 @@ void BlockedModsDialog::buildHashTask(QString path) qDebug() << "[Blocked Mods Dialog] Creating Hash task for path: " << path; - connect(hash_task.get(), &Task::succeeded, [this, hash_task, path] { checkMatchHash(hash_task->getResult(), path); }); - connect(hash_task.get(), &Task::failed, [path] { qDebug() << "Failed to hash path: " << path; }); + connect(hash_task.get(), &Task::succeeded, this, [this, hash_task, path] { checkMatchHash(hash_task->getResult(), path); }); + connect(hash_task.get(), &Task::failed, this, [path] { qDebug() << "Failed to hash path: " << path; }); m_hashing_task->addTask(hash_task); } diff --git a/launcher/ui/dialogs/BlockedModsDialog.ui b/launcher/ui/dialogs/BlockedModsDialog.ui index 371549cf..fb1036b7 100644 --- a/launcher/ui/dialogs/BlockedModsDialog.ui +++ b/launcher/ui/dialogs/BlockedModsDialog.ui @@ -15,17 +15,36 @@ - + Qt::RichText + + true + - + + + + + + true + + + + + + + + 0 + 165 + + true @@ -34,6 +53,41 @@ + + + + + 0 + 1 + + + + Watched Folders: + + + + + + + + 0 + 0 + + + + + 0 + 16 + + + + + 0 + 12 + + + + From 25b306b7e1c83ecdeb135c8100c3089d9147cde7 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Fri, 11 Nov 2022 18:32:11 -0700 Subject: [PATCH 6/7] feat: mark folder paths as links Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/ui/dialogs/BlockedModsDialog.cpp | 9 ++++++--- launcher/ui/dialogs/BlockedModsDialog.ui | 9 +++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/launcher/ui/dialogs/BlockedModsDialog.cpp b/launcher/ui/dialogs/BlockedModsDialog.cpp index 7f6b377b..a0dd1a10 100644 --- a/launcher/ui/dialogs/BlockedModsDialog.cpp +++ b/launcher/ui/dialogs/BlockedModsDialog.cpp @@ -39,12 +39,15 @@ BlockedModsDialog::BlockedModsDialog(QWidget* parent, const QString& title, cons "are automatically checked for the downloaded mods and they will be copied to the instance if found.
" "Optionally, you may drag and drop the downloaded mods onto this dialog or add a folder to watch " "if you did not download the mods to a default location.

" - "Global Mods Folder: %1
" - "Default Downloads Folder: %2")) + "Global Mods Folder: %1
" + "Default Downloads Folder: %2")) .arg(APPLICATION->settings()->get("CentralModsDir").toString(), QStandardPaths::writableLocation(QStandardPaths::DownloadLocation))); ui->labelModsFound->setText(tr("Please download the missing mods.")); + // force all URL handeling as external + connect(ui->textBrowserWatched, &QTextBrowser::anchorClicked, this, [](const QUrl url) { QDesktopServices::openUrl(url); }); + setAcceptDrops(true); update(); @@ -118,7 +121,7 @@ void BlockedModsDialog::update() QString watching; for (auto& dir : m_watcher.directories()) { - watching += QString("%1
").arg(dir); + watching += QString("%1
").arg(dir); } ui->textBrowserWatched->setText(watching); diff --git a/launcher/ui/dialogs/BlockedModsDialog.ui b/launcher/ui/dialogs/BlockedModsDialog.ui index fb1036b7..88105178 100644 --- a/launcher/ui/dialogs/BlockedModsDialog.ui +++ b/launcher/ui/dialogs/BlockedModsDialog.ui @@ -35,6 +35,9 @@ true + + true +
@@ -86,6 +89,12 @@ 12 + + true + + + false + From 52d43f843bceb861c92f8989a27194436924e087 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Thu, 17 Nov 2022 11:46:14 -0700 Subject: [PATCH 7/7] feat(BlockModsDialog): remove redundant Ui info Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/ui/dialogs/BlockedModsDialog.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/launcher/ui/dialogs/BlockedModsDialog.cpp b/launcher/ui/dialogs/BlockedModsDialog.cpp index a0dd1a10..edb4ff7d 100644 --- a/launcher/ui/dialogs/BlockedModsDialog.cpp +++ b/launcher/ui/dialogs/BlockedModsDialog.cpp @@ -38,12 +38,9 @@ BlockedModsDialog::BlockedModsDialog(QWidget* parent, const QString& title, cons QString(tr("Your configured global mods folder and default downloads folder " "are automatically checked for the downloaded mods and they will be copied to the instance if found.
" "Optionally, you may drag and drop the downloaded mods onto this dialog or add a folder to watch " - "if you did not download the mods to a default location.

" - "Global Mods Folder: %1
" - "Default Downloads Folder: %2")) + "if you did not download the mods to a default location.")) .arg(APPLICATION->settings()->get("CentralModsDir").toString(), QStandardPaths::writableLocation(QStandardPaths::DownloadLocation))); - ui->labelModsFound->setText(tr("Please download the missing mods.")); // force all URL handeling as external connect(ui->textBrowserWatched, &QTextBrowser::anchorClicked, this, [](const QUrl url) { QDesktopServices::openUrl(url); }); @@ -127,7 +124,7 @@ void BlockedModsDialog::update() ui->textBrowserWatched->setText(watching); if (allModsMatched()) { - ui->labelModsFound->setText(tr("All mods found ✔")); + ui->labelModsFound->setText("" + tr("All mods found")); } else { ui->labelModsFound->setText(tr("Please download the missing mods.")); }