Merge pull request #304 from Ryex/move-downloads
Fixes https://github.com/PrismLauncher/PrismLauncher/issues/222
This commit is contained in:
@ -1,28 +1,186 @@
|
||||
#include "BlockedModsDialog.h"
|
||||
#include "ui_BlockedModsDialog.h"
|
||||
#include <QPushButton>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDesktopServices>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QPushButton>
|
||||
#include "Application.h"
|
||||
#include "ui_BlockedModsDialog.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QStandardPaths>
|
||||
|
||||
BlockedModsDialog::BlockedModsDialog(QWidget *parent, const QString &title, const QString &text, const QString &body, const QList<QUrl> &urls) :
|
||||
QDialog(parent), ui(new Ui::BlockedModsDialog), urls(urls) {
|
||||
BlockedModsDialog::BlockedModsDialog(QWidget* parent, const QString& title, const QString& text, QList<BlockedMod>& mods)
|
||||
: QDialog(parent), ui(new Ui::BlockedModsDialog), mods(mods)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
auto openAllButton = ui->buttonBox->addButton(tr("Open All"), QDialogButtonBox::ActionRole);
|
||||
connect(openAllButton, &QPushButton::clicked, this, &BlockedModsDialog::openAll);
|
||||
|
||||
connect(&watcher, &QFileSystemWatcher::directoryChanged, this, &BlockedModsDialog::directoryChanged);
|
||||
|
||||
hashing_task = shared_qobject_ptr<ConcurrentTask>(new ConcurrentTask(this, "MakeHashesTask", 10));
|
||||
|
||||
qDebug() << "Mods List: " << mods;
|
||||
|
||||
setupWatch();
|
||||
scanPaths();
|
||||
|
||||
this->setWindowTitle(title);
|
||||
ui->label->setText(text);
|
||||
ui->textBrowser->setText(body);
|
||||
ui->labelModsFound->setText(tr("Please download the missing mods."));
|
||||
update();
|
||||
}
|
||||
|
||||
BlockedModsDialog::~BlockedModsDialog() {
|
||||
BlockedModsDialog::~BlockedModsDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void BlockedModsDialog::openAll() {
|
||||
for(auto &url : urls) {
|
||||
QDesktopServices::openUrl(url);
|
||||
void BlockedModsDialog::openAll()
|
||||
{
|
||||
for (auto& mod : mods) {
|
||||
QDesktopServices::openUrl(mod.websiteUrl);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief update UI with current status of the blocked mod detection
|
||||
void BlockedModsDialog::update()
|
||||
{
|
||||
QString text;
|
||||
QString span;
|
||||
|
||||
for (auto& mod : mods) {
|
||||
if (mod.matched) {
|
||||
// ✔ -> html for HEAVY CHECK MARK : ✔
|
||||
span = QString(tr("<span style=\"color:green\"> ✔ Found at %1 </span>")).arg(mod.localPath);
|
||||
} else {
|
||||
// ✘ -> html for HEAVY BALLOT X : ✘
|
||||
span = QString(tr("<span style=\"color:red\"> ✘ Not Found </span>"));
|
||||
}
|
||||
text += QString(tr("%1: <a href='%2'>%2</a> <p>Hash: %3 %4</p> <br/>")).arg(mod.name, mod.websiteUrl, mod.hash, span);
|
||||
}
|
||||
|
||||
ui->textBrowser->setText(text);
|
||||
|
||||
if (allModsMatched()) {
|
||||
ui->labelModsFound->setText(tr("All mods found ✔"));
|
||||
} else {
|
||||
ui->labelModsFound->setText(tr("Please download the missing mods."));
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Signal fired when a watched direcotry has changed
|
||||
/// @param path the path to the changed directory
|
||||
void BlockedModsDialog::directoryChanged(QString path)
|
||||
{
|
||||
qDebug() << "Directory changed: " << path;
|
||||
scanPath(path);
|
||||
}
|
||||
|
||||
/// @brief add the user downloads folder and the global mods folder to the filesystem watcher
|
||||
void BlockedModsDialog::setupWatch()
|
||||
{
|
||||
const QString downloadsFolder = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
|
||||
const QString modsFolder = APPLICATION->settings()->get("CentralModsDir").toString();
|
||||
watcher.addPath(downloadsFolder);
|
||||
watcher.addPath(modsFolder);
|
||||
}
|
||||
|
||||
/// @brief scan all watched folder
|
||||
void BlockedModsDialog::scanPaths()
|
||||
{
|
||||
for (auto& dir : watcher.directories()) {
|
||||
scanPath(dir);
|
||||
}
|
||||
}
|
||||
|
||||
/// @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)
|
||||
{
|
||||
QDir scan_dir(path);
|
||||
QDirIterator scan_it(path, QDir::Filter::Files | QDir::Filter::Hidden, QDirIterator::NoIteratorFlags);
|
||||
while (scan_it.hasNext()) {
|
||||
QString file = scan_it.next();
|
||||
|
||||
if (!checkValidPath(file)) {
|
||||
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);
|
||||
}
|
||||
|
||||
hashing_task->start();
|
||||
}
|
||||
|
||||
/// @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
|
||||
/// @param path the path to the local file being compared
|
||||
void BlockedModsDialog::checkMatchHash(QString hash, QString path)
|
||||
{
|
||||
bool match = false;
|
||||
|
||||
qDebug() << "Checking for match on hash: " << hash << "| From path:" << path;
|
||||
|
||||
for (auto& mod : mods) {
|
||||
if (mod.matched) {
|
||||
continue;
|
||||
}
|
||||
if (mod.hash.compare(hash, Qt::CaseInsensitive) == 0) {
|
||||
mod.matched = true;
|
||||
mod.localPath = path;
|
||||
match = true;
|
||||
|
||||
qDebug() << "Hash match found:" << mod.name << hash << "| From path:" << path;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Check if the name of the file at path matches the name of a blocked mod we are searching for
|
||||
/// @param path the path to check
|
||||
/// @return boolean: did the path match the name of a blocked mod?
|
||||
bool BlockedModsDialog::checkValidPath(QString path)
|
||||
{
|
||||
QFileInfo file = QFileInfo(path);
|
||||
QString filename = file.fileName();
|
||||
|
||||
for (auto& mod : mods) {
|
||||
if (mod.name.compare(filename, Qt::CaseInsensitive) == 0) {
|
||||
qDebug() << "Name match found:" << mod.name << "| From path:" << path;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BlockedModsDialog::allModsMatched()
|
||||
{
|
||||
return std::all_of(mods.begin(), mods.end(), [](auto const& mod) { return mod.matched; });
|
||||
}
|
||||
|
||||
/// qDebug print support for the BlockedMod struct
|
||||
QDebug operator<<(QDebug debug, const BlockedMod& m)
|
||||
{
|
||||
QDebugStateSaver saver(debug);
|
||||
|
||||
debug.nospace() << "{ name: " << m.name << ", websiteUrl: " << m.websiteUrl << ", hash: " << m.hash << ", matched: " << m.matched
|
||||
<< ", localPath: " << m.localPath << "}";
|
||||
|
||||
return debug;
|
||||
}
|
||||
|
@ -1,7 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
|
||||
#include <QFileSystemWatcher>
|
||||
|
||||
#include "modplatform/helpers/HashUtils.h"
|
||||
|
||||
#include "tasks/ConcurrentTask.h"
|
||||
|
||||
struct BlockedMod {
|
||||
QString name;
|
||||
QString websiteUrl;
|
||||
QString hash;
|
||||
bool matched;
|
||||
QString localPath;
|
||||
|
||||
};
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class BlockedModsDialog; }
|
||||
@ -11,12 +27,27 @@ class BlockedModsDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
BlockedModsDialog(QWidget *parent, const QString &title, const QString &text, const QString &body, const QList<QUrl> &urls);
|
||||
BlockedModsDialog(QWidget *parent, const QString &title, const QString &text, QList<BlockedMod> &mods);
|
||||
|
||||
~BlockedModsDialog() override;
|
||||
|
||||
|
||||
private:
|
||||
Ui::BlockedModsDialog *ui;
|
||||
const QList<QUrl> &urls;
|
||||
QList<BlockedMod> &mods;
|
||||
QFileSystemWatcher watcher;
|
||||
shared_qobject_ptr<ConcurrentTask> hashing_task;
|
||||
|
||||
void openAll();
|
||||
void update();
|
||||
void directoryChanged(QString path);
|
||||
void setupWatch();
|
||||
void scanPaths();
|
||||
void scanPath(QString path);
|
||||
void checkMatchHash(QString hash, QString path);
|
||||
|
||||
bool checkValidPath(QString path);
|
||||
bool allModsMatched();
|
||||
};
|
||||
|
||||
QDebug operator<<(QDebug debug, const BlockedMod &m);
|
||||
|
@ -13,8 +13,8 @@
|
||||
<property name="windowTitle">
|
||||
<string notr="true">BlockedModsDialog</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
@ -24,17 +24,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="textBrowser">
|
||||
<property name="acceptRichText">
|
||||
<bool>true</bool>
|
||||
@ -44,6 +34,27 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="bottomBoxH">
|
||||
<item>
|
||||
<widget class="QLabel" name="labelModsFound">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
|
Reference in New Issue
Block a user