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