diff options
| author | Mikaël Capelle <capelle.mikael@gmail.com> | 2022-05-17 11:47:01 +0200 |
|---|---|---|
| committer | Mikaël Capelle <capelle.mikael@gmail.com> | 2023-07-09 17:20:40 +0200 |
| commit | d13f6bb870cdda71257f665367be8ef9fca86255 (patch) | |
| tree | 52e214718478f1e52856572f5aa1a2ac58537f9f | |
| parent | 86bb01ba9eac879d3685c439ac9da0028bc4bc80 (diff) | |
Apply clang-format.
309 files changed, 17621 insertions, 17688 deletions
diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..6098e1f5 --- /dev/null +++ b/.clang-format @@ -0,0 +1,41 @@ +--- +# We'll use defaults from the LLVM style, but with 4 columns indentation. +BasedOnStyle: LLVM +IndentWidth: 2 +--- +Language: Cpp +DeriveLineEnding: false +UseCRLF: true +DerivePointerAlignment: false +PointerAlignment: Left +AlignConsecutiveAssignments: true +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: Empty +AlwaysBreakTemplateDeclarations: Yes +AccessModifierOffset: -2 +AlignTrailingComments: true +SpacesBeforeTrailingComments: 2 +NamespaceIndentation: Inner +MaxEmptyLinesToKeep: 1 +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: false + AfterClass: true + AfterControlStatement: false + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: true +ColumnLimit: 88 +ForEachMacros: ['Q_FOREACH', 'foreach'] diff --git a/src/aboutdialog.cpp b/src/aboutdialog.cpp index a8b8d81d..d61aa4fa 100644 --- a/src/aboutdialog.cpp +++ b/src/aboutdialog.cpp @@ -17,45 +17,43 @@ You should have received a copy of the GNU General Public License along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ - #include "aboutdialog.h" -#include "ui_aboutdialog.h" #include "shared/util.h" +#include "ui_aboutdialog.h" #include <utility.h> #include <QApplication> +#include <QFontDatabase> #include <QLabel> #include <QListWidget> #include <QListWidgetItem> #include <QTextBrowser> #include <QVariant> #include <Qt> -#include <QFontDatabase> -AboutDialog::AboutDialog(const QString &version, QWidget *parent) - : QDialog(parent) - , ui(new Ui::AboutDialog) +AboutDialog::AboutDialog(const QString& version, QWidget* parent) + : QDialog(parent), ui(new Ui::AboutDialog) { ui->setupUi(this); - m_LicenseFiles[LICENSE_LGPL3] = "LGPL-v3.0.txt"; - m_LicenseFiles[LICENSE_LGPL21] = "GNU-LGPL-v2.1.txt"; - m_LicenseFiles[LICENSE_GPL3] = "GPL-v3.0.txt"; - m_LicenseFiles[LICENSE_GPL2] = "GPL-v2.0.txt"; - m_LicenseFiles[LICENSE_BOOST] = "boost.txt"; - m_LicenseFiles[LICENSE_7ZIP] = "7zip.txt"; - m_LicenseFiles[LICENSE_CCBY3] = "BY-SA-v3.0.txt"; - m_LicenseFiles[LICENSE_ZLIB] = "zlib.txt"; - m_LicenseFiles[LICENSE_PYTHON] = "python.txt"; - m_LicenseFiles[LICENSE_SSL] = "openssl.txt"; + m_LicenseFiles[LICENSE_LGPL3] = "LGPL-v3.0.txt"; + m_LicenseFiles[LICENSE_LGPL21] = "GNU-LGPL-v2.1.txt"; + m_LicenseFiles[LICENSE_GPL3] = "GPL-v3.0.txt"; + m_LicenseFiles[LICENSE_GPL2] = "GPL-v2.0.txt"; + m_LicenseFiles[LICENSE_BOOST] = "boost.txt"; + m_LicenseFiles[LICENSE_7ZIP] = "7zip.txt"; + m_LicenseFiles[LICENSE_CCBY3] = "BY-SA-v3.0.txt"; + m_LicenseFiles[LICENSE_ZLIB] = "zlib.txt"; + m_LicenseFiles[LICENSE_PYTHON] = "python.txt"; + m_LicenseFiles[LICENSE_SSL] = "openssl.txt"; m_LicenseFiles[LICENSE_CPPTOML] = "cpptoml.txt"; - m_LicenseFiles[LICENSE_UDIS] = "udis86.txt"; - m_LicenseFiles[LICENSE_SPDLOG] = "spdlog.txt"; - m_LicenseFiles[LICENSE_FMT] = "fmt.txt"; - m_LicenseFiles[LICENSE_SIP] = "sip.txt"; - m_LicenseFiles[LICENSE_CASTLE] = "Castle.txt"; - m_LicenseFiles[LICENSE_ANTLR] = "AntlrBuildTask.txt"; - m_LicenseFiles[LICENSE_DXTEX] = "DXTex.txt"; + m_LicenseFiles[LICENSE_UDIS] = "udis86.txt"; + m_LicenseFiles[LICENSE_SPDLOG] = "spdlog.txt"; + m_LicenseFiles[LICENSE_FMT] = "fmt.txt"; + m_LicenseFiles[LICENSE_SIP] = "sip.txt"; + m_LicenseFiles[LICENSE_CASTLE] = "Castle.txt"; + m_LicenseFiles[LICENSE_ANTLR] = "AntlrBuildTask.txt"; + m_LicenseFiles[LICENSE_DXTEX] = "DXTex.txt"; addLicense("Qt", LICENSE_LGPL3); addLicense("Qt Json", LICENSE_GPL3); @@ -64,7 +62,8 @@ AboutDialog::AboutDialog(const QString &version, QWidget *parent) addLicense("ZLib", LICENSE_NONE); addLicense("Tango Icon Theme", LICENSE_NONE); addLicense("RRZE Icon Set", LICENSE_CCBY3); - addLicense("Icons by Lorc, Delapouite and sbed available on http://game-icons.net", LICENSE_CCBY3); + addLicense("Icons by Lorc, Delapouite and sbed available on http://game-icons.net", + LICENSE_CCBY3); addLicense("Castle Core", LICENSE_CASTLE); addLicense("ANTLR", LICENSE_ANTLR); addLicense("LOOT", LICENSE_GPL3); @@ -77,7 +76,10 @@ AboutDialog::AboutDialog(const QString &version, QWidget *parent) addLicense("SIP", LICENSE_SIP); addLicense("DXTex Headers", LICENSE_DXTEX); - ui->nameLabel->setText(QString("<span style=\"font-size:12pt; font-weight:600;\">%1 %2</span>").arg(ui->nameLabel->text()).arg(version)); + ui->nameLabel->setText( + QString("<span style=\"font-size:12pt; font-weight:600;\">%1 %2</span>") + .arg(ui->nameLabel->text()) + .arg(version)); #if defined(HGID) ui->revisionLabel->setText(ui->revisionLabel->text() + " " + HGID); #elif defined(GITID) @@ -86,39 +88,37 @@ AboutDialog::AboutDialog(const QString &version, QWidget *parent) ui->revisionLabel->setText(ui->revisionLabel->text() + " unknown"); #endif - - ui->usvfsLabel->setText(ui->usvfsLabel->text() + " " + MOShared::getUsvfsVersionString()); + ui->usvfsLabel->setText(ui->usvfsLabel->text() + " " + + MOShared::getUsvfsVersionString()); ui->licenseText->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); } - AboutDialog::~AboutDialog() { delete ui; } - -void AboutDialog::addLicense(const QString &name, Licenses license) +void AboutDialog::addLicense(const QString& name, Licenses license) { - QListWidgetItem *item = new QListWidgetItem(name); + QListWidgetItem* item = new QListWidgetItem(name); item->setData(Qt::UserRole, license); ui->creditsList->addItem(item); } - -void AboutDialog::on_creditsList_currentItemChanged(QListWidgetItem *current, QListWidgetItem*) +void AboutDialog::on_creditsList_currentItemChanged(QListWidgetItem* current, + QListWidgetItem*) { auto iter = m_LicenseFiles.find(current->data(Qt::UserRole).toInt()); if (iter != m_LicenseFiles.end()) { QString filePath = qApp->applicationDirPath() + "/licenses/" + iter->second; - QString text = MOBase::readFileText(filePath); + QString text = MOBase::readFileText(filePath); ui->licenseText->setText(text); } else { ui->licenseText->setText(tr("No license")); } } -void AboutDialog::on_sourceText_linkActivated(const QString &link) +void AboutDialog::on_sourceText_linkActivated(const QString& link) { MOBase::shell::Open(QUrl(link)); } diff --git a/src/aboutdialog.h b/src/aboutdialog.h index f029f931..8b95e2e7 100644 --- a/src/aboutdialog.h +++ b/src/aboutdialog.h @@ -18,7 +18,6 @@ You should have received a copy of the GNU General Public License along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ - #define ABOUTDIALOG_H #include <QDialog> @@ -28,8 +27,9 @@ class QListWidgetItem; #include <map> -namespace Ui { - class AboutDialog; +namespace Ui +{ +class AboutDialog; } class AboutDialog : public QDialog @@ -37,12 +37,12 @@ class AboutDialog : public QDialog Q_OBJECT public: - explicit AboutDialog(const QString &version, QWidget *parent = 0); + explicit AboutDialog(const QString& version, QWidget* parent = 0); ~AboutDialog(); private: - - enum Licenses { + enum Licenses + { LICENSE_NONE, LICENSE_LGPL3, LICENSE_LGPL21, @@ -65,19 +65,17 @@ private: }; private: - - void addLicense(const QString &name, Licenses license); + void addLicense(const QString& name, Licenses license); private slots: - void on_creditsList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous); - void on_sourceText_linkActivated(const QString &link); + void on_creditsList_currentItemChanged(QListWidgetItem* current, + QListWidgetItem* previous); + void on_sourceText_linkActivated(const QString& link); private: - - Ui::AboutDialog *ui; + Ui::AboutDialog* ui; std::map<int, QString> m_LicenseFiles; - }; -#endif // ABOUTDIALOG_H +#endif // ABOUTDIALOG_H diff --git a/src/activatemodsdialog.cpp b/src/activatemodsdialog.cpp index 4870d62b..67ad5b48 100644 --- a/src/activatemodsdialog.cpp +++ b/src/activatemodsdialog.cpp @@ -28,13 +28,14 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QtGlobal> -ActivateModsDialog::ActivateModsDialog(SaveGameInfo::MissingAssets const &missingAssets, QWidget *parent) - : TutorableDialog("ActivateMods", parent), ui(new Ui::ActivateModsDialog) +ActivateModsDialog::ActivateModsDialog(SaveGameInfo::MissingAssets const& missingAssets, + QWidget* parent) + : TutorableDialog("ActivateMods", parent), ui(new Ui::ActivateModsDialog) { ui->setupUi(this); - QTableWidget *modsTable = findChild<QTableWidget*>("modsTable"); - QHeaderView *headerView = modsTable->horizontalHeader(); + QTableWidget* modsTable = findChild<QTableWidget*>("modsTable"); + QHeaderView* headerView = modsTable->horizontalHeader(); headerView->setSectionResizeMode(0, QHeaderView::Stretch); headerView->setSectionResizeMode(1, QHeaderView::Interactive); @@ -49,7 +50,7 @@ ActivateModsDialog::ActivateModsDialog(SaveGameInfo::MissingAssets const &missin modsTable->setCellWidget(row, 1, new QLabel(tr("not found"))); } else { QComboBox* combo = new QComboBox(); - for (QString const &mod : espIter.value()) { + for (QString const& mod : espIter.value()) { combo->addItem(mod); } modsTable->setCellWidget(row, 1, combo); @@ -57,20 +58,18 @@ ActivateModsDialog::ActivateModsDialog(SaveGameInfo::MissingAssets const &missin } } - ActivateModsDialog::~ActivateModsDialog() { delete ui; } - std::set<QString> ActivateModsDialog::getModsToActivate() { std::set<QString> result; - QTableWidget *modsTable = findChild<QTableWidget*>("modsTable"); + QTableWidget* modsTable = findChild<QTableWidget*>("modsTable"); for (int row = 0; row < modsTable->rowCount(); ++row) { - QComboBox *comboBox = dynamic_cast<QComboBox*>(modsTable->cellWidget(row, 1)); + QComboBox* comboBox = dynamic_cast<QComboBox*>(modsTable->cellWidget(row, 1)); if (comboBox != nullptr) { result.insert(comboBox->currentText()); } @@ -78,16 +77,15 @@ std::set<QString> ActivateModsDialog::getModsToActivate() return result; } - std::set<QString> ActivateModsDialog::getESPsToActivate() { std::set<QString> result; - QTableWidget *modsTable = findChild<QTableWidget*>("modsTable"); + QTableWidget* modsTable = findChild<QTableWidget*>("modsTable"); for (int row = 0; row < modsTable->rowCount(); ++row) { - QComboBox *comboBox = dynamic_cast<QComboBox*>(modsTable->cellWidget(row, 1)); + QComboBox* comboBox = dynamic_cast<QComboBox*>(modsTable->cellWidget(row, 1)); if (comboBox != nullptr) { - QLabel *espName = dynamic_cast<QLabel*>(modsTable->cellWidget(row, 0)); + QLabel* espName = dynamic_cast<QLabel*>(modsTable->cellWidget(row, 0)); result.insert(espName->text()); } diff --git a/src/activatemodsdialog.h b/src/activatemodsdialog.h index 0c94d1d1..f7fd719f 100644 --- a/src/activatemodsdialog.h +++ b/src/activatemodsdialog.h @@ -30,8 +30,9 @@ class QWidget; #include <set> -namespace Ui { - class ActivateModsDialog; +namespace Ui +{ +class ActivateModsDialog; } /** @@ -42,13 +43,14 @@ class ActivateModsDialog : public MOBase::TutorableDialog Q_OBJECT public: - /** - * @brief constructor - * - * @param missingPlugins a map containing missing plugins that need to be activated - * @param parent ... Defaults to 0. - **/ - explicit ActivateModsDialog(SaveGameInfo::MissingAssets const &missingAssets, QWidget *parent = 0); + /** + * @brief constructor + * + * @param missingPlugins a map containing missing plugins that need to be activated + * @param parent ... Defaults to 0. + **/ + explicit ActivateModsDialog(SaveGameInfo::MissingAssets const& missingAssets, + QWidget* parent = 0); ~ActivateModsDialog(); /** @@ -63,14 +65,15 @@ public: /** * @brief get a list of plugins that should be activated * - * @return set< QString > the plugins to activate. This contains only plugins that become available after enabling the mods retrieved with getModsToActivate + * @return set< QString > the plugins to activate. This contains only plugins that + *become available after enabling the mods retrieved with getModsToActivate **/ std::set<QString> getESPsToActivate(); private slots: private: - Ui::ActivateModsDialog *ui; + Ui::ActivateModsDialog* ui; }; -#endif // ACTIVATEMODSDIALOG_H +#endif // ACTIVATEMODSDIALOG_H diff --git a/src/apiuseraccount.cpp b/src/apiuseraccount.cpp index 976dd488..4b908df0 100644 --- a/src/apiuseraccount.cpp +++ b/src/apiuseraccount.cpp @@ -2,25 +2,20 @@ QString localizedUserAccountType(APIUserAccountTypes t) { - switch (t) - { - case APIUserAccountTypes::Regular: - return QObject::tr("Regular"); + switch (t) { + case APIUserAccountTypes::Regular: + return QObject::tr("Regular"); - case APIUserAccountTypes::Premium: - return QObject::tr("Premium"); + case APIUserAccountTypes::Premium: + return QObject::tr("Premium"); - case APIUserAccountTypes::None: // fall-through - default: - return QObject::tr("None"); + case APIUserAccountTypes::None: // fall-through + default: + return QObject::tr("None"); } } - -APIUserAccount::APIUserAccount() - : m_type(APIUserAccountTypes::None) -{ -} +APIUserAccount::APIUserAccount() : m_type(APIUserAccountTypes::None) {} bool APIUserAccount::isValid() const { @@ -84,9 +79,7 @@ APIUserAccount& APIUserAccount::limits(const APILimits& limits) int APIUserAccount::remainingRequests() const { - return std::max( - m_limits.remainingDailyRequests, - m_limits.remainingHourlyRequests); + return std::max(m_limits.remainingDailyRequests, m_limits.remainingHourlyRequests); } bool APIUserAccount::shouldThrottle() const diff --git a/src/apiuseraccount.h b/src/apiuseraccount.h index ac8931cf..829654a5 100644 --- a/src/apiuseraccount.h +++ b/src/apiuseraccount.h @@ -4,8 +4,8 @@ #include <QString> /** -* represents user account types on a mod provider website such as nexus -*/ + * represents user account types on a mod provider website such as nexus + */ enum class APIUserAccountTypes { // not logged in @@ -20,10 +20,9 @@ enum class APIUserAccountTypes QString localizedUserAccountType(APIUserAccountTypes t); - /** -* current limits imposed on the user account -**/ + * current limits imposed on the user account + **/ struct APILimits { // maximum number of requests per day @@ -39,20 +38,18 @@ struct APILimits int remainingHourlyRequests = 0; }; - /** -* API statistics -*/ + * API statistics + */ struct APIStats { // number of API requests currently queued int requestsQueued = 0; }; - /** -* represents a user account on the mod provider website -*/ + * represents a user account on the mod provider website + */ class APIUserAccount { public: @@ -62,79 +59,76 @@ public: APIUserAccount(); - /** * whether the user is logged in */ bool isValid() const; /** - * api key - */ + * api key + */ const QString& apiKey() const; /** - * user id - */ + * user id + */ const QString& id() const; /** - * user name - */ + * user name + */ const QString& name() const; /** - * account type - */ + * account type + */ APIUserAccountTypes type() const; /** - * current API limits - */ + * current API limits + */ const APILimits& limits() const; - /** * sets the api key */ APIUserAccount& apiKey(const QString& key); /** - * sets the user id - */ + * sets the user id + */ APIUserAccount& id(const QString& id); /** - * sets the user name - **/ + * sets the user name + **/ APIUserAccount& name(const QString& name); /** - * sets the account type - */ + * sets the account type + */ APIUserAccount& type(APIUserAccountTypes type); /** - * sets the current limits - */ + * sets the current limits + */ APIUserAccount& limits(const APILimits& limits); - /** - * returns the number of remaining requests - */ + * returns the number of remaining requests + */ int remainingRequests() const; /** - * whether the number of remaining requests is low enough that further - * requests should be throttled - */ + * whether the number of remaining requests is low enough that further + * requests should be throttled + */ bool shouldThrottle() const; /** - * true if all the remaining requests have been used and the API will refuse - * further requests - */ + * true if all the remaining requests have been used and the API will refuse + * further requests + */ bool exhausted() const; private: @@ -143,4 +137,4 @@ private: APILimits m_limits; }; -#endif // APIUSERACCOUNT_H +#endif // APIUSERACCOUNT_H diff --git a/src/archivefiletree.cpp b/src/archivefiletree.cpp index 11e165b8..b90c4798 100644 --- a/src/archivefiletree.cpp +++ b/src/archivefiletree.cpp @@ -29,9 +29,9 @@ using namespace MOBase; /** * We use custom file entries to store the index. */ -class ArchiveFileEntry : public virtual FileTreeEntry { +class ArchiveFileEntry : public virtual FileTreeEntry +{ public: - /** * @brief Create a new entry. * @@ -39,11 +39,12 @@ public: * @param name The name of this entry. * @param index The index of the entry in the archive. */ - ArchiveFileEntry(std::shared_ptr<const IFileTree> parent, QString name, int index) : - FileTreeEntry(parent, name), m_Index(index) { - } + ArchiveFileEntry(std::shared_ptr<const IFileTree> parent, QString name, int index) + : FileTreeEntry(parent, name), m_Index(index) + {} - virtual std::shared_ptr<FileTreeEntry> clone() const override { + virtual std::shared_ptr<FileTreeEntry> clone() const override + { return std::make_shared<ArchiveFileEntry>(nullptr, name(), m_Index); } @@ -51,67 +52,70 @@ public: const int m_Index; }; - /** * */ -class ArchiveFileTreeImpl: public virtual ArchiveFileTree, public virtual ArchiveFileEntry { +class ArchiveFileTreeImpl : public virtual ArchiveFileTree, + public virtual ArchiveFileEntry +{ public: - using File = std::tuple<QStringList, bool, int>; -public: // Public for make_shared (but not accessible by other since not exposed in .h): +public + : // Public for make_shared (but not accessible by other since not exposed in .h): + ArchiveFileTreeImpl(std::shared_ptr<const IFileTree> parent, QString name, int index, + std::vector<File> files) + : FileTreeEntry(parent, name), ArchiveFileEntry(parent, name, index), IFileTree(), + m_Files(std::move(files)) + {} - ArchiveFileTreeImpl(std::shared_ptr<const IFileTree> parent, QString name, int index, std::vector<File> files) - : FileTreeEntry(parent, name), ArchiveFileEntry(parent, name, index), IFileTree(), m_Files(std::move(files)) { } +public: // Override to avoid VS warnings: + virtual std::shared_ptr<IFileTree> astree() override { return IFileTree::astree(); } -public: // Override to avoid VS warnings: - - virtual std::shared_ptr<IFileTree> astree() override { - return IFileTree::astree(); - } - - virtual std::shared_ptr<const IFileTree> astree() const override { + virtual std::shared_ptr<const IFileTree> astree() const override + { return IFileTree::astree(); } protected: - - virtual std::shared_ptr<FileTreeEntry> clone() const override { + virtual std::shared_ptr<FileTreeEntry> clone() const override + { return IFileTree::clone(); } -public: // Overrides: - +public: // Overrides: /** * */ - static void mapToArchive(IFileTree const& tree, QString path, std::vector<FileData*> const& data) + static void mapToArchive(IFileTree const& tree, QString path, + std::vector<FileData*> const& data) { if (path.length() > 0) { - // when using a long windows path (starting with \\?\) we apparently can have redundant - // . components in the path. This wasn't a problem with "regular" path names. + // when using a long windows path (starting with \\?\) we apparently can have + // redundant . components in the path. This wasn't a problem with "regular" path + // names. if (path == ".") { path.clear(); - } - else { + } else { path.append("\\"); } } for (auto const& entry : tree) { if (entry->isDir()) { - const ArchiveFileTreeImpl& archiveEntry = dynamic_cast<const ArchiveFileTreeImpl&>(*entry); + const ArchiveFileTreeImpl& archiveEntry = + dynamic_cast<const ArchiveFileTreeImpl&>(*entry); QString tmp = path + archiveEntry.name(); if (archiveEntry.m_Index != -1) { data[archiveEntry.m_Index]->addOutputFilePath(tmp.toStdWString()); } mapToArchive(*archiveEntry.astree(), tmp, data); - } - else { - const ArchiveFileEntry& archiveFileEntry = dynamic_cast<const ArchiveFileEntry&>(*entry); + } else { + const ArchiveFileEntry& archiveFileEntry = + dynamic_cast<const ArchiveFileEntry&>(*entry); if (archiveFileEntry.m_Index != -1) { - data[archiveFileEntry.m_Index]->addOutputFilePath((path + archiveFileEntry.name()).toStdWString()); + data[archiveFileEntry.m_Index]->addOutputFilePath( + (path + archiveFileEntry.name()).toStdWString()); } } } @@ -120,36 +124,42 @@ public: // Overrides: /** * */ - void mapToArchive(Archive &archive) const override { + void mapToArchive(Archive& archive) const override + { mapToArchive(*this, "", archive.getFileList()); } protected: - /** - * Overriding makeDirectory and makeFile to create file tree or file entry with index -1. + * Overriding makeDirectory and makeFile to create file tree or file entry with index + * -1. * */ - virtual std::shared_ptr<IFileTree> makeDirectory( - std::shared_ptr<const IFileTree> parent, QString name) const override { + virtual std::shared_ptr<IFileTree> + makeDirectory(std::shared_ptr<const IFileTree> parent, QString name) const override + { return std::make_shared<ArchiveFileTreeImpl>(parent, name, -1, std::vector<File>{}); } - virtual std::shared_ptr<FileTreeEntry> makeFile( - std::shared_ptr<const IFileTree> parent, QString name) const override { + virtual std::shared_ptr<FileTreeEntry> + makeFile(std::shared_ptr<const IFileTree> parent, QString name) const override + { return std::make_shared<ArchiveFileEntry>(parent, name, -1); } - virtual bool doPopulate(std::shared_ptr<const IFileTree> parent, std::vector<std::shared_ptr<FileTreeEntry>>& entries) const override { + virtual bool + doPopulate(std::shared_ptr<const IFileTree> parent, + std::vector<std::shared_ptr<FileTreeEntry>>& entries) const override + { // Sort by name: - std::sort(std::begin(m_Files), std::end(m_Files), - [](const auto& a, const auto& b) { - return std::get<0>(a)[0].compare(std::get<0>(b)[0], Qt::CaseInsensitive) < 0; }); + std::sort(std::begin(m_Files), std::end(m_Files), [](const auto& a, const auto& b) { + return std::get<0>(a)[0].compare(std::get<0>(b)[0], Qt::CaseInsensitive) < 0; + }); // We know that the files are sorted: QString currentName = ""; - int currentIndex = -1; + int currentIndex = -1; std::vector<File> currentFiles; for (auto& p : m_Files) { @@ -162,11 +172,12 @@ protected: // accumulated: if (currentName != std::get<0>(p)[0]) { - // We may or may not have an index here, it depends on the type of archive (some archives list - // intermediate non-empty folders, some don't): - entries.push_back(std::make_shared<ArchiveFileTreeImpl>(parent, currentName, currentIndex, std::move(currentFiles))); + // We may or may not have an index here, it depends on the type of archive (some + // archives list intermediate non-empty folders, some don't): + entries.push_back(std::make_shared<ArchiveFileTreeImpl>( + parent, currentName, currentIndex, std::move(currentFiles))); - currentFiles.clear(); // Back to a valid state. + currentFiles.clear(); // Back to a valid state. // Reset the index: currentIndex = -1; @@ -181,36 +192,35 @@ protected: // If it is not a directory, then it is a file in directly under this tree: if (!std::get<1>(p)) { entries.push_back( - std::make_shared<ArchiveFileEntry>(parent, currentName, std::get<2>(p))); + std::make_shared<ArchiveFileEntry>(parent, currentName, std::get<2>(p))); currentName = ""; - } - else { - // Otherwize, it is the actual "file" corresponding to the directory we are listing, so we can retrieve - // the index here: + } else { + // Otherwize, it is the actual "file" corresponding to the directory we are + // listing, so we can retrieve the index here: currentIndex = std::get<2>(p); } - } - else { - currentFiles.push_back({ - QStringList(std::get<0>(p).begin() + 1, std::get<0>(p).end()), std::get<1>(p), std::get<2>(p) - }); + } else { + currentFiles.push_back( + {QStringList(std::get<0>(p).begin() + 1, std::get<0>(p).end()), + std::get<1>(p), std::get<2>(p)}); } } if (currentName != "") { - entries.push_back(std::make_shared<ArchiveFileTreeImpl>(parent, currentName, currentIndex, std::move(currentFiles))); + entries.push_back(std::make_shared<ArchiveFileTreeImpl>( + parent, currentName, currentIndex, std::move(currentFiles))); } // Let the parent class sort the entries: return false; } - virtual std::shared_ptr<IFileTree> doClone() const override { + virtual std::shared_ptr<IFileTree> doClone() const override + { return std::make_shared<ArchiveFileTreeImpl>(nullptr, name(), m_Index, m_Files); } private: - mutable std::vector<File> m_Files; }; @@ -224,15 +234,15 @@ std::shared_ptr<ArchiveFileTree> ArchiveFileTree::makeTree(Archive const& archiv for (size_t i = 0; i < data.size(); ++i) { // Ignore "." and ".." as they're useless and muck things up if (data[i]->getArchiveFilePath().compare(L".") == 0 || - data[i]->getArchiveFilePath().compare(L"..") == 0) - { + data[i]->getArchiveFilePath().compare(L"..") == 0) { continue; } - files.push_back(std::make_tuple( - QString::fromStdWString(data[i]->getArchiveFilePath()).replace("\\", "/").split("/", Qt::SkipEmptyParts), - data[i]->isDirectory(), - (int) i)); + files.push_back( + std::make_tuple(QString::fromStdWString(data[i]->getArchiveFilePath()) + .replace("\\", "/") + .split("/", Qt::SkipEmptyParts), + data[i]->isDirectory(), (int)i)); } auto tree = std::make_shared<ArchiveFileTreeImpl>(nullptr, "", -1, std::move(files)); @@ -240,15 +250,16 @@ std::shared_ptr<ArchiveFileTree> ArchiveFileTree::makeTree(Archive const& archiv } /** - * @brief Recursive function for the ArchiveFileTree::mapToArchive method. Need a template - * here because iterators from a vector of entries are not exactly the same as the iterators - * returned by a IFileTree. + * @brief Recursive function for the ArchiveFileTree::mapToArchive method. Need a + * template here because iterators from a vector of entries are not exactly the same as + * the iterators returned by a IFileTree. * */ template <class It> -void mapToArchive(std::vector<FileData*> const& data, It begin, It end) { +void mapToArchive(std::vector<FileData*> const& data, It begin, It end) +{ for (auto it = begin; it != end; ++it) { - auto entry = *it; + auto entry = *it; auto* aentry = dynamic_cast<const ArchiveFileEntry*>(entry.get()); if (aentry->m_Index != -1) { @@ -262,6 +273,8 @@ void mapToArchive(std::vector<FileData*> const& data, It begin, It end) { } } -void ArchiveFileTree::mapToArchive(Archive &archive, std::vector<std::shared_ptr<const FileTreeEntry>> const& entries) { +void ArchiveFileTree::mapToArchive( + Archive& archive, std::vector<std::shared_ptr<const FileTreeEntry>> const& entries) +{ ::mapToArchive(archive.getFileList(), entries.cbegin(), entries.cend()); } diff --git a/src/archivefiletree.h b/src/archivefiletree.h index e4a5cbdd..3b95769d 100644 --- a/src/archivefiletree.h +++ b/src/archivefiletree.h @@ -23,13 +23,12 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "archive.h" #include "ifiletree.h" - /** * */ -class ArchiveFileTree: public virtual MOBase::IFileTree { +class ArchiveFileTree : public virtual MOBase::IFileTree +{ public: - /** * @brief Create a new file tree representing the given archive. * @@ -48,7 +47,7 @@ public: * @param archive The archive to update. Must be the one used to * create the tree. */ - virtual void mapToArchive(Archive &archive) const = 0; + virtual void mapToArchive(Archive& archive) const = 0; /** * @brief Update the given archive to prepare for the extraction @@ -61,12 +60,12 @@ public: * @param entries List of entries to mark for extraction. All the entries must * come from a tree created with the given archive. */ - static void mapToArchive(Archive &archive, std::vector<std::shared_ptr<const FileTreeEntry>> const& entries); + static void + mapToArchive(Archive& archive, + std::vector<std::shared_ptr<const FileTreeEntry>> const& entries); protected: - using IFileTree::IFileTree; - }; #endif diff --git a/src/bbcode.cpp b/src/bbcode.cpp index e143909f..f1a3d375 100644 --- a/src/bbcode.cpp +++ b/src/bbcode.cpp @@ -18,29 +18,32 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ #include "bbcode.h" -#include <log.h> #include <QRegularExpression> +#include <log.h> #include <map> -namespace BBCode { +namespace BBCode +{ namespace log = MOBase::log; -class BBCodeMap { +class BBCodeMap +{ - typedef std::map<QString, std::pair<QRegularExpression, QString> > TagMap; + typedef std::map<QString, std::pair<QRegularExpression, QString>> TagMap; public: - - static BBCodeMap &instance() { + static BBCodeMap& instance() + { static BBCodeMap s_Instance; return s_Instance; } - QString convertTag(QString input, int &length) + QString convertTag(QString input, int& length) { // extract the tag name - auto match = m_TagNameExp.match(input, 1, QRegularExpression::NormalMatch, QRegularExpression::AnchoredMatchOption); + auto match = m_TagNameExp.match(input, 1, QRegularExpression::NormalMatch, + QRegularExpression::AnchoredMatchOption); QString tagName = match.captured(0).toLower(); TagMap::iterator tagIter = m_TagMap.find(tagName); if (tagIter != m_TagMap.end()) { @@ -49,25 +52,31 @@ public: tagName.chop(1); } - int closeTagPos = 0; - int nextTagPos = 0; + int closeTagPos = 0; + int nextTagPos = 0; int nextTagSearchIndex = input.indexOf("]"); - int closeTagLength = 0; + int closeTagLength = 0; if (tagName == "*") { // ends at the next bullet point - closeTagPos = input.indexOf(QRegularExpression("(\\[\\*\\]|</ul>)", QRegularExpression::CaseInsensitiveOption), 3); - // leave closeTagLength at 0 because we don't want to "eat" the next bullet point + closeTagPos = + input.indexOf(QRegularExpression("(\\[\\*\\]|</ul>)", + QRegularExpression::CaseInsensitiveOption), + 3); + // leave closeTagLength at 0 because we don't want to "eat" the next bullet + // point } else if (tagName == "line") { // ends immediately after the tag closeTagPos = 6; // leave closeTagLength at 0 because there is no close tag to skip over } else { - QRegularExpression nextTag(QString("\\[%1[=\\]]?").arg(tagName), QRegularExpression::CaseInsensitiveOption); + QRegularExpression nextTag(QString("\\[%1[=\\]]?").arg(tagName), + QRegularExpression::CaseInsensitiveOption); QString closeTag = QString("[/%1]").arg(tagName); - closeTagPos = input.indexOf(closeTag, 0, Qt::CaseInsensitive); - nextTagPos = nextTag.match(input, nextTagSearchIndex).capturedStart(0); + closeTagPos = input.indexOf(closeTag, 0, Qt::CaseInsensitive); + nextTagPos = nextTag.match(input, nextTagSearchIndex).capturedStart(0); while (nextTagPos != -1 && closeTagPos != -1 && nextTagPos < closeTagPos) { - closeTagPos = input.indexOf(closeTag, closeTagPos + closeTag.size(), Qt::CaseInsensitive); + closeTagPos = input.indexOf(closeTag, closeTagPos + closeTag.size(), + Qt::CaseInsensitive); nextTagSearchIndex = input.indexOf("]", nextTagPos); nextTagPos = nextTag.match(input, nextTagSearchIndex).capturedStart(0); } @@ -80,23 +89,28 @@ public: } if (closeTagPos > -1) { - length = closeTagPos + closeTagLength; + length = closeTagPos + closeTagLength; QString temp = input.mid(0, length); - tagIter->second.first.setPatternOptions(QRegularExpression::PatternOption::DotMatchesEverythingOption); + tagIter->second.first.setPatternOptions( + QRegularExpression::PatternOption::DotMatchesEverythingOption); auto match = tagIter->second.first.match(temp); if (match.hasMatch()) { if (tagIter->second.second.isEmpty()) { if (tagName == "color") { - QString color = match.captured(1); + QString color = match.captured(1); QString content = match.captured(2); if (color.at(0) == '#') { - return temp.replace(tagIter->second.first, QString("<font style=\"color: %1;\">%2</font>").arg(color, content)); + return temp.replace(tagIter->second.first, + QString("<font style=\"color: %1;\">%2</font>") + .arg(color, content)); } else { auto colIter = m_ColorMap.find(color.toLower()); if (colIter != m_ColorMap.end()) { color = colIter->second; } - return temp.replace(tagIter->second.first, QString("<font style=\"color: #%1;\">%2</font>").arg(color, content)); + return temp.replace(tagIter->second.first, + QString("<font style=\"color: #%1;\">%2</font>") + .arg(color, content)); } } else { log::warn("don't know how to deal with tag {}", tagName); @@ -123,89 +137,105 @@ public: } private: - BBCodeMap() - : m_TagNameExp("[a-zA-Z*]*=?") + BBCodeMap() : m_TagNameExp("[a-zA-Z*]*=?") { - m_TagMap["b"] = std::make_pair(QRegularExpression("\\[b\\](.*)\\[/b\\]"), - "<b>\\1</b>"); - m_TagMap["i"] = std::make_pair(QRegularExpression("\\[i\\](.*)\\[/i\\]"), - "<i>\\1</i>"); - m_TagMap["u"] = std::make_pair(QRegularExpression("\\[u\\](.*)\\[/u\\]"), - "<u>\\1</u>"); - m_TagMap["s"] = std::make_pair(QRegularExpression("\\[s\\](.*)\\[/s\\]"), - "<s>\\1</s>"); - m_TagMap["sub"] = std::make_pair(QRegularExpression("\\[sub\\](.*)\\[/sub\\]"), - "<sub>\\1</sub>"); - m_TagMap["sup"] = std::make_pair(QRegularExpression("\\[sup\\](.*)\\[/sup\\]"), - "<sup>\\1</sup>"); - m_TagMap["size="] = std::make_pair(QRegularExpression("\\[size=([^\\]]*)\\](.*)\\[/size\\]"), - "<font size=\"\\1\">\\2</font>"); - m_TagMap["color="] = std::make_pair(QRegularExpression("\\[color=([^\\]]*)\\](.*)\\[/color\\]"), - ""); - m_TagMap["font="] = std::make_pair(QRegularExpression("\\[font=([^\\]]*)\\](.*)\\[/font\\]"), - "<font style=\"font-family: \\1;\">\\2</font>"); - m_TagMap["center"] = std::make_pair(QRegularExpression("\\[center\\](.*)\\[/center\\]"), - "<div align=\"center\">\\1</div>"); - m_TagMap["right"] = std::make_pair(QRegularExpression("\\[right\\](.*)\\[/right\\]"), - "<div align=\"right\">\\1</div>"); - m_TagMap["quote"] = std::make_pair(QRegularExpression("\\[quote\\](.*)\\[/quote\\]"), - "<figure class=\"quote\"><blockquote>\\1</blockquote></figure>"); - m_TagMap["quote="] = std::make_pair(QRegularExpression("\\[quote=([^\\]]*)\\](.*)\\[/quote\\]"), - "<figure class=\"quote\"><blockquote>\\2</blockquote></figure>"); - m_TagMap["spoiler"] = std::make_pair(QRegularExpression("\\[spoiler\\](.*)\\[/spoiler\\]"), - "<details><summary>Spoiler: <div class=\"bbc_spoiler_show\">Show</div></summary><div class=\"spoiler_content\">\\1</div></details>"); - m_TagMap["code"] = std::make_pair(QRegularExpression("\\[code\\](.*)\\[/code\\]"), - "<code>\\1</code>"); - m_TagMap["heading"]= std::make_pair(QRegularExpression("\\[heading\\](.*)\\[/heading\\]"), - "<h2><strong>\\1</strong></h2>"); - m_TagMap["line"] = std::make_pair(QRegularExpression("\\[line\\]"), - "<hr>"); + m_TagMap["b"] = + std::make_pair(QRegularExpression("\\[b\\](.*)\\[/b\\]"), "<b>\\1</b>"); + m_TagMap["i"] = + std::make_pair(QRegularExpression("\\[i\\](.*)\\[/i\\]"), "<i>\\1</i>"); + m_TagMap["u"] = + std::make_pair(QRegularExpression("\\[u\\](.*)\\[/u\\]"), "<u>\\1</u>"); + m_TagMap["s"] = + std::make_pair(QRegularExpression("\\[s\\](.*)\\[/s\\]"), "<s>\\1</s>"); + m_TagMap["sub"] = + std::make_pair(QRegularExpression("\\[sub\\](.*)\\[/sub\\]"), "<sub>\\1</sub>"); + m_TagMap["sup"] = + std::make_pair(QRegularExpression("\\[sup\\](.*)\\[/sup\\]"), "<sup>\\1</sup>"); + m_TagMap["size="] = + std::make_pair(QRegularExpression("\\[size=([^\\]]*)\\](.*)\\[/size\\]"), + "<font size=\"\\1\">\\2</font>"); + m_TagMap["color="] = + std::make_pair(QRegularExpression("\\[color=([^\\]]*)\\](.*)\\[/color\\]"), ""); + m_TagMap["font="] = + std::make_pair(QRegularExpression("\\[font=([^\\]]*)\\](.*)\\[/font\\]"), + "<font style=\"font-family: \\1;\">\\2</font>"); + m_TagMap["center"] = + std::make_pair(QRegularExpression("\\[center\\](.*)\\[/center\\]"), + "<div align=\"center\">\\1</div>"); + m_TagMap["right"] = + std::make_pair(QRegularExpression("\\[right\\](.*)\\[/right\\]"), + "<div align=\"right\">\\1</div>"); + m_TagMap["quote"] = + std::make_pair(QRegularExpression("\\[quote\\](.*)\\[/quote\\]"), + "<figure class=\"quote\"><blockquote>\\1</blockquote></figure>"); + m_TagMap["quote="] = + std::make_pair(QRegularExpression("\\[quote=([^\\]]*)\\](.*)\\[/quote\\]"), + "<figure class=\"quote\"><blockquote>\\2</blockquote></figure>"); + m_TagMap["spoiler"] = + std::make_pair(QRegularExpression("\\[spoiler\\](.*)\\[/spoiler\\]"), + "<details><summary>Spoiler: <div " + "class=\"bbc_spoiler_show\">Show</div></summary><div " + "class=\"spoiler_content\">\\1</div></details>"); + m_TagMap["code"] = std::make_pair(QRegularExpression("\\[code\\](.*)\\[/code\\]"), + "<code>\\1</code>"); + m_TagMap["heading"] = + std::make_pair(QRegularExpression("\\[heading\\](.*)\\[/heading\\]"), + "<h2><strong>\\1</strong></h2>"); + m_TagMap["line"] = std::make_pair(QRegularExpression("\\[line\\]"), "<hr>"); // lists - m_TagMap["list"] = std::make_pair(QRegularExpression("\\[list\\](.*)\\[/list\\]"), - "<ul>\\1</ul>"); - m_TagMap["list="] = std::make_pair(QRegularExpression("\\[list.*\\](.*)\\[/list\\]"), - "<ol>\\1</ol>"); - m_TagMap["ul"] = std::make_pair(QRegularExpression("\\[ul\\](.*)\\[/ul\\]"), - "<ul>\\1</ul>"); - m_TagMap["ol"] = std::make_pair(QRegularExpression("\\[ol\\](.*)\\[/ol\\]"), - "<ol>\\1</ol>"); - m_TagMap["li"] = std::make_pair(QRegularExpression("\\[li\\](.*)\\[/li\\]"), - "<li>\\1</li>"); + m_TagMap["list"] = + std::make_pair(QRegularExpression("\\[list\\](.*)\\[/list\\]"), "<ul>\\1</ul>"); + m_TagMap["list="] = std::make_pair( + QRegularExpression("\\[list.*\\](.*)\\[/list\\]"), "<ol>\\1</ol>"); + m_TagMap["ul"] = + std::make_pair(QRegularExpression("\\[ul\\](.*)\\[/ul\\]"), "<ul>\\1</ul>"); + m_TagMap["ol"] = + std::make_pair(QRegularExpression("\\[ol\\](.*)\\[/ol\\]"), "<ol>\\1</ol>"); + m_TagMap["li"] = + std::make_pair(QRegularExpression("\\[li\\](.*)\\[/li\\]"), "<li>\\1</li>"); // tables - m_TagMap["table"] = std::make_pair(QRegularExpression("\\[table\\](.*)\\[/table\\]"), - "<table>\\1</table>"); - m_TagMap["tr"] = std::make_pair(QRegularExpression("\\[tr\\](.*)\\[/tr\\]"), - "<tr>\\1</tr>"); - m_TagMap["th"] = std::make_pair(QRegularExpression("\\[th\\](.*)\\[/th\\]"), - "<th>\\1</th>"); - m_TagMap["td"] = std::make_pair(QRegularExpression("\\[td\\](.*)\\[/td\\]"), - "<td>\\1</td>"); + m_TagMap["table"] = std::make_pair( + QRegularExpression("\\[table\\](.*)\\[/table\\]"), "<table>\\1</table>"); + m_TagMap["tr"] = + std::make_pair(QRegularExpression("\\[tr\\](.*)\\[/tr\\]"), "<tr>\\1</tr>"); + m_TagMap["th"] = + std::make_pair(QRegularExpression("\\[th\\](.*)\\[/th\\]"), "<th>\\1</th>"); + m_TagMap["td"] = + std::make_pair(QRegularExpression("\\[td\\](.*)\\[/td\\]"), "<td>\\1</td>"); // web content - m_TagMap["url"] = std::make_pair(QRegularExpression("\\[url\\](.*)\\[/url\\]"), - "<a href=\"\\1\">\\1</a>"); - m_TagMap["url="] = std::make_pair(QRegularExpression("\\[url=([^\\]]*)\\](.*)\\[/url\\]"), - "<a href=\"\\1\">\\2</a>"); - m_TagMap["img"] = std::make_pair(QRegularExpression("\\[img(?:\\s*width=\\d+\\s*,?\\s*height=\\d+)?\\](.*)\\[/img\\]"), - "<img src=\"\\1\">"); - m_TagMap["img="] = std::make_pair(QRegularExpression("\\[img=([^\\]]*)\\](.*)\\[/img\\]"), - "<img src=\"\\2\" alt=\"\\1\">"); - m_TagMap["email="] = std::make_pair(QRegularExpression("\\[email=\"?([^\\]]*)\"?\\](.*)\\[/email\\]"), - "<a href=\"mailto:\\1\">\\2</a>"); - m_TagMap["youtube"] = std::make_pair(QRegularExpression("\\[youtube\\](.*)\\[/youtube\\]"), - "<a href=\"https://www.youtube.com/watch?v=\\1\">https://www.youtube.com/watch?v=\\1</a>"); - + m_TagMap["url"] = std::make_pair(QRegularExpression("\\[url\\](.*)\\[/url\\]"), + "<a href=\"\\1\">\\1</a>"); + m_TagMap["url="] = + std::make_pair(QRegularExpression("\\[url=([^\\]]*)\\](.*)\\[/url\\]"), + "<a href=\"\\1\">\\2</a>"); + m_TagMap["img"] = std::make_pair( + QRegularExpression( + "\\[img(?:\\s*width=\\d+\\s*,?\\s*height=\\d+)?\\](.*)\\[/img\\]"), + "<img src=\"\\1\">"); + m_TagMap["img="] = + std::make_pair(QRegularExpression("\\[img=([^\\]]*)\\](.*)\\[/img\\]"), + "<img src=\"\\2\" alt=\"\\1\">"); + m_TagMap["email="] = std::make_pair( + QRegularExpression("\\[email=\"?([^\\]]*)\"?\\](.*)\\[/email\\]"), + "<a href=\"mailto:\\1\">\\2</a>"); + m_TagMap["youtube"] = + std::make_pair(QRegularExpression("\\[youtube\\](.*)\\[/youtube\\]"), + "<a " + "href=\"https://www.youtube.com/watch?v=\\1\">https://" + "www.youtube.com/watch?v=\\1</a>"); // make all patterns non-greedy and case-insensitive for (TagMap::iterator iter = m_TagMap.begin(); iter != m_TagMap.end(); ++iter) { - iter->second.first.setPatternOptions(QRegularExpression::CaseInsensitiveOption | QRegularExpression::InvertedGreedinessOption); + iter->second.first.setPatternOptions( + QRegularExpression::CaseInsensitiveOption | + QRegularExpression::InvertedGreedinessOption); } // this tag is in fact greedy - m_TagMap["*"] = std::make_pair(QRegularExpression("\\[\\*\\](.*)"), - "<li>\\1</li>"); + m_TagMap["*"] = std::make_pair(QRegularExpression("\\[\\*\\](.*)"), "<li>\\1</li>"); m_ColorMap.insert(std::make_pair<QString, QString>("red", "FF0000")); m_ColorMap.insert(std::make_pair<QString, QString>("green", "00FF00")); @@ -227,14 +257,12 @@ private: } private: - QRegularExpression m_TagNameExp; TagMap m_TagMap; std::map<QString, QString> m_ColorMap; }; - -QString convertToHTML(const QString &inputParam) +QString convertToHTML(const QString& inputParam) { // this code goes over the input string once and replaces all bbtags // it encounters. This function is called recursively for every replaced @@ -248,7 +276,7 @@ QString convertToHTML(const QString &inputParam) input.replace("\\\"", "\"").replace("\\'", "'"); QString result; int lastBlock = 0; - int pos = 0; + int pos = 0; // iterate over the input buffer while ((pos = input.indexOf('[', lastBlock)) != -1) { @@ -256,19 +284,18 @@ QString convertToHTML(const QString &inputParam) result.append(input.mid(lastBlock, pos - lastBlock)); if ((pos < (input.size() - 1)) && (input.at(pos + 1) == '/')) { - // skip invalid end tag - int tagEnd = input.indexOf(']', pos) + 1; + // skip invalid end tag + int tagEnd = input.indexOf(']', pos) + 1; if (tagEnd == 0) { - //no closing tag found - //move the pos up one so that the opening bracket is ignored next iteration + // no closing tag found + // move the pos up one so that the opening bracket is ignored next iteration pos++; - } - else { + } else { pos = tagEnd; } } else { // convert the tag and content if necessary - int length = -1; + int length = -1; QString replacement = BBCodeMap::instance().convertTag(input.mid(pos), length); if (length != 0) { result.append(convertToHTML(replacement)); @@ -288,5 +315,4 @@ QString convertToHTML(const QString &inputParam) return result; } -} // namespace BBCode - +} // namespace BBCode diff --git a/src/bbcode.h b/src/bbcode.h index 9aea9d9c..00e31da6 100644 --- a/src/bbcode.h +++ b/src/bbcode.h @@ -20,21 +20,20 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef BBCODE_H #define BBCODE_H - #include <QString> - -namespace BBCode { +namespace BBCode +{ /** * @brief convert a string with BB Code-Tags to HTML * @param input the input string with BB tags - * @param replaceOccured if not nullptr, this parameter will be set to true if any bb tags were replaced + * @param replaceOccured if not nullptr, this parameter will be set to true if any bb + *tags were replaced * @return the same string in html representation **/ -QString convertToHTML(const QString &input); - -} +QString convertToHTML(const QString& input); +} // namespace BBCode -#endif // BBCODE_H +#endif // BBCODE_H diff --git a/src/browserdialog.cpp b/src/browserdialog.cpp index 4f16d352..f9396db9 100644 --- a/src/browserdialog.cpp +++ b/src/browserdialog.cpp @@ -19,41 +19,40 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "browserdialog.h" -#include "ui_browserdialog.h" #include "browserview.h" #include "messagedialog.h" -#include "report.h" #include "persistentcookiejar.h" +#include "report.h" #include "settings.h" +#include "ui_browserdialog.h" -#include <utility.h> #include <log.h> +#include <utility.h> -#include <QWebEngineSettings> -#include <QNetworkCookieJar> -#include <QNetworkCookie> -#include <QMenu> -#include <QInputDialog> -#include <QWebEngineHistory> #include <QDir> +#include <QInputDialog> #include <QKeyEvent> +#include <QMenu> +#include <QNetworkCookie> +#include <QNetworkCookieJar> +#include <QWebEngineHistory> +#include <QWebEngineSettings> using namespace MOBase; - -BrowserDialog::BrowserDialog(QWidget *parent) - : QDialog(parent) - , ui(new Ui::BrowserDialog) - , m_AccessManager(new QNetworkAccessManager(this)) +BrowserDialog::BrowserDialog(QWidget* parent) + : QDialog(parent), ui(new Ui::BrowserDialog), + m_AccessManager(new QNetworkAccessManager(this)) { ui->setupUi(this); - m_AccessManager->setCookieJar(new PersistentCookieJar( - QDir::fromNativeSeparators(Settings::instance().paths().cache() + "/cookies.dat"))); + m_AccessManager->setCookieJar(new PersistentCookieJar(QDir::fromNativeSeparators( + Settings::instance().paths().cache() + "/cookies.dat"))); - Qt::WindowFlags flags = windowFlags() | Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint; + Qt::WindowFlags flags = + windowFlags() | Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint; Qt::WindowFlags helpFlag = Qt::WindowContextHelpButtonHint; - flags = flags & (~helpFlag); + flags = flags & (~helpFlag); setWindowFlags(flags); m_Tabs = this->findChild<QTabWidget*>("browserTabWidget"); @@ -70,16 +69,16 @@ BrowserDialog::~BrowserDialog() delete ui; } -void BrowserDialog::closeEvent(QCloseEvent *event) +void BrowserDialog::closeEvent(QCloseEvent* event) { Settings::instance().geometry().saveGeometry(this); QDialog::closeEvent(event); } -void BrowserDialog::initTab(BrowserView *newView) +void BrowserDialog::initTab(BrowserView* newView) { - //newView->page()->setNetworkAccessManager(m_AccessManager); - //newView->page()->setForwardUnsupportedContent(true); + // newView->page()->setNetworkAccessManager(m_AccessManager); + // newView->page()->setForwardUnsupportedContent(true); connect(newView, SIGNAL(loadProgress(int)), this, SLOT(progress(int))); connect(newView, SIGNAL(titleChanged(QString)), this, SLOT(titleChanged(QString))); @@ -87,8 +86,10 @@ void BrowserDialog::initTab(BrowserView *newView) connect(newView, SIGNAL(startFind()), this, SLOT(startSearch())); connect(newView, SIGNAL(urlChanged(QUrl)), this, SLOT(urlChanged(QUrl))); connect(newView, SIGNAL(openUrlInNewTab(QUrl)), this, SLOT(openInNewTab(QUrl))); - connect(newView, SIGNAL(downloadRequested(QNetworkRequest)), this, SLOT(downloadRequested(QNetworkRequest))); - connect(newView, SIGNAL(unsupportedContent(QNetworkReply*)), this, SLOT(unsupportedContent(QNetworkReply*))); + connect(newView, SIGNAL(downloadRequested(QNetworkRequest)), this, + SLOT(downloadRequested(QNetworkRequest))); + connect(newView, SIGNAL(unsupportedContent(QNetworkReply*)), this, + SLOT(unsupportedContent(QNetworkReply*))); ui->backBtn->setEnabled(false); ui->fwdBtn->setEnabled(false); @@ -97,24 +98,21 @@ void BrowserDialog::initTab(BrowserView *newView) newView->settings()->setAttribute(QWebEngineSettings::AutoLoadImages, true); } - -void BrowserDialog::openInNewTab(const QUrl &url) +void BrowserDialog::openInNewTab(const QUrl& url) { - BrowserView *newView = new BrowserView(this); + BrowserView* newView = new BrowserView(this); initTab(newView); newView->setUrl(url); } - -BrowserView *BrowserDialog::getCurrentView() +BrowserView* BrowserDialog::getCurrentView() { return qobject_cast<BrowserView*>(m_Tabs->currentWidget()); } - -void BrowserDialog::urlChanged(const QUrl &url) +void BrowserDialog::urlChanged(const QUrl& url) { - BrowserView *currentView = getCurrentView(); + BrowserView* currentView = getCurrentView(); if (currentView != nullptr) { ui->backBtn->setEnabled(currentView->history()->canGoBack()); ui->fwdBtn->setEnabled(currentView->history()->canGoForward()); @@ -122,8 +120,7 @@ void BrowserDialog::urlChanged(const QUrl &url) ui->urlEdit->setText(url.toString()); } - -void BrowserDialog::openUrl(const QUrl &url) +void BrowserDialog::openUrl(const QUrl& url) { if (isHidden()) { Settings::instance().geometry().restoreGeometry(this); @@ -132,22 +129,21 @@ void BrowserDialog::openUrl(const QUrl &url) openInNewTab(url); } - void BrowserDialog::maximizeWidth() { - int viewportWidth = getCurrentView()->page()->contentsSize ().width(); - int frameWidth = width() - viewportWidth; + int viewportWidth = getCurrentView()->page()->contentsSize().width(); + int frameWidth = width() - viewportWidth; int contentWidth = getCurrentView()->page()->contentsSize().width(); QScreen* screen = this->window()->windowHandle()->screen(); int screenWidth = screen->geometry().size().width(); - int targetWidth = std::min<int>(std::max<int>(viewportWidth, contentWidth) + frameWidth, screenWidth); + int targetWidth = std::min<int>( + std::max<int>(viewportWidth, contentWidth) + frameWidth, screenWidth); this->resize(targetWidth, height()); } - void BrowserDialog::progress(int value) { ui->loadProgress->setValue(value); @@ -159,10 +155,9 @@ void BrowserDialog::progress(int value) } } - -void BrowserDialog::titleChanged(const QString &title) +void BrowserDialog::titleChanged(const QString& title) { - BrowserView *view = qobject_cast<BrowserView*>(sender()); + BrowserView* view = qobject_cast<BrowserView*>(sender()); for (int i = 0; i < m_Tabs->count(); ++i) { if (m_Tabs->widget(i) == view) { m_Tabs->setTabText(i, title.mid(0, 15)); @@ -171,8 +166,7 @@ void BrowserDialog::titleChanged(const QString &title) } } - -QString BrowserDialog::guessFileName(const QString &url) +QString BrowserDialog::guessFileName(const QString& url) { QRegularExpression uploadsExp(QString("https://.+/uploads/([^/]+)$")); auto match = uploadsExp.match(url); @@ -190,10 +184,10 @@ QString BrowserDialog::guessFileName(const QString &url) return "unknown"; } -void BrowserDialog::unsupportedContent(QNetworkReply *reply) +void BrowserDialog::unsupportedContent(QNetworkReply* reply) { try { - QWebEnginePage *page = qobject_cast<QWebEnginePage*>(sender()); + QWebEnginePage* page = qobject_cast<QWebEnginePage*>(sender()); if (page == nullptr) { log::error("sender not a page"); return; @@ -205,7 +199,7 @@ void BrowserDialog::unsupportedContent(QNetworkReply *reply) }*/ emit requestDownload(page->url(), reply); - } catch (const std::exception &e) { + } catch (const std::exception& e) { if (isVisible()) { MessageDialog::showMessage(tr("failed to start download"), this); } @@ -213,13 +207,11 @@ void BrowserDialog::unsupportedContent(QNetworkReply *reply) } } - -void BrowserDialog::downloadRequested(const QNetworkRequest &request) +void BrowserDialog::downloadRequested(const QNetworkRequest& request) { log::error("download request {} ignored", request.url().toString()); } - void BrowserDialog::tabCloseRequested(int index) { if (m_Tabs->count() == 1) { @@ -232,7 +224,7 @@ void BrowserDialog::tabCloseRequested(int index) void BrowserDialog::on_backBtn_clicked() { - BrowserView *currentView = getCurrentView(); + BrowserView* currentView = getCurrentView(); if (currentView != nullptr) { currentView->back(); } @@ -240,25 +232,24 @@ void BrowserDialog::on_backBtn_clicked() void BrowserDialog::on_fwdBtn_clicked() { - BrowserView *currentView = getCurrentView(); + BrowserView* currentView = getCurrentView(); if (currentView != nullptr) { currentView->forward(); } } - void BrowserDialog::startSearch() { ui->searchEdit->setFocus(); } - void BrowserDialog::on_searchEdit_returnPressed() { -// BrowserView *currentView = getCurrentView(); -// if (currentView != nullptr) { -// currentView->findText(ui->searchEdit->text(), QWebEnginePage::FindWrapsAroundDocument); -// } + // BrowserView *currentView = getCurrentView(); + // if (currentView != nullptr) { + // currentView->findText(ui->searchEdit->text(), + // QWebEnginePage::FindWrapsAroundDocument); + // } } void BrowserDialog::on_refreshBtn_clicked() @@ -268,7 +259,8 @@ void BrowserDialog::on_refreshBtn_clicked() void BrowserDialog::on_browserTabWidget_currentChanged(int index) { - BrowserView *currentView = qobject_cast<BrowserView*>(ui->browserTabWidget->widget(index)); + BrowserView* currentView = + qobject_cast<BrowserView*>(ui->browserTabWidget->widget(index)); if (currentView != nullptr) { ui->backBtn->setEnabled(currentView->history()->canGoBack()); ui->fwdBtn->setEnabled(currentView->history()->canGoForward()); @@ -277,18 +269,18 @@ void BrowserDialog::on_browserTabWidget_currentChanged(int index) void BrowserDialog::on_urlEdit_returnPressed() { - QWebEngineView *currentView = getCurrentView(); + QWebEngineView* currentView = getCurrentView(); if (currentView != nullptr) { currentView->setUrl(QUrl(ui->urlEdit->text())); } } -bool BrowserDialog::eventFilter(QObject *object, QEvent *event) +bool BrowserDialog::eventFilter(QObject* object, QEvent* event) { if (event->type() == QEvent::KeyPress) { - QKeyEvent *keyEvent = reinterpret_cast<QKeyEvent*>(event); - if ((keyEvent->modifiers() & Qt::ControlModifier) - && (keyEvent->key() == Qt::Key_U)) { + QKeyEvent* keyEvent = reinterpret_cast<QKeyEvent*>(event); + if ((keyEvent->modifiers() & Qt::ControlModifier) && + (keyEvent->key() == Qt::Key_U)) { ui->urlEdit->setVisible(!ui->urlEdit->isVisible()); return true; } diff --git a/src/browserdialog.h b/src/browserdialog.h index 31b86fff..2c9781b2 100644 --- a/src/browserdialog.h +++ b/src/browserdialog.h @@ -20,18 +20,18 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef BROWSERDIALOG_H #define BROWSERDIALOG_H +#include <QAtomicInt> #include <QDialog> -#include <QNetworkRequest> #include <QNetworkReply> -#include <QTimer> -#include <QWebEngineView> +#include <QNetworkRequest> #include <QQueue> #include <QTabWidget> -#include <QAtomicInt> - +#include <QTimer> +#include <QWebEngineView> -namespace Ui { - class BrowserDialog; +namespace Ui +{ +class BrowserDialog; } class BrowserView; @@ -41,27 +41,27 @@ class BrowserView; **/ class BrowserDialog : public QDialog { - Q_OBJECT + Q_OBJECT public: - - /** - * @brief constructor - * - * @param accessManager the access manager to use for network requests - * @param parent parent widget - **/ - explicit BrowserDialog(QWidget *parent = 0); + /** + * @brief constructor + * + * @param accessManager the access manager to use for network requests + * @param parent parent widget + **/ + explicit BrowserDialog(QWidget* parent = 0); ~BrowserDialog(); /** - * @brief set the url to open. If automatic login is enabled, the url is opened after login + * @brief set the url to open. If automatic login is enabled, the url is opened after + *login * * @param url the url to open **/ - void openUrl(const QUrl &url); + void openUrl(const QUrl& url); - virtual bool eventFilter(QObject *object, QEvent *event); + virtual bool eventFilter(QObject* object, QEvent* event); signals: /** @@ -69,26 +69,25 @@ signals: * @param pageUrl url of the current web site from which the download was started * @param reply network reply of the started download */ - void requestDownload(const QUrl &pageUrl, QNetworkReply *reply); + void requestDownload(const QUrl& pageUrl, QNetworkReply* reply); protected: - - virtual void closeEvent(QCloseEvent *); + virtual void closeEvent(QCloseEvent*); private slots: - void initTab(BrowserView *newView); - void openInNewTab(const QUrl &url); + void initTab(BrowserView* newView); + void openInNewTab(const QUrl& url); void progress(int value); - void titleChanged(const QString &title); - void unsupportedContent(QNetworkReply *reply); - void downloadRequested(const QNetworkRequest &request); + void titleChanged(const QString& title); + void unsupportedContent(QNetworkReply* reply); + void downloadRequested(const QNetworkRequest& request); void tabCloseRequested(int index); - void urlChanged(const QUrl &url); + void urlChanged(const QUrl& url); void on_backBtn_clicked(); @@ -105,22 +104,18 @@ private slots: void on_urlEdit_returnPressed(); private: + QString guessFileName(const QString& url); - QString guessFileName(const QString &url); - - BrowserView *getCurrentView(); + BrowserView* getCurrentView(); void maximizeWidth(); private: + Ui::BrowserDialog* ui; - Ui::BrowserDialog *ui; - - QNetworkAccessManager *m_AccessManager; - - QTabWidget *m_Tabs; - + QNetworkAccessManager* m_AccessManager; + QTabWidget* m_Tabs; }; -#endif // BROWSERDIALOG_H +#endif // BROWSERDIALOG_H diff --git a/src/browserview.cpp b/src/browserview.cpp index c45bf928..55ed1f7b 100644 --- a/src/browserview.cpp +++ b/src/browserview.cpp @@ -19,58 +19,57 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "browserview.h" +#include "utility.h" #include <QEvent> #include <QKeyEvent> +#include <QMenu> #include <QNetworkDiskCache> #include <QWebEngineContextMenuRequest> #include <QWebEngineSettings> -#include <QMenu> #include <Shlwapi.h> -#include "utility.h" - -BrowserView::BrowserView(QWidget *parent) - : QWebEngineView(parent) +BrowserView::BrowserView(QWidget* parent) : QWebEngineView(parent) { installEventFilter(this); - //page()->settings()->setMaximumPagesInCache(10); + // page()->settings()->setMaximumPagesInCache(10); } -QWebEngineView *BrowserView::createWindow(QWebEnginePage::WebWindowType) +QWebEngineView* BrowserView::createWindow(QWebEnginePage::WebWindowType) { - BrowserView *newView = new BrowserView(parentWidget()); + BrowserView* newView = new BrowserView(parentWidget()); emit initTab(newView); return newView; } -bool BrowserView::eventFilter(QObject *obj, QEvent *event) +bool BrowserView::eventFilter(QObject* obj, QEvent* event) { if (event->type() == QEvent::ShortcutOverride) { - QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event); + QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event); if (keyEvent->matches(QKeySequence::Find)) { emit startFind(); } else if (keyEvent->matches(QKeySequence::FindNext)) { emit findAgain(); } } else if (event->type() == QEvent::MouseButtonPress) { - QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event); + QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event); if (mouseEvent->button() == Qt::MouseButton::MiddleButton) { mouseEvent->ignore(); return true; } -// TODO This is due to that QTWebEnginePage doesn't support QWebFrame anymore -// } else if (event->type() == QEvent::MouseButtonRelease) { -// QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event); -// if (mouseEvent->button() == Qt::MidButton) { -// QWebEngineContextMenuData hitTest = page()->hitTestContent(mouseEvent->pos()); -// if (hitTest.linkUrl().isValid()) { -// emit openUrlInNewTab(hitTest.linkUrl()); -// } -// mouseEvent->ignore(); -// -// return true; -// } + // TODO This is due to that QTWebEnginePage doesn't support QWebFrame anymore + // } else if (event->type() == QEvent::MouseButtonRelease) { + // QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event); + // if (mouseEvent->button() == Qt::MidButton) { + // QWebEngineContextMenuData hitTest = + // page()->hitTestContent(mouseEvent->pos()); if (hitTest.linkUrl().isValid()) + // { + // emit openUrlInNewTab(hitTest.linkUrl()); + // } + // mouseEvent->ignore(); + // + // return true; + // } } return QWebEngineView::eventFilter(obj, event); } diff --git a/src/browserview.h b/src/browserview.h index c0248263..b07f0ad0 100644 --- a/src/browserview.h +++ b/src/browserview.h @@ -20,23 +20,21 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef NEXUSVIEW_H #define NEXUSVIEW_H - class QEvent; class QUrl; class QWidget; -#include <QWebEngineView> #include <QWebEnginePage> +#include <QWebEngineView> /** * @brief web view used to display a nexus page **/ class BrowserView : public QWebEngineView { - Q_OBJECT + Q_OBJECT public: - - explicit BrowserView(QWidget *parent = 0); + explicit BrowserView(QWidget* parent = 0); signals: @@ -45,14 +43,15 @@ signals: * * @param newView the view for the newly opened window **/ - void initTab(BrowserView *newView); + void initTab(BrowserView* newView); /** - * @brief emitted when the user requests a link to be opened in a new tab by middle-clicking + * @brief emitted when the user requests a link to be opened in a new tab by + * middle-clicking * * @param url the url to open */ - void openUrlInNewTab(const QUrl &url); + void openUrlInNewTab(const QUrl& url); /** * @brief Ctrl-f was clicked. The containing dialog should activate its find-facility @@ -65,17 +64,13 @@ signals: void findAgain(); protected: + virtual QWebEngineView* createWindow(QWebEnginePage::WebWindowType type); - virtual QWebEngineView *createWindow(QWebEnginePage::WebWindowType type); - - virtual bool eventFilter(QObject *obj, QEvent *event); - + virtual bool eventFilter(QObject* obj, QEvent* event); private: - QString m_FindPattern; bool m_MiddleClick; - }; -#endif // NEXUSVIEW_H +#endif // NEXUSVIEW_H diff --git a/src/categories.cpp b/src/categories.cpp index 6071cc43..70efd706 100644 --- a/src/categories.cpp +++ b/src/categories.cpp @@ -19,29 +19,25 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "categories.h" -#include <utility.h> -#include <report.h> #include <log.h> +#include <report.h> +#include <utility.h> -#include <QObject> -#include <QFile> +#include <QCoreApplication> #include <QDir> +#include <QFile> #include <QList> -#include <QCoreApplication> - +#include <QObject> using namespace MOBase; - CategoryFactory* CategoryFactory::s_Instance = nullptr; - QString CategoryFactory::categoriesFilePath() { return qApp->property("dataPath").toString() + "/categories.dat"; } - CategoryFactory::CategoryFactory() { atexit(&cleanup); @@ -62,16 +58,15 @@ void CategoryFactory::loadCategories() ++lineNum; QList<QByteArray> cells = line.split('|'); if (cells.count() != 4) { - log::error( - "invalid category line {}: {} ({} cells)", - lineNum, line.constData(), cells.count()); + log::error("invalid category line {}: {} ({} cells)", lineNum, line.constData(), + cells.count()); } else { std::vector<int> nexusIDs; if (cells[2].length() > 0) { QList<QByteArray> nexusIDStrings = cells[2].split(','); for (QList<QByteArray>::iterator iter = nexusIDStrings.begin(); iter != nexusIDStrings.end(); ++iter) { - bool ok = false; + bool ok = false; int temp = iter->toInt(&ok); if (!ok) { log::error("invalid category id {}", iter->constData()); @@ -81,7 +76,7 @@ void CategoryFactory::loadCategories() } bool cell0Ok = true; bool cell3Ok = true; - int id = cells[0].toInt(&cell0Ok); + int id = cells[0].toInt(&cell0Ok); int parentID = cells[3].trimmed().toInt(&cell3Ok); if (!cell0Ok || !cell3Ok) { log::error("invalid category line {}: {}", lineNum, line.constData()); @@ -95,8 +90,7 @@ void CategoryFactory::loadCategories() setParents(); } - -CategoryFactory &CategoryFactory::instance() +CategoryFactory& CategoryFactory::instance() { if (s_Instance == nullptr) { s_Instance = new CategoryFactory; @@ -104,7 +98,6 @@ CategoryFactory &CategoryFactory::instance() return *s_Instance; } - void CategoryFactory::reset() { m_Categories.clear(); @@ -113,10 +106,9 @@ void CategoryFactory::reset() // 43 = Savegames (makes no sense to install them through MO) // 45 = Videos and trailers // 87 = Miscelanous - addCategory(0, "None", { 4, 28, 43, 45, 87 }, 0); + addCategory(0, "None", {4, 28, 43, 45, 87}, 0); } - void CategoryFactory::setParents() { for (std::vector<Category>::iterator iter = m_Categories.begin(); @@ -127,7 +119,8 @@ void CategoryFactory::setParents() for (std::vector<Category>::const_iterator categoryIter = m_Categories.begin(); categoryIter != m_Categories.end(); ++categoryIter) { if (categoryIter->m_ParentID != 0) { - std::map<int, unsigned int>::const_iterator iter = m_IDMap.find(categoryIter->m_ParentID); + std::map<int, unsigned int>::const_iterator iter = + m_IDMap.find(categoryIter->m_ParentID); if (iter != m_IDMap.end()) { m_Categories[iter->second].m_HasChildren = true; } @@ -141,7 +134,6 @@ void CategoryFactory::cleanup() s_Instance = nullptr; } - void CategoryFactory::saveCategories() { QFile categoryFile(categoriesFilePath()); @@ -158,20 +150,24 @@ void CategoryFactory::saveCategories() continue; } QByteArray line; - line.append(QByteArray::number(iter->m_ID)).append("|") - .append(iter->m_Name.toUtf8()).append("|") - .append(VectorJoin(iter->m_NexusIDs, ",").toUtf8()).append("|") - .append(QByteArray::number(iter->m_ParentID)).append("\n"); + line.append(QByteArray::number(iter->m_ID)) + .append("|") + .append(iter->m_Name.toUtf8()) + .append("|") + .append(VectorJoin(iter->m_NexusIDs, ",").toUtf8()) + .append("|") + .append(QByteArray::number(iter->m_ParentID)) + .append("\n"); categoryFile.write(line); } categoryFile.close(); } - -unsigned int CategoryFactory::countCategories(std::function<bool (const Category &category)> filter) +unsigned int +CategoryFactory::countCategories(std::function<bool(const Category& category)> filter) { unsigned int result = 0; - for (const Category &cat : m_Categories) { + for (const Category& cat : m_Categories) { if (filter(cat)) { ++result; } @@ -179,7 +175,8 @@ unsigned int CategoryFactory::countCategories(std::function<bool (const Category return result; } -int CategoryFactory::addCategory(const QString &name, const std::vector<int> &nexusIDs, int parentID) +int CategoryFactory::addCategory(const QString& name, const std::vector<int>& nexusIDs, + int parentID) { int id = 1; while (m_IDMap.find(id) != m_IDMap.end()) { @@ -191,7 +188,8 @@ int CategoryFactory::addCategory(const QString &name, const std::vector<int> &ne return id; } -void CategoryFactory::addCategory(int id, const QString &name, const std::vector<int> &nexusIDs, int parentID) +void CategoryFactory::addCategory(int id, const QString& name, + const std::vector<int>& nexusIDs, int parentID) { int index = static_cast<int>(m_Categories.size()); m_Categories.push_back(Category(index, id, name, nexusIDs, parentID)); @@ -201,71 +199,69 @@ void CategoryFactory::addCategory(int id, const QString &name, const std::vector m_IDMap[id] = index; } - void CategoryFactory::loadDefaultCategories() { // the order here is relevant as it defines the order in which the // mods appear in the combo box - addCategory(1, "Animations", { 2, 4, 51 }, 0); - addCategory(52, "Poses", { 1, 29 }, 1); - addCategory(2, "Armour", { 2, 5, 54 }, 0); - addCategory(53, "Power Armor", { 1, 53 }, 2); - addCategory(3, "Audio", { 3, 33, 35, 106 }, 0); - addCategory(38, "Music", { 2, 34, 61 }, 0); - addCategory(39, "Voice", { 2, 36, 107 }, 0); - addCategory(5, "Clothing", { 2, 9, 60 }, 0); - addCategory(41, "Jewelry", { 1, 102 }, 5); - addCategory(42, "Backpacks", { 1, 49 }, 5); - addCategory(6, "Collectables", { 2, 10, 92 }, 0); - addCategory(28, "Companions", { 3, 11, 66, 96 }, 0); - addCategory(7, "Creatures, Mounts, & Vehicles", { 4, 12, 65, 83, 101 }, 0); - addCategory(8, "Factions", { 2, 16, 25 }, 0); - addCategory(9, "Gameplay", { 2, 15, 24 }, 0); - addCategory(27, "Combat", { 1, 77 }, 9); - addCategory(43, "Crafting", { 2, 50, 100 }, 9); - addCategory(48, "Overhauls", { 2, 24, 79 }, 9); - addCategory(49, "Perks", { 1, 27 }, 9); - addCategory(54, "Radio", { 1, 31 }, 9); - addCategory(55, "Shouts", { 1, 104 }, 9); - addCategory(22, "Skills & Levelling", { 2, 46, 73 }, 9); - addCategory(58, "Weather & Lighting", { 1, 56 }, 9); - addCategory(44, "Equipment", { 1, 44 }, 43); - addCategory(45, "Home/Settlement", { 1, 45 }, 43); - addCategory(10, "Body, Face, & Hair", { 2, 17, 26 }, 0); - addCategory(56, "Tattoos", { 1, 57 }, 10); - addCategory(40, "Character Presets", { 1, 58 }, 0); - addCategory(11, "Items", { 2, 27, 85 }, 0); - addCategory(32, "Mercantile", { 2, 23, 69 }, 0); - addCategory(37, "Ammo", { 1, 3 }, 11); - addCategory(19, "Weapons", { 2, 41, 55 }, 11); - addCategory(36, "Weapon & Armour Sets", { 1, 42 }, 11); - addCategory(23, "Player Homes", { 2, 28, 67 }, 0); - addCategory(25, "Castles & Mansions", { 1, 68 }, 23); - addCategory(51, "Settlements", { 1, 48 }, 23); - addCategory(12, "Locations", { 10, 20, 21, 22, 30, 47, 70, 88, 89, 90, 91 }, 0); - addCategory(4, "Cities", { 1, 53 }, 12); - addCategory(31, "Landscape Changes", { 1, 58 }, 0); - addCategory(29, "Environment", { 2, 14, 74 }, 0); - addCategory(30, "Immersion", { 2, 51, 78 }, 0); - addCategory(20, "Magic", { 3, 75, 93, 94 }, 0); - addCategory(21, "Models & Textures", { 2, 19, 29 }, 0); - addCategory(33, "Modders resources", { 2, 18, 82 }, 0); - addCategory(13, "NPCs", { 3, 22, 33, 99 }, 0); - addCategory(24, "Bugfixes", { 2, 6, 95 }, 0); - addCategory(14, "Patches", { 2, 25, 84 }, 24); - addCategory(35, "Utilities", { 2, 38, 39 }, 0); - addCategory(26, "Cheats", { 1, 8 }, 0); - addCategory(15, "Quests", { 2, 30, 35 }, 0); - addCategory(16, "Races & Classes", { 1, 34 }, 0); - addCategory(34, "Stealth", { 1, 76 }, 0); - addCategory(17, "UI", { 2, 37, 42 }, 0); - addCategory(18, "Visuals", { 2, 40, 62 }, 0); - addCategory(50, "Pip-Boy", { 1, 52 }, 18); - addCategory(46, "Shader Presets", { 3, 13, 97, 105 }, 0); - addCategory(47, "Miscellaneous", { 2, 2, 28 }, 0); + addCategory(1, "Animations", {2, 4, 51}, 0); + addCategory(52, "Poses", {1, 29}, 1); + addCategory(2, "Armour", {2, 5, 54}, 0); + addCategory(53, "Power Armor", {1, 53}, 2); + addCategory(3, "Audio", {3, 33, 35, 106}, 0); + addCategory(38, "Music", {2, 34, 61}, 0); + addCategory(39, "Voice", {2, 36, 107}, 0); + addCategory(5, "Clothing", {2, 9, 60}, 0); + addCategory(41, "Jewelry", {1, 102}, 5); + addCategory(42, "Backpacks", {1, 49}, 5); + addCategory(6, "Collectables", {2, 10, 92}, 0); + addCategory(28, "Companions", {3, 11, 66, 96}, 0); + addCategory(7, "Creatures, Mounts, & Vehicles", {4, 12, 65, 83, 101}, 0); + addCategory(8, "Factions", {2, 16, 25}, 0); + addCategory(9, "Gameplay", {2, 15, 24}, 0); + addCategory(27, "Combat", {1, 77}, 9); + addCategory(43, "Crafting", {2, 50, 100}, 9); + addCategory(48, "Overhauls", {2, 24, 79}, 9); + addCategory(49, "Perks", {1, 27}, 9); + addCategory(54, "Radio", {1, 31}, 9); + addCategory(55, "Shouts", {1, 104}, 9); + addCategory(22, "Skills & Levelling", {2, 46, 73}, 9); + addCategory(58, "Weather & Lighting", {1, 56}, 9); + addCategory(44, "Equipment", {1, 44}, 43); + addCategory(45, "Home/Settlement", {1, 45}, 43); + addCategory(10, "Body, Face, & Hair", {2, 17, 26}, 0); + addCategory(56, "Tattoos", {1, 57}, 10); + addCategory(40, "Character Presets", {1, 58}, 0); + addCategory(11, "Items", {2, 27, 85}, 0); + addCategory(32, "Mercantile", {2, 23, 69}, 0); + addCategory(37, "Ammo", {1, 3}, 11); + addCategory(19, "Weapons", {2, 41, 55}, 11); + addCategory(36, "Weapon & Armour Sets", {1, 42}, 11); + addCategory(23, "Player Homes", {2, 28, 67}, 0); + addCategory(25, "Castles & Mansions", {1, 68}, 23); + addCategory(51, "Settlements", {1, 48}, 23); + addCategory(12, "Locations", {10, 20, 21, 22, 30, 47, 70, 88, 89, 90, 91}, 0); + addCategory(4, "Cities", {1, 53}, 12); + addCategory(31, "Landscape Changes", {1, 58}, 0); + addCategory(29, "Environment", {2, 14, 74}, 0); + addCategory(30, "Immersion", {2, 51, 78}, 0); + addCategory(20, "Magic", {3, 75, 93, 94}, 0); + addCategory(21, "Models & Textures", {2, 19, 29}, 0); + addCategory(33, "Modders resources", {2, 18, 82}, 0); + addCategory(13, "NPCs", {3, 22, 33, 99}, 0); + addCategory(24, "Bugfixes", {2, 6, 95}, 0); + addCategory(14, "Patches", {2, 25, 84}, 24); + addCategory(35, "Utilities", {2, 38, 39}, 0); + addCategory(26, "Cheats", {1, 8}, 0); + addCategory(15, "Quests", {2, 30, 35}, 0); + addCategory(16, "Races & Classes", {1, 34}, 0); + addCategory(34, "Stealth", {1, 76}, 0); + addCategory(17, "UI", {2, 37, 42}, 0); + addCategory(18, "Visuals", {2, 40, 62}, 0); + addCategory(50, "Pip-Boy", {1, 52}, 18); + addCategory(46, "Shader Presets", {3, 13, 97, 105}, 0); + addCategory(47, "Miscellaneous", {2, 2, 28}, 0); } - int CategoryFactory::getParentID(unsigned int index) const { if (index >= m_Categories.size()) { @@ -275,13 +271,11 @@ int CategoryFactory::getParentID(unsigned int index) const return m_Categories[index].m_ParentID; } - bool CategoryFactory::categoryExists(int id) const { return m_IDMap.find(id) != m_IDMap.end(); } - bool CategoryFactory::isDescendantOf(int id, int parentID) const { // handles cycles @@ -289,8 +283,8 @@ bool CategoryFactory::isDescendantOf(int id, int parentID) const return isDescendantOfImpl(id, parentID, seen); } -bool CategoryFactory::isDescendantOfImpl( - int id, int parentID, std::set<int>& seen) const +bool CategoryFactory::isDescendantOfImpl(int id, int parentID, + std::set<int>& seen) const { if (!seen.insert(id).second) { log::error("cycle in category: {}", id); @@ -314,7 +308,6 @@ bool CategoryFactory::isDescendantOfImpl( } } - bool CategoryFactory::hasChildren(unsigned int index) const { if (index >= m_Categories.size()) { @@ -324,7 +317,6 @@ bool CategoryFactory::hasChildren(unsigned int index) const return m_Categories[index].m_HasChildren; } - QString CategoryFactory::getCategoryName(unsigned int index) const { if (index >= m_Categories.size()) { @@ -337,20 +329,42 @@ QString CategoryFactory::getCategoryName(unsigned int index) const QString CategoryFactory::getSpecialCategoryName(SpecialCategories type) const { QString label; - switch (type) - { - case Checked: label = QObject::tr("Active"); break; - case UpdateAvailable: label = QObject::tr("Update available"); break; - case HasCategory: label = QObject::tr("Has category"); break; - case Conflict: label = QObject::tr("Conflicted"); break; - case HasHiddenFiles: label = QObject::tr("Has hidden files"); break; - case Endorsed: label = QObject::tr("Endorsed"); break; - case Backup: label = QObject::tr("Has backup"); break; - case Managed: label = QObject::tr("Managed"); break; - case HasGameData: label = QObject::tr("Has valid game data"); break; - case HasNexusID: label = QObject::tr("Has Nexus ID"); break; - case Tracked: label = QObject::tr("Tracked on Nexus"); break; - default: return {}; + switch (type) { + case Checked: + label = QObject::tr("Active"); + break; + case UpdateAvailable: + label = QObject::tr("Update available"); + break; + case HasCategory: + label = QObject::tr("Has category"); + break; + case Conflict: + label = QObject::tr("Conflicted"); + break; + case HasHiddenFiles: + label = QObject::tr("Has hidden files"); + break; + case Endorsed: + label = QObject::tr("Endorsed"); + break; + case Backup: + label = QObject::tr("Has backup"); + break; + case Managed: + label = QObject::tr("Managed"); + break; + case HasGameData: + label = QObject::tr("Has valid game data"); + break; + case HasNexusID: + label = QObject::tr("Has Nexus ID"); + break; + case Tracked: + label = QObject::tr("Tracked on Nexus"); + break; + default: + return {}; } return QString("<%1>").arg(label); } @@ -380,7 +394,6 @@ int CategoryFactory::getCategoryID(unsigned int index) const return m_Categories[index].m_ID; } - int CategoryFactory::getCategoryIndex(int ID) const { std::map<int, unsigned int>::const_iterator iter = m_IDMap.find(ID); @@ -390,13 +403,12 @@ int CategoryFactory::getCategoryIndex(int ID) const return iter->second; } - -int CategoryFactory::getCategoryID(const QString &name) const +int CategoryFactory::getCategoryID(const QString& name) const { auto iter = std::find_if(m_Categories.begin(), m_Categories.end(), - [name] (const Category &cat) -> bool { - return cat.m_Name == name; - }); + [name](const Category& cat) -> bool { + return cat.m_Name == name; + }); if (iter != m_Categories.end()) { return iter->m_ID; @@ -405,7 +417,6 @@ int CategoryFactory::getCategoryID(const QString &name) const } } - unsigned int CategoryFactory::resolveNexusID(int nexusID) const { std::map<int, unsigned int>::const_iterator iter = m_NexusMap.find(nexusID); diff --git a/src/categories.h b/src/categories.h index 50be9fc4..b938bd19 100644 --- a/src/categories.h +++ b/src/categories.h @@ -20,19 +20,19 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef CATEGORIES_H #define CATEGORIES_H - #include <QString> -#include <vector> -#include <map> #include <functional> - +#include <map> +#include <vector> /** * @brief Manage the available mod categories - * @warning member functions of this class currently use a wild mix of ids and indexes to look up categories, - * optimized to where the request comes from. Therefore be very careful which of the two you have available + * @warning member functions of this class currently use a wild mix of ids and indexes + *to look up categories, optimized to where the request comes from. Therefore be very + *careful which of the two you have available **/ -class CategoryFactory { +class CategoryFactory +{ friend class CategoriesDialog; @@ -53,10 +53,13 @@ public: }; public: - struct Category { - Category(int sortValue, int id, const QString &name, const std::vector<int> &nexusIDs, int parentID) - : m_SortValue(sortValue), m_ID(id), m_Name(name), m_HasChildren(false), - m_NexusIDs(nexusIDs), m_ParentID(parentID) {} + struct Category + { + Category(int sortValue, int id, const QString& name, + const std::vector<int>& nexusIDs, int parentID) + : m_SortValue(sortValue), m_ID(id), m_Name(name), m_HasChildren(false), + m_NexusIDs(nexusIDs), m_ParentID(parentID) + {} int m_SortValue; int m_ID; int m_ParentID; @@ -64,13 +67,13 @@ public: QString m_Name; std::vector<int> m_NexusIDs; - friend bool operator<(const Category &LHS, const Category &RHS) { + friend bool operator<(const Category& LHS, const Category& RHS) + { return LHS.m_SortValue < RHS.m_SortValue; } }; public: - /** * @brief reset the list of categories **/ @@ -86,21 +89,21 @@ public: **/ void saveCategories(); - int addCategory(const QString &name, const std::vector<int> &nexusIDs, int parentID); + int addCategory(const QString& name, const std::vector<int>& nexusIDs, int parentID); /** * @brief retrieve the number of available categories * * @return unsigned int number of categories **/ - size_t numCategories() const { return m_Categories.size(); } + size_t numCategories() const { return m_Categories.size(); } /** * @brief count all categories that match a specified filter * @param filter the filter to test * @return number of matching categories */ - unsigned int countCategories(std::function<bool (const Category &category)> filter); + unsigned int countCategories(std::function<bool(const Category& category)> filter); /** * @brief get the id of the parent category @@ -156,7 +159,7 @@ public: * @brief look up the id of a category by its name * @note O(n) */ - int getCategoryID(const QString &name) const; + int getCategoryID(const QString& name) const; /** * @brief look up the index of a category by its id @@ -175,13 +178,12 @@ public: unsigned int resolveNexusID(int nexusID) const; public: - /** * @brief retrieve a reference to the singleton instance * * @return the reference to the singleton **/ - static CategoryFactory &instance(); + static CategoryFactory& instance(); /** * @return path to the file that contains the categories list @@ -189,20 +191,19 @@ public: static QString categoriesFilePath(); private: - CategoryFactory(); void loadDefaultCategories(); - void addCategory(int id, const QString &name, const std::vector<int> &nexusID, int parentID); + void addCategory(int id, const QString& name, const std::vector<int>& nexusID, + int parentID); void setParents(); static void cleanup(); private: - - static CategoryFactory *s_Instance; + static CategoryFactory* s_Instance; std::vector<Category> m_Categories; std::map<int, unsigned int> m_IDMap; @@ -213,5 +214,4 @@ private: bool isDescendantOfImpl(int id, int parentID, std::set<int>& seen) const; }; - -#endif // CATEGORIES_H +#endif // CATEGORIES_H diff --git a/src/categoriesdialog.cpp b/src/categoriesdialog.cpp index 7d195ce6..99a931ef 100644 --- a/src/categoriesdialog.cpp +++ b/src/categoriesdialog.cpp @@ -18,45 +18,46 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ #include "categoriesdialog.h" -#include "ui_categoriesdialog.h" #include "categories.h" -#include "utility.h" #include "settings.h" +#include "ui_categoriesdialog.h" +#include "utility.h" #include <QItemDelegate> -#include <QRegularExpressionValidator> #include <QLineEdit> #include <QMenu> +#include <QRegularExpressionValidator> - -class NewIDValidator : public QIntValidator { +class NewIDValidator : public QIntValidator +{ public: - NewIDValidator(const std::set<int> &ids) - : m_UsedIDs(ids) {} - virtual State validate(QString &input, int &pos) const { + NewIDValidator(const std::set<int>& ids) : m_UsedIDs(ids) {} + virtual State validate(QString& input, int& pos) const + { State intRes = QIntValidator::validate(input, pos); if (intRes == Acceptable) { bool ok = false; - int id = input.toInt(&ok); + int id = input.toInt(&ok); if (m_UsedIDs.find(id) != m_UsedIDs.end()) { return QValidator::Intermediate; } } return intRes; } + private: - const std::set<int> &m_UsedIDs; + const std::set<int>& m_UsedIDs; }; - -class ExistingIDValidator : public QIntValidator { +class ExistingIDValidator : public QIntValidator +{ public: - ExistingIDValidator(const std::set<int> &ids) - : m_UsedIDs(ids) {} - virtual State validate(QString &input, int &pos) const { + ExistingIDValidator(const std::set<int>& ids) : m_UsedIDs(ids) {} + virtual State validate(QString& input, int& pos) const + { State intRes = QIntValidator::validate(input, pos); if (intRes == Acceptable) { bool ok = false; - int id = input.toInt(&ok); + int id = input.toInt(&ok); if ((id == 0) || (m_UsedIDs.find(id) != m_UsedIDs.end())) { return QValidator::Acceptable; } else { @@ -66,43 +67,48 @@ public: return intRes; } } + private: - const std::set<int> &m_UsedIDs; + const std::set<int>& m_UsedIDs; }; - -class ValidatingDelegate : public QItemDelegate { +class ValidatingDelegate : public QItemDelegate +{ public: - ValidatingDelegate(QObject *parent, QValidator *validator) - : QItemDelegate(parent), m_Validator(validator) {} + ValidatingDelegate(QObject* parent, QValidator* validator) + : QItemDelegate(parent), m_Validator(validator) + {} - QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem&, const QModelIndex&) const + QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem&, + const QModelIndex&) const { - QLineEdit *edit = new QLineEdit(parent); + QLineEdit* edit = new QLineEdit(parent); edit->setValidator(m_Validator); return edit; } - virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const + virtual void setModelData(QWidget* editor, QAbstractItemModel* model, + const QModelIndex& index) const { - QLineEdit *edit = qobject_cast<QLineEdit*>(editor); - int pos = 0; + QLineEdit* edit = qobject_cast<QLineEdit*>(editor); + int pos = 0; QString editText = edit->text(); if (m_Validator->validate(editText, pos) == QValidator::Acceptable) { QItemDelegate::setModelData(editor, model, index); } } + private: - QValidator *m_Validator; + QValidator* m_Validator; }; - -CategoriesDialog::CategoriesDialog(QWidget *parent) - : TutorableDialog("Categories", parent), ui(new Ui::CategoriesDialog) +CategoriesDialog::CategoriesDialog(QWidget* parent) + : TutorableDialog("Categories", parent), ui(new Ui::CategoriesDialog) { ui->setupUi(this); fillTable(); - connect(ui->categoriesTable, SIGNAL(cellChanged(int,int)), this, SLOT(cellChanged(int,int))); + connect(ui->categoriesTable, SIGNAL(cellChanged(int, int)), this, + SLOT(cellChanged(int, int))); } CategoriesDialog::~CategoriesDialog() @@ -116,7 +122,6 @@ int CategoriesDialog::exec() return QDialog::exec(); } - void CategoriesDialog::cellChanged(int row, int) { int currentID = ui->categoriesTable->item(row, 0)->text().toInt(); @@ -125,14 +130,13 @@ void CategoriesDialog::cellChanged(int row, int) } } - void CategoriesDialog::commitChanges() { - CategoryFactory &categories = CategoryFactory::instance(); + CategoryFactory& categories = CategoryFactory::instance(); categories.reset(); for (int i = 0; i < ui->categoriesTable->rowCount(); ++i) { - int index = ui->categoriesTable->verticalHeader()->logicalIndex(i); + int index = ui->categoriesTable->verticalHeader()->logicalIndex(i); QString nexusIDString = ui->categoriesTable->item(index, 2)->text(); QStringList nexusIDStringList = nexusIDString.split(',', Qt::SkipEmptyParts); std::vector<int> nexusIDs; @@ -141,18 +145,15 @@ void CategoriesDialog::commitChanges() nexusIDs.push_back(iter->toInt()); } - categories.addCategory( - ui->categoriesTable->item(index, 0)->text().toInt(), - ui->categoriesTable->item(index, 1)->text(), - nexusIDs, - ui->categoriesTable->item(index, 3)->text().toInt()); + categories.addCategory(ui->categoriesTable->item(index, 0)->text().toInt(), + ui->categoriesTable->item(index, 1)->text(), nexusIDs, + ui->categoriesTable->item(index, 3)->text().toInt()); } categories.setParents(); categories.saveCategories(); } - void CategoriesDialog::refreshIDs() { m_HighestID = 0; @@ -165,13 +166,12 @@ void CategoriesDialog::refreshIDs() } } - void CategoriesDialog::fillTable() { - CategoryFactory &categories = CategoryFactory::instance(); - QTableWidget *table = ui->categoriesTable; + CategoryFactory& categories = CategoryFactory::instance(); + QTableWidget* table = ui->categoriesTable; -#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed); table->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); table->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Fixed); @@ -187,27 +187,33 @@ void CategoriesDialog::fillTable() table->verticalHeader()->setResizeMode(QHeaderView::Fixed); #endif - - table->setItemDelegateForColumn(0, new ValidatingDelegate(this, new NewIDValidator(m_IDs))); - table->setItemDelegateForColumn(2, new ValidatingDelegate(this, new QRegularExpressionValidator(QRegularExpression("([0-9]+)?(,[0-9]+)*"), this))); - table->setItemDelegateForColumn(3, new ValidatingDelegate(this, new ExistingIDValidator(m_IDs))); + table->setItemDelegateForColumn( + 0, new ValidatingDelegate(this, new NewIDValidator(m_IDs))); + table->setItemDelegateForColumn( + 2, new ValidatingDelegate(this, + new QRegularExpressionValidator( + QRegularExpression("([0-9]+)?(,[0-9]+)*"), this))); + table->setItemDelegateForColumn( + 3, new ValidatingDelegate(this, new ExistingIDValidator(m_IDs))); int row = 0; - for (std::vector<CategoryFactory::Category>::const_iterator iter = categories.m_Categories.begin(); + for (std::vector<CategoryFactory::Category>::const_iterator iter = + categories.m_Categories.begin(); iter != categories.m_Categories.end(); ++iter, ++row) { - const CategoryFactory::Category &category = *iter; + const CategoryFactory::Category& category = *iter; if (category.m_ID == 0) { --row; continue; } table->insertRow(row); -// table->setVerticalHeaderItem(row, new QTableWidgetItem(" ")); + // table->setVerticalHeaderItem(row, new QTableWidgetItem(" ")); QScopedPointer<QTableWidgetItem> idItem(new QTableWidgetItem()); idItem->setData(Qt::DisplayRole, category.m_ID); QScopedPointer<QTableWidgetItem> nameItem(new QTableWidgetItem(category.m_Name)); - QScopedPointer<QTableWidgetItem> nexusIDItem(new QTableWidgetItem(MOBase::VectorJoin(category.m_NexusIDs, ","))); + QScopedPointer<QTableWidgetItem> nexusIDItem( + new QTableWidgetItem(MOBase::VectorJoin(category.m_NexusIDs, ","))); QScopedPointer<QTableWidgetItem> parentIDItem(new QTableWidgetItem()); parentIDItem->setData(Qt::DisplayRole, category.m_ParentID); @@ -220,26 +226,24 @@ void CategoriesDialog::fillTable() refreshIDs(); } - void CategoriesDialog::addCategory_clicked() { int row = m_ContextRow >= 0 ? m_ContextRow : 0; ui->categoriesTable->insertRow(row); ui->categoriesTable->setVerticalHeaderItem(row, new QTableWidgetItem(" ")); - ui->categoriesTable->setItem(row, 0, new QTableWidgetItem(QString::number(++m_HighestID))); + ui->categoriesTable->setItem(row, 0, + new QTableWidgetItem(QString::number(++m_HighestID))); ui->categoriesTable->setItem(row, 1, new QTableWidgetItem("new")); ui->categoriesTable->setItem(row, 2, new QTableWidgetItem("")); ui->categoriesTable->setItem(row, 3, new QTableWidgetItem("0")); } - void CategoriesDialog::removeCategory_clicked() { ui->categoriesTable->removeRow(m_ContextRow); } - -void CategoriesDialog::on_categoriesTable_customContextMenuRequested(const QPoint &pos) +void CategoriesDialog::on_categoriesTable_customContextMenuRequested(const QPoint& pos) { m_ContextRow = ui->categoriesTable->rowAt(pos.y()); QMenu menu; diff --git a/src/categoriesdialog.h b/src/categoriesdialog.h index 39fb7130..2ac84124 100644 --- a/src/categoriesdialog.h +++ b/src/categoriesdialog.h @@ -23,7 +23,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "tutorabledialog.h" #include <set> -namespace Ui { +namespace Ui +{ class CategoriesDialog; } @@ -35,8 +36,7 @@ class CategoriesDialog : public MOBase::TutorableDialog Q_OBJECT public: - - explicit CategoriesDialog(QWidget *parent = 0); + explicit CategoriesDialog(QWidget* parent = 0); ~CategoriesDialog(); // also saves and restores geometry @@ -51,25 +51,21 @@ public: private slots: - void on_categoriesTable_customContextMenuRequested(const QPoint &pos); + void on_categoriesTable_customContextMenuRequested(const QPoint& pos); void addCategory_clicked(); void removeCategory_clicked(); void cellChanged(int row, int column); private: - void refreshIDs(); void fillTable(); private: - - Ui::CategoriesDialog *ui; + Ui::CategoriesDialog* ui; int m_ContextRow; int m_HighestID; std::set<int> m_IDs; - }; -#endif // CATEGORIESDIALOG_H - +#endif // CATEGORIESDIALOG_H diff --git a/src/colortable.cpp b/src/colortable.cpp index b1e4ef6c..c4e21d3d 100644 --- a/src/colortable.cpp +++ b/src/colortable.cpp @@ -1,29 +1,23 @@ #include "colortable.h" -#include "modflagicondelegate.h" #include "modconflicticondelegate.h" +#include "modflagicondelegate.h" #include "settings.h" class ColorItem; ColorItem* colorItemForRow(QTableWidget* table, int row); -void paintBackground( - QTableWidget* table, QPainter* p, const QStyleOptionViewItem& option, - const QModelIndex& index); - +void paintBackground(QTableWidget* table, QPainter* p, + const QStyleOptionViewItem& option, const QModelIndex& index); // delegate for the sample text column; paints the background color // class ColoredBackgroundDelegate : public QStyledItemDelegate { public: - ColoredBackgroundDelegate(QTableWidget* table) - : m_table(table) - { - } + ColoredBackgroundDelegate(QTableWidget* table) : m_table(table) {} - void paint( - QPainter* p, const QStyleOptionViewItem& option, - const QModelIndex& index) const override + void paint(QPainter* p, const QStyleOptionViewItem& option, + const QModelIndex& index) const override { paintBackground(m_table, p, option, index); @@ -41,20 +35,15 @@ private: QTableWidget* m_table; }; - // delegate for the icons column; paints the background and icons // class FakeModFlagIconDelegate : public ModFlagIconDelegate { public: - explicit FakeModFlagIconDelegate(QTableWidget* table) - : m_table(table) - { - } + explicit FakeModFlagIconDelegate(QTableWidget* table) : m_table(table) {} - void paint( - QPainter* painter, const QStyleOptionViewItem& option, - const QModelIndex& index) const override + void paint(QPainter* painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const override { paintBackground(m_table, painter, option, index); ModFlagIconDelegate::paintIcons(painter, option, index, getIcons(index)); @@ -63,12 +52,8 @@ public: protected: QList<QString> getIcons(const QModelIndex& index) const override { - const auto flags = { - ModInfo::FLAG_BACKUP, - ModInfo::FLAG_NOTENDORSED, - ModInfo::FLAG_NOTES, - ModInfo::FLAG_ALTERNATE_GAME - }; + const auto flags = {ModInfo::FLAG_BACKUP, ModInfo::FLAG_NOTENDORSED, + ModInfo::FLAG_NOTES, ModInfo::FLAG_ALTERNATE_GAME}; return getIconsForFlags(flags, false); } @@ -82,20 +67,15 @@ private: QTableWidget* m_table; }; - // delegate for the icons column; paints the background and icons // class FakeModConflictIconDelegate : public ModConflictIconDelegate { public: - explicit FakeModConflictIconDelegate(QTableWidget* table) - : m_table(table) - { - } + explicit FakeModConflictIconDelegate(QTableWidget* table) : m_table(table) {} - void paint( - QPainter* painter, const QStyleOptionViewItem& option, - const QModelIndex& index) const override + void paint(QPainter* painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const override { paintBackground(m_table, painter, option, index); ModFlagIconDelegate::paintIcons(painter, option, index, getIcons(index)); @@ -104,12 +84,10 @@ public: protected: QList<QString> getIcons(const QModelIndex& index) const override { - const auto flags = { - ModInfo::FLAG_CONFLICT_MIXED, - ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITE, - ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITTEN, - ModInfo::FLAG_ARCHIVE_CONFLICT_MIXED - }; + const auto flags = {ModInfo::FLAG_CONFLICT_MIXED, + ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITE, + ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITTEN, + ModInfo::FLAG_ARCHIVE_CONFLICT_MIXED}; return getIconsForFlags(flags, false); } @@ -123,18 +101,15 @@ private: QTableWidget* m_table; }; - // item used in the first column of the table // class ColorItem : public QTableWidgetItem { public: - ColorItem( - QString caption, QColor defaultColor, - std::function<QColor ()> get, - std::function<void (const QColor&)> commit) : - m_caption(std::move(caption)), m_default(defaultColor), - m_get(get), m_commit(commit) + ColorItem(QString caption, QColor defaultColor, std::function<QColor()> get, + std::function<void(const QColor&)> commit) + : m_caption(std::move(caption)), m_default(defaultColor), m_get(get), + m_commit(commit) { setText(m_caption); set(get()); @@ -142,17 +117,11 @@ public: // color caption // - const QString& caption() const - { - return m_caption; - } + const QString& caption() const { return m_caption; } // the current color // - QColor get() const - { - return m_temp; - } + QColor get() const { return m_temp; } // sets the current color, commit() must be called to save it // @@ -168,27 +137,20 @@ public: // resets the current color, commit() must be called to save it // - bool reset() - { - return set(m_default); - } + bool reset() { return set(m_default); } // saves the current color // - void commit() - { - m_commit(m_temp); - } + void commit() { m_commit(m_temp); } private: const QString m_caption; const QColor m_default; - std::function<QColor ()> m_get; - std::function<void (const QColor&)> m_commit; + std::function<QColor()> m_get; + std::function<void(const QColor&)> m_commit; QColor m_temp; }; - ColorItem* colorItemForRow(QTableWidget* table, int row) { return dynamic_cast<ColorItem*>(table->item(row, 0)); @@ -199,27 +161,24 @@ void forEachColorItem(QTableWidget* table, F&& f) { const auto rowCount = table->rowCount(); - for (int i=0; i<rowCount; ++i) { - if (auto* ci=colorItemForRow(table, i)) { + for (int i = 0; i < rowCount; ++i) { + if (auto* ci = colorItemForRow(table, i)) { f(ci); } } } -void paintBackground( - QTableWidget* table, QPainter* p, const QStyleOptionViewItem& option, - const QModelIndex& index) +void paintBackground(QTableWidget* table, QPainter* p, + const QStyleOptionViewItem& option, const QModelIndex& index) { - if (auto* ci=colorItemForRow(table, index.row())) { + if (auto* ci = colorItemForRow(table, index.row())) { p->save(); p->fillRect(option.rect, ci->get()); p->restore(); } } - -ColorTable::ColorTable(QWidget* parent) - : QTableWidget(parent), m_settings(nullptr) +ColorTable::ColorTable(QWidget* parent) : QTableWidget(parent), m_settings(nullptr) { setColumnCount(4); setHorizontalHeaderLabels({"", "", "", ""}); @@ -228,9 +187,9 @@ ColorTable::ColorTable(QWidget* parent) setItemDelegateForColumn(2, new FakeModConflictIconDelegate(this)); setItemDelegateForColumn(3, new FakeModFlagIconDelegate(this)); - connect( - this, &QTableWidget::cellActivated, - [&]{ onColorActivated(); }); + connect(this, &QTableWidget::cellActivated, [&] { + onColorActivated(); + }); } void ColorTable::load(Settings& s) @@ -238,40 +197,58 @@ void ColorTable::load(Settings& s) m_settings = &s; addColor( - QObject::tr("Is overwritten (loose files)"), - QColor(0, 255, 0, 64), - [this]{ return m_settings->colors().modlistOverwrittenLoose(); }, - [this](auto&& v){ m_settings->colors().setModlistOverwrittenLoose(v); }); + QObject::tr("Is overwritten (loose files)"), QColor(0, 255, 0, 64), + [this] { + return m_settings->colors().modlistOverwrittenLoose(); + }, + [this](auto&& v) { + m_settings->colors().setModlistOverwrittenLoose(v); + }); addColor( - QObject::tr("Is overwriting (loose files)"), - QColor(255, 0, 0, 64), - [this]{ return m_settings->colors().modlistOverwritingLoose(); }, - [this](auto&& v){ m_settings->colors().setModlistOverwritingLoose(v); }); + QObject::tr("Is overwriting (loose files)"), QColor(255, 0, 0, 64), + [this] { + return m_settings->colors().modlistOverwritingLoose(); + }, + [this](auto&& v) { + m_settings->colors().setModlistOverwritingLoose(v); + }); addColor( - QObject::tr("Is overwritten (archives)"), - QColor(0, 255, 255, 64), - [this]{ return m_settings->colors().modlistOverwrittenArchive(); }, - [this](auto&& v){ m_settings->colors().setModlistOverwrittenArchive(v); }); + QObject::tr("Is overwritten (archives)"), QColor(0, 255, 255, 64), + [this] { + return m_settings->colors().modlistOverwrittenArchive(); + }, + [this](auto&& v) { + m_settings->colors().setModlistOverwrittenArchive(v); + }); addColor( - QObject::tr("Is overwriting (archives)"), - QColor(255, 0, 255, 64), - [this]{ return m_settings->colors().modlistOverwritingArchive(); }, - [this](auto&& v){ m_settings->colors().setModlistOverwritingArchive(v); }); + QObject::tr("Is overwriting (archives)"), QColor(255, 0, 255, 64), + [this] { + return m_settings->colors().modlistOverwritingArchive(); + }, + [this](auto&& v) { + m_settings->colors().setModlistOverwritingArchive(v); + }); addColor( - QObject::tr("Mod contains selected plugin"), - QColor(0, 0, 255, 64), - [this]{ return m_settings->colors().modlistContainsPlugin(); }, - [this](auto&& v){ m_settings->colors().setModlistContainsPlugin(v); }); + QObject::tr("Mod contains selected plugin"), QColor(0, 0, 255, 64), + [this] { + return m_settings->colors().modlistContainsPlugin(); + }, + [this](auto&& v) { + m_settings->colors().setModlistContainsPlugin(v); + }); addColor( - QObject::tr("Plugin is contained in selected mod"), - QColor(0, 0, 255, 64), - [this]{ return m_settings->colors().pluginListContained(); }, - [this](auto&& v){ m_settings->colors().setPluginListContained(v); }); + QObject::tr("Plugin is contained in selected mod"), QColor(0, 0, 255, 64), + [this] { + return m_settings->colors().pluginListContained(); + }, + [this](auto&& v) { + m_settings->colors().setPluginListContained(v); + }); } void ColorTable::resetColors() @@ -296,10 +273,9 @@ void ColorTable::commitColors() }); } -void ColorTable::addColor( - const QString& text, const QColor& defaultColor, - std::function<QColor ()> get, - std::function<void (const QColor&)> commit) +void ColorTable::addColor(const QString& text, const QColor& defaultColor, + std::function<QColor()> get, + std::function<void(const QColor&)> commit) { const auto r = rowCount(); setRowCount(r + 1); @@ -319,13 +295,13 @@ void ColorTable::onColorActivated() } const auto row = rows[0].row(); - auto* ci = colorItemForRow(this, row); + auto* ci = colorItemForRow(this, row); if (!ci) { return; } const QColor result = QColorDialog::getColor( - ci->get(), topLevelWidget(), ci->caption(), QColorDialog::ShowAlphaChannel); + ci->get(), topLevelWidget(), ci->caption(), QColorDialog::ShowAlphaChannel); if (result.isValid()) { ci->set(result); diff --git a/src/colortable.h b/src/colortable.h index 039b6024..075171c3 100644 --- a/src/colortable.h +++ b/src/colortable.h @@ -10,7 +10,7 @@ class Settings; class ColorTable : public QTableWidget { public: - ColorTable(QWidget* parent=nullptr); + ColorTable(QWidget* parent = nullptr); // adds colors to the table from the settings // @@ -28,12 +28,10 @@ public: private: Settings* m_settings; - void addColor( - const QString& text, const QColor& defaultColor, - std::function<QColor ()> get, - std::function<void (const QColor&)> commit); + void addColor(const QString& text, const QColor& defaultColor, + std::function<QColor()> get, std::function<void(const QColor&)> commit); void onColorActivated(); }; -#endif // COLORTABLE_H +#endif // COLORTABLE_H diff --git a/src/commandline.cpp b/src/commandline.cpp index f64ff7cb..9082d710 100644 --- a/src/commandline.cpp +++ b/src/commandline.cpp @@ -1,11 +1,11 @@ #include "commandline.h" #include "env.h" -#include "organizercore.h" #include "instancemanager.h" -#include "multiprocess.h" #include "loglist.h" -#include "shared/util.h" +#include "multiprocess.h" +#include "organizercore.h" #include "shared/appconfig.h" +#include "shared/util.h" #include <log.h> #include <report.h> @@ -14,19 +14,18 @@ namespace cl using namespace MOBase; -std::string pad_right(std::string s, std::size_t n, char c=' ') +std::string pad_right(std::string s, std::size_t n, char c = ' ') { if (s.size() < n) - s.append(n - s.size() , c); + s.append(n - s.size(), c); return s; } // formats the list of pairs in two columns // -std::string table( - const std::vector<std::pair<std::string, std::string>>& v, - std::size_t indent, std::size_t spacing) +std::string table(const std::vector<std::pair<std::string, std::string>>& v, + std::size_t indent, std::size_t spacing) { std::size_t longest = 0; @@ -35,40 +34,28 @@ std::string table( std::string s; - for (auto&& p : v) - { + for (auto&& p : v) { if (!s.empty()) s += "\n"; - s += - std::string(indent, ' ') + - pad_right(p.first, longest) + " " + - std::string(spacing, ' ') + - p.second; + s += std::string(indent, ' ') + pad_right(p.first, longest) + " " + + std::string(spacing, ' ') + p.second; } return s; - } - -CommandLine::CommandLine() - : m_command(nullptr) +CommandLine::CommandLine() : m_command(nullptr) { createOptions(); - add< - RunCommand, - ReloadPluginCommand, - RefreshCommand, - CrashDumpCommand, - LaunchCommand>(); + add<RunCommand, ReloadPluginCommand, RefreshCommand, CrashDumpCommand, + LaunchCommand>(); } std::optional<int> CommandLine::process(const std::wstring& line) { - try - { + try { auto args = po::split_winmain(line); if (!args.empty()) { // remove program name @@ -79,18 +66,16 @@ std::optional<int> CommandLine::process(const std::wstring& line) // command name, but not the rest, which will be collected below auto parsed = po::wcommand_line_parser(args) - .options(m_allOptions) - .positional(m_positional) - .allow_unregistered() - .run(); + .options(m_allOptions) + .positional(m_positional) + .allow_unregistered() + .run(); po::store(parsed, m_vm); po::notify(m_vm); // collect options past the command name - auto opts = po::collect_unrecognized( - parsed.options, po::include_positional); - + auto opts = po::collect_unrecognized(parsed.options, po::include_positional); if (m_vm.count("command")) { // there's a word as the first argument; this may be a command name or @@ -106,8 +91,7 @@ std::optional<int> CommandLine::process(const std::wstring& line) // remove the command name itself opts.erase(opts.begin()); - try - { + try { // legacy commands handle their own parsing, such as 'launch'; don't // attempt to parse anything here if (!c->legacy()) { @@ -140,14 +124,10 @@ std::optional<int> CommandLine::process(const std::wstring& line) m_command = c.get(); return runEarly(); - } - catch(po::error& e) - { + } catch (po::error& e) { env::Console console; - std::cerr - << e.what() << "\n" - << usage(c.get()) << "\n"; + std::cerr << e.what() << "\n" << usage(c.get()) << "\n"; return 1; } @@ -155,7 +135,6 @@ std::optional<int> CommandLine::process(const std::wstring& line) } } - // the first word on the command line is not a valid command, try the other // stuff; this is used in setupCore() below when called from // MOApplication::doOneRun() @@ -167,7 +146,6 @@ std::optional<int> CommandLine::process(const std::wstring& line) return 0; } - if (!opts.empty()) { const auto qs = QString::fromStdWString(opts[0]); @@ -202,14 +180,10 @@ std::optional<int> CommandLine::process(const std::wstring& line) } return {}; - } - catch(po::error& e) - { + } catch (po::error& e) { env::Console console; - std::cerr - << e.what() << "\n" - << usage() << "\n"; + std::cerr << e.what() << "\n" << usage() << "\n"; return 1; } @@ -250,7 +224,7 @@ std::optional<int> CommandLine::runPostApplication(MOApplication& a) if (m_vm.count("instance") && m_vm["instance"].as<std::string>() == "") { env::Console c; - if (auto i=InstanceManager::singleton().currentInstance()) { + if (auto i = InstanceManager::singleton().currentInstance()) { std::cout << i->displayName().toStdString() << "\n"; } else { std::cout << "no instance configured\n"; @@ -283,13 +257,12 @@ std::optional<int> CommandLine::runPostOrganizer(OrganizerCore& core) // make sure MO doesn't exit even if locking is disabled, ForceWait and // PreventExit will do that core.processRunner() - .setFromShortcut(m_shortcut) - .setWaitForCompletion(ProcessRunner::ForCommandLine, UILocker::PreventExit) - .run(); + .setFromShortcut(m_shortcut) + .setWaitForCompletion(ProcessRunner::ForCommandLine, UILocker::PreventExit) + .run(); return 0; - } - catch (std::exception&) { + } catch (std::exception&) { // user was already warned return 1; } @@ -301,23 +274,19 @@ std::optional<int> CommandLine::runPostOrganizer(OrganizerCore& core) const QString exeName = *m_executable; log::debug("starting {} from command line", exeName); - try - { + try { // pass the remaining parameters to the binary // // make sure MO doesn't exit even if locking is disabled, ForceWait and // PreventExit will do that core.processRunner() - .setFromFileOrExecutable(exeName, m_untouched) - .setWaitForCompletion(ProcessRunner::ForCommandLine, UILocker::PreventExit) - .run(); + .setFromFileOrExecutable(exeName, m_untouched) + .setWaitForCompletion(ProcessRunner::ForCommandLine, UILocker::PreventExit) + .run(); return 0; - } - catch (const std::exception &e) - { - reportError( - QObject::tr("failed to start application: %1").arg(e.what())); + } catch (const std::exception& e) { + reportError(QObject::tr("failed to start application: %1").arg(e.what())); return 1; } } else if (m_command) { @@ -331,42 +300,31 @@ void CommandLine::clear() { m_vm.clear(); m_shortcut = {}; - m_nxmLink = {}; + m_nxmLink = {}; } void CommandLine::createOptions() { - m_visibleOptions.add_options() - ("help", - "show this message") - - ("multiple", - "allow multiple MO processes to run; see below") + m_visibleOptions.add_options()("help", "show this message") - ("pick", - "show the select instance dialog on startup") + ("multiple", "allow multiple MO processes to run; see below") - ("logs", - "duplicates the logs to stdout") + ("pick", "show the select instance dialog on startup") - ("instance,i", - po::value<std::string>()->implicit_value(""), - "use the given instance (defaults to last used)") + ("logs", "duplicates the logs to stdout") - ("profile,p", - po::value<std::string>(), - "use the given profile (defaults to last used)"); + ("instance,i", po::value<std::string>()->implicit_value(""), + "use the given instance (defaults to last used)") + ("profile,p", po::value<std::string>(), + "use the given profile (defaults to last used)"); po::options_description options; - options.add_options() - ("command", po::value<std::string>(), "command") - ("subargs", po::value<std::vector<std::string> >(), "args"); + options.add_options()("command", po::value<std::string>(), "command")( + "subargs", po::value<std::vector<std::string>>(), "args"); // one command name, followed by any arguments for that command - m_positional - .add("command", 1) - .add("subargs", -1); + m_positional.add("command", 1).add("subargs", -1); m_allOptions.add(m_visibleOptions); m_allOptions.add(options); @@ -376,27 +334,22 @@ std::string CommandLine::usage(const Command* c) const { std::ostringstream oss; - oss - << "\n" - << "Usage:\n"; + oss << "\n" + << "Usage:\n"; if (c) { - oss - << " ModOrganizer.exe [global-options] " << c->usageLine() << "\n\n"; + oss << " ModOrganizer.exe [global-options] " << c->usageLine() << "\n\n"; const std::string more = c->moreInfo(); if (!more.empty()) { oss << more << "\n\n"; } - oss - << "Command options:\n" - << c->visibleOptions() << "\n"; + oss << "Command options:\n" << c->visibleOptions() << "\n"; } else { - oss - << " ModOrganizer.exe [options] [[command] [command-options]]\n" - << "\n" - << "Commands:\n"; + oss << " ModOrganizer.exe [options] [[command] [command-options]]\n" + << "\n" + << "Commands:\n"; // name and description for all commands std::vector<std::pair<std::string, std::string>> v; @@ -409,14 +362,11 @@ std::string CommandLine::usage(const Command* c) const v.push_back({c->name(), c->description()}); } - oss - << table(v, 2, 4) << "\n" - << "\n"; + oss << table(v, 2, 4) << "\n" + << "\n"; } - oss - << "Global options:\n" - << m_visibleOptions << "\n"; + oss << "Global options:\n" << m_visibleOptions << "\n"; // show the more text unless this is usage for a specific command if (!c) { @@ -480,32 +430,29 @@ const QStringList& CommandLine::untouched() const std::string CommandLine::more() const { - return - "Multiple processes\n" - " A note on terminology: 'instance' can either mean an MO process\n" - " that's running on the system, or a set of mods and profiles managed\n" - " by MO. To avoid confusion, the term 'process' is used below for the\n" - " former.\n" - " \n" - " --multiple can be used to allow multiple MO processes to run\n" - " simultaneously. This is unsupported and can create all sorts of weird\n" - " problems. To minimize these:\n" - " \n" - " 1) Never have multiple MO processes running that manage the same\n" - " game instance.\n" - " 2) If an executable is launched from an MO process, only this\n" - " process may launch executables until all processes are \n" - " terminated.\n" - " \n" - " It is recommended to close _all_ MO processes as soon as multiple\n" - " processes become unnecessary."; + return "Multiple processes\n" + " A note on terminology: 'instance' can either mean an MO process\n" + " that's running on the system, or a set of mods and profiles managed\n" + " by MO. To avoid confusion, the term 'process' is used below for the\n" + " former.\n" + " \n" + " --multiple can be used to allow multiple MO processes to run\n" + " simultaneously. This is unsupported and can create all sorts of weird\n" + " problems. To minimize these:\n" + " \n" + " 1) Never have multiple MO processes running that manage the same\n" + " game instance.\n" + " 2) If an executable is launched from an MO process, only this\n" + " process may launch executables until all processes are \n" + " terminated.\n" + " \n" + " It is recommended to close _all_ MO processes as soon as multiple\n" + " processes become unnecessary."; } - Command::Meta::Meta(std::string n, std::string d, std::string u, std::string m) - : name(n), description(d), usage(u), more(m) -{ -} + : name(n), description(d), usage(u), more(m) +{} std::string Command::name() const { @@ -541,8 +488,7 @@ po::options_description Command::visibleOptions() const { po::options_description d(getVisibleOptions()); - d.add_options() - ("help", "shows this message"); + d.add_options()("help", "shows this message"); return d; } @@ -575,13 +521,11 @@ po::positional_options_description Command::getPositional() const return {}; } -void Command::set( - const std::wstring& originalLine, - po::variables_map vm, - std::vector<std::wstring> untouched) +void Command::set(const std::wstring& originalLine, po::variables_map vm, + std::vector<std::wstring> untouched) { - m_original = originalLine; - m_vm = vm; + m_original = originalLine; + m_vm = vm; m_untouched = untouched; } @@ -625,25 +569,20 @@ const std::vector<std::wstring>& Command::untouched() const return m_untouched; } - po::options_description CrashDumpCommand::getVisibleOptions() const { po::options_description d; - d.add_options() - ("type", po::value<std::string>()->default_value("mini"), "mini|data|full"); + d.add_options()("type", po::value<std::string>()->default_value("mini"), + "mini|data|full"); return d; } Command::Meta CrashDumpCommand::meta() const { - return { - "crashdump", - "writes a crashdump for a running process of MO", - "[options]", - "" - }; + return {"crashdump", "writes a crashdump for a running process of MO", "[options]", + ""}; } std::optional<int> CrashDumpCommand::runEarly() @@ -651,7 +590,7 @@ std::optional<int> CrashDumpCommand::runEarly() env::Console console; const auto typeString = vm()["type"].as<std::string>(); - const auto type = env::coreDumpTypeFromString(typeString); + const auto type = env::coreDumpTypeFromString(typeString); // dump const auto b = env::coredumpOther(type); @@ -665,7 +604,6 @@ std::optional<int> CrashDumpCommand::runEarly() return (b ? 0 : 1); } - Command::Meta LaunchCommand::meta() const { return {"launch", "(internal, do not use)", "", ""}; @@ -691,14 +629,15 @@ std::optional<int> LaunchCommand::runEarly() int LaunchCommand::SpawnWaitProcess(LPCWSTR workingDirectory, LPCWSTR commandLine) { - PROCESS_INFORMATION pi{ 0 }; - STARTUPINFO si{ 0 }; - si.cb = sizeof(si); + PROCESS_INFORMATION pi{0}; + STARTUPINFO si{0}; + si.cb = sizeof(si); std::wstring commandLineCopy = commandLine; - if (!CreateProcessW(NULL, &commandLineCopy[0], NULL, NULL, FALSE, 0, NULL, workingDirectory, &si, &pi)) { - // A bit of a problem where to log the error message here, at least this way you can get the message - // using a either DebugView or a live debugger: + if (!CreateProcessW(NULL, &commandLineCopy[0], NULL, NULL, FALSE, 0, NULL, + workingDirectory, &si, &pi)) { + // A bit of a problem where to log the error message here, at least this way you can + // get the message using a either DebugView or a live debugger: std::wostringstream ost; ost << L"CreateProcess failed: " << commandLine << ", " << GetLastError(); OutputDebugStringW(ost.str().c_str()); @@ -714,15 +653,15 @@ int LaunchCommand::SpawnWaitProcess(LPCWSTR workingDirectory, LPCWSTR commandLin return static_cast<int>(exitCode); } -// Parses the first parseArgCount arguments of the current process command line and returns -// them in parsedArgs, the rest of the command line is returned untouched. -LPCWSTR LaunchCommand::UntouchedCommandLineArguments( - int parseArgCount, std::vector<std::wstring>& parsedArgs) +// Parses the first parseArgCount arguments of the current process command line and +// returns them in parsedArgs, the rest of the command line is returned untouched. +LPCWSTR +LaunchCommand::UntouchedCommandLineArguments(int parseArgCount, + std::vector<std::wstring>& parsedArgs) { LPCWSTR cmd = GetCommandLineW(); - LPCWSTR arg = nullptr; // to skip executable name - for (; parseArgCount >= 0 && *cmd; ++cmd) - { + LPCWSTR arg = nullptr; // to skip executable name + for (; parseArgCount >= 0 && *cmd; ++cmd) { if (*cmd == '"') { int escaped = 0; for (++cmd; *cmd && (*cmd != '"' || escaped % 2 != 0); ++cmd) @@ -730,8 +669,8 @@ LPCWSTR LaunchCommand::UntouchedCommandLineArguments( } if (*cmd == ' ') { if (arg) - if (cmd-1 > arg && *arg == '"' && *(cmd-1) == '"') - parsedArgs.push_back(std::wstring(arg+1, cmd-1)); + if (cmd - 1 > arg && *arg == '"' && *(cmd - 1) == '"') + parsedArgs.push_back(std::wstring(arg + 1, cmd - 1)); else parsedArgs.push_back(std::wstring(arg, cmd)); arg = cmd + 1; @@ -741,29 +680,25 @@ LPCWSTR LaunchCommand::UntouchedCommandLineArguments( return cmd; } - Command::Meta RunCommand::meta() const { - return { - "run", - "runs a program, file or a configured executable", - "[options] NAME", + return {"run", "runs a program, file or a configured executable", "[options] NAME", - "Runs a program or a file with the virtual filesystem. If NAME is a path\n" - "to a non-executable file, the program that is associated with the file\n" - "extension is run instead. With -e, NAME must refer to the name of an\n" - "executable in the instance (for example, \"SKSE\")." - }; + "Runs a program or a file with the virtual filesystem. If NAME is a path\n" + "to a non-executable file, the program that is associated with the file\n" + "extension is run instead. With -e, NAME must refer to the name of an\n" + "executable in the instance (for example, \"SKSE\")."}; } po::options_description RunCommand::getVisibleOptions() const { po::options_description d; - d.add_options() - ("executable,e", po::value<bool>()->default_value(false)->zero_tokens(), "the name is a configured executable name") - ("arguments,a", po::value<std::string>(), "override arguments") - ("cwd,c", po::value<std::string>(), "override working directory"); + d.add_options()("executable,e", + po::value<bool>()->default_value(false)->zero_tokens(), + "the name is a configured executable name")( + "arguments,a", po::value<std::string>(), "override arguments")( + "cwd,c", po::value<std::string>(), "override working directory"); return d; } @@ -772,8 +707,8 @@ po::options_description RunCommand::getInternalOptions() const { po::options_description d; - d.add_options() - ("NAME", po::value<std::string>()->required(), "program or executable name"); + d.add_options()("NAME", po::value<std::string>()->required(), + "program or executable name"); return d; } @@ -796,8 +731,7 @@ std::optional<int> RunCommand::runPostOrganizer(OrganizerCore& core) { const auto program = QString::fromStdString(vm()["NAME"].as<std::string>()); - try - { + try { // make sure MO doesn't exit even if locking is disabled, ForceWait and // PreventExit will do that auto p = core.processRunner(); @@ -814,9 +748,9 @@ std::optional<int> RunCommand::runPostOrganizer(OrganizerCore& core) if (itor == exes.end()) { // not found reportError( - QObject::tr("Executable '%1' not found in instance '%2'.") - .arg(program) - .arg(InstanceManager::singleton().currentInstance()->displayName())); + QObject::tr("Executable '%1' not found in instance '%2'.") + .arg(program) + .arg(InstanceManager::singleton().currentInstance()->displayName())); return 1; } @@ -840,40 +774,33 @@ std::optional<int> RunCommand::runPostOrganizer(OrganizerCore& core) const auto r = p.run(); if (r == ProcessRunner::Error) { reportError( - QObject::tr("Failed to run '%1'. The logs might have more information.").arg(program)); + QObject::tr("Failed to run '%1'. The logs might have more information.") + .arg(program)); return 1; } return 0; - } - catch (const std::exception &e) { + } catch (const std::exception& e) { reportError( - QObject::tr("Failed to run '%1'. The logs might have more information. %2") - .arg(program).arg(e.what())); + QObject::tr("Failed to run '%1'. The logs might have more information. %2") + .arg(program) + .arg(e.what())); return 1; } } - - Command::Meta ReloadPluginCommand::meta() const { - return { - "reload-plugin", - "reloads the given plugin", - "PLUGIN", - "" - }; + return {"reload-plugin", "reloads the given plugin", "PLUGIN", ""}; } po::options_description ReloadPluginCommand::getInternalOptions() const { po::options_description d; - d.add_options() - ("PLUGIN", po::value<std::string>()->required(), "plugin name"); + d.add_options()("PLUGIN", po::value<std::string>()->required(), "plugin name"); return d; } @@ -896,10 +823,9 @@ std::optional<int> ReloadPluginCommand::runPostOrganizer(OrganizerCore& core) { const QString name = QString::fromStdString(vm()["PLUGIN"].as<std::string>()); - QString filepath = QDir( - qApp->applicationDirPath() + "/" + - ToQString(AppConfig::pluginPath())) - .absoluteFilePath(name); + QString filepath = + QDir(qApp->applicationDirPath() + "/" + ToQString(AppConfig::pluginPath())) + .absoluteFilePath(name); log::debug("reloading plugin from {}", filepath); core.pluginContainer().reloadPlugin(filepath); @@ -907,14 +833,9 @@ std::optional<int> ReloadPluginCommand::runPostOrganizer(OrganizerCore& core) return {}; } - Command::Meta RefreshCommand::meta() const { - return { - "refresh", - "refreshes MO (same as F5)", - "", "" - }; + return {"refresh", "refreshes MO (same as F5)", "", ""}; } bool RefreshCommand::canForwardToPrimary() const @@ -928,4 +849,4 @@ std::optional<int> RefreshCommand::runPostOrganizer(OrganizerCore& core) return {}; } -} // namespace +} // namespace cl diff --git a/src/commandline.h b/src/commandline.h index a0b70fb2..c93d77f5 100644 --- a/src/commandline.h +++ b/src/commandline.h @@ -1,8 +1,8 @@ #ifndef MODORGANIZER_COMMANDLINE_INCLUDED #define MODORGANIZER_COMMANDLINE_INCLUDED #include "moshortcut.h" -#include <vector> #include <memory> +#include <vector> class OrganizerCore; class MOApplication; @@ -37,7 +37,6 @@ public: // std::string moreInfo() const; - // returns all options for this command, including hidden ones; used to parse // the command line // @@ -58,11 +57,8 @@ public: // remembers the given values // - void set( - const std::wstring& originalLine, - po::variables_map vm, - std::vector<std::wstring> untouched); - + void set(const std::wstring& originalLine, po::variables_map vm, + std::vector<std::wstring> untouched); // called as soon as the command line has been parsed; return something to // exit immediately @@ -105,17 +101,14 @@ protected: { std::string name, description, usage, more; - Meta( - std::string name, std::string description, - std::string usage, std::string more); + Meta(std::string name, std::string description, std::string usage, + std::string more); }; - // meta // virtual Meta meta() const = 0; - // returns visible options specific to this command // virtual po::options_description getVisibleOptions() const; @@ -128,7 +121,6 @@ protected: // virtual po::positional_options_description getPositional() const; - // returns the original command line // const std::wstring& originalCmd() const; @@ -147,7 +139,6 @@ private: std::vector<std::wstring> m_untouched; }; - // generates a crash dump for another MO process // class CrashDumpCommand : public Command @@ -158,7 +149,6 @@ protected: std::optional<int> runEarly() override; }; - // this is the `launch` command used when starting a process from within the // virtualized directory, see processrunner.cpp // @@ -182,11 +172,10 @@ protected: int SpawnWaitProcess(LPCWSTR workingDirectory, LPCWSTR commandLine); - LPCWSTR UntouchedCommandLineArguments( - int parseArgCount, std::vector<std::wstring>& parsedArgs); + LPCWSTR UntouchedCommandLineArguments(int parseArgCount, + std::vector<std::wstring>& parsedArgs); }; - // runs a program or an executable // class RunCommand : public Command @@ -202,7 +191,6 @@ protected: std::optional<int> runPostOrganizer(OrganizerCore& core) override; }; - // reloads the given plugin // class ReloadPluginCommand : public Command @@ -217,7 +205,6 @@ protected: std::optional<int> runPostOrganizer(OrganizerCore& core) override; }; - // refreshes mo // class RefreshCommand : public Command @@ -228,8 +215,6 @@ protected: std::optional<int> runPostOrganizer(OrganizerCore& core) override; }; - - // parses the command line and runs any given command // // the command line used to support a few commands but with no real conventions; @@ -308,7 +293,6 @@ public: // bool forwardToPrimary(MOMultiProcess& multiProcess); - // clears parsed options, used when MO is "restarted" so the options aren't // processed again // @@ -316,7 +300,7 @@ public: // global usage string plus usage for the given command, if any // - std::string usage(const Command* c=nullptr) const; + std::string usage(const Command* c = nullptr) const; // whether --pick was given // @@ -374,6 +358,6 @@ private: std::optional<int> runEarly(); }; -} // namespace +} // namespace cl #endif // MODORGANIZER_COMMANDLINE_INCLUDED diff --git a/src/copyeventfilter.cpp b/src/copyeventfilter.cpp index bd61e04d..cee574c3 100644 --- a/src/copyeventfilter.cpp +++ b/src/copyeventfilter.cpp @@ -4,18 +4,16 @@ #include <QGuiApplication> #include <QKeyEvent> -CopyEventFilter::CopyEventFilter(QAbstractItemView* view, int column, int role) : - CopyEventFilter(view, [=](auto& index) { return index.sibling(index.row(), column).data(role).toString(); }) -{ - -} +CopyEventFilter::CopyEventFilter(QAbstractItemView* view, int column, int role) + : CopyEventFilter(view, [=](auto& index) { + return index.sibling(index.row(), column).data(role).toString(); + }) +{} -CopyEventFilter::CopyEventFilter( - QAbstractItemView* view, std::function<QString(const QModelIndex&)> format) : - QObject(view), m_view(view), m_format(format) -{ - -} +CopyEventFilter::CopyEventFilter(QAbstractItemView* view, + std::function<QString(const QModelIndex&)> format) + : QObject(view), m_view(view), m_format(format) +{} void CopyEventFilter::copySelection() const { @@ -25,9 +23,10 @@ void CopyEventFilter::copySelection() const // sort to reflect the visual order QModelIndexList selectedRows = m_view->selectionModel()->selectedRows(); - std::sort(selectedRows.begin(), selectedRows.end(), [=](const auto& lidx, const auto& ridx) { - return m_view->visualRect(lidx).top() < m_view->visualRect(ridx).top(); - }); + std::sort(selectedRows.begin(), selectedRows.end(), + [=](const auto& lidx, const auto& ridx) { + return m_view->visualRect(lidx).top() < m_view->visualRect(ridx).top(); + }); QStringList rows; for (auto& idx : selectedRows) { @@ -41,8 +40,7 @@ bool CopyEventFilter::eventFilter(QObject* sender, QEvent* event) { if (sender == m_view && event->type() == QEvent::KeyPress) { QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event); - if (keyEvent->modifiers() == Qt::ControlModifier - && keyEvent->key() == Qt::Key_C) { + if (keyEvent->modifiers() == Qt::ControlModifier && keyEvent->key() == Qt::Key_C) { copySelection(); return true; } diff --git a/src/copyeventfilter.h b/src/copyeventfilter.h index 141ddae1..0ad51584 100644 --- a/src/copyeventfilter.h +++ b/src/copyeventfilter.h @@ -22,9 +22,9 @@ class CopyEventFilter : public QObject Q_OBJECT public: - CopyEventFilter(QAbstractItemView* view, int column = 0, int role = Qt::DisplayRole); - CopyEventFilter(QAbstractItemView* view, std::function<QString(const QModelIndex&)> format); + CopyEventFilter(QAbstractItemView* view, + std::function<QString(const QModelIndex&)> format); // copy the selection of the view associated with this // event filter into the clipboard @@ -34,10 +34,8 @@ public: bool eventFilter(QObject* sender, QEvent* event) override; private: - QAbstractItemView* m_view; std::function<QString(const QModelIndex&)> m_format; - }; #endif diff --git a/src/createinstancedialog.cpp b/src/createinstancedialog.cpp index e728aec1..c5f51e0e 100644 --- a/src/createinstancedialog.cpp +++ b/src/createinstancedialog.cpp @@ -1,17 +1,17 @@ #include "createinstancedialog.h" -#include "ui_createinstancedialog.h" #include "createinstancedialogpages.h" #include "instancemanager.h" #include "settings.h" -#include "shared/util.h" #include "shared/appconfig.h" +#include "shared/util.h" +#include "ui_createinstancedialog.h" #include <iplugingame.h> #include <utility.h> using namespace MOBase; - -class Failed {}; +class Failed +{}; // create() will create all the directories in `target`; if any path component // fails to create, it will throw Failed @@ -22,31 +22,24 @@ class Failed {}; class DirectoryCreator { public: - DirectoryCreator(const DirectoryCreator&) = delete; + DirectoryCreator(const DirectoryCreator&) = delete; DirectoryCreator& operator=(const DirectoryCreator&) = delete; - static std::unique_ptr<DirectoryCreator> create( - const QDir& target, std::function<void (QString)> log) + static std::unique_ptr<DirectoryCreator> create(const QDir& target, + std::function<void(QString)> log) { return std::unique_ptr<DirectoryCreator>(new DirectoryCreator(target, log)); } - ~DirectoryCreator() - { - rollback(); - } + ~DirectoryCreator() { rollback(); } - void commit() - { - m_created.clear(); - } + void commit() { m_created.clear(); } void rollback() noexcept { - try - { + try { // delete each directory starting from the end - for (auto itor=m_created.rbegin(); itor!=m_created.rend(); ++itor) { + for (auto itor = m_created.rbegin(); itor != m_created.rend(); ++itor) { const auto r = shell::DeleteDirectoryRecursive(*itor); if (!r) { m_logger(r.toString()); @@ -54,23 +47,19 @@ public: } m_created.clear(); - } - catch(...) - { + } catch (...) { // eat it } } private: - std::function<void (QString)> m_logger; + std::function<void(QString)> m_logger; - DirectoryCreator(const QDir& target, std::function<void (QString)> log) - : m_logger(log) + DirectoryCreator(const QDir& target, std::function<void(QString)> log) : m_logger(log) { - try - { + try { // split on separators - const QString s = QDir::toNativeSeparators(target.absolutePath()); + const QString s = QDir::toNativeSeparators(target.absolutePath()); const QStringList cs = s.split("\\"); if (cs.empty()) { @@ -81,7 +70,7 @@ private: QDir d(cs[0]); // for each directory after the root - for (int i=1; i<cs.size(); ++i) { + for (int i = 1; i < cs.size(); ++i) { d = d.filePath(cs[i]); if (!d.exists()) { @@ -96,9 +85,7 @@ private: m_created.push_back(d); } } - } - catch(...) - { + } catch (...) { rollback(); throw; } @@ -108,11 +95,10 @@ private: std::vector<QDir> m_created; }; - -CreateInstanceDialog::CreateInstanceDialog( - const PluginContainer& pc, Settings* s, QWidget *parent) : - QDialog(parent), ui(new Ui::CreateInstanceDialog), m_pc(pc), m_settings(s), - m_switching(false), m_singlePage(false) +CreateInstanceDialog::CreateInstanceDialog(const PluginContainer& pc, Settings* s, + QWidget* parent) + : QDialog(parent), ui(new Ui::CreateInstanceDialog), m_pc(pc), m_settings(s), + m_switching(false), m_singlePage(false) { using namespace cid; @@ -131,8 +117,7 @@ CreateInstanceDialog::CreateInstanceDialog( ui->pages->setCurrentIndex(0); ui->launch->setChecked(true); - if (!InstanceManager::singleton().hasAnyInstances()) - { + if (!InstanceManager::singleton().hasAnyInstances()) { // first run of MO, there are no instances yet, force launch ui->launch->setEnabled(false); } @@ -147,13 +132,25 @@ CreateInstanceDialog::CreateInstanceDialog( addShortcutAction(QKeySequence::Find, Actions::Find); - addShortcut(Qt::ALT+Qt::Key_Left, [&]{ back(); }); - addShortcut(Qt::ALT+Qt::Key_Right, [&]{ next(false); }); - addShortcut(Qt::CTRL+Qt::Key_Return, [&]{ next(); }); + addShortcut(Qt::ALT + Qt::Key_Left, [&] { + back(); + }); + addShortcut(Qt::ALT + Qt::Key_Right, [&] { + next(false); + }); + addShortcut(Qt::CTRL + Qt::Key_Return, [&] { + next(); + }); - connect(ui->next, &QPushButton::clicked, [&]{ next(); }); - connect(ui->back, &QPushButton::clicked, [&]{ back(); }); - connect(ui->cancel, &QPushButton::clicked, [&]{ reject(); }); + connect(ui->next, &QPushButton::clicked, [&] { + next(); + }); + connect(ui->back, &QPushButton::clicked, [&] { + back(); + }); + connect(ui->cancel, &QPushButton::clicked, [&] { + reject(); + }); } CreateInstanceDialog::~CreateInstanceDialog() = default; @@ -175,7 +172,7 @@ Settings* CreateInstanceDialog::settings() bool CreateInstanceDialog::isOnLastPage() const { - for (int i=ui->pages->currentIndex() + 1; i < ui->pages->count(); ++i) { + for (int i = ui->pages->currentIndex() + 1; i < ui->pages->count(); ++i) { if (!m_pages[i]->skip()) { return false; } @@ -190,7 +187,7 @@ void CreateInstanceDialog::next(bool allowFinish) return; } - const auto i = ui->pages->currentIndex(); + const auto i = ui->pages->currentIndex(); const auto last = isOnLastPage(); if (last) { @@ -216,8 +213,7 @@ void CreateInstanceDialog::back() changePage(-1); } -void CreateInstanceDialog::addShortcut( - QKeySequence seq, std::function<void ()> f) +void CreateInstanceDialog::addShortcut(QKeySequence seq, std::function<void()> f) { auto* sc = new QShortcut(seq, this); @@ -229,7 +225,9 @@ void CreateInstanceDialog::addShortcut( void CreateInstanceDialog::addShortcutAction(QKeySequence seq, Actions a) { - addShortcut(seq, [this, a]{ doAction(a); }); + addShortcut(seq, [this, a] { + doAction(a); + }); } void CreateInstanceDialog::doAction(Actions a) @@ -313,13 +311,10 @@ void CreateInstanceDialog::finish() return DirectoryCreator::create(path, logger); }; - // don't restart if this is the first instance, it'll be selected and opened const bool mustRestart = InstanceManager::singleton().hasAnyInstances(); - - try - { + try { std::vector<std::unique_ptr<DirectoryCreator>> dirs; // creating all these directories; if any of them fail, this throws and @@ -331,7 +326,6 @@ void CreateInstanceDialog::finish() dirs.push_back(createDir(PathSettings::resolve(ci.paths.profiles, ci.paths.base))); dirs.push_back(createDir(PathSettings::resolve(ci.paths.overwrite, ci.paths.base))); - // creating ini Settings s(ci.iniPath); s.game().setName(ci.game->gameName()); @@ -367,25 +361,23 @@ void CreateInstanceDialog::finish() const auto r = s.sync(); if (r != QSettings::NoError) { - switch (r) - { - case QSettings::AccessError: - logCreation(formatSystemMessage(ERROR_ACCESS_DENIED)); - break; + switch (r) { + case QSettings::AccessError: + logCreation(formatSystemMessage(ERROR_ACCESS_DENIED)); + break; - case QSettings::FormatError: - logCreation(tr("Format error.")); - break; + case QSettings::FormatError: + logCreation(tr("Format error.")); + break; - default: - logCreation(tr("Error %1.").arg(static_cast<int>(r))); - break; + default: + logCreation(tr("Error %1.").arg(static_cast<int>(r))); + break; } throw Failed(); } - // committing all the directories so they don't get deleted for (auto& d : dirs) { d->commit(); @@ -405,9 +397,7 @@ void CreateInstanceDialog::finish() // close the dialog accept(); - } - catch(Failed&) - { + } catch (Failed&) { // if Failed was thrown, all the directories have been deleted } } @@ -436,7 +426,7 @@ void CreateInstanceDialog::selectPage(std::size_t i) void CreateInstanceDialog::updateNavigation() { - const auto i = ui->pages->currentIndex(); + const auto i = ui->pages->currentIndex(); const auto last = isOnLastPage(); ui->next->setEnabled(canNext()); @@ -459,8 +449,7 @@ bool CreateInstanceDialog::canBack() const { auto i = ui->pages->currentIndex(); - for (;;) - { + for (;;) { if (i == 0) { break; } @@ -480,8 +469,7 @@ bool CreateInstanceDialog::switching() const return m_switching; } -CreateInstanceDialog::CreationInfo -CreateInstanceDialog::rawCreationInfo() const +CreateInstanceDialog::CreationInfo CreateInstanceDialog::rawCreationInfo() const { const auto iniFilename = QString::fromStdWString(AppConfig::iniFileName()); @@ -500,17 +488,15 @@ CreateInstanceDialog::rawCreationInfo() const ci.dataPath = InstanceManager::singleton().instancePath(ci.instanceName); } - ci.dataPath = QDir::toNativeSeparators(ci.dataPath); - ci.iniPath = ci.dataPath + "/" + iniFilename; + ci.dataPath = QDir::toNativeSeparators(ci.dataPath); + ci.iniPath = ci.dataPath + "/" + iniFilename; return ci; } -CreateInstanceDialog::CreationInfo -CreateInstanceDialog::creationInfo() const +CreateInstanceDialog::CreationInfo CreateInstanceDialog::creationInfo() const { - auto fixVarDir = [](QString& path, const std::wstring& defaultDir) - { + auto fixVarDir = [](QString& path, const std::wstring& defaultDir) { // if the path is empty, it wasn't filled by the user, probably because // the "Advanced" checkbox wasn't checked, so use the base dir variable // with the default dir @@ -524,17 +510,14 @@ CreateInstanceDialog::creationInfo() const path = QDir::toNativeSeparators(path); }; - auto fixDirPath = [](QString& path) - { + auto fixDirPath = [](QString& path) { path = QDir::toNativeSeparators(QDir(path).absolutePath()); }; - auto fixFilePath = [](QString& path) - { + auto fixFilePath = [](QString& path) { path = QDir::toNativeSeparators(QFileInfo(path).absolutePath()); }; - auto ci = rawCreationInfo(); fixDirPath(ci.paths.base); diff --git a/src/createinstancedialog.h b/src/createinstancedialog.h index 8e8fe517..fe3c5646 100644 --- a/src/createinstancedialog.h +++ b/src/createinstancedialog.h @@ -3,9 +3,18 @@ #include <QDialog> -namespace MOBase { class IPluginGame; } -namespace Ui { class CreateInstanceDialog; }; -namespace cid { class Page; } +namespace MOBase +{ +class IPluginGame; +} +namespace Ui +{ +class CreateInstanceDialog; +}; +namespace cid +{ +class Page; +} class PluginContainer; class Settings; @@ -71,9 +80,8 @@ public: Paths paths; }; - - CreateInstanceDialog( - const PluginContainer& pc, Settings* s, QWidget *parent = nullptr); + CreateInstanceDialog(const PluginContainer& pc, Settings* s, + QWidget* parent = nullptr); ~CreateInstanceDialog(); @@ -87,7 +95,7 @@ public: void setSinglePage(const QString& instanceName) { for (auto&& p : m_pages) { - if (auto* tp=dynamic_cast<Page*>(p.get())) { + if (auto* tp = dynamic_cast<Page*>(p.get())) { tp->setSkip(false); } else { p->setSkip(true); @@ -103,7 +111,7 @@ public: Page* getPage() { for (auto&& p : m_pages) { - if (auto* tp=dynamic_cast<Page*>(p.get())) { + if (auto* tp = dynamic_cast<Page*>(p.get())) { return tp; } } @@ -111,11 +119,10 @@ public: return nullptr; } - // moves to the next page; if `allowFinish` is true, calls finish() if // currently on the last page // - void next(bool allowFinish=true); + void next(bool allowFinish = true); // moves to the previous page, if any // @@ -144,7 +151,6 @@ public: // void finish(); - // updates the navigation buttons based on the current page // void updateNavigation(); @@ -176,10 +182,9 @@ private: bool m_switching; bool m_singlePage; - // creates a shortcut for the given sequence // - void addShortcut(QKeySequence seq, std::function<void ()> f); + void addShortcut(QKeySequence seq, std::function<void()> f); // creates a shortcut for the given sequence and executes the action when // activated @@ -219,4 +224,4 @@ private: } }; -#endif // MODORGANIZER_CREATEINSTANCEDIALOG_INCLUDED +#endif // MODORGANIZER_CREATEINSTANCEDIALOG_INCLUDED diff --git a/src/createinstancedialogpages.cpp b/src/createinstancedialogpages.cpp index 481f032d..c8cec45f 100644 --- a/src/createinstancedialogpages.cpp +++ b/src/createinstancedialogpages.cpp @@ -1,14 +1,14 @@ #include "createinstancedialogpages.h" -#include "ui_createinstancedialog.h" +#include "filesystemutilities.h" #include "instancemanager.h" -#include "settings.h" #include "plugincontainer.h" +#include "settings.h" #include "settingsdialognexus.h" #include "shared/appconfig.h" +#include "ui_createinstancedialog.h" #include <iplugingame.h> #include <report.h> #include <utility.h> -#include "filesystemutilities.h" namespace cid { @@ -20,31 +20,27 @@ using MOBase::TaskDialog; // QString makeDefaultPath(const std::wstring& dir) { - return QDir::toNativeSeparators(PathSettings::makeDefaultPath( - QString::fromStdWString(dir))); + return QDir::toNativeSeparators( + PathSettings::makeDefaultPath(QString::fromStdWString(dir))); } QString toLocalizedString(CreateInstanceDialog::Types t) { - switch (t) - { - case CreateInstanceDialog::Global: - return QObject::tr("Global"); + switch (t) { + case CreateInstanceDialog::Global: + return QObject::tr("Global"); - case CreateInstanceDialog::Portable: - return QObject::tr("Portable"); + case CreateInstanceDialog::Portable: + return QObject::tr("Portable"); - default: - return QObject::tr("Instance type: %1").arg(QObject::tr("?")); + default: + return QObject::tr("Instance type: %1").arg(QObject::tr("?")); } } - - PlaceholderLabel::PlaceholderLabel(QLabel* label) - : m_label(label), m_original(label->text()) -{ -} + : m_label(label), m_original(label->text()) +{} void PlaceholderLabel::setText(const QString& arg) { @@ -58,13 +54,10 @@ void PlaceholderLabel::setVisible(bool b) m_label->setVisible(b); } - - -Page::Page(CreateInstanceDialog& dlg) : - ui(dlg.getUI()), m_dlg(dlg), m_pc(dlg.pluginContainer()), - m_skip(false), m_firstActivation(true) -{ -} +Page::Page(CreateInstanceDialog& dlg) + : ui(dlg.getUI()), m_dlg(dlg), m_pc(dlg.pluginContainer()), m_skip(false), + m_firstActivation(true) +{} bool Page::ready() const { @@ -114,7 +107,6 @@ bool Page::action(CreateInstanceDialog::Actions a) return false; } - CreateInstanceDialog::Types Page::selectedInstanceType() const { // no-op @@ -151,9 +143,8 @@ CreateInstanceDialog::Paths Page::selectedPaths() const return {}; } - IntroPage::IntroPage(CreateInstanceDialog& dlg) - : Page(dlg), m_skip(GlobalSettings::hideCreateInstanceIntro()) + : Page(dlg), m_skip(GlobalSettings::hideCreateInstanceIntro()) { QObject::connect(ui->hideIntro, &QCheckBox::toggled, [&] { GlobalSettings::setHideCreateInstanceIntro(ui->hideIntro->isChecked()); @@ -165,18 +156,15 @@ bool IntroPage::doSkip() const return m_skip; } - TypePage::TypePage(CreateInstanceDialog& dlg) - : Page(dlg), m_type(CreateInstanceDialog::NoType) + : Page(dlg), m_type(CreateInstanceDialog::NoType) { // replace placeholders with actual paths - ui->createGlobal->setDescription( - ui->createGlobal->description() - .arg(InstanceManager::singleton().globalInstancesRootPath())); + ui->createGlobal->setDescription(ui->createGlobal->description().arg( + InstanceManager::singleton().globalInstancesRootPath())); - ui->createPortable->setDescription( - ui->createPortable->description() - .arg(InstanceManager::singleton().portablePath())); + ui->createPortable->setDescription(ui->createPortable->description().arg( + InstanceManager::singleton().portablePath())); // disable portable button if it already exists if (InstanceManager::singleton().portableInstanceExists()) { @@ -187,11 +175,13 @@ TypePage::TypePage(CreateInstanceDialog& dlg) ui->portableExistsLabel->setVisible(false); } - QObject::connect( - ui->createGlobal, &QAbstractButton::clicked, [&]{ global(); }); + QObject::connect(ui->createGlobal, &QAbstractButton::clicked, [&] { + global(); + }); - QObject::connect( - ui->createPortable, &QAbstractButton::clicked, [&]{ portable(); }); + QObject::connect(ui->createPortable, &QAbstractButton::clicked, [&] { + portable(); + }); } bool TypePage::ready() const @@ -231,26 +221,26 @@ void TypePage::doActivated(bool firstTime) } } - -GamePage::Game::Game(IPluginGame* g) - : game(g), installed(g->isInstalled()) +GamePage::Game::Game(IPluginGame* g) : game(g), installed(g->isInstalled()) { if (installed) { dir = game->gameDirectory().path(); } } - -GamePage::GamePage(CreateInstanceDialog& dlg) - : Page(dlg), m_selection(nullptr) +GamePage::GamePage(CreateInstanceDialog& dlg) : Page(dlg), m_selection(nullptr) { createGames(); fillList(); m_filter.setEdit(ui->gamesFilter); - QObject::connect(&m_filter, &FilterWidget::changed, [&]{ fillList(); }); - QObject::connect(ui->showAllGames, &QCheckBox::clicked, [&]{ fillList(); }); + QObject::connect(&m_filter, &FilterWidget::changed, [&] { + fillList(); + }); + QObject::connect(ui->showAllGames, &QCheckBox::clicked, [&] { + fillList(); + }); } bool GamePage::ready() const @@ -293,14 +283,14 @@ void GamePage::select(IPluginGame* game, const QString& dir) Game* checked = findGame(game); if (checked) { - if (!checked->installed || (detectMicrosoftStore(checked->dir) && !confirmMicrosoftStore(checked->dir, checked->game))) { + if (!checked->installed || (detectMicrosoftStore(checked->dir) && + !confirmMicrosoftStore(checked->dir, checked->game))) { if (dir.isEmpty()) { // the selected game has no installation directory and none was given, // ask the user const auto path = QFileDialog::getExistingDirectory( - &m_dlg, QObject::tr("Find game installation for %1") - .arg(game->gameName())); + &m_dlg, QObject::tr("Find game installation for %1").arg(game->gameName())); if (path.isEmpty()) { // cancelled @@ -315,20 +305,19 @@ void GamePage::select(IPluginGame* game, const QString& dir) if (checked) { // plugin was found, remember this path - checked->dir = path; + checked->dir = path; checked->installed = true; } } } else { // the selected game didn't detect anything, but a directory was given, // so use that - checked->dir = dir; - checked->installed = true; + checked->dir = dir; + checked->installed = true; } } } - // select this plugin, if any m_selection = checked; @@ -348,8 +337,8 @@ void GamePage::select(IPluginGame* game, const QString& dir) void GamePage::selectCustom() { - const auto path = QFileDialog::getExistingDirectory( - &m_dlg, QObject::tr("Find game installation")); + const auto path = + QFileDialog::getExistingDirectory(&m_dlg, QObject::tr("Find game installation")); if (path.isEmpty()) { // reselect the previous button @@ -368,7 +357,7 @@ void GamePage::selectCustom() for (auto& g : m_games) { if (g->game->looksValid(path)) { // found one - g->dir = path; + g->dir = path; g->installed = true; // select it @@ -399,11 +388,11 @@ void GamePage::warnUnrecognized(const QString& path) QMessageBox dlg(&m_dlg); dlg.setWindowTitle(QObject::tr("Unrecognized game")); - dlg.setText(QObject::tr( - "The folder %1 does not seem to contain a game Mod Organizer can " - "manage.").arg(path)); - dlg.setInformativeText( - QObject::tr("See details for the list of supported games.")); + dlg.setText( + QObject::tr("The folder %1 does not seem to contain a game Mod Organizer can " + "manage.") + .arg(path)); + dlg.setInformativeText(QObject::tr("See details for the list of supported games.")); dlg.setDetailedText(supportedGames); dlg.setIcon(QMessageBox::Warning); dlg.setStandardButtons(QMessageBox::Ok); @@ -533,7 +522,7 @@ void GamePage::clearButtons() // stretch widgets added with addStretch() are not in the parent widget, // they have to be deleted from the layout itself - while (auto* child=ly->takeAt(0)) + while (auto* child = ly->takeAt(0)) delete child; // add a stretch, buttons will be added before @@ -552,8 +541,7 @@ QCommandLinkButton* GamePage::createCustomButton() auto* b = new QCommandLinkButton; b->setText(QObject::tr("Browse...")); - b->setDescription( - QObject::tr("The folder must contain a valid game installation")); + b->setDescription(QObject::tr("The folder must contain a valid game installation")); QObject::connect(b, &QAbstractButton::clicked, [&] { selectCustom(); @@ -647,7 +635,7 @@ GamePage::Game* GamePage::checkInstallation(const QString& path, Game* g) } // remember this path - g->dir = path; + g->dir = path; g->installed = true; updateButton(g); @@ -657,102 +645,91 @@ GamePage::Game* GamePage::checkInstallation(const QString& path, Game* g) bool GamePage::detectMicrosoftStore(const QString& path) { - return path.contains("/ModifiableWindowsApps/") || - path.contains("/WindowsApps/"); + return path.contains("/ModifiableWindowsApps/") || path.contains("/WindowsApps/"); } bool GamePage::confirmMicrosoftStore(const QString& path, IPluginGame* game) { - const auto r = TaskDialog(&m_dlg) - .title(QObject::tr("Microsoft Store game")) - .main(QObject::tr("Microsoft Store game")) - .content(QObject::tr( - "The folder %1 seems to be a Microsoft Store game install. Games" - " installed through the Microsoft Store are not supported by Mod Organizer" - " and will not work properly.") - .arg(path)) - .button({ - game ? QObject::tr("Use this folder for %1").arg(game->gameName()) - : QObject::tr("Use this folder"), - QObject::tr("I know what I'm doing"), - QMessageBox::Ignore}) - .button({ - QObject::tr("Cancel"), - QMessageBox::Cancel}) - .exec(); + const auto r = + TaskDialog(&m_dlg) + .title(QObject::tr("Microsoft Store game")) + .main(QObject::tr("Microsoft Store game")) + .content( + QObject::tr( + "The folder %1 seems to be a Microsoft Store game install. Games" + " installed through the Microsoft Store are not supported by Mod " + "Organizer" + " and will not work properly.") + .arg(path)) + .button({game ? QObject::tr("Use this folder for %1").arg(game->gameName()) + : QObject::tr("Use this folder"), + QObject::tr("I know what I'm doing"), QMessageBox::Ignore}) + .button({QObject::tr("Cancel"), QMessageBox::Cancel}) + .exec(); return (r == QMessageBox::Ignore); } bool GamePage::confirmUnknown(const QString& path, IPluginGame* game) { - const auto r = TaskDialog(&m_dlg) - .title(QObject::tr("Unrecognized game")) - .main(QObject::tr("Unrecognized game")) - .content(QObject::tr( - "The folder %1 does not seem to contain an installation for " - "<span style=\"white-space: nowrap; font-weight: bold;\">%2</span> or " - "for any other game Mod Organizer can manage.") - .arg(path) - .arg(game->gameName())) - .button({ - QObject::tr("Use this folder for %1").arg(game->gameName()), - QObject::tr("I know what I'm doing"), - QMessageBox::Ignore}) - .button({ - QObject::tr("Cancel"), - QMessageBox::Cancel}) - .exec(); + const auto r = + TaskDialog(&m_dlg) + .title(QObject::tr("Unrecognized game")) + .main(QObject::tr("Unrecognized game")) + .content( + QObject::tr("The folder %1 does not seem to contain an installation for " + "<span style=\"white-space: nowrap; font-weight: " + "bold;\">%2</span> or " + "for any other game Mod Organizer can manage.") + .arg(path) + .arg(game->gameName())) + .button({QObject::tr("Use this folder for %1").arg(game->gameName()), + QObject::tr("I know what I'm doing"), QMessageBox::Ignore}) + .button({QObject::tr("Cancel"), QMessageBox::Cancel}) + .exec(); return (r == QMessageBox::Ignore); } -IPluginGame* GamePage::confirmOtherGame( - const QString& path, - IPluginGame* selectedGame, IPluginGame* guessedGame) +IPluginGame* GamePage::confirmOtherGame(const QString& path, IPluginGame* selectedGame, + IPluginGame* guessedGame) { - const auto r = TaskDialog(&m_dlg) - .title(QObject::tr("Incorrect game")) - .main(QObject::tr("Incorrect game")) - .content(QObject::tr( - "The folder %1 seems to contain an installation for " - "<span style=\"white-space: nowrap; font-weight: bold;\">%2</span>, " - "not " - "<span style=\"white-space: nowrap; font-weight: bold;\">%3</span>.") - .arg(path) - .arg(guessedGame->gameName()) - .arg(selectedGame->gameName())) - .button({ - QObject::tr("Manage %1 instead").arg(guessedGame->gameName()), - QMessageBox::Ok}) - .button({ - QObject::tr("Use this folder for %1").arg(selectedGame->gameName()), - QObject::tr("I know what I'm doing"), - QMessageBox::Ignore}) - .button({ - QObject::tr("Cancel"), - QMessageBox::Cancel}) - .exec(); + const auto r = + TaskDialog(&m_dlg) + .title(QObject::tr("Incorrect game")) + .main(QObject::tr("Incorrect game")) + .content( + QObject::tr( + "The folder %1 seems to contain an installation for " + "<span style=\"white-space: nowrap; font-weight: bold;\">%2</span>, " + "not " + "<span style=\"white-space: nowrap; font-weight: bold;\">%3</span>.") + .arg(path) + .arg(guessedGame->gameName()) + .arg(selectedGame->gameName())) + .button({QObject::tr("Manage %1 instead").arg(guessedGame->gameName()), + QMessageBox::Ok}) + .button({QObject::tr("Use this folder for %1").arg(selectedGame->gameName()), + QObject::tr("I know what I'm doing"), QMessageBox::Ignore}) + .button({QObject::tr("Cancel"), QMessageBox::Cancel}) + .exec(); - switch (r) - { - case QMessageBox::Ok: - return guessedGame; + switch (r) { + case QMessageBox::Ok: + return guessedGame; - case QMessageBox::Ignore: - return selectedGame; + case QMessageBox::Ignore: + return selectedGame; - case QMessageBox::Cancel: - default: - return nullptr; + case QMessageBox::Cancel: + default: + return nullptr; } } - VariantsPage::VariantsPage(CreateInstanceDialog& dlg) - : Page(dlg), m_previousGame(nullptr) -{ -} + : Page(dlg), m_previousGame(nullptr) +{} bool VariantsPage::ready() const { @@ -780,7 +757,7 @@ void VariantsPage::doActivated(bool) if (m_previousGame != g) { // recreate the list, the game has changed m_previousGame = g; - m_selection = ""; + m_selection = ""; fillList(); } } @@ -848,17 +825,17 @@ void VariantsPage::fillList() } } - -NamePage::NamePage(CreateInstanceDialog& dlg) : - Page(dlg), m_modified(false), m_okay(false), - m_label(ui->instanceNameLabel), m_exists(ui->instanceNameExists), - m_invalid(ui->instanceNameInvalid) +NamePage::NamePage(CreateInstanceDialog& dlg) + : Page(dlg), m_modified(false), m_okay(false), m_label(ui->instanceNameLabel), + m_exists(ui->instanceNameExists), m_invalid(ui->instanceNameInvalid) { - QObject::connect( - ui->instanceName, &QLineEdit::textEdited, [&]{ onChanged(); }); + QObject::connect(ui->instanceName, &QLineEdit::textEdited, [&] { + onChanged(); + }); - QObject::connect( - ui->instanceName, &QLineEdit::returnPressed, [&]{ next(); }); + QObject::connect(ui->instanceName, &QLineEdit::returnPressed, [&] { + next(); + }); } bool NamePage::ready() const @@ -913,15 +890,15 @@ void NamePage::onChanged() void NamePage::verify() { const auto root = InstanceManager::singleton().globalInstancesRootPath(); - m_okay = checkName(root, ui->instanceName->text()); + m_okay = checkName(root, ui->instanceName->text()); updateNavigation(); } bool NamePage::checkName(QString parentDir, QString name) { - bool exists = false; + bool exists = false; bool invalid = false; - bool empty = false; + bool empty = false; name = name.trimmed(); @@ -954,22 +931,25 @@ bool NamePage::checkName(QString parentDir, QString name) return okay; } - -PathsPage::PathsPage(CreateInstanceDialog& dlg) : - Page(dlg), m_lastType(CreateInstanceDialog::NoType), - m_label(ui->pathsLabel), - m_simpleExists(ui->locationExists), m_simpleInvalid(ui->locationInvalid), - m_advancedExists(ui->advancedDirExists), - m_advancedInvalid(ui->advancedDirInvalid), - m_okay(false) +PathsPage::PathsPage(CreateInstanceDialog& dlg) + : Page(dlg), m_lastType(CreateInstanceDialog::NoType), m_label(ui->pathsLabel), + m_simpleExists(ui->locationExists), m_simpleInvalid(ui->locationInvalid), + m_advancedExists(ui->advancedDirExists), + m_advancedInvalid(ui->advancedDirInvalid), m_okay(false) { auto setEdit = [&](QLineEdit* e) { - QObject::connect(e, &QLineEdit::textEdited, [&]{ onChanged(); }); - QObject::connect(e, &QLineEdit::returnPressed, [&]{ next(); }); + QObject::connect(e, &QLineEdit::textEdited, [&] { + onChanged(); + }); + QObject::connect(e, &QLineEdit::returnPressed, [&] { + next(); + }); }; auto setBrowse = [&](QAbstractButton* b, QLineEdit* e) { - QObject::connect(b, &QAbstractButton::clicked, [this, e]{ browse(e); }); + QObject::connect(b, &QAbstractButton::clicked, [this, e] { + browse(e); + }); }; setEdit(ui->location); @@ -986,8 +966,9 @@ PathsPage::PathsPage(CreateInstanceDialog& dlg) : setBrowse(ui->browseProfiles, ui->profiles); setBrowse(ui->browseOverwrite, ui->overwrite); - QObject::connect( - ui->advancedPathOptions, &QCheckBox::clicked, [&]{ onAdvanced(); }); + QObject::connect(ui->advancedPathOptions, &QCheckBox::clicked, [&] { + onAdvanced(); + }); ui->pathPages->setCurrentIndex(0); } @@ -1008,7 +989,6 @@ void PathsPage::doActivated(bool firstTime) // regenerated const bool changed = (m_lastInstanceName != name) || (m_lastType != type); - // generating and paths setPaths(name, changed); checkPaths(); @@ -1017,7 +997,7 @@ void PathsPage::doActivated(bool firstTime) m_label.setText(m_dlg.rawCreationInfo().game->gameName()); m_lastInstanceName = name; - m_lastType = type; + m_lastType = type; if (firstTime) { ui->location->setFocus(); @@ -1029,10 +1009,10 @@ CreateInstanceDialog::Paths PathsPage::selectedPaths() const CreateInstanceDialog::Paths p; if (ui->advancedPathOptions->isChecked()) { - p.base = ui->base->text(); + p.base = ui->base->text(); p.downloads = ui->downloads->text(); - p.mods = ui->mods->text(); - p.profiles = ui->profiles->text(); + p.mods = ui->mods->text(); + p.profiles = ui->profiles->text(); p.overwrite = ui->overwrite->text(); } else { p.base = ui->location->text(); @@ -1061,16 +1041,14 @@ void PathsPage::checkPaths() { if (ui->advancedPathOptions->isChecked()) { // checking advanced paths - m_okay = - checkAdvancedPath(ui->base->text()) && - checkAdvancedPath(resolve(ui->downloads->text())) && - checkAdvancedPath(resolve(ui->mods->text())) && - checkAdvancedPath(resolve(ui->profiles->text())) && - checkAdvancedPath(resolve(ui->overwrite->text())); + m_okay = checkAdvancedPath(ui->base->text()) && + checkAdvancedPath(resolve(ui->downloads->text())) && + checkAdvancedPath(resolve(ui->mods->text())) && + checkAdvancedPath(resolve(ui->profiles->text())) && + checkAdvancedPath(resolve(ui->overwrite->text())); } else { // checking simple path - m_okay = - checkSimplePath(ui->location->text()); + m_okay = checkSimplePath(ui->location->text()); } } @@ -1113,7 +1091,7 @@ void PathsPage::setPaths(const QString& name, bool force) basePath = InstanceManager::singleton().portablePath(); } else { const auto root = InstanceManager::singleton().globalInstancesRootPath(); - basePath = root + "/" + name; + basePath = root + "/" + name; } basePath = QDir::toNativeSeparators(QDir::cleanPath(basePath)); @@ -1136,15 +1114,14 @@ void PathsPage::setIfEmpty(QLineEdit* e, const QString& path, bool force) } } -bool PathsPage::checkPath( - QString path, - PlaceholderLabel& existsLabel, PlaceholderLabel& invalidLabel) +bool PathsPage::checkPath(QString path, PlaceholderLabel& existsLabel, + PlaceholderLabel& invalidLabel) { auto& m = InstanceManager::singleton(); - bool exists = false; + bool exists = false; bool invalid = false; - bool empty = false; + bool empty = false; path = QDir::toNativeSeparators(path.trimmed()); @@ -1193,17 +1170,10 @@ bool PathsPage::checkPath( return okay; } - -NexusPage::NexusPage(CreateInstanceDialog& dlg) - : Page(dlg), m_skip(false) +NexusPage::NexusPage(CreateInstanceDialog& dlg) : Page(dlg), m_skip(false) { - m_connectionUI.reset(new NexusConnectionUI( - &m_dlg, - dlg.settings(), - ui->nexusConnect, - nullptr, - ui->nexusManual, - ui->nexusLog)); + m_connectionUI.reset(new NexusConnectionUI(&m_dlg, dlg.settings(), ui->nexusConnect, + nullptr, ui->nexusManual, ui->nexusLog)); // just check it once, or connecting and then going back and forth would skip // the page, which would be unexpected @@ -1223,11 +1193,7 @@ bool NexusPage::doSkip() const return m_skip; } - -ConfirmationPage::ConfirmationPage(CreateInstanceDialog& dlg) - : Page(dlg) -{ -} +ConfirmationPage::ConfirmationPage(CreateInstanceDialog& dlg) : Page(dlg) {} void ConfirmationPage::doActivated(bool) { @@ -1241,11 +1207,9 @@ QString ConfirmationPage::makeReview() const const auto ci = m_dlg.rawCreationInfo(); - lines.push_back(QObject::tr("Instance type: %1") - .arg(toLocalizedString(ci.type))); + lines.push_back(QObject::tr("Instance type: %1").arg(toLocalizedString(ci.type))); - lines.push_back(QObject::tr("Instance location: %1") - .arg(ci.dataPath)); + lines.push_back(QObject::tr("Instance location: %1").arg(ci.dataPath)); if (ci.type != CreateInstanceDialog::Portable) { lines.push_back(QObject::tr("Instance name: %1").arg(ci.instanceName)); @@ -1282,4 +1246,4 @@ QString ConfirmationPage::dirLine(const QString& caption, const QString& path) c return QString(" - %1: %2").arg(caption).arg(path); } -} // namespace +} // namespace cid diff --git a/src/createinstancedialogpages.h b/src/createinstancedialogpages.h index 7237bfb2..d9751a52 100644 --- a/src/createinstancedialogpages.h +++ b/src/createinstancedialogpages.h @@ -4,14 +4,16 @@ #include "createinstancedialog.h" #include <filterwidget.h> +#include <QCommandLinkButton> #include <QLabel> #include <QLineEdit> -#include <QCommandLinkButton> -namespace MOBase { class IPluginGame; } +namespace MOBase +{ +class IPluginGame; +} class NexusConnectionUI; - namespace cid { @@ -19,7 +21,6 @@ namespace cid // QString makeDefaultPath(const std::wstring& dir); - // remembers the original text of the given label and, if it contains a %1, // sets it in setText() // @@ -42,7 +43,6 @@ private: QString m_original; }; - // one page in the wizard // // each page can implement one or more selected*() below; those are called @@ -81,13 +81,11 @@ public: // void next(); - // called from the dialog when an action is requested on the current page; // returns true when handled // virtual bool action(CreateInstanceDialog::Actions a); - // returns the instance type // virtual CreateInstanceDialog::Types selectedInstanceType() const; @@ -119,7 +117,6 @@ protected: bool m_skip; bool m_firstActivation; - // called every time a page is shown in the screen; `firstTime` is true for // first activation // @@ -130,7 +127,6 @@ protected: virtual bool doSkip() const; }; - // introduction page, can be disabled by a global setting // class IntroPage : public Page @@ -148,7 +144,6 @@ private: bool m_skip; }; - // instance type page // class TypePage : public Page @@ -181,7 +176,6 @@ private: CreateInstanceDialog::Types m_type; }; - // game plugin page, displays a list of command buttons for each game, along // with a "browse" button for custom directories and filtering stuff // @@ -221,14 +215,13 @@ public: // returns the selected game directory QString selectedGameLocation() const override; - // selects the given game and toggles its associated button; the game // directory can be overridden // // pops up a directory selection dialog if `dir` is empty and the plugin // hasn't detected the game // - void select(MOBase::IPluginGame* game, const QString& dir={}); + void select(MOBase::IPluginGame* game, const QString& dir = {}); // pops up a directory selection dialog and looks for a plugin to manage // it @@ -260,9 +253,8 @@ private: // or by the user bool installed = false; - Game(MOBase::IPluginGame* g); - Game(const Game&) = delete; + Game(const Game&) = delete; Game& operator=(const Game&) = delete; }; @@ -276,7 +268,6 @@ private: // filter MOBase::FilterWidget m_filter; - // returns a list of all the game plugins sorted with natsort // std::vector<MOBase::IPluginGame*> sortedGamePlugins() const; @@ -319,7 +310,6 @@ private: // QCommandLinkButton* createCustomButton(); - // clears the button list and adds all the buttons to it, depending on // filtering and stuff // @@ -351,9 +341,9 @@ private: // 2) use the selection anyway, selectedGame is returned; or // 3) cancel, null is returned // - MOBase::IPluginGame* confirmOtherGame( - const QString& path, - MOBase::IPluginGame* selectedGame, MOBase::IPluginGame* guessedGame); + MOBase::IPluginGame* confirmOtherGame(const QString& path, + MOBase::IPluginGame* selectedGame, + MOBase::IPluginGame* guessedGame); // detects if the given path likely contains a Microsoft Store game // @@ -365,7 +355,6 @@ private: bool confirmMicrosoftStore(const QString& path, MOBase::IPluginGame* game); }; - // game variants page; displays a list of command buttons for game variants, as // reported by the game plugin // @@ -408,12 +397,10 @@ private: // selected variant QString m_selection; - // fills the list with buttons void fillList(); }; - // instance name page; displays a textbox where the user can enter a name and // does basic checks to make sure the name is valid and not a duplicate // @@ -461,7 +448,6 @@ private: // whether the instance name is valid bool m_okay; - // called when the user modifies the textbox, remember that it has changed and // calls verify() // @@ -477,7 +463,6 @@ private: bool checkName(QString parentDir, QString name); }; - // instance paths page; shows a single textbox for the base directory, or a // series of textboxes for all the configurable paths if the advanced checkbox // is checked @@ -523,7 +508,6 @@ private: // whether the paths are valid bool m_okay; - // called when the user changes any textbox, checks the path and updates nav // void onChanged(); @@ -547,9 +531,8 @@ private: // returns false if the path is invalid or already exists, sets the given // labels accordingly // - bool checkPath( - QString path, - PlaceholderLabel& existsLabel, PlaceholderLabel& invalidLabel); + bool checkPath(QString path, PlaceholderLabel& existsLabel, + PlaceholderLabel& invalidLabel); // replaces %base_dir% in the given path by whatever's in the base path // textbox @@ -574,7 +557,6 @@ private: void setIfEmpty(QLineEdit* e, const QString& path, bool force); }; - // nexus connection page; this reuses the ui found in the settings dialog and // is skipped if there's already an api key in the credentials manager // @@ -603,7 +585,6 @@ private: bool m_skip; }; - // shows a text log of all the creation parameters // class ConfirmationPage : public Page @@ -626,6 +607,6 @@ private: QString dirLine(const QString& caption, const QString& path) const; }; -} // namespace +} // namespace cid -#endif // MODORGANIZER_CREATEINSTANCEDIALOGPAGES_INCLUDED +#endif // MODORGANIZER_CREATEINSTANCEDIALOGPAGES_INCLUDED diff --git a/src/credentialsdialog.cpp b/src/credentialsdialog.cpp index 91e4d309..57037f91 100644 --- a/src/credentialsdialog.cpp +++ b/src/credentialsdialog.cpp @@ -20,9 +20,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "credentialsdialog.h" #include "ui_credentialsdialog.h" -CredentialsDialog::CredentialsDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::CredentialsDialog) +CredentialsDialog::CredentialsDialog(QWidget* parent) + : QDialog(parent), ui(new Ui::CredentialsDialog) { ui->setupUi(this); } diff --git a/src/credentialsdialog.h b/src/credentialsdialog.h index 598e100b..f2b0c820 100644 --- a/src/credentialsdialog.h +++ b/src/credentialsdialog.h @@ -22,23 +22,24 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QDialog> -namespace Ui { +namespace Ui +{ class CredentialsDialog; } class CredentialsDialog : public QDialog { Q_OBJECT - + public: - explicit CredentialsDialog(QWidget *parent = 0); + explicit CredentialsDialog(QWidget* parent = 0); ~CredentialsDialog(); bool store() const; bool neverAsk() const; private: - Ui::CredentialsDialog *ui; + Ui::CredentialsDialog* ui; }; -#endif // CREDENTIALSDIALOG_H +#endif // CREDENTIALSDIALOG_H diff --git a/src/csvbuilder.cpp b/src/csvbuilder.cpp index 411fa051..6a33afda 100644 --- a/src/csvbuilder.cpp +++ b/src/csvbuilder.cpp @@ -1,27 +1,21 @@ #include "csvbuilder.h" - -CSVBuilder::CSVBuilder(QIODevice *target) - : m_Out(target), m_Separator(','), m_LineBreak(BREAK_CRLF) +CSVBuilder::CSVBuilder(QIODevice* target) + : m_Out(target), m_Separator(','), m_LineBreak(BREAK_CRLF) { m_Out.setEncoding(QStringConverter::Encoding::Utf8); m_QuoteMode[TYPE_INTEGER] = QUOTE_NEVER; - m_QuoteMode[TYPE_FLOAT] = QUOTE_NEVER; - m_QuoteMode[TYPE_STRING] = QUOTE_ONDEMAND; -} - - -CSVBuilder::~CSVBuilder() -{ - + m_QuoteMode[TYPE_FLOAT] = QUOTE_NEVER; + m_QuoteMode[TYPE_STRING] = QUOTE_ONDEMAND; } +CSVBuilder::~CSVBuilder() {} void CSVBuilder::setFieldSeparator(char sep) { char oldSeparator = m_Separator; - m_Separator = sep; + m_Separator = sep; try { checkFields(m_Fields); } catch (const CSVException&) { @@ -30,20 +24,17 @@ void CSVBuilder::setFieldSeparator(char sep) } } - void CSVBuilder::setLineBreak(CSVBuilder::ELineBreak lineBreak) { m_LineBreak = lineBreak; } - void CSVBuilder::setEscapeMode(CSVBuilder::EFieldType type, CSVBuilder::EQuoteMode mode) { m_QuoteMode[type] = mode; } - -void CSVBuilder::setFields(const std::vector<std::pair<QString, EFieldType> > &fields) +void CSVBuilder::setFields(const std::vector<std::pair<QString, EFieldType>>& fields) { std::vector<QString> fieldNames; std::map<QString, EFieldType> fieldTypes; @@ -55,15 +46,13 @@ void CSVBuilder::setFields(const std::vector<std::pair<QString, EFieldType> > &f checkFields(fieldNames); - m_Fields = fieldNames; + m_Fields = fieldNames; m_FieldTypes = fieldTypes; m_Defaults.clear(); m_RowBuffer.clear(); - } - -void CSVBuilder::checkValue(const QString &field, const QVariant &value) +void CSVBuilder::checkValue(const QString& field, const QVariant& value) { auto typeIter = m_FieldTypes.find(field); if (typeIter == m_FieldTypes.end()) { @@ -71,32 +60,33 @@ void CSVBuilder::checkValue(const QString &field, const QVariant &value) } switch (typeIter->second) { - case TYPE_INTEGER: { - if (!value.canConvert<int>()) { - throw CSVException(QObject::tr("invalid type for \"%1\" (should be integer)").arg(field)); - } - } break; - case TYPE_STRING: { - if (!value.canConvert<QString>()) { - throw CSVException(QObject::tr("invalid type for \"%1\" (should be string)").arg(field)); - } - } break; - case TYPE_FLOAT: { - if (!value.canConvert<float>()) { - throw CSVException(QObject::tr("invalid type for \"%1\" (should be float)").arg(field)); - } - } break; + case TYPE_INTEGER: { + if (!value.canConvert<int>()) { + throw CSVException( + QObject::tr("invalid type for \"%1\" (should be integer)").arg(field)); + } + } break; + case TYPE_STRING: { + if (!value.canConvert<QString>()) { + throw CSVException( + QObject::tr("invalid type for \"%1\" (should be string)").arg(field)); + } + } break; + case TYPE_FLOAT: { + if (!value.canConvert<float>()) { + throw CSVException( + QObject::tr("invalid type for \"%1\" (should be float)").arg(field)); + } + } break; } } - -void CSVBuilder::setDefault(const QString &field, const QVariant &value) +void CSVBuilder::setDefault(const QString& field, const QVariant& value) { checkValue(field, value); m_Defaults[field] = value; } - void CSVBuilder::writeHeader() { if (m_Fields.size() == 0) { @@ -113,15 +103,13 @@ void CSVBuilder::writeHeader() m_Out.flush(); } - -void CSVBuilder::setRowField(const QString &field, const QVariant &value) +void CSVBuilder::setRowField(const QString& field, const QVariant& value) { checkValue(field, value); m_RowBuffer[field] = value; } - -void CSVBuilder::writeData(const std::map<QString, QVariant> &data, bool check) +void CSVBuilder::writeData(const std::map<QString, QVariant>& data, bool check) { QString line; QTextStream temp(&line); @@ -150,89 +138,81 @@ void CSVBuilder::writeData(const std::map<QString, QVariant> &data, bool check) } switch (m_FieldTypes[*iter]) { - case TYPE_INTEGER: { - quoteInsert(temp, val.toInt()); - } break; - case TYPE_FLOAT: { - quoteInsert(temp, val.toFloat()); - } break; - case TYPE_STRING: { - quoteInsert(temp, val.toString()); - } break; + case TYPE_INTEGER: { + quoteInsert(temp, val.toInt()); + } break; + case TYPE_FLOAT: { + quoteInsert(temp, val.toFloat()); + } break; + case TYPE_STRING: { + quoteInsert(temp, val.toString()); + } break; } } m_Out << line << lineBreak(); m_Out.flush(); } - -void CSVBuilder::quoteInsert(QTextStream &stream, int value) +void CSVBuilder::quoteInsert(QTextStream& stream, int value) { switch (m_QuoteMode[TYPE_INTEGER]) { - case QUOTE_NEVER: - case QUOTE_ONDEMAND: { - stream << value; - } break; - case QUOTE_ALWAYS: { - stream << "\"" << value << "\""; - } break; + case QUOTE_NEVER: + case QUOTE_ONDEMAND: { + stream << value; + } break; + case QUOTE_ALWAYS: { + stream << "\"" << value << "\""; + } break; } } - -void CSVBuilder::quoteInsert(QTextStream &stream, float value) +void CSVBuilder::quoteInsert(QTextStream& stream, float value) { switch (m_QuoteMode[TYPE_FLOAT]) { - case QUOTE_NEVER: - case QUOTE_ONDEMAND: { - stream << value; - } break; - case QUOTE_ALWAYS: { - stream << "\"" << value << "\""; - } break; + case QUOTE_NEVER: + case QUOTE_ONDEMAND: { + stream << value; + } break; + case QUOTE_ALWAYS: { + stream << "\"" << value << "\""; + } break; } } - -void CSVBuilder::quoteInsert(QTextStream &stream, const QString &value) +void CSVBuilder::quoteInsert(QTextStream& stream, const QString& value) { switch (m_QuoteMode[TYPE_STRING]) { - case QUOTE_NEVER: { - stream << value; - } break; - case QUOTE_ONDEMAND: { - if (value.contains("[,\r\n]")) { - stream << "\"" << value.mid(0).replace("\"", "\"\"") << "\""; - } else { - stream << value; - } - } break; - case QUOTE_ALWAYS: { + case QUOTE_NEVER: { + stream << value; + } break; + case QUOTE_ONDEMAND: { + if (value.contains("[,\r\n]")) { stream << "\"" << value.mid(0).replace("\"", "\"\"") << "\""; - } break; + } else { + stream << value; + } + } break; + case QUOTE_ALWAYS: { + stream << "\"" << value.mid(0).replace("\"", "\"\"") << "\""; + } break; } } - void CSVBuilder::writeRow() { - writeData(m_RowBuffer, false); // data was tested on input + writeData(m_RowBuffer, false); // data was tested on input m_RowBuffer.clear(); } - -void CSVBuilder::addRow(const std::map<QString, QVariant> &data) +void CSVBuilder::addRow(const std::map<QString, QVariant>& data) { writeData(data, true); } - -void CSVBuilder::checkFields(const std::vector<QString> &fields) +void CSVBuilder::checkFields(const std::vector<QString>& fields) { for (auto iter = fields.begin(); iter != fields.end(); ++iter) { - if (iter->contains(m_Separator) || - iter->contains('\r') || - iter->contains('\n') || + if (iter->contains(m_Separator) || iter->contains('\r') || iter->contains('\n') || iter->contains('"')) { throw CSVException(QObject::tr("invalid character in field \"%1\"").arg(*iter)); } @@ -242,7 +222,6 @@ void CSVBuilder::checkFields(const std::vector<QString> &fields) } } - /* if(cell.contains(KDefaultEscapeChar) || cell.contains(KDefaultNewLine) @@ -255,14 +234,17 @@ if(cell.contains(KDefaultEscapeChar) || cell.contains(KDefaultNewLine) m_currentLine->append(cell); }*/ - -const char *CSVBuilder::lineBreak() +const char* CSVBuilder::lineBreak() { switch (m_LineBreak) { - case BREAK_CR: return "\r"; - case BREAK_CRLF: return "\r\n"; - case BREAK_LF: return "\n"; - default: return "\n"; // default shouldn't be necessary + case BREAK_CR: + return "\r"; + case BREAK_CRLF: + return "\r\n"; + case BREAK_LF: + return "\n"; + default: + return "\n"; // default shouldn't be necessary } } diff --git a/src/csvbuilder.h b/src/csvbuilder.h index 9d135db3..3a4e0551 100644 --- a/src/csvbuilder.h +++ b/src/csvbuilder.h @@ -1,84 +1,79 @@ #ifndef CSVBUILDER_H #define CSVBUILDER_H - -#include <vector> #include <QString> -#include <QVariant> #include <QTextStream> +#include <QVariant> +#include <vector> - -class CSVException : public std::exception { +class CSVException : public std::exception +{ public: - CSVException(const QString &text) - : std::exception(), m_Message(text.toLocal8Bit()) {} + CSVException(const QString& text) : std::exception(), m_Message(text.toLocal8Bit()) {} + + virtual const char* what() const throw() { return m_Message.constData(); } - virtual const char* what() const throw() - { return m_Message.constData(); } private: QByteArray m_Message; - }; - class CSVBuilder { public: - - enum EFieldType { + enum EFieldType + { TYPE_INTEGER, TYPE_STRING, TYPE_FLOAT }; - enum EQuoteMode { + enum EQuoteMode + { QUOTE_NEVER, QUOTE_ONDEMAND, QUOTE_ALWAYS }; - enum ELineBreak { + enum ELineBreak + { BREAK_LF, BREAK_CRLF, BREAK_CR }; public: - - CSVBuilder(QIODevice *target); + CSVBuilder(QIODevice* target); ~CSVBuilder(); void setFieldSeparator(char sep); void setLineBreak(ELineBreak lineBreak); void setEscapeMode(EFieldType type, EQuoteMode mode); - void setFields(const std::vector<std::pair<QString, EFieldType> > &fields); - void setDefault(const QString &field, const QVariant &value); + void setFields(const std::vector<std::pair<QString, EFieldType>>& fields); + void setDefault(const QString& field, const QVariant& value); void writeHeader(); - void setRowField(const QString &field, const QVariant &value); + void setRowField(const QString& field, const QVariant& value); void writeRow(); - void addRow(const std::map<QString, QVariant> &data); + void addRow(const std::map<QString, QVariant>& data); private: - - const char *lineBreak(); + const char* lineBreak(); const char separator(); void fieldValid(); - void checkFields(const std::vector<QString> &fields); - void checkValue(const QString &field, const QVariant &value); - void writeData(const std::map<QString, QVariant> &data, bool check); + void checkFields(const std::vector<QString>& fields); + void checkValue(const QString& field, const QVariant& value); + void writeData(const std::map<QString, QVariant>& data, bool check); - void quoteInsert(QTextStream &stream, int value); - void quoteInsert(QTextStream &stream, float value); - void quoteInsert(QTextStream &stream, const QString &value); + void quoteInsert(QTextStream& stream, int value); + void quoteInsert(QTextStream& stream, float value); + void quoteInsert(QTextStream& stream, const QString& value); private: - QTextStream m_Out; char m_Separator; ELineBreak m_LineBreak; @@ -87,7 +82,6 @@ private: std::map<QString, EFieldType> m_FieldTypes; std::map<QString, QVariant> m_Defaults; std::map<QString, QVariant> m_RowBuffer; - }; -#endif // CSVBUILDER_H +#endif // CSVBUILDER_H diff --git a/src/datatab.cpp b/src/datatab.cpp index 0aee247e..567fa99d 100644 --- a/src/datatab.cpp +++ b/src/datatab.cpp @@ -1,10 +1,10 @@ #include "datatab.h" -#include "ui_mainwindow.h" -#include "settings.h" -#include "organizercore.h" -#include "messagedialog.h" #include "filetree.h" #include "filetreemodel.h" +#include "messagedialog.h" +#include "organizercore.h" +#include "settings.h" +#include "ui_mainwindow.h" #include <log.h> #include <report.h> @@ -14,15 +14,16 @@ using namespace MOBase; // in mainwindow.cpp QString UnmanagedModName(); - -DataTab::DataTab( - OrganizerCore& core, PluginContainer& pc, - QWidget* parent, Ui::MainWindow* mwui) : - m_core(core), m_pluginContainer(pc), m_parent(parent), - ui{ - mwui->tabWidget, mwui->dataTab, mwui->dataTabRefresh, mwui->dataTree, - mwui->dataTabShowOnlyConflicts, mwui->dataTabShowFromArchives}, - m_needUpdate(true) +DataTab::DataTab(OrganizerCore& core, PluginContainer& pc, QWidget* parent, + Ui::MainWindow* mwui) + : m_core(core), m_pluginContainer(pc), + m_parent(parent), ui{mwui->tabWidget, + mwui->dataTab, + mwui->dataTabRefresh, + mwui->dataTree, + mwui->dataTabShowOnlyConflicts, + mwui->dataTabShowFromArchives}, + m_needUpdate(true) { m_filetree.reset(new FileTree(core, m_pluginContainer, ui.tree)); m_filter.setUseSourceSort(true); @@ -31,37 +32,33 @@ DataTab::DataTab( m_filter.setList(mwui->dataTree); m_filter.setUpdateDelay(true); - if (auto* m=m_filter.proxyModel()) { + if (auto* m = m_filter.proxyModel()) { m->setDynamicSortFilter(false); } - connect( - &m_filter, &FilterWidget::aboutToChange, - [&]{ ensureFullyLoaded(); }); + connect(&m_filter, &FilterWidget::aboutToChange, [&] { + ensureFullyLoaded(); + }); - connect( - ui.refresh, &QPushButton::clicked, - [&]{ onRefresh(); }); + connect(ui.refresh, &QPushButton::clicked, [&] { + onRefresh(); + }); - connect( - ui.conflicts, &QCheckBox::toggled, - [&]{ onConflicts(); }); + connect(ui.conflicts, &QCheckBox::toggled, [&] { + onConflicts(); + }); - connect( - ui.archives, &QCheckBox::toggled, - [&]{ onArchives(); }); + connect(ui.archives, &QCheckBox::toggled, [&] { + onArchives(); + }); - connect( - m_filetree.get(), &FileTree::executablesChanged, - this, &DataTab::executablesChanged); + connect(m_filetree.get(), &FileTree::executablesChanged, this, + &DataTab::executablesChanged); - connect( - m_filetree.get(), &FileTree::originModified, - this, &DataTab::originModified); + connect(m_filetree.get(), &FileTree::originModified, this, &DataTab::originModified); - connect( - m_filetree.get(), &FileTree::displayModInformation, - this, &DataTab::displayModInformation); + connect(m_filetree.get(), &FileTree::displayModInformation, this, + &DataTab::displayModInformation); } void DataTab::saveState(Settings& s) const @@ -109,8 +106,7 @@ void DataTab::updateTree() { if (isActive()) { doUpdateTree(); - } - else { + } else { m_needUpdate = true; } } @@ -123,7 +119,7 @@ void DataTab::doUpdateTree() if (!m_filter.empty()) { ensureFullyLoaded(); - if (auto* m=m_filter.proxyModel()) { + if (auto* m = m_filter.proxyModel()) { m->invalidate(); } } diff --git a/src/datatab.h b/src/datatab.h index ad172ab0..3eb91681 100644 --- a/src/datatab.h +++ b/src/datatab.h @@ -1,29 +1,34 @@ #ifndef MODORGANIZER_DATATAB_INCLUDED #define MODORGANIZER_DATATAB_INCLUDED -#include "modinfodialogfwd.h" #include "modinfo.h" -#include <filterwidget.h> +#include "modinfodialogfwd.h" +#include <QCheckBox> #include <QPushButton> #include <QTreeWidget> -#include <QCheckBox> +#include <filterwidget.h> -namespace Ui { class MainWindow; } +namespace Ui +{ +class MainWindow; +} class OrganizerCore; class Settings; class PluginContainer; class FileTree; -namespace MOShared { class DirectoryEntry; } +namespace MOShared +{ +class DirectoryEntry; +} class DataTab : public QObject { Q_OBJECT; public: - DataTab( - OrganizerCore& core, PluginContainer& pc, - QWidget* parent, Ui::MainWindow* ui); + DataTab(OrganizerCore& core, PluginContainer& pc, QWidget* parent, + Ui::MainWindow* ui); void saveState(Settings& s) const; void restoreState(const Settings& s); @@ -70,4 +75,4 @@ private: void doUpdateTree(); }; -#endif // MODORGANIZER_DATATAB_INCLUDED +#endif // MODORGANIZER_DATATAB_INCLUDED diff --git a/src/directoryrefresher.cpp b/src/directoryrefresher.cpp index e9934cef..fe951101 100644 --- a/src/directoryrefresher.cpp +++ b/src/directoryrefresher.cpp @@ -21,14 +21,14 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "shared/fileentry.h" #include "shared/filesorigin.h" +#include "envfs.h" #include "iplugingame.h" -#include "utility.h" -#include "report.h" #include "modinfo.h" -#include "settings.h" -#include "envfs.h" #include "modinfodialogfwd.h" +#include "report.h" +#include "settings.h" #include "shared/util.h" +#include "utility.h" #include <gameplugins.h> @@ -38,11 +38,9 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <fstream> - using namespace MOBase; using namespace MOShared; - DirectoryStats::DirectoryStats() { std::memset(this, 0, sizeof(DirectoryStats)); @@ -80,26 +78,25 @@ DirectoryStats& DirectoryStats::operator+=(const DirectoryStats& o) std::string DirectoryStats::csvHeader() { - QStringList sl = { - "dirTimes", - "fileTimes", - "sortTimes", - "subdirLookupTimes", - "addDirectoryTimes", - "filesLookupTimes", - "addFileTimes", - "addOriginToFileTimes", - "addFileToOriginTimes", - "addFileToRegisterTimes", - "originExists", - "originCreate", - "originsNeededEnabled", - "subdirExists", - "subdirCreate", - "fileExists", - "fileCreate", - "filesInsertedInRegister", - "filesAssignedInRegister"}; + QStringList sl = {"dirTimes", + "fileTimes", + "sortTimes", + "subdirLookupTimes", + "addDirectoryTimes", + "filesLookupTimes", + "addFileTimes", + "addOriginToFileTimes", + "addFileToOriginTimes", + "addFileToRegisterTimes", + "originExists", + "originCreate", + "originsNeededEnabled", + "subdirExists", + "subdirCreate", + "fileExists", + "fileCreate", + "filesInsertedInRegister", + "filesAssignedInRegister"}; return sl.join(",").toStdString(); } @@ -112,31 +109,24 @@ std::string DirectoryStats::toCsv() const return ns.count() / 1000.0 / 1000.0 / 1000.0; }; - oss - << QString::number(s(dirTimes)) - << QString::number(s(fileTimes)) - << QString::number(s(sortTimes)) + oss << QString::number(s(dirTimes)) << QString::number(s(fileTimes)) + << QString::number(s(sortTimes)) - << QString::number(s(subdirLookupTimes)) - << QString::number(s(addDirectoryTimes)) + << QString::number(s(subdirLookupTimes)) << QString::number(s(addDirectoryTimes)) - << QString::number(s(filesLookupTimes)) - << QString::number(s(addFileTimes)) - << QString::number(s(addOriginToFileTimes)) - << QString::number(s(addFileToOriginTimes)) - << QString::number(s(addFileToRegisterTimes)) + << QString::number(s(filesLookupTimes)) << QString::number(s(addFileTimes)) + << QString::number(s(addOriginToFileTimes)) + << QString::number(s(addFileToOriginTimes)) + << QString::number(s(addFileToRegisterTimes)) - << QString::number(originExists) - << QString::number(originCreate) - << QString::number(originsNeededEnabled) + << QString::number(originExists) << QString::number(originCreate) + << QString::number(originsNeededEnabled) - << QString::number(subdirExists) - << QString::number(subdirCreate) + << QString::number(subdirExists) << QString::number(subdirCreate) - << QString::number(fileExists) - << QString::number(fileCreate) - << QString::number(filesInsertedInRegister) - << QString::number(filesAssignedInRegister); + << QString::number(fileExists) << QString::number(fileCreate) + << QString::number(filesInsertedInRegister) + << QString::number(filesAssignedInRegister); return oss.join(",").toStdString(); } @@ -147,13 +137,14 @@ void dumpStats(std::vector<DirectoryStats>& stats) static const std::string file("c:\\tmp\\data.csv"); if (run == 0) { - std::ofstream out(file, std::ios::out|std::ios::trunc); + std::ofstream out(file, std::ios::out | std::ios::trunc); out << fmt::format("what,run,{}", DirectoryStats::csvHeader()) << "\n"; } - std::sort(stats.begin(), stats.end(), [](auto&& a, auto&& b){ - return (naturalCompare(QString::fromStdString(a.mod), QString::fromStdString(b.mod)) < 0); - }); + std::sort(stats.begin(), stats.end(), [](auto&& a, auto&& b) { + return (naturalCompare(QString::fromStdString(a.mod), + QString::fromStdString(b.mod)) < 0); + }); std::ofstream out(file, std::ios::app); @@ -168,51 +159,52 @@ void dumpStats(std::vector<DirectoryStats>& stats) ++run; } - DirectoryRefresher::DirectoryRefresher(std::size_t threadCount) - : m_threadCount(threadCount), m_lastFileCount(0) -{ -} + : m_threadCount(threadCount), m_lastFileCount(0) +{} -DirectoryEntry *DirectoryRefresher::stealDirectoryStructure() +DirectoryEntry* DirectoryRefresher::stealDirectoryStructure() { QMutexLocker locker(&m_RefreshLock); return m_Root.release(); } -void DirectoryRefresher::setMods(const std::vector<std::tuple<QString, QString, int> > &mods - , const std::set<QString> &managedArchives) +void DirectoryRefresher::setMods( + const std::vector<std::tuple<QString, QString, int>>& mods, + const std::set<QString>& managedArchives) { QMutexLocker locker(&m_RefreshLock); m_Mods.clear(); for (auto mod = mods.begin(); mod != mods.end(); ++mod) { - QString name = std::get<0>(*mod); + QString name = std::get<0>(*mod); ModInfo::Ptr info = ModInfo::getByIndex(ModInfo::getIndex(name)); - m_Mods.push_back(EntryInfo(name, std::get<1>(*mod), info->stealFiles(), info->archives(), std::get<2>(*mod))); + m_Mods.push_back(EntryInfo(name, std::get<1>(*mod), info->stealFiles(), + info->archives(), std::get<2>(*mod))); } m_EnabledArchives = managedArchives; } -void DirectoryRefresher::cleanStructure(DirectoryEntry *structure) +void DirectoryRefresher::cleanStructure(DirectoryEntry* structure) { - static const wchar_t *files[] = { L"meta.ini", L"readme.txt" }; + static const wchar_t* files[] = {L"meta.ini", L"readme.txt"}; for (int i = 0; i < sizeof(files) / sizeof(wchar_t*); ++i) { structure->removeFile(files[i]); } - static const wchar_t *dirs[] = { L"fomod" }; + static const wchar_t* dirs[] = {L"fomod"}; for (int i = 0; i < sizeof(dirs) / sizeof(wchar_t*); ++i) { structure->removeDir(std::wstring(dirs[i])); } } -void DirectoryRefresher::addModBSAToStructure( - DirectoryEntry* root, const QString& modName, - int priority, const QString& directory, const QStringList& archives) +void DirectoryRefresher::addModBSAToStructure(DirectoryEntry* root, + const QString& modName, int priority, + const QString& directory, + const QStringList& archives) { - const IPluginGame *game = qApp->property("managed_game").value<IPluginGame*>(); + const IPluginGame* game = qApp->property("managed_game").value<IPluginGame*>(); QStringList loadOrder; @@ -238,29 +230,26 @@ void DirectoryRefresher::addModBSAToStructure( DirectoryStats dummy; - root->addFromAllBSAs( - modName.toStdWString(), - QDir::toNativeSeparators(directory).toStdWString(), - priority, - archivesW, - enabledArchives, - lo, - dummy); + root->addFromAllBSAs(modName.toStdWString(), + QDir::toNativeSeparators(directory).toStdWString(), priority, + archivesW, enabledArchives, lo, dummy); } -void DirectoryRefresher::stealModFilesIntoStructure( - DirectoryEntry *directoryStructure, const QString &modName, - int priority, const QString &directory, const QStringList &stealFiles) +void DirectoryRefresher::stealModFilesIntoStructure(DirectoryEntry* directoryStructure, + const QString& modName, + int priority, + const QString& directory, + const QStringList& stealFiles) { std::wstring directoryW = ToWString(QDir::toNativeSeparators(directory)); - // instead of adding all the files of the target directory, we just change the root of the specified - // files to this mod + // instead of adding all the files of the target directory, we just change the root of + // the specified files to this mod DirectoryStats dummy; - FilesOrigin &origin = directoryStructure->createOrigin( - ToWString(modName), directoryW, priority, dummy); + FilesOrigin& origin = + directoryStructure->createOrigin(ToWString(modName), directoryW, priority, dummy); - for (const QString &filename : stealFiles) { + for (const QString& filename : stealFiles) { if (filename.isEmpty()) { log::warn("Trying to find file with no name"); log::warn(" . modName: {}", modName); @@ -288,9 +277,10 @@ void DirectoryRefresher::stealModFilesIntoStructure( } } -void DirectoryRefresher::addModFilesToStructure( - DirectoryEntry *directoryStructure, const QString &modName, - int priority, const QString &directory, const QStringList &stealFiles) +void DirectoryRefresher::addModFilesToStructure(DirectoryEntry* directoryStructure, + const QString& modName, int priority, + const QString& directory, + const QStringList& stealFiles) { TimeThis tt("DirectoryRefresher::addModFilesToStructure()"); @@ -298,51 +288,46 @@ void DirectoryRefresher::addModFilesToStructure( DirectoryStats dummy; if (stealFiles.length() > 0) { - stealModFilesIntoStructure( - directoryStructure, modName, priority, directory, stealFiles); + stealModFilesIntoStructure(directoryStructure, modName, priority, directory, + stealFiles); } else { - directoryStructure->addFromOrigin( - ToWString(modName), directoryW, priority, dummy); + directoryStructure->addFromOrigin(ToWString(modName), directoryW, priority, dummy); } } -void DirectoryRefresher::addModToStructure(DirectoryEntry *directoryStructure - , const QString &modName - , int priority - , const QString &directory - , const QStringList &stealFiles - , const QStringList &archives) +void DirectoryRefresher::addModToStructure(DirectoryEntry* directoryStructure, + const QString& modName, int priority, + const QString& directory, + const QStringList& stealFiles, + const QStringList& archives) { TimeThis tt("DirectoryRefresher::addModToStructure()"); DirectoryStats dummy; if (stealFiles.length() > 0) { - stealModFilesIntoStructure( - directoryStructure, modName, priority, directory, stealFiles); + stealModFilesIntoStructure(directoryStructure, modName, priority, directory, + stealFiles); } else { std::wstring directoryW = ToWString(QDir::toNativeSeparators(directory)); - directoryStructure->addFromOrigin( - ToWString(modName), directoryW, priority, dummy); + directoryStructure->addFromOrigin(ToWString(modName), directoryW, priority, dummy); } if (Settings::instance().archiveParsing()) { - addModBSAToStructure( - directoryStructure, modName, priority, directory, archives); + addModBSAToStructure(directoryStructure, modName, priority, directory, archives); } } - struct ModThread { DirectoryRefreshProgress* progress = nullptr; - DirectoryEntry* ds = nullptr; + DirectoryEntry* ds = nullptr; std::wstring modName; std::wstring path; int prio = -1; std::vector<std::wstring> archives; std::set<std::wstring> enabledArchives; - DirectoryStats* stats = nullptr; + DirectoryStats* stats = nullptr; env::DirectoryWalker walker; std::condition_variable cv; @@ -362,13 +347,15 @@ struct ModThread void run() { std::unique_lock lock(mutex); - cv.wait(lock, [&]{ return ready; }); + cv.wait(lock, [&] { + return ready; + }); SetThisThreadName(QString::fromStdWString(modName + L" refresher")); ds->addFromOrigin(walker, modName, path, prio, *stats); if (Settings::instance().archiveParsing()) { - const IPluginGame *game = qApp->property("managed_game").value<IPluginGame*>(); + const IPluginGame* game = qApp->property("managed_game").value<IPluginGame*>(); QStringList loadOrder; GamePlugins* gamePlugins = game->feature<GamePlugins>(); @@ -381,8 +368,7 @@ struct ModThread lo.push_back(s.toStdWString()); } - ds->addFromAllBSAs( - modName, path, prio, archives, enabledArchives, lo, *stats); + ds->addFromAllBSAs(modName, path, prio, archives, enabledArchives, lo, *stats); } if (progress) { @@ -396,7 +382,6 @@ struct ModThread env::ThreadPool<ModThread> g_threads; - void DirectoryRefresher::updateProgress(const DirectoryRefreshProgress* p) { // careful: called from multiple threads @@ -404,8 +389,8 @@ void DirectoryRefresher::updateProgress(const DirectoryRefreshProgress* p) } void DirectoryRefresher::addMultipleModsFilesToStructure( - MOShared::DirectoryEntry *directoryStructure, - const std::vector<EntryInfo>& entries, DirectoryRefreshProgress* progress) + MOShared::DirectoryEntry* directoryStructure, const std::vector<EntryInfo>& entries, + DirectoryRefreshProgress* progress) { std::vector<DirectoryStats> stats(entries.size()); @@ -416,19 +401,18 @@ void DirectoryRefresher::addMultipleModsFilesToStructure( log::debug("refresher: using {} threads", m_threadCount); g_threads.setMax(m_threadCount); - for (std::size_t i=0; i<entries.size(); ++i) { - const auto& e = entries[i]; + for (std::size_t i = 0; i < entries.size(); ++i) { + const auto& e = entries[i]; const int prio = e.priority + 1; if constexpr (DirectoryStats::EnableInstrumentation) { stats[i].mod = entries[i].modName.toStdString(); } - try - { + try { if (e.stealFiles.length() > 0) { - stealModFilesIntoStructure( - directoryStructure, e.modName, prio, e.absolutePath, e.stealFiles); + stealModFilesIntoStructure(directoryStructure, e.modName, prio, e.absolutePath, + e.stealFiles); if (progress) { progress->addDone(); @@ -437,10 +421,10 @@ void DirectoryRefresher::addMultipleModsFilesToStructure( auto& mt = g_threads.request(); mt.progress = progress; - mt.ds = directoryStructure; - mt.modName = e.modName.toStdWString(); - mt.path = QDir::toNativeSeparators(e.absolutePath).toStdWString(); - mt.prio = prio; + mt.ds = directoryStructure; + mt.modName = e.modName.toStdWString(); + mt.path = QDir::toNativeSeparators(e.absolutePath).toStdWString(); + mt.prio = prio; mt.archives.clear(); for (auto&& a : e.archives) { @@ -479,10 +463,10 @@ void DirectoryRefresher::refresh() m_Root.reset(new DirectoryEntry(L"data", nullptr, 0)); - IPluginGame *game = qApp->property("managed_game").value<IPluginGame*>(); + IPluginGame* game = qApp->property("managed_game").value<IPluginGame*>(); std::wstring dataDirectory = - QDir::toNativeSeparators(game->dataDirectory().absolutePath()).toStdWString(); + QDir::toNativeSeparators(game->dataDirectory().absolutePath()).toStdWString(); { DirectoryStats dummy; diff --git a/src/directoryrefresher.h b/src/directoryrefresher.h index cb0434ca..2e6de1a0 100644 --- a/src/directoryrefresher.h +++ b/src/directoryrefresher.h @@ -20,18 +20,19 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef DIRECTORYREFRESHER_H #define DIRECTORYREFRESHER_H +#include "profile.h" #include "shared/directoryentry.h" #include "shared/fileregisterfwd.h" -#include "profile.h" -#include <QObject> #include <QMutex> +#include <QObject> #include <QStringList> -#include <vector> #include <set> #include <tuple> +#include <vector> /** - * @brief used to asynchronously generate the virtual view of the combined data directory + * @brief used to asynchronously generate the virtual view of the combined data + *directory **/ class DirectoryRefresher : public QObject { @@ -40,12 +41,11 @@ class DirectoryRefresher : public QObject public: struct EntryInfo { - EntryInfo(const QString &modName, const QString &absolutePath, - const QStringList &stealFiles, const QStringList &archives, int priority) - : modName(modName), absolutePath(absolutePath), stealFiles(stealFiles) - , archives(archives), priority(priority) - { - } + EntryInfo(const QString& modName, const QString& absolutePath, + const QStringList& stealFiles, const QStringList& archives, int priority) + : modName(modName), absolutePath(absolutePath), stealFiles(stealFiles), + archives(archives), priority(priority) + {} QString modName; QString absolutePath; @@ -54,7 +54,6 @@ public: int priority; }; - DirectoryRefresher(std::size_t threadCount); /** @@ -72,20 +71,23 @@ public: * * @param mods list of the mods to include **/ - void setMods(const std::vector<std::tuple<QString, QString, int> > &mods, const std::set<QString> &managedArchives); + void setMods(const std::vector<std::tuple<QString, QString, int>>& mods, + const std::set<QString>& managedArchives); /** * @brief sets up the directory where mods are stored * @param modDirectory the mod directory - * @note this function could be obsoleted easily by storing absolute paths in the parameter to setMods. This is legacy + * @note this function could be obsoleted easily by storing absolute paths in the + * parameter to setMods. This is legacy */ - //void setModDirectory(const QString &modDirectory); + // void setModDirectory(const QString &modDirectory); /** - * @brief remove files from the directory structure that are known to be irrelevant to the game + * @brief remove files from the directory structure that are known to be irrelevant to + * the game * @param the structure to clean */ - static void cleanStructure(MOShared::DirectoryEntry *structure); + static void cleanStructure(MOShared::DirectoryEntry* structure); /** * @brief add files for a mod to the directory structure, including bsas @@ -96,7 +98,9 @@ public: * @param stealFiles * @param archives */ - void addModToStructure(MOShared::DirectoryEntry *directoryStructure, const QString &modName, int priority, const QString &directory, const QStringList &stealFiles, const QStringList &archives); + void addModToStructure(MOShared::DirectoryEntry* directoryStructure, + const QString& modName, int priority, const QString& directory, + const QStringList& stealFiles, const QStringList& archives); /** * @brief add only the bsas of a mod to the directory structure @@ -106,7 +110,9 @@ public: * @param directory * @param archives */ - void addModBSAToStructure(MOShared::DirectoryEntry *directoryStructure, const QString &modName, int priority, const QString &directory, const QStringList &archives); + void addModBSAToStructure(MOShared::DirectoryEntry* directoryStructure, + const QString& modName, int priority, + const QString& directory, const QStringList& archives); /** * @brief add only regular files ofr a mod to the directory structure @@ -116,14 +122,13 @@ public: * @param directory * @param stealFiles */ - void addModFilesToStructure( - MOShared::DirectoryEntry *directoryStructure, const QString &modName, - int priority, const QString &directory, const QStringList &stealFiles); + void addModFilesToStructure(MOShared::DirectoryEntry* directoryStructure, + const QString& modName, int priority, + const QString& directory, const QStringList& stealFiles); - void addMultipleModsFilesToStructure( - MOShared::DirectoryEntry *directoryStructure, - const std::vector<EntryInfo>& entries, - DirectoryRefreshProgress* progress=nullptr); + void addMultipleModsFilesToStructure(MOShared::DirectoryEntry* directoryStructure, + const std::vector<EntryInfo>& entries, + DirectoryRefreshProgress* progress = nullptr); void updateProgress(const DirectoryRefreshProgress* p); @@ -137,7 +142,7 @@ public slots: signals: void progress(const DirectoryRefreshProgress* p); - void error(const QString &error); + void error(const QString& error); void refreshed(); private: @@ -148,34 +153,29 @@ private: std::size_t m_threadCount; std::size_t m_lastFileCount; - void stealModFilesIntoStructure( - MOShared::DirectoryEntry *directoryStructure, const QString &modName, - int priority, const QString &directory, const QStringList &stealFiles); + void stealModFilesIntoStructure(MOShared::DirectoryEntry* directoryStructure, + const QString& modName, int priority, + const QString& directory, + const QStringList& stealFiles); }; - class DirectoryRefreshProgress : public QObject { Q_OBJECT public: - DirectoryRefreshProgress(DirectoryRefresher* r) : - QObject(r), m_refresher(r), m_modCount(0), m_modDone(0), m_finished(false) - { - } + DirectoryRefreshProgress(DirectoryRefresher* r) + : QObject(r), m_refresher(r), m_modCount(0), m_modDone(0), m_finished(false) + {} void start(std::size_t modCount) { m_modCount = modCount; - m_modDone = 0; + m_modDone = 0; m_finished = false; } - - bool finished() const - { - return m_finished; - } + bool finished() const { return m_finished; } int percentDone() const { @@ -183,17 +183,13 @@ public: if (m_modCount > 0) { const double d = static_cast<double>(m_modDone) / m_modCount; - percent = static_cast<int>(d * 100); + percent = static_cast<int>(d * 100); } return percent; } - - void finish() - { - m_finished = true; - } + void finish() { m_finished = true; } void addDone() { @@ -208,4 +204,4 @@ private: bool m_finished; }; -#endif // DIRECTORYREFRESHER_H +#endif // DIRECTORYREFRESHER_H diff --git a/src/disableproxyplugindialog.cpp b/src/disableproxyplugindialog.cpp index c05e30e3..a99b0a07 100644 --- a/src/disableproxyplugindialog.cpp +++ b/src/disableproxyplugindialog.cpp @@ -5,15 +5,17 @@ using namespace MOBase; DisableProxyPluginDialog::DisableProxyPluginDialog( - MOBase::IPlugin* proxyPlugin, std::vector<MOBase::IPlugin*> const& required, QWidget* parent) - : QDialog(parent), ui(new Ui::DisableProxyPluginDialog) + MOBase::IPlugin* proxyPlugin, std::vector<MOBase::IPlugin*> const& required, + QWidget* parent) + : QDialog(parent), ui(new Ui::DisableProxyPluginDialog) { ui->setupUi(this); - ui->topLabel->setText(QObject::tr( - "Disabling the '%1' plugin will prevent the following %2 plugin(s) from working:", "", required.size()) - .arg(proxyPlugin->localizedName()) - .arg(required.size())); + ui->topLabel->setText(QObject::tr("Disabling the '%1' plugin will prevent the " + "following %2 plugin(s) from working:", + "", required.size()) + .arg(proxyPlugin->localizedName()) + .arg(required.size())); connect(ui->noBtn, &QPushButton::clicked, this, &QDialog::reject); connect(ui->yesBtn, &QPushButton::clicked, this, &QDialog::accept); @@ -21,8 +23,10 @@ DisableProxyPluginDialog::DisableProxyPluginDialog( ui->requiredPlugins->setSelectionMode(QAbstractItemView::NoSelection); ui->requiredPlugins->setRowCount(required.size()); for (int i = 0; i < required.size(); ++i) { - ui->requiredPlugins->setItem(i, 0, new QTableWidgetItem(required[i]->localizedName())); - ui->requiredPlugins->setItem(i, 1, new QTableWidgetItem(required[i]->description())); + ui->requiredPlugins->setItem(i, 0, + new QTableWidgetItem(required[i]->localizedName())); + ui->requiredPlugins->setItem(i, 1, + new QTableWidgetItem(required[i]->description())); ui->requiredPlugins->setRowHeight(i, 9); } ui->requiredPlugins->verticalHeader()->setVisible(false); diff --git a/src/disableproxyplugindialog.h b/src/disableproxyplugindialog.h index b55a3d43..421697b6 100644 --- a/src/disableproxyplugindialog.h +++ b/src/disableproxyplugindialog.h @@ -24,20 +24,21 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "ipluginproxy.h" -namespace Ui { class DisableProxyPluginDialog; } +namespace Ui +{ +class DisableProxyPluginDialog; +} -class DisableProxyPluginDialog : public QDialog { +class DisableProxyPluginDialog : public QDialog +{ public: - - DisableProxyPluginDialog( - MOBase::IPlugin* proxyPlugin, - std::vector<MOBase::IPlugin*> const& required, - QWidget* parent = nullptr); + DisableProxyPluginDialog(MOBase::IPlugin* proxyPlugin, + std::vector<MOBase::IPlugin*> const& required, + QWidget* parent = nullptr); private slots: Ui::DisableProxyPluginDialog* ui; - }; #endif diff --git a/src/downloadlist.cpp b/src/downloadlist.cpp index e16c1cda..e38d13fa 100644 --- a/src/downloadlist.cpp +++ b/src/downloadlist.cpp @@ -17,28 +17,28 @@ You should have received a copy of the GNU General Public License along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ -#include "organizercore.h" #include "downloadlist.h" #include "downloadmanager.h" #include "modlistdropinfo.h" +#include "organizercore.h" #include "settings.h" -#include <utility.h> -#include <log.h> -#include <QEvent> #include <QColor> +#include <QEvent> #include <QIcon> #include <QSortFilterProxyModel> +#include <log.h> +#include <utility.h> using namespace MOBase; -DownloadList::DownloadList(OrganizerCore& core, QObject *parent) - : QAbstractTableModel(parent), m_manager(*core.downloadManager()), m_settings(core.settings()) +DownloadList::DownloadList(OrganizerCore& core, QObject* parent) + : QAbstractTableModel(parent), m_manager(*core.downloadManager()), + m_settings(core.settings()) { connect(&m_manager, SIGNAL(update(int)), this, SLOT(update(int))); connect(&m_manager, SIGNAL(aboutToUpdate()), this, SLOT(aboutToUpdate())); } - int DownloadList::rowCount(const QModelIndex& parent) const { if (!parent.isValid()) { @@ -49,39 +49,44 @@ int DownloadList::rowCount(const QModelIndex& parent) const } } - int DownloadList::columnCount(const QModelIndex&) const { return COL_COUNT; } - QModelIndex DownloadList::index(int row, int column, const QModelIndex&) const { return createIndex(row, column, row); } - QModelIndex DownloadList::parent(const QModelIndex&) const { return QModelIndex(); } - -QVariant DownloadList::headerData(int section, Qt::Orientation orientation, int role) const +QVariant DownloadList::headerData(int section, Qt::Orientation orientation, + int role) const { - if ((role == Qt::DisplayRole) && - (orientation == Qt::Horizontal)) { + if ((role == Qt::DisplayRole) && (orientation == Qt::Horizontal)) { switch (section) { - case COL_NAME: return tr("Name"); - case COL_MODNAME: return tr("Mod name"); - case COL_VERSION: return tr("Version"); - case COL_ID: return tr("Nexus ID"); - case COL_SIZE: return tr("Size"); - case COL_STATUS: return tr("Status"); - case COL_FILETIME: return tr("Filetime"); - case COL_SOURCEGAME: return tr("Source Game"); - default: return QVariant(); + case COL_NAME: + return tr("Name"); + case COL_MODNAME: + return tr("Mod name"); + case COL_VERSION: + return tr("Version"); + case COL_ID: + return tr("Nexus ID"); + case COL_SIZE: + return tr("Size"); + case COL_STATUS: + return tr("Status"); + case COL_FILETIME: + return tr("Filetime"); + case COL_SOURCEGAME: + return tr("Source Game"); + default: + return QVariant(); } } else { return QAbstractItemModel::headerData(section, orientation, role); @@ -100,68 +105,94 @@ QMimeData* DownloadList::mimeData(const QModelIndexList& indexes) const return result; } -QVariant DownloadList::data(const QModelIndex &index, int role) const +QVariant DownloadList::data(const QModelIndex& index, int role) const { bool pendingDownload = index.row() >= m_manager.numTotalDownloads(); if (role == Qt::DisplayRole) { if (pendingDownload) { - std::tuple<QString, int, int> nexusids = m_manager.getPendingDownload(index.row() - m_manager.numTotalDownloads()); + std::tuple<QString, int, int> nexusids = + m_manager.getPendingDownload(index.row() - m_manager.numTotalDownloads()); switch (index.column()) { - case COL_NAME: return tr("< game %1 mod %2 file %3 >").arg(std::get<0>(nexusids)).arg(std::get<1>(nexusids)).arg(std::get<2>(nexusids)); - case COL_SIZE: return tr("Unknown"); - case COL_STATUS: return tr("Pending"); + case COL_NAME: + return tr("< game %1 mod %2 file %3 >") + .arg(std::get<0>(nexusids)) + .arg(std::get<1>(nexusids)) + .arg(std::get<2>(nexusids)); + case COL_SIZE: + return tr("Unknown"); + case COL_STATUS: + return tr("Pending"); } } else { switch (index.column()) { - case COL_NAME: return m_settings.interface().metaDownloads() ? m_manager.getDisplayName(index.row()) : m_manager.getFileName(index.row()); - case COL_MODNAME: { - if (m_manager.isInfoIncomplete(index.row())) { - return {}; - } else { - const MOBase::ModRepositoryFileInfo *info = m_manager.getFileInfo(index.row()); - return info->modName; - } + case COL_NAME: + return m_settings.interface().metaDownloads() + ? m_manager.getDisplayName(index.row()) + : m_manager.getFileName(index.row()); + case COL_MODNAME: { + if (m_manager.isInfoIncomplete(index.row())) { + return {}; + } else { + const MOBase::ModRepositoryFileInfo* info = + m_manager.getFileInfo(index.row()); + return info->modName; } - case COL_VERSION: { - if (m_manager.isInfoIncomplete(index.row())) { - return {}; - } else { - const MOBase::ModRepositoryFileInfo *info = m_manager.getFileInfo(index.row()); - return info->version.canonicalString(); - } + } + case COL_VERSION: { + if (m_manager.isInfoIncomplete(index.row())) { + return {}; + } else { + const MOBase::ModRepositoryFileInfo* info = + m_manager.getFileInfo(index.row()); + return info->version.canonicalString(); } - case COL_ID: { - if (m_manager.isInfoIncomplete(index.row())) { - return {}; - } else { - return QString("%1").arg(m_manager.getModID(index.row())); - } + } + case COL_ID: { + if (m_manager.isInfoIncomplete(index.row())) { + return {}; + } else { + return QString("%1").arg(m_manager.getModID(index.row())); } - case COL_SOURCEGAME: { - if (m_manager.isInfoIncomplete(index.row())) { - return {}; - } else { - return QString("%1").arg(m_manager.getDisplayGameName(index.row())); - } + } + case COL_SOURCEGAME: { + if (m_manager.isInfoIncomplete(index.row())) { + return {}; + } else { + return QString("%1").arg(m_manager.getDisplayGameName(index.row())); + } + } + case COL_SIZE: + return MOBase::localizedByteSize(m_manager.getFileSize(index.row())); + case COL_FILETIME: + return m_manager.getFileTime(index.row()); + case COL_STATUS: + switch (m_manager.getState(index.row())) { + // STATE_DOWNLOADING handled by DownloadProgressDelegate + case DownloadManager::STATE_STARTED: + return tr("Started"); + case DownloadManager::STATE_CANCELING: + return tr("Canceling"); + case DownloadManager::STATE_PAUSING: + return tr("Pausing"); + case DownloadManager::STATE_CANCELED: + return tr("Canceled"); + case DownloadManager::STATE_PAUSED: + return tr("Paused"); + case DownloadManager::STATE_ERROR: + return tr("Error"); + case DownloadManager::STATE_FETCHINGMODINFO: + return tr("Fetching Info"); + case DownloadManager::STATE_FETCHINGFILEINFO: + return tr("Fetching Info"); + case DownloadManager::STATE_FETCHINGMODINFO_MD5: + return tr("Fetching Info"); + case DownloadManager::STATE_READY: + return tr("Downloaded"); + case DownloadManager::STATE_INSTALLED: + return tr("Installed"); + case DownloadManager::STATE_UNINSTALLED: + return tr("Uninstalled"); } - case COL_SIZE: return MOBase::localizedByteSize(m_manager.getFileSize(index.row())); - case COL_FILETIME: return m_manager.getFileTime(index.row()); - case COL_STATUS: - switch (m_manager.getState(index.row())) { - // STATE_DOWNLOADING handled by DownloadProgressDelegate - case DownloadManager::STATE_STARTED: return tr("Started"); - case DownloadManager::STATE_CANCELING: return tr("Canceling"); - case DownloadManager::STATE_PAUSING: return tr("Pausing"); - case DownloadManager::STATE_CANCELED: return tr("Canceled"); - case DownloadManager::STATE_PAUSED: return tr("Paused"); - case DownloadManager::STATE_ERROR: return tr("Error"); - case DownloadManager::STATE_FETCHINGMODINFO: return tr("Fetching Info"); - case DownloadManager::STATE_FETCHINGFILEINFO: return tr("Fetching Info"); - case DownloadManager::STATE_FETCHINGMODINFO_MD5: return tr("Fetching Info"); - case DownloadManager::STATE_READY: return tr("Downloaded"); - case DownloadManager::STATE_INSTALLED: return tr("Installed"); - case DownloadManager::STATE_UNINSTALLED: return tr("Uninstalled"); - } } } } else if (role == Qt::ForegroundRole && index.column() == COL_STATUS) { @@ -182,16 +213,22 @@ QVariant DownloadList::data(const QModelIndex &index, int role) const } else { QString text = m_manager.getFileName(index.row()) + "\n"; if (m_manager.isInfoIncomplete(index.row())) { - text += tr("Information missing, please select \"Query Info\" from the context menu to re-retrieve."); + text += tr("Information missing, please select \"Query Info\" from the context " + "menu to re-retrieve."); } else { - const MOBase::ModRepositoryFileInfo *info = m_manager.getFileInfo(index.row()); - return QString("%1 (ID %2) %3<br><span>%4</span>").arg(info->modName).arg(m_manager.getModID(index.row())).arg(info->version.canonicalString()).arg(info->description.chopped(4096)); + const MOBase::ModRepositoryFileInfo* info = m_manager.getFileInfo(index.row()); + return QString("%1 (ID %2) %3<br><span>%4</span>") + .arg(info->modName) + .arg(m_manager.getModID(index.row())) + .arg(info->version.canonicalString()) + .arg(info->description.chopped(4096)); } return text; } } else if (role == Qt::DecorationRole && index.column() == COL_NAME) { - if (!pendingDownload && m_manager.getState(index.row()) >= DownloadManager::STATE_READY - && m_manager.isInfoIncomplete(index.row())) + if (!pendingDownload && + m_manager.getState(index.row()) >= DownloadManager::STATE_READY && + m_manager.isInfoIncomplete(index.row())) return QIcon(":/MO/gui/warning_16"); } else if (role == Qt::TextAlignmentRole) { if (index.column() == COL_SIZE) @@ -202,75 +239,78 @@ QVariant DownloadList::data(const QModelIndex &index, int role) const return QVariant(); } - void DownloadList::aboutToUpdate() { emit beginResetModel(); } - void DownloadList::update(int row) { if (row < 0) emit endResetModel(); else if (row < this->rowCount()) - emit dataChanged(this->index(row, 0, QModelIndex()), this->index(row, this->columnCount(QModelIndex())-1, QModelIndex())); + emit dataChanged( + this->index(row, 0, QModelIndex()), + this->index(row, this->columnCount(QModelIndex()) - 1, QModelIndex())); else log::error("invalid row {} in download list, update failed", row); } -bool DownloadList::lessThanPredicate(const QModelIndex &left, const QModelIndex &right) +bool DownloadList::lessThanPredicate(const QModelIndex& left, const QModelIndex& right) { int leftIndex = left.row(); int rightIndex = right.row(); - if ((leftIndex < m_manager.numTotalDownloads()) - && (rightIndex < m_manager.numTotalDownloads())) { + if ((leftIndex < m_manager.numTotalDownloads()) && + (rightIndex < m_manager.numTotalDownloads())) { if (left.column() == DownloadList::COL_NAME) { - return left.data(Qt::DisplayRole).toString().compare(right.data(Qt::DisplayRole).toString(), Qt::CaseInsensitive) < 0; + return left.data(Qt::DisplayRole) + .toString() + .compare(right.data(Qt::DisplayRole).toString(), Qt::CaseInsensitive) < + 0; } else if (left.column() == DownloadList::COL_MODNAME) { QString leftName, rightName; if (!m_manager.isInfoIncomplete(left.row())) { - const MOBase::ModRepositoryFileInfo *info = m_manager.getFileInfo(left.row()); - leftName = info->modName; + const MOBase::ModRepositoryFileInfo* info = m_manager.getFileInfo(left.row()); + leftName = info->modName; } if (!m_manager.isInfoIncomplete(right.row())) { - const MOBase::ModRepositoryFileInfo *info = m_manager.getFileInfo(right.row()); - rightName = info->modName; + const MOBase::ModRepositoryFileInfo* info = m_manager.getFileInfo(right.row()); + rightName = info->modName; } return leftName.compare(rightName, Qt::CaseInsensitive) < 0; } else if (left.column() == DownloadList::COL_VERSION) { - MOBase::VersionInfo versionLeft, versionRight; + MOBase::VersionInfo versionLeft, versionRight; - if (!m_manager.isInfoIncomplete(left.row())) { - const MOBase::ModRepositoryFileInfo *info = m_manager.getFileInfo(left.row()); - versionLeft = info->version; - } + if (!m_manager.isInfoIncomplete(left.row())) { + const MOBase::ModRepositoryFileInfo* info = m_manager.getFileInfo(left.row()); + versionLeft = info->version; + } - if (!m_manager.isInfoIncomplete(right.row())) { - const MOBase::ModRepositoryFileInfo *info = m_manager.getFileInfo(right.row()); - versionRight = info->version; - } + if (!m_manager.isInfoIncomplete(right.row())) { + const MOBase::ModRepositoryFileInfo* info = m_manager.getFileInfo(right.row()); + versionRight = info->version; + } - return versionLeft < versionRight; + return versionLeft < versionRight; } else if (left.column() == DownloadList::COL_ID) { - int leftID=0, rightID=0; + int leftID = 0, rightID = 0; if (!m_manager.isInfoIncomplete(left.row())) { - const MOBase::ModRepositoryFileInfo *info = m_manager.getFileInfo(left.row()); - leftID = info->modID; + const MOBase::ModRepositoryFileInfo* info = m_manager.getFileInfo(left.row()); + leftID = info->modID; } if (!m_manager.isInfoIncomplete(right.row())) { - const MOBase::ModRepositoryFileInfo *info = m_manager.getFileInfo(right.row()); - rightID = info->modID; + const MOBase::ModRepositoryFileInfo* info = m_manager.getFileInfo(right.row()); + rightID = info->modID; } return leftID < rightID; } else if (left.column() == DownloadList::COL_STATUS) { - DownloadManager::DownloadState leftState = m_manager.getState(left.row()); + DownloadManager::DownloadState leftState = m_manager.getState(left.row()); DownloadManager::DownloadState rightState = m_manager.getState(right.row()); if (leftState == rightState) return m_manager.getFileTime(left.row()) > m_manager.getFileTime(right.row()); @@ -281,7 +321,8 @@ bool DownloadList::lessThanPredicate(const QModelIndex &left, const QModelIndex } else if (left.column() == DownloadList::COL_FILETIME) { return m_manager.getFileTime(left.row()) < m_manager.getFileTime(right.row()); } else if (left.column() == DownloadList::COL_SOURCEGAME) { - return m_manager.getDisplayGameName(left.row()) < m_manager.getDisplayGameName(right.row()); + return m_manager.getDisplayGameName(left.row()) < + m_manager.getDisplayGameName(right.row()); } else { return leftIndex < rightIndex; } diff --git a/src/downloadlist.h b/src/downloadlist.h index 6d19e5ab..c9adaa7f 100644 --- a/src/downloadlist.h +++ b/src/downloadlist.h @@ -26,7 +26,6 @@ class OrganizerCore; class DownloadManager; class Settings; - /** * @brief model of the list of active and completed downloads **/ @@ -36,8 +35,8 @@ class DownloadList : public QAbstractTableModel Q_OBJECT public: - - enum EColumn { + enum EColumn + { COL_NAME = 0, COL_STATUS, COL_SIZE, @@ -52,8 +51,7 @@ public: }; public: - - explicit DownloadList(OrganizerCore& core, QObject *parent = 0); + explicit DownloadList(OrganizerCore& core, QObject* parent = 0); /** * @brief retrieve the number of rows to display. Invoked by Qt @@ -61,11 +59,11 @@ public: * @param parent not relevant for this implementation * @return number of rows to display **/ - virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; - virtual int columnCount(const QModelIndex &parent) const; + virtual int rowCount(const QModelIndex& parent = QModelIndex()) const; + virtual int columnCount(const QModelIndex& parent) const; - QModelIndex index(int row, int column, const QModelIndex &parent) const; - QModelIndex parent(const QModelIndex &child) const; + QModelIndex index(int row, int column, const QModelIndex& parent) const; + QModelIndex parent(const QModelIndex& child) const; Qt::ItemFlags flags(const QModelIndex& idx) const override; QMimeData* mimeData(const QModelIndexList& indexes) const override; @@ -76,13 +74,14 @@ public: * * @param index location to look up * @param role ... Defaults to Qt::DisplayRole. - * @return this implementation only returns the row, the QItemDelegate implementation is expected to fetch its information from the DownloadManager + * @return this implementation only returns the row, the QItemDelegate implementation + *is expected to fetch its information from the DownloadManager **/ - virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; // used in DownloadsTab as the sorting predicate for the filter widget // - bool lessThanPredicate(const QModelIndex &left, const QModelIndex &right); + bool lessThanPredicate(const QModelIndex& left, const QModelIndex& right); public slots: @@ -96,9 +95,8 @@ public slots: void aboutToUpdate(); private: - DownloadManager& m_manager; Settings& m_settings; }; -#endif // DOWNLOADLIST_H +#endif // DOWNLOADLIST_H diff --git a/src/downloadlistview.cpp b/src/downloadlistview.cpp index 0264f3f7..a895d2e2 100644 --- a/src/downloadlistview.cpp +++ b/src/downloadlistview.cpp @@ -17,42 +17,42 @@ You should have received a copy of the GNU General Public License along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ -#include "downloadlist.h" #include "downloadlistview.h" -#include <report.h> -#include <log.h> -#include <QPainter> -#include <QMouseEvent> +#include "downloadlist.h" +#include <QApplication> +#include <QCheckBox> +#include <QHeaderView> #include <QMenu> #include <QMessageBox> +#include <QMouseEvent> +#include <QPainter> #include <QSortFilterProxyModel> -#include <QApplication> -#include <QHeaderView> -#include <QCheckBox> #include <QWidgetAction> +#include <log.h> +#include <report.h> using namespace MOBase; -DownloadProgressDelegate::DownloadProgressDelegate( - DownloadManager* manager, DownloadListView* list) +DownloadProgressDelegate::DownloadProgressDelegate(DownloadManager* manager, + DownloadListView* list) : QStyledItemDelegate(list), m_Manager(manager), m_List(list) -{ -} +{} -void DownloadProgressDelegate::paint( - QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const +void DownloadProgressDelegate::paint(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const { QModelIndex sourceIndex; - if (auto* proxy=dynamic_cast<QSortFilterProxyModel*>(m_List->model())) { + if (auto* proxy = dynamic_cast<QSortFilterProxyModel*>(m_List->model())) { sourceIndex = proxy->mapToSource(index); } else { sourceIndex = index; } bool pendingDownload = (sourceIndex.row() >= m_Manager->numTotalDownloads()); - if (sourceIndex.column() == DownloadList::COL_STATUS && !pendingDownload - && m_Manager->getState(sourceIndex.row()) == DownloadManager::STATE_DOWNLOADING) { + if (sourceIndex.column() == DownloadList::COL_STATUS && !pendingDownload && + m_Manager->getState(sourceIndex.row()) == DownloadManager::STATE_DOWNLOADING) { QProgressBar progressBar; progressBar.setProperty("downloadView", option.widget->property("downloadView")); progressBar.setProperty("downloadProgress", true); @@ -90,7 +90,8 @@ void DownloadListHeader::customResizeSections() for (int idx = rightVisible; idx >= 0; idx--) { if (!isSectionHidden(idx)) { if (length() != width()) - resizeSection(idx, std::max(sectionSize(idx) + width() - length(), minimumSectionSize())); + resizeSection(idx, std::max(sectionSize(idx) + width() - length(), + minimumSectionSize())); else break; } @@ -99,7 +100,8 @@ void DownloadListHeader::customResizeSections() for (int idx = 0; idx <= rightVisible; idx++) { if (!isSectionHidden(idx)) { if (length() != width()) - resizeSection(idx, std::max(sectionSize(idx) + width() - length(), minimumSectionSize())); + resizeSection(idx, std::max(sectionSize(idx) + width() - length(), + minimumSectionSize())); else break; } @@ -107,14 +109,13 @@ void DownloadListHeader::customResizeSections() } } -void DownloadListHeader::mouseReleaseEvent(QMouseEvent *event) +void DownloadListHeader::mouseReleaseEvent(QMouseEvent* event) { QHeaderView::mouseReleaseEvent(event); customResizeSections(); } -DownloadListView::DownloadListView(QWidget *parent) - : QTreeView(parent) +DownloadListView::DownloadListView(QWidget* parent) : QTreeView(parent) { setHeader(new DownloadListHeader(Qt::Horizontal, this)); @@ -130,16 +131,17 @@ DownloadListView::DownloadListView(QWidget *parent) setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); sortByColumn(1, Qt::DescendingOrder); - connect(header(), SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onHeaderCustomContextMenu(QPoint))); - connect(this, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(onDoubleClick(QModelIndex))); - connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onCustomContextMenu(QPoint))); + connect(header(), SIGNAL(customContextMenuRequested(QPoint)), this, + SLOT(onHeaderCustomContextMenu(QPoint))); + connect(this, SIGNAL(doubleClicked(QModelIndex)), this, + SLOT(onDoubleClick(QModelIndex))); + connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, + SLOT(onCustomContextMenu(QPoint))); } -DownloadListView::~DownloadListView() -{ -} +DownloadListView::~DownloadListView() {} -void DownloadListView::setManager(DownloadManager *manager) +void DownloadListView::setManager(DownloadManager* manager) { m_Manager = manager; @@ -154,33 +156,34 @@ void DownloadListView::setManager(DownloadManager *manager) header()->hideSection(DownloadList::COL_SOURCEGAME); } -void DownloadListView::setSourceModel(DownloadList *sourceModel) +void DownloadListView::setSourceModel(DownloadList* sourceModel) { m_SourceModel = sourceModel; } -void DownloadListView::onDoubleClick(const QModelIndex &index) +void DownloadListView::onDoubleClick(const QModelIndex& index) { - QModelIndex sourceIndex = qobject_cast<QSortFilterProxyModel*>(model())->mapToSource(index); + QModelIndex sourceIndex = + qobject_cast<QSortFilterProxyModel*>(model())->mapToSource(index); if (m_Manager->getState(sourceIndex.row()) >= DownloadManager::STATE_READY) emit installDownload(sourceIndex.row()); - else if ((m_Manager->getState(sourceIndex.row()) == DownloadManager::STATE_PAUSED) - || (m_Manager->getState(sourceIndex.row()) == DownloadManager::STATE_PAUSING)) + else if ((m_Manager->getState(sourceIndex.row()) == DownloadManager::STATE_PAUSED) || + (m_Manager->getState(sourceIndex.row()) == DownloadManager::STATE_PAUSING)) emit resumeDownload(sourceIndex.row()); } -void DownloadListView::onHeaderCustomContextMenu(const QPoint &point) +void DownloadListView::onHeaderCustomContextMenu(const QPoint& point) { QMenu menu; // display a list of all headers as checkboxes - QAbstractItemModel *model = header()->model(); + QAbstractItemModel* model = header()->model(); for (int i = 1; i < model->columnCount(); ++i) { - QString columnName = model->headerData(i, Qt::Horizontal).toString(); - QCheckBox *checkBox = new QCheckBox(&menu); + QString columnName = model->headerData(i, Qt::Horizontal).toString(); + QCheckBox* checkBox = new QCheckBox(&menu); checkBox->setText(columnName); checkBox->setChecked(!header()->isSectionHidden(i)); - QWidgetAction *checkableAction = new QWidgetAction(&menu); + QWidgetAction* checkableAction = new QWidgetAction(&menu); checkableAction->setDefaultWidget(checkBox); menu.addAction(checkableAction); } @@ -189,10 +192,11 @@ void DownloadListView::onHeaderCustomContextMenu(const QPoint &point) // view/hide columns depending on check-state int i = 1; - for (const QAction *action : menu.actions()) { - const QWidgetAction *widgetAction = qobject_cast<const QWidgetAction*>(action); + for (const QAction* action : menu.actions()) { + const QWidgetAction* widgetAction = qobject_cast<const QWidgetAction*>(action); if (widgetAction != nullptr) { - const QCheckBox *checkBox = qobject_cast<const QCheckBox*>(widgetAction->defaultWidget()); + const QCheckBox* checkBox = + qobject_cast<const QCheckBox*>(widgetAction->defaultWidget()); if (checkBox != nullptr) { header()->setSectionHidden(i, !checkBox->isChecked()); } @@ -203,73 +207,117 @@ void DownloadListView::onHeaderCustomContextMenu(const QPoint &point) qobject_cast<DownloadListHeader*>(header())->customResizeSections(); } -void DownloadListView::resizeEvent(QResizeEvent *event) +void DownloadListView::resizeEvent(QResizeEvent* event) { QTreeView::resizeEvent(event); qobject_cast<DownloadListHeader*>(header())->customResizeSections(); } -void DownloadListView::onCustomContextMenu(const QPoint &point) +void DownloadListView::onCustomContextMenu(const QPoint& point) { QMenu menu(this); QModelIndex index = indexAt(point); - bool hidden = false; + bool hidden = false; try { if (index.row() >= 0) { - const int row = qobject_cast<QSortFilterProxyModel*>(model())->mapToSource(index).row(); + const int row = + qobject_cast<QSortFilterProxyModel*>(model())->mapToSource(index).row(); DownloadManager::DownloadState state = m_Manager->getState(row); hidden = m_Manager->isHidden(row); if (state >= DownloadManager::STATE_READY) { - menu.addAction(tr("Install"), [=] { issueInstall(row); }); + menu.addAction(tr("Install"), [=] { + issueInstall(row); + }); if (m_Manager->isInfoIncomplete(row)) - menu.addAction(tr("Query Info"), [=] { issueQueryInfoMd5(row); }); + menu.addAction(tr("Query Info"), [=] { + issueQueryInfoMd5(row); + }); else - menu.addAction(tr("Visit on Nexus"), [=] { issueVisitOnNexus(row); }); - menu.addAction(tr("Open File"), [=] { issueOpenFile(row); }); - menu.addAction(tr("Open Meta File"), [=] { issueOpenMetaFile(row); }); - menu.addAction(tr("Reveal in Explorer"), [=] { issueOpenInDownloadsFolder(row); }); + menu.addAction(tr("Visit on Nexus"), [=] { + issueVisitOnNexus(row); + }); + menu.addAction(tr("Open File"), [=] { + issueOpenFile(row); + }); + menu.addAction(tr("Open Meta File"), [=] { + issueOpenMetaFile(row); + }); + menu.addAction(tr("Reveal in Explorer"), [=] { + issueOpenInDownloadsFolder(row); + }); menu.addSeparator(); - menu.addAction(tr("Delete..."), [=] { issueDelete(row); }); + menu.addAction(tr("Delete..."), [=] { + issueDelete(row); + }); if (hidden) - menu.addAction(tr("Un-Hide"), [=] { issueRestoreToView(row); }); + menu.addAction(tr("Un-Hide"), [=] { + issueRestoreToView(row); + }); else - menu.addAction(tr("Hide"), [=] { issueRemoveFromView(row); }); + menu.addAction(tr("Hide"), [=] { + issueRemoveFromView(row); + }); } else if (state == DownloadManager::STATE_DOWNLOADING) { - menu.addAction(tr("Cancel"), [=] { issueCancel(row); }); - menu.addAction(tr("Pause"), [=] { issuePause(row); }); - menu.addAction(tr("Reveal in Explorer"), [=] { issueOpenInDownloadsFolder(row); }); - } - else if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR) - || (state == DownloadManager::STATE_PAUSING)) { - menu.addAction(tr("Delete..."), [=] { issueDelete(row); }); - menu.addAction(tr("Resume"), [=] { issueResume(row); }); - menu.addAction(tr("Reveal in Explorer"), [=] { issueOpenInDownloadsFolder(row); }); + menu.addAction(tr("Cancel"), [=] { + issueCancel(row); + }); + menu.addAction(tr("Pause"), [=] { + issuePause(row); + }); + menu.addAction(tr("Reveal in Explorer"), [=] { + issueOpenInDownloadsFolder(row); + }); + } else if ((state == DownloadManager::STATE_PAUSED) || + (state == DownloadManager::STATE_ERROR) || + (state == DownloadManager::STATE_PAUSING)) { + menu.addAction(tr("Delete..."), [=] { + issueDelete(row); + }); + menu.addAction(tr("Resume"), [=] { + issueResume(row); + }); + menu.addAction(tr("Reveal in Explorer"), [=] { + issueOpenInDownloadsFolder(row); + }); } menu.addSeparator(); } - } - catch(std::exception&) { + } catch (std::exception&) { // this happens when the download index is not found, ignore it and don't // display download-specific actions } - menu.addAction(tr("Delete Installed Downloads..."), [=] { issueDeleteCompleted(); }); - menu.addAction(tr("Delete Uninstalled Downloads..."), [=] { issueDeleteUninstalled(); }); - menu.addAction(tr("Delete All Downloads..."), [=] { issueDeleteAll(); }); + menu.addAction(tr("Delete Installed Downloads..."), [=] { + issueDeleteCompleted(); + }); + menu.addAction(tr("Delete Uninstalled Downloads..."), [=] { + issueDeleteUninstalled(); + }); + menu.addAction(tr("Delete All Downloads..."), [=] { + issueDeleteAll(); + }); menu.addSeparator(); if (!hidden) { - menu.addAction(tr("Hide Installed..."), [=] { issueRemoveFromViewCompleted(); }); - menu.addAction(tr("Hide Uninstalled..."), [=] { issueRemoveFromViewUninstalled(); }); - menu.addAction(tr("Hide All..."), [=] { issueRemoveFromViewAll(); }); + menu.addAction(tr("Hide Installed..."), [=] { + issueRemoveFromViewCompleted(); + }); + menu.addAction(tr("Hide Uninstalled..."), [=] { + issueRemoveFromViewUninstalled(); + }); + menu.addAction(tr("Hide All..."), [=] { + issueRemoveFromViewAll(); + }); } else { - menu.addAction(tr("Un-Hide All..."), [=] { issueRestoreToViewAll(); } ); + menu.addAction(tr("Un-Hide All..."), [=] { + issueRestoreToViewAll(); + }); } menu.exec(viewport()->mapToGlobal(point)); @@ -278,31 +326,28 @@ void DownloadListView::onCustomContextMenu(const QPoint &point) void DownloadListView::keyPressEvent(QKeyEvent* event) { if (selectionModel()->hasSelection()) { - const int row = qobject_cast<QSortFilterProxyModel*>(model())->mapToSource(currentIndex()).row(); + const int row = qobject_cast<QSortFilterProxyModel*>(model()) + ->mapToSource(currentIndex()) + .row(); auto state = m_Manager->getState(row); if (state >= DownloadManager::STATE_READY) { if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) { issueInstall(row); - } - else if (event->key() == Qt::Key_Delete) { + } else if (event->key() == Qt::Key_Delete) { issueDelete(row); } - } - else if (state == DownloadManager::STATE_DOWNLOADING) { + } else if (state == DownloadManager::STATE_DOWNLOADING) { if (event->key() == Qt::Key_Delete) { issueCancel(row); - } - else if (event->key() == Qt::Key_Space) { + } else if (event->key() == Qt::Key_Space) { issuePause(event->key()); } - } - else if (state == DownloadManager::STATE_PAUSED - || state == DownloadManager::STATE_ERROR - || state == DownloadManager::STATE_PAUSING) { + } else if (state == DownloadManager::STATE_PAUSED || + state == DownloadManager::STATE_ERROR || + state == DownloadManager::STATE_PAUSING) { if (event->key() == Qt::Key_Delete) { issueDelete(row); - } - else if (event->key() == Qt::Key_Space) { + } else if (event->key() == Qt::Key_Space) { issueResume(row); } } @@ -328,12 +373,12 @@ void DownloadListView::issueQueryInfoMd5(int index) void DownloadListView::issueDelete(int index) { const auto r = MOBase::TaskDialog(this, tr("Delete download")) - .main("Are you sure you want to delete this download?") - .content(m_Manager->getFilePath(index)) - .icon(QMessageBox::Question) - .button({tr("Move to the Recycle Bin"), QMessageBox::Yes}) - .button({tr("Cancel"), QMessageBox::Cancel}) - .exec(); + .main("Are you sure you want to delete this download?") + .content(m_Manager->getFilePath(index)) + .icon(QMessageBox::Question) + .button({tr("Move to the Recycle Bin"), QMessageBox::Yes}) + .button({tr("Cancel"), QMessageBox::Cancel}) + .exec(); if (r != QMessageBox::Yes) { return; @@ -350,17 +395,17 @@ void DownloadListView::issueRemoveFromView(int index) void DownloadListView::issueRestoreToView(int index) { - emit restoreDownload(index); + emit restoreDownload(index); } void DownloadListView::issueRestoreToViewAll() { - emit restoreDownload(-1); + emit restoreDownload(-1); } void DownloadListView::issueVisitOnNexus(int index) { - emit visitOnNexus(index); + emit visitOnNexus(index); } void DownloadListView::issueOpenFile(int index) @@ -368,7 +413,8 @@ void DownloadListView::issueOpenFile(int index) emit openFile(index); } -void DownloadListView::issueOpenMetaFile(int index) { +void DownloadListView::issueOpenMetaFile(int index) +{ emit openMetaFile(index); } @@ -394,27 +440,33 @@ void DownloadListView::issueResume(int index) void DownloadListView::issueDeleteAll() { - if (QMessageBox::warning(nullptr, tr("Delete Files?"), - tr("This will remove all finished downloads from this list and from disk.\n\nAre you absolutely sure you want to proceed?"), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + if (QMessageBox::warning( + nullptr, tr("Delete Files?"), + tr("This will remove all finished downloads from this list and from " + "disk.\n\nAre you absolutely sure you want to proceed?"), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { emit removeDownload(-1, true); } } void DownloadListView::issueDeleteCompleted() { - if (QMessageBox::warning(nullptr, tr("Delete Files?"), - tr("This will remove all installed downloads from this list and from disk.\n\nAre you absolutely sure you want to proceed?"), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + if (QMessageBox::warning( + nullptr, tr("Delete Files?"), + tr("This will remove all installed downloads from this list and from " + "disk.\n\nAre you absolutely sure you want to proceed?"), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { emit removeDownload(-2, true); } } void DownloadListView::issueDeleteUninstalled() { - if (QMessageBox::warning(nullptr, tr("Delete Files?"), - tr("This will remove all uninstalled downloads from this list and from disk.\n\nAre you absolutely sure you want to proceed?"), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + if (QMessageBox::warning( + nullptr, tr("Delete Files?"), + tr("This will remove all uninstalled downloads from this list and from " + "disk.\n\nAre you absolutely sure you want to proceed?"), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { emit removeDownload(-3, true); } } @@ -422,7 +474,8 @@ void DownloadListView::issueDeleteUninstalled() void DownloadListView::issueRemoveFromViewAll() { if (QMessageBox::question(nullptr, tr("Hide Files?"), - tr("This will remove all finished downloads from this list (but NOT from disk)."), + tr("This will remove all finished downloads from this list " + "(but NOT from disk)."), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { emit removeDownload(-1, false); } @@ -431,7 +484,8 @@ void DownloadListView::issueRemoveFromViewAll() void DownloadListView::issueRemoveFromViewCompleted() { if (QMessageBox::question(nullptr, tr("Hide Files?"), - tr("This will remove all installed downloads from this list (but NOT from disk)."), + tr("This will remove all installed downloads from this " + "list (but NOT from disk)."), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { emit removeDownload(-2, false); } @@ -440,7 +494,8 @@ void DownloadListView::issueRemoveFromViewCompleted() void DownloadListView::issueRemoveFromViewUninstalled() { if (QMessageBox::question(nullptr, tr("Hide Files?"), - tr("This will remove all uninstalled downloads from this list (but NOT from disk)."), + tr("This will remove all uninstalled downloads from this " + "list (but NOT from disk)."), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { emit removeDownload(-3, false); } diff --git a/src/downloadlistview.h b/src/downloadlistview.h index dfeec8a5..65d98849 100644 --- a/src/downloadlistview.h +++ b/src/downloadlistview.h @@ -20,19 +20,19 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef DOWNLOADLISTWIDGET_H #define DOWNLOADLISTWIDGET_H -#include "downloadmanager.h" #include "downloadlist.h" -#include <QWidget> +#include "downloadmanager.h" +#include <QHeaderView> #include <QItemDelegate> #include <QLabel> #include <QProgressBar> -#include <QTreeView> -#include <QHeaderView> #include <QStyledItemDelegate> +#include <QTreeView> +#include <QWidget> - -namespace Ui { - class DownloadListView; +namespace Ui +{ +class DownloadListView; } class DownloadListView; @@ -44,8 +44,8 @@ class DownloadProgressDelegate : public QStyledItemDelegate public: DownloadProgressDelegate(DownloadManager* manager, DownloadListView* list); - void paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index) const override; + void paint(QPainter* painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const override; private: DownloadManager* m_Manager; @@ -57,11 +57,13 @@ class DownloadListHeader : public QHeaderView Q_OBJECT public: - explicit DownloadListHeader(Qt::Orientation orientation, QWidget *parent = nullptr) : QHeaderView(orientation, parent) {} + explicit DownloadListHeader(Qt::Orientation orientation, QWidget* parent = nullptr) + : QHeaderView(orientation, parent) + {} void customResizeSections(); private: - void mouseReleaseEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent* event) override; }; class DownloadListView : public QTreeView @@ -69,11 +71,11 @@ class DownloadListView : public QTreeView Q_OBJECT public: - explicit DownloadListView(QWidget *parent = 0); + explicit DownloadListView(QWidget* parent = 0); ~DownloadListView(); - void setManager(DownloadManager *manager); - void setSourceModel(DownloadList *sourceModel); + void setManager(DownloadManager* manager); + void setSourceModel(DownloadList* sourceModel); signals: void installDownload(int index); @@ -119,10 +121,10 @@ private slots: void issueQueryInfoMd5(int index); private: - DownloadManager *m_Manager; - DownloadList *m_SourceModel = 0; + DownloadManager* m_Manager; + DownloadList* m_SourceModel = 0; - void resizeEvent(QResizeEvent *event); + void resizeEvent(QResizeEvent* event); }; -#endif // DOWNLOADLISTWIDGET_H +#endif // DOWNLOADLISTWIDGET_H diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index 5bf91c01..6fb88c3b 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -19,76 +19,79 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "downloadmanager.h" -#include "organizercore.h" -#include "nxmurl.h" +#include "bbcode.h" +#include "envfs.h" +#include "filesystemutilities.h" +#include "iplugingame.h" #include "nexusinterface.h" #include "nxmaccessmanager.h" -#include "iplugingame.h" -#include "envfs.h" -#include <nxmurl.h> -#include <taskprogressmanager.h> -#include "utility.h" +#include "nxmurl.h" +#include "organizercore.h" #include "selectiondialog.h" -#include "bbcode.h" #include "shared/util.h" -#include <utility.h> +#include "utility.h" +#include <nxmurl.h> #include <report.h> -#include "filesystemutilities.h" +#include <taskprogressmanager.h> +#include <utility.h> -#include <QTimer> -#include <QFileInfo> -#include <QDirIterator> +#include <QCoreApplication> #include <QDesktopServices> +#include <QDirIterator> +#include <QFileInfo> +#include <QHttp2Configuration> #include <QInputDialog> #include <QMessageBox> -#include <QCoreApplication> #include <QTextDocument> -#include <QHttp2Configuration> +#include <QTimer> #include <boost/bind/bind.hpp> #include <regex> - using namespace MOBase; - -// TODO limit number of downloads, also display download during nxm requests, store modid/fileid with downloads - +// TODO limit number of downloads, also display download during nxm requests, store +// modid/fileid with downloads static const char UNFINISHED[] = ".unfinished"; unsigned int DownloadManager::DownloadInfo::s_NextDownloadID = 1U; -int DownloadManager::m_DirWatcherDisabler = 0; - +int DownloadManager::m_DirWatcherDisabler = 0; -DownloadManager::DownloadInfo *DownloadManager::DownloadInfo::createNew(const ModRepositoryFileInfo *fileInfo, const QStringList &URLs) +DownloadManager::DownloadInfo* +DownloadManager::DownloadInfo::createNew(const ModRepositoryFileInfo* fileInfo, + const QStringList& URLs) { - DownloadInfo *info = new DownloadInfo; + DownloadInfo* info = new DownloadInfo; info->m_DownloadID = s_NextDownloadID++; info->m_StartTime.start(); - info->m_PreResumeSize = 0LL; - info->m_Progress = std::make_pair<int, QString>(0, "0.0 B/s "); - info->m_ResumePos = 0; - info->m_FileInfo = new ModRepositoryFileInfo(*fileInfo); - info->m_Urls = URLs; - info->m_CurrentUrl = 0; - info->m_Tries = AUTOMATIC_RETRIES; - info->m_State = STATE_STARTED; + info->m_PreResumeSize = 0LL; + info->m_Progress = std::make_pair<int, QString>(0, "0.0 B/s "); + info->m_ResumePos = 0; + info->m_FileInfo = new ModRepositoryFileInfo(*fileInfo); + info->m_Urls = URLs; + info->m_CurrentUrl = 0; + info->m_Tries = AUTOMATIC_RETRIES; + info->m_State = STATE_STARTED; info->m_TaskProgressId = TaskProgressManager::instance().getId(); - info->m_Reply = nullptr; + info->m_Reply = nullptr; return info; } -DownloadManager::DownloadInfo *DownloadManager::DownloadInfo::createFromMeta( - const QString &filePath, bool showHidden, const QString outputDirectory, - std::optional<uint64_t> fileSize) +DownloadManager::DownloadInfo* +DownloadManager::DownloadInfo::createFromMeta(const QString& filePath, bool showHidden, + const QString outputDirectory, + std::optional<uint64_t> fileSize) { - DownloadInfo *info = new DownloadInfo; + DownloadInfo* info = new DownloadInfo; QString metaFileName = filePath + ".meta"; QFileInfo metaFileInfo(metaFileName); - if (QDir::fromNativeSeparators(metaFileInfo.path()).compare(QDir::fromNativeSeparators(outputDirectory), Qt::CaseInsensitive) != 0) return nullptr; + if (QDir::fromNativeSeparators(metaFileInfo.path()) + .compare(QDir::fromNativeSeparators(outputDirectory), Qt::CaseInsensitive) != + 0) + return nullptr; QSettings metaFile(metaFileName, QSettings::IniFormat); if (!showHidden && metaFile.value("removed", false).toBool()) { return nullptr; @@ -99,8 +102,8 @@ DownloadManager::DownloadInfo *DownloadManager::DownloadInfo::createFromMeta( QString fileName = QFileInfo(filePath).fileName(); if (fileName.endsWith(UNFINISHED)) { - info->m_FileName = fileName.mid( - 0, fileName.length() - static_cast<int>(strlen(UNFINISHED))); + info->m_FileName = + fileName.mid(0, fileName.length() - static_cast<int>(strlen(UNFINISHED))); info->m_State = STATE_PAUSED; } else { info->m_FileName = fileName; @@ -118,33 +121,34 @@ DownloadManager::DownloadInfo *DownloadManager::DownloadInfo::createFromMeta( info->m_DownloadID = s_NextDownloadID++; info->m_Output.setFileName(filePath); - info->m_TotalSize = fileSize ? *fileSize : QFileInfo(filePath).size(); - info->m_PreResumeSize = info->m_TotalSize; - info->m_CurrentUrl = 0; - info->m_Urls = metaFile.value("url", "").toString().split(";"); - info->m_Tries = 0; + info->m_TotalSize = fileSize ? *fileSize : QFileInfo(filePath).size(); + info->m_PreResumeSize = info->m_TotalSize; + info->m_CurrentUrl = 0; + info->m_Urls = metaFile.value("url", "").toString().split(";"); + info->m_Tries = 0; info->m_TaskProgressId = TaskProgressManager::instance().getId(); - QString gameName = metaFile.value("gameName", "").toString(); - int modID = metaFile.value("modID", 0).toInt(); - int fileID = metaFile.value("fileID", 0).toInt(); - info->m_FileInfo = new ModRepositoryFileInfo(gameName, modID, fileID); - info->m_FileInfo->name = metaFile.value("name", "").toString(); + QString gameName = metaFile.value("gameName", "").toString(); + int modID = metaFile.value("modID", 0).toInt(); + int fileID = metaFile.value("fileID", 0).toInt(); + info->m_FileInfo = new ModRepositoryFileInfo(gameName, modID, fileID); + info->m_FileInfo->name = metaFile.value("name", "").toString(); if (info->m_FileInfo->name == "0") { // bug in earlier version info->m_FileInfo->name = ""; } - info->m_FileInfo->modName = metaFile.value("modName", "").toString(); - info->m_FileInfo->gameName = gameName; - info->m_FileInfo->modID = modID; - info->m_FileInfo->fileID = fileID; + info->m_FileInfo->modName = metaFile.value("modName", "").toString(); + info->m_FileInfo->gameName = gameName; + info->m_FileInfo->modID = modID; + info->m_FileInfo->fileID = fileID; info->m_FileInfo->description = metaFile.value("description").toString(); info->m_FileInfo->version.parse(metaFile.value("version", "0").toString()); - info->m_FileInfo->newestVersion.parse(metaFile.value("newestVersion", "0").toString()); - info->m_FileInfo->categoryID = metaFile.value("category", 0).toInt(); + info->m_FileInfo->newestVersion.parse( + metaFile.value("newestVersion", "0").toString()); + info->m_FileInfo->categoryID = metaFile.value("category", 0).toInt(); info->m_FileInfo->fileCategory = metaFile.value("fileCategory", 0).toInt(); - info->m_FileInfo->repository = metaFile.value("repository", "Nexus").toString(); - info->m_FileInfo->userData = metaFile.value("userData").toMap(); - info->m_Reply = nullptr; + info->m_FileInfo->repository = metaFile.value("repository", "Nexus").toString(); + info->m_FileInfo->userData = metaFile.value("userData").toMap(); + info->m_Reply = nullptr; return info; } @@ -154,16 +158,13 @@ void DownloadManager::startDisableDirWatcher() DownloadManager::m_DirWatcherDisabler++; } - void DownloadManager::endDisableDirWatcher() { - if (DownloadManager::m_DirWatcherDisabler > 0) - { + if (DownloadManager::m_DirWatcherDisabler > 0) { if (DownloadManager::m_DirWatcherDisabler == 1) QCoreApplication::processEvents(); DownloadManager::m_DirWatcherDisabler--; - } - else { + } else { DownloadManager::m_DirWatcherDisabler = 0; } } @@ -171,7 +172,7 @@ void DownloadManager::endDisableDirWatcher() void DownloadManager::DownloadInfo::setName(QString newName, bool renameFile) { QString oldMetaFileName = QString("%1.meta").arg(m_FileName); - m_FileName = QFileInfo(newName).fileName(); + m_FileName = QFileInfo(newName).fileName(); if ((m_State == DownloadManager::STATE_STARTED) || (m_State == DownloadManager::STATE_DOWNLOADING) || (m_State == DownloadManager::STATE_PAUSED)) { @@ -180,7 +181,9 @@ void DownloadManager::DownloadInfo::setName(QString newName, bool renameFile) } if (renameFile) { if ((newName != m_Output.fileName()) && !m_Output.rename(newName)) { - reportError(tr("failed to rename \"%1\" to \"%2\"").arg(m_Output.fileName()).arg(newName)); + reportError(tr("failed to rename \"%1\" to \"%2\"") + .arg(m_Output.fileName()) + .arg(newName)); return; } @@ -204,22 +207,22 @@ QString DownloadManager::DownloadInfo::currentURL() return m_Urls[m_CurrentUrl]; } - -DownloadManager::DownloadManager(NexusInterface *nexusInterface, QObject *parent) : - m_NexusInterface(nexusInterface), m_DirWatcher(), m_ShowHidden(false), - m_ParentWidget(nullptr) +DownloadManager::DownloadManager(NexusInterface* nexusInterface, QObject* parent) + : m_NexusInterface(nexusInterface), m_DirWatcher(), m_ShowHidden(false), + m_ParentWidget(nullptr) { m_OrganizerCore = dynamic_cast<OrganizerCore*>(parent); - connect(&m_DirWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(directoryChanged(QString))); + connect(&m_DirWatcher, SIGNAL(directoryChanged(QString)), this, + SLOT(directoryChanged(QString))); m_TimeoutTimer.setSingleShot(false); - //connect(&m_TimeoutTimer, SIGNAL(timeout()), this, SLOT(checkDownloadTimeout())); + // connect(&m_TimeoutTimer, SIGNAL(timeout()), this, SLOT(checkDownloadTimeout())); m_TimeoutTimer.start(5 * 1000); } - DownloadManager::~DownloadManager() { - for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); iter != m_ActiveDownloads.end(); ++iter) { + for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); + iter != m_ActiveDownloads.end(); ++iter) { delete *iter; } m_ActiveDownloads.clear(); @@ -232,7 +235,8 @@ void DownloadManager::setParentWidget(QWidget* w) bool DownloadManager::downloadsInProgress() { - for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); iter != m_ActiveDownloads.end(); ++iter) { + for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); + iter != m_ActiveDownloads.end(); ++iter) { if ((*iter)->m_State < STATE_READY) { return true; } @@ -242,7 +246,8 @@ bool DownloadManager::downloadsInProgress() bool DownloadManager::downloadsInProgressNoPause() { - for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); iter != m_ActiveDownloads.end(); ++iter) { + for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); + iter != m_ActiveDownloads.end(); ++iter) { if ((*iter)->m_State < STATE_READY && (*iter)->m_State != STATE_PAUSED) { return true; } @@ -250,7 +255,6 @@ bool DownloadManager::downloadsInProgressNoPause() return false; } - void DownloadManager::pauseAll() { @@ -263,13 +267,13 @@ void DownloadManager::pauseAll() ::Sleep(100); - bool done = false; + bool done = false; QTime startTime = QTime::currentTime(); // further loops: busy waiting for all downloads to complete. This could be neater... while (!done && (startTime.secsTo(QTime::currentTime()) < 5)) { QCoreApplication::processEvents(); done = true; - foreach (DownloadInfo *info, m_ActiveDownloads) { + foreach (DownloadInfo* info, m_ActiveDownloads) { if ((info->m_State < STATE_CANCELED) || (info->m_State == STATE_FETCHINGFILEINFO) || (info->m_State == STATE_FETCHINGMODINFO) || @@ -282,11 +286,10 @@ void DownloadManager::pauseAll() ::Sleep(100); } } - } - -void DownloadManager::setOutputDirectory(const QString &outputDirectory, const bool refresh) +void DownloadManager::setOutputDirectory(const QString& outputDirectory, + const bool refresh) { QStringList directories = m_DirWatcher.directories(); if (directories.length() != 0) { @@ -305,7 +308,7 @@ void DownloadManager::setShowHidden(bool showHidden) refreshList(); } -void DownloadManager::setPluginContainer(PluginContainer *pluginContainer) +void DownloadManager::setPluginContainer(PluginContainer* pluginContainer) { m_NexusInterface->setPluginContainer(pluginContainer); } @@ -315,14 +318,16 @@ void DownloadManager::refreshList() TimeThis tt("DownloadManager::refreshList()"); try { - //avoid triggering other refreshes + // avoid triggering other refreshes startDisableDirWatcher(); int downloadsBefore = m_ActiveDownloads.size(); // remove finished downloads - for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); iter != m_ActiveDownloads.end();) { - if (((*iter)->m_State == STATE_READY) || ((*iter)->m_State == STATE_INSTALLED) || ((*iter)->m_State == STATE_UNINSTALLED)) { + for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); + iter != m_ActiveDownloads.end();) { + if (((*iter)->m_State == STATE_READY) || ((*iter)->m_State == STATE_INSTALLED) || + ((*iter)->m_State == STATE_UNINSTALLED)) { delete *iter; iter = m_ActiveDownloads.erase(iter); } else { @@ -330,7 +335,8 @@ void DownloadManager::refreshList() } } - const QStringList supportedExtensions = m_OrganizerCore->installationManager()->getSupportedExtensions(); + const QStringList supportedExtensions = + m_OrganizerCore->installationManager()->getSupportedExtensions(); std::vector<std::wstring> nameFilters; for (const auto& extension : supportedExtensions) { nameFilters.push_back(L"." + extension.toLower().toStdWString()); @@ -338,13 +344,13 @@ void DownloadManager::refreshList() nameFilters.push_back(QString(UNFINISHED).toLower().toStdWString()); - QDir dir(QDir::fromNativeSeparators(m_OutputDirectory)); - // find orphaned meta files and delete them (sounds cruel but it's better for everyone) + // find orphaned meta files and delete them (sounds cruel but it's better for + // everyone) QStringList orphans; QStringList metaFiles = dir.entryList(QStringList() << "*.meta"); - foreach (const QString &metaFile, metaFiles) { + foreach (const QString& metaFile, metaFiles) { QString baseFile = metaFile.left(metaFile.length() - 5); if (!QFile::exists(dir.absoluteFilePath(baseFile))) { orphans.append(dir.absoluteFilePath(metaFile)); @@ -355,7 +361,6 @@ void DownloadManager::refreshList() shellDelete(orphans, true); } - std::set<std::wstring> seen; struct Context @@ -369,54 +374,54 @@ void DownloadManager::refreshList() for (auto&& d : m_ActiveDownloads) { cx.seen.insert(d->m_FileName.toLower().toStdWString()); - cx.seen.insert(QFileInfo(d->m_Output.fileName()).fileName().toLower().toStdWString()); + cx.seen.insert( + QFileInfo(d->m_Output.fileName()).fileName().toLower().toStdWString()); } - env::forEachEntry( - QDir::toNativeSeparators(m_OutputDirectory).toStdWString(), &cx, nullptr, nullptr, - [](void* data, std::wstring_view f, FILETIME, uint64_t size) { - auto& cx = *static_cast<Context*>(data); + QDir::toNativeSeparators(m_OutputDirectory).toStdWString(), &cx, nullptr, + nullptr, [](void* data, std::wstring_view f, FILETIME, uint64_t size) { + auto& cx = *static_cast<Context*>(data); - std::wstring lc = MOShared::ToLowerCopy(f); + std::wstring lc = MOShared::ToLowerCopy(f); - bool interestingExt = false; - for (auto&& ext : cx.extensions) { - if (lc.ends_with(ext)) { - interestingExt = true; - break; + bool interestingExt = false; + for (auto&& ext : cx.extensions) { + if (lc.ends_with(ext)) { + interestingExt = true; + break; + } } - } - if (!interestingExt) { - return; - } + if (!interestingExt) { + return; + } - if (cx.seen.contains(lc)) { - return; - } + if (cx.seen.contains(lc)) { + return; + } - QString fileName = - QDir::fromNativeSeparators(cx.self.m_OutputDirectory) + "/" + - QString::fromWCharArray(f.data(), f.size()); + QString fileName = QDir::fromNativeSeparators(cx.self.m_OutputDirectory) + + "/" + QString::fromWCharArray(f.data(), f.size()); - DownloadInfo *info = DownloadInfo::createFromMeta( - fileName, cx.self.m_ShowHidden, cx.self.m_OutputDirectory, size); + DownloadInfo* info = DownloadInfo::createFromMeta( + fileName, cx.self.m_ShowHidden, cx.self.m_OutputDirectory, size); - if (info == nullptr) { - return; - } + if (info == nullptr) { + return; + } - cx.self.m_ActiveDownloads.push_front(info); - cx.seen.insert(std::move(lc)); - cx.seen.insert(QFileInfo(info->m_Output.fileName()).fileName().toLower().toStdWString()); - }); + cx.self.m_ActiveDownloads.push_front(info); + cx.seen.insert(std::move(lc)); + cx.seen.insert( + QFileInfo(info->m_Output.fileName()).fileName().toLower().toStdWString()); + }); log::debug("saw {} downloads", m_ActiveDownloads.size()); emit update(-1); - //let watcher trigger refreshes again + // let watcher trigger refreshes again endDisableDirWatcher(); } catch (const std::bad_alloc&) { @@ -424,9 +429,8 @@ void DownloadManager::refreshList() } } - -bool DownloadManager::addDownload(const QStringList &URLs, QString gameName, - int modID, int fileID, const ModRepositoryFileInfo *fileInfo) +bool DownloadManager::addDownload(const QStringList& URLs, QString gameName, int modID, + int fileID, const ModRepositoryFileInfo* fileInfo) { QString fileName = QFileInfo(URLs.first()).fileName(); if (fileName.isEmpty()) { @@ -436,31 +440,36 @@ bool DownloadManager::addDownload(const QStringList &URLs, QString gameName, QUrl preferredUrl = QUrl::fromEncoded(URLs.first().toLocal8Bit()); log::debug("selected download url: {}", preferredUrl.toString()); QHttp2Configuration h2Conf; - h2Conf.setSessionReceiveWindowSize(16777215); // 16 MiB, based on Chrome and Firefox values + h2Conf.setSessionReceiveWindowSize( + 16777215); // 16 MiB, based on Chrome and Firefox values h2Conf.setStreamReceiveWindowSize(16777215); QNetworkRequest request(preferredUrl); - request.setHeader(QNetworkRequest::UserAgentHeader, m_NexusInterface->getAccessManager()->userAgent()); + request.setHeader(QNetworkRequest::UserAgentHeader, + m_NexusInterface->getAccessManager()->userAgent()); request.setHttp2Configuration(h2Conf); - return addDownload(m_NexusInterface->getAccessManager()->get(request), URLs, fileName, gameName, modID, fileID, fileInfo); + return addDownload(m_NexusInterface->getAccessManager()->get(request), URLs, fileName, + gameName, modID, fileID, fileInfo); } - -bool DownloadManager::addDownload(QNetworkReply *reply, const ModRepositoryFileInfo *fileInfo) +bool DownloadManager::addDownload(QNetworkReply* reply, + const ModRepositoryFileInfo* fileInfo) { QString fileName = getFileNameFromNetworkReply(reply); if (fileName.isEmpty()) { fileName = "unknown"; } - return addDownload(reply, QStringList(reply->url().toString()), fileName, fileInfo->gameName, fileInfo->modID, fileInfo->fileID, fileInfo); + return addDownload(reply, QStringList(reply->url().toString()), fileName, + fileInfo->gameName, fileInfo->modID, fileInfo->fileID, fileInfo); } - -bool DownloadManager::addDownload(QNetworkReply *reply, const QStringList &URLs, const QString &fileName, - QString gameName, int modID, int fileID, const ModRepositoryFileInfo *fileInfo) +bool DownloadManager::addDownload(QNetworkReply* reply, const QStringList& URLs, + const QString& fileName, QString gameName, int modID, + int fileID, const ModRepositoryFileInfo* fileInfo) { - // download invoked from an already open network reply (i.e. download link in the browser) - DownloadInfo *newDownload = DownloadInfo::createNew(fileInfo, URLs); + // download invoked from an already open network reply (i.e. download link in the + // browser) + DownloadInfo* newDownload = DownloadInfo::createNew(fileInfo, URLs); QString baseName = fileName; if (!fileInfo->fileName.isEmpty()) { @@ -475,8 +484,7 @@ bool DownloadManager::addDownload(QNetworkReply *reply, const QStringList &URLs, // baseName could be a URL at this point so strip out the URL query int queryIndex = baseName.indexOf("?"); - if (queryIndex >= 0) - { + if (queryIndex >= 0) { baseName.truncate(queryIndex); } @@ -485,26 +493,27 @@ bool DownloadManager::addDownload(QNetworkReply *reply, const QStringList &URLs, endDisableDirWatcher(); startDownload(reply, newDownload, false); -// emit update(-1); + // emit update(-1); return true; } - void DownloadManager::removePending(QString gameName, int modID, int fileID) { QString gameShortName = gameName; QStringList games(m_ManagedGame->validShortNames()); games += m_ManagedGame->gameShortName(); for (auto game : games) { - MOBase::IPluginGame *gamePlugin = m_OrganizerCore->getGame(game); - if (gamePlugin != nullptr && gamePlugin->gameNexusName().compare(gameName, Qt::CaseInsensitive) == 0) { + MOBase::IPluginGame* gamePlugin = m_OrganizerCore->getGame(game); + if (gamePlugin != nullptr && + gamePlugin->gameNexusName().compare(gameName, Qt::CaseInsensitive) == 0) { gameShortName = gamePlugin->gameShortName(); break; } } emit aboutToUpdate(); for (auto iter : m_PendingDownloads) { - if (gameShortName.compare(std::get<0>(iter), Qt::CaseInsensitive) == 0 && (std::get<1>(iter) == modID) && (std::get<2>(iter) == fileID)) { + if (gameShortName.compare(std::get<0>(iter), Qt::CaseInsensitive) == 0 && + (std::get<1>(iter) == modID) && (std::get<2>(iter) == fileID)) { m_PendingDownloads.removeAt(m_PendingDownloads.indexOf(iter)); break; } @@ -512,10 +521,11 @@ void DownloadManager::removePending(QString gameName, int modID, int fileID) emit update(-1); } - -void DownloadManager::startDownload(QNetworkReply *reply, DownloadInfo *newDownload, bool resume) +void DownloadManager::startDownload(QNetworkReply* reply, DownloadInfo* newDownload, + bool resume) { - reply->setReadBufferSize(1024 * 1024); // don't read more than 1MB at once to avoid memory troubles + reply->setReadBufferSize( + 1024 * 1024); // don't read more than 1MB at once to avoid memory troubles newDownload->m_Reply = reply; setState(newDownload, STATE_DOWNLOADING); if (newDownload->m_Urls.count() == 0) { @@ -532,18 +542,23 @@ void DownloadManager::startDownload(QNetworkReply *reply, DownloadInfo *newDownl if (!newDownload->m_Output.open(mode)) { reportError(tr("failed to download %1: could not open output file: %2") - .arg(reply->url().toString()).arg(newDownload->m_Output.fileName())); + .arg(reply->url().toString()) + .arg(newDownload->m_Output.fileName())); return; } - connect(newDownload->m_Reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(downloadProgress(qint64, qint64))); - connect(newDownload->m_Reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(downloadError(QNetworkReply::NetworkError))); + connect(newDownload->m_Reply, SIGNAL(downloadProgress(qint64, qint64)), this, + SLOT(downloadProgress(qint64, qint64))); + connect(newDownload->m_Reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), + this, SLOT(downloadError(QNetworkReply::NetworkError))); connect(newDownload->m_Reply, SIGNAL(readyRead()), this, SLOT(downloadReadyRead())); - connect(newDownload->m_Reply, SIGNAL(metaDataChanged()), this, SLOT(metaDataChanged())); + connect(newDownload->m_Reply, SIGNAL(metaDataChanged()), this, + SLOT(metaDataChanged())); if (!resume) { newDownload->m_PreResumeSize = newDownload->m_Output.size(); - removePending(newDownload->m_FileInfo->gameName, newDownload->m_FileInfo->modID, newDownload->m_FileInfo->fileID); + removePending(newDownload->m_FileInfo->gameName, newDownload->m_FileInfo->modID, + newDownload->m_FileInfo->fileID); emit aboutToUpdate(); m_ActiveDownloads.append(newDownload); @@ -554,9 +569,13 @@ void DownloadManager::startDownload(QNetworkReply *reply, DownloadInfo *newDownl if (QFile::exists(m_OutputDirectory + "/" + newDownload->m_FileName)) { setState(newDownload, STATE_PAUSING); QCoreApplication::processEvents(); - if (QMessageBox::question(m_ParentWidget, tr("Download again?"), tr("A file with the same name \"%1\" has already been downloaded. " - "Do you want to download it again? The new file will receive a different name.").arg(newDownload->m_FileName), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) { + if (QMessageBox::question( + m_ParentWidget, tr("Download again?"), + tr("A file with the same name \"%1\" has already been downloaded. " + "Do you want to download it again? The new file will receive a " + "different name.") + .arg(newDownload->m_FileName), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) { if (reply->isFinished()) setState(newDownload, STATE_CANCELED); else @@ -573,13 +592,11 @@ void DownloadManager::startDownload(QNetworkReply *reply, DownloadInfo *newDownl } else connect(newDownload->m_Reply, SIGNAL(finished()), this, SLOT(downloadFinished())); - QCoreApplication::processEvents(); if (newDownload->m_State != STATE_DOWNLOADING && - newDownload->m_State != STATE_READY && - newDownload->m_State != STATE_FETCHINGMODINFO && - reply->isFinished()) { + newDownload->m_State != STATE_READY && + newDownload->m_State != STATE_FETCHINGMODINFO && reply->isFinished()) { downloadFinished(indexByInfo(newDownload)); return; } @@ -587,8 +604,7 @@ void DownloadManager::startDownload(QNetworkReply *reply, DownloadInfo *newDownl connect(newDownload->m_Reply, SIGNAL(finished()), this, SLOT(downloadFinished())); } - -void DownloadManager::addNXMDownload(const QString &url) +void DownloadManager::addNXMDownload(const QString& url) { NXMUrl nxmInfo(url); @@ -608,77 +624,90 @@ void DownloadManager::addNXMDownload(const QString &url) continue; } - if ( - nxmInfo.game().compare(gamePlugin->gameShortName(), Qt::CaseInsensitive) == 0 || - nxmInfo.game().compare(gamePlugin->gameNexusName(), Qt::CaseInsensitive) == 0 - ) { + if (nxmInfo.game().compare(gamePlugin->gameShortName(), Qt::CaseInsensitive) == 0 || + nxmInfo.game().compare(gamePlugin->gameNexusName(), Qt::CaseInsensitive) == 0) { foundGame = gamePlugin; break; } } log::debug("add nxm download: {}", url); if (foundGame == nullptr) { - log::debug("download requested for wrong game (game: {}, url: {})", m_ManagedGame->gameShortName(), nxmInfo.game()); - QMessageBox::information(m_ParentWidget, tr("Wrong Game"), tr("The download link is for a mod for \"%1\" but this instance of MO " - "has been set up for \"%2\".").arg(nxmInfo.game()).arg(m_ManagedGame->gameShortName()), QMessageBox::Ok); + log::debug("download requested for wrong game (game: {}, url: {})", + m_ManagedGame->gameShortName(), nxmInfo.game()); + QMessageBox::information( + m_ParentWidget, tr("Wrong Game"), + tr("The download link is for a mod for \"%1\" but this instance of MO " + "has been set up for \"%2\".") + .arg(nxmInfo.game()) + .arg(m_ManagedGame->gameShortName()), + QMessageBox::Ok); return; } for (auto tuple : m_PendingDownloads) { - if (std::get<0>(tuple).compare(foundGame->gameShortName(), Qt::CaseInsensitive) == 0, std::get<1>(tuple) == nxmInfo.modId() && std::get<2>(tuple) == nxmInfo.fileId()) { + if (std::get<0>(tuple).compare(foundGame->gameShortName(), Qt::CaseInsensitive) == + 0, + std::get<1>(tuple) == nxmInfo.modId() && + std::get<2>(tuple) == nxmInfo.fileId()) { const auto infoStr = - tr("There is already a download queued for this file.\n\nMod %1\nFile %2") - .arg(nxmInfo.modId()).arg(nxmInfo.fileId()); + tr("There is already a download queued for this file.\n\nMod %1\nFile %2") + .arg(nxmInfo.modId()) + .arg(nxmInfo.fileId()); - log::debug( - "download requested is already queued (mod: {}, file: {})", - nxmInfo.modId(), nxmInfo.fileId()); + log::debug("download requested is already queued (mod: {}, file: {})", + nxmInfo.modId(), nxmInfo.fileId()); - QMessageBox::information(m_ParentWidget, tr("Already Queued"), infoStr, QMessageBox::Ok); + QMessageBox::information(m_ParentWidget, tr("Already Queued"), infoStr, + QMessageBox::Ok); return; } } - for (DownloadInfo *download : m_ActiveDownloads) { - if (download->m_FileInfo->modID == nxmInfo.modId() && download->m_FileInfo->fileID == nxmInfo.fileId()) { - if (download->m_State == STATE_DOWNLOADING || download->m_State == STATE_PAUSED || download->m_State == STATE_STARTED) { - QString debugStr("download requested is already started (mod %1: %2, file %3: %4)"); - QString infoStr(tr("There is already a download started for this file.\n\nMod %1:\t%2\nFile %3:\t%4")); + for (DownloadInfo* download : m_ActiveDownloads) { + if (download->m_FileInfo->modID == nxmInfo.modId() && + download->m_FileInfo->fileID == nxmInfo.fileId()) { + if (download->m_State == STATE_DOWNLOADING || download->m_State == STATE_PAUSED || + download->m_State == STATE_STARTED) { + QString debugStr( + "download requested is already started (mod %1: %2, file %3: %4)"); + QString infoStr(tr("There is already a download started for this file.\n\nMod " + "%1:\t%2\nFile %3:\t%4")); // %1 debugStr = debugStr.arg(download->m_FileInfo->modID); - infoStr = infoStr.arg(download->m_FileInfo->modID); + infoStr = infoStr.arg(download->m_FileInfo->modID); // %2 if (!download->m_FileInfo->name.isEmpty()) { debugStr = debugStr.arg(download->m_FileInfo->name); - infoStr = infoStr.arg(download->m_FileInfo->name); + infoStr = infoStr.arg(download->m_FileInfo->name); } else if (!download->m_FileInfo->modName.isEmpty()) { debugStr = debugStr.arg(download->m_FileInfo->modName); - infoStr = infoStr.arg(download->m_FileInfo->modName); + infoStr = infoStr.arg(download->m_FileInfo->modName); } else { debugStr = debugStr.arg(QStringLiteral("<blank>")); - infoStr = infoStr.arg(QStringLiteral("<blank>")); + infoStr = infoStr.arg(QStringLiteral("<blank>")); } // %3 debugStr = debugStr.arg(download->m_FileInfo->fileID); - infoStr = infoStr.arg(download->m_FileInfo->fileID); + infoStr = infoStr.arg(download->m_FileInfo->fileID); // %4 if (!download->m_FileInfo->fileName.isEmpty()) { debugStr = debugStr.arg(download->m_FileInfo->fileName); - infoStr = infoStr.arg(download->m_FileInfo->fileName); + infoStr = infoStr.arg(download->m_FileInfo->fileName); } else if (!download->m_FileName.isEmpty()) { debugStr = debugStr.arg(download->m_FileName); - infoStr = infoStr.arg(download->m_FileName); + infoStr = infoStr.arg(download->m_FileName); } else { debugStr = debugStr.arg(QStringLiteral("<blank>")); - infoStr = infoStr.arg(QStringLiteral("<blank>")); + infoStr = infoStr.arg(QStringLiteral("<blank>")); } log::debug("{}", debugStr); - QMessageBox::information(m_ParentWidget, tr("Already Started"), infoStr, QMessageBox::Ok); + QMessageBox::information(m_ParentWidget, tr("Already Started"), infoStr, + QMessageBox::Ok); return; } } @@ -686,32 +715,34 @@ void DownloadManager::addNXMDownload(const QString &url) emit aboutToUpdate(); - m_PendingDownloads.append(std::make_tuple(foundGame->gameShortName(), nxmInfo.modId(), nxmInfo.fileId())); + m_PendingDownloads.append( + std::make_tuple(foundGame->gameShortName(), nxmInfo.modId(), nxmInfo.fileId())); emit update(-1); emit downloadAdded(); - ModRepositoryFileInfo *info = new ModRepositoryFileInfo(); + ModRepositoryFileInfo* info = new ModRepositoryFileInfo(); - info->nexusKey = nxmInfo.key(); - info->nexusExpires = nxmInfo.expires(); + info->nexusKey = nxmInfo.key(); + info->nexusExpires = nxmInfo.expires(); info->nexusDownloadUser = nxmInfo.userId(); - QObject *test = info; - m_RequestIDs.insert(m_NexusInterface->requestFileInfo(foundGame->gameShortName(), nxmInfo.modId(), nxmInfo.fileId(), this, QVariant::fromValue(test), "")); + QObject* test = info; + m_RequestIDs.insert(m_NexusInterface->requestFileInfo( + foundGame->gameShortName(), nxmInfo.modId(), nxmInfo.fileId(), this, + QVariant::fromValue(test), "")); } - void DownloadManager::removeFile(int index, bool deleteFile) { - //Avoid triggering refreshes from DirWatcher + // Avoid triggering refreshes from DirWatcher startDisableDirWatcher(); if (index >= m_ActiveDownloads.size()) { throw MyException(tr("remove: invalid download index %1").arg(index)); } - DownloadInfo *download = m_ActiveDownloads.at(index); - QString filePath = m_OutputDirectory + "/" + download->m_FileName; + DownloadInfo* download = m_ActiveDownloads.at(index); + QString filePath = m_OutputDirectory + "/" + download->m_FileName; if ((download->m_State == STATE_STARTED) || (download->m_State == STATE_DOWNLOADING)) { // shouldn't have been possible @@ -737,7 +768,7 @@ void DownloadManager::removeFile(int index, bool deleteFile) } } else { QSettings metaSettings(filePath.append(".meta"), QSettings::IniFormat); - if(!download->m_Hidden) + if (!download->m_Hidden) metaSettings.setValue("removed", true); } m_DownloadRemoved(index); @@ -748,64 +779,64 @@ void DownloadManager::removeFile(int index, bool deleteFile) class LessThanWrapper { public: - LessThanWrapper(DownloadManager *manager) : m_Manager(manager) {} - bool operator()(int LHS, int RHS) { - return m_Manager->getFileName(LHS).compare(m_Manager->getFileName(RHS), Qt::CaseInsensitive) < 0; - + LessThanWrapper(DownloadManager* manager) : m_Manager(manager) {} + bool operator()(int LHS, int RHS) + { + return m_Manager->getFileName(LHS).compare(m_Manager->getFileName(RHS), + Qt::CaseInsensitive) < 0; } private: - DownloadManager *m_Manager; + DownloadManager* m_Manager; }; - bool DownloadManager::ByName(int LHS, int RHS) { return m_ActiveDownloads[LHS]->m_FileName < m_ActiveDownloads[RHS]->m_FileName; } - void DownloadManager::refreshAlphabeticalTranslation() { m_AlphabeticalTranslation.clear(); int pos = 0; - for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); iter != m_ActiveDownloads.end(); ++iter, ++pos) { + for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); + iter != m_ActiveDownloads.end(); ++iter, ++pos) { m_AlphabeticalTranslation.push_back(pos); } - std::sort(m_AlphabeticalTranslation.begin(), m_AlphabeticalTranslation.end(), LessThanWrapper(this)); + std::sort(m_AlphabeticalTranslation.begin(), m_AlphabeticalTranslation.end(), + LessThanWrapper(this)); } - void DownloadManager::restoreDownload(int index) { if (index < 0) { - DownloadState minState = STATE_READY ; - index = 0; + DownloadState minState = STATE_READY; + index = 0; - for (QVector<DownloadInfo*>::const_iterator iter = m_ActiveDownloads.begin(); iter != m_ActiveDownloads.end(); ++iter ) { + for (QVector<DownloadInfo*>::const_iterator iter = m_ActiveDownloads.begin(); + iter != m_ActiveDownloads.end(); ++iter) { if ((*iter)->m_State >= minState) { restoreDownload(index); } index++; } - } - else { + } else { if (index >= m_ActiveDownloads.size()) { throw MyException(tr("restore: invalid download index: %1").arg(index)); } - DownloadInfo *download = m_ActiveDownloads.at(index); + DownloadInfo* download = m_ActiveDownloads.at(index); if (download->m_Hidden) { download->m_Hidden = false; QString filePath = m_OutputDirectory + "/" + download->m_FileName; - //avoid dirWatcher triggering refreshes + // avoid dirWatcher triggering refreshes startDisableDirWatcher(); - QSettings metaSettings(filePath.append(".meta"), QSettings::IniFormat); + QSettings metaSettings(filePath.append(".meta"), QSettings::IniFormat); metaSettings.setValue("removed", false); endDisableDirWatcher(); @@ -813,21 +844,21 @@ void DownloadManager::restoreDownload(int index) } } - void DownloadManager::removeDownload(int index, bool deleteFile) { try { - //avoid dirWatcher triggering refreshes + // avoid dirWatcher triggering refreshes startDisableDirWatcher(); emit aboutToUpdate(); if (index < 0) { - bool removeAll = (index == -1); + bool removeAll = (index == -1); DownloadState removeState = (index == -2 ? STATE_INSTALLED : STATE_UNINSTALLED); index = 0; - for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); iter != m_ActiveDownloads.end();) { + for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); + iter != m_ActiveDownloads.end();) { DownloadState downloadState = (*iter)->m_State; if ((removeAll && (downloadState >= STATE_READY)) || (removeState == downloadState)) { @@ -842,7 +873,7 @@ void DownloadManager::removeDownload(int index, bool deleteFile) } else { if (index >= m_ActiveDownloads.size()) { reportError(tr("remove: invalid download index %1").arg(index)); - //emit update(-1); + // emit update(-1); endDisableDirWatcher(); return; } @@ -853,13 +884,12 @@ void DownloadManager::removeDownload(int index, bool deleteFile) } emit update(-1); endDisableDirWatcher(); - } catch (const std::exception &e) { + } catch (const std::exception& e) { log::error("failed to remove download: {}", e.what()); } refreshList(); } - void DownloadManager::cancelDownload(int index) { if ((index < 0) || (index >= m_ActiveDownloads.size())) { @@ -872,7 +902,6 @@ void DownloadManager::cancelDownload(int index) } } - void DownloadManager::pauseDownload(int index) { if ((index < 0) || (index >= m_ActiveDownloads.size())) { @@ -880,7 +909,7 @@ void DownloadManager::pauseDownload(int index) return; } - DownloadInfo *info = m_ActiveDownloads.at(index); + DownloadInfo* info = m_ActiveDownloads.at(index); if (info->m_State == STATE_DOWNLOADING) { if ((info->m_Reply != nullptr) && (info->m_Reply->isRunning())) { @@ -901,8 +930,8 @@ void DownloadManager::resumeDownload(int index) reportError(tr("resume: invalid download index %1").arg(index)); return; } - DownloadInfo *info = m_ActiveDownloads[index]; - info->m_Tries = AUTOMATIC_RETRIES; + DownloadInfo* info = m_ActiveDownloads[index]; + info->m_Tries = AUTOMATIC_RETRIES; resumeDownloadInt(index); } @@ -912,11 +941,12 @@ void DownloadManager::resumeDownloadInt(int index) reportError(tr("resume (int): invalid download index %1").arg(index)); return; } - DownloadInfo *info = m_ActiveDownloads[index]; + DownloadInfo* info = m_ActiveDownloads[index]; // Check for finished download; - if (info->m_TotalSize <= info->m_Output.size() && info->m_Reply != nullptr - && info->m_Reply->isOpen() && info->m_Reply->isFinished() && info->m_State != STATE_ERROR) { + if (info->m_TotalSize <= info->m_Output.size() && info->m_Reply != nullptr && + info->m_Reply->isOpen() && info->m_Reply->isFinished() && + info->m_State != STATE_ERROR) { setState(info, STATE_DOWNLOADING); downloadFinished(index); return; @@ -931,9 +961,10 @@ void DownloadManager::resumeDownloadInt(int index) } } } - if ((info->m_Urls.size() == 0) - || ((info->m_Urls.size() == 1) && (info->m_Urls[0].size() == 0))) { - emit showMessage(tr("No known download urls. Sorry, this download can't be resumed.")); + if ((info->m_Urls.size() == 0) || + ((info->m_Urls.size() == 1) && (info->m_Urls[0].size() == 0))) { + emit showMessage( + tr("No known download urls. Sorry, this download can't be resumed.")); return; } if (info->m_State == STATE_ERROR) { @@ -941,27 +972,31 @@ void DownloadManager::resumeDownloadInt(int index) } log::debug("request resume from url {}", info->currentURL()); QNetworkRequest request(QUrl::fromEncoded(info->currentURL().toLocal8Bit())); - request.setHeader(QNetworkRequest::UserAgentHeader, m_NexusInterface->getAccessManager()->userAgent()); + request.setHeader(QNetworkRequest::UserAgentHeader, + m_NexusInterface->getAccessManager()->userAgent()); if (info->m_State != STATE_ERROR) { - info->m_ResumePos = info->m_Output.size(); + info->m_ResumePos = info->m_Output.size(); QByteArray rangeHeader = "bytes=" + QByteArray::number(info->m_ResumePos) + "-"; request.setRawHeader("Range", rangeHeader); } - info->m_DownloadLast = 0; + info->m_DownloadLast = 0; info->m_DownloadTimeLast = 0; - info->m_DownloadAcc = accumulator_set<qint64, stats<tag::rolling_mean>>(tag::rolling_window::window_size = 200); - info->m_DownloadTimeAcc = accumulator_set<qint64, stats<tag::rolling_mean>>(tag::rolling_window::window_size = 200); + info->m_DownloadAcc = accumulator_set<qint64, stats<tag::rolling_mean>>( + tag::rolling_window::window_size = 200); + info->m_DownloadTimeAcc = accumulator_set<qint64, stats<tag::rolling_mean>>( + tag::rolling_window::window_size = 200); log::debug("resume at {} bytes", info->m_ResumePos); startDownload(m_NexusInterface->getAccessManager()->get(request), info, true); } emit update(index); } - -DownloadManager::DownloadInfo *DownloadManager::downloadInfoByID(unsigned int id) +DownloadManager::DownloadInfo* DownloadManager::downloadInfoByID(unsigned int id) { auto iter = std::find_if(m_ActiveDownloads.begin(), m_ActiveDownloads.end(), - [id](DownloadInfo *info) { return info->m_DownloadID == id; }); + [id](DownloadInfo* info) { + return info->m_DownloadID == id; + }); if (iter != m_ActiveDownloads.end()) { return *iter; } else { @@ -969,14 +1004,13 @@ DownloadManager::DownloadInfo *DownloadManager::downloadInfoByID(unsigned int id } } - void DownloadManager::queryInfo(int index) { if ((index < 0) || (index >= m_ActiveDownloads.size())) { reportError(tr("query: invalid download index %1").arg(index)); return; } - DownloadInfo *info = m_ActiveDownloads[index]; + DownloadInfo* info = m_ActiveDownloads[index]; if (info->m_FileInfo->repository != "Nexus") { log::warn("re-querying file info is currently only possible with Nexus"); @@ -991,12 +1025,13 @@ void DownloadManager::queryInfo(int index) if (info->m_FileInfo->modID <= 0) { QString fileName = getFileName(index); QString ignore; - NexusInterface::interpretNexusFileName(fileName, ignore, info->m_FileInfo->modID, true); + NexusInterface::interpretNexusFileName(fileName, ignore, info->m_FileInfo->modID, + true); if (info->m_FileInfo->modID < 0) { - bool ok = false; - int modId = QInputDialog::getInt( - nullptr, tr("Please enter the nexus mod id"), tr("Mod ID:"), 1, 1, - std::numeric_limits<int>::max(), 1, &ok); + bool ok = false; + int modId = QInputDialog::getInt(nullptr, tr("Please enter the nexus mod id"), + tr("Mod ID:"), 1, 1, + std::numeric_limits<int>::max(), 1, &ok); // careful now: while the dialog was displayed, events were processed. // the download list might have changed and our info-ptr invalidated. if (ok) @@ -1006,21 +1041,20 @@ void DownloadManager::queryInfo(int index) } if (info->m_FileInfo->gameName.size() == 0) { - SelectionDialog selection(tr("Please select the source game code for %1").arg(getFileName(index))); + SelectionDialog selection( + tr("Please select the source game code for %1").arg(getFileName(index))); - std::vector<std::pair<QString, QString>> choices = m_NexusInterface->getGameChoices(m_ManagedGame); - if (choices.size() == 1) - { + std::vector<std::pair<QString, QString>> choices = + m_NexusInterface->getGameChoices(m_ManagedGame); + if (choices.size() == 1) { info->m_FileInfo->gameName = choices[0].first; - } - else { + } else { for (auto choice : choices) { selection.addChoice(choice.first, choice.second, choice.first); } if (selection.exec() == QDialog::Accepted) { info->m_FileInfo->gameName = selection.getChoiceData().toString(); - } - else { + } else { info->m_FileInfo->gameName = m_ManagedGame->gameShortName(); } } @@ -1035,7 +1069,7 @@ void DownloadManager::queryInfoMd5(int index) reportError(tr("query: invalid download index %1").arg(index)); return; } - DownloadInfo *info = m_ActiveDownloads[index]; + DownloadInfo* info = m_ActiveDownloads[index]; if (info->m_FileInfo->repository != "Nexus") { log::warn("re-querying file info is currently only possible with Nexus"); @@ -1052,7 +1086,8 @@ void DownloadManager::queryInfoMd5(int index) QFile downloadFile(info->m_FileName); if (!downloadFile.exists()) { - downloadFile.setFileName(m_OrganizerCore->downloadsPath() + "\\" + info->m_FileName); + downloadFile.setFileName(m_OrganizerCore->downloadsPath() + "\\" + + info->m_FileName); } if (!downloadFile.exists()) { log::error("Can't find download file '{}'", info->m_FileName); @@ -1066,14 +1101,12 @@ void DownloadManager::queryInfoMd5(int index) QCryptographicHash hash(QCryptographicHash::Md5); const qint64 progressStep = 10 * 1024 * 1024; QProgressDialog progress(tr("Hashing download file '%1'").arg(info->m_FileName), - tr("Cancel"), - 0, - downloadFile.size() / progressStep); + tr("Cancel"), 0, downloadFile.size() / progressStep); progress.setWindowModality(Qt::WindowModal); progress.setMinimumDuration(1000); for (qint64 i = 0; i < downloadFile.size(); i += progressStep) { - progress.setValue(progress.value()+1); + progress.setValue(progress.value() + 1); if (progress.wasCanceled()) { break; } @@ -1087,7 +1120,7 @@ void DownloadManager::queryInfoMd5(int index) progress.close(); downloadFile.close(); - info->m_Hash = hash.result(); + info->m_Hash = hash.result(); info->m_ReQueried = true; setState(info, STATE_FETCHINGMODINFO_MD5); } @@ -1098,7 +1131,7 @@ void DownloadManager::visitOnNexus(int index) reportError(tr("VisitNexus: invalid download index %1").arg(index)); return; } - DownloadInfo *info = m_ActiveDownloads[index]; + DownloadInfo* info = m_ActiveDownloads[index]; if (info->m_FileInfo->repository != "Nexus") { log::warn("Visiting mod page is currently only possible with Nexus"); @@ -1114,8 +1147,7 @@ void DownloadManager::visitOnNexus(int index) QString gameName = info->m_FileInfo->gameName; if (modID > 0) { shell::Open(QUrl(m_NexusInterface->getModURL(modID, gameName))); - } - else { + } else { emit showMessage(tr("Nexus ID for this Mod is unknown")); } } @@ -1137,21 +1169,21 @@ void DownloadManager::openFile(int index) return; } -void DownloadManager::openMetaFile(int index) { +void DownloadManager::openMetaFile(int index) +{ if (index < 0 || index >= m_ActiveDownloads.size()) { log::error("OpenMetaFile: invalid download index {}", index); return; } - const auto path = QDir(m_OutputDirectory); + const auto path = QDir(m_OutputDirectory); const auto filePath = getFilePath(index); const auto metaPath = filePath + ".meta"; if (path.exists(metaPath)) { shell::Open(metaPath); return; - } - else { + } else { QSettings metaFile(metaPath, QSettings::IniFormat); metaFile.setValue("removed", false); } @@ -1176,8 +1208,7 @@ void DownloadManager::openInDownloadsFolder(int index) if (QFile::exists(path)) { shell::Explore(path); return; - } - else { + } else { const auto unfinished = path + ".unfinished"; if (QFile::exists(unfinished)) { shell::Explore(unfinished); @@ -1188,7 +1219,6 @@ void DownloadManager::openInDownloadsFolder(int index) shell::Explore(m_OutputDirectory); } - int DownloadManager::numTotalDownloads() const { return m_ActiveDownloads.size(); @@ -1220,14 +1250,22 @@ QString DownloadManager::getFilePath(int index) const QString DownloadManager::getFileTypeString(int fileType) { switch (fileType) { - case 1: return tr("Main"); - case 2: return tr("Update"); - case 3: return tr("Optional"); - case 4: return tr("Old"); - case 5: return tr("Miscellaneous"); - case 6: return tr("Deleted"); - case 7: return tr("Archived"); - default: return tr("Unknown"); + case 1: + return tr("Main"); + case 2: + return tr("Update"); + case 3: + return tr("Optional"); + case 4: + return tr("Old"); + case 5: + return tr("Miscellaneous"); + case 6: + return tr("Deleted"); + case 7: + return tr("Archived"); + default: + return tr("Unknown"); } } @@ -1237,14 +1275,15 @@ QString DownloadManager::getDisplayName(int index) const throw MyException(tr("display name: invalid download index %1").arg(index)); } - DownloadInfo *info = m_ActiveDownloads.at(index); + DownloadInfo* info = m_ActiveDownloads.at(index); QTextDocument doc; if (!info->m_FileInfo->name.isEmpty()) { doc.setHtml(info->m_FileInfo->name); - return QString("%1 (%2, v%3)").arg(doc.toPlainText()) - .arg(getFileTypeString(info->m_FileInfo->fileCategory)) - .arg(info->m_FileInfo->version.displayString()); + return QString("%1 (%2, v%3)") + .arg(doc.toPlainText()) + .arg(getFileTypeString(info->m_FileInfo->fileCategory)) + .arg(info->m_FileInfo->version.displayString()); } else { doc.setHtml(info->m_FileName); return doc.toPlainText(); @@ -1266,7 +1305,7 @@ QDateTime DownloadManager::getFileTime(int index) const throw MyException(tr("file time: invalid download index %1").arg(index)); } - DownloadInfo *info = m_ActiveDownloads.at(index); + DownloadInfo* info = m_ActiveDownloads.at(index); if (!info->m_Created.isValid()) { QFileInfo fileInfo(info->m_Output); info->m_Created = fileInfo.birthTime(); @@ -1288,7 +1327,6 @@ qint64 DownloadManager::getFileSize(int index) const return m_ActiveDownloads.at(index)->m_TotalSize; } - std::pair<int, QString> DownloadManager::getProgress(int index) const { if ((index < 0) || (index >= m_ActiveDownloads.size())) { @@ -1298,7 +1336,6 @@ std::pair<int, QString> DownloadManager::getProgress(int index) const return m_ActiveDownloads.at(index)->m_Progress; } - DownloadManager::DownloadState DownloadManager::getState(int index) const { if ((index < 0) || (index >= m_ActiveDownloads.size())) { @@ -1308,14 +1345,13 @@ DownloadManager::DownloadState DownloadManager::getState(int index) const return m_ActiveDownloads.at(index)->m_State; } - bool DownloadManager::isInfoIncomplete(int index) const { if ((index < 0) || (index >= m_ActiveDownloads.size())) { throw MyException(tr("infocomplete: invalid download index %1").arg(index)); } - DownloadInfo *info = m_ActiveDownloads.at(index); + DownloadInfo* info = m_ActiveDownloads.at(index); if (info->m_FileInfo->repository != "Nexus") { // other repositories currently don't support re-querying info anyway return false; @@ -1323,7 +1359,6 @@ bool DownloadManager::isInfoIncomplete(int index) const return (info->m_FileInfo->fileID == 0) || (info->m_FileInfo->modID == 0); } - int DownloadManager::getModID(int index) const { if ((index < 0) || (index >= m_ActiveDownloads.size())) { @@ -1337,7 +1372,7 @@ QString DownloadManager::getDisplayGameName(int index) const if ((index < 0) || (index >= m_ActiveDownloads.size())) { throw MyException(tr("mod id: invalid download index %1").arg(index)); } - QString gameName = m_ActiveDownloads.at(index)->m_FileInfo->gameName; + QString gameName = m_ActiveDownloads.at(index)->m_FileInfo->gameName; IPluginGame* gamePlugin = m_OrganizerCore->getGame(gameName); if (gamePlugin) { gameName = gamePlugin->gameName(); @@ -1361,8 +1396,7 @@ bool DownloadManager::isHidden(int index) const return m_ActiveDownloads.at(index)->m_Hidden; } - -const ModRepositoryFileInfo *DownloadManager::getFileInfo(int index) const +const ModRepositoryFileInfo* DownloadManager::getFileInfo(int index) const { if ((index < 0) || (index >= m_ActiveDownloads.size())) { throw MyException(tr("file info: invalid download index %1").arg(index)); @@ -1371,17 +1405,16 @@ const ModRepositoryFileInfo *DownloadManager::getFileInfo(int index) const return m_ActiveDownloads.at(index)->m_FileInfo; } - void DownloadManager::markInstalled(int index) { if ((index < 0) || (index >= m_ActiveDownloads.size())) { throw MyException(tr("mark installed: invalid download index %1").arg(index)); } - //Avoid triggering refreshes from DirWatcher + // Avoid triggering refreshes from DirWatcher startDisableDirWatcher(); - DownloadInfo *info = m_ActiveDownloads.at(index); + DownloadInfo* info = m_ActiveDownloads.at(index); QSettings metaFile(info->m_Output.fileName() + ".meta", QSettings::IniFormat); metaFile.setValue("installed", true); metaFile.setValue("uninstalled", false); @@ -1397,9 +1430,9 @@ void DownloadManager::markInstalled(QString fileName) if (index >= 0) { markInstalled(index); } else { - DownloadInfo *info = getDownloadInfo(fileName); + DownloadInfo* info = getDownloadInfo(fileName); if (info != nullptr) { - //Avoid triggering refreshes from DirWatcher + // Avoid triggering refreshes from DirWatcher startDisableDirWatcher(); QSettings metaFile(info->m_Output.fileName() + ".meta", QSettings::IniFormat); @@ -1423,10 +1456,10 @@ void DownloadManager::markUninstalled(int index) throw MyException(tr("mark uninstalled: invalid download index %1").arg(index)); } - //Avoid triggering refreshes from DirWatcher + // Avoid triggering refreshes from DirWatcher startDisableDirWatcher(); - DownloadInfo *info = m_ActiveDownloads.at(index); + DownloadInfo* info = m_ActiveDownloads.at(index); QSettings metaFile(info->m_Output.fileName() + ".meta", QSettings::IniFormat); metaFile.setValue("uninstalled", true); @@ -1435,18 +1468,17 @@ void DownloadManager::markUninstalled(int index) setState(m_ActiveDownloads.at(index), STATE_UNINSTALLED); } - void DownloadManager::markUninstalled(QString fileName) { int index = indexByName(fileName); if (index >= 0) { markUninstalled(index); } else { - QString filePath = QDir::fromNativeSeparators(m_OutputDirectory) + "/" + fileName; - DownloadInfo *info = getDownloadInfo(filePath); + QString filePath = QDir::fromNativeSeparators(m_OutputDirectory) + "/" + fileName; + DownloadInfo* info = getDownloadInfo(filePath); if (info != nullptr) { - //Avoid triggering refreshes from DirWatcher + // Avoid triggering refreshes from DirWatcher startDisableDirWatcher(); QSettings metaFile(info->m_Output.fileName() + ".meta", QSettings::IniFormat); @@ -1458,13 +1490,13 @@ void DownloadManager::markUninstalled(QString fileName) } } - -QString DownloadManager::getDownloadFileName(const QString &baseName, bool rename) const +QString DownloadManager::getDownloadFileName(const QString& baseName, bool rename) const { QString fullPath = m_OutputDirectory + "/" + MOBase::sanitizeFileName(baseName); if (QFile::exists(fullPath) && rename) { int i = 1; - while (QFile::exists(QString("%1/%2_%3").arg(m_OutputDirectory).arg(i).arg(baseName))) { + while (QFile::exists( + QString("%1/%2_%3").arg(m_OutputDirectory).arg(i).arg(baseName))) { ++i; } @@ -1473,14 +1505,14 @@ QString DownloadManager::getDownloadFileName(const QString &baseName, bool renam return fullPath; } - -QString DownloadManager::getFileNameFromNetworkReply(QNetworkReply *reply) +QString DownloadManager::getFileNameFromNetworkReply(QNetworkReply* reply) { if (reply->hasRawHeader("Content-Disposition")) { std::regex exp("filename=\"(.*)\""); std::cmatch result; - if (std::regex_search(reply->rawHeader("Content-Disposition").constData(), result, exp)) { + if (std::regex_search(reply->rawHeader("Content-Disposition").constData(), result, + exp)) { return MOBase::sanitizeFileName(QString::fromUtf8(result.str(1).c_str())); } } @@ -1488,8 +1520,8 @@ QString DownloadManager::getFileNameFromNetworkReply(QNetworkReply *reply) return QString(); } - -void DownloadManager::setState(DownloadManager::DownloadInfo *info, DownloadManager::DownloadState state) +void DownloadManager::setState(DownloadManager::DownloadInfo* info, + DownloadManager::DownloadState state) { int row = 0; for (int i = 0; i < m_ActiveDownloads.size(); ++i) { @@ -1500,41 +1532,48 @@ void DownloadManager::setState(DownloadManager::DownloadInfo *info, DownloadMana } info->m_State = state; switch (state) { - case STATE_PAUSED: { - info->m_Reply->abort(); - info->m_Output.close(); - m_DownloadPaused(row); - } break; - case STATE_ERROR: { - info->m_Reply->abort(); - info->m_Output.close(); - m_DownloadFailed(row); - } break; - case STATE_CANCELED: { - info->m_Reply->abort(); - m_DownloadFailed(row); - } break; - case STATE_FETCHINGMODINFO: { - m_RequestIDs.insert(m_NexusInterface->requestDescription(info->m_FileInfo->gameName, info->m_FileInfo->modID, this, info->m_DownloadID, QString())); - } break; - case STATE_FETCHINGFILEINFO: { - m_RequestIDs.insert(m_NexusInterface->requestFiles(info->m_FileInfo->gameName, info->m_FileInfo->modID, this, info->m_DownloadID, QString())); - } break; - case STATE_FETCHINGMODINFO_MD5: { - log::debug("Searching {} for MD5 of {}", info->m_GamesToQuery[0], QString(info->m_Hash.toHex())); - m_RequestIDs.insert(m_NexusInterface->requestInfoFromMd5(info->m_GamesToQuery[0], info->m_Hash, this, info->m_DownloadID, QString())); - } break; - case STATE_READY: { - createMetaFile(info); - m_DownloadComplete(row); - } break; - default: /* NOP */ break; + case STATE_PAUSED: { + info->m_Reply->abort(); + info->m_Output.close(); + m_DownloadPaused(row); + } break; + case STATE_ERROR: { + info->m_Reply->abort(); + info->m_Output.close(); + m_DownloadFailed(row); + } break; + case STATE_CANCELED: { + info->m_Reply->abort(); + m_DownloadFailed(row); + } break; + case STATE_FETCHINGMODINFO: { + m_RequestIDs.insert(m_NexusInterface->requestDescription( + info->m_FileInfo->gameName, info->m_FileInfo->modID, this, info->m_DownloadID, + QString())); + } break; + case STATE_FETCHINGFILEINFO: { + m_RequestIDs.insert(m_NexusInterface->requestFiles(info->m_FileInfo->gameName, + info->m_FileInfo->modID, this, + info->m_DownloadID, QString())); + } break; + case STATE_FETCHINGMODINFO_MD5: { + log::debug("Searching {} for MD5 of {}", info->m_GamesToQuery[0], + QString(info->m_Hash.toHex())); + m_RequestIDs.insert(m_NexusInterface->requestInfoFromMd5( + info->m_GamesToQuery[0], info->m_Hash, this, info->m_DownloadID, QString())); + } break; + case STATE_READY: { + createMetaFile(info); + m_DownloadComplete(row); + } break; + default: /* NOP */ + break; } emit stateChanged(row, state); } - -DownloadManager::DownloadInfo *DownloadManager::findDownload(QObject *reply, int *index) const +DownloadManager::DownloadInfo* DownloadManager::findDownload(QObject* reply, + int* index) const { // reverse search as newer, thus more relevant, downloads are at the end for (int i = m_ActiveDownloads.size() - 1; i >= 0; --i) { @@ -1548,7 +1587,6 @@ DownloadManager::DownloadInfo *DownloadManager::findDownload(QObject *reply, int return nullptr; } - void DownloadManager::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) { if (bytesTotal == 0) { @@ -1556,20 +1594,20 @@ void DownloadManager::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) } int index = 0; try { - DownloadInfo *info = findDownload(this->sender(), &index); + DownloadInfo* info = findDownload(this->sender(), &index); if (info != nullptr) { info->m_HasData = true; if (info->m_State == STATE_CANCELING) { setState(info, STATE_CANCELED); } else if (info->m_State == STATE_PAUSING) { setState(info, STATE_PAUSED); - } - else { + } else { if (bytesTotal > info->m_TotalSize) { info->m_TotalSize = bytesTotal; } - int oldProgress = info->m_Progress.first; - info->m_Progress.first = ((info->m_ResumePos + bytesReceived) * 100) / (info->m_ResumePos + bytesTotal); + int oldProgress = info->m_Progress.first; + info->m_Progress.first = ((info->m_ResumePos + bytesReceived) * 100) / + (info->m_ResumePos + bytesTotal); qint64 elapsed = info->m_StartTime.elapsed(); info->m_DownloadAcc(bytesReceived - info->m_DownloadLast); @@ -1578,16 +1616,19 @@ void DownloadManager::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) info->m_DownloadTimeLast = elapsed; // calculate the download speed - const double speed = rolling_mean(info->m_DownloadAcc) / (rolling_mean(info->m_DownloadTimeAcc) / 1000.0);; + const double speed = rolling_mean(info->m_DownloadAcc) / + (rolling_mean(info->m_DownloadTimeAcc) / 1000.0); + ; const qint64 remaining = (bytesTotal - bytesReceived) / speed * 1000; info->m_Progress.second = tr("%1% - %2 - ~%3") - .arg(info->m_Progress.first) - .arg(MOBase::localizedByteSpeed(speed)) - .arg(MOBase::localizedTimeRemaining(remaining)); + .arg(info->m_Progress.first) + .arg(MOBase::localizedByteSpeed(speed)) + .arg(MOBase::localizedTimeRemaining(remaining)); - TaskProgressManager::instance().updateProgress(info->m_TaskProgressId, bytesReceived, bytesTotal); + TaskProgressManager::instance().updateProgress(info->m_TaskProgressId, + bytesReceived, bytesTotal); emit update(index); } } @@ -1596,7 +1637,6 @@ void DownloadManager::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) } } - void DownloadManager::downloadReadyRead() { try { @@ -1606,13 +1646,13 @@ void DownloadManager::downloadReadyRead() } } - -void DownloadManager::createMetaFile(DownloadInfo *info) +void DownloadManager::createMetaFile(DownloadInfo* info) { - //Avoid triggering refreshes from DirWatcher + // Avoid triggering refreshes from DirWatcher startDisableDirWatcher(); - QSettings metaFile(QString("%1.meta").arg(info->m_Output.fileName()), QSettings::IniFormat); + QSettings metaFile(QString("%1.meta").arg(info->m_Output.fileName()), + QSettings::IniFormat); metaFile.setValue("gameName", info->m_FileInfo->gameName); metaFile.setValue("modID", info->m_FileInfo->modID); metaFile.setValue("fileID", info->m_FileInfo->fileID); @@ -1630,7 +1670,7 @@ void DownloadManager::createMetaFile(DownloadInfo *info) metaFile.setValue("installed", info->m_State == DownloadManager::STATE_INSTALLED); metaFile.setValue("uninstalled", info->m_State == DownloadManager::STATE_UNINSTALLED); metaFile.setValue("paused", (info->m_State == DownloadManager::STATE_PAUSED) || - (info->m_State == DownloadManager::STATE_ERROR)); + (info->m_State == DownloadManager::STATE_ERROR)); metaFile.setValue("removed", info->m_Hidden); endDisableDirWatcher(); @@ -1642,8 +1682,8 @@ void DownloadManager::createMetaFile(DownloadInfo *info) } } - -void DownloadManager::nxmDescriptionAvailable(QString, int, QVariant userData, QVariant resultData, int requestID) +void DownloadManager::nxmDescriptionAvailable(QString, int, QVariant userData, + QVariant resultData, int requestID) { std::set<int>::iterator idIter = m_RequestIDs.find(requestID); if (idIter == m_RequestIDs.end()) { @@ -1654,8 +1694,9 @@ void DownloadManager::nxmDescriptionAvailable(QString, int, QVariant userData, Q QVariantMap result = resultData.toMap(); - DownloadInfo *info = downloadInfoByID(userData.toInt()); - if (info == nullptr) return; + DownloadInfo* info = downloadInfoByID(userData.toInt()); + if (info == nullptr) + return; info->m_FileInfo->categoryID = result["category_id"].toInt(); QTextDocument doc; doc.setHtml(result["name"].toString().trimmed()); @@ -1667,7 +1708,8 @@ void DownloadManager::nxmDescriptionAvailable(QString, int, QVariant userData, Q } } -void DownloadManager::nxmFilesAvailable(QString, int, QVariant userData, QVariant resultData, int requestID) +void DownloadManager::nxmFilesAvailable(QString, int, QVariant userData, + QVariant resultData, int requestID) { std::set<int>::iterator idIter = m_RequestIDs.find(requestID); if (idIter == m_RequestIDs.end()) { @@ -1676,13 +1718,13 @@ void DownloadManager::nxmFilesAvailable(QString, int, QVariant userData, QVarian m_RequestIDs.erase(idIter); } - DownloadInfo *info = downloadInfoByID(userData.toInt()); - if (info == nullptr) return; + DownloadInfo* info = downloadInfoByID(userData.toInt()); + if (info == nullptr) + return; QVariantMap result = resultData.toMap(); QVariantList files = result["files"].toList(); - // MO sometimes prepends <digit>_ to the filename in case of duplicate downloads. // this may muck up the file name comparison QString alternativeLocalName = info->m_FileName; @@ -1696,22 +1738,25 @@ void DownloadManager::nxmFilesAvailable(QString, int, QVariant userData, QVarian bool found = false; for (QVariant file : files) { - QVariantMap fileInfo = file.toMap(); - QString fileName = fileInfo["file_name"].toString(); + QVariantMap fileInfo = file.toMap(); + QString fileName = fileInfo["file_name"].toString(); QString fileNameVariant = fileName.mid(0).replace(' ', '_'); - if ((fileName == info->m_RemoteFileName) || (fileNameVariant == info->m_RemoteFileName) || - (fileName == info->m_FileName) || (fileNameVariant == info->m_FileName) || - (fileName == alternativeLocalName) || (fileNameVariant == alternativeLocalName)) { + if ((fileName == info->m_RemoteFileName) || + (fileNameVariant == info->m_RemoteFileName) || (fileName == info->m_FileName) || + (fileNameVariant == info->m_FileName) || (fileName == alternativeLocalName) || + (fileNameVariant == alternativeLocalName)) { info->m_FileInfo->name = fileInfo["name"].toString(); info->m_FileInfo->version.parse(fileInfo["version"].toString()); if (!info->m_FileInfo->version.isValid()) { info->m_FileInfo->version = info->m_FileInfo->newestVersion; } info->m_FileInfo->fileCategory = fileInfo["category_id"].toInt(); - info->m_FileInfo->fileTime = QDateTime::fromMSecsSinceEpoch(fileInfo["uploaded_timestamp"].toLongLong()); - info->m_FileInfo->fileID = fileInfo["file_id"].toInt(); + info->m_FileInfo->fileTime = + QDateTime::fromMSecsSinceEpoch(fileInfo["uploaded_timestamp"].toLongLong()); + info->m_FileInfo->fileID = fileInfo["file_id"].toInt(); info->m_FileInfo->fileName = fileInfo["file_name"].toString(); - info->m_FileInfo->description = BBCode::convertToHTML(fileInfo["description"].toString()); + info->m_FileInfo->description = + BBCode::convertToHTML(fileInfo["description"].toString()); found = true; break; } @@ -1721,40 +1766,46 @@ void DownloadManager::nxmFilesAvailable(QString, int, QVariant userData, QVarian if (found) { emit showMessage(tr("Information updated")); } else if (result.count() == 0) { - emit showMessage(tr("No matching file found on Nexus! Maybe this file is no longer available or it was renamed?")); + emit showMessage(tr("No matching file found on Nexus! Maybe this file is no " + "longer available or it was renamed?")); } else { - SelectionDialog selection(tr("No file on Nexus matches the selected file by name. Please manually choose the correct one.")); - std::sort(files.begin(), files.end(), [](const QVariant& lhs, const QVariant& rhs) - {return lhs.toMap()["uploaded_timestamp"].toInt() > rhs.toMap()["uploaded_timestamp"].toInt();}); + SelectionDialog selection(tr("No file on Nexus matches the selected file by " + "name. Please manually choose the correct one.")); + std::sort(files.begin(), files.end(), + [](const QVariant& lhs, const QVariant& rhs) { + return lhs.toMap()["uploaded_timestamp"].toInt() > + rhs.toMap()["uploaded_timestamp"].toInt(); + }); for (QVariant file : files) { QVariantMap fileInfo = file.toMap(); if (fileInfo["category_id"].toInt() != NexusInterface::FileStatus::REMOVED && - fileInfo["category_id"].toInt() != NexusInterface::FileStatus::ARCHIVED) + fileInfo["category_id"].toInt() != NexusInterface::FileStatus::ARCHIVED) selection.addChoice(fileInfo["file_name"].toString(), "", file); } if (selection.exec() == QDialog::Accepted) { - QVariantMap fileInfo = selection.getChoiceData().toMap(); + QVariantMap fileInfo = selection.getChoiceData().toMap(); info->m_FileInfo->name = fileInfo["name"].toString(); info->m_FileInfo->version.parse(fileInfo["version"].toString()); info->m_FileInfo->fileCategory = fileInfo["category_id"].toInt(); - info->m_FileInfo->fileID = fileInfo["file_id"].toInt(); + info->m_FileInfo->fileID = fileInfo["file_id"].toInt(); } else { - emit showMessage(tr("No matching file found on Nexus! Maybe this file is no longer available or it was renamed?")); + emit showMessage(tr("No matching file found on Nexus! Maybe this file is no " + "longer available or it was renamed?")); } } } else { if (info->m_FileInfo->fileID == 0) { - log::warn( - "could not determine file id for {} (state {})", - info->m_FileName, info->m_State); + log::warn("could not determine file id for {} (state {})", info->m_FileName, + info->m_State); } } setState(info, STATE_READY); } - -void DownloadManager::nxmFileInfoAvailable(QString gameName, int modID, int fileID, QVariant userData, QVariant resultData, int requestID) +void DownloadManager::nxmFileInfoAvailable(QString gameName, int modID, int fileID, + QVariant userData, QVariant resultData, + int requestID) { std::set<int>::iterator idIter = m_RequestIDs.find(requestID); if (idIter == m_RequestIDs.end()) { @@ -1763,17 +1814,19 @@ void DownloadManager::nxmFileInfoAvailable(QString gameName, int modID, int file m_RequestIDs.erase(idIter); } - ModRepositoryFileInfo *info = qobject_cast<ModRepositoryFileInfo*>(qvariant_cast<QObject*>(userData)); + ModRepositoryFileInfo* info = + qobject_cast<ModRepositoryFileInfo*>(qvariant_cast<QObject*>(userData)); QVariantMap result = resultData.toMap(); - info->name = result["name"].toString(); + info->name = result["name"].toString(); info->version.parse(result["version"].toString()); if (!info->version.isValid()) { info->version = info->newestVersion; } - info->fileName = result["file_name"].toString(); + info->fileName = result["file_name"].toString(); info->fileCategory = result["category_id"].toInt(); - info->fileTime = QDateTime::fromMSecsSinceEpoch(result["uploaded_timestamp"].toLongLong()); + info->fileTime = + QDateTime::fromMSecsSinceEpoch(result["uploaded_timestamp"].toLongLong()); info->description = BBCode::convertToHTML(result["description"].toString()); info->repository = "Nexus"; @@ -1781,31 +1834,33 @@ void DownloadManager::nxmFileInfoAvailable(QString gameName, int modID, int file QStringList games(m_ManagedGame->validShortNames()); games += m_ManagedGame->gameShortName(); for (auto game : games) { - MOBase::IPluginGame *gamePlugin = m_OrganizerCore->getGame(game); - if (gamePlugin != nullptr && gamePlugin->gameNexusName().compare(gameName, Qt::CaseInsensitive) == 0) { + MOBase::IPluginGame* gamePlugin = m_OrganizerCore->getGame(game); + if (gamePlugin != nullptr && + gamePlugin->gameNexusName().compare(gameName, Qt::CaseInsensitive) == 0) { info->gameName = gamePlugin->gameShortName(); } } - info->modID = modID; + info->modID = modID; info->fileID = fileID; - QObject *test = info; - m_RequestIDs.insert(m_NexusInterface->requestDownloadURL(info->gameName, info->modID, info->fileID, this, QVariant::fromValue(test), QString())); + QObject* test = info; + m_RequestIDs.insert( + m_NexusInterface->requestDownloadURL(info->gameName, info->modID, info->fileID, + this, QVariant::fromValue(test), QString())); } -static int evaluateFileInfoMap( - const QVariantMap &map, - const ServerList::container& preferredServers) +static int evaluateFileInfoMap(const QVariantMap& map, + const ServerList::container& preferredServers) { - int preference = 0; - bool found = false; + int preference = 0; + bool found = false; const auto name = map["short_name"].toString(); for (const auto& server : preferredServers) { if (server.name() == name) { preference = server.preferred(); - found = true; + found = true; break; } } @@ -1814,21 +1869,20 @@ static int evaluateFileInfoMap( return 0; } - return 100 + preference * 20; + return 100 + preference * 20; } // sort function to sort by best download server // -bool ServerByPreference( - const ServerList::container& preferredServers, - const QVariant &LHS, const QVariant &RHS) +bool ServerByPreference(const ServerList::container& preferredServers, + const QVariant& LHS, const QVariant& RHS) { const auto a = evaluateFileInfoMap(LHS.toMap(), preferredServers); const auto b = evaluateFileInfoMap(RHS.toMap(), preferredServers); return (a > b); } -int DownloadManager::startDownloadURLs(const QStringList &urls) +int DownloadManager::startDownloadURLs(const QStringList& urls) { ModRepositoryFileInfo info; addDownload(urls, "", -1, -1, &info); @@ -1838,7 +1892,10 @@ int DownloadManager::startDownloadURLs(const QStringList &urls) int DownloadManager::startDownloadNexusFile(int modID, int fileID) { int newID = m_ActiveDownloads.size(); - addNXMDownload(QString("nxm://%1/mods/%2/files/%3").arg(m_ManagedGame->gameShortName()).arg(modID).arg(fileID)); + addNXMDownload(QString("nxm://%1/mods/%2/files/%3") + .arg(m_ManagedGame->gameShortName()) + .arg(modID) + .arg(fileID)); return newID; } @@ -1847,27 +1904,31 @@ QString DownloadManager::downloadPath(int id) return getFilePath(id); } -boost::signals2::connection DownloadManager::onDownloadComplete(const std::function<void(int)>& callback) +boost::signals2::connection +DownloadManager::onDownloadComplete(const std::function<void(int)>& callback) { return m_DownloadComplete.connect(callback); } -boost::signals2::connection DownloadManager::onDownloadPaused(const std::function<void(int)>& callback) +boost::signals2::connection +DownloadManager::onDownloadPaused(const std::function<void(int)>& callback) { return m_DownloadPaused.connect(callback); } -boost::signals2::connection DownloadManager::onDownloadFailed(const std::function<void(int)>& callback) +boost::signals2::connection +DownloadManager::onDownloadFailed(const std::function<void(int)>& callback) { return m_DownloadFailed.connect(callback); } -boost::signals2::connection DownloadManager::onDownloadRemoved(const std::function<void(int)>& callback) +boost::signals2::connection +DownloadManager::onDownloadRemoved(const std::function<void(int)>& callback) { return m_DownloadRemoved.connect(callback); } -int DownloadManager::indexByName(const QString &fileName) const +int DownloadManager::indexByName(const QString& fileName) const { for (int i = 0; i < m_ActiveDownloads.size(); ++i) { if (m_ActiveDownloads[i]->m_FileName == fileName) { @@ -1887,7 +1948,9 @@ int DownloadManager::indexByInfo(const DownloadInfo* info) const return -1; } -void DownloadManager::nxmDownloadURLsAvailable(QString gameName, int modID, int fileID, QVariant userData, QVariant resultData, int requestID) +void DownloadManager::nxmDownloadURLsAvailable(QString gameName, int modID, int fileID, + QVariant userData, QVariant resultData, + int requestID) { using namespace boost::placeholders; @@ -1898,7 +1961,8 @@ void DownloadManager::nxmDownloadURLsAvailable(QString gameName, int modID, int m_RequestIDs.erase(idIter); } - ModRepositoryFileInfo *info = qobject_cast<ModRepositoryFileInfo*>(qvariant_cast<QObject*>(userData)); + ModRepositoryFileInfo* info = + qobject_cast<ModRepositoryFileInfo*>(qvariant_cast<QObject*>(userData)); QVariantList resultList = resultData.toList(); if (resultList.length() == 0) { removePending(gameName, modID, fileID); @@ -1908,23 +1972,21 @@ void DownloadManager::nxmDownloadURLsAvailable(QString gameName, int modID, int const auto servers = m_OrganizerCore->settings().network().servers(); - std::sort( - resultList.begin(), - resultList.end(), - boost::bind(&ServerByPreference, servers.getPreferred(), _1, _2)); + std::sort(resultList.begin(), resultList.end(), + boost::bind(&ServerByPreference, servers.getPreferred(), _1, _2)); info->userData["downloadMap"] = resultList; QStringList URLs; - foreach (const QVariant &server, resultList) { + foreach (const QVariant& server, resultList) { URLs.append(server.toMap()["URI"].toString()); } addDownload(URLs, gameName, modID, fileID, info); } - -void DownloadManager::nxmFileInfoFromMd5Available(QString gameName, QVariant userData, QVariant resultData, int requestID) +void DownloadManager::nxmFileInfoFromMd5Available(QString gameName, QVariant userData, + QVariant resultData, int requestID) { std::set<int>::iterator idIter = m_RequestIDs.find(requestID); if (idIter == m_RequestIDs.end()) { @@ -1933,23 +1995,24 @@ void DownloadManager::nxmFileInfoFromMd5Available(QString gameName, QVariant use m_RequestIDs.erase(idIter); } - DownloadInfo *info = downloadInfoByID(userData.toInt()); + DownloadInfo* info = downloadInfoByID(userData.toInt()); - //This can come back with multiple results with the same file was uploaded multiple times (for whatever reason) + // This can come back with multiple results with the same file was uploaded multiple + // times (for whatever reason) auto resultlist = resultData.toList(); - int chosenIdx = resultlist.count() > 1 ? -1 : 0; + int chosenIdx = resultlist.count() > 1 ? -1 : 0; - //Look for the exact file name + // Look for the exact file name if (chosenIdx < 0) { for (int i = 0; i < resultlist.count(); i++) { - auto results = resultlist[i].toMap(); + auto results = resultlist[i].toMap(); auto fileDetails = results["file_details"].toMap(); - if (fileDetails["file_name"].toString().compare(info->m_FileName, Qt::CaseInsensitive) == 0) { + if (fileDetails["file_name"].toString().compare(info->m_FileName, + Qt::CaseInsensitive) == 0) { if (chosenIdx < 0) { - chosenIdx = i; //intentional to not break in order to check other results - } - else { + chosenIdx = i; // intentional to not break in order to check other results + } else { log::debug("Multiple files with same name found during MD5 search."); chosenIdx = -1; break; @@ -1958,16 +2021,16 @@ void DownloadManager::nxmFileInfoFromMd5Available(QString gameName, QVariant use } } - //Look for the only active one + // Look for the only active one if (chosenIdx < 0) { for (int i = 0; i < resultlist.count(); i++) { - auto results = resultlist[i].toMap(); + auto results = resultlist[i].toMap(); auto fileDetails = results["file_details"].toMap(); if (fileDetails["category_id"].toInt() != NexusInterface::FileStatus::REMOVED && fileDetails["category_id"].toInt() != NexusInterface::FileStatus::ARCHIVED) { if (chosenIdx < 0) { - chosenIdx = i; //intentional to not break in order to check other results + chosenIdx = i; // intentional to not break in order to check other results } else { log::debug("Multiple active files found during MD5 search."); chosenIdx = -1; @@ -1977,36 +2040,38 @@ void DownloadManager::nxmFileInfoFromMd5Available(QString gameName, QVariant use } } - //Unable to determine the correct mod / file. Revert to the old method + // Unable to determine the correct mod / file. Revert to the old method if (chosenIdx < 0) { - //don't use the normal state set function as we don't want to create a meta file + // don't use the normal state set function as we don't want to create a meta file info->m_State = DownloadManager::STATE_READY; queryInfo(m_ActiveDownloads.indexOf(info)); return; } - auto results = resultlist[chosenIdx].toMap(); + auto results = resultlist[chosenIdx].toMap(); auto fileDetails = results["file_details"].toMap(); - auto modDetails = results["mod"].toMap(); + auto modDetails = results["mod"].toMap(); - info->m_FileInfo->name = fileDetails["name"].toString(); + info->m_FileInfo->name = fileDetails["name"].toString(); info->m_FileInfo->fileID = fileDetails["file_id"].toInt(); - info->m_FileInfo->description = BBCode::convertToHTML(fileDetails["description"].toString()); + info->m_FileInfo->description = + BBCode::convertToHTML(fileDetails["description"].toString()); info->m_FileInfo->version.parse(fileDetails["version"].toString()); if (!info->m_FileInfo->version.isValid()) info->m_FileInfo->version.parse(fileDetails["mod_version"].toString()); info->m_FileInfo->fileCategory = fileDetails["category_id"].toInt(); - info->m_FileInfo->modID = modDetails["mod_id"].toInt(); - info->m_FileInfo->modName = modDetails["name"].toString(); + info->m_FileInfo->modID = modDetails["mod_id"].toInt(); + info->m_FileInfo->modName = modDetails["name"].toString(); info->m_FileInfo->categoryID = modDetails["category_id"].toInt(); QString gameShortName = gameName; QStringList games(m_ManagedGame->validShortNames()); games += m_ManagedGame->gameShortName(); for (auto game : games) { - MOBase::IPluginGame *gamePlugin = m_OrganizerCore->getGame(game); - if (gamePlugin != nullptr && gamePlugin->gameNexusName().compare(gameName, Qt::CaseInsensitive) == 0) { + MOBase::IPluginGame* gamePlugin = m_OrganizerCore->getGame(game); + if (gamePlugin != nullptr && + gamePlugin->gameNexusName().compare(gameName, Qt::CaseInsensitive) == 0) { gameShortName = gamePlugin->gameShortName(); break; } @@ -2014,7 +2079,7 @@ void DownloadManager::nxmFileInfoFromMd5Available(QString gameName, QVariant use info->m_FileInfo->gameName = gameShortName; - //If the file description is not present, send another query to get it + // If the file description is not present, send another query to get it if (!fileDetails["description"].isValid()) { info->m_RemoteFileName = fileDetails["file_name"].toString(); setState(info, STATE_FETCHINGFILEINFO); @@ -2023,8 +2088,9 @@ void DownloadManager::nxmFileInfoFromMd5Available(QString gameName, QVariant use } } - -void DownloadManager::nxmRequestFailed(QString gameName, int modID, int fileID, QVariant userData, int requestID, int errorCode, const QString &errorString) +void DownloadManager::nxmRequestFailed(QString gameName, int modID, int fileID, + QVariant userData, int requestID, int errorCode, + const QString& errorString) { std::set<int>::iterator idIter = m_RequestIDs.find(requestID); if (idIter == m_RequestIDs.end()) { @@ -2033,12 +2099,13 @@ void DownloadManager::nxmRequestFailed(QString gameName, int modID, int fileID, m_RequestIDs.erase(idIter); } - DownloadInfo *userDataInfo = downloadInfoByID(userData.toInt()); + DownloadInfo* userDataInfo = downloadInfoByID(userData.toInt()); int index = 0; - for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); iter != m_ActiveDownloads.end(); ++iter, ++index) { - DownloadInfo *info = *iter; + for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); + iter != m_ActiveDownloads.end(); ++iter, ++index) { + DownloadInfo* info = *iter; if (info != userDataInfo) continue; @@ -2072,17 +2139,16 @@ void DownloadManager::nxmRequestFailed(QString gameName, int modID, int fileID, emit showMessage(tr("Failed to request file info from nexus: %1").arg(errorString)); } - void DownloadManager::downloadFinished(int index) { - DownloadInfo *info; + DownloadInfo* info; if (index) info = m_ActiveDownloads[index]; else info = findDownload(this->sender(), &index); if (info != nullptr) { - QNetworkReply *reply = info->m_Reply; + QNetworkReply* reply = info->m_Reply; QByteArray data; if (reply->isOpen() && info->m_HasData) { data = reply->readAll(); @@ -2092,18 +2158,26 @@ void DownloadManager::downloadFinished(int index) TaskProgressManager::instance().forgetMe(info->m_TaskProgressId); bool error = false; - if ((info->m_State != STATE_CANCELING) && - (info->m_State != STATE_PAUSING)) { - bool textData = reply->header(QNetworkRequest::ContentTypeHeader).toString().startsWith("text", Qt::CaseInsensitive); + if ((info->m_State != STATE_CANCELING) && (info->m_State != STATE_PAUSING)) { + bool textData = reply->header(QNetworkRequest::ContentTypeHeader) + .toString() + .startsWith("text", Qt::CaseInsensitive); if (textData) - emit showMessage(tr("Warning: Content type is: %1").arg(reply->header(QNetworkRequest::ContentTypeHeader).toString())); + emit showMessage( + tr("Warning: Content type is: %1") + .arg(reply->header(QNetworkRequest::ContentTypeHeader).toString())); if ((info->m_Output.size() == 0) || - ((reply->error() != QNetworkReply::NoError) - && (reply->error() != QNetworkReply::OperationCanceledError))) { + ((reply->error() != QNetworkReply::NoError) && + (reply->error() != QNetworkReply::OperationCanceledError))) { if (reply->error() == QNetworkReply::UnknownContentError) - emit showMessage(tr("Download header content length: %1 downloaded file size: %2").arg(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong()).arg(info->m_Output.size())); + emit showMessage( + tr("Download header content length: %1 downloaded file size: %2") + .arg(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong()) + .arg(info->m_Output.size())); if (info->m_Tries == 0) { - emit showMessage(tr("Download failed: %1 (%2)").arg(reply->errorString()).arg(reply->error())); + emit showMessage(tr("Download failed: %1 (%2)") + .arg(reply->errorString()) + .arg(reply->error())); } error = true; setState(info, STATE_ERROR); @@ -2125,7 +2199,9 @@ void DownloadManager::downloadFinished(int index) delete info; m_ActiveDownloads.erase(m_ActiveDownloads.begin() + index); if (error) - emit showMessage(tr("We were unable to download the file due to errors after four retries. There may be an issue with the Nexus servers.")); + emit showMessage( + tr("We were unable to download the file due to errors after four retries. " + "There may be an issue with the Nexus servers.")); emit update(-1); } else if (info->isPausedState() || info->m_State == STATE_PAUSING) { info->m_Output.close(); @@ -2134,20 +2210,25 @@ void DownloadManager::downloadFinished(int index) } else { QString url = info->m_Urls[info->m_CurrentUrl]; if (info->m_FileInfo->userData.contains("downloadMap")) { - foreach (const QVariant &server, info->m_FileInfo->userData["downloadMap"].toList()) { + foreach (const QVariant& server, + info->m_FileInfo->userData["downloadMap"].toList()) { QVariantMap serverMap = server.toMap(); if (serverMap["URI"].toString() == url) { int deltaTime = info->m_StartTime.elapsed() / 1000; if (deltaTime > 5) { - emit downloadSpeed(serverMap["short_name"].toString(), (info->m_TotalSize - info->m_PreResumeSize) / deltaTime); - } // no division by zero please! Also, if the download is shorter than a few seconds, the result is way to inprecise + emit downloadSpeed(serverMap["short_name"].toString(), + (info->m_TotalSize - info->m_PreResumeSize) / + deltaTime); + } // no division by zero please! Also, if the download is shorter than a + // few seconds, the result is way to inprecise break; } } } bool isNexus = info->m_FileInfo->repository == "Nexus"; - // need to change state before changing the file name, otherwise .unfinished is appended + // need to change state before changing the file name, otherwise .unfinished is + // appended if (isNexus) { setState(info, STATE_FETCHINGMODINFO); } else { @@ -2161,7 +2242,8 @@ void DownloadManager::downloadFinished(int index) if (!newName.isEmpty() && (oldName.isEmpty())) { info->setName(getDownloadFileName(newName), true); } else { - info->setName(m_OutputDirectory + "/" + info->m_FileName, true); // don't rename but remove the ".unfinished" extension + info->setName(m_OutputDirectory + "/" + info->m_FileName, + true); // don't rename but remove the ".unfinished" extension } endDisableDirWatcher(); @@ -2183,23 +2265,21 @@ void DownloadManager::downloadFinished(int index) } } - void DownloadManager::downloadError(QNetworkReply::NetworkError error) { if (error != QNetworkReply::OperationCanceledError) { - QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender()); + QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender()); log::warn("{} ({})", - reply != nullptr ? reply->errorString() : "Download error occured", - error); + reply != nullptr ? reply->errorString() : "Download error occured", + error); } } - void DownloadManager::metaDataChanged() { int index = 0; - DownloadInfo *info = findDownload(this->sender(), &index); + DownloadInfo* info = findDownload(this->sender(), &index); if (info != nullptr) { QString newName = getFileNameFromNetworkReply(info->m_Reply); if (!newName.isEmpty() && (info->m_FileName.isEmpty())) { @@ -2207,7 +2287,8 @@ void DownloadManager::metaDataChanged() info->setName(getDownloadFileName(newName), true); endDisableDirWatcher(); refreshAlphabeticalTranslation(); - if (!info->m_Output.isOpen() && !info->m_Output.open(QIODevice::WriteOnly | QIODevice::Append)) { + if (!info->m_Output.isOpen() && + !info->m_Output.open(QIODevice::WriteOnly | QIODevice::Append)) { reportError(tr("failed to re-open %1").arg(info->m_FileName)); setState(info, STATE_CANCELING); } @@ -2219,11 +2300,11 @@ void DownloadManager::metaDataChanged() void DownloadManager::directoryChanged(const QString&) { - if(DownloadManager::m_DirWatcherDisabler==0) + if (DownloadManager::m_DirWatcherDisabler == 0) refreshList(); } -void DownloadManager::managedGameChanged(MOBase::IPluginGame const *managedGame) +void DownloadManager::managedGameChanged(MOBase::IPluginGame const* managedGame) { m_ManagedGame = managedGame; } @@ -2231,8 +2312,11 @@ void DownloadManager::managedGameChanged(MOBase::IPluginGame const *managedGame) void DownloadManager::checkDownloadTimeout() { for (int i = 0; i < m_ActiveDownloads.size(); ++i) { - if (m_ActiveDownloads[i]->m_StartTime.elapsed() - m_ActiveDownloads[i]->m_DownloadTimeLast > 5 * 1000 && - m_ActiveDownloads[i]->m_State == STATE_DOWNLOADING && m_ActiveDownloads[i]->m_Reply != nullptr && + if (m_ActiveDownloads[i]->m_StartTime.elapsed() - + m_ActiveDownloads[i]->m_DownloadTimeLast > + 5 * 1000 && + m_ActiveDownloads[i]->m_State == STATE_DOWNLOADING && + m_ActiveDownloads[i]->m_Reply != nullptr && m_ActiveDownloads[i]->m_Reply->isOpen()) { pauseDownload(i); downloadFinished(i); @@ -2241,21 +2325,23 @@ void DownloadManager::checkDownloadTimeout() } } -void DownloadManager::writeData(DownloadInfo *info) +void DownloadManager::writeData(DownloadInfo* info) { if (info != nullptr) { qint64 ret = info->m_Output.write(info->m_Reply->readAll()); if (ret < info->m_Reply->size()) { - QString fileName = info->m_FileName; // m_FileName may be destroyed after setState + QString fileName = + info->m_FileName; // m_FileName may be destroyed after setState setState(info, DownloadState::STATE_CANCELED); - log::error( - "Unable to write download \"{}\" to drive (return {})", - info->m_FileName, ret); + log::error("Unable to write download \"{}\" to drive (return {})", + info->m_FileName, ret); reportError(tr("Unable to write download to drive (return %1).\n" "Check the drive's available storage.\n\n" - "Canceling download \"%2\"...").arg(ret).arg(fileName)); + "Canceling download \"%2\"...") + .arg(ret) + .arg(fileName)); } } } diff --git a/src/downloadmanager.h b/src/downloadmanager.h index 2bb3f6e8..305c10e3 100644 --- a/src/downloadmanager.h +++ b/src/downloadmanager.h @@ -21,44 +21,48 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #define DOWNLOADMANAGER_H #include "serverinfo.h" -#include <idownloadmanager.h> -#include <modrepositoryfileinfo.h> -#include <set> -#include <QObject> -#include <QUrl> -#include <QQueue> +#include <QElapsedTimer> #include <QFile> +#include <QFileSystemWatcher> +#include <QMap> #include <QNetworkReply> +#include <QObject> +#include <QQueue> +#include <QSettings> +#include <QStringList> #include <QTime> #include <QTimer> -#include <QElapsedTimer> +#include <QUrl> #include <QVector> -#include <QMap> -#include <QStringList> -#include <QFileSystemWatcher> -#include <QSettings> -#include <boost/signals2.hpp> #include <boost/accumulators/accumulators.hpp> #include <boost/accumulators/statistics.hpp> #include <boost/accumulators/statistics/rolling_mean.hpp> +#include <boost/signals2.hpp> +#include <idownloadmanager.h> +#include <modrepositoryfileinfo.h> +#include <set> using namespace boost::accumulators; -namespace MOBase { class IPluginGame; } +namespace MOBase +{ +class IPluginGame; +} class NexusInterface; class PluginContainer; class OrganizerCore; /*! - * \brief manages downloading of files and provides progress information for gui elements + * \brief manages downloading of files and provides progress information for gui + *elements **/ class DownloadManager : public QObject { Q_OBJECT public: - - enum DownloadState { + enum DownloadState + { STATE_STARTED = 0, STATE_DOWNLOADING, STATE_CANCELING, @@ -76,8 +80,8 @@ public: }; private: - - struct DownloadInfo { + struct DownloadInfo + { ~DownloadInfo() { delete m_FileInfo; } accumulator_set<qint64, stats<tag::rolling_mean>> m_DownloadAcc; accumulator_set<qint64, stats<tag::rolling_mean>> m_DownloadTimeAcc; @@ -86,7 +90,7 @@ private: unsigned int m_DownloadID; QString m_FileName; QFile m_Output; - QNetworkReply *m_Reply; + QNetworkReply* m_Reply; QElapsedTimer m_StartTime; qint64 m_PreResumeSize; std::pair<int, QString> m_Progress; @@ -96,7 +100,8 @@ private: QStringList m_Urls; qint64 m_ResumePos; qint64 m_TotalSize; - QDateTime m_Created; // used as a cache in DownloadManager::getFileTime, may not be valid elsewhere + QDateTime m_Created; // used as a cache in DownloadManager::getFileTime, may not be + // valid elsewhere QByteArray m_Hash; QStringList m_GamesToQuery; QString m_RemoteFileName; @@ -106,22 +111,23 @@ private: quint32 m_TaskProgressId; - MOBase::ModRepositoryFileInfo *m_FileInfo { nullptr }; + MOBase::ModRepositoryFileInfo* m_FileInfo{nullptr}; bool m_Hidden; - static DownloadInfo *createNew(const MOBase::ModRepositoryFileInfo *fileInfo, const QStringList &URLs); - static DownloadInfo *createFromMeta( - const QString &filePath, bool showHidden, const QString outputDirectory, - std::optional<uint64_t> fileSize={}); + static DownloadInfo* createNew(const MOBase::ModRepositoryFileInfo* fileInfo, + const QStringList& URLs); + static DownloadInfo* createFromMeta(const QString& filePath, bool showHidden, + const QString outputDirectory, + std::optional<uint64_t> fileSize = {}); /** * @brief rename the file * this will change the file name as well as the display name. It will automatically * append .unfinished to the name if this file is still being downloaded * @param newName the new name to setName - * @param renameFile if true, the file is assumed to exist and renamed. If the file does not - * yet exist, set this to false + * @param renameFile if true, the file is assumed to exist and renamed. If the file + *does not yet exist, set this to false **/ void setName(QString newName, bool renameFile); @@ -130,13 +136,17 @@ private: bool isPausedState(); QString currentURL(); + private: static unsigned int s_NextDownloadID; + private: - DownloadInfo() : m_TotalSize(0), m_ReQueried(false), m_Hidden(false), m_HasData(false), - m_DownloadTimeLast(0), m_DownloadLast(0), - m_DownloadAcc(tag::rolling_window::window_size = 200), - m_DownloadTimeAcc(tag::rolling_window::window_size = 200) {} + DownloadInfo() + : m_TotalSize(0), m_ReQueried(false), m_Hidden(false), m_HasData(false), + m_DownloadTimeLast(0), m_DownloadLast(0), + m_DownloadAcc(tag::rolling_window::window_size = 200), + m_DownloadTimeAcc(tag::rolling_window::window_size = 200) + {} }; friend class DownloadManagerProxy; @@ -144,14 +154,14 @@ private: using SignalDownloadCallback = boost::signals2::signal<void(int)>; public: - /** * @brief constructor * - * @param nexusInterface interface to use to retrieve information from the relevant nexus page + * @param nexusInterface interface to use to retrieve information from the relevant + *nexus page * @param parent parent object **/ - explicit DownloadManager(NexusInterface *nexusInterface, QObject *parent); + explicit DownloadManager(NexusInterface* nexusInterface, QObject* parent); ~DownloadManager(); @@ -165,10 +175,12 @@ public: bool downloadsInProgress(); /** - * @brief determine if a download is currently in progress, does not count paused ones. - * - * @return true if there is currently a download in progress (that is not paused already). - **/ + * @brief determine if a download is currently in progress, does not count paused + *ones. + * + * @return true if there is currently a download in progress (that is not paused + *already). + **/ bool downloadsInProgressNoPause(); /** @@ -176,17 +188,19 @@ public: * * @param outputDirectory the new output directory **/ - void setOutputDirectory(const QString &outputDirectory, const bool refresh = true); + void setOutputDirectory(const QString& outputDirectory, const bool refresh = true); /** - * @brief disables feedback from the downlods fileSystemWhatcher untill disableDownloadsWatcherEnd() is called - * - **/ + * @brief disables feedback from the downlods fileSystemWhatcher untill + *disableDownloadsWatcherEnd() is called + * + **/ static void startDisableDirWatcher(); /** - * @brief re-enables feedback from the downlods fileSystemWhatcher after disableDownloadsWatcherStart() was called - **/ + * @brief re-enables feedback from the downlods fileSystemWhatcher after + *disableDownloadsWatcherStart() was called + **/ static void endDisableDirWatcher(); /** @@ -199,26 +213,32 @@ public: */ void setShowHidden(bool showHidden); - void setPluginContainer(PluginContainer *pluginContainer); + void setPluginContainer(PluginContainer* pluginContainer); /** * @brief download from an already open network connection * * @param reply the network reply to download from * @param fileInfo information about the file, like mod id, file id, version, ... - * @return true if the download was started, false if it wasn't. The latter currently only happens if there is a duplicate and the user decides not to download again + * @return true if the download was started, false if it wasn't. The latter currently + *only happens if there is a duplicate and the user decides not to download again **/ - bool addDownload(QNetworkReply *reply, const MOBase::ModRepositoryFileInfo *fileInfo); + bool addDownload(QNetworkReply* reply, const MOBase::ModRepositoryFileInfo* fileInfo); /** * @brief download from an already open network connection * * @param reply the network reply to download from - * @param fileName the name to use for the file. This may be overridden by the name in the fileInfo-structure or if the http stream specifies a name + * @param fileName the name to use for the file. This may be overridden by the name in + *the fileInfo-structure or if the http stream specifies a name * @param fileInfo information previously retrieved from the nexus network - * @return true if the download was started, false if it wasn't. The latter currently only happens if there is a duplicate and the user decides not to download again + * @return true if the download was started, false if it wasn't. The latter currently + *only happens if there is a duplicate and the user decides not to download again **/ - bool addDownload(QNetworkReply *reply, const QStringList &URLs, const QString &fileName, QString gameName, int modID, int fileID = 0, const MOBase::ModRepositoryFileInfo *fileInfo = new MOBase::ModRepositoryFileInfo()); + bool addDownload(QNetworkReply* reply, const QStringList& URLs, + const QString& fileName, QString gameName, int modID, int fileID = 0, + const MOBase::ModRepositoryFileInfo* fileInfo = + new MOBase::ModRepositoryFileInfo()); /** * @brief start a download using a nxm-link @@ -226,26 +246,30 @@ public: * starts a download using a nxm-link. The download manager will first query the nexus * page for file information. * @param url a nxm link looking like this: nxm://skyrim/mods/1234/files/4711 - * @todo the game name encoded into the link is currently ignored, all downloads are incorrectly assumed to be for the identified game + * @todo the game name encoded into the link is currently ignored, all downloads are + *incorrectly assumed to be for the identified game **/ - void addNXMDownload(const QString &url); + void addNXMDownload(const QString& url); /** - * @brief retrieve the total number of downloads, both finished and unfinished including downloads from previous sessions + * @brief retrieve the total number of downloads, both finished and unfinished + *including downloads from previous sessions * * @return total number of downloads **/ int numTotalDownloads() const; /** - * @brief retrieve number of pending downloads (nexus downloads for which we don't know the name and url yet) + * @brief retrieve number of pending downloads (nexus downloads for which we don't + * know the name and url yet) * @return number of pending downloads */ int numPendingDownloads() const; /** * @brief retrieve the info of a pending download - * @param index index of the pending download (index in the range [0, numPendingDownloads()[) + * @param index index of the pending download (index in the range [0, + * numPendingDownloads()[) * @return pair of modid, fileid */ std::tuple<QString, int, int> getPendingDownload(int index); @@ -353,7 +377,7 @@ public: * @param index index of the file to look up * @return the nexus mod information **/ - const MOBase::ModRepositoryFileInfo *getFileInfo(int index) const; + const MOBase::ModRepositoryFileInfo* getFileInfo(int index) const; /** * @brief mark a download as installed @@ -378,23 +402,26 @@ public: */ void refreshList(); -public: // IDownloadManager interface: - - int startDownloadURLs(const QStringList &urls); +public: // IDownloadManager interface: + int startDownloadURLs(const QStringList& urls); int startDownloadNexusFile(int modID, int fileID); QString downloadPath(int id); - boost::signals2::connection onDownloadComplete(const std::function<void(int)>& callback); - boost::signals2::connection onDownloadPaused(const std::function<void(int)>& callback); - boost::signals2::connection onDownloadFailed(const std::function<void(int)>& callback); - boost::signals2::connection onDownloadRemoved(const std::function<void(int)>& callback); + boost::signals2::connection + onDownloadComplete(const std::function<void(int)>& callback); + boost::signals2::connection + onDownloadPaused(const std::function<void(int)>& callback); + boost::signals2::connection + onDownloadFailed(const std::function<void(int)>& callback); + boost::signals2::connection + onDownloadRemoved(const std::function<void(int)>& callback); /** * @brief retrieve a download index from the filename * @param fileName file to look up * @return index of that download or -1 if it wasn't found */ - int indexByName(const QString &fileName) const; + int indexByName(const QString& fileName) const; int indexByInfo(const DownloadInfo* info) const; void pauseAll(); @@ -415,7 +442,7 @@ Q_SIGNALS: * * @param message the message to display **/ - void showMessage(const QString &message); + void showMessage(const QString& message); /** * @brief emitted whenever the state of a download changes @@ -425,9 +452,10 @@ Q_SIGNALS: void stateChanged(int row, DownloadManager::DownloadState state); /** - * @brief emitted whenever a download completes successfully, reporting the download speed for the server used + * @brief emitted whenever a download completes successfully, reporting the download + * speed for the server used */ - void downloadSpeed(const QString &serverName, int bytesPerSecond); + void downloadSpeed(const QString& serverName, int bytesPerSecond); /** * @brief emitted whenever a new download is added to the list @@ -440,7 +468,8 @@ public slots: * @brief removes the specified download * * @param index index of the download to remove - * @param deleteFile if true, the file will also be deleted from disc, otherwise it is only marked as hidden. + * @param deleteFile if true, the file will also be deleted from disc, otherwise it is + *only marked as hidden. **/ void removeDownload(int index, bool deleteFile); @@ -451,7 +480,8 @@ public slots: void restoreDownload(int index); /** - * @brief cancel the specified download. This will lead to the corresponding file to be deleted + * @brief cancel the specified download. This will lead to the corresponding file to + *be deleted * * @param index index of the download to cancel **/ @@ -473,19 +503,25 @@ public slots: void openInDownloadsFolder(int index); - void nxmDescriptionAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID); + void nxmDescriptionAvailable(QString gameName, int modID, QVariant userData, + QVariant resultData, int requestID); - void nxmFilesAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID); + void nxmFilesAvailable(QString gameName, int modID, QVariant userData, + QVariant resultData, int requestID); - void nxmFileInfoAvailable(QString gameName, int modID, int fileID, QVariant userData, QVariant resultData, int requestID); + void nxmFileInfoAvailable(QString gameName, int modID, int fileID, QVariant userData, + QVariant resultData, int requestID); - void nxmDownloadURLsAvailable(QString gameName, int modID, int fileID, QVariant userData, QVariant resultData, int requestID); + void nxmDownloadURLsAvailable(QString gameName, int modID, int fileID, + QVariant userData, QVariant resultData, int requestID); - void nxmFileInfoFromMd5Available(QString gameName, QVariant userData, QVariant resultData, int requestID); + void nxmFileInfoFromMd5Available(QString gameName, QVariant userData, + QVariant resultData, int requestID); - void nxmRequestFailed(QString gameName, int modID, int fileID, QVariant userData, int requestID, int errorCode, const QString &errorString); + void nxmRequestFailed(QString gameName, int modID, int fileID, QVariant userData, + int requestID, int errorCode, const QString& errorString); - void managedGameChanged(MOBase::IPluginGame const *gamePlugin); + void managedGameChanged(MOBase::IPluginGame const* gamePlugin); private slots: @@ -494,16 +530,14 @@ private slots: void downloadFinished(int index = 0); void downloadError(QNetworkReply::NetworkError error); void metaDataChanged(); - void directoryChanged(const QString &dirctory); + void directoryChanged(const QString& dirctory); void checkDownloadTimeout(); private: - - void createMetaFile(DownloadInfo *info); + void createMetaFile(DownloadInfo* info); DownloadManager::DownloadInfo* getDownloadInfo(QString fileName); public: - /** Get a unique filename for a download. * * This allows you multiple versions of download files, useful if the file @@ -513,11 +547,10 @@ public: * * @return Unique(ish) name */ - QString getDownloadFileName(const QString &baseName, bool rename = false) const; + QString getDownloadFileName(const QString& baseName, bool rename = false) const; private: - - void startDownload(QNetworkReply *reply, DownloadInfo *newDownload, bool resume); + void startDownload(QNetworkReply* reply, DownloadInfo* newDownload, bool resume); void resumeDownloadInt(int index); /** @@ -525,12 +558,15 @@ private: * * @param url the url to download from * @param fileInfo information previously retrieved from the mod page - * @return true if the download was started, false if it wasn't. The latter currently only happens if there is a duplicate and the user decides not to download again + * @return true if the download was started, false if it wasn't. The latter currently + *only happens if there is a duplicate and the user decides not to download again **/ - bool addDownload(const QStringList &URLs, QString gameName, int modID, int fileID, const MOBase::ModRepositoryFileInfo *fileInfo); + bool addDownload(const QStringList& URLs, QString gameName, int modID, int fileID, + const MOBase::ModRepositoryFileInfo* fileInfo); - // important: the caller has to lock the list-mutex, otherwise the DownloadInfo-pointer might get invalidated at any time - DownloadInfo *findDownload(QObject *reply, int *index = nullptr) const; + // important: the caller has to lock the list-mutex, otherwise the + // DownloadInfo-pointer might get invalidated at any time + DownloadInfo* findDownload(QObject* reply, int* index = nullptr) const; void removeFile(int index, bool deleteFile); @@ -538,27 +574,25 @@ private: bool ByName(int LHS, int RHS); - QString getFileNameFromNetworkReply(QNetworkReply *reply); + QString getFileNameFromNetworkReply(QNetworkReply* reply); - void setState(DownloadInfo *info, DownloadManager::DownloadState state); + void setState(DownloadInfo* info, DownloadManager::DownloadState state); - DownloadInfo *downloadInfoByID(unsigned int id); + DownloadInfo* downloadInfoByID(unsigned int id); void removePending(QString gameName, int modID, int fileID); static QString getFileTypeString(int fileType); - void writeData(DownloadInfo *info); + void writeData(DownloadInfo* info); private: - static const int AUTOMATIC_RETRIES = 3; private: + NexusInterface* m_NexusInterface; - NexusInterface *m_NexusInterface; - - OrganizerCore *m_OrganizerCore; + OrganizerCore* m_OrganizerCore; QWidget* m_ParentWidget; QVector<std::tuple<QString, int, int>> m_PendingDownloads; @@ -576,21 +610,20 @@ private: SignalDownloadCallback m_DownloadFailed; SignalDownloadCallback m_DownloadRemoved; - //The dirWatcher is actually triggering off normal Mo operations such as deleting downloads or editing .meta files - //so it needs to be disabled during operations that are known to cause the creation or deletion of files in the Downloads folder. - //Notably using QSettings to edit a file creates a temporarily .lock file that causes the Watcher to trigger multiple listRefreshes freezing the ui. + // The dirWatcher is actually triggering off normal Mo operations such as deleting + // downloads or editing .meta files so it needs to be disabled during operations that + // are known to cause the creation or deletion of files in the Downloads folder. + // Notably using QSettings to edit a file creates a temporarily .lock file that causes + // the Watcher to trigger multiple listRefreshes freezing the ui. static int m_DirWatcherDisabler; - std::map<QString, int> m_DownloadFails; bool m_ShowHidden; - MOBase::IPluginGame const *m_ManagedGame; + MOBase::IPluginGame const* m_ManagedGame; QTimer m_TimeoutTimer; }; - - -#endif // DOWNLOADMANAGER_H +#endif // DOWNLOADMANAGER_H diff --git a/src/downloadmanagerproxy.cpp b/src/downloadmanagerproxy.cpp index 95099044..ab4ed83b 100644 --- a/src/downloadmanagerproxy.cpp +++ b/src/downloadmanagerproxy.cpp @@ -1,13 +1,15 @@ #include "downloadmanagerproxy.h" -#include "proxyutils.h" #include "organizerproxy.h" +#include "proxyutils.h" using namespace MOBase; using namespace MOShared; -DownloadManagerProxy::DownloadManagerProxy(OrganizerProxy* oproxy, DownloadManager* downloadManager) : - m_OrganizerProxy(oproxy), m_Proxied(downloadManager) { } +DownloadManagerProxy::DownloadManagerProxy(OrganizerProxy* oproxy, + DownloadManager* downloadManager) + : m_OrganizerProxy(oproxy), m_Proxied(downloadManager) +{} DownloadManagerProxy::~DownloadManagerProxy() { @@ -16,10 +18,14 @@ DownloadManagerProxy::~DownloadManagerProxy() void DownloadManagerProxy::connectSignals() { - m_Connections.push_back(m_Proxied->onDownloadComplete(callSignalIfPluginActive(m_OrganizerProxy, m_DownloadComplete))); - m_Connections.push_back(m_Proxied->onDownloadFailed(callSignalIfPluginActive(m_OrganizerProxy, m_DownloadFailed))); - m_Connections.push_back(m_Proxied->onDownloadRemoved(callSignalIfPluginActive(m_OrganizerProxy, m_DownloadRemoved))); - m_Connections.push_back(m_Proxied->onDownloadPaused(callSignalIfPluginActive(m_OrganizerProxy, m_DownloadPaused))); + m_Connections.push_back(m_Proxied->onDownloadComplete( + callSignalIfPluginActive(m_OrganizerProxy, m_DownloadComplete))); + m_Connections.push_back(m_Proxied->onDownloadFailed( + callSignalIfPluginActive(m_OrganizerProxy, m_DownloadFailed))); + m_Connections.push_back(m_Proxied->onDownloadRemoved( + callSignalIfPluginActive(m_OrganizerProxy, m_DownloadRemoved))); + m_Connections.push_back(m_Proxied->onDownloadPaused( + callSignalIfPluginActive(m_OrganizerProxy, m_DownloadPaused))); } void DownloadManagerProxy::disconnectSignals() diff --git a/src/downloadmanagerproxy.h b/src/downloadmanagerproxy.h index 729fde91..dde4efe1 100644 --- a/src/downloadmanagerproxy.h +++ b/src/downloadmanagerproxy.h @@ -1,8 +1,8 @@ #ifndef DOWNLOADMANAGERPROXY_H #define DOWNLOADMANAGERPROXY_H -#include <idownloadmanager.h> #include "downloadmanager.h" +#include <idownloadmanager.h> class OrganizerProxy; @@ -10,7 +10,6 @@ class DownloadManagerProxy : public MOBase::IDownloadManager { public: - DownloadManagerProxy(OrganizerProxy* oproxy, DownloadManager* downloadManager); virtual ~DownloadManagerProxy(); @@ -24,7 +23,6 @@ public: bool onDownloadRemoved(const std::function<void(int)>& callback) override; private: - friend class OrganizerProxy; // See OrganizerProxy::connectSignals(). @@ -42,4 +40,4 @@ private: std::vector<boost::signals2::connection> m_Connections; }; -#endif // ORGANIZERPROXY_H +#endif // ORGANIZERPROXY_H diff --git a/src/downloadstab.cpp b/src/downloadstab.cpp index 8a6573bd..bf3ea9ad 100644 --- a/src/downloadstab.cpp +++ b/src/downloadstab.cpp @@ -5,16 +5,15 @@ #include "ui_mainwindow.h" DownloadsTab::DownloadsTab(OrganizerCore& core, Ui::MainWindow* mwui) - : m_core(core), ui{ - mwui->btnRefreshDownloads, mwui->downloadView, mwui->showHiddenBox, - mwui->downloadFilterEdit} + : m_core(core), ui{mwui->btnRefreshDownloads, mwui->downloadView, + mwui->showHiddenBox, mwui->downloadFilterEdit} { - DownloadList *sourceModel = new DownloadList(m_core, ui.list); + DownloadList* sourceModel = new DownloadList(m_core, ui.list); ui.list->setModel(sourceModel); ui.list->setManager(m_core.downloadManager()); - ui.list->setItemDelegate(new DownloadProgressDelegate( - m_core.downloadManager(), ui.list)); + ui.list->setItemDelegate( + new DownloadProgressDelegate(m_core.downloadManager(), ui.list)); update(); @@ -24,19 +23,33 @@ DownloadsTab::DownloadsTab(OrganizerCore& core, Ui::MainWindow* mwui) return sourceModel->lessThanPredicate(left, right); }); - connect(ui.refresh, &QPushButton::clicked, [&]{ refresh(); }); + connect(ui.refresh, &QPushButton::clicked, [&] { + refresh(); + }); connect(ui.list, SIGNAL(installDownload(int)), &m_core, SLOT(installDownload(int))); - connect(ui.list, SIGNAL(queryInfo(int)), m_core.downloadManager(), SLOT(queryInfo(int))); - connect(ui.list, SIGNAL(queryInfoMd5(int)), m_core.downloadManager(), SLOT(queryInfoMd5(int))); - connect(ui.list, SIGNAL(visitOnNexus(int)), m_core.downloadManager(), SLOT(visitOnNexus(int))); - connect(ui.list, SIGNAL(openFile(int)), m_core.downloadManager(), SLOT(openFile(int))); - connect(ui.list, SIGNAL(openMetaFile(int)), m_core.downloadManager(), SLOT(openMetaFile(int))); - connect(ui.list, SIGNAL(openInDownloadsFolder(int)), m_core.downloadManager(), SLOT(openInDownloadsFolder(int))); - connect(ui.list, SIGNAL(removeDownload(int, bool)), m_core.downloadManager(), SLOT(removeDownload(int, bool))); - connect(ui.list, SIGNAL(restoreDownload(int)), m_core.downloadManager(), SLOT(restoreDownload(int))); - connect(ui.list, SIGNAL(cancelDownload(int)), m_core.downloadManager(), SLOT(cancelDownload(int))); - connect(ui.list, SIGNAL(pauseDownload(int)), m_core.downloadManager(), SLOT(pauseDownload(int))); - connect(ui.list, &DownloadListView::resumeDownload, [&](int i){ resumeDownload(i); }); + connect(ui.list, SIGNAL(queryInfo(int)), m_core.downloadManager(), + SLOT(queryInfo(int))); + connect(ui.list, SIGNAL(queryInfoMd5(int)), m_core.downloadManager(), + SLOT(queryInfoMd5(int))); + connect(ui.list, SIGNAL(visitOnNexus(int)), m_core.downloadManager(), + SLOT(visitOnNexus(int))); + connect(ui.list, SIGNAL(openFile(int)), m_core.downloadManager(), + SLOT(openFile(int))); + connect(ui.list, SIGNAL(openMetaFile(int)), m_core.downloadManager(), + SLOT(openMetaFile(int))); + connect(ui.list, SIGNAL(openInDownloadsFolder(int)), m_core.downloadManager(), + SLOT(openInDownloadsFolder(int))); + connect(ui.list, SIGNAL(removeDownload(int, bool)), m_core.downloadManager(), + SLOT(removeDownload(int, bool))); + connect(ui.list, SIGNAL(restoreDownload(int)), m_core.downloadManager(), + SLOT(restoreDownload(int))); + connect(ui.list, SIGNAL(cancelDownload(int)), m_core.downloadManager(), + SLOT(cancelDownload(int))); + connect(ui.list, SIGNAL(pauseDownload(int)), m_core.downloadManager(), + SLOT(pauseDownload(int))); + connect(ui.list, &DownloadListView::resumeDownload, [&](int i) { + resumeDownload(i); + }); } void DownloadsTab::update() diff --git a/src/downloadstab.h b/src/downloadstab.h index f39f4ba5..f0b85d91 100644 --- a/src/downloadstab.h +++ b/src/downloadstab.h @@ -3,7 +3,10 @@ #include <filterwidget.h> -namespace Ui { class MainWindow; } +namespace Ui +{ +class MainWindow; +} class OrganizerCore; class DownloadListView; @@ -33,4 +36,4 @@ private: void resumeDownload(int downloadIndex); }; -#endif // MODORGANIZER_DOWNLOADTAB_INCLUDED +#endif // MODORGANIZER_DOWNLOADTAB_INCLUDED diff --git a/src/editexecutablesdialog.cpp b/src/editexecutablesdialog.cpp index ea7d20de..8a01b9f0 100644 --- a/src/editexecutablesdialog.cpp +++ b/src/editexecutablesdialog.cpp @@ -18,17 +18,17 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ #include "editexecutablesdialog.h" -#include "ui_editexecutablesdialog.h" #include "filedialogmemory.h" -#include "modlist.h" #include "forcedloaddialog.h" +#include "modlist.h" #include "organizercore.h" #include "spawn.h" +#include "ui_editexecutablesdialog.h" #include <QMessageBox> #include <Shellapi.h> -#include <utility.h> #include <algorithm> +#include <utility.h> using namespace MOBase; using namespace MOShared; @@ -36,32 +36,25 @@ using namespace MOShared; class IgnoreChanges { public: - IgnoreChanges(EditExecutablesDialog* d) - : m_dialog(d) + IgnoreChanges(EditExecutablesDialog* d) : m_dialog(d) { m_dialog->m_settingUI = true; } - ~IgnoreChanges() - { - m_dialog->m_settingUI = false; - } + ~IgnoreChanges() { m_dialog->m_settingUI = false; } - IgnoreChanges(const IgnoreChanges&) = delete; + IgnoreChanges(const IgnoreChanges&) = delete; IgnoreChanges& operator=(const IgnoreChanges&) = delete; private: EditExecutablesDialog* m_dialog; }; - -EditExecutablesDialog::EditExecutablesDialog(OrganizerCore& oc, int sel, QWidget* parent) - : TutorableDialog("EditExecutables", parent) - , ui(new Ui::EditExecutablesDialog) - , m_organizerCore(oc) - , m_originalExecutables(*oc.executablesList()) - , m_executablesList(*oc.executablesList()) - , m_settingUI(false) +EditExecutablesDialog::EditExecutablesDialog(OrganizerCore& oc, int sel, + QWidget* parent) + : TutorableDialog("EditExecutables", parent), ui(new Ui::EditExecutablesDialog), + m_organizerCore(oc), m_originalExecutables(*oc.executablesList()), + m_executablesList(*oc.executablesList()), m_settingUI(false) { ui->setupUi(this); ui->splitter->setSizes({200, 1}); @@ -71,15 +64,12 @@ EditExecutablesDialog::EditExecutablesDialog(OrganizerCore& oc, int sel, QWidget loadCustomOverwrites(); loadForcedLibraries(); - QStringList modNames; for (auto&& m : m_organizerCore.modList()->allMods()) { auto mod = ModInfo::getByName(m); - if (!mod->hasAnyOfTheseFlags({ ModInfo::FLAG_FOREIGN, - ModInfo::FLAG_BACKUP, - ModInfo::FLAG_OVERWRITE, - ModInfo::FLAG_SEPARATOR })) { + if (!mod->hasAnyOfTheseFlags({ModInfo::FLAG_FOREIGN, ModInfo::FLAG_BACKUP, + ModInfo::FLAG_OVERWRITE, ModInfo::FLAG_SEPARATOR})) { ui->mods->addItem(m); modNames.push_back(m); } @@ -90,7 +80,6 @@ EditExecutablesDialog::EditExecutablesDialog(OrganizerCore& oc, int sel, QWidget c->setCompletionMode(QCompleter::UnfilteredPopupCompletion); ui->mods->setCompleter(c); - fillList(); setDirty(false); @@ -99,20 +88,42 @@ EditExecutablesDialog::EditExecutablesDialog(OrganizerCore& oc, int sel, QWidget } auto* m = new QMenu; - m->addAction(tr("Add from file..."), [&]{ addFromFile(); }); - m->addAction(tr("Add empty"), [&]{ addEmpty(); }); - m->addAction(tr("Clone selected"), [&]{ clone(); }); + m->addAction(tr("Add from file..."), [&] { + addFromFile(); + }); + m->addAction(tr("Add empty"), [&] { + addEmpty(); + }); + m->addAction(tr("Clone selected"), [&] { + clone(); + }); ui->add->setMenu(m); // some widgets need to do more than just save() and have their own handler - connect(ui->binary, &QLineEdit::textChanged, [&]{ save(); }); - connect(ui->workingDirectory, &QLineEdit::textChanged, [&]{ save(); }); - connect(ui->arguments, &QLineEdit::textChanged, [&]{ save(); }); - connect(ui->steamAppID, &QLineEdit::textChanged, [&]{ save(); }); - connect(ui->mods, &QComboBox::currentTextChanged, [&]{ save(); }); - connect(ui->useApplicationIcon, &QCheckBox::toggled, [&]{ save(); }); - connect(ui->hide, &QCheckBox::toggled, [&]{ save(); }); - connect(ui->list->model(), &QAbstractItemModel::rowsMoved, [&]{ saveOrder(); }); + connect(ui->binary, &QLineEdit::textChanged, [&] { + save(); + }); + connect(ui->workingDirectory, &QLineEdit::textChanged, [&] { + save(); + }); + connect(ui->arguments, &QLineEdit::textChanged, [&] { + save(); + }); + connect(ui->steamAppID, &QLineEdit::textChanged, [&] { + save(); + }); + connect(ui->mods, &QComboBox::currentTextChanged, [&] { + save(); + }); + connect(ui->useApplicationIcon, &QCheckBox::toggled, [&] { + save(); + }); + connect(ui->hide, &QCheckBox::toggled, [&] { + save(); + }); + connect(ui->list->model(), &QAbstractItemModel::rowsMoved, [&] { + saveOrder(); + }); } EditExecutablesDialog::~EditExecutablesDialog() = default; @@ -141,10 +152,8 @@ void EditExecutablesDialog::loadForcedLibraries() const auto* p = m_organizerCore.currentProfile(); for (const auto& e : m_executablesList) { - m_forcedLibraries.set( - e.title(), - p->forcedLibrariesEnabled(e.title()), - p->determineForcedLibraries(e.title())); + m_forcedLibraries.set(e.title(), p->forcedLibrariesEnabled(e.title()), + p->determineForcedLibraries(e.title())); } } @@ -199,16 +208,15 @@ bool EditExecutablesDialog::checkOutputMods(const ExecutablesList& exes) if (modName && modName->enabled) { if (modName->value.isEmpty()) { - QMessageBox::critical( - this, tr("Empty output mod"), - tr("The output mod for %2 is empty.").arg(e.title())); + QMessageBox::critical(this, tr("Empty output mod"), + tr("The output mod for %2 is empty.").arg(e.title())); return false; } else if (ModInfo::getIndex(modName->value) == UINT_MAX) { - QMessageBox::critical( - this, tr("Output mod not found"), - tr("The output mod '%1' for %2 does not exist.") - .arg(modName->value).arg(e.title())); + QMessageBox::critical(this, tr("Output mod not found"), + tr("The output mod '%1' for %2 does not exist.") + .arg(modName->value) + .arg(e.title())); return false; } @@ -236,13 +244,13 @@ bool EditExecutablesDialog::commitChanges() // set the new custom overwrites and forced libraries for (const auto& e : newExecutables) { - if (auto modName=m_customOverwrites.find(e.title())) { + if (auto modName = m_customOverwrites.find(e.title())) { if (modName && modName->enabled) { profile->storeSetting("custom_overwrites", e.title(), modName->value); } } - if (auto libraryList=m_forcedLibraries.find(e.title())) { + if (auto libraryList = m_forcedLibraries.find(e.title())) { if (libraryList && !libraryList->value.empty()) { profile->setForcedLibrariesEnabled(e.title(), libraryList->enabled); profile->storeForcedLibraries(e.title(), libraryList->value); @@ -260,7 +268,7 @@ bool EditExecutablesDialog::commitChanges() void EditExecutablesDialog::setDirty(bool b) { - if (auto* button=ui->buttons->button(QDialogButtonBox::Apply)) { + if (auto* button = ui->buttons->button(QDialogButtonBox::Apply)) { button->setEnabled(b); } } @@ -268,8 +276,8 @@ void EditExecutablesDialog::setDirty(bool b) void EditExecutablesDialog::selectIndex(int i) { if (i >= 0 && i < ui->list->count()) { - ui->list->selectionModel()->setCurrentIndex( - ui->list->model()->index(i, 0), QItemSelectionModel::ClearAndSelect); + ui->list->selectionModel()->setCurrentIndex(ui->list->model()->index(i, 0), + QItemSelectionModel::ClearAndSelect); } } @@ -292,7 +300,7 @@ Executable* EditExecutablesDialog::selectedExe() } const auto& title = item->text(); - auto itor = m_executablesList.find(title); + auto itor = m_executablesList.find(title); if (itor == m_executablesList.end()) { return nullptr; @@ -305,7 +313,7 @@ void EditExecutablesDialog::fillList() { ui->list->clear(); - for(const auto& exe : m_executablesList) { + for (const auto& exe : m_executablesList) { ui->list->addItem(createListItem(exe)); } @@ -322,8 +330,7 @@ QListWidgetItem* EditExecutablesDialog::createListItem(const Executable& exe) return new QListWidgetItem(exe.title()); } -void EditExecutablesDialog::updateUI( - const QListWidgetItem* item, const Executable* e) +void EditExecutablesDialog::updateUI(const QListWidgetItem* item, const Executable* e) { // the ui is currently being set, ignore changes IgnoreChanges c(this); @@ -337,8 +344,7 @@ void EditExecutablesDialog::updateUI( setButtons(item, e); } -void EditExecutablesDialog::setButtons( - const QListWidgetItem* item, const Executable* e) +void EditExecutablesDialog::setButtons(const QListWidgetItem* item, const Executable* e) { // add and remove are always enabled @@ -405,10 +411,9 @@ void EditExecutablesDialog::setEdits(const Executable& e) modIndex = ui->mods->findText(modName->value); if (modIndex == -1) { - log::warn( - "executable '{}' uses mod '{}' as a custom overwrite, but that mod " - "doesn't exist", - e.title(), modName->value); + log::warn("executable '{}' uses mod '{}' as a custom overwrite, but that mod " + "doesn't exist", + e.title(), modName->value); } } @@ -420,7 +425,7 @@ void EditExecutablesDialog::setEdits(const Executable& e) } { - const auto libraryList = m_forcedLibraries.find(e.title()); + const auto libraryList = m_forcedLibraries.find(e.title()); const bool hasForcedLibraries = (libraryList && libraryList->enabled); ui->forceLoadLibraries->setChecked(hasForcedLibraries); @@ -557,10 +562,10 @@ void EditExecutablesDialog::on_reset_clicked() { const auto title = tr("Reset plugin executables"); - const auto text = tr( - "This will restore all the executables provided by the game plugin. If " - "there are existing executables with the same names, they will be " - "automatically renamed and left unchanged."); + const auto text = + tr("This will restore all the executables provided by the game plugin. If " + "there are existing executables with the same names, they will be " + "automatically renamed and left unchanged."); const auto buttons = QMessageBox::Ok | QMessageBox::Cancel; @@ -596,7 +601,6 @@ void EditExecutablesDialog::on_remove_clicked() const int currentRow = ui->list->row(item); delete item; - m_customOverwrites.remove(exe->title()); m_forcedLibraries.remove(exe->title()); @@ -604,7 +608,6 @@ void EditExecutablesDialog::on_remove_clicked() // exe pointer m_executablesList.remove(exe->title()); - // reselecting the same row as before, or the last one if (currentRow >= ui->list->count()) { // that was the last item, select the new list item, if any @@ -678,7 +681,7 @@ void EditExecutablesDialog::on_title_textChanged(const QString& original) // once the executable is saved, the list item must be changed to match the // new name - if (auto* i=selectedItem()) { + if (auto* i = selectedItem()) { i->setText(s); } } @@ -790,7 +793,7 @@ void EditExecutablesDialog::setBinary(const QFileInfo& binary) // setting title if some variation of "New Executable" if (ui->title->text().startsWith(tr("New Executable"), Qt::CaseInsensitive)) { - const auto prefix = binary.completeBaseName(); + const auto prefix = binary.completeBaseName(); const auto newTitle = m_executablesList.makeNonConflictingTitle(prefix); if (newTitle) { @@ -802,8 +805,8 @@ void EditExecutablesDialog::setBinary(const QFileInfo& binary) void EditExecutablesDialog::on_browseWorkingDirectory_clicked() { QString dirName = FileDialogMemory::getExistingDirectory( - "editExecutableDirectory", this, tr("Select a directory"), - ui->workingDirectory->text()); + "editExecutableDirectory", this, tr("Select a directory"), + ui->workingDirectory->text()); if (dirName.isNull()) { // cancelled @@ -823,7 +826,7 @@ void EditExecutablesDialog::on_configureLibraries_clicked() ForcedLoadDialog dialog(m_organizerCore.managedGame(), this); - if (auto libraryList=m_forcedLibraries.find(e->title())) { + if (auto libraryList = m_forcedLibraries.find(e->title())) { dialog.setValues(libraryList->value); } @@ -849,12 +852,10 @@ void EditExecutablesDialog::on_buttons_clicked(QAbstractButton* b) QFileInfo EditExecutablesDialog::browseBinary(const QString& initial) { const QString Filters = - tr("Executables (*.exe *.bat *.jar)") + ";;" + - tr("All Files (*.*)"); + tr("Executables (*.exe *.bat *.jar)") + ";;" + tr("All Files (*.*)"); const auto f = FileDialogMemory::getOpenFileName( - "editExecutableBinary", this, tr("Select an executable"), - initial, Filters); + "editExecutableBinary", this, tr("Select an executable"), initial, Filters); if (f.isNull()) { return {}; @@ -869,10 +870,10 @@ void EditExecutablesDialog::setJarBinary(const QFileInfo& binary) if (java.isEmpty()) { QMessageBox::information( - this, tr("Java required"), - tr("MO requires Java to run this application. If you already " - "have it installed, select javaw.exe from that installation as " - "the binary.")); + this, tr("Java required"), + tr("MO requires Java to run this application. If you already " + "have it installed, select javaw.exe from that installation as " + "the binary.")); } { @@ -881,7 +882,8 @@ void EditExecutablesDialog::setJarBinary(const QFileInfo& binary) ui->binary->setText(java); ui->workingDirectory->setText(QDir::toNativeSeparators(binary.absolutePath())); - ui->arguments->setText("-jar \"" + QDir::toNativeSeparators(binary.absoluteFilePath()) + "\""); + ui->arguments->setText("-jar \"" + + QDir::toNativeSeparators(binary.absoluteFilePath()) + "\""); } save(); diff --git a/src/editexecutablesdialog.h b/src/editexecutablesdialog.h index da30bf0b..1d0bd4a0 100644 --- a/src/editexecutablesdialog.h +++ b/src/editexecutablesdialog.h @@ -20,17 +20,18 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef EDITEXECUTABLESDIALOG_H #define EDITEXECUTABLESDIALOG_H -#include "tutorabledialog.h" -#include <QListWidgetItem> #include "executableslist.h" -#include "profile.h" #include "iplugingame.h" -#include <QTimer> +#include "profile.h" +#include "tutorabledialog.h" #include <QAbstractButton> +#include <QListWidgetItem> +#include <QTimer> #include <optional> -namespace Ui { - class EditExecutablesDialog; +namespace Ui +{ +class EditExecutablesDialog; } class ModList; @@ -48,10 +49,7 @@ public: bool enabled; T value; - Value(bool b, T&& v) - : enabled(b), value(std::forward<T>(v)) - { - } + Value(bool b, T&& v) : enabled(b), value(std::forward<T>(v)) {} }; /** @@ -135,21 +133,20 @@ private: std::map<QString, Value> m_map; }; - /** * @brief Dialog to manage the list of executables **/ class EditExecutablesDialog : public MOBase::TutorableDialog { - Q_OBJECT; - friend class IgnoreChanges; + Q_OBJECT; + friend class IgnoreChanges; public: using CustomOverwrites = ToggableMap<QString>; - using ForcedLibraries = ToggableMap<QList<MOBase::ExecutableForcedLoadSetting>>; + using ForcedLibraries = ToggableMap<QList<MOBase::ExecutableForcedLoadSetting>>; - explicit EditExecutablesDialog( - OrganizerCore& oc, int selection=-1, QWidget* parent=nullptr); + explicit EditExecutablesDialog(OrganizerCore& oc, int selection = -1, + QWidget* parent = nullptr); ~EditExecutablesDialog(); @@ -207,7 +204,6 @@ private: // the executable's data into the UI, not from a user change bool m_settingUI; - void loadCustomOverwrites(); void loadForcedLibraries(); @@ -240,4 +236,4 @@ private: void setJarBinary(const QFileInfo& binary); }; -#endif // EDITEXECUTABLESDIALOG_H +#endif // EDITEXECUTABLESDIALOG_H diff --git a/src/env.cpp b/src/env.cpp index 818ce8fb..9e67ef88 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -1,10 +1,10 @@ #include "env.h" +#include "envdump.h" #include "envmetrics.h" #include "envmodule.h" #include "envsecurity.h" #include "envshortcut.h" #include "envwindows.h" -#include "envdump.h" #include "settings.h" #include "shared/util.h" #include <log.h> @@ -15,8 +15,7 @@ namespace env using namespace MOBase; -Console::Console() - : m_hasConsole(false), m_in(nullptr), m_out(nullptr), m_err(nullptr) +Console::Console() : m_hasConsole(false), m_in(nullptr), m_out(nullptr), m_err(nullptr) { // try to attach to parent if (!AttachConsole(ATTACH_PARENT_PROCESS)) { @@ -63,11 +62,9 @@ Console::~Console() } } - -ModuleNotification::ModuleNotification(QObject* o, std::function<void (Module)> f) - : m_cookie(nullptr), m_object(o), m_f(std::move(f)) -{ -} +ModuleNotification::ModuleNotification(QObject* o, std::function<void(Module)> f) + : m_cookie(nullptr), m_object(o), m_f(std::move(f)) +{} ModuleNotification::~ModuleNotification() { @@ -75,9 +72,7 @@ ModuleNotification::~ModuleNotification() return; } - typedef NTSTATUS NTAPI LdrUnregisterDllNotificationType( - PVOID Cookie - ); + typedef NTSTATUS NTAPI LdrUnregisterDllNotificationType(PVOID Cookie); LibraryPtr ntdll(LoadLibraryW(L"ntdll.dll")); @@ -86,8 +81,9 @@ ModuleNotification::~ModuleNotification() return; } - auto* LdrUnregisterDllNotification = reinterpret_cast<LdrUnregisterDllNotificationType*>( - GetProcAddress(ntdll.get(), "LdrUnregisterDllNotification")); + auto* LdrUnregisterDllNotification = + reinterpret_cast<LdrUnregisterDllNotificationType*>( + GetProcAddress(ntdll.get(), "LdrUnregisterDllNotification")); if (!LdrUnregisterDllNotification) { log::error("LdrUnregisterDllNotification not found in ntdll.dll"); @@ -123,23 +119,23 @@ void ModuleNotification::fire(QString path, std::size_t fileSize) // so this queues the callback in the main thread if (m_f) { - QMetaObject::invokeMethod(m_object, [path, fileSize, f=m_f] { - f(Module(path, fileSize)); - }, Qt::QueuedConnection); + QMetaObject::invokeMethod( + m_object, + [path, fileSize, f = m_f] { + f(Module(path, fileSize)); + }, + Qt::QueuedConnection); } } - -Environment::Environment() -{ -} +Environment::Environment() {} // anchor Environment::~Environment() = default; const std::vector<Module>& Environment::loadedModules() const { - if (m_modules.empty()){ + if (m_modules.empty()) { m_modules = getLoadedModules(); } @@ -190,24 +186,19 @@ QString Environment::timezone() const } auto offsetString = [](int o) { - return - QString("%1%2:%3") - .arg(o < 0 ? "" : "+") - .arg(QString::number(o / 60), 2, QChar::fromLatin1('0')) - .arg(QString::number(o % 60), 2, QChar::fromLatin1('0')); + return QString("%1%2:%3") + .arg(o < 0 ? "" : "+") + .arg(QString::number(o / 60), 2, QChar::fromLatin1('0')) + .arg(QString::number(o % 60), 2, QChar::fromLatin1('0')); }; - const auto stdName = QString::fromWCharArray(tz.StandardName); + const auto stdName = QString::fromWCharArray(tz.StandardName); const auto stdOffset = -(tz.Bias + tz.StandardBias); - const auto std = QString("%1, %2") - .arg(stdName) - .arg(offsetString(stdOffset)); + const auto std = QString("%1, %2").arg(stdName).arg(offsetString(stdOffset)); - const auto dstName = QString::fromWCharArray(tz.DaylightName); + const auto dstName = QString::fromWCharArray(tz.DaylightName); const auto dstOffset = -(tz.Bias + tz.DaylightBias); - const auto dst = QString("%1, %2") - .arg(dstName) - .arg(offsetString(dstOffset)); + const auto dst = QString("%1, %2").arg(dstName).arg(offsetString(dstOffset)); QString s; @@ -220,57 +211,55 @@ QString Environment::timezone() const return s; } -std::unique_ptr<ModuleNotification> Environment::onModuleLoaded( - QObject* o, std::function<void (Module)> f) +std::unique_ptr<ModuleNotification> +Environment::onModuleLoaded(QObject* o, std::function<void(Module)> f) { - typedef struct _UNICODE_STRING { + typedef struct _UNICODE_STRING + { USHORT Length; USHORT MaximumLength; - PWSTR Buffer; + PWSTR Buffer; } UNICODE_STRING, *PUNICODE_STRING; typedef const PUNICODE_STRING PCUNICODE_STRING; - typedef struct _LDR_DLL_LOADED_NOTIFICATION_DATA { - ULONG Flags; //Reserved. - PCUNICODE_STRING FullDllName; //The full path name of the DLL module. - PCUNICODE_STRING BaseDllName; //The base file name of the DLL module. - PVOID DllBase; //A pointer to the base address for the DLL in memory. - ULONG SizeOfImage; //The size of the DLL image, in bytes. + typedef struct _LDR_DLL_LOADED_NOTIFICATION_DATA + { + ULONG Flags; // Reserved. + PCUNICODE_STRING FullDllName; // The full path name of the DLL module. + PCUNICODE_STRING BaseDllName; // The base file name of the DLL module. + PVOID DllBase; // A pointer to the base address for the DLL in memory. + ULONG SizeOfImage; // The size of the DLL image, in bytes. } LDR_DLL_LOADED_NOTIFICATION_DATA, *PLDR_DLL_LOADED_NOTIFICATION_DATA; - typedef struct _LDR_DLL_UNLOADED_NOTIFICATION_DATA { - ULONG Flags; //Reserved. - PCUNICODE_STRING FullDllName; //The full path name of the DLL module. - PCUNICODE_STRING BaseDllName; //The base file name of the DLL module. - PVOID DllBase; //A pointer to the base address for the DLL in memory. - ULONG SizeOfImage; //The size of the DLL image, in bytes. + typedef struct _LDR_DLL_UNLOADED_NOTIFICATION_DATA + { + ULONG Flags; // Reserved. + PCUNICODE_STRING FullDllName; // The full path name of the DLL module. + PCUNICODE_STRING BaseDllName; // The base file name of the DLL module. + PVOID DllBase; // A pointer to the base address for the DLL in memory. + ULONG SizeOfImage; // The size of the DLL image, in bytes. } LDR_DLL_UNLOADED_NOTIFICATION_DATA, *PLDR_DLL_UNLOADED_NOTIFICATION_DATA; - typedef union _LDR_DLL_NOTIFICATION_DATA { + typedef union _LDR_DLL_NOTIFICATION_DATA + { LDR_DLL_LOADED_NOTIFICATION_DATA Loaded; LDR_DLL_UNLOADED_NOTIFICATION_DATA Unloaded; } LDR_DLL_NOTIFICATION_DATA, *PLDR_DLL_NOTIFICATION_DATA; typedef VOID CALLBACK LDR_DLL_NOTIFICATION_FUNCTION( - ULONG NotificationReason, - const PLDR_DLL_NOTIFICATION_DATA NotificationData, - PVOID Context - ); + ULONG NotificationReason, const PLDR_DLL_NOTIFICATION_DATA NotificationData, + PVOID Context); typedef LDR_DLL_NOTIFICATION_FUNCTION* PLDR_DLL_NOTIFICATION_FUNCTION; typedef NTSTATUS NTAPI LdrRegisterDllNotificationType( - ULONG Flags, - PLDR_DLL_NOTIFICATION_FUNCTION NotificationFunction, - PVOID Context, - PVOID *Cookie - ); + ULONG Flags, PLDR_DLL_NOTIFICATION_FUNCTION NotificationFunction, PVOID Context, + PVOID * Cookie); - const ULONG LDR_DLL_NOTIFICATION_REASON_LOADED = 1; + const ULONG LDR_DLL_NOTIFICATION_REASON_LOADED = 1; const ULONG LDR_DLL_NOTIFICATION_REASON_UNLOADED = 2; - // loading ntdll.dll, the function will be found with GetProcAddress() LibraryPtr ntdll(LoadLibraryW(L"ntdll.dll")); @@ -280,33 +269,32 @@ std::unique_ptr<ModuleNotification> Environment::onModuleLoaded( } auto* LdrRegisterDllNotification = reinterpret_cast<LdrRegisterDllNotificationType*>( - GetProcAddress(ntdll.get(), "LdrRegisterDllNotification")); + GetProcAddress(ntdll.get(), "LdrRegisterDllNotification")); if (!LdrRegisterDllNotification) { log::error("LdrRegisterDllNotification not found in ntdll.dll"); return {}; } - auto context = std::make_unique<ModuleNotification>(o, f); void* cookie = nullptr; - auto OnDllLoaded = [](ULONG reason, const PLDR_DLL_NOTIFICATION_DATA data, void* context) { + auto OnDllLoaded = [](ULONG reason, const PLDR_DLL_NOTIFICATION_DATA data, + void* context) { if (reason == LDR_DLL_NOTIFICATION_REASON_LOADED) { if (data && data->Loaded.FullDllName) { if (context) { static_cast<ModuleNotification*>(context)->fire( - QString::fromWCharArray( - data->Loaded.FullDllName->Buffer, - data->Loaded.FullDllName->Length / sizeof(wchar_t)), - data->Loaded.SizeOfImage); + QString::fromWCharArray(data->Loaded.FullDllName->Buffer, + data->Loaded.FullDllName->Length / + sizeof(wchar_t)), + data->Loaded.SizeOfImage); } } } }; - const auto r = LdrRegisterDllNotification( - 0, OnDllLoaded, context.get(), &cookie); + const auto r = LdrRegisterDllNotification(0, OnDllLoaded, context.get(), &cookie); if (r != 0) { log::error("failed to register for module notifications, error {}", r); @@ -356,9 +344,8 @@ void Environment::dump(const Settings& s) const } const auto r = metrics().desktopGeometry(); - log::debug( - "desktop geometry: ({},{})-({},{})", - r.left(), r.top(), r.right(), r.bottom()); + log::debug("desktop geometry: ({},{})-({},{})", r.left(), r.top(), r.right(), + r.bottom()); dumpDisks(s); } @@ -379,11 +366,8 @@ void Environment::dumpDisks(const Settings& s) const // remember rootPaths.insert(si.rootPath()); - log::debug( - " . {} free={} MB{}", - si.rootPath(), - (si.bytesFree() / 1000 / 1000), - (si.isReadOnly() ? " (readonly)" : "")); + log::debug(" . {} free={} MB{}", si.rootPath(), (si.bytesFree() / 1000 / 1000), + (si.isReadOnly() ? " (readonly)" : "")); }; log::debug("drives:"); @@ -398,7 +382,6 @@ void Environment::dumpDisks(const Settings& s) const dump(QCoreApplication::applicationDirPath()); } - QString path() { return get("PATH"); @@ -426,19 +409,17 @@ void setPath(const QString& s) QString get(const QString& name) { std::size_t bufferSize = 4000; - auto buffer = std::make_unique<wchar_t[]>(bufferSize); + auto buffer = std::make_unique<wchar_t[]>(bufferSize); - DWORD realSize = ::GetEnvironmentVariableW( - name.toStdWString().c_str(), - buffer.get(), static_cast<DWORD>(bufferSize)); + DWORD realSize = ::GetEnvironmentVariableW(name.toStdWString().c_str(), buffer.get(), + static_cast<DWORD>(bufferSize)); if (realSize > bufferSize) { bufferSize = realSize; - buffer = std::make_unique<wchar_t[]>(bufferSize); + buffer = std::make_unique<wchar_t[]>(bufferSize); - realSize = ::GetEnvironmentVariableW( - name.toStdWString().c_str(), - buffer.get(), static_cast<DWORD>(bufferSize)); + realSize = ::GetEnvironmentVariableW(name.toStdWString().c_str(), buffer.get(), + static_cast<DWORD>(bufferSize)); } if (realSize == 0) { @@ -446,9 +427,8 @@ QString get(const QString& name) // don't log if not found if (e != ERROR_ENVVAR_NOT_FOUND) { - log::error( - "failed to get environment variable '{}', {}", - name, formatSystemMessage(e)); + log::error("failed to get environment variable '{}', {}", name, + formatSystemMessage(e)); } return {}; @@ -462,16 +442,12 @@ void set(const QString& n, const QString& v) ::SetEnvironmentVariableW(n.toStdWString().c_str(), v.toStdWString().c_str()); } - -Service::Service(QString name) - : Service(std::move(name), StartType::None, Status::None) -{ -} +Service::Service(QString name) : Service(std::move(name), StartType::None, Status::None) +{} Service::Service(QString name, StartType st, Status s) - : m_name(std::move(name)), m_startType(st), m_status(s) -{ -} + : m_name(std::move(name)), m_startType(st), m_status(s) +{} const QString& Service::name() const { @@ -496,29 +472,27 @@ Service::Status Service::status() const QString Service::toString() const { return QString("service '%1', start=%2, status=%3") - .arg(m_name) - .arg(env::toString(m_startType)) - .arg(env::toString(m_status)); + .arg(m_name) + .arg(env::toString(m_startType)) + .arg(env::toString(m_status)); } - QString toString(Service::StartType st) { using ST = Service::StartType; - switch (st) - { - case ST::None: - return "none"; + switch (st) { + case ST::None: + return "none"; - case ST::Disabled: - return "disabled"; + case ST::Disabled: + return "disabled"; - case ST::Enabled: - return "enabled"; + case ST::Enabled: + return "enabled"; - default: - return QString("unknown %1").arg(static_cast<int>(st)); + default: + return QString("unknown %1").arg(static_cast<int>(st)); } } @@ -526,19 +500,18 @@ QString toString(Service::Status st) { using S = Service::Status; - switch (st) - { - case S::None: - return "none"; + switch (st) { + case S::None: + return "none"; - case S::Stopped: - return "stopped"; + case S::Stopped: + return "stopped"; - case S::Running: - return "running"; + case S::Running: + return "running"; - default: - return QString("unknown %1").arg(static_cast<int>(st)); + default: + return QString("unknown %1").arg(static_cast<int>(st)); } } @@ -550,9 +523,8 @@ Service::StartType getServiceStartType(SC_HANDLE s, const QString& name) const auto e = GetLastError(); if (e != ERROR_INSUFFICIENT_BUFFER) { - log::error( - "QueryServiceConfig() for size for '{}' failed, {}", - name, GetLastError()); + log::error("QueryServiceConfig() for size for '{}' failed, {}", name, + GetLastError()); return Service::StartType::None; } @@ -560,41 +532,33 @@ Service::StartType getServiceStartType(SC_HANDLE s, const QString& name) const auto size = needed; MallocPtr<QUERY_SERVICE_CONFIG> config( - static_cast<QUERY_SERVICE_CONFIG*>(std::malloc(size))); + static_cast<QUERY_SERVICE_CONFIG*>(std::malloc(size))); if (!QueryServiceConfig(s, config.get(), size, &needed)) { const auto e = GetLastError(); - log::error( - "QueryServiceConfig() for '{}' failed", name, formatSystemMessage(e)); + log::error("QueryServiceConfig() for '{}' failed", name, formatSystemMessage(e)); return Service::StartType::None; } + switch (config->dwStartType) { + case SERVICE_AUTO_START: // fall-through + case SERVICE_BOOT_START: + case SERVICE_DEMAND_START: + case SERVICE_SYSTEM_START: { + return Service::StartType::Enabled; + } - switch (config->dwStartType) - { - case SERVICE_AUTO_START: // fall-through - case SERVICE_BOOT_START: - case SERVICE_DEMAND_START: - case SERVICE_SYSTEM_START: - { - return Service::StartType::Enabled; - } - - case SERVICE_DISABLED: - { - return Service::StartType::Disabled; - } + case SERVICE_DISABLED: { + return Service::StartType::Disabled; + } - default: - { - log::error( - "unknown service start type {} for '{}'", - config->dwStartType, name); + default: { + log::error("unknown service start type {} for '{}'", config->dwStartType, name); - return Service::StartType::None; - } + return Service::StartType::None; + } } } @@ -606,9 +570,8 @@ Service::Status getServiceStatus(SC_HANDLE s, const QString& name) const auto e = GetLastError(); if (e != ERROR_INSUFFICIENT_BUFFER) { - log::error( - "QueryServiceStatusEx() for size for '{}' failed, {}", - name, GetLastError()); + log::error("QueryServiceStatusEx() for size for '{}' failed, {}", name, + GetLastError()); return Service::Status::None; } @@ -616,56 +579,47 @@ Service::Status getServiceStatus(SC_HANDLE s, const QString& name) const auto size = needed; MallocPtr<SERVICE_STATUS_PROCESS> status( - static_cast<SERVICE_STATUS_PROCESS*>(std::malloc(size))); + static_cast<SERVICE_STATUS_PROCESS*>(std::malloc(size))); const auto r = QueryServiceStatusEx( - s, SC_STATUS_PROCESS_INFO, reinterpret_cast<BYTE*>(status.get()), - size, &needed); + s, SC_STATUS_PROCESS_INFO, reinterpret_cast<BYTE*>(status.get()), size, &needed); if (!r) { const auto e = GetLastError(); - log::error( - "QueryServiceStatusEx() failed for '{}', {}", - name, formatSystemMessage(e)); + log::error("QueryServiceStatusEx() failed for '{}', {}", name, + formatSystemMessage(e)); return Service::Status::None; } + switch (status->dwCurrentState) { + case SERVICE_START_PENDING: // fall-through + case SERVICE_CONTINUE_PENDING: + case SERVICE_RUNNING: { + return Service::Status::Running; + } - switch (status->dwCurrentState) - { - case SERVICE_START_PENDING: // fall-through - case SERVICE_CONTINUE_PENDING: - case SERVICE_RUNNING: - { - return Service::Status::Running; - } - - case SERVICE_STOPPED: // fall-through - case SERVICE_STOP_PENDING: - case SERVICE_PAUSE_PENDING: - case SERVICE_PAUSED: - { - return Service::Status::Stopped; - } + case SERVICE_STOPPED: // fall-through + case SERVICE_STOP_PENDING: + case SERVICE_PAUSE_PENDING: + case SERVICE_PAUSED: { + return Service::Status::Stopped; + } - default: - { - log::error( - "unknown service status {} for '{}'", - status->dwCurrentState, name); + default: { + log::error("unknown service status {} for '{}'", status->dwCurrentState, name); - return Service::Status::None; - } + return Service::Status::None; + } } } Service getService(const QString& name) { // service manager - const LocalPtr<SC_HANDLE> scm(OpenSCManager( - NULL, NULL, SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG)); + const LocalPtr<SC_HANDLE> scm( + OpenSCManager(NULL, NULL, SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG)); if (!scm) { const auto e = GetLastError(); @@ -674,9 +628,8 @@ Service getService(const QString& name) } // service - const LocalPtr<SC_HANDLE> s(OpenService( - scm.get(), name.toStdWString().c_str(), - SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG)); + const LocalPtr<SC_HANDLE> s(OpenService(scm.get(), name.toStdWString().c_str(), + SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG)); if (!s) { const auto e = GetLastError(); @@ -685,20 +638,19 @@ Service getService(const QString& name) } const auto startType = getServiceStartType(s.get(), name); - const auto status = getServiceStatus(s.get(), name); + const auto status = getServiceStatus(s.get(), name); return {name, startType, status}; } - std::optional<QString> getAssocString(const QFileInfo& file, ASSOCSTR astr) { const auto ext = L"." + file.suffix().toStdWString(); // getting buffer size DWORD bufferSize = 0; - auto r = AssocQueryStringW( - ASSOCF_INIT_IGNOREUNKNOWN, astr, ext.c_str(), L"open", nullptr, &bufferSize); + auto r = AssocQueryStringW(ASSOCF_INIT_IGNOREUNKNOWN, astr, ext.c_str(), L"open", + nullptr, &bufferSize); // returns S_FALSE when giving back the buffer size, so that's actually the // expected return value @@ -707,9 +659,8 @@ std::optional<QString> getAssocString(const QFileInfo& file, ASSOCSTR astr) if (r == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION)) { log::error("file '{}' has no associated executable", file.absoluteFilePath()); } else { - log::error( - "can't get buffer size for AssocQueryStringW(), {}", - formatSystemMessage(r)); + log::error("can't get buffer size for AssocQueryStringW(), {}", + formatSystemMessage(r)); } return {}; } @@ -718,13 +669,12 @@ std::optional<QString> getAssocString(const QFileInfo& file, ASSOCSTR astr) auto buffer = std::make_unique<wchar_t[]>(bufferSize + 1); std::fill(buffer.get(), buffer.get() + bufferSize + 1, 0); - r = AssocQueryStringW( - ASSOCF_INIT_IGNOREUNKNOWN, astr, ext.c_str(), L"open", buffer.get(), &bufferSize); + r = AssocQueryStringW(ASSOCF_INIT_IGNOREUNKNOWN, astr, ext.c_str(), L"open", + buffer.get(), &bufferSize); if (FAILED(r)) { - log::error( - "failed to get exe associated with '{}', {}", - file.suffix(), formatSystemMessage(r)); + log::error("failed to get exe associated with '{}', {}", file.suffix(), + formatSystemMessage(r)); return {}; } @@ -751,7 +701,7 @@ QString formatCommandLine(const QFileInfo& targetInfo, const QString& cmd) // first one is the filename const auto wpath = targetInfo.absoluteFilePath().toStdWString(); - args[0] = reinterpret_cast<DWORD_PTR>(wpath.c_str()); + args[0] = reinterpret_cast<DWORD_PTR>(wpath.c_str()); // remaining are "" std::fill(args.begin() + 1, args.end(), reinterpret_cast<DWORD_PTR>(L"")); @@ -761,20 +711,17 @@ QString formatCommandLine(const QFileInfo& targetInfo, const QString& cmd) const auto wcmd = cmd.toStdWString(); - const auto n = ::FormatMessageW( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_ARGUMENT_ARRAY | - FORMAT_MESSAGE_FROM_STRING, - wcmd.c_str(), 0, 0, - reinterpret_cast<LPWSTR>(&buffer), - 0, reinterpret_cast<va_list*>(&args[0])); + const auto n = + ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY | + FORMAT_MESSAGE_FROM_STRING, + wcmd.c_str(), 0, 0, reinterpret_cast<LPWSTR>(&buffer), 0, + reinterpret_cast<va_list*>(&args[0])); - if (n == 0 || !buffer){ + if (n == 0 || !buffer) { const auto e = GetLastError(); - log::error( - "failed to format command line '{}' with path '{}', {}", - cmd, targetInfo.absoluteFilePath(), formatSystemMessage(e)); + log::error("failed to format command line '{}' with path '{}', {}", cmd, + targetInfo.absoluteFilePath(), formatSystemMessage(e)); return {}; } @@ -788,12 +735,12 @@ QString formatCommandLine(const QFileInfo& targetInfo, const QString& cmd) std::pair<QString, QString> splitExeAndArguments(const QString& cmd) { int exeBegin = 0; - int exeEnd = -1; + int exeEnd = -1; - if (cmd[0] == '"'){ + if (cmd[0] == '"') { // surrounded by double-quotes, so find the next one exeBegin = 1; - exeEnd = cmd.indexOf('"', exeBegin); + exeEnd = cmd.indexOf('"', exeBegin); if (exeEnd == -1) { log::error("missing terminating double-quote in command line '{}'", cmd); @@ -807,7 +754,7 @@ std::pair<QString, QString> splitExeAndArguments(const QString& cmd) } } - QString exe = cmd.mid(exeBegin, exeEnd - exeBegin).trimmed(); + QString exe = cmd.mid(exeBegin, exeEnd - exeBegin).trimmed(); QString args = cmd.mid(exeEnd + 1).trimmed(); return {std::move(exe), std::move(args)}; @@ -815,9 +762,8 @@ std::pair<QString, QString> splitExeAndArguments(const QString& cmd) Association getAssociation(const QFileInfo& targetInfo) { - log::debug( - "getting association for '{}', extension is '.{}'", - targetInfo.absoluteFilePath(), targetInfo.suffix()); + log::debug("getting association for '{}', extension is '.{}'", + targetInfo.absoluteFilePath(), targetInfo.suffix()); const auto cmd = getAssocString(targetInfo, ASSOCSTR_COMMAND); if (!cmd) { @@ -828,9 +774,8 @@ Association getAssociation(const QFileInfo& targetInfo) QString formattedCmd = formatCommandLine(targetInfo, *cmd); if (formattedCmd.isEmpty()) { - log::error( - "command line associated with '{}' is empty", - targetInfo.absoluteFilePath()); + log::error("command line associated with '{}' is empty", + targetInfo.absoluteFilePath()); return {}; } @@ -847,7 +792,6 @@ Association getAssociation(const QFileInfo& targetInfo) return {QFileInfo(p.first), *cmd, p.second}; } - struct RegistryKeyCloser { using pointer = HKEY; @@ -866,10 +810,9 @@ RegistryKeyPtr openRegistryKey(HKEY parent, const wchar_t* name) { HKEY subkey = 0; - auto r = ::RegOpenKeyExW( - parent, name, - 0, KEY_SET_VALUE|KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE, - &subkey); + auto r = ::RegOpenKeyExW(parent, name, 0, + KEY_SET_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, + &subkey); if (r != ERROR_SUCCESS) { return {}; @@ -880,12 +823,12 @@ RegistryKeyPtr openRegistryKey(HKEY parent, const wchar_t* name) bool keyHasValues(HKEY key) { - auto name = std::make_unique<wchar_t[]>(1000 + 1); + auto name = std::make_unique<wchar_t[]>(1000 + 1); DWORD nameSize = 1000; // note that RegEnumValueW() also enumerates the default value if it exists - auto r = ::RegEnumValueW( - key, 0, name.get(), &nameSize, nullptr, nullptr, nullptr, nullptr); + auto r = ::RegEnumValueW(key, 0, name.get(), &nameSize, nullptr, nullptr, nullptr, + nullptr); if (r != ERROR_NO_MORE_ITEMS) { return true; @@ -895,18 +838,17 @@ bool keyHasValues(HKEY key) return false; } -bool forEachSubKey(HKEY key, std::function<bool (const wchar_t* name)> f) +bool forEachSubKey(HKEY key, std::function<bool(const wchar_t* name)> f) { - auto name = std::make_unique<wchar_t[]>(1000 + 1); + auto name = std::make_unique<wchar_t[]>(1000 + 1); DWORD nameSize = 1000; DWORD i = 0; // something would be really wrong if it had more than 100 keys - while (i < 100) - { - auto r = ::RegEnumKeyExW( - key, i, name.get(), &nameSize, nullptr, nullptr, nullptr, nullptr); + while (i < 100) { + auto r = ::RegEnumKeyExW(key, i, name.get(), &nameSize, nullptr, nullptr, nullptr, + nullptr); if (r == ERROR_NO_MORE_ITEMS) { // no more subkeys @@ -991,8 +933,7 @@ void deleteRegistryKeyIfEmpty(const QString& name) bool registryValueExists(const QString& keyName, const QString& valueName) { - auto key = openRegistryKey( - HKEY_CURRENT_USER, keyName.toStdWString().c_str()); + auto key = openRegistryKey(HKEY_CURRENT_USER, keyName.toStdWString().c_str()); if (!key) { return false; @@ -1000,25 +941,22 @@ bool registryValueExists(const QString& keyName, const QString& valueName) DWORD type = 0; - auto r = ::RegQueryValueExW( - key.get(), valueName.toStdWString().c_str(), - nullptr, &type, nullptr, nullptr); + auto r = ::RegQueryValueExW(key.get(), valueName.toStdWString().c_str(), nullptr, + &type, nullptr, nullptr); return (r == ERROR_SUCCESS); } - // returns the filename of the given process or the current one // -std::filesystem::path processPath(HANDLE process=INVALID_HANDLE_VALUE) +std::filesystem::path processPath(HANDLE process = INVALID_HANDLE_VALUE) { // double the buffer size 10 times const int MaxTries = 10; DWORD bufferSize = MAX_PATH; - for (int tries=0; tries<MaxTries; ++tries) - { + for (int tries = 0; tries < MaxTries; ++tries) { auto buffer = std::make_unique<wchar_t[]>(bufferSize + 1); std::fill(buffer.get(), buffer.get() + bufferSize + 1, 0); @@ -1063,7 +1001,7 @@ std::filesystem::path processPath(HANDLE process=INVALID_HANDLE_VALUE) return {}; } -std::wstring processFilename(HANDLE process=INVALID_HANDLE_VALUE) +std::wstring processFilename(HANDLE process = INVALID_HANDLE_VALUE) { const auto p = processPath(process); if (p.empty()) { @@ -1092,9 +1030,8 @@ DWORD findOtherPid() // same one auto filename = processFilename(); if (filename.empty()) { - std::wcerr - << L"can't get current process filename, defaulting to " - << defaultName << L"\n"; + std::wcerr << L"can't get current process filename, defaulting to " << defaultName + << L"\n"; filename = defaultName; } else { @@ -1115,25 +1052,23 @@ DWORD findOtherPid() } } - std::wclog - << L"no process with this filename\n" - << L"MO may not be running, or it may be running as administrator\n" - << L"you can try running this again as administrator\n"; + std::wclog << L"no process with this filename\n" + << L"MO may not be running, or it may be running as administrator\n" + << L"you can try running this again as administrator\n"; return 0; } std::wstring tempDir() { - const DWORD bufferSize = MAX_PATH + 1; + const DWORD bufferSize = MAX_PATH + 1; wchar_t buffer[bufferSize + 1] = {}; const auto written = GetTempPathW(bufferSize, buffer); if (written == 0) { const auto e = GetLastError(); - std::wcerr - << L"failed to get temp path, " << formatSystemMessage(e) << L"\n"; + std::wcerr << L"failed to get temp path, " << formatSystemMessage(e) << L"\n"; return {}; } @@ -1144,13 +1079,10 @@ std::wstring tempDir() std::wstring safeVersion() { - try - { + try { // this can throw return MOShared::createVersionInfo().displayString(3).toStdWString() + L"-"; - } - catch(...) - { + } catch (...) { return {}; } } @@ -1162,32 +1094,28 @@ HandlePtr tempFile(const std::wstring dir) // UTC time and date will be in the filename const auto now = std::time(0); - const auto tm = std::gmtime(&now); + const auto tm = std::gmtime(&now); // "ModOrganizer-YYYYMMDDThhmmss.dmp", with a possible "-i" appended, where // i can go until MaxTries std::wostringstream oss; - oss - << L"ModOrganizer-" << safeVersion() - << std::setw(4) << (1900 + tm->tm_year) - << std::setw(2) << std::setfill(L'0') << (tm->tm_mon + 1) - << std::setw(2) << std::setfill(L'0') << tm->tm_mday << "T" - << std::setw(2) << std::setfill(L'0') << tm->tm_hour - << std::setw(2) << std::setfill(L'0') << tm->tm_min - << std::setw(2) << std::setfill(L'0') << tm->tm_sec; + oss << L"ModOrganizer-" << safeVersion() << std::setw(4) << (1900 + tm->tm_year) + << std::setw(2) << std::setfill(L'0') << (tm->tm_mon + 1) << std::setw(2) + << std::setfill(L'0') << tm->tm_mday << "T" << std::setw(2) << std::setfill(L'0') + << tm->tm_hour << std::setw(2) << std::setfill(L'0') << tm->tm_min << std::setw(2) + << std::setfill(L'0') << tm->tm_sec; const std::wstring prefix = oss.str(); - const std::wstring ext = L".dmp"; + const std::wstring ext = L".dmp"; // first path to try, without counter in it std::wstring path = dir + L"\\" + prefix + ext; - for (int i=0; i<MaxTries; ++i) { + for (int i = 0; i < MaxTries; ++i) { std::wclog << L"trying file '" << path << L"'\n"; - HandlePtr h (CreateFileW( - path.c_str(), GENERIC_WRITE, 0, nullptr, - CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr)); + HandlePtr h(CreateFileW(path.c_str(), GENERIC_WRITE, 0, nullptr, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, nullptr)); if (h.get() != INVALID_HANDLE_VALUE) { // worked @@ -1198,8 +1126,7 @@ HandlePtr tempFile(const std::wstring dir) if (e != ERROR_FILE_EXISTS) { // probably no write access - std::wcerr - << L"failed to create dump file, " << formatSystemMessage(e) << L"\n"; + std::wcerr << L"failed to create dump file, " << formatSystemMessage(e) << L"\n"; return {}; } @@ -1243,7 +1170,6 @@ HandlePtr dumpFile(const wchar_t* dir) return {}; } - CoreDumpTypes coreDumpTypeFromString(const std::string& s) { if (s == "data") @@ -1256,23 +1182,21 @@ CoreDumpTypes coreDumpTypeFromString(const std::string& s) std::string toString(CoreDumpTypes type) { - switch (type) - { - case CoreDumpTypes::Mini: - return "mini"; + switch (type) { + case CoreDumpTypes::Mini: + return "mini"; - case CoreDumpTypes::Data: - return "data"; + case CoreDumpTypes::Data: + return "data"; - case CoreDumpTypes::Full: - return "full"; + case CoreDumpTypes::Full: + return "full"; - default: - return "?"; + default: + return "?"; } } - bool createMiniDump(const wchar_t* dir, HANDLE process, CoreDumpTypes type) { const DWORD pid = GetProcessId(process); @@ -1283,30 +1207,27 @@ bool createMiniDump(const wchar_t* dir, HANDLE process, CoreDumpTypes type) return false; } - auto flags = _MINIDUMP_TYPE( - MiniDumpNormal | - MiniDumpWithHandleData | - MiniDumpWithUnloadedModules | - MiniDumpWithProcessThreadData); + auto flags = + _MINIDUMP_TYPE(MiniDumpNormal | MiniDumpWithHandleData | + MiniDumpWithUnloadedModules | MiniDumpWithProcessThreadData); if (type == CoreDumpTypes::Data) { std::wclog << L"writing minidump with data\n"; flags = _MINIDUMP_TYPE(flags | MiniDumpWithDataSegs); - } else if (type == CoreDumpTypes::Full) { + } else if (type == CoreDumpTypes::Full) { std::wclog << L"writing full minidump\n"; flags = _MINIDUMP_TYPE(flags | MiniDumpWithFullMemory); } else { std::wclog << L"writing mini minidump\n"; } - const auto ret = MiniDumpWriteDump( - process, pid, file.get(), flags, nullptr, nullptr, nullptr); + const auto ret = + MiniDumpWriteDump(process, pid, file.get(), flags, nullptr, nullptr, nullptr); if (!ret) { const auto e = GetLastError(); - std::wcerr - << L"failed to write mini dump, " << formatSystemMessage(e) << L"\n"; + std::wcerr << L"failed to write mini dump, " << formatSystemMessage(e) << L"\n"; return false; } @@ -1315,7 +1236,6 @@ bool createMiniDump(const wchar_t* dir, HANDLE process, CoreDumpTypes type) return true; } - bool coredump(const wchar_t* dir, CoreDumpTypes type) { std::wclog << L"creating minidump for the current process\n"; @@ -1334,15 +1254,14 @@ bool coredumpOther(CoreDumpTypes type) std::wclog << L"found other process with pid " << pid << L"\n"; - HandlePtr handle(OpenProcess( - PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid)); + HandlePtr handle( + OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid)); if (!handle) { const auto e = GetLastError(); - std::wcerr - << L"failed to open process " << pid << L", " - << formatSystemMessage(e) << L"\n"; + std::wcerr << L"failed to open process " << pid << L", " << formatSystemMessage(e) + << L"\n"; return false; } @@ -1350,4 +1269,4 @@ bool coredumpOther(CoreDumpTypes type) return createMiniDump(nullptr, handle.get(), type); } -} // namespace +} // namespace env @@ -12,7 +12,6 @@ class SecurityProduct; class WindowsInfo; class Metrics; - // used by DesktopDCPtr, calls ReleaseDC(0, dc) as the deleter // struct DesktopDCReleaser @@ -29,7 +28,6 @@ struct DesktopDCReleaser using DesktopDCPtr = std::unique_ptr<HDC, DesktopDCReleaser>; - // used by HMenuPtr, calls DestroyMenu() as the deleter // struct HMenuFreer @@ -46,7 +44,6 @@ struct HMenuFreer using HMenuPtr = std::unique_ptr<HMENU, HMenuFreer>; - // used by LibraryPtr, calls FreeLibrary as the deleter // struct LibraryFreer @@ -63,7 +60,6 @@ struct LibraryFreer using LibraryPtr = std::unique_ptr<HINSTANCE, LibraryFreer>; - // used by COMPtr, calls Release() as the deleter // struct COMReleaser @@ -79,21 +75,16 @@ struct COMReleaser template <class T> using COMPtr = std::unique_ptr<T, COMReleaser>; - // used by MallocPtr, calls std::free() as the deleter // struct MallocFreer { - void operator()(void* p) - { - std::free(p); - } + void operator()(void* p) { std::free(p); } }; template <class T> using MallocPtr = std::unique_ptr<T, MallocFreer>; - // used by LocalPtr, calls LocalFree() as the deleter // template <class T> @@ -101,16 +92,12 @@ struct LocalFreer { using pointer = T; - void operator()(T p) - { - ::LocalFree(p); - } + void operator()(T p) { ::LocalFree(p); } }; template <class T> using LocalPtr = std::unique_ptr<T, LocalFreer<T>>; - // used by the CoTaskMemPtr, calls CoTaskMemFree() as the deleter // template <class T> @@ -118,16 +105,12 @@ struct CoTaskMemFreer { using pointer = T; - void operator()(T p) - { - ::CoTaskMemFree(p); - } + void operator()(T p) { ::CoTaskMemFree(p); } }; template <class T> using CoTaskMemPtr = std::unique_ptr<T, CoTaskMemFreer<T>>; - // creates a console in the constructor and destroys it in the destructor, // also redirects standard streams // @@ -152,17 +135,16 @@ private: FILE* m_err; }; - class ModuleNotification { public: - ModuleNotification(QObject* o, std::function<void (Module)> f); + ModuleNotification(QObject* o, std::function<void(Module)> f); ~ModuleNotification(); - ModuleNotification(const ModuleNotification&) = delete; + ModuleNotification(const ModuleNotification&) = delete; ModuleNotification& operator=(const ModuleNotification&) = delete; - ModuleNotification(ModuleNotification&&) = default; + ModuleNotification(ModuleNotification&&) = default; ModuleNotification& operator=(ModuleNotification&&) = default; void setCookie(void* c); @@ -172,10 +154,9 @@ private: void* m_cookie; QObject* m_object; std::set<QString> m_loaded; - std::function<void (Module)> m_f; + std::function<void(Module)> m_f; }; - // represents the process's environment // class Environment @@ -211,8 +192,8 @@ public: // will call `f` on the same thread `o` is running on every time a module // is loaded in the process // - std::unique_ptr<ModuleNotification> onModuleLoaded( - QObject* o, std::function<void (Module)> f); + std::unique_ptr<ModuleNotification> onModuleLoaded(QObject* o, + std::function<void(Module)> f); // logs the environment // @@ -229,7 +210,6 @@ private: void dumpDisks(const Settings& s) const; }; - // environment variables // QString get(const QString& name); @@ -240,7 +220,6 @@ QString appendToPath(const QString& s); QString prependToPath(const QString& s); void setPath(const QString& s); - class Service { public: @@ -258,7 +237,6 @@ public: Running }; - explicit Service(QString name); Service(QString name, StartType st, Status s); @@ -276,12 +254,10 @@ private: Status m_status; }; - Service getService(const QString& name); QString toString(Service::StartType st); QString toString(Service::Status st); - struct Association { // path to the executable associated with the file @@ -300,7 +276,6 @@ struct Association // Association getAssociation(const QFileInfo& file); - // returns whether the given value exists // bool registryValueExists(const QString& key, const QString& value); @@ -313,6 +288,6 @@ void deleteRegistryKeyIfEmpty(const QString& name); // std::filesystem::path thisProcessPath(); -} // namespace env +} // namespace env -#endif // ENV_ENV_H +#endif // ENV_ENV_H diff --git a/src/envdump.h b/src/envdump.h index 355df783..91da5280 100644 --- a/src/envdump.h +++ b/src/envdump.h @@ -12,7 +12,6 @@ enum class CoreDumpTypes Full }; - CoreDumpTypes coreDumpTypeFromString(const std::string& s); std::string toString(CoreDumpTypes type); @@ -25,6 +24,6 @@ bool coredump(const wchar_t* dir, CoreDumpTypes type); // bool coredumpOther(CoreDumpTypes type); -} // namespace +} // namespace env #endif // MODORGANIZER_ENVDUMP_INCLUDED diff --git a/src/envfs.cpp b/src/envfs.cpp index dfea6598..fe84fd17 100644 --- a/src/envfs.cpp +++ b/src/envfs.cpp @@ -1,19 +1,21 @@ #include "envfs.h" #include "env.h" #include "shared/util.h" -#include <utility.h> #include <log.h> +#include <utility.h> using namespace MOBase; -typedef struct _UNICODE_STRING { +typedef struct _UNICODE_STRING +{ USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING, *PUNICODE_STRING; -typedef const UNICODE_STRING *PCUNICODE_STRING; +typedef const UNICODE_STRING* PCUNICODE_STRING; -typedef struct _OBJECT_ATTRIBUTES { +typedef struct _OBJECT_ATTRIBUTES +{ ULONG Length; HANDLE RootDirectory; PUNICODE_STRING ObjectName; @@ -22,23 +24,22 @@ typedef struct _OBJECT_ATTRIBUTES { PVOID SecurityQualityOfService; } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; - -typedef struct _FILE_DIRECTORY_INFORMATION { - ULONG NextEntryOffset; - ULONG FileIndex; +typedef struct _FILE_DIRECTORY_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; LARGE_INTEGER CreationTime; LARGE_INTEGER LastAccessTime; LARGE_INTEGER LastWriteTime; LARGE_INTEGER ChangeTime; LARGE_INTEGER EndOfFile; LARGE_INTEGER AllocationSize; - ULONG FileAttributes; - ULONG FileNameLength; - WCHAR FileName[1]; + ULONG FileAttributes; + ULONG FileNameLength; + WCHAR FileName[1]; } FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION; - -#define FILE_SHARE_VALID_FLAGS 0x00000007 +#define FILE_SHARE_VALID_FLAGS 0x00000007 // copied from ntstatus.h #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) @@ -48,72 +49,71 @@ typedef struct _FILE_DIRECTORY_INFORMATION { typedef struct _IO_STATUS_BLOCK IO_STATUS_BLOCK; -typedef struct _IO_STATUS_BLOCK *PIO_STATUS_BLOCK; +typedef struct _IO_STATUS_BLOCK* PIO_STATUS_BLOCK; // typedef VOID (NTAPI *PIO_APC_ROUTINE )(__in PVOID ApcContext, __in // PIO_STATUS_BLOCK IoStatusBlock, __in ULONG Reserved); -typedef VOID(NTAPI *PIO_APC_ROUTINE)(PVOID ApcContext, - PIO_STATUS_BLOCK IoStatusBlock, - ULONG Reserved); - +typedef VOID(NTAPI* PIO_APC_ROUTINE)(PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, + ULONG Reserved); -typedef enum _FILE_INFORMATION_CLASS { +typedef enum _FILE_INFORMATION_CLASS +{ FileDirectoryInformation = 1 } FILE_INFORMATION_CLASS; -typedef NTSTATUS(WINAPI *NtQueryDirectoryFile_type)( - HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, PIO_STATUS_BLOCK, PVOID, ULONG, - FILE_INFORMATION_CLASS, BOOLEAN, PUNICODE_STRING, BOOLEAN); - -typedef NTSTATUS(WINAPI *NtOpenFile_type)(PHANDLE, ACCESS_MASK, - POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, - ULONG, ULONG); +typedef NTSTATUS(WINAPI* NtQueryDirectoryFile_type)(HANDLE, HANDLE, PIO_APC_ROUTINE, + PVOID, PIO_STATUS_BLOCK, PVOID, + ULONG, FILE_INFORMATION_CLASS, + BOOLEAN, PUNICODE_STRING, BOOLEAN); -typedef NTSTATUS(WINAPI *NtClose_type)(HANDLE); +typedef NTSTATUS(WINAPI* NtOpenFile_type)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, + PIO_STATUS_BLOCK, ULONG, ULONG); +typedef NTSTATUS(WINAPI* NtClose_type)(HANDLE); -NtOpenFile_type NtOpenFile = nullptr; +NtOpenFile_type NtOpenFile = nullptr; NtQueryDirectoryFile_type NtQueryDirectoryFile = nullptr; -extern NtClose_type NtClose = nullptr; +extern NtClose_type NtClose = nullptr; +#define FILE_DIRECTORY_FILE 0x00000001 +#define FILE_WRITE_THROUGH 0x00000002 +#define FILE_SEQUENTIAL_ONLY 0x00000004 +#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 -#define FILE_DIRECTORY_FILE 0x00000001 -#define FILE_WRITE_THROUGH 0x00000002 -#define FILE_SEQUENTIAL_ONLY 0x00000004 -#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 +#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 +#define FILE_NON_DIRECTORY_FILE 0x00000040 +#define FILE_CREATE_TREE_CONNECTION 0x00000080 -#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 -#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 -#define FILE_NON_DIRECTORY_FILE 0x00000040 -#define FILE_CREATE_TREE_CONNECTION 0x00000080 +#define FILE_COMPLETE_IF_OPLOCKED 0x00000100 +#define FILE_NO_EA_KNOWLEDGE 0x00000200 +#define FILE_OPEN_REMOTE_INSTANCE 0x00000400 +#define FILE_RANDOM_ACCESS 0x00000800 -#define FILE_COMPLETE_IF_OPLOCKED 0x00000100 -#define FILE_NO_EA_KNOWLEDGE 0x00000200 -#define FILE_OPEN_REMOTE_INSTANCE 0x00000400 -#define FILE_RANDOM_ACCESS 0x00000800 - -#define FILE_DELETE_ON_CLOSE 0x00001000 -#define FILE_OPEN_BY_FILE_ID 0x00002000 -#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 -#define FILE_NO_COMPRESSION 0x00008000 +#define FILE_DELETE_ON_CLOSE 0x00001000 +#define FILE_OPEN_BY_FILE_ID 0x00002000 +#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 +#define FILE_NO_COMPRESSION 0x00008000 #if (_WIN32_WINNT >= _WIN32_WINNT_WIN7) -#define FILE_OPEN_REQUIRING_OPLOCK 0x00010000 +#define FILE_OPEN_REQUIRING_OPLOCK 0x00010000 #endif -#define FILE_RESERVE_OPFILTER 0x00100000 -#define FILE_OPEN_REPARSE_POINT 0x00200000 -#define FILE_OPEN_NO_RECALL 0x00400000 -#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 +#define FILE_RESERVE_OPFILTER 0x00100000 +#define FILE_OPEN_REPARSE_POINT 0x00200000 +#define FILE_OPEN_NO_RECALL 0x00400000 +#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 -#define FILE_VALID_OPTION_FLAGS 0x00ffffff -#define FILE_VALID_PIPE_OPTION_FLAGS 0x00000032 -#define FILE_VALID_MAILSLOT_OPTION_FLAGS 0x00000032 -#define FILE_VALID_SET_FLAGS 0x00000036 +#define FILE_VALID_OPTION_FLAGS 0x00ffffff +#define FILE_VALID_PIPE_OPTION_FLAGS 0x00000032 +#define FILE_VALID_MAILSLOT_OPTION_FLAGS 0x00000032 +#define FILE_VALID_SET_FLAGS 0x00000036 -typedef struct _IO_STATUS_BLOCK { +typedef struct _IO_STATUS_BLOCK +{ #pragma warning(push) -#pragma warning(disable: 4201) // we'll always use the Microsoft compiler - union { +#pragma warning(disable : 4201) // we'll always use the Microsoft compiler + union + { NTSTATUS Status; PVOID Pointer; } DUMMYUNIONNAME; @@ -122,8 +122,6 @@ typedef struct _IO_STATUS_BLOCK { ULONG_PTR Information; } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; - - namespace env { @@ -151,25 +149,14 @@ QString toString(POBJECT_ATTRIBUTES poa) return QString::fromWCharArray(sv.data(), static_cast<int>(sv.size())); } - class HandleCloserThread { public: - HandleCloserThread() - : m_ready(false) - { - m_handles.reserve(50000); - } + HandleCloserThread() : m_ready(false) { m_handles.reserve(50000); } - void shrink() - { - m_handles.shrink_to_fit(); - } + void shrink() { m_handles.shrink_to_fit(); } - void add(HANDLE h) - { - m_handles.push_back(h); - } + void add(HANDLE h) { m_handles.push_back(h); } void wakeup() { @@ -186,7 +173,9 @@ public: MOShared::SetThisThreadName("HandleCloserThread"); std::unique_lock lock(m_mutex); - m_cv.wait(lock, [&]{ return m_ready; }); + m_cv.wait(lock, [&] { + return m_ready; + }); closeHandles(); } @@ -216,24 +205,23 @@ void setHandleCloserThreadCount(std::size_t n) g_handleClosers.setMax(n); } -void forEachEntryImpl( - void* cx, HandleCloserThread& hc, std::vector<std::unique_ptr<unsigned char[]>>& buffers, - POBJECT_ATTRIBUTES poa, std::size_t depth, - DirStartF* dirStartF, DirEndF* dirEndF, FileF* fileF) +void forEachEntryImpl(void* cx, HandleCloserThread& hc, + std::vector<std::unique_ptr<unsigned char[]>>& buffers, + POBJECT_ATTRIBUTES poa, std::size_t depth, DirStartF* dirStartF, + DirEndF* dirEndF, FileF* fileF) { IO_STATUS_BLOCK iosb; UNICODE_STRING ObjectName; - OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName }; + OBJECT_ATTRIBUTES oa = {sizeof(oa), 0, &ObjectName}; NTSTATUS status; - status = NtOpenFile( - &oa.RootDirectory, FILE_GENERIC_READ, poa, &iosb, FILE_SHARE_VALID_FLAGS, - FILE_SYNCHRONOUS_IO_NONALERT|FILE_OPEN_FOR_BACKUP_INTENT); + status = NtOpenFile(&oa.RootDirectory, FILE_GENERIC_READ, poa, &iosb, + FILE_SHARE_VALID_FLAGS, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT); if (status < 0) { - log::error( - "failed to open directory '{}': {}", - toString(poa), formatNtMessage(status)); + log::error("failed to open directory '{}': {}", toString(poa), + formatNtMessage(status)); return; } @@ -256,16 +244,15 @@ void forEachEntryImpl( }; for (;;) { - status = NtQueryDirectoryFile( - oa.RootDirectory, NULL, NULL, NULL, &iosb, - buffer, AllocSize, FileDirectoryInformation, FALSE, NULL, FALSE); + status = + NtQueryDirectoryFile(oa.RootDirectory, NULL, NULL, NULL, &iosb, buffer, + AllocSize, FileDirectoryInformation, FALSE, NULL, FALSE); if (status == STATUS_NO_MORE_FILES) { break; } else if (status < 0) { - log::error( - "failed to read directory '{}': {}", - toString(poa), formatNtMessage(status)); + log::error("failed to read directory '{}': {}", toString(poa), + formatNtMessage(status)); break; } @@ -301,12 +288,13 @@ void forEachEntryImpl( if (DirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (dirStartF && dirEndF) { dirStartF(cx, toStringView(&oa)); - forEachEntryImpl(cx, hc, buffers, &oa, depth+1, dirStartF, dirEndF, fileF); + forEachEntryImpl(cx, hc, buffers, &oa, depth + 1, dirStartF, dirEndF, + fileF); dirEndF(cx, toStringView(&oa)); } } else { FILETIME ft; - ft.dwLowDateTime = DirInfo->LastWriteTime.LowPart; + ft.dwLowDateTime = DirInfo->LastWriteTime.LowPart; ft.dwHighDateTime = DirInfo->LastWriteTime.HighPart; fileF(cx, toStringView(&oa), ft, DirInfo->AllocationSize.QuadPart); @@ -324,9 +312,9 @@ void forEachEntryImpl( std::wstring makeNtPath(const std::wstring& path) { - constexpr const wchar_t* nt_prefix = L"\\??\\"; + constexpr const wchar_t* nt_prefix = L"\\??\\"; constexpr const wchar_t* nt_unc_prefix = L"\\??\\UNC\\"; - constexpr const wchar_t* share_prefix = L"\\\\"; + constexpr const wchar_t* share_prefix = L"\\\\"; if (path.starts_with(nt_prefix)) { // already an nt path @@ -340,38 +328,36 @@ std::wstring makeNtPath(const std::wstring& path) } } -void DirectoryWalker::forEachEntry( - const std::wstring& path, void* cx, - DirStartF* dirStartF, DirEndF* dirEndF, FileF* fileF) +void DirectoryWalker::forEachEntry(const std::wstring& path, void* cx, + DirStartF* dirStartF, DirEndF* dirEndF, FileF* fileF) { auto& hc = g_handleClosers.request(); if (!NtOpenFile) { LibraryPtr m(::LoadLibraryW(L"ntdll.dll")); NtOpenFile = (NtOpenFile_type)::GetProcAddress(m.get(), "NtOpenFile"); - NtQueryDirectoryFile = (NtQueryDirectoryFile_type)::GetProcAddress(m.get(), "NtQueryDirectoryFile"); + NtQueryDirectoryFile = + (NtQueryDirectoryFile_type)::GetProcAddress(m.get(), "NtQueryDirectoryFile"); NtClose = (NtClose_type)::GetProcAddress(m.get(), "NtClose"); } const std::wstring ntpath = makeNtPath(path); UNICODE_STRING ObjectName = {}; - ObjectName.Buffer = const_cast<wchar_t*>(ntpath.c_str()); - ObjectName.Length = (USHORT)ntpath.size() * sizeof(wchar_t); - ObjectName.MaximumLength = ObjectName.Length; + ObjectName.Buffer = const_cast<wchar_t*>(ntpath.c_str()); + ObjectName.Length = (USHORT)ntpath.size() * sizeof(wchar_t); + ObjectName.MaximumLength = ObjectName.Length; OBJECT_ATTRIBUTES oa = {}; - oa.Length = sizeof(oa); - oa.ObjectName = &ObjectName; + oa.Length = sizeof(oa); + oa.ObjectName = &ObjectName; forEachEntryImpl(cx, hc, m_buffers, &oa, 0, dirStartF, dirEndF, fileF); hc.wakeup(); } - -void forEachEntry( - const std::wstring& path, void* cx, - DirStartF* dirStartF, DirEndF* dirEndF, FileF* fileF) +void forEachEntry(const std::wstring& path, void* cx, DirStartF* dirStartF, + DirEndF* dirEndF, FileF* fileF) { DirectoryWalker().forEachEntry(path, cx, dirStartF, dirEndF, fileF); } @@ -388,45 +374,39 @@ Directory getFilesAndDirs(const std::wstring& path) Context cx; cx.current.push(&root); - env::forEachEntry(path, &cx, - [](void* pcx, std::wstring_view path) { - Context* cx = (Context*)pcx; + env::forEachEntry( + path, &cx, + [](void* pcx, std::wstring_view path) { + Context* cx = (Context*)pcx; - cx->current.top()->dirs.push_back(Directory(path)); - cx->current.push(&cx->current.top()->dirs.back()); - }, + cx->current.top()->dirs.push_back(Directory(path)); + cx->current.push(&cx->current.top()->dirs.back()); + }, - [](void* pcx, std::wstring_view path) { - Context* cx = (Context*)pcx; - cx->current.pop(); - }, + [](void* pcx, std::wstring_view path) { + Context* cx = (Context*)pcx; + cx->current.pop(); + }, - [](void* pcx, std::wstring_view path, FILETIME ft, uint64_t s) { - Context* cx = (Context*)pcx; + [](void* pcx, std::wstring_view path, FILETIME ft, uint64_t s) { + Context* cx = (Context*)pcx; - cx->current.top()->files.push_back(File(path, ft, s)); - } - ); + cx->current.top()->files.push_back(File(path, ft, s)); + }); return root; } -File::File(std::wstring_view n, FILETIME ft, uint64_t s) : - name(n.begin(), n.end()), - lcname(MOShared::ToLowerCopy(name)), - lastModified(ft), size(s) -{ -} +File::File(std::wstring_view n, FILETIME ft, uint64_t s) + : name(n.begin(), n.end()), lcname(MOShared::ToLowerCopy(name)), lastModified(ft), + size(s) +{} -Directory::Directory() -{ -} +Directory::Directory() {} Directory::Directory(std::wstring_view n) - : name(n.begin(), n.end()), lcname(MOShared::ToLowerCopy(name)) -{ -} - + : name(n.begin(), n.end()), lcname(MOShared::ToLowerCopy(name)) +{} void getFilesAndDirsWithFindImpl(const std::wstring& path, Directory& d) { @@ -434,9 +414,9 @@ void getFilesAndDirsWithFindImpl(const std::wstring& path, Directory& d) WIN32_FIND_DATAW findData; - HANDLE searchHandle = ::FindFirstFileExW( - searchString.c_str(), FindExInfoBasic, &findData, FindExSearchNameMatch, - nullptr, FIND_FIRST_EX_LARGE_FETCH); + HANDLE searchHandle = + ::FindFirstFileExW(searchString.c_str(), FindExInfoBasic, &findData, + FindExSearchNameMatch, nullptr, FIND_FIRST_EX_LARGE_FETCH); if (searchHandle != INVALID_HANDLE_VALUE) { BOOL result = true; @@ -444,17 +424,16 @@ void getFilesAndDirsWithFindImpl(const std::wstring& path, Directory& d) while (result) { if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if ((wcscmp(findData.cFileName, L".") != 0) && - (wcscmp(findData.cFileName, L"..") != 0)) { + (wcscmp(findData.cFileName, L"..") != 0)) { const std::wstring newPath = path + L"\\" + findData.cFileName; d.dirs.push_back(Directory(findData.cFileName)); getFilesAndDirsWithFindImpl(newPath, d.dirs.back()); } } else { const auto size = - (findData.nFileSizeHigh * (MAXDWORD+1)) + findData.nFileSizeLow; + (findData.nFileSizeHigh * (MAXDWORD + 1)) + findData.nFileSizeLow; - d.files.push_back(File( - findData.cFileName, findData.ftLastWriteTime, size)); + d.files.push_back(File(findData.cFileName, findData.ftLastWriteTime, size)); } result = ::FindNextFileW(searchHandle, &findData); @@ -471,4 +450,4 @@ Directory getFilesAndDirsWithFind(const std::wstring& path) return d; } -} // namespace +} // namespace env diff --git a/src/envfs.h b/src/envfs.h index 62540e18..4ee1fab1 100644 --- a/src/envfs.h +++ b/src/envfs.h @@ -29,25 +29,15 @@ struct Directory Directory(std::wstring_view name); }; - template <class T> class ThreadPool { public: - ThreadPool(std::size_t max=1) - { - setMax(max); - } + ThreadPool(std::size_t max = 1) { setMax(max); } - ~ThreadPool() - { - stopAndJoin(); - } + ~ThreadPool() { stopAndJoin(); } - void setMax(std::size_t n) - { - m_threads.resize(n); - } + void setMax(std::size_t n) { m_threads.resize(n); } void stopAndJoin() { @@ -124,10 +114,11 @@ private: std::atomic<bool> stop; - ThreadInfo() - : busy(true), ready(false), stop(false) + ThreadInfo() : busy(true), ready(false), stop(false) { - thread = MOShared::startSafeThread([&]{ run(); }); + thread = MOShared::startSafeThread([&] { + run(); + }); } ~ThreadInfo() @@ -155,7 +146,9 @@ private: while (!stop) { std::unique_lock lock(mutex); - cv.wait(lock, [&]{ return ready; }); + cv.wait(lock, [&] { + return ready; + }); if (stop) { break; @@ -164,7 +157,7 @@ private: o.run(); ready = false; - busy = false; + busy = false; } } }; @@ -172,33 +165,28 @@ private: std::list<ThreadInfo> m_threads; }; - -using DirStartF = void (void*, std::wstring_view); -using DirEndF = void (void*, std::wstring_view); -using FileF = void (void*, std::wstring_view, FILETIME, uint64_t); +using DirStartF = void(void*, std::wstring_view); +using DirEndF = void(void*, std::wstring_view); +using FileF = void(void*, std::wstring_view, FILETIME, uint64_t); void setHandleCloserThreadCount(std::size_t n); - class DirectoryWalker { public: - void forEachEntry( - const std::wstring& path, void* cx, - DirStartF* dirStartF, DirEndF* dirEndF, FileF* fileF); + void forEachEntry(const std::wstring& path, void* cx, DirStartF* dirStartF, + DirEndF* dirEndF, FileF* fileF); private: std::vector<std::unique_ptr<unsigned char[]>> m_buffers; }; - -void forEachEntry( - const std::wstring& path, void* cx, - DirStartF* dirStartF, DirEndF* dirEndF, FileF* fileF); +void forEachEntry(const std::wstring& path, void* cx, DirStartF* dirStartF, + DirEndF* dirEndF, FileF* fileF); Directory getFilesAndDirs(const std::wstring& path); Directory getFilesAndDirsWithFind(const std::wstring& path); -} // namespace +} // namespace env -#endif // ENV_ENVFS_H +#endif // ENV_ENVFS_H diff --git a/src/envmetrics.cpp b/src/envmetrics.cpp index b47ca2f5..645645e4 100644 --- a/src/envmetrics.cpp +++ b/src/envmetrics.cpp @@ -1,10 +1,10 @@ #include "envmetrics.h" #include "env.h" +#include <QScreen> #include <Windows.h> -#include <shellscalingapi.h> #include <log.h> +#include <shellscalingapi.h> #include <utility.h> -#include <QScreen> namespace env { @@ -46,14 +46,13 @@ HMONITOR findMonitor(const QString& name) auto& data = *reinterpret_cast<Data*>(lp); MONITORINFOEX mi = {}; - mi.cbSize = sizeof(mi); + mi.cbSize = sizeof(mi); // monitor info will include the name if (!GetMonitorInfoW(hm, &mi)) { const auto e = GetLastError(); - log::error( - "GetMonitorInfo() failed for '{}', {}", - data.name, formatSystemMessage(e)); + log::error("GetMonitorInfo() failed for '{}', {}", data.name, + formatSystemMessage(e)); // error for this monitor, but continue return TRUE; @@ -69,7 +68,6 @@ HMONITOR findMonitor(const QString& name) return TRUE; }; - // for each monitor EnumDisplayMonitors(0, nullptr, callback, reinterpret_cast<LPARAM>(&data)); @@ -82,11 +80,11 @@ HMONITOR findMonitor(const QString& name) int getDpi(const QString& monitorDevice) { using GetDpiForMonitorFunction = - HRESULT WINAPI (HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*); + HRESULT WINAPI(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*); static LibraryPtr shcore; static GetDpiForMonitorFunction* GetDpiForMonitor = nullptr; - static bool checked = false; + static bool checked = false; if (!checked) { // try to find GetDpiForMonitor() from shcored.dll @@ -96,7 +94,7 @@ int getDpi(const QString& monitorDevice) if (shcore) { // windows 8.1+ only GetDpiForMonitor = reinterpret_cast<GetDpiForMonitorFunction*>( - GetProcAddress(shcore.get(), "GetDpiForMonitor")); + GetProcAddress(shcore.get(), "GetDpiForMonitor")); } checked = true; @@ -107,7 +105,6 @@ int getDpi(const QString& monitorDevice) return getDesktopDpi(); } - // there's no way to get an HMONITOR from a device name, so all monitors // will have to be enumerated and their name checked HMONITOR hm = findMonitor(monitorDevice); @@ -116,13 +113,12 @@ int getDpi(const QString& monitorDevice) return 0; } - UINT dpiX=0, dpiY=0; + UINT dpiX = 0, dpiY = 0; const auto r = GetDpiForMonitor(hm, MDT_EFFECTIVE_DPI, &dpiX, &dpiY); if (FAILED(r)) { - log::error( - "GetDpiForMonitor() failed for '{}', {}", - monitorDevice, formatSystemMessage(r)); + log::error("GetDpiForMonitor() failed for '{}', {}", monitorDevice, + formatSystemMessage(r)); return 0; } @@ -131,12 +127,9 @@ int getDpi(const QString& monitorDevice) return dpiX; } - -Display::Display(QString adapter, QString monitorDevice, bool primary) : - m_adapter(std::move(adapter)), - m_monitorDevice(std::move(monitorDevice)), - m_primary(primary), - m_resX(0), m_resY(0), m_dpi(0), m_refreshRate(0) +Display::Display(QString adapter, QString monitorDevice, bool primary) + : m_adapter(std::move(adapter)), m_monitorDevice(std::move(monitorDevice)), + m_primary(primary), m_resX(0), m_resY(0), m_dpi(0), m_refreshRate(0) { getSettings(); m_dpi = getDpi(m_monitorDevice); @@ -180,18 +173,18 @@ int Display::refreshRate() const QString Display::toString() const { return QString("%1*%2 %3hz dpi=%4 on %5%6") - .arg(m_resX) - .arg(m_resY) - .arg(m_refreshRate) - .arg(m_dpi) - .arg(m_adapter) - .arg(m_primary ? " (primary)" : ""); + .arg(m_resX) + .arg(m_resY) + .arg(m_refreshRate) + .arg(m_dpi) + .arg(m_adapter) + .arg(m_primary ? " (primary)" : ""); } void Display::getSettings() { DEVMODEW dm = {}; - dm.dmSize = sizeof(dm); + dm.dmSize = sizeof(dm); const auto wsDevice = m_monitorDevice.toStdWString(); @@ -215,7 +208,6 @@ void Display::getSettings() } } - Metrics::Metrics() { getDisplays(); @@ -240,9 +232,9 @@ QRect Metrics::desktopGeometry() const void Metrics::getDisplays() { // don't bother if it goes over 100 - for (int i=0; i<100; ++i) { + for (int i = 0; i < 100; ++i) { DISPLAY_DEVICEW device = {}; - device.cb = sizeof(device); + device.cb = sizeof(device); if (!EnumDisplayDevicesW(nullptr, i, &device, 0)) { // no more @@ -256,11 +248,10 @@ void Metrics::getDisplays() continue; } - m_displays.emplace_back( - QString::fromWCharArray(device.DeviceString), - QString::fromWCharArray(device.DeviceName), - (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)); + m_displays.emplace_back(QString::fromWCharArray(device.DeviceString), + QString::fromWCharArray(device.DeviceName), + (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)); } } -} // namespace +} // namespace env diff --git a/src/envmetrics.h b/src/envmetrics.h index 8dfdb087..578c4234 100644 --- a/src/envmetrics.h +++ b/src/envmetrics.h @@ -54,7 +54,6 @@ private: void getSettings(); }; - // holds various information about Windows metrics // class Metrics @@ -76,6 +75,6 @@ private: void getDisplays(); }; -} // namespace +} // namespace env -#endif // ENV_METRICS_H +#endif // ENV_METRICS_H diff --git a/src/envmodule.cpp b/src/envmodule.cpp index 5b1e7621..2bba4c41 100644 --- a/src/envmodule.cpp +++ b/src/envmodule.cpp @@ -1,7 +1,7 @@ #include "envmodule.h" #include "env.h" -#include <utility.h> #include <log.h> +#include <utility.h> namespace env { @@ -13,14 +13,13 @@ using namespace MOBase; // while adding to the startup time constexpr bool UseMD5 = false; - Module::Module(QString path, std::size_t fileSize) - : m_path(std::move(path)), m_fileSize(fileSize) + : m_path(std::move(path)), m_fileSize(fileSize) { const auto fi = getFileInfo(); - m_version = getVersion(fi.ffi); - m_timestamp = getTimestamp(fi.ffi); + m_version = getVersion(fi.ffi); + m_timestamp = getTimestamp(fi.ffi); m_versionString = fi.fileDescription; if (UseMD5) { @@ -113,7 +112,7 @@ Module::FileInfo Module::getFileInfo() const const auto wspath = m_path.toStdWString(); // getting version info size - DWORD dummy = 0; + DWORD dummy = 0; const DWORD size = GetFileVersionInfoSizeW(wspath.c_str(), &dummy); if (size == 0) { @@ -130,9 +129,8 @@ Module::FileInfo Module::getFileInfo() const return {}; } - log::debug( - "GetFileVersionInfoSizeW() failed on '{}', {}", - m_path, formatSystemMessage(e)); + log::debug("GetFileVersionInfoSizeW() failed on '{}', {}", m_path, + formatSystemMessage(e)); return {}; } @@ -143,9 +141,8 @@ Module::FileInfo Module::getFileInfo() const if (!GetFileVersionInfoW(wspath.c_str(), 0, size, buffer.get())) { const auto e = GetLastError(); - log::error( - "GetFileVersionInfoW() failed on '{}', {}", - m_path, formatSystemMessage(e)); + log::error("GetFileVersionInfoW() failed on '{}', {}", m_path, + formatSystemMessage(e)); return {}; } @@ -154,7 +151,7 @@ Module::FileInfo Module::getFileInfo() const // set of strings FileInfo fi; - fi.ffi = getFixedFileInfo(buffer.get()); + fi.ffi = getFixedFileInfo(buffer.get()); fi.fileDescription = getFileDescription(buffer.get()); return fi; @@ -162,7 +159,7 @@ Module::FileInfo Module::getFileInfo() const VS_FIXEDFILEINFO Module::getFixedFileInfo(std::byte* buffer) const { - void* valuePointer = nullptr; + void* valuePointer = nullptr; unsigned int valueSize = 0; // the fixed version info is in the root @@ -177,9 +174,7 @@ VS_FIXEDFILEINFO Module::getFixedFileInfo(std::byte* buffer) const // signature is always 0xfeef04bd if (fi->dwSignature != 0xfeef04bd) { - log::error( - "bad file info signature {:#x} for '{}'", - fi->dwSignature, m_path); + log::error("bad file info signature {:#x} for '{}'", fi->dwSignature, m_path); return {}; } @@ -195,12 +190,12 @@ QString Module::getFileDescription(std::byte* buffer) const WORD wCodePage; }; - void* valuePointer = nullptr; + void* valuePointer = nullptr; unsigned int valueSize = 0; // getting list of available languages - auto ret = VerQueryValueW( - buffer, L"\\VarFileInfo\\Translation", &valuePointer, &valueSize); + auto ret = + VerQueryValueW(buffer, L"\\VarFileInfo\\Translation", &valuePointer, &valueSize); if (!ret || !valuePointer || valueSize == 0) { log::error("VerQueryValueW() for translations failed on '{}'", m_path); @@ -217,11 +212,11 @@ QString Module::getFileDescription(std::byte* buffer) const const auto* lcp = static_cast<LANGANDCODEPAGE*>(valuePointer); const auto subBlock = QString("\\StringFileInfo\\%1%2\\FileVersion") - .arg(lcp->wLanguage, 4, 16, QChar('0')) - .arg(lcp->wCodePage, 4, 16, QChar('0')); + .arg(lcp->wLanguage, 4, 16, QChar('0')) + .arg(lcp->wCodePage, 4, 16, QChar('0')); - ret = VerQueryValueW( - buffer, subBlock.toStdWString().c_str(), &valuePointer, &valueSize); + ret = VerQueryValueW(buffer, subBlock.toStdWString().c_str(), &valuePointer, + &valueSize); if (!ret || !valuePointer || valueSize == 0) { // not an error, no file version @@ -229,8 +224,7 @@ QString Module::getFileDescription(std::byte* buffer) const } // valueSize includes the null terminator - return QString::fromWCharArray( - static_cast<wchar_t*>(valuePointer), valueSize - 1); + return QString::fromWCharArray(static_cast<wchar_t*>(valuePointer), valueSize - 1); } QString Module::getVersion(const VS_FIXEDFILEINFO& fi) const @@ -239,17 +233,16 @@ QString Module::getVersion(const VS_FIXEDFILEINFO& fi) const return {}; } - const DWORD major = (fi.dwFileVersionMS >> 16 ) & 0xffff; - const DWORD minor = (fi.dwFileVersionMS >> 0 ) & 0xffff; - const DWORD maintenance = (fi.dwFileVersionLS >> 16 ) & 0xffff; - const DWORD build = (fi.dwFileVersionLS >> 0 ) & 0xffff; + const DWORD major = (fi.dwFileVersionMS >> 16) & 0xffff; + const DWORD minor = (fi.dwFileVersionMS >> 0) & 0xffff; + const DWORD maintenance = (fi.dwFileVersionLS >> 16) & 0xffff; + const DWORD build = (fi.dwFileVersionLS >> 0) & 0xffff; if (major == 0 && minor == 0 && maintenance == 0 && build == 0) { return {}; } - return QString("%1.%2.%3.%4") - .arg(major).arg(minor).arg(maintenance).arg(build); + return QString("%1.%2.%3.%4").arg(major).arg(minor).arg(maintenance).arg(build); } QDateTime Module::getTimestamp(const VS_FIXEDFILEINFO& fi) const @@ -261,16 +254,15 @@ QDateTime Module::getTimestamp(const VS_FIXEDFILEINFO& fi) const // time on the file // opening the file - HandlePtr h(CreateFileW( - m_path.toStdWString().c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)); + HandlePtr h(CreateFileW(m_path.toStdWString().c_str(), GENERIC_READ, + FILE_SHARE_READ, nullptr, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, 0)); if (h.get() == INVALID_HANDLE_VALUE) { const auto e = GetLastError(); - log::debug( - "can't open file '{}' for timestamp, {}", - m_path, formatSystemMessage(e)); + log::debug("can't open file '{}' for timestamp, {}", m_path, + formatSystemMessage(e)); return {}; } @@ -279,50 +271,42 @@ QDateTime Module::getTimestamp(const VS_FIXEDFILEINFO& fi) const if (!GetFileTime(h.get(), &ft, nullptr, nullptr)) { const auto e = GetLastError(); - log::error( - "can't get file time for '{}', {}", - m_path, formatSystemMessage(e)); + log::error("can't get file time for '{}', {}", m_path, formatSystemMessage(e)); return {}; } } else { // use the time from the file info ft.dwHighDateTime = fi.dwFileDateMS; - ft.dwLowDateTime = fi.dwFileDateLS; + ft.dwLowDateTime = fi.dwFileDateLS; } - // converting to SYSTEMTIME SYSTEMTIME utc = {}; if (!FileTimeToSystemTime(&ft, &utc)) { log::error( - "FileTimeToSystemTime() failed on timestamp high={:#x} low={:#x} for '{}'", - ft.dwHighDateTime, ft.dwLowDateTime, m_path); + "FileTimeToSystemTime() failed on timestamp high={:#x} low={:#x} for '{}'", + ft.dwHighDateTime, ft.dwLowDateTime, m_path); return {}; } - return QDateTime( - QDate(utc.wYear, utc.wMonth, utc.wDay), - QTime(utc.wHour, utc.wMinute, utc.wSecond, utc.wMilliseconds)); + return QDateTime(QDate(utc.wYear, utc.wMonth, utc.wDay), + QTime(utc.wHour, utc.wMinute, utc.wSecond, utc.wMilliseconds)); } bool Module::interesting() const { static const auto windir = []() -> QString { - try - { - return QDir::toNativeSeparators( - MOBase::getKnownFolder(FOLDERID_Windows).path()) + "\\"; - } - catch(...) - { + try { + return QDir::toNativeSeparators(MOBase::getKnownFolder(FOLDERID_Windows).path()) + + "\\"; + } catch (...) { return "c:\\windows\\"; } }(); - if (m_path.startsWith(windir, Qt::CaseInsensitive)) { return false; } @@ -330,15 +314,10 @@ bool Module::interesting() const return true; } - QString Module::getMD5() const { static const std::set<QString> ignore = { - "\\windows\\", - "\\program files\\", - "\\program files (x86)\\", - "\\programdata\\" - }; + "\\windows\\", "\\program files\\", "\\program files (x86)\\", "\\programdata\\"}; // don't calculate md5 for system files, it's not really relevant and // it takes a while @@ -366,21 +345,13 @@ QString Module::getMD5() const return hash.result().toHex(); } +Process::Process() : Process(0, 0, {}) {} -Process::Process() - : Process(0, 0, {}) -{ -} - -Process::Process(HANDLE h) - : Process(::GetProcessId(h), 0, {}) -{ -} +Process::Process(HANDLE h) : Process(::GetProcessId(h), 0, {}) {} Process::Process(DWORD pid, DWORD ppid, QString name) - : m_pid(pid), m_ppid(ppid), m_name(std::move(name)) -{ -} + : m_pid(pid), m_ppid(ppid), m_name(std::move(name)) +{} bool Process::isValid() const { @@ -413,9 +384,9 @@ const QString& Process::name() const HandlePtr Process::openHandleForWait() const { const auto rights = - PROCESS_QUERY_LIMITED_INFORMATION | // exit code, image name, etc. - SYNCHRONIZE | // wait functions - PROCESS_SET_QUOTA | PROCESS_TERMINATE; // add to job + PROCESS_QUERY_LIMITED_INFORMATION | // exit code, image name, etc. + SYNCHRONIZE | // wait functions + PROCESS_SET_QUOTA | PROCESS_TERMINATE; // add to job // don't log errors, failure can happen if the process doesn't exist return HandlePtr(OpenProcess(rights, FALSE, m_pid)); @@ -426,8 +397,7 @@ HandlePtr Process::openHandleForWait() const // bool Process::canAccess() const { - HandlePtr h(OpenProcess( - PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, m_pid)); + HandlePtr h(OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, m_pid)); if (!h) { const auto e = GetLastError(); @@ -454,25 +424,22 @@ const std::vector<Process>& Process::children() const return m_children; } - std::vector<Module> getLoadedModules() { - HandlePtr snapshot(CreateToolhelp32Snapshot( - TH32CS_SNAPMODULE32 | TH32CS_SNAPMODULE, GetCurrentProcessId())); + HandlePtr snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPMODULE32 | TH32CS_SNAPMODULE, + GetCurrentProcessId())); - if (snapshot.get() == INVALID_HANDLE_VALUE) - { + if (snapshot.get() == INVALID_HANDLE_VALUE) { const auto e = GetLastError(); log::error("CreateToolhelp32Snapshot() failed, {}", formatSystemMessage(e)); return {}; } MODULEENTRY32 me = {}; - me.dwSize = sizeof(me); + me.dwSize = sizeof(me); // first module, this shouldn't fail because there's at least the executable - if (!Module32First(snapshot.get(), &me)) - { + if (!Module32First(snapshot.get(), &me)) { const auto e = GetLastError(); log::error("Module32First() failed, {}", formatSystemMessage(e)); return {}; @@ -480,8 +447,7 @@ std::vector<Module> getLoadedModules() std::vector<Module> v; - for (;;) - { + for (;;) { const auto path = QString::fromWCharArray(me.szExePath); if (!path.isEmpty()) { v.push_back(Module(path, me.modBaseSize)); @@ -503,26 +469,24 @@ std::vector<Module> getLoadedModules() // sorting by display name std::sort(v.begin(), v.end(), [](auto&& a, auto&& b) { return (a.displayPath().compare(b.displayPath(), Qt::CaseInsensitive) < 0); - }); + }); return v; } - template <class F> void forEachRunningProcess(F&& f) { HandlePtr snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)); - if (snapshot.get() == INVALID_HANDLE_VALUE) - { + if (snapshot.get() == INVALID_HANDLE_VALUE) { const auto e = GetLastError(); log::error("CreateToolhelp32Snapshot() failed, {}", formatSystemMessage(e)); return; } PROCESSENTRY32 entry = {}; - entry.dwSize = sizeof(entry); + entry.dwSize = sizeof(entry); // first process, this shouldn't fail because there's at least one process // running @@ -532,15 +496,13 @@ void forEachRunningProcess(F&& f) return; } - for (;;) - { + for (;;) { if (!f(entry)) { break; } // next process - if (!Process32Next(snapshot.get(), &entry)) - { + if (!Process32Next(snapshot.get(), &entry)) { const auto e = GetLastError(); // no more processes is not an error @@ -557,10 +519,8 @@ std::vector<Process> getRunningProcesses() std::vector<Process> v; forEachRunningProcess([&](auto&& entry) { - v.push_back(Process( - entry.th32ProcessID, - entry.th32ParentProcessID, - QString::fromStdWString(entry.szExeFile))); + v.push_back(Process(entry.th32ProcessID, entry.th32ParentProcessID, + QString::fromStdWString(entry.szExeFile))); return true; }); @@ -580,13 +540,12 @@ void findChildren(Process& parent, const std::vector<Process>& processes) } } - Process getProcessTreeFromProcess(HANDLE h) { Process root; const auto parentPID = ::GetProcessId(h); - const auto v = getRunningProcesses(); + const auto v = getRunningProcesses(); for (auto&& p : v) { if (p.pid() == parentPID) { @@ -600,7 +559,6 @@ Process getProcessTreeFromProcess(HANDLE h) return root; } - std::vector<DWORD> processesInJob(HANDLE h) { const int MaxTries = 5; @@ -609,18 +567,17 @@ std::vector<DWORD> processesInJob(HANDLE h) DWORD maxIds = 100; // for logging - DWORD lastCount=0, lastAssigned=0; + DWORD lastCount = 0, lastAssigned = 0; - - for (int tries=0; tries<MaxTries; ++tries) { - const DWORD idsSize = sizeof(ULONG_PTR) * maxIds; + for (int tries = 0; tries < MaxTries; ++tries) { + const DWORD idsSize = sizeof(ULONG_PTR) * maxIds; const DWORD bufferSize = sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + idsSize; MallocPtr<void> buffer(std::malloc(bufferSize)); auto* ids = static_cast<JOBOBJECT_BASIC_PROCESS_ID_LIST*>(buffer.get()); - const auto r = QueryInformationJobObject( - h, JobObjectBasicProcessIdList, ids, bufferSize, nullptr); + const auto r = QueryInformationJobObject(h, JobObjectBasicProcessIdList, ids, + bufferSize, nullptr); if (!r) { const auto e = GetLastError(); @@ -632,7 +589,7 @@ std::vector<DWORD> processesInJob(HANDLE h) if (ids->NumberOfProcessIdsInList >= ids->NumberOfAssignedProcesses) { std::vector<DWORD> v; - for (DWORD i=0; i<ids->NumberOfProcessIdsInList; ++i) { + for (DWORD i = 0; i < ids->NumberOfProcessIdsInList; ++i) { v.push_back(ids->ProcessIdList[i]); } @@ -643,18 +600,17 @@ std::vector<DWORD> processesInJob(HANDLE h) maxIds *= 2; // for logging - lastCount = ids->NumberOfProcessIdsInList; + lastCount = ids->NumberOfProcessIdsInList; lastAssigned = ids->NumberOfAssignedProcesses; } - log::error( - "failed to get processes in job, can't get a buffer large enough, " - "{}/{} ids", lastCount, lastAssigned); + log::error("failed to get processes in job, can't get a buffer large enough, " + "{}/{} ids", + lastCount, lastAssigned); return {}; } - void findChildProcesses(Process& parent, std::vector<Process>& processes) { // find all processes that are direct children of `parent` @@ -687,10 +643,8 @@ Process getProcessTreeFromJob(HANDLE h) forEachRunningProcess([&](auto&& entry) { for (auto&& id : ids) { if (entry.th32ProcessID == id) { - ps.push_back(Process( - entry.th32ProcessID, - entry.th32ParentProcessID, - QString::fromStdWString(entry.szExeFile))); + ps.push_back(Process(entry.th32ProcessID, entry.th32ParentProcessID, + QString::fromStdWString(entry.szExeFile))); break; } @@ -705,7 +659,7 @@ Process getProcessTreeFromJob(HANDLE h) // getting processes whose parent is not in the list for (auto&& possibleRoot : ps) { const auto ppid = possibleRoot.ppid(); - bool found = false; + bool found = false; for (auto&& p : ps) { if (p.pid() == ppid) { @@ -756,8 +710,8 @@ bool isJobHandle(HANDLE h) { JOBOBJECT_BASIC_ACCOUNTING_INFORMATION info = {}; - const auto r = ::QueryInformationJobObject( - h, JobObjectBasicAccountingInformation, &info, sizeof(info), nullptr); + const auto r = ::QueryInformationJobObject(h, JobObjectBasicAccountingInformation, + &info, sizeof(info), nullptr); return r; } @@ -792,7 +746,7 @@ QString getProcessName(HANDLE process) return badName; } - const DWORD bufferSize = MAX_PATH; + const DWORD bufferSize = MAX_PATH; wchar_t buffer[bufferSize + 1] = {}; const auto realSize = ::GetProcessImageFileNameW(process, buffer, bufferSize); @@ -829,10 +783,9 @@ DWORD getProcessParentID(DWORD pid) return ppid; } - DWORD getProcessParentID(HANDLE handle) { return getProcessParentID(GetProcessId(handle)); } -} // namespace +} // namespace env diff --git a/src/envmodule.h b/src/envmodule.h index 4b85d737..1bf99d5b 100644 --- a/src/envmodule.h +++ b/src/envmodule.h @@ -1,8 +1,8 @@ #ifndef ENV_MODULE_H #define ENV_MODULE_H -#include <QString> #include <QDateTime> +#include <QString> namespace env { @@ -23,7 +23,6 @@ struct HandleCloser using HandlePtr = std::unique_ptr<HANDLE, HandleCloser>; - // represents one module // class Module @@ -116,7 +115,6 @@ private: QString getFileDescription(std::byte* buffer) const; }; - // represents one process // class Process @@ -149,7 +147,6 @@ private: std::vector<Process> m_children; }; - std::vector<Process> getRunningProcesses(); std::vector<Module> getLoadedModules(); @@ -163,6 +160,6 @@ QString getProcessName(HANDLE process); DWORD getProcessParentID(DWORD pid); DWORD getProcessParentID(HANDLE handle); -} // namespace env +} // namespace env -#endif // ENV_MODULE_H +#endif // ENV_MODULE_H diff --git a/src/envsecurity.cpp b/src/envsecurity.cpp index fd65b483..914a70ba 100644 --- a/src/envsecurity.cpp +++ b/src/envsecurity.cpp @@ -1,13 +1,13 @@ #include "envsecurity.h" #include "env.h" #include "envmodule.h" -#include <utility.h> #include <log.h> +#include <utility.h> #include <Wbemidl.h> -#include <wscapi.h> #include <comdef.h> #include <netfw.h> +#include <wscapi.h> #pragma comment(lib, "Wbemuuid.lib") #include <accctrl.h> @@ -23,18 +23,16 @@ using namespace MOBase; class WMI { public: - class failed {}; + class failed + {}; WMI(const std::string& ns) { - try - { + try { createLocator(); createService(ns); setSecurity(); - } - catch(failed&) - { + } catch (failed&) { } } @@ -50,13 +48,12 @@ public: return; } - for (;;) - { + for (;;) { COMPtr<IWbemClassObject> object; { IWbemClassObject* rawObject = nullptr; - ULONG count = 0; + ULONG count = 0; auto ret = enumerator->Next(WBEM_INFINITE, 1, &rawObject, &count); if (count == 0 || !rawObject) { @@ -83,14 +80,12 @@ private: { void* rawLocator = nullptr; - const auto ret = CoCreateInstance( - CLSID_WbemLocator, nullptr, CLSCTX_INPROC_SERVER, - IID_IWbemLocator, &rawLocator); + const auto ret = CoCreateInstance(CLSID_WbemLocator, nullptr, CLSCTX_INPROC_SERVER, + IID_IWbemLocator, &rawLocator); if (FAILED(ret) || !rawLocator) { - log::error( - "CoCreateInstance for WbemLocator failed, {}", - formatSystemMessage(ret)); + log::error("CoCreateInstance for WbemLocator failed, {}", + formatSystemMessage(ret)); throw failed(); } @@ -102,16 +97,14 @@ private: { IWbemServices* rawService = nullptr; - const auto res = m_locator->ConnectServer( - _bstr_t(ns.c_str()), - nullptr, nullptr, nullptr, 0, nullptr, nullptr, - &rawService); + const auto res = + m_locator->ConnectServer(_bstr_t(ns.c_str()), nullptr, nullptr, nullptr, 0, + nullptr, nullptr, &rawService); if (FAILED(res) || !rawService) { // don't log as error, seems to happen often for some people - log::debug( - "locator->ConnectServer() failed for namespace '{}', {}", - ns, formatSystemMessage(res)); + log::debug("locator->ConnectServer() failed for namespace '{}', {}", ns, + formatSystemMessage(res)); throw failed(); } @@ -121,31 +114,25 @@ private: void setSecurity() { - auto ret = CoSetProxyBlanket( - m_service.get(), RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr, - RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, 0, EOAC_NONE); + auto ret = CoSetProxyBlanket(m_service.get(), RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, + nullptr, RPC_C_AUTHN_LEVEL_CALL, + RPC_C_IMP_LEVEL_IMPERSONATE, 0, EOAC_NONE); - if (FAILED(ret)) - { + if (FAILED(ret)) { log::error("CoSetProxyBlanket() failed, {}", formatSystemMessage(ret)); throw failed(); } } - COMPtr<IEnumWbemClassObject> getEnumerator( - const std::string& query) + COMPtr<IEnumWbemClassObject> getEnumerator(const std::string& query) { IEnumWbemClassObject* rawEnumerator = NULL; auto ret = m_service->ExecQuery( - bstr_t("WQL"), - bstr_t(query.c_str()), - WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, - NULL, - &rawEnumerator); + bstr_t("WQL"), bstr_t(query.c_str()), + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &rawEnumerator); - if (FAILED(ret) || !rawEnumerator) - { + if (FAILED(ret) || !rawEnumerator) { log::error("query '{}' failed, {}", query, formatSystemMessage(ret)); return {}; } @@ -154,14 +141,11 @@ private: } }; - -SecurityProduct::SecurityProduct( - QUuid guid, QString name, int provider, - bool active, bool upToDate) : - m_guid(std::move(guid)), m_name(std::move(name)), m_provider(provider), - m_active(active), m_upToDate(upToDate) -{ -} +SecurityProduct::SecurityProduct(QUuid guid, QString name, int provider, bool active, + bool upToDate) + : m_guid(std::move(guid)), m_name(std::move(name)), m_provider(provider), + m_active(active), m_upToDate(upToDate) +{} const QUuid& SecurityProduct::guid() const { @@ -250,12 +234,10 @@ QString SecurityProduct::providerToString() const return ps.join("|"); } - std::optional<SecurityProduct> handleProduct(IWbemClassObject* o) { VARIANT prop; - // guid auto ret = o->Get(L"instanceGuid", 0, &prop, 0, 0); if (FAILED(ret)) { @@ -271,7 +253,6 @@ std::optional<SecurityProduct> handleProduct(IWbemClassObject* o) const QUuid guid(QString::fromWCharArray(prop.bstrVal)); VariantClear(&prop); - // display name QString displayName; ret = o->Get(L"displayName", 0, &prop, 0, 0); @@ -286,10 +267,9 @@ std::optional<SecurityProduct> handleProduct(IWbemClassObject* o) VariantClear(&prop); - // product state DWORD state = 0; - ret = o->Get(L"productState", 0, &prop, 0, 0); + ret = o->Get(L"productState", 0, &prop, 0, 0); if (FAILED(ret)) { log::error("failed to get productState, {}", formatSystemMessage(ret)); @@ -309,12 +289,11 @@ std::optional<SecurityProduct> handleProduct(IWbemClassObject* o) VariantClear(&prop); - - const auto provider = static_cast<int>((state >> 16) & 0xff); - const auto scanner = (state >> 8) & 0xff; + const auto provider = static_cast<int>((state >> 16) & 0xff); + const auto scanner = (state >> 8) & 0xff; const auto definitions = state & 0xff; - const bool active = ((scanner & 0x10) != 0); + const bool active = ((scanner & 0x10) != 0); const bool upToDate = (definitions == 0); return SecurityProduct(guid, displayName, provider, active, upToDate); @@ -328,7 +307,7 @@ std::vector<SecurityProduct> getSecurityProductsFromWMI() std::map<QUuid, SecurityProduct> map; auto f = [&](auto* o) { - if (auto p=handleProduct(o)) { + if (auto p = handleProduct(o)) { map.emplace(p->guid(), std::move(*p)); } }; @@ -365,14 +344,12 @@ std::optional<SecurityProduct> getWindowsFirewall() { void* rawPolicy = nullptr; - hr = CoCreateInstance( - __uuidof(NetFwPolicy2), nullptr, CLSCTX_INPROC_SERVER, - __uuidof(INetFwPolicy2), &rawPolicy); + hr = CoCreateInstance(__uuidof(NetFwPolicy2), nullptr, CLSCTX_INPROC_SERVER, + __uuidof(INetFwPolicy2), &rawPolicy); if (FAILED(hr) || !rawPolicy) { - log::error( - "CoCreateInstance for NetFwPolicy2 failed, {}", - formatSystemMessage(hr)); + log::error("CoCreateInstance for NetFwPolicy2 failed, {}", + formatSystemMessage(hr)); return {}; } @@ -384,8 +361,7 @@ std::optional<SecurityProduct> getWindowsFirewall() if (policy) { hr = policy->get_FirewallEnabled(NET_FW_PROFILE2_PUBLIC, &enabledVariant); - if (FAILED(hr)) - { + if (FAILED(hr)) { // EPT_S_NOT_REGISTERED is "There are no more endpoints available from the // endpoint mapper", which seems to happen sometimes on Windows 7 when the // firewall has been disabled, so treat it as such and don't log it @@ -408,58 +384,49 @@ std::optional<SecurityProduct> getWindowsFirewall() return {}; } - return SecurityProduct( - {}, "Windows Firewall", WSC_SECURITY_PROVIDER_FIREWALL, true, true); + return SecurityProduct({}, "Windows Firewall", WSC_SECURITY_PROVIDER_FIREWALL, true, + true); } - std::vector<SecurityProduct> getSecurityProducts() { std::vector<SecurityProduct> v; { auto fromWMI = getSecurityProductsFromWMI(); - v.insert( - v.end(), - std::make_move_iterator(fromWMI.begin()), - std::make_move_iterator(fromWMI.end())); + v.insert(v.end(), std::make_move_iterator(fromWMI.begin()), + std::make_move_iterator(fromWMI.end())); } - if (auto p=getWindowsFirewall()) { + if (auto p = getWindowsFirewall()) { v.push_back(std::move(*p)); } return v; } - class failed { public: failed(DWORD e, QString what) - : m_what(what + ", " + QString::fromStdWString(formatSystemMessage(e))) - { - } + : m_what(what + ", " + QString::fromStdWString(formatSystemMessage(e))) + {} - QString what() const - { - return m_what; - } + QString what() const { return m_what; } private: QString m_what; }; - MallocPtr<SECURITY_DESCRIPTOR> getSecurityDescriptor(const QString& path) { const auto wpath = path.toStdWString(); - BOOL ret = FALSE; + BOOL ret = FALSE; DWORD length = 0; - ret = ::GetFileSecurityW( - wpath.c_str(), DACL_SECURITY_INFORMATION|OWNER_SECURITY_INFORMATION, - nullptr, 0, &length); + ret = ::GetFileSecurityW(wpath.c_str(), + DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION, + nullptr, 0, &length); if (!ret || length == 0) { const auto e = GetLastError(); @@ -478,13 +445,13 @@ MallocPtr<SECURITY_DESCRIPTOR> getSecurityDescriptor(const QString& path) } MallocPtr<SECURITY_DESCRIPTOR> sd( - static_cast<SECURITY_DESCRIPTOR*>(std::malloc(length))); + static_cast<SECURITY_DESCRIPTOR*>(std::malloc(length))); std::memset(sd.get(), 0, length); - ret = ::GetFileSecurityW( - wpath.c_str(), DACL_SECURITY_INFORMATION|OWNER_SECURITY_INFORMATION, - sd.get(), length, &length); + ret = ::GetFileSecurityW(wpath.c_str(), + DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION, + sd.get(), length, &length); if (!ret) { const auto e = GetLastError(); @@ -496,9 +463,9 @@ MallocPtr<SECURITY_DESCRIPTOR> getSecurityDescriptor(const QString& path) PACL getDacl(SECURITY_DESCRIPTOR* sd) { - BOOL present = FALSE; + BOOL present = FALSE; BOOL daclDefaulted = FALSE; - PACL acl = nullptr; + PACL acl = nullptr; BOOL ret = ::GetSecurityDescriptorDacl(sd, &present, &acl, &daclDefaulted); @@ -531,7 +498,7 @@ PSID getFileOwner(SECURITY_DESCRIPTOR* sd) MallocPtr<void> getCurrentUser() { - HANDLE hnd = ::GetCurrentProcess(); + HANDLE hnd = ::GetCurrentProcess(); HANDLE rawToken = 0; BOOL ret = ::OpenProcessToken(hnd, TOKEN_QUERY, &rawToken); @@ -543,7 +510,7 @@ MallocPtr<void> getCurrentUser() HandlePtr token(rawToken); DWORD retsize = 0; - ret = ::GetTokenInformation(token.get(), TokenUser, 0, 0, &retsize); + ret = ::GetTokenInformation(token.get(), TokenUser, 0, 0, &retsize); if (!ret) { const auto e = GetLastError(); @@ -553,8 +520,8 @@ MallocPtr<void> getCurrentUser() } MallocPtr<void> tokenBuffer(std::malloc(retsize)); - ret = ::GetTokenInformation( - token.get(), TokenUser, tokenBuffer.get(), retsize, &retsize); + ret = ::GetTokenInformation(token.get(), TokenUser, tokenBuffer.get(), retsize, + &retsize); if (!ret) { const auto e = GetLastError(); @@ -562,7 +529,7 @@ MallocPtr<void> getCurrentUser() } PSID tokenSid = ((PTOKEN_USER)(tokenBuffer.get()))->User.Sid; - DWORD sidLen = ::GetLengthSid(tokenSid); + DWORD sidLen = ::GetLengthSid(tokenSid); MallocPtr<void> currentUserSID((SID*)(malloc(sidLen))); ret = ::CopySid(sidLen, currentUserSID.get(), tokenSid); @@ -581,7 +548,7 @@ ACCESS_MASK getEffectiveRights(ACL* dacl, PSID sid) BuildTrusteeWithSid(&trustee, sid); ACCESS_MASK access = 0; - DWORD ret = ::GetEffectiveRightsFromAclW(dacl, &trustee, &access); + DWORD ret = ::GetEffectiveRightsFromAclW(dacl, &trustee, &access); if (ret != ERROR_SUCCESS) { throw failed(ret, "GetEffectiveRightsFromAclW()"); @@ -592,11 +559,11 @@ ACCESS_MASK getEffectiveRights(ACL* dacl, PSID sid) QString getUsername(PSID owner) { - DWORD nameSize=0, domainSize=0; + DWORD nameSize = 0, domainSize = 0; auto use = SidTypeUnknown; - BOOL ret = LookupAccountSidW( - nullptr, owner, nullptr, &nameSize, nullptr, &domainSize, &use); + BOOL ret = + LookupAccountSidW(nullptr, owner, nullptr, &nameSize, nullptr, &domainSize, &use); if (!ret) { const auto e = GetLastError(); @@ -606,18 +573,18 @@ QString getUsername(PSID owner) } } - auto wsName = std::make_unique<wchar_t[]>(nameSize); + auto wsName = std::make_unique<wchar_t[]>(nameSize); auto wsDomain = std::make_unique<wchar_t[]>(domainSize); - ret = LookupAccountSidW( - nullptr, owner, wsName.get(), &nameSize, wsDomain.get(), &domainSize, &use); + ret = LookupAccountSidW(nullptr, owner, wsName.get(), &nameSize, wsDomain.get(), + &domainSize, &use); if (!ret) { const auto e = GetLastError(); throw failed(e, "LookupAccountSid()"); } - const QString name = QString::fromWCharArray(wsName.get(), nameSize); + const QString name = QString::fromWCharArray(wsName.get(), nameSize); const QString domain = QString::fromWCharArray(wsDomain.get(), domainSize); if (!name.isEmpty() && !domain.isEmpty()) { @@ -720,10 +687,9 @@ FileRights makeFileRights(ACCESS_MASK m) } // 0x001f01ff - const auto normalRights = - STANDARD_RIGHTS_ALL | - FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | - FILE_DELETE_CHILD; + const auto normalRights = STANDARD_RIGHTS_ALL | FILE_GENERIC_READ | + FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | + FILE_DELETE_CHILD; if (m == normalRights) { fr.normalRights = true; @@ -736,13 +702,12 @@ FileSecurity getFileSecurity(const QString& path) { FileSecurity fs; - try - { - auto sd = getSecurityDescriptor(path); - auto dacl = getDacl(sd.get()); + try { + auto sd = getSecurityDescriptor(path); + auto dacl = getDacl(sd.get()); auto currentUser = getCurrentUser(); - auto owner = getFileOwner(sd.get()); - auto access = getEffectiveRights(dacl, currentUser.get()); + auto owner = getFileOwner(sd.get()); + auto access = getEffectiveRights(dacl, currentUser.get()); fs.rights = makeFileRights(access); @@ -751,12 +716,10 @@ FileSecurity getFileSecurity(const QString& path) } else { fs.owner = getUsername(owner); } - } - catch(failed& f) - { + } catch (failed& f) { fs.error = f.what(); } return fs; } -} // namespace +} // namespace env diff --git a/src/envsecurity.h b/src/envsecurity.h index 5f9e5332..ca69b1a2 100644 --- a/src/envsecurity.h +++ b/src/envsecurity.h @@ -1,8 +1,8 @@ #ifndef ENV_SECURITY_H #define ENV_SECURITY_H -#include <QUuid> #include <QString> +#include <QUuid> namespace env { @@ -12,9 +12,7 @@ namespace env class SecurityProduct { public: - SecurityProduct( - QUuid guid, QString name, int provider, - bool active, bool upToDate); + SecurityProduct(QUuid guid, QString name, int provider, bool active, bool upToDate); // guid // @@ -50,14 +48,12 @@ private: QString providerToString() const; }; - std::vector<SecurityProduct> getSecurityProducts(); - struct FileRights { QStringList list; - bool hasExecute = false; + bool hasExecute = false; bool normalRights = false; }; @@ -70,6 +66,6 @@ struct FileSecurity FileSecurity getFileSecurity(const QString& file); -} // namespace env +} // namespace env -#endif // ENV_SECURITY_H +#endif // ENV_SECURITY_H diff --git a/src/envshell.cpp b/src/envshell.cpp index f3146b9f..3d0f774e 100644 --- a/src/envshell.cpp +++ b/src/envshell.cpp @@ -9,46 +9,34 @@ namespace env using namespace MOBase; const int QCM_FIRST = 1; -const int QCM_LAST = 0x7ff; +const int QCM_LAST = 0x7ff; class MenuFailed : public std::runtime_error { public: MenuFailed(HRESULT r, const std::string& what) - : runtime_error(fmt::format( - "{}, {}", - what, QString::fromStdWString(formatSystemMessage(r)).toStdString())) - { - } + : runtime_error( + fmt::format("{}, {}", what, + QString::fromStdWString(formatSystemMessage(r)).toStdString())) + {} }; - class DummyMenu { public: - DummyMenu(QString s) - : m_what(s) - { - } + DummyMenu(QString s) : m_what(s) {} - const QString& what() const - { - return m_what; - } + const QString& what() const { return m_what; } private: QString m_what; }; - struct IdlsFreer { const std::vector<LPCITEMIDLIST>& v; - IdlsFreer(const std::vector<LPCITEMIDLIST>& v) - : v(v) - { - } + IdlsFreer(const std::vector<LPCITEMIDLIST>& v) : v(v) {} ~IdlsFreer() { @@ -58,19 +46,16 @@ struct IdlsFreer } }; - class WndProcFilter : public QAbstractNativeEventFilter { public: - using function_type = std::function< - bool (HWND hwnd, UINT m, WPARAM wp, LPARAM lp, LRESULT* out)>; + using function_type = + std::function<bool(HWND hwnd, UINT m, WPARAM wp, LPARAM lp, LRESULT* out)>; - WndProcFilter(function_type f) - : m_f(std::move(f)) - { - } + WndProcFilter(function_type f) : m_f(std::move(f)) {} - bool nativeEventFilter(const QByteArray& eventType, void* message, qintptr* result) override + bool nativeEventFilter(const QByteArray& eventType, void* message, + qintptr* result) override { MSG* msg = (MSG*)message; if (!msg) { @@ -92,9 +77,6 @@ private: function_type m_f; }; - - - HWND getHWND(QMainWindow* mw) { if (mw) { @@ -107,9 +89,8 @@ HWND getHWND(QMainWindow* mw) // adapted from // https://devblogs.microsoft.com/oldnewthing/20040928-00/?p=37723 // -HRESULT IContextMenu_GetCommandString( - IContextMenu *pcm, UINT_PTR idCmd, UINT uFlags, - UINT *pwReserved, LPWSTR pszName, UINT cchMax) +HRESULT IContextMenu_GetCommandString(IContextMenu* pcm, UINT_PTR idCmd, UINT uFlags, + UINT* pwReserved, LPWSTR pszName, UINT cchMax) { // Callers are expected to be using Unicode. if (!(uFlags & GCS_UNICODE)) { @@ -130,8 +111,7 @@ HRESULT IContextMenu_GetCommandString( // doing anything. pszName[0] = L'\0'; - HRESULT hr = pcm->GetCommandString( - idCmd, uFlags, pwReserved, (LPSTR)pszName, cchMax); + HRESULT hr = pcm->GetCommandString(idCmd, uFlags, pwReserved, (LPSTR)pszName, cchMax); if (SUCCEEDED(hr) && pszName[0] == L'\0') { // Rats, a buggy IContextMenu handler that returned success @@ -143,14 +123,13 @@ HRESULT IContextMenu_GetCommandString( // try again with ANSI � pad the buffer with one extra character // to compensate for context menu handlers that overflow by // one character. - LPSTR pszAnsi = (LPSTR)LocalAlloc( - LMEM_FIXED, (cchMax + 1) * sizeof(CHAR)); + LPSTR pszAnsi = (LPSTR)LocalAlloc(LMEM_FIXED, (cchMax + 1) * sizeof(CHAR)); if (pszAnsi) { pszAnsi[0] = '\0'; - hr = pcm->GetCommandString( - idCmd, uFlags & ~GCS_UNICODE, pwReserved, pszAnsi, cchMax); + hr = pcm->GetCommandString(idCmd, uFlags & ~GCS_UNICODE, pwReserved, pszAnsi, + cchMax); if (SUCCEEDED(hr) && pszAnsi[0] == '\0') { // Rats, a buggy IContextMenu handler that returned success @@ -174,11 +153,7 @@ HRESULT IContextMenu_GetCommandString( return hr; } - -ShellMenu::ShellMenu(QMainWindow* mw) - : m_mw(mw) -{ -} +ShellMenu::ShellMenu(QMainWindow* mw) : m_mw(mw) {} void ShellMenu::addFile(QFileInfo fi) { @@ -197,22 +172,21 @@ void ShellMenu::exec(const QPoint& pos) return; } - try - { + try { const auto hwnd = getHWND(m_mw); auto filter = std::make_unique<WndProcFilter>( - [&](HWND h, UINT m, WPARAM wp, LPARAM lp, LRESULT* out) { - return wndProc(h, m, wp, lp, out); - }); + [&](HWND h, UINT m, WPARAM wp, LPARAM lp, LRESULT* out) { + return wndProc(h, m, wp, lp, out); + }); QCoreApplication::instance()->installNativeEventFilter(filter.get()); - const int cmd = TrackPopupMenuEx( - menu, TPM_RETURNCMD, pos.x(), pos.y(), hwnd, nullptr); + const int cmd = + TrackPopupMenuEx(menu, TPM_RETURNCMD, pos.x(), pos.y(), hwnd, nullptr); if (m_mw) { - if (auto* sb=m_mw->statusBar()) { + if (auto* sb = m_mw->statusBar()) { sb->clearMessage(); } } @@ -222,17 +196,12 @@ void ShellMenu::exec(const QPoint& pos) } invoke(pos, cmd - QCM_FIRST); - } - catch(MenuFailed& e) - { + } catch (MenuFailed& e) { if (m_files.size() == 1) { - log::error( - "can't exec shell menu for '{}': {}", - QDir::toNativeSeparators(m_files[0].absoluteFilePath()), e.what()); + log::error("can't exec shell menu for '{}': {}", + QDir::toNativeSeparators(m_files[0].absoluteFilePath()), e.what()); } else { - log::error( - "can't exec shell menu for {} files: {}", - m_files.size(), e.what()); + log::error("can't exec shell menu for {} files: {}", m_files.size(), e.what()); } } } @@ -279,21 +248,21 @@ bool ShellMenu::wndProc(HWND h, UINT m, WPARAM wp, LPARAM lp, LRESULT* out) // adapted from // https://devblogs.microsoft.com/oldnewthing/20040928-00/?p=37723 // -void ShellMenu::onMenuSelect( - HWND hwnd, HMENU hmenu, int item, HMENU hmenuPopup, UINT flags) +void ShellMenu::onMenuSelect(HWND hwnd, HMENU hmenu, int item, HMENU hmenuPopup, + UINT flags) { if (m_cm && item >= QCM_FIRST && item <= QCM_LAST) { WCHAR szBuf[MAX_PATH]; - const auto r = IContextMenu_GetCommandString( - m_cm.get(), item - QCM_FIRST, GCS_HELPTEXTW, NULL, szBuf, MAX_PATH); + const auto r = IContextMenu_GetCommandString(m_cm.get(), item - QCM_FIRST, + GCS_HELPTEXTW, NULL, szBuf, MAX_PATH); if (FAILED(r)) { lstrcpynW(szBuf, L"No help available.", MAX_PATH); } if (m_mw) { - if (auto* sb=m_mw->statusBar()) { + if (auto* sb = m_mw->statusBar()) { sb->showMessage(QString::fromWCharArray(szBuf)); } } @@ -307,8 +276,7 @@ void ShellMenu::create() return; } - try - { + try { auto idls = createIdls(m_files); if (idls.empty()) { @@ -322,21 +290,14 @@ void ShellMenu::create() createContextMenu(array.get()); createPopupMenu(m_cm.get()); - } - catch(DummyMenu& dm) - { + } catch (DummyMenu& dm) { m_menu = createDummyMenu(dm.what()); - } - catch(MenuFailed& e) - { + } catch (MenuFailed& e) { if (m_files.size() == 1) { - log::error( - "can't create shell menu for '{}': {}", - QDir::toNativeSeparators(m_files[0].absoluteFilePath()), e.what()); + log::error("can't create shell menu for '{}': {}", + QDir::toNativeSeparators(m_files[0].absoluteFilePath()), e.what()); } else { - log::error( - "can't create shell menu for {} files: {}", - m_files.size(), e.what()); + log::error("can't create shell menu for {} files: {}", m_files.size(), e.what()); } m_menu = createDummyMenu(QObject::tr("No menu available")); @@ -345,8 +306,7 @@ void ShellMenu::create() HMenuPtr ShellMenu::createDummyMenu(const QString& what) { - try - { + try { HMENU menu = CreatePopupMenu(); if (!menu) { const auto e = GetLastError(); @@ -359,9 +319,7 @@ HMenuPtr ShellMenu::createDummyMenu(const QString& what) } return HMenuPtr(menu); - } - catch(MenuFailed& e) - { + } catch (MenuFailed& e) { log::error("{}", what); log::error("additionally, creating the dummy menu failed: {}", e.what()); @@ -369,8 +327,7 @@ HMenuPtr ShellMenu::createDummyMenu(const QString& what) } } -std::vector<LPCITEMIDLIST> ShellMenu::createIdls( - const std::vector<QFileInfo>& files) +std::vector<LPCITEMIDLIST> ShellMenu::createIdls(const std::vector<QFileInfo>& files) { std::vector<LPCITEMIDLIST> idls; std::optional<QDir> parent; @@ -382,14 +339,13 @@ std::vector<LPCITEMIDLIST> ShellMenu::createIdls( parent = f.absoluteDir(); } else { if (*parent != f.absoluteDir()) { - throw DummyMenu(QObject::tr( - "Selected files must be in the same directory")); + throw DummyMenu(QObject::tr("Selected files must be in the same directory")); } } - auto item = createShellItem(path); + auto item = createShellItem(path); auto pidlist = getPersistIDList(item.get()); - auto absIdl = getIDList(pidlist.get()); + auto absIdl = getIDList(pidlist.get()); idls.push_back(absIdl.release()); } @@ -397,12 +353,11 @@ std::vector<LPCITEMIDLIST> ShellMenu::createIdls( return idls; } -COMPtr<IShellItemArray> ShellMenu::createItemArray( - std::vector<LPCITEMIDLIST>& idls) +COMPtr<IShellItemArray> ShellMenu::createItemArray(std::vector<LPCITEMIDLIST>& idls) { IShellItemArray* array = nullptr; - auto r = SHCreateShellItemArrayFromIDLists( - static_cast<UINT>(idls.size()), &idls[0], &array); + auto r = SHCreateShellItemArrayFromIDLists(static_cast<UINT>(idls.size()), &idls[0], + &array); if (FAILED(r)) { throw MenuFailed(r, "SHCreateShellItemArrayFromIDLists failed"); @@ -415,8 +370,8 @@ void ShellMenu::createContextMenu(IShellItemArray* array) { IContextMenu* cm = nullptr; - auto r = array->BindToHandler( - nullptr, BHID_SFUIObject, IID_IContextMenu, (void**)&cm); + auto r = + array->BindToHandler(nullptr, BHID_SFUIObject, IID_IContextMenu, (void**)&cm); if (FAILED(r)) { throw MenuFailed(r, "BindToHandler failed"); @@ -447,8 +402,7 @@ void ShellMenu::createPopupMenu(IContextMenu* cm) throw MenuFailed(e, "CreatePopupMenu failed"); } - const auto r = cm->QueryContextMenu( - hmenu, 0, QCM_FIRST, QCM_LAST, CMF_EXTENDEDVERBS); + const auto r = cm->QueryContextMenu(hmenu, 0, QCM_FIRST, QCM_LAST, CMF_EXTENDEDVERBS); if (FAILED(r)) { throw MenuFailed(r, "QueryContextMenu failed"); @@ -461,8 +415,8 @@ COMPtr<IShellItem> ShellMenu::createShellItem(const std::wstring& path) { IShellItem* item = nullptr; - auto r = SHCreateItemFromParsingName( - path.c_str(), nullptr, IID_IShellItem, (void**)&item); + auto r = + SHCreateItemFromParsingName(path.c_str(), nullptr, IID_IShellItem, (void**)&item); if (FAILED(r)) { throw MenuFailed(r, "SHCreateItemFromParsingName failed"); @@ -474,7 +428,7 @@ COMPtr<IShellItem> ShellMenu::createShellItem(const std::wstring& path) COMPtr<IPersistIDList> ShellMenu::getPersistIDList(IShellItem* item) { IPersistIDList* idl = nullptr; - auto r = item->QueryInterface(IID_IPersistIDList, (void**)&idl); + auto r = item->QueryInterface(IID_IPersistIDList, (void**)&idl); if (FAILED(r)) { throw MenuFailed(r, "QueryInterface IID_IPersistIDList failed"); @@ -486,7 +440,7 @@ COMPtr<IPersistIDList> ShellMenu::getPersistIDList(IShellItem* item) CoTaskMemPtr<LPITEMIDLIST> ShellMenu::getIDList(IPersistIDList* pidlist) { LPITEMIDLIST absIdl = nullptr; - auto r = pidlist->GetIDList(&absIdl); + auto r = pidlist->GetIDList(&absIdl); if (FAILED(r)) { throw MenuFailed(r, "GetIDList failed"); @@ -501,12 +455,12 @@ void ShellMenu::invoke(const QPoint& p, int cmd) CMINVOKECOMMANDINFOEX info = {}; - info.cbSize = sizeof(info); - info.fMask = CMIC_MASK_UNICODE | CMIC_MASK_PTINVOKE; - info.hwnd = hwnd; - info.lpVerb = MAKEINTRESOURCEA(cmd); - info.lpVerbW = MAKEINTRESOURCEW(cmd); - info.nShow = SW_SHOWNORMAL; + info.cbSize = sizeof(info); + info.fMask = CMIC_MASK_UNICODE | CMIC_MASK_PTINVOKE; + info.hwnd = hwnd; + info.lpVerb = MAKEINTRESOURCEA(cmd); + info.lpVerbW = MAKEINTRESOURCEW(cmd); + info.nShow = SW_SHOWNORMAL; info.ptInvoke = {p.x(), p.y()}; // note: this calls the query version because the Qt even loop hasn't run @@ -528,11 +482,8 @@ void ShellMenu::invoke(const QPoint& p, int cmd) } } - -ShellMenuCollection::ShellMenuCollection(QMainWindow* mw) - : m_mw(mw), m_active(nullptr) -{ -} +ShellMenuCollection::ShellMenuCollection(QMainWindow* mw) : m_mw(mw), m_active(nullptr) +{} void ShellMenuCollection::addDetails(QString s) { @@ -550,9 +501,7 @@ void ShellMenuCollection::exec(const QPoint& pos) if (!menu) { const auto e = GetLastError(); - log::error( - "CreatePopupMenu for merged menus failed, {}", - formatSystemMessage(e)); + log::error("CreatePopupMenu for merged menus failed, {}", formatSystemMessage(e)); return; } @@ -560,22 +509,19 @@ void ShellMenuCollection::exec(const QPoint& pos) if (!m_details.empty()) { for (auto&& d : m_details) { const auto s = d.toStdWString(); - const auto r = AppendMenuW(menu, MF_STRING|MF_DISABLED, 0, s.c_str()); + const auto r = AppendMenuW(menu, MF_STRING | MF_DISABLED, 0, s.c_str()); if (!r) { const auto e = GetLastError(); - log::error( - "AppendMenuW failed for details '{}', {}", - d, formatSystemMessage(e)); + log::error("AppendMenuW failed for details '{}', {}", d, + formatSystemMessage(e)); } } const auto r = AppendMenuW(menu, MF_SEPARATOR, 0, nullptr); if (!r) { const auto e = GetLastError(); - log::error( - "AppendMenuW failed for separator, {}", - formatSystemMessage(e)); + log::error("AppendMenuW failed for separator, {}", formatSystemMessage(e)); } } @@ -585,16 +531,15 @@ void ShellMenuCollection::exec(const QPoint& pos) continue; } - const auto r = AppendMenuW( - menu, MF_POPUP | MF_STRING, - reinterpret_cast<UINT_PTR>(hmenu), m.name.toStdWString().c_str()); + const auto r = + AppendMenuW(menu, MF_POPUP | MF_STRING, reinterpret_cast<UINT_PTR>(hmenu), + m.name.toStdWString().c_str()); if (!r) { const auto e = GetLastError(); - log::error( - "AppendMenuW failed for merged menu {}, {}", - m.name, formatSystemMessage(e)); + log::error("AppendMenuW failed for merged menu {}, {}", m.name, + formatSystemMessage(e)); continue; } @@ -603,17 +548,17 @@ void ShellMenuCollection::exec(const QPoint& pos) auto hwnd = getHWND(m_mw); auto filter = std::make_unique<WndProcFilter>( - [&](HWND h, UINT m, WPARAM wp, LPARAM lp, LRESULT* out) { - return wndProc(h, m, wp, lp, out); - }); + [&](HWND h, UINT m, WPARAM wp, LPARAM lp, LRESULT* out) { + return wndProc(h, m, wp, lp, out); + }); QCoreApplication::instance()->installNativeEventFilter(filter.get()); - const int cmd = TrackPopupMenuEx( - menu, TPM_RETURNCMD, pos.x(), pos.y(), hwnd, nullptr); + const int cmd = + TrackPopupMenuEx(menu, TPM_RETURNCMD, pos.x(), pos.y(), hwnd, nullptr); if (m_mw) { - if (auto* sb=m_mw->statusBar()) { + if (auto* sb = m_mw->statusBar()) { sb->clearMessage(); } } @@ -633,12 +578,11 @@ void ShellMenuCollection::exec(const QPoint& pos) m_active->menu.invoke(pos, realCmd); } -bool ShellMenuCollection::wndProc( - HWND h, UINT m, WPARAM wp, LPARAM lp, LRESULT* out) +bool ShellMenuCollection::wndProc(HWND h, UINT m, WPARAM wp, LPARAM lp, LRESULT* out) { if (m == WM_MENUSELECT) { auto* oldActive = m_active; - m_active = nullptr; + m_active = nullptr; HANDLE_WM_MENUSELECT(h, wp, lp, onMenuSelect); @@ -662,8 +606,8 @@ bool ShellMenuCollection::wndProc( return m_active->menu.wndProc(h, m, wp, lp, out); } -void ShellMenuCollection::onMenuSelect( - HWND hwnd, HMENU hmenu, int item, HMENU hmenuPopup, UINT flags) +void ShellMenuCollection::onMenuSelect(HWND hwnd, HMENU hmenu, int item, + HMENU hmenuPopup, UINT flags) { for (auto&& m : m_menus) { if (m.menu.getMenu() == hmenuPopup) { @@ -673,4 +617,4 @@ void ShellMenuCollection::onMenuSelect( } } -} // namespace +} // namespace env diff --git a/src/envshell.h b/src/envshell.h index f9245a37..f47c58c8 100644 --- a/src/envshell.h +++ b/src/envshell.h @@ -14,10 +14,10 @@ public: ShellMenu(QMainWindow* mw); // noncopyable - ShellMenu(const ShellMenu&) = delete; + ShellMenu(const ShellMenu&) = delete; ShellMenu& operator=(const ShellMenu&) = delete; - ShellMenu(ShellMenu&&) = default; - ShellMenu& operator=(ShellMenu&&) = default; + ShellMenu(ShellMenu&&) = default; + ShellMenu& operator=(ShellMenu&&) = default; void addFile(QFileInfo fi); int fileCount() const; @@ -48,11 +48,9 @@ private: CoTaskMemPtr<LPITEMIDLIST> getIDList(IPersistIDList* pidlist); HMenuPtr createDummyMenu(const QString& what); - void onMenuSelect( - HWND hwnd, HMENU hmenu, int item, HMENU hmenuPopup, UINT flags); + void onMenuSelect(HWND hwnd, HMENU hmenu, int item, HMENU hmenuPopup, UINT flags); }; - class ShellMenuCollection { public: @@ -77,10 +75,9 @@ private: bool wndProc(HWND hwnd, UINT m, WPARAM wp, LPARAM lp, LRESULT* out); - void onMenuSelect( - HWND hwnd, HMENU hmenu, int item, HMENU hmenuPopup, UINT flags); + void onMenuSelect(HWND hwnd, HMENU hmenu, int item, HMENU hmenuPopup, UINT flags); }; -} // namespace +} // namespace env -#endif // ENV_SHELL_H +#endif // ENV_SHELL_H diff --git a/src/envshortcut.cpp b/src/envshortcut.cpp index 4c9f0679..204435b7 100644 --- a/src/envshortcut.cpp +++ b/src/envshortcut.cpp @@ -1,10 +1,10 @@ #include "envshortcut.h" #include "env.h" #include "executableslist.h" -#include "instancemanager.h" #include "filesystemutilities.h" -#include <utility.h> +#include "instancemanager.h" #include <log.h> +#include <utility.h> namespace env { @@ -14,15 +14,9 @@ using namespace MOBase; class ShellLinkException { public: - ShellLinkException(QString s) - : m_what(std::move(s)) - { - } + ShellLinkException(QString s) : m_what(std::move(s)) {} - const QString& what() const - { - return m_what; - } + const QString& what() const { return m_what; } private: QString m_what; @@ -99,9 +93,7 @@ private: void throwOnFail(HRESULT r, const QString& s) { if (FAILED(r)) { - throw ShellLinkException(QString("%1, %2") - .arg(s) - .arg(formatSystemMessage(r))); + throw ShellLinkException(QString("%1, %2").arg(s).arg(formatSystemMessage(r))); } } @@ -109,9 +101,8 @@ private: { void* link = nullptr; - const auto r = CoCreateInstance( - CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, - IID_IShellLink, &link); + const auto r = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, + IID_IShellLink, &link); throwOnFail(r, "failed to create IShellLink instance"); @@ -137,23 +128,18 @@ private: } }; +Shortcut::Shortcut() : m_iconIndex(0) {} -Shortcut::Shortcut() - : m_iconIndex(0) -{ -} - -Shortcut::Shortcut(const Executable& exe) - : Shortcut() +Shortcut::Shortcut(const Executable& exe) : Shortcut() { const auto i = *InstanceManager::singleton().currentInstance(); - m_name = MOBase::sanitizeFileName(exe.title()); + m_name = MOBase::sanitizeFileName(exe.title()); m_target = QFileInfo(qApp->applicationFilePath()).absoluteFilePath(); m_arguments = QString("\"moshortcut://%1:%2\"") - .arg(i.isPortable() ? "" : i.displayName()) - .arg(exe.title()); + .arg(i.isPortable() ? "" : i.displayName()) + .arg(exe.title()); m_description = QString("Run %1 with ModOrganizer").arg(exe.title()); @@ -190,7 +176,7 @@ Shortcut& Shortcut::description(const QString& s) Shortcut& Shortcut::icon(const QString& s, int index) { - m_icon = s; + m_icon = s; m_iconIndex = index; return *this; } @@ -222,21 +208,15 @@ bool Shortcut::toggle(Locations loc) bool Shortcut::add(Locations loc) { - log::debug( - "adding shortcut to {}:\n" - " . name: '{}'\n" - " . target: '{}'\n" - " . arguments: '{}'\n" - " . description: '{}'\n" - " . icon: '{}' @ {}\n" - " . working directory: '{}'", - toString(loc), - m_name, - m_target, - m_arguments, - m_description, - m_icon, m_iconIndex, - m_workingDirectory); + log::debug("adding shortcut to {}:\n" + " . name: '{}'\n" + " . target: '{}'\n" + " . arguments: '{}'\n" + " . description: '{}'\n" + " . icon: '{}' @ {}\n" + " . working directory: '{}'", + toString(loc), m_name, m_target, m_arguments, m_description, m_icon, + m_iconIndex, m_workingDirectory); if (m_target.isEmpty()) { log::error("shortcut: target is empty"); @@ -250,8 +230,7 @@ bool Shortcut::add(Locations loc) log::debug("shorcut file will be saved at '{}'", path); - try - { + try { ShellLinkWrapper link; link.setPath(m_target); @@ -263,9 +242,7 @@ bool Shortcut::add(Locations loc) link.save(path); return true; - } - catch(ShellLinkException& e) - { + } catch (ShellLinkException& e) { log::error("{}\nshortcut file was not saved", e.what()); } @@ -291,9 +268,7 @@ bool Shortcut::remove(Locations loc) if (!MOBase::shellDelete({path})) { const auto e = ::GetLastError(); - log::error( - "failed to remove shortcut '{}', {}", - path, formatSystemMessage(e)); + log::error("failed to remove shortcut '{}', {}", path, formatSystemMessage(e)); return false; } @@ -320,26 +295,22 @@ QString Shortcut::shortcutDirectory(Locations loc) const { QString dir; - try - { - switch (loc) - { - case Desktop: - dir = MOBase::getDesktopDirectory(); - break; + try { + switch (loc) { + case Desktop: + dir = MOBase::getDesktopDirectory(); + break; - case StartMenu: - dir = MOBase::getStartMenuDirectory(); - break; + case StartMenu: + dir = MOBase::getStartMenuDirectory(); + break; - case None: - default: - log::error("shortcut: bad location {}", loc); - break; + case None: + default: + log::error("shortcut: bad location {}", loc); + break; } - } - catch(std::exception&) - { + } catch (std::exception&) { } return QDir::toNativeSeparators(dir); @@ -355,23 +326,21 @@ QString Shortcut::shortcutFilename() const return m_name + ".lnk"; } - QString toString(Shortcut::Locations loc) { - switch (loc) - { - case Shortcut::None: - return "none"; + switch (loc) { + case Shortcut::None: + return "none"; - case Shortcut::Desktop: - return "desktop"; + case Shortcut::Desktop: + return "desktop"; - case Shortcut::StartMenu: - return "start menu"; + case Shortcut::StartMenu: + return "start menu"; - default: - return QString("? (%1)").arg(static_cast<int>(loc)); + default: + return QString("? (%1)").arg(static_cast<int>(loc)); } } -} // namespace +} // namespace env diff --git a/src/envshortcut.h b/src/envshortcut.h index a05528d9..0cea1401 100644 --- a/src/envshortcut.h +++ b/src/envshortcut.h @@ -26,7 +26,6 @@ public: StartMenu }; - // empty shortcut // Shortcut(); @@ -53,13 +52,12 @@ public: // path to a binary that contains the icon and its index // - Shortcut& icon(const QString& s, int index=0); + Shortcut& icon(const QString& s, int index = 0); // "start in" option for this shortcut // Shortcut& workingDirectory(const QString& s); - // returns whether this shortcut already exists at the given location; this // does not check whether the shortcut parameters are different, it merely if // the .lnk file exists @@ -100,11 +98,10 @@ private: QString shortcutFilename() const; }; - // returns a string representation of the given location // QString toString(Shortcut::Locations loc); -} // namespace +} // namespace env -#endif // ENV_SHORTCUT_H +#endif // ENV_SHORTCUT_H diff --git a/src/envwindows.cpp b/src/envwindows.cpp index a2019fab..d62047fa 100644 --- a/src/envwindows.cpp +++ b/src/envwindows.cpp @@ -1,8 +1,8 @@ #include "envwindows.h" #include "env.h" #include "envmodule.h" -#include <utility.h> #include <log.h> +#include <utility.h> namespace env { @@ -19,10 +19,10 @@ WindowsInfo::WindowsInfo() return; } else { m_reported = getReportedVersion(ntdll.get()); - m_real = getRealVersion(ntdll.get()); + m_real = getRealVersion(ntdll.get()); } - m_release = getRelease(); + m_release = getRelease(); m_elevated = getElevated(); } @@ -61,7 +61,7 @@ QString WindowsInfo::toString() const QStringList sl; const QString reported = m_reported.toString(); - const QString real = m_real.toString(); + const QString real = m_real.toString(); // version sl.push_back("version " + reported); @@ -113,17 +113,17 @@ WindowsInfo::Version WindowsInfo::getReportedVersion(HINSTANCE ntdll) const // // there's still RtlGetVersion() though - using RtlGetVersionType = NTSTATUS (NTAPI)(PRTL_OSVERSIONINFOW); + using RtlGetVersionType = NTSTATUS(NTAPI)(PRTL_OSVERSIONINFOW); - auto* RtlGetVersion = reinterpret_cast<RtlGetVersionType*>( - GetProcAddress(ntdll, "RtlGetVersion")); + auto* RtlGetVersion = + reinterpret_cast<RtlGetVersionType*>(GetProcAddress(ntdll, "RtlGetVersion")); if (!RtlGetVersion) { log::error("RtlGetVersion() not found in ntdll.dll"); return {}; } - OSVERSIONINFOEX vi = {}; + OSVERSIONINFOEX vi = {}; vi.dwOSVersionInfoSize = sizeof(vi); // this apparently never fails @@ -140,17 +140,17 @@ WindowsInfo::Version WindowsInfo::getRealVersion(HINSTANCE ntdll) const // RtlGetNtVersionNumbers() is an undocumented function that seems to work // fine, but it might not in the future - using RtlGetNtVersionNumbersType = void (NTAPI)(DWORD*, DWORD*, DWORD*); + using RtlGetNtVersionNumbersType = void(NTAPI)(DWORD*, DWORD*, DWORD*); auto* RtlGetNtVersionNumbers = reinterpret_cast<RtlGetNtVersionNumbersType*>( - GetProcAddress(ntdll, "RtlGetNtVersionNumbers")); + GetProcAddress(ntdll, "RtlGetNtVersionNumbers")); if (!RtlGetNtVersionNumbers) { log::error("RtlGetNtVersionNumbers not found in ntdll.dll"); return {}; } - DWORD major=0, minor=0, build=0; + DWORD major = 0, minor = 0, build = 0; RtlGetNtVersionNumbers(&major, &minor, &build); // for whatever reason, the build number has 0xf0000000 set @@ -168,8 +168,8 @@ WindowsInfo::Release WindowsInfo::getRelease() const // any of the other versions fail to work QSettings settings( - R"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion)", - QSettings::NativeFormat); + R"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion)", + QSettings::NativeFormat); Release r; @@ -201,12 +201,12 @@ std::optional<bool> WindowsInfo::getElevated() const { HANDLE rawToken = 0; - if (!OpenProcessToken(GetCurrentProcess( ), TOKEN_QUERY, &rawToken)) { + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &rawToken)) { const auto e = GetLastError(); - log::error( - "while trying to check if process is elevated, " - "OpenProcessToken() failed: {}", formatSystemMessage(e)); + log::error("while trying to check if process is elevated, " + "OpenProcessToken() failed: {}", + formatSystemMessage(e)); return {}; } @@ -215,14 +215,14 @@ std::optional<bool> WindowsInfo::getElevated() const } TOKEN_ELEVATION e = {}; - DWORD size = sizeof(TOKEN_ELEVATION); + DWORD size = sizeof(TOKEN_ELEVATION); if (!GetTokenInformation(token.get(), TokenElevation, &e, sizeof(e), &size)) { const auto e = GetLastError(); - log::error( - "while trying to check if process is elevated, " - "GetTokenInformation() failed: {}", formatSystemMessage(e)); + log::error("while trying to check if process is elevated, " + "GetTokenInformation() failed: {}", + formatSystemMessage(e)); return {}; } @@ -230,4 +230,4 @@ std::optional<bool> WindowsInfo::getElevated() const return (e.TokenIsElevated != 0); } -} // namespace +} // namespace env diff --git a/src/envwindows.h b/src/envwindows.h index 61ef609d..7076bcc2 100644 --- a/src/envwindows.h +++ b/src/envwindows.h @@ -14,7 +14,7 @@ class WindowsInfo public: struct Version { - DWORD major=0, minor=0, build=0; + DWORD major = 0, minor = 0, build = 0; QString toString() const { @@ -23,16 +23,10 @@ public: friend bool operator==(const Version& a, const Version& b) { - return - a.major == b.major && - a.minor == b.minor && - a.build == b.build; + return a.major == b.major && a.minor == b.minor && a.build == b.build; } - friend bool operator!=(const Version& a, const Version& b) - { - return !(a == b); - } + friend bool operator!=(const Version& a, const Version& b) { return !(a == b); } }; struct Release @@ -46,13 +40,9 @@ public: // some sub-build number, undocumented, may be empty DWORD UBR; - Release() - : UBR(0) - { - } + Release() : UBR(0) {} }; - WindowsInfo(); // tries to guess whether this process is running in compatibility mode @@ -102,6 +92,6 @@ private: std::optional<bool> getElevated() const; }; -} // namespace +} // namespace env -#endif // ENV_WINDOWS_H +#endif // ENV_WINDOWS_H diff --git a/src/executableslist.cpp b/src/executableslist.cpp index 81fb53cb..c683bdcb 100644 --- a/src/executableslist.cpp +++ b/src/executableslist.cpp @@ -20,19 +20,17 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "executableslist.h" #include "iplugingame.h" -#include "utility.h" #include "settings.h" +#include "utility.h" #include <log.h> -#include <QFileInfo> -#include <QDir> -#include <QDebug> #include <QCoreApplication> - +#include <QDebug> +#include <QDir> +#include <QFileInfo> #include <algorithm> - using namespace MOBase; ExecutablesList::iterator ExecutablesList::begin() @@ -93,12 +91,12 @@ void ExecutablesList::load(const MOBase::IPluginGame* game, const Settings& s) } setExecutable(Executable() - .title(map["title"].toString()) - .binaryInfo(QFileInfo(map["binary"].toString())) - .arguments(map["arguments"].toString()) - .steamAppID(map["steamAppID"].toString()) - .workingDirectory(map["workingDirectory"].toString()) - .flags(flags)); + .title(map["title"].toString()) + .binaryInfo(QFileInfo(map["binary"].toString())) + .arguments(map["arguments"].toString()) + .steamAppID(map["steamAppID"].toString()) + .workingDirectory(map["workingDirectory"].toString()) + .flags(flags)); } addFromPlugin(game, IgnoreExisting); @@ -116,14 +114,14 @@ void ExecutablesList::store(Settings& s) for (const auto& item : *this) { std::map<QString, QVariant> map; - map["title"] = item.title(); - map["toolbar"] = item.isShownOnToolbar(); - map["ownicon"] = item.usesOwnIcon(); - map["hide"] = item.hide(); - map["binary"] = item.binaryInfo().filePath(); - map["arguments"] = item.arguments(); + map["title"] = item.title(); + map["toolbar"] = item.isShownOnToolbar(); + map["ownicon"] = item.usesOwnIcon(); + map["hide"] = item.hide(); + map["binary"] = item.binaryInfo().filePath(); + map["arguments"] = item.arguments(); map["workingDirectory"] = item.workingDirectory(); - map["steamAppID"] = item.steamAppID(); + map["steamAppID"] = item.steamAppID(); v.push_back(std::move(map)); } @@ -131,14 +129,14 @@ void ExecutablesList::store(Settings& s) s.setExecutables(v); } -std::vector<Executable> ExecutablesList::getPluginExecutables( - MOBase::IPluginGame const *game) const +std::vector<Executable> +ExecutablesList::getPluginExecutables(MOBase::IPluginGame const* game) const { Q_ASSERT(game != nullptr); std::vector<Executable> v; - for (const ExecutableInfo &info : game->executables()) { + for (const ExecutableInfo& info : game->executables()) { if (!info.isValid()) { continue; } @@ -146,18 +144,19 @@ std::vector<Executable> ExecutablesList::getPluginExecutables( v.push_back({info, Executable::UseApplicationIcon}); } - const QFileInfo eppBin(QCoreApplication::applicationDirPath() + "/explorer++/Explorer++.exe"); + const QFileInfo eppBin(QCoreApplication::applicationDirPath() + + "/explorer++/Explorer++.exe"); if (eppBin.exists()) { - const auto args = QString("\"%1\"") - .arg(QDir::toNativeSeparators(game->dataDirectory().absolutePath())); + const auto args = QString("\"%1\"").arg( + QDir::toNativeSeparators(game->dataDirectory().absolutePath())); const auto exe = Executable() - .title("Explore Virtual Folder") - .binaryInfo(eppBin) - .arguments(args) - .workingDirectory(eppBin.absolutePath()) - .flags(Executable::UseApplicationIcon); + .title("Explore Virtual Folder") + .binaryInfo(eppBin) + .arguments(args) + .workingDirectory(eppBin.absolutePath()) + .flags(Executable::UseApplicationIcon); v.push_back(exe); } @@ -165,7 +164,7 @@ std::vector<Executable> ExecutablesList::getPluginExecutables( return v; } -void ExecutablesList::resetFromPlugin(MOBase::IPluginGame const *game) +void ExecutablesList::resetFromPlugin(MOBase::IPluginGame const* game) { log::debug("resetting plugin executables"); @@ -176,7 +175,7 @@ void ExecutablesList::resetFromPlugin(MOBase::IPluginGame const *game) } } -void ExecutablesList::addFromPlugin(IPluginGame const *game, SetFlags flags) +void ExecutablesList::addFromPlugin(IPluginGame const* game, SetFlags flags) { Q_ASSERT(game != nullptr); @@ -185,7 +184,7 @@ void ExecutablesList::addFromPlugin(IPluginGame const *game, SetFlags flags) } } -const Executable &ExecutablesList::get(const QString &title) const +const Executable& ExecutablesList::get(const QString& title) const { for (const auto& exe : m_Executables) { if (exe.title() == title) { @@ -193,17 +192,18 @@ const Executable &ExecutablesList::get(const QString &title) const } } - throw std::runtime_error(QString("executable not found: %1").arg(title).toLocal8Bit().constData()); + throw std::runtime_error( + QString("executable not found: %1").arg(title).toLocal8Bit().constData()); } -Executable &ExecutablesList::get(const QString &title) +Executable& ExecutablesList::get(const QString& title) { return const_cast<Executable&>(std::as_const(*this).get(title)); } -Executable &ExecutablesList::getByBinary(const QFileInfo &info) +Executable& ExecutablesList::getByBinary(const QFileInfo& info) { - for (Executable &exe : m_Executables) { + for (Executable& exe : m_Executables) { if (exe.binaryInfo() == info) { return exe; } @@ -211,7 +211,7 @@ Executable &ExecutablesList::getByBinary(const QFileInfo &info) throw std::runtime_error("invalid info"); } -ExecutablesList::iterator ExecutablesList::find(const QString &title, bool ci) +ExecutablesList::iterator ExecutablesList::find(const QString& title, bool ci) { const auto cif = ci ? Qt::CaseInsensitive : Qt::CaseSensitive; @@ -220,7 +220,8 @@ ExecutablesList::iterator ExecutablesList::find(const QString &title, bool ci) }); } -ExecutablesList::const_iterator ExecutablesList::find(const QString &title, bool ci) const +ExecutablesList::const_iterator ExecutablesList::find(const QString& title, + bool ci) const { const auto cif = ci ? Qt::CaseInsensitive : Qt::CaseSensitive; @@ -229,18 +230,21 @@ ExecutablesList::const_iterator ExecutablesList::find(const QString &title, bool }); } -bool ExecutablesList::titleExists(const QString &title) const +bool ExecutablesList::titleExists(const QString& title) const { - auto test = [&] (const Executable &exe) { return exe.title() == title; }; - return std::find_if(m_Executables.begin(), m_Executables.end(), test) != m_Executables.end(); + auto test = [&](const Executable& exe) { + return exe.title() == title; + }; + return std::find_if(m_Executables.begin(), m_Executables.end(), test) != + m_Executables.end(); } -void ExecutablesList::setExecutable(const Executable &exe) +void ExecutablesList::setExecutable(const Executable& exe) { setExecutable(exe, MergeExisting); } -void ExecutablesList::setExecutable(const Executable &exe, SetFlags flags) +void ExecutablesList::setExecutable(const Executable& exe, SetFlags flags) { auto itor = find(exe.title()); @@ -252,16 +256,14 @@ void ExecutablesList::setExecutable(const Executable &exe, SetFlags flags) if (flags == MoveExisting) { const auto newTitle = makeNonConflictingTitle(exe.title()); if (!newTitle) { - log::error( - "executable '{}' was in the way but could not be renamed", - exe.title()); + log::error("executable '{}' was in the way but could not be renamed", + exe.title()); return; } - log::warn( - "executable '{}' was in the way and was renamed to '{}'", - itor->title(), *newTitle); + log::warn("executable '{}' was in the way and was renamed to '{}'", itor->title(), + *newTitle); itor->title(*newTitle); itor = end(); @@ -275,7 +277,7 @@ void ExecutablesList::setExecutable(const Executable &exe, SetFlags flags) } } -void ExecutablesList::remove(const QString &title) +void ExecutablesList::remove(const QString& title) { auto itor = find(title); if (itor != m_Executables.end()) { @@ -283,14 +285,13 @@ void ExecutablesList::remove(const QString &title) } } -std::optional<QString> ExecutablesList::makeNonConflictingTitle( - const QString& prefix) +std::optional<QString> ExecutablesList::makeNonConflictingTitle(const QString& prefix) { const int max = 100; QString title = prefix; - for (int i=1; i<max; ++i) { + for (int i = 1; i < max; ++i) { if (!titleExists(title)) { return title; } @@ -302,7 +303,7 @@ std::optional<QString> ExecutablesList::makeNonConflictingTitle( return {}; } -void ExecutablesList::upgradeFromCustom(MOBase::IPluginGame const *game) +void ExecutablesList::upgradeFromCustom(MOBase::IPluginGame const* game) { log::debug("upgrading executables list"); @@ -328,7 +329,7 @@ void ExecutablesList::upgradeFromCustom(MOBase::IPluginGame const *game) for (const auto& exe : getPluginExecutables(game)) { auto itor = find(exe.title()); - if (itor == end()){ + if (itor == end()) { continue; } @@ -359,33 +360,24 @@ void ExecutablesList::dump() const flags.push_back("hide"); } - log::debug( - " . executable '{}'\n" - " binary: {}\n" - " arguments: {}\n" - " steam ID: {}\n" - " directory: {}\n" - " flags: {} ({})", - e.title(), e.binaryInfo().filePath(), e.arguments(), - e.steamAppID(), e.workingDirectory(), flags.join("|"), e.flags()); + log::debug(" . executable '{}'\n" + " binary: {}\n" + " arguments: {}\n" + " steam ID: {}\n" + " directory: {}\n" + " flags: {} ({})", + e.title(), e.binaryInfo().filePath(), e.arguments(), e.steamAppID(), + e.workingDirectory(), flags.join("|"), e.flags()); } } +Executable::Executable(QString title) : m_title(title) {} -Executable::Executable(QString title) - : m_title(title) -{ -} - -Executable::Executable(const MOBase::ExecutableInfo& info, Flags flags) : - m_title(info.title()), - m_binaryInfo(info.binary()), - m_arguments(info.arguments().join(" ")), - m_steamAppID(info.steamAppID()), - m_workingDirectory(info.workingDirectory().path()), - m_flags(flags) -{ -} +Executable::Executable(const MOBase::ExecutableInfo& info, Flags flags) + : m_title(info.title()), m_binaryInfo(info.binary()), + m_arguments(info.arguments().join(" ")), m_steamAppID(info.steamAppID()), + m_workingDirectory(info.workingDirectory().path()), m_flags(flags) +{} const QString& Executable::title() const { @@ -482,10 +474,10 @@ void Executable::mergeFrom(const Executable& other) // this happens after executables are loaded from settings and plugin // executables are being added, or when users are modifying executables - m_title = other.title(); - m_binaryInfo = other.binaryInfo(); - m_arguments = other.arguments(); - m_steamAppID = other.steamAppID(); + m_title = other.title(); + m_binaryInfo = other.binaryInfo(); + m_arguments = other.arguments(); + m_steamAppID = other.steamAppID(); m_workingDirectory = other.workingDirectory(); - m_flags = other.flags(); + m_flags = other.flags(); } diff --git a/src/executableslist.h b/src/executableslist.h index b8016c72..21a30056 100644 --- a/src/executableslist.h +++ b/src/executableslist.h @@ -22,13 +22,17 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "executableinfo.h" -#include <vector> #include <optional> +#include <vector> #include <QFileInfo> #include <QMetaType> -namespace MOBase { class IPluginGame; class ExecutableInfo; } +namespace MOBase +{ +class IPluginGame; +class ExecutableInfo; +} // namespace MOBase class Settings; /*! @@ -46,11 +50,11 @@ public: Q_DECLARE_FLAGS(Flags, Flag); - Executable(QString title={}); + Executable(QString title = {}); /** - * @brief Executable from plugin - */ + * @brief Executable from plugin + */ Executable(const MOBase::ExecutableInfo& info, Flags flags); const QString& title() const; @@ -83,14 +87,14 @@ private: Flags m_flags; }; - /*! * @brief List of executables configured to by started from MO **/ -class ExecutablesList { +class ExecutablesList +{ public: - using vector_type = std::vector<Executable>; - using iterator = vector_type::iterator; + using vector_type = std::vector<Executable>; + using iterator = vector_type::iterator; using const_iterator = vector_type::const_iterator; /** @@ -112,7 +116,7 @@ public: * @brief re-adds all the executables from the plugin and renames existing * executables that are in the way **/ - void resetFromPlugin(MOBase::IPluginGame const *game); + void resetFromPlugin(MOBase::IPluginGame const* game); /** * @brief writes the current list to the settings @@ -126,7 +130,7 @@ public: * @return the executable * @exception runtime_error will throw an exception if the executable is not found **/ - const Executable &get(const QString &title) const; + const Executable& get(const QString& title) const; /** * @brief find an executable by its name @@ -135,7 +139,7 @@ public: * @return the executable * @exception runtime_error will throw an exception if the name is not correct **/ - Executable &get(const QString &title); + Executable& get(const QString& title); /** * @brief find an executable by a fileinfo structure @@ -143,26 +147,26 @@ public: * @return the executable * @exception runtime_error will throw an exception if the name is not correct */ - Executable &getByBinary(const QFileInfo &info); + Executable& getByBinary(const QFileInfo& info); /** * @brief returns an iterator for the given executable by title, or end() */ - iterator find(const QString &title, bool caseSensitive=true); - const_iterator find(const QString &title, bool caseSensitive=true) const; + iterator find(const QString& title, bool caseSensitive = true); + const_iterator find(const QString& title, bool caseSensitive = true) const; /** * @brief determine if an executable exists * @param title the title of the executable to look up * @return true if the executable exists, false otherwise **/ - bool titleExists(const QString &title) const; + bool titleExists(const QString& title) const; /** * @brief add a new executable to the list * @param executable */ - void setExecutable(const Executable &executable); + void setExecutable(const Executable& executable); /** * @brief remove the executable with the specified file name. This needs to @@ -172,7 +176,7 @@ public: * @note if the executable name is invalid, nothing happens. There is no way * to determine if this was successful **/ - void remove(const QString &title); + void remove(const QString& title); /** * returns a title that starts with the given prefix and does not clash with @@ -195,23 +199,21 @@ private: std::vector<Executable> m_Executables; - /** * @brief add the executables preconfigured for this game **/ - void addFromPlugin(MOBase::IPluginGame const *game, SetFlags flags); + void addFromPlugin(MOBase::IPluginGame const* game, SetFlags flags); /** * @brief add a new executable to the list * @param executable */ - void setExecutable(const Executable &exe, SetFlags flags); + void setExecutable(const Executable& exe, SetFlags flags); /** * returns the executables provided by the game plugin **/ - std::vector<Executable> getPluginExecutables( - MOBase::IPluginGame const *game) const; + std::vector<Executable> getPluginExecutables(MOBase::IPluginGame const* game) const; /** * called when MO is still using the old custom executables from 2.2.0 @@ -225,4 +227,4 @@ private: Q_DECLARE_OPERATORS_FOR_FLAGS(Executable::Flags) -#endif // EXECUTABLESLIST_H +#endif // EXECUTABLESLIST_H diff --git a/src/filedialogmemory.cpp b/src/filedialogmemory.cpp index 62c29a3f..721fca84 100644 --- a/src/filedialogmemory.cpp +++ b/src/filedialogmemory.cpp @@ -33,10 +33,11 @@ void FileDialogMemory::restore(const Settings& s) g_Cache = s.paths().recent(); } -QString FileDialogMemory::getOpenFileName( - const QString &dirID, QWidget *parent, const QString &caption, - const QString &dir, const QString &filter, QString *selectedFilter, - QFileDialog::Options options) +QString FileDialogMemory::getOpenFileName(const QString& dirID, QWidget* parent, + const QString& caption, const QString& dir, + const QString& filter, + QString* selectedFilter, + QFileDialog::Options options) { QString currentDir = dir; @@ -47,8 +48,8 @@ QString FileDialogMemory::getOpenFileName( } } - QString result = QFileDialog::getOpenFileName( - parent, caption, currentDir, filter, selectedFilter, options); + QString result = QFileDialog::getOpenFileName(parent, caption, currentDir, filter, + selectedFilter, options); if (!result.isNull()) { g_Cache[dirID] = QFileInfo(result).path(); @@ -57,10 +58,10 @@ QString FileDialogMemory::getOpenFileName( return result; } - -QString FileDialogMemory::getExistingDirectory( - const QString &dirID, QWidget *parent, const QString &caption, - const QString &dir, QFileDialog::Options options) +QString FileDialogMemory::getExistingDirectory(const QString& dirID, QWidget* parent, + const QString& caption, + const QString& dir, + QFileDialog::Options options) { QString currentDir = dir; @@ -71,8 +72,8 @@ QString FileDialogMemory::getExistingDirectory( } } - QString result = QFileDialog::getExistingDirectory( - parent, caption, currentDir, options); + QString result = + QFileDialog::getExistingDirectory(parent, caption, currentDir, options); if (!result.isNull()) { g_Cache[dirID] = result; diff --git a/src/filedialogmemory.h b/src/filedialogmemory.h index 995d5640..464ac3bc 100644 --- a/src/filedialogmemory.h +++ b/src/filedialogmemory.h @@ -20,10 +20,9 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef FILEDIALOGMEMORY_H #define FILEDIALOGMEMORY_H - -#include <map> -#include <QString> #include <QFileDialog> +#include <QString> +#include <map> class Settings; @@ -35,15 +34,18 @@ public: static void save(Settings& settings); static void restore(const Settings& settings); - static QString getOpenFileName( - const QString &dirID, QWidget *parent = 0, const QString &caption = QString(), - const QString &dir = QString(), const QString &filter = QString(), - QString *selectedFilter = 0, QFileDialog::Options options = QFileDialog::Option(0)); + static QString getOpenFileName(const QString& dirID, QWidget* parent = 0, + const QString& caption = QString(), + const QString& dir = QString(), + const QString& filter = QString(), + QString* selectedFilter = 0, + QFileDialog::Options options = QFileDialog::Option(0)); - static QString getExistingDirectory( - const QString &dirID, QWidget *parent = 0, const QString &caption = QString(), - const QString &dir = QString(), - QFileDialog::Options options = QFileDialog::ShowDirsOnly); + static QString + getExistingDirectory(const QString& dirID, QWidget* parent = 0, + const QString& caption = QString(), + const QString& dir = QString(), + QFileDialog::Options options = QFileDialog::ShowDirsOnly); }; -#endif // FILEDIALOGMEMORY_H +#endif // FILEDIALOGMEMORY_H diff --git a/src/filerenamer.cpp b/src/filerenamer.cpp index dd5876b6..c6172dc6 100644 --- a/src/filerenamer.cpp +++ b/src/filerenamer.cpp @@ -1,23 +1,24 @@ #include "filerenamer.h" -#include <utility.h> -#include <log.h> -#include <QMessageBox> #include <QFileInfo> +#include <QMessageBox> +#include <log.h> +#include <utility.h> using namespace MOBase; FileRenamer::FileRenamer(QWidget* parent, QFlags<RenameFlags> flags) - : m_parent(parent), m_flags(flags) + : m_parent(parent), m_flags(flags) { // sanity check for flags - if ((m_flags & (HIDE|UNHIDE)) == 0) { + if ((m_flags & (HIDE | UNHIDE)) == 0) { log::error("renameFile() missing hide flag"); // doesn't really matter, it's just for text m_flags = HIDE; } } -FileRenamer::RenameResults FileRenamer::rename(const QString& oldName, const QString& newName) +FileRenamer::RenameResults FileRenamer::rename(const QString& oldName, + const QString& newName) { log::debug("renaming {} to {}", oldName, newName); @@ -28,42 +29,42 @@ FileRenamer::RenameResults FileRenamer::rename(const QString& oldName, const QSt auto answer = confirmReplace(newName); switch (answer) { - case DECISION_SKIP: { - // user wants to skip this file - log::debug("skipping {}", oldName); - return RESULT_SKIP; - } - - case DECISION_REPLACE: { - log::debug("removing {}", newName); + case DECISION_SKIP: { + // user wants to skip this file + log::debug("skipping {}", oldName); + return RESULT_SKIP; + } - // user wants to replace the file, so remove it - const auto r = shell::Delete(QFileInfo(newName)); + case DECISION_REPLACE: { + log::debug("removing {}", newName); - if (!r.success()) { - log::error("failed to remove '{}': {}", newName, r.toString()); + // user wants to replace the file, so remove it + const auto r = shell::Delete(QFileInfo(newName)); - // removal failed, warn the user and allow canceling - if (!removeFailed(newName, r)) { - log::debug("canceling {}", oldName); - // user wants to cancel - return RESULT_CANCEL; - } + if (!r.success()) { + log::error("failed to remove '{}': {}", newName, r.toString()); - // ignore this file and continue on - log::debug("skipping {}", oldName); - return RESULT_SKIP; + // removal failed, warn the user and allow canceling + if (!removeFailed(newName, r)) { + log::debug("canceling {}", oldName); + // user wants to cancel + return RESULT_CANCEL; } - break; + // ignore this file and continue on + log::debug("skipping {}", oldName); + return RESULT_SKIP; } - case DECISION_CANCEL: // fall-through - default: { - // user wants to stop - log::debug("canceling"); - return RESULT_CANCEL; - } + break; + } + + case DECISION_CANCEL: // fall-through + default: { + // user wants to stop + log::debug("canceling"); + return RESULT_CANCEL; + } } } @@ -71,9 +72,7 @@ FileRenamer::RenameResults FileRenamer::rename(const QString& oldName, const QSt const auto r = shell::Rename(QFileInfo(oldName), QFileInfo(newName)); if (!r.success()) { - log::error( - "failed to rename '{}' to '{}': {}", - oldName, newName, r.toString()); + log::error("failed to rename '{}' to '{}': {}", oldName, newName, r.toString()); // renaming failed, warn the user and allow canceling if (!renameFailed(oldName, newName, r)) { @@ -98,8 +97,7 @@ FileRenamer::RenameDecision FileRenamer::confirmReplace(const QString& newName) // user wants to silently replace all log::debug("user has selected replace all"); return DECISION_REPLACE; - } - else if (m_flags & REPLACE_NONE) { + } else if (m_flags & REPLACE_NONE) { // user wants to silently skip all log::debug("user has selected replace none"); return DECISION_SKIP; @@ -108,10 +106,11 @@ FileRenamer::RenameDecision FileRenamer::confirmReplace(const QString& newName) QString text; if (m_flags & HIDE) { - text = QObject::tr("The hidden file \"%1\" already exists. Replace it?").arg(newName); - } - else if (m_flags & UNHIDE) { - text = QObject::tr("The visible file \"%1\" already exists. Replace it?").arg(newName); + text = + QObject::tr("The hidden file \"%1\" already exists. Replace it?").arg(newName); + } else if (m_flags & UNHIDE) { + text = + QObject::tr("The visible file \"%1\" already exists. Replace it?").arg(newName); } auto buttons = QMessageBox::Yes | QMessageBox::No; @@ -120,34 +119,34 @@ FileRenamer::RenameDecision FileRenamer::confirmReplace(const QString& newName) buttons |= QMessageBox::YesToAll | QMessageBox::NoToAll | QMessageBox::Cancel; } - const auto answer = QMessageBox::question( - m_parent, QObject::tr("Replace file?"), text, buttons); + const auto answer = + QMessageBox::question(m_parent, QObject::tr("Replace file?"), text, buttons); switch (answer) { - case QMessageBox::Yes: - log::debug("user wants to replace"); - return DECISION_REPLACE; + case QMessageBox::Yes: + log::debug("user wants to replace"); + return DECISION_REPLACE; - case QMessageBox::No: - log::debug("user wants to skip"); - return DECISION_SKIP; + case QMessageBox::No: + log::debug("user wants to skip"); + return DECISION_SKIP; - case QMessageBox::YesToAll: - log::debug("user wants to replace all"); - // remember the answer - m_flags |= REPLACE_ALL; - return DECISION_REPLACE; + case QMessageBox::YesToAll: + log::debug("user wants to replace all"); + // remember the answer + m_flags |= REPLACE_ALL; + return DECISION_REPLACE; - case QMessageBox::NoToAll: - log::debug("user wants to replace none"); - // remember the answer - m_flags |= REPLACE_NONE; - return DECISION_SKIP; + case QMessageBox::NoToAll: + log::debug("user wants to replace none"); + // remember the answer + m_flags |= REPLACE_NONE; + return DECISION_SKIP; - case QMessageBox::Cancel: // fall-through - default: - log::debug("user wants to cancel"); - return DECISION_CANCEL; + case QMessageBox::Cancel: // fall-through + default: + log::debug("user wants to cancel"); + return DECISION_CANCEL; } } @@ -160,10 +159,8 @@ bool FileRenamer::removeFailed(const QString& name, const shell::Result& r) } const auto answer = QMessageBox::critical( - m_parent, - QObject::tr("File operation failed"), - QObject::tr("Failed to remove \"%1\": %2").arg(name).arg(r.toString()), - buttons); + m_parent, QObject::tr("File operation failed"), + QObject::tr("Failed to remove \"%1\": %2").arg(name).arg(r.toString()), buttons); if (answer == QMessageBox::Cancel) { // user wants to stop @@ -176,8 +173,8 @@ bool FileRenamer::removeFailed(const QString& name, const shell::Result& r) return true; } -bool FileRenamer::renameFailed( - const QString& oldName, const QString& newName, const shell::Result& r) +bool FileRenamer::renameFailed(const QString& oldName, const QString& newName, + const shell::Result& r) { QMessageBox::StandardButtons buttons = QMessageBox::Ok; if (m_flags & MULTIPLE) { @@ -185,17 +182,15 @@ bool FileRenamer::renameFailed( buttons |= QMessageBox::Cancel; } - const auto answer = QMessageBox::critical( - m_parent, - QObject::tr("File operation failed"), - QObject::tr( - "Failed to rename file: %1.\r\n\r\n" - "Source:\r\n\"%2\"\r\n\r\n" - "Destination:\r\n\"%3\"") - .arg(r.toString()) - .arg(QDir::toNativeSeparators(oldName)) - .arg(QDir::toNativeSeparators(newName)), - buttons); + const auto answer = + QMessageBox::critical(m_parent, QObject::tr("File operation failed"), + QObject::tr("Failed to rename file: %1.\r\n\r\n" + "Source:\r\n\"%2\"\r\n\r\n" + "Destination:\r\n\"%3\"") + .arg(r.toString()) + .arg(QDir::toNativeSeparators(oldName)) + .arg(QDir::toNativeSeparators(newName)), + buttons); if (answer == QMessageBox::Cancel) { // user wants to stop diff --git a/src/filerenamer.h b/src/filerenamer.h index 5583ecbd..a848a7fb 100644 --- a/src/filerenamer.h +++ b/src/filerenamer.h @@ -3,142 +3,142 @@ #include <QWidget> -namespace MOBase::shell { class Result; } +namespace MOBase::shell +{ +class Result; +} /** -* Renames individual files and handles dialog boxes to confirm replacements and -* failures with the user -**/ + * Renames individual files and handles dialog boxes to confirm replacements and + * failures with the user + **/ class FileRenamer { public: /** - * controls appearance and replacement behaviour; if RENAME_REPLACE_ALL and - * RENAME_REPLACE_NONE are not provided, the user will have the option to - * choose on the first replacement - **/ + * controls appearance and replacement behaviour; if RENAME_REPLACE_ALL and + * RENAME_REPLACE_NONE are not provided, the user will have the option to + * choose on the first replacement + **/ enum RenameFlags { /** - * this renamer will be used on multiple files, so display additional - * buttons to replace all and for canceling - **/ - MULTIPLE = 0x01, + * this renamer will be used on multiple files, so display additional + * buttons to replace all and for canceling + **/ + MULTIPLE = 0x01, /** - * customizes some of the text shown on dialog to mention that files are - * being hidden - **/ - HIDE = 0x02, + * customizes some of the text shown on dialog to mention that files are + * being hidden + **/ + HIDE = 0x02, /** - * customizes some of the text shown on dialog to mention that files are - * being unhidden - **/ - UNHIDE = 0x04, + * customizes some of the text shown on dialog to mention that files are + * being unhidden + **/ + UNHIDE = 0x04, /** - * silently replaces all existing files - **/ - REPLACE_ALL = 0x08, + * silently replaces all existing files + **/ + REPLACE_ALL = 0x08, /** - * silently skips all existing files - **/ - REPLACE_NONE = 0x10, + * silently skips all existing files + **/ + REPLACE_NONE = 0x10, }; - /** result of a single rename - * - **/ + * + **/ enum RenameResults { /** - * the user skipped this file - */ + * the user skipped this file + */ RESULT_SKIP, /** - * the file was successfully renamed - */ + * the file was successfully renamed + */ RESULT_OK, /** - * the user wants to cancel - */ + * the user wants to cancel + */ RESULT_CANCEL }; - /** - * @param parent Parent widget for dialog boxes - **/ + * @param parent Parent widget for dialog boxes + **/ FileRenamer(QWidget* parent, QFlags<RenameFlags> flags); /** - * renames the given file - * @param oldName current filename - * @param newName new filename - * @return whether the file was renamed, skipped or the user wants to cancel - **/ + * renames the given file + * @param oldName current filename + * @param newName new filename + * @return whether the file was renamed, skipped or the user wants to cancel + **/ RenameResults rename(const QString& oldName, const QString& newName); private: /** - *user's decision when replacing - **/ + *user's decision when replacing + **/ enum RenameDecision { /** - * replace the file - **/ + * replace the file + **/ DECISION_REPLACE, /** - * skip the file - **/ + * skip the file + **/ DECISION_SKIP, /** - * cancel the whole thing - **/ + * cancel the whole thing + **/ DECISION_CANCEL }; /** - * parent widget for dialog boxes - **/ + * parent widget for dialog boxes + **/ QWidget* m_parent; /** - * flags - **/ + * flags + **/ QFlags<RenameFlags> m_flags; /** - * asks the user to replace an existing file, may return early if the user - * has already selected to replace all/none - * @return whether to replace, skip or cancel - **/ + * asks the user to replace an existing file, may return early if the user + * has already selected to replace all/none + * @return whether to replace, skip or cancel + **/ RenameDecision confirmReplace(const QString& newName); /** - * removal of a file failed, ask the user to continue or cancel - * @param name The name of the file that failed to be removed - * @return true to continue, false to stop - **/ + * removal of a file failed, ask the user to continue or cancel + * @param name The name of the file that failed to be removed + * @return true to continue, false to stop + **/ bool removeFailed(const QString& name, const MOBase::shell::Result& r); /** - * renaming a file failed, ask the user to continue or cancel - * @param oldName current filename - * @param newName new filename - * @return true to continue, false to stop - **/ - bool renameFailed( - const QString& oldName, const QString& newName, - const MOBase::shell::Result& r); + * renaming a file failed, ask the user to continue or cancel + * @param oldName current filename + * @param newName new filename + * @return true to continue, false to stop + **/ + bool renameFailed(const QString& oldName, const QString& newName, + const MOBase::shell::Result& r); }; -#endif // FILERENAMER_H +#endif // FILERENAMER_H diff --git a/src/filetree.cpp b/src/filetree.cpp index 02c85fdd..f043448f 100644 --- a/src/filetree.cpp +++ b/src/filetree.cpp @@ -1,10 +1,10 @@ #include "filetree.h" -#include "filetreemodel.h" +#include "envshell.h" #include "filetreeitem.h" +#include "filetreemodel.h" #include "organizercore.h" -#include "envshell.h" -#include "shared/fileentry.h" #include "shared/directoryentry.h" +#include "shared/fileentry.h" #include "shared/filesorigin.h" #include <log.h> #include <widgetutility.h> @@ -12,11 +12,10 @@ using namespace MOShared; using namespace MOBase; - bool canPreviewFile(const PluginContainer& pc, const FileEntry& file) { - return canPreviewFile( - pc, file.isFromArchive(), QString::fromStdWString(file.getName())); + return canPreviewFile(pc, file.isFromArchive(), + QString::fromStdWString(file.getName())); } bool canRunFile(const FileEntry& file) @@ -31,21 +30,18 @@ bool canOpenFile(const FileEntry& file) bool isHidden(const FileEntry& file) { - return (QString::fromStdWString(file.getName()).endsWith(ModInfo::s_HiddenExt, Qt::CaseInsensitive)); + return (QString::fromStdWString(file.getName()) + .endsWith(ModInfo::s_HiddenExt, Qt::CaseInsensitive)); } bool canExploreFile(const FileEntry& file); bool canHideFile(const FileEntry& file); bool canUnhideFile(const FileEntry& file); - class MenuItem { public: - MenuItem(QString s={}) - : m_action(new QAction(std::move(s))) - { - } + MenuItem(QString s = {}) : m_action(new QAction(std::move(s))) {} MenuItem& caption(const QString& s) { @@ -120,9 +116,8 @@ private: } }; - FileTree::FileTree(OrganizerCore& core, PluginContainer& pc, QTreeView* tree) - : m_core(core), m_plugins(pc), m_tree(tree), m_model(new FileTreeModel(core)) + : m_core(core), m_plugins(pc), m_tree(tree), m_model(new FileTreeModel(core)) { m_tree->sortByColumn(0, Qt::AscendingOrder); m_tree->setModel(m_model); @@ -130,21 +125,21 @@ FileTree::FileTree(OrganizerCore& core, PluginContainer& pc, QTreeView* tree) MOBase::setCustomizableColumns(m_tree); - connect( - m_tree, &QTreeView::customContextMenuRequested, - [&](auto pos){ onContextMenu(pos); }); + connect(m_tree, &QTreeView::customContextMenuRequested, [&](auto pos) { + onContextMenu(pos); + }); - connect( - m_tree, &QTreeView::expanded, - [&](auto&& index){ onExpandedChanged(index, true); }); + connect(m_tree, &QTreeView::expanded, [&](auto&& index) { + onExpandedChanged(index, true); + }); - connect( - m_tree, &QTreeView::collapsed, - [&](auto&& index){ onExpandedChanged(index, false); }); + connect(m_tree, &QTreeView::collapsed, [&](auto&& index) { + onExpandedChanged(index, false); + }); - connect( - m_tree, &QTreeView::activated, - [&](auto&& index){ onItemActivated(index); }); + connect(m_tree, &QTreeView::activated, [&](auto&& index) { + onItemActivated(index); + }); } FileTreeModel* FileTree::model() @@ -200,10 +195,10 @@ void FileTree::open(FileTreeItem* item) const QFileInfo targetInfo(path); m_core.processRunner() - .setFromFile(m_tree->window(), targetInfo) - .setHooked(false) - .setWaitForCompletion(ProcessRunner::TriggerRefresh) - .run(); + .setFromFile(m_tree->window(), targetInfo) + .setHooked(false) + .setWaitForCompletion(ProcessRunner::TriggerRefresh) + .run(); } void FileTree::openHooked(FileTreeItem* item) @@ -224,10 +219,10 @@ void FileTree::openHooked(FileTreeItem* item) const QFileInfo targetInfo(path); m_core.processRunner() - .setFromFile(m_tree->window(), targetInfo) - .setHooked(true) - .setWaitForCompletion(ProcessRunner::TriggerRefresh) - .run(); + .setFromFile(m_tree->window(), targetInfo) + .setHooked(true) + .setWaitForCompletion(ProcessRunner::TriggerRefresh) + .run(); } void FileTree::preview(FileTreeItem* item) @@ -256,8 +251,7 @@ void FileTree::activate(FileTreeItem* item) return; } - const auto tryPreview = - m_core.settings().interface().doubleClicksOpenPreviews(); + const auto tryPreview = m_core.settings().interface().doubleClicksOpenPreviews(); if (tryPreview) { const QFileInfo fi(item->realPath()); @@ -284,38 +278,34 @@ void FileTree::addAsExecutable(FileTreeItem* item) const QFileInfo target(path); const auto fec = spawn::getFileExecutionContext(m_tree->window(), target); - switch (fec.type) - { - case spawn::FileExecutionTypes::Executable: - { - const QString name = QInputDialog::getText( - m_tree->window(), tr("Enter Name"), - tr("Enter a name for the executable"), QLineEdit::Normal, - target.completeBaseName()); + switch (fec.type) { + case spawn::FileExecutionTypes::Executable: { + const QString name = QInputDialog::getText( + m_tree->window(), tr("Enter Name"), tr("Enter a name for the executable"), + QLineEdit::Normal, target.completeBaseName()); - if (!name.isEmpty()) { - //Note: If this already exists, you'll lose custom settings - m_core.executablesList()->setExecutable(Executable() - .title(name) - .binaryInfo(fec.binary) - .arguments(fec.arguments) - .workingDirectory(target.absolutePath())); + if (!name.isEmpty()) { + // Note: If this already exists, you'll lose custom settings + m_core.executablesList()->setExecutable( + Executable() + .title(name) + .binaryInfo(fec.binary) + .arguments(fec.arguments) + .workingDirectory(target.absolutePath())); - emit executablesChanged(); - } - - break; + emit executablesChanged(); } - case spawn::FileExecutionTypes::Other: // fall-through - default: - { - QMessageBox::information( - m_tree->window(), tr("Not an executable"), - tr("This is not a recognized executable.")); + break; + } - break; - } + case spawn::FileExecutionTypes::Other: // fall-through + default: { + QMessageBox::information(m_tree->window(), tr("Not an executable"), + tr("This is not a recognized executable.")); + + break; + } } } @@ -357,7 +347,7 @@ void FileTree::openModInfo(FileTreeItem* item) } const auto& origin = m_core.directoryStructure()->getOriginByID(originID); - const auto& name = QString::fromStdWString(origin.getName()); + const auto& name = QString::fromStdWString(origin.getName()); unsigned int index = ModInfo::getIndex(name); if (index == UINT_MAX) { @@ -386,9 +376,8 @@ void FileTree::toggleVisibility(bool visible, FileTreeItem* item) if (visible) { if (!currentName.endsWith(ModInfo::s_HiddenExt)) { - log::error( - "cannot unhide '{}', doesn't end with '{}'", - currentName, ModInfo::s_HiddenExt); + log::error("cannot unhide '{}', doesn't end with '{}'", currentName, + ModInfo::s_HiddenExt); return; } @@ -396,9 +385,8 @@ void FileTree::toggleVisibility(bool visible, FileTreeItem* item) newName = currentName.left(currentName.size() - ModInfo::s_HiddenExt.size()); } else { if (currentName.endsWith(ModInfo::s_HiddenExt)) { - log::error( - "cannot hide '{}', already ends with '{}'", - currentName, ModInfo::s_HiddenExt); + log::error("cannot hide '{}', already ends with '{}'", currentName, + ModInfo::s_HiddenExt); return; } @@ -408,9 +396,8 @@ void FileTree::toggleVisibility(bool visible, FileTreeItem* item) log::debug("attempting to rename '{}' to '{}'", currentName, newName); - FileRenamer renamer( - m_tree->window(), - (visible ? FileRenamer::UNHIDE : FileRenamer::HIDE)); + FileRenamer renamer(m_tree->window(), + (visible ? FileRenamer::UNHIDE : FileRenamer::HIDE)); if (renamer.rename(currentName, newName) == FileRenamer::RESULT_OK) { emit originModified(item->originID()); @@ -428,7 +415,8 @@ void FileTree::unhide(FileTreeItem* item) toggleVisibility(true, item); } -class DumpFailed {}; +class DumpFailed +{}; void FileTree::dumpToFile() const { @@ -445,7 +433,7 @@ void FileTree::dumpToFile() const void FileTree::onExpandedChanged(const QModelIndex& index, bool expanded) { - if (auto* item=m_model->itemFromIndex(proxiedIndex(index))) { + if (auto* item = m_model->itemFromIndex(proxiedIndex(index))) { item->setExpanded(expanded); } } @@ -460,7 +448,7 @@ void FileTree::onItemActivated(const QModelIndex& index) activate(item); } -void FileTree::onContextMenu(const QPoint &pos) +void FileTree::onContextMenu(const QPoint& pos) { const auto m = QApplication::keyboardModifiers(); @@ -473,11 +461,9 @@ void FileTree::onContextMenu(const QPoint &pos) const auto index = m_tree->indexAt(pos); if (!m_tree->selectionModel()->isSelected(index)) { - m_tree->selectionModel()->select( - index, - QItemSelectionModel::ClearAndSelect | - QItemSelectionModel::Rows | - QItemSelectionModel::Current); + m_tree->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect | + QItemSelectionModel::Rows | + QItemSelectionModel::Current); } // if no shell menu was available, continue on and show the regular @@ -489,12 +475,12 @@ void FileTree::onContextMenu(const QPoint &pos) QMenu menu; - if (auto* item=singleSelection()) { + if (auto* item = singleSelection()) { if (item->isDirectory()) { addDirectoryMenus(menu, *item); } else { const auto file = m_core.directoryStructure()->searchFile( - item->dataRelativeFilePath().toStdWString(), nullptr); + item->dataRelativeFilePath().toStdWString(), nullptr); if (file) { addFileMenus(menu, *file, item->originID()); @@ -512,7 +498,7 @@ QMainWindow* getMainWindow(QWidget* w) QWidget* p = w; while (p) { - if (auto* mw=dynamic_cast<QMainWindow*>(p)) { + if (auto* mw = dynamic_cast<QMainWindow*>(p)) { return mw; } @@ -528,7 +514,7 @@ bool FileTree::showShellMenu(QPoint pos) // menus by origin std::map<int, env::ShellMenu> menus; - int totalFiles = 0; + int totalFiles = 0; bool warnOnEmpty = true; for (auto&& index : m_tree->selectionModel()->selectedRows()) { @@ -540,9 +526,7 @@ bool FileTree::showShellMenu(QPoint pos) if (item->isDirectory()) { warnOnEmpty = false; - log::warn( - "directories do not have shell menus; '{}' selected", - item->filename()); + log::warn("directories do not have shell menus; '{}' selected", item->filename()); continue; } @@ -550,9 +534,8 @@ bool FileTree::showShellMenu(QPoint pos) if (item->isFromArchive()) { warnOnEmpty = false; - log::warn( - "files from archives do not have shell menus; '{}' selected", - item->filename()); + log::warn("files from archives do not have shell menus; '{}' selected", + item->filename()); continue; } @@ -563,9 +546,8 @@ bool FileTree::showShellMenu(QPoint pos) } if (!QFile::exists(item->realPath())) { - log::error("{}", - tr("File '%1' does not exist, you may need to refresh.") - .arg(item->realPath())); + log::error("{}", tr("File '%1' does not exist, you may need to refresh.") + .arg(item->realPath())); } itor->second.addFile(QFileInfo(item->realPath())); @@ -573,21 +555,19 @@ bool FileTree::showShellMenu(QPoint pos) if (item->isConflicted()) { const auto file = m_core.directoryStructure()->searchFile( - item->dataRelativeFilePath().toStdWString(), nullptr); + item->dataRelativeFilePath().toStdWString(), nullptr); if (!file) { - log::error( - "file '{}' not found, data path={}, real path={}", - item->filename(), item->dataRelativeFilePath(), item->realPath()); + log::error("file '{}' not found, data path={}, real path={}", item->filename(), + item->dataRelativeFilePath(), item->realPath()); continue; } const auto alts = file->getAlternatives(); if (alts.empty()) { - log::warn( - "file '{}' has no alternative origins but is marked as conflicted", - item->dataRelativeFilePath()); + log::warn("file '{}' has no alternative origins but is marked as conflicted", + item->dataRelativeFilePath()); } for (auto&& alt : alts) { @@ -598,17 +578,15 @@ bool FileTree::showShellMenu(QPoint pos) const auto fullPath = file->getFullPath(alt.originID()); if (fullPath.empty()) { - log::error( - "file {} not found in origin {}", - item->dataRelativeFilePath(), alt.originID()); + log::error("file {} not found in origin {}", item->dataRelativeFilePath(), + alt.originID()); continue; } if (!QFile::exists(QString::fromStdWString(fullPath))) { - log::error("{}", - tr("File '%1' does not exist, you may need to refresh.") - .arg(QString::fromStdWString(fullPath))); + log::error("{}", tr("File '%1' does not exist, you may need to refresh.") + .arg(QString::fromStdWString(fullPath))); } itor->second.addFile(QFileInfo(QString::fromStdWString(fullPath))); @@ -624,8 +602,7 @@ bool FileTree::showShellMenu(QPoint pos) } return false; - } - else if (menus.size() == 1) { + } else if (menus.size() == 1) { auto& menu = menus.begin()->second; menu.exec(m_tree->viewport()->mapToGlobal(pos)); } else { @@ -676,40 +653,50 @@ void FileTree::addFileMenus(QMenu& menu, const FileEntry& file, int originID) const QFileInfo target(QString::fromStdWString(file.getFullPath())); MenuItem(tr("&Add as Executable")) - .callback([&]{ addAsExecutable(); }) - .hint(tr("Add this file to the executables list")) - .disabledHint(tr("This file is not executable")) - .enabled(getFileExecutionType(target) == FileExecutionTypes::Executable) - .addTo(menu); + .callback([&] { + addAsExecutable(); + }) + .hint(tr("Add this file to the executables list")) + .disabledHint(tr("This file is not executable")) + .enabled(getFileExecutionType(target) == FileExecutionTypes::Executable) + .addTo(menu); MenuItem(tr("Reveal in E&xplorer")) - .callback([&]{ exploreOrigin(); }) - .hint(tr("Opens the file in Explorer")) - .disabledHint(tr("This file is in an archive")) - .enabled(!file.isFromArchive()) - .addTo(menu); + .callback([&] { + exploreOrigin(); + }) + .hint(tr("Opens the file in Explorer")) + .disabledHint(tr("This file is in an archive")) + .enabled(!file.isFromArchive()) + .addTo(menu); MenuItem(tr("Open &Mod Info")) - .callback([&]{ openModInfo(); }) - .hint(tr("Opens the Mod Info Window")) - .disabledHint(tr("This file is not in a managed mod")) - .enabled(originID != 0) - .addTo(menu); + .callback([&] { + openModInfo(); + }) + .hint(tr("Opens the Mod Info Window")) + .disabledHint(tr("This file is not in a managed mod")) + .enabled(originID != 0) + .addTo(menu); if (isHidden(file)) { MenuItem(tr("&Un-Hide")) - .callback([&]{ unhide(); }) - .hint(tr("Un-hides the file")) - .disabledHint(tr("This file is in an archive")) - .enabled(!file.isFromArchive()) - .addTo(menu); + .callback([&] { + unhide(); + }) + .hint(tr("Un-hides the file")) + .disabledHint(tr("This file is in an archive")) + .enabled(!file.isFromArchive()) + .addTo(menu); } else { MenuItem(tr("&Hide")) - .callback([&]{ hide(); }) - .hint(tr("Hides the file")) - .disabledHint(tr("This file is in an archive")) - .enabled(!file.isFromArchive()) - .addTo(menu); + .callback([&] { + hide(); + }) + .hint(tr("Hides the file")) + .disabledHint(tr("This file is in an archive")) + .enabled(!file.isFromArchive()) + .addTo(menu); } } @@ -722,43 +709,48 @@ void FileTree::addOpenMenus(QMenu& menu, const MOShared::FileEntry& file) const QFileInfo target(QString::fromStdWString(file.getFullPath())); if (getFileExecutionType(target) == FileExecutionTypes::Executable) { - openMenu - .caption(tr("&Execute")) - .callback([&]{ open(); }) - .hint(tr("Launches this program")) - .disabledHint(tr("This file is in an archive")) - .enabled(!file.isFromArchive()); + openMenu.caption(tr("&Execute")) + .callback([&] { + open(); + }) + .hint(tr("Launches this program")) + .disabledHint(tr("This file is in an archive")) + .enabled(!file.isFromArchive()); - openHookedMenu - .caption(tr("Execute with &VFS")) - .callback([&]{ openHooked(); }) - .hint(tr("Launches this program hooked to the VFS")) - .disabledHint(tr("This file is in an archive")) - .enabled(!file.isFromArchive()); + openHookedMenu.caption(tr("Execute with &VFS")) + .callback([&] { + openHooked(); + }) + .hint(tr("Launches this program hooked to the VFS")) + .disabledHint(tr("This file is in an archive")) + .enabled(!file.isFromArchive()); } else { - openMenu - .caption(tr("&Open")) - .callback([&]{ open(); }) - .hint(tr("Opens this file with its default handler")) - .disabledHint(tr("This file is in an archive")) - .enabled(!file.isFromArchive()); + openMenu.caption(tr("&Open")) + .callback([&] { + open(); + }) + .hint(tr("Opens this file with its default handler")) + .disabledHint(tr("This file is in an archive")) + .enabled(!file.isFromArchive()); - openHookedMenu - .caption(tr("Open with &VFS")) - .callback([&]{ openHooked(); }) - .hint(tr("Opens this file with its default handler hooked to the VFS")) - .disabledHint(tr("This file is in an archive")) - .enabled(!file.isFromArchive()); + openHookedMenu.caption(tr("Open with &VFS")) + .callback([&] { + openHooked(); + }) + .hint(tr("Opens this file with its default handler hooked to the VFS")) + .disabledHint(tr("This file is in an archive")) + .enabled(!file.isFromArchive()); } MenuItem previewMenu(tr("&Preview")); previewMenu - .callback([&]{ preview(); }) - .hint(tr("Previews this file within Mod Organizer")) - .disabledHint(tr( - "This file is in an archive or has no preview handler " - "associated with it")) - .enabled(canPreviewFile(m_plugins, file)); + .callback([&] { + preview(); + }) + .hint(tr("Previews this file within Mod Organizer")) + .disabledHint(tr("This file is in an archive or has no preview handler " + "associated with it")) + .enabled(canPreviewFile(m_plugins, file)); if (m_core.settings().interface().doubleClicksOpenPreviews()) { previewMenu.addTo(menu); @@ -771,7 +763,7 @@ void FileTree::addOpenMenus(QMenu& menu, const MOShared::FileEntry& file) } // bold the first enabled option, only first three are considered - for (int i=0; i<3; ++i) { + for (int i = 0; i < 3; ++i) { if (i >= menu.actions().size()) { break; } @@ -792,29 +784,37 @@ void FileTree::addCommonMenus(QMenu& menu) menu.addSeparator(); MenuItem(tr("&Save Tree to Text File...")) - .callback([&]{ dumpToFile(); }) - .hint(tr("Writes the list of files to a text file")) - .addTo(menu); + .callback([&] { + dumpToFile(); + }) + .hint(tr("Writes the list of files to a text file")) + .addTo(menu); MenuItem(tr("&Refresh")) - .callback([&]{ refresh(); }) - .hint(tr("Refreshes the list")) - .addTo(menu); + .callback([&] { + refresh(); + }) + .hint(tr("Refreshes the list")) + .addTo(menu); MenuItem(tr("Ex&pand All")) - .callback([&]{ expandAll(); }) - .addTo(menu); + .callback([&] { + expandAll(); + }) + .addTo(menu); MenuItem(tr("&Collapse All")) - .callback([&]{ collapseAll(); }) - .addTo(menu); + .callback([&] { + collapseAll(); + }) + .addTo(menu); } QModelIndex FileTree::proxiedIndex(const QModelIndex& index) { auto* model = m_tree->model(); - if (auto* proxy=dynamic_cast<QSortFilterProxyModel*>(model)) { + if (auto* proxy = dynamic_cast<QSortFilterProxyModel*>(model)) { return proxy->mapToSource(index); } else { return index; diff --git a/src/filetree.h b/src/filetree.h index 8d71abb3..d9597322 100644 --- a/src/filetree.h +++ b/src/filetree.h @@ -4,7 +4,10 @@ #include "modinfo.h" #include "modinfodialogfwd.h" -namespace MOShared { class FileEntry; } +namespace MOShared +{ +class FileEntry; +} class OrganizerCore; class PluginContainer; @@ -28,17 +31,17 @@ public: void expandAll(); void collapseAll(); - void open(FileTreeItem* item=nullptr); - void openHooked(FileTreeItem* item=nullptr); - void preview(FileTreeItem* item=nullptr); - void activate(FileTreeItem* item=nullptr); + void open(FileTreeItem* item = nullptr); + void openHooked(FileTreeItem* item = nullptr); + void preview(FileTreeItem* item = nullptr); + void activate(FileTreeItem* item = nullptr); - void addAsExecutable(FileTreeItem* item=nullptr); - void exploreOrigin(FileTreeItem* item=nullptr); - void openModInfo(FileTreeItem* item=nullptr); + void addAsExecutable(FileTreeItem* item = nullptr); + void exploreOrigin(FileTreeItem* item = nullptr); + void openModInfo(FileTreeItem* item = nullptr); - void hide(FileTreeItem* item=nullptr); - void unhide(FileTreeItem* item=nullptr); + void hide(FileTreeItem* item = nullptr); + void unhide(FileTreeItem* item = nullptr); void dumpToFile() const; @@ -57,7 +60,7 @@ private: void onExpandedChanged(const QModelIndex& index, bool expanded); void onItemActivated(const QModelIndex& index); - void onContextMenu(const QPoint &pos); + void onContextMenu(const QPoint& pos); bool showShellMenu(QPoint pos); void addDirectoryMenus(QMenu& menu, FileTreeItem& item); @@ -65,9 +68,9 @@ private: void addOpenMenus(QMenu& menu, const MOShared::FileEntry& file); void addCommonMenus(QMenu& menu); - void toggleVisibility(bool b, FileTreeItem* item=nullptr); + void toggleVisibility(bool b, FileTreeItem* item = nullptr); QModelIndex proxiedIndex(const QModelIndex& index); }; -#endif // MODORGANIZER_FILETREE_INCLUDED +#endif // MODORGANIZER_FILETREE_INCLUDED diff --git a/src/filetreeitem.cpp b/src/filetreeitem.cpp index 7997974f..16c04094 100644 --- a/src/filetreeitem.cpp +++ b/src/filetreeitem.cpp @@ -1,8 +1,8 @@ #include "filetreeitem.h" #include "filetreemodel.h" #include "modinfo.h" -#include "shared/util.h" #include "modinfodialogfwd.h" +#include "shared/util.h" #include <log.h> #include <utility.h> @@ -16,7 +16,7 @@ const QString& directoryFileType() { static const QString name = [] { const DWORD flags = SHGFI_TYPENAME; - SHFILEINFOW sfi = {}; + SHFILEINFOW sfi = {}; // "." for the current directory, which should always exist const auto r = SHGetFileInfoW(L".", 0, &sfi, sizeof(sfi), flags); @@ -24,9 +24,8 @@ const QString& directoryFileType() if (!r) { const auto e = GetLastError(); - log::error( - "SHGetFileInfoW failed for folder file type, {}", - formatSystemMessage(e)); + log::error("SHGetFileInfoW failed for folder file type, {}", + formatSystemMessage(e)); return QString("File folder"); } else { @@ -41,7 +40,7 @@ const QString& cachedFileTypeNoExtension() { static const QString name = [] { const DWORD flags = SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES; - SHFILEINFOW sfi = {}; + SHFILEINFOW sfi = {}; // dummy filename with no extension const auto r = SHGetFileInfoW(L"file", 0, &sfi, sizeof(sfi), flags); @@ -49,9 +48,8 @@ const QString& cachedFileTypeNoExtension() if (!r) { const auto e = GetLastError(); - log::error( - "SHGetFileInfoW failed for file without extension, {}", - formatSystemMessage(e)); + log::error("SHGetFileInfoW failed for file without extension, {}", + formatSystemMessage(e)); return QString("File"); } else { @@ -80,7 +78,6 @@ const QString& cachedFileType(const std::wstring& file, bool isOnFilesystem) return itor->second; } - DWORD flags = SHGFI_TYPENAME; if (!isOnFilesystem) { @@ -90,16 +87,14 @@ const QString& cachedFileType(const std::wstring& file, bool isOnFilesystem) } SHFILEINFOW sfi = {}; - const auto r = SHGetFileInfoW(file.c_str(), 0, &sfi, sizeof(sfi), flags); + const auto r = SHGetFileInfoW(file.c_str(), 0, &sfi, sizeof(sfi), flags); QString s; if (!r) { const auto e = GetLastError(); - log::error( - "SHGetFileInfoW failed for '{}', {}", - file, formatSystemMessage(e)); + log::error("SHGetFileInfoW failed for '{}', {}", file, formatSystemMessage(e)); s = cachedFileTypeNoExtension(); } else { @@ -109,51 +104,41 @@ const QString& cachedFileType(const std::wstring& file, bool isOnFilesystem) return map.emplace(sv, s).first->second; } +FileTreeItem::FileTreeItem(FileTreeModel* model, FileTreeItem* parent, + std::wstring dataRelativeParentPath, bool isDirectory, + std::wstring file) + : m_model(model), m_parent(parent), m_indexGuess(NoIndexGuess), + m_virtualParentPath(QString::fromStdWString(dataRelativeParentPath)), + m_wsFile(file), m_wsLcFile(ToLowerCopy(file)), m_key(m_wsLcFile), + m_file(QString::fromStdWString(file)), m_isDirectory(isDirectory), m_originID(-1), + m_flags(NoFlags), m_loaded(false), m_expanded(false), m_sortingStale(true) +{} - -FileTreeItem::FileTreeItem( - FileTreeModel* model, FileTreeItem* parent, - std::wstring dataRelativeParentPath, bool isDirectory, std::wstring file) : - m_model(model), m_parent(parent), m_indexGuess(NoIndexGuess), - m_virtualParentPath(QString::fromStdWString(dataRelativeParentPath)), - m_wsFile(file), - m_wsLcFile(ToLowerCopy(file)), - m_key(m_wsLcFile), - m_file(QString::fromStdWString(file)), - m_isDirectory(isDirectory), - m_originID(-1), - m_flags(NoFlags), - m_loaded(false), - m_expanded(false), - m_sortingStale(true) -{ -} - -FileTreeItem::Ptr FileTreeItem::createFile( - FileTreeModel* model, FileTreeItem* parent, - std::wstring dataRelativeParentPath, std::wstring file) +FileTreeItem::Ptr FileTreeItem::createFile(FileTreeModel* model, FileTreeItem* parent, + std::wstring dataRelativeParentPath, + std::wstring file) { return std::unique_ptr<FileTreeItem>(new FileTreeItem( - model, parent, std::move(dataRelativeParentPath), false, std::move(file))); + model, parent, std::move(dataRelativeParentPath), false, std::move(file))); } -FileTreeItem::Ptr FileTreeItem::createDirectory( - FileTreeModel* model, FileTreeItem* parent, - std::wstring dataRelativeParentPath, std::wstring file) +FileTreeItem::Ptr FileTreeItem::createDirectory(FileTreeModel* model, + FileTreeItem* parent, + std::wstring dataRelativeParentPath, + std::wstring file) { return std::unique_ptr<FileTreeItem>(new FileTreeItem( - model, parent, std::move(dataRelativeParentPath), true, std::move(file))); + model, parent, std::move(dataRelativeParentPath), true, std::move(file))); } -void FileTreeItem::setOrigin( - int originID, const std::wstring& realPath, Flags flags, - const std::wstring& mod) +void FileTreeItem::setOrigin(int originID, const std::wstring& realPath, Flags flags, + const std::wstring& mod) { - m_originID = originID; + m_originID = originID; m_wsRealPath = realPath; - m_realPath = QString::fromStdWString(realPath); - m_flags = flags; - m_mod = QString::fromStdWString(mod); + m_realPath = QString::fromStdWString(realPath); + m_flags = flags; + m_mod = QString::fromStdWString(mod); m_fileSize.reset(); m_lastModified.reset(); @@ -164,9 +149,8 @@ void FileTreeItem::setOrigin( void FileTreeItem::insert(FileTreeItem::Ptr child, std::size_t at) { if (at > m_children.size()) { - log::error( - "{}: can't insert child {} at {}, out of range", - debugName(), child->debugName(), at); + log::error("{}: can't insert child {} at {}, out of range", debugName(), + child->debugName(), at); return; } @@ -193,12 +177,11 @@ void FileTreeItem::remove(std::size_t from, std::size_t n) } auto begin = m_children.begin() + from; - auto end = begin + n; + auto end = begin + n; m_children.erase(begin, end); } - template <class T> int threeWayCompare(T&& a, T&& b) { @@ -218,31 +201,26 @@ class FileTreeItem::Sorter public: static int compare(int column, const FileTreeItem* a, const FileTreeItem* b) { - switch (column) - { - case FileTreeModel::FileName: - return naturalCompare(a->m_file, b->m_file); + switch (column) { + case FileTreeModel::FileName: + return naturalCompare(a->m_file, b->m_file); - case FileTreeModel::ModName: - return naturalCompare(a->m_mod, b->m_mod); + case FileTreeModel::ModName: + return naturalCompare(a->m_mod, b->m_mod); - case FileTreeModel::FileType: - return naturalCompare( - a->fileType().value_or(QString()), - b->fileType().value_or(QString())); + case FileTreeModel::FileType: + return naturalCompare(a->fileType().value_or(QString()), + b->fileType().value_or(QString())); - case FileTreeModel::FileSize: - return threeWayCompare( - a->fileSize().value_or(0), - b->fileSize().value_or(0)); + case FileTreeModel::FileSize: + return threeWayCompare(a->fileSize().value_or(0), b->fileSize().value_or(0)); - case FileTreeModel::LastModified: - return threeWayCompare( - a->lastModified().value_or(QDateTime()), - b->lastModified().value_or(QDateTime())); + case FileTreeModel::LastModified: + return threeWayCompare(a->lastModified().value_or(QDateTime()), + b->lastModified().value_or(QDateTime())); - default: - return 0; + default: + return 0; } } }; @@ -271,7 +249,7 @@ void FileTreeItem::sort(int column, Qt::SortOrder order, bool force) } if (m_sortingStale || force) { - //log::debug("sorting is stale for {}, sorting now", debugName()); + // log::debug("sorting is stale for {}, sorting now", debugName()); m_sortingStale = false; std::sort(m_children.begin(), m_children.end(), [&](auto&& a, auto&& b) { @@ -448,7 +426,7 @@ bool FileTreeItem::areChildrenVisible() const QString FileTreeItem::debugName() const { return QString("%1(ld=%2,cs=%3)") - .arg(virtualPath()) - .arg(m_loaded) - .arg(m_children.size()); + .arg(virtualPath()) + .arg(m_loaded) + .arg(m_children.size()); } diff --git a/src/filetreeitem.h b/src/filetreeitem.h index 750e4719..ea2fd308 100644 --- a/src/filetreeitem.h +++ b/src/filetreeitem.h @@ -11,7 +11,7 @@ class FileTreeItem class Sorter; public: - using Ptr = std::unique_ptr<FileTreeItem>; + using Ptr = std::unique_ptr<FileTreeItem>; using Children = std::vector<Ptr>; enum Flag @@ -21,25 +21,21 @@ public: Conflicted = 0x02 }; - Q_DECLARE_FLAGS(Flags, Flag); - static Ptr createFile( - FileTreeModel* model, FileTreeItem* parent, - std::wstring dataRelativeParentPath, std::wstring file); + static Ptr createFile(FileTreeModel* model, FileTreeItem* parent, + std::wstring dataRelativeParentPath, std::wstring file); - static Ptr createDirectory( - FileTreeModel* model, FileTreeItem* parent, - std::wstring dataRelativeParentPath, std::wstring file); + static Ptr createDirectory(FileTreeModel* model, FileTreeItem* parent, + std::wstring dataRelativeParentPath, std::wstring file); - FileTreeItem(const FileTreeItem&) = delete; + FileTreeItem(const FileTreeItem&) = delete; FileTreeItem& operator=(const FileTreeItem&) = delete; - FileTreeItem(FileTreeItem&&) = default; - FileTreeItem& operator=(FileTreeItem&&) = default; + FileTreeItem(FileTreeItem&&) = default; + FileTreeItem& operator=(FileTreeItem&&) = default; - void setOrigin( - int originID, const std::wstring& realPath, - Flags flags, const std::wstring& mod); + void setOrigin(int originID, const std::wstring& realPath, Flags flags, + const std::wstring& mod); void add(Ptr child) { @@ -53,7 +49,7 @@ public: void insert(Itor begin, Itor end, std::size_t at) { std::size_t nextRowGuess = m_children.size(); - for (auto itor=begin; itor!=end; ++itor) { + for (auto itor = begin; itor != end; ++itor) { (*itor)->m_indexGuess = nextRowGuess++; } @@ -69,10 +65,7 @@ public: m_loaded = false; } - const Children& children() const - { - return m_children; - } + const Children& children() const { return m_children; } int childIndex(const FileTreeItem& item) const { @@ -82,7 +75,7 @@ public: } } - for (std::size_t i=0; i<m_children.size(); ++i) { + for (std::size_t i = 0; i < m_children.size(); ++i) { if (m_children[i].get() == &item) { item.m_indexGuess = i; return static_cast<int>(i); @@ -95,47 +88,23 @@ public: void sort(int column, Qt::SortOrder order, bool force); void makeSortingStale(); - FileTreeItem* parent() - { - return m_parent; - } + FileTreeItem* parent() { return m_parent; } - int originID() const - { - return m_originID; - } + int originID() const { return m_originID; } - const QString& virtualParentPath() const - { - return m_virtualParentPath; - } + const QString& virtualParentPath() const { return m_virtualParentPath; } QString virtualPath() const; - const QString& filename() const - { - return m_file; - } + const QString& filename() const { return m_file; } - const std::wstring& filenameWs() const - { - return m_wsFile; - } + const std::wstring& filenameWs() const { return m_wsFile; } - const std::wstring& filenameWsLowerCase() const - { - return m_wsLcFile; - } + const std::wstring& filenameWsLowerCase() const { return m_wsLcFile; } - const MOShared::DirectoryEntryFileKey& key() const - { - return m_key; - } + const MOShared::DirectoryEntryFileKey& key() const { return m_key; } - const QString& mod() const - { - return m_mod; - } + const QString& mod() const { return m_mod; } QFont font() const; @@ -148,44 +117,26 @@ public: return m_compressedFileSize.value; } - void setFileSize(uint64_t size) - { - m_fileSize.override(size); - } + void setFileSize(uint64_t size) { m_fileSize.override(size); } void setCompressedFileSize(uint64_t compressedSize) { m_compressedFileSize.override(compressedSize); } - const QString& realPath() const - { - return m_realPath; - } + const QString& realPath() const { return m_realPath; } - const QString& dataRelativeParentPath() const - { - return m_virtualParentPath; - } + const QString& dataRelativeParentPath() const { return m_virtualParentPath; } QString dataRelativeFilePath() const; QFileIconProvider::IconType icon() const; - bool isDirectory() const - { - return m_isDirectory; - } + bool isDirectory() const { return m_isDirectory; } - bool isFromArchive() const - { - return (m_flags & FromArchive); - } + bool isFromArchive() const { return (m_flags & FromArchive); } - bool isConflicted() const - { - return (m_flags & Conflicted); - } + bool isConflicted() const { return (m_flags & Conflicted); } bool isHidden() const; @@ -202,16 +153,9 @@ public: return true; } + void setLoaded(bool b) { m_loaded = b; } - void setLoaded(bool b) - { - m_loaded = b; - } - - bool isLoaded() const - { - return m_loaded; - } + bool isLoaded() const { return m_loaded; } void unload(); @@ -228,10 +172,7 @@ public: } } - bool isStrictlyExpanded() const - { - return m_expanded; - } + bool isStrictlyExpanded() const { return m_expanded; } bool areChildrenVisible() const; @@ -242,46 +183,42 @@ private: struct Cached { std::optional<T> value; - bool failed = false; + bool failed = false; bool overridden = false; - bool empty() const - { - return !failed && !value; - } + bool empty() const { return !failed && !value; } void set(T t) { - value = std::move(t); - failed = false; + value = std::move(t); + failed = false; overridden = false; } void override(T t) { - value = std::move(t); - failed = false; + value = std::move(t); + failed = false; overridden = true; } void fail() { - value = {}; - failed = true; + value = {}; + failed = true; overridden = false; } void reset() { if (!overridden) { - value = {}; + value = {}; failed = false; } } }; - static constexpr std::size_t NoIndexGuess = - std::numeric_limits<std::size_t>::max(); + static constexpr std::size_t NoIndexGuess = std::numeric_limits<std::size_t>::max(); FileTreeModel* m_model; FileTreeItem* m_parent; @@ -309,13 +246,12 @@ private: bool m_sortingStale; Children m_children; - - FileTreeItem( - FileTreeModel* model, FileTreeItem* parent, - std::wstring dataRelativeParentPath, bool isDirectory, std::wstring file); + FileTreeItem(FileTreeModel* model, FileTreeItem* parent, + std::wstring dataRelativeParentPath, bool isDirectory, + std::wstring file); void getFileType() const; void queueSort(); }; -#endif // MODORGANIZER_FILETREEITEM_INCLUDED +#endif // MODORGANIZER_FILETREEITEM_INCLUDED diff --git a/src/filetreemodel.cpp b/src/filetreemodel.cpp index bd9cd067..9d63a782 100644 --- a/src/filetreemodel.cpp +++ b/src/filetreemodel.cpp @@ -1,9 +1,9 @@ #include "filetreemodel.h" #include "organizercore.h" -#include "shared/filesorigin.h" -#include "shared/util.h" #include "shared/directoryentry.h" #include "shared/fileentry.h" +#include "shared/filesorigin.h" +#include "shared/util.h" #include <log.h> #include <moassert.h> @@ -15,7 +15,6 @@ QString UnmanagedModName(); #define trace(f) - // about queueRemoveItem(), queueSortItems() and the `forFetching` parameter // // update() can be called when refreshing the tree or expanding a node; @@ -52,7 +51,6 @@ QString UnmanagedModName(); // (such as when removeDisappearingFiles()) because they cannot happen while // fetching - // tracks a contiguous range in the model to avoid calling begin*Rows(), etc. // for every single item that's added/removed // @@ -62,10 +60,9 @@ public: // note that file ranges can start from an index higher than 0 if there are // directories // - Range(FileTreeModel* model, FileTreeItem& parentItem, int start=0) - : m_model(model), m_parentItem(parentItem), m_first(-1), m_current(start) - { - } + Range(FileTreeModel* model, FileTreeItem& parentItem, int start = 0) + : m_model(model), m_parentItem(parentItem), m_first(-1), m_current(start) + {} // includes the current index in the range // @@ -80,23 +77,17 @@ public: // moves to the next row // - void next() - { - ++m_current; - } + void next() { ++m_current; } // returns the current row // - int current() const - { - return m_current; - } + int current() const { return m_current; } // manually set this range // void set(int first, int last) { - m_first = first; + m_first = first; m_current = last; } @@ -110,7 +101,7 @@ public: return; } - const auto last = m_current - 1; + const auto last = m_current - 1; const auto parentIndex = m_model->indexFromItem(m_parentItem); // make sure the number of items is the same as the size of this range @@ -120,10 +111,9 @@ public: m_model->beginInsertRows(parentIndex, m_first, last); - m_parentItem.insert( - std::make_move_iterator(toAdd.begin()), - std::make_move_iterator(toAdd.end()), - static_cast<std::size_t>(m_first)); + m_parentItem.insert(std::make_move_iterator(toAdd.begin()), + std::make_move_iterator(toAdd.end()), + static_cast<std::size_t>(m_first)); m_model->endInsertRows(); @@ -137,16 +127,15 @@ public: FileTreeItem::Children::const_iterator remove() { if (m_first >= 0) { - const auto last = m_current - 1; + const auto last = m_current - 1; const auto parentIndex = m_model->indexFromItem(m_parentItem); trace(log::debug("Range::remove() {} to {}", m_first, last)); m_model->beginRemoveRows(parentIndex, m_first, last); - m_parentItem.remove( - static_cast<std::size_t>(m_first), - static_cast<std::size_t>(last - m_first + 1)); + m_parentItem.remove(static_cast<std::size_t>(m_first), + static_cast<std::size_t>(last - m_first + 1)); m_model->endRemoveRows(); @@ -181,7 +170,6 @@ private: int m_current; }; - FileTreeItem* getItem(const QModelIndex& index) { return static_cast<FileTreeItem*>(index.internalPointer()); @@ -192,18 +180,23 @@ void* makeInternalPointer(FileTreeItem* item) return item; } - -FileTreeModel::FileTreeModel(OrganizerCore& core, QObject* parent) : - QAbstractItemModel(parent), m_core(core), m_enabled(true), - m_root(FileTreeItem::createDirectory(this, nullptr, L"", L"")), - m_flags(NoFlags), m_fullyLoaded(false), m_sortingEnabled(true) +FileTreeModel::FileTreeModel(OrganizerCore& core, QObject* parent) + : QAbstractItemModel(parent), m_core(core), m_enabled(true), + m_root(FileTreeItem::createDirectory(this, nullptr, L"", L"")), m_flags(NoFlags), + m_fullyLoaded(false), m_sortingEnabled(true) { m_root->setExpanded(true); m_sortTimer.setSingleShot(true); - connect(&m_removeTimer, &QTimer::timeout, [&]{ removeItems(); }); - connect(&m_sortTimer, &QTimer::timeout, [&]{ sortItems(); }); - connect(&m_iconPendingTimer, &QTimer::timeout, [&]{ updatePendingIcons(); }); + connect(&m_removeTimer, &QTimer::timeout, [&] { + removeItems(); + }); + connect(&m_sortTimer, &QTimer::timeout, [&] { + sortItems(); + }); + connect(&m_iconPendingTimer, &QTimer::timeout, [&] { + updatePendingIcons(); + }); } void FileTreeModel::refresh() @@ -230,7 +223,7 @@ void FileTreeModel::recursiveFetchMore(const QModelIndex& m) doFetchMore(m, false, false); } - for (int i=0; i<rowCount(m); ++i) { + for (int i = 0; i < rowCount(m); ++i) { recursiveFetchMore(index(i, 0, m)); } } @@ -276,10 +269,9 @@ bool FileTreeModel::showArchives() const return (m_flags.testFlag(Archives) && m_core.settings().archiveParsing()); } -QModelIndex FileTreeModel::index( - int row, int col, const QModelIndex& parentIndex) const +QModelIndex FileTreeModel::index(int row, int col, const QModelIndex& parentIndex) const { - if (auto* parentItem=itemFromIndex(parentIndex)) { + if (auto* parentItem = itemFromIndex(parentIndex)) { if (row < 0 || row >= parentItem->children().size()) { log::error("row {} out of range for {}", row, parentItem->debugName()); return {}; @@ -309,7 +301,7 @@ QModelIndex FileTreeModel::parent(const QModelIndex& index) const int FileTreeModel::rowCount(const QModelIndex& parent) const { - if (auto* item=itemFromIndex(parent)) { + if (auto* item = itemFromIndex(parent)) { return static_cast<int>(item->children().size()); } @@ -327,7 +319,7 @@ bool FileTreeModel::hasChildren(const QModelIndex& parent) const return false; } - if (auto* item=itemFromIndex(parent)) { + if (auto* item = itemFromIndex(parent)) { if (parent.column() <= 0) { return item->hasChildren(); } @@ -342,7 +334,7 @@ bool FileTreeModel::canFetchMore(const QModelIndex& parent) const return false; } - if (auto* item=itemFromIndex(parent)) { + if (auto* item = itemFromIndex(parent)) { return !item->isLoaded(); } @@ -354,8 +346,7 @@ void FileTreeModel::fetchMore(const QModelIndex& parent) doFetchMore(parent, true, true); } -void FileTreeModel::doFetchMore( - const QModelIndex& parent, bool forFetch, bool doSort) +void FileTreeModel::doFetchMore(const QModelIndex& parent, bool forFetch, bool doSort) { FileTreeItem* item = itemFromIndex(parent); if (!item) { @@ -364,8 +355,8 @@ void FileTreeModel::doFetchMore( const auto path = item->dataRelativeFilePath(); - auto* parentEntry = m_core.directoryStructure() - ->findSubDirectoryRecursive(path.toStdWString()); + auto* parentEntry = + m_core.directoryStructure()->findSubDirectoryRecursive(path.toStdWString()); if (!parentEntry) { log::error("FileTreeModel::fetchMore(): directory '{}' not found", path); @@ -382,58 +373,52 @@ void FileTreeModel::doFetchMore( QVariant FileTreeModel::data(const QModelIndex& index, int role) const { - switch (role) - { - case Qt::DisplayRole: - { - if (auto* item=itemFromIndex(index)) { - return displayData(item, index.column()); - } - - break; + switch (role) { + case Qt::DisplayRole: { + if (auto* item = itemFromIndex(index)) { + return displayData(item, index.column()); } - case Qt::FontRole: - { - if (auto* item=itemFromIndex(index)) { - return item->font(); - } + break; + } - break; + case Qt::FontRole: { + if (auto* item = itemFromIndex(index)) { + return item->font(); } - case Qt::ToolTipRole: - { - if (auto* item=itemFromIndex(index)) { - return makeTooltip(*item); - } + break; + } - return {}; + case Qt::ToolTipRole: { + if (auto* item = itemFromIndex(index)) { + return makeTooltip(*item); } - case Qt::ForegroundRole: - { - if (index.column() == 1) { - if (auto* item=itemFromIndex(index)) { - if (item->isConflicted()) { - return QBrush(Qt::red); - } + return {}; + } + + case Qt::ForegroundRole: { + if (index.column() == 1) { + if (auto* item = itemFromIndex(index)) { + if (item->isConflicted()) { + return QBrush(Qt::red); } } - - break; } - case Qt::DecorationRole: - { - if (index.column() == 0) { - if (auto* item=itemFromIndex(index)) { - return makeIcon(*item, index); - } - } + break; + } - break; + case Qt::DecorationRole: { + if (index.column() == 0) { + if (auto* item = itemFromIndex(index)) { + return makeIcon(*item, index); + } } + + break; + } } return {}; @@ -442,8 +427,7 @@ QVariant FileTreeModel::data(const QModelIndex& index, int role) const QVariant FileTreeModel::headerData(int i, Qt::Orientation ori, int role) const { static const std::array<QString, ColumnCount> names = { - tr("Name"), tr("Mod"), tr("Type"), tr("Size"), tr("Date modified") - }; + tr("Name"), tr("Mod"), tr("Type"), tr("Size"), tr("Date modified")}; if (role == Qt::DisplayRole) { if (i >= 0 && i < static_cast<int>(names.size())) { @@ -458,7 +442,7 @@ Qt::ItemFlags FileTreeModel::flags(const QModelIndex& index) const { auto f = QAbstractItemModel::flags(index); - if (auto* item=itemFromIndex(index)) { + if (auto* item = itemFromIndex(index)) { if (!item->hasChildren()) { f |= Qt::ItemNeverHasChildren; } @@ -471,14 +455,13 @@ void FileTreeModel::sortItem(FileTreeItem& item, bool force) { emit layoutAboutToBeChanged({}, QAbstractItemModel::VerticalSortHint); - const auto oldList = persistentIndexList(); std::vector<std::pair<FileTreeItem*, int>> oldItems; const auto itemCount = oldList.size(); oldItems.reserve(static_cast<std::size_t>(itemCount)); - for (int i=0; i<itemCount; ++i) { + for (int i = 0; i < itemCount; ++i) { const QModelIndex& index = oldList[i]; oldItems.push_back({itemFromIndex(index), index.column()}); } @@ -488,7 +471,7 @@ void FileTreeModel::sortItem(FileTreeItem& item, bool force) QModelIndexList newList; newList.reserve(itemCount); - for (int i=0; i<itemCount; ++i) { + for (int i = 0; i < itemCount; ++i) { const auto& pair = oldItems[static_cast<std::size_t>(i)]; newList.append(indexFromItem(*pair.first, pair.second)); } @@ -501,7 +484,7 @@ void FileTreeModel::sortItem(FileTreeItem& item, bool force) void FileTreeModel::sort(int column, Qt::SortOrder order) { m_sort.column = column; - m_sort.order = order; + m_sort.order = order; sortItem(*m_root, true); } @@ -519,9 +502,8 @@ FileTreeItem* FileTreeModel::itemFromIndex(const QModelIndex& index) const } if (index.row() < 0 || index.row() >= parentItem->children().size()) { - log::error( - "FileTreeModel::itemFromIndex(): row {} is out of range for {}", - index.row(), parentItem->debugName()); + log::error("FileTreeModel::itemFromIndex(): row {} is out of range for {}", + index.row(), parentItem->debugName()); return nullptr; } @@ -538,9 +520,8 @@ QModelIndex FileTreeModel::indexFromItem(FileTreeItem& item, int col) const const int index = parent->childIndex(item); if (index == -1) { - log::error( - "FileTreeMode::indexFromItem(): item {} not found in parent", - item.debugName()); + log::error("FileTreeMode::indexFromItem(): item {} not found in parent", + item.debugName()); return {}; } @@ -548,9 +529,9 @@ QModelIndex FileTreeModel::indexFromItem(FileTreeItem& item, int col) const return createIndex(index, col, makeInternalPointer(parent)); } -void FileTreeModel::update( - FileTreeItem& parentItem, const MOShared::DirectoryEntry& parentEntry, - const std::wstring& parentPath, bool forFetching) +void FileTreeModel::update(FileTreeItem& parentItem, + const MOShared::DirectoryEntry& parentEntry, + const std::wstring& parentPath, bool forFetching) { trace(log::debug("updating {}", parentItem.debugName())); @@ -588,9 +569,10 @@ void FileTreeModel::update( } } -bool FileTreeModel::updateDirectories( - FileTreeItem& parentItem, const std::wstring& parentPath, - const MOShared::DirectoryEntry& parentEntry, bool forFetching) +bool FileTreeModel::updateDirectories(FileTreeItem& parentItem, + const std::wstring& parentPath, + const MOShared::DirectoryEntry& parentEntry, + bool forFetching) { // removeDisappearingDirectories() will add directories that are in the // tree and still on the filesystem to this set; addNewDirectories() will @@ -602,12 +584,12 @@ bool FileTreeModel::updateDirectories( } void FileTreeModel::removeDisappearingDirectories( - FileTreeItem& parentItem, const MOShared::DirectoryEntry& parentEntry, - const std::wstring& parentPath, std::unordered_set<std::wstring_view>& seen, - bool forFetching) + FileTreeItem& parentItem, const MOShared::DirectoryEntry& parentEntry, + const std::wstring& parentPath, std::unordered_set<std::wstring_view>& seen, + bool forFetching) { auto& children = parentItem.children(); - auto itor = children.begin(); + auto itor = children.begin(); // keeps track of the contiguous directories that need to be removed to // avoid calling beginRemoveRows(), etc. for each item @@ -688,10 +670,10 @@ void FileTreeModel::removeDisappearingDirectories( range.remove(); } -bool FileTreeModel::addNewDirectories( - FileTreeItem& parentItem, const MOShared::DirectoryEntry& parentEntry, - const std::wstring& parentPath, - const std::unordered_set<std::wstring_view>& seen) +bool FileTreeModel::addNewDirectories(FileTreeItem& parentItem, + const MOShared::DirectoryEntry& parentEntry, + const std::wstring& parentPath, + const std::unordered_set<std::wstring_view>& seen) { // keeps track of the contiguous directories that need to be added to // avoid calling beginAddRows(), etc. for each item @@ -715,7 +697,8 @@ bool FileTreeModel::addNewDirectories( } else { if (!shouldShowFolder(*d, nullptr)) { // this is a new directory, but it doesn't contain anything interesting - trace(log::debug("new dir {}, empty and pruned", QString::fromStdWString(d->getName()))); + trace(log::debug("new dir {}, empty and pruned", + QString::fromStdWString(d->getName()))); // act as if this directory doesn't exist at all continue; @@ -739,9 +722,9 @@ bool FileTreeModel::addNewDirectories( return added; } -bool FileTreeModel::updateFiles( - FileTreeItem& parentItem, const std::wstring& parentPath, - const MOShared::DirectoryEntry& parentEntry) +bool FileTreeModel::updateFiles(FileTreeItem& parentItem, + const std::wstring& parentPath, + const MOShared::DirectoryEntry& parentEntry) { // removeDisappearingFiles() will add files that are in the tree and still on // the filesystem to this set; addNewFiless() will use this to figure out if @@ -754,12 +737,13 @@ bool FileTreeModel::updateFiles( return addNewFiles(parentItem, parentEntry, parentPath, firstFileRow, seen); } -void FileTreeModel::removeDisappearingFiles( - FileTreeItem& parentItem, const MOShared::DirectoryEntry& parentEntry, - int& firstFileRow, std::unordered_set<FileIndex>& seen) +void FileTreeModel::removeDisappearingFiles(FileTreeItem& parentItem, + const MOShared::DirectoryEntry& parentEntry, + int& firstFileRow, + std::unordered_set<FileIndex>& seen) { auto& children = parentItem.children(); - auto itor = children.begin(); + auto itor = children.begin(); firstFileRow = -1; @@ -814,10 +798,10 @@ void FileTreeModel::removeDisappearingFiles( } } -bool FileTreeModel::addNewFiles( - FileTreeItem& parentItem, const MOShared::DirectoryEntry& parentEntry, - const std::wstring& parentPath, const int firstFileRow, - const std::unordered_set<FileIndex>& seen) +bool FileTreeModel::addNewFiles(FileTreeItem& parentItem, + const MOShared::DirectoryEntry& parentEntry, + const std::wstring& parentPath, const int firstFileRow, + const std::unordered_set<FileIndex>& seen) { // keeps track of the contiguous files that need to be added to // avoid calling beginAddRows(), etc. for each item @@ -838,9 +822,8 @@ bool FileTreeModel::addNewFiles( const auto file = parentEntry.getFileByIndex(fileIndex); if (!file) { - log::error( - "FileTreeModel::addNewFiles(): file index {} in path {} not found", - fileIndex, parentPath); + log::error("FileTreeModel::addNewFiles(): file index {} in path {} not found", + fileIndex, parentPath); return true; } @@ -855,7 +838,8 @@ bool FileTreeModel::addNewFiles( range.includeCurrent(); } else { // this is a new file, but it shouldn't be shown - trace(log::debug("new file {}, not shown", QString::fromStdWString(file->getName()))); + trace(log::debug("new file {}, not shown", + QString::fromStdWString(file->getName()))); return true; } } @@ -924,12 +908,11 @@ void FileTreeModel::sortItems() } } -FileTreeItem::Ptr FileTreeModel::createDirectoryItem( - FileTreeItem& parentItem, const std::wstring& parentPath, - const DirectoryEntry& d) +FileTreeItem::Ptr FileTreeModel::createDirectoryItem(FileTreeItem& parentItem, + const std::wstring& parentPath, + const DirectoryEntry& d) { - auto item = FileTreeItem::createDirectory( - this, &parentItem, parentPath, d.getName()); + auto item = FileTreeItem::createDirectory(this, &parentItem, parentPath, d.getName()); if (d.isEmpty()) { // if this directory is empty, mark the item as loaded so the expand @@ -940,12 +923,11 @@ FileTreeItem::Ptr FileTreeModel::createDirectoryItem( return item; } -FileTreeItem::Ptr FileTreeModel::createFileItem( - FileTreeItem& parentItem, const std::wstring& parentPath, - const FileEntry& file) +FileTreeItem::Ptr FileTreeModel::createFileItem(FileTreeItem& parentItem, + const std::wstring& parentPath, + const FileEntry& file) { - auto item = FileTreeItem::createFile( - this, &parentItem, parentPath, file.getName()); + auto item = FileTreeItem::createFile(this, &parentItem, parentPath, file.getName()); updateFileItem(*item, file); @@ -954,11 +936,10 @@ FileTreeItem::Ptr FileTreeModel::createFileItem( return item; } -void FileTreeModel::updateFileItem( - FileTreeItem& item, const MOShared::FileEntry& file) +void FileTreeModel::updateFileItem(FileTreeItem& item, const MOShared::FileEntry& file) { bool isArchive = false; - int originID = file.getOrigin(isArchive); + int originID = file.getOrigin(isArchive); FileTreeItem::Flags flags = FileTreeItem::NoFlags; @@ -970,8 +951,7 @@ void FileTreeModel::updateFileItem( flags |= FileTreeItem::Conflicted; } - item.setOrigin( - originID, file.getFullPath(), flags, makeModName(file, originID)); + item.setOrigin(originID, file.getFullPath(), flags, makeModName(file, originID)); if (file.getFileSize() != FileEntry::NoFileSize) { item.setFileSize(file.getFileSize()); @@ -997,8 +977,8 @@ bool FileTreeModel::shouldShowFile(const FileEntry& file) const return true; } -bool FileTreeModel::shouldShowFolder( - const DirectoryEntry& dir, const FileTreeItem* item) const +bool FileTreeModel::shouldShowFolder(const DirectoryEntry& dir, + const FileTreeItem* item) const { bool shouldPrune = m_flags.testFlag(PruneDirectories); @@ -1061,62 +1041,55 @@ bool FileTreeModel::shouldShowFolder( QVariant FileTreeModel::displayData(const FileTreeItem* item, int column) const { - switch (column) - { - case FileName: - { - return item->filename(); - } + switch (column) { + case FileName: { + return item->filename(); + } - case ModName: - { - return item->mod(); - } + case ModName: { + return item->mod(); + } - case FileType: - { - return item->fileType().value_or(QString()); - } + case FileType: { + return item->fileType().value_or(QString()); + } - case FileSize: - { - if (item->isDirectory()) { - return {}; - } else { - QString fs; + case FileSize: { + if (item->isDirectory()) { + return {}; + } else { + QString fs; - if (auto n=item->fileSize()) { - fs = localizedByteSize(*n); - } + if (auto n = item->fileSize()) { + fs = localizedByteSize(*n); + } - if (auto n=item->compressedFileSize()) { - return QString("%1 (%2)").arg(fs).arg(localizedByteSize(*n)); - } else { - return fs; - } + if (auto n = item->compressedFileSize()) { + return QString("%1 (%2)").arg(fs).arg(localizedByteSize(*n)); + } else { + return fs; } } + } - case LastModified: - { - if (auto d=item->lastModified()) { - if (d.has_value() && d.value().isValid()) { - return QLocale::system().toString(d.value(), QLocale::ShortFormat); - } + case LastModified: { + if (auto d = item->lastModified()) { + if (d.has_value() && d.value().isValid()) { + return QLocale::system().toString(d.value(), QLocale::ShortFormat); } - - return {}; } - default: - { - return {}; - } + return {}; + } + + default: { + return {}; + } } } -std::wstring FileTreeModel::makeModName( - const MOShared::FileEntry& file, int originID) const +std::wstring FileTreeModel::makeModName(const MOShared::FileEntry& file, + int originID) const { static const std::wstring Unmanaged = UnmanagedModName().toStdWString(); @@ -1150,34 +1123,26 @@ QString FileTreeModel::makeTooltip(const FileTreeItem& item) const } }; - if (item.isDirectory()) { - return - line(tr("Directory"), item.filename()) + - line(tr("Virtual path"), item.virtualPath()); + return line(tr("Directory"), item.filename()) + + line(tr("Virtual path"), item.virtualPath()); } - - static const QString ListStart = - "<ul style=\"" - "margin-left: 20px; " - "margin-top: 0; " - "margin-bottom: 0; " - "padding: 0; " - "-qt-list-indent: 0;" - "\">"; + static const QString ListStart = "<ul style=\"" + "margin-left: 20px; " + "margin-top: 0; " + "margin-bottom: 0; " + "padding: 0; " + "-qt-list-indent: 0;" + "\">"; static const QString ListEnd = "</ul>"; - - QString s = - line(tr("Virtual path"), item.virtualPath()) + - line(tr("Real path"), item.realPath()) + - line(tr("From"), item.mod()); - + QString s = line(tr("Virtual path"), item.virtualPath()) + + line(tr("Real path"), item.realPath()) + line(tr("From"), item.mod()); const auto file = m_core.directoryStructure()->searchFile( - item.dataRelativeFilePath().toStdWString(), nullptr); + item.dataRelativeFilePath().toStdWString(), nullptr); if (file) { const auto alternatives = file->getAlternatives(); @@ -1194,7 +1159,7 @@ QString FileTreeModel::makeTooltip(const FileTreeItem& item) const s += line(tr("Also in"), QString()) + ListStart; for (auto&& alt : list) { - s += "<li>" + alt +"</li>"; + s += "<li>" + alt + "</li>"; } s += ListEnd; @@ -1204,8 +1169,8 @@ QString FileTreeModel::makeTooltip(const FileTreeItem& item) const return s; } -QVariant FileTreeModel::makeIcon( - const FileTreeItem& item, const QModelIndex& index) const +QVariant FileTreeModel::makeIcon(const FileTreeItem& item, + const QModelIndex& index) const { if (item.isDirectory()) { return m_iconFetcher.genericDirectoryIcon(); @@ -1236,8 +1201,7 @@ void FileTreeModel::updatePendingIcons() } } -void FileTreeModel::removePendingIcons( - const QModelIndex& parent, int first, int last) +void FileTreeModel::removePendingIcons(const QModelIndex& parent, int first, int last) { auto itor = m_iconPending.begin(); diff --git a/src/filetreemodel.h b/src/filetreemodel.h index 73a18d91..fbb70c7a 100644 --- a/src/filetreemodel.h +++ b/src/filetreemodel.h @@ -36,25 +36,18 @@ public: struct SortInfo { - int column = 0; + int column = 0; Qt::SortOrder order = Qt::AscendingOrder; }; + FileTreeModel(OrganizerCore& core, QObject* parent = nullptr); - FileTreeModel(OrganizerCore& core, QObject* parent=nullptr); - - void setFlags(Flags f) - { - m_flags = f; - } + void setFlags(Flags f) { m_flags = f; } void refresh(); void clear(); - bool fullyLoaded() const - { - return m_fullyLoaded; - } + bool fullyLoaded() const { return m_fullyLoaded; } void ensureFullyLoaded(); @@ -64,20 +57,20 @@ public: void aboutToExpandAll(); void expandedAll(); - const SortInfo& sortInfo() const; - QModelIndex index(int row, int col, const QModelIndex& parent={}) const override; + QModelIndex index(int row, int col, const QModelIndex& parent = {}) const override; QModelIndex parent(const QModelIndex& index) const override; - int rowCount(const QModelIndex& parent={}) const override; - int columnCount(const QModelIndex& parent={}) const override; - bool hasChildren(const QModelIndex& parent={}) const override; + int rowCount(const QModelIndex& parent = {}) const override; + int columnCount(const QModelIndex& parent = {}) const override; + bool hasChildren(const QModelIndex& parent = {}) const override; bool canFetchMore(const QModelIndex& parent) const override; void fetchMore(const QModelIndex& parent) override; - QVariant data(const QModelIndex& index, int role=Qt::DisplayRole) const override; - QVariant headerData(int i, Qt::Orientation ori, int role=Qt::DisplayRole) const override; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + QVariant headerData(int i, Qt::Orientation ori, + int role = Qt::DisplayRole) const override; Qt::ItemFlags flags(const QModelIndex& index) const override; - void sort(int column, Qt::SortOrder order=Qt::AscendingOrder) override; + void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; FileTreeItem* itemFromIndex(const QModelIndex& index) const; void sortItem(FileTreeItem& item, bool force); @@ -105,19 +98,13 @@ private: QTimer m_removeTimer; QTimer m_sortTimer; - - bool showConflictsOnly() const - { - return (m_flags & ConflictsOnly); - } + bool showConflictsOnly() const { return (m_flags & ConflictsOnly); } bool showArchives() const; - // for `forFetching`, see top of filetreemodel.cpp - void update( - FileTreeItem& parentItem, const MOShared::DirectoryEntry& parentEntry, - const std::wstring& parentPath, bool forFetching); + void update(FileTreeItem& parentItem, const MOShared::DirectoryEntry& parentEntry, + const std::wstring& parentPath, bool forFetching); void doFetchMore(const QModelIndex& parent, bool forFetch, bool doSort); @@ -126,49 +113,45 @@ private: void sortItems(); - // for `forFetching`, see top of filetreemodel.cpp - bool updateDirectories( - FileTreeItem& parentItem, const std::wstring& path, - const MOShared::DirectoryEntry& parentEntry, bool forFetching); + bool updateDirectories(FileTreeItem& parentItem, const std::wstring& path, + const MOShared::DirectoryEntry& parentEntry, bool forFetching); // for `forFetching`, see top of filetreemodel.cpp - void removeDisappearingDirectories( - FileTreeItem& parentItem, const MOShared::DirectoryEntry& parentEntry, - const std::wstring& parentPath, std::unordered_set<std::wstring_view>& seen, - bool forFetching); - - bool addNewDirectories( - FileTreeItem& parentItem, const MOShared::DirectoryEntry& parentEntry, - const std::wstring& parentPath, - const std::unordered_set<std::wstring_view>& seen); + void removeDisappearingDirectories(FileTreeItem& parentItem, + const MOShared::DirectoryEntry& parentEntry, + const std::wstring& parentPath, + std::unordered_set<std::wstring_view>& seen, + bool forFetching); + bool addNewDirectories(FileTreeItem& parentItem, + const MOShared::DirectoryEntry& parentEntry, + const std::wstring& parentPath, + const std::unordered_set<std::wstring_view>& seen); - bool updateFiles( - FileTreeItem& parentItem, const std::wstring& path, - const MOShared::DirectoryEntry& parentEntry); + bool updateFiles(FileTreeItem& parentItem, const std::wstring& path, + const MOShared::DirectoryEntry& parentEntry); - void removeDisappearingFiles( - FileTreeItem& parentItem, const MOShared::DirectoryEntry& parentEntry, - int& firstFileRow, std::unordered_set<MOShared::FileIndex>& seen); + void removeDisappearingFiles(FileTreeItem& parentItem, + const MOShared::DirectoryEntry& parentEntry, + int& firstFileRow, + std::unordered_set<MOShared::FileIndex>& seen); - bool addNewFiles( - FileTreeItem& parentItem, const MOShared::DirectoryEntry& parentEntry, - const std::wstring& parentPath, int firstFileRow, - const std::unordered_set<MOShared::FileIndex>& seen); + bool addNewFiles(FileTreeItem& parentItem, + const MOShared::DirectoryEntry& parentEntry, + const std::wstring& parentPath, int firstFileRow, + const std::unordered_set<MOShared::FileIndex>& seen); + FileTreeItem::Ptr createDirectoryItem(FileTreeItem& parentItem, + const std::wstring& parentPath, + const MOShared::DirectoryEntry& d); - FileTreeItem::Ptr createDirectoryItem( - FileTreeItem& parentItem, const std::wstring& parentPath, - const MOShared::DirectoryEntry& d); - - FileTreeItem::Ptr createFileItem( - FileTreeItem& parentItem, const std::wstring& parentPath, - const MOShared::FileEntry& file); + FileTreeItem::Ptr createFileItem(FileTreeItem& parentItem, + const std::wstring& parentPath, + const MOShared::FileEntry& file); void updateFileItem(FileTreeItem& item, const MOShared::FileEntry& file); - QVariant displayData(const FileTreeItem* item, int column) const; std::wstring makeModName(const MOShared::FileEntry& file, int originID) const; @@ -177,15 +160,16 @@ private: void removePendingIcons(const QModelIndex& parent, int first, int last); bool shouldShowFile(const MOShared::FileEntry& file) const; - bool shouldShowFolder(const MOShared::DirectoryEntry& dir, const FileTreeItem* item) const; + bool shouldShowFolder(const MOShared::DirectoryEntry& dir, + const FileTreeItem* item) const; QString makeTooltip(const FileTreeItem& item) const; QVariant makeIcon(const FileTreeItem& item, const QModelIndex& index) const; - QModelIndex indexFromItem(FileTreeItem& item, int col=0) const; + QModelIndex indexFromItem(FileTreeItem& item, int col = 0) const; void recursiveFetchMore(const QModelIndex& m); }; Q_DECLARE_OPERATORS_FOR_FLAGS(FileTreeModel::Flags); Q_DECLARE_OPERATORS_FOR_FLAGS(FileTreeItem::Flags); -#endif // MODORGANIZER_FILETREEMODEL_INCLUDED +#endif // MODORGANIZER_FILETREEMODEL_INCLUDED diff --git a/src/filterlist.cpp b/src/filterlist.cpp index b594bcc6..d0c7199e 100644 --- a/src/filterlist.cpp +++ b/src/filterlist.cpp @@ -1,23 +1,22 @@ #include "filterlist.h" -#include "ui_mainwindow.h" #include "categories.h" #include "categoriesdialog.h" -#include "settings.h" #include "organizercore.h" +#include "settings.h" +#include "ui_mainwindow.h" #include <utility.h> using namespace MOBase; using CriteriaType = ModListSortProxy::CriteriaType; -using Criteria = ModListSortProxy::Criteria; +using Criteria = ModListSortProxy::Criteria; class FilterList::CriteriaItem : public QTreeWidgetItem { - static constexpr int IDRole = Qt::UserRole; + static constexpr int IDRole = Qt::UserRole; static constexpr int TypeRole = Qt::UserRole + 1; public: - static constexpr int StateRole = Qt::UserRole + 2; enum States @@ -32,7 +31,7 @@ public: }; CriteriaItem(FilterList* list, QString name, CriteriaType type, int id) - : QTreeWidgetItem({"", name}), m_list(list), m_state(Inactive) + : QTreeWidgetItem({"", name}), m_list(list), m_state(Inactive) { setData(0, Qt::ToolTipRole, name); setData(0, TypeRole, type); @@ -45,15 +44,9 @@ public: return static_cast<CriteriaType>(data(0, TypeRole).toInt()); } - int id() const - { - return data(0, IDRole).toInt(); - } + int id() const { return data(0, IDRole).toInt(); } - States state() const - { - return m_state; - } + States state() const { return m_state; } void setState(States s) { @@ -89,17 +82,16 @@ public: return QTreeWidgetItem::data(column, role); } - void setData(int column, int role, const QVariant& value) { + void setData(int column, int role, const QVariant& value) + { if (role == StateRole) { setState(static_cast<States>(value.toInt())); - } - else { + } else { QTreeWidgetItem::setData(column, role, value); } } private: - FilterList* m_list; States m_state; @@ -107,40 +99,34 @@ private: { QIcon i; - switch (m_state) - { - case Inactive: - { - i = QIcon(":/MO/gui/unchecked-checkbox"); - break; - } + switch (m_state) { + case Inactive: { + i = QIcon(":/MO/gui/unchecked-checkbox"); + break; + } - case Active: - { - i = QIcon(":/MO/gui/checked-checkbox"); - break; - } + case Active: { + i = QIcon(":/MO/gui/checked-checkbox"); + break; + } - case Inverted: - { - i = QIcon(":/MO/gui/indeterminate-checkbox"); - break; - } + case Inverted: { + i = QIcon(":/MO/gui/indeterminate-checkbox"); + break; + } } setData(0, Qt::DecorationRole, i); } }; - class CriteriaItemFilter : public QObject { public: - using Callback = std::function<bool (QTreeWidgetItem*, int)>; + using Callback = std::function<bool(QTreeWidgetItem*, int)>; CriteriaItemFilter(QTreeWidget* tree, Callback f) - : QObject(tree), m_tree(tree), m_f(std::move(f)) - { - } + : QObject(tree), m_tree(tree), m_f(std::move(f)) + {} bool eventFilter(QObject* o, QEvent* e) override { @@ -150,7 +136,8 @@ public: // viewport only and keyboard events from the tree only if (m_f) { - if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonDblClick) { + if (e->type() == QEvent::MouseButtonPress || + e->type() == QEvent::MouseButtonDblClick) { if (handleMouse(static_cast<QMouseEvent*>(e))) { return true; } @@ -177,7 +164,7 @@ private: m_tree->setCurrentItem(item); - const auto dir = (e->button() == Qt::LeftButton ? 1 : - 1); + const auto dir = (e->button() == Qt::LeftButton ? 1 : -1); return m_f(item, dir); } @@ -191,7 +178,7 @@ private: } const auto shiftPressed = (e->modifiers() & Qt::ShiftModifier); - const auto dir = (shiftPressed ? -1 : 1); + const auto dir = (shiftPressed ? -1 : 1); return m_f(item, dir); } @@ -200,33 +187,45 @@ private: } }; - -FilterList::FilterList(Ui::MainWindow* ui, OrganizerCore& core, CategoryFactory& factory) - : ui(ui), m_core(core), m_factory(factory) +FilterList::FilterList(Ui::MainWindow* ui, OrganizerCore& core, + CategoryFactory& factory) + : ui(ui), m_core(core), m_factory(factory) { - auto* eventFilter = new CriteriaItemFilter( - ui->filters, [&](auto* item, int dir){ return cycleItem(item, dir); }); + auto* eventFilter = new CriteriaItemFilter(ui->filters, [&](auto* item, int dir) { + return cycleItem(item, dir); + }); ui->filters->installEventFilter(eventFilter); ui->filters->viewport()->installEventFilter(eventFilter); - connect(ui->filtersClear, &QPushButton::clicked, [&]{ clearSelection(); }); - connect(ui->filtersEdit, &QPushButton::clicked, [&]{ editCategories(); }); - connect(ui->filtersAnd, &QCheckBox::toggled, [&]{ onOptionsChanged(); }); - connect(ui->filtersOr, &QCheckBox::toggled, [&]{ onOptionsChanged(); }); + connect(ui->filtersClear, &QPushButton::clicked, [&] { + clearSelection(); + }); + connect(ui->filtersEdit, &QPushButton::clicked, [&] { + editCategories(); + }); + connect(ui->filtersAnd, &QCheckBox::toggled, [&] { + onOptionsChanged(); + }); + connect(ui->filtersOr, &QCheckBox::toggled, [&] { + onOptionsChanged(); + }); - connect( - ui->filtersSeparators, qOverload<int>(&QComboBox::currentIndexChanged), - [&]{ onOptionsChanged(); }); + connect(ui->filtersSeparators, qOverload<int>(&QComboBox::currentIndexChanged), [&] { + onOptionsChanged(); + }); ui->filters->header()->setMinimumSectionSize(0); ui->filters->header()->resizeSection(0, 23); ui->categoriesSplitter->setCollapsible(0, false); ui->categoriesSplitter->setCollapsible(1, false); - ui->filtersSeparators->addItem(tr("Filter separators"), ModListSortProxy::SeparatorFilter); - ui->filtersSeparators->addItem(tr("Show separators"), ModListSortProxy::SeparatorShow); - ui->filtersSeparators->addItem(tr("Hide separators"), ModListSortProxy::SeparatorHide); + ui->filtersSeparators->addItem(tr("Filter separators"), + ModListSortProxy::SeparatorFilter); + ui->filtersSeparators->addItem(tr("Show separators"), + ModListSortProxy::SeparatorShow); + ui->filtersSeparators->addItem(tr("Hide separators"), + ModListSortProxy::SeparatorHide); } void FilterList::restoreState(const Settings& s) @@ -249,9 +248,8 @@ void FilterList::saveState(Settings& s) const s.widgets().saveIndex(ui->filtersSeparators); } -QTreeWidgetItem* FilterList::addCriteriaItem( - QTreeWidgetItem *root, const QString &name, int categoryID, - CriteriaType type) +QTreeWidgetItem* FilterList::addCriteriaItem(QTreeWidgetItem* root, const QString& name, + int categoryID, CriteriaType type) { auto* item = new CriteriaItem(this, name, type, categoryID); @@ -264,23 +262,26 @@ QTreeWidgetItem* FilterList::addCriteriaItem( void FilterList::addContentCriteria() { - m_core.modDataContents().forEachContent([this](auto const& content) { - addCriteriaItem( - nullptr, QString("<%1>").arg(tr("Contains %1").arg(content.name())), - content.id(), ModListSortProxy::TypeContent); - }, true); + m_core.modDataContents().forEachContent( + [this](auto const& content) { + addCriteriaItem(nullptr, + QString("<%1>").arg(tr("Contains %1").arg(content.name())), + content.id(), ModListSortProxy::TypeContent); + }, + true); } -void FilterList::addCategoryCriteria(QTreeWidgetItem *root, const std::set<int> &categoriesUsed, int targetID) +void FilterList::addCategoryCriteria(QTreeWidgetItem* root, + const std::set<int>& categoriesUsed, int targetID) { const auto count = static_cast<unsigned int>(m_factory.numCategories()); for (unsigned int i = 1; i < count; ++i) { if (m_factory.getParentID(i) == targetID) { int categoryID = m_factory.getCategoryID(i); if (categoriesUsed.find(categoryID) != categoriesUsed.end()) { - QTreeWidgetItem *item = - addCriteriaItem(root, m_factory.getCategoryName(i), - categoryID, ModListSortProxy::TypeCategory); + QTreeWidgetItem* item = + addCriteriaItem(root, m_factory.getCategoryName(i), categoryID, + ModListSortProxy::TypeCategory); if (m_factory.hasChildren(i)) { addCategoryCriteria(item, categoriesUsed, categoryID); } @@ -293,9 +294,8 @@ void FilterList::addSpecialCriteria(int type) { const auto sc = static_cast<CategoryFactory::SpecialCategories>(type); - addCriteriaItem( - nullptr, m_factory.getSpecialCategoryName(sc), - type, ModListSortProxy::TypeSpecial); + addCriteriaItem(nullptr, m_factory.getSpecialCategoryName(sc), type, + ModListSortProxy::TypeSpecial); } void FilterList::refresh() @@ -367,7 +367,7 @@ void FilterList::setSelection(const std::vector<Criteria>& criteria) void FilterList::clearSelection() { - for (int i=0; i<ui->filters->topLevelItemCount(); ++i) { + for (int i = 0; i < ui->filters->topLevelItemCount(); ++i) { auto* ci = dynamic_cast<CriteriaItem*>(ui->filters->topLevelItem(i)); if (!ci) { continue; @@ -402,16 +402,15 @@ std::vector<ModListSortProxy::Criteria> FilterList::selectedCriteria() const { std::vector<Criteria> criteria; - for (int i=0; i<ui->filters->topLevelItemCount(); ++i) { + for (int i = 0; i < ui->filters->topLevelItemCount(); ++i) { const auto* ci = dynamic_cast<CriteriaItem*>(ui->filters->topLevelItem(i)); if (!ci) { continue; } if (ci->state() != CriteriaItem::Inactive) { - criteria.push_back({ - ci->type(), ci->id(), (ci->state() == CriteriaItem::Inverted) - }); + criteria.push_back( + {ci->type(), ci->id(), (ci->state() == CriteriaItem::Inverted)}); } } @@ -435,11 +434,11 @@ void FilterList::editCategories() void FilterList::onOptionsChanged() { - const auto mode = ui->filtersAnd->isChecked() ? - ModListSortProxy::FilterAnd: ModListSortProxy::FilterOr; + const auto mode = ui->filtersAnd->isChecked() ? ModListSortProxy::FilterAnd + : ModListSortProxy::FilterOr; const auto separators = static_cast<ModListSortProxy::SeparatorsMode>( - ui->filtersSeparators->currentData().toInt()); + ui->filtersSeparators->currentData().toInt()); emit optionsChanged(mode, separators); } diff --git a/src/filterlist.h b/src/filterlist.h index 0788d224..f572762e 100644 --- a/src/filterlist.h +++ b/src/filterlist.h @@ -4,7 +4,10 @@ #include "modlistsortproxy.h" #include <QTreeWidgetItem> -namespace Ui { class MainWindow; }; +namespace Ui +{ +class MainWindow; +}; class CategoryFactory; class Settings; class OrganizerCore; @@ -25,8 +28,8 @@ public: signals: void criteriaChanged(std::vector<ModListSortProxy::Criteria> criteria); - void optionsChanged( - ModListSortProxy::FilterMode mode, ModListSortProxy::SeparatorsMode sep); + void optionsChanged(ModListSortProxy::FilterMode mode, + ModListSortProxy::SeparatorsMode sep); private: class CriteriaItem; @@ -44,14 +47,13 @@ private: std::vector<ModListSortProxy::Criteria> selectedCriteria() const; bool cycleItem(QTreeWidgetItem* item, int direction); - QTreeWidgetItem* addCriteriaItem( - QTreeWidgetItem *root, const QString &name, int categoryID, - ModListSortProxy::CriteriaType type); + QTreeWidgetItem* addCriteriaItem(QTreeWidgetItem* root, const QString& name, + int categoryID, ModListSortProxy::CriteriaType type); void addContentCriteria(); - void addCategoryCriteria( - QTreeWidgetItem *root, const std::set<int> &categoriesUsed, int targetID); + void addCategoryCriteria(QTreeWidgetItem* root, const std::set<int>& categoriesUsed, + int targetID); void addSpecialCriteria(int type); }; -#endif // MODORGANIZER_CATEGORIESLIST_INCLUDED +#endif // MODORGANIZER_CATEGORIESLIST_INCLUDED diff --git a/src/forcedloaddialog.cpp b/src/forcedloaddialog.cpp index ab0bd583..14011b1b 100644 --- a/src/forcedloaddialog.cpp +++ b/src/forcedloaddialog.cpp @@ -8,25 +8,23 @@ using namespace MOBase; -ForcedLoadDialog::ForcedLoadDialog(const IPluginGame *game, QWidget *parent) : - QDialog(parent), - ui(new Ui::ForcedLoadDialog), - m_GamePlugin(game) +ForcedLoadDialog::ForcedLoadDialog(const IPluginGame* game, QWidget* parent) + : QDialog(parent), ui(new Ui::ForcedLoadDialog), m_GamePlugin(game) { - ui->setupUi(this); + ui->setupUi(this); } ForcedLoadDialog::~ForcedLoadDialog() { - delete ui; + delete ui; } -void ForcedLoadDialog::setValues(QList<MOBase::ExecutableForcedLoadSetting> &values) +void ForcedLoadDialog::setValues(QList<MOBase::ExecutableForcedLoadSetting>& values) { ui->tableWidget->clearContents(); for (int i = 0; i < values.count(); i++) { - ForcedLoadDialogWidget *item = new ForcedLoadDialogWidget(m_GamePlugin, this); + ForcedLoadDialogWidget* item = new ForcedLoadDialogWidget(m_GamePlugin, this); item->setEnabled(values[i].enabled()); item->setProcess(values[i].process()); item->setLibraryPath(values[i].library()); @@ -45,32 +43,28 @@ QList<MOBase::ExecutableForcedLoadSetting> ForcedLoadDialog::values() for (int row = 0; row < ui->tableWidget->rowCount(); row++) { auto widget = (ForcedLoadDialogWidget*)ui->tableWidget->cellWidget(row, 0); results.append( - ExecutableForcedLoadSetting( - widget->getProcess(), - widget->getLibraryPath() - ).withEnabled(widget->getEnabled()) - .withForced(widget->getForced()) - ); + ExecutableForcedLoadSetting(widget->getProcess(), widget->getLibraryPath()) + .withEnabled(widget->getEnabled()) + .withForced(widget->getForced())); } return results; } - void ForcedLoadDialog::on_addRowButton_clicked() { int row = ui->tableWidget->rowCount(); ui->tableWidget->insertRow(row); - ForcedLoadDialogWidget *item = new ForcedLoadDialogWidget(m_GamePlugin, this); + ForcedLoadDialogWidget* item = new ForcedLoadDialogWidget(m_GamePlugin, this); ui->tableWidget->setCellWidget(row, 0, item); ui->tableWidget->resizeRowsToContents(); } void ForcedLoadDialog::on_deleteRowButton_clicked() { - for (auto rowIndex: ui->tableWidget->selectionModel()->selectedRows()) { - int row = rowIndex.row(); + for (auto rowIndex : ui->tableWidget->selectionModel()->selectedRows()) { + int row = rowIndex.row(); auto widget = (ForcedLoadDialogWidget*)ui->tableWidget->cellWidget(row, 0); - if (!widget->getForced()){ + if (!widget->getForced()) { ui->tableWidget->removeRow(row); } } diff --git a/src/forcedloaddialog.h b/src/forcedloaddialog.h index 6a88bccf..ca57ab94 100644 --- a/src/forcedloaddialog.h +++ b/src/forcedloaddialog.h @@ -7,7 +7,8 @@ #include "executableinfo.h" #include "iplugingame.h" -namespace Ui { +namespace Ui +{ class ForcedLoadDialog; } @@ -16,10 +17,10 @@ class ForcedLoadDialog : public QDialog Q_OBJECT public: - explicit ForcedLoadDialog(const MOBase::IPluginGame *game, QWidget *parent = nullptr); + explicit ForcedLoadDialog(const MOBase::IPluginGame* game, QWidget* parent = nullptr); ~ForcedLoadDialog(); - void setValues(QList<MOBase::ExecutableForcedLoadSetting> &values); + void setValues(QList<MOBase::ExecutableForcedLoadSetting>& values); QList<MOBase::ExecutableForcedLoadSetting> values(); private slots: @@ -27,8 +28,8 @@ private slots: void on_deleteRowButton_clicked(); private: - Ui::ForcedLoadDialog *ui; - const MOBase::IPluginGame *m_GamePlugin; + Ui::ForcedLoadDialog* ui; + const MOBase::IPluginGame* m_GamePlugin; }; -#endif // FORCEDLOADDIALOG_H +#endif // FORCEDLOADDIALOG_H diff --git a/src/forcedloaddialogwidget.cpp b/src/forcedloaddialogwidget.cpp index b84f785f..c2e44437 100644 --- a/src/forcedloaddialogwidget.cpp +++ b/src/forcedloaddialogwidget.cpp @@ -1,22 +1,20 @@ #include "forcedloaddialogwidget.h" -#include "ui_forcedloaddialogwidget.h" #include "executableinfo.h" -#include <log.h> +#include "ui_forcedloaddialogwidget.h" #include <QFileDialog> +#include <log.h> using namespace MOBase; -ForcedLoadDialogWidget::ForcedLoadDialogWidget(const IPluginGame *game, QWidget *parent) : - QWidget(parent), - ui(new Ui::ForcedLoadDialogWidget), - m_GamePlugin(game) +ForcedLoadDialogWidget::ForcedLoadDialogWidget(const IPluginGame* game, QWidget* parent) + : QWidget(parent), ui(new Ui::ForcedLoadDialogWidget), m_GamePlugin(game) { - ui->setupUi(this); + ui->setupUi(this); } ForcedLoadDialogWidget::~ForcedLoadDialogWidget() { - delete ui; + delete ui; } bool ForcedLoadDialogWidget::getEnabled() @@ -53,12 +51,12 @@ void ForcedLoadDialogWidget::setForced(bool forced) ui->processEdit->setEnabled(!forced); } -void ForcedLoadDialogWidget::setLibraryPath(const QString &path) +void ForcedLoadDialogWidget::setLibraryPath(const QString& path) { ui->libraryPathEdit->setText(path); } -void ForcedLoadDialogWidget::setProcess(const QString &name) +void ForcedLoadDialogWidget::setProcess(const QString& name) { ui->processEdit->setText(name); } @@ -72,11 +70,13 @@ void ForcedLoadDialogWidget::on_libraryPathBrowseButton_clicked() { QDir gameDir(m_GamePlugin->gameDirectory()); QString startPath = gameDir.absolutePath(); - QString result = QFileDialog::getOpenFileName(nullptr, "Select a library...", startPath, "Dynamic link library (*.dll)", nullptr, QFileDialog::ReadOnly); + QString result = QFileDialog::getOpenFileName( + nullptr, "Select a library...", startPath, "Dynamic link library (*.dll)", + nullptr, QFileDialog::ReadOnly); if (!result.isEmpty()) { QFileInfo fileInfo(result); QString relativePath = gameDir.relativeFilePath(fileInfo.filePath()); - QString filePath = fileInfo.filePath(); + QString filePath = fileInfo.filePath(); if (!relativePath.startsWith("..")) { filePath = relativePath; } @@ -93,7 +93,9 @@ void ForcedLoadDialogWidget::on_processBrowseButton_clicked() { QDir gameDir(m_GamePlugin->gameDirectory()); QString startPath = gameDir.absolutePath(); - QString result = QFileDialog::getOpenFileName(nullptr, "Select a process...", startPath, "Executable (*.exe)", nullptr, QFileDialog::ReadOnly); + QString result = QFileDialog::getOpenFileName(nullptr, "Select a process...", + startPath, "Executable (*.exe)", + nullptr, QFileDialog::ReadOnly); if (!result.isEmpty()) { QFileInfo fileInfo(result); QString fileName = fileInfo.fileName(); diff --git a/src/forcedloaddialogwidget.h b/src/forcedloaddialogwidget.h index 239653c8..68ece9c0 100644 --- a/src/forcedloaddialogwidget.h +++ b/src/forcedloaddialogwidget.h @@ -1,41 +1,42 @@ #ifndef FORCEDLOADDIALOGWIDGET_H #define FORCEDLOADDIALOGWIDGET_H -#include <QWidget> #include "iplugingame.h" +#include <QWidget> -namespace Ui { +namespace Ui +{ class ForcedLoadDialogWidget; } class ForcedLoadDialogWidget : public QWidget { - Q_OBJECT + Q_OBJECT public: - explicit ForcedLoadDialogWidget(const MOBase::IPluginGame *game, QWidget *parent = nullptr); - ~ForcedLoadDialogWidget(); + explicit ForcedLoadDialogWidget(const MOBase::IPluginGame* game, + QWidget* parent = nullptr); + ~ForcedLoadDialogWidget(); - bool getEnabled(); - bool getForced(); - QString getLibraryPath(); - QString getProcess(); + bool getEnabled(); + bool getForced(); + QString getLibraryPath(); + QString getProcess(); - void setEnabled(bool enabled); - void setForced(bool forced); - void setLibraryPath(const QString &path); - void setProcess(const QString &name); + void setEnabled(bool enabled); + void setForced(bool forced); + void setLibraryPath(const QString& path); + void setProcess(const QString& name); private slots: - void on_enabledBox_toggled(); - void on_libraryPathBrowseButton_clicked(); - void on_processBrowseButton_clicked(); + void on_enabledBox_toggled(); + void on_libraryPathBrowseButton_clicked(); + void on_processBrowseButton_clicked(); private: - Ui::ForcedLoadDialogWidget *ui; - bool m_Forced; - const MOBase::IPluginGame *m_GamePlugin; - + Ui::ForcedLoadDialogWidget* ui; + bool m_Forced; + const MOBase::IPluginGame* m_GamePlugin; }; -#endif // FORCEDLOADDIALOGWIDGET_H +#endif // FORCEDLOADDIALOGWIDGET_H diff --git a/src/genericicondelegate.cpp b/src/genericicondelegate.cpp index bb039b05..1ee980ab 100644 --- a/src/genericicondelegate.cpp +++ b/src/genericicondelegate.cpp @@ -3,18 +3,16 @@ #include <QList> #include <QPixmapCache> +GenericIconDelegate::GenericIconDelegate(QTreeView* parent, int role, int logicalIndex, + int compactSize) + : IconDelegate(parent, logicalIndex, compactSize), m_Role(role) +{} -GenericIconDelegate::GenericIconDelegate(QTreeView* parent, int role, int logicalIndex, int compactSize) - : IconDelegate(parent, logicalIndex, compactSize) - , m_Role(role) -{ -} - -QList<QString> GenericIconDelegate::getIcons(const QModelIndex &index) const +QList<QString> GenericIconDelegate::getIcons(const QModelIndex& index) const { QList<QString> result; if (index.isValid()) { - for (const QVariant &var : index.data(m_Role).toList()) { + for (const QVariant& var : index.data(m_Role).toList()) { if (!compact() || !var.toString().isEmpty()) { result.append(var.toString()); } @@ -23,7 +21,7 @@ QList<QString> GenericIconDelegate::getIcons(const QModelIndex &index) const return result; } -size_t GenericIconDelegate::getNumIcons(const QModelIndex &index) const +size_t GenericIconDelegate::getNumIcons(const QModelIndex& index) const { return index.data(m_Role).toList().count(); } diff --git a/src/genericicondelegate.h b/src/genericicondelegate.h index 60cdf94b..028738f5 100644 --- a/src/genericicondelegate.h +++ b/src/genericicondelegate.h @@ -8,23 +8,28 @@ */ class GenericIconDelegate : public IconDelegate { -Q_OBJECT + Q_OBJECT public: /** * @brief constructor * @param parent parent object - * @param role role of the itemmodel from which the icon list can be queried (as a QVariantList) - * @param logicalIndex logical index within the model. This is part of a "hack". Normally "empty" icons will be allocated the same - * space as a regular icon. This way the model can use empty icons as spacers and thus align same icons horizontally. - * Now, if you set the logical Index to a valid column and connect the columnResized slot to the sectionResized signal - * of the view, the delegate will turn off this behaviour if the column is smaller than "compactSize" + * @param role role of the itemmodel from which the icon list can be queried (as a + * QVariantList) + * @param logicalIndex logical index within the model. This is part of a "hack". + * Normally "empty" icons will be allocated the same space as a regular icon. This way + * the model can use empty icons as spacers and thus align same icons horizontally. + * Now, if you set the logical Index to a valid column and connect + * the columnResized slot to the sectionResized signal of the view, the delegate will + * turn off this behaviour if the column is smaller than "compactSize" * @param compactSize see explanation of logicalIndex */ - GenericIconDelegate(QTreeView* parent, int role = Qt::UserRole + 1, int logicalIndex = -1, int compactSize = 150); + GenericIconDelegate(QTreeView* parent, int role = Qt::UserRole + 1, + int logicalIndex = -1, int compactSize = 150); private: - virtual QList<QString> getIcons(const QModelIndex &index) const; - virtual size_t getNumIcons(const QModelIndex &index) const; + virtual QList<QString> getIcons(const QModelIndex& index) const; + virtual size_t getNumIcons(const QModelIndex& index) const; + private: int m_Role; int m_LogicalIndex; @@ -32,4 +37,4 @@ private: bool m_Compact; }; -#endif // GENERICICONDELEGATE_H +#endif // GENERICICONDELEGATE_H diff --git a/src/glob_matching.h b/src/glob_matching.h index e7e7b621..b47d30ac 100644 --- a/src/glob_matching.h +++ b/src/glob_matching.h @@ -6,208 +6,180 @@ #ifndef GLOB_MATCHING_H #define GLOB_MATCHING_H +#include <QString> #include <cctype> #include <string_view> -#include <QString> - -namespace MOShared { - /** - * Contraints string_traits to allow usage of both standard strings and QString in - * GlobPattern. - */ - namespace details { +namespace MOShared +{ - template < - class CharT, - class Traits = std::char_traits<CharT>, - class Allocator = std::allocator<CharT>> - struct string_traits { - using string_type = std::basic_string<CharT, Traits, Allocator>; - using string_view = std::basic_string_view<CharT, Traits>; +/** + * Contraints string_traits to allow usage of both standard strings and QString in + * GlobPattern. + */ +namespace details +{ - static auto tolower(CharT c) { return std::tolower(c); } + template <class CharT, class Traits = std::char_traits<CharT>, + class Allocator = std::allocator<CharT>> + struct string_traits + { + using string_type = std::basic_string<CharT, Traits, Allocator>; + using string_view = std::basic_string_view<CharT, Traits>; - static auto empty(string_view const& view) { return view.empty(); } - }; + static auto tolower(CharT c) { return std::tolower(c); } - template <> - struct string_traits<QChar> { - using string_type = QString; - using string_view = QString; - - static auto tolower(QChar const& c) { return c.toLower(); } - static auto empty(string_view const& view) { return view.isEmpty(); } - }; + static auto empty(string_view const& view) { return view.empty(); } + }; - } + template <> + struct string_traits<QChar> + { + using string_type = QString; + using string_view = QString; - /** - * @brief Class that provides basic wildcard pattern matching. - * - * From https://gitlab.com/G_ka/playground/-/commits/master/include/wildcards.hpp - * - * Currently, this supports the following globbing character: - * - '*' matches zero or more characters. - * - '?' matches exactly one character. - * - '[abc]' matches one of 'a', 'b' or 'c'. - * - * Standard globbing feature not supported: - * - You cannot escape globbing characters with \. - * - You cannot use `[a-z]` to match any character from 'a' to 'z'. - * - * Custom class because the following alternatives have some issues: - * - QRegExp is a tad slow, and we need to convert everything to QString. - * - QDir::match is VERY slow. I think it converts the glob pattern to a QRegularExpression and - * then use it. - * - PatchMatchSpecW (Windows API) is fast but does not support some useful glob pattern (e.g., - * [ab]). - * - * Advantage of this over the above methods: - * - It is fast. Quick testing show that this is faster than PatchMatchSpecW. - * - It can be used on most string types (QString, std::string, std::wstring, etc.). - */ - template < - class CharT, - class Traits = std::char_traits<CharT>, - class Allocator = std::allocator<CharT>> - class GlobPattern { - public: + static auto tolower(QChar const& c) { return c.toLower(); } + static auto empty(string_view const& view) { return view.isEmpty(); } + }; - using traits = details::string_traits<CharT, Traits, Allocator>; +} // namespace details - using string_type = typename traits::string_type; - using string_view_type = typename traits::string_view; +/** + * @brief Class that provides basic wildcard pattern matching. + * + * From https://gitlab.com/G_ka/playground/-/commits/master/include/wildcards.hpp + * + * Currently, this supports the following globbing character: + * - '*' matches zero or more characters. + * - '?' matches exactly one character. + * - '[abc]' matches one of 'a', 'b' or 'c'. + * + * Standard globbing feature not supported: + * - You cannot escape globbing characters with \. + * - You cannot use `[a-z]` to match any character from 'a' to 'z'. + * + * Custom class because the following alternatives have some issues: + * - QRegExp is a tad slow, and we need to convert everything to QString. + * - QDir::match is VERY slow. I think it converts the glob pattern to a + * QRegularExpression and then use it. + * - PatchMatchSpecW (Windows API) is fast but does not support some useful glob + * pattern (e.g., [ab]). + * + * Advantage of this over the above methods: + * - It is fast. Quick testing show that this is faster than PatchMatchSpecW. + * - It can be used on most string types (QString, std::string, std::wstring, etc.). + */ +template <class CharT, class Traits = std::char_traits<CharT>, + class Allocator = std::allocator<CharT>> +class GlobPattern +{ +public: + using traits = details::string_traits<CharT, Traits, Allocator>; - struct card { - // Relying on automatic conversion: - static constexpr CharT any = '?'; - static constexpr CharT any_repeat = '*'; - static constexpr CharT set_begin = '['; - static constexpr CharT set_end = ']'; - }; + using string_type = typename traits::string_type; + using string_view_type = typename traits::string_view; - public: + struct card + { + // Relying on automatic conversion: + static constexpr CharT any = '?'; + static constexpr CharT any_repeat = '*'; + static constexpr CharT set_begin = '['; + static constexpr CharT set_end = ']'; + }; - GlobPattern(string_view_type const& s) : v{ s } { } +public: + GlobPattern(string_view_type const& s) : v{s} {} - const string_type& native() const { return v; } + const string_type& native() const { return v; } - constexpr bool match( - string_view_type const& str, - bool case_sensitive = false) - { - // Empty pattern can only match with empty sting - if (traits::empty(v)) - return traits::empty(str); + constexpr bool match(string_view_type const& str, bool case_sensitive = false) + { + // Empty pattern can only match with empty sting + if (traits::empty(v)) + return traits::empty(str); - auto pat_it = v.begin(); - auto pat_end = v.end(); + auto pat_it = v.begin(); + auto pat_end = v.end(); - auto str_it = str.begin(); - auto str_end = str.end(); + auto str_it = str.begin(); + auto str_end = str.end(); - auto anyrep_pos_pat = pat_end; - auto anyrep_pos_str = str_end; + auto anyrep_pos_pat = pat_end; + auto anyrep_pos_str = str_end; - auto set_pos_pat = pat_end; + auto set_pos_pat = pat_end; - while (str_it != str_end) - { - CharT current_pat = QChar(0); - CharT current_str = QChar(-1); - if (pat_it != pat_end) - { - current_pat = case_sensitive ? *pat_it : traits::tolower(*pat_it); - current_str = case_sensitive ? *str_it : traits::tolower(*str_it); - } - if (pat_it != pat_end && current_pat == card::set_begin) - { - set_pos_pat = pat_it; - pat_it++; - } - else if (pat_it != pat_end && current_pat == card::set_end) - { - if (anyrep_pos_pat != pat_end) - { - set_pos_pat = pat_end; - pat_it++; - } - else - { - return false; - } + while (str_it != str_end) { + CharT current_pat = QChar(0); + CharT current_str = QChar(-1); + if (pat_it != pat_end) { + current_pat = case_sensitive ? *pat_it : traits::tolower(*pat_it); + current_str = case_sensitive ? *str_it : traits::tolower(*str_it); + } + if (pat_it != pat_end && current_pat == card::set_begin) { + set_pos_pat = pat_it; + pat_it++; + } else if (pat_it != pat_end && current_pat == card::set_end) { + if (anyrep_pos_pat != pat_end) { + set_pos_pat = pat_end; + pat_it++; + } else { + return false; + } - } - else if (set_pos_pat != pat_end) - { - if (current_pat == current_str) - { - set_pos_pat = pat_end; - pat_it = std::find(pat_it, pat_end, card::set_end) + 1; - str_it++; - } - else - { - if (pat_it == pat_end) - { - return false; - } - pat_it++; - } - } - else if (pat_it != pat_end && current_pat == current_str) - { - pat_it++; - str_it++; - } - else if (pat_it != pat_end && current_pat == card::any) - { - pat_it++; - str_it++; - } - else if (pat_it != pat_end && current_pat == card::any_repeat) - { - anyrep_pos_pat = pat_it; - anyrep_pos_str = str_it; - pat_it++; - } - else if (anyrep_pos_pat != pat_end) - { - pat_it = anyrep_pos_pat + 1; - str_it = anyrep_pos_str + 1; - anyrep_pos_str++; - } - else - { + } else if (set_pos_pat != pat_end) { + if (current_pat == current_str) { + set_pos_pat = pat_end; + pat_it = std::find(pat_it, pat_end, card::set_end) + 1; + str_it++; + } else { + if (pat_it == pat_end) { return false; } + pat_it++; } - while (pat_it != pat_end) - { - CharT cur = case_sensitive ? *pat_it : traits::tolower(*pat_it); - if (cur == card::any_repeat) - pat_it++; - else - break; - } - return pat_it == pat_end; + } else if (pat_it != pat_end && current_pat == current_str) { + pat_it++; + str_it++; + } else if (pat_it != pat_end && current_pat == card::any) { + pat_it++; + str_it++; + } else if (pat_it != pat_end && current_pat == card::any_repeat) { + anyrep_pos_pat = pat_it; + anyrep_pos_str = str_it; + pat_it++; + } else if (anyrep_pos_pat != pat_end) { + pat_it = anyrep_pos_pat + 1; + str_it = anyrep_pos_str + 1; + anyrep_pos_str++; + } else { + return false; } + } + while (pat_it != pat_end) { + CharT cur = case_sensitive ? *pat_it : traits::tolower(*pat_it); + if (cur == card::any_repeat) + pat_it++; + else + break; + } + return pat_it == pat_end; + } - private: - string_type v; - }; +private: + string_type v; +}; - template <class CharT, class Traits, class Allocator> - GlobPattern(std::basic_string<CharT, Traits, Allocator> const&) +template <class CharT, class Traits, class Allocator> +GlobPattern(std::basic_string<CharT, Traits, Allocator> const&) -> GlobPattern<CharT, Traits, Allocator>; - template <class CharT> - GlobPattern(CharT const*) -> GlobPattern<CharT>; - - GlobPattern(QString const&) -> GlobPattern<QChar>; +template <class CharT> +GlobPattern(CharT const*) -> GlobPattern<CharT>; +GlobPattern(QString const&)->GlobPattern<QChar>; -} // namespace wildcards +} // namespace MOShared #endif diff --git a/src/icondelegate.cpp b/src/icondelegate.cpp index 23235814..bec7d995 100644 --- a/src/icondelegate.cpp +++ b/src/icondelegate.cpp @@ -18,41 +18,42 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ #include "icondelegate.h" -#include <log.h> +#include <QDebug> #include <QHBoxLayout> #include <QLabel> #include <QPainter> -#include <QDebug> #include <QPixmapCache> +#include <log.h> using namespace MOBase; -IconDelegate::IconDelegate(QTreeView* view, int column, int compactSize) : - QStyledItemDelegate(view), m_column(column), m_compactSize(compactSize), m_compact(false) +IconDelegate::IconDelegate(QTreeView* view, int column, int compactSize) + : QStyledItemDelegate(view), m_column(column), m_compactSize(compactSize), + m_compact(false) { if (view) { - connect(view->header(), &QHeaderView::sectionResized, [=](int column, int, int size) { - if (column == m_column) { - m_compact = size < m_compactSize; - } - }); + connect(view->header(), &QHeaderView::sectionResized, + [=](int column, int, int size) { + if (column == m_column) { + m_compact = size < m_compactSize; + } + }); } } -void IconDelegate::paintIcons( - QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index, const QList<QString>& icons) +void IconDelegate::paintIcons(QPainter* painter, const QStyleOptionViewItem& option, + const QModelIndex& index, const QList<QString>& icons) { int x = 4; painter->save(); int iconWidth = icons.size() > 0 ? ((option.rect.width() / icons.size()) - 4) : 16; - iconWidth = std::min(16, iconWidth); + iconWidth = std::min(16, iconWidth); const int margin = (option.rect.height() - iconWidth) / 2; painter->translate(option.rect.topLeft()); - for (const QString &iconId : icons) { + for (const QString& iconId : icons) { if (iconId.isEmpty()) { x += iconWidth + 4; continue; @@ -73,15 +74,14 @@ void IconDelegate::paintIcons( painter->restore(); } -void IconDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const +void IconDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const { if (auto* w = qobject_cast<QAbstractItemView*>(parent())) { w->itemDelegate()->paint(painter, option, index); - } - else { + } else { QStyledItemDelegate::paint(painter, option, index); } paintIcons(painter, option, index, getIcons(index)); } - diff --git a/src/icondelegate.h b/src/icondelegate.h index 04621591..65886804 100644 --- a/src/icondelegate.h +++ b/src/icondelegate.h @@ -20,11 +20,10 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef ICONDELEGATE_H #define ICONDELEGATE_H -#include <QAbstractProxyModel> #include <QAbstractItemView> +#include <QAbstractProxyModel> #include <QStyledItemDelegate> - class IconDelegate : public QStyledItemDelegate { Q_OBJECT; @@ -32,26 +31,24 @@ class IconDelegate : public QStyledItemDelegate public: explicit IconDelegate(QTreeView* view, int column = -1, int compactSize = 100); - void paint(QPainter *painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override; + void paint(QPainter* painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const override; protected: - // check if icons should be compacted or not // bool compact() const { return m_compact; } - static void paintIcons( - QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index, const QList<QString>& icons); + static void paintIcons(QPainter* painter, const QStyleOptionViewItem& option, + const QModelIndex& index, const QList<QString>& icons); - virtual QList<QString> getIcons(const QModelIndex &index) const = 0; - virtual size_t getNumIcons(const QModelIndex &index) const = 0; + virtual QList<QString> getIcons(const QModelIndex& index) const = 0; + virtual size_t getNumIcons(const QModelIndex& index) const = 0; private: - int m_column; int m_compactSize; bool m_compact; }; -#endif // ICONDELEGATE_H +#endif // ICONDELEGATE_H diff --git a/src/iconfetcher.cpp b/src/iconfetcher.cpp index 32b0d58b..c677424c 100644 --- a/src/iconfetcher.cpp +++ b/src/iconfetcher.cpp @@ -1,11 +1,13 @@ #include "iconfetcher.h" -#include "thread_utils.h" #include "shared/util.h" +#include "thread_utils.h" void IconFetcher::Waiter::wait() { std::unique_lock lock(m_wakeUpMutex); - m_wakeUp.wait(lock, [&]{ return m_queueAvailable; }); + m_wakeUp.wait(lock, [&] { + return m_queueAvailable; + }); m_queueAvailable = false; } @@ -19,14 +21,14 @@ void IconFetcher::Waiter::wakeUp() m_wakeUp.notify_one(); } - -IconFetcher::IconFetcher() - : m_iconSize(GetSystemMetrics(SM_CXSMICON)), m_stop(false) +IconFetcher::IconFetcher() : m_iconSize(GetSystemMetrics(SM_CXSMICON)), m_stop(false) { - m_quickCache.file = getPixmapIcon(QFileIconProvider::File); + m_quickCache.file = getPixmapIcon(QFileIconProvider::File); m_quickCache.directory = getPixmapIcon(QFileIconProvider::Folder); - m_thread = MOShared::startSafeThread([&]{ threadFun(); }); + m_thread = MOShared::startSafeThread([&] { + threadFun(); + }); } IconFetcher::~IconFetcher() @@ -73,10 +75,9 @@ bool IconFetcher::hasOwnIcon(const QString& path) const static const QString lnk = ".lnk"; static const QString ico = ".ico"; - return - path.endsWith(exe, Qt::CaseInsensitive) || - path.endsWith(lnk, Qt::CaseInsensitive) || - path.endsWith(ico, Qt::CaseInsensitive); + return path.endsWith(exe, Qt::CaseInsensitive) || + path.endsWith(lnk, Qt::CaseInsensitive) || + path.endsWith(ico, Qt::CaseInsensitive); } void IconFetcher::threadFun() diff --git a/src/iconfetcher.h b/src/iconfetcher.h index 78857d05..3207a57e 100644 --- a/src/iconfetcher.h +++ b/src/iconfetcher.h @@ -1,9 +1,9 @@ #ifndef MODORGANIZER_ICONFETCHER_INCLUDED #define MODORGANIZER_ICONFETCHER_INCLUDED -#include <set> -#include <mutex> #include <QFileIconProvider> #include <QStringView> +#include <mutex> +#include <set> class IconFetcher { @@ -45,7 +45,6 @@ private: bool m_queueAvailable = false; }; - const int m_iconSize; QFileIconProvider m_provider; std::thread m_thread; @@ -56,7 +55,6 @@ private: mutable Cache m_fileCache; mutable Waiter m_waiter; - bool hasOwnIcon(const QString& path) const; template <class T> @@ -74,4 +72,4 @@ private: QVariant extensionIcon(const QStringView& ext) const; }; -#endif // MODORGANIZER_ICONFETCHER_INCLUDED +#endif // MODORGANIZER_ICONFETCHER_INCLUDED diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp index 0c6af11d..8c2ce78d 100644 --- a/src/installationmanager.cpp +++ b/src/installationmanager.cpp @@ -21,33 +21,32 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "installationmanager.h" -#include "filesystemutilities.h" -#include "report.h" #include "categories.h" -#include "questionboxmemory.h" -#include "settings.h" -#include "queryoverwritedialog.h" -#include "messagedialog.h" -#include "iplugininstallersimple.h" +#include "filesystemutilities.h" #include "iplugininstallercustom.h" +#include "iplugininstallersimple.h" +#include "messagedialog.h" +#include "modinfo.h" #include "nexusinterface.h" +#include "queryoverwritedialog.h" +#include "questionboxmemory.h" +#include "report.h" #include "selectiondialog.h" -#include "modinfo.h" +#include "settings.h" #include <scopeguard.h> #include <utility.h> -#include <scopeguard.h> +#include <QApplication> +#include <QDateTime> +#include <QDebug> +#include <QDir> +#include <QDirIterator> #include <QFileInfo> -#include <QLibrary> #include <QInputDialog> -#include <QDir> +#include <QLibrary> #include <QMessageBox> -#include <QSettings> #include <QPushButton> -#include <QApplication> -#include <QDateTime> -#include <QDirIterator> -#include <QDebug> +#include <QSettings> #include <QTextDocument> #include <QtConcurrent/QtConcurrentRun> @@ -58,19 +57,16 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "archivefiletree.h" - using namespace MOBase; using namespace MOShared; - -InstallationResult::InstallationResult(IPluginInstaller::EInstallResult result) : - m_result(result), m_name(), m_iniTweaks(false), m_backup(false), m_merged(false), m_replaced(false) -{ -} - +InstallationResult::InstallationResult(IPluginInstaller::EInstallResult result) + : m_result(result), m_name(), m_iniTweaks(false), m_backup(false), m_merged(false), + m_replaced(false) +{} template <typename T> -static T resolveFunction(QLibrary &lib, const char *name) +static T resolveFunction(QLibrary& lib, const char* name) { T temp = reinterpret_cast<T>(lib.resolve(name)); if (temp == nullptr) { @@ -82,10 +78,8 @@ static T resolveFunction(QLibrary &lib, const char *name) return temp; } -InstallationManager::InstallationManager() - : - m_ParentWidget(nullptr), - m_IsRunning(false) { +InstallationManager::InstallationManager() : m_ParentWidget(nullptr), m_IsRunning(false) +{ m_ArchiveHandler = CreateArchive(); if (!m_ArchiveHandler->isValid()) { throw MyException(getErrorString(m_ArchiveHandler->getLastError())); @@ -108,18 +102,16 @@ InstallationManager::InstallationManager() } }); - // Connect the query password slot - This is the only way I found to be able to query user - // from a separate thread. We use a BlockingQueuedConnection so that calling passwordRequested() - // will block until the end of the slot. - connect(this, &InstallationManager::passwordRequested, - this, &InstallationManager::queryPassword, Qt::BlockingQueuedConnection); + // Connect the query password slot - This is the only way I found to be able to query + // user from a separate thread. We use a BlockingQueuedConnection so that calling + // passwordRequested() will block until the end of the slot. + connect(this, &InstallationManager::passwordRequested, this, + &InstallationManager::queryPassword, Qt::BlockingQueuedConnection); } -InstallationManager::~InstallationManager() -{ -} +InstallationManager::~InstallationManager() {} -void InstallationManager::setParentWidget(QWidget *widget) +void InstallationManager::setParentWidget(QWidget* widget) { m_ParentWidget = widget; } @@ -129,12 +121,14 @@ void InstallationManager::setPluginContainer(const PluginContainer* pluginContai m_PluginContainer = pluginContainer; } -void InstallationManager::queryPassword() { +void InstallationManager::queryPassword() +{ m_Password = QInputDialog::getText(m_ParentWidget, tr("Password required"), - tr("Password"), QLineEdit::Password); + tr("Password"), QLineEdit::Password); } -bool InstallationManager::extractFiles(QString extractPath, QString title, bool showFilenames, bool silent) +bool InstallationManager::extractFiles(QString extractPath, QString title, + bool showFilenames, bool silent) { TimeThis tt("InstallationManager::extractFiles"); @@ -150,24 +144,19 @@ bool InstallationManager::extractFiles(QString extractPath, QString title, bool if (silent) { future = QtConcurrent::run([&]() -> bool { - return m_ArchiveHandler->extract( - extractPath.toStdWString(), - nullptr, - nullptr, - errorCallback - ); + return m_ArchiveHandler->extract(extractPath.toStdWString(), nullptr, nullptr, + errorCallback); }); future.waitForFinished(); - } - else { + } else { QProgressDialog* installationProgress = new QProgressDialog(m_ParentWidget); ON_BLOCK_EXIT([=]() { installationProgress->cancel(); installationProgress->hide(); installationProgress->deleteLater(); }); - installationProgress->setWindowFlags( - installationProgress->windowFlags() & (~Qt::WindowContextHelpButtonHint)); + installationProgress->setWindowFlags(installationProgress->windowFlags() & + (~Qt::WindowContextHelpButtonHint)); if (!title.isEmpty()) { installationProgress->setWindowTitle(title); } @@ -176,27 +165,32 @@ bool InstallationManager::extractFiles(QString extractPath, QString title, bool // Turn off auto-reset otherwize the progress dialog is reset before the end. This // is kind of annoying because updateProgress consider percentage of progression - // through the archive (pack), while we are waiting for extracting archive entries, so - // the percentage of in updateProgress is not really related to the percentage of files - // extracted... + // through the archive (pack), while we are waiting for extracting archive entries, + // so the percentage of in updateProgress is not really related to the percentage of + // files extracted... installationProgress->setAutoReset(false); - // Note: Using a loop with a progressUpdate() that only wake-up the loop. The event-loop - // will be used in a loop and not via exec() because connecting to QProgressDialog::setValue - // and using .exec() creates huge recursion that leads to stack-overflow. - // See https://bugreports.qt.io/browse/QTBUG-10561 + // Note: Using a loop with a progressUpdate() that only wake-up the loop. The + // event-loop will be used in a loop and not via exec() because connecting to + // QProgressDialog::setValue and using .exec() creates huge recursion that leads to + // stack-overflow. See https://bugreports.qt.io/browse/QTBUG-10561 QEventLoop loop; - connect(this, &InstallationManager::progressUpdate, &loop, &QEventLoop::wakeUp, Qt::QueuedConnection); + connect(this, &InstallationManager::progressUpdate, &loop, &QEventLoop::wakeUp, + Qt::QueuedConnection); - // Cancelling progress only cancel the extraction, we do not force exiting the event-loop: - connect(installationProgress, &QProgressDialog::canceled, [this]() { m_ArchiveHandler->cancel(); }); + // Cancelling progress only cancel the extraction, we do not force exiting the + // event-loop: + connect(installationProgress, &QProgressDialog::canceled, [this]() { + m_ArchiveHandler->cancel(); + }); std::mutex mutex; int currentProgress = 0; QString currentFileName; // The callbacks: - auto progressCallback = [this, ¤tProgress, &mutex](auto progressType, uint64_t current, uint64_t total) { + auto progressCallback = [this, ¤tProgress, &mutex]( + auto progressType, uint64_t current, uint64_t total) { if (progressType == Archive::ProgressType::EXTRACTION) { { std::scoped_lock guard(mutex); @@ -205,28 +199,25 @@ bool InstallationManager::extractFiles(QString extractPath, QString title, bool emit progressUpdate(); } }; - Archive::FileChangeCallback fileChangeCallback = [this, ¤tFileName, &mutex](auto changeType, std::wstring const& file) { - if (changeType == Archive::FileChangeType::EXTRACTION_START) { - { - std::scoped_lock guard(mutex); - currentFileName = QString::fromStdWString(file); - } - emit progressUpdate(); - } - }; + Archive::FileChangeCallback fileChangeCallback = + [this, ¤tFileName, &mutex](auto changeType, std::wstring const& file) { + if (changeType == Archive::FileChangeType::EXTRACTION_START) { + { + std::scoped_lock guard(mutex); + currentFileName = QString::fromStdWString(file); + } + emit progressUpdate(); + } + }; // unpack only the files we need for the installer QFutureWatcher<bool> futureWatcher; - connect(&futureWatcher, &QFutureWatcher<bool>::finished, - &loop, &QEventLoop::wakeUp, - Qt::QueuedConnection); + connect(&futureWatcher, &QFutureWatcher<bool>::finished, &loop, &QEventLoop::wakeUp, + Qt::QueuedConnection); futureWatcher.setFuture(QtConcurrent::run([&]() -> bool { - return m_ArchiveHandler->extract( - extractPath.toStdWString(), - progressCallback, - showFilenames ? fileChangeCallback : nullptr, - errorCallback - ); + return m_ArchiveHandler->extract(extractPath.toStdWString(), progressCallback, + showFilenames ? fileChangeCallback : nullptr, + errorCallback); })); installationProgress->setModal(true); @@ -253,31 +244,34 @@ bool InstallationManager::extractFiles(QString extractPath, QString title, bool if (m_ArchiveHandler->getLastError() == Archive::Error::ERROR_EXTRACT_CANCELLED) { if (!errorMessage.isEmpty()) { throw MyException(tr("Extraction failed: %1").arg(errorMessage)); - } - else { + } else { return false; } - } - else { - throw MyException(tr("Extraction failed: %1").arg(static_cast<int>(m_ArchiveHandler->getLastError()))); + } else { + throw MyException(tr("Extraction failed: %1") + .arg(static_cast<int>(m_ArchiveHandler->getLastError()))); } } return true; } -QString InstallationManager::extractFile(std::shared_ptr<const FileTreeEntry> entry, bool silent) +QString InstallationManager::extractFile(std::shared_ptr<const FileTreeEntry> entry, + bool silent) { - QStringList result = this->extractFiles({ entry }, silent); + QStringList result = this->extractFiles({entry}, silent); return result.isEmpty() ? QString() : result[0]; } -QStringList InstallationManager::extractFiles(std::vector<std::shared_ptr<const FileTreeEntry>> const& entries, bool silent) +QStringList InstallationManager::extractFiles( + std::vector<std::shared_ptr<const FileTreeEntry>> const& entries, bool silent) { // Remove the directory since mapToArchive would add them: std::vector<std::shared_ptr<const FileTreeEntry>> files; std::copy_if(entries.begin(), entries.end(), std::back_inserter(files), - [](auto const& entry) { return entry->isFile(); }); + [](auto const& entry) { + return entry->isFile(); + }); // Update the archive: ArchiveFileTree::mapToArchive(*m_ArchiveHandler, files); @@ -285,7 +279,7 @@ QStringList InstallationManager::extractFiles(std::vector<std::shared_ptr<const // Retrieve the file path: QStringList result; - for (auto &entry : files) { + for (auto& entry : files) { auto path = entry->path(); result.append(QDir::tempPath().append("/").append(path)); m_TempFilesToDelete.insert(path); @@ -298,11 +292,12 @@ QStringList InstallationManager::extractFiles(std::vector<std::shared_ptr<const return result; } - -QString InstallationManager::createFile(std::shared_ptr<const MOBase::FileTreeEntry> entry) +QString +InstallationManager::createFile(std::shared_ptr<const MOBase::FileTreeEntry> entry) { // Use QTemporaryFile to create the temporary file with the given template: - QTemporaryFile tempFile(QDir::cleanPath(QDir::tempPath() + QDir::separator() + "mo2-install")); + QTemporaryFile tempFile( + QDir::cleanPath(QDir::tempPath() + QDir::separator() + "mo2-install")); // Turn-off autoRemove otherwise the file is deleted when destructor is called: tempFile.setAutoRemove(false); @@ -323,10 +318,11 @@ QString InstallationManager::createFile(std::shared_ptr<const MOBase::FileTreeEn return QDir::toNativeSeparators(absPath); } -void InstallationManager::cleanCreatedFiles(std::shared_ptr<const MOBase::IFileTree> fileTree) +void InstallationManager::cleanCreatedFiles( + std::shared_ptr<const MOBase::IFileTree> fileTree) { // We simply have to check if all the entries have fileTree as a parent: - for (auto it = std::begin(m_CreatedFiles); it != std::end(m_CreatedFiles); ) { + for (auto it = std::begin(m_CreatedFiles); it != std::end(m_CreatedFiles);) { // Find the parent - Could this be in FileTreeEntry? bool found = false; @@ -335,38 +331,38 @@ void InstallationManager::cleanCreatedFiles(std::shared_ptr<const MOBase::IFileT while (parent && !found) { if (parent == fileTree) { found = true; - } - else { + } else { parent = parent->parent(); } } } - // If the parent was not found, we remove the entry, otherwize we move to the next one: + // If the parent was not found, we remove the entry, otherwize we move to the next + // one: if (!found) { it = m_CreatedFiles.erase(it); - } - else { + } else { ++it; } } } - -IPluginInstaller::EInstallResult InstallationManager::installArchive(GuessedValue<QString> &modName, const QString &archiveName, int modId) +IPluginInstaller::EInstallResult +InstallationManager::installArchive(GuessedValue<QString>& modName, + const QString& archiveName, int modId) { - // in earlier versions the modName was copied here and the copy passed to install. I don't know why I did this and it causes - // a problem if this is called by the bundle installer and the bundled installer adds additional names that then end up being used, - // because the caller will then not have the right name. + // in earlier versions the modName was copied here and the copy passed to install. I + // don't know why I did this and it causes a problem if this is called by the bundle + // installer and the bundled installer adds additional names that then end up being + // used, because the caller will then not have the right name. return install(archiveName, modName, modId).result(); } - -QString InstallationManager::generateBackupName(const QString &directoryName) const +QString InstallationManager::generateBackupName(const QString& directoryName) const { QString backupName = directoryName + "_backup"; if (QDir(backupName).exists()) { - int idx = 2; + int idx = 2; QString temp = backupName + QString::number(idx); while (QDir(temp).exists()) { ++idx; @@ -377,21 +373,21 @@ QString InstallationManager::generateBackupName(const QString &directoryName) co return backupName; } - -InstallationResult InstallationManager::testOverwrite(GuessedValue<QString> &modName) +InstallationResult InstallationManager::testOverwrite(GuessedValue<QString>& modName) { - QString targetDirectory = QDir::fromNativeSeparators(m_ModsDirectory + "\\" + modName); + QString targetDirectory = + QDir::fromNativeSeparators(m_ModsDirectory + "\\" + modName); // this is only returned on success - InstallationResult result{ IPluginInstaller::RESULT_SUCCESS }; + InstallationResult result{IPluginInstaller::RESULT_SUCCESS}; while (QDir(targetDirectory).exists()) { - Settings &settings(Settings::instance()); + Settings& settings(Settings::instance()); const bool backup = settings.keepBackupOnInstall(); - QueryOverwriteDialog overwriteDialog( - m_ParentWidget, - backup ? QueryOverwriteDialog::BACKUP_YES : QueryOverwriteDialog::BACKUP_NO); + QueryOverwriteDialog overwriteDialog(m_ParentWidget, + backup ? QueryOverwriteDialog::BACKUP_YES + : QueryOverwriteDialog::BACKUP_NO); if (overwriteDialog.exec()) { settings.setKeepBackupOnInstall(overwriteDialog.backup()); @@ -400,22 +396,22 @@ InstallationResult InstallationManager::testOverwrite(GuessedValue<QString> &mod QString backupDirectory = generateBackupName(targetDirectory); if (!copyDir(targetDirectory, backupDirectory, false)) { reportError(tr("Failed to create backup")); - return { IPluginInstaller::RESULT_FAILED }; + return {IPluginInstaller::RESULT_FAILED}; } } - result.m_merged = overwriteDialog.action() == QueryOverwriteDialog::ACT_MERGE; + result.m_merged = overwriteDialog.action() == QueryOverwriteDialog::ACT_MERGE; result.m_replaced = overwriteDialog.action() == QueryOverwriteDialog::ACT_REPLACE; - result.m_backup = overwriteDialog.backup(); + result.m_backup = overwriteDialog.backup(); if (overwriteDialog.action() == QueryOverwriteDialog::ACT_RENAME) { - bool ok = false; + bool ok = false; QString name = QInputDialog::getText(m_ParentWidget, tr("Mod Name"), tr("Name"), QLineEdit::Normal, modName, &ok); if (ok && !name.isEmpty()) { modName.update(name, GUESS_USER); if (!ensureValidModName(modName)) { - return { IPluginInstaller::RESULT_FAILED }; + return {IPluginInstaller::RESULT_FAILED}; } targetDirectory = QDir::fromNativeSeparators(m_ModsDirectory) + "/" + modName; } @@ -438,8 +434,8 @@ InstallationResult InstallationManager::testOverwrite(GuessedValue<QString> &mod // remove the directory with all content, then recreate it empty shellDelete(QStringList(targetDirectory)); if (!QDir().mkdir(targetDirectory)) { - // windows may keep the directory around for a moment, preventing its re-creation. Not sure - // if this still happens with shellDelete + // windows may keep the directory around for a moment, preventing its + // re-creation. Not sure if this still happens with shellDelete Sleep(100); QDir().mkdir(targetDirectory); } @@ -453,11 +449,12 @@ InstallationResult InstallationManager::testOverwrite(GuessedValue<QString> &mod return result; } else if (overwriteDialog.action() == QueryOverwriteDialog::ACT_MERGE) { return result; - } else /* if (overwriteDialog.action() == QueryOverwriteDialog::ACT_NONE) */ { - return { IPluginInstaller::RESULT_CANCELED }; + } else /* if (overwriteDialog.action() == QueryOverwriteDialog::ACT_NONE) */ + { + return {IPluginInstaller::RESULT_CANCELED}; } } else { - return { IPluginInstaller::RESULT_CANCELED }; + return {IPluginInstaller::RESULT_CANCELED}; } } @@ -466,15 +463,16 @@ InstallationResult InstallationManager::testOverwrite(GuessedValue<QString> &mod return result; } - -bool InstallationManager::ensureValidModName(GuessedValue<QString> &name) const +bool InstallationManager::ensureValidModName(GuessedValue<QString>& name) const { while (name->isEmpty()) { bool ok; - name.update(QInputDialog::getText(m_ParentWidget, tr("Invalid name"), - tr("The name you entered is invalid, please enter a different one."), - QLineEdit::Normal, "", &ok), - GUESS_USER); + name.update( + QInputDialog::getText( + m_ParentWidget, tr("Invalid name"), + tr("The name you entered is invalid, please enter a different one."), + QLineEdit::Normal, "", &ok), + GUESS_USER); if (!ok) { return false; } @@ -482,13 +480,15 @@ bool InstallationManager::ensureValidModName(GuessedValue<QString> &name) const return true; } -InstallationResult InstallationManager::doInstall( - GuessedValue<QString> &modName, QString gameName, int modID, - const QString &version, const QString &newestVersion, - int categoryID, int fileCategoryID, const QString &repository) +InstallationResult InstallationManager::doInstall(GuessedValue<QString>& modName, + QString gameName, int modID, + const QString& version, + const QString& newestVersion, + int categoryID, int fileCategoryID, + const QString& repository) { if (!ensureValidModName(modName)) { - return { IPluginInstaller::RESULT_FAILED }; + return {IPluginInstaller::RESULT_FAILED}; } bool merge = false; @@ -500,17 +500,18 @@ InstallationResult InstallationManager::doInstall( result.m_name = modName; - QString targetDirectory = QDir(m_ModsDirectory + "/" + modName).canonicalPath(); + QString targetDirectory = QDir(m_ModsDirectory + "/" + modName).canonicalPath(); QString targetDirectoryNative = QDir::toNativeSeparators(targetDirectory); log::debug("installing to \"{}\"", targetDirectoryNative); if (!extractFiles(targetDirectory, "", true, false)) { - return { IPluginInstaller::RESULT_CANCELED }; + return {IPluginInstaller::RESULT_CANCELED}; } // Copy the created files: for (auto& p : m_CreatedFiles) { - QString destPath = QDir::cleanPath(targetDirectory + QDir::separator() + p.first->path()); + QString destPath = + QDir::cleanPath(targetDirectory + QDir::separator() + p.first->path()); log::debug("Moving {} to {}.", p.second, destPath); // We need to remove the path if it exists: @@ -528,7 +529,8 @@ InstallationResult InstallationManager::doInstall( QSettings settingsFile(targetDirectory + "/meta.ini", QSettings::IniFormat); - // overwrite settings only if they are actually are available or haven't been set before + // overwrite settings only if they are actually are available or haven't been set + // before if ((gameName != "") || !settingsFile.contains("gameName")) { settingsFile.setValue("gameName", gameName); } @@ -537,7 +539,8 @@ InstallationResult InstallationManager::doInstall( } if (!settingsFile.contains("version") || (!version.isEmpty() && - (!merge || (VersionInfo(version) >= VersionInfo(settingsFile.value("version").toString()))))) { + (!merge || (VersionInfo(version) >= + VersionInfo(settingsFile.value("version").toString()))))) { settingsFile.setValue("version", version); } if (!newestVersion.isEmpty() || !settingsFile.contains("newestVersion")) { @@ -552,8 +555,9 @@ InstallationResult InstallationManager::doInstall( settingsFile.setValue("repository", repository); if (!merge) { - // this does not clear the list we have in memory but the mod is going to have to be re-read anyway - // btw.: installedFiles were written with beginWriteArray but we can still clear it with beginGroup. nice + // this does not clear the list we have in memory but the mod is going to have to be + // re-read anyway btw.: installedFiles were written with beginWriteArray but we can + // still clear it with beginGroup. nice settingsFile.beginGroup("installedFiles"); settingsFile.remove(""); settingsFile.endGroup(); @@ -562,7 +566,6 @@ InstallationResult InstallationManager::doInstall( return result; } - bool InstallationManager::wasCancelled() const { return m_ArchiveHandler->getLastError() == Archive::Error::ERROR_EXTRACT_CANCELLED; @@ -573,7 +576,6 @@ bool InstallationManager::isRunning() const return m_IsRunning; } - void InstallationManager::postInstallCleanup() { // Clear the list of created files: @@ -582,21 +584,27 @@ void InstallationManager::postInstallCleanup() // Close the archive: m_ArchiveHandler->close(); - // directories we may want to remove. sorted from longest to shortest to ensure we remove subdirectories first. - auto longestFirst = [](const QString &LHS, const QString &RHS) -> bool { - if (LHS.size() != RHS.size()) return LHS.size() > RHS.size(); - else return LHS < RHS; - }; + // directories we may want to remove. sorted from longest to shortest to ensure we + // remove subdirectories first. + auto longestFirst = [](const QString& LHS, const QString& RHS) -> bool { + if (LHS.size() != RHS.size()) + return LHS.size() > RHS.size(); + else + return LHS < RHS; + }; - std::set<QString, std::function<bool(const QString&, const QString&)>> directoriesToRemove(longestFirst); + std::set<QString, std::function<bool(const QString&, const QString&)>> + directoriesToRemove(longestFirst); // clean up temp files - // TODO: this doesn't yet remove directories. Also, the files may be left there if this point isn't reached - for (const QString &tempFile : m_TempFilesToDelete) { + // TODO: this doesn't yet remove directories. Also, the files may be left there if + // this point isn't reached + for (const QString& tempFile : m_TempFilesToDelete) { QFileInfo fileInfo(QDir::tempPath() + "/" + tempFile); if (fileInfo.exists()) { if (!fileInfo.isReadable() || !fileInfo.isWritable()) { - QFile::setPermissions(fileInfo.absoluteFilePath(), QFile::ReadOther | QFile::WriteOther); + QFile::setPermissions(fileInfo.absoluteFilePath(), + QFile::ReadOther | QFile::WriteOther); } if (!QFile::remove(fileInfo.absoluteFilePath())) { log::warn("Unable to delete {}", fileInfo.absoluteFilePath()); @@ -607,17 +615,21 @@ void InstallationManager::postInstallCleanup() m_TempFilesToDelete.clear(); - // try to delete each directory we had temporary files in. the call fails for non-empty directories which is ok - for (const QString &dir : directoriesToRemove) { + // try to delete each directory we had temporary files in. the call fails for + // non-empty directories which is ok + for (const QString& dir : directoriesToRemove) { QDir().rmdir(dir); } } -InstallationResult InstallationManager::install( - const QString &fileName, GuessedValue<QString> &modName, int modID) +InstallationResult InstallationManager::install(const QString& fileName, + GuessedValue<QString>& modName, + int modID) { m_IsRunning = true; - ON_BLOCK_EXIT([this]() { m_IsRunning = false; }); + ON_BLOCK_EXIT([this]() { + m_IsRunning = false; + }); QFileInfo fileInfo(fileName); if (!getSupportedExtensions().contains(fileInfo.suffix(), Qt::CaseInsensitive)) { @@ -630,41 +642,43 @@ InstallationResult InstallationManager::install( modName.update(QFileInfo(fileName).completeBaseName(), GUESS_FALLBACK); // read out meta information from the download if available - QString gameName = ""; - QString version = ""; + QString gameName = ""; + QString version = ""; QString newestVersion = ""; - int categoryID = 0; - int fileCategoryID = 1; - QString repository = "Nexus"; + int categoryID = 0; + int fileCategoryID = 1; + QString repository = "Nexus"; QString metaName = fileName + ".meta"; if (QFile(metaName).exists()) { QSettings metaFile(metaName, QSettings::IniFormat); gameName = metaFile.value("gameName", "").toString(); - modID = metaFile.value("modID", 0).toInt(); + modID = metaFile.value("modID", 0).toInt(); QTextDocument doc; doc.setHtml(metaFile.value("name", "").toString()); modName.update(doc.toPlainText(), GUESS_FALLBACK); modName.update(metaFile.value("modName", "").toString(), GUESS_META); - version = metaFile.value("version", "").toString(); - newestVersion = metaFile.value("newestVersion", "").toString(); + version = metaFile.value("version", "").toString(); + newestVersion = metaFile.value("newestVersion", "").toString(); unsigned int categoryIndex = CategoryFactory::instance().resolveNexusID( metaFile.value("category", 0).toInt()); - categoryID = CategoryFactory::instance().getCategoryID(categoryIndex); - repository = metaFile.value("repository", "").toString(); + categoryID = CategoryFactory::instance().getCategoryID(categoryIndex); + repository = metaFile.value("repository", "").toString(); fileCategoryID = metaFile.value("fileCategory", 1).toInt(); } if (version.isEmpty()) { QDateTime lastMod = fileInfo.lastModified(); - version = "d" + lastMod.toString("yyyy.M.d"); + version = "d" + lastMod.toString("yyyy.M.d"); } - { // guess the mod name and mod if from the file name if there was no meta information + { // guess the mod name and mod if from the file name if there was no meta + // information QString guessedModName; int guessedModID = modID; - NexusInterface::interpretNexusFileName(QFileInfo(fileName).fileName(), guessedModName, guessedModID, false); + NexusInterface::interpretNexusFileName(QFileInfo(fileName).fileName(), + guessedModName, guessedModID, false); if ((modID == 0) && (guessedModID != -1)) { modID = guessedModID; } else if (modID != guessedModID) { @@ -678,52 +692,54 @@ InstallationResult InstallationManager::install( if (fileInfo.dir() == QDir(m_DownloadsDirectory)) { m_CurrentFile = fileInfo.fileName(); } - log::debug("using mod name \"{}\" (id {}) -> {}", QString(modName), modID, m_CurrentFile); + log::debug("using mod name \"{}\" (id {}) -> {}", QString(modName), modID, + m_CurrentFile); - //If there's an archive already open, close it. This happens with the bundle - //installer when it uncompresses a split archive, then finds it has a real archive - //to deal with. + // If there's an archive already open, close it. This happens with the bundle + // installer when it uncompresses a split archive, then finds it has a real archive + // to deal with. m_ArchiveHandler->close(); // open the archive and construct the directory tree the installers work on - bool archiveOpen = m_ArchiveHandler->open( - fileName.toStdWString(), [this]() -> std::wstring { - m_Password = QString(); + bool archiveOpen = + m_ArchiveHandler->open(fileName.toStdWString(), [this]() -> std::wstring { + m_Password = QString(); - // Note: If we are not in the Qt event thread, we cannot use queryPassword() directly, - // so we emit passwordRequested() that is connected to queryPassword(). The connection is - // made using Qt::BlockingQueuedConnection, so the emit "call" is actually blocking. We - // cannot use emit if we are in the even thread, otherwize we have a deadlock. - if (QThread::currentThread() != QApplication::instance()->thread()) { - emit passwordRequested(); - } - else { - queryPassword(); - } - return m_Password.toStdWString(); - }); + // Note: If we are not in the Qt event thread, we cannot use queryPassword() + // directly, so we emit passwordRequested() that is connected to + // queryPassword(). The connection is made using Qt::BlockingQueuedConnection, + // so the emit "call" is actually blocking. We cannot use emit if we are in the + // even thread, otherwize we have a deadlock. + if (QThread::currentThread() != QApplication::instance()->thread()) { + emit passwordRequested(); + } else { + queryPassword(); + } + return m_Password.toStdWString(); + }); if (!archiveOpen) { - log::debug("integrated archiver can't open {}: {} ({})", - fileName, - getErrorString(m_ArchiveHandler->getLastError()), - m_ArchiveHandler->getLastError()); + log::debug("integrated archiver can't open {}: {} ({})", fileName, + getErrorString(m_ArchiveHandler->getLastError()), + m_ArchiveHandler->getLastError()); } ON_BLOCK_EXIT(std::bind(&InstallationManager::postInstallCleanup, this)); std::shared_ptr<IFileTree> filesTree = - archiveOpen ? ArchiveFileTree::makeTree(*m_ArchiveHandler) : nullptr; + archiveOpen ? ArchiveFileTree::makeTree(*m_ArchiveHandler) : nullptr; auto installers = m_PluginContainer->plugins<IPluginInstaller>(); - std::sort(installers.begin(), installers.end(), [] (IPluginInstaller* lhs, IPluginInstaller* rhs) { - return lhs->priority() > rhs->priority(); - }); + std::sort(installers.begin(), installers.end(), + [](IPluginInstaller* lhs, IPluginInstaller* rhs) { + return lhs->priority() > rhs->priority(); + }); InstallationResult installResult(IPluginInstaller::RESULT_NOTATTEMPTED); - for (IPluginInstaller *installer : installers) { - // don't use inactive installers (installer can't be null here but vc static code analysis thinks it could) + for (IPluginInstaller* installer : installers) { + // don't use inactive installers (installer can't be null here but vc static code + // analysis thinks it could) if ((installer == nullptr) || !m_PluginContainer->isEnabled(installer)) { continue; } @@ -738,13 +754,13 @@ InstallationResult InstallationManager::install( } try { - { // simple case - IPluginInstallerSimple *installerSimple - = dynamic_cast<IPluginInstallerSimple *>(installer); - if ((installerSimple != nullptr) && (filesTree != nullptr) - && (installer->isArchiveSupported(filesTree))) { - installResult.m_result - = installerSimple->install(modName, filesTree, version, modID); + { // simple case + IPluginInstallerSimple* installerSimple = + dynamic_cast<IPluginInstallerSimple*>(installer); + if ((installerSimple != nullptr) && (filesTree != nullptr) && + (installer->isArchiveSupported(filesTree))) { + installResult.m_result = + installerSimple->install(modName, filesTree, version, modID); if (installResult) { // Downcast to an actual ArchiveFileTree and map to the archive. Test if @@ -752,7 +768,8 @@ InstallationResult InstallationManager::install( // did some bad stuff. ArchiveFileTree* p = dynamic_cast<ArchiveFileTree*>(filesTree.get()); if (p == nullptr) { - throw IncompatibilityException(tr("Invalid file tree returned by plugin.")); + throw IncompatibilityException( + tr("Invalid file tree returned by plugin.")); } // Detach the file tree (this ensure the parent is null and call to path() @@ -766,25 +783,23 @@ InstallationResult InstallationManager::install( // the simple installer only prepares the installation, the rest // works the same for all installers - installResult = doInstall(modName, gameName, modID, version, - newestVersion, categoryID, fileCategoryID, repository); + installResult = doInstall(modName, gameName, modID, version, newestVersion, + categoryID, fileCategoryID, repository); } } } - if (installResult.result() != IPluginInstaller::RESULT_CANCELED) { // custom case - IPluginInstallerCustom *installerCustom - = dynamic_cast<IPluginInstallerCustom *>(installer); - if ((installerCustom != nullptr) - && (((filesTree != nullptr) - && installer->isArchiveSupported(filesTree)) - || ((filesTree == nullptr) - && installerCustom->isArchiveSupported(fileName)))) { - std::set<QString> installerExt - = installerCustom->supportedExtensions(); + if (installResult.result() != IPluginInstaller::RESULT_CANCELED) { // custom case + IPluginInstallerCustom* installerCustom = + dynamic_cast<IPluginInstallerCustom*>(installer); + if ((installerCustom != nullptr) && + (((filesTree != nullptr) && installer->isArchiveSupported(filesTree)) || + ((filesTree == nullptr) && + installerCustom->isArchiveSupported(fileName)))) { + std::set<QString> installerExt = installerCustom->supportedExtensions(); if (installerExt.find(fileInfo.suffix()) != installerExt.end()) { - installResult.m_result - = installerCustom->install(modName, gameName, fileName, version, modID); + installResult.m_result = + installerCustom->install(modName, gameName, fileName, version, modID); unsigned int idx = ModInfo::getIndex(modName); if (idx != UINT_MAX) { ModInfo::Ptr info = ModInfo::getByIndex(idx); @@ -793,40 +808,42 @@ InstallationResult InstallationManager::install( } } } - } catch (const IncompatibilityException &e) { + } catch (const IncompatibilityException& e) { log::error("plugin \"{}\" incompatible: {}", installer->name(), e.what()); } // act upon the installation result. at this point the files have already been // extracted to the correct location switch (installResult.result()) { - case IPluginInstaller::RESULT_FAILED: { - QMessageBox::information(qApp->activeWindow(), tr("Installation failed"), - tr("Something went wrong while installing this mod."), - QMessageBox::Ok); - return installResult; - } break; - case IPluginInstaller::RESULT_SUCCESS: - case IPluginInstaller::RESULT_SUCCESSCANCEL: { - if (filesTree != nullptr) { - auto iniTweakEntry = filesTree->find("INI Tweaks", FileTreeEntry::DIRECTORY); - installResult.m_iniTweaks = iniTweakEntry != nullptr - && !iniTweakEntry->astree()->empty(); - } - installResult.m_result = IPluginInstaller::RESULT_SUCCESS; - return installResult; - } break; - case IPluginInstaller::RESULT_NOTATTEMPTED: - case IPluginInstaller::RESULT_MANUALREQUESTED: { - continue; + case IPluginInstaller::RESULT_FAILED: { + QMessageBox::information(qApp->activeWindow(), tr("Installation failed"), + tr("Something went wrong while installing this mod."), + QMessageBox::Ok); + return installResult; + } break; + case IPluginInstaller::RESULT_SUCCESS: + case IPluginInstaller::RESULT_SUCCESSCANCEL: { + if (filesTree != nullptr) { + auto iniTweakEntry = filesTree->find("INI Tweaks", FileTreeEntry::DIRECTORY); + installResult.m_iniTweaks = + iniTweakEntry != nullptr && !iniTweakEntry->astree()->empty(); } - default: - return installResult; + installResult.m_result = IPluginInstaller::RESULT_SUCCESS; + return installResult; + } break; + case IPluginInstaller::RESULT_NOTATTEMPTED: + case IPluginInstaller::RESULT_MANUALREQUESTED: { + continue; + } + default: + return installResult; } } if (installResult.result() == IPluginInstaller::RESULT_NOTATTEMPTED) { - reportError(tr("None of the available installer plugins were able to handle that archive.\n" - "This is likely due to a corrupted or incompatible download or unrecognized archive format.")); + reportError( + tr("None of the available installer plugins were able to handle that archive.\n" + "This is likely due to a corrupted or incompatible download or unrecognized " + "archive format.")); } return installResult; @@ -835,40 +852,41 @@ InstallationResult InstallationManager::install( QString InstallationManager::getErrorString(Archive::Error errorCode) { switch (errorCode) { - case Archive::Error::ERROR_NONE: { - return tr("no error"); - } break; - case Archive::Error::ERROR_LIBRARY_NOT_FOUND: { - return tr("7z.dll not found"); - } break; - case Archive::Error::ERROR_LIBRARY_INVALID: { - return tr("7z.dll isn't valid"); - } break; - case Archive::Error::ERROR_ARCHIVE_NOT_FOUND: { - return tr("archive not found"); - } break; - case Archive::Error::ERROR_FAILED_TO_OPEN_ARCHIVE: { - return tr("failed to open archive"); - } break; - case Archive::Error::ERROR_INVALID_ARCHIVE_FORMAT: { - return tr("unsupported archive type"); - } break; - case Archive::Error::ERROR_LIBRARY_ERROR: { - return tr("internal library error"); - } break; - case Archive::Error::ERROR_ARCHIVE_INVALID: { - return tr("archive invalid"); - } break; - default: { - // this probably means the archiver.dll is newer than this - return tr("unknown archive error"); - } break; + case Archive::Error::ERROR_NONE: { + return tr("no error"); + } break; + case Archive::Error::ERROR_LIBRARY_NOT_FOUND: { + return tr("7z.dll not found"); + } break; + case Archive::Error::ERROR_LIBRARY_INVALID: { + return tr("7z.dll isn't valid"); + } break; + case Archive::Error::ERROR_ARCHIVE_NOT_FOUND: { + return tr("archive not found"); + } break; + case Archive::Error::ERROR_FAILED_TO_OPEN_ARCHIVE: { + return tr("failed to open archive"); + } break; + case Archive::Error::ERROR_INVALID_ARCHIVE_FORMAT: { + return tr("unsupported archive type"); + } break; + case Archive::Error::ERROR_LIBRARY_ERROR: { + return tr("internal library error"); + } break; + case Archive::Error::ERROR_ARCHIVE_INVALID: { + return tr("archive invalid"); + } break; + default: { + // this probably means the archiver.dll is newer than this + return tr("unknown archive error"); + } break; } } QStringList InstallationManager::getSupportedExtensions() const { - std::set<QString, CaseInsensitive> supportedExtensions({ "zip", "rar", "7z", "fomod", "001" }); + std::set<QString, CaseInsensitive> supportedExtensions( + {"zip", "rar", "7z", "fomod", "001"}); for (auto* installer : m_PluginContainer->plugins<IPluginInstaller>()) { if (m_PluginContainer->isEnabled(installer)) { if (auto* installerCustom = dynamic_cast<IPluginInstallerCustom*>(installer)) { @@ -880,7 +898,9 @@ QStringList InstallationManager::getSupportedExtensions() const return QStringList(supportedExtensions.begin(), supportedExtensions.end()); } -void InstallationManager::notifyInstallationStart(QString const& archive, bool reinstallation, ModInfo::Ptr currentMod) +void InstallationManager::notifyInstallationStart(QString const& archive, + bool reinstallation, + ModInfo::Ptr currentMod) { auto& installers = m_PluginContainer->plugins<IPluginInstaller>(); for (auto* installer : installers) { @@ -890,7 +910,8 @@ void InstallationManager::notifyInstallationStart(QString const& archive, bool r } } -void InstallationManager::notifyInstallationEnd(const InstallationResult& result, ModInfo::Ptr newMod) +void InstallationManager::notifyInstallationEnd(const InstallationResult& result, + ModInfo::Ptr newMod) { auto& installers = m_PluginContainer->plugins<IPluginInstaller>(); for (auto* installer : installers) { diff --git a/src/installationmanager.h b/src/installationmanager.h index a5ec11d9..e8e97515 100644 --- a/src/installationmanager.h +++ b/src/installationmanager.h @@ -20,28 +20,28 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef INSTALLATIONMANAGER_H #define INSTALLATIONMANAGER_H +#include <guessedvalue.h> #include <ifiletree.h> #include <iinstallationmanager.h> #include <iplugininstaller.h> -#include <guessedvalue.h> #include <QObject> #define WIN32_LEAN_AND_MEAN +#include <QProgressDialog> #include <Windows.h> #include <archive.h> -#include <QProgressDialog> -#include <set> -#include <map> #include <errorcodes.h> +#include <map> +#include <set> #include "modinfo.h" #include "plugincontainer.h" // contains installation result from the manager, internal class // for MO2 that is not forwarded to plugin -class InstallationResult { +class InstallationResult +{ public: - // result status of the installation // auto result() const { return m_result; } @@ -58,14 +58,17 @@ public: // check if the installation was a success // - explicit operator bool() const { return result() == MOBase::IPluginInstaller::EInstallResult::RESULT_SUCCESS; } + explicit operator bool() const + { + return result() == MOBase::IPluginInstaller::EInstallResult::RESULT_SUCCESS; + } private: - friend class InstallationManager; // create a failed result - InstallationResult(MOBase::IPluginInstaller::EInstallResult result = MOBase::IPluginInstaller::EInstallResult::RESULT_FAILED); + InstallationResult(MOBase::IPluginInstaller::EInstallResult result = + MOBase::IPluginInstaller::EInstallResult::RESULT_FAILED); MOBase::IPluginInstaller::EInstallResult m_result; @@ -75,16 +78,13 @@ private: bool m_backup; bool m_merged; bool m_replaced; - }; - class InstallationManager : public QObject, public MOBase::IInstallationManager { Q_OBJECT public: - /** * @brief constructor * @@ -94,23 +94,25 @@ public: virtual ~InstallationManager(); - void setParentWidget(QWidget *widget); + void setParentWidget(QWidget* widget); /** * @brief Notify all installer plugins that an installation is about to start. * * @param archive Path to the archive that is going to be installed. * @param reinstallation True if this is a reinstallation, false otherwise. - * @param currentMod The installed mod corresponding to the archive being installed, or a null - * if there is no such mod. + * @param currentMod The installed mod corresponding to the archive being installed, + * or a null if there is no such mod. */ - void notifyInstallationStart(QString const& archive, bool reinstallation, ModInfo::Ptr currentMod); + void notifyInstallationStart(QString const& archive, bool reinstallation, + ModInfo::Ptr currentMod); /** * @brief notify all installer plugins that an installation has ended. * * @param result The result of the installation process. - * @param currentMod The newly install mod, if result is SUCCESS, a null pointer otherwise. + * @param currentMod The newly install mod, if result is SUCCESS, a null pointer + * otherwise. */ void notifyInstallationEnd(const InstallationResult& result, ModInfo::Ptr newMod); @@ -119,7 +121,10 @@ public: * @param modsDirectory the mod directory * @note this is called a lot, probably redundantly */ - void setModsDirectory(const QString &modsDirectory) { m_ModsDirectory = modsDirectory; } + void setModsDirectory(const QString& modsDirectory) + { + m_ModsDirectory = modsDirectory; + } /** * @@ -130,17 +135,25 @@ public: * @brief update the directory where downloads are stored * @param downloadDirectory the download directory */ - void setDownloadDirectory(const QString &downloadDirectory) { m_DownloadsDirectory = downloadDirectory; } + void setDownloadDirectory(const QString& downloadDirectory) + { + m_DownloadsDirectory = downloadDirectory; + } /** * @brief install a mod from an archive * * @param fileName absolute file name of the archive to install - * @param modName suggested name of the mod. If this is empty (the default), a name will be guessed based on the filename. The user will always have a chance to rename the mod - * @return true if the archive was installed, false if installation failed or was refused - * @exception std::exception an exception may be thrown if the archive can't be opened (maybe the format is invalid or the file is damaged) + * @param modName suggested name of the mod. If this is empty (the default), a name + *will be guessed based on the filename. The user will always have a chance to rename + *the mod + * @return true if the archive was installed, false if installation failed or was + *refused + * @exception std::exception an exception may be thrown if the archive can't be opened + *(maybe the format is invalid or the file is damaged) **/ - InstallationResult install(const QString &fileName, MOBase::GuessedValue<QString> &modName, int modID = 0); + InstallationResult install(const QString& fileName, + MOBase::GuessedValue<QString>& modName, int modID = 0); /** * @return true if the installation was canceled @@ -157,7 +170,8 @@ public: * * @param errorCode an error code as returned by the archiving function * @return the error string - * @todo This function doesn't belong here, it is only public because the SelfUpdater class also uses "Archive" to get to the package.txt file + * @todo This function doesn't belong here, it is only public because the SelfUpdater + *class also uses "Archive" to get to the package.txt file **/ static QString getErrorString(Archive::Error errorCode); @@ -167,7 +181,8 @@ public: QStringList getSupportedExtensions() const override; /** - * @brief Extract the specified file from the currently opened archive to a temporary location. + * @brief Extract the specified file from the currently opened archive to a temporary + * location. * * This method cannot be used to extract directory. * @@ -181,10 +196,12 @@ public: * @note The temporary file is automatically cleaned up after the installation. * @note This call can be very slow if the archive is large and "solid". */ - QString extractFile(std::shared_ptr<const MOBase::FileTreeEntry> entry, bool silent = false) override; + QString extractFile(std::shared_ptr<const MOBase::FileTreeEntry> entry, + bool silent = false) override; /** - * @brief Extract the specified files from the currently opened archive to a temporary location. + * @brief Extract the specified files from the currently opened archive to a temporary + * location. * * This method cannot be used to extract directory. * @@ -198,20 +215,24 @@ public: * @note The temporary file is automatically cleaned up after the installation. * @note This call can be very slow if the archive is large and "solid". * - * The flatten argument is not present here while it is present in the deprecated QStringList - * version for multiple reasons: 1) it was never used, 2) it is kind of fishy because there - * is no way to know if a file is going to be overriden, 3) it is quite easy to flatten a - * IFileTree and thus to given a list of entries flattened (this was not possible with the - * QStringList version since these were based on the name of the file inside the archive). + * The flatten argument is not present here while it is present in the deprecated + * QStringList version for multiple reasons: 1) it was never used, 2) it is kind of + * fishy because there is no way to know if a file is going to be overriden, 3) it is + * quite easy to flatten a IFileTree and thus to given a list of entries flattened + * (this was not possible with the QStringList version since these were based on the + * name of the file inside the archive). */ - QStringList extractFiles(std::vector<std::shared_ptr<const MOBase::FileTreeEntry>> const& entries, bool silent = false) override; + QStringList + extractFiles(std::vector<std::shared_ptr<const MOBase::FileTreeEntry>> const& entries, + bool silent = false) override; /** * @brief Create a new file on the disk corresponding to the given entry. * - * This method can be used by installer that needs to create files that are not in the original - * archive. At the end of the installation, if there are entries in the final tree that were used - * to create files, the corresponding files will be moved to the mod folder. + * This method can be used by installer that needs to create files that are not in the + * original archive. At the end of the installation, if there are entries in the final + * tree that were used to create files, the corresponding files will be moved to the + * mod folder. * * @param entry The entry for which a temporary file should be created. * @@ -228,7 +249,9 @@ public: * * @return the installation result. */ - MOBase::IPluginInstaller::EInstallResult installArchive(MOBase::GuessedValue<QString> &modName, const QString &archiveName, int modId = 0) override; + MOBase::IPluginInstaller::EInstallResult + installArchive(MOBase::GuessedValue<QString>& modName, const QString& archiveName, + int modId = 0) override; /** * @param modName current possible names for the mod @@ -237,17 +260,16 @@ public: */ InstallationResult testOverwrite(MOBase::GuessedValue<QString>& modName); - QString generateBackupName(const QString &directoryName) const; + QString generateBackupName(const QString& directoryName) const; private: - // actually perform the installation (write files to the disk, etc.), returns the // installation result // - InstallationResult doInstall( - MOBase::GuessedValue<QString> &modName, QString gameName, - int modID, const QString &version, const QString &newestVersion, - int categoryID, int fileCategoryID, const QString &repository); + InstallationResult doInstall(MOBase::GuessedValue<QString>& modName, QString gameName, + int modID, const QString& version, + const QString& newestVersion, int categoryID, + int fileCategoryID, const QString& repository); /** * @brief Clean the list of created files by removing all entries that are not @@ -257,7 +279,7 @@ private: */ void cleanCreatedFiles(std::shared_ptr<const MOBase::IFileTree> fileTree); - bool ensureValidModName(MOBase::GuessedValue<QString> &name) const; + bool ensureValidModName(MOBase::GuessedValue<QString>& name) const; void postInstallCleanup(); @@ -281,17 +303,17 @@ signals: void progressUpdate(); /** - * @brief An existing mod has been replaced with a newly installed one. - */ + * @brief An existing mod has been replaced with a newly installed one. + */ void modReplaced(const QString fileName); private: - - struct CaseInsensitive { - bool operator() (const QString &LHS, const QString &RHS) const - { - return QString::compare(LHS, RHS, Qt::CaseInsensitive) < 0; - } + struct CaseInsensitive + { + bool operator()(const QString& LHS, const QString& RHS) const + { + return QString::compare(LHS, RHS, Qt::CaseInsensitive) < 0; + } }; /** @@ -305,16 +327,16 @@ private: * @return true if the extraction was successful, false if the extraciton was * cancelled. If an error occured, an exception is thrown. */ - bool extractFiles(QString extractPath, QString title, bool showFilenames, bool silent); + bool extractFiles(QString extractPath, QString title, bool showFilenames, + bool silent); private: - // The plugin container, mostly to check if installer are enabled or not. - const PluginContainer *m_PluginContainer; + const PluginContainer* m_PluginContainer; bool m_IsRunning; - QWidget *m_ParentWidget; + QWidget* m_ParentWidget; QString m_ModsDirectory; QString m_DownloadsDirectory; @@ -330,5 +352,4 @@ private: std::set<QString> m_TempFilesToDelete; }; - -#endif // INSTALLATIONMANAGER_H +#endif // INSTALLATIONMANAGER_H diff --git a/src/instancemanager.cpp b/src/instancemanager.cpp index 3a5aee4c..df4b0078 100644 --- a/src/instancemanager.cpp +++ b/src/instancemanager.cpp @@ -17,37 +17,35 @@ You should have received a copy of the GNU General Public License along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ - #include "instancemanager.h" -#include "selectiondialog.h" -#include "settings.h" -#include "plugincontainer.h" -#include "nexusinterface.h" #include "createinstancedialog.h" -#include "instancemanagerdialog.h" #include "createinstancedialogpages.h" +#include "filesystemutilities.h" +#include "instancemanagerdialog.h" +#include "nexusinterface.h" +#include "plugincontainer.h" +#include "selectiondialog.h" +#include "settings.h" #include "shared/appconfig.h" #include "shared/util.h" -#include <report.h> #include <iplugingame.h> -#include <utility.h> #include <log.h> -#include "filesystemutilities.h" +#include <report.h> +#include <utility.h> #include <QCoreApplication> #include <QDir> -#include <QStandardPaths> #include <QInputDialog> #include <QMessageBox> +#include <QStandardPaths> #include <cstdint> using namespace MOBase; -Instance::Instance(QString dir, bool portable, QString profileName) : - m_dir(std::move(dir)), m_portable(portable), m_plugin(nullptr), - m_profile(std::move(profileName)) -{ -} +Instance::Instance(QString dir, bool portable, QString profileName) + : m_dir(std::move(dir)), m_portable(portable), m_plugin(nullptr), + m_profile(std::move(profileName)) +{} QString Instance::displayName() const { @@ -101,8 +99,7 @@ bool Instance::isActive() const { auto& m = InstanceManager::singleton(); - if (auto i=m.currentInstance()) - { + if (auto i = m.currentInstance()) { if (m_portable) { return i->isPortable(); } else { @@ -124,17 +121,17 @@ bool Instance::readFromIni() // game name and directory are from ini unless overridden by setGame() if (m_gameName.isEmpty()) { - if (auto v=s.game().name()) + if (auto v = s.game().name()) m_gameName = *v; } if (m_gameDir.isEmpty()) { - if (auto v=s.game().directory()) + if (auto v = s.game().directory()) m_gameDir = *v; } if (m_gameVariant.isEmpty()) { - if (auto v=s.game().edition()) { + if (auto v = s.game().edition()) { m_gameVariant = *v; } } @@ -203,7 +200,7 @@ void Instance::updateIni() void Instance::setGame(const QString& name, const QString& dir) { m_gameName = name; - m_gameDir = dir; + m_gameDir = dir; } void Instance::setVariant(const QString& name) @@ -213,8 +210,7 @@ void Instance::setVariant(const QString& name) Instance::SetupResults Instance::getGamePlugin(PluginContainer& plugins) { - if (!m_gameName.isEmpty() && !m_gameDir.isEmpty()) - { + if (!m_gameName.isEmpty() && !m_gameDir.isEmpty()) { // normal case: both the name and dir are in the ini // find the plugin by name @@ -224,9 +220,8 @@ Instance::SetupResults Instance::getGamePlugin(PluginContainer& plugins) if (!game->looksValid(m_gameDir)) { // the directory from the ini is not valid anymore - log::warn( - "game plugin {} says dir {} from ini {} is not valid", - game->gameName(), m_gameDir, iniPath()); + log::warn("game plugin {} says dir {} from ini {} is not valid", + game->gameName(), m_gameDir, iniPath()); // note that some plugins return true for isInstalled() if a path // is found in the registry, but without actually checking if it's @@ -235,14 +230,14 @@ Instance::SetupResults Instance::getGamePlugin(PluginContainer& plugins) if (game->isInstalled() && game->looksValid(game->gameDirectory())) { // bad game directory but the plugin reports there's a valid one // somewhere; take it instead - log::warn( - "game plugin {} found a game at {}, taking it", - game->gameName(), game->gameDirectory().absolutePath()); + log::warn("game plugin {} found a game at {}, taking it", game->gameName(), + game->gameDirectory().absolutePath()); m_gameDir = game->gameDirectory().absolutePath(); } else { // game seems to be gone completely - log::warn("game plugin {} found no game installation at all", game->gameName()); + log::warn("game plugin {} found no game installation at all", + game->gameName()); return SetupResults::GameGone; } } @@ -254,22 +249,19 @@ Instance::SetupResults Instance::getGamePlugin(PluginContainer& plugins) log::warn("game plugin {} not found", m_gameName); return SetupResults::PluginGone; - } - else if (m_gameName.isEmpty() && !m_gameDir.isEmpty()) - { + } else if (m_gameName.isEmpty() && !m_gameDir.isEmpty()) { // the name is missing, but there's a directory; find a plugin that can // handle it - log::warn( - "game name is missing from ini {} but dir {} is available", - iniPath(), m_gameDir); + log::warn("game name is missing from ini {} but dir {} is available", iniPath(), + m_gameDir); for (IPluginGame* game : plugins.plugins<IPluginGame>()) { if (game->looksValid(m_gameDir)) { // take it log::warn("found plugin {} that can use dir {}", game->gameName(), m_gameDir); - m_plugin = game; + m_plugin = game; m_gameName = game->gameName(); return SetupResults::Okay; @@ -278,35 +270,30 @@ Instance::SetupResults Instance::getGamePlugin(PluginContainer& plugins) log::error("no plugins can use dir {}", m_gameDir); return SetupResults::GameGone; - } - else if (!m_gameName.isEmpty() && m_gameDir.isEmpty()) - { + } else if (!m_gameName.isEmpty() && m_gameDir.isEmpty()) { // dir is missing, find a plugin with the correct name and use the install // dir it detected - log::warn( - "game dir is missing from ini {} but name {} is available", - iniPath(), m_gameName); + log::warn("game dir is missing from ini {} but name {} is available", iniPath(), + m_gameName); for (IPluginGame* game : plugins.plugins<IPluginGame>()) { if (m_gameName.compare(game->gameName(), Qt::CaseInsensitive) == 0) { // plugin found, use its detected installation dir if (game->isInstalled()) { - log::warn( - "found plugin {} that matches name in ini {}, using auto detected " - "game dir {}", - game->gameName(), iniPath(), game->gameDirectory().absolutePath()); + log::warn("found plugin {} that matches name in ini {}, using auto detected " + "game dir {}", + game->gameName(), iniPath(), game->gameDirectory().absolutePath()); - m_plugin = game; + m_plugin = game; m_gameDir = game->gameDirectory().absolutePath(); return SetupResults::Okay; } else { - log::warn( - "found plugin {} that matches name in ini {}, but no game install " - "detected by plugin", - game->gameName(), iniPath()); + log::warn("found plugin {} that matches name in ini {}, but no game install " + "detected by plugin", + game->gameName(), iniPath()); return SetupResults::GameGone; } @@ -316,9 +303,7 @@ Instance::SetupResults Instance::getGamePlugin(PluginContainer& plugins) // plugin seems to be gone log::error("no plugin matches name {}", m_gameName); return SetupResults::PluginGone; - } - else - { + } else { // can't do anything with these two missing log::error("both game name and dir are missing from ini {}", iniPath()); return SetupResults::IniMissingGame; @@ -332,7 +317,7 @@ void Instance::getProfile(const Settings& s) return; } - if (auto name=s.game().selectedProfileName()) { + if (auto name = s.game().selectedProfileName()) { // use last profile m_profile = *name; return; @@ -341,9 +326,7 @@ void Instance::getProfile(const Settings& s) // profile missing from ini, use the default m_profile = QString::fromStdWString(AppConfig::defaultProfileName()); - log::warn( - "no profile found in ini {}, using default '{}'", - iniPath(), m_profile); + log::warn("no profile found in ini {}, using default '{}'", iniPath(), m_profile); } // returns a list of files and folders that must be deleted when deleting @@ -365,7 +348,6 @@ std::vector<Instance::Object> Instance::objectsForDeletion() const return QDir::toNativeSeparators(s); }; - // lowercase, native separators and ending slash auto canonicalDir = [](QString s) { s = s.toLower(); @@ -382,8 +364,6 @@ std::vector<Instance::Object> Instance::objectsForDeletion() const return QDir::toNativeSeparators(s.toLower()); }; - - // whether the given directory is contained in the root auto dirInRoot = [&](const QString& root, const QString& dir) { return canonicalDir(dir).startsWith(canonicalDir(root)); @@ -394,7 +374,6 @@ std::vector<Instance::Object> Instance::objectsForDeletion() const return canonicalFile(file).startsWith(canonicalDir(root)); }; - Settings settings(iniPath()); if (settings.iniStatus() != QSettings::NoError) { @@ -402,12 +381,9 @@ std::vector<Instance::Object> Instance::objectsForDeletion() const return {}; } - - - const QString loc = directory(); + const QString loc = directory(); const QString base = settings.paths().base(); - // directories that might contain the individual files and directories // set in the path settings std::vector<Object> roots; @@ -428,25 +404,23 @@ std::vector<Instance::Object> Instance::objectsForDeletion() const } } - // all the directories that are part of an instance; none of them are // mandatory for deletion const std::vector<Object> dirs = { - settings.paths().downloads(), - settings.paths().mods(), - settings.paths().cache(), - settings.paths().profiles(), - settings.paths().overwrite(), - QDir(m_dir).filePath(QString::fromStdWString(AppConfig::dumpsDir())), - QDir(m_dir).filePath(QString::fromStdWString(AppConfig::logPath())), + settings.paths().downloads(), + settings.paths().mods(), + settings.paths().cache(), + settings.paths().profiles(), + settings.paths().overwrite(), + QDir(m_dir).filePath(QString::fromStdWString(AppConfig::dumpsDir())), + QDir(m_dir).filePath(QString::fromStdWString(AppConfig::logPath())), }; // all the files that are part of an instance const std::vector<Object> files = { - {iniPath(), true}, // the ini file must be deleted + {iniPath(), true}, // the ini file must be deleted }; - // this will contain the root directories, plus all the individual // directories that are not inside these roots std::vector<Object> cleanDirs; @@ -471,14 +445,10 @@ std::vector<Instance::Object> Instance::objectsForDeletion() const } // prepending the roots - for (auto itor=roots.rbegin(); itor!=roots.rend(); ++itor) { - cleanDirs.insert( - cleanDirs.begin(), - {prettyDir(itor->path), itor->mandatoryDelete}); + for (auto itor = roots.rbegin(); itor != roots.rend(); ++itor) { + cleanDirs.insert(cleanDirs.begin(), {prettyDir(itor->path), itor->mandatoryDelete}); } - - // this will contain the individual files that are not inside the roots; // not that this only contains the INI file for now, so most of this is // useless @@ -503,7 +473,6 @@ std::vector<Instance::Object> Instance::objectsForDeletion() const } } - // contains all the directories and files to be deleted std::vector<Object> all; all.insert(all.end(), cleanDirs.begin(), cleanDirs.end()); @@ -515,14 +484,12 @@ std::vector<Instance::Object> Instance::objectsForDeletion() const return all; } - - InstanceManager::InstanceManager() { GlobalSettings::updateRegistryKey(); } -InstanceManager &InstanceManager::singleton() +InstanceManager& InstanceManager::singleton() { static InstanceManager s_Instance; return s_Instance; @@ -541,17 +508,15 @@ void InstanceManager::overrideProfile(const QString& profileName) void InstanceManager::clearOverrides() { m_overrideInstanceName = {}; - m_overrideProfileName = {}; + m_overrideProfileName = {}; } std::unique_ptr<Instance> InstanceManager::currentInstance() const { - const QString profile = m_overrideProfileName ? - *m_overrideProfileName : ""; - - const QString name = m_overrideInstanceName ? - *m_overrideInstanceName : GlobalSettings::currentInstance(); + const QString profile = m_overrideProfileName ? *m_overrideProfileName : ""; + const QString name = m_overrideInstanceName ? *m_overrideInstanceName + : GlobalSettings::currentInstance(); if (!allowedToChangeInstance()) { // force portable instance @@ -577,7 +542,7 @@ void InstanceManager::clearCurrentInstance() m_overrideInstanceName = {}; } -void InstanceManager::setCurrentInstance(const QString &name) +void InstanceManager::setCurrentInstance(const QString& name) { GlobalSettings::setCurrentInstance(name); } @@ -590,18 +555,17 @@ QString InstanceManager::instancePath(const QString& instanceName) const QString InstanceManager::globalInstancesRootPath() const { return QDir::fromNativeSeparators( - QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)); + QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)); } QString InstanceManager::iniPath(const QString& instanceDir) const { - return QDir(instanceDir).filePath( - QString::fromStdWString(AppConfig::iniFileName())); + return QDir(instanceDir).filePath(QString::fromStdWString(AppConfig::iniFileName())); } std::vector<QString> InstanceManager::globalInstancePaths() const { - const std::set<QString> ignore = { "qtwebengine" }; + const std::set<QString> ignore = {"qtwebengine"}; const QDir root(globalInstancesRootPath()); const auto dirs = root.entryList(QDir::Dirs | QDir::NoDotAndDotDot); @@ -635,30 +599,30 @@ bool InstanceManager::portableInstanceExists() const bool InstanceManager::allowedToChangeInstance() const { - const auto lockFile = - qApp->applicationDirPath() + "/" + - QString::fromStdWString(AppConfig::portableLockFileName()); + const auto lockFile = qApp->applicationDirPath() + "/" + + QString::fromStdWString(AppConfig::portableLockFileName()); return !QFile::exists(lockFile); } -MOBase::IPluginGame* InstanceManager::gamePluginForDirectory( - const QString& instanceDir, PluginContainer& plugins) const +MOBase::IPluginGame* +InstanceManager::gamePluginForDirectory(const QString& instanceDir, + PluginContainer& plugins) const { - return const_cast<MOBase::IPluginGame*>(gamePluginForDirectory( - instanceDir, const_cast<const PluginContainer&>(plugins))); + return const_cast<MOBase::IPluginGame*>( + gamePluginForDirectory(instanceDir, const_cast<const PluginContainer&>(plugins))); } -const MOBase::IPluginGame* InstanceManager::gamePluginForDirectory( - const QString& instanceDir, const PluginContainer& plugins) const +const MOBase::IPluginGame* +InstanceManager::gamePluginForDirectory(const QString& instanceDir, + const PluginContainer& plugins) const { const QString ini = iniPath(instanceDir); // reading ini Settings s(ini); - if (s.iniStatus() != QSettings::NoError) - { + if (s.iniStatus() != QSettings::NoError) { log::error("failed to load settings from {}", ini); return nullptr; } @@ -666,45 +630,35 @@ const MOBase::IPluginGame* InstanceManager::gamePluginForDirectory( // using game name from ini, if available const auto instanceGameName = s.game().name(); - if (instanceGameName && !instanceGameName->isEmpty()) - { + if (instanceGameName && !instanceGameName->isEmpty()) { for (const IPluginGame* game : plugins.plugins<IPluginGame>()) { if (instanceGameName->compare(game->gameName(), Qt::CaseInsensitive) == 0) { return game; } } - log::error( - "no plugin has game name '{}' that was found in ini {}", - *instanceGameName, ini); - } - else - { + log::error("no plugin has game name '{}' that was found in ini {}", + *instanceGameName, ini); + } else { log::error("no game name found in ini {}", ini); } - // using game directory from ini, if available const auto gameDir = s.game().directory(); - if (gameDir && !gameDir->isEmpty()) - { + if (gameDir && !gameDir->isEmpty()) { for (const IPluginGame* game : plugins.plugins<IPluginGame>()) { if (game->looksValid(*gameDir)) { return game; } } - log::error( - "no plugin appears to support game directory '{}' from ini {}", - *gameDir, ini); - } - else - { + log::error("no plugin appears to support game directory '{}' from ini {}", *gameDir, + ini); + } else { log::error("no game directory found in ini {}", ini); } - // looking for a plugin that can handle the directory log::debug("falling back on looksValid check"); @@ -714,7 +668,6 @@ const MOBase::IPluginGame* InstanceManager::gamePluginForDirectory( } } - return nullptr; } @@ -724,7 +677,7 @@ QString InstanceManager::makeUniqueName(const QString& instanceName) const // trying "name (N)" QString name = sanitized; - for (int i=2; i<100; ++i) { + for (int i = 2; i < 100; ++i) { if (!instanceExists(name)) { return name; } @@ -805,9 +758,8 @@ SetupInstanceResults selectGame(Instance& instance, PluginContainer& pc) // this info will be used instead of the ini, which should fix this // particular problem - instance.setGame( - dlg.creationInfo().game->gameName(), - dlg.creationInfo().gameLocation); + instance.setGame(dlg.creationInfo().game->gameName(), + dlg.creationInfo().gameLocation); return SetupInstanceResults::TryAgain; } @@ -826,8 +778,7 @@ SetupInstanceResults selectVariant(Instance& instance, PluginContainer& pc) // the variant page uses the game page to know which game was selected, so // set it manually - dlg.getPage<cid::GamePage>()->select( - instance.gamePlugin(), instance.gameDirectory()); + dlg.getPage<cid::GamePage>()->select(instance.gamePlugin(), instance.gameDirectory()); // only show the variant page dlg.setSinglePage<cid::VariantsPage>(instance.displayName()); @@ -852,84 +803,77 @@ SetupInstanceResults setupInstance(Instance& instance, PluginContainer& pc) // set up the instance const auto setupResult = instance.setup(pc); - switch (setupResult) - { - case Instance::SetupResults::Okay: - { - // all good - return SetupInstanceResults::Okay; - } + switch (setupResult) { + case Instance::SetupResults::Okay: { + // all good + return SetupInstanceResults::Okay; + } - case Instance::SetupResults::BadIni: - { - // unreadable ini, there's not much that can be done, select another - // instance + case Instance::SetupResults::BadIni: { + // unreadable ini, there's not much that can be done, select another + // instance - reportError( - QObject::tr("Cannot open instance '%1', failed to read INI file %2.") - .arg(instance.displayName()).arg(instance.iniPath())); + reportError(QObject::tr("Cannot open instance '%1', failed to read INI file %2.") + .arg(instance.displayName()) + .arg(instance.iniPath())); - return SetupInstanceResults::SelectAnother; - } + return SetupInstanceResults::SelectAnother; + } - case Instance::SetupResults::IniMissingGame: - { - // both the game name and directory are missing from the ini; although - // this shouldn't happen, setup() is able to handle when either is - // missing, but not both - // - // ask the user for the game managed by this instance + case Instance::SetupResults::IniMissingGame: { + // both the game name and directory are missing from the ini; although + // this shouldn't happen, setup() is able to handle when either is + // missing, but not both + // + // ask the user for the game managed by this instance - reportError( + reportError( QObject::tr( - "Cannot open instance '%1', the managed game was not found in the INI " - "file %2. Select the game managed by this instance.") - .arg(instance.displayName()).arg(instance.iniPath())); + "Cannot open instance '%1', the managed game was not found in the INI " + "file %2. Select the game managed by this instance.") + .arg(instance.displayName()) + .arg(instance.iniPath())); - return selectGame(instance, pc); - } + return selectGame(instance, pc); + } - case Instance::SetupResults::PluginGone: - { - // there is no plugin that can handle the game name/directory from the - // ini, so this instance is unusable + case Instance::SetupResults::PluginGone: { + // there is no plugin that can handle the game name/directory from the + // ini, so this instance is unusable - reportError( - QObject::tr( - "Cannot open instance '%1', the game plugin '%2' doesn't exist. It " - "may have been deleted by an antivirus. Select another instance.") - .arg(instance.displayName()).arg(instance.gameName())); + reportError( + QObject::tr("Cannot open instance '%1', the game plugin '%2' doesn't exist. It " + "may have been deleted by an antivirus. Select another instance.") + .arg(instance.displayName()) + .arg(instance.gameName())); - return SetupInstanceResults::SelectAnother; - } + return SetupInstanceResults::SelectAnother; + } - case Instance::SetupResults::GameGone: - { - // the game directory doesn't exist or the plugin doesn't recognize it; - // ask the user for the game managed by this instance + case Instance::SetupResults::GameGone: { + // the game directory doesn't exist or the plugin doesn't recognize it; + // ask the user for the game managed by this instance - reportError( + reportError( QObject::tr( - "Cannot open instance '%1', the game directory '%2' doesn't exist or " - "the game plugin '%3' doesn't recognize it. Select the game managed " - "by this instance.") - .arg(instance.displayName()) - .arg(instance.gameDirectory()) - .arg(instance.gameName())); + "Cannot open instance '%1', the game directory '%2' doesn't exist or " + "the game plugin '%3' doesn't recognize it. Select the game managed " + "by this instance.") + .arg(instance.displayName()) + .arg(instance.gameDirectory()) + .arg(instance.gameName())); - return selectGame(instance, pc); - } + return selectGame(instance, pc); + } - case Instance::SetupResults::MissingVariant: - { - // the game variant is missing from the ini, ask the user for it - return selectVariant(instance, pc); - } + case Instance::SetupResults::MissingVariant: { + // the game variant is missing from the ini, ask the user for it + return selectVariant(instance, pc); + } - default: - { - // shouldn't happen - return SetupInstanceResults::Exit; - } + default: { + // shouldn't happen + return SetupInstanceResults::Exit; + } } } diff --git a/src/instancemanager.h b/src/instancemanager.h index 7174ec3a..176033e8 100644 --- a/src/instancemanager.h +++ b/src/instancemanager.h @@ -1,15 +1,17 @@ #ifndef MODORGANIZER_INSTANCEMANAGER_INCLUDED #define MODORGANIZER_INSTANCEMANAGER_INCLUDED -#include <QString> #include <QSettings> +#include <QString> -namespace MOBase { class IPluginGame; } +namespace MOBase +{ +class IPluginGame; +} class Settings; class PluginContainer; - // represents an instance, either global or portable // // if setup() is not called, the game plugin is not available and the INI is @@ -54,7 +56,6 @@ public: MissingVariant }; - // a file or directory owned by this instance, used by objectsForDeletion() // struct Object @@ -67,11 +68,7 @@ public: // base directory, etc. bool mandatoryDelete; - - Object(QString p, bool d=false) - : path(std::move(p)), mandatoryDelete(d) - { - } + Object(QString p, bool d = false) : path(std::move(p)), mandatoryDelete(d) {} // puts mandatory delete on top // @@ -87,16 +84,13 @@ public: } }; - - // an instance that lives in the given directory; `portable` must be `true` // if this is a portable instance // // `profileName` can be given to override what's in the INI; this typically // happens when the profile is overriden on the command line // - Instance(QString dir, bool portable, QString profileName={}); - + Instance(QString dir, bool portable, QString profileName = {}); // reads in values from the INI if they were not given yet: // - game name @@ -110,7 +104,6 @@ public: // bool readFromIni(); - // finds the appropriate game plugin and sets it up so MO can use it; this // calls readFromIni() first // @@ -119,7 +112,6 @@ public: // SetupResults setup(PluginContainer& plugins); - // overrides the game name and directory // void setGame(const QString& name, const QString& dir); @@ -128,7 +120,6 @@ public: // void setVariant(const QString& name); - // returns the instance name; this is the directory name or "Portable" for // portable instances // @@ -218,7 +209,6 @@ private: void updateIni(); }; - // manages global and portable instances // class InstanceManager @@ -253,11 +243,11 @@ public: // // returns null if all of this fails // - const MOBase::IPluginGame* gamePluginForDirectory( - const QString& dir, const PluginContainer& plugins) const; + const MOBase::IPluginGame* + gamePluginForDirectory(const QString& dir, const PluginContainer& plugins) const; - MOBase::IPluginGame* gamePluginForDirectory( - const QString& dir, PluginContainer& plugins) const; + MOBase::IPluginGame* gamePluginForDirectory(const QString& dir, + PluginContainer& plugins) const; // clears the instance name from the registry; on restart, this will make MO // either select the portable instance if it exists, or display the instance @@ -274,7 +264,7 @@ public: // sets the instance name in the registry so the same instance is opened next // time MO runs // - void setCurrentInstance(const QString &name); + void setCurrentInstance(const QString& name); // whether MO should allow the user to change the current instance from the // user interface @@ -335,7 +325,6 @@ private: std::optional<QString> m_overrideProfileName; }; - // see setupInstance() // enum class SetupInstanceResults diff --git a/src/instancemanagerdialog.cpp b/src/instancemanagerdialog.cpp index 776b2496..b5139e90 100644 --- a/src/instancemanagerdialog.cpp +++ b/src/instancemanagerdialog.cpp @@ -1,16 +1,16 @@ #include "instancemanagerdialog.h" -#include "ui_instancemanagerdialog.h" -#include "instancemanager.h" #include "createinstancedialog.h" -#include "settings.h" -#include "selectiondialog.h" +#include "filesystemutilities.h" +#include "instancemanager.h" #include "plugincontainer.h" +#include "selectiondialog.h" +#include "settings.h" #include "shared/appconfig.h" #include "shared/util.h" -#include <utility.h> -#include <report.h> +#include "ui_instancemanagerdialog.h" #include <iplugingame.h> -#include "filesystemutilities.h" +#include <report.h> +#include <utility.h> using namespace MOBase; @@ -19,8 +19,7 @@ using namespace MOBase; // QIcon instanceIcon(PluginContainer& pc, const Instance& i) { - auto* game = InstanceManager::singleton() - .gamePluginForDirectory(i.directory(), pc); + auto* game = InstanceManager::singleton().gamePluginForDirectory(i.directory(), pc); if (!game) { QPixmap empty(32, 32); @@ -49,7 +48,6 @@ QIcon instanceIcon(PluginContainer& pc, const Instance& i) // current instance, which should _definitely_ keep pointing to the same // directory as before - // remember old game directory // // note that gameDirectory() returns a QDir, which doesn't support empty @@ -60,7 +58,9 @@ QIcon instanceIcon(PluginContainer& pc, const Instance& i) const QString old = game->isInstalled() ? game->gameDirectory().path() : ""; // revert - Guard g([&]{ game->setGamePath(old); }); + Guard g([&] { + game->setGamePath(old); + }); // set directory for this instance game->setGamePath(i.gameDirectory()); @@ -70,9 +70,8 @@ QIcon instanceIcon(PluginContainer& pc, const Instance& i) // pops up a dialog to ask for an instance name when renaming // -QString getInstanceName( - QWidget* parent, const QString& title, const QString& moreText, - const QString& label, const QString& oldName={}) +QString getInstanceName(QWidget* parent, const QString& title, const QString& moreText, + const QString& label, const QString& oldName = {}) { auto& m = InstanceManager::singleton(); @@ -81,8 +80,7 @@ QString getInstanceName( auto* ly = new QVBoxLayout(&dlg); - auto* bb = new QDialogButtonBox( - QDialogButtonBox::Cancel | QDialogButtonBox::Ok); + auto* bb = new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Ok); auto* text = new QLineEdit(oldName); text->selectAll(); @@ -126,9 +124,15 @@ QString getInstanceName( bb->button(QDialogButtonBox::Ok)->setEnabled(okay); }; - QObject::connect(text, &QLineEdit::textChanged, [&] { check(); }); - QObject::connect(bb, &QDialogButtonBox::accepted, [&]{ dlg.accept(); }); - QObject::connect(bb, &QDialogButtonBox::rejected, [&]{ dlg.reject(); }); + QObject::connect(text, &QLineEdit::textChanged, [&] { + check(); + }); + QObject::connect(bb, &QDialogButtonBox::accepted, [&] { + dlg.accept(); + }); + QObject::connect(bb, &QDialogButtonBox::rejected, [&] { + dlg.reject(); + }); check(); @@ -140,13 +144,11 @@ QString getInstanceName( return MOBase::sanitizeFileName(text->text()); } - InstanceManagerDialog::~InstanceManagerDialog() = default; -InstanceManagerDialog::InstanceManagerDialog( - PluginContainer& pc, QWidget *parent) : - QDialog(parent), ui(new Ui::InstanceManagerDialog), m_pc(pc), - m_model(nullptr), m_restartOnSelect(true) +InstanceManagerDialog::InstanceManagerDialog(PluginContainer& pc, QWidget* parent) + : QDialog(parent), ui(new Ui::InstanceManagerDialog), m_pc(pc), m_model(nullptr), + m_restartOnSelect(true) { ui->setupUi(this); @@ -165,23 +167,49 @@ InstanceManagerDialog::InstanceManagerDialog( updateList(); selectActiveInstance(); - connect(ui->createNew, &QPushButton::clicked, [&]{ createNew(); }); + connect(ui->createNew, &QPushButton::clicked, [&] { + createNew(); + }); - connect(ui->list->selectionModel(), &QItemSelectionModel::selectionChanged, [&]{ onSelection(); }); - connect(ui->list, &QListView::activated, [&]{ openSelectedInstance(); }); + connect(ui->list->selectionModel(), &QItemSelectionModel::selectionChanged, [&] { + onSelection(); + }); + connect(ui->list, &QListView::activated, [&] { + openSelectedInstance(); + }); - connect(ui->rename, &QPushButton::clicked, [&]{ rename(); }); - connect(ui->exploreLocation, &QPushButton::clicked, [&]{ exploreLocation(); }); - connect(ui->exploreBaseDirectory, &QPushButton::clicked, [&]{ exploreBaseDirectory(); }); - connect(ui->exploreGame, &QPushButton::clicked, [&]{ exploreGame(); }); + connect(ui->rename, &QPushButton::clicked, [&] { + rename(); + }); + connect(ui->exploreLocation, &QPushButton::clicked, [&] { + exploreLocation(); + }); + connect(ui->exploreBaseDirectory, &QPushButton::clicked, [&] { + exploreBaseDirectory(); + }); + connect(ui->exploreGame, &QPushButton::clicked, [&] { + exploreGame(); + }); - connect(ui->convertToGlobal, &QPushButton::clicked, [&]{ convertToGlobal(); }); - connect(ui->convertToPortable, &QPushButton::clicked, [&]{ convertToPortable(); }); - connect(ui->openINI, &QPushButton::clicked, [&]{ openINI(); }); - connect(ui->deleteInstance, &QPushButton::clicked, [&]{ deleteInstance(); }); + connect(ui->convertToGlobal, &QPushButton::clicked, [&] { + convertToGlobal(); + }); + connect(ui->convertToPortable, &QPushButton::clicked, [&] { + convertToPortable(); + }); + connect(ui->openINI, &QPushButton::clicked, [&] { + openINI(); + }); + connect(ui->deleteInstance, &QPushButton::clicked, [&] { + deleteInstance(); + }); - connect(ui->switchToInstance, &QPushButton::clicked, [&]{ openSelectedInstance(); }); - connect(ui->close, &QPushButton::clicked, [&]{ close(); }); + connect(ui->switchToInstance, &QPushButton::clicked, [&] { + openSelectedInstance(); + }); + connect(ui->close, &QPushButton::clicked, [&] { + close(); + }); } void InstanceManagerDialog::showEvent(QShowEvent* e) @@ -226,9 +254,8 @@ void InstanceManagerDialog::updateInstances() }); if (m.portableInstanceExists()) { - m_instances.insert( - m_instances.begin(), - std::make_unique<Instance>(m.portablePath(), true)); + m_instances.insert(m_instances.begin(), + std::make_unique<Instance>(m.portablePath(), true)); } // read all inis, ignore errors @@ -240,14 +267,14 @@ void InstanceManagerDialog::updateInstances() void InstanceManagerDialog::updateList() { const auto prevSelIndex = singleSelectionIndex(); - const auto* prevSel = singleSelection(); + const auto* prevSel = singleSelection(); m_model->clear(); std::size_t sel = NoSelection; // creating items for instances - for (std::size_t i=0; i<m_instances.size(); ++i) { + for (std::size_t i = 0; i < m_instances.size(); ++i) { const auto& ii = *m_instances[i]; auto* item = new QStandardItem(ii.displayName()); @@ -286,8 +313,8 @@ void InstanceManagerDialog::select(std::size_t i) fillData(*ii); ui->list->selectionModel()->select( - m_filter.mapFromSource(m_filter.sourceModel()->index(i, 0)), - QItemSelectionModel::ClearAndSelect); + m_filter.mapFromSource(m_filter.sourceModel()->index(i, 0)), + QItemSelectionModel::ClearAndSelect); } else { clearData(); } @@ -295,7 +322,7 @@ void InstanceManagerDialog::select(std::size_t i) void InstanceManagerDialog::select(const QString& name) { - for (std::size_t i=0; i<m_instances.size(); ++i) { + for (std::size_t i = 0; i < m_instances.size(); ++i) { if (m_instances[i]->displayName() == name) { select(i); return; @@ -310,12 +337,11 @@ void InstanceManagerDialog::selectActiveInstance() const auto active = InstanceManager::singleton().currentInstance(); if (active) { - for (std::size_t i=0; i<m_instances.size(); ++i) { + for (std::size_t i = 0; i < m_instances.size(); ++i) { if (m_instances[i]->displayName() == active->displayName()) { select(i); - ui->list->scrollTo( - m_filter.mapFromSource(m_filter.sourceModel()->index(i, 0))); + ui->list->scrollTo(m_filter.mapFromSource(m_filter.sourceModel()->index(i, 0))); return; } @@ -370,15 +396,14 @@ bool InstanceManagerDialog::confirmSwitch(const Instance& to) MOBase::TaskDialog dlg(this); - const auto r = dlg - .title(tr("Switching instances")) - .main(tr("Mod Organizer must restart to manage the instance '%1'.") - .arg(to.displayName())) - .content(tr("This confirmation can be disabled in the settings.")) - .icon(QMessageBox::Question) - .button({tr("Restart Mod Organizer"), QMessageBox::Ok}) - .button({tr("Cancel"), QMessageBox::Cancel}) - .exec(); + const auto r = dlg.title(tr("Switching instances")) + .main(tr("Mod Organizer must restart to manage the instance '%1'.") + .arg(to.displayName())) + .content(tr("This confirmation can be disabled in the settings.")) + .icon(QMessageBox::Question) + .button({tr("Restart Mod Organizer"), QMessageBox::Ok}) + .button({tr("Cancel"), QMessageBox::Cancel}) + .exec(); return (r == QMessageBox::Ok); } @@ -394,43 +419,41 @@ void InstanceManagerDialog::rename() auto& m = InstanceManager::singleton(); if (i->isActive()) { - QMessageBox::information(this, - tr("Rename instance"), tr("The active instance cannot be renamed.")); + QMessageBox::information(this, tr("Rename instance"), + tr("The active instance cannot be renamed.")); return; } - // getting new name - const auto newName = getInstanceName( - this, tr("Rename instance"), "", tr("Instance name"), i->displayName()); + const auto newName = getInstanceName(this, tr("Rename instance"), "", + tr("Instance name"), i->displayName()); if (newName.isEmpty()) { return; } - // renaming const QString src = i->directory(); - const QString dest = QDir::toNativeSeparators( - QFileInfo(src).dir().path() + "/" + newName); + const QString dest = + QDir::toNativeSeparators(QFileInfo(src).dir().path() + "/" + newName); log::info("renaming {} to {}", src, dest); const auto r = shell::Rename(QFileInfo(src), QFileInfo(dest), false); if (!r) { - QMessageBox::critical( - this, tr("Error"), - tr("Failed to rename \"%1\" to \"%2\": %3") - .arg(src).arg(dest).arg(r.toString())); + QMessageBox::critical(this, tr("Error"), + tr("Failed to rename \"%1\" to \"%2\": %3") + .arg(src) + .arg(dest) + .arg(r.toString())); return; } - // updating ui auto newInstance = std::make_unique<Instance>(dest, false); - i = newInstance.get(); + i = newInstance.get(); m_model->item(selIndex)->setText(newName); m_instances[selIndex] = std::move(newInstance); @@ -440,28 +463,28 @@ void InstanceManagerDialog::rename() void InstanceManagerDialog::exploreLocation() { - if (const auto* i=singleSelection()) { + if (const auto* i = singleSelection()) { shell::Explore(i->directory()); } } void InstanceManagerDialog::exploreBaseDirectory() { - if (const auto* i=singleSelection()) { + if (const auto* i = singleSelection()) { shell::Explore(i->baseDirectory()); } } void InstanceManagerDialog::exploreGame() { - if (const auto* i=singleSelection()) { + if (const auto* i = singleSelection()) { shell::Explore(i->gameDirectory()); } } void InstanceManagerDialog::openINI() { - if (const auto* i=singleSelection()) { + if (const auto* i = singleSelection()) { shell::Open(i->iniPath()); } } @@ -475,37 +498,34 @@ void InstanceManagerDialog::deleteInstance() auto& m = InstanceManager::singleton(); if (i->isActive()) { - QMessageBox::information(this, - tr("Deleting instance"), tr("The active instance cannot be deleted.")); + QMessageBox::information(this, tr("Deleting instance"), + tr("The active instance cannot be deleted.")); return; } // creating dialog const auto Recycle = QMessageBox::Save; - const auto Delete = QMessageBox::Yes; - const auto Cancel = QMessageBox::Cancel; + const auto Delete = QMessageBox::Yes; + const auto Cancel = QMessageBox::Cancel; const auto files = i->objectsForDeletion(); MOBase::TaskDialog dlg(this); - dlg - .title(tr("Deleting instance")) - .main(tr("These files and folders will be deleted")) - .content(tr("All checked items will be deleted.")) - .icon(QMessageBox::Warning) - .button({tr("Move to the recycle bin"), Recycle}) - .button({tr("Delete permanently"), Delete}) - .button({tr("Cancel"), Cancel}); - + dlg.title(tr("Deleting instance")) + .main(tr("These files and folders will be deleted")) + .content(tr("All checked items will be deleted.")) + .icon(QMessageBox::Warning) + .button({tr("Move to the recycle bin"), Recycle}) + .button({tr("Delete permanently"), Delete}) + .button({tr("Cancel"), Cancel}); auto* list = new QListWidget(); list->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); list->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); list->setMaximumHeight(160); - // filling the list for (const auto& f : files) { auto* item = new QListWidgetItem(f.path); @@ -529,43 +549,37 @@ void InstanceManagerDialog::deleteInstance() dlg.addContent(list); dlg.setWidth(600); - const auto r = dlg.exec(); if (r != Recycle && r != Delete) { return; } - // gathering all the selected items QStringList selected; - for (int i=0; i<list->count(); ++i) { + for (int i = 0; i < list->count(); ++i) { if (list->item(i)->checkState() == Qt::Checked) { selected.append(list->item(i)->text()); } } if (selected.isEmpty()) { - QMessageBox::information( - this, tr("Deleting instance"), tr("Nothing to delete.")); + QMessageBox::information(this, tr("Deleting instance"), tr("Nothing to delete.")); return; } - // deleting if (!doDelete(selected, (r == Recycle))) { return; } - // updating ui updateInstances(); updateList(); } - void InstanceManagerDialog::setRestartOnSelect(bool b) { m_restartOnSelect = b; @@ -640,8 +654,8 @@ void InstanceManagerDialog::createNew() std::size_t InstanceManagerDialog::singleSelectionIndex() const { - const auto sel = m_filter.mapSelectionToSource( - ui->list->selectionModel()->selection()); + const auto sel = + m_filter.mapSelectionToSource(ui->list->selectionModel()->selection()); if (sel.size() != 1) { return NoSelection; diff --git a/src/instancemanagerdialog.h b/src/instancemanagerdialog.h index bb03fd95..884beaa5 100644 --- a/src/instancemanagerdialog.h +++ b/src/instancemanagerdialog.h @@ -1,10 +1,13 @@ #ifndef MODORGANIZER_INSTANCEMANAGERDIALOG_INCLUDED #define MODORGANIZER_INSTANCEMANAGERDIALOG_INCLUDED -#include <filterwidget.h> #include <QDialog> +#include <filterwidget.h> -namespace Ui { class InstanceManagerDialog; }; +namespace Ui +{ +class InstanceManagerDialog; +}; class Instance; class PluginContainer; @@ -16,8 +19,7 @@ class InstanceManagerDialog : public QDialog Q_OBJECT public: - explicit InstanceManagerDialog( - PluginContainer& pc, QWidget *parent = nullptr); + explicit InstanceManagerDialog(PluginContainer& pc, QWidget* parent = nullptr); ~InstanceManagerDialog(); @@ -54,7 +56,6 @@ public: // void exploreGame(); - // converts the selected, portable instance to a global one; not implemented // void convertToGlobal(); @@ -71,13 +72,11 @@ public: // void deleteInstance(); - // sets whether the dialog should restart MO when selecting an instance; this // is false on startup when no instances exist // void setRestartOnSelect(bool b); - // saves geometry // void done(int r) override; @@ -113,7 +112,6 @@ private: // bool confirmSwitch(const Instance& to); - // returns the index of selected instance, NoSelection if none // std::size_t singleSelectionIndex() const; @@ -144,4 +142,4 @@ private: bool doDelete(const QStringList& files, bool recycle); }; -#endif // MODORGANIZER_INSTANCEMANAGERDIALOG_INCLUDED +#endif // MODORGANIZER_INSTANCEMANAGERDIALOG_INCLUDED diff --git a/src/iuserinterface.h b/src/iuserinterface.h index 61e78768..7ddc545d 100644 --- a/src/iuserinterface.h +++ b/src/iuserinterface.h @@ -1,33 +1,32 @@ #ifndef IUSERINTERFACE_H #define IUSERINTERFACE_H - #include "modinfodialogfwd.h" -#include <iplugintool.h> -#include <ipluginmodpage.h> -#include <delayedfilewriter.h> -#include <QMenu> #include <QMainWindow> - +#include <QMenu> +#include <delayedfilewriter.h> +#include <ipluginmodpage.h> +#include <iplugintool.h> class IUserInterface { public: - virtual void registerModPage(MOBase::IPluginModPage *modPage) = 0; + virtual void registerModPage(MOBase::IPluginModPage* modPage) = 0; - virtual void installTranslator(const QString &name) = 0; + virtual void installTranslator(const QString& name) = 0; - virtual bool closeWindow() = 0; + virtual bool closeWindow() = 0; virtual void setWindowEnabled(bool enabled) = 0; - virtual void displayModInformation( - ModInfoPtr modInfo, unsigned int modIndex, ModInfoTabIDs tabID) = 0; + virtual void displayModInformation(ModInfoPtr modInfo, unsigned int modIndex, + ModInfoTabIDs tabID) = 0; - virtual void updateBSAList(const QStringList &defaultArchives, const QStringList &activeArchives) = 0; + virtual void updateBSAList(const QStringList& defaultArchives, + const QStringList& activeArchives) = 0; - virtual MOBase::DelayedFileWriterBase &archivesWriter() = 0; + virtual MOBase::DelayedFileWriterBase& archivesWriter() = 0; virtual QMainWindow* mainWindow() = 0; }; -#endif // IUSERINTERFACE_H +#endif // IUSERINTERFACE_H @@ -1,143 +1,133 @@ #ifndef MODORGANIZER_JSON_INCLUDED #define MODORGANIZER_JSON_INCLUDED -#include <log.h> +#include <QJsonArray> #include <QJsonDocument> #include <QJsonObject> -#include <QJsonArray> #include <QJsonValue> +#include <log.h> namespace json { -class failed {}; - +class failed +{}; namespace details { -QString typeName(const QJsonValue& v) -{ - if (v.isUndefined()) { - return "undefined"; - } else if (v.isNull()) { - return "null"; - } else if (v.isArray()) { - return "an array"; - } else if (v.isBool()) { - return "a bool"; - } else if (v.isDouble()) { - return "a double"; - } else if (v.isObject()) { - return "an object"; - } else if (v.isString()) { - return "a string"; - } else { - return "an unknown type"; + QString typeName(const QJsonValue& v) + { + if (v.isUndefined()) { + return "undefined"; + } else if (v.isNull()) { + return "null"; + } else if (v.isArray()) { + return "an array"; + } else if (v.isBool()) { + return "a bool"; + } else if (v.isDouble()) { + return "a double"; + } else if (v.isObject()) { + return "an object"; + } else if (v.isString()) { + return "a string"; + } else { + return "an unknown type"; + } } -} -QString typeName(const QJsonDocument& doc) -{ - if (doc.isEmpty()) { - return "empty"; - } else if (doc.isNull()) { - return "null"; - } else if (doc.isArray()) { - return "an array"; - } else if (doc.isObject()) { - return "an object"; - } else { - return "an unknown type"; + QString typeName(const QJsonDocument& doc) + { + if (doc.isEmpty()) { + return "empty"; + } else if (doc.isNull()) { + return "null"; + } else if (doc.isArray()) { + return "an array"; + } else if (doc.isObject()) { + return "an object"; + } else { + return "an unknown type"; + } } -} + template <class T> + T convert(const QJsonValue& v) = delete; -template <class T> -T convert(const QJsonValue& v) = delete; + template <> + bool convert<bool>(const QJsonValue& v) + { + if (!v.isBool()) { + throw failed(); + } -template <> -bool convert<bool>(const QJsonValue& v) -{ - if (!v.isBool()) { - throw failed(); + return v.toBool(); } - return v.toBool(); -} + template <> + QJsonObject convert<QJsonObject>(const QJsonValue& v) + { + if (!v.isObject()) { + throw failed(); + } -template <> -QJsonObject convert<QJsonObject>(const QJsonValue& v) -{ - if (!v.isObject()) { - throw failed(); + return v.toObject(); } - return v.toObject(); -} + template <> + QString convert<QString>(const QJsonValue& v) + { + if (!v.isString()) { + throw failed(); + } -template <> -QString convert<QString>(const QJsonValue& v) -{ - if (!v.isString()) { - throw failed(); + return v.toString(); } - return v.toString(); -} + template <> + QJsonArray convert<QJsonArray>(const QJsonValue& v) + { + if (!v.isArray()) { + throw failed(); + } -template <> -QJsonArray convert<QJsonArray>(const QJsonValue& v) -{ - if (!v.isArray()) { - throw failed(); + return v.toArray(); } - return v.toArray(); -} + template <> + qint64 convert<qint64>(const QJsonValue& v) + { + if (!v.isDouble()) { + throw failed(); + } -template <> -qint64 convert<qint64>(const QJsonValue& v) -{ - if (!v.isDouble()) { - throw failed(); + return static_cast<qint64>(v.toDouble()); } - return static_cast<qint64>(v.toDouble()); -} - -} // namespace - +} // namespace details template <class T> T convert(const QJsonValue& value, const char* what) { - try - { + try { return details::convert<T>(value); - } - catch(failed&) - { - MOBase::log::error( - "'{}' is a {}, not a {}", - what, details::typeName(value), typeid(T).name); + } catch (failed&) { + MOBase::log::error("'{}' is a {}, not a {}", what, details::typeName(value), + typeid(T).name); throw; } } template <class T> -T convertWarn(const QJsonValue& value, const char* what, T def={}) +T convertWarn(const QJsonValue& value, const char* what, T def = {}) { - try - { + try { return details::convert<T>(value); - } - catch(failed&) - { - MOBase::log::warn( - "'{}' is a {}, not a {}", - what, details::typeName(value), typeid(T).name()); + } catch (failed&) { + MOBase::log::warn("'{}' is a {}, not a {}", what, details::typeName(value), + typeid(T).name()); return def; } @@ -155,7 +145,7 @@ T get(const QJsonObject& o, const char* e) } template <class T> -T getWarn(const QJsonObject& o, const char* e, T def={}) +T getWarn(const QJsonObject& o, const char* e, T def = {}) { if (!o.contains(e)) { MOBase::log::warn("property '{}' is missing", e); @@ -166,7 +156,7 @@ T getWarn(const QJsonObject& o, const char* e, T def={}) } template <class T> -T getOpt(const QJsonObject& o, const char* e, T def={}) +T getOpt(const QJsonObject& o, const char* e, T def = {}) { if (!o.contains(e)) { return def; @@ -175,7 +165,6 @@ T getOpt(const QJsonObject& o, const char* e, T def={}) return convertWarn<T>(o[e], e); } - template <class Value> void requireObject(const Value& v, const char* what) { @@ -185,6 +174,6 @@ void requireObject(const Value& v, const char* what) } } -} // namespace +} // namespace json -#endif // MODORGANIZER_JSON_INCLUDED +#endif // MODORGANIZER_JSON_INCLUDED diff --git a/src/lcdnumber.cpp b/src/lcdnumber.cpp index 3191b434..c8e17608 100644 --- a/src/lcdnumber.cpp +++ b/src/lcdnumber.cpp @@ -17,15 +17,12 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "lcdnumber.h" -#include <QToolTip> #include <QTimer> +#include <QToolTip> -LCDNumber::LCDNumber(QWidget *parent) - : QLCDNumber(parent) -{ -} +LCDNumber::LCDNumber(QWidget* parent) : QLCDNumber(parent) {} -void LCDNumber::mousePressEvent(QMouseEvent *event) +void LCDNumber::mousePressEvent(QMouseEvent* event) { m_toolTipPosition = mapToGlobal(event->pos()); QTimer::singleShot(100, this, SLOT(showToolTip())); diff --git a/src/lcdnumber.h b/src/lcdnumber.h index 2f8e0454..75f4124a 100644 --- a/src/lcdnumber.h +++ b/src/lcdnumber.h @@ -24,8 +24,8 @@ class LCDNumber : public QLCDNumber Q_OBJECT public: - LCDNumber(QWidget *parent = nullptr); - void mousePressEvent(QMouseEvent *event); + LCDNumber(QWidget* parent = nullptr); + void mousePressEvent(QMouseEvent* event); public slots: void showToolTip(); diff --git a/src/listdialog.cpp b/src/listdialog.cpp index 9334186a..09e37602 100644 --- a/src/listdialog.cpp +++ b/src/listdialog.cpp @@ -16,13 +16,11 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ #include "listdialog.h" -#include "ui_listdialog.h" #include "settings.h" +#include "ui_listdialog.h" -ListDialog::ListDialog(QWidget *parent) - : QDialog(parent) - , ui(new Ui::ListDialog) - , m_Choices() +ListDialog::ListDialog(QWidget* parent) + : QDialog(parent), ui(new Ui::ListDialog), m_Choices() { ui->setupUi(this); ui->filterEdit->setFocus(); @@ -60,7 +58,7 @@ void ListDialog::on_filterEdit_textChanged(QString filter) { QStringList newChoices; for (auto choice : m_Choices) { - if (choice.contains(filter, Qt::CaseInsensitive)){ + if (choice.contains(filter, Qt::CaseInsensitive)) { newChoices << choice; } } @@ -68,7 +66,7 @@ void ListDialog::on_filterEdit_textChanged(QString filter) ui->choiceList->addItems(newChoices); if (newChoices.length() == 1) { - QListWidgetItem *item = ui->choiceList->item(0); + QListWidgetItem* item = ui->choiceList->item(0); item->setSelected(true); ui->choiceList->setCurrentItem(item); } @@ -79,4 +77,3 @@ void ListDialog::on_filterEdit_textChanged(QString filter) ui->choiceList->setStyleSheet(""); } } - diff --git a/src/listdialog.h b/src/listdialog.h index d0594bd7..2e33742b 100644 --- a/src/listdialog.h +++ b/src/listdialog.h @@ -3,7 +3,8 @@ #include <QDialog> -namespace Ui { +namespace Ui +{ class ListDialog; } @@ -12,7 +13,7 @@ class ListDialog : public QDialog Q_OBJECT public: - explicit ListDialog(QWidget *parent = nullptr); + explicit ListDialog(QWidget* parent = nullptr); ~ListDialog(); // also saves and restores geometry @@ -26,8 +27,8 @@ public slots: void on_filterEdit_textChanged(QString filter); private: - Ui::ListDialog *ui; + Ui::ListDialog* ui; QStringList m_Choices; }; -#endif // LISTDIALOG_H +#endif // LISTDIALOG_H diff --git a/src/loghighlighter.cpp b/src/loghighlighter.cpp index ef83cd58..c230c75f 100644 --- a/src/loghighlighter.cpp +++ b/src/loghighlighter.cpp @@ -19,13 +19,9 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "loghighlighter.h" -LogHighlighter::LogHighlighter(QObject *parent) : - QSyntaxHighlighter(parent) -{ -} - +LogHighlighter::LogHighlighter(QObject* parent) : QSyntaxHighlighter(parent) {} -void LogHighlighter::highlightBlock(const QString &text) +void LogHighlighter::highlightBlock(const QString& text) { int spacePos = text.indexOf(" "); if (spacePos != -1) { diff --git a/src/loghighlighter.h b/src/loghighlighter.h index 95ea6f2f..893f036d 100644 --- a/src/loghighlighter.h +++ b/src/loghighlighter.h @@ -28,18 +28,16 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. **/ class LogHighlighter : public QSyntaxHighlighter { - Q_OBJECT + Q_OBJECT public: - explicit LogHighlighter(QObject *parent = 0); + explicit LogHighlighter(QObject* parent = 0); signals: public slots: protected: - - virtual void highlightBlock(const QString &text); - + virtual void highlightBlock(const QString& text); }; -#endif // LOGHIGHLIGHTER_H +#endif // LOGHIGHLIGHTER_H diff --git a/src/loglist.cpp b/src/loglist.cpp index 587cf223..345e0c6b 100644 --- a/src/loglist.cpp +++ b/src/loglist.cpp @@ -18,23 +18,20 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ #include "loglist.h" -#include "organizercore.h" #include "copyeventfilter.h" #include "env.h" +#include "organizercore.h" using namespace MOBase; static LogModel* g_instance = nullptr; -const std::size_t MaxLines = 1000; +const std::size_t MaxLines = 1000; static std::unique_ptr<env::Console> m_console; static bool m_stdout = false; static std::mutex m_stdoutMutex; - -LogModel::LogModel() -{ -} +LogModel::LogModel() {} void LogModel::create() { @@ -49,7 +46,11 @@ LogModel& LogModel::instance() void LogModel::add(MOBase::log::Entry e) { QMetaObject::invokeMethod( - this, [this, e]{ onEntryAdded(std::move(e)); }, Qt::QueuedConnection); + this, + [this, e] { + onEntryAdded(std::move(e)); + }, + Qt::QueuedConnection); } QString LogModel::formattedMessage(const QModelIndex& index) const @@ -91,9 +92,7 @@ void LogModel::onEntryAdded(MOBase::log::Entry e) if (!full) { endInsertRows(); } else { - emit dataChanged( - createIndex(row, 0), - createIndex(row + 1, columnCount({}))); + emit dataChanged(createIndex(row, 0), createIndex(row + 1, columnCount({}))); } } @@ -134,10 +133,10 @@ QVariant LogModel::data(const QModelIndex& index, int role) const if (role == Qt::DisplayRole) { if (index.column() == 0) { const auto ms = duration_cast<milliseconds>(e.time.time_since_epoch()); - const auto s = duration_cast<seconds>(ms); + const auto s = duration_cast<seconds>(ms); const std::time_t tt = s.count(); - const int frac = static_cast<int>(ms.count() % 1000); + const int frac = static_cast<int>(ms.count() % 1000); const auto time = QDateTime::fromSecsSinceEpoch(tt).time().addMSecs(frac); return time.toString("hh:mm:ss.zzz"); @@ -149,18 +148,18 @@ QVariant LogModel::data(const QModelIndex& index, int role) const if (role == Qt::DecorationRole) { if (index.column() == 1) { switch (e.level) { - case log::Warning: - return QIcon(":/MO/gui/warning"); + case log::Warning: + return QIcon(":/MO/gui/warning"); - case log::Error: - return QIcon(":/MO/gui/problem"); + case log::Error: + return QIcon(":/MO/gui/problem"); - case log::Debug: - return QIcon(":/MO/gui/debug"); - case log::Info: - return QIcon(":/MO/gui/information"); - default: - return {}; + case log::Debug: + return QIcon(":/MO/gui/debug"); + case log::Info: + return QIcon(":/MO/gui/information"); + default: + return {}; } } } @@ -173,11 +172,10 @@ QVariant LogModel::headerData(int, Qt::Orientation, int) const return {}; } - LogList::LogList(QWidget* parent) - : QTreeView(parent), - m_core(nullptr), - m_copyFilter(this, [=](auto&& index) { return LogModel::instance().formattedMessage(index); }) + : QTreeView(parent), m_core(nullptr), m_copyFilter(this, [=](auto&& index) { + return LogModel::instance().formattedMessage(index); + }) { setModel(&LogModel::instance()); @@ -188,15 +186,21 @@ LogList::LogList(QWidget* parent) setAutoScroll(true); scrollToBottom(); - connect( - this, &QWidget::customContextMenuRequested, - [&](auto&& pos){ onContextMenu(pos); }); + connect(this, &QWidget::customContextMenuRequested, [&](auto&& pos) { + onContextMenu(pos); + }); - connect(model(), &LogModel::rowsInserted, this, [&]{ onNewEntry(); }); - connect(model(), &LogModel::dataChanged, this, [&]{ onNewEntry(); }); + connect(model(), &LogModel::rowsInserted, this, [&] { + onNewEntry(); + }); + connect(model(), &LogModel::dataChanged, this, [&] { + onNewEntry(); + }); m_timer.setSingleShot(true); - connect(&m_timer, &QTimer::timeout, [&]{ scrollToBottom(); }); + connect(&m_timer, &QTimer::timeout, [&] { + scrollToBottom(); + }); installEventFilter(&m_copyFilter); } @@ -234,7 +238,8 @@ void LogList::clear() void LogList::openLogsFolder() { - QString logsPath = qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath()); + QString logsPath = qApp->property("dataPath").toString() + "/" + + QString::fromStdWString(AppConfig::logPath()); shell::Explore(logsPath); } @@ -242,11 +247,19 @@ QMenu* LogList::createMenu(QWidget* parent) { auto* menu = new QMenu(parent); - menu->addAction(tr("Copy"), [&]{ m_copyFilter.copySelection(); }); - menu->addAction(tr("&Copy all"), [&]{ copyToClipboard(); }); + menu->addAction(tr("Copy"), [&] { + m_copyFilter.copySelection(); + }); + menu->addAction(tr("&Copy all"), [&] { + copyToClipboard(); + }); menu->addSeparator(); - menu->addAction(tr("C&lear all"), [&]{ clear(); }); - menu->addAction(tr("&Open logs folder"), [&]{ openLogsFolder(); }); + menu->addAction(tr("C&lear all"), [&] { + clear(); + }); + menu->addAction(tr("&Open logs folder"), [&] { + openLogsFolder(); + }); auto* levels = new QMenu(tr("&Level")); menu->addMenu(levels); @@ -259,7 +272,7 @@ QMenu* LogList::createMenu(QWidget* parent) a->setCheckable(true); a->setChecked(log::getDefault().level() == level); - connect(a, &QAction::triggered, [this, level]{ + connect(a, &QAction::triggered, [this, level] { if (m_core) { m_core->setLogLevel(level); } @@ -282,29 +295,27 @@ void LogList::onContextMenu(const QPoint& pos) menu->popup(viewport()->mapToGlobal(pos)); } - log::Levels convertQtLevel(QtMsgType t) { - switch (t) - { - case QtDebugMsg: - return log::Debug; + switch (t) { + case QtDebugMsg: + return log::Debug; - case QtWarningMsg: - return log::Warning; + case QtWarningMsg: + return log::Warning; - case QtCriticalMsg: // fall-through - case QtFatalMsg: - return log::Error; + case QtCriticalMsg: // fall-through + case QtFatalMsg: + return log::Error; - case QtInfoMsg: // fall-through - default: - return log::Info; + case QtInfoMsg: // fall-through + default: + return log::Info; } } -void qtLogCallback( - QtMsgType type, const QMessageLogContext& context, const QString& message) +void qtLogCallback(QtMsgType type, const QMessageLogContext& context, + const QString& message) { std::string_view file = ""; @@ -320,13 +331,10 @@ void qtLogCallback( } if (file.empty()) { - log::log( - convertQtLevel(type), "{}", - message.toStdString()); + log::log(convertQtLevel(type), "{}", message.toStdString()); } else { - log::log( - convertQtLevel(type), "[{}:{}] {}", - file, context.line, message.toStdString()); + log::log(convertQtLevel(type), "[{}:{}] {}", file, context.line, + message.toStdString()); } } @@ -351,29 +359,32 @@ void initLogging() log::LoggerConfiguration conf; conf.maxLevel = MOBase::log::Debug; - conf.pattern = "%^[%Y-%m-%d %H:%M:%S.%e %L] %v%$"; - conf.utc = true; + conf.pattern = "%^[%Y-%m-%d %H:%M:%S.%e %L] %v%$"; + conf.utc = true; log::createDefault(conf); - log::getDefault().setCallback( - [](log::Entry e){ LogModel::instance().add(e); }); + log::getDefault().setCallback([](log::Entry e) { + LogModel::instance().add(e); + }); - log::getDefault().addToBlacklist(std::string("\\") + getenv("USERNAME"), "\\USERNAME"); + log::getDefault().addToBlacklist(std::string("\\") + getenv("USERNAME"), + "\\USERNAME"); log::getDefault().addToBlacklist(std::string("/") + getenv("USERNAME"), "/USERNAME"); qInstallMessageHandler(qtLogCallback); } -bool createAndMakeWritable(const std::wstring &subPath) { +bool createAndMakeWritable(const std::wstring& subPath) +{ QString const dataPath = qApp->property("dataPath").toString(); - QString fullPath = dataPath + "/" + QString::fromStdWString(subPath); + QString fullPath = dataPath + "/" + QString::fromStdWString(subPath); if (!QDir(fullPath).exists() && !QDir().mkdir(fullPath)) { QMessageBox::critical(nullptr, QObject::tr("Error"), - QObject::tr("Failed to create \"%1\". Your user " - "account probably lacks permission.") - .arg(fullPath)); + QObject::tr("Failed to create \"%1\". Your user " + "account probably lacks permission.") + .arg(fullPath)); return false; } else { return true; @@ -382,10 +393,8 @@ bool createAndMakeWritable(const std::wstring &subPath) { bool setLogDirectory(const QString& dir) { - const auto logFile = - dir + "/" + - QString::fromStdWString(AppConfig::logPath()) + "/" + - QString::fromStdWString(AppConfig::logFileName()); + const auto logFile = dir + "/" + QString::fromStdWString(AppConfig::logPath()) + "/" + + QString::fromStdWString(AppConfig::logFileName()); if (!createAndMakeWritable(AppConfig::logPath())) { return false; diff --git a/src/loglist.h b/src/loglist.h index ddf5f49c..58f4d1c7 100644 --- a/src/loglist.h +++ b/src/loglist.h @@ -20,12 +20,11 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef LOGBUFFER_H #define LOGBUFFER_H - -#include "shared/appconfig.h" #include "copyeventfilter.h" -#include <log.h> +#include "shared/appconfig.h" #include <QTreeView> #include <deque> +#include <log.h> class OrganizerCore; @@ -46,13 +45,13 @@ public: protected: QModelIndex index(int row, int column, const QModelIndex& parent) const override; - QModelIndex parent(const QModelIndex &child) const override; - int rowCount(const QModelIndex &parent) const override; - int columnCount(const QModelIndex &parent) const override; - QVariant data(const QModelIndex &index, int role) const override; + QModelIndex parent(const QModelIndex& child) const override; + int rowCount(const QModelIndex& parent) const override; + int columnCount(const QModelIndex& parent) const override; + QVariant data(const QModelIndex& index, int role) const override; - QVariant headerData( - int section, Qt::Orientation ori, int role=Qt::DisplayRole) const override; + QVariant headerData(int section, Qt::Orientation ori, + int role = Qt::DisplayRole) const override; private: std::deque<MOBase::log::Entry> m_entries; @@ -61,13 +60,12 @@ private: void onEntryAdded(MOBase::log::Entry e); }; - class LogList : public QTreeView { Q_OBJECT; public: - LogList(QWidget* parent=nullptr); + LogList(QWidget* parent = nullptr); void setCore(OrganizerCore& core); @@ -75,7 +73,7 @@ public: void clear(); void openLogsFolder(); - QMenu* createMenu(QWidget* parent=nullptr); + QMenu* createMenu(QWidget* parent = nullptr); private: OrganizerCore* m_core; @@ -86,9 +84,8 @@ private: void onNewEntry(); }; - void logToStdout(bool b); void initLogging(); bool setLogDirectory(const QString& dir); -#endif // LOGBUFFER_H +#endif // LOGBUFFER_H diff --git a/src/loot.cpp b/src/loot.cpp index 9c9ab2ae..5ff56987 100644 --- a/src/loot.cpp +++ b/src/loot.cpp @@ -1,23 +1,21 @@ #include "loot.h" +#include "json.h" #include "lootdialog.h" -#include "spawn.h" #include "organizercore.h" -#include "json.h" +#include "spawn.h" #include <log.h> #include <report.h> using namespace MOBase; using namespace json; -static QString LootReportPath = QDir::temp().absoluteFilePath("lootreport.json"); +static QString LootReportPath = QDir::temp().absoluteFilePath("lootreport.json"); static const DWORD PipeTimeout = 500; - class AsyncPipe { public: - AsyncPipe() - : m_ioPending(false) + AsyncPipe() : m_ioPending(false) { std::fill(std::begin(m_buffer), std::end(m_buffer), 0); std::memset(&m_ov, 0, sizeof(m_ov)); @@ -68,17 +66,17 @@ private: static const wchar_t* PipeName = L"\\\\.\\pipe\\lootcli_pipe"; SECURITY_ATTRIBUTES sa = {}; - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.bInheritHandle = TRUE; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = TRUE; env::HandlePtr pipe; // creating pipe { - HANDLE pipeHandle = ::CreateNamedPipe( - PipeName, PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, - PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_WAIT, - 1, 50'000, 50'000, PipeTimeout, &sa); + HANDLE pipeHandle = + ::CreateNamedPipe(PipeName, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 50'000, + 50'000, PipeTimeout, &sa); if (pipeHandle == INVALID_HANDLE_VALUE) { const auto e = GetLastError(); @@ -93,9 +91,9 @@ private: // duplicating the handle to read from it HANDLE outputRead = INVALID_HANDLE_VALUE; - const auto r = DuplicateHandle( - GetCurrentProcess(), pipe.get(), GetCurrentProcess(), &outputRead, - 0, TRUE, DUPLICATE_SAME_ACCESS); + const auto r = + DuplicateHandle(GetCurrentProcess(), pipe.get(), GetCurrentProcess(), + &outputRead, 0, TRUE, DUPLICATE_SAME_ACCESS); if (!r) { const auto e = GetLastError(); @@ -106,11 +104,9 @@ private: m_stdout.reset(outputRead); } - // creating handle to pipe which is passed to CreateProcess() - HANDLE outputWrite = ::CreateFileW( - PipeName, FILE_WRITE_DATA|SYNCHRONIZE, 0, - &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + HANDLE outputWrite = ::CreateFileW(PipeName, FILE_WRITE_DATA | SYNCHRONIZE, 0, &sa, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (outputWrite == INVALID_HANDLE_VALUE) { const auto e = GetLastError(); @@ -128,25 +124,21 @@ private: if (!::ReadFile(m_stdout.get(), m_buffer, bufferSize, &bytesRead, &m_ov)) { const auto e = GetLastError(); - switch (e) - { - case ERROR_IO_PENDING: - { - m_ioPending = true; - break; - } + switch (e) { + case ERROR_IO_PENDING: { + m_ioPending = true; + break; + } - case ERROR_BROKEN_PIPE: - { - // broken pipe probably means lootcli is finished - break; - } + case ERROR_BROKEN_PIPE: { + // broken pipe probably means lootcli is finished + break; + } - default: - { - log::error("{}", formatSystemMessage(e)); - break; - } + default: { + log::error("{}", formatSystemMessage(e)); + break; + } } return {}; @@ -170,29 +162,24 @@ private: if (!::GetOverlappedResult(m_stdout.get(), &m_ov, &bytesRead, FALSE)) { const auto e = GetLastError(); - switch (e) - { - case ERROR_IO_INCOMPLETE: - { - break; - } + switch (e) { + case ERROR_IO_INCOMPLETE: { + break; + } - case WAIT_TIMEOUT: - { - break; - } + case WAIT_TIMEOUT: { + break; + } - case ERROR_BROKEN_PIPE: - { - // broken pipe probably means lootcli is finished - break; - } + case ERROR_BROKEN_PIPE: { + // broken pipe probably means lootcli is finished + break; + } - default: - { - log::error("GetOverlappedResult failed, {}", formatSystemMessage(e)); - break; - } + default: { + log::error("GetOverlappedResult failed, {}", formatSystemMessage(e)); + break; + } } return {}; @@ -205,29 +192,26 @@ private: } }; - - log::Levels levelFromLoot(lootcli::LogLevels level) { using LC = lootcli::LogLevels; - switch (level) - { - case LC::Trace: // fall-through - case LC::Debug: - return log::Debug; + switch (level) { + case LC::Trace: // fall-through + case LC::Debug: + return log::Debug; - case LC::Info: - return log::Info; + case LC::Info: + return log::Info; - case LC::Warning: - return log::Warning; + case LC::Warning: + return log::Warning; - case LC::Error: - return log::Error; + case LC::Error: + return log::Error; - default: - return log::Info; + default: + return log::Info; } } @@ -318,9 +302,9 @@ QString Loot::Report::errorsMarkdown() const QString Loot::Stats::toMarkdown() const { return QString("`stats: %1s, lootcli %2, loot %3`") - .arg(QString::number(time / 1000.0, 'f', 2)) - .arg(lootcliVersion) - .arg(lootVersion); + .arg(QString::number(time / 1000.0, 'f', 2)) + .arg(lootcliVersion) + .arg(lootVersion); } QString Loot::Plugin::toMarkdown() const @@ -376,7 +360,7 @@ QString Loot::Dirty::toString(bool isClean) const { if (isClean) { return QObject::tr("Verified clean by %1") - .arg(cleaningUtility.isEmpty() ? "?" : cleaningUtility); + .arg(cleaningUtility.isEmpty() ? "?" : cleaningUtility); } QString s = cleaningString(); @@ -395,35 +379,32 @@ QString Loot::Dirty::toMarkdown(bool isClean) const QString Loot::Dirty::cleaningString() const { - return QObject::tr("%1 found %2 ITM record(s), %3 deleted reference(s) and %4 deleted navmesh(es).") - .arg(cleaningUtility.isEmpty() ? "?" : cleaningUtility) - .arg(itm) - .arg(deletedReferences) - .arg(deletedNavmesh); + return QObject::tr("%1 found %2 ITM record(s), %3 deleted reference(s) and %4 " + "deleted navmesh(es).") + .arg(cleaningUtility.isEmpty() ? "?" : cleaningUtility) + .arg(itm) + .arg(deletedReferences) + .arg(deletedNavmesh); } QString Loot::Message::toMarkdown() const { QString s; - switch (type) - { - case log::Error: - { - s += "**" + QObject::tr("Error") + "**: "; - break; - } + switch (type) { + case log::Error: { + s += "**" + QObject::tr("Error") + "**: "; + break; + } - case log::Warning: - { - s += "**" + QObject::tr("Warning") + "**: "; - break; - } + case log::Warning: { + s += "**" + QObject::tr("Warning") + "**: "; + break; + } - default: - { - break; - } + default: { + break; + } } s += text; @@ -431,11 +412,9 @@ QString Loot::Message::toMarkdown() const return s; } - Loot::Loot(OrganizerCore& core) - : m_core(core), m_thread(nullptr), m_cancel(false), m_result(false) -{ -} + : m_core(core), m_thread(nullptr), m_cancel(false), m_result(false) +{} Loot::~Loot() { @@ -469,43 +448,42 @@ bool Loot::start(QWidget* parent, bool didUpdateMasterList) // starting thread log::debug("starting loot thread"); - m_thread.reset(QThread::create([&]{ lootThread(); })); + m_thread.reset(QThread::create([&] { + lootThread(); + })); m_thread->start(); return true; } -bool Loot::spawnLootcli( - QWidget* parent, bool didUpdateMasterList, env::HandlePtr stdoutHandle) +bool Loot::spawnLootcli(QWidget* parent, bool didUpdateMasterList, + env::HandlePtr stdoutHandle) { const auto logLevel = m_core.settings().diagnostics().lootLogLevel(); QStringList parameters; - parameters - << "--game" - << m_core.managedGame()->gameShortName() + parameters << "--game" << m_core.managedGame()->gameShortName() - << "--gamePath" - << QString("\"%1\"").arg(m_core.managedGame()->gameDirectory().absolutePath()) + << "--gamePath" + << QString("\"%1\"").arg( + m_core.managedGame()->gameDirectory().absolutePath()) - << "--pluginListPath" - << QString("\"%1/loadorder.txt\"").arg(m_core.profilePath()) + << "--pluginListPath" + << QString("\"%1/loadorder.txt\"").arg(m_core.profilePath()) - << "--logLevel" - << QString::fromStdString(lootcli::logLevelToString(logLevel)) + << "--logLevel" + << QString::fromStdString(lootcli::logLevelToString(logLevel)) - << "--out" - << QString("\"%1\"").arg(LootReportPath) + << "--out" << QString("\"%1\"").arg(LootReportPath) - << "--language" - << m_core.settings().interface().language(); + << "--language" << m_core.settings().interface().language(); if (didUpdateMasterList) { parameters << "--skipUpdateMasterlist"; } spawn::SpawnParameters sp; - sp.binary = QFileInfo(qApp->applicationDirPath() + "/loot/lootcli.exe"); + sp.binary = QFileInfo(qApp->applicationDirPath() + "/loot/lootcli.exe"); sp.arguments = parameters.join(" "); sp.currentDirectory.setPath(qApp->applicationDirPath() + "/loot"); sp.hooked = true; @@ -558,8 +536,7 @@ const std::vector<QString>& Loot::warnings() const void Loot::lootThread() { - try - { + try { m_result = false; if (waitForCompletion()) { @@ -567,9 +544,7 @@ void Loot::lootThread() } m_report = createReport(); - } - catch(...) - { + } catch (...) { log::error("unhandled exception in loot thread"); } @@ -577,7 +552,6 @@ void Loot::lootThread() emit finished(); } - bool Loot::waitForCompletion() { bool terminating = false; @@ -629,14 +603,15 @@ bool Loot::waitForCompletion() } if (exitCode != 0UL) { - emit log(log::Levels::Error, tr("Loot failed. Exit code was: 0x%1").arg(exitCode, 0, 16)); + emit log(log::Levels::Error, + tr("Loot failed. Exit code was: 0x%1").arg(exitCode, 0, 16)); return false; } return true; } -void Loot::processStdout(const std::string &lootOut) +void Loot::processStdout(const std::string& lootOut) { emit output(QString::fromStdString(lootOut)); @@ -671,27 +646,24 @@ void Loot::processStdout(const std::string &lootOut) void Loot::processMessage(const lootcli::Message& m) { - switch (m.type) - { - case lootcli::MessageType::Log: - { - const auto level = levelFromLoot(m.logLevel); - - if (level == log::Error) { - m_errors.push_back(QString::fromStdString(m.log)); - } else if (level == log::Warning) { - m_warnings.push_back(QString::fromStdString(m.log)); - } + switch (m.type) { + case lootcli::MessageType::Log: { + const auto level = levelFromLoot(m.logLevel); - emit log(level, QString::fromStdString(m.log)); - break; + if (level == log::Error) { + m_errors.push_back(QString::fromStdString(m.log)); + } else if (level == log::Warning) { + m_warnings.push_back(QString::fromStdString(m.log)); } - case lootcli::MessageType::Progress: - { - emit progress(m.progress); - break; - } + emit log(level, QString::fromStdString(m.log)); + break; + } + + case lootcli::MessageType::Progress: { + emit progress(m.progress); + break; + } } } @@ -699,8 +671,8 @@ Loot::Report Loot::createReport() const { Report r; - r.okay = m_result; - r.errors = m_errors; + r.okay = m_result; + r.errors = m_errors; r.warnings = m_warnings; if (m_result) { @@ -717,9 +689,8 @@ void Loot::deleteReportFile() const auto r = shell::Delete(QFileInfo(LootReportPath)); if (!r) { - log::error( - "failed to remove temporary loot json report '{}': {}", - LootReportPath, r.toString()); + log::error("failed to remove temporary loot json report '{}': {}", LootReportPath, + r.toString()); } } } @@ -730,10 +701,9 @@ void Loot::processOutputFile(Report& r) const QFile outFile(LootReportPath); if (!outFile.open(QIODevice::ReadOnly)) { - emit log( - MOBase::log::Error, - QString("failed to open file, %1 (error %2)") - .arg(outFile.errorString()).arg(outFile.error())); + emit log(MOBase::log::Error, QString("failed to open file, %1 (error %2)") + .arg(outFile.errorString()) + .arg(outFile.error())); return; } @@ -741,10 +711,8 @@ void Loot::processOutputFile(Report& r) const QJsonParseError e; const QJsonDocument doc = QJsonDocument::fromJson(outFile.readAll(), &e); if (doc.isNull()) { - emit log( - MOBase::log::Error, - QString("invalid json, %1 (error %2)") - .arg(e.errorString()).arg(e.error)); + emit log(MOBase::log::Error, + QString("invalid json, %1 (error %2)").arg(e.errorString()).arg(e.error)); return; } @@ -754,8 +722,8 @@ void Loot::processOutputFile(Report& r) const const QJsonObject object = doc.object(); r.messages = reportMessages(getOpt<QJsonArray>(object, "messages")); - r.plugins = reportPlugins(getOpt<QJsonArray>(object, "plugins")); - r.stats = reportStats(getWarn<QJsonObject>(object, "stats")); + r.plugins = reportPlugins(getOpt<QJsonArray>(object, "plugins")); + r.stats = reportStats(getWarn<QJsonObject>(object, "stats")); } std::vector<Loot::Plugin> Loot::reportPlugins(const QJsonArray& plugins) const @@ -812,8 +780,8 @@ Loot::Plugin Loot::reportPlugin(const QJsonObject& plugin) const p.missingMasters = reportStringArray(getOpt<QJsonArray>(plugin, "missingMasters")); } - p.loadsArchive = getOpt(plugin, "loadsArchive", false); - p.isMaster = getOpt(plugin, "isMaster", false); + p.loadsArchive = getOpt(plugin, "loadsArchive", false); + p.isMaster = getOpt(plugin, "isMaster", false); p.isLightMaster = getOpt(plugin, "isLightMaster", false); return p; @@ -823,9 +791,9 @@ Loot::Stats Loot::reportStats(const QJsonObject& stats) const { Stats s; - s.time = getWarn<qint64>(stats, "time"); + s.time = getWarn<qint64>(stats, "time"); s.lootcliVersion = getWarn<QString>(stats, "lootcliVersion"); - s.lootVersion = getWarn<QString>(stats, "lootVersion"); + s.lootVersion = getWarn<QString>(stats, "lootVersion"); return s; } @@ -877,7 +845,7 @@ std::vector<Loot::File> Loot::reportFiles(const QJsonArray& array) const File f; - f.name = getWarn<QString>(o, "name"); + f.name = getWarn<QString>(o, "name"); f.displayName = getOpt<QString>(o, "displayName"); if (!f.name.isEmpty()) { @@ -897,12 +865,12 @@ std::vector<Loot::Dirty> Loot::reportDirty(const QJsonArray& array) const Dirty d; - d.crc = getWarn<qint64>(o, "crc"); - d.itm = getOpt<qint64>(o, "itm"); + d.crc = getWarn<qint64>(o, "crc"); + d.itm = getOpt<qint64>(o, "itm"); d.deletedReferences = getOpt<qint64>(o, "deletedReferences"); - d.deletedNavmesh = getOpt<qint64>(o, "deletedNavmesh"); - d.cleaningUtility = getOpt<QString>(o, "cleaningUtility"); - d.info = getOpt<QString>(o, "info"); + d.deletedNavmesh = getOpt<qint64>(o, "deletedNavmesh"); + d.cleaningUtility = getOpt<QString>(o, "cleaningUtility"); + d.info = getOpt<QString>(o, "info"); v.emplace_back(std::move(d)); } @@ -926,7 +894,6 @@ std::vector<QString> Loot::reportStringArray(const QJsonArray& array) const return v; } - bool runLoot(QWidget* parent, OrganizerCore& core, bool didUpdateMasterList) { core.savePluginList(); @@ -942,10 +909,10 @@ bool runLoot(QWidget* parent, OrganizerCore& core, bool didUpdateMasterList) dialog.exec(); return dialog.result(); - } catch (const UsvfsConnectorException &e) { + } catch (const UsvfsConnectorException& e) { log::debug("{}", e.what()); return false; - } catch (const std::exception &e) { + } catch (const std::exception& e) { reportError(QObject::tr("failed to run loot: %1").arg(e.what())); return false; } @@ -2,10 +2,10 @@ #define MODORGANIZER_LOOT_H #include "envmodule.h" +#include <QWidget> #include <log.h> #include <lootcli/lootcli.h> #include <windows.h> -#include <QWidget> Q_DECLARE_METATYPE(lootcli::Progress); Q_DECLARE_METATYPE(MOBase::log::Levels); @@ -34,10 +34,10 @@ public: struct Dirty { - qint64 crc=0; - qint64 itm=0; - qint64 deletedReferences=0; - qint64 deletedNavmesh=0; + qint64 crc = 0; + qint64 itm = 0; + qint64 deletedReferences = 0; + qint64 deletedNavmesh = 0; QString cleaningUtility; QString info; @@ -53,8 +53,8 @@ public: std::vector<Message> messages; std::vector<Dirty> dirty, clean; std::vector<QString> missingMasters; - bool loadsArchive = false; - bool isMaster = false; + bool loadsArchive = false; + bool isMaster = false; bool isLightMaster = false; QString toMarkdown() const; @@ -84,7 +84,6 @@ public: QString errorsMarkdown() const; }; - Loot(OrganizerCore& core); ~Loot(); @@ -114,13 +113,13 @@ private: std::vector<QString> m_errors, m_warnings; Report m_report; - bool spawnLootcli( - QWidget* parent, bool didUpdateMasterList, env::HandlePtr stdoutHandle); + bool spawnLootcli(QWidget* parent, bool didUpdateMasterList, + env::HandlePtr stdoutHandle); void lootThread(); bool waitForCompletion(); - void processStdout(const std::string &lootOut); + void processStdout(const std::string& lootOut); void processMessage(const lootcli::Message& m); Report createReport() const; @@ -138,7 +137,6 @@ private: std::vector<QString> reportStringArray(const QJsonArray& array) const; }; - bool runLoot(QWidget* parent, OrganizerCore& core, bool didUpdateMasterList); -#endif // MODORGANIZER_LOOT_H +#endif // MODORGANIZER_LOOT_H diff --git a/src/lootdialog.cpp b/src/lootdialog.cpp index 9f7b16f0..6e31b8a6 100644 --- a/src/lootdialog.cpp +++ b/src/lootdialog.cpp @@ -1,9 +1,9 @@ #include "lootdialog.h" -#include "ui_lootdialog.h" #include "loot.h" #include "organizercore.h" -#include <utility.h> +#include "ui_lootdialog.h" #include <QWebChannel> +#include <utility.h> using namespace MOBase; @@ -12,15 +12,14 @@ QString progressToString(lootcli::Progress p) using P = lootcli::Progress; static const std::map<P, QString> map = { - {P::CheckingMasterlistExistence, QObject::tr("Checking masterlist existence")}, - {P::UpdatingMasterlist, QObject::tr("Updating masterlist")}, - {P::LoadingLists, QObject::tr("Loading lists")}, - {P::ReadingPlugins, QObject::tr("Reading plugins")}, - {P::SortingPlugins, QObject::tr("Sorting plugins")}, - {P::WritingLoadorder, QObject::tr("Writing loadorder.txt")}, - {P::ParsingLootMessages, QObject::tr("Parsing loot messages")}, - {P::Done, QObject::tr("Done")} - }; + {P::CheckingMasterlistExistence, QObject::tr("Checking masterlist existence")}, + {P::UpdatingMasterlist, QObject::tr("Updating masterlist")}, + {P::LoadingLists, QObject::tr("Loading lists")}, + {P::ReadingPlugins, QObject::tr("Reading plugins")}, + {P::SortingPlugins, QObject::tr("Sorting plugins")}, + {P::WritingLoadorder, QObject::tr("Writing loadorder.txt")}, + {P::ParsingLootMessages, QObject::tr("Parsing loot messages")}, + {P::Done, QObject::tr("Done")}}; auto itor = map.find(p); if (itor == map.end()) { @@ -30,11 +29,7 @@ QString progressToString(lootcli::Progress p) } } - -MarkdownDocument::MarkdownDocument(QObject* parent) - : QObject(parent) -{ -} +MarkdownDocument::MarkdownDocument(QObject* parent) : QObject(parent) {} void MarkdownDocument::setText(const QString& text) { @@ -45,13 +40,9 @@ void MarkdownDocument::setText(const QString& text) emit textChanged(m_text); } +MarkdownPage::MarkdownPage(QObject* parent) : QWebEnginePage(parent) {} -MarkdownPage::MarkdownPage(QObject* parent) - : QWebEnginePage(parent) -{ -} - -bool MarkdownPage::acceptNavigationRequest(const QUrl &url, NavigationType, bool) +bool MarkdownPage::acceptNavigationRequest(const QUrl& url, NavigationType, bool) { static const QStringList allowed = {"qrc", "data"}; @@ -63,28 +54,39 @@ bool MarkdownPage::acceptNavigationRequest(const QUrl &url, NavigationType, bool return true; } - -LootDialog::LootDialog(QWidget* parent, OrganizerCore& core, Loot& loot) : - QDialog(parent, Qt::WindowMaximizeButtonHint), ui(new Ui::LootDialog), m_core(core), m_loot(loot), - m_finished(false), m_cancelling(false) +LootDialog::LootDialog(QWidget* parent, OrganizerCore& core, Loot& loot) + : QDialog(parent, Qt::WindowMaximizeButtonHint), ui(new Ui::LootDialog), + m_core(core), m_loot(loot), m_finished(false), m_cancelling(false) { createUI(); QObject::connect( - &m_loot, &Loot::output, this, - [&](auto&& s){ addOutput(s); }, Qt::QueuedConnection); + &m_loot, &Loot::output, this, + [&](auto&& s) { + addOutput(s); + }, + Qt::QueuedConnection); QObject::connect( - &m_loot, &Loot::progress, - this, [&](auto&& p){ setProgress(p); }, Qt::QueuedConnection); + &m_loot, &Loot::progress, this, + [&](auto&& p) { + setProgress(p); + }, + Qt::QueuedConnection); QObject::connect( - &m_loot, &Loot::log, this, - [&](auto&& lv, auto&& s){ log(lv, s); }, Qt::QueuedConnection); + &m_loot, &Loot::log, this, + [&](auto&& lv, auto&& s) { + log(lv, s); + }, + Qt::QueuedConnection); QObject::connect( - &m_loot, &Loot::finished, this, - [&]{ onFinished(); }, Qt::QueuedConnection); + &m_loot, &Loot::finished, this, + [&] { + onFinished(); + }, + Qt::QueuedConnection); } LootDialog::~LootDialog() = default; @@ -208,7 +210,9 @@ void LootDialog::createUI() m_expander.set(ui->details, ui->detailsPanel); ui->openJsonReport->setEnabled(false); - connect(ui->openJsonReport, &QPushButton::clicked, [&]{ openReport(); }); + connect(ui->openJsonReport, &QPushButton::clicked, [&] { + openReport(); + }); ui->buttons->setStandardButtons(QDialogButtonBox::Cancel); diff --git a/src/lootdialog.h b/src/lootdialog.h index 3cec15c6..f632b9c1 100644 --- a/src/lootdialog.h +++ b/src/lootdialog.h @@ -1,48 +1,49 @@ #ifndef MODORGANIZER_LOOTDIALOG_H #define MODORGANIZER_LOOTDIALOG_H -#include <lootcli/lootcli.h> -#include <log.h> #include <expanderwidget.h> +#include <log.h> +#include <lootcli/lootcli.h> -namespace Ui { class LootDialog; } +namespace Ui +{ +class LootDialog; +} class OrganizerCore; class Loot; - class MarkdownDocument : public QObject { Q_OBJECT; Q_PROPERTY(QString text MEMBER m_text NOTIFY textChanged FINAL); public: - explicit MarkdownDocument(QObject* parent=nullptr); + explicit MarkdownDocument(QObject* parent = nullptr); void setText(const QString& text); signals: - void textChanged(const QString &text); + void textChanged(const QString& text); private: QString m_text; }; - class MarkdownPage : public QWebEnginePage { Q_OBJECT; public: - explicit MarkdownPage(QObject* parent=nullptr); + explicit MarkdownPage(QObject* parent = nullptr); protected: - bool acceptNavigationRequest(const QUrl &url, NavigationType, bool) override; + bool acceptNavigationRequest(const QUrl& url, NavigationType, bool) override; }; - class LootDialog : public QDialog { Q_OBJECT; + public: LootDialog(QWidget* parent, OrganizerCore& core, Loot& loot); ~LootDialog(); @@ -76,4 +77,4 @@ private: void showReport(); }; -#endif // MODORGANIZER_LOOTDIALOG_H +#endif // MODORGANIZER_LOOTDIALOG_H diff --git a/src/main.cpp b/src/main.cpp index 84db88cb..de157859 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,36 +1,36 @@ -#include "multiprocess.h" -#include "loglist.h" -#include "moapplication.h" -#include "organizercore.h" #include "commandline.h" #include "env.h" #include "instancemanager.h" -#include "thread_utils.h" +#include "loglist.h" +#include "moapplication.h" +#include "multiprocess.h" +#include "organizercore.h" #include "shared/util.h" -#include <report.h> +#include "thread_utils.h" #include <log.h> +#include <report.h> using namespace MOBase; thread_local LPTOP_LEVEL_EXCEPTION_FILTER g_prevExceptionFilter = nullptr; -thread_local std::terminate_handler g_prevTerminateHandler = nullptr; +thread_local std::terminate_handler g_prevTerminateHandler = nullptr; -int run(int argc, char *argv[]); +int run(int argc, char* argv[]); -int main(int argc, char *argv[]) +int main(int argc, char* argv[]) { const int r = run(argc, argv); std::cout << "mod organizer done\n"; return r; } -int run(int argc, char *argv[]) +int run(int argc, char* argv[]) { MOShared::SetThisThreadName("main"); setExceptionHandlers(); cl::CommandLine cl; - if (auto r=cl.process(GetCommandLineW())) { + if (auto r = cl.process(GetCommandLineW())) { return *r; } @@ -42,13 +42,11 @@ int run(int argc, char *argv[]) QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); MOApplication app(argc, argv); - // check if the command line wants to run something right now - if (auto r=cl.runPostApplication(app)) { + if (auto r = cl.runPostApplication(app)) { return *r; } - // check if there's another process running MOMultiProcess multiProcess(cl.multiple()); @@ -62,21 +60,19 @@ int run(int argc, char *argv[]) } QMessageBox::information( - nullptr, QObject::tr("Mod Organizer"), - QObject::tr("An instance of Mod Organizer is already running")); + nullptr, QObject::tr("Mod Organizer"), + QObject::tr("An instance of Mod Organizer is already running")); return 1; } - // check if the command line wants to run something right now - if (auto r=cl.runPostMultiProcess(multiProcess)) { + if (auto r = cl.runPostMultiProcess(multiProcess)) { return *r; } tt.stop(); - // stuff that's done only once, even if MO restarts in the loop below app.firstTimeSetup(multiProcess); @@ -86,10 +82,8 @@ int run(int argc, char *argv[]) // MO runs in a loop because it can be restarted in several ways, such as // when switching instances or changing some settings - for (;;) - { - try - { + for (;;) { + try { auto& m = InstanceManager::singleton(); if (cl.instance()) { @@ -100,11 +94,10 @@ int run(int argc, char *argv[]) m.overrideProfile(*cl.profile()); } - // set up plugins, OrganizerCore, etc. { const auto r = app.setup(multiProcess, pick); - pick = false; + pick = false; if (r == RestartExitCode || r == ReselectExitCode) { // resets things when MO is "restarted" @@ -124,17 +117,14 @@ int run(int argc, char *argv[]) } } - // check if the command line wants to run something right now - if (auto r=cl.runPostOrganizer(app.core())) { + if (auto r = cl.runPostOrganizer(app.core())) { return *r; } - // run the main window const auto r = app.run(multiProcess); - if (r == RestartExitCode) { // resets things when MO is "restarted" app.resetForRestart(); @@ -146,9 +136,7 @@ int run(int argc, char *argv[]) } return r; - } - catch (const std::exception &e) - { + } catch (const std::exception& e) { reportError(e.what()); return 1; } @@ -178,16 +166,11 @@ LONG WINAPI onUnhandledException(_EXCEPTION_POINTERS* ptrs) void onTerminate() noexcept { - __try - { + __try { // force an exception to get a valid stack trace for this thread *(int*)0 = 42; - } - __except - ( - onUnhandledException(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER - ) - { + } __except (onUnhandledException(GetExceptionInformation()), + EXCEPTION_EXECUTE_HANDLER) { } if (g_prevTerminateHandler) { @@ -204,6 +187,6 @@ void setExceptionHandlers() return; } - g_prevExceptionFilter = SetUnhandledExceptionFilter(onUnhandledException); + g_prevExceptionFilter = SetUnhandledExceptionFilter(onUnhandledException); g_prevTerminateHandler = std::set_terminate(onTerminate); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 551f4494..ebe7da98 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -20,65 +20,64 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "mainwindow.h" #include "ui_mainwindow.h" +#include "aboutdialog.h" +#include "browserdialog.h" +#include "categories.h" +#include "categoriesdialog.h" +#include "datatab.h" +#include "downloadlist.h" +#include "downloadstab.h" +#include "editexecutablesdialog.h" +#include "envshortcut.h" +#include "eventfilter.h" #include "executableinfo.h" #include "executableslist.h" +#include "filedialogmemory.h" +#include "filterlist.h" #include "guessedvalue.h" #include "imodinterface.h" -#include "iplugingame.h" +#include "installationmanager.h" +#include "instancemanager.h" +#include "instancemanagerdialog.h" #include "iplugindiagnose.h" +#include "iplugingame.h" #include "isavegame.h" #include "isavegameinfowidget.h" +#include "listdialog.h" +#include "localsavegames.h" +#include "messagedialog.h" +#include "modlist.h" +#include "modlistcontextmenu.h" +#include "modlistviewactions.h" +#include "motddialog.h" #include "nexusinterface.h" +#include "nxmaccessmanager.h" #include "organizercore.h" +#include "overwriteinfodialog.h" +#include "pluginlist.h" +#include "previewdialog.h" #include "previewgenerator.h" -#include "serverinfo.h" -#include "savegameinfo.h" -#include "spawn.h" -#include "versioninfo.h" -#include "instancemanager.h" -#include "report.h" -#include "modlist.h" +#include "problemsdialog.h" #include "profile.h" -#include "pluginlist.h" #include "profilesdialog.h" -#include "editexecutablesdialog.h" -#include "categories.h" -#include "categoriesdialog.h" -#include "overwriteinfodialog.h" -#include "downloadlist.h" -#include "messagedialog.h" -#include "installationmanager.h" -#include "motddialog.h" -#include "filedialogmemory.h" -#include "tutorialmanager.h" +#include "report.h" +#include "savegameinfo.h" +#include "savestab.h" #include "selectiondialog.h" -#include "problemsdialog.h" -#include "previewdialog.h" -#include "browserdialog.h" -#include "aboutdialog.h" +#include "serverinfo.h" #include "settingsdialog.h" -#include <safewritefile.h> -#include "nxmaccessmanager.h" #include "shared/appconfig.h" -#include "eventfilter.h" +#include "spawn.h" #include "statusbar.h" -#include "filterlist.h" -#include "datatab.h" -#include "downloadstab.h" -#include "savestab.h" -#include "instancemanagerdialog.h" -#include <utility.h> -#include <dataarchives.h> +#include "tutorialmanager.h" +#include "versioninfo.h" #include <bsainvalidation.h> -#include <taskprogressmanager.h> +#include <dataarchives.h> +#include <safewritefile.h> #include <scopeguard.h> +#include <taskprogressmanager.h> #include <usvfs.h> -#include "localsavegames.h" -#include "listdialog.h" -#include "envshortcut.h" -#include "browserdialog.h" -#include "modlistviewactions.h" -#include "modlistcontextmenu.h" +#include <utility.h> #include "directoryrefresher.h" #include "shared/directoryentry.h" @@ -88,22 +87,25 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QAbstractItemDelegate> #include <QAction> #include <QApplication> -#include <QButtonGroup> #include <QBuffer> +#include <QButtonGroup> #include <QCheckBox> #include <QClipboard> #include <QCloseEvent> +#include <QColor> +#include <QColorDialog> #include <QCoreApplication> #include <QCursor> #include <QDebug> #include <QDesktopServices> #include <QDialog> +#include <QDialogButtonBox> #include <QDirIterator> #include <QDragEnterEvent> #include <QDropEvent> #include <QEvent> -#include <QFileDialog> #include <QFIleIconProvider> +#include <QFileDialog> #include <QFont> #include <QFuture> #include <QHash> @@ -128,14 +130,14 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QPoint> #include <QProcess> #include <QProgressDialog> -#include <QDialogButtonBox> #include <QPushButton> #include <QRadioButton> #include <QRect> #include <QResizeEvent> #include <QScopedPointer> -#include <QSizePolicy> +#include <QShortcut> #include <QSize> +#include <QSizePolicy> #include <QTime> #include <QTimer> #include <QToolButton> @@ -146,42 +148,39 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QUrl> #include <QVariantList> #include <QVersionNumber> +#include <QWebEngineProfile> #include <QWhatsThis> #include <QWidgetAction> -#include <QWebEngineProfile> -#include <QShortcut> -#include <QColorDialog> -#include <QColor> #include <QDebug> #include <QtGlobal> #ifndef Q_MOC_RUN -#include <boost/thread.hpp> #include <boost/algorithm/string.hpp> -#include <boost/bind/bind.hpp> #include <boost/assign.hpp> +#include <boost/bind/bind.hpp> #include <boost/range/adaptor/reversed.hpp> +#include <boost/thread.hpp> #endif #include <shlobj.h> -#include <limits.h> #include <exception> #include <functional> +#include <limits.h> #include <map> #include <regex> -#include <stdexcept> #include <sstream> +#include <stdexcept> #include <utility> #include "gameplugins.h" #ifdef TEST_MODELS #include "modeltest.h" -#endif // TEST_MODELS +#endif // TEST_MODELS -#pragma warning( disable : 4428 ) +#pragma warning(disable : 4428) using namespace MOBase; using namespace MOShared; @@ -223,7 +222,6 @@ void setFilterShortcuts(QWidget* widget, QLineEdit* edit) QObject::connect(s, &QShortcut::activated, reset); }; - hookActivate(widget); hookReset(widget); @@ -231,27 +229,16 @@ void setFilterShortcuts(QWidget* widget, QLineEdit* edit) hookReset(edit); } -MainWindow::MainWindow(Settings &settings - , OrganizerCore &organizerCore - , PluginContainer &pluginContainer - , QWidget *parent) - : QMainWindow(parent) - , ui(new Ui::MainWindow) - , m_WasVisible(false) - , m_FirstPaint(true) - , m_linksSeparator(nullptr) - , m_Tutorial(this, "MainWindow") - , m_OldProfileIndex(-1) - , m_OldExecutableIndex(-1) - , m_CategoryFactory(CategoryFactory::instance()) - , m_OrganizerCore(organizerCore) - , m_PluginContainer(pluginContainer) - , m_ArchiveListWriter(std::bind(&MainWindow::saveArchiveList, this)) - , m_LinkToolbar(nullptr) - , m_LinkDesktop(nullptr) - , m_LinkStartMenu(nullptr) - , m_NumberOfProblems(0) - , m_ProblemsCheckRequired(false) +MainWindow::MainWindow(Settings& settings, OrganizerCore& organizerCore, + PluginContainer& pluginContainer, QWidget* parent) + : QMainWindow(parent), ui(new Ui::MainWindow), m_WasVisible(false), + m_FirstPaint(true), m_linksSeparator(nullptr), m_Tutorial(this, "MainWindow"), + m_OldProfileIndex(-1), m_OldExecutableIndex(-1), + m_CategoryFactory(CategoryFactory::instance()), m_OrganizerCore(organizerCore), + m_PluginContainer(pluginContainer), + m_ArchiveListWriter(std::bind(&MainWindow::saveArchiveList, this)), + m_LinkToolbar(nullptr), m_LinkDesktop(nullptr), m_LinkStartMenu(nullptr), + m_NumberOfProblems(0), m_ProblemsCheckRequired(false) { // disables incredibly slow menu fade in effect that looks and feels like crap. // this was only happening to users with the windows @@ -263,10 +250,12 @@ MainWindow::MainWindow(Settings &settings QApplication::setEffectEnabled(Qt::UI_AnimateTooltip, false); QApplication::setEffectEnabled(Qt::UI_FadeTooltip, false); - QWebEngineProfile::defaultProfile()->setPersistentCookiesPolicy(QWebEngineProfile::NoPersistentCookies); + QWebEngineProfile::defaultProfile()->setPersistentCookiesPolicy( + QWebEngineProfile::NoPersistentCookies); QWebEngineProfile::defaultProfile()->setHttpCacheMaximumSize(52428800); QWebEngineProfile::defaultProfile()->setCachePath(settings.paths().cache()); - QWebEngineProfile::defaultProfile()->setPersistentStoragePath(settings.paths().cache()); + QWebEngineProfile::defaultProfile()->setPersistentStoragePath( + settings.paths().cache()); // qt resets the thread name somewhere within the QWebEngineProfile calls // above @@ -303,7 +292,6 @@ MainWindow::MainWindow(Settings &settings ui->logList->setCore(m_OrganizerCore); - setupToolbar(); toggleMO2EndorseState(); toggleUpdateAction(); @@ -316,23 +304,24 @@ MainWindow::MainWindow(Settings &settings ui->bsaList->setHeaderHidden(true); const bool pluginListAdjusted = - settings.geometry().restoreState(ui->espList->header()); - + settings.geometry().restoreState(ui->espList->header()); // data tab m_DataTab.reset(new DataTab(m_OrganizerCore, m_PluginContainer, this, ui)); m_DataTab->restoreState(settings); - connect(m_DataTab.get(), &DataTab::executablesChanged, [&]{ refreshExecutablesList(); }); - - connect( - m_DataTab.get(), &DataTab::originModified, - [&](int id){ originModified(id); }); + connect(m_DataTab.get(), &DataTab::executablesChanged, [&] { + refreshExecutablesList(); + }); - connect( - m_DataTab.get(), &DataTab::displayModInformation, - [&](auto&& m, auto&& i, auto&& tab){ displayModInformation(m, i, tab); }); + connect(m_DataTab.get(), &DataTab::originModified, [&](int id) { + originModified(id); + }); + connect(m_DataTab.get(), &DataTab::displayModInformation, + [&](auto&& m, auto&& i, auto&& tab) { + displayModInformation(m, i, tab); + }); // downloads tab m_DownloadsTab.reset(new DownloadsTab(m_OrganizerCore, ui)); @@ -357,82 +346,112 @@ MainWindow::MainWindow(Settings &settings resizeLists(pluginListAdjusted); - QMenu *linkMenu = new QMenu(this); - m_LinkToolbar = linkMenu->addAction(QIcon(":/MO/gui/link"), tr("Toolbar and Menu"), this, SLOT(linkToolbar())); - m_LinkDesktop = linkMenu->addAction(QIcon(":/MO/gui/link"), tr("Desktop"), this, SLOT(linkDesktop())); - m_LinkStartMenu = linkMenu->addAction(QIcon(":/MO/gui/link"), tr("Start Menu"), this, SLOT(linkMenu())); + QMenu* linkMenu = new QMenu(this); + m_LinkToolbar = linkMenu->addAction(QIcon(":/MO/gui/link"), tr("Toolbar and Menu"), + this, SLOT(linkToolbar())); + m_LinkDesktop = linkMenu->addAction(QIcon(":/MO/gui/link"), tr("Desktop"), this, + SLOT(linkDesktop())); + m_LinkStartMenu = linkMenu->addAction(QIcon(":/MO/gui/link"), tr("Start Menu"), this, + SLOT(linkMenu())); ui->linkButton->setMenu(linkMenu); - ui->listOptionsBtn->setMenu(new ModListGlobalContextMenu(m_OrganizerCore, ui->modList, this)); + ui->listOptionsBtn->setMenu( + new ModListGlobalContextMenu(m_OrganizerCore, ui->modList, this)); ui->openFolderMenu->setMenu(openFolderMenu()); // don't allow mouse wheel to switch grouping, too many people accidentally // turn on grouping and then don't understand what happened - EventFilter *noWheel - = new EventFilter(this, [](QObject *, QEvent *event) -> bool { - return event->type() == QEvent::Wheel; - }); + EventFilter* noWheel = new EventFilter(this, [](QObject*, QEvent* event) -> bool { + return event->type() == QEvent::Wheel; + }); ui->groupCombo->installEventFilter(noWheel); ui->profileBox->installEventFilter(noWheel); - if (organizerCore.managedGame()->sortMechanism() == MOBase::IPluginGame::SortMechanism::NONE) { + if (organizerCore.managedGame()->sortMechanism() == + MOBase::IPluginGame::SortMechanism::NONE) { ui->bossButton->setDisabled(true); - ui->bossButton->setToolTip(tr("There is no supported sort mechanism for this game. You will probably have to use a third-party tool.")); + ui->bossButton->setToolTip(tr("There is no supported sort mechanism for this game. " + "You will probably have to use a third-party tool.")); } - connect(&m_PluginContainer, SIGNAL(diagnosisUpdate()), this, SLOT(scheduleCheckForProblems())); + connect(&m_PluginContainer, SIGNAL(diagnosisUpdate()), this, + SLOT(scheduleCheckForProblems())); - connect(&m_OrganizerCore, &OrganizerCore::directoryStructureReady, - this, &MainWindow::onDirectoryStructureChanged); - connect(m_OrganizerCore.directoryRefresher(), SIGNAL(progress(const DirectoryRefreshProgress*)), - this, SLOT(refresherProgress(const DirectoryRefreshProgress*))); - connect(m_OrganizerCore.directoryRefresher(), SIGNAL(error(QString)), this, SLOT(showError(QString))); + connect(&m_OrganizerCore, &OrganizerCore::directoryStructureReady, this, + &MainWindow::onDirectoryStructureChanged); + connect(m_OrganizerCore.directoryRefresher(), + SIGNAL(progress(const DirectoryRefreshProgress*)), this, + SLOT(refresherProgress(const DirectoryRefreshProgress*))); + connect(m_OrganizerCore.directoryRefresher(), SIGNAL(error(QString)), this, + SLOT(showError(QString))); - connect(&m_OrganizerCore.settings(), SIGNAL(languageChanged(QString)), this, SLOT(languageChange(QString))); - connect(&m_OrganizerCore.settings(), SIGNAL(styleChanged(QString)), this, SIGNAL(styleChanged(QString))); + connect(&m_OrganizerCore.settings(), SIGNAL(languageChanged(QString)), this, + SLOT(languageChange(QString))); + connect(&m_OrganizerCore.settings(), SIGNAL(styleChanged(QString)), this, + SIGNAL(styleChanged(QString))); connect(m_OrganizerCore.updater(), SIGNAL(restart()), this, SLOT(close())); - connect(m_OrganizerCore.updater(), SIGNAL(updateAvailable()), this, SLOT(updateAvailable())); - connect(m_OrganizerCore.updater(), SIGNAL(motdAvailable(QString)), this, SLOT(motdReceived(QString))); + connect(m_OrganizerCore.updater(), SIGNAL(updateAvailable()), this, + SLOT(updateAvailable())); + connect(m_OrganizerCore.updater(), SIGNAL(motdAvailable(QString)), this, + SLOT(motdReceived(QString))); - connect(&NexusInterface::instance(), SIGNAL(requestNXMDownload(QString)), &m_OrganizerCore, SLOT(downloadRequestedNXM(QString))); - connect(&NexusInterface::instance(), SIGNAL(nxmDownloadURLsAvailable(QString,int,int,QVariant,QVariant,int)), this, SLOT(nxmDownloadURLs(QString,int,int,QVariant,QVariant,int))); - connect(&NexusInterface::instance(), SIGNAL(needLogin()), &m_OrganizerCore, SLOT(nexusApi())); + connect(&NexusInterface::instance(), SIGNAL(requestNXMDownload(QString)), + &m_OrganizerCore, SLOT(downloadRequestedNXM(QString))); + connect(&NexusInterface::instance(), + SIGNAL(nxmDownloadURLsAvailable(QString, int, int, QVariant, QVariant, int)), + this, SLOT(nxmDownloadURLs(QString, int, int, QVariant, QVariant, int))); + connect(&NexusInterface::instance(), SIGNAL(needLogin()), &m_OrganizerCore, + SLOT(nexusApi())); - connect( - NexusInterface::instance().getAccessManager(), - SIGNAL(credentialsReceived(const APIUserAccount&)), - this, - SLOT(updateWindowTitle(const APIUserAccount&))); + connect(NexusInterface::instance().getAccessManager(), + SIGNAL(credentialsReceived(const APIUserAccount&)), this, + SLOT(updateWindowTitle(const APIUserAccount&))); - connect( - NexusInterface::instance().getAccessManager(), - SIGNAL(credentialsReceived(const APIUserAccount&)), - &NexusInterface::instance(), - SLOT(setUserAccount(const APIUserAccount&))); + connect(NexusInterface::instance().getAccessManager(), + SIGNAL(credentialsReceived(const APIUserAccount&)), + &NexusInterface::instance(), SLOT(setUserAccount(const APIUserAccount&))); - connect( - &NexusInterface::instance(), - SIGNAL(requestsChanged(const APIStats&, const APIUserAccount&)), - this, - SLOT(onRequestsChanged(const APIStats&, const APIUserAccount&))); + connect(&NexusInterface::instance(), + SIGNAL(requestsChanged(const APIStats&, const APIUserAccount&)), this, + SLOT(onRequestsChanged(const APIStats&, const APIUserAccount&))); - connect(&TutorialManager::instance(), SIGNAL(windowTutorialFinished(QString)), this, SLOT(windowTutorialFinished(QString))); - connect(ui->tabWidget, SIGNAL(currentChanged(int)), &TutorialManager::instance(), SIGNAL(tabChanged(int))); - connect(ui->toolBar, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(toolBar_customContextMenuRequested(QPoint))); - connect(ui->menuToolbars, &QMenu::aboutToShow, [&]{ updateToolbarMenu(); }); - connect(ui->menuView, &QMenu::aboutToShow, [&]{ updateViewMenu(); }); - connect(ui->actionTool->menu(), &QMenu::aboutToShow, [&] { updateToolMenu(); }); - connect(&m_PluginContainer, &PluginContainer::pluginEnabled, this, [this](IPlugin* plugin) { - if (m_PluginContainer.implementInterface<IPluginModPage>(plugin)) { updateModPageMenu(); } }); - connect(&m_PluginContainer, &PluginContainer::pluginDisabled, this, [this](IPlugin* plugin) { - if (m_PluginContainer.implementInterface<IPluginModPage>(plugin)) { updateModPageMenu(); } }); - connect(&m_PluginContainer, &PluginContainer::pluginRegistered, this, &MainWindow::onPluginRegistrationChanged); - connect(&m_PluginContainer, &PluginContainer::pluginUnregistered, this, &MainWindow::onPluginRegistrationChanged); + connect(&TutorialManager::instance(), SIGNAL(windowTutorialFinished(QString)), this, + SLOT(windowTutorialFinished(QString))); + connect(ui->tabWidget, SIGNAL(currentChanged(int)), &TutorialManager::instance(), + SIGNAL(tabChanged(int))); + connect(ui->toolBar, SIGNAL(customContextMenuRequested(QPoint)), this, + SLOT(toolBar_customContextMenuRequested(QPoint))); + connect(ui->menuToolbars, &QMenu::aboutToShow, [&] { + updateToolbarMenu(); + }); + connect(ui->menuView, &QMenu::aboutToShow, [&] { + updateViewMenu(); + }); + connect(ui->actionTool->menu(), &QMenu::aboutToShow, [&] { + updateToolMenu(); + }); + connect(&m_PluginContainer, &PluginContainer::pluginEnabled, this, + [this](IPlugin* plugin) { + if (m_PluginContainer.implementInterface<IPluginModPage>(plugin)) { + updateModPageMenu(); + } + }); + connect(&m_PluginContainer, &PluginContainer::pluginDisabled, this, + [this](IPlugin* plugin) { + if (m_PluginContainer.implementInterface<IPluginModPage>(plugin)) { + updateModPageMenu(); + } + }); + connect(&m_PluginContainer, &PluginContainer::pluginRegistered, this, + &MainWindow::onPluginRegistrationChanged); + connect(&m_PluginContainer, &PluginContainer::pluginUnregistered, this, + &MainWindow::onPluginRegistrationChanged); - connect(&m_OrganizerCore, &OrganizerCore::modInstalled, this, &MainWindow::modInstalled); + connect(&m_OrganizerCore, &OrganizerCore::modInstalled, this, + &MainWindow::modInstalled); m_CheckBSATimer.setSingleShot(true); connect(&m_CheckBSATimer, SIGNAL(timeout()), this, SLOT(checkBSAList())); @@ -442,8 +461,10 @@ MainWindow::MainWindow(Settings &settings setFilterShortcuts(ui->downloadView, ui->downloadFilterEdit); m_UpdateProblemsTimer.setSingleShot(true); - connect(&m_UpdateProblemsTimer, &QTimer::timeout, this, &MainWindow::checkForProblemsAsync); - connect(this, &MainWindow::checkForProblemsDone, this, &MainWindow::updateProblemsButton, Qt::ConnectionType::QueuedConnection); + connect(&m_UpdateProblemsTimer, &QTimer::timeout, this, + &MainWindow::checkForProblemsAsync); + connect(this, &MainWindow::checkForProblemsDone, this, + &MainWindow::updateProblemsButton, Qt::ConnectionType::QueuedConnection); m_SaveMetaTimer.setSingleShot(false); connect(&m_SaveMetaTimer, SIGNAL(timeout()), this, SLOT(saveModMetas())); @@ -459,19 +480,28 @@ MainWindow::MainWindow(Settings &settings m_Tutorial.expose("espList", m_OrganizerCore.pluginList()); m_OrganizerCore.setUserInterface(this); - connect(m_OrganizerCore.modList(), &ModList::showMessage, - [=](auto&& message) { showMessage(message); }); + connect(m_OrganizerCore.modList(), &ModList::showMessage, [=](auto&& message) { + showMessage(message); + }); connect(m_OrganizerCore.modList(), &ModList::modRenamed, - [=](auto&& oldName, auto&& newName) { modRenamed(oldName, newName); }); - connect(m_OrganizerCore.modList(), &ModList::modUninstalled, - [=](auto&& name) { modRemoved(name); }); - connect(m_OrganizerCore.modList(), &ModList::fileMoved, - [=](auto&& ...args) { fileMoved(args...); }); + [=](auto&& oldName, auto&& newName) { + modRenamed(oldName, newName); + }); + connect(m_OrganizerCore.modList(), &ModList::modUninstalled, [=](auto&& name) { + modRemoved(name); + }); + connect(m_OrganizerCore.modList(), &ModList::fileMoved, [=](auto&&... args) { + fileMoved(args...); + }); connect(m_OrganizerCore.installationManager(), &InstallationManager::modReplaced, - [=](auto&& name) { modRemoved(name); }); + [=](auto&& name) { + modRemoved(name); + }); connect(m_OrganizerCore.downloadManager(), &DownloadManager::showMessage, - [=](auto&& message) { showMessage(message); }); - for (const QString &fileName : m_PluginContainer.pluginFileNames()) { + [=](auto&& message) { + showMessage(message); + }); + for (const QString& fileName : m_PluginContainer.pluginFileNames()) { installTranslator(QFileInfo(fileName).baseName()); } @@ -482,13 +512,10 @@ MainWindow::MainWindow(Settings &settings ui->profileBox->setCurrentText(m_OrganizerCore.currentProfile()->name()); - if (settings.archiveParsing()) - { + if (settings.archiveParsing()) { ui->dataTabShowFromArchives->setCheckState(Qt::Checked); ui->dataTabShowFromArchives->setEnabled(true); - } - else - { + } else { ui->dataTabShowFromArchives->setCheckState(Qt::Unchecked); ui->dataTabShowFromArchives->setEnabled(false); } @@ -510,11 +537,17 @@ void MainWindow::setupModList() { ui->modList->setup(m_OrganizerCore, m_CategoryFactory, this, ui); - connect(&ui->modList->actions(), &ModListViewActions::overwriteCleared, [=]() { scheduleCheckForProblems(); }); - connect(&ui->modList->actions(), &ModListViewActions::originModified, this, &MainWindow::originModified); - connect(&ui->modList->actions(), &ModListViewActions::modInfoDisplayed, this, &MainWindow::modInfoDisplayed); + connect(&ui->modList->actions(), &ModListViewActions::overwriteCleared, [=]() { + scheduleCheckForProblems(); + }); + connect(&ui->modList->actions(), &ModListViewActions::originModified, this, + &MainWindow::originModified); + connect(&ui->modList->actions(), &ModListViewActions::modInfoDisplayed, this, + &MainWindow::modInfoDisplayed); - connect(m_OrganizerCore.modList(), &ModList::modPrioritiesChanged, [&]() { m_ArchiveListWriter.write(); }); + connect(m_OrganizerCore.modList(), &ModList::modPrioritiesChanged, [&]() { + m_ArchiveListWriter.write(); + }); } void MainWindow::resetActionIcons() @@ -566,7 +599,7 @@ void MainWindow::resetActionIcons() // button associated with the action on the toolbar QWidget* actionWidget = ui->toolBar->widgetForAction(action); - if (auto* actionButton=dynamic_cast<QAbstractButton*>(actionWidget)) { + if (auto* actionButton = dynamic_cast<QAbstractButton*>(actionWidget)) { actionButton->setIcon(icon); } @@ -597,19 +630,21 @@ MainWindow::~MainWindow() } delete ui; - } catch (std::exception &e) { - QMessageBox::critical(nullptr, tr("Crash on exit"), - tr("MO crashed while exiting. Some settings may not be saved.\n\nError: %1").arg(e.what()), - QMessageBox::Ok); + } catch (std::exception& e) { + QMessageBox::critical( + nullptr, tr("Crash on exit"), + tr("MO crashed while exiting. Some settings may not be saved.\n\nError: %1") + .arg(e.what()), + QMessageBox::Ok); } } void MainWindow::updateWindowTitle(const APIUserAccount& user) { //"\xe2\x80\x93" is an "em dash", a longer "-" - QString title = QString("%1 \xe2\x80\x93 Mod Organizer v%2").arg( - m_OrganizerCore.managedGame()->gameName(), - m_OrganizerCore.getVersion().displayString(3)); + QString title = QString("%1 \xe2\x80\x93 Mod Organizer v%2") + .arg(m_OrganizerCore.managedGame()->gameName(), + m_OrganizerCore.getVersion().displayString(3)); if (!user.name().isEmpty()) { const QString premium = (user.type() == APIUserAccountTypes::Premium ? "*" : ""); @@ -662,7 +697,7 @@ void MainWindow::updateStyle(const QString&) resetActionIcons(); } -void MainWindow::resizeEvent(QResizeEvent *event) +void MainWindow::resizeEvent(QResizeEvent* event) { m_Tutorial.resize(event->size()); QMainWindow::resizeEvent(event); @@ -706,7 +741,7 @@ void MainWindow::setupActionMenu(QAction* a) a->setMenu(new QMenu(this)); auto* w = ui->toolBar->widgetForAction(a); - if (auto* tb=dynamic_cast<QToolButton*>(w)) + if (auto* tb = dynamic_cast<QToolButton*>(w)) tb->setPopupMode(QToolButton::InstantPopup); } @@ -727,8 +762,8 @@ void MainWindow::updatePinnedExecutables() if (!exe.hide() && exe.isShownOnToolbar()) { hasLinks = true; - QAction *exeAction = new QAction( - iconForExecutable(exe.binaryInfo().filePath()), exe.title()); + QAction* exeAction = + new QAction(iconForExecutable(exe.binaryInfo().filePath()), exe.title()); exeAction->setObjectName(QString("custom__") + exe.title()); exeAction->setStatusTip(exe.binaryInfo().filePath()); @@ -759,12 +794,16 @@ void MainWindow::updateToolbarMenu() ui->actionStatusBarToggle->setChecked(ui->statusBar->isVisible()); ui->actionToolBarSmallIcons->setChecked(ui->toolBar->iconSize() == SmallToolbarSize); - ui->actionToolBarMediumIcons->setChecked(ui->toolBar->iconSize() == MediumToolbarSize); + ui->actionToolBarMediumIcons->setChecked(ui->toolBar->iconSize() == + MediumToolbarSize); ui->actionToolBarLargeIcons->setChecked(ui->toolBar->iconSize() == LargeToolbarSize); - ui->actionToolBarIconsOnly->setChecked(ui->toolBar->toolButtonStyle() == Qt::ToolButtonIconOnly); - ui->actionToolBarTextOnly->setChecked(ui->toolBar->toolButtonStyle() == Qt::ToolButtonTextOnly); - ui->actionToolBarIconsAndText->setChecked(ui->toolBar->toolButtonStyle() == Qt::ToolButtonTextUnderIcon); + ui->actionToolBarIconsOnly->setChecked(ui->toolBar->toolButtonStyle() == + Qt::ToolButtonIconOnly); + ui->actionToolBarTextOnly->setChecked(ui->toolBar->toolButtonStyle() == + Qt::ToolButtonTextOnly); + ui->actionToolBarIconsAndText->setChecked(ui->toolBar->toolButtonStyle() == + Qt::ToolButtonTextUnderIcon); } void MainWindow::updateViewMenu() @@ -857,7 +896,7 @@ void MainWindow::setToolbarButtonStyle(Qt::ToolButtonStyle s) } } -void MainWindow::on_centralWidget_customContextMenuRequested(const QPoint &pos) +void MainWindow::on_centralWidget_customContextMenuRequested(const QPoint& pos) { // this allows for getting the context menu even if both the menubar and all // the toolbars are hidden; an alternative is the Alt key handled in @@ -892,8 +931,9 @@ void MainWindow::updateProblemsButton() const std::size_t numProblems = m_NumberOfProblems; // original icon without a count painted on it - const QIcon original = m_originalNotificationIcon.isNull() ? - QIcon(DefaultIconName) : m_originalNotificationIcon; + const QIcon original = m_originalNotificationIcon.isNull() + ? QIcon(DefaultIconName) + : m_originalNotificationIcon; // final icon QIcon final; @@ -910,8 +950,9 @@ void MainWindow::updateProblemsButton() QPainter painter(&merged); const std::string badgeName = - std::string(":/MO/gui/badge_") + - (numProblems < 10 ? std::to_string(static_cast<long long>(numProblems)) : "more"); + std::string(":/MO/gui/badge_") + + (numProblems < 10 ? std::to_string(static_cast<long long>(numProblems)) + : "more"); painter.drawPixmap(32, 32, 32, 32, QPixmap(badgeName.c_str())); } @@ -930,8 +971,8 @@ void MainWindow::updateProblemsButton() ui->actionNotifications->setIcon(final); // setting the icon on the toolbar button - if (auto* actionWidget=ui->toolBar->widgetForAction(ui->actionNotifications)) { - if (auto* button=dynamic_cast<QAbstractButton*>(actionWidget)) { + if (auto* actionWidget = ui->toolBar->widgetForAction(ui->actionNotifications)) { + if (auto* button = dynamic_cast<QAbstractButton*>(actionWidget)) { button->setIcon(final); } } @@ -942,11 +983,13 @@ void MainWindow::updateProblemsButton() } } -bool MainWindow::errorReported(QString &logFile) +bool MainWindow::errorReported(QString& logFile) { - QDir dir(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath())); - QFileInfoList files = dir.entryInfoList(QStringList("ModOrganizer_??_??_??_??_??.log"), - QDir::Files, QDir::Name | QDir::Reversed); + QDir dir(qApp->property("dataPath").toString() + "/" + + QString::fromStdWString(AppConfig::logPath())); + QFileInfoList files = + dir.entryInfoList(QStringList("ModOrganizer_??_??_??_??_??.log"), QDir::Files, + QDir::Name | QDir::Reversed); if (files.count() > 0) { logFile = files.at(0).absoluteFilePath(); @@ -971,10 +1014,11 @@ bool MainWindow::errorReported(QString &logFile) return false; } -QFuture<void> MainWindow::checkForProblemsAsync() { +QFuture<void> MainWindow::checkForProblemsAsync() +{ return QtConcurrent::run([this]() { checkForProblemsImpl(); - }); + }); } void MainWindow::checkForProblemsImpl() @@ -988,10 +1032,10 @@ void MainWindow::checkForProblemsImpl() m_ProblemsCheckRequired = false; TimeThis tt("MainWindow::checkForProblemsImpl()"); size_t numProblems = 0; - for (QObject *pluginObj : m_PluginContainer.plugins<QObject>()) { - IPlugin *plugin = qobject_cast<IPlugin*>(pluginObj); + for (QObject* pluginObj : m_PluginContainer.plugins<QObject>()) { + IPlugin* plugin = qobject_cast<IPlugin*>(pluginObj); if (plugin == nullptr || m_PluginContainer.isEnabled(plugin)) { - IPluginDiagnose *diagnose = qobject_cast<IPluginDiagnose*>(pluginObj); + IPluginDiagnose* diagnose = qobject_cast<IPluginDiagnose*>(pluginObj); if (diagnose != nullptr) numProblems += diagnose->activeProblems().size(); } @@ -1016,11 +1060,11 @@ void MainWindow::createEndorseMenu() menu->clear(); - QAction *endorseAction = new QAction(tr("Endorse"), menu); + QAction* endorseAction = new QAction(tr("Endorse"), menu); connect(endorseAction, SIGNAL(triggered()), this, SLOT(actionEndorseMO())); menu->addAction(endorseAction); - QAction *wontEndorseAction = new QAction(tr("Won't Endorse"), menu); + QAction* wontEndorseAction = new QAction(tr("Won't Endorse"), menu); connect(wontEndorseAction, SIGNAL(triggered()), this, SLOT(actionWontEndorseMO())); menu->addAction(wontEndorseAction); } @@ -1036,35 +1080,36 @@ void MainWindow::createHelpMenu() menu->clear(); - QAction *helpAction = new QAction(tr("Help on UI"), menu); + QAction* helpAction = new QAction(tr("Help on UI"), menu); connect(helpAction, SIGNAL(triggered()), this, SLOT(helpTriggered())); menu->addAction(helpAction); - QAction *wikiAction = new QAction(tr("Documentation"), menu); + QAction* wikiAction = new QAction(tr("Documentation"), menu); connect(wikiAction, SIGNAL(triggered()), this, SLOT(wikiTriggered())); menu->addAction(wikiAction); - if(!m_OrganizerCore.managedGame()->getSupportURL().isEmpty()) { - QAction *gameSupportAction = new QAction(tr("Game Support Wiki"), menu); + if (!m_OrganizerCore.managedGame()->getSupportURL().isEmpty()) { + QAction* gameSupportAction = new QAction(tr("Game Support Wiki"), menu); connect(gameSupportAction, SIGNAL(triggered()), this, SLOT(gameSupportTriggered())); menu->addAction(gameSupportAction); } - QAction *discordAction = new QAction(tr("Chat on Discord"), menu); + QAction* discordAction = new QAction(tr("Chat on Discord"), menu); connect(discordAction, SIGNAL(triggered()), this, SLOT(discordTriggered())); menu->addAction(discordAction); - QAction *issueAction = new QAction(tr("Report Issue"), menu); + QAction* issueAction = new QAction(tr("Report Issue"), menu); connect(issueAction, SIGNAL(triggered()), this, SLOT(issueTriggered())); menu->addAction(issueAction); - QMenu *tutorialMenu = new QMenu(tr("Tutorials"), menu); + QMenu* tutorialMenu = new QMenu(tr("Tutorials"), menu); - typedef std::vector<std::pair<int, QAction*> > ActionList; + typedef std::vector<std::pair<int, QAction*>> ActionList; ActionList tutorials; - QDirIterator dirIter(QApplication::applicationDirPath() + "/tutorials", QStringList("*.js"), QDir::Files); + QDirIterator dirIter(QApplication::applicationDirPath() + "/tutorials", + QStringList("*.js"), QDir::Files); while (dirIter.hasNext()) { dirIter.next(); QString fileName = dirIter.fileName(); @@ -1078,18 +1123,20 @@ void MainWindow::createHelpMenu() if (firstLine.startsWith("//TL")) { QStringList params = firstLine.mid(4).trimmed().split('#'); if (params.size() != 2) { - log::error("invalid header line for tutorial {}, expected 2 parameters", fileName); + log::error("invalid header line for tutorial {}, expected 2 parameters", + fileName); continue; } - QAction *tutAction = new QAction(params.at(0), tutorialMenu); + QAction* tutAction = new QAction(params.at(0), tutorialMenu); tutAction->setData(fileName); tutorials.push_back(std::make_pair(params.at(1).toInt(), tutAction)); } } std::sort(tutorials.begin(), tutorials.end(), - [] (const ActionList::value_type &LHS, const ActionList::value_type &RHS) { - return LHS.first < RHS.first; } ); + [](const ActionList::value_type& LHS, const ActionList::value_type& RHS) { + return LHS.first < RHS.first; + }); for (auto iter = tutorials.begin(); iter != tutorials.end(); ++iter) { connect(iter->second, SIGNAL(triggered()), this, SLOT(tutorialTriggered())); @@ -1103,8 +1150,8 @@ void MainWindow::createHelpMenu() bool MainWindow::addProfile() { - QComboBox *profileBox = findChild<QComboBox*>("profileBox"); - bool okClicked = false; + QComboBox* profileBox = findChild<QComboBox*>("profileBox"); + bool okClicked = false; QString name = QInputDialog::getText(this, tr("Name"), tr("Please enter a name for the new profile"), @@ -1125,7 +1172,8 @@ bool MainWindow::addProfile() void MainWindow::hookUpWindowTutorials() { - QDirIterator dirIter(QApplication::applicationDirPath() + "/tutorials", QStringList("*.js"), QDir::Files); + QDirIterator dirIter(QApplication::applicationDirPath() + "/tutorials", + QStringList("*.js"), QDir::Files); while (dirIter.hasNext()) { dirIter.next(); QString fileName = dirIter.fileName(); @@ -1151,11 +1199,11 @@ bool MainWindow::shouldStartTutorial() const } QMessageBox dlg( - QMessageBox::Question, tr("Show tutorial?"), - tr("You are starting Mod Organizer for the first time. " - "Do you want to show a tutorial of its basic features? If you choose " - "no you can always start the tutorial from the \"Help\" menu."), - QMessageBox::Yes | QMessageBox::No); + QMessageBox::Question, tr("Show tutorial?"), + tr("You are starting Mod Organizer for the first time. " + "Do you want to show a tutorial of its basic features? If you choose " + "no you can always start the tutorial from the \"Help\" menu."), + QMessageBox::Yes | QMessageBox::No); dlg.setCheckBox(new QCheckBox(tr("Never ask to show tutorials"))); @@ -1168,7 +1216,7 @@ bool MainWindow::shouldStartTutorial() const return (r == QMessageBox::Yes); } -void MainWindow::showEvent(QShowEvent *event) +void MainWindow::showEvent(QShowEvent* event) { QMainWindow::showEvent(event); @@ -1195,7 +1243,8 @@ void MainWindow::showEvent(QShowEvent *event) QString firstStepsTutorial = ToQString(AppConfig::firstStepsTutorial()); if (TutorialManager::instance().hasTutorial(firstStepsTutorial)) { if (shouldStartTutorial()) { - TutorialManager::instance().activateTutorial("MainWindow", firstStepsTutorial); + TutorialManager::instance().activateTutorial("MainWindow", + firstStepsTutorial); } } else { log::error("{} missing", firstStepsTutorial); @@ -1203,13 +1252,17 @@ void MainWindow::showEvent(QShowEvent *event) pos.rx() += ui->toolBar->width() / 2; pos.ry() += ui->toolBar->height(); QWhatsThis::showText(pos, - QObject::tr("Please use \"Help\" from the toolbar to get usage instructions to all elements")); + QObject::tr("Please use \"Help\" from the toolbar to get " + "usage instructions to all elements")); } if (!m_OrganizerCore.managedGame()->getSupportURL().isEmpty()) { QMessageBox::information(this, tr("Game Support Wiki"), - tr("Do you know how to mod this game? Do you need to learn? There's a game support wiki available! " - "Click OK to open the wiki. In the future, you can access this link from the \"Help\" menu."), QMessageBox::Ok); + tr("Do you know how to mod this game? Do you need to " + "learn? There's a game support wiki available! " + "Click OK to open the wiki. In the future, you can " + "access this link from the \"Help\" menu."), + QMessageBox::Ok); gameSupportTriggered(); } @@ -1314,9 +1367,10 @@ void MainWindow::closeEvent(QCloseEvent* event) bool MainWindow::canExit() { if (m_OrganizerCore.downloadManager()->downloadsInProgressNoPause()) { - if (QMessageBox::question(this, tr("Downloads in progress"), - tr("There are still downloads in progress, do you really want to quit?"), - QMessageBox::Yes | QMessageBox::Cancel) == QMessageBox::Cancel) { + if (QMessageBox::question( + this, tr("Downloads in progress"), + tr("There are still downloads in progress, do you really want to quit?"), + QMessageBox::Yes | QMessageBox::Cancel) == QMessageBox::Cancel) { return false; } else { m_OrganizerCore.downloadManager()->pauseAll(); @@ -1345,7 +1399,7 @@ void MainWindow::cleanup() m_MetaSave.waitForFinished(); } -bool MainWindow::eventFilter(QObject *object, QEvent *event) +bool MainWindow::eventFilter(QObject* object, QEvent* event) { if (event->type() == QEvent::StatusTip && object != this) { QMainWindow::event(event); @@ -1355,7 +1409,7 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) return false; } -void MainWindow::registerPluginTool(IPluginTool *tool, QString name, QMenu *menu) +void MainWindow::registerPluginTool(IPluginTool* tool, QString name, QMenu* menu) { if (!menu) { menu = ui->actionTool->menu(); @@ -1364,20 +1418,22 @@ void MainWindow::registerPluginTool(IPluginTool *tool, QString name, QMenu *menu if (name.isEmpty()) name = tool->displayName(); - QAction *action = new QAction(tool->icon(), name, menu); + QAction* action = new QAction(tool->icon(), name, menu); action->setToolTip(tool->tooltip()); tool->setParentWidget(this); - connect(action, &QAction::triggered, this, [this, tool]() { - try { - tool->display(); - } - catch (const std::exception& e) { - reportError(tr("Plugin \"%1\" failed: %2").arg(tool->localizedName()).arg(e.what())); - } - catch (...) { - reportError(tr("Plugin \"%1\" failed").arg(tool->localizedName())); - } - }, Qt::QueuedConnection); + connect( + action, &QAction::triggered, this, + [this, tool]() { + try { + tool->display(); + } catch (const std::exception& e) { + reportError( + tr("Plugin \"%1\" failed: %2").arg(tool->localizedName()).arg(e.what())); + } catch (...) { + reportError(tr("Plugin \"%1\" failed").arg(tool->localizedName())); + } + }, + Qt::QueuedConnection); menu->addAction(action); } @@ -1391,63 +1447,64 @@ void MainWindow::updateToolMenu() // Sort the plugins by display name std::sort(std::begin(toolPlugins), std::end(toolPlugins), - [](IPluginTool *left, IPluginTool *right) { - return left->displayName().toLower() < right->displayName().toLower(); - } - ); + [](IPluginTool* left, IPluginTool* right) { + return left->displayName().toLower() < right->displayName().toLower(); + }); // Remove disabled plugins: - toolPlugins.erase( - std::remove_if(std::begin(toolPlugins), std::end(toolPlugins), [&](auto* tool) { - return !m_PluginContainer.isEnabled(tool); - }), - toolPlugins.end()); + toolPlugins.erase(std::remove_if(std::begin(toolPlugins), std::end(toolPlugins), + [&](auto* tool) { + return !m_PluginContainer.isEnabled(tool); + }), + toolPlugins.end()); // Group the plugins into submenus - QMap<QString, QList<QPair<QString, IPluginTool *>>> submenuMap; + QMap<QString, QList<QPair<QString, IPluginTool*>>> submenuMap; for (auto toolPlugin : toolPlugins) { QStringList toolName = toolPlugin->displayName().split("/"); - QString submenu = toolName[0]; + QString submenu = toolName[0]; toolName.pop_front(); - submenuMap[submenu].append(QPair<QString, IPluginTool *>(toolName.join("/"), toolPlugin)); + submenuMap[submenu].append( + QPair<QString, IPluginTool*>(toolName.join("/"), toolPlugin)); } // Start registering plugins for (auto submenuKey : submenuMap.keys()) { if (submenuMap[submenuKey].length() > 1) { - QMenu *submenu = new QMenu(submenuKey, this); + QMenu* submenu = new QMenu(submenuKey, this); for (auto info : submenuMap[submenuKey]) { registerPluginTool(info.second, info.first, submenu); } ui->actionTool->menu()->addMenu(submenu); - } - else { + } else { registerPluginTool(submenuMap[submenuKey].front().second); } } } -void MainWindow::registerModPage(IPluginModPage *modPage) +void MainWindow::registerModPage(IPluginModPage* modPage) { - QAction *action = new QAction(modPage->icon(), modPage->displayName(), this); - connect(action, &QAction::triggered, this, [this, modPage]() { - if (modPage->useIntegratedBrowser()) { + QAction* action = new QAction(modPage->icon(), modPage->displayName(), this); + connect( + action, &QAction::triggered, this, + [this, modPage]() { + if (modPage->useIntegratedBrowser()) { - if (!m_IntegratedBrowser) { - m_IntegratedBrowser.reset(new BrowserDialog); + if (!m_IntegratedBrowser) { + m_IntegratedBrowser.reset(new BrowserDialog); - connect( - m_IntegratedBrowser.get(), SIGNAL(requestDownload(QUrl, QNetworkReply*)), - &m_OrganizerCore, SLOT(requestDownload(QUrl, QNetworkReply*))); - } + connect(m_IntegratedBrowser.get(), + SIGNAL(requestDownload(QUrl, QNetworkReply*)), &m_OrganizerCore, + SLOT(requestDownload(QUrl, QNetworkReply*))); + } - m_IntegratedBrowser->setWindowTitle(modPage->displayName()); - m_IntegratedBrowser->openUrl(modPage->pageURL()); - } - else { - shell::Open(QUrl(modPage->pageURL())); - } - }, Qt::QueuedConnection); + m_IntegratedBrowser->setWindowTitle(modPage->displayName()); + m_IntegratedBrowser->openUrl(modPage->pageURL()); + } else { + shell::Open(QUrl(modPage->pageURL())); + } + }, + Qt::QueuedConnection); ui->actionModPage->menu()->addAction(action); } @@ -1465,15 +1522,16 @@ bool MainWindow::registerNexusPage(const QString& gameName) return false; // Create an action - QAction* action = new QAction( - plugin->gameIcon(), - QObject::tr("Visit %1 on Nexus").arg(gameName), - this); + QAction* action = new QAction(plugin->gameIcon(), + QObject::tr("Visit %1 on Nexus").arg(gameName), this); // Bind the action - connect(action, &QAction::triggered, this, [this, gameURL]() { - shell::Open(QUrl(gameURL)); - }, Qt::QueuedConnection); + connect( + action, &QAction::triggered, this, + [this, gameURL]() { + shell::Open(QUrl(gameURL)); + }, + Qt::QueuedConnection); // Add the action ui->actionModPage->menu()->addAction(action); @@ -1487,21 +1545,22 @@ void MainWindow::updateModPageMenu() ui->actionModPage->menu()->clear(); // Determine the loaded mod page plugins - std::vector<IPluginModPage*> modPagePlugins = m_PluginContainer.plugins<IPluginModPage>(); + std::vector<IPluginModPage*> modPagePlugins = + m_PluginContainer.plugins<IPluginModPage>(); // Sort the plugins by display name std::sort(std::begin(modPagePlugins), std::end(modPagePlugins), - [](IPluginModPage* left, IPluginModPage* right) { - return left->displayName().toLower() < right->displayName().toLower(); - } - ); + [](IPluginModPage* left, IPluginModPage* right) { + return left->displayName().toLower() < right->displayName().toLower(); + }); // Remove disabled plugins - modPagePlugins.erase( - std::remove_if(std::begin(modPagePlugins), std::end(modPagePlugins), [&](auto* tool) { - return !m_PluginContainer.isEnabled(tool); - }), - modPagePlugins.end()); + modPagePlugins.erase(std::remove_if(std::begin(modPagePlugins), + std::end(modPagePlugins), + [&](auto* tool) { + return !m_PluginContainer.isEnabled(tool); + }), + modPagePlugins.end()); for (auto* modPagePlugin : modPagePlugins) { registerModPage(modPagePlugin); @@ -1515,8 +1574,7 @@ void MainWindow::updateModPageMenu() registeredSources << gameShortName; // Add the primary sources - for (auto gameName : m_OrganizerCore.managedGame()->primarySources()) - { + for (auto gameName : m_OrganizerCore.managedGame()->primarySources()) { if (!registeredSources.contains(gameName) && registerNexusPage(gameName)) registeredSources << gameName; } @@ -1528,18 +1586,17 @@ void MainWindow::updateModPageMenu() // Add the secondary games (sorted) QStringList secondaryGames = m_OrganizerCore.managedGame()->validShortNames(); secondaryGames.sort(Qt::CaseInsensitive); - for (auto gameName : secondaryGames) - { + for (auto gameName : secondaryGames) { if (!registeredSources.contains(gameName) && registerNexusPage(gameName)) registeredSources << gameName; } // No mod page plugin and the menu was visible - bool keepOriginalAction = modPagePlugins.size() == 0 && registeredSources.length() <= 1; + bool keepOriginalAction = + modPagePlugins.size() == 0 && registeredSources.length() <= 1; if (keepOriginalAction) { ui->toolBar->insertAction(ui->actionAdd_Profile, ui->actionNexus); - } - else { + } else { ui->toolBar->removeAction(ui->actionNexus); } ui->actionModPage->setVisible(!keepOriginalAction); @@ -1547,7 +1604,7 @@ void MainWindow::updateModPageMenu() void MainWindow::startExeAction() { - QAction *action = qobject_cast<QAction*>(sender()); + QAction* action = qobject_cast<QAction*>(sender()); if (action == nullptr) { log::error("not an action?"); @@ -1557,7 +1614,7 @@ void MainWindow::startExeAction() const auto& list = *m_OrganizerCore.executablesList(); const auto title = action->text(); - auto itor = list.find(title); + auto itor = list.find(title); if (itor == list.end()) { log::warn("startExeAction(): executable '{}' not found", title); @@ -1565,12 +1622,14 @@ void MainWindow::startExeAction() } action->setEnabled(false); - Guard g([&]{ action->setEnabled(true); }); + Guard g([&] { + action->setEnabled(true); + }); m_OrganizerCore.processRunner() - .setFromExecutable(*itor) - .setWaitForCompletion(ProcessRunner::TriggerRefresh) - .run(); + .setFromExecutable(*itor) + .setWaitForCompletion(ProcessRunner::TriggerRefresh) + .run(); } void MainWindow::activateSelectedProfile() @@ -1594,8 +1653,7 @@ void MainWindow::on_profileBox_currentIndexChanged(int index) m_OldProfileIndex = index; // select has changed, save stuff - if ((previousIndex != -1) && - (m_OrganizerCore.currentProfile() != nullptr) && + if ((previousIndex != -1) && (m_OrganizerCore.currentProfile() != nullptr) && m_OrganizerCore.currentProfile()->exists()) { m_OrganizerCore.saveCurrentLists(); } @@ -1603,10 +1661,9 @@ void MainWindow::on_profileBox_currentIndexChanged(int index) // Avoid doing any refresh if currentProfile is already set but previous // index was -1 as it means that this is happening during initialization so // everything has already been set. - if (previousIndex == -1 - && m_OrganizerCore.currentProfile() != nullptr - && m_OrganizerCore.currentProfile()->exists() - && ui->profileBox->currentText() == m_OrganizerCore.currentProfile()->name()){ + if (previousIndex == -1 && m_OrganizerCore.currentProfile() != nullptr && + m_OrganizerCore.currentProfile()->exists() && + ui->profileBox->currentText() == m_OrganizerCore.currentProfile()->name()) { return; } @@ -1616,7 +1673,6 @@ void MainWindow::on_profileBox_currentIndexChanged(int index) ui->profileBox->setCurrentIndex(ui->profileBox->count() - 1); } - // handle <manage> item if (ui->profileBox->currentIndex() == 0) { // remember the profile name that was selected before, previousIndex can't @@ -1657,17 +1713,17 @@ void MainWindow::on_profileBox_currentIndexChanged(int index) return; } - activateSelectedProfile(); - LocalSavegames *saveGames = m_OrganizerCore.managedGame()->feature<LocalSavegames>(); + LocalSavegames* saveGames = m_OrganizerCore.managedGame()->feature<LocalSavegames>(); if (saveGames != nullptr) { if (saveGames->prepareProfile(m_OrganizerCore.currentProfile())) { m_SavesTab->refreshSaveList(); } } - BSAInvalidation *invalidation = m_OrganizerCore.managedGame()->feature<BSAInvalidation>(); + BSAInvalidation* invalidation = + m_OrganizerCore.managedGame()->feature<BSAInvalidation>(); if (invalidation != nullptr) { if (invalidation->prepareProfile(m_OrganizerCore.currentProfile())) { QTimer::singleShot(5, &m_OrganizerCore, SLOT(profileRefresh())); @@ -1695,7 +1751,9 @@ bool MainWindow::refreshProfiles(bool selectProfile, QString newProfile) try { profileBox->addItem(profileIter.fileName()); } catch (const std::runtime_error& error) { - reportError(QObject::tr("failed to parse profile %1: %2").arg(profileIter.fileName()).arg(error.what())); + reportError(QObject::tr("failed to parse profile %1: %2") + .arg(profileIter.fileName()) + .arg(error.what())); } } @@ -1706,8 +1764,7 @@ bool MainWindow::refreshProfiles(bool selectProfile, QString newProfile) if (profileBox->count() > 1) { if (newProfile.isEmpty()) { profileBox->setCurrentText(currentProfileName); - } - else { + } else { profileBox->setCurrentText(newProfile); } if (profileBox->currentIndex() == 0) { @@ -1720,7 +1777,7 @@ bool MainWindow::refreshProfiles(bool selectProfile, QString newProfile) void MainWindow::refreshExecutablesList() { - QAbstractItemModel *model = ui->executablesListBox->model(); + QAbstractItemModel* model = ui->executablesListBox->model(); auto add = [&](const QString& title, const QFileInfo& binary) { QIcon icon; @@ -1732,13 +1789,11 @@ void MainWindow::refreshExecutablesList() const auto i = ui->executablesListBox->count() - 1; - model->setData( - model->index(i, 0), - QSize(0, ui->executablesListBox->iconSize().height() + 4), - Qt::SizeHintRole); + model->setData(model->index(i, 0), + QSize(0, ui->executablesListBox->iconSize().height() + 4), + Qt::SizeHintRole); }; - ui->executablesListBox->setEnabled(false); ui->executablesListBox->clear(); @@ -1760,7 +1815,8 @@ void MainWindow::refreshExecutablesList() ui->executablesListBox->setEnabled(true); } -static bool BySortValue(const std::pair<UINT32, QTreeWidgetItem*> &LHS, const std::pair<UINT32, QTreeWidgetItem*> &RHS) +static bool BySortValue(const std::pair<UINT32, QTreeWidgetItem*>& LHS, + const std::pair<UINT32, QTreeWidgetItem*>& RHS) { return LHS.first < RHS.first; } @@ -1775,27 +1831,32 @@ static QStringList toStringList(InputIterator current, InputIterator end) return result; } -void MainWindow::updateBSAList(const QStringList &defaultArchives, const QStringList &activeArchives) +void MainWindow::updateBSAList(const QStringList& defaultArchives, + const QStringList& activeArchives) { m_DefaultArchives = defaultArchives; ui->bsaList->clear(); ui->bsaList->header()->setSectionResizeMode(QHeaderView::ResizeToContents); std::vector<std::pair<UINT32, QTreeWidgetItem*>> items; - BSAInvalidation * invalidation = m_OrganizerCore.managedGame()->feature<BSAInvalidation>(); + BSAInvalidation* invalidation = + m_OrganizerCore.managedGame()->feature<BSAInvalidation>(); std::vector<FileEntryPtr> files = m_OrganizerCore.directoryStructure()->getFiles(); - QStringList plugins = m_OrganizerCore.findFiles("", [](const QString &fileName) -> bool { - return fileName.endsWith(".esp", Qt::CaseInsensitive) - || fileName.endsWith(".esm", Qt::CaseInsensitive) - || fileName.endsWith(".esl", Qt::CaseInsensitive); - }); + QStringList plugins = + m_OrganizerCore.findFiles("", [](const QString& fileName) -> bool { + return fileName.endsWith(".esp", Qt::CaseInsensitive) || + fileName.endsWith(".esm", Qt::CaseInsensitive) || + fileName.endsWith(".esl", Qt::CaseInsensitive); + }); - auto hasAssociatedPlugin = [&](const QString &bsaName) -> bool { - for (const QString &pluginName : plugins) { + auto hasAssociatedPlugin = [&](const QString& bsaName) -> bool { + for (const QString& pluginName : plugins) { QFileInfo pluginInfo(pluginName); - if (bsaName.startsWith(QFileInfo(pluginName).completeBaseName(), Qt::CaseInsensitive) - && (m_OrganizerCore.pluginList()->state(pluginInfo.fileName()) == IPluginList::STATE_ACTIVE)) { + if (bsaName.startsWith(QFileInfo(pluginName).completeBaseName(), + Qt::CaseInsensitive) && + (m_OrganizerCore.pluginList()->state(pluginInfo.fileName()) == + IPluginList::STATE_ACTIVE)) { return true; } } @@ -1809,28 +1870,29 @@ void MainWindow::updateBSAList(const QStringList &defaultArchives, const QString int index = activeArchives.indexOf(fileInfo.fileName()); if (index == -1) { index = 0xFFFF; - } - else { + } else { index += 2; } - if ((invalidation != nullptr) && invalidation->isInvalidationBSA(fileInfo.fileName())) { + if ((invalidation != nullptr) && + invalidation->isInvalidationBSA(fileInfo.fileName())) { index = 1; } int originId = current->getOrigin(); - FilesOrigin & origin = m_OrganizerCore.directoryStructure()->getOriginByID(originId); + FilesOrigin& origin = + m_OrganizerCore.directoryStructure()->getOriginByID(originId); - QTreeWidgetItem * newItem = new QTreeWidgetItem(QStringList() - << fileInfo.fileName() - << ToQString(origin.getName())); + QTreeWidgetItem* newItem = new QTreeWidgetItem( + QStringList() << fileInfo.fileName() << ToQString(origin.getName())); newItem->setData(0, Qt::UserRole, index); newItem->setData(1, Qt::UserRole, originId); - newItem->setFlags(newItem->flags() & ~(Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable)); + newItem->setFlags(newItem->flags() & + ~(Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable)); newItem->setCheckState(0, (index != -1) ? Qt::Checked : Qt::Unchecked); newItem->setData(0, Qt::UserRole, false); - if (m_OrganizerCore.settings().game().forceEnableCoreFiles() - && defaultArchives.contains(fileInfo.fileName())) { + if (m_OrganizerCore.settings().game().forceEnableCoreFiles() && + defaultArchives.contains(fileInfo.fileName())) { newItem->setCheckState(0, Qt::Checked); newItem->setDisabled(true); newItem->setData(0, Qt::UserRole, true); @@ -1844,7 +1906,8 @@ void MainWindow::updateBSAList(const QStringList &defaultArchives, const QString newItem->setCheckState(0, Qt::Unchecked); newItem->setDisabled(true); } - if (index < 0) index = 0; + if (index < 0) + index = 0; UINT32 sortValue = ((origin.getPriority() & 0xFFFF) << 16) | (index & 0xFFFF); items.push_back(std::make_pair(sortValue, newItem)); @@ -1855,7 +1918,8 @@ void MainWindow::updateBSAList(const QStringList &defaultArchives, const QString for (auto iter = items.begin(); iter != items.end(); ++iter) { int originID = iter->second->data(1, Qt::UserRole).toInt(); - const FilesOrigin& origin = m_OrganizerCore.directoryStructure()->getOriginByID(originID); + const FilesOrigin& origin = + m_OrganizerCore.directoryStructure()->getOriginByID(originID); QString modName; const unsigned int modIndex = ModInfo::getIndex(ToQString(origin.getName())); @@ -1864,15 +1928,15 @@ void MainWindow::updateBSAList(const QStringList &defaultArchives, const QString modName = UnmanagedModName(); } else { ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex); - modName = modInfo->name(); + modName = modInfo->name(); } - QList<QTreeWidgetItem*> items = ui->bsaList->findItems(modName, Qt::MatchFixedString); - QTreeWidgetItem * subItem = nullptr; + QList<QTreeWidgetItem*> items = + ui->bsaList->findItems(modName, Qt::MatchFixedString); + QTreeWidgetItem* subItem = nullptr; if (items.length() > 0) { subItem = items.at(0); - } - else { + } else { subItem = new QTreeWidgetItem(QStringList(modName)); subItem->setFlags(subItem->flags() & ~Qt::ItemIsDragEnabled); ui->bsaList->addTopLevelItem(subItem); @@ -1885,29 +1949,32 @@ void MainWindow::updateBSAList(const QStringList &defaultArchives, const QString void MainWindow::checkBSAList() { - DataArchives * archives = m_OrganizerCore.managedGame()->feature<DataArchives>(); + DataArchives* archives = m_OrganizerCore.managedGame()->feature<DataArchives>(); if (archives != nullptr) { ui->bsaList->blockSignals(true); - ON_BLOCK_EXIT([&]() { ui->bsaList->blockSignals(false); }); + ON_BLOCK_EXIT([&]() { + ui->bsaList->blockSignals(false); + }); QStringList defaultArchives = archives->archives(m_OrganizerCore.currentProfile()); bool warning = false; for (int i = 0; i < ui->bsaList->topLevelItemCount(); ++i) { - bool modWarning = false; - QTreeWidgetItem * tlItem = ui->bsaList->topLevelItem(i); + bool modWarning = false; + QTreeWidgetItem* tlItem = ui->bsaList->topLevelItem(i); for (int j = 0; j < tlItem->childCount(); ++j) { - QTreeWidgetItem * item = tlItem->child(j); - QString filename = item->text(0); + QTreeWidgetItem* item = tlItem->child(j); + QString filename = item->text(0); item->setIcon(0, QIcon()); item->setToolTip(0, QString()); if (item->checkState(0) == Qt::Unchecked) { if (defaultArchives.contains(filename)) { item->setIcon(0, QIcon(":/MO/gui/warning")); - item->setToolTip(0, tr("This bsa is enabled in the ini file so it may be required!")); + item->setToolTip( + 0, tr("This bsa is enabled in the ini file so it may be required!")); modWarning = true; } } @@ -1940,10 +2007,10 @@ void MainWindow::saveModMetas() void MainWindow::fixCategories() { for (unsigned int i = 0; i < ModInfo::getNumMods(); ++i) { - ModInfo::Ptr modInfo = ModInfo::getByIndex(i); + ModInfo::Ptr modInfo = ModInfo::getByIndex(i); std::set<int> categories = modInfo->getCategories(); - for (std::set<int>::iterator iter = categories.begin(); - iter != categories.end(); ++iter) { + for (std::set<int>::iterator iter = categories.begin(); iter != categories.end(); + ++iter) { if (!m_CategoryFactory.categoryExists(*iter)) { modInfo->setCategory(*iter, false); } @@ -1958,20 +2025,19 @@ void MainWindow::setupNetworkProxy(bool activate) void MainWindow::activateProxy(bool activate) { - QProgressDialog busyDialog(tr("Activating Network Proxy"), QString(), 0, 0, parentWidget()); - busyDialog.setWindowFlags(busyDialog.windowFlags() & ~Qt::WindowContextHelpButtonHint); + QProgressDialog busyDialog(tr("Activating Network Proxy"), QString(), 0, 0, + parentWidget()); + busyDialog.setWindowFlags(busyDialog.windowFlags() & + ~Qt::WindowContextHelpButtonHint); busyDialog.setWindowModality(Qt::WindowModal); busyDialog.show(); QFutureWatcher<void> futureWatcher; QEventLoop loop; - connect(&futureWatcher, &QFutureWatcher<void>::finished, - &loop, &QEventLoop::quit, + connect(&futureWatcher, &QFutureWatcher<void>::finished, &loop, &QEventLoop::quit, Qt::QueuedConnection); - futureWatcher.setFuture( - QtConcurrent::run(MainWindow::setupNetworkProxy, activate) - ); + futureWatcher.setFuture(QtConcurrent::run(MainWindow::setupNetworkProxy, activate)); // wait for setupNetworkProxy while keeping ui responsive loop.exec(); @@ -2023,11 +2089,12 @@ void MainWindow::readSettings() } } -void MainWindow::processUpdates() { - auto& settings = m_OrganizerCore.settings(); +void MainWindow::processUpdates() +{ + auto& settings = m_OrganizerCore.settings(); const auto earliest = QVersionNumber::fromString("2.1.2").normalized(); - const auto lastVersion = settings.version().value_or(earliest); + const auto lastVersion = settings.version().value_or(earliest); const auto currentVersion = m_OrganizerCore.getVersion().asQVersionNumber(); settings.processUpdates(currentVersion, lastVersion); @@ -2039,24 +2106,25 @@ void MainWindow::processUpdates() { if (lastVersion < QVersionNumber(2, 2, 1)) { // hide new columns by default - for (int i=DownloadList::COL_MODNAME; i<DownloadList::COL_COUNT; ++i) { + for (int i = DownloadList::COL_MODNAME; i < DownloadList::COL_COUNT; ++i) { ui->downloadView->header()->hideSection(i); } } if (lastVersion < QVersionNumber(2, 3)) { - for (int i=1; i<ui->dataTree->header()->count(); ++i) + for (int i = 1; i < ui->dataTree->header()->count(); ++i) ui->dataTree->setColumnWidth(i, 150); } } if (currentVersion < lastVersion) { - const auto text = tr( - "Notice: Your current MO version (%1) is lower than the previously used one (%2). " - "The GUI may not downgrade gracefully, so you may experience oddities. " - "However, there should be no serious issues.") - .arg(currentVersion.toString()) - .arg(lastVersion.toString()); + const auto text = + tr("Notice: Your current MO version (%1) is lower than the previously used one " + "(%2). " + "The GUI may not downgrade gracefully, so you may experience oddities. " + "However, there should be no serious issues.") + .arg(currentVersion.toString()) + .arg(lastVersion.toString()); log::warn("{}", text); } @@ -2118,12 +2186,14 @@ void MainWindow::on_startButton_clicked() } ui->startButton->setEnabled(false); - Guard g([&]{ ui->startButton->setEnabled(true); }); + Guard g([&] { + ui->startButton->setEnabled(true); + }); m_OrganizerCore.processRunner() - .setFromExecutable(*selectedExecutable) - .setWaitForCompletion(ProcessRunner::TriggerRefresh) - .run(); + .setFromExecutable(*selectedExecutable) + .setWaitForCompletion(ProcessRunner::TriggerRefresh) + .run(); } bool MainWindow::modifyExecutablesDialog(int selection) @@ -2137,7 +2207,7 @@ bool MainWindow::modifyExecutablesDialog(int selection) refreshExecutablesList(); updatePinnedExecutables(); - } catch (const std::exception &e) { + } catch (const std::exception& e) { reportError(e.what()); } @@ -2150,8 +2220,7 @@ void MainWindow::on_executablesListBox_currentIndexChanged(int index) return; } - const int previousIndex = - (m_OldExecutableIndex > 0 ? m_OldExecutableIndex : 1); + const int previousIndex = (m_OldExecutableIndex > 0 ? m_OldExecutableIndex : 1); m_OldExecutableIndex = index; @@ -2194,12 +2263,15 @@ void MainWindow::issueTriggered() void MainWindow::tutorialTriggered() { - QAction *tutorialAction = qobject_cast<QAction*>(sender()); + QAction* tutorialAction = qobject_cast<QAction*>(sender()); if (tutorialAction != nullptr) { if (QMessageBox::question(this, tr("Start Tutorial?"), - tr("You're about to start a tutorial. For technical reasons it's not possible to end " - "the tutorial early. Continue?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - TutorialManager::instance().activateTutorial("MainWindow", tutorialAction->data().toString()); + tr("You're about to start a tutorial. For technical " + "reasons it's not possible to end " + "the tutorial early. Continue?"), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + TutorialManager::instance().activateTutorial("MainWindow", + tutorialAction->data().toString()); } } } @@ -2218,28 +2290,30 @@ void MainWindow::on_actionAdd_Profile_triggered() { for (;;) { ProfilesDialog profilesDialog(m_OrganizerCore.currentProfile()->name(), - m_OrganizerCore, - this); + m_OrganizerCore, this); - // workaround: need to disable monitoring of the saves directory, otherwise the active - // profile directory is locked + // workaround: need to disable monitoring of the saves directory, otherwise the + // active profile directory is locked m_SavesTab->stopMonitorSaves(); profilesDialog.exec(); - m_SavesTab->refreshSaveList(); // since the save list may now be outdated we have to refresh it completely + m_SavesTab->refreshSaveList(); // since the save list may now be outdated we have + // to refresh it completely - if (refreshProfiles(true, profilesDialog.selectedProfile().value_or("")) && !profilesDialog.failed()) { + if (refreshProfiles(true, profilesDialog.selectedProfile().value_or("")) && + !profilesDialog.failed()) { break; } } - LocalSavegames *saveGames = m_OrganizerCore.managedGame()->feature<LocalSavegames>(); + LocalSavegames* saveGames = m_OrganizerCore.managedGame()->feature<LocalSavegames>(); if (saveGames != nullptr) { if (saveGames->prepareProfile(m_OrganizerCore.currentProfile())) { m_SavesTab->refreshSaveList(); } } - BSAInvalidation *invalidation = m_OrganizerCore.managedGame()->feature<BSAInvalidation>(); + BSAInvalidation* invalidation = + m_OrganizerCore.managedGame()->feature<BSAInvalidation>(); if (invalidation != nullptr) { if (invalidation->prepareProfile(m_OrganizerCore.currentProfile())) { QTimer::singleShot(5, &m_OrganizerCore, SLOT(profileRefresh())); @@ -2249,7 +2323,7 @@ void MainWindow::on_actionAdd_Profile_triggered() void MainWindow::on_actionModify_Executables_triggered() { - const auto sel = (m_OldExecutableIndex > 0 ? m_OldExecutableIndex - 1 : 0); + const auto sel = (m_OldExecutableIndex > 0 ? m_OldExecutableIndex - 1 : 0); if (modifyExecutablesDialog(sel)) { const auto newCount = ui->executablesListBox->count(); @@ -2274,13 +2348,13 @@ void MainWindow::refresherProgress(const DirectoryRefreshProgress* p) void MainWindow::onDirectoryStructureChanged() { - // some problem-reports may rely on the virtual directory tree so they need to be updated - // now + // some problem-reports may rely on the virtual directory tree so they need to be + // updated now scheduleCheckForProblems(); m_DataTab->updateTree(); } -void MainWindow::modInstalled(const QString &modName) +void MainWindow::modInstalled(const QString& modName) { if (!m_OrganizerCore.settings().interface().checkUpdateAfterInstallation()) { return; @@ -2293,20 +2367,21 @@ void MainWindow::modInstalled(const QString &modName) } // force an update to happen - ui->modList->actions().checkModsForUpdates({ m_OrganizerCore.modList()->index(index, 0) }); + ui->modList->actions().checkModsForUpdates( + {m_OrganizerCore.modList()->index(index, 0)}); } -void MainWindow::showMessage(const QString &message) +void MainWindow::showMessage(const QString& message) { MessageDialog::showMessage(message, this); } -void MainWindow::showError(const QString &message) +void MainWindow::showError(const QString& message) { reportError(message); } -void MainWindow::modRenamed(const QString &oldName, const QString &newName) +void MainWindow::modRenamed(const QString& oldName, const QString& newName) { Profile::renameModInAllProfiles(oldName, newName); @@ -2316,23 +2391,27 @@ void MainWindow::modRenamed(const QString &oldName, const QString &newName) // also fix the directory structure try { if (m_OrganizerCore.directoryStructure()->originExists(ToWString(oldName))) { - FilesOrigin &origin = m_OrganizerCore.directoryStructure()->getOriginByName(ToWString(oldName)); + FilesOrigin& origin = + m_OrganizerCore.directoryStructure()->getOriginByName(ToWString(oldName)); origin.setName(ToWString(newName)); } else { - } - } catch (const std::exception &e) { + } catch (const std::exception& e) { reportError(tr("failed to change origin name: %1").arg(e.what())); } } -void MainWindow::fileMoved(const QString &filePath, const QString &oldOriginName, const QString &newOriginName) +void MainWindow::fileMoved(const QString& filePath, const QString& oldOriginName, + const QString& newOriginName) { - const FileEntryPtr filePtr = m_OrganizerCore.directoryStructure()->findFile(ToWString(filePath)); + const FileEntryPtr filePtr = + m_OrganizerCore.directoryStructure()->findFile(ToWString(filePath)); if (filePtr.get() != nullptr) { try { - if (m_OrganizerCore.directoryStructure()->originExists(ToWString(newOriginName))) { - FilesOrigin &newOrigin = m_OrganizerCore.directoryStructure()->getOriginByName(ToWString(newOriginName)); + if (m_OrganizerCore.directoryStructure()->originExists( + ToWString(newOriginName))) { + FilesOrigin& newOrigin = m_OrganizerCore.directoryStructure()->getOriginByName( + ToWString(newOriginName)); QString fullNewPath = ToQString(newOrigin.getPath()) + "\\" + filePath; WIN32_FIND_DATAW findData; @@ -2341,31 +2420,38 @@ void MainWindow::fileMoved(const QString &filePath, const QString &oldOriginName filePtr->addOrigin(newOrigin.getID(), findData.ftCreationTime, L"", -1); FindClose(hFind); } - if (m_OrganizerCore.directoryStructure()->originExists(ToWString(oldOriginName))) { - FilesOrigin &oldOrigin = m_OrganizerCore.directoryStructure()->getOriginByName(ToWString(oldOriginName)); + if (m_OrganizerCore.directoryStructure()->originExists( + ToWString(oldOriginName))) { + FilesOrigin& oldOrigin = m_OrganizerCore.directoryStructure()->getOriginByName( + ToWString(oldOriginName)); filePtr->removeOrigin(oldOrigin.getID()); } - } catch (const std::exception &e) { - reportError(tr("failed to move \"%1\" from mod \"%2\" to \"%3\": %4").arg(filePath).arg(oldOriginName).arg(newOriginName).arg(e.what())); + } catch (const std::exception& e) { + reportError(tr("failed to move \"%1\" from mod \"%2\" to \"%3\": %4") + .arg(filePath) + .arg(oldOriginName) + .arg(newOriginName) + .arg(e.what())); } } else { // this is probably not an error, the specified path is likely a directory } } -void MainWindow::modRemoved(const QString &fileName) +void MainWindow::modRemoved(const QString& fileName) { if (!fileName.isEmpty() && !QFileInfo(fileName).isAbsolute()) { m_OrganizerCore.downloadManager()->markUninstalled(fileName); } } -void MainWindow::windowTutorialFinished(const QString &windowName) +void MainWindow::windowTutorialFinished(const QString& windowName) { m_OrganizerCore.settings().interface().setTutorialCompleted(windowName); } -void MainWindow::displayModInformation(ModInfo::Ptr modInfo, unsigned int modIndex, ModInfoTabIDs tabID) +void MainWindow::displayModInformation(ModInfo::Ptr modInfo, unsigned int modIndex, + ModInfoTabIDs tabID) { ui->modList->actions().displayModInformation(modInfo, modIndex, tabID); } @@ -2382,7 +2468,7 @@ void MainWindow::setWindowEnabled(bool enabled) void MainWindow::refreshProfile_activated() { - m_OrganizerCore.profileRefresh(); + m_OrganizerCore.profileRefresh(); } void MainWindow::saveArchiveList() @@ -2390,9 +2476,9 @@ void MainWindow::saveArchiveList() if (m_OrganizerCore.isArchivesInit()) { SafeWriteFile archiveFile(m_OrganizerCore.currentProfile()->getArchivesFileName()); for (int i = 0; i < ui->bsaList->topLevelItemCount(); ++i) { - QTreeWidgetItem * tlItem = ui->bsaList->topLevelItem(i); + QTreeWidgetItem* tlItem = ui->bsaList->topLevelItem(i); for (int j = 0; j < tlItem->childCount(); ++j) { - QTreeWidgetItem * item = tlItem->child(j); + QTreeWidgetItem* item = tlItem->child(j); if (item->checkState(0) == Qt::Checked) { archiveFile->write(item->text(0).toUtf8().append("\r\n")); } @@ -2417,13 +2503,15 @@ void MainWindow::openInstallFolder() void MainWindow::openPluginsFolder() { - QString pluginsPath = QCoreApplication::applicationDirPath() + "/" + ToQString(AppConfig::pluginPath()); + QString pluginsPath = + QCoreApplication::applicationDirPath() + "/" + ToQString(AppConfig::pluginPath()); shell::Explore(pluginsPath); } void MainWindow::openStylesheetsFolder() { - QString ssPath = QCoreApplication::applicationDirPath() + "/" + ToQString(AppConfig::stylesheetsPath()); + QString ssPath = QCoreApplication::applicationDirPath() + "/" + + ToQString(AppConfig::stylesheetsPath()); shell::Explore(ssPath); } @@ -2434,11 +2522,9 @@ void MainWindow::openProfileFolder() void MainWindow::openIniFolder() { - if (m_OrganizerCore.currentProfile()->localSettingsEnabled()) - { + if (m_OrganizerCore.currentProfile()->localSettingsEnabled()) { shell::Explore(m_OrganizerCore.currentProfile()->absolutePath()); - } - else { + } else { shell::Explore(m_OrganizerCore.managedGame()->documentsDirectory()); } } @@ -2463,33 +2549,36 @@ void MainWindow::openMyGamesFolder() shell::Explore(m_OrganizerCore.managedGame()->documentsDirectory()); } -QMenu *MainWindow::openFolderMenu() +QMenu* MainWindow::openFolderMenu() { - QMenu *FolderMenu = new QMenu(this); + QMenu* FolderMenu = new QMenu(this); // game folders that are not necessarily MO-specific - FolderMenu->addAction(tr("Open Game folder"), this, SLOT(openGameFolder())); - FolderMenu->addAction(tr("Open MyGames folder"), this, SLOT(openMyGamesFolder())); + FolderMenu->addAction(tr("Open Game folder"), this, SLOT(openGameFolder())); + FolderMenu->addAction(tr("Open MyGames folder"), this, SLOT(openMyGamesFolder())); FolderMenu->addAction(tr("Open INIs folder"), this, SLOT(openIniFolder())); - FolderMenu->addSeparator(); + FolderMenu->addSeparator(); // MO-specific folders that are related to modding the game - FolderMenu->addAction(tr("Open Instance folder"), this, SLOT(openInstanceFolder())); + FolderMenu->addAction(tr("Open Instance folder"), this, SLOT(openInstanceFolder())); FolderMenu->addAction(tr("Open Mods folder"), this, SLOT(openModsFolder())); - FolderMenu->addAction(tr("Open Profile folder"), this, SLOT(openProfileFolder())); - FolderMenu->addAction(tr("Open Downloads folder"), this, SLOT(openDownloadsFolder())); + FolderMenu->addAction(tr("Open Profile folder"), this, SLOT(openProfileFolder())); + FolderMenu->addAction(tr("Open Downloads folder"), this, SLOT(openDownloadsFolder())); - FolderMenu->addSeparator(); + FolderMenu->addSeparator(); // MO-specific folders that are not directly related to modding and are either // in the installation folder or the instance - FolderMenu->addAction(tr("Open MO2 Install folder"), this, SLOT(openInstallFolder())); - FolderMenu->addAction(tr("Open MO2 Plugins folder"), this, SLOT(openPluginsFolder())); - FolderMenu->addAction(tr("Open MO2 Stylesheets folder"), this, SLOT(openStylesheetsFolder())); - FolderMenu->addAction(tr("Open MO2 Logs folder"), [=] { ui->logList->openLogsFolder(); }); + FolderMenu->addAction(tr("Open MO2 Install folder"), this, SLOT(openInstallFolder())); + FolderMenu->addAction(tr("Open MO2 Plugins folder"), this, SLOT(openPluginsFolder())); + FolderMenu->addAction(tr("Open MO2 Stylesheets folder"), this, + SLOT(openStylesheetsFolder())); + FolderMenu->addAction(tr("Open MO2 Logs folder"), [=] { + ui->logList->openLogsFolder(); + }); - return FolderMenu; + return FolderMenu; } void MainWindow::linkToolbar() @@ -2505,14 +2594,14 @@ void MainWindow::linkToolbar() void MainWindow::linkDesktop() { - if (auto* exe=getSelectedExecutable()) { + if (auto* exe = getSelectedExecutable()) { env::Shortcut(*exe).toggle(env::Shortcut::Desktop); } } void MainWindow::linkMenu() { - if (auto* exe=getSelectedExecutable()) { + if (auto* exe = getSelectedExecutable()) { env::Shortcut(*exe).toggle(env::Shortcut::StartMenu); } } @@ -2529,19 +2618,18 @@ void MainWindow::on_linkButton_pressed() env::Shortcut shortcut(*exe); - m_LinkToolbar->setIcon( - exe->isShownOnToolbar() ? removeIcon : addIcon); + m_LinkToolbar->setIcon(exe->isShownOnToolbar() ? removeIcon : addIcon); - m_LinkDesktop->setIcon( - shortcut.exists(env::Shortcut::Desktop) ? removeIcon : addIcon); + m_LinkDesktop->setIcon(shortcut.exists(env::Shortcut::Desktop) ? removeIcon + : addIcon); - m_LinkStartMenu->setIcon( - shortcut.exists(env::Shortcut::StartMenu) ? removeIcon : addIcon); + m_LinkStartMenu->setIcon(shortcut.exists(env::Shortcut::StartMenu) ? removeIcon + : addIcon); } void MainWindow::on_actionSettings_triggered() { - Settings &settings = m_OrganizerCore.settings(); + Settings& settings = m_OrganizerCore.settings(); QString oldModDirectory(settings.paths().mods()); QString oldCacheDirectory(settings.paths().cache()); @@ -2549,11 +2637,10 @@ void MainWindow::on_actionSettings_triggered() QString oldManagedGameDirectory(settings.game().directory().value_or("")); bool oldDisplayForeign(settings.interface().displayForeign()); bool oldArchiveParsing(settings.archiveParsing()); - bool proxy = settings.network().useProxy(); - DownloadManager *dlManager = m_OrganizerCore.downloadManager(); + bool proxy = settings.network().useProxy(); + DownloadManager* dlManager = m_OrganizerCore.downloadManager(); const bool oldCheckForUpdates = settings.checkForUpdates(); - const int oldMaxDumps = settings.diagnostics().maxCoreDumps(); - + const int oldMaxDumps = settings.diagnostics().maxCoreDumps(); SettingsDialog dialog(&m_PluginContainer, settings, this); dialog.exec(); @@ -2565,21 +2652,23 @@ void MainWindow::on_actionSettings_triggered() } if (e.testFlag(Exit::Restart)) { - const auto r = MOBase::TaskDialog(this) - .title(tr("Restart Mod Organizer")) - .main("Restart Mod Organizer") - .content(tr("Mod Organizer must restart to finish configuration changes")) - .icon(QMessageBox::Question) - .button({tr("Restart"), QMessageBox::Yes}) - .button({tr("Continue"), tr("Some things might be weird."), QMessageBox::No}) - .exec(); + const auto r = + MOBase::TaskDialog(this) + .title(tr("Restart Mod Organizer")) + .main("Restart Mod Organizer") + .content(tr("Mod Organizer must restart to finish configuration changes")) + .icon(QMessageBox::Question) + .button({tr("Restart"), QMessageBox::Yes}) + .button( + {tr("Continue"), tr("Some things might be weird."), QMessageBox::No}) + .exec(); if (r == QMessageBox::Yes) { ExitModOrganizer(e); } } - InstallationManager *instManager = m_OrganizerCore.installationManager(); + InstallationManager* instManager = m_OrganizerCore.installationManager(); instManager->setModsDirectory(settings.paths().mods()); instManager->setDownloadDirectory(settings.paths().downloads()); @@ -2604,21 +2693,17 @@ void MainWindow::on_actionSettings_triggered() } } - if ((settings.paths().mods() != oldModDirectory) - || (settings.interface().displayForeign() != oldDisplayForeign)) { + if ((settings.paths().mods() != oldModDirectory) || + (settings.interface().displayForeign() != oldDisplayForeign)) { m_OrganizerCore.profileRefresh(); } const auto state = settings.archiveParsing(); - if (state != oldArchiveParsing) - { - if (!state) - { + if (state != oldArchiveParsing) { + if (!state) { ui->dataTabShowFromArchives->setCheckState(Qt::Unchecked); ui->dataTabShowFromArchives->setEnabled(false); - } - else - { + } else { ui->dataTabShowFromArchives->setCheckState(Qt::Checked); ui->dataTabShowFromArchives->setEnabled(true); } @@ -2626,8 +2711,7 @@ void MainWindow::on_actionSettings_triggered() } if (settings.paths().cache() != oldCacheDirectory) { - NexusInterface::instance().setCacheDirectory( - settings.paths().cache()); + NexusInterface::instance().setCacheDirectory(settings.paths().cache()); } if (proxy != settings.network().useProxy()) { @@ -2663,30 +2747,31 @@ void MainWindow::onPluginRegistrationChanged() void MainWindow::on_actionNexus_triggered() { - const IPluginGame *game = m_OrganizerCore.managedGame(); - QString gameName = game->gameShortName(); + const IPluginGame* game = m_OrganizerCore.managedGame(); + QString gameName = game->gameShortName(); if (game->gameNexusName().isEmpty() && game->primarySources().count()) gameName = game->primarySources()[0]; shell::Open(QUrl(NexusInterface::instance().getGameURL(gameName))); } -void MainWindow::installTranslator(const QString &name) +void MainWindow::installTranslator(const QString& name) { - QTranslator *translator = new QTranslator(this); - QString fileName = name + "_" + m_CurrentLanguage; + QTranslator* translator = new QTranslator(this); + QString fileName = name + "_" + m_CurrentLanguage; if (!translator->load(fileName, qApp->applicationDirPath() + "/translations")) { if (m_CurrentLanguage.contains(QRegularExpression("^.*_(EN|en)(-.*)?$"))) { log::debug("localization file %s not found", fileName); - } // we don't actually expect localization files for English (en, en-us, en-uk, and any variation thereof) + } // we don't actually expect localization files for English (en, en-us, en-uk, and + // any variation thereof) } qApp->installTranslator(translator); m_Translators.push_back(translator); } -void MainWindow::languageChange(const QString &newLanguage) +void MainWindow::languageChange(const QString& newLanguage) { - for (QTranslator *trans : m_Translators) { + for (QTranslator* trans : m_Translators) { qApp->removeTranslator(trans); } m_Translators.clear(); @@ -2696,7 +2781,7 @@ void MainWindow::languageChange(const QString &newLanguage) installTranslator("qt"); installTranslator("qtbase"); installTranslator(ToQString(AppConfig::translationPrefix())); - for (const QString &fileName : m_PluginContainer.pluginFileNames()) { + for (const QString& fileName : m_PluginContainer.pluginFileNames()) { installTranslator(QFileInfo(fileName).baseName()); } ui->retranslateUi(this); @@ -2710,18 +2795,19 @@ void MainWindow::languageChange(const QString &newLanguage) m_DownloadsTab->update(); } - ui->listOptionsBtn->setMenu(new ModListGlobalContextMenu(m_OrganizerCore, ui->modList, this)); + ui->listOptionsBtn->setMenu( + new ModListGlobalContextMenu(m_OrganizerCore, ui->modList, this)); ui->openFolderMenu->setMenu(openFolderMenu()); } void MainWindow::originModified(int originID) { - FilesOrigin &origin = m_OrganizerCore.directoryStructure()->getOriginByID(originID); + FilesOrigin& origin = m_OrganizerCore.directoryStructure()->getOriginByID(originID); origin.enable(false); DirectoryStats dummy; m_OrganizerCore.directoryStructure()->addFromOrigin( - origin.getName(), origin.getPath(), origin.getPriority(), dummy); + origin.getName(), origin.getPath(), origin.getPriority(), dummy); DirectoryRefresher::cleanStructure(m_OrganizerCore.directoryStructure()); } @@ -2733,7 +2819,7 @@ void MainWindow::updateAvailable() ui->statusBar->setUpdateAvailable(true); } -void MainWindow::motdReceived(const QString &motd) +void MainWindow::motdReceived(const QString& motd) { // don't show motd after 5 seconds, may be annoying. Hopefully the user's // internet connection is faster next time @@ -2759,32 +2845,43 @@ void MainWindow::on_actionExit_triggered() void MainWindow::actionEndorseMO() { - // Normally this would be the managed game but MO2 is only uploaded to the Skyrim SE site right now - IPluginGame * game = m_OrganizerCore.getGame("skyrimse"); - if (!game) return; + // Normally this would be the managed game but MO2 is only uploaded to the Skyrim SE + // site right now + IPluginGame* game = m_OrganizerCore.getGame("skyrimse"); + if (!game) + return; - if (QMessageBox::question(this, tr("Endorse Mod Organizer"), - tr("Do you want to endorse Mod Organizer on %1 now?").arg( - NexusInterface::instance().getGameURL(game->gameShortName())), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + if (QMessageBox::question( + this, tr("Endorse Mod Organizer"), + tr("Do you want to endorse Mod Organizer on %1 now?") + .arg(NexusInterface::instance().getGameURL(game->gameShortName())), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { NexusInterface::instance().requestToggleEndorsement( - game->gameShortName(), game->nexusModOrganizerID(), m_OrganizerCore.getVersion().canonicalString(), true, this, QVariant(), QString()); + game->gameShortName(), game->nexusModOrganizerID(), + m_OrganizerCore.getVersion().canonicalString(), true, this, QVariant(), + QString()); } } void MainWindow::actionWontEndorseMO() { - // Normally this would be the managed game but MO2 is only uploaded to the Skyrim SE site right now - IPluginGame * game = m_OrganizerCore.getGame("skyrimse"); - if (!game) return; + // Normally this would be the managed game but MO2 is only uploaded to the Skyrim SE + // site right now + IPluginGame* game = m_OrganizerCore.getGame("skyrimse"); + if (!game) + return; - if (QMessageBox::question(this, tr("Abstain from Endorsing Mod Organizer"), - tr("Are you sure you want to abstain from endorsing Mod Organizer 2?\n" - "You will have to visit the mod page on the %1 Nexus site to change your mind.").arg( - NexusInterface::instance().getGameURL(game->gameShortName())), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + if (QMessageBox::question( + this, tr("Abstain from Endorsing Mod Organizer"), + tr("Are you sure you want to abstain from endorsing Mod Organizer 2?\n" + "You will have to visit the mod page on the %1 Nexus site to change your " + "mind.") + .arg(NexusInterface::instance().getGameURL(game->gameShortName())), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { NexusInterface::instance().requestToggleEndorsement( - game->gameShortName(), game->nexusModOrganizerID(), m_OrganizerCore.getVersion().canonicalString(), false, this, QVariant(), QString()); + game->gameShortName(), game->nexusModOrganizerID(), + m_OrganizerCore.getVersion().canonicalString(), false, this, QVariant(), + QString()); } } @@ -2802,25 +2899,21 @@ void MainWindow::toggleMO2EndorseState() bool enabled = false; QString text; - switch (s.nexus().endorsementState()) - { - case EndorsementState::Accepted: - { - text = tr("Thank you for endorsing MO2! :)"); - break; - } + switch (s.nexus().endorsementState()) { + case EndorsementState::Accepted: { + text = tr("Thank you for endorsing MO2! :)"); + break; + } - case EndorsementState::Refused: - { - text = tr("Please reconsider endorsing MO2 on Nexus!"); - break; - } + case EndorsementState::Refused: { + text = tr("Please reconsider endorsing MO2 on Nexus!"); + break; + } - case EndorsementState::NoDecision: - { - enabled = true; - break; - } + case EndorsementState::NoDecision: { + enabled = true; + break; + } } ui->actionEndorseMO->menu()->setEnabled(enabled); @@ -2842,17 +2935,21 @@ void MainWindow::nxmEndorsementsAvailable(QVariant userData, QVariant resultData games += m_OrganizerCore.managedGame()->gameShortName(); bool searchedMO2NexusGame = false; for (auto endorsementData : data) { - QVariantMap endorsement = endorsementData.toMap(); - std::pair<int, QString> data = std::make_pair<int, QString>(endorsement["mod_id"].toInt(), endorsement["status"].toString()); - sorted.insert(std::pair<QString, std::pair<int, QString>>(endorsement["domain_name"].toString(), data)); + QVariantMap endorsement = endorsementData.toMap(); + std::pair<int, QString> data = std::make_pair<int, QString>( + endorsement["mod_id"].toInt(), endorsement["status"].toString()); + sorted.insert(std::pair<QString, std::pair<int, QString>>( + endorsement["domain_name"].toString(), data)); } for (auto game : games) { - IPluginGame *gamePlugin = m_OrganizerCore.getGame(game); - if (gamePlugin != nullptr && gamePlugin->gameShortName().compare("SkyrimSE", Qt::CaseInsensitive) == 0) + IPluginGame* gamePlugin = m_OrganizerCore.getGame(game); + if (gamePlugin != nullptr && + gamePlugin->gameShortName().compare("SkyrimSE", Qt::CaseInsensitive) == 0) searchedMO2NexusGame = true; auto iter = sorted.equal_range(gamePlugin->gameNexusName()); for (auto result = iter.first; result != iter.second; ++result) { - std::vector<ModInfo::Ptr> modsList = ModInfo::getByModID(result->first, result->second.first); + std::vector<ModInfo::Ptr> modsList = + ModInfo::getByModID(result->first, result->second.first); for (auto mod : modsList) { if (result->second.second == "Endorsed") @@ -2864,9 +2961,10 @@ void MainWindow::nxmEndorsementsAvailable(QVariant userData, QVariant resultData } if (Settings::instance().nexus().endorsementIntegration()) { - if (result->first == "skyrimspecialedition" && result->second.first == gamePlugin->nexusModOrganizerID()) { + if (result->first == "skyrimspecialedition" && + result->second.first == gamePlugin->nexusModOrganizerID()) { m_OrganizerCore.settings().nexus().setEndorsementState( - endorsementStateFromString(result->second.second)); + endorsementStateFromString(result->second.second)); toggleMO2EndorseState(); } @@ -2881,7 +2979,7 @@ void MainWindow::nxmEndorsementsAvailable(QVariant userData, QVariant resultData for (auto result = iter.first; result != iter.second; ++result) { if (result->second.first == gamePlugin->nexusModOrganizerID()) { m_OrganizerCore.settings().nexus().setEndorsementState( - endorsementStateFromString(result->second.second)); + endorsementStateFromString(result->second.second)); toggleMO2EndorseState(); break; @@ -2891,10 +2989,11 @@ void MainWindow::nxmEndorsementsAvailable(QVariant userData, QVariant resultData } } -void MainWindow::nxmUpdateInfoAvailable(QString gameName, QVariant userData, QVariant resultData, int) +void MainWindow::nxmUpdateInfoAvailable(QString gameName, QVariant userData, + QVariant resultData, int) { QString gameNameReal; - for (IPluginGame *game : m_PluginContainer.plugins<IPluginGame>()) { + for (IPluginGame* game : m_PluginContainer.plugins<IPluginGame>()) { if (game->gameNexusName() == gameName) { gameNameReal = game->gameShortName(); break; @@ -2903,12 +3002,15 @@ void MainWindow::nxmUpdateInfoAvailable(QString gameName, QVariant userData, QVa QVariantList resultList = resultData.toList(); auto* watcher = new QFutureWatcher<NxmUpdateInfoData>(); - QObject::connect(watcher, &QFutureWatcher<NxmUpdateInfoData>::finished, [this, watcher]() { - finishUpdateInfo(watcher->result()); - watcher->deleteLater(); - }); + QObject::connect(watcher, &QFutureWatcher<NxmUpdateInfoData>::finished, + [this, watcher]() { + finishUpdateInfo(watcher->result()); + watcher->deleteLater(); + }); auto future = QtConcurrent::run([=]() { - return NxmUpdateInfoData{ gameNameReal, ModInfo::filteredMods(gameNameReal, resultList, userData.toBool(), true) }; + return NxmUpdateInfoData{ + gameNameReal, + ModInfo::filteredMods(gameNameReal, resultList, userData.toBool(), true)}; }); watcher->setFuture(future); ui->modList->invalidateFilter(); @@ -2917,32 +3019,37 @@ void MainWindow::nxmUpdateInfoAvailable(QString gameName, QVariant userData, QVa void MainWindow::finishUpdateInfo(const NxmUpdateInfoData& data) { if (data.finalMods.empty()) { - log::info("{}", tr("None of your %1 mods appear to have had recent file updates.").arg(data.game)); + log::info("{}", tr("None of your %1 mods appear to have had recent file updates.") + .arg(data.game)); } std::set<std::pair<QString, int>> organizedGames; for (auto& mod : data.finalMods) { if (mod->canBeUpdated()) { - organizedGames.insert(std::make_pair<QString, int>(mod->gameName().toLower(), mod->nexusId())); + organizedGames.insert( + std::make_pair<QString, int>(mod->gameName().toLower(), mod->nexusId())); } } if (!data.finalMods.empty() && organizedGames.empty()) - log::warn("{}", tr("All of your mods have been checked recently. We restrict update checks to help preserve your available API requests.")); + log::warn("{}", tr("All of your mods have been checked recently. We restrict " + "update checks to help preserve your available API requests.")); for (const auto& game : organizedGames) { - NexusInterface::instance().requestUpdates(game.second, this, QVariant(), game.first, QString()); + NexusInterface::instance().requestUpdates(game.second, this, QVariant(), game.first, + QString()); } } -void MainWindow::nxmUpdatesAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID) +void MainWindow::nxmUpdatesAvailable(QString gameName, int modID, QVariant userData, + QVariant resultData, int requestID) { QVariantMap resultInfo = resultData.toMap(); - QList files = resultInfo["files"].toList(); - QList fileUpdates = resultInfo["file_updates"].toList(); + QList files = resultInfo["files"].toList(); + QList fileUpdates = resultInfo["file_updates"].toList(); QString gameNameReal; - for (IPluginGame *game : m_PluginContainer.plugins<IPluginGame>()) { + for (IPluginGame* game : m_PluginContainer.plugins<IPluginGame>()) { if (game->gameNexusName() == gameName) { gameNameReal = game->gameShortName(); break; @@ -2955,25 +3062,27 @@ void MainWindow::nxmUpdatesAvailable(QString gameName, int modID, QVariant userD for (auto mod : modsList) { QString validNewVersion; - int newModStatus = -1; + int newModStatus = -1; QString installedFile = QFileInfo(mod->installationFile()).fileName(); if (!installedFile.isEmpty()) { QVariantMap foundFileData; // update the file status - for (auto &file : files) { + for (auto& file : files) { QVariantMap fileData = file.toMap(); - if (fileData["file_name"].toString().compare(installedFile, Qt::CaseInsensitive) == 0) { + if (fileData["file_name"].toString().compare(installedFile, + Qt::CaseInsensitive) == 0) { foundFileData = fileData; - newModStatus = foundFileData["category_id"].toInt(); + newModStatus = foundFileData["category_id"].toInt(); if (newModStatus != NexusInterface::FileStatus::OLD_VERSION && newModStatus != NexusInterface::FileStatus::REMOVED && newModStatus != NexusInterface::FileStatus::ARCHIVED) { - // since the file is still active if there are no updates for it, use this as current version + // since the file is still active if there are no updates for it, use this + // as current version validNewVersion = foundFileData["version"].toString(); } break; @@ -2981,18 +3090,21 @@ void MainWindow::nxmUpdatesAvailable(QString gameName, int modID, QVariant userD } if (foundFileData.isEmpty()) { - // The file was not listed, the file is likely archived and archived files are being hidden on the mod + // The file was not listed, the file is likely archived and archived files are + // being hidden on the mod newModStatus = NexusInterface::FileStatus::ARCHIVED_HIDDEN; } // look for updates of the file int currentUpdateId = -1; - // find installed file ID from the updates list since old filenames are not guaranteed to be unique + // find installed file ID from the updates list since old filenames are not + // guaranteed to be unique for (auto& updateEntry : fileUpdates) { const QVariantMap& updateData = updateEntry.toMap(); - if (installedFile.compare(updateData["old_file_name"].toString(), Qt::CaseInsensitive) == 0) { + if (installedFile.compare(updateData["old_file_name"].toString(), + Qt::CaseInsensitive) == 0) { currentUpdateId = updateData["old_file_id"].toInt(); break; } @@ -3026,7 +3138,7 @@ void MainWindow::nxmUpdatesAvailable(QString gameName, int modID, QVariant userD updateStatus != NexusInterface::FileStatus::ARCHIVED) { // new version is active, so record it - validNewVersion = fileData["version"].toString(); + validNewVersion = fileData["version"].toString(); foundActiveUpdate = true; } break; @@ -3048,8 +3160,7 @@ void MainWindow::nxmUpdatesAvailable(QString gameName, int modID, QVariant userD requiresInfo = true; } } - } - else { + } else { // No installedFile means we don't know what to look at for a version so // just get the global mod version requiresInfo = true; @@ -3069,17 +3180,19 @@ void MainWindow::nxmUpdatesAvailable(QString gameName, int modID, QVariant userD ui->modList->invalidateFilter(); if (requiresInfo) { - NexusInterface::instance().requestModInfo(gameNameReal, modID, this, QVariant(), QString()); + NexusInterface::instance().requestModInfo(gameNameReal, modID, this, QVariant(), + QString()); } } -void MainWindow::nxmModInfoAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID) +void MainWindow::nxmModInfoAvailable(QString gameName, int modID, QVariant userData, + QVariant resultData, int requestID) { QVariantMap result = resultData.toMap(); QString gameNameReal; bool foundUpdate = false; - for (IPluginGame *game : m_PluginContainer.plugins<IPluginGame>()) { + for (IPluginGame* game : m_PluginContainer.plugins<IPluginGame>()) { if (game->gameNexusName() == gameName) { gameNameReal = game->gameShortName(); break; @@ -3089,11 +3202,11 @@ void MainWindow::nxmModInfoAvailable(QString gameName, int modID, QVariant userD std::vector<ModInfo::Ptr> modsList = ModInfo::getByModID(gameNameReal, modID); for (auto mod : modsList) { - QDateTime now = QDateTime::currentDateTimeUtc(); + QDateTime now = QDateTime::currentDateTimeUtc(); QDateTime updateTarget = mod->getExpires(); - // if file is still listed as optional or miscellaneous don't update the version as often optional files are left - // with an older version than the main mod version. + // if file is still listed as optional or miscellaneous don't update the version as + // often optional files are left with an older version than the main mod version. if (!result["version"].toString().isEmpty() && mod->getNexusFileStatus() != NexusInterface::FileStatus::OPTIONAL_FILE && mod->getNexusFileStatus() != NexusInterface::FileStatus::MISCELLANEOUS) { @@ -3107,8 +3220,9 @@ void MainWindow::nxmModInfoAvailable(QString gameName, int modID, QVariant userD mod->setNexusDescription(result["description"].toString()); - if ((mod->endorsedState() != EndorsedState::ENDORSED_NEVER) && (result.contains("endorsement"))) { - QVariantMap endorsement = result["endorsement"].toMap(); + if ((mod->endorsedState() != EndorsedState::ENDORSED_NEVER) && + (result.contains("endorsement"))) { + QVariantMap endorsement = result["endorsement"].toMap(); QString endorsementStatus = endorsement["endorse_status"].toString(); if (endorsementStatus.compare("Endorsed") == 00) @@ -3120,7 +3234,8 @@ void MainWindow::nxmModInfoAvailable(QString gameName, int modID, QVariant userD } mod->setLastNexusQuery(QDateTime::currentDateTimeUtc()); - mod->setNexusLastModified(QDateTime::fromSecsSinceEpoch(result["updated_timestamp"].toInt(), Qt::UTC)); + mod->setNexusLastModified( + QDateTime::fromSecsSinceEpoch(result["updated_timestamp"].toInt(), Qt::UTC)); m_OrganizerCore.modList()->notifyChange(ModInfo::getIndex(mod->name())); } @@ -3143,33 +3258,33 @@ void MainWindow::nxmEndorsementToggled(QString, int, QVariant, QVariant resultDa const auto s = endorsementStateFromString(itor->toString()); - switch (s) - { - case EndorsementState::Accepted: - { - QMessageBox::information(this, tr("Thank you!"), tr("Thank you for your endorsement!")); - break; - } + switch (s) { + case EndorsementState::Accepted: { + QMessageBox::information(this, tr("Thank you!"), + tr("Thank you for your endorsement!")); + break; + } - case EndorsementState::Refused: - { - // don't spam message boxes if the user doesn't want to endorse - log::info("Mod Organizer will not be endorsed and will no longer ask you to endorse."); - break; - } + case EndorsementState::Refused: { + // don't spam message boxes if the user doesn't want to endorse + log::info( + "Mod Organizer will not be endorsed and will no longer ask you to endorse."); + break; + } - case EndorsementState::NoDecision: - { - log::error("bad status '{}' in endorsement response", itor->toString()); - return; - } + case EndorsementState::NoDecision: { + log::error("bad status '{}' in endorsement response", itor->toString()); + return; + } } m_OrganizerCore.settings().nexus().setEndorsementState(s); toggleMO2EndorseState(); - if (!disconnect(sender(), SIGNAL(nxmEndorsementToggled(QString, int, QVariant, QVariant, int)), - this, SLOT(nxmEndorsementToggled(QString, int, QVariant, QVariant, int)))) { + if (!disconnect(sender(), + SIGNAL(nxmEndorsementToggled(QString, int, QVariant, QVariant, int)), + this, + SLOT(nxmEndorsementToggled(QString, int, QVariant, QVariant, int)))) { log::error("failed to disconnect endorsement slot"); } } @@ -3186,11 +3301,12 @@ void MainWindow::nxmTrackedModsAvailable(QVariant userData, QVariant resultData, if (modInfo->nexusId() <= 0) continue; - bool found = false; + bool found = false; auto resultsList = resultData.toList(); for (auto item : resultsList) { auto results = item.toMap(); - if ((gameNames[results["domain_name"].toString()].compare(modInfo->gameName(), Qt::CaseInsensitive) == 0) && + if ((gameNames[results["domain_name"].toString()].compare( + modInfo->gameName(), Qt::CaseInsensitive) == 0) && (results["mod_id"].toInt() == modInfo->nexusId())) { found = true; break; @@ -3206,12 +3322,14 @@ void MainWindow::nxmDownloadURLs(QString, int, int, QVariant, QVariant resultDat { auto servers = m_OrganizerCore.settings().network().servers(); - for (const QVariant &var : resultData.toList()) { + for (const QVariant& var : resultData.toList()) { const QVariantMap map = var.toMap(); const auto name = map["short_name"].toString(); - const auto isPremium = map["name"].toString().contains("Premium", Qt::CaseInsensitive); - const auto isCDN = map["short_name"].toString().contains("CDN", Qt::CaseInsensitive); + const auto isPremium = + map["name"].toString().contains("Premium", Qt::CaseInsensitive); + const auto isCDN = + map["short_name"].toString().contains("CDN", Qt::CaseInsensitive); bool found = false; @@ -3235,12 +3353,16 @@ void MainWindow::nxmDownloadURLs(QString, int, int, QVariant, QVariant resultDat m_OrganizerCore.settings().network().updateServers(servers); } -void MainWindow::nxmRequestFailed(QString gameName, int modID, int, QVariant, int, int errorCode, const QString &errorString) +void MainWindow::nxmRequestFailed(QString gameName, int modID, int, QVariant, int, + int errorCode, const QString& errorString) { - if (errorCode == QNetworkReply::ContentAccessDenied || errorCode == QNetworkReply::ContentNotFoundError) { - log::debug("{}", tr("Mod ID %1 no longer seems to be available on Nexus.").arg(modID)); + if (errorCode == QNetworkReply::ContentAccessDenied || + errorCode == QNetworkReply::ContentNotFoundError) { + log::debug("{}", + tr("Mod ID %1 no longer seems to be available on Nexus.").arg(modID)); - // update last checked timestamp on orphaned mods as well to avoid repeating requests + // update last checked timestamp on orphaned mods as well to avoid repeating + // requests QString gameNameReal; for (IPluginGame* game : m_PluginContainer.plugins<IPluginGame>()) { if (game->gameNexusName() == gameName) { @@ -3254,12 +3376,15 @@ void MainWindow::nxmRequestFailed(QString gameName, int modID, int, QVariant, in mod->setLastNexusQuery(QDateTime::currentDateTimeUtc()); } } else { - MessageDialog::showMessage(tr("Error %1: Request to Nexus failed: %2").arg(errorCode).arg(errorString), this); + MessageDialog::showMessage( + tr("Error %1: Request to Nexus failed: %2").arg(errorCode).arg(errorString), + this); } } -BSA::EErrorCode MainWindow::extractBSA(BSA::Archive &archive, BSA::Folder::Ptr folder, const QString &destination, - QProgressDialog &progress) +BSA::EErrorCode MainWindow::extractBSA(BSA::Archive& archive, BSA::Folder::Ptr folder, + const QString& destination, + QProgressDialog& progress) { QDir().mkdir(destination); BSA::EErrorCode result = BSA::ERROR_NONE; @@ -3281,16 +3406,19 @@ BSA::EErrorCode MainWindow::extractBSA(BSA::Archive &archive, BSA::Folder::Ptr f } if (result != BSA::ERROR_NONE) { - if (QMessageBox::critical(this, tr("Error"), tr("failed to extract %1 (errorcode %2)").arg(errorFile).arg(result), - QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel) { + if (QMessageBox::critical( + this, tr("Error"), + tr("failed to extract %1 (errorcode %2)").arg(errorFile).arg(result), + QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel) { return result; } } for (unsigned int i = 0; i < folder->getNumSubFolders(); ++i) { BSA::Folder::Ptr subFolder = folder->getSubFolder(i); - BSA::EErrorCode res = extractBSA(archive, subFolder, - destination.mid(0).append("/").append(subFolder->getName().c_str()), progress); + BSA::EErrorCode res = extractBSA( + archive, subFolder, + destination.mid(0).append("/").append(subFolder->getName().c_str()), progress); if (res != BSA::ERROR_NONE) { return res; } @@ -3298,8 +3426,8 @@ BSA::EErrorCode MainWindow::extractBSA(BSA::Archive &archive, BSA::Folder::Ptr f return BSA::ERROR_NONE; } - -bool MainWindow::extractProgress(QProgressDialog &progress, int percentage, std::string fileName) +bool MainWindow::extractProgress(QProgressDialog& progress, int percentage, + std::string fileName) { progress.setLabelText(fileName.c_str()); progress.setValue(percentage); @@ -3307,30 +3435,37 @@ bool MainWindow::extractProgress(QProgressDialog &progress, int percentage, std: return !progress.wasCanceled(); } - void MainWindow::extractBSATriggered(QTreeWidgetItem* item) { using namespace boost::placeholders; QString origin; - QString targetFolder = FileDialogMemory::getExistingDirectory("extractBSA", this, tr("Extract BSA")); + QString targetFolder = + FileDialogMemory::getExistingDirectory("extractBSA", this, tr("Extract BSA")); QStringList archives = {}; if (!targetFolder.isEmpty()) { if (!item->parent()) { for (int i = 0; i < item->childCount(); ++i) { archives.append(item->child(i)->text(0)); } - origin = QDir::fromNativeSeparators(ToQString(m_OrganizerCore.directoryStructure()->getOriginByName(ToWString(item->text(0))).getPath())); + origin = QDir::fromNativeSeparators( + ToQString(m_OrganizerCore.directoryStructure() + ->getOriginByName(ToWString(item->text(0))) + .getPath())); } else { - origin = QDir::fromNativeSeparators(ToQString(m_OrganizerCore.directoryStructure()->getOriginByName(ToWString(item->text(1))).getPath())); - archives = QStringList({ item->text(0) }); + origin = QDir::fromNativeSeparators( + ToQString(m_OrganizerCore.directoryStructure() + ->getOriginByName(ToWString(item->text(1))) + .getPath())); + archives = QStringList({item->text(0)}); } for (auto archiveName : archives) { BSA::Archive archive; QString archivePath = QString("%1\\%2").arg(origin).arg(archiveName); - BSA::EErrorCode result = archive.read(archivePath.toLocal8Bit().constData(), true); + BSA::EErrorCode result = + archive.read(archivePath.toLocal8Bit().constData(), true); if ((result != BSA::ERROR_NONE) && (result != BSA::ERROR_INVALIDHASHES)) { reportError(tr("failed to read %1: %2").arg(archivePath).arg(result)); return; @@ -3340,10 +3475,13 @@ void MainWindow::extractBSATriggered(QTreeWidgetItem* item) progress.setMaximum(100); progress.setValue(0); progress.show(); - archive.extractAll(QDir::toNativeSeparators(targetFolder).toLocal8Bit().constData(), - boost::bind(&MainWindow::extractProgress, this, boost::ref(progress), _1, _2)); + archive.extractAll( + QDir::toNativeSeparators(targetFolder).toLocal8Bit().constData(), + boost::bind(&MainWindow::extractProgress, this, boost::ref(progress), _1, + _2)); if (result == BSA::ERROR_INVALIDHASHES) { - reportError(tr("This archive contains invalid hashes. Some files may be broken.")); + reportError( + tr("This archive contains invalid hashes. Some files may be broken.")); } archive.close(); } @@ -3353,8 +3491,9 @@ void MainWindow::extractBSATriggered(QTreeWidgetItem* item) void MainWindow::on_bsaList_customContextMenuRequested(const QPoint& pos) { QMenu menu; - menu.addAction(tr("Extract..."), - [=, item = ui->bsaList->itemAt(pos)]() { extractBSATriggered(item); }); + menu.addAction(tr("Extract..."), [=, item = ui->bsaList->itemAt(pos)]() { + extractBSATriggered(item); + }); menu.exec(ui->bsaList->viewport()->mapToGlobal(pos)); } @@ -3402,7 +3541,7 @@ void MainWindow::on_displayCategoriesBtn_toggled(bool checked) void MainWindow::removeFromToolbar(QAction* action) { const auto& title = action->text(); - auto& list = *m_OrganizerCore.executablesList(); + auto& list = *m_OrganizerCore.executablesList(); auto itor = list.find(title); if (itor == list.end()) { @@ -3414,17 +3553,17 @@ void MainWindow::removeFromToolbar(QAction* action) updatePinnedExecutables(); } - -void MainWindow::toolBar_customContextMenuRequested(const QPoint &point) +void MainWindow::toolBar_customContextMenuRequested(const QPoint& point) { - QAction *action = ui->toolBar->actionAt(point); + QAction* action = ui->toolBar->actionAt(point); if (action != nullptr) { if (action->objectName().startsWith("custom_")) { QMenu menu; - menu.addAction( - tr("Remove '%1' from the toolbar").arg(action->text()), - [&, action]() { removeFromToolbar(action); }); + menu.addAction(tr("Remove '%1' from the toolbar").arg(action->text()), + [&, action]() { + removeFromToolbar(action); + }); menu.exec(ui->toolBar->mapToGlobal(point)); return; } @@ -3437,15 +3576,12 @@ void MainWindow::toolBar_customContextMenuRequested(const QPoint &point) Executable* MainWindow::getSelectedExecutable() { - const QString name = ui->executablesListBox->itemText( - ui->executablesListBox->currentIndex()); + const QString name = + ui->executablesListBox->itemText(ui->executablesListBox->currentIndex()); - try - { + try { return &m_OrganizerCore.executablesList()->get(name); - } - catch(std::runtime_error&) - { + } catch (std::runtime_error&) { return nullptr; } } @@ -3455,16 +3591,18 @@ void MainWindow::on_showHiddenBox_toggled(bool checked) m_OrganizerCore.downloadManager()->setShowHidden(checked); } -const char *MainWindow::PATTERN_BACKUP_GLOB = ".????_??_??_??_??_??"; -const char *MainWindow::PATTERN_BACKUP_REGEX = "\\.(\\d\\d\\d\\d_\\d\\d_\\d\\d_\\d\\d_\\d\\d_\\d\\d)"; -const char *MainWindow::PATTERN_BACKUP_DATE = "yyyy_MM_dd_hh_mm_ss"; +const char* MainWindow::PATTERN_BACKUP_GLOB = ".????_??_??_??_??_??"; +const char* MainWindow::PATTERN_BACKUP_REGEX = + "\\.(\\d\\d\\d\\d_\\d\\d_\\d\\d_\\d\\d_\\d\\d_\\d\\d)"; +const char* MainWindow::PATTERN_BACKUP_DATE = "yyyy_MM_dd_hh_mm_ss"; -bool MainWindow::createBackup(const QString &filePath, const QDateTime &time) +bool MainWindow::createBackup(const QString& filePath, const QDateTime& time) { QString outPath = filePath + "." + time.toString(PATTERN_BACKUP_DATE); if (shellCopy(QStringList(filePath), QStringList(outPath), this)) { QFileInfo fileInfo(filePath); - removeOldFiles(fileInfo.absolutePath(), fileInfo.fileName() + PATTERN_BACKUP_GLOB, 10, QDir::Name); + removeOldFiles(fileInfo.absolutePath(), fileInfo.fileName() + PATTERN_BACKUP_GLOB, + 10, QDir::Name); return true; } else { return false; @@ -3475,24 +3613,27 @@ void MainWindow::on_saveButton_clicked() { m_OrganizerCore.savePluginList(); QDateTime now = QDateTime::currentDateTime(); - if (createBackup(m_OrganizerCore.currentProfile()->getPluginsFileName(), now) - && createBackup(m_OrganizerCore.currentProfile()->getLoadOrderFileName(), now) - && createBackup(m_OrganizerCore.currentProfile()->getLockedOrderFileName(), now)) { + if (createBackup(m_OrganizerCore.currentProfile()->getPluginsFileName(), now) && + createBackup(m_OrganizerCore.currentProfile()->getLoadOrderFileName(), now) && + createBackup(m_OrganizerCore.currentProfile()->getLockedOrderFileName(), now)) { MessageDialog::showMessage(tr("Backup of load order created"), this); } } -QString MainWindow::queryRestore(const QString &filePath) +QString MainWindow::queryRestore(const QString& filePath) { QFileInfo pluginFileInfo(filePath); - QString pattern = pluginFileInfo.fileName() + ".*"; - QFileInfoList files = pluginFileInfo.absoluteDir().entryInfoList(QStringList(pattern), QDir::Files, QDir::Name); + QString pattern = pluginFileInfo.fileName() + ".*"; + QFileInfoList files = pluginFileInfo.absoluteDir().entryInfoList( + QStringList(pattern), QDir::Files, QDir::Name); SelectionDialog dialog(tr("Choose backup to restore"), this); - QRegularExpression exp(QRegularExpression::anchoredPattern(pluginFileInfo.fileName() + PATTERN_BACKUP_REGEX)); - QRegularExpression exp2(QRegularExpression::anchoredPattern(pluginFileInfo.fileName() + "\\.(.*)")); - for(const QFileInfo &info : boost::adaptors::reverse(files)) { - auto match = exp.match(info.fileName()); + QRegularExpression exp(QRegularExpression::anchoredPattern(pluginFileInfo.fileName() + + PATTERN_BACKUP_REGEX)); + QRegularExpression exp2( + QRegularExpression::anchoredPattern(pluginFileInfo.fileName() + "\\.(.*)")); + for (const QFileInfo& info : boost::adaptors::reverse(files)) { + auto match = exp.match(info.fileName()); auto match2 = exp2.match(info.fileName()); if (match.hasMatch()) { QDateTime time = QDateTime::fromString(match.captured(1), PATTERN_BACKUP_DATE); @@ -3503,7 +3644,8 @@ QString MainWindow::queryRestore(const QString &filePath) } if (dialog.numChoices() == 0) { - QMessageBox::information(this, tr("No Backups"), tr("There are no backups to restore")); + QMessageBox::information(this, tr("No Backups"), + tr("There are no backups to restore")); return QString(); } @@ -3517,20 +3659,19 @@ QString MainWindow::queryRestore(const QString &filePath) void MainWindow::on_restoreButton_clicked() { QString pluginName = m_OrganizerCore.currentProfile()->getPluginsFileName(); - QString choice = queryRestore(pluginName); + QString choice = queryRestore(pluginName); if (!choice.isEmpty()) { QString loadOrderName = m_OrganizerCore.currentProfile()->getLoadOrderFileName(); - QString lockedName = m_OrganizerCore.currentProfile()->getLockedOrderFileName(); - if (!shellCopy(pluginName + "." + choice, pluginName, true, this) || + QString lockedName = m_OrganizerCore.currentProfile()->getLockedOrderFileName(); + if (!shellCopy(pluginName + "." + choice, pluginName, true, this) || !shellCopy(loadOrderName + "." + choice, loadOrderName, true, this) || - !shellCopy(lockedName + "." + choice, lockedName, true, this)) { + !shellCopy(lockedName + "." + choice, lockedName, true, this)) { const auto e = GetLastError(); - QMessageBox::critical( - this, tr("Restore failed"), - tr("Failed to restore the backup. Errorcode: %1") - .arg(QString::fromStdWString(formatSystemMessage(e)))); + QMessageBox::critical(this, tr("Restore failed"), + tr("Failed to restore the backup. Errorcode: %1") + .arg(QString::fromStdWString(formatSystemMessage(e)))); } m_OrganizerCore.refreshESPList(true); } @@ -3548,14 +3689,13 @@ void MainWindow::on_saveModsButton_clicked() void MainWindow::on_restoreModsButton_clicked() { QString modlistName = m_OrganizerCore.currentProfile()->getModlistFileName(); - QString choice = queryRestore(modlistName); + QString choice = queryRestore(modlistName); if (!choice.isEmpty()) { if (!shellCopy(modlistName + "." + choice, modlistName, true, this)) { const auto e = GetLastError(); - QMessageBox::critical( - this, tr("Restore failed"), - tr("Failed to restore the backup. Errorcode: %1") - .arg(formatSystemMessage(e))); + QMessageBox::critical(this, tr("Restore failed"), + tr("Failed to restore the backup. Errorcode: %1") + .arg(formatSystemMessage(e))); } m_OrganizerCore.refresh(false); } @@ -3563,44 +3703,43 @@ void MainWindow::on_restoreModsButton_clicked() void MainWindow::on_managedArchiveLabel_linkHovered(const QString&) { - QToolTip::showText(QCursor::pos(), - ui->managedArchiveLabel->toolTip()); + QToolTip::showText(QCursor::pos(), ui->managedArchiveLabel->toolTip()); } -void MainWindow::dragEnterEvent(QDragEnterEvent *event) +void MainWindow::dragEnterEvent(QDragEnterEvent* event) { - //Accept copy or move drags to the download window. Link drags are not - //meaningful (Well, they are - we could drop a link in the download folder, - //but you need privileges to do that). + // Accept copy or move drags to the download window. Link drags are not + // meaningful (Well, they are - we could drop a link in the download folder, + // but you need privileges to do that). if (ui->downloadTab->isVisible() && (event->proposedAction() == Qt::CopyAction || event->proposedAction() == Qt::MoveAction) && event->answerRect().intersects(ui->downloadTab->rect())) { - //If I read the documentation right, this won't work under a motif windows - //manager and the check needs to be done at the drop. However, that means - //the user might be allowed to drop things which we can't sanely process - QMimeData const *data = event->mimeData(); + // If I read the documentation right, this won't work under a motif windows + // manager and the check needs to be done at the drop. However, that means + // the user might be allowed to drop things which we can't sanely process + QMimeData const* data = event->mimeData(); if (data->hasUrls()) { QStringList extensions = - m_OrganizerCore.installationManager()->getSupportedExtensions(); + m_OrganizerCore.installationManager()->getSupportedExtensions(); - //This is probably OK - scan to see if these are moderately sane archive - //types + // This is probably OK - scan to see if these are moderately sane archive + // types QList<QUrl> urls = data->urls(); - bool ok = true; - for (const QUrl &url : urls) { + bool ok = true; + for (const QUrl& url : urls) { if (url.isLocalFile()) { QString local = url.toLocalFile(); - bool fok = false; + bool fok = false; for (auto ext : extensions) { if (local.endsWith(ext, Qt::CaseInsensitive)) { fok = true; break; } } - if (! fok) { + if (!fok) { ok = false; break; } @@ -3613,7 +3752,7 @@ void MainWindow::dragEnterEvent(QDragEnterEvent *event) } } -void MainWindow::dropLocalFile(const QUrl &url, const QString &outputDir, bool move) +void MainWindow::dropLocalFile(const QUrl& url, const QString& outputDir, bool move) { QFileInfo file(url.toLocalFile()); if (!file.exists()) { @@ -3622,8 +3761,7 @@ void MainWindow::dropLocalFile(const QUrl &url, const QString &outputDir, bool m } QString target = outputDir + "/" + file.fileName(); if (QFile::exists(target)) { - QMessageBox box(QMessageBox::Question, - file.fileName(), + QMessageBox box(QMessageBox::Question, file.fileName(), tr("A file with the same name has already been downloaded. " "What would you like to do?")); box.addButton(tr("Overwrite"), QMessageBox::ActionRole); @@ -3632,14 +3770,14 @@ void MainWindow::dropLocalFile(const QUrl &url, const QString &outputDir, bool m box.exec(); switch (box.buttonRole(box.clickedButton())) { - case QMessageBox::RejectRole: - return; - case QMessageBox::ActionRole: - break; - default: - case QMessageBox::YesRole: - target = m_OrganizerCore.downloadManager()->getDownloadFileName(file.fileName()); - break; + case QMessageBox::RejectRole: + return; + case QMessageBox::ActionRole: + break; + default: + case QMessageBox::YesRole: + target = m_OrganizerCore.downloadManager()->getDownloadFileName(file.fileName()); + break; } } @@ -3655,15 +3793,15 @@ void MainWindow::dropLocalFile(const QUrl &url, const QString &outputDir, bool m } } -void MainWindow::dropEvent(QDropEvent *event) +void MainWindow::dropEvent(QDropEvent* event) { Qt::DropAction action = event->proposedAction(); - QString outputDir = m_OrganizerCore.downloadManager()->getOutputDirectory(); + QString outputDir = m_OrganizerCore.downloadManager()->getOutputDirectory(); if (action == Qt::MoveAction) { - //Tell windows I'm taking control and will delete the source of a move. + // Tell windows I'm taking control and will delete the source of a move. event->setDropAction(Qt::TargetMoveAction); } - for (const QUrl &url : event->mimeData()->urls()) { + for (const QUrl& url : event->mimeData()->urls()) { if (url.isLocalFile()) { dropLocalFile(url, outputDir, action == Qt::MoveAction); } else { @@ -3673,7 +3811,7 @@ void MainWindow::dropEvent(QDropEvent *event) event->accept(); } -void MainWindow::keyReleaseEvent(QKeyEvent *event) +void MainWindow::keyReleaseEvent(QKeyEvent* event) { // if the ui is locked, ignore the ALT key event // alt-tabbing out of a game triggers this diff --git a/src/mainwindow.h b/src/mainwindow.h index d08fdb0e..8cd55c90 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -24,14 +24,14 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "delayedfilewriter.h" #include "errorcodes.h" #include "imoinfo.h" +#include "iplugingame.h" //namespace MOBase { class IPluginGame; } #include "iuserinterface.h" #include "modinfo.h" #include "modlistbypriorityproxy.h" #include "modlistsortproxy.h" -#include "tutorialcontrol.h" -#include "plugincontainer.h" //class PluginContainer; -#include "iplugingame.h" //namespace MOBase { class IPluginGame; } +#include "plugincontainer.h" //class PluginContainer; #include "shared/fileregisterfwd.h" +#include "tutorialcontrol.h" #include <log.h> class Executable; @@ -44,17 +44,31 @@ class SavesTab; class BrowserDialog; class PluginListSortProxy; -namespace BSA { class Archive; } +namespace BSA +{ +class Archive; +} -namespace MOBase { class IPluginModPage; } -namespace MOBase { class IPluginTool; } +namespace MOBase +{ +class IPluginModPage; +} +namespace MOBase +{ +class IPluginTool; +} -namespace MOShared { class DirectoryEntry; } +namespace MOShared +{ +class DirectoryEntry; +} #include <QByteArray> #include <QDir> #include <QFileInfo> #include <QFileSystemWatcher> +#include <QFutureWatcher> +#include <QHeaderView> #include <QList> #include <QMainWindow> #include <QObject> @@ -64,11 +78,9 @@ namespace MOShared { class DirectoryEntry; } #include <QStringList> #include <QTime> #include <QTimer> -#include <QHeaderView> #include <QVariant> #include <Qt> #include <QtConcurrent/QtConcurrentRun> -#include <QFutureWatcher> class QAction; class QAbstractItemModel; @@ -89,7 +101,7 @@ class QWidget; #include <boost/signals2.hpp> #endif -//Sigh - just for HANDLE +// Sigh - just for HANDLE #define WIN32_LEAN_AND_MEAN #include <Windows.h> @@ -98,13 +110,13 @@ class QWidget; #include <string> #include <vector> -namespace Ui { - class MainWindow; +namespace Ui +{ +class MainWindow; } class Settings; - class MainWindow : public QMainWindow, public IUserInterface { Q_OBJECT @@ -112,9 +124,8 @@ class MainWindow : public QMainWindow, public IUserInterface friend class OrganizerProxy; public: - explicit MainWindow(Settings &settings, - OrganizerCore &organizerCore, PluginContainer &pluginContainer, - QWidget *parent = 0); + explicit MainWindow(Settings& settings, OrganizerCore& organizerCore, + PluginContainer& pluginContainer, QWidget* parent = 0); ~MainWindow(); void processUpdates(); @@ -122,14 +133,15 @@ public: QMainWindow* mainWindow() override; bool addProfile(); - void updateBSAList(const QStringList &defaultArchives, const QStringList &activeArchives); + void updateBSAList(const QStringList& defaultArchives, + const QStringList& activeArchives); void saveArchiveList(); - void installTranslator(const QString &name); + void installTranslator(const QString& name); - void displayModInformation( - ModInfo::Ptr modInfo, unsigned int modIndex, ModInfoTabIDs tabID) override; + void displayModInformation(ModInfo::Ptr modInfo, unsigned int modIndex, + ModInfoTabIDs tabID) override; bool canExit(); void onBeforeClose(); @@ -137,7 +149,10 @@ public: virtual bool closeWindow(); virtual void setWindowEnabled(bool enabled); - virtual MOBase::DelayedFileWriterBase &archivesWriter() override { return m_ArchiveListWriter; } + virtual MOBase::DelayedFileWriterBase& archivesWriter() override + { + return m_ArchiveListWriter; + } public slots: void refresherProgress(const DirectoryRefreshProgress* p); @@ -150,26 +165,24 @@ signals: /** * @brief emitted when the selected style changes */ - void styleChanged(const QString &styleFile); + void styleChanged(const QString& styleFile); void checkForProblemsDone(); protected: - - void showEvent(QShowEvent *event) override; + void showEvent(QShowEvent* event) override; void paintEvent(QPaintEvent* event) override; - void closeEvent(QCloseEvent *event) override; - bool eventFilter(QObject *obj, QEvent *event) override; - void resizeEvent(QResizeEvent *event) override; - void dragEnterEvent(QDragEnterEvent *event) override; - void dropEvent(QDropEvent *event) override; - void keyReleaseEvent(QKeyEvent *event) override; + void closeEvent(QCloseEvent* event) override; + bool eventFilter(QObject* obj, QEvent* event) override; + void resizeEvent(QResizeEvent* event) override; + void dragEnterEvent(QDragEnterEvent* event) override; + void dropEvent(QDropEvent* event) override; + void keyReleaseEvent(QKeyEvent* event) override; private slots: void on_actionChange_Game_triggered(); private: - // update data tab and schedule a problem check after a directory // structure update // @@ -188,7 +201,8 @@ private: void registerModPage(MOBase::IPluginModPage* modPage); bool registerNexusPage(const QString& gameName); - void registerPluginTool(MOBase::IPluginTool* tool, QString name = QString(), QMenu* menu = nullptr); + void registerPluginTool(MOBase::IPluginTool* tool, QString name = QString(), + QMenu* menu = nullptr); void updateToolbarMenu(); void updateToolMenu(); @@ -206,44 +220,44 @@ private: // remove invalid category-references from mods void fixCategories(); - bool extractProgress(QProgressDialog &extractProgress, int percentage, std::string fileName); + bool extractProgress(QProgressDialog& extractProgress, int percentage, + std::string fileName); // Performs checks, sets the m_NumberOfProblems and signals checkForProblemsDone(). void checkForProblemsImpl(); void setCategoryListVisible(bool visible); - bool errorReported(QString &logFile); + bool errorReported(QString& logFile); static void setupNetworkProxy(bool activate); void activateProxy(bool activate); - bool createBackup(const QString &filePath, const QDateTime &time); - QString queryRestore(const QString &filePath); + bool createBackup(const QString& filePath, const QDateTime& time); + QString queryRestore(const QString& filePath); - QMenu *openFolderMenu(); + QMenu* openFolderMenu(); - void dropLocalFile(const QUrl &url, const QString &outputDir, bool move); + void dropLocalFile(const QUrl& url, const QString& outputDir, bool move); void toggleMO2EndorseState(); void toggleUpdateAction(); // update info - struct NxmUpdateInfoData { + struct NxmUpdateInfoData + { QString game; std::set<ModInfo::Ptr> finalMods; }; void finishUpdateInfo(const NxmUpdateInfoData& data); private: - - static const char *PATTERN_BACKUP_GLOB; - static const char *PATTERN_BACKUP_REGEX; - static const char *PATTERN_BACKUP_DATE; + static const char* PATTERN_BACKUP_GLOB; + static const char* PATTERN_BACKUP_REGEX; + static const char* PATTERN_BACKUP_DATE; private: - - Ui::MainWindow *ui; + Ui::MainWindow* ui; bool m_WasVisible; bool m_FirstPaint; @@ -260,15 +274,16 @@ private: int m_OldProfileIndex; - std::vector<QString> m_ModNameList; // the mod-list to go with the directory structure + std::vector<QString> + m_ModNameList; // the mod-list to go with the directory structure QStringList m_DefaultArchives; int m_OldExecutableIndex; - QAction *m_ContextAction; + QAction* m_ContextAction; - CategoryFactory &m_CategoryFactory; + CategoryFactory& m_CategoryFactory; QTimer m_CheckBSATimer; QTimer m_SaveMetaTimer; @@ -278,8 +293,8 @@ private: QTime m_StartTime; - OrganizerCore &m_OrganizerCore; - PluginContainer &m_PluginContainer; + OrganizerCore& m_OrganizerCore; + PluginContainer& m_PluginContainer; QString m_CurrentLanguage; std::vector<QTranslator*> m_Translators; @@ -306,9 +321,8 @@ private: private slots: void updateWindowTitle(const APIUserAccount& user); - void showMessage(const QString &message); - void showError(const QString &message); - + void showMessage(const QString& message); + void showError(const QString& message); // main window actions void helpTriggered(); @@ -325,11 +339,13 @@ private slots: void linkDesktop(); void linkMenu(); - void languageChange(const QString &newLanguage); + void languageChange(const QString& newLanguage); - void windowTutorialFinished(const QString &windowName); + void windowTutorialFinished(const QString& windowName); - BSA::EErrorCode extractBSA(BSA::Archive &archive, BSA::Folder::Ptr folder, const QString &destination, QProgressDialog &extractProgress); + BSA::EErrorCode extractBSA(BSA::Archive& archive, BSA::Folder::Ptr folder, + const QString& destination, + QProgressDialog& extractProgress); // nexus related void updateAvailable(); @@ -337,34 +353,39 @@ private slots: void actionEndorseMO(); void actionWontEndorseMO(); - void motdReceived(const QString &motd); + void motdReceived(const QString& motd); void originModified(int originID); - void modInstalled(const QString &modName); + void modInstalled(const QString& modName); // update info - void nxmUpdateInfoAvailable(QString gameName, QVariant userData, QVariant resultData, int requestID); + void nxmUpdateInfoAvailable(QString gameName, QVariant userData, QVariant resultData, + int requestID); void nxmEndorsementsAvailable(QVariant userData, QVariant resultData, int); - void nxmUpdatesAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID); - void nxmModInfoAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID); + void nxmUpdatesAvailable(QString gameName, int modID, QVariant userData, + QVariant resultData, int requestID); + void nxmModInfoAvailable(QString gameName, int modID, QVariant userData, + QVariant resultData, int requestID); void nxmEndorsementToggled(QString, int, QVariant, QVariant resultData, int); void nxmTrackedModsAvailable(QVariant userData, QVariant resultData, int); - void nxmDownloadURLs(QString, int modID, int fileID, QVariant userData, QVariant resultData, int requestID); - void nxmRequestFailed(QString gameName, int modID, int fileID, QVariant userData, int requestID, int errorCode, const QString &errorString); + void nxmDownloadURLs(QString, int modID, int fileID, QVariant userData, + QVariant resultData, int requestID); + void nxmRequestFailed(QString gameName, int modID, int fileID, QVariant userData, + int requestID, int errorCode, const QString& errorString); void onRequestsChanged(const APIStats& stats, const APIUserAccount& user); - void modRenamed(const QString &oldName, const QString &newName); - void modRemoved(const QString &fileName); + void modRenamed(const QString& oldName, const QString& newName); + void modRemoved(const QString& fileName); void hookUpWindowTutorials(); bool shouldStartTutorial() const; void openInstanceFolder(); void openInstallFolder(); - void openPluginsFolder(); + void openPluginsFolder(); void openStylesheetsFolder(); void openDownloadsFolder(); void openModsFolder(); @@ -379,7 +400,8 @@ private slots: // Only visually update the problems icon. void updateProblemsButton(); - // Queue a problem check to allow collapsing of multiple requests in short amount of time. + // Queue a problem check to allow collapsing of multiple requests in short amount of + // time. void scheduleCheckForProblems(); // Perform the actual problem check in another thread. @@ -387,25 +409,26 @@ private slots: void saveModMetas(); - void updateStyle(const QString &style); + void updateStyle(const QString& style); void resizeLists(bool pluginListCustom); - void fileMoved(const QString& filePath, const QString& oldOriginName, const QString& newOriginName); + void fileMoved(const QString& filePath, const QString& oldOriginName, + const QString& newOriginName); /** * @brief allow columns in mod list and plugin list to be resized */ void allowListResize(); - void toolBar_customContextMenuRequested(const QPoint &point); + void toolBar_customContextMenuRequested(const QPoint& point); void removeFromToolbar(QAction* action); void about(); void resetActionIcons(); -private slots: // ui slots +private slots: // ui slots // actions void on_actionAdd_Profile_triggered(); void on_actionInstallMod_triggered(); @@ -427,8 +450,8 @@ private slots: // ui slots void on_actionToolBarIconsAndText_triggered(); void on_actionViewLog_triggered(); - void on_centralWidget_customContextMenuRequested(const QPoint &pos); - void on_bsaList_customContextMenuRequested(const QPoint &pos); + void on_centralWidget_customContextMenuRequested(const QPoint& pos); + void on_bsaList_customContextMenuRequested(const QPoint& pos); void on_executablesListBox_currentIndexChanged(int index); void on_profileBox_currentIndexChanged(int index); void on_startButton_clicked(); @@ -437,13 +460,13 @@ private slots: // ui slots void on_displayCategoriesBtn_toggled(bool checked); void on_linkButton_pressed(); void on_showHiddenBox_toggled(bool checked); - void on_bsaList_itemChanged(QTreeWidgetItem *item, int column); + void on_bsaList_itemChanged(QTreeWidgetItem* item, int column); void on_saveButton_clicked(); void on_restoreButton_clicked(); void on_restoreModsButton_clicked(); void on_saveModsButton_clicked(); - void on_managedArchiveLabel_linkHovered(const QString &link); + void on_managedArchiveLabel_linkHovered(const QString& link); void onPluginRegistrationChanged(); @@ -453,4 +476,4 @@ private slots: // ui slots void setupModList(); }; -#endif // MAINWINDOW_H +#endif // MAINWINDOW_H diff --git a/src/messagedialog.cpp b/src/messagedialog.cpp index afde0056..54b234e5 100644 --- a/src/messagedialog.cpp +++ b/src/messagedialog.cpp @@ -19,29 +19,32 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "messagedialog.h" #include "ui_messagedialog.h" -#include <log.h> -#include <QTimer> #include <QResizeEvent> +#include <QTimer> #include <Windows.h> +#include <log.h> using namespace MOBase; -MessageDialog::MessageDialog(const QString &text, QWidget *reference) : - QDialog(reference), - ui(new Ui::MessageDialog) +MessageDialog::MessageDialog(const QString& text, QWidget* reference) + : QDialog(reference), ui(new Ui::MessageDialog) { ui->setupUi(this); - // very crude way to ensure no single word in the test is wider than the message window. ellide in the center if necessary + // very crude way to ensure no single word in the test is wider than the message + // window. ellide in the center if necessary QFontMetrics metrics(ui->message->font()); QString restrictedText; QStringList lines = text.split("\n"); - foreach (const QString &line, lines) { + foreach (const QString& line, lines) { QString newLine; QStringList words = line.split(" "); - foreach (const QString &word, words) { + foreach (const QString& word, words) { if (word.length() > 10) { - newLine += "<span style=\"nobreak\">" + metrics.elidedText(word, Qt::ElideMiddle, ui->message->maximumWidth()) + "</span>"; + newLine += + "<span style=\"nobreak\">" + + metrics.elidedText(word, Qt::ElideMiddle, ui->message->maximumWidth()) + + "</span>"; } else { newLine += word; } @@ -56,23 +59,22 @@ MessageDialog::MessageDialog(const QString &text, QWidget *reference) : this->setAttribute(Qt::WA_ShowWithoutActivating); QTimer::singleShot(1000 + (text.length() * 40), this, SLOT(hide())); if (reference != nullptr) { - QPoint position = reference->mapToGlobal(QPoint(reference->width() / 2, reference->height())); + QPoint position = + reference->mapToGlobal(QPoint(reference->width() / 2, reference->height())); position.rx() -= this->width() / 2; position.ry() -= this->height() + 5; move(position); } } - MessageDialog::~MessageDialog() { - delete ui; + delete ui; } - -void MessageDialog::resizeEvent(QResizeEvent *event) +void MessageDialog::resizeEvent(QResizeEvent* event) { - QWidget *par = parentWidget(); + QWidget* par = parentWidget(); if (par != nullptr) { QPoint position = par->mapToGlobal(QPoint(par->width() / 2, par->height())); position.rx() -= event->size().width() / 2; @@ -81,8 +83,8 @@ void MessageDialog::resizeEvent(QResizeEvent *event) } } - -void MessageDialog::showMessage(const QString &text, QWidget *reference, bool bringToFront) +void MessageDialog::showMessage(const QString& text, QWidget* reference, + bool bringToFront) { log::debug("{}", text); @@ -99,7 +101,7 @@ void MessageDialog::showMessage(const QString &text, QWidget *reference, bool br return; } - MessageDialog *dialog = new MessageDialog(text, reference); + MessageDialog* dialog = new MessageDialog(text, reference); dialog->show(); if (bringToFront) { diff --git a/src/messagedialog.h b/src/messagedialog.h index 0dbc0e6e..d5bb0c57 100644 --- a/src/messagedialog.h +++ b/src/messagedialog.h @@ -22,8 +22,9 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QDialog> -namespace Ui { - class MessageDialog; +namespace Ui +{ +class MessageDialog; } /** @@ -32,36 +33,41 @@ namespace Ui { **/ class MessageDialog : public QDialog { - Q_OBJECT + Q_OBJECT public: - /** - * @brief constructor - * - * @param text the message to display - * @param reference parent widget. This will also be used to position the message at the bottom center of the dialog - **/ - - explicit MessageDialog(const QString &text, QWidget *reference); + /** + * @brief constructor + * + * @param text the message to display + * @param reference parent widget. This will also be used to position the message at + *the bottom center of the dialog + **/ + + explicit MessageDialog(const QString& text, QWidget* reference); ~MessageDialog(); /** - * factory function for message dialogs. This can be used as a fire-and-forget. The message - * will automatically positioned to the reference dialog and get a reasonable view time + * factory function for message dialogs. This can be used as a fire-and-forget. The + *message will automatically positioned to the reference dialog and get a reasonable + *view time * - * @param text the text to display. The length of this text is used to determine how long the dialog is to be shown - * @param reference the reference widget on top of which the message should be displayed - * @param true if the message should bring MO to front to ensure this message is visible + * @param text the text to display. The length of this text is used to determine how + *long the dialog is to be shown + * @param reference the reference widget on top of which the message should be + *displayed + * @param true if the message should bring MO to front to ensure this message is + *visible **/ - static void showMessage(const QString &text, QWidget *reference, bool bringToFront = true); + static void showMessage(const QString& text, QWidget* reference, + bool bringToFront = true); protected: - - virtual void resizeEvent(QResizeEvent *event); + virtual void resizeEvent(QResizeEvent* event); private: - Ui::MessageDialog *ui; + Ui::MessageDialog* ui; }; -#endif // MESSAGEDIALOG_H +#endif // MESSAGEDIALOG_H diff --git a/src/moapplication.cpp b/src/moapplication.cpp index ff3d32f3..e131d3d9 100644 --- a/src/moapplication.cpp +++ b/src/moapplication.cpp @@ -18,63 +18,59 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ #include "moapplication.h" -#include "settings.h" #include "commandline.h" #include "instancemanager.h" -#include "organizercore.h" -#include "thread_utils.h" #include "loglist.h" +#include "mainwindow.h" +#include "messagedialog.h" #include "multiprocess.h" #include "nexusinterface.h" #include "nxmaccessmanager.h" -#include "tutorialmanager.h" +#include "organizercore.h" #include "sanitychecks.h" -#include "mainwindow.h" -#include "messagedialog.h" -#include "shared/util.h" -#include <iplugingame.h> -#include <report.h> -#include <utility.h> -#include <log.h> +#include "settings.h" #include "shared/appconfig.h" +#include "shared/util.h" +#include "thread_utils.h" +#include "tutorialmanager.h" +#include <QDebug> #include <QFile> -#include <QStringList> +#include <QPainter> #include <QProxyStyle> +#include <QSSLSocket> +#include <QStringList> #include <QStyleFactory> -#include <QPainter> #include <QStyleOption> -#include <QDebug> -#include <QSSLSocket> +#include <iplugingame.h> +#include <log.h> +#include <report.h> +#include <utility.h> // see addDllsToPath() below -#pragma comment(linker, "/manifestDependency:\"" \ - "name='dlls' " \ - "processorArchitecture='x86' " \ - "version='1.0.0.0' " \ - "type='win32' \"") +#pragma comment(linker, "/manifestDependency:\"" \ + "name='dlls' " \ + "processorArchitecture='x86' " \ + "version='1.0.0.0' " \ + "type='win32' \"") using namespace MOBase; using namespace MOShared; // style proxy that changes the appearance of drop indicators // -class ProxyStyle : public QProxyStyle { +class ProxyStyle : public QProxyStyle +{ public: - ProxyStyle(QStyle* baseStyle = 0) - : QProxyStyle(baseStyle) - { - } + ProxyStyle(QStyle* baseStyle = 0) : QProxyStyle(baseStyle) {} - void drawPrimitive( - PrimitiveElement element, const QStyleOption* option, - QPainter* painter, const QWidget* widget) const override + void drawPrimitive(PrimitiveElement element, const QStyleOption* option, + QPainter* painter, const QWidget* widget) const override { if (element == QStyle::PE_IndicatorItemViewItemDrop) { // 0. Fix a bug that made the drop indicator sometimes appear on top // of the mod list when selecting a mod. - if (option->rect.height() == 0 - && option->rect.bottomRight() == QPoint(-1, -1)) { + if (option->rect.height() == 0 && option->rect.bottomRight() == QPoint(-1, -1)) { return; } @@ -96,26 +92,19 @@ public: painter->setPen(pen); painter->setBrush(QBrush(col)); if (rect.height() == 0) { - QPoint tri[3] = { - rect.topLeft(), - rect.topLeft() + QPoint(-5, 5), - rect.topLeft() + QPoint(-5, -5) - }; + QPoint tri[3] = {rect.topLeft(), rect.topLeft() + QPoint(-5, 5), + rect.topLeft() + QPoint(-5, -5)}; painter->drawPolygon(tri, 3); painter->drawLine(rect.topLeft(), rect.topRight()); - } - else { + } else { painter->drawRoundedRect(rect, 5, 5); } - } - else { + } else { QProxyStyle::drawPrimitive(element, option, painter, widget); } } - }; - // This adds the `dlls` directory to the path so the dlls can be found. How // MO is able to find dlls in there is a bit convoluted: // @@ -145,24 +134,22 @@ public: // void addDllsToPath() { - const auto dllsPath = QDir::toNativeSeparators( - QCoreApplication::applicationDirPath() + "/dlls"); + const auto dllsPath = + QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + "/dlls"); - QCoreApplication::setLibraryPaths( - QStringList(dllsPath) + QCoreApplication::libraryPaths()); + QCoreApplication::setLibraryPaths(QStringList(dllsPath) + + QCoreApplication::libraryPaths()); env::prependToPath(dllsPath); } - -MOApplication::MOApplication(int& argc, char** argv) - : QApplication(argc, argv) +MOApplication::MOApplication(int& argc, char** argv) : QApplication(argc, argv) { TimeThis tt("MOApplication()"); qputenv("QML_DISABLE_DISK_CACHE", "true"); - connect(&m_styleWatcher, &QFileSystemWatcher::fileChanged, [&](auto&& file){ + connect(&m_styleWatcher, &QFileSystemWatcher::fileChanged, [&](auto&& file) { log::debug("style file '{}' changed, reloading", file); updateStyle(file); }); @@ -180,9 +167,11 @@ OrganizerCore& MOApplication::core() void MOApplication::firstTimeSetup(MOMultiProcess& multiProcess) { connect( - &multiProcess, &MOMultiProcess::messageSent, this, - [this](auto&& s){ externalMessage(s); }, - Qt::QueuedConnection); + &multiProcess, &MOMultiProcess::messageSent, this, + [this](auto&& s) { + externalMessage(s); + }, + Qt::QueuedConnection); } int MOApplication::setup(MOMultiProcess& multiProcess, bool forceSelect) @@ -212,10 +201,9 @@ int MOApplication::setup(MOMultiProcess& multiProcess, bool forceSelect) log::debug("command line: '{}'", QString::fromWCharArray(GetCommandLineW())); - log::info( - "starting Mod Organizer version {} revision {} in {}, usvfs: {}", - createVersionInfo().displayString(3), GITID, - QCoreApplication::applicationDirPath(), MOShared::getUsvfsVersionString()); + log::info("starting Mod Organizer version {} revision {} in {}, usvfs: {}", + createVersionInfo().displayString(3), GITID, + QCoreApplication::applicationDirPath(), MOShared::getUsvfsVersionString()); if (multiProcess.secondary()) { log::debug("another instance of MO is running but --multiple was given"); @@ -224,7 +212,6 @@ int MOApplication::setup(MOMultiProcess& multiProcess, bool forceSelect) log::info("data path: {}", m_instance->directory()); log::info("working directory: {}", QDir::currentPath()); - tt.start("MOApplication::doOneRun() settings"); // deleting old files, only for the main instance @@ -239,7 +226,6 @@ int MOApplication::setup(MOMultiProcess& multiProcess, bool forceSelect) OrganizerCore::setGlobalCoreDumpType(m_settings->diagnostics().coreDumpType()); - tt.start("MOApplication::doOneRun() log and checks"); // logging and checking @@ -257,8 +243,9 @@ int MOApplication::setup(MOMultiProcess& multiProcess, bool forceSelect) })); auto sslBuildVersion = QSslSocket::sslLibraryBuildVersionString(); - auto sslVersion = QSslSocket::sslLibraryVersionString(); - log::debug("SSL Build Version: {}, SSL Runtime Version {}", sslBuildVersion, sslVersion); + auto sslVersion = QSslSocket::sslLibraryVersionString(); + log::debug("SSL Build Version: {}, SSL Runtime Version {}", sslBuildVersion, + sslVersion); // nexus interface tt.start("MOApplication::doOneRun() NexusInterface"); @@ -284,7 +271,7 @@ int MOApplication::setup(MOMultiProcess& multiProcess, bool forceSelect) m_plugins->loadPlugins(); // instance - if (auto r=setupInstanceLoop(*m_instance, *m_plugins)) { + if (auto r = setupInstanceLoop(*m_instance, *m_plugins)) { return *r; } @@ -300,14 +287,14 @@ int MOApplication::setup(MOMultiProcess& multiProcess, bool forceSelect) m_core->setManagedGame(m_instance->gamePlugin()); m_core->createDefaultProfile(); - log::info( - "using game plugin '{}' ('{}', variant {}, steam id '{}') at {}", - m_instance->gamePlugin()->gameName(), - m_instance->gamePlugin()->gameShortName(), - (m_settings->game().edition().value_or("").isEmpty() ? - "(none)" : *m_settings->game().edition()), - m_instance->gamePlugin()->steamAPPId(), - m_instance->gamePlugin()->gameDirectory().absolutePath()); + log::info("using game plugin '{}' ('{}', variant {}, steam id '{}') at {}", + m_instance->gamePlugin()->gameName(), + m_instance->gamePlugin()->gameShortName(), + (m_settings->game().edition().value_or("").isEmpty() + ? "(none)" + : *m_settings->game().edition()), + m_instance->gamePlugin()->steamAPPId(), + m_instance->gamePlugin()->gameDirectory().absolutePath()); CategoryFactory::instance().loadCategories(); m_core->updateExecutablesList(); @@ -337,10 +324,9 @@ int MOApplication::run(MOMultiProcess& multiProcess) // tutorials log::debug("initializing tutorials"); - TutorialManager::init( - qApp->applicationDirPath() + "/" - + QString::fromStdWString(AppConfig::tutorialsPath()) + "/", - m_core.get()); + TutorialManager::init(qApp->applicationDirPath() + "/" + + QString::fromStdWString(AppConfig::tutorialsPath()) + "/", + m_core.get()); // styling if (!setStyleFile(m_settings->interface().styleName().value_or(""))) { @@ -348,7 +334,6 @@ int MOApplication::run(MOMultiProcess& multiProcess) m_settings->interface().setStyleName(""); } - int res = 1; { @@ -360,10 +345,11 @@ int MOApplication::run(MOMultiProcess& multiProcess) m_nexus->getAccessManager()->setTopLevelWidget(&mainWindow); connect( - &mainWindow, &MainWindow::styleChanged, this, - [this](auto&& file){ setStyleFile(file); }, - Qt::QueuedConnection); - + &mainWindow, &MainWindow::styleChanged, this, + [this](auto&& file) { + setStyleFile(file); + }, + Qt::QueuedConnection); log::debug("displaying main window"); mainWindow.show(); @@ -392,13 +378,13 @@ void MOApplication::externalMessage(const QString& message) MOShortcut moshortcut(message); if (moshortcut.isValid()) { - if(moshortcut.hasExecutable()) { + if (moshortcut.hasExecutable()) { try { m_core->processRunner() - .setFromShortcut(moshortcut) - .setWaitForCompletion(ProcessRunner::TriggerRefresh) - .run(); - } catch(std::exception&) { + .setFromShortcut(moshortcut) + .setWaitForCompletion(ProcessRunner::TriggerRefresh) + .run(); + } catch (std::exception&) { // user was already warned } } @@ -408,33 +394,34 @@ void MOApplication::externalMessage(const QString& message) } else { cl::CommandLine cl; - if (auto r=cl.process(message.toStdWString())) { - log::debug( - "while processing external message, command line wants to " - "exit; ignoring"); + if (auto r = cl.process(message.toStdWString())) { + log::debug("while processing external message, command line wants to " + "exit; ignoring"); return; } - if (auto i=cl.instance()) { + if (auto i = cl.instance()) { const auto ci = InstanceManager::singleton().currentInstance(); if (*i != ci->displayName()) { - reportError(tr( - "This shortcut or command line is for instance '%1', but the current " - "instance is '%2'.") - .arg(*i).arg(ci->displayName())); + reportError( + tr("This shortcut or command line is for instance '%1', but the current " + "instance is '%2'.") + .arg(*i) + .arg(ci->displayName())); return; } } - if (auto p=cl.profile()) { + if (auto p = cl.profile()) { if (*p != m_core->profileName()) { - reportError(tr( - "This shortcut or command line is for profile '%1', but the current " - "profile is '%2'.") - .arg(*p).arg(m_core->profileName())); + reportError( + tr("This shortcut or command line is for profile '%1', but the current " + "profile is '%2'.") + .arg(*p) + .arg(m_core->profileName())); return; } @@ -446,17 +433,14 @@ void MOApplication::externalMessage(const QString& message) std::unique_ptr<Instance> MOApplication::getCurrentInstance(bool forceSelect) { - auto& m = InstanceManager::singleton(); + auto& m = InstanceManager::singleton(); auto currentInstance = m.currentInstance(); - if (forceSelect || !currentInstance) - { + if (forceSelect || !currentInstance) { // clear any overrides that might have been given on the command line m.clearOverrides(); currentInstance = selectInstance(); - } - else - { + } else { if (!QDir(currentInstance->directory()).exists()) { // the previously used instance doesn't exist anymore @@ -464,13 +448,12 @@ std::unique_ptr<Instance> MOApplication::getCurrentInstance(bool forceSelect) m.clearOverrides(); if (m.hasAnyInstances()) { - reportError(QObject::tr( - "Instance at '%1' not found. Select another instance.") - .arg(currentInstance->directory())); + reportError(QObject::tr("Instance at '%1' not found. Select another instance.") + .arg(currentInstance->directory())); } else { - reportError(QObject::tr( - "Instance at '%1' not found. You must create a new instance") - .arg(currentInstance->directory())); + reportError( + QObject::tr("Instance at '%1' not found. You must create a new instance") + .arg(currentInstance->directory())); } currentInstance = selectInstance(); @@ -480,11 +463,10 @@ std::unique_ptr<Instance> MOApplication::getCurrentInstance(bool forceSelect) return currentInstance; } -std::optional<int> MOApplication::setupInstanceLoop( - Instance& currentInstance, PluginContainer& pc) +std::optional<int> MOApplication::setupInstanceLoop(Instance& currentInstance, + PluginContainer& pc) { - for (;;) - { + for (;;) { const auto setupResult = setupInstance(currentInstance, pc); if (setupResult == SetupInstanceResults::Okay) { @@ -510,9 +492,9 @@ void MOApplication::purgeOldFiles() } // cycle log file - removeOldFiles( - qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath()), - "usvfs*.log", 5, QDir::Name); + removeOldFiles(qApp->property("dataPath").toString() + "/" + + QString::fromStdWString(AppConfig::logPath()), + "usvfs*.log", 5, QDir::Name); } void MOApplication::resetForRestart() @@ -527,9 +509,9 @@ void MOApplication::resetForRestart() // clear instance and profile overrides InstanceManager::singleton().clearOverrides(); - m_core = {}; - m_plugins = {}; - m_nexus = {}; + m_core = {}; + m_plugins = {}; + m_nexus = {}; m_settings = {}; m_instance = {}; } @@ -543,7 +525,9 @@ bool MOApplication::setStyleFile(const QString& styleName) } // set new stylesheet or clear it if (styleName.length() != 0) { - QString styleSheetName = applicationDirPath() + "/" + MOBase::ToQString(AppConfig::stylesheetsPath()) + "/" + styleName; + QString styleSheetName = applicationDirPath() + "/" + + MOBase::ToQString(AppConfig::stylesheetsPath()) + "/" + + styleName; if (QFile::exists(styleSheetName)) { m_styleWatcher.addPath(styleSheetName); updateStyle(styleSheetName); @@ -561,16 +545,14 @@ bool MOApplication::notify(QObject* receiver, QEvent* event) { try { return QApplication::notify(receiver, event); - } catch (const std::exception &e) { - log::error( - "uncaught exception in handler (object {}, eventtype {}): {}", - receiver->objectName(), event->type(), e.what()); + } catch (const std::exception& e) { + log::error("uncaught exception in handler (object {}, eventtype {}): {}", + receiver->objectName(), event->type(), e.what()); reportError(tr("an error occurred: %1").arg(e.what())); return false; } catch (...) { - log::error( - "uncaught non-std exception in handler (object {}, eventtype {})", - receiver->objectName(), event->type()); + log::error("uncaught non-std exception in handler (object {}, eventtype {})", + receiver->objectName(), event->type()); reportError(tr("an error occurred")); return false; } @@ -591,10 +573,8 @@ void MOApplication::updateStyle(const QString& fileName) } } - -MOSplash::MOSplash( - const Settings& settings, const QString& dataPath, - const MOBase::IPluginGame* game) +MOSplash::MOSplash(const Settings& settings, const QString& dataPath, + const MOBase::IPluginGame* game) { const auto splashPath = getSplashPath(settings, dataPath, game); if (splashPath.isEmpty()) { @@ -623,9 +603,8 @@ void MOSplash::close() } } -QString MOSplash::getSplashPath( - const Settings& settings, const QString& dataPath, - const MOBase::IPluginGame* game) const +QString MOSplash::getSplashPath(const Settings& settings, const QString& dataPath, + const MOBase::IPluginGame* game) const { if (!settings.useSplash()) { return {}; diff --git a/src/moapplication.h b/src/moapplication.h index 91090764..498242f3 100644 --- a/src/moapplication.h +++ b/src/moapplication.h @@ -20,9 +20,9 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef MOAPPLICATION_H #define MOAPPLICATION_H +#include "env.h" #include <QApplication> #include <QFileSystemWatcher> -#include "env.h" class Settings; class MOMultiProcess; @@ -31,7 +31,10 @@ class PluginContainer; class OrganizerCore; class NexusInterface; -namespace MOBase { class IPluginGame; } +namespace MOBase +{ +class IPluginGame; +} class MOApplication : public QApplication { @@ -90,22 +93,19 @@ private: void purgeOldFiles(); }; - class MOSplash { public: - MOSplash( - const Settings& settings, const QString& dataPath, - const MOBase::IPluginGame* game); + MOSplash(const Settings& settings, const QString& dataPath, + const MOBase::IPluginGame* game); void close(); private: std::unique_ptr<QSplashScreen> ss_; - QString getSplashPath( - const Settings& settings, const QString& dataPath, - const MOBase::IPluginGame* game) const; + QString getSplashPath(const Settings& settings, const QString& dataPath, + const MOBase::IPluginGame* game) const; }; -#endif // MOAPPLICATION_H +#endif // MOAPPLICATION_H diff --git a/src/modconflicticondelegate.cpp b/src/modconflicticondelegate.cpp index fc0ee48a..c0b4d46d 100644 --- a/src/modconflicticondelegate.cpp +++ b/src/modconflicticondelegate.cpp @@ -1,29 +1,31 @@ #include "modconflicticondelegate.h" #include "modlist.h" #include "modlistview.h" -#include <log.h> #include <QList> +#include <log.h> using namespace MOBase; -ModConflictIconDelegate::ModConflictIconDelegate(ModListView* view, int logicalIndex, int compactSize) - : IconDelegate(view, logicalIndex, compactSize), m_view(view) -{ -} +ModConflictIconDelegate::ModConflictIconDelegate(ModListView* view, int logicalIndex, + int compactSize) + : IconDelegate(view, logicalIndex, compactSize), m_view(view) +{} -QList<QString> ModConflictIconDelegate::getIconsForFlags( - std::vector<ModInfo::EConflictFlag> flags, bool compact) +QList<QString> +ModConflictIconDelegate::getIconsForFlags(std::vector<ModInfo::EConflictFlag> flags, + bool compact) { QList<QString> result; // Don't do flags for overwrite - if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE_CONFLICT) != flags.end()) + if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE_CONFLICT) != + flags.end()) return result; // insert conflict icons to provide nicer alignment - { // insert loose file conflicts first - auto iter = std::find_first_of(flags.begin(), flags.end(), - s_ConflictFlags.begin(), s_ConflictFlags.end()); + { // insert loose file conflicts first + auto iter = std::find_first_of(flags.begin(), flags.end(), s_ConflictFlags.begin(), + s_ConflictFlags.end()); if (iter != flags.end()) { result.append(getFlagIcon(*iter)); flags.erase(iter); @@ -32,9 +34,9 @@ QList<QString> ModConflictIconDelegate::getIconsForFlags( } } - { // insert loose vs archive overwrite second + { // insert loose vs archive overwrite second auto iter = std::find(flags.begin(), flags.end(), - ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITE); + ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITE); if (iter != flags.end()) { result.append(getFlagIcon(*iter)); flags.erase(iter); @@ -43,9 +45,9 @@ QList<QString> ModConflictIconDelegate::getIconsForFlags( } } - { // insert loose vs archive overwritten third + { // insert loose vs archive overwritten third auto iter = std::find(flags.begin(), flags.end(), - ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITTEN); + ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITTEN); if (iter != flags.end()) { result.append(getFlagIcon(*iter)); flags.erase(iter); @@ -54,9 +56,10 @@ QList<QString> ModConflictIconDelegate::getIconsForFlags( } } - { // insert archive conflicts last - auto iter = std::find_first_of(flags.begin(), flags.end(), - s_ArchiveConflictFlags.begin(), s_ArchiveConflictFlags.end()); + { // insert archive conflicts last + auto iter = + std::find_first_of(flags.begin(), flags.end(), s_ArchiveConflictFlags.begin(), + s_ArchiveConflictFlags.end()); if (iter != flags.end()) { result.append(getFlagIcon(*iter)); flags.erase(iter); @@ -74,7 +77,7 @@ QList<QString> ModConflictIconDelegate::getIconsForFlags( return result; } -QList<QString> ModConflictIconDelegate::getIcons(const QModelIndex &index) const +QList<QString> ModConflictIconDelegate::getIcons(const QModelIndex& index) const { QVariant modIndex = index.data(ModList::IndexRole); @@ -90,23 +93,33 @@ QList<QString> ModConflictIconDelegate::getIcons(const QModelIndex &index) const QString ModConflictIconDelegate::getFlagIcon(ModInfo::EConflictFlag flag) { switch (flag) { - case ModInfo::FLAG_CONFLICT_MIXED: return QStringLiteral(":/MO/gui/emblem_conflict_mixed"); - case ModInfo::FLAG_CONFLICT_OVERWRITE: return QStringLiteral(":/MO/gui/emblem_conflict_overwrite"); - case ModInfo::FLAG_CONFLICT_OVERWRITTEN: return QStringLiteral(":/MO/gui/emblem_conflict_overwritten"); - case ModInfo::FLAG_CONFLICT_REDUNDANT: return QStringLiteral(":/MO/gui/emblem_conflict_redundant"); - case ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITE: return QStringLiteral(":/MO/gui/archive_loose_conflict_overwrite"); - case ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITTEN: return QStringLiteral(":/MO/gui/archive_loose_conflict_overwritten"); - case ModInfo::FLAG_ARCHIVE_CONFLICT_MIXED: return QStringLiteral(":/MO/gui/archive_conflict_mixed"); - case ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITE: return QStringLiteral(":/MO/gui/archive_conflict_winner"); - case ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITTEN: return QStringLiteral(":/MO/gui/archive_conflict_loser"); - case ModInfo::FLAG_OVERWRITE_CONFLICT: return QString(); - default: - log::warn("ModInfo flag {} has no defined icon", flag); - return QString(); + case ModInfo::FLAG_CONFLICT_MIXED: + return QStringLiteral(":/MO/gui/emblem_conflict_mixed"); + case ModInfo::FLAG_CONFLICT_OVERWRITE: + return QStringLiteral(":/MO/gui/emblem_conflict_overwrite"); + case ModInfo::FLAG_CONFLICT_OVERWRITTEN: + return QStringLiteral(":/MO/gui/emblem_conflict_overwritten"); + case ModInfo::FLAG_CONFLICT_REDUNDANT: + return QStringLiteral(":/MO/gui/emblem_conflict_redundant"); + case ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITE: + return QStringLiteral(":/MO/gui/archive_loose_conflict_overwrite"); + case ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITTEN: + return QStringLiteral(":/MO/gui/archive_loose_conflict_overwritten"); + case ModInfo::FLAG_ARCHIVE_CONFLICT_MIXED: + return QStringLiteral(":/MO/gui/archive_conflict_mixed"); + case ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITE: + return QStringLiteral(":/MO/gui/archive_conflict_winner"); + case ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITTEN: + return QStringLiteral(":/MO/gui/archive_conflict_loser"); + case ModInfo::FLAG_OVERWRITE_CONFLICT: + return QString(); + default: + log::warn("ModInfo flag {} has no defined icon", flag); + return QString(); } } -size_t ModConflictIconDelegate::getNumIcons(const QModelIndex &index) const +size_t ModConflictIconDelegate::getNumIcons(const QModelIndex& index) const { QVariant modIndex = index.data(ModList::IndexRole); @@ -117,9 +130,10 @@ size_t ModConflictIconDelegate::getNumIcons(const QModelIndex &index) const return m_view->conflictFlags(index, nullptr).size(); } -QSize ModConflictIconDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &modelIndex) const +QSize ModConflictIconDelegate::sizeHint(const QStyleOptionViewItem& option, + const QModelIndex& modelIndex) const { - size_t count = getNumIcons(modelIndex); + size_t count = getNumIcons(modelIndex); unsigned int index = modelIndex.data(ModList::IndexRole).toInt(); QSize result; if (index < ModInfo::getNumMods()) { diff --git a/src/modconflicticondelegate.h b/src/modconflicticondelegate.h index fd524444..81e97179 100644 --- a/src/modconflicticondelegate.h +++ b/src/modconflicticondelegate.h @@ -13,39 +13,35 @@ class ModConflictIconDelegate : public IconDelegate Q_OBJECT; public: - explicit ModConflictIconDelegate(ModListView* view, int logicalIndex = -1, int compactSize = 80); - QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex &index) const override; + explicit ModConflictIconDelegate(ModListView* view, int logicalIndex = -1, + int compactSize = 80); + QSize sizeHint(const QStyleOptionViewItem& option, + const QModelIndex& index) const override; protected: - - static QList<QString> getIconsForFlags(std::vector<ModInfo::EConflictFlag> flags, bool compact); + static QList<QString> getIconsForFlags(std::vector<ModInfo::EConflictFlag> flags, + bool compact); static QString getFlagIcon(ModInfo::EConflictFlag flag); - QList<QString> getIcons(const QModelIndex &index) const override; - size_t getNumIcons(const QModelIndex &index) const override; + QList<QString> getIcons(const QModelIndex& index) const override; + size_t getNumIcons(const QModelIndex& index) const override; // constructor for color table // - ModConflictIconDelegate() : ModConflictIconDelegate(nullptr) { } + ModConflictIconDelegate() : ModConflictIconDelegate(nullptr) {} private: static constexpr std::array s_ConflictFlags{ - ModInfo::FLAG_CONFLICT_MIXED, - ModInfo::FLAG_CONFLICT_OVERWRITE, - ModInfo::FLAG_CONFLICT_OVERWRITTEN, - ModInfo::FLAG_CONFLICT_REDUNDANT - }; + ModInfo::FLAG_CONFLICT_MIXED, ModInfo::FLAG_CONFLICT_OVERWRITE, + ModInfo::FLAG_CONFLICT_OVERWRITTEN, ModInfo::FLAG_CONFLICT_REDUNDANT}; static constexpr std::array s_ArchiveLooseConflictFlags{ - ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITE, - ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITTEN - }; + ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITE, + ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITTEN}; static constexpr std::array s_ArchiveConflictFlags{ - ModInfo::FLAG_ARCHIVE_CONFLICT_MIXED, - ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITE, - ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITTEN - }; + ModInfo::FLAG_ARCHIVE_CONFLICT_MIXED, ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITE, + ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITTEN}; ModListView* m_view; }; -#endif // MODCONFLICTICONDELEGATE_H +#endif // MODCONFLICTICONDELEGATE_H diff --git a/src/modcontenticondelegate.cpp b/src/modcontenticondelegate.cpp index 57a4dc6d..c2c88933 100644 --- a/src/modcontenticondelegate.cpp +++ b/src/modcontenticondelegate.cpp @@ -2,10 +2,10 @@ #include "modlistview.h" -ModContentIconDelegate::ModContentIconDelegate(ModListView* view, int column, int compactSize) - : IconDelegate(view, column, compactSize), m_view(view) -{ -} +ModContentIconDelegate::ModContentIconDelegate(ModListView* view, int column, + int compactSize) + : IconDelegate(view, column, compactSize), m_view(view) +{} QList<QString> ModContentIconDelegate::getIcons(const QModelIndex& index) const { @@ -30,8 +30,9 @@ size_t ModContentIconDelegate::getNumIcons(const QModelIndex& index) const return getIcons(index).size(); } -bool ModContentIconDelegate::helpEvent( - QHelpEvent* event, QAbstractItemView* view, const QStyleOptionViewItem& option, const QModelIndex& index) +bool ModContentIconDelegate::helpEvent(QHelpEvent* event, QAbstractItemView* view, + const QStyleOptionViewItem& option, + const QModelIndex& index) { if (!event || !view) { return false; @@ -39,19 +40,21 @@ bool ModContentIconDelegate::helpEvent( if (event->type() == QEvent::ToolTip) { // this code is from QAbstractItemDelegate::helpEvent, only the the way // text is retrieved has been changed - QHelpEvent* he = static_cast<QHelpEvent*>(event); - const int precision = inherits("QItemDelegate") ? 10 : 6; // keep in sync with DBL_DIG in qitemdelegate.cpp - const QString tooltip = index.isValid() ? m_view->contentsTooltip(index) : QString(); + QHelpEvent* he = static_cast<QHelpEvent*>(event); + const int precision = inherits("QItemDelegate") + ? 10 + : 6; // keep in sync with DBL_DIG in qitemdelegate.cpp + const QString tooltip = + index.isValid() ? m_view->contentsTooltip(index) : QString(); QRect rect; if (index.isValid()) { const QRect r = view->visualRect(index); - rect = QRect(view->mapToGlobal(r.topLeft()), r.size()); + rect = QRect(view->mapToGlobal(r.topLeft()), r.size()); } QToolTip::showText(he->globalPos(), tooltip, view, rect); event->setAccepted(!tooltip.isEmpty()); return true; - } - else { + } else { return IconDelegate::helpEvent(event, view, option, index); } } diff --git a/src/modcontenticondelegate.h b/src/modcontenticondelegate.h index c195df18..736244f6 100644 --- a/src/modcontenticondelegate.h +++ b/src/modcontenticondelegate.h @@ -9,11 +9,11 @@ class ModContentIconDelegate : public IconDelegate { Q_OBJECT public: - - explicit ModContentIconDelegate(ModListView* view, int column = -1, int compactSize = 150); + explicit ModContentIconDelegate(ModListView* view, int column = -1, + int compactSize = 150); bool helpEvent(QHelpEvent* event, QAbstractItemView* view, - const QStyleOptionViewItem& option, const QModelIndex& index) override; + const QStyleOptionViewItem& option, const QModelIndex& index) override; protected: QList<QString> getIcons(const QModelIndex& index) const override; @@ -21,10 +21,10 @@ protected: // constructor for color table // - ModContentIconDelegate() : ModContentIconDelegate(nullptr) { } + ModContentIconDelegate() : ModContentIconDelegate(nullptr) {} private: ModListView* m_view; }; -#endif // GENERICICONDELEGATE_H +#endif // GENERICICONDELEGATE_H diff --git a/src/modelutils.cpp b/src/modelutils.cpp index 83054806..1cdf9657 100644 --- a/src/modelutils.cpp +++ b/src/modelutils.cpp @@ -2,10 +2,11 @@ #include <QAbstractProxyModel> -namespace MOShared { +namespace MOShared +{ -QModelIndexList flatIndex( - const QAbstractItemModel* model, int column, const QModelIndex& parent) +QModelIndexList flatIndex(const QAbstractItemModel* model, int column, + const QModelIndex& parent) { QModelIndexList index; for (std::size_t i = 0; i < model->rowCount(parent); ++i) { @@ -15,7 +16,8 @@ QModelIndexList flatIndex( return index; } -static QModelIndexList visibleIndexImpl(QTreeView* view, int column, const QModelIndex& parent) +static QModelIndexList visibleIndexImpl(QTreeView* view, int column, + const QModelIndex& parent) { if (parent.isValid() && !view->isExpanded(parent)) { return {}; @@ -59,7 +61,8 @@ QModelIndex indexModelToView(const QModelIndex& index, const QAbstractItemView* return qindex; } -QModelIndexList indexModelToView(const QModelIndexList& index, const QAbstractItemView* view) +QModelIndexList indexModelToView(const QModelIndexList& index, + const QAbstractItemView* view) { QModelIndexList result; for (auto& idx : index) { @@ -72,16 +75,15 @@ QModelIndex indexViewToModel(const QModelIndex& index, const QAbstractItemModel* { if (index.model() == model) { return index; - } - else if (auto* proxy = qobject_cast<const QAbstractProxyModel*>(index.model())) { + } else if (auto* proxy = qobject_cast<const QAbstractProxyModel*>(index.model())) { return indexViewToModel(proxy->mapToSource(index), model); - } - else { + } else { return QModelIndex(); } } -QModelIndexList indexViewToModel(const QModelIndexList& index, const QAbstractItemModel* model) +QModelIndexList indexViewToModel(const QModelIndexList& index, + const QAbstractItemModel* model) { QModelIndexList result; for (auto& idx : index) { @@ -90,4 +92,4 @@ QModelIndexList indexViewToModel(const QModelIndexList& index, const QAbstractIt return result; } -} +} // namespace MOShared diff --git a/src/modelutils.h b/src/modelutils.h index e6510941..f2faeff7 100644 --- a/src/modelutils.h +++ b/src/modelutils.h @@ -1,25 +1,28 @@ #ifndef MODELUTILS_H #define MODELUTILS_H -#include <QAbstractItemView> #include <QAbstractItemModel> +#include <QAbstractItemView> #include <QColor> -namespace MOShared { +namespace MOShared +{ // retrieve all the row index under the given parent -QModelIndexList flatIndex( - const QAbstractItemModel* model, int column = 0, const QModelIndex& parent = QModelIndex()); +QModelIndexList flatIndex(const QAbstractItemModel* model, int column = 0, + const QModelIndex& parent = QModelIndex()); // retrieve all the visible index in the given view QModelIndexList visibleIndex(QTreeView* view, int column = 0); // convert back-and-forth through model proxies QModelIndex indexModelToView(const QModelIndex& index, const QAbstractItemView* view); -QModelIndexList indexModelToView(const QModelIndexList& index, const QAbstractItemView* view); +QModelIndexList indexModelToView(const QModelIndexList& index, + const QAbstractItemView* view); QModelIndex indexViewToModel(const QModelIndex& index, const QAbstractItemModel* model); -QModelIndexList indexViewToModel(const QModelIndexList& index, const QAbstractItemModel* model); +QModelIndexList indexViewToModel(const QModelIndexList& index, + const QAbstractItemModel* model); -} +} // namespace MOShared #endif diff --git a/src/modflagicondelegate.cpp b/src/modflagicondelegate.cpp index 43976999..e656e390 100644 --- a/src/modflagicondelegate.cpp +++ b/src/modflagicondelegate.cpp @@ -1,18 +1,17 @@ #include "modflagicondelegate.h" #include "modlist.h" #include "modlistview.h" -#include <log.h> #include <QList> +#include <log.h> using namespace MOBase; ModFlagIconDelegate::ModFlagIconDelegate(ModListView* view, int column, int compactSize) - : IconDelegate(view, column, compactSize), m_view(view) -{ -} + : IconDelegate(view, column, compactSize), m_view(view) +{} -QList<QString> ModFlagIconDelegate::getIconsForFlags( - std::vector<ModInfo::EFlag> flags, bool compact) +QList<QString> ModFlagIconDelegate::getIconsForFlags(std::vector<ModInfo::EFlag> flags, + bool compact) { QList<QString> result; @@ -29,7 +28,7 @@ QList<QString> ModFlagIconDelegate::getIconsForFlags( return result; } -QList<QString> ModFlagIconDelegate::getIcons(const QModelIndex &index) const +QList<QString> ModFlagIconDelegate::getIcons(const QModelIndex& index) const { QVariant modid = index.data(ModList::IndexRole); @@ -45,28 +44,39 @@ QList<QString> ModFlagIconDelegate::getIcons(const QModelIndex &index) const QString ModFlagIconDelegate::getFlagIcon(ModInfo::EFlag flag) { switch (flag) { - case ModInfo::FLAG_BACKUP: return QStringLiteral(":/MO/gui/emblem_backup"); - case ModInfo::FLAG_INVALID: return QStringLiteral(":/MO/gui/problem"); - case ModInfo::FLAG_NOTENDORSED: return QStringLiteral(":/MO/gui/emblem_notendorsed"); - case ModInfo::FLAG_NOTES: return QStringLiteral(":/MO/gui/emblem_notes"); - case ModInfo::FLAG_HIDDEN_FILES: return QStringLiteral(":/MO/gui/emblem_hidden_files"); - case ModInfo::FLAG_ALTERNATE_GAME: return QStringLiteral(":/MO/gui/alternate_game"); - case ModInfo::FLAG_FOREIGN: return QString(); - case ModInfo::FLAG_SEPARATOR: return QString(); - case ModInfo::FLAG_OVERWRITE: return QString(); - case ModInfo::FLAG_PLUGIN_SELECTED: return QString(); - case ModInfo::FLAG_TRACKED: return QStringLiteral(":/MO/gui/tracked"); - default: - log::warn("ModInfo flag {} has no defined icon", flag); - return QString(); + case ModInfo::FLAG_BACKUP: + return QStringLiteral(":/MO/gui/emblem_backup"); + case ModInfo::FLAG_INVALID: + return QStringLiteral(":/MO/gui/problem"); + case ModInfo::FLAG_NOTENDORSED: + return QStringLiteral(":/MO/gui/emblem_notendorsed"); + case ModInfo::FLAG_NOTES: + return QStringLiteral(":/MO/gui/emblem_notes"); + case ModInfo::FLAG_HIDDEN_FILES: + return QStringLiteral(":/MO/gui/emblem_hidden_files"); + case ModInfo::FLAG_ALTERNATE_GAME: + return QStringLiteral(":/MO/gui/alternate_game"); + case ModInfo::FLAG_FOREIGN: + return QString(); + case ModInfo::FLAG_SEPARATOR: + return QString(); + case ModInfo::FLAG_OVERWRITE: + return QString(); + case ModInfo::FLAG_PLUGIN_SELECTED: + return QString(); + case ModInfo::FLAG_TRACKED: + return QStringLiteral(":/MO/gui/tracked"); + default: + log::warn("ModInfo flag {} has no defined icon", flag); + return QString(); } } -size_t ModFlagIconDelegate::getNumIcons(const QModelIndex &index) const +size_t ModFlagIconDelegate::getNumIcons(const QModelIndex& index) const { unsigned int modIdx = index.data(ModList::IndexRole).toInt(); if (modIdx < ModInfo::getNumMods()) { - ModInfo::Ptr info = ModInfo::getByIndex(modIdx); + ModInfo::Ptr info = ModInfo::getByIndex(modIdx); std::vector<ModInfo::EFlag> flags = info->getFlags(); return flags.size(); } else { @@ -74,10 +84,10 @@ size_t ModFlagIconDelegate::getNumIcons(const QModelIndex &index) const } } - -QSize ModFlagIconDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &modelIndex) const +QSize ModFlagIconDelegate::sizeHint(const QStyleOptionViewItem& option, + const QModelIndex& modelIndex) const { - size_t count = getNumIcons(modelIndex); + size_t count = getNumIcons(modelIndex); unsigned int index = modelIndex.data(ModList::IndexRole).toInt(); QSize result; if (index < ModInfo::getNumMods()) { @@ -90,4 +100,3 @@ QSize ModFlagIconDelegate::sizeHint(const QStyleOptionViewItem &option, const QM } return result; } - diff --git a/src/modflagicondelegate.h b/src/modflagicondelegate.h index 982bfefd..e3571b2f 100644 --- a/src/modflagicondelegate.h +++ b/src/modflagicondelegate.h @@ -13,23 +13,25 @@ class ModFlagIconDelegate : public IconDelegate Q_OBJECT; public: - explicit ModFlagIconDelegate(ModListView* view, int column = -1, int compactSize = 120); - QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; + explicit ModFlagIconDelegate(ModListView* view, int column = -1, + int compactSize = 120); + QSize sizeHint(const QStyleOptionViewItem& option, + const QModelIndex& index) const override; protected: - static QList<QString> getIconsForFlags(std::vector<ModInfo::EFlag> flags, bool compact); + static QList<QString> getIconsForFlags(std::vector<ModInfo::EFlag> flags, + bool compact); static QString getFlagIcon(ModInfo::EFlag flag); - QList<QString> getIcons(const QModelIndex &index) const override; - size_t getNumIcons(const QModelIndex &index) const override; + QList<QString> getIcons(const QModelIndex& index) const override; + size_t getNumIcons(const QModelIndex& index) const override; // constructor for color table // - ModFlagIconDelegate() : ModFlagIconDelegate(nullptr) { } + ModFlagIconDelegate() : ModFlagIconDelegate(nullptr) {} private: ModListView* m_view; - }; -#endif // MODFLAGICONDELEGATE_H +#endif // MODFLAGICONDELEGATE_H diff --git a/src/modidlineedit.cpp b/src/modidlineedit.cpp index 50cb0f0b..1920f377 100644 --- a/src/modidlineedit.cpp +++ b/src/modidlineedit.cpp @@ -4,14 +4,15 @@ #include <QEvent> #include <QWhatsThisClickedEvent> -ModIDLineEdit::ModIDLineEdit(QWidget *parent) : QLineEdit(parent) {} -ModIDLineEdit::ModIDLineEdit(const QString &text, QWidget *parent) : QLineEdit(text, parent) {} +ModIDLineEdit::ModIDLineEdit(QWidget* parent) : QLineEdit(parent) {} +ModIDLineEdit::ModIDLineEdit(const QString& text, QWidget* parent) + : QLineEdit(text, parent) +{} -bool ModIDLineEdit::event(QEvent *event) +bool ModIDLineEdit::event(QEvent* event) { - if (event->type() == QEvent::WhatsThisClicked) - { - QWhatsThisClickedEvent *wtcEvent = static_cast<QWhatsThisClickedEvent*>(event); + if (event->type() == QEvent::WhatsThisClicked) { + QWhatsThisClickedEvent* wtcEvent = static_cast<QWhatsThisClickedEvent*>(event); emit linkClicked(wtcEvent->href().trimmed()); } diff --git a/src/modidlineedit.h b/src/modidlineedit.h index 8f945a8c..1572f07d 100644 --- a/src/modidlineedit.h +++ b/src/modidlineedit.h @@ -8,15 +8,14 @@ class ModIDLineEdit : public QLineEdit Q_OBJECT public: - explicit ModIDLineEdit(QWidget *parent = 0); - explicit ModIDLineEdit(const QString &text, QWidget *parent = 0); + explicit ModIDLineEdit(QWidget* parent = 0); + explicit ModIDLineEdit(const QString& text, QWidget* parent = 0); public: virtual bool event(QEvent* event) override; signals: void linkClicked(QString); - }; -#endif //MODIDLINEEDIT_H +#endif // MODIDLINEEDIT_H diff --git a/src/modinfo.cpp b/src/modinfo.cpp index 3c54fc27..1d30ac95 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -20,26 +20,26 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "modinfo.h" #include "modinfobackup.h" -#include "modinforegular.h" #include "modinfoforeign.h" #include "modinfooverwrite.h" +#include "modinforegular.h" #include "modinfoseparator.h" #include "categories.h" #include "modinfodialog.h" -#include "organizercore.h" #include "modlist.h" +#include "organizercore.h" #include "overwriteinfodialog.h" -#include "versioninfo.h" #include "thread_utils.h" +#include "versioninfo.h" -#include <iplugingame.h> -#include <versioninfo.h> #include "shared/appconfig.h" -#include <scriptextender.h> -#include <unmanagedmods.h> +#include <iplugingame.h> #include <log.h> #include <report.h> +#include <scriptextender.h> +#include <unmanagedmods.h> +#include <versioninfo.h> #include <QApplication> #include <QDirIterator> @@ -48,7 +48,6 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. using namespace MOBase; using namespace MOShared; - const std::set<unsigned int> ModInfo::s_EmptySet; std::vector<ModInfo::Ptr> ModInfo::s_Collection; ModInfo::Ptr ModInfo::s_Overwrite; @@ -59,21 +58,22 @@ QRecursiveMutex ModInfo::s_Mutex; QString ModInfo::s_HiddenExt(".mohidden"); - -bool ModInfo::ByName(const ModInfo::Ptr &LHS, const ModInfo::Ptr &RHS) +bool ModInfo::ByName(const ModInfo::Ptr& LHS, const ModInfo::Ptr& RHS) { return QString::compare(LHS->name(), RHS->name(), Qt::CaseInsensitive) < 0; } bool ModInfo::isSeparatorName(const QString& name) { - static QRegularExpression separatorExp(QRegularExpression::anchoredPattern(".*_separator")); + static QRegularExpression separatorExp( + QRegularExpression::anchoredPattern(".*_separator")); return separatorExp.match(name).hasMatch(); } bool ModInfo::isBackupName(const QString& name) { - static QRegularExpression backupExp(QRegularExpression::anchoredPattern(".*backup[0-9]*")); + static QRegularExpression backupExp( + QRegularExpression::anchoredPattern(".*backup[0-9]*")); return backupExp.match(name).hasMatch(); } @@ -82,8 +82,7 @@ bool ModInfo::isRegularName(const QString& name) return !isSeparatorName(name) && !isBackupName(name); } - -ModInfo::Ptr ModInfo::createFrom(const QDir &dir, OrganizerCore& core) +ModInfo::Ptr ModInfo::createFrom(const QDir& dir, OrganizerCore& core) { QMutexLocker locker(&s_Mutex); ModInfo::Ptr result; @@ -100,13 +99,13 @@ ModInfo::Ptr ModInfo::createFrom(const QDir &dir, OrganizerCore& core) return result; } -ModInfo::Ptr ModInfo::createFromPlugin(const QString &modName, - const QString &espName, - const QStringList &bsaNames, - ModInfo::EModType modType, - OrganizerCore& core) { +ModInfo::Ptr ModInfo::createFromPlugin(const QString& modName, const QString& espName, + const QStringList& bsaNames, + ModInfo::EModType modType, OrganizerCore& core) +{ QMutexLocker locker(&s_Mutex); - ModInfo::Ptr result = ModInfo::Ptr(new ModInfoForeign(modName, espName, bsaNames, modType, core)); + ModInfo::Ptr result = + ModInfo::Ptr(new ModInfoForeign(modName, espName, bsaNames, modType, core)); result->m_Index = s_Collection.size(); s_Collection.push_back(result); return result; @@ -116,7 +115,7 @@ ModInfo::Ptr ModInfo::createFromOverwrite(OrganizerCore& core) { QMutexLocker locker(&s_Mutex); ModInfo::Ptr overwrite = ModInfo::Ptr(new ModInfoOverwrite(core)); - overwrite->m_Index = s_Collection.size(); + overwrite->m_Index = s_Collection.size(); s_Collection.push_back(overwrite); return overwrite; } @@ -127,7 +126,6 @@ unsigned int ModInfo::getNumMods() return static_cast<unsigned int>(s_Collection.size()); } - ModInfo::Ptr ModInfo::getByIndex(unsigned int index) { QMutexLocker locker(&s_Mutex); @@ -135,11 +133,11 @@ ModInfo::Ptr ModInfo::getByIndex(unsigned int index) if (index >= s_Collection.size() && index != ULONG_MAX) { throw MyException(tr("invalid mod index: %1").arg(index)); } - if (index == ULONG_MAX) return s_Collection[ModInfo::getIndex("Overwrite")]; + if (index == ULONG_MAX) + return s_Collection[ModInfo::getIndex("Overwrite")]; return s_Collection[index]; } - std::vector<ModInfo::Ptr> ModInfo::getByModID(QString game, int modID) { QMutexLocker locker(&s_Mutex); @@ -164,15 +162,13 @@ std::vector<ModInfo::Ptr> ModInfo::getByModID(QString game, int modID) return result; } - -ModInfo::Ptr ModInfo::getByName(const QString &name) +ModInfo::Ptr ModInfo::getByName(const QString& name) { QMutexLocker locker(&s_Mutex); return s_Collection[ModInfo::getIndex(name)]; } - bool ModInfo::removeMod(unsigned int index) { QMutexLocker locker(&s_Mutex); @@ -186,7 +182,8 @@ bool ModInfo::removeMod(unsigned int index) // remove the actual mod (this is the most likely to fail so we do this first) if (modInfo->isRegular()) { if (!shellDelete(QStringList(modInfo->absolutePath()), true)) { - reportError(tr("remove: failed to delete mod '%1' directory").arg(modInfo->name())); + reportError( + tr("remove: failed to delete mod '%1' directory").arg(modInfo->name())); return false; } } @@ -194,11 +191,13 @@ bool ModInfo::removeMod(unsigned int index) // update the indices s_ModsByName.erase(s_ModsByName.find(modInfo->name())); - auto iter = s_ModsByModID.find(std::pair<QString, int>(modInfo->gameName(), modInfo->nexusId())); + auto iter = s_ModsByModID.find( + std::pair<QString, int>(modInfo->gameName(), modInfo->nexusId())); if (iter != s_ModsByModID.end()) { std::vector<unsigned int> indices = iter->second; indices.erase(std::remove(indices.begin(), indices.end(), index), indices.end()); - s_ModsByModID[std::pair<QString, int>(modInfo->gameName(), modInfo->nexusId())] = indices; + s_ModsByModID[std::pair<QString, int>(modInfo->gameName(), modInfo->nexusId())] = + indices; } // finally, remove the mod from the collection @@ -209,8 +208,7 @@ bool ModInfo::removeMod(unsigned int index) return true; } - -unsigned int ModInfo::getIndex(const QString &name) +unsigned int ModInfo::getIndex(const QString& name) { QMutexLocker locker(&s_Mutex); @@ -222,7 +220,7 @@ unsigned int ModInfo::getIndex(const QString &name) return iter->second; } -unsigned int ModInfo::findMod(const boost::function<bool (ModInfo::Ptr)> &filter) +unsigned int ModInfo::findMod(const boost::function<bool(ModInfo::Ptr)>& filter) { for (unsigned int i = 0U; i < s_Collection.size(); ++i) { if (filter(s_Collection[i])) { @@ -232,19 +230,17 @@ unsigned int ModInfo::findMod(const boost::function<bool (ModInfo::Ptr)> &filter return UINT_MAX; } - -void ModInfo::updateFromDisc( - const QString& modsDirectory, OrganizerCore& core, - bool displayForeign, std::size_t refreshThreadCount) +void ModInfo::updateFromDisc(const QString& modsDirectory, OrganizerCore& core, + bool displayForeign, std::size_t refreshThreadCount) { TimeThis tt("ModInfo::updateFromDisc()"); QMutexLocker lock(&s_Mutex); s_Collection.clear(); - s_NextID = 0; + s_NextID = 0; s_Overwrite = nullptr; - { // list all directories in the mod directory and make a mod out of each + { // list all directories in the mod directory and make a mod out of each QDir mods(QDir::fromNativeSeparators(modsDirectory)); mods.setFilter(QDir::Dirs | QDir::NoDotAndDotDot); QDirIterator modIter(mods); @@ -253,17 +249,22 @@ void ModInfo::updateFromDisc( } } - auto* game = core.managedGame(); - UnmanagedMods *unmanaged = game->feature<UnmanagedMods>(); + auto* game = core.managedGame(); + UnmanagedMods* unmanaged = game->feature<UnmanagedMods>(); if (unmanaged != nullptr) { - for (const QString &modName : unmanaged->mods(!displayForeign)) { - ModInfo::EModType modType = game->DLCPlugins().contains(unmanaged->referenceFile(modName).fileName(), Qt::CaseInsensitive) ? ModInfo::EModType::MOD_DLC : - (game->CCPlugins().contains(unmanaged->referenceFile(modName).fileName(), Qt::CaseInsensitive) ? ModInfo::EModType::MOD_CC : ModInfo::EModType::MOD_DEFAULT); + for (const QString& modName : unmanaged->mods(!displayForeign)) { + ModInfo::EModType modType = + game->DLCPlugins().contains(unmanaged->referenceFile(modName).fileName(), + Qt::CaseInsensitive) + ? ModInfo::EModType::MOD_DLC + : (game->CCPlugins().contains( + unmanaged->referenceFile(modName).fileName(), Qt::CaseInsensitive) + ? ModInfo::EModType::MOD_CC + : ModInfo::EModType::MOD_DEFAULT); createFromPlugin(unmanaged->displayName(modName), unmanaged->referenceFile(modName).absoluteFilePath(), - unmanaged->secondaryFiles(modName), - modType, core); + unmanaged->secondaryFiles(modName), modType, core); } } @@ -271,41 +272,35 @@ void ModInfo::updateFromDisc( std::sort(s_Collection.begin(), s_Collection.end(), ModInfo::ByName); - parallelMap(std::begin(s_Collection), std::end(s_Collection), &ModInfo::prefetch, refreshThreadCount); + parallelMap(std::begin(s_Collection), std::end(s_Collection), &ModInfo::prefetch, + refreshThreadCount); updateIndices(); - } - void ModInfo::updateIndices() { s_ModsByName.clear(); s_ModsByModID.clear(); for (unsigned int i = 0; i < s_Collection.size(); ++i) { - QString modName = s_Collection[i]->internalName(); - QString game = s_Collection[i]->gameName(); - int modID = s_Collection[i]->nexusId(); + QString modName = s_Collection[i]->internalName(); + QString game = s_Collection[i]->gameName(); + int modID = s_Collection[i]->nexusId(); s_Collection[i]->m_Index = i; - s_ModsByName[modName] = i; + s_ModsByName[modName] = i; s_ModsByModID[std::pair<QString, int>(game, modID)].push_back(i); } } +ModInfo::ModInfo(OrganizerCore& core) : m_PrimaryCategory(-1), m_Core(core) {} -ModInfo::ModInfo(OrganizerCore& core) - : m_PrimaryCategory(-1), m_Core(core) -{ -} - - -bool ModInfo::checkAllForUpdate(PluginContainer *pluginContainer, QObject *receiver) +bool ModInfo::checkAllForUpdate(PluginContainer* pluginContainer, QObject* receiver) { bool updatesAvailable = true; QDateTime earliest = QDateTime::currentDateTimeUtc(); - QDateTime latest = QDateTime::fromMSecsSinceEpoch(0); + QDateTime latest = QDateTime::fromMSecsSinceEpoch(0); std::set<QString> games; for (auto mod : s_Collection) { if (mod->canBeUpdated()) { @@ -319,16 +314,19 @@ bool ModInfo::checkAllForUpdate(PluginContainer *pluginContainer, QObject *recei // Detect invalid source games for (auto itr = games.begin(); itr != games.end();) { - auto gamePlugins = pluginContainer->plugins<IPluginGame>(); + auto gamePlugins = pluginContainer->plugins<IPluginGame>(); IPluginGame* gamePlugin = qApp->property("managed_game").value<IPluginGame*>(); for (auto plugin : gamePlugins) { - if (plugin != nullptr && plugin->gameShortName().compare(*itr, Qt::CaseInsensitive) == 0) { + if (plugin != nullptr && + plugin->gameShortName().compare(*itr, Qt::CaseInsensitive) == 0) { gamePlugin = plugin; break; } } if (gamePlugin != nullptr && gamePlugin->gameNexusName().isEmpty()) { - log::warn("{}", tr("The update check has found a mod with a Nexus ID and source game of %1, but this game is not a valid Nexus source.").arg(gamePlugin->gameName())); + log::warn("{}", tr("The update check has found a mod with a Nexus ID and source " + "game of %1, but this game is not a valid Nexus source.") + .arg(gamePlugin->gameName())); itr = games.erase(itr); } else { ++itr; @@ -338,66 +336,95 @@ bool ModInfo::checkAllForUpdate(PluginContainer *pluginContainer, QObject *recei if (latest < QDateTime::currentDateTimeUtc().addMonths(-1)) { std::set<std::pair<QString, int>> organizedGames; for (auto mod : s_Collection) { - if (mod->canBeUpdated() && mod->getLastNexusUpdate() < QDateTime::currentDateTimeUtc().addMonths(-1)) { - organizedGames.insert(std::make_pair<QString, int>(mod->gameName().toLower(), mod->nexusId())); + if (mod->canBeUpdated() && + mod->getLastNexusUpdate() < QDateTime::currentDateTimeUtc().addMonths(-1)) { + organizedGames.insert( + std::make_pair<QString, int>(mod->gameName().toLower(), mod->nexusId())); } } if (organizedGames.empty()) { - log::warn("{}", tr("All of your mods have been checked recently. We restrict update checks to help preserve your available API requests.")); + log::warn("{}", + tr("All of your mods have been checked recently. We restrict update " + "checks to help preserve your available API requests.")); updatesAvailable = false; } else { - log::info("{}", tr( - "You have mods that haven't been checked within the last month using the new API. These mods must be checked before we can use the bulk update API. " - "This will consume significantly more API requests than usual. You will need to rerun the update check once complete in order to parse the remaining mods.")); + log::info("{}", tr("You have mods that haven't been checked within the last " + "month using the new API. These mods must be checked before " + "we can use the bulk update API. " + "This will consume significantly more API requests than " + "usual. You will need to rerun the update check once complete " + "in order to parse the remaining mods.")); } for (auto game : organizedGames) - NexusInterface::instance().requestUpdates(game.second, receiver, QVariant(), game.first, QString()); + NexusInterface::instance().requestUpdates(game.second, receiver, QVariant(), + game.first, QString()); } else if (earliest < QDateTime::currentDateTimeUtc().addMonths(-1)) { for (auto gameName : games) - NexusInterface::instance().requestUpdateInfo(gameName, NexusInterface::UpdatePeriod::MONTH, receiver, QVariant(true), QString()); + NexusInterface::instance().requestUpdateInfo(gameName, + NexusInterface::UpdatePeriod::MONTH, + receiver, QVariant(true), QString()); } else if (earliest < QDateTime::currentDateTimeUtc().addDays(-7)) { for (auto gameName : games) - NexusInterface::instance().requestUpdateInfo(gameName, NexusInterface::UpdatePeriod::MONTH, receiver, QVariant(false), QString()); + NexusInterface::instance().requestUpdateInfo( + gameName, NexusInterface::UpdatePeriod::MONTH, receiver, QVariant(false), + QString()); } else if (earliest < QDateTime::currentDateTimeUtc().addDays(-1)) { for (auto gameName : games) - NexusInterface::instance().requestUpdateInfo(gameName, NexusInterface::UpdatePeriod::WEEK, receiver, QVariant(false), QString()); + NexusInterface::instance().requestUpdateInfo( + gameName, NexusInterface::UpdatePeriod::WEEK, receiver, QVariant(false), + QString()); } else { for (auto gameName : games) - NexusInterface::instance().requestUpdateInfo(gameName, NexusInterface::UpdatePeriod::DAY, receiver, QVariant(false), QString()); + NexusInterface::instance().requestUpdateInfo( + gameName, NexusInterface::UpdatePeriod::DAY, receiver, QVariant(false), + QString()); } return updatesAvailable; } -std::set<QSharedPointer<ModInfo>> ModInfo::filteredMods(QString gameName, QVariantList updateData, bool addOldMods, bool markUpdated) +std::set<QSharedPointer<ModInfo>> ModInfo::filteredMods(QString gameName, + QVariantList updateData, + bool addOldMods, + bool markUpdated) { std::set<QSharedPointer<ModInfo>> finalMods; for (QVariant result : updateData) { QVariantMap update = result.toMap(); - std::copy_if(s_Collection.begin(), s_Collection.end(), std::inserter(finalMods, finalMods.end()), [=](QSharedPointer<ModInfo> info) -> bool { - if (info->nexusId() == update["mod_id"].toInt() && info->gameName().compare(gameName, Qt::CaseInsensitive) == 0) - if (info->getLastNexusUpdate().addSecs(-3600) < QDateTime::fromSecsSinceEpoch(update["latest_file_update"].toInt(), Qt::UTC)) - return true; - return false; - }); + std::copy_if(s_Collection.begin(), s_Collection.end(), + std::inserter(finalMods, finalMods.end()), + [=](QSharedPointer<ModInfo> info) -> bool { + if (info->nexusId() == update["mod_id"].toInt() && + info->gameName().compare(gameName, Qt::CaseInsensitive) == 0) + if (info->getLastNexusUpdate().addSecs(-3600) < + QDateTime::fromSecsSinceEpoch( + update["latest_file_update"].toInt(), Qt::UTC)) + return true; + return false; + }); } if (addOldMods) for (auto mod : s_Collection) - if (mod->getLastNexusUpdate() < QDateTime::currentDateTimeUtc().addMonths(-1) && mod->gameName().compare(gameName, Qt::CaseInsensitive) == 0) + if (mod->getLastNexusUpdate() < QDateTime::currentDateTimeUtc().addMonths(-1) && + mod->gameName().compare(gameName, Qt::CaseInsensitive) == 0) finalMods.insert(mod); if (markUpdated) { std::set<QSharedPointer<ModInfo>> updates; - std::copy_if(s_Collection.begin(), s_Collection.end(), std::inserter(updates, updates.end()), [=](QSharedPointer<ModInfo> info) -> bool { - if (info->gameName().compare(gameName, Qt::CaseInsensitive) == 0 && info->canBeUpdated()) - return true; - return false; - }); + std::copy_if(s_Collection.begin(), s_Collection.end(), + std::inserter(updates, updates.end()), + [=](QSharedPointer<ModInfo> info) -> bool { + if (info->gameName().compare(gameName, Qt::CaseInsensitive) == 0 && + info->canBeUpdated()) + return true; + return false; + }); std::set<QSharedPointer<ModInfo>> diff; - std::set_difference(updates.begin(), updates.end(), finalMods.begin(), finalMods.end(), std::inserter(diff, diff.end())); + std::set_difference(updates.begin(), updates.end(), finalMods.begin(), + finalMods.end(), std::inserter(diff, diff.end())); for (auto skipped : diff) { skipped->setLastNexusUpdate(QDateTime::currentDateTimeUtc()); } @@ -405,7 +432,7 @@ std::set<QSharedPointer<ModInfo>> ModInfo::filteredMods(QString gameName, QVaria return finalMods; } -void ModInfo::manualUpdateCheck(QObject *receiver, std::multimap<QString, int> IDs) +void ModInfo::manualUpdateCheck(QObject* receiver, std::multimap<QString, int> IDs) { std::vector<QSharedPointer<ModInfo>> mods; std::set<std::pair<QString, int>> organizedGames; @@ -423,45 +450,48 @@ void ModInfo::manualUpdateCheck(QObject *receiver, std::multimap<QString, int> I mods.push_back(matchedMod); } } - mods.erase( - std::remove_if(mods.begin(), mods.end(), [](ModInfo::Ptr mod) -> bool { return mod->nexusId() <= 0; }), - mods.end() - ); + mods.erase(std::remove_if(mods.begin(), mods.end(), + [](ModInfo::Ptr mod) -> bool { + return mod->nexusId() <= 0; + }), + mods.end()); for (auto mod : mods) { mod->setLastNexusUpdate(QDateTime()); } - std::sort(mods.begin(), mods.end(), [](QSharedPointer<ModInfo> a, QSharedPointer<ModInfo> b) -> bool { - return a->getLastNexusUpdate() < b->getLastNexusUpdate(); - }); + std::sort(mods.begin(), mods.end(), + [](QSharedPointer<ModInfo> a, QSharedPointer<ModInfo> b) -> bool { + return a->getLastNexusUpdate() < b->getLastNexusUpdate(); + }); if (mods.size()) { log::info("Checking updates for {} mods...", mods.size()); for (auto mod : mods) { - organizedGames.insert(std::make_pair<QString, int>(mod->gameName().toLower(), mod->nexusId())); + organizedGames.insert( + std::make_pair<QString, int>(mod->gameName().toLower(), mod->nexusId())); } for (auto game : organizedGames) { - NexusInterface::instance().requestUpdates(game.second, receiver, QVariant(), game.first, QString()); + NexusInterface::instance().requestUpdates(game.second, receiver, QVariant(), + game.first, QString()); } } else { log::info("None of the selected mods can be updated."); } } - -void ModInfo::setVersion(const VersionInfo &version) +void ModInfo::setVersion(const VersionInfo& version) { m_Version = version; } -void ModInfo::setPluginSelected(const bool &isSelected) +void ModInfo::setPluginSelected(const bool& isSelected) { m_PluginSelected = isSelected; } -void ModInfo::addCategory(const QString &categoryName) +void ModInfo::addCategory(const QString& categoryName) { int id = CategoryFactory::instance().getCategoryID(categoryName); if (id == -1) { @@ -470,7 +500,7 @@ void ModInfo::addCategory(const QString &categoryName) setCategory(id, true); } -bool ModInfo::removeCategory(const QString &categoryName) +bool ModInfo::removeCategory(const QString& categoryName) { int id = CategoryFactory::instance().getCategoryID(categoryName); if (id == -1) { @@ -487,7 +517,7 @@ QStringList ModInfo::categories() const { QStringList result; - CategoryFactory &catFac = CategoryFactory::instance(); + CategoryFactory& catFac = CategoryFactory::instance(); for (int id : m_Categories) { result.append(catFac.getCategoryName(catFac.getCategoryIndex(id))); } @@ -504,12 +534,9 @@ bool ModInfo::hasFlag(ModInfo::EFlag flag) const bool ModInfo::hasAnyOfTheseFlags(std::vector<ModInfo::EFlag> flags) const { std::vector<EFlag> modFlags = getFlags(); - for (auto modFlag : modFlags) - { - for (auto flag : flags) - { - if (modFlag == flag) - { + for (auto modFlag : modFlags) { + for (auto flag : flags) { + if (modFlag == flag) { return true; } } @@ -519,7 +546,8 @@ bool ModInfo::hasAnyOfTheseFlags(std::vector<ModInfo::EFlag> flags) const bool ModInfo::categorySet(int categoryID) const { - for (std::set<int>::const_iterator iter = m_Categories.begin(); iter != m_Categories.end(); ++iter) { + for (std::set<int>::const_iterator iter = m_Categories.begin(); + iter != m_Categories.end(); ++iter) { if ((*iter == categoryID) || (CategoryFactory::instance().isDescendantOf(*iter, categoryID))) { return true; diff --git a/src/modinfo.h b/src/modinfo.h index 8f82a453..9895d44c 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -20,8 +20,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef MODINFO_H #define MODINFO_H -#include "imodinterface.h" #include "ifiletree.h" +#include "imodinterface.h" #include "versioninfo.h" class OrganizerCore; @@ -29,11 +29,11 @@ class PluginContainer; class QDir; class QDateTime; +#include <QColor> #include <QRecursiveMutex> #include <QSharedPointer> #include <QString> #include <QStringList> -#include <QColor> #include <boost/function.hpp> @@ -41,8 +41,14 @@ class QDateTime; #include <set> #include <vector> -namespace MOBase { class IPluginGame; } -namespace MOShared { class DirectoryEntry; } +namespace MOBase +{ +class IPluginGame; +} +namespace MOShared +{ +class DirectoryEntry; +} /** * @brief Represents meta information about a single mod. @@ -56,13 +62,13 @@ class ModInfo : public QObject, public MOBase::IModInterface Q_OBJECT -public: // Type definitions: - +public: // Type definitions: typedef QSharedPointer<ModInfo> Ptr; static QString s_HiddenExt; - enum EConflictFlag { + enum EConflictFlag + { FLAG_CONFLICT_OVERWRITE, FLAG_CONFLICT_OVERWRITTEN, FLAG_CONFLICT_MIXED, @@ -75,7 +81,8 @@ public: // Type definitions: FLAG_OVERWRITE_CONFLICT, }; - enum EFlag { + enum EFlag + { FLAG_INVALID, FLAG_BACKUP, FLAG_SEPARATOR, @@ -89,31 +96,35 @@ public: // Type definitions: FLAG_TRACKED, }; - enum EHighlight { - HIGHLIGHT_NONE = 0, - HIGHLIGHT_INVALID = 1, - HIGHLIGHT_CENTER = 2, + enum EHighlight + { + HIGHLIGHT_NONE = 0, + HIGHLIGHT_INVALID = 1, + HIGHLIGHT_CENTER = 2, HIGHLIGHT_IMPORTANT = 4, - HIGHLIGHT_PLUGIN = 8 + HIGHLIGHT_PLUGIN = 8 }; - enum EModType { + enum EModType + { MOD_DEFAULT, MOD_DLC, MOD_CC }; - -public: // Static functions: - +public: // Static functions: /** * @brief Read the mod directory and Mod ModInfo objects for all subdirectories. */ - static void updateFromDisc( - const QString &modDirectory, OrganizerCore& core, - bool displayForeign, std::size_t refreshThreadCount); + static void updateFromDisc(const QString& modDirectory, OrganizerCore& core, + bool displayForeign, std::size_t refreshThreadCount); - static void clear() { s_Collection.clear(); s_ModsByName.clear(); s_ModsByModID.clear(); } + static void clear() + { + s_Collection.clear(); + s_ModsByName.clear(); + s_ModsByModID.clear(); + } /** * @brief Retrieve the number of mods. @@ -129,8 +140,8 @@ public: // Static functions: * * @return a reference counting pointer to the mod info. * - * @note since the pointer is reference counting, the pointer remains valid even if the - * collection is refreshed in a different thread. + * @note since the pointer is reference counting, the pointer remains valid even if + * the collection is refreshed in a different thread. */ static ModInfo::Ptr getByIndex(unsigned int index); @@ -139,7 +150,8 @@ public: // Static functions: * * @param modID The mod id to look up. * - * @return a vector of reference counting pointer to the mod info objects with the given mod ID. + * @return a vector of reference counting pointer to the mod info objects with the + * given mod ID. */ static std::vector<ModInfo::Ptr> getByModID(QString game, int modID); @@ -153,13 +165,13 @@ public: // Static functions: * @note Since the pointer is reference counter, the pointer remains valid even if the * collection is refreshed in a different thread. */ - static ModInfo::Ptr getByName(const QString &name); + static ModInfo::Ptr getByName(const QString& name); /** * @brief Remove a mod by index. * - * This physically deletes the specified mod from the disc and updates the ModInfo collection - * but not other structures that reference mods. + * This physically deletes the specified mod from the disc and updates the ModInfo + * collection but not other structures that reference mods. * * @param index Index of the mod to delete. * @@ -174,7 +186,7 @@ public: // Static functions: * * @return The index of the mod. If the mod doesn't exist, UINT_MAX is returned. */ - static unsigned int getIndex(const QString &name); + static unsigned int getIndex(const QString& name); /** * @brief Retrieve the overwrite mod. @@ -182,32 +194,35 @@ public: // Static functions: static ModInfo::Ptr getOverwrite() { return s_Overwrite; } /** - * @brief Find the first mod that fulfills the filter function (after no particular order). + * @brief Find the first mod that fulfills the filter function (after no particular + * order). * * @param filter A function to filter mods by. Should return true for a match. * * @return index of the matching mod or UINT_MAX if there was no match. */ - static unsigned int findMod(const boost::function<bool (ModInfo::Ptr)> &filter); + static unsigned int findMod(const boost::function<bool(ModInfo::Ptr)>& filter); /** * @brief Run a limited batch of mod update checks for "newest version" information. * */ - static void manualUpdateCheck(QObject *receiver, std::multimap<QString, int> IDs); + static void manualUpdateCheck(QObject* receiver, std::multimap<QString, int> IDs); /** - * @brief Query nexus information for every mod and update the "newest version" information. + * @brief Query nexus information for every mod and update the "newest version" + * information. * * @return true if any mods are checked for update. */ - static bool checkAllForUpdate(PluginContainer *pluginContainer, QObject *receiver); + static bool checkAllForUpdate(PluginContainer* pluginContainer, QObject* receiver); /** * */ - static std::set<ModInfo::Ptr> filteredMods( - QString gameName, QVariantList updateData, bool addOldMods = false, bool markUpdated = false); + static std::set<ModInfo::Ptr> filteredMods(QString gameName, QVariantList updateData, + bool addOldMods = false, + bool markUpdated = false); /** * @brief Check wheter a name corresponds to a separator or not, @@ -230,11 +245,10 @@ public: // Static functions: */ static bool isRegularName(const QString& name); -public: // IModInterface implementations / Re-declaration - - // Note: This section contains default-implementation for some of the virtual methods from - // IModInterface, but also redeclaration of all the pure-virtual methods to centralize all - // of them in a single place. +public: // IModInterface implementations / Re-declaration + // Note: This section contains default-implementation for some of the virtual methods + // from IModInterface, but also redeclaration of all the pure-virtual methods to + // centralize all of them in a single place. /** * @return the name of the mod. @@ -257,8 +271,8 @@ public: // IModInterface implementations / Re-declaration virtual QString notes() const = 0; /** - * @brief Retrieve the short name of the game associated with this mod. This may differ - * from the current game plugin (e.g. you can install a Skyrim LE game in a SSE + * @brief Retrieve the short name of the game associated with this mod. This may + * differ from the current game plugin (e.g. you can install a Skyrim LE game in a SSE * installation). * * @return the name of the game associated with this mod. @@ -281,14 +295,14 @@ public: // IModInterface implementations / Re-declaration virtual MOBase::VersionInfo version() const override { return m_Version; } /** - * @return the newest version of thid mod (as known by MO2). If this matches version(), - * then the mod is up-to-date. + * @return the newest version of thid mod (as known by MO2). If this matches + * version(), then the mod is up-to-date. */ virtual MOBase::VersionInfo newestVersion() const = 0; /** - * @return the ignored version of this mod (for update), or an invalid version if the user - * did not ignore version for this mod. + * @return the ignored version of this mod (for update), or an invalid version if the + * user did not ignore version for this mod. */ virtual MOBase::VersionInfo ignoredVersion() const = 0; @@ -302,17 +316,17 @@ public: // IModInterface implementations / Re-declaration /** * @return true if this mod was marked as converted by the user. * - * @note When a mod is for a different game, a flag is shown to users to warn them, but - * they can mark mods as converted to remove this flag. + * @note When a mod is for a different game, a flag is shown to users to warn them, + * but they can mark mods as converted to remove this flag. */ virtual bool converted() const = 0; /** * @return true if th is mod was marked as containing valid game data. * - * @note MO2 uses ModDataChecker to check the content of mods, but sometimes these fail, in - * which case mods are incorrectly marked as 'not containing valid games data'. Users can - * choose to mark these mods as valid to hide the warning / flag. + * @note MO2 uses ModDataChecker to check the content of mods, but sometimes these + * fail, in which case mods are incorrectly marked as 'not containing valid games + * data'. Users can choose to mark these mods as valid to hide the warning / flag. */ virtual bool validated() const = 0; @@ -340,12 +354,18 @@ public: // IModInterface implementations / Re-declaration /** * @return the tracked state of this mod. */ - virtual MOBase::TrackedState trackedState() const override { return MOBase::TrackedState::TRACKED_FALSE; } + virtual MOBase::TrackedState trackedState() const override + { + return MOBase::TrackedState::TRACKED_FALSE; + } /** * @return the endorsement state of this mod. */ - virtual MOBase::EndorsedState endorsedState() const override { return MOBase::EndorsedState::ENDORSED_NEVER; } + virtual MOBase::EndorsedState endorsedState() const override + { + return MOBase::EndorsedState::ENDORSED_NEVER; + } /** * @brief Retrieve a file tree corresponding to the underlying disk content @@ -383,8 +403,7 @@ public: // IModInterface implementations / Re-declaration */ virtual bool isForeign() const { return false; } -public: // Mutable operations: - +public: // Mutable operations: /** * @brief Sets or changes the version of this mod. * @@ -431,7 +450,8 @@ public: // Mutable operations: virtual void addNexusCategory(int categoryID) = 0; /** - * @brief Assigns a category to the mod. If the named category does not exist it is created. + * @brief Assigns a category to the mod. If the named category does not exist it is + * created. * * @param categoryName Name of the new category. */ @@ -466,8 +486,7 @@ public: // Mutable operations: */ virtual bool setName(const QString& name) = 0; -public: // Methods after this do not come from IModInterface: - +public: // Methods after this do not come from IModInterface: /** * @return true if this mod is empty, false otherwise. */ @@ -490,7 +509,8 @@ public: // Methods after this do not come from IModInterface: virtual bool updateIgnored() const = 0; /** - * @brief Check if the "newest" version of the mod is older than the installed version. + * @brief Check if the "newest" version of the mod is older than the installed + * version. * * Check if there is a newer version of the mod. This does NOT cause information to be * retrieved from the nexus, it will only test version information already available @@ -504,9 +524,9 @@ public: // Methods after this do not come from IModInterface: * @brief Request an update of nexus description for this mod. * * This requests mod information from the nexus. This is an asynchronous request, - * so there is no immediate effect of this call. Right now, Mod Organizer interprets the - * "newest version" and "description" from the response, though the description is only - * stored in memory. + * so there is no immediate effect of this call. Right now, Mod Organizer interprets + * the "newest version" and "description" from the response, though the description is + * only stored in memory. * */ virtual bool updateNXMInfo() = 0; @@ -519,39 +539,41 @@ public: // Methods after this do not come from IModInterface: * @param categoryID ID of the category to set. * @param active Determines whether the category is assigned or unassigned. * - * @note This function does not test whether categoryID actually identifies a valid category. + * @note This function does not test whether categoryID actually identifies a valid + * category. */ virtual void setCategory(int categoryID, bool active) = 0; /** - * @brief Changes the comments (manually set information displayed in the mod list) for this mod. + * @brief Changes the comments (manually set information displayed in the mod list) + * for this mod. * * @param comments The new comments. */ - virtual void setComments(const QString &comments) = 0; + virtual void setComments(const QString& comments) = 0; /** * @brief Change the notes (manually set information) for this mod. * * @param notes The new notes. */ - virtual void setNotes(const QString ¬es) = 0; + virtual void setNotes(const QString& notes) = 0; /** - * @brief Controls if mod should be highlighted based on plugin selection. - * - * @param isSelected Whether or not the plugin has a selected mod. - */ - virtual void setPluginSelected(const bool &isSelected); + * @brief Controls if mod should be highlighted based on plugin selection. + * + * @param isSelected Whether or not the plugin has a selected mod. + */ + virtual void setPluginSelected(const bool& isSelected); /** * @brief Sets the repository that was used to download the mod. */ - virtual void setRepository(const QString &) {} + virtual void setRepository(const QString&) {} /** - * @brief Set the mod to "I do not intend to endorse.". The mod will not show as unendorsed - * but can still be endorsed. + * @brief Set the mod to "I do not intend to endorse.". The mod will not show as + * unendorsed but can still be endorsed. */ virtual void setNeverEndorse() = 0; @@ -589,9 +611,9 @@ public: // Methods after this do not come from IModInterface: virtual void clearCaches() {} /** - * @brief Retrieve the internal name of the mod. This is usually the same as the regular name, - * but with special mod types it might be used to distinguish between mods that have the same - * visible name. + * @brief Retrieve the internal name of the mod. This is usually the same as the + * regular name, but with special mod types it might be used to distinguish between + * mods that have the same visible name. * * @return the internal mod name. */ @@ -640,8 +662,8 @@ public: // Methods after this do not come from IModInterface: /** * @return a list of content types contained in a mod. * - * @note The IDs of the content are game-dependent. See the ModDataContent game feature - * for more details on this. + * @note The IDs of the content are game-dependent. See the ModDataContent game + * feature for more details on this. */ virtual const std::set<int>& getContents() const = 0; @@ -693,8 +715,8 @@ public: // Methods after this do not come from IModInterface: virtual QDateTime creationTime() const = 0; /** - * @return the list of files that, if they exist in the data directory are treated as files in - * THIS mod. + * @return the list of files that, if they exist in the data directory are treated as + * files in THIS mod. */ virtual QStringList stealFiles() const { return QStringList(); } @@ -710,7 +732,7 @@ public: // Methods after this do not come from IModInterface: * * @note Currently, this changes the color of the cell under the "Notes" column. */ - virtual void setColor(QColor color) { } + virtual void setColor(QColor color) {} /** * @brief Adds the information that a file has been installed into this mod. @@ -736,7 +758,7 @@ public: // Methods after this do not come from IModInterface: * * @return the IDs of categories this mod belongs to. */ - const std::set<int> &getCategories() const { return m_Categories; } + const std::set<int>& getCategories() const { return m_Categories; } /** * @brief Sets the new primary category of the mod. @@ -746,20 +768,21 @@ public: // Methods after this do not come from IModInterface: virtual void setPrimaryCategory(int categoryID) { m_PrimaryCategory = categoryID; } /** - * @return true if this mod is considered "valid", that is it contains data used by the game. + * @return true if this mod is considered "valid", that is it contains data used by + * the game. */ virtual bool isValid() const = 0; /** - * @brief Updates the mod to flag it as converted in order to ignore the alternate game - * warning. + * @brief Updates the mod to flag it as converted in order to ignore the alternate + * game warning. */ virtual void markConverted(bool) {} /** - * @brief Updates the mod to flag it as valid in order to ignore the invalid game data - * flag. - */ + * @brief Updates the mod to flag it as valid in order to ignore the invalid game data + * flag. + */ virtual void markValidated(bool) {} /** @@ -797,7 +820,8 @@ public: // Methods after this do not come from IModInterface: * * @param url The new URL. */ - void setUrl(QString const& url) override { + void setUrl(QString const& url) override + { setHasCustomURL(true); setCustomURL(url); } @@ -809,8 +833,7 @@ public: // Methods after this do not come from IModInterface: */ QUrl parseCustomURL() const; -public: // Nexus stuff - +public: // Nexus stuff /** * @brief Changes the nexus description text. * @@ -865,8 +888,7 @@ public: // Nexus stuff */ virtual void setNexusLastModified(QDateTime time) = 0; -public: // Conflicts - +public: // Conflicts // retrieve the list of mods (as mod index) that are overwritten by this one. // Updates may be delayed. // @@ -880,22 +902,34 @@ public: // Conflicts // retrieve the list of mods (as mod index) with archives that are overwritten by // this one. Updates may be delayed // - virtual const std::set<unsigned int>& getModArchiveOverwrite() const { return s_EmptySet; } + virtual const std::set<unsigned int>& getModArchiveOverwrite() const + { + return s_EmptySet; + } - // retrieve the list of mods (as mod index) with archives that overwrite this one. Updates - // may be delayed. + // retrieve the list of mods (as mod index) with archives that overwrite this one. + // Updates may be delayed. // - virtual const std::set<unsigned int>& getModArchiveOverwritten() const { return s_EmptySet; } + virtual const std::set<unsigned int>& getModArchiveOverwritten() const + { + return s_EmptySet; + } - // retrieve the list of mods (as mod index) with archives that are overwritten by loose - // files of this mod. Updates may be delayed. + // retrieve the list of mods (as mod index) with archives that are overwritten by + // loose files of this mod. Updates may be delayed. // - virtual const std::set<unsigned int>& getModArchiveLooseOverwrite() const { return s_EmptySet; } + virtual const std::set<unsigned int>& getModArchiveLooseOverwrite() const + { + return s_EmptySet; + } // retrieve the list of mods (as mod index) with loose files that overwrite this one's // archive files. Updates may be delayed. // - virtual const std::set<unsigned int>& getModArchiveLooseOverwritten() const { return s_EmptySet; } + virtual const std::set<unsigned int>& getModArchiveLooseOverwritten() const + { + return s_EmptySet; + } public slots: @@ -914,7 +948,6 @@ signals: void modDetailsUpdated(bool success); protected: - /** * */ @@ -928,10 +961,9 @@ protected: * using multiple threads for all the mods. */ virtual void prefetch() = 0; - static bool ByName(const ModInfo::Ptr &LHS, const ModInfo::Ptr &RHS); + static bool ByName(const ModInfo::Ptr& LHS, const ModInfo::Ptr& RHS); protected: - // the mod list OrganizerCore& m_Core; @@ -948,7 +980,6 @@ protected: static const std::set<unsigned int> s_EmptySet; protected: - friend class OrganizerCore; /** @@ -968,9 +999,9 @@ protected: * * @return a new mod. */ - static ModInfo::Ptr createFromPlugin( - const QString& modName, const QString& espName, const QStringList& bsaNames, - ModInfo::EModType modType, OrganizerCore& core); + static ModInfo::Ptr createFromPlugin(const QString& modName, const QString& espName, + const QStringList& bsaNames, + ModInfo::EModType modType, OrganizerCore& core); static ModInfo::Ptr createFromOverwrite(OrganizerCore& core); @@ -979,15 +1010,12 @@ protected: static void updateIndices(); protected: - static QRecursiveMutex s_Mutex; static std::vector<ModInfo::Ptr> s_Collection; static ModInfo::Ptr s_Overwrite; static std::map<QString, unsigned int, MOBase::FileNameComparator> s_ModsByName; static std::map<std::pair<QString, int>, std::vector<unsigned int>> s_ModsByModID; static int s_NextID; - }; - -#endif // MODINFO_H +#endif // MODINFO_H diff --git a/src/modinfobackup.cpp b/src/modinfobackup.cpp index 603e74f6..4b6af838 100644 --- a/src/modinfobackup.cpp +++ b/src/modinfobackup.cpp @@ -1,6 +1,5 @@ #include "modinfobackup.h" - std::vector<ModInfo::EFlag> ModInfoBackup::getFlags() const { std::vector<ModInfo::EFlag> result = ModInfoRegular::getFlags(); @@ -8,14 +7,11 @@ std::vector<ModInfo::EFlag> ModInfoBackup::getFlags() const return result; } - QString ModInfoBackup::getDescription() const { return tr("This is the backup of a mod"); } - ModInfoBackup::ModInfoBackup(const QDir& path, OrganizerCore& core) - : ModInfoRegular(path, core) -{ -} + : ModInfoRegular(path, core) +{} diff --git a/src/modinfobackup.h b/src/modinfobackup.h index 853a1211..01abf184 100644 --- a/src/modinfobackup.h +++ b/src/modinfobackup.h @@ -11,7 +11,6 @@ class ModInfoBackup : public ModInfoRegular friend class ModInfo; public: - virtual bool updateAvailable() const override { return false; } virtual bool updateIgnored() const override { return false; } virtual bool downgradeAvailable() const override { return false; } @@ -24,7 +23,10 @@ public: virtual bool canBeUpdated() const override { return false; } virtual QDateTime getExpires() const override { return QDateTime(); } virtual bool canBeEnabled() const override { return false; } - virtual std::vector<QString> getIniTweaks() const override { return std::vector<QString>(); } + virtual std::vector<QString> getIniTweaks() const override + { + return std::vector<QString>(); + } virtual std::vector<EFlag> getFlags() const override; virtual QString getDescription() const override; virtual int getNexusFileStatus() const override { return 0; } @@ -41,10 +43,7 @@ public: virtual void addInstalledFile(int, int) override {} private: - ModInfoBackup(const QDir& path, OrganizerCore& core); - }; - -#endif // MODINFOBACKUP_H +#endif // MODINFOBACKUP_H diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index fc83bf11..d0e8d1ad 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -18,19 +18,19 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ #include "modinfodialog.h" -#include "ui_modinfodialog.h" -#include "plugincontainer.h" -#include "organizercore.h" -#include "modlistview.h" -#include "modinfodialogtextfiles.h" -#include "modinfodialogimages.h" -#include "modinfodialogesps.h" -#include "modinfodialogconflicts.h" #include "modinfodialogcategories.h" -#include "modinfodialognexus.h" +#include "modinfodialogconflicts.h" +#include "modinfodialogesps.h" #include "modinfodialogfiletree.h" +#include "modinfodialogimages.h" +#include "modinfodialognexus.h" +#include "modinfodialogtextfiles.h" +#include "modlistview.h" +#include "organizercore.h" +#include "plugincontainer.h" #include "shared/directoryentry.h" #include "shared/filesorigin.h" +#include "ui_modinfodialog.h" #include <filesystem> using namespace MOBase; @@ -39,10 +39,8 @@ namespace fs = std::filesystem; const int max_scan_for_context_menu = 50; - -bool canPreviewFile( - const PluginContainer& pluginContainer, - bool isArchive, const QString& filename) +bool canPreviewFile(const PluginContainer& pluginContainer, bool isArchive, + const QString& filename) { if (isArchive) { return false; @@ -54,9 +52,7 @@ bool canPreviewFile( bool isExecutableFilename(const QString& filename) { - static const std::set<QString> exeExtensions = { - "exe", "cmd", "bat" - }; + static const std::set<QString> exeExtensions = {"exe", "cmd", "bat"}; const auto ext = QFileInfo(filename).suffix().toLower(); @@ -111,26 +107,26 @@ bool canUnhideFile(bool isArchive, const QString& filename) return true; } -FileRenamer::RenameResults hideFile(FileRenamer& renamer, const QString &oldName) +FileRenamer::RenameResults hideFile(FileRenamer& renamer, const QString& oldName) { const QString newName = oldName + ModInfo::s_HiddenExt; return renamer.rename(oldName, newName); } -FileRenamer::RenameResults unhideFile(FileRenamer& renamer, const QString &oldName) +FileRenamer::RenameResults unhideFile(FileRenamer& renamer, const QString& oldName) { QString newName = oldName.left(oldName.length() - ModInfo::s_HiddenExt.length()); return renamer.rename(oldName, newName); } - -FileRenamer::RenameResults restoreHiddenFilesRecursive(FileRenamer& renamer, const QString& targetDir) +FileRenamer::RenameResults restoreHiddenFilesRecursive(FileRenamer& renamer, + const QString& targetDir) { FileRenamer::RenameResults results = FileRenamer::RESULT_OK; - QDir currentDir = targetDir; - for (QString hiddenFile : currentDir.entryList( - (QStringList() << "*" + ModInfo::s_HiddenExt), - QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) { + QDir currentDir = targetDir; + for (QString hiddenFile : + currentDir.entryList((QStringList() << "*" + ModInfo::s_HiddenExt), + QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) { QString oldName = currentDir.absoluteFilePath(hiddenFile); QString newName = oldName.left(oldName.length() - ModInfo::s_HiddenExt.length()); @@ -163,51 +159,61 @@ FileRenamer::RenameResults restoreHiddenFilesRecursive(FileRenamer& renamer, con return results; } - ModInfoDialog::TabInfo::TabInfo(std::unique_ptr<ModInfoDialogTab> tab) - : tab(std::move(tab)), realPos(-1), widget(nullptr) -{ -} + : tab(std::move(tab)), realPos(-1), widget(nullptr) +{} bool ModInfoDialog::TabInfo::isVisible() const { return (realPos != -1); } -ModInfoDialog::ModInfoDialog( - OrganizerCore& core, PluginContainer& plugin, - ModInfo::Ptr mod, ModListView* modListView, QWidget *parent) : - TutorableDialog("ModInfoDialog", parent), - ui(new Ui::ModInfoDialog), - m_core(core), - m_plugin(plugin), - m_modListView(modListView), - m_initialTab(ModInfoTabIDs::None), - m_arrangingTabs(false) +ModInfoDialog::ModInfoDialog(OrganizerCore& core, PluginContainer& plugin, + ModInfo::Ptr mod, ModListView* modListView, + QWidget* parent) + : TutorableDialog("ModInfoDialog", parent), ui(new Ui::ModInfoDialog), m_core(core), + m_plugin(plugin), m_modListView(modListView), m_initialTab(ModInfoTabIDs::None), + m_arrangingTabs(false) { ui->setupUi(this); { auto* sc = new QShortcut(QKeySequence::Delete, this); - connect(sc, &QShortcut::activated, [&] { onDeleteShortcut(); }); + connect(sc, &QShortcut::activated, [&] { + onDeleteShortcut(); + }); } { auto* sc = new QShortcut(QKeySequence::MoveToNextPage, this); - connect(sc, &QShortcut::activated, [&] { onNextMod(); }); + connect(sc, &QShortcut::activated, [&] { + onNextMod(); + }); } { auto* sc = new QShortcut(QKeySequence::MoveToPreviousPage, this); - connect(sc, &QShortcut::activated, [&] { onPreviousMod(); }); + connect(sc, &QShortcut::activated, [&] { + onPreviousMod(); + }); } setMod(mod); createTabs(); - connect(ui->tabWidget, &QTabWidget::currentChanged, [&]{ onTabSelectionChanged(); }); - connect(ui->tabWidget->tabBar(), &QTabBar::tabMoved, [&]{ onTabMoved(); }); - connect(ui->close, &QPushButton::clicked, [&]{ onCloseButton(); }); - connect(ui->previousMod, &QPushButton::clicked, [&]{ onPreviousMod(); }); - connect(ui->nextMod, &QPushButton::clicked, [&]{ onNextMod(); }); + connect(ui->tabWidget, &QTabWidget::currentChanged, [&] { + onTabSelectionChanged(); + }); + connect(ui->tabWidget->tabBar(), &QTabBar::tabMoved, [&] { + onTabMoved(); + }); + connect(ui->close, &QPushButton::clicked, [&] { + onCloseButton(); + }); + connect(ui->previousMod, &QPushButton::clicked, [&] { + onPreviousMod(); + }); + connect(ui->nextMod, &QPushButton::clicked, [&] { + onNextMod(); + }); } ModInfoDialog::~ModInfoDialog() = default; @@ -216,7 +222,7 @@ template <class T> std::unique_ptr<ModInfoDialogTab> createTab(ModInfoDialog& d, ModInfoTabIDs id) { return std::make_unique<T>(ModInfoDialogTabContext( - d.m_core, d.m_plugin, &d, d.ui.get(), id, d.m_mod, d.getOrigin())); + d.m_core, d.m_plugin, &d, d.ui.get(), id, d.m_mod, d.getOrigin())); } void ModInfoDialog::createTabs() @@ -242,29 +248,31 @@ void ModInfoDialog::createTabs() // for each tab in the widget; connects the widgets with the tab objects // - for (int i=0; i<count; ++i) { + for (int i = 0; i < count; ++i) { auto& tabInfo = m_tabs[static_cast<std::size_t>(i)]; // remembering tab information so tabs can be removed and re-added - tabInfo.widget = ui->tabWidget->widget(i); + tabInfo.widget = ui->tabWidget->widget(i); tabInfo.caption = ui->tabWidget->tabText(i); - tabInfo.icon = ui->tabWidget->tabIcon(i); + tabInfo.icon = ui->tabWidget->tabIcon(i); - connect( - tabInfo.tab.get(), &ModInfoDialogTab::originModified, - [this](int originID){ onOriginModified(originID); }); + connect(tabInfo.tab.get(), &ModInfoDialogTab::originModified, [this](int originID) { + onOriginModified(originID); + }); - connect( - tabInfo.tab.get(), &ModInfoDialogTab::modOpen, - [&](const QString& name){ setMod(name); update(); }); + connect(tabInfo.tab.get(), &ModInfoDialogTab::modOpen, [&](const QString& name) { + setMod(name); + update(); + }); - connect( - tabInfo.tab.get(), &ModInfoDialogTab::hasDataChanged, - [&]{ setTabsColors(); }); + connect(tabInfo.tab.get(), &ModInfoDialogTab::hasDataChanged, [&] { + setTabsColors(); + }); - connect( - tabInfo.tab.get(), &ModInfoDialogTab::wantsFocus, - [&, id=tabInfo.tab->tabID()]{ switchToTab(id); }); + connect(tabInfo.tab.get(), &ModInfoDialogTab::wantsFocus, + [&, id = tabInfo.tab->tabID()] { + switchToTab(id); + }); } } @@ -276,7 +284,7 @@ int ModInfoDialog::exec() // whether to select the first tab; if the main window requested a specific // tab, it is selected when encountered in update() const auto noCustomTabRequested = (m_initialTab == ModInfoTabIDs::None); - const auto requestedTab = m_initialTab; + const auto requestedTab = m_initialTab; update(true); @@ -369,7 +377,7 @@ void ModInfoDialog::update(bool firstTime) } if (ui->tabWidget->currentIndex() == oldTab) { - if (auto* tabInfo=currentTab()) { + if (auto* tabInfo = currentTab()) { // activated() has to be fired manually because the tab index hasn't been // changed tabInfo->tab->activated(); @@ -390,7 +398,7 @@ void ModInfoDialog::setTabsVisibility(bool firstTime) bool changed = false; - for (std::size_t i=0; i<m_tabs.size(); ++i) { + for (std::size_t i = 0; i < m_tabs.size(); ++i) { const auto& tabInfo = m_tabs[i]; bool visible = true; @@ -428,7 +436,7 @@ void ModInfoDialog::setTabsVisibility(bool firstTime) // remember selection, if any auto sel = ModInfoTabIDs::None; - if (const auto* tabInfo=currentTab()) { + if (const auto* tabInfo = currentTab()) { sel = tabInfo->tab->tabID(); } @@ -436,8 +444,7 @@ void ModInfoDialog::setTabsVisibility(bool firstTime) reAddTabs(visibility, sel); } -void ModInfoDialog::reAddTabs( - const std::vector<bool>& visibility, ModInfoTabIDs sel) +void ModInfoDialog::reAddTabs(const std::vector<bool>& visibility, ModInfoTabIDs sel) { Q_ASSERT(visibility.size() == m_tabs.size()); @@ -453,7 +460,7 @@ void ModInfoDialog::reAddTabs( // gathering visible tabs std::vector<TabInfo*> visibleTabs; - for (std::size_t i=0; i<m_tabs.size(); ++i) { + for (std::size_t i = 0; i < m_tabs.size(); ++i) { if (!visibility[i]) { // this tab is not visible, skip it continue; @@ -478,15 +485,13 @@ void ModInfoDialog::reAddTabs( // sorting tabs if (canSort) { - std::sort(visibleTabs.begin(), visibleTabs.end(), [&](auto&& a, auto&& b){ + std::sort(visibleTabs.begin(), visibleTabs.end(), [&](auto&& a, auto&& b) { // looking the names in the ordered list - auto aItor = std::find( - orderedNames.begin(), orderedNames.end(), - a->widget->objectName()); + auto aItor = + std::find(orderedNames.begin(), orderedNames.end(), a->widget->objectName()); - auto bItor = std::find( - orderedNames.begin(), orderedNames.end(), - b->widget->objectName()); + auto bItor = + std::find(orderedNames.begin(), orderedNames.end(), b->widget->objectName()); // this shouldn't happen, it was checked above Q_ASSERT(aItor != orderedNames.end() && bItor != orderedNames.end()); @@ -495,7 +500,6 @@ void ModInfoDialog::reAddTabs( }); } - // removing all tabs ui->tabWidget->clear(); @@ -505,7 +509,7 @@ void ModInfoDialog::reAddTabs( } // add visible tabs - for (std::size_t i=0; i<visibleTabs.size(); ++i) { + for (std::size_t i = 0; i < visibleTabs.size(); ++i) { auto& tabInfo = *visibleTabs[i]; // remembering real position @@ -549,7 +553,6 @@ void ModInfoDialog::updateTabs(bool becauseOriginChanged) interestedTabs.push_back(&tabInfo); } - for (auto* tabInfo : interestedTabs) { // set the current mod tabInfo->tab->setMod(m_mod, origin); @@ -606,9 +609,9 @@ void ModInfoDialog::setTabsColors() continue; } - const QColor color = tabInfo.tab->hasData() ? - QColor::Invalid : - p.color(QPalette::Disabled, QPalette::WindowText); + const QColor color = tabInfo.tab->hasData() + ? QColor::Invalid + : p.color(QPalette::Disabled, QPalette::WindowText); ui->tabWidget->tabBar()->setTabTextColor(tabInfo.realPos, color); } @@ -682,7 +685,7 @@ void ModInfoDialog::saveTabOrder() const QString names; - for (int i=0; i<ui->tabWidget->count(); ++i) { + for (int i = 0; i < ui->tabWidget->count(); ++i) { if (!names.isEmpty()) { names += " "; } @@ -707,7 +710,7 @@ void ModInfoDialog::onOriginModified(int originID) void ModInfoDialog::onDeleteShortcut() { // forward the request to the current tab - if (auto* tabInfo=currentTab()) { + if (auto* tabInfo = currentTab()) { tabInfo->tab->deleteRequested(); } } @@ -753,7 +756,7 @@ void ModInfoDialog::onTabSelectionChanged() } // this will call firstActivation() on the tab if needed - if (auto* tabInfo=currentTab()) { + if (auto* tabInfo = currentTab()) { tabInfo->tab->activated(); } } @@ -766,7 +769,7 @@ void ModInfoDialog::onTabMoved() } // for each tab in the widget - for (int i=0; i<ui->tabWidget->count(); ++i) { + for (int i = 0; i < ui->tabWidget->count(); ++i) { const auto* w = ui->tabWidget->widget(i); bool found = false; @@ -775,7 +778,7 @@ void ModInfoDialog::onTabMoved() for (auto& tabInfo : m_tabs) { if (tabInfo.widget == w) { tabInfo.realPos = i; - found = true; + found = true; break; } } diff --git a/src/modinfodialog.h b/src/modinfodialog.h index f25b740d..e894efb0 100644 --- a/src/modinfodialog.h +++ b/src/modinfodialog.h @@ -20,14 +20,19 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef MODINFODIALOG_H #define MODINFODIALOG_H - -#include "modinfo.h" -#include "tutorabledialog.h" #include "filerenamer.h" +#include "modinfo.h" #include "modinfodialogfwd.h" +#include "tutorabledialog.h" -namespace Ui { class ModInfoDialog; } -namespace MOShared { class FilesOrigin; } +namespace Ui +{ +class ModInfoDialog; +} +namespace MOShared +{ +class FilesOrigin; +} class PluginContainer; class OrganizerCore; @@ -47,13 +52,12 @@ class ModInfoDialog : public MOBase::TutorableDialog // to create ModInfoDialogTabContext // template <class T> - friend std::unique_ptr<ModInfoDialogTab> createTab( - ModInfoDialog& d, ModInfoTabIDs index); + friend std::unique_ptr<ModInfoDialogTab> createTab(ModInfoDialog& d, + ModInfoTabIDs index); public: - ModInfoDialog( - OrganizerCore& core, PluginContainer& plugin, - ModInfo::Ptr mod, ModListView* view, QWidget* parent = nullptr); + ModInfoDialog(OrganizerCore& core, PluginContainer& plugin, ModInfo::Ptr mod, + ModListView* view, QWidget* parent = nullptr); ~ModInfoDialog(); @@ -110,7 +114,6 @@ private: // icon for this tab, see `widget` QIcon icon; - TabInfo(std::unique_ptr<ModInfoDialogTab> tab); // returns whether this tab is part of the tab widget @@ -137,12 +140,10 @@ private: // are not fired incorrectly bool m_arrangingTabs; - // creates all the tabs and connects events // void createTabs(); - // saves the dialog state and calls saveState() on all tabs // void saveState() const; @@ -151,7 +152,6 @@ private: // void restoreState(); - // sets the currently selected mod; resets first activation, but doesn't // update anything // @@ -165,19 +165,17 @@ private: // MOShared::FilesOrigin* getOrigin(); - // returns the currently selected tab, taking re-ordering in to account; // shouldn't be null, but could be // TabInfo* currentTab(); - // fully updates the dialog; sets the title, the tab visibility and updates // all the tabs; used when the current mod changes // // see setTabsVisibility() for firstTime // - void update(bool firstTime=false); + void update(bool firstTime = false); // builds the list of visible tabs; if the list is different from what's // currently displayed, or firstTime is true, forwards to reAddTabs() @@ -191,7 +189,7 @@ private: // called by update(); clears tabs, feeds files and calls update() on all // tabs, then setTabsColors() // - void updateTabs(bool becauseOriginChanged=false); + void updateTabs(bool becauseOriginChanged = false); // goes through all files on the filesystem for the current mod and calls // feedFile() on every tab until one accepts it @@ -203,18 +201,15 @@ private: // void setTabsColors(); - // called when the delete key is pressed anywhere in the dialog; forwards to // ModInfoDialogTab::deleteRequest() for the currently selected tab // void onDeleteShortcut(); - // finds the tab with the given id and selects it // void switchToTab(ModInfoTabIDs id); - // saves the current tab order; used by saveState(), but also by // setTabsVisibility() to make sure any changes to order are saved before // re-adding tabs @@ -226,7 +221,6 @@ private: // bool tryClose(); - // called when the user clicks the close button; closing the dialog by other // means ends up in closeEvent(); forwards to tryClose() // @@ -257,4 +251,4 @@ private: void onOriginModified(int originID); }; -#endif // MODINFODIALOG_H +#endif // MODINFODIALOG_H diff --git a/src/modinfodialogcategories.cpp b/src/modinfodialogcategories.cpp index 8bdea6e8..a7a4ce1e 100644 --- a/src/modinfodialogcategories.cpp +++ b/src/modinfodialogcategories.cpp @@ -1,19 +1,20 @@ #include "modinfodialogcategories.h" -#include "ui_modinfodialog.h" #include "categories.h" #include "modinfo.h" +#include "ui_modinfodialog.h" CategoriesTab::CategoriesTab(ModInfoDialogTabContext cx) - : ModInfoDialogTab(std::move(cx)) + : ModInfoDialogTab(std::move(cx)) { - connect( - ui->categories, &QTreeWidget::itemChanged, - [&](auto* item, int col){ onCategoryChanged(item, col); }); + connect(ui->categories, &QTreeWidget::itemChanged, [&](auto* item, int col) { + onCategoryChanged(item, col); + }); - connect( - ui->primaryCategories, - static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), - [&](int index){ onPrimaryChanged(index); }); + connect(ui->primaryCategories, + static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), + [&](int index) { + onPrimaryChanged(index); + }); } void CategoriesTab::clear() @@ -27,9 +28,8 @@ void CategoriesTab::update() { clear(); - add( - CategoryFactory::instance(), mod().getCategories(), - ui->categories->invisibleRootItem(), 0); + add(CategoryFactory::instance(), mod().getCategories(), + ui->categories->invisibleRootItem(), 0); updatePrimary(); } @@ -44,26 +44,26 @@ bool CategoriesTab::usesOriginFiles() const return false; } -void CategoriesTab::add( - const CategoryFactory &factory, const std::set<int>& enabledCategories, - QTreeWidgetItem* root, int rootLevel) +void CategoriesTab::add(const CategoryFactory& factory, + const std::set<int>& enabledCategories, QTreeWidgetItem* root, + int rootLevel) { - for (int i=0; i<static_cast<int>(factory.numCategories()); ++i) { + for (int i = 0; i < static_cast<int>(factory.numCategories()); ++i) { if (factory.getParentID(i) != rootLevel) { continue; } int categoryID = factory.getCategoryID(i); - QTreeWidgetItem *newItem - = new QTreeWidgetItem(QStringList(factory.getCategoryName(i))); + QTreeWidgetItem* newItem = + new QTreeWidgetItem(QStringList(factory.getCategoryName(i))); newItem->setFlags(newItem->flags() | Qt::ItemIsUserCheckable); - newItem->setCheckState(0, enabledCategories.find(categoryID) - != enabledCategories.end() - ? Qt::Checked - : Qt::Unchecked); + newItem->setCheckState(0, + enabledCategories.find(categoryID) != enabledCategories.end() + ? Qt::Checked + : Qt::Unchecked); newItem->setData(0, Qt::UserRole, categoryID); @@ -96,7 +96,7 @@ void CategoriesTab::updatePrimary() void CategoriesTab::addChecked(QTreeWidgetItem* tree) { for (int i = 0; i < tree->childCount(); ++i) { - QTreeWidgetItem *child = tree->child(i); + QTreeWidgetItem* child = tree->child(i); if (child->checkState(0) == Qt::Checked) { ui->primaryCategories->addItem(child->text(0), child->data(0, Qt::UserRole)); addChecked(child); @@ -107,10 +107,10 @@ void CategoriesTab::addChecked(QTreeWidgetItem* tree) void CategoriesTab::save(QTreeWidgetItem* currentNode) { for (int i = 0; i < currentNode->childCount(); ++i) { - QTreeWidgetItem *childNode = currentNode->child(i); + QTreeWidgetItem* childNode = currentNode->child(i); - mod().setCategory( - childNode->data(0, Qt::UserRole).toInt(), childNode->checkState(0)); + mod().setCategory(childNode->data(0, Qt::UserRole).toInt(), + childNode->checkState(0)); save(childNode); } @@ -118,9 +118,10 @@ void CategoriesTab::save(QTreeWidgetItem* currentNode) void CategoriesTab::onCategoryChanged(QTreeWidgetItem* item, int) { - QTreeWidgetItem *parent = item->parent(); + QTreeWidgetItem* parent = item->parent(); - while ((parent != nullptr) && ((parent->flags() & Qt::ItemIsUserCheckable) != 0) && (parent->checkState(0) == Qt::Unchecked)) { + while ((parent != nullptr) && ((parent->flags() & Qt::ItemIsUserCheckable) != 0) && + (parent->checkState(0) == Qt::Unchecked)) { parent->setCheckState(0, Qt::Checked); parent = parent->parent(); } diff --git a/src/modinfodialogcategories.h b/src/modinfodialogcategories.h index c8b52fec..03b3555b 100644 --- a/src/modinfodialogcategories.h +++ b/src/modinfodialogcategories.h @@ -13,9 +13,8 @@ public: bool usesOriginFiles() const override; private: - void add( - const CategoryFactory& factory, const std::set<int>& enabledCategories, - QTreeWidgetItem* root, int rootLevel); + void add(const CategoryFactory& factory, const std::set<int>& enabledCategories, + QTreeWidgetItem* root, int rootLevel); void updatePrimary(); void addChecked(QTreeWidgetItem* tree); diff --git a/src/modinfodialogconflicts.cpp b/src/modinfodialogconflicts.cpp index 923e9778..715214b3 100644 --- a/src/modinfodialogconflicts.cpp +++ b/src/modinfodialogconflicts.cpp @@ -1,13 +1,13 @@ #include "modinfodialogconflicts.h" -#include "ui_modinfodialog.h" -#include "modinfodialogconflictsmodels.h" #include "modinfodialog.h" -#include "utility.h" -#include "settings.h" +#include "modinfodialogconflictsmodels.h" #include "organizercore.h" +#include "settings.h" #include "shared/directoryentry.h" -#include "shared/filesorigin.h" #include "shared/fileentry.h" +#include "shared/filesorigin.h" +#include "ui_modinfodialog.h" +#include "utility.h" using namespace MOShared; using namespace MOBase; @@ -20,7 +20,7 @@ std::size_t smallSelectionSize(const QTreeView* tree) { const std::size_t too_many = std::numeric_limits<std::size_t>::max(); - std::size_t n = 0; + std::size_t n = 0; const auto* sel = tree->selectionModel(); for (const auto& range : sel->selection()) { @@ -63,18 +63,17 @@ void forEachInSelection(QTreeView* tree, F&& f) } } - -ConflictsTab::ConflictsTab(ModInfoDialogTabContext cx) : - ModInfoDialogTab(cx), // don't move, cx is used again - m_general(this, cx.ui, cx.core), m_advanced(this, cx.ui, cx.core) +ConflictsTab::ConflictsTab(ModInfoDialogTabContext cx) + : ModInfoDialogTab(cx), // don't move, cx is used again + m_general(this, cx.ui, cx.core), m_advanced(this, cx.ui, cx.core) { - connect( - &m_general, &GeneralConflictsTab::modOpen, - [&](const QString& name){ emitModOpen(name); }); + connect(&m_general, &GeneralConflictsTab::modOpen, [&](const QString& name) { + emitModOpen(name); + }); - connect( - &m_advanced, &AdvancedConflictsTab::modOpen, - [&](const QString& name){ emitModOpen(name); }); + connect(&m_advanced, &AdvancedConflictsTab::modOpen, [&](const QString& name) { + emitModOpen(name); + }); } void ConflictsTab::update() @@ -114,7 +113,7 @@ bool ConflictsTab::canHandleUnmanaged() const void ConflictsTab::changeItemsVisibility(QTreeView* tree, bool visible) { bool changed = false; - bool stop = false; + bool stop = false; const auto n = smallSelectionSize(tree); @@ -132,7 +131,7 @@ void ConflictsTab::changeItemsVisibility(QTreeView* tree, bool visible) } QFlags<FileRenamer::RenameFlags> flags = - (visible ? FileRenamer::UNHIDE : FileRenamer::HIDE); + (visible ? FileRenamer::UNHIDE : FileRenamer::HIDE); if (n > 1) { flags |= FileRenamer::MULTIPLE; @@ -179,22 +178,22 @@ void ConflictsTab::changeItemsVisibility(QTreeView* tree, bool visible) } switch (result) { - case FileRenamer::RESULT_OK: { - // will trigger a refresh at the end - changed = true; - break; - } + case FileRenamer::RESULT_OK: { + // will trigger a refresh at the end + changed = true; + break; + } - case FileRenamer::RESULT_SKIP: { - // nop - break; - } + case FileRenamer::RESULT_SKIP: { + // nop + break; + } - case FileRenamer::RESULT_CANCEL: { - // stop right now, but make sure to refresh if needed - stop = true; - break; - } + case FileRenamer::RESULT_CANCEL: { + // stop right now, but make sure to refresh if needed + stop = true; + break; + } } return true; @@ -244,11 +243,12 @@ void ConflictsTab::openItems(QTreeView* tree, bool hooked) void ConflictsTab::openItem(const ConflictItem* item, bool hooked) { - core().processRunner() - .setFromFile(parentWidget(), QFileInfo(item->fileName())) - .setHooked(hooked) - .setWaitForCompletion() - .run(); + core() + .processRunner() + .setFromFile(parentWidget(), QFileInfo(item->fileName())) + .setHooked(hooked) + .setWaitForCompletion() + .run(); } void ConflictsTab::previewItems(QTreeView* tree) @@ -276,7 +276,7 @@ void ConflictsTab::exploreItems(QTreeView* tree) }); } -void ConflictsTab::showContextMenu(const QPoint &pos, QTreeView* tree) +void ConflictsTab::showContextMenu(const QPoint& pos, QTreeView* tree) { auto actions = createMenuActions(tree); @@ -284,19 +284,20 @@ void ConflictsTab::showContextMenu(const QPoint &pos, QTreeView* tree) // open if (actions.open) { - connect(actions.open, &QAction::triggered, [&]{ + connect(actions.open, &QAction::triggered, [&] { openItems(tree, false); }); } // preview if (actions.preview) { - connect(actions.preview, &QAction::triggered, [&]{ + connect(actions.preview, &QAction::triggered, [&] { previewItems(tree); }); } - if ((actions.open && actions.open->isEnabled()) && (actions.preview && actions.preview->isEnabled())) { + if ((actions.open && actions.open->isEnabled()) && + (actions.preview && actions.preview->isEnabled())) { if (Settings::instance().interface().doubleClicksOpenPreviews()) { menu.addAction(actions.preview); menu.addAction(actions.open); @@ -316,7 +317,7 @@ void ConflictsTab::showContextMenu(const QPoint &pos, QTreeView* tree) // run hooked if (actions.runHooked) { - connect(actions.runHooked, &QAction::triggered, [&]{ + connect(actions.runHooked, &QAction::triggered, [&] { openItems(tree, true); }); @@ -328,9 +329,9 @@ void ConflictsTab::showContextMenu(const QPoint &pos, QTreeView* tree) menu.addMenu(actions.gotoMenu); for (auto* a : actions.gotoActions) { - connect(a, &QAction::triggered, [&, name=a->text()]{ + connect(a, &QAction::triggered, [&, name = a->text()] { emitModOpen(name); - }); + }); actions.gotoMenu->addAction(a); } @@ -338,7 +339,7 @@ void ConflictsTab::showContextMenu(const QPoint &pos, QTreeView* tree) // explore if (actions.explore) { - connect(actions.explore, &QAction::triggered, [&]{ + connect(actions.explore, &QAction::triggered, [&] { exploreItems(tree); }); @@ -349,7 +350,7 @@ void ConflictsTab::showContextMenu(const QPoint &pos, QTreeView* tree) // hide if (actions.hide) { - connect(actions.hide, &QAction::triggered, [&]{ + connect(actions.hide, &QAction::triggered, [&] { changeItemsVisibility(tree, false); }); @@ -358,7 +359,7 @@ void ConflictsTab::showContextMenu(const QPoint &pos, QTreeView* tree) // unhide if (actions.unhide) { - connect(actions.unhide, &QAction::triggered, [&]{ + connect(actions.unhide, &QAction::triggered, [&] { changeItemsVisibility(tree, true); }); @@ -369,7 +370,7 @@ void ConflictsTab::showContextMenu(const QPoint &pos, QTreeView* tree) if (actions.open || actions.preview || actions.runHooked) { // bold the first option auto* top = menu.actions()[0]; - auto f = top->font(); + auto f = top->font(); f.setBold(true); top->setFont(f); } @@ -384,13 +385,13 @@ ConflictsTab::Actions ConflictsTab::createMenuActions(QTreeView* tree) return {}; } - bool enableHide = true; - bool enableUnhide = true; - bool enableRun = true; - bool enableOpen = true; + bool enableHide = true; + bool enableUnhide = true; + bool enableRun = true; + bool enableOpen = true; bool enablePreview = true; bool enableExplore = true; - bool enableGoto = true; + bool enableGoto = true; const auto n = smallSelectionSize(tree); @@ -410,29 +411,27 @@ ConflictsTab::Actions ConflictsTab::createMenuActions(QTreeView* tree) auto modelSel = proxy->mapSelectionToSource(tree->selectionModel()->selection()); - if (n == 1) { // this is a single selection - const auto* item = model->getItem(static_cast<std::size_t>( - modelSel.indexes()[0].row())); + const auto* item = + model->getItem(static_cast<std::size_t>(modelSel.indexes()[0].row())); if (!item) { return {}; } - enableHide = item->canHide(); - enableUnhide = item->canUnhide(); - enableRun = item->canRun(); - enableOpen = item->canOpen(); + enableHide = item->canHide(); + enableUnhide = item->canUnhide(); + enableRun = item->canRun(); + enableOpen = item->canOpen(); enablePreview = item->canPreview(plugin()); enableExplore = item->canExplore(); - enableGoto = item->hasAlts(); - } - else { + enableGoto = item->hasAlts(); + } else { // this is a multiple selection, don't show open/preview so users don't open // a thousand files - enableRun = false; - enableOpen = false; + enableRun = false; + enableOpen = false; enablePreview = false; // can't explore multiple files @@ -444,7 +443,7 @@ ConflictsTab::Actions ConflictsTab::createMenuActions(QTreeView* tree) if (n <= max_small_selection) { // if the number of selected items is low, checking them to accurately // show the menu items is worth it - enableHide = false; + enableHide = false; enableUnhide = false; forEachInSelection(tree, [&](const ConflictItem* item) { @@ -469,10 +468,10 @@ ConflictsTab::Actions ConflictsTab::createMenuActions(QTreeView* tree) Actions actions; if (enableRun) { - actions.open = new QAction(tr("&Execute"), parentWidget()); + actions.open = new QAction(tr("&Execute"), parentWidget()); actions.runHooked = new QAction(tr("Execute with &VFS"), parentWidget()); } else if (enableOpen) { - actions.open = new QAction(tr("&Open"), parentWidget()); + actions.open = new QAction(tr("&Open"), parentWidget()); actions.runHooked = new QAction(tr("Open with &VFS"), parentWidget()); } @@ -494,8 +493,8 @@ ConflictsTab::Actions ConflictsTab::createMenuActions(QTreeView* tree) actions.unhide->setEnabled(enableUnhide); if (enableGoto && n == 1) { - const auto* item = model->getItem(static_cast<std::size_t>( - modelSel.indexes()[0].row())); + const auto* item = + model->getItem(static_cast<std::size_t>(modelSel.indexes()[0].row())); actions.gotoActions = createGotoActions(item); } @@ -514,7 +513,6 @@ std::vector<QAction*> ConflictsTab::createGotoActions(const ConflictItem* item) return {}; } - std::vector<QString> mods; const auto& ds = *core().directoryStructure(); @@ -534,7 +532,7 @@ std::vector<QAction*> ConflictsTab::createGotoActions(const ConflictItem* item) std::sort(mods.begin(), mods.end(), [](const auto& a, const auto& b) { return (QString::localeAwareCompare(a, b) < 0); - }); + }); std::vector<QAction*> actions; @@ -545,13 +543,12 @@ std::vector<QAction*> ConflictsTab::createGotoActions(const ConflictItem* item) return actions; } - -GeneralConflictsTab::GeneralConflictsTab( - ConflictsTab* tab, Ui::ModInfoDialog* pui, OrganizerCore& oc) : - m_tab(tab), ui(pui), m_core(oc), - m_overwriteModel(new OverwriteConflictListModel(ui->overwriteTree)), - m_overwrittenModel(new OverwrittenConflictListModel(ui->overwrittenTree)), - m_noConflictModel(new NoConflictListModel(ui->noConflictTree)) +GeneralConflictsTab::GeneralConflictsTab(ConflictsTab* tab, Ui::ModInfoDialog* pui, + OrganizerCore& oc) + : m_tab(tab), ui(pui), m_core(oc), + m_overwriteModel(new OverwriteConflictListModel(ui->overwriteTree)), + m_overwrittenModel(new OverwrittenConflictListModel(ui->overwrittenTree)), + m_noConflictModel(new NoConflictListModel(ui->noConflictTree)) { m_expanders.overwrite.set(ui->overwriteExpander, ui->overwriteTree, true); m_expanders.overwritten.set(ui->overwrittenExpander, ui->overwrittenTree, true); @@ -569,29 +566,32 @@ GeneralConflictsTab::GeneralConflictsTab( m_filterNoConflicts.setList(ui->noConflictTree); m_filterNoConflicts.setUseSourceSort(true); - QObject::connect( - ui->overwriteTree, &QTreeView::doubleClicked, - [&](auto&&){ m_tab->activateItems(ui->overwriteTree); }); + QObject::connect(ui->overwriteTree, &QTreeView::doubleClicked, [&](auto&&) { + m_tab->activateItems(ui->overwriteTree); + }); - QObject::connect( - ui->overwrittenTree, &QTreeView::doubleClicked, - [&](auto&& item){ m_tab->activateItems(ui->overwrittenTree); }); + QObject::connect(ui->overwrittenTree, &QTreeView::doubleClicked, [&](auto&& item) { + m_tab->activateItems(ui->overwrittenTree); + }); - QObject::connect( - ui->noConflictTree, &QTreeView::doubleClicked, - [&](auto&& item){ m_tab->activateItems(ui->noConflictTree); }); + QObject::connect(ui->noConflictTree, &QTreeView::doubleClicked, [&](auto&& item) { + m_tab->activateItems(ui->noConflictTree); + }); - QObject::connect( - ui->overwriteTree, &QTreeView::customContextMenuRequested, - [&](const QPoint& p){ m_tab->showContextMenu(p, ui->overwriteTree); }); + QObject::connect(ui->overwriteTree, &QTreeView::customContextMenuRequested, + [&](const QPoint& p) { + m_tab->showContextMenu(p, ui->overwriteTree); + }); - QObject::connect( - ui->overwrittenTree, &QTreeView::customContextMenuRequested, - [&](const QPoint& p){ m_tab->showContextMenu(p, ui->overwrittenTree); }); + QObject::connect(ui->overwrittenTree, &QTreeView::customContextMenuRequested, + [&](const QPoint& p) { + m_tab->showContextMenu(p, ui->overwrittenTree); + }); - QObject::connect( - ui->noConflictTree, &QTreeView::customContextMenuRequested, - [&](const QPoint& p){ m_tab->showContextMenu(p, ui->noConflictTree); }); + QObject::connect(ui->noConflictTree, &QTreeView::customContextMenuRequested, + [&](const QPoint& p) { + m_tab->showContextMenu(p, ui->noConflictTree); + }); } void GeneralConflictsTab::clear() @@ -636,10 +636,11 @@ bool GeneralConflictsTab::update() for (const auto& file : m_tab->origin()->getFiles()) { // careful: these two strings are moved into createXItem() below - QString relativeName = QDir::fromNativeSeparators(ToQString(file->getRelativePath())); + QString relativeName = + QDir::fromNativeSeparators(ToQString(file->getRelativePath())); QString fileName = rootPath + relativeName; - bool archive = false; + bool archive = false; const int fileOrigin = file->getOrigin(archive); ++m_counts.numTotalFiles; @@ -651,55 +652,52 @@ bool GeneralConflictsTab::update() (archive) ? ++m_counts.numTotalArchive : ++m_counts.numTotalLoose; if (!alternatives.empty()) { - m_overwriteModel->add(createOverwriteItem( - file->getIndex(), archive, - std::move(fileName), std::move(relativeName), alternatives)); + m_overwriteModel->add( + createOverwriteItem(file->getIndex(), archive, std::move(fileName), + std::move(relativeName), alternatives)); ++m_counts.numOverwrite; if (archive) { ++m_counts.numOverwriteArchive; - } - else { + } else { ++m_counts.numOverwriteLoose; } } else { // otherwise, put the file in the noconflict tree - m_noConflictModel->add(createNoConflictItem( - file->getIndex(), archive, - std::move(fileName), std::move(relativeName))); + m_noConflictModel->add(createNoConflictItem( + file->getIndex(), archive, std::move(fileName), std::move(relativeName))); ++m_counts.numNonConflicting; if (archive) { ++m_counts.numNonConflictingArchive; - } - else { + } else { ++m_counts.numNonConflictingLoose; } } } else { - auto currId = m_tab->origin()->getID(); + auto currId = m_tab->origin()->getID(); auto currModAlt = std::find_if(alternatives.begin(), alternatives.end(), - [&currId](auto const& alt) { - return currId == alt.originID(); - }); + [&currId](auto const& alt) { + return currId == alt.originID(); + }); if (currModAlt == alternatives.end()) { - log::error("Mod {} not found in the list of origins for file {}", m_tab->origin()->getName(), fileName); + log::error("Mod {} not found in the list of origins for file {}", + m_tab->origin()->getName(), fileName); continue; } bool currModFileArchive = currModAlt->isFromArchive(); - m_overwrittenModel->add(createOverwrittenItem( - file->getIndex(), fileOrigin, archive, - std::move(fileName), std::move(relativeName))); + m_overwrittenModel->add(createOverwrittenItem(file->getIndex(), fileOrigin, + archive, std::move(fileName), + std::move(relativeName))); ++m_counts.numOverwritten; if (currModFileArchive) { ++m_counts.numOverwrittenArchive; ++m_counts.numTotalArchive; - } - else { + } else { ++m_counts.numOverwrittenLoose; ++m_counts.numTotalLoose; } @@ -717,8 +715,8 @@ bool GeneralConflictsTab::update() } ConflictItem GeneralConflictsTab::createOverwriteItem( - FileIndex index, bool archive, QString fileName, QString relativeName, - const MOShared::AlternativesVector& alternatives) + FileIndex index, bool archive, QString fileName, QString relativeName, + const MOShared::AlternativesVector& alternatives) { const auto& ds = *m_core.directoryStructure(); std::wstring altString; @@ -733,35 +731,34 @@ ConflictItem GeneralConflictsTab::createOverwriteItem( auto origin = ToQString(ds.getOriginByID(alternatives.back().originID()).getName()); - return ConflictItem( - ToQString(altString), std::move(relativeName), QString(), index, - std::move(fileName), true, std::move(origin), archive); + return ConflictItem(ToQString(altString), std::move(relativeName), QString(), index, + std::move(fileName), true, std::move(origin), archive); } -ConflictItem GeneralConflictsTab::createNoConflictItem( - FileIndex index, bool archive, QString fileName, QString relativeName) +ConflictItem GeneralConflictsTab::createNoConflictItem(FileIndex index, bool archive, + QString fileName, + QString relativeName) { - return ConflictItem( - QString(), std::move(relativeName), QString(), index, - std::move(fileName), false, QString(), archive); + return ConflictItem(QString(), std::move(relativeName), QString(), index, + std::move(fileName), false, QString(), archive); } -ConflictItem GeneralConflictsTab::createOverwrittenItem( - FileIndex index, int fileOrigin, bool archive, - QString fileName, QString relativeName) +ConflictItem GeneralConflictsTab::createOverwrittenItem(FileIndex index, int fileOrigin, + bool archive, QString fileName, + QString relativeName) { - const auto& ds = *m_core.directoryStructure(); + const auto& ds = *m_core.directoryStructure(); const FilesOrigin& realOrigin = ds.getOriginByID(fileOrigin); - QString after = ToQString(realOrigin.getName()); + QString after = ToQString(realOrigin.getName()); QString altOrigin = after; - return ConflictItem( - QString(), std::move(relativeName), std::move(after), - index, std::move(fileName), true, std::move(altOrigin), archive); + return ConflictItem(QString(), std::move(relativeName), std::move(after), index, + std::move(fileName), true, std::move(altOrigin), archive); } -QString percent(int a, int b) { +QString percent(int a, int b) +{ if (b == 0) { return QString::number(0, 'f', 2); } @@ -774,49 +771,52 @@ void GeneralConflictsTab::updateUICounters() ui->overwrittenCount->display(m_counts.numOverwritten); ui->noConflictCount->display(m_counts.numNonConflicting); - QString tooltipBase = tr("<table cellspacing=\"5\">" - "<tr><th>Type</th><th>%1</th><th>Total</th><th>Percent</th></tr>" - "<tr><td>Loose files: </td>" - "<td align=right>%2</td><td align=right>%3</td><td align=right>%4%</td></tr>" - "<tr><td>Archive files: </td>" - "<td align=right>%5</td><td align=right>%6</td><td align=right>%7%</td></tr>" - "<tr><td>Combined: </td>" - "<td align=right>%8</td><td align=right>%9</td><td align=right>%10%</td></tr>" - "</table>"); - - QString tooltipOverwrite = tooltipBase.arg(tr("Winning")) - .arg(m_counts.numOverwriteLoose) - .arg(m_counts.numTotalLoose) - .arg(percent(m_counts.numOverwriteLoose, m_counts.numTotalLoose)) - .arg(m_counts.numOverwriteArchive) - .arg(m_counts.numTotalArchive) - .arg(percent(m_counts.numOverwriteArchive, m_counts.numTotalArchive)) - .arg(m_counts.numOverwrite) - .arg(m_counts.numTotalFiles) - .arg(percent(m_counts.numOverwrite, m_counts.numTotalFiles)); + QString tooltipBase = + tr("<table cellspacing=\"5\">" + "<tr><th>Type</th><th>%1</th><th>Total</th><th>Percent</th></tr>" + "<tr><td>Loose files: </td>" + "<td align=right>%2</td><td align=right>%3</td><td align=right>%4%</td></tr>" + "<tr><td>Archive files: </td>" + "<td align=right>%5</td><td align=right>%6</td><td align=right>%7%</td></tr>" + "<tr><td>Combined: </td>" + "<td align=right>%8</td><td align=right>%9</td><td align=right>%10%</td></tr>" + "</table>"); - QString tooltipOverwritten = tooltipBase.arg(tr("Losing")) - .arg(m_counts.numOverwrittenLoose) - .arg(m_counts.numTotalLoose) - .arg(percent(m_counts.numOverwrittenLoose, m_counts.numTotalLoose)) - .arg(m_counts.numOverwrittenArchive) - .arg(m_counts.numTotalArchive) - .arg(percent(m_counts.numOverwrittenArchive, m_counts.numTotalArchive)) - .arg(m_counts.numOverwritten) - .arg(m_counts.numTotalFiles) - .arg(percent(m_counts.numOverwritten, m_counts.numTotalFiles)); + QString tooltipOverwrite = + tooltipBase.arg(tr("Winning")) + .arg(m_counts.numOverwriteLoose) + .arg(m_counts.numTotalLoose) + .arg(percent(m_counts.numOverwriteLoose, m_counts.numTotalLoose)) + .arg(m_counts.numOverwriteArchive) + .arg(m_counts.numTotalArchive) + .arg(percent(m_counts.numOverwriteArchive, m_counts.numTotalArchive)) + .arg(m_counts.numOverwrite) + .arg(m_counts.numTotalFiles) + .arg(percent(m_counts.numOverwrite, m_counts.numTotalFiles)); + QString tooltipOverwritten = + tooltipBase.arg(tr("Losing")) + .arg(m_counts.numOverwrittenLoose) + .arg(m_counts.numTotalLoose) + .arg(percent(m_counts.numOverwrittenLoose, m_counts.numTotalLoose)) + .arg(m_counts.numOverwrittenArchive) + .arg(m_counts.numTotalArchive) + .arg(percent(m_counts.numOverwrittenArchive, m_counts.numTotalArchive)) + .arg(m_counts.numOverwritten) + .arg(m_counts.numTotalFiles) + .arg(percent(m_counts.numOverwritten, m_counts.numTotalFiles)); - QString tooltipNonConflict = tooltipBase.arg(tr("Non conflicting")) - .arg(m_counts.numNonConflictingLoose) - .arg(m_counts.numTotalLoose) - .arg(percent(m_counts.numNonConflictingLoose, m_counts.numTotalLoose)) - .arg(m_counts.numNonConflictingArchive) - .arg(m_counts.numTotalArchive) - .arg(percent(m_counts.numNonConflictingArchive, m_counts.numTotalArchive)) - .arg(m_counts.numNonConflicting) - .arg(m_counts.numTotalFiles) - .arg(percent(m_counts.numNonConflicting, m_counts.numTotalFiles)); + QString tooltipNonConflict = + tooltipBase.arg(tr("Non conflicting")) + .arg(m_counts.numNonConflictingLoose) + .arg(m_counts.numTotalLoose) + .arg(percent(m_counts.numNonConflictingLoose, m_counts.numTotalLoose)) + .arg(m_counts.numNonConflictingArchive) + .arg(m_counts.numTotalArchive) + .arg(percent(m_counts.numNonConflictingArchive, m_counts.numTotalArchive)) + .arg(m_counts.numNonConflicting) + .arg(m_counts.numTotalFiles) + .arg(percent(m_counts.numNonConflicting, m_counts.numTotalFiles)); ui->overwriteCount->setToolTip(tooltipOverwrite); ui->overwrittenCount->setToolTip(tooltipOverwritten); @@ -883,11 +883,10 @@ void GeneralConflictsTab::onOverwrittenActivated(const QModelIndex& index) } } - -AdvancedConflictsTab::AdvancedConflictsTab( - ConflictsTab* tab, Ui::ModInfoDialog* pui, OrganizerCore& oc) : - m_tab(tab), ui(pui), m_core(oc), - m_model(new AdvancedConflictListModel(ui->conflictsAdvancedList)) +AdvancedConflictsTab::AdvancedConflictsTab(ConflictsTab* tab, Ui::ModInfoDialog* pui, + OrganizerCore& oc) + : m_tab(tab), ui(pui), m_core(oc), + m_model(new AdvancedConflictListModel(ui->conflictsAdvancedList)) { m_filter.setEdit(ui->conflictsAdvancedFilter); m_filter.setList(ui->conflictsAdvancedList); @@ -895,33 +894,34 @@ AdvancedConflictsTab::AdvancedConflictsTab( // left-elide the overwrites column so that the nearest are visible ui->conflictsAdvancedList->setItemDelegateForColumn( - 0, new ElideLeftDelegate(ui->conflictsAdvancedList)); + 0, new ElideLeftDelegate(ui->conflictsAdvancedList)); // left-elide the file column to see filenames ui->conflictsAdvancedList->setItemDelegateForColumn( - 1, new ElideLeftDelegate(ui->conflictsAdvancedList)); + 1, new ElideLeftDelegate(ui->conflictsAdvancedList)); // don't elide the overwritten by column so that the nearest are visible - QObject::connect( - ui->conflictsAdvancedShowNoConflict, &QCheckBox::clicked, - [&]{ update(); }); + QObject::connect(ui->conflictsAdvancedShowNoConflict, &QCheckBox::clicked, [&] { + update(); + }); - QObject::connect( - ui->conflictsAdvancedShowAll, &QRadioButton::clicked, - [&]{ update(); }); + QObject::connect(ui->conflictsAdvancedShowAll, &QRadioButton::clicked, [&] { + update(); + }); - QObject::connect( - ui->conflictsAdvancedShowNearest, &QRadioButton::clicked, - [&]{ update(); }); + QObject::connect(ui->conflictsAdvancedShowNearest, &QRadioButton::clicked, [&] { + update(); + }); - QObject::connect( - ui->conflictsAdvancedList, &QTreeView::activated, - [&]{ m_tab->activateItems(ui->conflictsAdvancedList); }); + QObject::connect(ui->conflictsAdvancedList, &QTreeView::activated, [&] { + m_tab->activateItems(ui->conflictsAdvancedList); + }); - QObject::connect( - ui->conflictsAdvancedList, &QTreeView::customContextMenuRequested, - [&](const QPoint& p){ m_tab->showContextMenu(p, ui->conflictsAdvancedList); }); + QObject::connect(ui->conflictsAdvancedList, &QTreeView::customContextMenuRequested, + [&](const QPoint& p) { + m_tab->showContextMenu(p, ui->conflictsAdvancedList); + }); } void AdvancedConflictsTab::clear() @@ -957,16 +957,16 @@ void AdvancedConflictsTab::update() for (const auto& file : files) { // careful: these two strings are moved into createItem() below - QString relativeName = QDir::fromNativeSeparators(ToQString(file->getRelativePath())); + QString relativeName = + QDir::fromNativeSeparators(ToQString(file->getRelativePath())); QString fileName = rootPath + relativeName; - bool archive = false; - const int fileOrigin = file->getOrigin(archive); + bool archive = false; + const int fileOrigin = file->getOrigin(archive); const auto& alternatives = file->getAlternatives(); - auto item = createItem( - file->getIndex(), fileOrigin, archive, - std::move(fileName), std::move(relativeName), alternatives); + auto item = createItem(file->getIndex(), fileOrigin, archive, std::move(fileName), + std::move(relativeName), alternatives); if (item) { m_model->add(std::move(*item)); @@ -977,16 +977,16 @@ void AdvancedConflictsTab::update() } } -std::optional<ConflictItem> AdvancedConflictsTab::createItem( - FileIndex index, int fileOrigin, bool archive, - QString fileName, QString relativeName, - const MOShared::AlternativesVector& alternatives) +std::optional<ConflictItem> +AdvancedConflictsTab::createItem(FileIndex index, int fileOrigin, bool archive, + QString fileName, QString relativeName, + const MOShared::AlternativesVector& alternatives) { const auto& ds = *m_core.directoryStructure(); std::wstring before, after; - auto currOrigin = m_tab->origin(); + auto currOrigin = m_tab->origin(); bool isCurrOrigArchive = archive; if (!alternatives.empty()) { @@ -996,8 +996,7 @@ std::optional<ConflictItem> AdvancedConflictsTab::createItem( // current origin is the active winner, all alternatives go in 'before' if (showAllAlts) { - for (const auto& alt : alternatives) - { + for (const auto& alt : alternatives) { const auto& altOrigin = ds.getOriginByID(alt.originID()); if (!before.empty()) { before += L", "; @@ -1005,27 +1004,26 @@ std::optional<ConflictItem> AdvancedConflictsTab::createItem( before += altOrigin.getName(); } - } - else { + } else { // only add nearest, which is the last element of alternatives const auto& altOrigin = ds.getOriginByID(alternatives.back().originID()); before += altOrigin.getName(); } - } - else { + } else { // current mod is one of the alternatives, find its position auto currOrgId = currOrigin->getID(); auto currModIter = std::find_if(alternatives.begin(), alternatives.end(), - [&currOrgId](auto const& alt) { - return currOrgId == alt.originID(); - }); + [&currOrgId](auto const& alt) { + return currOrgId == alt.originID(); + }); if (currModIter == alternatives.end()) { - log::error("Mod {} not found in the list of origins for file {}", currOrigin->getName(), fileName); + log::error("Mod {} not found in the list of origins for file {}", + currOrigin->getName(), fileName); return {}; } @@ -1048,8 +1046,7 @@ std::optional<ConflictItem> AdvancedConflictsTab::createItem( } before += altOrigin.getName(); - } - else if (iter > currModIter) { + } else if (iter > currModIter) { // mod comes after current if (!after.empty()) { @@ -1066,14 +1063,12 @@ std::optional<ConflictItem> AdvancedConflictsTab::createItem( } after += ds.getOriginByID(fileOrigin).getName(); - - } - else { + } else { // only show nearest origins // before if (currModIter > alternatives.begin()) { - auto previousOrigId = (currModIter-1)->originID(); + auto previousOrigId = (currModIter - 1)->originID(); before += ds.getOriginByID(previousOrigId).getName(); } @@ -1081,13 +1076,11 @@ std::optional<ConflictItem> AdvancedConflictsTab::createItem( if (currModIter < (alternatives.end() - 1)) { auto followingOrigId = (currModIter + 1)->originID(); after += ds.getOriginByID(followingOrigId).getName(); - } - else { + } else { // current mod is last of alternatives, so closest to the active winner after += ds.getOriginByID(fileOrigin).getName(); } - } } } @@ -1103,9 +1096,9 @@ std::optional<ConflictItem> AdvancedConflictsTab::createItem( } auto beforeQS = QString::fromStdWString(before); - auto afterQS = QString::fromStdWString(after); + auto afterQS = QString::fromStdWString(after); - return ConflictItem( - std::move(beforeQS), std::move(relativeName), std::move(afterQS), - index, std::move(fileName), hasAlts, QString(), isCurrOrigArchive); + return ConflictItem(std::move(beforeQS), std::move(relativeName), std::move(afterQS), + index, std::move(fileName), hasAlts, QString(), + isCurrOrigArchive); } diff --git a/src/modinfodialogconflicts.h b/src/modinfodialogconflicts.h index db195e3d..f1edd33a 100644 --- a/src/modinfodialogconflicts.h +++ b/src/modinfodialogconflicts.h @@ -1,9 +1,9 @@ #ifndef MODINFODIALOGCONFLICTS_H #define MODINFODIALOGCONFLICTS_H -#include "modinfodialogtab.h" #include "expanderwidget.h" #include "filterwidget.h" +#include "modinfodialogtab.h" #include "shared/fileregisterfwd.h" #include <QTreeWidget> #include <optional> @@ -20,8 +20,7 @@ class GeneralConflictsTab : public QObject Q_OBJECT; public: - GeneralConflictsTab( - ConflictsTab* tab, Ui::ModInfoDialog* ui, OrganizerCore& oc); + GeneralConflictsTab(ConflictsTab* tab, Ui::ModInfoDialog* ui, OrganizerCore& oc); void clear(); void saveState(Settings& s); @@ -53,38 +52,34 @@ private: struct GeneralConflictNumbers { - int numTotalFiles = 0; - int numTotalLoose = 0; - int numTotalArchive = 0; - int numNonConflicting = 0; - int numNonConflictingLoose = 0; + int numTotalFiles = 0; + int numTotalLoose = 0; + int numTotalArchive = 0; + int numNonConflicting = 0; + int numNonConflictingLoose = 0; int numNonConflictingArchive = 0; - int numOverwrite = 0; - int numOverwriteLoose = 0; - int numOverwriteArchive = 0; - int numOverwritten = 0; - int numOverwrittenLoose = 0; - int numOverwrittenArchive = 0; + int numOverwrite = 0; + int numOverwriteLoose = 0; + int numOverwriteArchive = 0; + int numOverwritten = 0; + int numOverwrittenLoose = 0; + int numOverwrittenArchive = 0; - void clear() { - *this = {}; - }; + void clear() { *this = {}; }; }; GeneralConflictNumbers m_counts; - ConflictItem createOverwriteItem( - MOShared::FileIndex index, bool archive, - QString fileName, QString relativeName, - const MOShared::AlternativesVector& alternatives); + ConflictItem createOverwriteItem(MOShared::FileIndex index, bool archive, + QString fileName, QString relativeName, + const MOShared::AlternativesVector& alternatives); - ConflictItem createNoConflictItem( - MOShared::FileIndex index, bool archive, - QString fileName, QString relativeName); + ConflictItem createNoConflictItem(MOShared::FileIndex index, bool archive, + QString fileName, QString relativeName); - ConflictItem createOverwrittenItem( - MOShared::FileIndex index, int fileOrigin, bool archive, - QString fileName, QString relativeName); + ConflictItem createOverwrittenItem(MOShared::FileIndex index, int fileOrigin, + bool archive, QString fileName, + QString relativeName); void updateUICounters(); @@ -92,14 +87,12 @@ private: void onOverwrittenActivated(const QModelIndex& index); }; - class AdvancedConflictsTab : public QObject { Q_OBJECT; public: - AdvancedConflictsTab( - ConflictsTab* tab, Ui::ModInfoDialog* ui, OrganizerCore& oc); + AdvancedConflictsTab(ConflictsTab* tab, Ui::ModInfoDialog* ui, OrganizerCore& oc); void clear(); void saveState(Settings& s); @@ -117,13 +110,11 @@ private: FilterWidget m_filter; ConflictListModel* m_model; - std::optional<ConflictItem> createItem( - MOShared::FileIndex index, int fileOrigin, bool archive, - QString fileName, QString relativeName, - const MOShared::AlternativesVector& alternatives); + std::optional<ConflictItem> + createItem(MOShared::FileIndex index, int fileOrigin, bool archive, QString fileName, + QString relativeName, const MOShared::AlternativesVector& alternatives); }; - class ConflictsTab : public ModInfoDialogTab { Q_OBJECT; @@ -146,18 +137,18 @@ public: void previewItem(const ConflictItem* item); void changeItemsVisibility(QTreeView* tree, bool visible); - void showContextMenu(const QPoint &pos, QTreeView* tree); + void showContextMenu(const QPoint& pos, QTreeView* tree); private: struct Actions { - QAction* hide = nullptr; - QAction* unhide = nullptr; - QAction* open = nullptr; + QAction* hide = nullptr; + QAction* unhide = nullptr; + QAction* open = nullptr; QAction* runHooked = nullptr; - QAction* preview = nullptr; - QAction* explore = nullptr; - QMenu* gotoMenu = nullptr; + QAction* preview = nullptr; + QAction* explore = nullptr; + QMenu* gotoMenu = nullptr; std::vector<QAction*> gotoActions; }; @@ -169,4 +160,4 @@ private: std::vector<QAction*> createGotoActions(const ConflictItem* item); }; -#endif // MODINFODIALOGCONFLICTS_H +#endif // MODINFODIALOGCONFLICTS_H diff --git a/src/modinfodialogconflictsmodels.cpp b/src/modinfodialogconflictsmodels.cpp index 464abbd3..a1806e61 100644 --- a/src/modinfodialogconflictsmodels.cpp +++ b/src/modinfodialogconflictsmodels.cpp @@ -4,20 +4,14 @@ using MOBase::naturalCompare; -ConflictItem::ConflictItem( - QString before, QString relativeName, QString after, - MOShared::FileIndex index, QString fileName, - bool hasAltOrigins, QString altOrigin, bool archive) : - m_before(std::move(before)), - m_relativeName(std::move(relativeName)), - m_after(std::move(after)), - m_index(index), - m_fileName(std::move(fileName)), - m_hasAltOrigins(hasAltOrigins), - m_altOrigin(std::move(altOrigin)), +ConflictItem::ConflictItem(QString before, QString relativeName, QString after, + MOShared::FileIndex index, QString fileName, + bool hasAltOrigins, QString altOrigin, bool archive) + : m_before(std::move(before)), m_relativeName(std::move(relativeName)), + m_after(std::move(after)), m_index(index), m_fileName(std::move(fileName)), + m_hasAltOrigins(hasAltOrigins), m_altOrigin(std::move(altOrigin)), m_isArchive(archive) -{ -} +{} const QString& ConflictItem::before() const { @@ -89,10 +83,9 @@ bool ConflictItem::canExplore() const return canExploreFile(isArchive(), fileName()); } - -ConflictListModel::ConflictListModel(QTreeView* tree, std::vector<Column> columns) : - m_tree(tree), m_columns(std::move(columns)), - m_sortColumn(-1), m_sortOrder(Qt::AscendingOrder) +ConflictListModel::ConflictListModel(QTreeView* tree, std::vector<Column> columns) + : m_tree(tree), m_columns(std::move(columns)), m_sortColumn(-1), + m_sortOrder(Qt::AscendingOrder) { m_tree->setModel(this); } @@ -133,8 +126,7 @@ int ConflictListModel::columnCount(const QModelIndex&) const return static_cast<int>(m_columns.size()); } -const ConflictItem* ConflictListModel::itemFromIndex( - const QModelIndex& index) const +const ConflictItem* ConflictListModel::itemFromIndex(const QModelIndex& index) const { const auto row = index.row(); if (row < 0) { @@ -149,10 +141,9 @@ const ConflictItem* ConflictListModel::itemFromIndex( return &m_items[i]; } -QModelIndex ConflictListModel::indexFromItem( - const ConflictItem* item, int col) +QModelIndex ConflictListModel::indexFromItem(const ConflictItem* item, int col) { - for (std::size_t i=0; i<m_items.size(); ++i) { + for (std::size_t i = 0; i < m_items.size(); ++i) { if (&m_items[i] == item) { return createIndex(static_cast<int>(i), col); } @@ -214,7 +205,7 @@ QVariant ConflictListModel::headerData(int col, Qt::Orientation, int role) const void ConflictListModel::sort(int colIndex, Qt::SortOrder order) { m_sortColumn = colIndex; - m_sortOrder = order; + m_sortOrder = order; emit layoutAboutToBeChanged({}, QAbstractItemModel::VerticalSortHint); @@ -224,7 +215,7 @@ void ConflictListModel::sort(int colIndex, Qt::SortOrder order) const auto itemCount = oldList.size(); oldItems.reserve(static_cast<std::size_t>(itemCount)); - for (int i=0; i<itemCount; ++i) { + for (int i = 0; i < itemCount; ++i) { const QModelIndex& index = oldList[i]; oldItems.push_back({itemFromIndex(index), index.column()}); } @@ -234,7 +225,7 @@ void ConflictListModel::sort(int colIndex, Qt::SortOrder order) QModelIndexList newList; newList.reserve(itemCount); - for (int i=0; i<itemCount; ++i) { + for (int i = 0; i < itemCount; ++i) { const auto& pair = oldItems[static_cast<std::size_t>(i)]; newList.append(indexFromItem(pair.first, pair.second)); } @@ -299,38 +290,22 @@ void ConflictListModel::doSort() } } - OverwriteConflictListModel::OverwriteConflictListModel(QTreeView* tree) - : ConflictListModel(tree, { - {tr("File"), &ConflictItem::relativeName}, - {tr("Overwritten Mods"), &ConflictItem::before} - }) -{ -} - + : ConflictListModel(tree, {{tr("File"), &ConflictItem::relativeName}, + {tr("Overwritten Mods"), &ConflictItem::before}}) +{} OverwrittenConflictListModel::OverwrittenConflictListModel(QTreeView* tree) - : ConflictListModel(tree, { - {tr("File"), &ConflictItem::relativeName}, - {tr("Providing Mod"), &ConflictItem::after} - }) -{ -} - + : ConflictListModel(tree, {{tr("File"), &ConflictItem::relativeName}, + {tr("Providing Mod"), &ConflictItem::after}}) +{} NoConflictListModel::NoConflictListModel(QTreeView* tree) - : ConflictListModel(tree, { - {tr("File"), &ConflictItem::relativeName} - }) -{ -} - + : ConflictListModel(tree, {{tr("File"), &ConflictItem::relativeName}}) +{} AdvancedConflictListModel::AdvancedConflictListModel(QTreeView* tree) - : ConflictListModel(tree, { - {tr("Overwrites"), &ConflictItem::before}, - {tr("File"), &ConflictItem::relativeName}, - {tr("Overwritten By"), &ConflictItem::after} - }) -{ -} + : ConflictListModel(tree, {{tr("Overwrites"), &ConflictItem::before}, + {tr("File"), &ConflictItem::relativeName}, + {tr("Overwritten By"), &ConflictItem::after}}) +{} diff --git a/src/modinfodialogconflictsmodels.h b/src/modinfodialogconflictsmodels.h index e12460b1..26372328 100644 --- a/src/modinfodialogconflictsmodels.h +++ b/src/modinfodialogconflictsmodels.h @@ -5,10 +5,9 @@ class PluginContainer; class ConflictItem { public: - ConflictItem( - QString before, QString relativeName, QString after, - MOShared::FileIndex index, QString fileName, - bool hasAltOrigins, QString altOrigin, bool archive); + ConflictItem(QString before, QString relativeName, QString after, + MOShared::FileIndex index, QString fileName, bool hasAltOrigins, + QString altOrigin, bool archive); const QString& before() const; const QString& relativeName() const; @@ -40,7 +39,6 @@ private: bool m_isArchive; }; - class ConflictListModel : public QAbstractItemModel { Q_OBJECT; @@ -57,14 +55,14 @@ public: void clear(); void reserve(std::size_t s); - QModelIndex index(int row, int col, const QModelIndex& ={}) const override; + QModelIndex index(int row, int col, const QModelIndex& = {}) const override; QModelIndex parent(const QModelIndex&) const override; - int rowCount(const QModelIndex& parent={}) const override; - int columnCount(const QModelIndex& ={}) const override; + int rowCount(const QModelIndex& parent = {}) const override; + int columnCount(const QModelIndex& = {}) const override; QVariant data(const QModelIndex& index, int role) const override; QVariant headerData(int col, Qt::Orientation, int role) const; - void sort(int colIndex, Qt::SortOrder order=Qt::AscendingOrder); + void sort(int colIndex, Qt::SortOrder order = Qt::AscendingOrder); void add(ConflictItem item); void finished(); @@ -84,7 +82,6 @@ private: void doSort(); }; - class OverwriteConflictListModel : public ConflictListModel { Q_OBJECT; @@ -93,7 +90,6 @@ public: OverwriteConflictListModel(QTreeView* tree); }; - class OverwrittenConflictListModel : public ConflictListModel { Q_OBJECT; @@ -102,7 +98,6 @@ public: OverwrittenConflictListModel(QTreeView* tree); }; - class NoConflictListModel : public ConflictListModel { Q_OBJECT; @@ -111,7 +106,6 @@ public: NoConflictListModel(QTreeView* tree); }; - class AdvancedConflictListModel : public ConflictListModel { Q_OBJECT; diff --git a/src/modinfodialogesps.cpp b/src/modinfodialogesps.cpp index e5f1637f..f9a3ba8c 100644 --- a/src/modinfodialogesps.cpp +++ b/src/modinfodialogesps.cpp @@ -1,9 +1,9 @@ #include "modinfodialogesps.h" -#include "ui_modinfodialog.h" #include "modinfodialog.h" #include "settings.h" -#include <report.h> +#include "ui_modinfodialog.h" #include <log.h> +#include <report.h> using namespace MOBase; @@ -11,22 +11,19 @@ class ESPItem { public: ESPItem(QString rootPath, QString relativePath) - : m_rootPath(std::move(rootPath)), m_active(false) + : m_rootPath(std::move(rootPath)), m_active(false) { if (relativePath.contains('/') || relativePath.contains('\\')) { m_inactivePath = relativePath; } else { m_activePath = relativePath; - m_active = true; + m_active = true; } pathChanged(); } - const QString& rootPath() const - { - return m_rootPath; - } + const QString& rootPath() const { return m_rootPath; } const QString& relativePath() const { @@ -37,37 +34,22 @@ public: } } - const QString& filename() const - { - return m_filename; - } + const QString& filename() const { return m_filename; } - const QString& activePath() const - { - return m_activePath; - } + const QString& activePath() const { return m_activePath; } - const QString& inactivePath() const - { - return m_inactivePath; - } + const QString& inactivePath() const { return m_inactivePath; } - const QFileInfo& fileInfo() const - { - return m_fileInfo; - } + const QFileInfo& fileInfo() const { return m_fileInfo; } - bool isActive() const - { - return m_active; - } + bool isActive() const { return m_active; } bool activate(const QString& newName) { QDir root(m_rootPath); if (root.rename(m_inactivePath, newName)) { - m_active = true; + m_active = true; m_activePath = newName; if (QFileInfo(m_inactivePath).fileName() != newName) { @@ -88,7 +70,7 @@ public: QDir root(m_rootPath); if (root.rename(m_activePath, newName)) { - m_active = false; + m_active = false; m_inactivePath = newName; pathChanged(); return true; @@ -112,7 +94,6 @@ private: } }; - class ESPListModel : public QAbstractItemModel { public: @@ -122,30 +103,24 @@ public: endResetModel(); } - QModelIndex index(int row, int col, const QModelIndex& ={}) const override + QModelIndex index(int row, int col, const QModelIndex& = {}) const override { return createIndex(row, col); } - QModelIndex parent(const QModelIndex&) const override - { - return {}; - } + QModelIndex parent(const QModelIndex&) const override { return {}; } - int rowCount(const QModelIndex& ={}) const override + int rowCount(const QModelIndex& = {}) const override { return static_cast<int>(m_esps.size()); } - int columnCount(const QModelIndex& ={}) const override - { - return 1; - } + int columnCount(const QModelIndex& = {}) const override { return 1; } QVariant data(const QModelIndex& index, int role) const override { if (role == Qt::DisplayRole) { - if (auto* esp=getESP(index)) { + if (auto* esp = getESP(index)) { return esp->filename(); } } @@ -153,11 +128,7 @@ public: return {}; } - - void add(ESPItem esp) - { - m_esps.emplace_back(std::move(esp)); - } + void add(ESPItem esp) { m_esps.emplace_back(std::move(esp)); } void addOne(ESPItem esp) { @@ -179,9 +150,7 @@ public: return false; } - const auto end = std::min( - start + static_cast<std::size_t>(count), - m_esps.size()); + const auto end = std::min(start + static_cast<std::size_t>(count), m_esps.size()); beginRemoveRows({}, static_cast<int>(start), static_cast<int>(end)); m_esps.erase(m_esps.begin() + start, m_esps.begin() + end); @@ -223,20 +192,20 @@ private: std::deque<ESPItem> m_esps; }; - - -ESPsTab::ESPsTab(ModInfoDialogTabContext cx) : - ModInfoDialogTab(std::move(cx)), - m_inactiveModel(new ESPListModel), m_activeModel(new ESPListModel) +ESPsTab::ESPsTab(ModInfoDialogTabContext cx) + : ModInfoDialogTab(std::move(cx)), m_inactiveModel(new ESPListModel), + m_activeModel(new ESPListModel) { ui->inactiveESPList->setModel(m_inactiveModel); ui->activeESPList->setModel(m_activeModel); - QObject::connect( - ui->activateESP, &QToolButton::clicked, [&]{ onActivate(); }); + QObject::connect(ui->activateESP, &QToolButton::clicked, [&] { + onActivate(); + }); - QObject::connect( - ui->deactivateESP, &QToolButton::clicked, [&]{ onDeactivate(); }); + QObject::connect(ui->deactivateESP, &QToolButton::clicked, [&] { + onDeactivate(); + }); } void ESPsTab::clear() @@ -311,10 +280,9 @@ void ESPsTab::onActivate() bool okClicked = false; newName = QInputDialog::getText( - parentWidget(), - QObject::tr("File Exists"), - QObject::tr("A file with that name exists, please enter a new one"), - QLineEdit::Normal, file.fileName(), &okClicked); + parentWidget(), QObject::tr("File Exists"), + QObject::tr("A file with that name exists, please enter a new one"), + QLineEdit::Normal, file.fileName(), &okClicked); if (!okClicked) { return; @@ -387,7 +355,7 @@ void ESPsTab::onDeactivate() void ESPsTab::selectRow(QListView* list, int row) { const auto* model = list->model(); - const auto count = model->rowCount(); + const auto count = model->rowCount(); if (count == 0) { return; } diff --git a/src/modinfodialogesps.h b/src/modinfodialogesps.h index b128f279..d65cb580 100644 --- a/src/modinfodialogesps.h +++ b/src/modinfodialogesps.h @@ -28,4 +28,4 @@ private: void selectRow(QListView* list, int row); }; -#endif // MODINFODIALOGESPS_H +#endif // MODINFODIALOGESPS_H diff --git a/src/modinfodialogfiletree.cpp b/src/modinfodialogfiletree.cpp index 9f39447d..140b813d 100644 --- a/src/modinfodialogfiletree.cpp +++ b/src/modinfodialogfiletree.cpp @@ -1,11 +1,11 @@ #include "modinfodialogfiletree.h" -#include "ui_modinfodialog.h" +#include "filerenamer.h" #include "modinfodialog.h" #include "organizercore.h" -#include "filerenamer.h" -#include <utility.h> -#include <report.h> +#include "ui_modinfodialog.h" #include <log.h> +#include <report.h> +#include <utility.h> using namespace MOBase; namespace shell = MOBase::shell; @@ -15,7 +15,7 @@ namespace shell = MOBase::shell; const int max_scan_for_context_menu = 50; FileTreeTab::FileTreeTab(ModInfoDialogTabContext cx) - : ModInfoDialogTab(std::move(cx)), m_fs(nullptr) + : ModInfoDialogTab(std::move(cx)), m_fs(nullptr) { m_fs = new QFileSystemModel(this); m_fs->setReadOnly(false); @@ -23,36 +23,58 @@ FileTreeTab::FileTreeTab(ModInfoDialogTabContext cx) ui->filetree->setColumnWidth(0, 300); m_actions.newFolder = new QAction(tr("&New Folder"), ui->filetree); - m_actions.open = new QAction(tr("&Open/Execute"), ui->filetree); + m_actions.open = new QAction(tr("&Open/Execute"), ui->filetree); m_actions.runHooked = new QAction(tr("Open with &VFS"), ui->filetree); - m_actions.preview = new QAction(tr("&Preview"), ui->filetree); - m_actions.explore = new QAction(tr("Open in &Explorer"), ui->filetree); - m_actions.rename = new QAction(tr("&Rename"), ui->filetree); - m_actions.del = new QAction(tr("&Delete"), ui->filetree); - m_actions.hide = new QAction(tr("&Hide"), ui->filetree); - m_actions.unhide = new QAction(tr("&Unhide"), ui->filetree); + m_actions.preview = new QAction(tr("&Preview"), ui->filetree); + m_actions.explore = new QAction(tr("Open in &Explorer"), ui->filetree); + m_actions.rename = new QAction(tr("&Rename"), ui->filetree); + m_actions.del = new QAction(tr("&Delete"), ui->filetree); + m_actions.hide = new QAction(tr("&Hide"), ui->filetree); + m_actions.unhide = new QAction(tr("&Unhide"), ui->filetree); - connect(m_actions.newFolder, &QAction::triggered, [&]{ onCreateDirectory(); }); - connect(m_actions.open, &QAction::triggered, [&]{ onOpen(); }); - connect(m_actions.runHooked, &QAction::triggered, [&]{ onRunHooked(); }); - connect(m_actions.preview, &QAction::triggered, [&]{ onPreview(); }); - connect(m_actions.explore, &QAction::triggered, [&]{ onExplore(); }); - connect(m_actions.rename, &QAction::triggered, [&]{ onRename(); }); - connect(m_actions.del, &QAction::triggered, [&]{ onDelete(); }); - connect(m_actions.hide, &QAction::triggered, [&]{ onHide(); }); - connect(m_actions.unhide, &QAction::triggered, [&]{ onUnhide(); }); + connect(m_actions.newFolder, &QAction::triggered, [&] { + onCreateDirectory(); + }); + connect(m_actions.open, &QAction::triggered, [&] { + onOpen(); + }); + connect(m_actions.runHooked, &QAction::triggered, [&] { + onRunHooked(); + }); + connect(m_actions.preview, &QAction::triggered, [&] { + onPreview(); + }); + connect(m_actions.explore, &QAction::triggered, [&] { + onExplore(); + }); + connect(m_actions.rename, &QAction::triggered, [&] { + onRename(); + }); + connect(m_actions.del, &QAction::triggered, [&] { + onDelete(); + }); + connect(m_actions.hide, &QAction::triggered, [&] { + onHide(); + }); + connect(m_actions.unhide, &QAction::triggered, [&] { + onUnhide(); + }); - connect(ui->openInExplorer, &QToolButton::clicked, [&]{ onOpenInExplorer(); }); + connect(ui->openInExplorer, &QToolButton::clicked, [&] { + onOpenInExplorer(); + }); - connect( - ui->filetree, &QTreeView::customContextMenuRequested, - [&](const QPoint& pos){ onContextMenu(pos); }); + connect(ui->filetree, &QTreeView::customContextMenuRequested, [&](const QPoint& pos) { + onContextMenu(pos); + }); // disable renaming on double click, open the file instead - ui->filetree->setEditTriggers( - ui->filetree->editTriggers() & (~QAbstractItemView::DoubleClicked)); + ui->filetree->setEditTriggers(ui->filetree->editTriggers() & + (~QAbstractItemView::DoubleClicked)); - connect(ui->filetree, &QTreeView::activated, [&](auto&&){ onActivated(); }); + connect(ui->filetree, &QTreeView::activated, [&](auto&&) { + onActivated(); + }); } void FileTreeTab::clear() @@ -119,15 +141,15 @@ void FileTreeTab::onCreateDirectory() } QModelIndex index = m_fs->isDir(selection) ? selection : selection.parent(); - index = index.sibling(index.row(), 0); + index = index.sibling(index.row(), 0); QString name = tr("New Folder"); QString path = m_fs->filePath(index).append("/"); QModelIndex existingIndex = m_fs->index(path + name); - int suffix = 1; + int suffix = 1; while (existingIndex.isValid()) { - name = tr("New Folder") + QString::number(suffix++); + name = tr("New Folder") + QString::number(suffix++); existingIndex = m_fs->index(path + name); } @@ -153,7 +175,7 @@ void FileTreeTab::onActivated() return; } - const auto path = m_fs->filePath(selection); + const auto path = m_fs->filePath(selection); const auto tryPreview = core().settings().interface().doubleClicksOpenPreviews(); if (tryPreview && canPreviewFile(plugin(), false, path)) { @@ -171,11 +193,12 @@ void FileTreeTab::onOpen() } const auto path = m_fs->filePath(selection); - core().processRunner() - .setFromFile(parentWidget(), QFileInfo(path)) - .setHooked(false) - .setWaitForCompletion() - .run(); + core() + .processRunner() + .setFromFile(parentWidget(), QFileInfo(path)) + .setHooked(false) + .setWaitForCompletion() + .run(); } void FileTreeTab::onRunHooked() @@ -186,11 +209,12 @@ void FileTreeTab::onRunHooked() } const auto path = m_fs->filePath(selection); - core().processRunner() - .setFromFile(parentWidget(), QFileInfo(path)) - .setHooked(true) - .setWaitForCompletion() - .run(); + core() + .processRunner() + .setFromFile(parentWidget(), QFileInfo(path)) + .setHooked(true) + .setWaitForCompletion() + .run(); } void FileTreeTab::onPreview() @@ -240,12 +264,13 @@ void FileTreeTab::onDelete() if (rows.count() == 1) { QString fileName = m_fs->fileName(rows[0]); - message = tr("Are you sure you want to delete \"%1\"?").arg(fileName); + message = tr("Are you sure you want to delete \"%1\"?").arg(fileName); } else { message = tr("Are you sure you want to delete the selected files?"); } - if (QMessageBox::question(parentWidget(), tr("Confirm"), message) != QMessageBox::Yes) { + if (QMessageBox::question(parentWidget(), tr("Confirm"), message) != + QMessageBox::Yes) { return; } @@ -288,7 +313,7 @@ bool FileTreeTab::deleteFile(const QModelIndex& index) bool FileTreeTab::deleteFileRecursive(const QModelIndex& parent) { - for (int row = 0; row<m_fs->rowCount(parent); ++row) { + for (int row = 0; row < m_fs->rowCount(parent); ++row) { QModelIndex index = m_fs->index(row, 0, parent); if (m_fs->isDir(index)) { @@ -317,14 +342,13 @@ void FileTreeTab::changeVisibility(bool visible) const auto selection = ui->filetree->selectionModel()->selectedRows(); bool changed = false; - bool stop = false; + bool stop = false; - log::debug( - "{} {} filetree files", - (visible ? "unhiding" : "hiding"), selection.size()); + log::debug("{} {} filetree files", (visible ? "unhiding" : "hiding"), + selection.size()); QFlags<FileRenamer::RenameFlags> flags = - (visible ? FileRenamer::UNHIDE : FileRenamer::HIDE); + (visible ? FileRenamer::UNHIDE : FileRenamer::HIDE); if (selection.size() > 1) { flags |= FileRenamer::MULTIPLE; @@ -338,7 +362,7 @@ void FileTreeTab::changeVisibility(bool visible) } const QString path = m_fs->filePath(index); - auto result = FileRenamer::RESULT_CANCEL; + auto result = FileRenamer::RESULT_CANCEL; if (visible) { if (!canUnhideFile(false, path)) { @@ -355,22 +379,22 @@ void FileTreeTab::changeVisibility(bool visible) } switch (result) { - case FileRenamer::RESULT_OK: { - // will trigger a refresh at the end - changed = true; - break; - } + case FileRenamer::RESULT_OK: { + // will trigger a refresh at the end + changed = true; + break; + } - case FileRenamer::RESULT_SKIP: { - // nop - break; - } + case FileRenamer::RESULT_SKIP: { + // nop + break; + } - case FileRenamer::RESULT_CANCEL: { - // stop right now, but make sure to refresh if needed - stop = true; - break; - } + case FileRenamer::RESULT_CANCEL: { + // stop right now, but make sure to refresh if needed + stop = true; + break; + } } } @@ -383,31 +407,31 @@ void FileTreeTab::changeVisibility(bool visible) } } -void FileTreeTab::onContextMenu(const QPoint &pos) +void FileTreeTab::onContextMenu(const QPoint& pos) { const auto selection = ui->filetree->selectionModel()->selectedRows(); QMenu menu(ui->filetree); bool enableNewFolder = false; - bool enableRun = false; - bool enableOpen = false; - bool enablePreview = false; - bool enableExplore = false; - bool enableRename = false; - bool enableDelete = false; - bool enableHide = false; - bool enableUnhide = false; + bool enableRun = false; + bool enableOpen = false; + bool enablePreview = false; + bool enableExplore = false; + bool enableRename = false; + bool enableDelete = false; + bool enableHide = false; + bool enableUnhide = false; if (selection.size() == 0) { // no selection, only new folder and explore enableNewFolder = true; - enableExplore = true; + enableExplore = true; } else if (selection.size() == 1) { // single selection enableNewFolder = true; - enableRename = true; - enableDelete = true; + enableRename = true; + enableDelete = true; // only enable open action if a file is selected bool hasFiles = false; @@ -424,13 +448,13 @@ void FileTreeTab::onContextMenu(const QPoint &pos) enablePreview = canPreviewFile(plugin(), false, fileName); enableExplore = canExploreFile(false, fileName); - enableHide = canHideFile(false, fileName); - enableUnhide = canUnhideFile(false, fileName); + enableHide = canHideFile(false, fileName); + enableUnhide = canUnhideFile(false, fileName); } else { // this is a multiple selection, don't show open or explore actions so users // don't open a thousand files enableNewFolder = true; - enableDelete = true; + enableDelete = true; if (selection.size() < max_scan_for_context_menu) { // if the number of selected items is low, checking them to accurately @@ -458,7 +482,7 @@ void FileTreeTab::onContextMenu(const QPoint &pos) bool enableRunHooked = false; if (enableRun || enableOpen) { - if (auto* p=core().currentProfile()) { + if (auto* p = core().currentProfile()) { if (mod().canBeEnabled()) { const auto index = ModInfo::getIndex(mod().name()); if (index == UINT_MAX) { @@ -526,8 +550,8 @@ void FileTreeTab::onContextMenu(const QPoint &pos) if (enableOpen || enableRun || enablePreview) { // bold the first option, unbold all the others - for (int i=0; i<menu.actions().size(); ++i) { - if (auto* a=menu.actions()[i]) { + for (int i = 0; i < menu.actions().size(); ++i) { + if (auto* a = menu.actions()[i]) { auto f = a->font(); f.setBold(i == 0); a->setFont(f); diff --git a/src/modinfodialogfiletree.h b/src/modinfodialogfiletree.h index c3c84ed4..a7cfbcd6 100644 --- a/src/modinfodialogfiletree.h +++ b/src/modinfodialogfiletree.h @@ -21,14 +21,14 @@ private: struct Actions { QAction* newFolder = nullptr; - QAction* open = nullptr; + QAction* open = nullptr; QAction* runHooked = nullptr; - QAction* preview = nullptr; - QAction* explore = nullptr; - QAction* rename = nullptr; - QAction* del = nullptr; - QAction* hide = nullptr; - QAction* unhide = nullptr; + QAction* preview = nullptr; + QAction* explore = nullptr; + QAction* rename = nullptr; + QAction* del = nullptr; + QAction* hide = nullptr; + QAction* unhide = nullptr; }; QFileSystemModel* m_fs; @@ -45,7 +45,7 @@ private: void onHide(); void onUnhide(); void onOpenInExplorer(); - void onContextMenu(const QPoint &pos); + void onContextMenu(const QPoint& pos); QModelIndex singleSelection() const; bool deleteFile(const QModelIndex& index); @@ -53,4 +53,4 @@ private: void changeVisibility(bool visible); }; -#endif // MODINFODIALOGFILETREE_H +#endif // MODINFODIALOGFILETREE_H diff --git a/src/modinfodialogfwd.h b/src/modinfodialogfwd.h index 805e8a06..08626323 100644 --- a/src/modinfodialogfwd.h +++ b/src/modinfodialogfwd.h @@ -9,7 +9,7 @@ using ModInfoPtr = QSharedPointer<ModInfo>; enum class ModInfoTabIDs { - None = -1, + None = -1, TextFiles = 0, IniFiles, Images, @@ -23,17 +23,18 @@ enum class ModInfoTabIDs class PluginContainer; -bool canPreviewFile(const PluginContainer& pluginContainer, bool isArchive, const QString& filename); +bool canPreviewFile(const PluginContainer& pluginContainer, bool isArchive, + const QString& filename); bool canRunFile(bool isArchive, const QString& filename); bool canOpenFile(bool isArchive, const QString& filename); bool canExploreFile(bool isArchive, const QString& filename); bool canHideFile(bool isArchive, const QString& filename); bool canUnhideFile(bool isArchive, const QString& filename); -FileRenamer::RenameResults hideFile(FileRenamer& renamer, const QString &oldName); +FileRenamer::RenameResults hideFile(FileRenamer& renamer, const QString& oldName); FileRenamer::RenameResults unhideFile(FileRenamer& renamer, const QString& oldName); -FileRenamer::RenameResults restoreHiddenFilesRecursive(FileRenamer& renamer, const QString &targetDir); - +FileRenamer::RenameResults restoreHiddenFilesRecursive(FileRenamer& renamer, + const QString& targetDir); class ElideLeftDelegate : public QStyledItemDelegate { @@ -48,4 +49,4 @@ protected: } }; -#endif // MODINFODIALOGFWD_H +#endif // MODINFODIALOGFWD_H diff --git a/src/modinfodialogimages.cpp b/src/modinfodialogimages.cpp index 530d23d5..e48a34d3 100644 --- a/src/modinfodialogimages.cpp +++ b/src/modinfodialogimages.cpp @@ -1,6 +1,6 @@ #include "modinfodialogimages.h" -#include "ui_modinfodialog.h" #include "settings.h" +#include "ui_modinfodialog.h" #include "utility.h" #include <log.h> @@ -9,37 +9,31 @@ using namespace ImagesTabHelpers; QSize resizeWithAspectRatio(const QSize& original, const QSize& available) { - const auto ratio = std::min({ - 1.0, - static_cast<double>(available.width()) / original.width(), - static_cast<double>(available.height()) / original.height()}); + const auto ratio = + std::min({1.0, static_cast<double>(available.width()) / original.width(), + static_cast<double>(available.height()) / original.height()}); - const QSize scaledSize( - static_cast<int>(std::round(original.width() * ratio)), - static_cast<int>(std::round(original.height() * ratio))); + const QSize scaledSize(static_cast<int>(std::round(original.width() * ratio)), + static_cast<int>(std::round(original.height() * ratio))); return scaledSize; } QRect centeredRect(const QRect& rect, const QSize& size) { - return QRect( - (rect.left()+rect.width()/2) - size.width()/2, - (rect.top()+rect.height()/2) - size.height()/2, - size.width(), - size.height()); + return QRect((rect.left() + rect.width() / 2) - size.width() / 2, + (rect.top() + rect.height() / 2) - size.height() / 2, size.width(), + size.height()); } QString dimensionString(const QSize& s) { - return QString::fromUtf8("%1 \xc3\x97 %2") - .arg(s.width()).arg(s.height()); + return QString::fromUtf8("%1 \xc3\x97 %2").arg(s.width()).arg(s.height()); } - -ImagesTab::ImagesTab(ModInfoDialogTabContext cx) : - ModInfoDialogTab(std::move(cx)), m_image(new ScalableImage), - m_ddsAvailable(false), m_ddsEnabled(false) +ImagesTab::ImagesTab(ModInfoDialogTabContext cx) + : ModInfoDialogTab(std::move(cx)), m_image(new ScalableImage), + m_ddsAvailable(false), m_ddsEnabled(false) { getSupportedFormats(); @@ -58,16 +52,26 @@ ImagesTab::ImagesTab(ModInfoDialogTabContext cx) : ui->imagesThumbnails->setTab(this); ui->imagesScrollerVBar->setTab(this); - connect(ui->imagesScrollerVBar, &QScrollBar::valueChanged, [&]{ onScrolled(); }); + connect(ui->imagesScrollerVBar, &QScrollBar::valueChanged, [&] { + onScrolled(); + }); ui->imagesShowDDS->setEnabled(m_ddsAvailable); m_filter.setEdit(ui->imagesFilter); - connect(&m_filter, &FilterWidget::changed, [&]{ onFilterChanged(); }); + connect(&m_filter, &FilterWidget::changed, [&] { + onFilterChanged(); + }); - connect(ui->imagesExplore, &QAbstractButton::clicked, [&]{ onExplore(); }); - connect(ui->imagesShowDDS, &QCheckBox::toggled, [&]{ onShowDDS(); }); - connect(ui->previewPluginButton, &QAbstractButton::clicked, [&] { onPreviewButton(); }); + connect(ui->imagesExplore, &QAbstractButton::clicked, [&] { + onExplore(); + }); + connect(ui->imagesShowDDS, &QCheckBox::toggled, [&] { + onShowDDS(); + }); + connect(ui->previewPluginButton, &QAbstractButton::clicked, [&] { + onPreviewButton(); + }); ui->imagesShowDDS->setEnabled(m_ddsAvailable); @@ -78,12 +82,12 @@ ImagesTab::ImagesTab(ModInfoDialogTabContext cx) : auto list = std::make_unique<QListWidget>(); parentWidget()->style()->polish(list.get()); - m_theme.borderColor = QColor(Qt::black); + m_theme.borderColor = QColor(Qt::black); m_theme.backgroundColor = QColor(Qt::black); - m_theme.textColor = list->palette().color(QPalette::WindowText); + m_theme.textColor = list->palette().color(QPalette::WindowText); m_theme.highlightBackgroundColor = list->palette().color(QPalette::Highlight); - m_theme.highlightTextColor = list->palette().color(QPalette::HighlightedText); + m_theme.highlightTextColor = list->palette().color(QPalette::HighlightedText); m_theme.font = list->font(); @@ -246,7 +250,7 @@ void ImagesTab::select(std::size_t i, Visibility v) { m_files.select(i); - if (auto* f=m_files.selectedFile()) { + if (auto* f = m_files.selectedFile()) { // when jumping elsewhere in the list, such as with page down/up, the file // might not be visible yet, which means it hasn't been loaded and would // pass a null image in setImage() below @@ -254,7 +258,8 @@ void ImagesTab::select(std::size_t i, Visibility v) ui->imagesPath->setText(QDir::toNativeSeparators(f->path())); ui->imagesExplore->setEnabled(true); - if (plugin().previewGenerator().previewSupported(QFileInfo(f->path()).suffix().toLower())) + if (plugin().previewGenerator().previewSupported( + QFileInfo(f->path()).suffix().toLower())) ui->previewPluginButton->setEnabled(true); else ui->previewPluginButton->setEnabled(false); @@ -269,9 +274,11 @@ void ImagesTab::select(std::size_t i, Visibility v) paint.fillRect(0, 0, 300, 100, QBrush(QColor(0, 0, 0, 255))); paint.setPen(m_theme.textColor); paint.setFont(m_theme.font); - paint.drawImage(QPoint(150-16, 50-20-16), QImage(":/MO/gui/warning")); + paint.drawImage(QPoint(150 - 16, 50 - 20 - 16), QImage(":/MO/gui/warning")); const auto flags = Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextWordWrap; - paint.drawText(0, 46, 300, 54, flags, "This image format is not supported by Qt, but the preview plugin may be able to display it. Use the button above."); + paint.drawText(0, 46, 300, 54, flags, + "This image format is not supported by Qt, but the preview plugin " + "may be able to display it. Use the button above."); paint.end(); m_image->setImage(image); @@ -329,12 +336,12 @@ void ImagesTab::ensureVisible(std::size_t i, Visibility v) const auto geo = makeGeometry(); - const auto fullyVisible = geo.fullyVisibleCount(); + const auto fullyVisible = geo.fullyVisibleCount(); const auto partiallyVisible = fullyVisible + 1; const auto first = ui->imagesScrollerVBar->value(); - const auto last = (v == Visibility::Full ? - first + fullyVisible : first + partiallyVisible); + const auto last = + (v == Visibility::Full ? first + fullyVisible : first + partiallyVisible); if (i < first) { // go up @@ -390,23 +397,22 @@ void ImagesTab::paintThumbnailsArea(QPaintEvent* e) { PaintContext cx(ui->imagesThumbnails, makeGeometry()); - cx.painter.fillRect( - ui->imagesThumbnails->rect(), - ui->imagesThumbnails->palette().color(QPalette::Window)); + cx.painter.fillRect(ui->imagesThumbnails->rect(), + ui->imagesThumbnails->palette().color(QPalette::Window)); const auto visible = cx.geo.fullyVisibleCount() + 1; - const auto first = ui->imagesScrollerVBar->value(); + const auto first = ui->imagesScrollerVBar->value(); - for (std::size_t i=0; i<visible; ++i) { + for (std::size_t i = 0; i < visible; ++i) { const auto fileIndex = first + i; - auto* file = m_files.get(fileIndex); + auto* file = m_files.get(fileIndex); if (!file) { break; } - cx.file = file; + cx.file = file; cx.thumbIndex = i; - cx.fileIndex = fileIndex; + cx.fileIndex = fileIndex; paintThumbnail(cx); } @@ -449,9 +455,8 @@ void ImagesTab::paintThumbnailImage(const PaintContext& cx) cx.file->loadIfNeeded(cx.geo); - const auto imageRect = cx.geo.imageRect(cx.thumbIndex); - const auto scaledThumbRect = centeredRect( - imageRect, cx.file->thumbnail().size()); + const auto imageRect = cx.geo.imageRect(cx.thumbIndex); + const auto scaledThumbRect = centeredRect(imageRect, cx.file->thumbnail().size()); cx.painter.fillRect(scaledThumbRect, m_theme.backgroundColor); cx.painter.drawImage(scaledThumbRect, cx.file->thumbnail()); @@ -471,8 +476,7 @@ void ImagesTab::paintThumbnailText(const PaintContext& cx) QFontMetrics fm(m_theme.font); - const auto text = fm.elidedText( - cx.file->filename(), Qt::ElideRight, tr.width()); + const auto text = fm.elidedText(cx.file->filename(), Qt::ElideRight, tr.width()); const auto flags = Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextSingleLine; @@ -503,45 +507,44 @@ void ImagesTab::thumbnailAreaWheelEvent(QWheelEvent* e) { const auto d = (e->angleDelta() / 8).y(); - ui->imagesScrollerVBar->setValue( - ui->imagesScrollerVBar->value() + (d > 0 ? -1 : 1)); + ui->imagesScrollerVBar->setValue(ui->imagesScrollerVBar->value() + (d > 0 ? -1 : 1)); } bool ImagesTab::thumbnailAreaKeyPressEvent(QKeyEvent* e) { switch (e->key()) { - case Qt::Key_Down: { - moveSelection(ui->imagesScrollerVBar->singleStep()); - return true; - } - - case Qt::Key_Up: { - moveSelection(-ui->imagesScrollerVBar->singleStep()); - return true; - } + case Qt::Key_Down: { + moveSelection(ui->imagesScrollerVBar->singleStep()); + return true; + } - case Qt::Key_PageDown: { - moveSelection(ui->imagesScrollerVBar->pageStep()); - return true; - } + case Qt::Key_Up: { + moveSelection(-ui->imagesScrollerVBar->singleStep()); + return true; + } - case Qt::Key_PageUp: { - moveSelection(-ui->imagesScrollerVBar->pageStep()); - return true; - } + case Qt::Key_PageDown: { + moveSelection(ui->imagesScrollerVBar->pageStep()); + return true; + } - case Qt::Key_Home: { - select(0); - return true; - } + case Qt::Key_PageUp: { + moveSelection(-ui->imagesScrollerVBar->pageStep()); + return true; + } - case Qt::Key_End: { - if (!m_files.empty()) { - select(m_files.size() - 1); - } + case Qt::Key_Home: { + select(0); + return true; + } - return true; + case Qt::Key_End: { + if (!m_files.empty()) { + select(m_files.size() - 1); } + + return true; + } } return false; @@ -562,15 +565,15 @@ void ImagesTab::showTooltip(QHelpEvent* e) } const auto s = QString("%1 (%2)") - .arg(QDir::toNativeSeparators(f->path())) - .arg(dimensionString(f->original().size())); + .arg(QDir::toNativeSeparators(f->path())) + .arg(dimensionString(f->original().size())); QToolTip::showText(e->globalPos(), s, ui->imagesThumbnails); } void ImagesTab::onExplore() { - if (auto* f=m_files.selectedFile()) { + if (auto* f = m_files.selectedFile()) { shell::Explore(f->path()); } } @@ -602,9 +605,9 @@ void ImagesTab::updateScrollbar() return; } - const auto geo = makeGeometry(); + const auto geo = makeGeometry(); const auto availableSize = ui->imagesThumbnails->size(); - const auto fullyVisible = geo.fullyVisibleCount(); + const auto fullyVisible = geo.fullyVisibleCount(); if (fullyVisible >= m_files.size()) { ui->imagesScrollerVBar->setRange(0, 0); @@ -618,7 +621,6 @@ void ImagesTab::updateScrollbar() } } - namespace ImagesTabHelpers { @@ -634,7 +636,6 @@ void Scrollbar::wheelEvent(QWheelEvent* e) } } - void ThumbnailsWidget::setTab(ImagesTab* tab) { m_tab = tab; @@ -689,9 +690,7 @@ bool ThumbnailsWidget::event(QEvent* e) return QWidget::event(e); } - -ScalableImage::ScalableImage(QString path) - : m_path(std::move(path)), m_border(1) +ScalableImage::ScalableImage(QString path) : m_path(std::move(path)), m_border(1) { auto sp = sizePolicy(); sp.setHeightForWidth(true); @@ -700,9 +699,9 @@ ScalableImage::ScalableImage(QString path) void ScalableImage::setImage(const QString& path) { - m_path = path; + m_path = path; m_original = {}; - m_scaled = {}; + m_scaled = {}; update(); } @@ -711,7 +710,7 @@ void ScalableImage::setImage(QImage image) { m_path.clear(); m_original = std::move(image); - m_scaled = {}; + m_scaled = {}; update(); } @@ -733,7 +732,7 @@ int ScalableImage::heightForWidth(int w) const void ScalableImage::setColors(const QColor& border, const QColor& background) { - m_borderColor = border; + m_borderColor = border; m_backgroundColor = background; } @@ -752,20 +751,17 @@ void ScalableImage::paintEvent(QPaintEvent* e) } const QRect widgetRect = rect(); - const QRect imageRect = widgetRect.adjusted( - m_border, m_border, -m_border, -m_border); + const QRect imageRect = widgetRect.adjusted(m_border, m_border, -m_border, -m_border); - const QSize scaledSize = resizeWithAspectRatio( - m_original.size(), imageRect.size()); + const QSize scaledSize = resizeWithAspectRatio(m_original.size(), imageRect.size()); if (m_scaled.isNull() || m_scaled.size() != scaledSize) { - m_scaled = m_original.scaled( - scaledSize.width(), scaledSize.height(), - Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + m_scaled = m_original.scaled(scaledSize.width(), scaledSize.height(), + Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } const QRect drawBorderRect = widgetRect.adjusted(0, 0, -1, -1); - const QRect drawImageRect = centeredRect(imageRect, m_scaled.size()); + const QRect drawImageRect = centeredRect(imageRect, m_scaled.size()); QPainter painter(this); @@ -780,41 +776,24 @@ void ScalableImage::paintEvent(QPaintEvent* e) painter.drawImage(drawImageRect, m_scaled); } - -Metrics::Metrics() : - margins(3), - border(1), - padding(0), - spacing(5), - textSpacing(2), - textHeight(0) -{ -} - +Metrics::Metrics() + : margins(3), border(1), padding(0), spacing(5), textSpacing(2), textHeight(0) +{} Geometry::Geometry(QSize widgetSize, Metrics metrics) - : m_widgetSize(widgetSize), m_metrics(metrics), m_topRect(calcTopRect()) -{ -} + : m_widgetSize(widgetSize), m_metrics(metrics), m_topRect(calcTopRect()) +{} QRect Geometry::calcTopRect() const { const auto thumbWidth = m_widgetSize.width(); - const auto& m = m_metrics; + const auto& m = m_metrics; const auto imageSize = - thumbWidth - - (m.margins * 2) - - (m.border * 2) - - (m.padding * 2); + thumbWidth - (m.margins * 2) - (m.border * 2) - (m.padding * 2); - const auto thumbHeight = - m.margins + - m.border + m.padding + - imageSize + - m.padding + m.border + - m.textSpacing + m.textHeight + - m.margins; + const auto thumbHeight = m.margins + m.border + m.padding + imageSize + m.padding + + m.border + m.textSpacing + m.textHeight + m.margins; return {0, 0, thumbWidth, thumbHeight}; } @@ -824,7 +803,7 @@ std::size_t Geometry::fullyVisibleCount() const const auto r = thumbRect(0); const auto thumbWithSpacing = r.height() + m_metrics.spacing; - const auto visible = (m_widgetSize.height() / thumbWithSpacing); + const auto visible = (m_widgetSize.height() / thumbWithSpacing); return static_cast<std::size_t>(visible); } @@ -843,7 +822,7 @@ QRect Geometry::thumbRect(std::size_t i) const QRect Geometry::borderRect(std::size_t i) const { - auto r = thumbRect(i); + auto r = thumbRect(i); const auto& m = m_metrics; // remove margins and text @@ -870,11 +849,8 @@ QRect Geometry::textRect(std::size_t i) const { const auto r = borderRect(i); - return QRect( - r.left(), - r.bottom() + m_metrics.textSpacing, - r.width(), - m_metrics.textHeight); + return QRect(r.left(), r.bottom() + m_metrics.textSpacing, r.width(), + m_metrics.textHeight); } QRect Geometry::selectionRect(std::size_t i) const @@ -882,11 +858,7 @@ QRect Geometry::selectionRect(std::size_t i) const const auto br = borderRect(i); const auto tr = textRect(i); - return QRect( - br.left(), - br.top(), - br.width(), - tr.bottom() - br.top()); + return QRect(br.left(), br.top(), br.width(), tr.bottom() - br.top()); } std::size_t Geometry::indexAt(const QPoint& p) const @@ -907,11 +879,7 @@ QSize Geometry::scaledImageSize(const QSize& originalSize) const return resizeWithAspectRatio(originalSize, availableSize); } - -File::File(QString path) - : m_path(std::move(path)), m_failed(false) -{ -} +File::File(QString path) : m_path(std::move(path)), m_failed(false) {} void File::ensureOriginalLoaded() { @@ -923,9 +891,8 @@ void File::ensureOriginalLoaded() QImageReader reader(m_path); if (!reader.read(&m_original)) { - log::error( - "failed to load '{}'\n{} (error {})", - m_path, reader.errorString(), static_cast<int>(reader.error())); + log::error("failed to load '{}'\n{} (error {})", m_path, reader.errorString(), + static_cast<int>(reader.error())); m_failed = true; } @@ -990,28 +957,24 @@ void File::load(const Geometry& geo) QImage warning(":/MO/gui/warning"); const auto scaledSize = geo.scaledImageSize(warning.size()); - m_thumbnail = warning.scaled( - scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + m_thumbnail = + warning.scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } else { const auto scaledSize = geo.scaledImageSize(m_original.size()); - m_thumbnail = m_original.scaled( - scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + m_thumbnail = + m_original.scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } } - -Files::Files() - : m_selection(BadIndex), m_filtered(false) -{ -} +Files::Files() : m_selection(BadIndex), m_filtered(false) {} void Files::clear() { m_allFiles.clear(); m_filteredFiles.clear(); m_selection = BadIndex; - m_filtered = false; + m_filtered = false; } void Files::add(File f) @@ -1077,13 +1040,13 @@ File* Files::get(std::size_t i) std::size_t Files::indexOf(const File* f) const { if (m_filtered) { - for (std::size_t i=0; i<m_filteredFiles.size(); ++i) { + for (std::size_t i = 0; i < m_filteredFiles.size(); ++i) { if (m_filteredFiles[i] == f) { return i; } } } else { - for (std::size_t i=0; i<m_allFiles.size(); ++i) { + for (std::size_t i = 0; i < m_allFiles.size(); ++i) { if (&m_allFiles[i] == f) { return i; } @@ -1123,10 +1086,8 @@ bool Files::isFiltered() const return m_filtered; } - PaintContext::PaintContext(QWidget* w, Geometry geo) - : painter(w), geo(geo), file(nullptr), thumbIndex(0), fileIndex(0) -{ -} + : painter(w), geo(geo), file(nullptr), thumbIndex(0), fileIndex(0) +{} -} // namespace +} // namespace ImagesTabHelpers diff --git a/src/modinfodialogimages.h b/src/modinfodialogimages.h index 24255972..e7311aa0 100644 --- a/src/modinfodialogimages.h +++ b/src/modinfodialogimages.h @@ -1,11 +1,11 @@ #ifndef MODINFODIALOGIMAGES_H #define MODINFODIALOGIMAGES_H -#include "modinfodialogtab.h" #include "filterwidget.h" -#include <QScrollBar> -#include "plugincontainer.h" +#include "modinfodialogtab.h" #include "organizercore.h" +#include "plugincontainer.h" +#include <QScrollBar> using namespace MOBase; @@ -34,7 +34,6 @@ private: ImagesTab* m_tab = nullptr; }; - // widget inside the scroller, calls ImagesTab::paintThumbnailArea() when // needed and also forwards mouse clicks and tooltip events // @@ -75,7 +74,6 @@ private: ImagesTab* m_tab = nullptr; }; - // a widget that draws an image scaled to fit while keeping the aspect ratio // class ScalableImage : public QWidget @@ -83,7 +81,7 @@ class ScalableImage : public QWidget Q_OBJECT; public: - ScalableImage(QString path={}); + ScalableImage(QString path = {}); // sets the image to draw void setImage(const QString& path); @@ -109,7 +107,6 @@ private: QColor m_borderColor, m_backgroundColor; }; - struct Theme { QColor borderColor, backgroundColor, textColor; @@ -117,7 +114,6 @@ struct Theme QFont font; }; - struct Metrics { // space outside the thumbnail border @@ -141,7 +137,6 @@ struct Metrics Metrics(); }; - // handles all the geometry calculations by ImagesTab for painting or handling // mouse clicks // @@ -227,13 +222,11 @@ private: // rectangle of the first thumbnail on top const QRect m_topRect; - // calculates the top rectangle // QRect calcTopRect() const; }; - class File { public: @@ -259,7 +252,6 @@ private: void load(const Geometry& geo); }; - class Files { public: @@ -296,7 +288,6 @@ private: bool m_filtered; }; - struct PaintContext { mutable QPainter painter; @@ -308,8 +299,7 @@ struct PaintContext PaintContext(QWidget* w, Geometry geo); }; -} // namespace - +} // namespace ImagesTabHelpers class ImagesTab : public ModInfoDialogTab { @@ -335,12 +325,12 @@ private: }; using ScalableImage = ImagesTabHelpers::ScalableImage; - using Files = ImagesTabHelpers::Files; - using File = ImagesTabHelpers::File; - using Theme = ImagesTabHelpers::Theme; - using Metrics = ImagesTabHelpers::Metrics; - using PaintContext = ImagesTabHelpers::PaintContext; - using Geometry = ImagesTabHelpers::Geometry; + using Files = ImagesTabHelpers::Files; + using File = ImagesTabHelpers::File; + using Theme = ImagesTabHelpers::Theme; + using Metrics = ImagesTabHelpers::Metrics; + using PaintContext = ImagesTabHelpers::PaintContext; + using Geometry = ImagesTabHelpers::Geometry; ScalableImage* m_image; std::vector<QString> m_supportedFormats; @@ -366,7 +356,7 @@ private: void onPreviewButton(); void onFilterChanged(); - void select(std::size_t i, Visibility v=Visibility::Full); + void select(std::size_t i, Visibility v = Visibility::Full); void moveSelection(int by); void ensureVisible(std::size_t i, Visibility v); @@ -387,4 +377,4 @@ private: void updateScrollbar(); }; -#endif // MODINFODIALOGIMAGES_H +#endif // MODINFODIALOGIMAGES_H diff --git a/src/modinfodialognexus.cpp b/src/modinfodialognexus.cpp index fdcb2c03..56636145 100644 --- a/src/modinfodialognexus.cpp +++ b/src/modinfodialognexus.cpp @@ -1,12 +1,12 @@ #include "modinfodialognexus.h" -#include "ui_modinfodialog.h" -#include "settings.h" -#include "organizercore.h" -#include "iplugingame.h" #include "bbcode.h" -#include <versioninfo.h> -#include <utility.h> +#include "iplugingame.h" +#include "organizercore.h" +#include "settings.h" +#include "ui_modinfodialog.h" #include <log.h> +#include <utility.h> +#include <versioninfo.h> using namespace MOBase; @@ -15,28 +15,46 @@ bool isValidModID(int id) return (id > 0); } -NexusTab::NexusTab(ModInfoDialogTabContext cx) : - ModInfoDialogTab(std::move(cx)), m_requestStarted(false), m_loading(false) +NexusTab::NexusTab(ModInfoDialogTabContext cx) + : ModInfoDialogTab(std::move(cx)), m_requestStarted(false), m_loading(false) { ui->modID->setValidator(new QIntValidator(ui->modID)); ui->endorse->setVisible(core().settings().nexus().endorsementIntegration()); ui->track->setVisible(core().settings().nexus().trackedIntegration()); - connect(ui->modID, &QLineEdit::editingFinished, [&]{ onModIDChanged(); }); - connect( - ui->sourceGame, - static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), - [&]{ onSourceGameChanged(); }); - connect(ui->version, &QLineEdit::editingFinished, [&]{ onVersionChanged(); }); + connect(ui->modID, &QLineEdit::editingFinished, [&] { + onModIDChanged(); + }); + connect(ui->sourceGame, + static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), [&] { + onSourceGameChanged(); + }); + connect(ui->version, &QLineEdit::editingFinished, [&] { + onVersionChanged(); + }); - connect(ui->refresh, &QPushButton::clicked, [&]{ onRefreshBrowser(); }); - connect(ui->visitNexus, &QPushButton::clicked, [&]{ onVisitNexus(); }); - connect(ui->endorse, &QPushButton::clicked, [&]{ onEndorse(); }); - connect(ui->track, &QPushButton::clicked, [&]{ onTrack(); }); + connect(ui->refresh, &QPushButton::clicked, [&] { + onRefreshBrowser(); + }); + connect(ui->visitNexus, &QPushButton::clicked, [&] { + onVisitNexus(); + }); + connect(ui->endorse, &QPushButton::clicked, [&] { + onEndorse(); + }); + connect(ui->track, &QPushButton::clicked, [&] { + onTrack(); + }); - connect(ui->hasCustomURL, &QCheckBox::toggled, [&]{ onCustomURLToggled(); }); - connect(ui->customURL, &QLineEdit::editingFinished, [&]{ onCustomURLChanged(); }); - connect(ui->visitCustomURL, &QPushButton::clicked, [&]{ onVisitCustomURL(); }); + connect(ui->hasCustomURL, &QCheckBox::toggled, [&] { + onCustomURLToggled(); + }); + connect(ui->customURL, &QLineEdit::editingFinished, [&] { + onCustomURLChanged(); + }); + connect(ui->visitCustomURL, &QPushButton::clicked, [&] { + onVisitCustomURL(); + }); } NexusTab::~NexusTab() @@ -72,9 +90,8 @@ void NexusTab::update() ui->modID->setText(QString("%1").arg(mod().nexusId())); QString gameName = mod().gameName(); - ui->sourceGame->addItem( - core().managedGame()->gameName(), - core().managedGame()->gameShortName()); + ui->sourceGame->addItem(core().managedGame()->gameName(), + core().managedGame()->gameShortName()); if (core().managedGame()->validShortNames().size() == 0) { ui->sourceGame->setDisabled(true); @@ -94,13 +111,12 @@ void NexusTab::update() auto* page = new NexusTabWebpage(ui->browser); ui->browser->setPage(page); - connect( - page, &NexusTabWebpage::linkClicked, - [&](const QUrl& url){ shell::Open(url); }); + connect(page, &NexusTabWebpage::linkClicked, [&](const QUrl& url) { + shell::Open(url); + }); - ui->endorse->setEnabled( - (mod().endorsedState() == EndorsedState::ENDORSED_FALSE) || - (mod().endorsedState() == EndorsedState::ENDORSED_NEVER)); + ui->endorse->setEnabled((mod().endorsedState() == EndorsedState::ENDORSED_FALSE) || + (mod().endorsedState() == EndorsedState::ENDORSED_NEVER)); setHasData(mod().nexusId() >= 0); } @@ -116,8 +132,9 @@ void NexusTab::setMod(ModInfoPtr mod, MOShared::FilesOrigin* origin) ModInfoDialogTab::setMod(mod, origin); - m_modConnection = connect( - mod.data(), &ModInfo::modDetailsUpdated, [&]{ onModChanged(); }); + m_modConnection = connect(mod.data(), &ModInfo::modDetailsUpdated, [&] { + onModChanged(); + }); } bool NexusTab::usesOriginFiles() const @@ -129,8 +146,8 @@ void NexusTab::updateVersionColor() { if (mod().version() != mod().newestVersion()) { ui->version->setStyleSheet("color: red"); - ui->version->setToolTip(tr("Current Version: %1").arg( - mod().newestVersion().canonicalString())); + ui->version->setToolTip( + tr("Current Version: %1").arg(mod().newestVersion().canonicalString())); } else { ui->version->setStyleSheet("color: green"); ui->version->setToolTip(tr("No update available")); @@ -142,8 +159,8 @@ void NexusTab::updateWebpage() const int modID = mod().nexusId(); if (isValidModID(modID)) { - const QString nexusLink = NexusInterface::instance() - .getModURL(modID, mod().gameName()); + const QString nexusLink = + NexusInterface::instance().getModURL(modID, mod().gameName()); ui->visitNexus->setToolTip(nexusLink); refreshData(modID); @@ -287,8 +304,7 @@ void NexusTab::onModChanged() page for it in the "Custom URL" box below.</p> </div>)")); } else { - descriptionAsHTML = descriptionAsHTML.arg( - BBCode::convertToHTML(nexusDescription)); + descriptionAsHTML = descriptionAsHTML.arg(BBCode::convertToHTML(nexusDescription)); } ui->browser->page()->setHtml(descriptionAsHTML); @@ -305,7 +321,7 @@ void NexusTab::onModIDChanged() const int oldID = mod().nexusId(); const int newID = ui->modID->text().toInt(); - if (oldID != newID){ + if (oldID != newID) { mod().setNexusID(newID); mod().setLastNexusQuery(QDateTime::fromSecsSinceEpoch(0)); @@ -361,8 +377,8 @@ void NexusTab::onVisitNexus() const int modID = mod().nexusId(); if (isValidModID(modID)) { - const QString nexusLink = NexusInterface::instance() - .getModURL(modID, mod().gameName()); + const QString nexusLink = + NexusInterface::instance().getModURL(modID, mod().gameName()); shell::Open(QUrl(nexusLink)); } @@ -372,14 +388,16 @@ void NexusTab::onEndorse() { // use modPtr() instead of mod() or this because the callback may be // executed after the dialog is closed - core().loggedInAction(parentWidget(), [m=modPtr()]{ m->endorse(true); }); + core().loggedInAction(parentWidget(), [m = modPtr()] { + m->endorse(true); + }); } void NexusTab::onTrack() { // use modPtr() instead of mod() or this because the callback may be // executed after the dialog is closed - core().loggedInAction(parentWidget(), [m=modPtr()] { + core().loggedInAction(parentWidget(), [m = modPtr()] { if (m->trackedState() == TrackedState::TRACKED_TRUE) { m->track(false); } else { diff --git a/src/modinfodialognexus.h b/src/modinfodialognexus.h index 1cfa2057..e9a8720f 100644 --- a/src/modinfodialognexus.h +++ b/src/modinfodialognexus.h @@ -8,16 +8,12 @@ class NexusTabWebpage : public QWebEnginePage Q_OBJECT public: - NexusTabWebpage(QObject* parent = 0) - : QWebEnginePage(parent) - { - } + NexusTabWebpage(QObject* parent = 0) : QWebEnginePage(parent) {} - bool acceptNavigationRequest( - const QUrl & url, QWebEnginePage::NavigationType type, bool) override + bool acceptNavigationRequest(const QUrl& url, QWebEnginePage::NavigationType type, + bool) override { - if (type == QWebEnginePage::NavigationTypeLinkClicked) - { + if (type == QWebEnginePage::NavigationTypeLinkClicked) { emit linkClicked(url); return false; } @@ -29,7 +25,6 @@ signals: void linkClicked(const QUrl&); }; - class NexusTab : public ModInfoDialogTab { Q_OBJECT; @@ -73,4 +68,4 @@ private: void onVisitCustomURL(); }; -#endif // MODINFODIALOGNEXUS_H +#endif // MODINFODIALOGNEXUS_H diff --git a/src/modinfodialogtab.cpp b/src/modinfodialogtab.cpp index e5ced4f7..c443a389 100644 --- a/src/modinfodialogtab.cpp +++ b/src/modinfodialogtab.cpp @@ -1,14 +1,13 @@ #include "modinfodialogtab.h" -#include "ui_modinfodialog.h" -#include "texteditor.h" #include "modinfo.h" #include "shared/filesorigin.h" +#include "texteditor.h" +#include "ui_modinfodialog.h" -ModInfoDialogTab::ModInfoDialogTab(ModInfoDialogTabContext cx) : - ui(cx.ui), m_core(cx.core), m_plugin(cx.plugin), m_parent(cx.parent), - m_origin(cx.origin), m_tabID(cx.id), m_hasData(false), m_firstActivation(true) -{ -} +ModInfoDialogTab::ModInfoDialogTab(ModInfoDialogTabContext cx) + : ui(cx.ui), m_core(cx.core), m_plugin(cx.plugin), m_parent(cx.parent), + m_origin(cx.origin), m_tabID(cx.id), m_hasData(false), m_firstActivation(true) +{} void ModInfoDialogTab::activated() { @@ -77,7 +76,7 @@ bool ModInfoDialogTab::usesOriginFiles() const void ModInfoDialogTab::setMod(ModInfoPtr mod, MOShared::FilesOrigin* origin) { - m_mod = mod; + m_mod = mod; m_origin = origin; } @@ -148,20 +147,26 @@ void ModInfoDialogTab::setFocus() emit wantsFocus(); } - -NotesTab::NotesTab(ModInfoDialogTabContext cx) - : ModInfoDialogTab(std::move(cx)) +NotesTab::NotesTab(ModInfoDialogTabContext cx) : ModInfoDialogTab(std::move(cx)) { - connect(ui->comments, &QLineEdit::editingFinished, [&]{ onComments(); }); - connect(ui->notes, &HTMLEditor::editingFinished, [&]{ onNotes(); }); - connect(ui->setColorButton, &QPushButton::clicked, [&] { onSetColor(); }); - connect(ui->resetColorButton, &QPushButton::clicked, [&] { onResetColor(); }); + connect(ui->comments, &QLineEdit::editingFinished, [&] { + onComments(); + }); + connect(ui->notes, &HTMLEditor::editingFinished, [&] { + onNotes(); + }); + connect(ui->setColorButton, &QPushButton::clicked, [&] { + onSetColor(); + }); + connect(ui->resetColorButton, &QPushButton::clicked, [&] { + onResetColor(); + }); } void NotesTab::updateCommentsColor(bool clear) { QPalette commentPalette = QPalette(); - + if (!clear) { auto modColor = mod().color(); if (modColor.isValid()) { @@ -183,7 +188,7 @@ void NotesTab::clear() void NotesTab::update() { const auto comments = mod().comments(); - const auto notes = mod().notes(); + const auto notes = mod().notes(); ui->comments->setText(comments); ui->notes->setText(notes); @@ -220,7 +225,7 @@ void NotesTab::onSetColor() dialog.setOption(QColorDialog::ShowAlphaChannel); QColor currentColor = mod().color(); - + if (currentColor.isValid()) { dialog.setCurrentColor(currentColor); } @@ -253,8 +258,6 @@ bool NotesTab::usesOriginFiles() const void NotesTab::checkHasData() { - setHasData( - !ui->comments->text().isEmpty() || - !ui->notes->toPlainText().isEmpty() || - mod().color().isValid()); + setHasData(!ui->comments->text().isEmpty() || !ui->notes->toPlainText().isEmpty() || + mod().color().isValid()); } diff --git a/src/modinfodialogtab.h b/src/modinfodialogtab.h index 7a42bf7e..dff1732d 100644 --- a/src/modinfodialogtab.h +++ b/src/modinfodialogtab.h @@ -4,8 +4,14 @@ #include "modinfodialogfwd.h" #include <QObject> -namespace MOShared { class FilesOrigin; } -namespace Ui { class ModInfoDialog; } +namespace MOShared +{ +class FilesOrigin; +} +namespace Ui +{ +class ModInfoDialog; +} class Settings; class OrganizerCore; @@ -22,21 +28,14 @@ struct ModInfoDialogTabContext ModInfoPtr mod; MOShared::FilesOrigin* origin; - ModInfoDialogTabContext( - OrganizerCore& core, - PluginContainer& plugin, - QWidget* parent, - Ui::ModInfoDialog* ui, - ModInfoTabIDs id, - ModInfoPtr mod, - MOShared::FilesOrigin* origin) : - core(core), plugin(plugin), parent(parent), ui(ui), id(id), - mod(mod), origin(origin) - { - } + ModInfoDialogTabContext(OrganizerCore& core, PluginContainer& plugin, QWidget* parent, + Ui::ModInfoDialog* ui, ModInfoTabIDs id, ModInfoPtr mod, + MOShared::FilesOrigin* origin) + : core(core), plugin(plugin), parent(parent), ui(ui), id(id), mod(mod), + origin(origin) + {} }; - // base class for all tabs in the mod info dialog // // when the dialog is opened or when next/previous is clicked, the sequence is: @@ -72,11 +71,11 @@ class ModInfoDialogTab : public QObject Q_OBJECT; public: - ModInfoDialogTab(const ModInfoDialogTab&) = delete; + ModInfoDialogTab(const ModInfoDialogTab&) = delete; ModInfoDialogTab& operator=(const ModInfoDialogTab&) = delete; - ModInfoDialogTab(ModInfoDialogTab&&) = default; - ModInfoDialogTab& operator=(ModInfoDialogTab&&) = default; - virtual ~ModInfoDialogTab() = default; + ModInfoDialogTab(ModInfoDialogTab&&) = default; + ModInfoDialogTab& operator=(ModInfoDialogTab&&) = default; + virtual ~ModInfoDialogTab() = default; // called by ModInfoDialog every time this tab is selected; this will call // firstActivation() the first time it's called, until resetFirstActivation() @@ -89,7 +88,6 @@ public: // void resetFirstActivation(); - // called when the selected mod changed, `mod` can never be empty, but // `origin` can (if the mod is not active, for example) // @@ -143,7 +141,6 @@ public: // virtual bool canClose(); - // called after the dialog is closed, tabs should save whatever UI state they // want // @@ -154,7 +151,6 @@ public: // virtual void restoreState(const Settings& s); - // called on the selected tab when the Delete key is pressed on the keyboard; // tabs _must_ check which widget currently has focus to decide whether this // should be handled or not; do not blindly delete stuff when this is called @@ -163,7 +159,6 @@ public: // virtual bool deleteRequested(); - // return true if this tab can handle a separator mod, defaults to false; // when this returns false, the tab is removed from the widget entirely // @@ -188,7 +183,6 @@ public: // virtual bool usesOriginFiles() const; - // returns the currently selected mod // ModInfo& mod() const; @@ -202,7 +196,6 @@ public: // MOShared::FilesOrigin* origin() const; - // return this tab's ID // ModInfoTabIDs tabID() const; @@ -279,7 +272,6 @@ private: bool m_firstActivation; }; - // the Notes tab // class NotesTab : public ModInfoDialogTab @@ -307,4 +299,4 @@ private: void checkHasData(); }; -#endif // MODINFODIALOGTAB_H +#endif // MODINFODIALOGTAB_H diff --git a/src/modinfodialogtextfiles.cpp b/src/modinfodialogtextfiles.cpp index 564c2cf7..cc13e2d2 100644 --- a/src/modinfodialogtextfiles.cpp +++ b/src/modinfodialogtextfiles.cpp @@ -1,7 +1,7 @@ #include "modinfodialogtextfiles.h" -#include "ui_modinfodialog.h" #include "modinfodialog.h" #include "settings.h" +#include "ui_modinfodialog.h" #include <QMessageBox> class FileListModel : public QAbstractItemModel @@ -13,17 +13,14 @@ public: endResetModel(); } - QModelIndex index(int row, int col, const QModelIndex& ={}) const override + QModelIndex index(int row, int col, const QModelIndex& = {}) const override { return createIndex(row, col); } - QModelIndex parent(const QModelIndex&) const override - { - return {}; - } + QModelIndex parent(const QModelIndex&) const override { return {}; } - int rowCount(const QModelIndex& index={}) const override + int rowCount(const QModelIndex& index = {}) const override { // no child nodes if (index.isValid()) @@ -32,10 +29,7 @@ public: return static_cast<int>(m_files.size()); } - int columnCount(const QModelIndex& ={}) const override - { - return 1; - } + int columnCount(const QModelIndex& = {}) const override { return 1; } QVariant data(const QModelIndex& index, int role) const override { @@ -92,22 +86,16 @@ private: QString fullPath; QString text; - File(QString fp, QString t) - : fullPath(std::move(fp)), text(std::move(t)) - { - } + File(QString fp, QString t) : fullPath(std::move(fp)), text(std::move(t)) {} }; std::deque<File> m_files; }; - -GenericFilesTab::GenericFilesTab( - ModInfoDialogTabContext cx, - QListView* list, QSplitter* sp, - TextEditor* e, QLineEdit* filter) : - ModInfoDialogTab(std::move(cx)), - m_list(list), m_editor(e), m_splitter(sp), m_model(new FileListModel) +GenericFilesTab::GenericFilesTab(ModInfoDialogTabContext cx, QListView* list, + QSplitter* sp, TextEditor* e, QLineEdit* filter) + : ModInfoDialogTab(std::move(cx)), m_list(list), m_editor(e), m_splitter(sp), + m_model(new FileListModel) { m_list->setModel(m_model); m_editor->setupToolbar(); @@ -119,9 +107,10 @@ GenericFilesTab::GenericFilesTab( m_filter.setEdit(filter); m_filter.setList(m_list); - QObject::connect( - m_list->selectionModel(), &QItemSelectionModel::currentRowChanged, - [&](auto current, auto previous){ onSelection(current, previous); }); + QObject::connect(m_list->selectionModel(), &QItemSelectionModel::currentRowChanged, + [&](auto current, auto previous) { + onSelection(current, previous); + }); } void GenericFilesTab::clear() @@ -140,10 +129,9 @@ bool GenericFilesTab::canClose() setFocus(); const int res = QMessageBox::question( - parentWidget(), - QObject::tr("Save changes?"), - QObject::tr("Save changes to \"%1\"?").arg(m_editor->filename()), - QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); + parentWidget(), QObject::tr("Save changes?"), + QObject::tr("Save changes to \"%1\"?").arg(m_editor->filename()), + QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); if (res == QMessageBox::Cancel) { return false; @@ -182,8 +170,8 @@ void GenericFilesTab::restoreState(const Settings& s) s.geometry().restoreState(m_splitter); } -void GenericFilesTab::onSelection( - const QModelIndex& current, const QModelIndex& previous) +void GenericFilesTab::onSelection(const QModelIndex& current, + const QModelIndex& previous) { if (!canClose()) { m_list->selectionModel()->select(previous, QItemSelectionModel::Current); @@ -205,23 +193,14 @@ void GenericFilesTab::select(const QModelIndex& index) m_editor->load(m_model->fullPath(m_filter.mapToSource(index))); } - TextFilesTab::TextFilesTab(ModInfoDialogTabContext cx) - : GenericFilesTab(cx, - cx.ui->textFileList, cx.ui->tabTextSplitter, - cx.ui->textFileEditor, cx.ui->textFileFilter) -{ -} + : GenericFilesTab(cx, cx.ui->textFileList, cx.ui->tabTextSplitter, + cx.ui->textFileEditor, cx.ui->textFileFilter) +{} bool TextFilesTab::wantsFile(const QString& rootPath, const QString& fullPath) const { - static const QString extensions[] = { - ".txt", - ".json", - ".cfg", - ".log", - ".toml" - }; + static const QString extensions[] = {".txt", ".json", ".cfg", ".log", ".toml"}; for (const auto& e : extensions) { if (fullPath.endsWith(e, Qt::CaseInsensitive)) { @@ -233,11 +212,9 @@ bool TextFilesTab::wantsFile(const QString& rootPath, const QString& fullPath) c } IniFilesTab::IniFilesTab(ModInfoDialogTabContext cx) - : GenericFilesTab(cx, - cx.ui->iniFileList, cx.ui->tabIniSplitter, - cx.ui->iniFileEditor, cx.ui->iniFileFilter) -{ -} + : GenericFilesTab(cx, cx.ui->iniFileList, cx.ui->tabIniSplitter, + cx.ui->iniFileEditor, cx.ui->iniFileFilter) +{} bool IniFilesTab::wantsFile(const QString& rootPath, const QString& fullPath) const { diff --git a/src/modinfodialogtextfiles.h b/src/modinfodialogtextfiles.h index d57bf490..f6bd7d7b 100644 --- a/src/modinfodialogtextfiles.h +++ b/src/modinfodialogtextfiles.h @@ -1,10 +1,10 @@ #ifndef MODINFODIALOGTEXTFILES_H #define MODINFODIALOGTEXTFILES_H -#include "modinfodialogtab.h" #include "filterwidget.h" -#include <QSplitter> +#include "modinfodialogtab.h" #include <QListView> +#include <QSplitter> using namespace MOBase; @@ -31,10 +31,8 @@ protected: FileListModel* m_model; FilterWidget m_filter; - GenericFilesTab( - ModInfoDialogTabContext cx, - QListView* list, QSplitter* splitter, - TextEditor* editor, QLineEdit* filter); + GenericFilesTab(ModInfoDialogTabContext cx, QListView* list, QSplitter* splitter, + TextEditor* editor, QLineEdit* filter); virtual bool wantsFile(const QString& rootPath, const QString& fullPath) const = 0; @@ -43,7 +41,6 @@ private: void select(const QModelIndex& index); }; - class TextFilesTab : public GenericFilesTab { public: @@ -53,7 +50,6 @@ protected: bool wantsFile(const QString& rootPath, const QString& fullPath) const override; }; - class IniFilesTab : public GenericFilesTab { public: @@ -63,4 +59,4 @@ protected: bool wantsFile(const QString& rootPath, const QString& fullPath) const override; }; -#endif // MODINFODIALOGTEXTFILES_H +#endif // MODINFODIALOGTEXTFILES_H diff --git a/src/modinfoforeign.cpp b/src/modinfoforeign.cpp index 97d3f4e1..db90aa41 100644 --- a/src/modinfoforeign.cpp +++ b/src/modinfoforeign.cpp @@ -15,8 +15,8 @@ QDateTime ModInfoForeign::creationTime() const QString ModInfoForeign::absolutePath() const { - //I ought to store this, it's used elsewhere - IPluginGame const *game = qApp->property("managed_game").value<IPluginGame *>(); + // I ought to store this, it's used elsewhere + IPluginGame const* game = qApp->property("managed_game").value<IPluginGame*>(); return game->dataDirectory().absolutePath(); } @@ -39,28 +39,28 @@ int ModInfoForeign::getHighlight() const QString ModInfoForeign::getDescription() const { - return tr("This pseudo mod represents content managed outside MO. It isn't modified by MO."); + return tr("This pseudo mod represents content managed outside MO. It isn't modified " + "by MO."); } -ModInfoForeign::ModInfoForeign( - const QString &modName, const QString &referenceFile, - const QStringList &archives, ModInfo::EModType modType, - OrganizerCore& core) - : ModInfoWithConflictInfo(core), - m_ReferenceFile(referenceFile), m_Archives(archives), m_ModType(modType) +ModInfoForeign::ModInfoForeign(const QString& modName, const QString& referenceFile, + const QStringList& archives, ModInfo::EModType modType, + OrganizerCore& core) + : ModInfoWithConflictInfo(core), m_ReferenceFile(referenceFile), + m_Archives(archives), m_ModType(modType) { m_CreationTime = QFileInfo(referenceFile).birthTime(); switch (modType) { case ModInfo::EModType::MOD_DLC: - m_Name = tr("DLC: ") + modName; + m_Name = tr("DLC: ") + modName; m_InternalName = QString("DLC: ") + modName; break; case ModInfo::EModType::MOD_CC: - m_Name = tr("Creation Club: ") + modName; + m_Name = tr("Creation Club: ") + modName; m_InternalName = QString("Creation Club: ") + modName; break; default: - m_Name = tr("Unmanaged: ") + modName; + m_Name = tr("Unmanaged: ") + modName; m_InternalName = QString("Unmanaged: ") + modName; } } diff --git a/src/modinfoforeign.h b/src/modinfoforeign.h index 3acebeaf..2c956fb7 100644 --- a/src/modinfoforeign.h +++ b/src/modinfoforeign.h @@ -5,7 +5,7 @@ #include "modinfowithconflictinfo.h" -class ModInfoForeign: public ModInfoWithConflictInfo +class ModInfoForeign : public ModInfoWithConflictInfo { Q_OBJECT @@ -13,7 +13,6 @@ class ModInfoForeign: public ModInfoWithConflictInfo friend class ModInfo; public: - virtual bool updateAvailable() const override { return false; } virtual bool updateIgnored() const override { return false; } virtual bool downgradeAvailable() const override { return false; } @@ -50,7 +49,10 @@ public: virtual int nexusId() const override { return -1; } virtual bool isForeign() const override { return true; } virtual QDateTime getExpires() const override { return QDateTime(); } - virtual std::vector<QString> getIniTweaks() const override { return std::vector<QString>(); } + virtual std::vector<QString> getIniTweaks() const override + { + return std::vector<QString>(); + } virtual std::vector<ModInfo::EFlag> getFlags() const override; virtual int getHighlight() const override; virtual QString getDescription() const override; @@ -64,25 +66,43 @@ public: virtual void setNexusLastModified(QDateTime) override {} virtual QString getNexusDescription() const override { return QString(); } virtual QStringList archives(bool = false) override { return m_Archives; } - virtual QStringList stealFiles() const override { return m_Archives + QStringList(m_ReferenceFile); } + virtual QStringList stealFiles() const override + { + return m_Archives + QStringList(m_ReferenceFile); + } virtual bool alwaysEnabled() const override { return true; } virtual void addInstalledFile(int, int) override {} virtual std::set<std::pair<int, int>> installedFiles() const override { return {}; } - virtual QVariant pluginSetting(const QString& pluginName, const QString& key, const QVariant& defaultValue) const override { return defaultValue; } - virtual std::map<QString, QVariant> pluginSettings(const QString& pluginName) const override { return {}; } - virtual bool setPluginSetting(const QString& pluginName, const QString& key, const QVariant& value) override { return false; } - virtual std::map<QString, QVariant> clearPluginSettings(const QString& pluginName) override { return {}; } + virtual QVariant pluginSetting(const QString& pluginName, const QString& key, + const QVariant& defaultValue) const override + { + return defaultValue; + } + virtual std::map<QString, QVariant> + pluginSettings(const QString& pluginName) const override + { + return {}; + } + virtual bool setPluginSetting(const QString& pluginName, const QString& key, + const QVariant& value) override + { + return false; + } + virtual std::map<QString, QVariant> + clearPluginSettings(const QString& pluginName) override + { + return {}; + } ModInfo::EModType modType() const { return m_ModType; } protected: - ModInfoForeign(const QString &modName, const QString &referenceFile, - const QStringList &archives, ModInfo::EModType modType, - OrganizerCore &core); + ModInfoForeign(const QString& modName, const QString& referenceFile, + const QStringList& archives, ModInfo::EModType modType, + OrganizerCore& core); private: - QString m_Name; QString m_InternalName; QString m_ReferenceFile; @@ -92,4 +112,4 @@ private: ModInfo::EModType m_ModType; }; -#endif // MODINFOFOREIGN_H +#endif // MODINFOFOREIGN_H diff --git a/src/modinfooverwrite.cpp b/src/modinfooverwrite.cpp index 5ee7a0d9..9d0ed5f9 100644 --- a/src/modinfooverwrite.cpp +++ b/src/modinfooverwrite.cpp @@ -1,21 +1,22 @@ #include "modinfooverwrite.h" -#include "shared/appconfig.h" #include "settings.h" +#include "shared/appconfig.h" #include <QApplication> #include <QDirIterator> ModInfoOverwrite::ModInfoOverwrite(OrganizerCore& core) : ModInfoWithConflictInfo(core) -{ -} +{} bool ModInfoOverwrite::isEmpty() const { QDirIterator iter(absolutePath(), QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs); - if (!iter.hasNext()) return true; + if (!iter.hasNext()) + return true; iter.next(); - if ((iter.fileName() == "meta.ini") && !iter.hasNext()) return true; + if ((iter.fileName() == "meta.ini") && !iter.hasNext()) + return true; return false; } @@ -46,9 +47,11 @@ std::vector<ModInfo::EConflictFlag> ModInfoOverwrite::getConflictFlags() const int ModInfoOverwrite::getHighlight() const { - int highlight = (isValid() ? HIGHLIGHT_IMPORTANT : HIGHLIGHT_INVALID) | HIGHLIGHT_CENTER; + int highlight = + (isValid() ? HIGHLIGHT_IMPORTANT : HIGHLIGHT_INVALID) | HIGHLIGHT_CENTER; auto flags = getFlags(); - if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_PLUGIN_SELECTED) != flags.end()) + if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_PLUGIN_SELECTED) != + flags.end()) highlight |= HIGHLIGHT_PLUGIN; return highlight; } @@ -63,7 +66,7 @@ QStringList ModInfoOverwrite::archives(bool checkOnDisk) { QStringList result; QDir dir(this->absolutePath()); - for (const QString &archive : dir.entryList(QStringList({ "*.bsa", "*.ba2" }))) { + for (const QString& archive : dir.entryList(QStringList({"*.bsa", "*.ba2"}))) { result.append(this->absolutePath() + "/" + archive); } return result; diff --git a/src/modinfooverwrite.h b/src/modinfooverwrite.h index 997e24ea..02154902 100644 --- a/src/modinfooverwrite.h +++ b/src/modinfooverwrite.h @@ -15,7 +15,6 @@ class ModInfoOverwrite : public ModInfoWithConflictInfo friend class ModInfo; public: - virtual bool updateAvailable() const override { return false; } virtual bool updateIgnored() const override { return false; } virtual bool downgradeAvailable() const override { return false; } @@ -52,7 +51,10 @@ public: virtual int nexusId() const override { return -1; } virtual bool isOverwrite() const override { return true; } virtual QDateTime getExpires() const override { return QDateTime(); } - virtual std::vector<QString> getIniTweaks() const override { return std::vector<QString>(); } + virtual std::vector<QString> getIniTweaks() const override + { + return std::vector<QString>(); + } virtual std::vector<ModInfo::EFlag> getFlags() const override; virtual std::vector<ModInfo::EConflictFlag> getConflictFlags() const override; virtual int getHighlight() const override; @@ -70,14 +72,29 @@ public: virtual void addInstalledFile(int, int) override {} virtual std::set<std::pair<int, int>> installedFiles() const override { return {}; } - virtual QVariant pluginSetting(const QString& pluginName, const QString& key, const QVariant& defaultValue) const override { return defaultValue; } - virtual std::map<QString, QVariant> pluginSettings(const QString& pluginName) const override { return {}; } - virtual bool setPluginSetting(const QString& pluginName, const QString& key, const QVariant& value) override { return false; } - virtual std::map<QString, QVariant> clearPluginSettings(const QString& pluginName) override { return {}; } + virtual QVariant pluginSetting(const QString& pluginName, const QString& key, + const QVariant& defaultValue) const override + { + return defaultValue; + } + virtual std::map<QString, QVariant> + pluginSettings(const QString& pluginName) const override + { + return {}; + } + virtual bool setPluginSetting(const QString& pluginName, const QString& key, + const QVariant& value) override + { + return false; + } + virtual std::map<QString, QVariant> + clearPluginSettings(const QString& pluginName) override + { + return {}; + } private: ModInfoOverwrite(OrganizerCore& core); - }; -#endif // MODINFOOVERWRITE_H +#endif // MODINFOOVERWRITE_H diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index eb84a2ad..4c1004e6 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -2,11 +2,11 @@ #include "categories.h" #include "messagedialog.h" -#include "report.h" #include "moddatacontent.h" -#include "settings.h" #include "organizercore.h" #include "plugincontainer.h" +#include "report.h" +#include "settings.h" #include <iplugingame.h> #include <QApplication> @@ -18,28 +18,24 @@ using namespace MOBase; using namespace MOShared; -namespace { - //Arguably this should be a class static or we should be using FileString rather - //than QString for the names. Or both. - static bool ByName(const ModInfo::Ptr &LHS, const ModInfo::Ptr &RHS) - { - return QString::compare(LHS->name(), RHS->name(), Qt::CaseInsensitive) < 0; - } +namespace +{ +// Arguably this should be a class static or we should be using FileString rather +// than QString for the names. Or both. +static bool ByName(const ModInfo::Ptr& LHS, const ModInfo::Ptr& RHS) +{ + return QString::compare(LHS->name(), RHS->name(), Qt::CaseInsensitive) < 0; } +} // namespace -ModInfoRegular::ModInfoRegular(const QDir &path, OrganizerCore& core) - : ModInfoWithConflictInfo(core) - , m_Name(path.dirName()) - , m_Path(path.absolutePath()) - , m_Repository() - , m_GameName(core.managedGame()->gameShortName()) - , m_IsAlternate(false) - , m_Converted(false) - , m_Validated(false) - , m_MetaInfoChanged(false) - , m_EndorsedState(EndorsedState::ENDORSED_UNKNOWN) - , m_TrackedState(TrackedState::TRACKED_UNKNOWN) - , m_NexusBridge(&core.pluginContainer()) +ModInfoRegular::ModInfoRegular(const QDir& path, OrganizerCore& core) + : ModInfoWithConflictInfo(core), m_Name(path.dirName()), + m_Path(path.absolutePath()), m_Repository(), + m_GameName(core.managedGame()->gameShortName()), m_IsAlternate(false), + m_Converted(false), m_Validated(false), m_MetaInfoChanged(false), + m_EndorsedState(EndorsedState::ENDORSED_UNKNOWN), + m_TrackedState(TrackedState::TRACKED_UNKNOWN), + m_NexusBridge(&core.pluginContainer()) { m_CreationTime = QFileInfo(path.absolutePath()).birthTime(); // read out the meta-file for information @@ -48,28 +44,29 @@ ModInfoRegular::ModInfoRegular(const QDir &path, OrganizerCore& core) if (!core.managedGame()->primarySources().contains(m_GameName, Qt::CaseInsensitive)) m_IsAlternate = true; - //populate m_Archives + // populate m_Archives m_Archives = QStringList(); if (Settings::instance().archiveParsing()) { archives(true); } - connect(&m_NexusBridge, SIGNAL(descriptionAvailable(QString,int,QVariant,QVariant)) - , this, SLOT(nxmDescriptionAvailable(QString,int,QVariant,QVariant))); - connect(&m_NexusBridge, SIGNAL(endorsementToggled(QString,int,QVariant,QVariant)) - , this, SLOT(nxmEndorsementToggled(QString,int,QVariant,QVariant))); - connect(&m_NexusBridge, SIGNAL(trackingToggled(QString,int,QVariant,bool)) - , this, SLOT(nxmTrackingToggled(QString,int,QVariant,bool))); - connect(&m_NexusBridge, SIGNAL(requestFailed(QString,int,int,QVariant,int,QString)) - , this, SLOT(nxmRequestFailed(QString,int,int,QVariant,int,QString))); + connect(&m_NexusBridge, + SIGNAL(descriptionAvailable(QString, int, QVariant, QVariant)), this, + SLOT(nxmDescriptionAvailable(QString, int, QVariant, QVariant))); + connect(&m_NexusBridge, SIGNAL(endorsementToggled(QString, int, QVariant, QVariant)), + this, SLOT(nxmEndorsementToggled(QString, int, QVariant, QVariant))); + connect(&m_NexusBridge, SIGNAL(trackingToggled(QString, int, QVariant, bool)), this, + SLOT(nxmTrackingToggled(QString, int, QVariant, bool))); + connect(&m_NexusBridge, + SIGNAL(requestFailed(QString, int, int, QVariant, int, QString)), this, + SLOT(nxmRequestFailed(QString, int, int, QVariant, int, QString))); } - ModInfoRegular::~ModInfoRegular() { try { saveMeta(); - } catch (const std::exception &e) { + } catch (const std::exception& e) { log::error("failed to save meta information for \"{}\": {}", m_Name, e.what()); } } @@ -77,21 +74,23 @@ ModInfoRegular::~ModInfoRegular() bool ModInfoRegular::isEmpty() const { QDirIterator iter(m_Path, QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs); - if (!iter.hasNext()) return true; + if (!iter.hasNext()) + return true; iter.next(); - if ((iter.fileName() == "meta.ini") && !iter.hasNext()) return true; + if ((iter.fileName() == "meta.ini") && !iter.hasNext()) + return true; return false; } - void ModInfoRegular::readMeta() { QSettings metaFile(m_Path + "/meta.ini", QSettings::IniFormat); - m_Comments = metaFile.value("comments", "").toString(); - m_Notes = metaFile.value("notes", "").toString(); + m_Comments = metaFile.value("comments", "").toString(); + m_Notes = metaFile.value("notes", "").toString(); QString tempGameName = metaFile.value("gameName", m_GameName).toString(); - if (tempGameName.size()) m_GameName = tempGameName; - m_NexusID = metaFile.value("modid", -1).toInt(); + if (tempGameName.size()) + m_GameName = tempGameName; + m_NexusID = metaFile.value("modid", -1).toInt(); m_Version.parse(metaFile.value("version", "").toString()); m_NewestVersion = metaFile.value("newestVersion", "").toString(); m_IgnoredVersion = metaFile.value("ignoredVersion", "").toString(); @@ -165,36 +164,54 @@ void ModInfoRegular::readMeta() } } - m_LastNexusQuery = QDateTime::fromString(metaFile.value("lastNexusQuery", "").toString(), Qt::ISODate); - m_LastNexusUpdate = QDateTime::fromString(metaFile.value("lastNexusUpdate", "").toString(), Qt::ISODate); - m_NexusLastModified = QDateTime::fromString(metaFile.value("nexusLastModified", QDateTime::currentDateTimeUtc()).toString(), Qt::ISODate); - m_Color = metaFile.value("color",QColor()).value<QColor>(); - m_TrackedState = metaFile.value("tracked", false).toBool() ? TrackedState::TRACKED_TRUE : TrackedState::TRACKED_FALSE; + m_LastNexusQuery = QDateTime::fromString( + metaFile.value("lastNexusQuery", "").toString(), Qt::ISODate); + m_LastNexusUpdate = QDateTime::fromString( + metaFile.value("lastNexusUpdate", "").toString(), Qt::ISODate); + m_NexusLastModified = QDateTime::fromString( + metaFile.value("nexusLastModified", QDateTime::currentDateTimeUtc()).toString(), + Qt::ISODate); + m_Color = metaFile.value("color", QColor()).value<QColor>(); + m_TrackedState = metaFile.value("tracked", false).toBool() + ? TrackedState::TRACKED_TRUE + : TrackedState::TRACKED_FALSE; if (metaFile.contains("endorsed")) { if (metaFile.value("endorsed").canConvert<int>()) { using ut = std::underlying_type_t<EndorsedState>; switch (metaFile.value("endorsed").toInt()) { - case static_cast<ut>(EndorsedState::ENDORSED_FALSE): m_EndorsedState = EndorsedState::ENDORSED_FALSE; break; - case static_cast<ut>(EndorsedState::ENDORSED_TRUE): m_EndorsedState = EndorsedState::ENDORSED_TRUE; break; - case static_cast<ut>(EndorsedState::ENDORSED_NEVER): m_EndorsedState = EndorsedState::ENDORSED_NEVER; break; - default: m_EndorsedState = EndorsedState::ENDORSED_UNKNOWN; break; + case static_cast<ut>(EndorsedState::ENDORSED_FALSE): + m_EndorsedState = EndorsedState::ENDORSED_FALSE; + break; + case static_cast<ut>(EndorsedState::ENDORSED_TRUE): + m_EndorsedState = EndorsedState::ENDORSED_TRUE; + break; + case static_cast<ut>(EndorsedState::ENDORSED_NEVER): + m_EndorsedState = EndorsedState::ENDORSED_NEVER; + break; + default: + m_EndorsedState = EndorsedState::ENDORSED_UNKNOWN; + break; } } else { - m_EndorsedState = metaFile.value("endorsed", false).toBool() ? EndorsedState::ENDORSED_TRUE : EndorsedState::ENDORSED_FALSE; + m_EndorsedState = metaFile.value("endorsed", false).toBool() + ? EndorsedState::ENDORSED_TRUE + : EndorsedState::ENDORSED_FALSE; } } QString categoriesString = metaFile.value("category", "").toString(); QStringList categories = categoriesString.split(',', Qt::SkipEmptyParts); - for (QStringList::iterator iter = categories.begin(); iter != categories.end(); ++iter) { - bool ok = false; + for (QStringList::iterator iter = categories.begin(); iter != categories.end(); + ++iter) { + bool ok = false; int categoryID = iter->toInt(&ok); if (categoryID < 0) { // ignore invalid id continue; } - if (ok && (categoryID != 0) && (CategoryFactory::instance().categoryExists(categoryID))) { + if (ok && (categoryID != 0) && + (CategoryFactory::instance().categoryExists(categoryID))) { m_Categories.insert(categoryID); if (iter == categories.begin()) { m_PrimaryCategory = categoryID; @@ -205,13 +222,14 @@ void ModInfoRegular::readMeta() int numFiles = metaFile.beginReadArray("installedFiles"); for (int i = 0; i < numFiles; ++i) { metaFile.setArrayIndex(i); - m_InstalledFileIDs.insert(std::make_pair(metaFile.value("modid").toInt(), metaFile.value("fileid").toInt())); + m_InstalledFileIDs.insert(std::make_pair(metaFile.value("modid").toInt(), + metaFile.value("fileid").toInt())); } metaFile.endArray(); // Plugin settings: metaFile.beginGroup("Plugins"); - for (auto pluginName: metaFile.childGroups()) { + for (auto pluginName : metaFile.childGroups()) { metaFile.beginGroup(pluginName); for (auto settingKey : metaFile.childKeys()) { m_PluginSettings[pluginName][settingKey] = metaFile.value(settingKey); @@ -231,7 +249,8 @@ void ModInfoRegular::saveMeta() if (metaFile.status() == QSettings::NoError) { std::set<int> temp = m_Categories; temp.erase(m_PrimaryCategory); - metaFile.setValue("category", QString("%1").arg(m_PrimaryCategory) + "," + SetJoin(temp, ",")); + metaFile.setValue("category", QString("%1").arg(m_PrimaryCategory) + "," + + SetJoin(temp, ",")); metaFile.setValue("newestVersion", m_NewestVersion.canonicalString()); metaFile.setValue("ignoredVersion", m_IgnoredVersion.canonicalString()); metaFile.setValue("version", m_Version.canonicalString()); @@ -252,16 +271,20 @@ void ModInfoRegular::saveMeta() metaFile.setValue("validated", m_Validated); metaFile.setValue("color", m_Color); if (m_EndorsedState != EndorsedState::ENDORSED_UNKNOWN) { - metaFile.setValue("endorsed", static_cast<std::underlying_type_t<EndorsedState>>(m_EndorsedState)); + metaFile.setValue( + "endorsed", + static_cast<std::underlying_type_t<EndorsedState>>(m_EndorsedState)); } if (m_TrackedState != TrackedState::TRACKED_UNKNOWN) { - metaFile.setValue("tracked", static_cast<std::underlying_type_t<TrackedState>>(m_TrackedState)); + metaFile.setValue("tracked", static_cast<std::underlying_type_t<TrackedState>>( + m_TrackedState)); } metaFile.remove("installedFiles"); metaFile.beginWriteArray("installedFiles"); int idx = 0; - for (auto iter = m_InstalledFileIDs.begin(); iter != m_InstalledFileIDs.end(); ++iter) { + for (auto iter = m_InstalledFileIDs.begin(); iter != m_InstalledFileIDs.end(); + ++iter) { metaFile.setArrayIndex(idx++); metaFile.setValue("modid", iter->first); metaFile.setValue("fileid", iter->second); @@ -271,33 +294,30 @@ void ModInfoRegular::saveMeta() // Plugin settings: metaFile.remove("Plugins"); metaFile.beginGroup("Plugins"); - for (const auto& [pluginName, pluginSettings]: m_PluginSettings) { + for (const auto& [pluginName, pluginSettings] : m_PluginSettings) { metaFile.beginGroup(pluginName); - for (const auto& [settingName, settingValue]: pluginSettings) { + for (const auto& [settingName, settingValue] : pluginSettings) { metaFile.setValue(settingName, settingValue); } metaFile.endGroup(); } metaFile.endGroup(); - metaFile.sync(); // sync needs to be called to ensure the file is created + metaFile.sync(); // sync needs to be called to ensure the file is created if (metaFile.status() == QSettings::NoError) { m_MetaInfoChanged = false; } else { - log::error( - "failed to write {}/meta.ini: error {}", - absolutePath(), metaFile.status()); + log::error("failed to write {}/meta.ini: error {}", absolutePath(), + metaFile.status()); } } else { - log::error( - "failed to write {}/meta.ini: error {}", - absolutePath(), metaFile.status()); + log::error("failed to write {}/meta.ini: error {}", absolutePath(), + metaFile.status()); } } } - bool ModInfoRegular::updateAvailable() const { if (m_IgnoredVersion.isValid() && (m_IgnoredVersion == m_NewestVersion)) { @@ -309,7 +329,6 @@ bool ModInfoRegular::updateAvailable() const return m_NewestVersion.isValid() && (m_Version < m_NewestVersion); } - bool ModInfoRegular::downgradeAvailable() const { if (m_IgnoredVersion.isValid() && (m_IgnoredVersion == m_NewestVersion)) { @@ -318,14 +337,15 @@ bool ModInfoRegular::downgradeAvailable() const return m_NewestVersion.isValid() && (m_NewestVersion < m_Version); } - -void ModInfoRegular::nxmDescriptionAvailable(QString, int, QVariant, QVariant resultData) +void ModInfoRegular::nxmDescriptionAvailable(QString, int, QVariant, + QVariant resultData) { QVariantMap result = resultData.toMap(); setNexusDescription(result["description"].toString()); - if ((m_EndorsedState != EndorsedState::ENDORSED_NEVER) && (result.contains("endorsement"))) { - QVariantMap endorsement = result["endorsement"].toMap(); + if ((m_EndorsedState != EndorsedState::ENDORSED_NEVER) && + (result.contains("endorsement"))) { + QVariantMap endorsement = result["endorsement"].toMap(); QString endorsementStatus = endorsement["endorse_status"].toString(); if (endorsementStatus.compare("Endorsed", Qt::CaseInsensitive) == 00) setEndorsedState(EndorsedState::ENDORSED_TRUE); @@ -335,14 +355,14 @@ void ModInfoRegular::nxmDescriptionAvailable(QString, int, QVariant, QVariant re setEndorsedState(EndorsedState::ENDORSED_FALSE); } m_LastNexusQuery = QDateTime::currentDateTimeUtc(); - m_NexusLastModified = QDateTime::fromSecsSinceEpoch(result["updated_timestamp"].toInt(), Qt::UTC); + m_NexusLastModified = + QDateTime::fromSecsSinceEpoch(result["updated_timestamp"].toInt(), Qt::UTC); m_MetaInfoChanged = true; saveMeta(); disconnect(sender(), SIGNAL(descriptionAvailable(QString, int, QVariant, QVariant))); emit modDetailsUpdated(true); } - void ModInfoRegular::nxmEndorsementToggled(QString, int, QVariant, QVariant resultData) { QMap results = resultData.toMap(); @@ -358,7 +378,6 @@ void ModInfoRegular::nxmEndorsementToggled(QString, int, QVariant, QVariant resu emit modDetailsUpdated(true); } - void ModInfoRegular::nxmTrackingToggled(QString, int, QVariant, bool tracked) { if (tracked) @@ -370,12 +389,13 @@ void ModInfoRegular::nxmTrackingToggled(QString, int, QVariant, bool tracked) emit modDetailsUpdated(true); } - -void ModInfoRegular::nxmRequestFailed(QString, int, int, QVariant userData, int errorCode, const QString &errorMessage) +void ModInfoRegular::nxmRequestFailed(QString, int, int, QVariant userData, + int errorCode, const QString& errorMessage) { QString fullMessage = errorMessage; if (userData.canConvert<int>() && (userData.toInt() == 1)) { - fullMessage += "\nNexus will reject endorsements within 15 Minutes of a failed attempt, the error message may be misleading."; + fullMessage += "\nNexus will reject endorsements within 15 Minutes of a failed " + "attempt, the error message may be misleading."; } if (QApplication::activeWindow() != nullptr) { MessageDialog::showMessage(fullMessage, QApplication::activeWindow()); @@ -383,7 +403,6 @@ void ModInfoRegular::nxmRequestFailed(QString, int, int, QVariant userData, int emit modDetailsUpdated(false); } - bool ModInfoRegular::updateNXMInfo() { if (needsDescriptionUpdate()) { @@ -397,7 +416,7 @@ bool ModInfoRegular::updateNXMInfo() bool ModInfoRegular::needsDescriptionUpdate() const { if (m_NexusID > 0) { - QDateTime time = QDateTime::currentDateTimeUtc(); + QDateTime time = QDateTime::currentDateTimeUtc(); QDateTime target = m_LastNexusQuery.addDays(1); if (time >= target) { @@ -432,14 +451,14 @@ void ModInfoRegular::setCategory(int categoryID, bool active) } } - -bool ModInfoRegular::setName(const QString &name) +bool ModInfoRegular::setName(const QString& name) { if (name.contains('/') || name.contains('\\')) { return false; } - QString newPath = m_Path.mid(0).replace(m_Path.length() - m_Name.length(), m_Name.length(), name); + QString newPath = + m_Path.mid(0).replace(m_Path.length() - m_Name.length(), m_Name.length(), name); QDir modDir(m_Path.mid(0, m_Path.length() - m_Name.length())); if (m_Name.compare(name, Qt::CaseInsensitive) == 0) { @@ -452,7 +471,8 @@ bool ModInfoRegular::setName(const QString &name) return false; } if (!modDir.rename(tempName, name)) { - log::error("rename to final name failed after successful rename to intermediate name"); + log::error( + "rename to final name failed after successful rename to intermediate name"); modDir.rename(tempName, m_Name); return false; } @@ -477,7 +497,7 @@ bool ModInfoRegular::setName(const QString &name) std::sort(s_Collection.begin(), s_Collection.end(), ModInfo::ByName); updateIndices(); - } else { // otherwise mod isn't registered yet? + } else { // otherwise mod isn't registered yet? m_Name = name; m_Path = newPath; } @@ -485,56 +505,56 @@ bool ModInfoRegular::setName(const QString &name) return true; } -void ModInfoRegular::setComments(const QString &comments) +void ModInfoRegular::setComments(const QString& comments) { - m_Comments = comments; + m_Comments = comments; m_MetaInfoChanged = true; } -void ModInfoRegular::setNotes(const QString ¬es) +void ModInfoRegular::setNotes(const QString& notes) { - m_Notes = notes; + m_Notes = notes; m_MetaInfoChanged = true; } void ModInfoRegular::setGameName(const QString& gameName) { - m_GameName = gameName; + m_GameName = gameName; m_MetaInfoChanged = true; } void ModInfoRegular::setNexusID(int modID) { - m_NexusID = modID; + m_NexusID = modID; m_MetaInfoChanged = true; } -void ModInfoRegular::setVersion(const VersionInfo &version) +void ModInfoRegular::setVersion(const VersionInfo& version) { - m_Version = version; + m_Version = version; m_MetaInfoChanged = true; } -void ModInfoRegular::setNewestVersion(const VersionInfo &version) +void ModInfoRegular::setNewestVersion(const VersionInfo& version) { if (version != m_NewestVersion) { - m_NewestVersion = version; + m_NewestVersion = version; m_MetaInfoChanged = true; } } -void ModInfoRegular::setNexusDescription(const QString &description) +void ModInfoRegular::setNexusDescription(const QString& description) { if (qHash(description) != qHash(m_NexusDescription)) { m_NexusDescription = description; - m_MetaInfoChanged = true; + m_MetaInfoChanged = true; } } void ModInfoRegular::setEndorsedState(EndorsedState endorsedState) { if (endorsedState != m_EndorsedState) { - m_EndorsedState = endorsedState; + m_EndorsedState = endorsedState; m_MetaInfoChanged = true; } } @@ -542,15 +562,15 @@ void ModInfoRegular::setEndorsedState(EndorsedState endorsedState) void ModInfoRegular::setTrackedState(TrackedState trackedState) { if (trackedState != m_TrackedState) { - m_TrackedState = trackedState; + m_TrackedState = trackedState; m_MetaInfoChanged = true; } } -void ModInfoRegular::setInstallationFile(const QString &fileName) +void ModInfoRegular::setInstallationFile(const QString& fileName) { m_InstallationFile = fileName; - m_MetaInfoChanged = true; + m_MetaInfoChanged = true; } void ModInfoRegular::addNexusCategory(int categoryID) @@ -561,14 +581,15 @@ void ModInfoRegular::addNexusCategory(int categoryID) void ModInfoRegular::setIsEndorsed(bool endorsed) { if (m_EndorsedState != EndorsedState::ENDORSED_NEVER) { - m_EndorsedState = endorsed ? EndorsedState::ENDORSED_TRUE : EndorsedState::ENDORSED_FALSE; + m_EndorsedState = + endorsed ? EndorsedState::ENDORSED_TRUE : EndorsedState::ENDORSED_FALSE; m_MetaInfoChanged = true; } } void ModInfoRegular::setNeverEndorse() { - m_EndorsedState = EndorsedState::ENDORSED_NEVER; + m_EndorsedState = EndorsedState::ENDORSED_NEVER; m_MetaInfoChanged = true; } @@ -582,7 +603,7 @@ void ModInfoRegular::setIsTracked(bool tracked) void ModInfoRegular::setColor(QColor color) { - m_Color = color; + m_Color = color; m_MetaInfoChanged = true; } @@ -594,7 +615,8 @@ QColor ModInfoRegular::color() const void ModInfoRegular::endorse(bool doEndorse) { if (doEndorse != (m_EndorsedState == EndorsedState::ENDORSED_TRUE)) { - m_NexusBridge.requestToggleEndorsement(m_GameName, nexusId(), m_Version.canonicalString(), doEndorse, QVariant(1)); + m_NexusBridge.requestToggleEndorsement( + m_GameName, nexusId(), m_Version.canonicalString(), doEndorse, QVariant(1)); } } @@ -607,7 +629,7 @@ void ModInfoRegular::track(bool doTrack) void ModInfoRegular::markConverted(bool converted) { - m_Converted = converted; + m_Converted = converted; m_MetaInfoChanged = true; saveMeta(); emit modDetailsUpdated(true); @@ -615,7 +637,7 @@ void ModInfoRegular::markConverted(bool converted) void ModInfoRegular::markValidated(bool validated) { - m_Validated = validated; + m_Validated = validated; m_MetaInfoChanged = true; saveMeta(); emit modDetailsUpdated(true); @@ -638,7 +660,7 @@ void ModInfoRegular::ignoreUpdate(bool ignore) bool ModInfoRegular::canBeUpdated() const { - QDateTime now = QDateTime::currentDateTimeUtc(); + QDateTime now = QDateTime::currentDateTimeUtc(); QDateTime target = getExpires(); if (now >= target) return m_NexusID > 0; @@ -653,13 +675,11 @@ QDateTime ModInfoRegular::getExpires() const std::vector<ModInfo::EFlag> ModInfoRegular::getFlags() const { std::vector<ModInfo::EFlag> result = ModInfoWithConflictInfo::getFlags(); - if ((m_NexusID > 0) && - (endorsedState() == EndorsedState::ENDORSED_FALSE) && + if ((m_NexusID > 0) && (endorsedState() == EndorsedState::ENDORSED_FALSE) && Settings::instance().nexus().endorsementIntegration()) { result.push_back(ModInfo::FLAG_NOTENDORSED); } - if ((m_NexusID > 0) && - (trackedState() == TrackedState::TRACKED_TRUE) && + if ((m_NexusID > 0) && (trackedState() == TrackedState::TRACKED_TRUE) && Settings::instance().nexus().trackedIntegration()) { result.push_back(ModInfo::FLAG_TRACKED); } @@ -678,7 +698,6 @@ std::vector<ModInfo::EFlag> ModInfoRegular::getFlags() const return result; } - std::set<int> ModInfoRegular::doGetContents() const { ModDataContent* contentFeature = m_Core.managedGame()->feature<ModDataContent>(); @@ -691,33 +710,37 @@ std::set<int> ModInfoRegular::doGetContents() const return {}; } - int ModInfoRegular::getHighlight() const { if (!isValid() && !m_Validated) return HIGHLIGHT_INVALID; auto flags = getFlags(); - if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_PLUGIN_SELECTED) != flags.end()) + if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_PLUGIN_SELECTED) != + flags.end()) return HIGHLIGHT_PLUGIN; return HIGHLIGHT_NONE; } - QString ModInfoRegular::getDescription() const { - if (!isValid() && !m_Validated) { - return tr("%1 contains no esp/esm/esl and no asset (textures, meshes, interface, ...) directory").arg(name()); + if (!isValid() && !m_Validated) { + return tr("%1 contains no esp/esm/esl and no asset (textures, meshes, interface, " + "...) directory") + .arg(name()); } else { - const std::set<int> &categories = getCategories(); + const std::set<int>& categories = getCategories(); std::wostringstream categoryString; categoryString << ToWString(tr("Categories: <br>")); - CategoryFactory &categoryFactory = CategoryFactory::instance(); + CategoryFactory& categoryFactory = CategoryFactory::instance(); for (std::set<int>::const_iterator catIter = categories.begin(); catIter != categories.end(); ++catIter) { if (catIter != categories.begin()) { categoryString << " , "; } - categoryString << "<span style=\"white-space: nowrap;\"><i>" << ToWString(categoryFactory.getCategoryName(categoryFactory.getCategoryIndex(*catIter))) << "</font></span>"; + categoryString << "<span style=\"white-space: nowrap;\"><i>" + << ToWString(categoryFactory.getCategoryName( + categoryFactory.getCategoryIndex(*catIter))) + << "</font></span>"; } return ToQString(categoryString.str()); @@ -792,7 +815,7 @@ QDateTime ModInfoRegular::getLastNexusQuery() const void ModInfoRegular::setLastNexusQuery(QDateTime time) { - m_LastNexusQuery = time; + m_LastNexusQuery = time; m_MetaInfoChanged = true; saveMeta(); emit modDetailsUpdated(true); @@ -806,14 +829,14 @@ QDateTime ModInfoRegular::getNexusLastModified() const void ModInfoRegular::setNexusLastModified(QDateTime time) { m_NexusLastModified = time; - m_MetaInfoChanged = true; + m_MetaInfoChanged = true; saveMeta(); emit modDetailsUpdated(true); } -void ModInfoRegular::setCustomURL(QString const &url) +void ModInfoRegular::setCustomURL(QString const& url) { - m_CustomURL = url; + m_CustomURL = url; m_MetaInfoChanged = true; } @@ -824,7 +847,7 @@ QString ModInfoRegular::url() const void ModInfoRegular::setHasCustomURL(bool b) { - m_HasCustomURL = b; + m_HasCustomURL = b; m_MetaInfoChanged = true; } @@ -838,8 +861,8 @@ QStringList ModInfoRegular::archives(bool checkOnDisk) if (checkOnDisk) { QStringList result; QDir dir(this->absolutePath()); - QStringList bsaList = dir.entryList(QStringList({ "*.bsa", "*.ba2" })); - for (const QString &archive : bsaList) { + QStringList bsaList = dir.entryList(QStringList({"*.bsa", "*.ba2"})); + for (const QString& archive : bsaList) { result.append(this->absolutePath() + "/" + archive); } m_Archives = result; @@ -863,22 +886,22 @@ std::vector<QString> ModInfoRegular::getIniTweaks() const int numTweaks = metaFile.beginReadArray("INI Tweaks"); if (numTweaks != 0) { - log::debug( - "{} active ini tweaks in {}", - numTweaks, QDir::toNativeSeparators(metaFileName)); + log::debug("{} active ini tweaks in {}", numTweaks, + QDir::toNativeSeparators(metaFileName)); } for (int i = 0; i < numTweaks; ++i) { metaFile.setArrayIndex(i); - QString filename = absolutePath().append("/INI Tweaks/").append(metaFile.value("name").toString()); + QString filename = + absolutePath().append("/INI Tweaks/").append(metaFile.value("name").toString()); result.push_back(filename); } metaFile.endArray(); return result; } - -std::map<QString, QVariant> ModInfoRegular::pluginSettings(const QString& pluginName) const +std::map<QString, QVariant> +ModInfoRegular::pluginSettings(const QString& pluginName) const { auto itp = m_PluginSettings.find(pluginName); if (itp == std::end(m_PluginSettings)) { @@ -887,7 +910,8 @@ std::map<QString, QVariant> ModInfoRegular::pluginSettings(const QString& plugin return itp->second; } -QVariant ModInfoRegular::pluginSetting(const QString& pluginName, const QString& key, const QVariant& defaultValue) const +QVariant ModInfoRegular::pluginSetting(const QString& pluginName, const QString& key, + const QVariant& defaultValue) const { auto itp = m_PluginSettings.find(pluginName); if (itp == std::end(m_PluginSettings)) { @@ -902,15 +926,17 @@ QVariant ModInfoRegular::pluginSetting(const QString& pluginName, const QString& return its->second; } -bool ModInfoRegular::setPluginSetting(const QString& pluginName, const QString& key, const QVariant& value) +bool ModInfoRegular::setPluginSetting(const QString& pluginName, const QString& key, + const QVariant& value) { m_PluginSettings[pluginName][key] = value; - m_MetaInfoChanged = true; + m_MetaInfoChanged = true; saveMeta(); return true; } -std::map<QString, QVariant> ModInfoRegular::clearPluginSettings(const QString& pluginName) +std::map<QString, QVariant> +ModInfoRegular::clearPluginSettings(const QString& pluginName) { auto itp = m_PluginSettings.find(pluginName); if (itp == std::end(m_PluginSettings)) { diff --git a/src/modinforegular.h b/src/modinforegular.h index ef91ba69..6c85d66c 100644 --- a/src/modinforegular.h +++ b/src/modinforegular.h @@ -21,7 +21,6 @@ class ModInfoRegular : public ModInfoWithConflictInfo friend class ModInfo; public: - ~ModInfoRegular(); virtual bool isRegular() const override { return true; } @@ -36,8 +35,9 @@ public: * @brief test if there is a newer version of the mod * * test if there is a newer version of the mod. This does NOT cause - * information to be retrieved from the nexus, it will only test version information already - * available locally. Use checkAllForUpdate() to update this version information + * information to be retrieved from the nexus, it will only test version information + *already available locally. Use checkAllForUpdate() to update this version + *information * * @return true if there is a newer version **/ @@ -46,14 +46,18 @@ public: /** * @return true if the current update is being ignored */ - virtual bool updateIgnored() const override { return m_IgnoredVersion.isValid() && m_IgnoredVersion == m_NewestVersion; } + virtual bool updateIgnored() const override + { + return m_IgnoredVersion.isValid() && m_IgnoredVersion == m_NewestVersion; + } /** * @brief test if there is a newer version of the mod * * test if there is a newer version of the mod. This does NOT cause - * information to be retrieved from the nexus, it will only test version information already - * available locally. Use checkAllForUpdate() to update this version information + * information to be retrieved from the nexus, it will only test version information + *already available locally. Use checkAllForUpdate() to update this version + *information * * @return true if there is a newer version **/ @@ -65,7 +69,8 @@ public: * This requests mod information from the nexus. This is an asynchronous request, * so there is no immediate effect of this call. * - * @return returns true if information for this mod will be updated, false if there is no nexus mod id to use + * @return returns true if information for this mod will be updated, false if there is + *no nexus mod id to use **/ bool updateNXMInfo() override; @@ -76,7 +81,8 @@ public: * * @param categoryID id of the category to set * @param active determines wheter the category is assigned or unassigned - * @note this function does not test whether categoryID actually identifies a valid category + * @note this function does not test whether categoryID actually identifies a valid + *category **/ void setCategory(int categoryID, bool active) override; @@ -90,19 +96,20 @@ public: * @return true on success, false if the new name can't be used (i.e. because the new * directory name wouldn't be valid) **/ - bool setName(const QString &name) override; + bool setName(const QString& name) override; /** - * @brief changes the comments (manually set information displayed in the mod list) for this mod - * @param comments new comments - */ - void setComments(const QString &comments) override; + * @brief changes the comments (manually set information displayed in the mod list) + * for this mod + * @param comments new comments + */ + void setComments(const QString& comments) override; /** * @brief change the notes (manually set information) for this mod * @param notes new notes */ - void setNotes(const QString ¬es) override; + void setNotes(const QString& notes) override; /** * @brief set/change the source game of this mod @@ -126,7 +133,7 @@ public: * * @param version the new version to use **/ - void setVersion(const MOBase::VersionInfo &version) override; + void setVersion(const MOBase::VersionInfo& version) override; /** * @brief set the newest version of this mod on the nexus @@ -135,21 +142,22 @@ public: * updating the mod * * @param version the new version to use - * @todo this function should be made obsolete. All queries for mod information should go through - * this class so no public function for this change is required + * @todo this function should be made obsolete. All queries for mod information should + *go through this class so no public function for this change is required **/ - void setNewestVersion(const MOBase::VersionInfo &version) override; + void setNewestVersion(const MOBase::VersionInfo& version) override; /** * @brief changes/updates the nexus description text * @param description the current description text */ - virtual void setNexusDescription(const QString &description) override; + virtual void setNexusDescription(const QString& description) override; - virtual void setInstallationFile(const QString &fileName) override; + virtual void setInstallationFile(const QString& fileName) override; /** - * @brief sets the category id from a nexus category id. Conversion to MO id happens internally + * @brief sets the category id from a nexus category id. Conversion to MO id happens + * internally * @param categoryID the nexus category id * @note if a mapping is not possible, the category is set to the default value */ @@ -159,13 +167,20 @@ public: * @brief sets the new primary category of the mod * @param categoryID the category to set */ - virtual void setPrimaryCategory(int categoryID) override { m_PrimaryCategory = categoryID; m_MetaInfoChanged = true; } + virtual void setPrimaryCategory(int categoryID) override + { + m_PrimaryCategory = categoryID; + m_MetaInfoChanged = true; + } /** * @brief sets the download repository * @param repository */ - virtual void setRepository(const QString &repository) override { m_Repository = repository; } + virtual void setRepository(const QString& repository) override + { + m_Repository = repository; + } /** * update the endorsement state for the mod. This only changes the @@ -175,7 +190,8 @@ public: virtual void setIsEndorsed(bool endorsed) override; /** - * set the mod to "i don't intend to endorse". The mod will not show as unendorsed but can still be endorsed + * set the mod to "i don't intend to endorse". The mod will not show as unendorsed but + * can still be endorsed */ virtual void setNeverEndorse() override; @@ -194,20 +210,22 @@ public: virtual void endorse(bool doEndorse) override; /** - * @brief track or untrack the mod. This will sync with nexus! - * @param doTrack if true, the mod is tracked, if false, it's untracked. - * @note if doTrack doesn't differ from the current value, nothing happens. - */ + * @brief track or untrack the mod. This will sync with nexus! + * @param doTrack if true, the mod is tracked, if false, it's untracked. + * @note if doTrack doesn't differ from the current value, nothing happens. + */ virtual void track(bool doTrack) override; /** - * @brief updates the mod to flag it as converted in order to ignore the alternate game warning - */ + * @brief updates the mod to flag it as converted in order to ignore the alternate + * game warning + */ virtual void markConverted(bool converted) override; /** - * @brief updates the mod to flag it as valid in order to ignore the invalid game data flag - */ + * @brief updates the mod to flag it as valid in order to ignore the invalid game data + * flag + */ virtual void markValidated(bool validated) override; /** @@ -285,13 +303,11 @@ public: */ virtual QString getDescription() const override; - /** * @return the nexus file status (aka category ID) */ virtual int getNexusFileStatus() const override; - /** * @brief sets the file status (category ID) from Nexus * @param status the status id of the installed file @@ -299,8 +315,8 @@ public: virtual void setNexusFileStatus(int status) override; /** - * @return comments for this mod - */ + * @return comments for this mod + */ virtual QString comments() const override; /** @@ -380,42 +396,47 @@ public: virtual void setHasCustomURL(bool b) override; virtual bool hasCustomURL() const override; - virtual void setCustomURL(QString const &) override; + virtual void setCustomURL(QString const&) override; virtual QString url() const override; virtual QString gameName() const override { return m_GameName; } virtual QString installationFile() const override { return m_InstallationFile; } virtual bool converted() const override { return m_Converted; } virtual bool validated() const override { return m_Validated; } - virtual std::set<std::pair<int, int>> installedFiles() const override { return m_InstalledFileIDs; } - -public: // Plugin operations: + virtual std::set<std::pair<int, int>> installedFiles() const override + { + return m_InstalledFileIDs; + } - virtual QVariant pluginSetting(const QString& pluginName, const QString& key, const QVariant& defaultValue) const override; - virtual std::map<QString, QVariant> pluginSettings(const QString& pluginName) const override; - virtual bool setPluginSetting(const QString& pluginName, const QString& key, const QVariant& value) override; - virtual std::map<QString, QVariant> clearPluginSettings(const QString& pluginName) override; +public: // Plugin operations: + virtual QVariant pluginSetting(const QString& pluginName, const QString& key, + const QVariant& defaultValue) const override; + virtual std::map<QString, QVariant> + pluginSettings(const QString& pluginName) const override; + virtual bool setPluginSetting(const QString& pluginName, const QString& key, + const QVariant& value) override; + virtual std::map<QString, QVariant> + clearPluginSettings(const QString& pluginName) override; private: - void setEndorsedState(MOBase::EndorsedState endorsedState); void setTrackedState(MOBase::TrackedState trackedState); private slots: - void nxmDescriptionAvailable(QString, int modID, QVariant userData, QVariant resultData); + void nxmDescriptionAvailable(QString, int modID, QVariant userData, + QVariant resultData); void nxmEndorsementToggled(QString, int, QVariant userData, QVariant resultData); void nxmTrackingToggled(QString, int, QVariant userData, bool tracked); - void nxmRequestFailed(QString, int modID, int fileID, QVariant userData, int errorCode, const QString &errorMessage); + void nxmRequestFailed(QString, int modID, int fileID, QVariant userData, + int errorCode, const QString& errorMessage); protected: - virtual std::set<int> doGetContents() const override; ModInfoRegular(const QDir& path, OrganizerCore& core); private: - QString m_Name; QString m_Path; QString m_InstallationFile; @@ -432,7 +453,6 @@ private: mutable QStringList m_Archives; - QDateTime m_CreationTime; QDateTime m_LastNexusQuery; QDateTime m_LastNexusUpdate; @@ -462,5 +482,4 @@ private: bool needsDescriptionUpdate() const; }; - -#endif // MODINFOREGULAR_H +#endif // MODINFOREGULAR_H diff --git a/src/modinfoseparator.cpp b/src/modinfoseparator.cpp index 02a67ecd..a647c635 100644 --- a/src/modinfoseparator.cpp +++ b/src/modinfoseparator.cpp @@ -29,8 +29,6 @@ QString ModInfoSeparator::name() const return ModInfoRegular::name(); } - ModInfoSeparator::ModInfoSeparator(const QDir& path, OrganizerCore& core) - : ModInfoRegular(path, core) -{ -} + : ModInfoRegular(path, core) +{} diff --git a/src/modinfoseparator.h b/src/modinfoseparator.h index eaff7c42..c34dd92b 100644 --- a/src/modinfoseparator.h +++ b/src/modinfoseparator.h @@ -3,21 +3,19 @@ #include "modinforegular.h" -class ModInfoSeparator: - public ModInfoRegular +class ModInfoSeparator : public ModInfoRegular { Q_OBJECT; friend class ModInfo; public: - virtual bool updateAvailable() const override { return false; } virtual bool updateIgnored() const override { return false; } virtual bool downgradeAvailable() const override { return false; } virtual bool updateNXMInfo() override { return false; } virtual bool isValid() const override { return true; } - //TODO: Fix renaming method to avoid priority reset + // TODO: Fix renaming method to avoid priority reset virtual bool setName(const QString& name); virtual int nexusId() const override { return -1; } @@ -28,7 +26,10 @@ public: virtual bool canBeUpdated() const override { return false; } virtual QDateTime getExpires() const override { return QDateTime(); } virtual bool canBeEnabled() const override { return false; } - virtual std::vector<QString> getIniTweaks() const override { return std::vector<QString>(); } + virtual std::vector<QString> getIniTweaks() const override + { + return std::vector<QString>(); + } virtual std::vector<EFlag> getFlags() const override; virtual int getHighlight() const override; virtual QString getDescription() const override; @@ -46,14 +47,13 @@ public: virtual void setNexusLastModified(QDateTime) override {} virtual QDateTime creationTime() const override { return QDateTime(); } virtual QString getNexusDescription() const override { return QString(); } - virtual void addInstalledFile(int /*modId*/, int /*fileId*/) override { } + virtual void addInstalledFile(int /*modId*/, int /*fileId*/) override {} virtual bool isSeparator() const override { return true; } protected: virtual bool doIsValid() const override { return true; } private: - ModInfoSeparator(const QDir& path, OrganizerCore& core); }; diff --git a/src/modinfowithconflictinfo.cpp b/src/modinfowithconflictinfo.cpp index 7cdee6e6..8d496391 100644 --- a/src/modinfowithconflictinfo.cpp +++ b/src/modinfowithconflictinfo.cpp @@ -1,25 +1,33 @@ #include "modinfowithconflictinfo.h" -#include "utility.h" #include "shared/directoryentry.h" -#include "shared/filesorigin.h" #include "shared/fileentry.h" +#include "shared/filesorigin.h" +#include "utility.h" #include <filesystem> -#include "organizercore.h" #include "iplugingame.h" #include "moddatachecker.h" +#include "organizercore.h" #include "qdirfiletree.h" using namespace MOBase; using namespace MOShared; namespace fs = std::filesystem; -ModInfoWithConflictInfo::ModInfoWithConflictInfo(OrganizerCore& core) : - ModInfo(core), - m_FileTree([this]() { return QDirFileTree::makeTree(absolutePath()); }), - m_Valid([this]() { return doIsValid(); }), - m_Contents([this]() { return doGetContents(); }), - m_Conflicts([this]() { return doConflictCheck(); }) { } +ModInfoWithConflictInfo::ModInfoWithConflictInfo(OrganizerCore& core) + : ModInfo(core), m_FileTree([this]() { + return QDirFileTree::makeTree(absolutePath()); + }), + m_Valid([this]() { + return doIsValid(); + }), + m_Contents([this]() { + return doGetContents(); + }), + m_Conflicts([this]() { + return doConflictCheck(); + }) +{} void ModInfoWithConflictInfo::clearCaches() { @@ -39,66 +47,68 @@ std::vector<ModInfo::EConflictFlag> ModInfoWithConflictInfo::getConflictFlags() { std::vector<ModInfo::EConflictFlag> result; switch (isConflicted()) { - case CONFLICT_MIXED: { - result.push_back(ModInfo::FLAG_CONFLICT_MIXED); - } break; - case CONFLICT_OVERWRITE: { - result.push_back(ModInfo::FLAG_CONFLICT_OVERWRITE); - } break; - case CONFLICT_OVERWRITTEN: { - result.push_back(ModInfo::FLAG_CONFLICT_OVERWRITTEN); - } break; - case CONFLICT_REDUNDANT: { - result.push_back(ModInfo::FLAG_CONFLICT_REDUNDANT); - } break; - default: { /* NOP */ } + case CONFLICT_MIXED: { + result.push_back(ModInfo::FLAG_CONFLICT_MIXED); + } break; + case CONFLICT_OVERWRITE: { + result.push_back(ModInfo::FLAG_CONFLICT_OVERWRITE); + } break; + case CONFLICT_OVERWRITTEN: { + result.push_back(ModInfo::FLAG_CONFLICT_OVERWRITTEN); + } break; + case CONFLICT_REDUNDANT: { + result.push_back(ModInfo::FLAG_CONFLICT_REDUNDANT); + } break; + default: { /* NOP */ + } } switch (isLooseArchiveConflicted()) { - case CONFLICT_MIXED: { - result.push_back(ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITE); - result.push_back(ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITTEN); - } break; - case CONFLICT_OVERWRITE: { - result.push_back(ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITE); - } break; - case CONFLICT_OVERWRITTEN: { - result.push_back(ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITTEN); - } break; - default: { /* NOP */ } + case CONFLICT_MIXED: { + result.push_back(ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITE); + result.push_back(ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITTEN); + } break; + case CONFLICT_OVERWRITE: { + result.push_back(ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITE); + } break; + case CONFLICT_OVERWRITTEN: { + result.push_back(ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITTEN); + } break; + default: { /* NOP */ + } } switch (isArchiveConflicted()) { - case CONFLICT_MIXED: { - result.push_back(ModInfo::FLAG_ARCHIVE_CONFLICT_MIXED); - } break; - case CONFLICT_OVERWRITE: { - result.push_back(ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITE); - } break; - case CONFLICT_OVERWRITTEN: { - result.push_back(ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITTEN); - } break; - default: { /* NOP */ } + case CONFLICT_MIXED: { + result.push_back(ModInfo::FLAG_ARCHIVE_CONFLICT_MIXED); + } break; + case CONFLICT_OVERWRITE: { + result.push_back(ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITE); + } break; + case CONFLICT_OVERWRITTEN: { + result.push_back(ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITTEN); + } break; + default: { /* NOP */ + } } return result; } - ModInfoWithConflictInfo::Conflicts ModInfoWithConflictInfo::doConflictCheck() const { Conflicts conflicts; bool providesAnything = false; - bool hasHiddenFiles = false; + bool hasHiddenFiles = false; int dataID = 0; if (m_Core.directoryStructure()->originExists(L"data")) { dataID = m_Core.directoryStructure()->getOriginByName(L"data").getID(); } - std::wstring name = ToWString(this->name()); + std::wstring name = ToWString(this->name()); const std::wstring hideExt = ToWString(ModInfo::s_HiddenExt); if (m_Core.directoryStructure()->originExists(name)) { - FilesOrigin &origin = m_Core.directoryStructure()->getOriginByName(name); + FilesOrigin& origin = m_Core.directoryStructure()->getOriginByName(name); std::vector<FileEntryPtr> files = origin.getFiles(); std::set<const DirectoryEntry*> checkedDirs; @@ -111,8 +121,7 @@ ModInfoWithConflictInfo::Conflicts ModInfoWithConflictInfo::doConflictCheck() co if (nameAsPath.extension().wstring().compare(hideExt) == 0) { hasHiddenFiles = true; - } - else { + } else { const DirectoryEntry* parent = file->getParent(); // iterate on all parent direEntries to check for .mohiddden @@ -120,10 +129,10 @@ ModInfoWithConflictInfo::Conflicts ModInfoWithConflictInfo::doConflictCheck() co auto insertResult = checkedDirs.insert(parent); if (insertResult.second == false) { - // if already present break as we can assume to have checked the parents as well + // if already present break as we can assume to have checked the parents + // as well break; - } - else { + } else { const fs::path dirPath(parent->getName()); if (dirPath.extension().wstring().compare(hideExt) == 0) { hasHiddenFiles = true; @@ -155,15 +164,15 @@ ModInfoWithConflictInfo::Conflicts ModInfoWithConflictInfo::doConflictCheck() co // If this is not the origin then determine the correct overwrite if (file->getOrigin() != origin.getID()) { - FilesOrigin &altOrigin = m_Core.directoryStructure()->getOriginByID(file->getOrigin()); + FilesOrigin& altOrigin = + m_Core.directoryStructure()->getOriginByID(file->getOrigin()); unsigned int altIndex = ModInfo::getIndex(ToQString(altOrigin.getName())); if (!file->isFromArchive()) { if (!archiveData.isValid()) conflicts.m_OverwrittenList.insert(altIndex); else conflicts.m_ArchiveLooseOverwrittenList.insert(altIndex); - } - else { + } else { conflicts.m_ArchiveOverwrittenList.insert(altIndex); } } else { @@ -172,8 +181,10 @@ ModInfoWithConflictInfo::Conflicts ModInfoWithConflictInfo::doConflictCheck() co // Sort out the alternatives for (const auto& altInfo : alternatives) { - if ((altInfo.originID() != dataID) && (altInfo.originID() != origin.getID())) { - FilesOrigin &altOrigin = m_Core.directoryStructure()->getOriginByID(altInfo.originID()); + if ((altInfo.originID() != dataID) && + (altInfo.originID() != origin.getID())) { + FilesOrigin& altOrigin = + m_Core.directoryStructure()->getOriginByID(altInfo.originID()); QString altOriginName = ToQString(altOrigin.getName()); unsigned int altIndex = ModInfo::getIndex(altOriginName); if (!altInfo.isFromArchive()) { @@ -205,21 +216,24 @@ ModInfoWithConflictInfo::Conflicts ModInfoWithConflictInfo::doConflictCheck() co if (files.size() != 0) { if (!providesAnything) conflicts.m_CurrentConflictState = CONFLICT_REDUNDANT; - else if (!conflicts.m_OverwriteList.empty() && !conflicts.m_OverwrittenList.empty()) + else if (!conflicts.m_OverwriteList.empty() && + !conflicts.m_OverwrittenList.empty()) conflicts.m_CurrentConflictState = CONFLICT_MIXED; else if (!conflicts.m_OverwriteList.empty()) conflicts.m_CurrentConflictState = CONFLICT_OVERWRITE; else if (!conflicts.m_OverwrittenList.empty()) conflicts.m_CurrentConflictState = CONFLICT_OVERWRITTEN; - if (!conflicts.m_ArchiveOverwriteList.empty() && !conflicts.m_ArchiveOverwrittenList.empty()) + if (!conflicts.m_ArchiveOverwriteList.empty() && + !conflicts.m_ArchiveOverwrittenList.empty()) conflicts.m_ArchiveConflictState = CONFLICT_MIXED; else if (!conflicts.m_ArchiveOverwriteList.empty()) conflicts.m_ArchiveConflictState = CONFLICT_OVERWRITE; else if (!conflicts.m_ArchiveOverwrittenList.empty()) conflicts.m_ArchiveConflictState = CONFLICT_OVERWRITTEN; - if (!conflicts.m_ArchiveLooseOverwrittenList.empty() && !conflicts.m_ArchiveLooseOverwriteList.empty()) + if (!conflicts.m_ArchiveLooseOverwrittenList.empty() && + !conflicts.m_ArchiveLooseOverwriteList.empty()) conflicts.m_ArchiveConflictLooseState = CONFLICT_MIXED; else if (!conflicts.m_ArchiveLooseOverwrittenList.empty()) conflicts.m_ArchiveConflictLooseState = CONFLICT_OVERWRITTEN; @@ -238,24 +252,25 @@ ModInfoWithConflictInfo::EConflictType ModInfoWithConflictInfo::isConflicted() c return m_Conflicts.value().m_CurrentConflictState; } -ModInfoWithConflictInfo::EConflictType ModInfoWithConflictInfo::isArchiveConflicted() const +ModInfoWithConflictInfo::EConflictType +ModInfoWithConflictInfo::isArchiveConflicted() const { return m_Conflicts.value().m_ArchiveConflictState; } -ModInfoWithConflictInfo::EConflictType ModInfoWithConflictInfo::isLooseArchiveConflicted() const +ModInfoWithConflictInfo::EConflictType +ModInfoWithConflictInfo::isLooseArchiveConflicted() const { return m_Conflicts.value().m_ArchiveConflictLooseState; } - bool ModInfoWithConflictInfo::isRedundant() const { std::wstring name = ToWString(this->name()); if (m_Core.directoryStructure()->originExists(name)) { - FilesOrigin &origin = m_Core.directoryStructure()->getOriginByName(name); + FilesOrigin& origin = m_Core.directoryStructure()->getOriginByName(name); std::vector<FileEntryPtr> files = origin.getFiles(); - bool ignore = false; + bool ignore = false; for (auto iter = files.begin(); iter != files.end(); ++iter) { if ((*iter)->getOrigin(ignore) == origin.getID()) { return false; @@ -267,25 +282,27 @@ bool ModInfoWithConflictInfo::isRedundant() const } } - bool ModInfoWithConflictInfo::hasHiddenFiles() const { return m_Conflicts.value().m_HasHiddenFiles; } -void ModInfoWithConflictInfo::diskContentModified() { +void ModInfoWithConflictInfo::diskContentModified() +{ m_FileTree.invalidate(); m_Valid.invalidate(); m_Contents.invalidate(); } -void ModInfoWithConflictInfo::prefetch() { +void ModInfoWithConflictInfo::prefetch() +{ // Populating the tree to 1-depth (IFileTree is lazy, so size() forces the // tree to populate the first level): fileTree()->size(); } -bool ModInfoWithConflictInfo::doIsValid() const { +bool ModInfoWithConflictInfo::doIsValid() const +{ auto mdc = m_Core.managedGame()->feature<ModDataChecker>(); if (mdc) { @@ -296,19 +313,24 @@ bool ModInfoWithConflictInfo::doIsValid() const { return true; } -std::shared_ptr<const IFileTree> ModInfoWithConflictInfo::fileTree() const { +std::shared_ptr<const IFileTree> ModInfoWithConflictInfo::fileTree() const +{ return m_FileTree.value(); } -bool ModInfoWithConflictInfo::isValid() const { +bool ModInfoWithConflictInfo::isValid() const +{ return m_Valid.value(); } -const std::set<int>& ModInfoWithConflictInfo::getContents() const { +const std::set<int>& ModInfoWithConflictInfo::getContents() const +{ return m_Contents.value(); } -bool ModInfoWithConflictInfo::hasContent(int content) const { +bool ModInfoWithConflictInfo::hasContent(int content) const +{ auto& contents = m_Contents.value(); - return std::find(std::begin(contents), std::end(contents), content) != std::end(contents); + return std::find(std::begin(contents), std::end(contents), content) != + std::end(contents); } diff --git a/src/modinfowithconflictinfo.h b/src/modinfowithconflictinfo.h index 2136e093..c1d7a945 100644 --- a/src/modinfowithconflictinfo.h +++ b/src/modinfowithconflictinfo.h @@ -6,19 +6,19 @@ #include "memoizedlock.h" #include "modinfo.h" -#include <set> #include <QTime> +#include <set> class ModInfoWithConflictInfo : public ModInfo { public: - std::vector<ModInfo::EConflictFlag> getConflictFlags() const override; virtual std::vector<ModInfo::EFlag> getFlags() const override; /** - * @return true if this mod is considered "valid", that is: it contains data used by the game + * @return true if this mod is considered "valid", that is: it contains data used by + *the game **/ virtual bool isValid() const override; @@ -48,18 +48,35 @@ public: std::shared_ptr<const MOBase::IFileTree> fileTree() const override; public: - /** * @brief clear all caches held for this mod */ void clearCaches() override; - const std::set<unsigned int>& getModOverwrite() const override { return m_Conflicts.value().m_OverwriteList; } - const std::set<unsigned int>& getModOverwritten() const override { return m_Conflicts.value().m_OverwrittenList; } - const std::set<unsigned int>& getModArchiveOverwrite() const override { return m_Conflicts.value().m_ArchiveOverwriteList; } - const std::set<unsigned int>& getModArchiveOverwritten() const override { return m_Conflicts.value().m_ArchiveOverwrittenList; } - const std::set<unsigned int>& getModArchiveLooseOverwrite() const override { return m_Conflicts.value().m_ArchiveLooseOverwriteList; } - const std::set<unsigned int>& getModArchiveLooseOverwritten() const override { return m_Conflicts.value().m_ArchiveLooseOverwrittenList; } + const std::set<unsigned int>& getModOverwrite() const override + { + return m_Conflicts.value().m_OverwriteList; + } + const std::set<unsigned int>& getModOverwritten() const override + { + return m_Conflicts.value().m_OverwrittenList; + } + const std::set<unsigned int>& getModArchiveOverwrite() const override + { + return m_Conflicts.value().m_ArchiveOverwriteList; + } + const std::set<unsigned int>& getModArchiveOverwritten() const override + { + return m_Conflicts.value().m_ArchiveOverwrittenList; + } + const std::set<unsigned int>& getModArchiveLooseOverwrite() const override + { + return m_Conflicts.value().m_ArchiveLooseOverwriteList; + } + const std::set<unsigned int>& getModArchiveLooseOverwritten() const override + { + return m_Conflicts.value().m_ArchiveLooseOverwrittenList; + } public slots: @@ -69,7 +86,6 @@ public slots: virtual void diskContentModified(); protected: - // check if the content of this mod is valid // virtual bool doIsValid() const; @@ -84,8 +100,8 @@ protected: ModInfoWithConflictInfo(OrganizerCore& core); private: - - enum EConflictType { + enum EConflictType + { CONFLICT_NONE, CONFLICT_OVERWRITE, CONFLICT_OVERWRITTEN, @@ -95,7 +111,6 @@ private: }; private: - /** * @return true if there is a conflict for files in this mod */ @@ -119,7 +134,6 @@ private: bool hasHiddenFiles() const; protected: - /** * @brief Prefetch content for this mod. * @@ -130,20 +144,26 @@ protected: virtual void prefetch() override; private: - - struct Conflicts { - EConflictType m_CurrentConflictState = CONFLICT_NONE; - EConflictType m_ArchiveConflictState = CONFLICT_NONE; + struct Conflicts + { + EConflictType m_CurrentConflictState = CONFLICT_NONE; + EConflictType m_ArchiveConflictState = CONFLICT_NONE; EConflictType m_ArchiveConflictLooseState = CONFLICT_NONE; - bool m_HasLooseOverwrite = false; - bool m_HasHiddenFiles = false; + bool m_HasLooseOverwrite = false; + bool m_HasHiddenFiles = false; - std::set<unsigned int> m_OverwriteList; // indices of mods overritten by this mod - std::set<unsigned int> m_OverwrittenList; // indices of mods overwriting this mod - std::set<unsigned int> m_ArchiveOverwriteList; // indices of mods with archive files overritten by this mod - std::set<unsigned int> m_ArchiveOverwrittenList; // indices of mods with archive files overwriting this mod - std::set<unsigned int> m_ArchiveLooseOverwriteList; // indices of mods with archives being overwritten by this mod's loose files - std::set<unsigned int> m_ArchiveLooseOverwrittenList; // indices of mods with loose files overwriting this mod's archive files + std::set<unsigned int> m_OverwriteList; // indices of mods overritten by this mod + std::set<unsigned int> m_OverwrittenList; // indices of mods overwriting this mod + std::set<unsigned int> m_ArchiveOverwriteList; // indices of mods with archive + // files overritten by this mod + std::set<unsigned int> m_ArchiveOverwrittenList; // indices of mods with archive + // files overwriting this mod + std::set<unsigned int> + m_ArchiveLooseOverwriteList; // indices of mods with archives being overwritten + // by this mod's loose files + std::set<unsigned int> + m_ArchiveLooseOverwrittenList; // indices of mods with loose files overwriting + // this mod's archive files }; Conflicts doConflictCheck() const; @@ -152,9 +172,6 @@ private: MOBase::MemoizedLocked<bool> m_Valid; MOBase::MemoizedLocked<std::set<int>> m_Contents; MOBase::MemoizedLocked<Conflicts> m_Conflicts; - }; - - -#endif // MODINFOWITHCONFLICTINFO_H +#endif // MODINFOWITHCONFLICTINFO_H diff --git a/src/modlist.cpp b/src/modlist.cpp index b84e90fe..7a951369 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -19,57 +19,51 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "modlist.h" -#include "widgetutility.h" #include "messagedialog.h" -#include "qtgroupingproxy.h" -#include "viewmarkingscrollbar.h" +#include "modinforegular.h" +#include "modlistdropinfo.h" #include "modlistsortproxy.h" +#include "organizercore.h" #include "pluginlist.h" +#include "qtgroupingproxy.h" #include "settings.h" -#include "organizercore.h" -#include "modinforegular.h" -#include "modlistdropinfo.h" #include "shared/directoryentry.h" #include "shared/fileentry.h" #include "shared/filesorigin.h" +#include "viewmarkingscrollbar.h" +#include "widgetutility.h" -#include "shared/appconfig.h" #include "filesystemutilities.h" +#include "shared/appconfig.h" #include <report.h> -#include <QFileInfo> +#include <QAbstractItemView> +#include <QApplication> +#include <QCheckBox> +#include <QContextMenuEvent> #include <QDir> #include <QDirIterator> +#include <QEvent> +#include <QFileInfo> +#include <QFontDatabase> +#include <QMenu> +#include <QMessageBox> #include <QMimeData> +#include <QSortFilterProxyModel> #include <QStandardItemModel> -#include <QMessageBox> #include <QStringList> -#include <QEvent> -#include <QContextMenuEvent> -#include <QMenu> -#include <QCheckBox> #include <QWidgetAction> -#include <QAbstractItemView> -#include <QSortFilterProxyModel> -#include <QApplication> -#include <QFontDatabase> +#include <algorithm> #include <sstream> #include <stdexcept> -#include <algorithm> - using namespace MOBase; -ModList::ModList(PluginContainer *pluginContainer, OrganizerCore *organizer) - : QAbstractItemModel(organizer) - , m_Organizer(organizer) - , m_Profile(nullptr) - , m_NexusInterface(nullptr) - , m_Modified(false) - , m_InNotifyChange(false) - , m_FontMetrics(QFont()) - , m_PluginContainer(pluginContainer) +ModList::ModList(PluginContainer* pluginContainer, OrganizerCore* organizer) + : QAbstractItemModel(organizer), m_Organizer(organizer), m_Profile(nullptr), + m_NexusInterface(nullptr), m_Modified(false), m_InNotifyChange(false), + m_FontMetrics(QFont()), m_PluginContainer(pluginContainer) { m_LastCheck.start(); } @@ -82,12 +76,12 @@ ModList::~ModList() m_ModMoved.disconnect_all_slots(); } -void ModList::setProfile(Profile *profile) +void ModList::setProfile(Profile* profile) { m_Profile = profile; } -int ModList::rowCount(const QModelIndex &parent) const +int ModList::rowCount(const QModelIndex& parent) const { if (!parent.isValid()) { return ModInfo::getNumMods(); @@ -96,7 +90,7 @@ int ModList::rowCount(const QModelIndex &parent) const } } -bool ModList::hasChildren(const QModelIndex &parent) const +bool ModList::hasChildren(const QModelIndex& parent) const { if (!parent.isValid()) { return ModInfo::getNumMods() > 0; @@ -105,8 +99,7 @@ bool ModList::hasChildren(const QModelIndex &parent) const } } - -int ModList::columnCount(const QModelIndex &) const +int ModList::columnCount(const QModelIndex&) const { return COL_LASTCOLUMN + 1; } @@ -131,221 +124,212 @@ QString ModList::makeInternalName(ModInfo::Ptr info, QString name) const QString ModList::getFlagText(ModInfo::EFlag flag, ModInfo::Ptr modInfo) const { switch (flag) { - case ModInfo::FLAG_BACKUP: return tr("Backup"); - case ModInfo::FLAG_SEPARATOR: return tr("Separator"); - case ModInfo::FLAG_INVALID: return tr("No valid game data"); - case ModInfo::FLAG_NOTENDORSED: return tr("Not endorsed yet"); - case ModInfo::FLAG_NOTES: { - QStringList output; - if (!modInfo->comments().isEmpty()) - output << QString("<i>%1</i>").arg(modInfo->comments()); - if (!modInfo->notes().isEmpty()) - output << QString("<i>%1</i>").arg(modInfo->notes()); - return output.join(""); - } - case ModInfo::FLAG_ALTERNATE_GAME: return tr("This mod is for a different<br> game, " - "make sure it's compatible or it could cause crashes."); - case ModInfo::FLAG_TRACKED: return tr("Mod is being tracked on the website"); - case ModInfo::FLAG_HIDDEN_FILES: return tr("Contains hidden files"); - default: return ""; + case ModInfo::FLAG_BACKUP: + return tr("Backup"); + case ModInfo::FLAG_SEPARATOR: + return tr("Separator"); + case ModInfo::FLAG_INVALID: + return tr("No valid game data"); + case ModInfo::FLAG_NOTENDORSED: + return tr("Not endorsed yet"); + case ModInfo::FLAG_NOTES: { + QStringList output; + if (!modInfo->comments().isEmpty()) + output << QString("<i>%1</i>").arg(modInfo->comments()); + if (!modInfo->notes().isEmpty()) + output << QString("<i>%1</i>").arg(modInfo->notes()); + return output.join(""); + } + case ModInfo::FLAG_ALTERNATE_GAME: + return tr("This mod is for a different<br> game, " + "make sure it's compatible or it could cause crashes."); + case ModInfo::FLAG_TRACKED: + return tr("Mod is being tracked on the website"); + case ModInfo::FLAG_HIDDEN_FILES: + return tr("Contains hidden files"); + default: + return ""; } } - -QString ModList::getConflictFlagText(ModInfo::EConflictFlag flag, ModInfo::Ptr modInfo) const +QString ModList::getConflictFlagText(ModInfo::EConflictFlag flag, + ModInfo::Ptr modInfo) const { switch (flag) { - case ModInfo::FLAG_CONFLICT_OVERWRITE: return tr("Overwrites loose files"); - case ModInfo::FLAG_CONFLICT_OVERWRITTEN: return tr("Overwritten loose files"); - case ModInfo::FLAG_CONFLICT_MIXED: return tr("Loose files Overwrites & Overwritten"); - case ModInfo::FLAG_CONFLICT_REDUNDANT: return tr("Redundant"); - case ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITE: return tr("Overwrites an archive with loose files"); - case ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITTEN: return tr("Archive is overwritten by loose files"); - case ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITE: return tr("Overwrites another archive file"); - case ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITTEN: return tr("Overwritten by another archive file"); - case ModInfo::FLAG_ARCHIVE_CONFLICT_MIXED: return tr("Archive files overwrites & overwritten"); - default: return ""; + case ModInfo::FLAG_CONFLICT_OVERWRITE: + return tr("Overwrites loose files"); + case ModInfo::FLAG_CONFLICT_OVERWRITTEN: + return tr("Overwritten loose files"); + case ModInfo::FLAG_CONFLICT_MIXED: + return tr("Loose files Overwrites & Overwritten"); + case ModInfo::FLAG_CONFLICT_REDUNDANT: + return tr("Redundant"); + case ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITE: + return tr("Overwrites an archive with loose files"); + case ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITTEN: + return tr("Archive is overwritten by loose files"); + case ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITE: + return tr("Overwrites another archive file"); + case ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITTEN: + return tr("Overwritten by another archive file"); + case ModInfo::FLAG_ARCHIVE_CONFLICT_MIXED: + return tr("Archive files overwrites & overwritten"); + default: + return ""; } } -QVariant ModList::data(const QModelIndex &modelIndex, int role) const +QVariant ModList::data(const QModelIndex& modelIndex, int role) const { - if (m_Profile == nullptr) return QVariant(); - if (!modelIndex.isValid()) return QVariant(); + if (m_Profile == nullptr) + return QVariant(); + if (!modelIndex.isValid()) + return QVariant(); unsigned int modIndex = modelIndex.row(); - int column = modelIndex.column(); + int column = modelIndex.column(); ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex); - if ((role == Qt::DisplayRole) || - (role == Qt::EditRole)) { - if ((column == COL_FLAGS) - || (column == COL_CONTENT) - || (column == COL_CONFLICTFLAGS)) { + if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) { + if ((column == COL_FLAGS) || (column == COL_CONTENT) || + (column == COL_CONFLICTFLAGS)) { return QVariant(); - } - else if (column == COL_NAME) { + } else if (column == COL_NAME) { return getDisplayName(modInfo); - } - else if (column == COL_VERSION) { + } else if (column == COL_VERSION) { VersionInfo verInfo = modInfo->version(); - QString version = verInfo.displayString(); + QString version = verInfo.displayString(); if (role != Qt::EditRole) { if (version.isEmpty() && modInfo->canBeUpdated()) { version = "?"; } } return version; - } - else if (column == COL_PRIORITY) { + } else if (column == COL_PRIORITY) { if (modInfo->hasAutomaticPriority()) { - return QVariant(); // hide priority for mods where it's fixed - } - else { + return QVariant(); // hide priority for mods where it's fixed + } else { return m_Profile->getModPriority(modIndex); } - } - else if (column == COL_MODID) { + } else if (column == COL_MODID) { int modID = modInfo->nexusId(); if (modID > 0) { return modID; - } - else { + } else { return QVariant(); } - } - else if (column == COL_GAME) { + } else if (column == COL_GAME) { if (m_PluginContainer != nullptr) { for (auto game : m_PluginContainer->plugins<IPluginGame>()) { - if (game->gameShortName().compare(modInfo->gameName(), Qt::CaseInsensitive) == 0) + if (game->gameShortName().compare(modInfo->gameName(), Qt::CaseInsensitive) == + 0) return game->gameName(); } } return modInfo->gameName(); - } - else if (column == COL_CATEGORY) { + } else if (column == COL_CATEGORY) { if (modInfo->hasFlag(ModInfo::FLAG_FOREIGN)) { return tr("Non-MO"); - } - else { + } else { int category = modInfo->primaryCategory(); if (category != -1) { - CategoryFactory &categoryFactory = CategoryFactory::instance(); + CategoryFactory& categoryFactory = CategoryFactory::instance(); if (categoryFactory.categoryExists(category)) { try { int categoryIdx = categoryFactory.getCategoryIndex(category); return categoryFactory.getCategoryName(categoryIdx); - } - catch (const std::exception &e) { + } catch (const std::exception& e) { log::error("failed to retrieve category name: {}", e.what()); return QString(); } - } - else { + } else { log::warn("category {} doesn't exist (may have been removed)", category); modInfo->setCategory(category, false); return QString(); } - } - else { + } else { return QVariant(); } } - } - else if (column == COL_INSTALLTIME) { + } else if (column == COL_INSTALLTIME) { // display installation time for mods that can be updated if (modInfo->creationTime().isValid()) { return modInfo->creationTime(); - } - else { + } else { return QVariant(); } - } - else if (column == COL_NOTES) { + } else if (column == COL_NOTES) { return modInfo->comments(); - } - else { + } else { return tr("invalid"); } - } - else if ((role == Qt::CheckStateRole) && (column == 0)) { + } else if ((role == Qt::CheckStateRole) && (column == 0)) { if (modInfo->canBeEnabled()) { return m_Profile->modEnabled(modIndex) ? Qt::Checked : Qt::Unchecked; - } - else { + } else { return QVariant(); } - } - else if (role == Qt::TextAlignmentRole) { + } else if (role == Qt::TextAlignmentRole) { if (column == COL_NAME) { if (modInfo->getHighlight() & ModInfo::HIGHLIGHT_CENTER) { return QVariant(Qt::AlignCenter | Qt::AlignVCenter); - } - else { + } else { return QVariant(Qt::AlignLeft | Qt::AlignVCenter); } - } - else if (column == COL_VERSION) { + } else if (column == COL_VERSION) { return QVariant(Qt::AlignRight | Qt::AlignVCenter); - } - else if (column == COL_NOTES) { + } else if (column == COL_NOTES) { return QVariant(Qt::AlignLeft | Qt::AlignVCenter); - } - else { + } else { return QVariant(Qt::AlignCenter | Qt::AlignVCenter); } - } - else if (role == GroupingRole) { + } else if (role == GroupingRole) { if (column == COL_CATEGORY) { QVariantList categoryNames; - std::set<int> categories = modInfo->getCategories(); - CategoryFactory &categoryFactory = CategoryFactory::instance(); + std::set<int> categories = modInfo->getCategories(); + CategoryFactory& categoryFactory = CategoryFactory::instance(); for (auto iter = categories.begin(); iter != categories.end(); ++iter) { - categoryNames.append(categoryFactory.getCategoryName(categoryFactory.getCategoryIndex(*iter))); + categoryNames.append( + categoryFactory.getCategoryName(categoryFactory.getCategoryIndex(*iter))); } if (categoryNames.count() != 0) { return categoryNames; - } - else { + } else { return QVariant(); } - } - else { + } else { return modInfo->nexusId(); } - } - else if (role == IndexRole) { + } else if (role == IndexRole) { return modIndex; - } - else if (role == AggrRole) { + } else if (role == AggrRole) { switch (column) { - case COL_MODID: return QtGroupingProxy::AGGR_FIRST; - case COL_VERSION: return QtGroupingProxy::AGGR_MAX; - case COL_CATEGORY: return QtGroupingProxy::AGGR_FIRST; - case COL_PRIORITY: return QtGroupingProxy::AGGR_MIN; - default: return QtGroupingProxy::AGGR_NONE; + case COL_MODID: + return QtGroupingProxy::AGGR_FIRST; + case COL_VERSION: + return QtGroupingProxy::AGGR_MAX; + case COL_CATEGORY: + return QtGroupingProxy::AGGR_FIRST; + case COL_PRIORITY: + return QtGroupingProxy::AGGR_MIN; + default: + return QtGroupingProxy::AGGR_NONE; } - } - else if (role == GameNameRole) { + } else if (role == GameNameRole) { return modInfo->gameName(); - } - else if (role == PriorityRole) { + } else if (role == PriorityRole) { return m_Profile->getModPriority(modIndex); - } - else if (role == Qt::FontRole) { + } else if (role == Qt::FontRole) { QFont result; if (column == COL_NAME) { if (modInfo->isSeparator()) { result.setItalic(true); result.setBold(true); - } - else if (modInfo->getHighlight() & ModInfo::HIGHLIGHT_INVALID) { + } else if (modInfo->getHighlight() & ModInfo::HIGHLIGHT_INVALID) { result.setItalic(true); } - } - else if (column == COL_CATEGORY && modInfo->isForeign()) { + } else if (column == COL_CATEGORY && modInfo->isForeign()) { result.setItalic(true); - } - else if (column == COL_VERSION) { + } else if (column == COL_VERSION) { if (modInfo->updateAvailable() || modInfo->downgradeAvailable()) { result.setWeight(QFont::Bold); } @@ -354,148 +338,144 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const } } return result; - } - else if (role == Qt::DecorationRole) { + } else if (role == Qt::DecorationRole) { if (column == COL_VERSION) { if (modInfo->updateAvailable()) { return QIcon(":/MO/gui/update_available"); - } - else if (modInfo->downgradeAvailable()) { + } else if (modInfo->downgradeAvailable()) { return QIcon(":/MO/gui/warning"); - } - else if (modInfo->version().scheme() == VersionInfo::SCHEME_DATE) { + } else if (modInfo->version().scheme() == VersionInfo::SCHEME_DATE) { return QIcon(":/MO/gui/version_date"); } } return QVariant(); - } - else if (role == Qt::ForegroundRole) { + } else if (role == Qt::ForegroundRole) { if (column == COL_NAME) { int highlight = modInfo->getHighlight(); if (highlight & ModInfo::HIGHLIGHT_IMPORTANT) { return QBrush(Qt::darkRed); - } - else if (highlight & ModInfo::HIGHLIGHT_INVALID) { + } else if (highlight & ModInfo::HIGHLIGHT_INVALID) { return QBrush(Qt::darkGray); } - } - else if (column == COL_VERSION) { + } else if (column == COL_VERSION) { if (!modInfo->newestVersion().isValid()) { return QVariant(); - } - else if (modInfo->updateAvailable() || modInfo->downgradeAvailable()) { + } else if (modInfo->updateAvailable() || modInfo->downgradeAvailable()) { return QBrush(Qt::red); - } - else { + } else { return QBrush(Qt::darkGreen); } } return QVariant(); - } - else if (role == Qt::BackgroundRole || role == ScrollMarkRole) { + } else if (role == Qt::BackgroundRole || role == ScrollMarkRole) { if (column == COL_NOTES && modInfo->color().isValid()) { return modInfo->color(); - } - else if (modInfo->isSeparator() && modInfo->color().isValid() - && (role != ScrollMarkRole || Settings::instance().colors().colorSeparatorScrollbar())) { + } else if (modInfo->isSeparator() && modInfo->color().isValid() && + (role != ScrollMarkRole || + Settings::instance().colors().colorSeparatorScrollbar())) { return modInfo->color(); - } - else { + } else { return QVariant(); } - } - else if (role == Qt::ToolTipRole) { + } else if (role == Qt::ToolTipRole) { if (column == COL_FLAGS) { QString result; for (ModInfo::EFlag flag : modInfo->getFlags()) { - if (result.length() != 0) result += "<br>"; + if (result.length() != 0) + result += "<br>"; result += getFlagText(flag, modInfo); } return result; - } - else if (column == COL_CONFLICTFLAGS) { + } else if (column == COL_CONFLICTFLAGS) { QString result; for (ModInfo::EConflictFlag flag : modInfo->getConflictFlags()) { - if (result.length() != 0) result += "<br>"; + if (result.length() != 0) + result += "<br>"; result += getConflictFlagText(flag, modInfo); } return result; - } - else if (column == COL_NAME) { + } else if (column == COL_NAME) { try { return modInfo->getDescription(); - } - catch (const std::exception &e) { + } catch (const std::exception& e) { log::error("invalid mod description: {}", e.what()); return QString(); } - } - else if (column == COL_VERSION) { - QString text = tr("installed version: \"%1\", newest version: \"%2\"").arg(modInfo->version().displayString(3)).arg(modInfo->newestVersion().displayString(3)); + } else if (column == COL_VERSION) { + QString text = tr("installed version: \"%1\", newest version: \"%2\"") + .arg(modInfo->version().displayString(3)) + .arg(modInfo->newestVersion().displayString(3)); if (modInfo->downgradeAvailable()) { - text += "<br>" + tr("The newest version on Nexus seems to be older than the one you have installed. This could either mean the version you have has been withdrawn " - "(i.e. due to a bug) or the author uses a non-standard versioning scheme and that newest version is actually newer. " - "Either way you may want to \"upgrade\"."); + text += + "<br>" + tr("The newest version on Nexus seems to be older than the one " + "you have installed. This could either mean the version you " + "have has been withdrawn " + "(i.e. due to a bug) or the author uses a non-standard " + "versioning scheme and that newest version is actually newer. " + "Either way you may want to \"upgrade\"."); } if (modInfo->getNexusFileStatus() == NexusInterface::FileStatus::OLD_VERSION) { - text += "<br>" + tr("This file has been marked as \"Old\". There is most likely an updated version of this file available."); - } - else if (modInfo->getNexusFileStatus() == NexusInterface::FileStatus::REMOVED || - modInfo->getNexusFileStatus() == NexusInterface::FileStatus::ARCHIVED || - modInfo->getNexusFileStatus() == NexusInterface::FileStatus::ARCHIVED_HIDDEN) { - text += "<br>" + tr("This file has been marked as \"Deleted\"! You may want to check for an update or remove the nexus ID from this mod!"); + text += "<br>" + tr("This file has been marked as \"Old\". There is most " + "likely an updated version of this file available."); + } else if (modInfo->getNexusFileStatus() == NexusInterface::FileStatus::REMOVED || + modInfo->getNexusFileStatus() == + NexusInterface::FileStatus::ARCHIVED || + modInfo->getNexusFileStatus() == + NexusInterface::FileStatus::ARCHIVED_HIDDEN) { + text += + "<br>" + tr("This file has been marked as \"Deleted\"! You may want to " + "check for an update or remove the nexus ID from this mod!"); } if (modInfo->nexusId() > 0) { if (!modInfo->canBeUpdated()) { - qint64 remains = QDateTime::currentDateTimeUtc().secsTo(modInfo->getExpires()); + qint64 remains = + QDateTime::currentDateTimeUtc().secsTo(modInfo->getExpires()); qint64 minutes = remains / 60; qint64 seconds = remains % 60; - QString remainsStr(tr("%1 minute(s) and %2 second(s)").arg(minutes).arg(seconds)); - text += "<br>" + tr("This mod will be available to check in %2.") - .arg(remainsStr); + QString remainsStr( + tr("%1 minute(s) and %2 second(s)").arg(minutes).arg(seconds)); + text += + "<br>" + tr("This mod will be available to check in %2.").arg(remainsStr); } } return text; - } - else if (column == COL_CATEGORY) { - const std::set<int> &categories = modInfo->getCategories(); + } else if (column == COL_CATEGORY) { + const std::set<int>& categories = modInfo->getCategories(); std::wostringstream categoryString; categoryString << ToWString(tr("Categories: <br>")); - CategoryFactory &categoryFactory = CategoryFactory::instance(); + CategoryFactory& categoryFactory = CategoryFactory::instance(); for (std::set<int>::const_iterator catIter = categories.begin(); catIter != categories.end(); ++catIter) { if (catIter != categories.begin()) { categoryString << " , "; } try { - categoryString << "<span style=\"white-space: nowrap;\"><i>" << ToWString(categoryFactory.getCategoryName(categoryFactory.getCategoryIndex(*catIter))) << "</font></span>"; - } - catch (const std::exception &e) { + categoryString << "<span style=\"white-space: nowrap;\"><i>" + << ToWString(categoryFactory.getCategoryName( + categoryFactory.getCategoryIndex(*catIter))) + << "</font></span>"; + } catch (const std::exception& e) { log::error("failed to generate tooltip: {}", e.what()); return QString(); } } return ToQString(categoryString.str()); - } - else if (column == COL_NOTES) { + } else if (column == COL_NOTES) { return getFlagText(ModInfo::FLAG_NOTES, modInfo); - } - else { + } else { return QVariant(); } - } - else { + } else { return QVariant(); } } - -bool ModList::renameMod(int index, const QString &newName) +bool ModList::renameMod(int index, const QString& newName) { QString nameFixed = newName; if (!fixDirectoryName(nameFixed) || nameFixed.isEmpty()) { @@ -503,18 +483,18 @@ bool ModList::renameMod(int index, const QString &newName) return false; } - if (ModList::allMods().contains(nameFixed, Qt::CaseInsensitive) && nameFixed.toLower()!=ModInfo::getByIndex(index)->name().toLower() ) { - MessageDialog::showMessage(tr("Name is already in use by another mod"), nullptr); - return false; + if (ModList::allMods().contains(nameFixed, Qt::CaseInsensitive) && + nameFixed.toLower() != ModInfo::getByIndex(index)->name().toLower()) { + MessageDialog::showMessage(tr("Name is already in use by another mod"), nullptr); + return false; } ModInfo::Ptr modInfo = ModInfo::getByIndex(index); - QString oldName = modInfo->name(); + QString oldName = modInfo->name(); if (nameFixed != oldName) { // before we rename, ensure there is no scheduled asynchronous to rewrite m_Profile->cancelModlistWrite(); - if (modInfo->setName(nameFixed)) { // Notice there is a good chance that setName() updated the modinfo indexes // the modRenamed() call will refresh the indexes in the current profile @@ -528,9 +508,10 @@ bool ModList::renameMod(int index, const QString &newName) return true; } -bool ModList::setData(const QModelIndex &index, const QVariant &value, int role) +bool ModList::setData(const QModelIndex& index, const QVariant& value, int role) { - if (m_Profile == nullptr) return false; + if (m_Profile == nullptr) + return false; if (static_cast<unsigned int>(index.row()) >= ModInfo::getNumMods()) { return false; @@ -538,7 +519,7 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role) int modID = index.row(); - ModInfo::Ptr info = ModInfo::getByIndex(modID); + ModInfo::Ptr info = ModInfo::getByIndex(modID); IModList::ModStates oldState = state(modID); bool result = false; @@ -555,53 +536,51 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role) } result = true; emit dataChanged(index, index); - } - else if (role == Qt::EditRole) { + } else if (role == Qt::EditRole) { switch (index.column()) { - case COL_NAME: { - result = renameMod(modID, makeInternalName(info, value.toString())); - } break; - case COL_PRIORITY: { - bool ok = false; - int newPriority = value.toInt(&ok); - if (ok) { - changeModPriority(modID, newPriority); - result = true; - } else { - result = false; - } - } break; - case COL_MODID: { - bool ok = false; - int newID = value.toInt(&ok); - if (ok) { - info->setNexusID(newID); - emit tutorialModlistUpdate(); - result = true; - } else { - result = false; - } - } break; - case COL_VERSION: { - VersionInfo::VersionScheme scheme = info->version().scheme(); - VersionInfo version(value.toString(), scheme, true); - if (version.isValid()) { - info->setVersion(version); - result = true; - } else { - result = false; - } - } break; - case COL_NOTES: { - info->setComments(value.toString()); + case COL_NAME: { + result = renameMod(modID, makeInternalName(info, value.toString())); + } break; + case COL_PRIORITY: { + bool ok = false; + int newPriority = value.toInt(&ok); + if (ok) { + changeModPriority(modID, newPriority); result = true; - } break; - default: { - log::warn( - "edit on column \"{}\" not supported", - getColumnName(index.column()).toUtf8().constData()); + } else { result = false; - } break; + } + } break; + case COL_MODID: { + bool ok = false; + int newID = value.toInt(&ok); + if (ok) { + info->setNexusID(newID); + emit tutorialModlistUpdate(); + result = true; + } else { + result = false; + } + } break; + case COL_VERSION: { + VersionInfo::VersionScheme scheme = info->version().scheme(); + VersionInfo version(value.toString(), scheme, true); + if (version.isValid()) { + info->setVersion(version); + result = true; + } else { + result = false; + } + } break; + case COL_NOTES: { + info->setComments(value.toString()); + result = true; + } break; + default: { + log::warn("edit on column \"{}\" not supported", + getColumnName(index.column()).toUtf8().constData()); + result = false; + } break; } if (result) { emit dataChanged(index, index); @@ -612,9 +591,7 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role) return result; } - -QVariant ModList::headerData(int section, Qt::Orientation orientation, - int role) const +QVariant ModList::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal) { if (role == Qt::DisplayRole) { @@ -626,8 +603,7 @@ QVariant ModList::headerData(int section, Qt::Orientation orientation, } else if (role == MOBase::EnabledColumnRole) { if (section == COL_CONTENT) { return !m_Organizer->modDataContents().empty(); - } - else { + } else { return true; } } @@ -635,7 +611,7 @@ QVariant ModList::headerData(int section, Qt::Orientation orientation, return QAbstractItemModel::headerData(section, orientation, role); } -Qt::ItemFlags ModList::flags(const QModelIndex &modelIndex) const +Qt::ItemFlags ModList::flags(const QModelIndex& modelIndex) const { Qt::ItemFlags result = QAbstractItemModel::flags(modelIndex); if (modelIndex.internalId() < 0) { @@ -647,27 +623,24 @@ Qt::ItemFlags ModList::flags(const QModelIndex &modelIndex) const result |= Qt::ItemIsDragEnabled; result |= Qt::ItemIsUserCheckable; if ((modelIndex.column() == COL_PRIORITY) || - (modelIndex.column() == COL_VERSION) || - (modelIndex.column() == COL_MODID)) { + (modelIndex.column() == COL_VERSION) || (modelIndex.column() == COL_MODID)) { result |= Qt::ItemIsEditable; } - if ((modelIndex.column() == COL_NAME || modelIndex.column() == COL_NOTES) - && !modInfo->isForeign()) { + if ((modelIndex.column() == COL_NAME || modelIndex.column() == COL_NOTES) && + !modInfo->isForeign()) { result |= Qt::ItemIsEditable; } } if (modInfo->isSeparator() || m_DropOnMod) { result |= Qt::ItemIsDropEnabled; } - } - else if (!m_DropOnMod) { + } else if (!m_DropOnMod) { result |= Qt::ItemIsDropEnabled; } return result; } - QStringList ModList::mimeTypes() const { QStringList result = QAbstractItemModel::mimeTypes(); @@ -675,24 +648,25 @@ QStringList ModList::mimeTypes() const return result; } -QMimeData *ModList::mimeData(const QModelIndexList &indexes) const +QMimeData* ModList::mimeData(const QModelIndexList& indexes) const { - QMimeData *result = QAbstractItemModel::mimeData(indexes); + QMimeData* result = QAbstractItemModel::mimeData(indexes); result->setData("text/plain", ModListDropInfo::ModText); return result; } void ModList::changeModPriority(std::vector<int> sourceIndices, int newPriority) { - if (m_Profile == nullptr) return; + if (m_Profile == nullptr) + return; emit layoutAboutToBeChanged(); // sort the moving mods by ascending priorities std::sort(sourceIndices.begin(), sourceIndices.end(), - [=](const int &LHS, const int &RHS) { - return m_Profile->getModPriority(LHS) > m_Profile->getModPriority(RHS); - }); + [=](const int& LHS, const int& RHS) { + return m_Profile->getModPriority(LHS) > m_Profile->getModPriority(RHS); + }); // move mods that are decreasing in priority for (const auto& index : sourceIndices) { @@ -706,9 +680,9 @@ void ModList::changeModPriority(std::vector<int> sourceIndices, int newPriority) // sort the moving mods by descending priorities std::sort(sourceIndices.begin(), sourceIndices.end(), - [=](const int &LHS, const int &RHS) { - return m_Profile->getModPriority(LHS) < m_Profile->getModPriority(RHS); - }); + [=](const int& LHS, const int& RHS) { + return m_Profile->getModPriority(LHS) < m_Profile->getModPriority(RHS); + }); // if at least one mod is increasing in priority, the target index is // that of the row BELOW the dropped location, otherwise it's the one above @@ -740,19 +714,19 @@ void ModList::changeModPriority(std::vector<int> sourceIndices, int newPriority) emit modPrioritiesChanged(indices); } - void ModList::changeModPriority(int sourceIndex, int newPriority) { - if (m_Profile == nullptr) return; + if (m_Profile == nullptr) + return; emit layoutAboutToBeChanged(); m_Profile->setModPriority(sourceIndex, newPriority); emit layoutChanged(); - emit modPrioritiesChanged({ index(sourceIndex, 0) }); + emit modPrioritiesChanged({index(sourceIndex, 0)}); } -void ModList::setPluginContainer(PluginContainer *pluginContianer) +void ModList::setPluginContainer(PluginContainer* pluginContianer) { m_PluginContainer = pluginContianer; } @@ -760,7 +734,7 @@ void ModList::setPluginContainer(PluginContainer *pluginContianer) bool ModList::modInfoAboutToChange(ModInfo::Ptr info) { if (m_ChangeInfo.name.isEmpty()) { - m_ChangeInfo.name = info->name(); + m_ChangeInfo.name = info->name(); m_ChangeInfo.state = state(info->name()); return true; } else { @@ -773,7 +747,7 @@ void ModList::modInfoChanged(ModInfo::Ptr info) if (info->name() == m_ChangeInfo.name) { IModList::ModStates newState = state(info->name()); if (m_ChangeInfo.state != newState) { - m_ModStateChanged({ {info->name(), newState} }); + m_ModStateChanged({{info->name(), newState}}); } int row = ModInfo::getIndex(info->name()); @@ -787,7 +761,8 @@ void ModList::modInfoChanged(ModInfo::Ptr info) m_ChangeInfo.name = QString(); } -void ModList::disconnectSlots() { +void ModList::disconnectSlots() +{ m_ModMoved.disconnect_all_slots(); m_ModStateChanged.disconnect_all_slots(); } @@ -813,7 +788,8 @@ IModList::ModStates ModList::state(unsigned int modIndex) const result |= IModList::STATE_VALID; } if (modInfo->isRegular()) { - QSharedPointer<ModInfoRegular> modInfoRegular = modInfo.staticCast<ModInfoRegular>(); + QSharedPointer<ModInfoRegular> modInfoRegular = + modInfo.staticCast<ModInfoRegular>(); if (modInfoRegular->isAlternate() && !modInfoRegular->isConverted()) result |= IModList::STATE_ALTERNATE; if (!modInfo->isValid() && modInfoRegular->isValidated()) @@ -830,7 +806,7 @@ IModList::ModStates ModList::state(unsigned int modIndex) const return result; } -QString ModList::displayName(const QString &internalName) const +QString ModList::displayName(const QString& internalName) const { unsigned int modIndex = ModInfo::getIndex(internalName); if (modIndex == UINT_MAX) { @@ -852,8 +828,8 @@ QStringList ModList::allMods() const QStringList ModList::allModsByProfilePriority(MOBase::IProfile* profile) const { - Profile* mo2Profile = profile == nullptr ? - m_Organizer->currentProfile() : static_cast<Profile*>(profile); + Profile* mo2Profile = profile == nullptr ? m_Organizer->currentProfile() + : static_cast<Profile*>(profile); QStringList res; for (auto& [priority, index] : mo2Profile->getAllIndexesByPriority()) { @@ -880,41 +856,39 @@ bool ModList::removeMod(MOBase::IModInterface* mod) return result; } -MOBase::IModInterface* ModList::renameMod(MOBase::IModInterface* mod, const QString& name) +MOBase::IModInterface* ModList::renameMod(MOBase::IModInterface* mod, + const QString& name) { unsigned int index = ModInfo::getIndex(mod->name()); if (index == UINT_MAX) { if (auto* p = dynamic_cast<ModInfo*>(mod)) { p->setName(name); return p; - } - else { + } else { return nullptr; } - } - else { + } else { if (renameMod(index, name)) { return ModInfo::getByName(name).get(); - } - else { + } else { return nullptr; } } } -IModList::ModStates ModList::state(const QString &name) const +IModList::ModStates ModList::state(const QString& name) const { unsigned int modIndex = ModInfo::getIndex(name); return state(modIndex); } -bool ModList::setActive(const QString &name, bool active) +bool ModList::setActive(const QString& name, bool active) { unsigned int modIndex = ModInfo::getIndex(name); if (modIndex == UINT_MAX) { log::debug("Trying to {} mod {} which does not exist.", - active ? "enable" : "disable", name); + active ? "enable" : "disable", name); return false; } else { m_Profile->setModEnabled(modIndex, active); @@ -922,7 +896,8 @@ bool ModList::setActive(const QString &name, bool active) } } -int ModList::setActive(const QStringList& names, bool active) { +int ModList::setActive(const QStringList& names, bool active) +{ // We only add indices for mods that exist (modIndex != UINT_MAX) // and that can be enabled / disabled. @@ -931,24 +906,22 @@ int ModList::setActive(const QStringList& names, bool active) { auto modIndex = ModInfo::getIndex(name); if (modIndex != UINT_MAX) { indices.append(modIndex); - } - else { + } else { log::debug("Trying to {} mod {} which does not exist.", - active ? "enable" : "disable", name); + active ? "enable" : "disable", name); } } if (active) { m_Profile->setModsEnabled(indices, {}); - } - else { + } else { m_Profile->setModsEnabled({}, indices); } return indices.size(); } -int ModList::priority(const QString &name) const +int ModList::priority(const QString& name) const { unsigned int modIndex = ModInfo::getIndex(name); if (modIndex == UINT_MAX) { @@ -958,7 +931,7 @@ int ModList::priority(const QString &name) const } } -bool ModList::setPriority(const QString &name, int newPriority) +bool ModList::setPriority(const QString& name, int newPriority) { unsigned int index = ModInfo::getIndex(name); if (index == UINT_MAX) { @@ -971,17 +944,20 @@ bool ModList::setPriority(const QString &name, int newPriority) } } -boost::signals2::connection ModList::onModInstalled(const std::function<void(MOBase::IModInterface*)>& func) +boost::signals2::connection +ModList::onModInstalled(const std::function<void(MOBase::IModInterface*)>& func) { return m_ModInstalled.connect(func); } -boost::signals2::connection ModList::onModRemoved(const std::function<void(QString const&)>& func) +boost::signals2::connection +ModList::onModRemoved(const std::function<void(QString const&)>& func) { return m_ModRemoved.connect(func); } -boost::signals2::connection ModList::onModStateChanged(const std::function<void(const std::map<QString, IModList::ModStates>&)>& func) +boost::signals2::connection ModList::onModStateChanged( + const std::function<void(const std::map<QString, IModList::ModStates>&)>& func) { return m_ModStateChanged.connect(func); } @@ -1010,7 +986,8 @@ void ModList::notifyModStateChanged(QList<unsigned int> modIndices) const m_ModStateChanged(mods); } -boost::signals2::connection ModList::onModMoved(const std::function<void (const QString &, int, int)> &func) +boost::signals2::connection +ModList::onModMoved(const std::function<void(const QString&, int, int)>& func) { return m_ModMoved.connect(func); } @@ -1029,8 +1006,7 @@ int ModList::dropPriority(int row, const QModelIndex& parent) const { if (row < 0 || row >= rowCount()) { newPriority = Profile::MaximumPriority; - } - else { + } else { newPriority = m_Profile->getModPriority(row); } } @@ -1038,17 +1014,18 @@ int ModList::dropPriority(int row, const QModelIndex& parent) const return newPriority; } -bool ModList::dropLocalFiles(const ModListDropInfo& dropInfo, int row, const QModelIndex &parent) +bool ModList::dropLocalFiles(const ModListDropInfo& dropInfo, int row, + const QModelIndex& parent) { if (row == -1) { row = parent.row(); } ModInfo::Ptr modInfo = ModInfo::getByIndex(row); - QDir modDir = QDir(modInfo->absolutePath()); + QDir modDir = QDir(modInfo->absolutePath()); QStringList sourceList; QStringList targetList; - QList<QPair<QString,QString>> relativePathList; + QList<QPair<QString, QString>> relativePathList; for (auto localUrl : dropInfo.localUrls()) { @@ -1058,7 +1035,8 @@ bool ModList::dropLocalFiles(const ModListDropInfo& dropInfo, int row, const QMo QFileInfo targetInfo(modDir.absoluteFilePath(localUrl.relativePath)); sourceList << sourceFile; targetList << targetInfo.absoluteFilePath(); - relativePathList << QPair<QString,QString>(localUrl.relativePath, localUrl.originName); + relativePathList << QPair<QString, QString>(localUrl.relativePath, + localUrl.originName); } if (sourceList.count()) { @@ -1084,7 +1062,8 @@ void ModList::onDragEnter(const QMimeData* mimeData) m_DropOnMod = ModListDropInfo(mimeData, *m_Organizer).isLocalFileDrop(); } -bool ModList::canDropMimeData(const QMimeData* mimeData, Qt::DropAction action, int row, int column, const QModelIndex& parent) const +bool ModList::canDropMimeData(const QMimeData* mimeData, Qt::DropAction action, int row, + int column, const QModelIndex& parent) const { if (action == Qt::IgnoreAction) { return false; @@ -1097,17 +1076,14 @@ bool ModList::canDropMimeData(const QMimeData* mimeData, Qt::DropAction action, ModInfo::Ptr modInfo = ModInfo::getByIndex(parent.row()); return modInfo->isRegular() && !modInfo->isSeparator(); } - } - else if (dropInfo.isValid()) { + } else if (dropInfo.isValid()) { // drop on item if (row == -1 && parent.isValid()) { return true; - } - else if (hasIndex(row, column, parent)) { + } else if (hasIndex(row, column, parent)) { ModInfo::Ptr modInfo = ModInfo::getByIndex(row); return !modInfo->isBackup() && (modInfo->isSeparator() || !parent.isValid()); - } - else { + } else { return true; } } @@ -1115,7 +1091,8 @@ bool ModList::canDropMimeData(const QMimeData* mimeData, Qt::DropAction action, return false; } -bool ModList::dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int row, int, const QModelIndex &parent) +bool ModList::dropMimeData(const QMimeData* mimeData, Qt::DropAction action, int row, + int, const QModelIndex& parent) { if (action == Qt::IgnoreAction) { return true; @@ -1134,33 +1111,29 @@ bool ModList::dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int if (dropInfo.isLocalFileDrop()) { return dropLocalFiles(dropInfo, row, parent); - } - else { + } else { if (dropInfo.isModDrop()) { changeModPriority(dropInfo.rows(), dropPriority); - } - else if (dropInfo.isDownloadDrop()) { + } else if (dropInfo.isDownloadDrop()) { emit downloadArchiveDropped(dropInfo.download(), dropPriority); - } - else if (dropInfo.isExternalArchiveDrop()) { + } else if (dropInfo.isExternalArchiveDrop()) { emit externalArchiveDropped(dropInfo.externalUrl(), dropPriority); - } - else if (dropInfo.isExternalFolderDrop()) { + } else if (dropInfo.isExternalFolderDrop()) { emit externalFolderDropped(dropInfo.externalUrl(), dropPriority); - } - else { + } else { return false; } } return false; } -void ModList::removeRowForce(int row, const QModelIndex &parent) +void ModList::removeRowForce(int row, const QModelIndex& parent) { if (static_cast<unsigned int>(row) >= ModInfo::getNumMods()) { return; } - if (m_Profile == nullptr) return; + if (m_Profile == nullptr) + return; ModInfo::Ptr modInfo = ModInfo::getByIndex(row); @@ -1173,7 +1146,8 @@ void ModList::removeRowForce(int row, const QModelIndex &parent) ModInfo::removeMod(row); m_Profile->refreshModStatus(); // removes the mod from the status list endRemoveRows(); - m_Profile->writeModlist(); // this ensures the modified list gets written back before new mods can be installed + m_Profile->writeModlist(); // this ensures the modified list gets written back before + // new mods can be installed notifyModRemoved(modInfo->name()); @@ -1185,7 +1159,7 @@ void ModList::removeRowForce(int row, const QModelIndex &parent) } } -bool ModList::removeRows(int row, int count, const QModelIndex &parent) +bool ModList::removeRows(int row, int count, const QModelIndex& parent) { if (static_cast<unsigned int>(row) >= ModInfo::getNumMods()) { return false; @@ -1212,9 +1186,10 @@ bool ModList::removeRows(int row, int count, const QModelIndex &parent) success = true; - QMessageBox confirmBox(QMessageBox::Question, tr("Confirm"), - tr("Are you sure you want to remove \"%1\"?").arg(getDisplayName(modInfo)), - QMessageBox::Yes | QMessageBox::No); + QMessageBox confirmBox( + QMessageBox::Question, tr("Confirm"), + tr("Are you sure you want to remove \"%1\"?").arg(getDisplayName(modInfo)), + QMessageBox::Yes | QMessageBox::No); if (confirmBox.exec() == QMessageBox::Yes) { m_Profile->setModEnabled(row + i, false); @@ -1225,7 +1200,6 @@ bool ModList::removeRows(int row, int count, const QModelIndex &parent) return success; } - void ModList::notifyChange(int rowStart, int rowEnd) { // this function can emit dataChanged(), which can eventually recurse back @@ -1252,7 +1226,9 @@ void ModList::notifyChange(int rowStart, int rowEnd) } m_InNotifyChange = true; - Guard g([&]{ m_InNotifyChange = false; }); + Guard g([&] { + m_InNotifyChange = false; + }); if (rowStart < 0) { beginResetModel(); @@ -1261,11 +1237,11 @@ void ModList::notifyChange(int rowStart, int rowEnd) if (rowEnd == -1) { rowEnd = rowStart; } - emit dataChanged(this->index(rowStart, 0), this->index(rowEnd, this->columnCount() - 1)); + emit dataChanged(this->index(rowStart, 0), + this->index(rowEnd, this->columnCount() - 1)); } } - QModelIndex ModList::index(int row, int column, const QModelIndex&) const { if ((row < 0) || (row >= rowCount()) || (column < 0) || (column >= columnCount())) { @@ -1275,13 +1251,12 @@ QModelIndex ModList::index(int row, int column, const QModelIndex&) const return res; } - QModelIndex ModList::parent(const QModelIndex&) const { return QModelIndex(); } -QMap<int, QVariant> ModList::itemData(const QModelIndex &index) const +QMap<int, QVariant> ModList::itemData(const QModelIndex& index) const { QMap<int, QVariant> result = QAbstractItemModel::itemData(index); for (int role = Qt::UserRole; role < ModUserRole; ++role) { @@ -1293,49 +1268,74 @@ QMap<int, QVariant> ModList::itemData(const QModelIndex &index) const QString ModList::getColumnName(int column) { switch (column) { - case COL_CONFLICTFLAGS: return tr("Conflicts"); - case COL_FLAGS: return tr("Flags"); - case COL_CONTENT: return tr("Content"); - case COL_NAME: return tr("Mod Name"); - case COL_VERSION: return tr("Version"); - case COL_PRIORITY: return tr("Priority"); - case COL_CATEGORY: return tr("Category"); - case COL_GAME: return tr("Source Game"); - case COL_MODID: return tr("Nexus ID"); - case COL_INSTALLTIME: return tr("Installation"); - case COL_NOTES: return tr("Notes"); - default: return tr("unknown"); + case COL_CONFLICTFLAGS: + return tr("Conflicts"); + case COL_FLAGS: + return tr("Flags"); + case COL_CONTENT: + return tr("Content"); + case COL_NAME: + return tr("Mod Name"); + case COL_VERSION: + return tr("Version"); + case COL_PRIORITY: + return tr("Priority"); + case COL_CATEGORY: + return tr("Category"); + case COL_GAME: + return tr("Source Game"); + case COL_MODID: + return tr("Nexus ID"); + case COL_INSTALLTIME: + return tr("Installation"); + case COL_NOTES: + return tr("Notes"); + default: + return tr("unknown"); } } - QString ModList::getColumnToolTip(int column) const { switch (column) { - case COL_NAME: return tr("Name of your mods"); - case COL_VERSION: return tr("Version of the mod (if available)"); - case COL_PRIORITY: return tr("Installation priority of your mod. The higher, the more \"important\" it is and thus " - "overwrites files from mods with lower priority."); - case COL_CATEGORY: return tr("Primary category of the mod."); - case COL_GAME: return tr("The source game which was the origin of this mod."); - case COL_MODID: return tr("Id of the mod as used on Nexus."); - case COL_CONFLICTFLAGS: return tr("Indicators of file conflicts between mods."); - case COL_FLAGS: return tr("Emblems to highlight things that might require attention."); - case COL_CONTENT: { - auto& contents = m_Organizer->modDataContents(); - if (m_Organizer->modDataContents().empty()) { - return QString(); - } - QString result = tr("Depicts the content of the mod:") + "<br>" + "<table cellspacing=7>"; - m_Organizer->modDataContents().forEachContent([&result](auto const& content) { - result += QString("<tr><td><img src=\"%1\" width=32/></td><td>%2</td></tr>") - .arg(content.icon()).arg(content.name()); - }); - return result + "</table>"; - }; - case COL_INSTALLTIME: return tr("Time this mod was installed"); - case COL_NOTES: return tr("User notes about the mod"); - default: return tr("unknown"); + case COL_NAME: + return tr("Name of your mods"); + case COL_VERSION: + return tr("Version of the mod (if available)"); + case COL_PRIORITY: + return tr("Installation priority of your mod. The higher, the more \"important\" " + "it is and thus " + "overwrites files from mods with lower priority."); + case COL_CATEGORY: + return tr("Primary category of the mod."); + case COL_GAME: + return tr("The source game which was the origin of this mod."); + case COL_MODID: + return tr("Id of the mod as used on Nexus."); + case COL_CONFLICTFLAGS: + return tr("Indicators of file conflicts between mods."); + case COL_FLAGS: + return tr("Emblems to highlight things that might require attention."); + case COL_CONTENT: { + auto& contents = m_Organizer->modDataContents(); + if (m_Organizer->modDataContents().empty()) { + return QString(); + } + QString result = + tr("Depicts the content of the mod:") + "<br>" + "<table cellspacing=7>"; + m_Organizer->modDataContents().forEachContent([&result](auto const& content) { + result += QString("<tr><td><img src=\"%1\" width=32/></td><td>%2</td></tr>") + .arg(content.icon()) + .arg(content.name()); + }); + return result + "</table>"; + }; + case COL_INSTALLTIME: + return tr("Time this mod was installed"); + case COL_NOTES: + return tr("User notes about the mod"); + default: + return tr("unknown"); } } @@ -1386,8 +1386,7 @@ void ModList::changeModsPriority(const QModelIndexList& indices, int priority) if (allIndex.size() == 1) { changeModPriority(allIndex[0], priority); - } - else { + } else { changeModPriority(allIndex, priority); } } @@ -1430,8 +1429,7 @@ void ModList::setActive(const QModelIndexList& indices, bool active) if (active) { m_Profile->setModsEnabled(mods, {}); - } - else { + } else { m_Profile->setModsEnabled({}, mods); } } diff --git a/src/modlist.h b/src/modlist.h index f179d7ae..112070e1 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -20,26 +20,25 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef MODLIST_H #define MODLIST_H -#include "moddatacontent.h" #include "categories.h" -#include "nexusinterface.h" +#include "moddatacontent.h" #include "modinfo.h" +#include "nexusinterface.h" #include "profile.h" #include <imodlist.h> #include <QFile> #include <QListWidget> -#include <QNetworkReply> #include <QMetaEnum> #include <QNetworkAccessManager> +#include <QNetworkReply> #ifndef Q_MOC_RUN #include <boost/signals2.hpp> #endif +#include <QVector> #include <set> #include <vector> -#include <QVector> - class QSortFilterProxyModel; class PluginContainer; @@ -48,16 +47,16 @@ class ModListDropInfo; /** * Model presenting an overview of the installed mod - * This is used in a view in the main window of MO. It combines general information about - * the mods from ModInfo with status information from the Profile + * This is used in a view in the main window of MO. It combines general information + *about the mods from ModInfo with status information from the Profile **/ class ModList : public QAbstractItemModel { Q_OBJECT public: - - enum ModListRole { + enum ModListRole + { // data(GroupingRole) contains the "group" role - This is used by the // category and Nexus ID grouping proxy (but not the ByPriority proxy) @@ -79,7 +78,8 @@ public: ModUserRole = Qt::UserRole + 6 }; - enum EColumn { + enum EColumn + { COL_NAME, COL_CONFLICTFLAGS, COL_FLAGS, @@ -94,18 +94,19 @@ public: COL_LASTCOLUMN = COL_NOTES, }; - using SignalModInstalled = boost::signals2::signal<void(MOBase::IModInterface*)>; - using SignalModRemoved = boost::signals2::signal<void(QString const&)>; - using SignalModStateChanged = boost::signals2::signal<void (const std::map<QString, MOBase::IModList::ModStates>&)>; - using SignalModMoved = boost::signals2::signal<void (const QString &, int, int)>; + using SignalModInstalled = boost::signals2::signal<void(MOBase::IModInterface*)>; + using SignalModRemoved = boost::signals2::signal<void(QString const&)>; + using SignalModStateChanged = boost::signals2::signal<void( + const std::map<QString, MOBase::IModList::ModStates>&)>; + using SignalModMoved = boost::signals2::signal<void(const QString&, int, int)>; public: - /** * @brief constructor - * @todo ensure this view works without a profile set, otherwise there are intransparent dependencies on the initialisation order + * @todo ensure this view works without a profile set, otherwise there are + *intransparent dependencies on the initialisation order **/ - ModList(PluginContainer *pluginContainer, OrganizerCore *parent); + ModList(PluginContainer* pluginContainer, OrganizerCore* parent); ~ModList(); @@ -114,7 +115,7 @@ public: * * @param profile the profile to use **/ - void setProfile(Profile *profile); + void setProfile(Profile* profile); /** * @brief retrieve the current sorting mode @@ -127,7 +128,7 @@ public: * @brief remove the specified mod without asking for confirmation * @param row the row to remove */ - void removeRowForce(int row, const QModelIndex &parent); + void removeRowForce(int row, const QModelIndex& parent); void notifyChange(int rowStart, int rowEnd = -1); static QString getColumnName(int column); @@ -135,7 +136,7 @@ public: void changeModPriority(int sourceIndex, int newPriority); void changeModPriority(std::vector<int> sourceIndices, int newPriority); - void setPluginContainer(PluginContainer *pluginContainer); + void setPluginContainer(PluginContainer* pluginContainer); bool modInfoAboutToChange(ModInfo::Ptr info); void modInfoChanged(ModInfo::Ptr info); @@ -145,14 +146,13 @@ public: int timeElapsedSinceLastChecked() const; public: - /** * @brief Notify the mod list that the given mod has been installed. This is used * to notify the plugin that registered through onModInstalled(). * * @param mod The installed mod. */ - void notifyModInstalled(MOBase::IModInterface *mod) const; + void notifyModInstalled(MOBase::IModInterface* mod) const; /** * @brief Notify the mod list that a mod has been removed. This is used @@ -163,17 +163,16 @@ public: void notifyModRemoved(QString const& modName) const; /** - * @brief Notify the mod list that the state of the specified mods has changed. This is used - * to notify the plugin that registered through onModStateChanged(). + * @brief Notify the mod list that the state of the specified mods has changed. This + * is used to notify the plugin that registered through onModStateChanged(). * * @param modIndices Indices of the mods that changed. */ void notifyModStateChanged(QList<unsigned int> modIndices) const; public: - /// \copydoc MOBase::IModList::displayName - QString displayName(const QString &internalName) const; + QString displayName(const QString& internalName) const; /// \copydoc MOBase::IModList::allMods QStringList allMods() const; @@ -189,47 +188,58 @@ public: MOBase::IModInterface* renameMod(MOBase::IModInterface* mod, const QString& name); /// \copydoc MOBase::IModList::state - MOBase::IModList::ModStates state(const QString &name) const; + MOBase::IModList::ModStates state(const QString& name) const; /// \copydoc MOBase::IModList::setActive - bool setActive(const QString &name, bool active); + bool setActive(const QString& name, bool active); /// \copydoc MOBase::IModList::setActive int setActive(const QStringList& names, bool active); /// \copydoc MOBase::IModList::priority - int priority(const QString &name) const; + int priority(const QString& name) const; /// \copydoc MOBase::IModList::setPriority - bool setPriority(const QString &name, int newPriority); + bool setPriority(const QString& name, int newPriority); - boost::signals2::connection onModInstalled(const std::function<void(MOBase::IModInterface*)>& func); - boost::signals2::connection onModRemoved(const std::function<void(QString const&)>& func); - boost::signals2::connection onModStateChanged(const std::function<void(const std::map<QString, MOBase::IModList::ModStates>&)>& func); - boost::signals2::connection onModMoved(const std::function<void (const QString &, int, int)> &func); + boost::signals2::connection + onModInstalled(const std::function<void(MOBase::IModInterface*)>& func); + boost::signals2::connection + onModRemoved(const std::function<void(QString const&)>& func); + boost::signals2::connection onModStateChanged( + const std::function<void(const std::map<QString, MOBase::IModList::ModStates>&)>& + func); + boost::signals2::connection + onModMoved(const std::function<void(const QString&, int, int)>& func); -public: // implementation of virtual functions of QAbstractItemModel - - virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; - virtual bool hasChildren(const QModelIndex &parent = QModelIndex()) const; - virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; - virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); - virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - virtual Qt::ItemFlags flags(const QModelIndex &modelIndex) const; +public: // implementation of virtual functions of QAbstractItemModel + virtual int rowCount(const QModelIndex& parent = QModelIndex()) const; + virtual bool hasChildren(const QModelIndex& parent = QModelIndex()) const; + virtual int columnCount(const QModelIndex& parent = QModelIndex()) const; + virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; + virtual bool setData(const QModelIndex& index, const QVariant& value, + int role = Qt::EditRole); + virtual QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + virtual Qt::ItemFlags flags(const QModelIndex& modelIndex) const; virtual bool removeRows(int row, int count, const QModelIndex& parent); - Qt::DropActions supportedDropActions() const override { return Qt::MoveAction | Qt::CopyAction; } + Qt::DropActions supportedDropActions() const override + { + return Qt::MoveAction | Qt::CopyAction; + } QStringList mimeTypes() const override; - QMimeData *mimeData(const QModelIndexList &indexes) const override; - bool canDropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) const override; - bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; + QMimeData* mimeData(const QModelIndexList& indexes) const override; + bool canDropMimeData(const QMimeData* data, Qt::DropAction action, int row, + int column, const QModelIndex& parent) const override; + bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, + const QModelIndex& parent) override; virtual QModelIndex index(int row, int column, - const QModelIndex &parent = QModelIndex()) const; - virtual QModelIndex parent(const QModelIndex &child) const; + const QModelIndex& parent = QModelIndex()) const; + virtual QModelIndex parent(const QModelIndex& child) const; - virtual QMap<int, QVariant> itemData(const QModelIndex &index) const; + virtual QMap<int, QVariant> itemData(const QModelIndex& index) const; public slots: @@ -255,8 +265,8 @@ signals: // emitted when the priority of one or multiple mods have changed // - // the sorting of the list can only be manually changed if the list is sorted by priority - // in which case the move is intended to change the priority of a mod. + // the sorting of the list can only be manually changed if the list is sorted by + // priority in which case the move is intended to change the priority of a mod. // void modPrioritiesChanged(const QModelIndexList& indices) const; @@ -269,7 +279,7 @@ signals: * * @param message the message to display **/ - void showMessage(const QString &message); + void showMessage(const QString& message); /** * @brief signals change to the count of headers @@ -280,26 +290,28 @@ signals: * @brief emitted to remove a file origin * @param name name of the orign to remove */ - void removeOrigin(const QString &name); + void removeOrigin(const QString& name); /** * @brief emitted after a mod has been renamed - * This signal MUST be used to fix the mod names in profiles (except the active one) and to invalidate/refresh other - * structures that may have become invalid with the rename + * This signal MUST be used to fix the mod names in profiles (except the active one) + * and to invalidate/refresh other structures that may have become invalid with the + * rename * * @param oldName the old name of the mod * @param newName new name of the mod */ - void modRenamed(const QString &oldName, const QString &newName); + void modRenamed(const QString& oldName, const QString& newName); /** * @brief emitted after a mod has been uninstalled * @param fileName filename of the mod being uninstalled */ - void modUninstalled(const QString &fileName); + void modUninstalled(const QString& fileName); /** - * @brief QML seems to handle overloaded signals poorly - create unique signal for tutorials + * @brief QML seems to handle overloaded signals poorly - create unique signal for + * tutorials */ void tutorialModlistUpdate(); @@ -309,11 +321,12 @@ signals: * @param oldOriginName name of the origin that previously contained the file * @param newOriginName name of the origin that now contains the file */ - void fileMoved(const QString &relativePath, const QString &oldOriginName, const QString &newOriginName); + void fileMoved(const QString& relativePath, const QString& oldOriginName, + const QString& newOriginName); /** - * @brief emitted to have the overwrite folder cleared - */ + * @brief emitted to have the overwrite folder cleared + */ void clearOverwrite(); void aboutToChangeData(); @@ -334,7 +347,6 @@ signals: void externalFolderDropped(const QUrl& url, int priority); private: - // retrieve the display name of a mod or convert from a user-provided // name to internal name // @@ -347,23 +359,26 @@ private: QString getColumnToolTip(int column) const; - bool renameMod(int index, const QString &newName); + bool renameMod(int index, const QString& newName); MOBase::IModList::ModStates state(unsigned int modIndex) const; // handle dropping of local URLs files // - bool dropLocalFiles(const ModListDropInfo& dropInfo, int row, const QModelIndex& parent); + bool dropLocalFiles(const ModListDropInfo& dropInfo, int row, + const QModelIndex& parent); // return the priority of the mod for a drop event // int dropPriority(int row, const QModelIndex& parent) const; private: - - struct TModInfo { + struct TModInfo + { TModInfo(unsigned int index, ModInfo::Ptr modInfo) - : modInfo(modInfo), nameOrder(index), priorityOrder(0), modIDOrder(0), categoryOrder(0) {} + : modInfo(modInfo), nameOrder(index), priorityOrder(0), modIDOrder(0), + categoryOrder(0) + {} ModInfo::Ptr modInfo; unsigned int nameOrder; unsigned int priorityOrder; @@ -371,17 +386,17 @@ private: unsigned int categoryOrder; }; - struct TModInfoChange { + struct TModInfoChange + { QString name; QFlags<MOBase::IModList::ModState> state; }; private: + OrganizerCore* m_Organizer; + Profile* m_Profile; - OrganizerCore *m_Organizer; - Profile *m_Profile; - - NexusInterface *m_NexusInterface; + NexusInterface* m_NexusInterface; std::set<int> m_RequestIDs; mutable bool m_Modified; @@ -399,9 +414,7 @@ private: QElapsedTimer m_LastCheck; - PluginContainer *m_PluginContainer; - + PluginContainer* m_PluginContainer; }; -#endif // MODLIST_H - +#endif // MODLIST_H diff --git a/src/modlistbypriorityproxy.cpp b/src/modlistbypriorityproxy.cpp index 24e58ed0..ba53ee74 100644 --- a/src/modlistbypriorityproxy.cpp +++ b/src/modlistbypriorityproxy.cpp @@ -1,20 +1,18 @@ #include "modlistbypriorityproxy.h" +#include "log.h" #include "modinfo.h" -#include "profile.h" -#include "organizercore.h" #include "modlist.h" #include "modlistdropinfo.h" -#include "log.h" +#include "organizercore.h" +#include "profile.h" -ModListByPriorityProxy::ModListByPriorityProxy(Profile* profile, OrganizerCore& core, QObject* parent) : - QAbstractProxyModel(parent), m_core(core), m_profile(profile) -{ -} +ModListByPriorityProxy::ModListByPriorityProxy(Profile* profile, OrganizerCore& core, + QObject* parent) + : QAbstractProxyModel(parent), m_core(core), m_profile(profile) +{} -ModListByPriorityProxy::~ModListByPriorityProxy() -{ -} +ModListByPriorityProxy::~ModListByPriorityProxy() {} void ModListByPriorityProxy::setSourceModel(QAbstractItemModel* model) { @@ -25,10 +23,14 @@ void ModListByPriorityProxy::setSourceModel(QAbstractItemModel* model) QAbstractProxyModel::setSourceModel(model); if (sourceModel()) { - connect(sourceModel(), &QAbstractItemModel::layoutChanged, this, &ModListByPriorityProxy::onModelLayoutChanged, Qt::UniqueConnection); - connect(sourceModel(), &QAbstractItemModel::rowsRemoved, this, &ModListByPriorityProxy::onModelRowsRemoved, Qt::UniqueConnection); - connect(sourceModel(), &QAbstractItemModel::modelReset, this, &ModListByPriorityProxy::onModelReset, Qt::UniqueConnection); - connect(sourceModel(), &QAbstractItemModel::dataChanged, this, &ModListByPriorityProxy::onModelDataChanged, Qt::UniqueConnection); + connect(sourceModel(), &QAbstractItemModel::layoutChanged, this, + &ModListByPriorityProxy::onModelLayoutChanged, Qt::UniqueConnection); + connect(sourceModel(), &QAbstractItemModel::rowsRemoved, this, + &ModListByPriorityProxy::onModelRowsRemoved, Qt::UniqueConnection); + connect(sourceModel(), &QAbstractItemModel::modelReset, this, + &ModListByPriorityProxy::onModelReset, Qt::UniqueConnection); + connect(sourceModel(), &QAbstractItemModel::dataChanged, this, + &ModListByPriorityProxy::onModelDataChanged, Qt::UniqueConnection); onModelReset(); } @@ -51,16 +53,18 @@ void ModListByPriorityProxy::buildMapping() { m_IndexToItem.clear(); for (unsigned int index = 0; index < ModInfo::getNumMods(); ++index) { - m_IndexToItem[index] = std::make_unique<TreeItem>(ModInfo::getByIndex(index), index); + m_IndexToItem[index] = + std::make_unique<TreeItem>(ModInfo::getByIndex(index), index); } } void ModListByPriorityProxy::buildTree() { - if (!sourceModel()) return; + if (!sourceModel()) + return; // reset the root - m_Root = { }; + m_Root = {}; // clear all children for (auto& [index, item] : m_IndexToItem) { @@ -73,25 +77,22 @@ void ModListByPriorityProxy::buildTree() auto fn = [&](const auto& p) { auto& [priority, index] = p; - ModInfo::Ptr modInfo = ModInfo::getByIndex(index); - TreeItem* item = m_IndexToItem[index].get(); + ModInfo::Ptr modInfo = ModInfo::getByIndex(index); + TreeItem* item = m_IndexToItem[index].get(); if (modInfo->isSeparator()) { item->parent = &m_Root; m_Root.children.push_back(item); root = item; - } - else if (modInfo->isOverwrite()) { + } else if (modInfo->isOverwrite()) { // do not push here, because the overwrite is usually not at the right position item->parent = &m_Root; - overwrite = item; - } - else if (modInfo->isBackup()) { + overwrite = item; + } else if (modInfo->isBackup()) { // do not push here, because backups are usually not at the right position item->parent = &m_Root; backups.push_back(item); - } - else { + } else { item->parent = root; root->children.push_back(item); } @@ -101,23 +102,26 @@ void ModListByPriorityProxy::buildTree() if (m_sortOrder == Qt::AscendingOrder) { std::for_each(ibp.begin(), ibp.end(), fn); m_Root.children.insert(m_Root.children.begin(), - std::make_move_iterator(backups.begin()), std::make_move_iterator(backups.end())); + std::make_move_iterator(backups.begin()), + std::make_move_iterator(backups.end())); m_Root.children.push_back(std::move(overwrite)); - } - else { + } else { std::for_each(ibp.rbegin(), ibp.rend(), fn); m_Root.children.insert(m_Root.children.begin(), std::move(overwrite)); m_Root.children.insert(m_Root.children.end(), - std::make_move_iterator(backups.begin()), std::make_move_iterator(backups.end())); + std::make_move_iterator(backups.begin()), + std::make_move_iterator(backups.end())); } } -void ModListByPriorityProxy::onModelRowsRemoved(const QModelIndex& parent, int first, int last) +void ModListByPriorityProxy::onModelRowsRemoved(const QModelIndex& parent, int first, + int last) { onModelReset(); } -void ModListByPriorityProxy::onModelLayoutChanged(const QList<QPersistentModelIndex>&, LayoutChangeHint hint) +void ModListByPriorityProxy::onModelLayoutChanged(const QList<QPersistentModelIndex>&, + LayoutChangeHint hint) { emit layoutAboutToBeChanged(); auto persistent = persistentIndexList(); @@ -127,7 +131,8 @@ void ModListByPriorityProxy::onModelLayoutChanged(const QList<QPersistentModelIn for (auto& idx : persistent) { // we can still access the TreeItem* because we did not destroy them auto* item = static_cast<TreeItem*>(idx.internalPointer()); - toPersistent.append(createIndex(item->parent->childIndex(item), idx.column(), item)); + toPersistent.append( + createIndex(item->parent->childIndex(item), idx.column(), item)); } changePersistentIndexList(persistent, toPersistent); @@ -142,7 +147,9 @@ void ModListByPriorityProxy::onModelReset() endResetModel(); } -void ModListByPriorityProxy::onModelDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles) +void ModListByPriorityProxy::onModelDataChanged(const QModelIndex& topLeft, + const QModelIndex& bottomRight, + const QVector<int>& roles) { QModelIndex proxyTopLeft = mapFromSource(topLeft); if (!proxyTopLeft.isValid()) { @@ -151,8 +158,7 @@ void ModListByPriorityProxy::onModelDataChanged(const QModelIndex& topLeft, cons if (topLeft == bottomRight) { emit dataChanged(proxyTopLeft, proxyTopLeft); - } - else { + } else { QModelIndex proxyBottomRight = mapFromSource(bottomRight); emit dataChanged(proxyTopLeft, proxyBottomRight); } @@ -222,7 +228,9 @@ bool ModListByPriorityProxy::hasChildren(const QModelIndex& parent) const return item->children.size() > 0; } -bool ModListByPriorityProxy::canDropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) const +bool ModListByPriorityProxy::canDropMimeData(const QMimeData* data, + Qt::DropAction action, int row, int column, + const QModelIndex& parent) const { ModListDropInfo dropInfo(data, m_core); @@ -231,23 +239,26 @@ bool ModListByPriorityProxy::canDropMimeData(const QMimeData* data, Qt::DropActi } if (dropInfo.isModDrop()) { - bool hasSeparator = false; + bool hasSeparator = false; unsigned int firstRowIndex = -1; int firstRowPriority = Profile::MaximumPriority; for (auto sourceRow : dropInfo.rows()) { hasSeparator = hasSeparator || ModInfo::getByIndex(sourceRow)->isSeparator(); - if (m_sortOrder == Qt::AscendingOrder && m_profile->getModPriority(sourceRow) < firstRowPriority - || m_sortOrder == Qt::DescendingOrder && m_profile->getModPriority(sourceRow) > firstRowPriority) { - firstRowIndex = sourceRow; + if (m_sortOrder == Qt::AscendingOrder && + m_profile->getModPriority(sourceRow) < firstRowPriority || + m_sortOrder == Qt::DescendingOrder && + m_profile->getModPriority(sourceRow) > firstRowPriority) { + firstRowIndex = sourceRow; firstRowPriority = m_profile->getModPriority(sourceRow); } } - bool firstRowSeparator = firstRowIndex != -1 && ModInfo::getByIndex(firstRowIndex)->isSeparator(); + bool firstRowSeparator = + firstRowIndex != -1 && ModInfo::getByIndex(firstRowIndex)->isSeparator(); - // row = -1 and valid parent means we're dropping onto an item, we don't want to drop - // separators onto items or items into their own separator + // row = -1 and valid parent means we're dropping onto an item, we don't want to + // drop separators onto items or items into their own separator if (row == -1 && parent.isValid()) { auto* parentItem = static_cast<TreeItem*>(parent.internalPointer()); if (hasSeparator) { @@ -276,7 +287,9 @@ bool ModListByPriorityProxy::canDropMimeData(const QMimeData* data, Qt::DropActi return QAbstractProxyModel::canDropMimeData(data, action, row, column, parent); } -bool ModListByPriorityProxy::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) +bool ModListByPriorityProxy::dropMimeData(const QMimeData* data, Qt::DropAction action, + int row, int column, + const QModelIndex& parent) { // we need to fix the source model row if we are dropping at a // given priority (not a local file) @@ -287,8 +300,7 @@ bool ModListByPriorityProxy::dropMimeData(const QMimeData* data, Qt::DropAction if (parent.isValid()) { sourceRow = static_cast<TreeItem*>(parent.internalPointer())->index; } - } - else { + } else { if (row >= 0) { if (!parent.isValid()) { @@ -301,31 +313,26 @@ bool ModListByPriorityProxy::dropMimeData(const QMimeData* data, Qt::DropAction // // by default, Qt consider it's a drop at the end of that separator // but we want to make it a drop at the beginning - if (row > 0 - && m_sortOrder == Qt::AscendingOrder - && m_Root.children[row - 1]->mod->isSeparator() - && !m_Root.children[row - 1]->children.empty() - && m_dropExpanded - && m_dropPosition == ModListView::DropPosition::BelowItem) { + if (row > 0 && m_sortOrder == Qt::AscendingOrder && + m_Root.children[row - 1]->mod->isSeparator() && + !m_Root.children[row - 1]->children.empty() && m_dropExpanded && + m_dropPosition == ModListView::DropPosition::BelowItem) { sourceRow = m_Root.children[row - 1]->children[0]->index; } - } - else { + } else { sourceRow = m_Root.children[row - 1]->index; // fix drop below a collapsed separator or at the end of an expanded // separator, above the next item - if (row > 0 - && m_sortOrder == Qt::DescendingOrder - && m_Root.children[row - 1]->mod->isSeparator() - && !m_Root.children[row - 1]->children.empty() - && (!m_dropExpanded - || m_dropPosition == ModListView::DropPosition::AboveItem)) { + if (row > 0 && m_sortOrder == Qt::DescendingOrder && + m_Root.children[row - 1]->mod->isSeparator() && + !m_Root.children[row - 1]->children.empty() && + (!m_dropExpanded || + m_dropPosition == ModListView::DropPosition::AboveItem)) { sourceRow = m_Root.children[row - 1]->children.back()->index; } } - } - else { + } else { sourceRow = ModInfo::getNumMods(); } } @@ -336,11 +343,10 @@ bool ModListByPriorityProxy::dropMimeData(const QMimeData* data, Qt::DropAction // we usually need to decrement the row in descending priority, but if // it's the first row, we need to go back to the separator itself - if (m_sortOrder == Qt::DescendingOrder - && row == 0 && m_dropPosition == ModListView::DropPosition::AboveItem) { + if (m_sortOrder == Qt::DescendingOrder && row == 0 && + m_dropPosition == ModListView::DropPosition::AboveItem) { sourceRow = item->index; - } - else { + } else { // in descending priority, we decrement the row to fix the drop position // because this is not done by the sort proxy for us @@ -350,13 +356,10 @@ bool ModListByPriorityProxy::dropMimeData(const QMimeData* data, Qt::DropAction if (row < item->children.size()) { sourceRow = item->children[row]->index; - } - else if (parent.row() + 1 < m_Root.children.size()) { + } else if (parent.row() + 1 < m_Root.children.size()) { sourceRow = m_Root.children[parent.row() + 1]->index; } } - - } } @@ -387,7 +390,8 @@ bool ModListByPriorityProxy::dropMimeData(const QMimeData* data, Qt::DropAction return sourceModel()->dropMimeData(data, action, sourceRow, column, QModelIndex()); } -QModelIndex ModListByPriorityProxy::index(int row, int column, const QModelIndex& parent) const +QModelIndex ModListByPriorityProxy::index(int row, int column, + const QModelIndex& parent) const { if (!hasIndex(row, column, parent)) { return QModelIndex(); @@ -396,15 +400,15 @@ QModelIndex ModListByPriorityProxy::index(int row, int column, const QModelIndex const TreeItem* parentItem; if (!parent.isValid()) { parentItem = &m_Root; - } - else { + } else { parentItem = static_cast<TreeItem*>(parent.internalPointer()); } return createIndex(row, column, parentItem->children[row]); } -void ModListByPriorityProxy::onDropEnter(const QMimeData*, bool dropExpanded, ModListView::DropPosition dropPosition) +void ModListByPriorityProxy::onDropEnter(const QMimeData*, bool dropExpanded, + ModListView::DropPosition dropPosition) { m_dropExpanded = dropExpanded; m_dropPosition = dropPosition; diff --git a/src/modlistbypriorityproxy.h b/src/modlistbypriorityproxy.h index 0629bef7..5617d222 100644 --- a/src/modlistbypriorityproxy.h +++ b/src/modlistbypriorityproxy.h @@ -6,11 +6,11 @@ #include <vector> #include <QAbstractProxyModel> +#include <QIcon> #include <QModelIndex> #include <QMultiHash> -#include <QStringList> -#include <QIcon> #include <QSet> +#include <QStringList> #include "modinfo.h" #include "modlistview.h" @@ -24,7 +24,8 @@ class ModListByPriorityProxy : public QAbstractProxyModel Q_OBJECT public: - explicit ModListByPriorityProxy(Profile* profile, OrganizerCore& core, QObject* parent = nullptr); + explicit ModListByPriorityProxy(Profile* profile, OrganizerCore& core, + QObject* parent = nullptr); ~ModListByPriorityProxy(); void setProfile(Profile* profile); @@ -37,29 +38,35 @@ public: int rowCount(const QModelIndex& parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex& child) const override; - QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; + QModelIndex index(int row, int column, + const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex& index) const override; bool hasChildren(const QModelIndex& parent) const override; - bool canDropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) const override; - bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) override; + bool canDropMimeData(const QMimeData* data, Qt::DropAction action, int row, + int column, const QModelIndex& parent) const override; + bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, + const QModelIndex& parent) override; QModelIndex mapFromSource(const QModelIndex& sourceIndex) const override; QModelIndex mapToSource(const QModelIndex& proxyIndex) const override; public slots: - void onDropEnter(const QMimeData* data, bool dropExpanded, ModListView::DropPosition dropPosition); + void onDropEnter(const QMimeData* data, bool dropExpanded, + ModListView::DropPosition dropPosition); protected slots: void onModelRowsRemoved(const QModelIndex& parent, int first, int last); - void onModelLayoutChanged(const QList<QPersistentModelIndex>& parents = {}, LayoutChangeHint hint = LayoutChangeHint::NoLayoutChangeHint); + void + onModelLayoutChanged(const QList<QPersistentModelIndex>& parents = {}, + LayoutChangeHint hint = LayoutChangeHint::NoLayoutChangeHint); void onModelReset(); - void onModelDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles = QVector<int>()); + void onModelDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, + const QVector<int>& roles = QVector<int>()); private: - // fill the mapping from index to item (required by buildTree), should // only be used for full model reset because it destroys existing references // to tree items @@ -71,13 +78,15 @@ private: // void buildTree(); - struct TreeItem { + struct TreeItem + { ModInfo::Ptr mod; unsigned int index; std::vector<TreeItem*> children; TreeItem* parent; - std::size_t childIndex(TreeItem* child) const { + std::size_t childIndex(TreeItem* child) const + { for (std::size_t i = 0; i < children.size(); ++i) { if (children[i] == child) { return i; @@ -86,9 +95,10 @@ private: return -1; } - TreeItem() : TreeItem(nullptr, -1) { } - TreeItem(ModInfo::Ptr mod, unsigned int index, TreeItem* parent = nullptr) : - mod(mod), index(index), parent(parent) { } + TreeItem() : TreeItem(nullptr, -1) {} + TreeItem(ModInfo::Ptr mod, unsigned int index, TreeItem* parent = nullptr) + : mod(mod), index(index), parent(parent) + {} }; TreeItem m_Root; @@ -98,9 +108,9 @@ private: OrganizerCore& m_core; Profile* m_profile; - Qt::SortOrder m_sortOrder = Qt::AscendingOrder; - bool m_dropExpanded = false; + Qt::SortOrder m_sortOrder = Qt::AscendingOrder; + bool m_dropExpanded = false; ModListView::DropPosition m_dropPosition = ModListView::DropPosition::OnItem; }; -#endif //GROUPINGPROXY_H +#endif // GROUPINGPROXY_H diff --git a/src/modlistcontextmenu.cpp b/src/modlistcontextmenu.cpp index 2d9577c5..e88cadc8 100644 --- a/src/modlistcontextmenu.cpp +++ b/src/modlistcontextmenu.cpp @@ -9,18 +9,24 @@ using namespace MOBase; -ModListGlobalContextMenu::ModListGlobalContextMenu(OrganizerCore& core, ModListView* view, QWidget* parent) - : ModListGlobalContextMenu(core, view, QModelIndex(), parent) -{ -} +ModListGlobalContextMenu::ModListGlobalContextMenu(OrganizerCore& core, + ModListView* view, QWidget* parent) + : ModListGlobalContextMenu(core, view, QModelIndex(), parent) +{} -ModListGlobalContextMenu::ModListGlobalContextMenu(OrganizerCore& core, ModListView* view, const QModelIndex& index, QWidget* parent) - : QMenu(parent) +ModListGlobalContextMenu::ModListGlobalContextMenu(OrganizerCore& core, + ModListView* view, + const QModelIndex& index, + QWidget* parent) + : QMenu(parent) { - connect(this, &QMenu::aboutToShow, [=, &core] { populate(core, view, index); }); + connect(this, &QMenu::aboutToShow, [=, &core] { + populate(core, view, index); + }); } -void ModListGlobalContextMenu::populate(OrganizerCore& core, ModListView* view, const QModelIndex& index) +void ModListGlobalContextMenu::populate(OrganizerCore& core, ModListView* view, + const QModelIndex& index) { clear(); @@ -32,25 +38,35 @@ void ModListGlobalContextMenu::populate(OrganizerCore& core, ModListView* view, // the mod are not created/installed at the same position depending // on the clicked mod and the sort order QString installText = tr("Install mod above... "); - QString createText = tr("Create empty mod above"); + QString createText = tr("Create empty mod above"); if (info->isSeparator()) { installText = tr("Install mod inside... "); - createText = tr("Create empty mod inside"); - } - else if (view->sortOrder() == Qt::DescendingOrder) { + createText = tr("Create empty mod inside"); + } else if (view->sortOrder() == Qt::DescendingOrder) { installText = tr("Install mod below... "); - createText = tr("Create empty mod below"); + createText = tr("Create empty mod below"); } - addAction(installText, [=]() { view->actions().installMod("", index); }); - addAction(createText, [=]() { view->actions().createEmptyMod(index); }); - addAction(tr("Create separator above"), [=]() { view->actions().createSeparator(index); }); + addAction(installText, [=]() { + view->actions().installMod("", index); + }); + addAction(createText, [=]() { + view->actions().createEmptyMod(index); + }); + addAction(tr("Create separator above"), [=]() { + view->actions().createSeparator(index); + }); } - } - else { - addAction(tr("Install mod..."), [=]() { view->actions().installMod(); }); - addAction(tr("Create empty mod"), [=]() { view->actions().createEmptyMod(); }); - addAction(tr("Create separator"), [=]() { view->actions().createSeparator(); }); + } else { + addAction(tr("Install mod..."), [=]() { + view->actions().installMod(); + }); + addAction(tr("Create empty mod"), [=]() { + view->actions().createEmptyMod(); + }); + addAction(tr("Create separator"), [=]() { + view->actions().createSeparator(); + }); } if (view->hasCollapsibleSeparators()) { @@ -61,25 +77,32 @@ void ModListGlobalContextMenu::populate(OrganizerCore& core, ModListView* view, addSeparator(); - QString enableTxt = tr("Enable all"), - disableTxt = tr("Disable all"); + QString enableTxt = tr("Enable all"), disableTxt = tr("Disable all"); if (view->isFilterActive()) { - enableTxt = tr("Enable all matching mods"); + enableTxt = tr("Enable all matching mods"); disableTxt = tr("Disable all matching mods"); } - addAction(enableTxt, [=] { view->actions().setAllMatchingModsEnabled(true); }); - addAction(disableTxt, [=] { view->actions().setAllMatchingModsEnabled(false); }); + addAction(enableTxt, [=] { + view->actions().setAllMatchingModsEnabled(true); + }); + addAction(disableTxt, [=] { + view->actions().setAllMatchingModsEnabled(false); + }); - addAction(tr("Check for updates"), [=]() { view->actions().checkModsForUpdates(); }); + addAction(tr("Check for updates"), [=]() { + view->actions().checkModsForUpdates(); + }); addAction(tr("Refresh"), &core, &OrganizerCore::profileRefresh); - addAction(tr("Export to csv..."), [=]() { view->actions().exportModListCSV(); }); + addAction(tr("Export to csv..."), [=]() { + view->actions().exportModListCSV(); + }); } - -ModListChangeCategoryMenu::ModListChangeCategoryMenu(CategoryFactory& categories, ModInfo::Ptr mod, QMenu* parent) - : QMenu(tr("Change Categories"), parent) +ModListChangeCategoryMenu::ModListChangeCategoryMenu(CategoryFactory& categories, + ModInfo::Ptr mod, QMenu* parent) + : QMenu(tr("Change Categories"), parent) { populate(this, categories, mod); } @@ -89,15 +112,15 @@ std::vector<std::pair<int, bool>> ModListChangeCategoryMenu::categories() const return categories(this); } -std::vector<std::pair<int, bool>> ModListChangeCategoryMenu::categories(const QMenu* menu) const +std::vector<std::pair<int, bool>> +ModListChangeCategoryMenu::categories(const QMenu* menu) const { std::vector<std::pair<int, bool>> cats; for (QAction* action : menu->actions()) { if (action->menu() != nullptr) { auto pcats = categories(action->menu()); cats.insert(cats.end(), pcats.begin(), pcats.end()); - } - else { + } else { QWidgetAction* widgetAction = qobject_cast<QWidgetAction*>(action); if (widgetAction != nullptr) { QCheckBox* checkbox = qobject_cast<QCheckBox*>(widgetAction->defaultWidget()); @@ -108,7 +131,8 @@ std::vector<std::pair<int, bool>> ModListChangeCategoryMenu::categories(const QM return cats; } -bool ModListChangeCategoryMenu::populate(QMenu* menu, CategoryFactory& factory, ModInfo::Ptr mod, int targetId) +bool ModListChangeCategoryMenu::populate(QMenu* menu, CategoryFactory& factory, + ModInfo::Ptr mod, int targetId) { const std::set<int>& categories = mod->getCategories(); @@ -145,28 +169,30 @@ bool ModListChangeCategoryMenu::populate(QMenu* menu, CategoryFactory& factory, return childEnabled; } -ModListPrimaryCategoryMenu::ModListPrimaryCategoryMenu(CategoryFactory& categories, ModInfo::Ptr mod, QMenu* parent) - : QMenu(tr("Primary Category"), parent) +ModListPrimaryCategoryMenu::ModListPrimaryCategoryMenu(CategoryFactory& categories, + ModInfo::Ptr mod, QMenu* parent) + : QMenu(tr("Primary Category"), parent) { - connect(this, &QMenu::aboutToShow, [=]() { populate(categories, mod); }); + connect(this, &QMenu::aboutToShow, [=]() { + populate(categories, mod); + }); } -void ModListPrimaryCategoryMenu::populate(const CategoryFactory& factory, ModInfo::Ptr mod) +void ModListPrimaryCategoryMenu::populate(const CategoryFactory& factory, + ModInfo::Ptr mod) { clear(); const std::set<int>& categories = mod->getCategories(); for (int categoryID : categories) { - int catIdx = factory.getCategoryIndex(categoryID); + int catIdx = factory.getCategoryIndex(categoryID); QWidgetAction* action = new QWidgetAction(this); try { - QRadioButton* categoryBox = new QRadioButton( - factory.getCategoryName(catIdx).replace('&', "&&"), - this); + QRadioButton* categoryBox = + new QRadioButton(factory.getCategoryName(catIdx).replace('&', "&&"), this); categoryBox->setChecked(categoryID == mod->primaryCategory()); action->setDefaultWidget(categoryBox); action->setData(categoryID); - } - catch (const std::exception& e) { + } catch (const std::exception& e) { log::error("failed to create category checkbox: {}", e.what()); } @@ -189,25 +215,22 @@ int ModListPrimaryCategoryMenu::primaryCategory() const return -1; } -ModListContextMenu::ModListContextMenu( - const QModelIndex& index, OrganizerCore& core, CategoryFactory& categories, ModListView* view) : - QMenu(view) - , m_core(core) - , m_categories(categories) - , m_index(index.model() == view->model() ? view->indexViewToModel(index) : index) - , m_view(view) - , m_actions(view->actions()) +ModListContextMenu::ModListContextMenu(const QModelIndex& index, OrganizerCore& core, + CategoryFactory& categories, ModListView* view) + : QMenu(view), m_core(core), m_categories(categories), + m_index(index.model() == view->model() ? view->indexViewToModel(index) : index), + m_view(view), m_actions(view->actions()) { if (view->selectionModel()->hasSelection()) { m_selected = view->indexViewToModel(view->selectionModel()->selectedRows()); - } - else { - m_selected = { index }; + } else { + m_selected = {index}; } ModInfo::Ptr info = ModInfo::getByIndex(index.data(ModList::IndexRole).toInt()); - QMenu* allMods = new ModListGlobalContextMenu(core, view, m_index, view->topLevelWidget()); + QMenu* allMods = + new ModListGlobalContextMenu(core, view, m_index, view->topLevelWidget()); allMods->setTitle(tr("All Mods")); addMenu(allMods); @@ -228,23 +251,21 @@ ModListContextMenu::ModListContextMenu( // Add type-specific items if (info->isOverwrite()) { addOverwriteActions(info); - } - else if (info->isBackup()) { + } else if (info->isBackup()) { addBackupActions(info); - } - else if (info->isSeparator()) { + } else if (info->isSeparator()) { addSeparatorActions(info); - } - else if (info->isForeign()) { + } else if (info->isForeign()) { addForeignActions(info); - } - else { + } else { addRegularActions(info); } // add information for all except foreign if (!info->isForeign()) { - QAction* infoAction = addAction(tr("Information..."), [=]() { view->actions().displayModInformation(m_index.data(ModList::IndexRole).toInt()); }); + QAction* infoAction = addAction(tr("Information..."), [=]() { + view->actions().displayModInformation(m_index.data(ModList::IndexRole).toInt()); + }); setDefaultAction(infoAction); } } @@ -261,28 +282,26 @@ void ModListContextMenu::addMenuAsPushButton(QMenu* menu) void ModListContextMenu::addSendToContextMenu() { static const std::vector overwritten_flags{ - ModInfo::EConflictFlag::FLAG_CONFLICT_MIXED, - ModInfo::EConflictFlag::FLAG_CONFLICT_OVERWRITTEN, - ModInfo::EConflictFlag::FLAG_CONFLICT_REDUNDANT - }; + ModInfo::EConflictFlag::FLAG_CONFLICT_MIXED, + ModInfo::EConflictFlag::FLAG_CONFLICT_OVERWRITTEN, + ModInfo::EConflictFlag::FLAG_CONFLICT_REDUNDANT}; static const std::vector overwrite_flags{ - ModInfo::EConflictFlag::FLAG_CONFLICT_MIXED, - ModInfo::EConflictFlag::FLAG_CONFLICT_OVERWRITE - }; + ModInfo::EConflictFlag::FLAG_CONFLICT_MIXED, + ModInfo::EConflictFlag::FLAG_CONFLICT_OVERWRITE}; bool overwrite = false, overwritten = false; for (auto& idx : m_selected) { auto index = idx.data(ModList::IndexRole); if (index.isValid()) { - auto info = ModInfo::getByIndex(index.toInt()); + auto info = ModInfo::getByIndex(index.toInt()); auto flags = info->getConflictFlags(); - if (std::find_first_of(flags.begin(), flags.end(), - overwritten_flags.begin(), overwritten_flags.end()) != flags.end()) { + if (std::find_first_of(flags.begin(), flags.end(), overwritten_flags.begin(), + overwritten_flags.end()) != flags.end()) { overwritten = true; } - if (std::find_first_of(flags.begin(), flags.end(), - overwrite_flags.begin(), overwrite_flags.end()) != flags.end()) { + if (std::find_first_of(flags.begin(), flags.end(), overwrite_flags.begin(), + overwrite_flags.end()) != flags.end()) { overwrite = true; } } @@ -290,28 +309,42 @@ void ModListContextMenu::addSendToContextMenu() QMenu* menu = new QMenu(m_view); menu->setTitle(tr("Send to... ")); - menu->addAction(tr("Lowest priority"), [this] { m_actions.sendModsToTop(m_selected); }); - menu->addAction(tr("Highest priority"), [this] { m_actions.sendModsToBottom(m_selected); }); - menu->addAction(tr("Priority..."), [this] { m_actions.sendModsToPriority(m_selected); }); - menu->addAction(tr("Separator..."), [this] { m_actions.sendModsToSeparator(m_selected); }); + menu->addAction(tr("Lowest priority"), [this] { + m_actions.sendModsToTop(m_selected); + }); + menu->addAction(tr("Highest priority"), [this] { + m_actions.sendModsToBottom(m_selected); + }); + menu->addAction(tr("Priority..."), [this] { + m_actions.sendModsToPriority(m_selected); + }); + menu->addAction(tr("Separator..."), [this] { + m_actions.sendModsToSeparator(m_selected); + }); if (overwrite) { - menu->addAction(tr("First conflict"), [this] { m_actions.sendModsToFirstConflict(m_selected); }); + menu->addAction(tr("First conflict"), [this] { + m_actions.sendModsToFirstConflict(m_selected); + }); } if (overwritten) { - menu->addAction(tr("Last conflict"), [this] { m_actions.sendModsToLastConflict(m_selected); }); + menu->addAction(tr("Last conflict"), [this] { + m_actions.sendModsToLastConflict(m_selected); + }); } addMenu(menu); } void ModListContextMenu::addCategoryContextMenus(ModInfo::Ptr mod) { - ModListChangeCategoryMenu* categoriesMenu = new ModListChangeCategoryMenu(m_categories, mod, this); + ModListChangeCategoryMenu* categoriesMenu = + new ModListChangeCategoryMenu(m_categories, mod, this); connect(categoriesMenu, &QMenu::aboutToHide, [=]() { m_actions.setCategories(m_selected, m_index, categoriesMenu->categories()); }); addMenuAsPushButton(categoriesMenu); - ModListPrimaryCategoryMenu* primaryCategoryMenu = new ModListPrimaryCategoryMenu(m_categories, mod, this); + ModListPrimaryCategoryMenu* primaryCategoryMenu = + new ModListPrimaryCategoryMenu(m_categories, mod, this); connect(primaryCategoryMenu, &QMenu::aboutToHide, [=]() { int category = primaryCategoryMenu->primaryCategory(); if (category != -1) { @@ -324,12 +357,22 @@ void ModListContextMenu::addCategoryContextMenus(ModInfo::Ptr mod) void ModListContextMenu::addOverwriteActions(ModInfo::Ptr mod) { if (QDir(mod->absolutePath()).count() > 2) { - addAction(tr("Sync to Mods..."), [=]() { m_core.syncOverwrite(); }); - addAction(tr("Create Mod..."), [=]() { m_actions.createModFromOverwrite(); }); - addAction(tr("Move content to Mod..."), [=]() { m_actions.moveOverwriteContentToExistingMod(); }); - addAction(tr("Clear Overwrite..."), [=]() { m_actions.clearOverwrite(); }); + addAction(tr("Sync to Mods..."), [=]() { + m_core.syncOverwrite(); + }); + addAction(tr("Create Mod..."), [=]() { + m_actions.createModFromOverwrite(); + }); + addAction(tr("Move content to Mod..."), [=]() { + m_actions.moveOverwriteContentToExistingMod(); + }); + addAction(tr("Clear Overwrite..."), [=]() { + m_actions.clearOverwrite(); + }); } - addAction(tr("Open in Explorer"), [=]() { m_actions.openExplorer(m_selected); }); + addAction(tr("Open in Explorer"), [=]() { + m_actions.openExplorer(m_selected); + }); } void ModListContextMenu::addSeparatorActions(ModInfo::Ptr mod) @@ -337,19 +380,26 @@ void ModListContextMenu::addSeparatorActions(ModInfo::Ptr mod) addCategoryContextMenus(mod); addSeparator(); - - addAction(tr("Rename Separator..."), [=]() { m_actions.renameMod(m_index); }); - addAction(tr("Remove Separator..."), [=]() { m_actions.removeMods(m_selected); }); + addAction(tr("Rename Separator..."), [=]() { + m_actions.renameMod(m_index); + }); + addAction(tr("Remove Separator..."), [=]() { + m_actions.removeMods(m_selected); + }); addSeparator(); if (m_view->sortColumn() == ModList::COL_PRIORITY) { addSendToContextMenu(); addSeparator(); } - addAction(tr("Select Color..."), [=]() { m_actions.setColor(m_selected, m_index); }); + addAction(tr("Select Color..."), [=]() { + m_actions.setColor(m_selected, m_index); + }); if (mod->color().isValid()) { - addAction(tr("Reset Color"), [=]() { m_actions.resetColor(m_selected); }); + addAction(tr("Reset Color"), [=]() { + m_actions.resetColor(m_selected); + }); } addSeparator(); @@ -365,26 +415,41 @@ void ModListContextMenu::addForeignActions(ModInfo::Ptr mod) void ModListContextMenu::addBackupActions(ModInfo::Ptr mod) { auto flags = mod->getFlags(); - addAction(tr("Restore Backup"), [=]() { m_actions.restoreBackup(m_index); }); - addAction(tr("Remove Backup..."), [=]() { m_actions.removeMods(m_selected); }); + addAction(tr("Restore Backup"), [=]() { + m_actions.restoreBackup(m_index); + }); + addAction(tr("Remove Backup..."), [=]() { + m_actions.removeMods(m_selected); + }); addSeparator(); if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_INVALID) != flags.end()) { - addAction(tr("Ignore missing data"), [=]() { m_actions.ignoreMissingData(m_selected); }); + addAction(tr("Ignore missing data"), [=]() { + m_actions.ignoreMissingData(m_selected); + }); } - if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_ALTERNATE_GAME) != flags.end()) { - addAction(tr("Mark as converted/working"), [=]() { m_actions.markConverted(m_selected); }); + if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_ALTERNATE_GAME) != + flags.end()) { + addAction(tr("Mark as converted/working"), [=]() { + m_actions.markConverted(m_selected); + }); } addSeparator(); if (mod->nexusId() > 0) { - addAction(tr("Visit on Nexus"), [=]() { m_actions.visitOnNexus(m_selected); }); + addAction(tr("Visit on Nexus"), [=]() { + m_actions.visitOnNexus(m_selected); + }); } const auto url = mod->parseCustomURL(); if (url.isValid()) { - addAction(tr("Visit on %1").arg(url.host()), [=]() { m_actions.visitWebPage(m_selected); }); + addAction(tr("Visit on %1").arg(url.host()), [=]() { + m_actions.visitWebPage(m_selected); + }); } - addAction(tr("Open in Explorer"), [=]() { m_actions.openExplorer(m_selected); }); + addAction(tr("Open in Explorer"), [=]() { + m_actions.openExplorer(m_selected); + }); } void ModListContextMenu::addRegularActions(ModInfo::Ptr mod) @@ -395,47 +460,72 @@ void ModListContextMenu::addRegularActions(ModInfo::Ptr mod) addSeparator(); if (mod->downgradeAvailable()) { - addAction(tr("Change versioning scheme"), [=]() { m_actions.changeVersioningScheme(m_index); }); + addAction(tr("Change versioning scheme"), [=]() { + m_actions.changeVersioningScheme(m_index); + }); } if (mod->nexusId() > 0) - addAction(tr("Force-check updates"), [=]() { m_actions.checkModsForUpdates(m_selected); }); + addAction(tr("Force-check updates"), [=]() { + m_actions.checkModsForUpdates(m_selected); + }); if (mod->updateIgnored()) { - addAction(tr("Un-ignore update"), [=]() { m_actions.setIgnoreUpdate(m_selected, false); }); - } - else { + addAction(tr("Un-ignore update"), [=]() { + m_actions.setIgnoreUpdate(m_selected, false); + }); + } else { if (mod->updateAvailable() || mod->downgradeAvailable()) { - addAction(tr("Ignore update"), [=]() { m_actions.setIgnoreUpdate(m_selected, true); }); + addAction(tr("Ignore update"), [=]() { + m_actions.setIgnoreUpdate(m_selected, true); + }); } } addSeparator(); - addAction(tr("Enable selected"), [=]() { m_core.modList()->setActive(m_selected, true); }); - addAction(tr("Disable selected"), [=]() { m_core.modList()->setActive(m_selected, false); }); + addAction(tr("Enable selected"), [=]() { + m_core.modList()->setActive(m_selected, true); + }); + addAction(tr("Disable selected"), [=]() { + m_core.modList()->setActive(m_selected, false); + }); addSeparator(); - if (m_view->sortColumn() == ModList::COL_PRIORITY) { addSendToContextMenu(); addSeparator(); } - addAction(tr("Rename Mod..."), [=]() { m_actions.renameMod(m_index); }); - addAction(tr("Reinstall Mod"), [=]() { m_actions.reinstallMod(m_index); }); - addAction(tr("Remove Mod..."), [=]() { m_actions.removeMods(m_selected); }); - addAction(tr("Create Backup"), [=]() { m_actions.createBackup(m_index); }); + addAction(tr("Rename Mod..."), [=]() { + m_actions.renameMod(m_index); + }); + addAction(tr("Reinstall Mod"), [=]() { + m_actions.reinstallMod(m_index); + }); + addAction(tr("Remove Mod..."), [=]() { + m_actions.removeMods(m_selected); + }); + addAction(tr("Create Backup"), [=]() { + m_actions.createBackup(m_index); + }); - if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_HIDDEN_FILES) != flags.end()) { - addAction(tr("Restore hidden files"), [=]() { m_actions.restoreHiddenFiles(m_selected); }); + if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_HIDDEN_FILES) != + flags.end()) { + addAction(tr("Restore hidden files"), [=]() { + m_actions.restoreHiddenFiles(m_selected); + }); } addSeparator(); if (m_index.column() == ModList::COL_NOTES) { - addAction(tr("Select Color..."), [=]() { m_actions.setColor(m_selected, m_index); }); + addAction(tr("Select Color..."), [=]() { + m_actions.setColor(m_selected, m_index); + }); if (mod->color().isValid()) { - addAction(tr("Reset Color"), [=]() { m_actions.resetColor(m_selected); }); + addAction(tr("Reset Color"), [=]() { + m_actions.resetColor(m_selected); + }); } addSeparator(); } @@ -443,14 +533,22 @@ void ModListContextMenu::addRegularActions(ModInfo::Ptr mod) if (mod->nexusId() > 0 && Settings::instance().nexus().endorsementIntegration()) { switch (mod->endorsedState()) { case EndorsedState::ENDORSED_TRUE: { - addAction(tr("Un-Endorse"), [=]() { m_actions.setEndorsed(m_selected, false); }); + addAction(tr("Un-Endorse"), [=]() { + m_actions.setEndorsed(m_selected, false); + }); } break; case EndorsedState::ENDORSED_FALSE: { - addAction(tr("Endorse"), [=]() { m_actions.setEndorsed(m_selected, true); }); - addAction(tr("Won't endorse"), [=]() { m_actions.willNotEndorsed(m_selected); }); + addAction(tr("Endorse"), [=]() { + m_actions.setEndorsed(m_selected, true); + }); + addAction(tr("Won't endorse"), [=]() { + m_actions.willNotEndorsed(m_selected); + }); } break; case EndorsedState::ENDORSED_NEVER: { - addAction(tr("Endorse"), [=]() { m_actions.setEndorsed(m_selected, true); }); + addAction(tr("Endorse"), [=]() { + m_actions.setEndorsed(m_selected, true); + }); } break; default: { QAction* action = new QAction(tr("Endorsement state unknown"), this); @@ -463,10 +561,14 @@ void ModListContextMenu::addRegularActions(ModInfo::Ptr mod) if (mod->nexusId() > 0 && Settings::instance().nexus().trackedIntegration()) { switch (mod->trackedState()) { case TrackedState::TRACKED_FALSE: { - addAction(tr("Start tracking"), [=]() { m_actions.setTracked(m_selected, true); }); + addAction(tr("Start tracking"), [=]() { + m_actions.setTracked(m_selected, true); + }); } break; case TrackedState::TRACKED_TRUE: { - addAction(tr("Stop tracking"), [=]() { m_actions.setTracked(m_selected, false); }); + addAction(tr("Stop tracking"), [=]() { + m_actions.setTracked(m_selected, false); + }); } break; default: { QAction* action = new QAction(tr("Tracked state unknown"), this); @@ -479,23 +581,34 @@ void ModListContextMenu::addRegularActions(ModInfo::Ptr mod) addSeparator(); if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_INVALID) != flags.end()) { - addAction(tr("Ignore missing data"), [=]() { m_actions.ignoreMissingData(m_selected); }); + addAction(tr("Ignore missing data"), [=]() { + m_actions.ignoreMissingData(m_selected); + }); } - if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_ALTERNATE_GAME) != flags.end()) { - addAction(tr("Mark as converted/working"), [=]() { m_actions.markConverted(m_selected); }); + if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_ALTERNATE_GAME) != + flags.end()) { + addAction(tr("Mark as converted/working"), [=]() { + m_actions.markConverted(m_selected); + }); } addSeparator(); if (mod->nexusId() > 0) { - addAction(tr("Visit on Nexus"), [=]() { m_actions.visitOnNexus(m_selected); }); + addAction(tr("Visit on Nexus"), [=]() { + m_actions.visitOnNexus(m_selected); + }); } const auto url = mod->parseCustomURL(); if (url.isValid()) { - addAction(tr("Visit on %1").arg(url.host()), [=]() { m_actions.visitWebPage(m_selected); }); + addAction(tr("Visit on %1").arg(url.host()), [=]() { + m_actions.visitWebPage(m_selected); + }); } - addAction(tr("Open in Explorer"), [=]() { m_actions.openExplorer(m_selected); }); + addAction(tr("Open in Explorer"), [=]() { + m_actions.openExplorer(m_selected); + }); } diff --git a/src/modlistcontextmenu.h b/src/modlistcontextmenu.h index 8a6ce3df..320ece93 100644 --- a/src/modlistcontextmenu.h +++ b/src/modlistcontextmenu.h @@ -18,39 +18,37 @@ class ModListGlobalContextMenu : public QMenu { Q_OBJECT public: - - ModListGlobalContextMenu(OrganizerCore& core, ModListView* view, QWidget* parent = nullptr); + ModListGlobalContextMenu(OrganizerCore& core, ModListView* view, + QWidget* parent = nullptr); protected: - friend class ModListContextMenu; // populate the menu void populate(OrganizerCore& core, ModListView* view, const QModelIndex& index); // creates a "All mods" context menu for the given index (can be invalid). - ModListGlobalContextMenu(OrganizerCore& core, ModListView* view, const QModelIndex& index, QWidget* parent = nullptr); - + ModListGlobalContextMenu(OrganizerCore& core, ModListView* view, + const QModelIndex& index, QWidget* parent = nullptr); }; class ModListChangeCategoryMenu : public QMenu { Q_OBJECT public: - - ModListChangeCategoryMenu( - CategoryFactory& categories, ModInfo::Ptr mod, QMenu* parent = nullptr); + ModListChangeCategoryMenu(CategoryFactory& categories, ModInfo::Ptr mod, + QMenu* parent = nullptr); // return a list of pair <category id, enabled> from the menu // std::vector<std::pair<int, bool>> categories() const; private: - // populate the tree with the category, using the enabled/disabled state from the // given mod // - bool populate(QMenu* menu, CategoryFactory& categories, ModInfo::Ptr mod, int targetId = 0); + bool populate(QMenu* menu, CategoryFactory& categories, ModInfo::Ptr mod, + int targetId = 0); // internal implementation of categories() for recursion // @@ -61,19 +59,17 @@ class ModListPrimaryCategoryMenu : public QMenu { Q_OBJECT public: - - ModListPrimaryCategoryMenu(CategoryFactory& categories, ModInfo::Ptr mod, QMenu* parent = nullptr); + ModListPrimaryCategoryMenu(CategoryFactory& categories, ModInfo::Ptr mod, + QMenu* parent = nullptr); // return the selected primary category // int primaryCategory() const; private: - // populate the categories // void populate(const CategoryFactory& categories, ModInfo::Ptr mod); - }; class ModListContextMenu : public QMenu @@ -81,14 +77,13 @@ class ModListContextMenu : public QMenu Q_OBJECT public: - - // creates a new context menu, the given index is the one for the click and should be valid + // creates a new context menu, the given index is the one for the click and should be + // valid // - ModListContextMenu( - const QModelIndex& index, OrganizerCore& core, CategoryFactory& categories, ModListView* modListView); + ModListContextMenu(const QModelIndex& index, OrganizerCore& core, + CategoryFactory& categories, ModListView* modListView); private: - // adds the "Send to... " context menu // void addSendToContextMenu(); @@ -101,7 +96,6 @@ private: // void addMenuAsPushButton(QMenu* menu); - // add actions/menus to this menu for each type of mod // void addOverwriteActions(ModInfo::Ptr mod); @@ -115,8 +109,7 @@ private: QModelIndex m_index; QModelIndexList m_selected; ModListView* m_view; - ModListViewActions& m_actions; // shortcut for m_view->actions() - + ModListViewActions& m_actions; // shortcut for m_view->actions() }; #endif diff --git a/src/modlistdropinfo.cpp b/src/modlistdropinfo.cpp index a247194f..f0bb51bc 100644 --- a/src/modlistdropinfo.cpp +++ b/src/modlistdropinfo.cpp @@ -2,12 +2,13 @@ #include "organizercore.h" -ModListDropInfo::ModListDropInfo(const QMimeData* mimeData, OrganizerCore& core) : - m_rows{}, m_download{ -1 }, m_localUrls{}, m_url{} +ModListDropInfo::ModListDropInfo(const QMimeData* mimeData, OrganizerCore& core) + : m_rows{}, m_download{-1}, m_localUrls{}, m_url{} { // this only check if the drop is valid, not if the content of the drop // matches the target, a drop is valid if either - // 1. it contains items from another model (drag&drop in modlist or from download list) + // 1. it contains items from another model (drag&drop in modlist or from download + // list) // 2. it contains URLs from MO2 (overwrite or from another mod) // 3. it contains a single URL to an external folder // 4. it contains a single URL to a valid archive for MO2 @@ -27,15 +28,14 @@ ModListDropInfo::ModListDropInfo(const QMimeData* mimeData, OrganizerCore& core) QFileInfo info(url.toLocalFile()); if (info.isDir()) { m_url = url; - } - else if (core.installationManager()->getSupportedExtensions().contains(info.suffix(), Qt::CaseInsensitive)) { + } else if (core.installationManager()->getSupportedExtensions().contains( + info.suffix(), Qt::CaseInsensitive)) { m_url = url; } } } - } - else if (mimeData->hasText()) { + } else if (mimeData->hasText()) { QByteArray encoded = mimeData->data("application/x-qabstractitemmodeldatalist"); QDataStream stream(&encoded, QIODevice::ReadOnly); @@ -55,16 +55,16 @@ ModListDropInfo::ModListDropInfo(const QMimeData* mimeData, OrganizerCore& core) m_rows = {}; } } - } - catch (std::exception const&) { - m_rows = {}; + } catch (std::exception const&) { + m_rows = {}; m_download = -1; m_localUrls.clear(); m_url = {}; } } -std::optional<ModListDropInfo::RelativeUrl> ModListDropInfo::relativeUrl(const QUrl& url) const +std::optional<ModListDropInfo::RelativeUrl> +ModListDropInfo::relativeUrl(const QUrl& url) const { if (!url.isLocalFile()) { return {}; @@ -82,12 +82,12 @@ std::optional<ModListDropInfo::RelativeUrl> ModListDropInfo::relativeUrl(const Q if (sourceFile.startsWith(allModsDir.canonicalPath())) { QDir relativeDir(allModsDir.relativeFilePath(sourceFile)); QStringList splitPath = relativeDir.path().split("/"); - originName = splitPath[0]; + originName = splitPath[0]; splitPath.pop_front(); - return { { url, splitPath.join("/"), originName } }; - } - else if (sourceFile.startsWith(overwriteDir.canonicalPath())) { - return { { url, overwriteDir.relativeFilePath(sourceFile), ModInfo::getOverwrite()->name() } }; + return {{url, splitPath.join("/"), originName}}; + } else if (sourceFile.startsWith(overwriteDir.canonicalPath())) { + return {{url, overwriteDir.relativeFilePath(sourceFile), + ModInfo::getOverwrite()->name()}}; } return {}; diff --git a/src/modlistdropinfo.h b/src/modlistdropinfo.h index 5d2af92f..3082e2a1 100644 --- a/src/modlistdropinfo.h +++ b/src/modlistdropinfo.h @@ -12,25 +12,24 @@ class OrganizerCore; // small class that extract information from mimeData // -class ModListDropInfo { +class ModListDropInfo +{ public: - // text value for the mime-data for the various possible // origin (not for external drops) // - static constexpr const char* ModText = "mod"; + static constexpr const char* ModText = "mod"; static constexpr const char* DownloadText = "download"; public: - - struct RelativeUrl { + struct RelativeUrl + { const QUrl url; const QString relativePath; const QString originName; }; public: - ModListDropInfo(const QMimeData* mimeData, OrganizerCore& core); // returns true if this drop is valid @@ -68,7 +67,6 @@ public: const auto& externalUrl() const { return m_url; } private: - friend class ModList; // retrieve the relative path of file and its origin given a URL from Mime data @@ -77,10 +75,9 @@ private: std::optional<RelativeUrl> relativeUrl(const QUrl&) const; private: - // rows for drag&drop between views std::vector<int> m_rows; - int m_download; // -1 if invalid + int m_download; // -1 if invalid // local URLs from the data (relative path + origin name) std::vector<RelativeUrl> m_localUrls; diff --git a/src/modlistproxy.cpp b/src/modlistproxy.cpp index cae5b1f7..1d8481ba 100644 --- a/src/modlistproxy.cpp +++ b/src/modlistproxy.cpp @@ -1,13 +1,14 @@ #include "modlistproxy.h" +#include "modlist.h" #include "organizerproxy.h" #include "proxyutils.h" -#include "modlist.h" using namespace MOBase; using namespace MOShared; -ModListProxy::ModListProxy(OrganizerProxy* oproxy, ModList* modlist) : - m_OrganizerProxy(oproxy), m_Proxied(modlist) { } +ModListProxy::ModListProxy(OrganizerProxy* oproxy, ModList* modlist) + : m_OrganizerProxy(oproxy), m_Proxied(modlist) +{} ModListProxy::~ModListProxy() { @@ -16,10 +17,14 @@ ModListProxy::~ModListProxy() void ModListProxy::connectSignals() { - m_Connections.push_back(m_Proxied->onModInstalled(callSignalIfPluginActive(m_OrganizerProxy, m_ModInstalled))); - m_Connections.push_back(m_Proxied->onModMoved(callSignalIfPluginActive(m_OrganizerProxy, m_ModMoved))); - m_Connections.push_back(m_Proxied->onModRemoved(callSignalIfPluginActive(m_OrganizerProxy, m_ModRemoved))); - m_Connections.push_back(m_Proxied->onModStateChanged(callSignalIfPluginActive(m_OrganizerProxy, m_ModStateChanged))); + m_Connections.push_back(m_Proxied->onModInstalled( + callSignalIfPluginActive(m_OrganizerProxy, m_ModInstalled))); + m_Connections.push_back( + m_Proxied->onModMoved(callSignalIfPluginActive(m_OrganizerProxy, m_ModMoved))); + m_Connections.push_back(m_Proxied->onModRemoved( + callSignalIfPluginActive(m_OrganizerProxy, m_ModRemoved))); + m_Connections.push_back(m_Proxied->onModStateChanged( + callSignalIfPluginActive(m_OrganizerProxy, m_ModStateChanged))); } void ModListProxy::disconnectSignals() @@ -55,7 +60,8 @@ bool ModListProxy::removeMod(MOBase::IModInterface* mod) return m_Proxied->removeMod(mod); } -MOBase::IModInterface* ModListProxy::renameMod(MOBase::IModInterface* mod, const QString& name) +MOBase::IModInterface* ModListProxy::renameMod(MOBase::IModInterface* mod, + const QString& name) { return m_Proxied->renameMod(mod, name); } @@ -95,7 +101,8 @@ bool ModListProxy::onModRemoved(const std::function<void(QString const&)>& func) return m_ModRemoved.connect(func).connected(); } -bool ModListProxy::onModStateChanged(const std::function<void(const std::map<QString, ModStates>&)>& func) +bool ModListProxy::onModStateChanged( + const std::function<void(const std::map<QString, ModStates>&)>& func) { return m_ModStateChanged.connect(func).connected(); } diff --git a/src/modlistproxy.h b/src/modlistproxy.h index d886d8b5..dc6fff9b 100644 --- a/src/modlistproxy.h +++ b/src/modlistproxy.h @@ -1,8 +1,8 @@ #ifndef MODLISTPROXY_H #define MODLISTPROXY_H -#include <imodlist.h> #include "modlist.h" +#include <imodlist.h> class OrganizerProxy; @@ -10,28 +10,29 @@ class ModListProxy : public MOBase::IModList { public: - ModListProxy(OrganizerProxy* oproxy, ModList* modlist); virtual ~ModListProxy(); QString displayName(const QString& internalName) const override; QStringList allMods() const override; - QStringList allModsByProfilePriority(MOBase::IProfile* profile = nullptr) const override; + QStringList + allModsByProfilePriority(MOBase::IProfile* profile = nullptr) const override; MOBase::IModInterface* getMod(const QString& name) const override; bool removeMod(MOBase::IModInterface* mod) override; - MOBase::IModInterface* renameMod(MOBase::IModInterface* mod, const QString& name) override; + MOBase::IModInterface* renameMod(MOBase::IModInterface* mod, + const QString& name) override; ModStates state(const QString& name) const override; bool setActive(const QString& name, bool active) override; int setActive(const QStringList& names, bool active) override; int priority(const QString& name) const override; bool setPriority(const QString& name, int newPriority) override; - bool onModInstalled(const std::function<void(MOBase::IModInterface *)>& func) override; + bool onModInstalled(const std::function<void(MOBase::IModInterface*)>& func) override; bool onModRemoved(const std::function<void(QString const&)>& func) override; - bool onModStateChanged(const std::function<void(const std::map<QString, ModStates>&)>& func) override; + bool onModStateChanged( + const std::function<void(const std::map<QString, ModStates>&)>& func) override; bool onModMoved(const std::function<void(const QString&, int, int)>& func) override; private: - friend class OrganizerProxy; // See OrganizerProxy::connectSignals(). @@ -49,4 +50,4 @@ private: std::vector<boost::signals2::connection> m_Connections; }; -#endif // ORGANIZERPROXY_H +#endif // ORGANIZERPROXY_H diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp index 1795ff3c..704ec10b 100644 --- a/src/modlistsortproxy.cpp +++ b/src/modlistsortproxy.cpp @@ -18,38 +18,35 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ #include "modlistsortproxy.h" +#include "messagedialog.h" +#include "modinfo.h" #include "modlistbypriorityproxy.h" #include "modlistdropinfo.h" -#include "modinfo.h" +#include "organizercore.h" #include "profile.h" -#include "messagedialog.h" #include "qtgroupingproxy.h" -#include "organizercore.h" -#include <log.h> -#include <QMenu> -#include <QCheckBox> -#include <QWidgetAction> #include <QApplication> -#include <QMimeData> +#include <QCheckBox> #include <QDebug> +#include <QMenu> +#include <QMimeData> #include <QTreeView> +#include <QWidgetAction> +#include <log.h> using namespace MOBase; -ModListSortProxy::ModListSortProxy(Profile* profile, OrganizerCore * organizer) - : QSortFilterProxyModel(organizer) - , m_Organizer(organizer) - , m_Profile(profile) - , m_FilterActive(false) - , m_FilterMode(FilterAnd) - , m_FilterSeparators(SeparatorFilter) +ModListSortProxy::ModListSortProxy(Profile* profile, OrganizerCore* organizer) + : QSortFilterProxyModel(organizer), m_Organizer(organizer), m_Profile(profile), + m_FilterActive(false), m_FilterMode(FilterAnd), + m_FilterSeparators(SeparatorFilter) { - setDynamicSortFilter(true); // this seems to work without dynamicsortfilter - // but I don't know why. This should be necessary + setDynamicSortFilter(true); // this seems to work without dynamicsortfilter + // but I don't know why. This should be necessary } -void ModListSortProxy::setProfile(Profile *profile) +void ModListSortProxy::setProfile(Profile* profile) { m_Profile = profile; } @@ -64,9 +61,8 @@ void ModListSortProxy::setCriteria(const std::vector<Criteria>& criteria) { // avoid refreshing the filter unless we are checking all mods for update. const bool changed = (criteria != m_Criteria); - const bool isForUpdates = ( - !criteria.empty() && - criteria[0].id == CategoryFactory::UpdateAvailable); + const bool isForUpdates = + (!criteria.empty() && criteria[0].id == CategoryFactory::UpdateAvailable); if (changed || isForUpdates) { m_Criteria = criteria; @@ -76,19 +72,19 @@ void ModListSortProxy::setCriteria(const std::vector<Criteria>& criteria) } } -unsigned long ModListSortProxy::flagsId(const std::vector<ModInfo::EFlag> &flags) const +unsigned long ModListSortProxy::flagsId(const std::vector<ModInfo::EFlag>& flags) const { unsigned long result = 0; for (ModInfo::EFlag flag : flags) { - if ((flag != ModInfo::FLAG_FOREIGN) - && (flag != ModInfo::FLAG_OVERWRITE)) { + if ((flag != ModInfo::FLAG_FOREIGN) && (flag != ModInfo::FLAG_OVERWRITE)) { result += 1 << (int)flag; } } return result; } -unsigned long ModListSortProxy::conflictFlagsId(const std::vector<ModInfo::EConflictFlag>& flags) const +unsigned long ModListSortProxy::conflictFlagsId( + const std::vector<ModInfo::EConflictFlag>& flags) const { unsigned long result = 0; for (ModInfo::EConflictFlag flag : flags) { @@ -99,16 +95,14 @@ unsigned long ModListSortProxy::conflictFlagsId(const std::vector<ModInfo::EConf return result; } -bool ModListSortProxy::lessThan(const QModelIndex &left, - const QModelIndex &right) const +bool ModListSortProxy::lessThan(const QModelIndex& left, const QModelIndex& right) const { if (sourceModel()->hasChildren(left) || sourceModel()->hasChildren(right)) { // when sorting by priority, we do not want to use the parent lessThan because // it uses the display role which can be inconsistent (e.g. for backups) if (sortColumn() != ModList::COL_PRIORITY) { return QSortFilterProxyModel::lessThan(left, right); - } - else if (qobject_cast<QtGroupingProxy*>(sourceModel())) { + } else if (qobject_cast<QtGroupingProxy*>(sourceModel())) { // if the underlying proxy is a QtGroupingProxy we need to rely on // Qt::DisplayRole because the other roles are not correctly handled // by that kind of proxy @@ -124,113 +118,118 @@ bool ModListSortProxy::lessThan(const QModelIndex &left, return false; } - ModInfo::Ptr leftMod = ModInfo::getByIndex(leftIndex); + ModInfo::Ptr leftMod = ModInfo::getByIndex(leftIndex); ModInfo::Ptr rightMod = ModInfo::getByIndex(rightIndex); - bool lt = left.data(ModList::PriorityRole).toInt() < right.data(ModList::PriorityRole).toInt(); + bool lt = left.data(ModList::PriorityRole).toInt() < + right.data(ModList::PriorityRole).toInt(); switch (left.column()) { - case ModList::COL_FLAGS: { - std::vector<ModInfo::EFlag> leftFlags = leftMod->getFlags(); - std::vector<ModInfo::EFlag> rightFlags = rightMod->getFlags(); - if (leftFlags.size() != rightFlags.size()) { - lt = leftFlags.size() < rightFlags.size(); - } else { - lt = flagsId(leftFlags) < flagsId(rightFlags); - } - } break; - case ModList::COL_CONFLICTFLAGS: { - std::vector<ModInfo::EConflictFlag> leftFlags = leftMod->getConflictFlags(); - std::vector<ModInfo::EConflictFlag> rightFlags = rightMod->getConflictFlags(); - if (leftFlags.size() != rightFlags.size()) { - lt = leftFlags.size() < rightFlags.size(); - } + case ModList::COL_FLAGS: { + std::vector<ModInfo::EFlag> leftFlags = leftMod->getFlags(); + std::vector<ModInfo::EFlag> rightFlags = rightMod->getFlags(); + if (leftFlags.size() != rightFlags.size()) { + lt = leftFlags.size() < rightFlags.size(); + } else { + lt = flagsId(leftFlags) < flagsId(rightFlags); + } + } break; + case ModList::COL_CONFLICTFLAGS: { + std::vector<ModInfo::EConflictFlag> leftFlags = leftMod->getConflictFlags(); + std::vector<ModInfo::EConflictFlag> rightFlags = rightMod->getConflictFlags(); + if (leftFlags.size() != rightFlags.size()) { + lt = leftFlags.size() < rightFlags.size(); + } else { + lt = conflictFlagsId(leftFlags) < conflictFlagsId(rightFlags); + } + } break; + case ModList::COL_CONTENT: { + const auto& lContents = leftMod->getContents(); + const auto& rContents = rightMod->getContents(); + unsigned int lValue = 0; + unsigned int rValue = 0; + m_Organizer->modDataContents().forEachContentIn( + lContents, [&lValue](auto const& content) { + lValue += 2U << static_cast<unsigned int>(content.id()); + }); + m_Organizer->modDataContents().forEachContentIn( + rContents, [&rValue](auto const& content) { + rValue += 2U << static_cast<unsigned int>(content.id()); + }); + lt = lValue < rValue; + } break; + case ModList::COL_NAME: { + int comp = QString::compare(leftMod->name(), rightMod->name(), Qt::CaseInsensitive); + if (comp != 0) + lt = comp < 0; + } break; + case ModList::COL_CATEGORY: { + if (leftMod->primaryCategory() != rightMod->primaryCategory()) { + if (leftMod->primaryCategory() < 0) + lt = false; + else if (rightMod->primaryCategory() < 0) + lt = true; else { - lt = conflictFlagsId(leftFlags) < conflictFlagsId(rightFlags); + try { + CategoryFactory& categories = CategoryFactory::instance(); + QString leftCatName = categories.getCategoryName( + categories.getCategoryIndex(leftMod->primaryCategory())); + QString rightCatName = categories.getCategoryName( + categories.getCategoryIndex(rightMod->primaryCategory())); + lt = leftCatName < rightCatName; + } catch (const std::exception& e) { + log::error("failed to compare categories: {}", e.what()); + } } - } break; - case ModList::COL_CONTENT: { - const auto& lContents = leftMod->getContents(); - const auto& rContents = rightMod->getContents(); - unsigned int lValue = 0; - unsigned int rValue = 0; - m_Organizer->modDataContents().forEachContentIn(lContents, [&lValue](auto const& content) { - lValue += 2U << static_cast<unsigned int>(content.id()); - }); - m_Organizer->modDataContents().forEachContentIn(rContents, [&rValue](auto const& content) { - rValue += 2U << static_cast<unsigned int>(content.id()); - }); - lt = lValue < rValue; - } break; - case ModList::COL_NAME: { - int comp = QString::compare(leftMod->name(), rightMod->name(), Qt::CaseInsensitive); + } + } break; + case ModList::COL_MODID: { + if (leftMod->nexusId() != rightMod->nexusId()) + lt = leftMod->nexusId() < rightMod->nexusId(); + } break; + case ModList::COL_VERSION: { + if (leftMod->version() != rightMod->version()) + lt = leftMod->version() < rightMod->version(); + } break; + case ModList::COL_INSTALLTIME: { + QDateTime leftTime = left.data().toDateTime(); + QDateTime rightTime = right.data().toDateTime(); + if (leftTime != rightTime) + return leftTime < rightTime; + } break; + case ModList::COL_GAME: { + if (leftMod->gameName() != rightMod->gameName()) { + lt = leftMod->gameName() < rightMod->gameName(); + } else { + int comp = + QString::compare(leftMod->name(), rightMod->name(), Qt::CaseInsensitive); if (comp != 0) lt = comp < 0; - } break; - case ModList::COL_CATEGORY: { - if (leftMod->primaryCategory() != rightMod->primaryCategory()) { - if (leftMod->primaryCategory() < 0) lt = false; - else if (rightMod->primaryCategory() < 0) lt = true; - else { - try { - CategoryFactory &categories = CategoryFactory::instance(); - QString leftCatName = categories.getCategoryName(categories.getCategoryIndex(leftMod->primaryCategory())); - QString rightCatName = categories.getCategoryName(categories.getCategoryIndex(rightMod->primaryCategory())); - lt = leftCatName < rightCatName; - } catch (const std::exception &e) { - log::error("failed to compare categories: {}", e.what()); - } - } - } - } break; - case ModList::COL_MODID: { - if (leftMod->nexusId() != rightMod->nexusId()) - lt = leftMod->nexusId() < rightMod->nexusId(); - } break; - case ModList::COL_VERSION: { - if (leftMod->version() != rightMod->version()) - lt = leftMod->version() < rightMod->version(); - } break; - case ModList::COL_INSTALLTIME: { - QDateTime leftTime = left.data().toDateTime(); - QDateTime rightTime = right.data().toDateTime(); - if (leftTime != rightTime) - return leftTime < rightTime; - } break; - case ModList::COL_GAME: { - if (leftMod->gameName() != rightMod->gameName()) { - lt = leftMod->gameName() < rightMod->gameName(); - } - else { - int comp = QString::compare(leftMod->name(), rightMod->name(), Qt::CaseInsensitive); - if (comp != 0) - lt = comp < 0; - } - } break; - case ModList::COL_NOTES: { - QString leftComments = leftMod->comments(); - QString rightComments = rightMod->comments(); - if (leftComments != rightComments) { - if (leftComments.isEmpty()) { - lt = sortOrder() == Qt::DescendingOrder; - } else if (rightComments.isEmpty()) { - lt = sortOrder() == Qt::AscendingOrder; - } else { - lt = leftComments < rightComments; - } - } - } break; - case ModList::COL_PRIORITY: { - if (leftMod->isBackup() != rightMod->isBackup()) { - lt = leftMod->isBackup(); - } - else if (leftMod->isOverwrite() != rightMod->isOverwrite()) { - lt = rightMod->isOverwrite(); + } + } break; + case ModList::COL_NOTES: { + QString leftComments = leftMod->comments(); + QString rightComments = rightMod->comments(); + if (leftComments != rightComments) { + if (leftComments.isEmpty()) { + lt = sortOrder() == Qt::DescendingOrder; + } else if (rightComments.isEmpty()) { + lt = sortOrder() == Qt::AscendingOrder; + } else { + lt = leftComments < rightComments; } - } break; - default: { - log::warn("Sorting is not defined for column {}", left.column()); - } break; + } + } break; + case ModList::COL_PRIORITY: { + if (leftMod->isBackup() != rightMod->isBackup()) { + lt = leftMod->isBackup(); + } else if (leftMod->isOverwrite() != rightMod->isOverwrite()) { + lt = rightMod->isOverwrite(); + } + } break; + default: { + log::warn("Sorting is not defined for column {}", left.column()); + } break; } return lt; } @@ -243,18 +242,19 @@ void ModListSortProxy::updateFilter(const QString& filter) emit filterInvalidated(); } -bool ModListSortProxy::hasConflictFlag(const std::vector<ModInfo::EConflictFlag> &flags) const +bool ModListSortProxy::hasConflictFlag( + const std::vector<ModInfo::EConflictFlag>& flags) const { for (ModInfo::EConflictFlag flag : flags) { if ((flag == ModInfo::FLAG_CONFLICT_MIXED) || - (flag == ModInfo::FLAG_CONFLICT_OVERWRITE) || - (flag == ModInfo::FLAG_CONFLICT_OVERWRITTEN) || - (flag == ModInfo::FLAG_CONFLICT_REDUNDANT) || - (flag == ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITE) || - (flag == ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITTEN) || - (flag == ModInfo::FLAG_ARCHIVE_CONFLICT_MIXED) || - (flag == ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITE) || - (flag == ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITTEN)) { + (flag == ModInfo::FLAG_CONFLICT_OVERWRITE) || + (flag == ModInfo::FLAG_CONFLICT_OVERWRITTEN) || + (flag == ModInfo::FLAG_CONFLICT_REDUNDANT) || + (flag == ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITE) || + (flag == ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITTEN) || + (flag == ModInfo::FLAG_ARCHIVE_CONFLICT_MIXED) || + (flag == ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITE) || + (flag == ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITTEN)) { return true; } } @@ -294,31 +294,27 @@ bool ModListSortProxy::optionsMatchMod(ModInfo::Ptr info, bool) const return true; } -bool ModListSortProxy::criteriaMatchMod( - ModInfo::Ptr info, bool enabled, const Criteria& c) const +bool ModListSortProxy::criteriaMatchMod(ModInfo::Ptr info, bool enabled, + const Criteria& c) const { bool b = false; - switch (c.type) - { - case TypeSpecial: // fall-through - case TypeCategory: - { - b = categoryMatchesMod(info, enabled, c.id); - break; - } + switch (c.type) { + case TypeSpecial: // fall-through + case TypeCategory: { + b = categoryMatchesMod(info, enabled, c.id); + break; + } - case TypeContent: - { - b = contentMatchesMod(info, enabled, c.id); - break; - } + case TypeContent: { + b = contentMatchesMod(info, enabled, c.id); + break; + } - default: - { - log::error("bad criteria type {}", c.type); - break; - } + default: { + log::error("bad criteria type {}", c.type); + break; + } } if (c.inverse) { @@ -328,99 +324,84 @@ bool ModListSortProxy::criteriaMatchMod( return b; } -bool ModListSortProxy::categoryMatchesMod( - ModInfo::Ptr info, bool enabled, int category) const +bool ModListSortProxy::categoryMatchesMod(ModInfo::Ptr info, bool enabled, + int category) const { bool b = false; - switch (category) - { - case CategoryFactory::Checked: - { - b = (enabled || info->alwaysEnabled()); - break; - } - - case CategoryFactory::UpdateAvailable: - { - b = (info->updateAvailable() || info->downgradeAvailable()); - break; - } + switch (category) { + case CategoryFactory::Checked: { + b = (enabled || info->alwaysEnabled()); + break; + } - case CategoryFactory::HasCategory: - { - b = !info->getCategories().empty(); - break; - } + case CategoryFactory::UpdateAvailable: { + b = (info->updateAvailable() || info->downgradeAvailable()); + break; + } - case CategoryFactory::Conflict: - { - b = (hasConflictFlag(info->getConflictFlags())); - break; - } + case CategoryFactory::HasCategory: { + b = !info->getCategories().empty(); + break; + } - case CategoryFactory::HasHiddenFiles: - { - b = (info->hasFlag(ModInfo::FLAG_HIDDEN_FILES)); - break; - } + case CategoryFactory::Conflict: { + b = (hasConflictFlag(info->getConflictFlags())); + break; + } - case CategoryFactory::Endorsed: - { - b = (info->endorsedState() == EndorsedState::ENDORSED_TRUE); - break; - } + case CategoryFactory::HasHiddenFiles: { + b = (info->hasFlag(ModInfo::FLAG_HIDDEN_FILES)); + break; + } - case CategoryFactory::Backup: - { - b = (info->hasFlag(ModInfo::FLAG_BACKUP)); - break; - } + case CategoryFactory::Endorsed: { + b = (info->endorsedState() == EndorsedState::ENDORSED_TRUE); + break; + } - case CategoryFactory::Managed: - { - b = (!info->hasFlag(ModInfo::FLAG_FOREIGN)); - break; - } + case CategoryFactory::Backup: { + b = (info->hasFlag(ModInfo::FLAG_BACKUP)); + break; + } - case CategoryFactory::HasGameData: - { - b = !info->hasFlag(ModInfo::FLAG_INVALID); - break; - } + case CategoryFactory::Managed: { + b = (!info->hasFlag(ModInfo::FLAG_FOREIGN)); + break; + } - case CategoryFactory::HasNexusID: - { - // never show these - if ( - info->hasFlag(ModInfo::FLAG_FOREIGN) || - info->hasFlag(ModInfo::FLAG_BACKUP) || - info->hasFlag(ModInfo::FLAG_OVERWRITE)) - { - return false; - } + case CategoryFactory::HasGameData: { + b = !info->hasFlag(ModInfo::FLAG_INVALID); + break; + } - b = (info->nexusId() > 0); - break; + case CategoryFactory::HasNexusID: { + // never show these + if (info->hasFlag(ModInfo::FLAG_FOREIGN) || info->hasFlag(ModInfo::FLAG_BACKUP) || + info->hasFlag(ModInfo::FLAG_OVERWRITE)) { + return false; } - case CategoryFactory::Tracked: - { - b = (info->trackedState() == TrackedState::TRACKED_TRUE); - break; - } + b = (info->nexusId() > 0); + break; + } - default: - { - b = (info->categorySet(category)); - break; - } + case CategoryFactory::Tracked: { + b = (info->trackedState() == TrackedState::TRACKED_TRUE); + break; + } + + default: { + b = (info->categorySet(category)); + break; + } } return b; } -bool ModListSortProxy::contentMatchesMod(ModInfo::Ptr info, bool enabled, int content) const +bool ModListSortProxy::contentMatchesMod(ModInfo::Ptr info, bool enabled, + int content) const { return info->hasContent(content); } @@ -432,66 +413,59 @@ bool ModListSortProxy::filterMatchesMod(ModInfo::Ptr info, bool enabled) const return true; } - // special case for separators if (info->hasFlag(ModInfo::FLAG_SEPARATOR)) { - switch (m_FilterSeparators) - { - case SeparatorFilter: - { - // filter normally - break; - } + switch (m_FilterSeparators) { + case SeparatorFilter: { + // filter normally + break; + } - case SeparatorShow: - { - // force visible - return true; - } + case SeparatorShow: { + // force visible + return true; + } - case SeparatorHide: - { - // force hide - return false; - } + case SeparatorHide: { + // force hide + return false; + } } } - if (!m_Filter.isEmpty()) { - bool display = false; + bool display = false; QString filterCopy = QString(m_Filter); filterCopy.replace("||", ";").replace("OR", ";").replace("|", ";"); QStringList ORList = filterCopy.split(";", Qt::SkipEmptyParts); bool segmentGood = true; - //split in ORSegments that internally use AND logic + // split in ORSegments that internally use AND logic for (auto& ORSegment : ORList) { QStringList ANDKeywords = ORSegment.split(" ", Qt::SkipEmptyParts); - segmentGood = true; - bool foundKeyword = false; + segmentGood = true; + bool foundKeyword = false; - //check each word in the segment for match, each word needs to be matched but it doesn't matter where. + // check each word in the segment for match, each word needs to be matched but it + // doesn't matter where. for (auto& currentKeyword : ANDKeywords) { foundKeyword = false; - //search keyword in name + // search keyword in name if (m_EnabledColumns[ModList::COL_NAME] && - info->name().contains(currentKeyword, Qt::CaseInsensitive)) { + info->name().contains(currentKeyword, Qt::CaseInsensitive)) { foundKeyword = true; } // Search by notes - if (!foundKeyword && - m_EnabledColumns[ModList::COL_NOTES] && - info->comments().contains(currentKeyword, Qt::CaseInsensitive)) { + if (!foundKeyword && m_EnabledColumns[ModList::COL_NOTES] && + info->comments().contains(currentKeyword, Qt::CaseInsensitive)) { foundKeyword = true; } // Search by categories - if (!foundKeyword && - m_EnabledColumns[ModList::COL_CATEGORY]) { + if (!foundKeyword && m_EnabledColumns[ModList::COL_CATEGORY]) { for (auto category : info->categories()) { if (category.contains(currentKeyword, Qt::CaseInsensitive)) { foundKeyword = true; @@ -501,8 +475,7 @@ bool ModListSortProxy::filterMatchesMod(ModInfo::Ptr info, bool enabled) const } // Search by Nexus ID - if (!foundKeyword && - m_EnabledColumns[ModList::COL_MODID]) { + if (!foundKeyword && m_EnabledColumns[ModList::COL_MODID]) { bool ok; int filterID = currentKeyword.toInt(&ok); if (ok) { @@ -518,31 +491,31 @@ bool ModListSortProxy::filterMatchesMod(ModInfo::Ptr info, bool enabled) const } if (!foundKeyword) { - //currentKeword is missing from everything, AND fails and we need to check next ORsegment + // currentKeword is missing from everything, AND fails and we need to check + // next ORsegment segmentGood = false; break; } - }//for ANDKeywords loop + } // for ANDKeywords loop if (segmentGood) { - //the last AND loop didn't break so the ORSegments is true so mod matches filter + // the last AND loop didn't break so the ORSegments is true so mod matches + // filter display = true; break; } - }//for ORList loop + } // for ORList loop if (!display) { return false; } - }//if (!m_CurrentFilter.isEmpty()) - + } // if (!m_CurrentFilter.isEmpty()) if (m_FilterMode == FilterAnd) { return filterMatchesModAnd(info, enabled); - } - else { + } else { return filterMatchesModOr(info, enabled); } } @@ -552,18 +525,18 @@ void ModListSortProxy::setColumnVisible(int column, bool visible) m_EnabledColumns[column] = visible; } -void ModListSortProxy::setOptions( - ModListSortProxy::FilterMode mode, SeparatorsMode separators) +void ModListSortProxy::setOptions(ModListSortProxy::FilterMode mode, + SeparatorsMode separators) { if (m_FilterMode != mode || separators != m_FilterSeparators) { - m_FilterMode = mode; + m_FilterMode = mode; m_FilterSeparators = separators; invalidateFilter(); emit filterInvalidated(); } } -bool ModListSortProxy::filterAcceptsRow(int source_row, const QModelIndex &parent) const +bool ModListSortProxy::filterAcceptsRow(int source_row, const QModelIndex& parent) const { if (m_Profile == nullptr) { return false; @@ -583,7 +556,7 @@ bool ModListSortProxy::filterAcceptsRow(int source_row, const QModelIndex &paren unsigned int index = ULONG_MAX; { bool ok = false; - index = idx.data(ModList::IndexRole).toInt(&ok); + index = idx.data(ModList::IndexRole).toInt(&ok); if (!ok) { index = ULONG_MAX; } @@ -604,7 +577,8 @@ bool ModListSortProxy::filterAcceptsRow(int source_row, const QModelIndex &paren return false; } else { - bool modEnabled = idx.sibling(source_row, 0).data(Qt::CheckStateRole).toInt() == Qt::Checked; + bool modEnabled = + idx.sibling(source_row, 0).data(Qt::CheckStateRole).toInt() == Qt::Checked; return filterMatchesMod(ModInfo::getByIndex(index), modEnabled); } } @@ -614,7 +588,9 @@ bool ModListSortProxy::sourceIsByPriorityProxy() const return dynamic_cast<ModListByPriorityProxy*>(sourceModel()) != nullptr; } -bool ModListSortProxy::canDropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) const +bool ModListSortProxy::canDropMimeData(const QMimeData* data, Qt::DropAction action, + int row, int column, + const QModelIndex& parent) const { ModListDropInfo dropInfo(data, *m_Organizer); @@ -641,14 +617,15 @@ bool ModListSortProxy::canDropMimeData(const QMimeData* data, Qt::DropAction act return QSortFilterProxyModel::canDropMimeData(data, action, row, column, parent); } -bool ModListSortProxy::dropMimeData(const QMimeData *data, Qt::DropAction action, - int row, int column, const QModelIndex &parent) +bool ModListSortProxy::dropMimeData(const QMimeData* data, Qt::DropAction action, + int row, int column, const QModelIndex& parent) { ModListDropInfo dropInfo(data, *m_Organizer); if (!dropInfo.isLocalFileDrop() && sortColumn() != ModList::COL_PRIORITY) { - QWidget *wid = qApp->activeWindow()->findChild<QTreeView*>("modList"); - MessageDialog::showMessage(tr("Drag&Drop is only supported when sorting by priority"), wid); + QWidget* wid = qApp->activeWindow()->findChild<QTreeView*>("modList"); + MessageDialog::showMessage( + tr("Drag&Drop is only supported when sorting by priority"), wid); return false; } @@ -669,16 +646,18 @@ bool ModListSortProxy::dropMimeData(const QMimeData *data, Qt::DropAction action return QSortFilterProxyModel::dropMimeData(data, action, row, column, parent); } -void ModListSortProxy::setSourceModel(QAbstractItemModel *sourceModel) +void ModListSortProxy::setSourceModel(QAbstractItemModel* sourceModel) { QSortFilterProxyModel::setSourceModel(sourceModel); - QAbstractProxyModel *proxy = qobject_cast<QAbstractProxyModel*>(sourceModel); + QAbstractProxyModel* proxy = qobject_cast<QAbstractProxyModel*>(sourceModel); if (proxy != nullptr) { sourceModel = proxy->sourceModel(); } if (sourceModel) { - connect(sourceModel, SIGNAL(aboutToChangeData()), this, SLOT(aboutToChangeData()), Qt::UniqueConnection); - connect(sourceModel, SIGNAL(postDataChanged()), this, SLOT(postDataChanged()), Qt::UniqueConnection); + connect(sourceModel, SIGNAL(aboutToChangeData()), this, SLOT(aboutToChangeData()), + Qt::UniqueConnection); + connect(sourceModel, SIGNAL(postDataChanged()), this, SLOT(postDataChanged()), + Qt::UniqueConnection); } } @@ -686,20 +665,19 @@ void ModListSortProxy::aboutToChangeData() { // having a filter active when dataChanged is called caused a crash // (at least with some Qt versions) - // this may be related to the fact that the item being edited may disappear from the view as a - // result of the edit + // this may be related to the fact that the item being edited may disappear from the + // view as a result of the edit m_PreChangeCriteria = m_Criteria; setCriteria({}); } void ModListSortProxy::postDataChanged() { - // if the filter is re-activated right away the editor can't be deleted but becomes invisible - // or at least the view continues to think it's being edited. As a result no new editor can be - // opened - QTimer::singleShot(10, [this] () { + // if the filter is re-activated right away the editor can't be deleted but becomes + // invisible or at least the view continues to think it's being edited. As a result no + // new editor can be opened + QTimer::singleShot(10, [this]() { setCriteria(m_PreChangeCriteria); m_PreChangeCriteria.clear(); }); } - diff --git a/src/modlistsortproxy.h b/src/modlistsortproxy.h index b59ab358..2d7fbea3 100644 --- a/src/modlistsortproxy.h +++ b/src/modlistsortproxy.h @@ -20,9 +20,9 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef MODLISTSORTPROXY_H #define MODLISTSORTPROXY_H +#include "modlist.h" #include <QSortFilterProxyModel> #include <bitset> -#include "modlist.h" class Profile; class OrganizerCore; @@ -38,7 +38,8 @@ public: FilterOr }; - enum CriteriaType { + enum CriteriaType + { TypeSpecial, TypeCategory, TypeContent @@ -59,28 +60,23 @@ public: bool operator==(const Criteria& other) const { - return - (type == other.type) && - (id == other.id) && - (inverse == other.inverse); + return (type == other.type) && (id == other.id) && (inverse == other.inverse); } - bool operator!=(const Criteria& other) const - { - return !(*this == other); - } + bool operator!=(const Criteria& other) const { return !(*this == other); } }; public: + explicit ModListSortProxy(Profile* profile, OrganizerCore* organizer); - explicit ModListSortProxy(Profile *profile, OrganizerCore *organizer); + void setProfile(Profile* profile); - void setProfile(Profile *profile); + bool canDropMimeData(const QMimeData* data, Qt::DropAction action, int row, + int column, const QModelIndex& parent) const override; + bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, + const QModelIndex& parent) override; - bool canDropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) const override; - bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; - - virtual void setSourceModel(QAbstractItemModel *sourceModel) override; + virtual void setSourceModel(QAbstractItemModel* sourceModel) override; /** * @brief tests if a filtere matches for a mod @@ -106,7 +102,8 @@ public: * @param parent the node to test * @return true if there are child nodes */ - virtual bool hasChildren ( const QModelIndex & parent = QModelIndex() ) const { + virtual bool hasChildren(const QModelIndex& parent = QModelIndex()) const + { return rowCount(parent) > 0; } @@ -119,7 +116,7 @@ public: public slots: - void updateFilter(const QString &filter); + void updateFilter(const QString& filter); signals: @@ -127,15 +124,13 @@ signals: void filterInvalidated(); protected: - - virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const; - virtual bool filterAcceptsRow(int row, const QModelIndex &parent) const; + virtual bool lessThan(const QModelIndex& left, const QModelIndex& right) const; + virtual bool filterAcceptsRow(int row, const QModelIndex& parent) const; private: - - unsigned long flagsId(const std::vector<ModInfo::EFlag> &flags) const; + unsigned long flagsId(const std::vector<ModInfo::EFlag>& flags) const; unsigned long conflictFlagsId(const std::vector<ModInfo::EConflictFlag>& flags) const; - bool hasConflictFlag(const std::vector<ModInfo::EConflictFlag> &flags) const; + bool hasConflictFlag(const std::vector<ModInfo::EConflictFlag>& flags) const; void updateFilterActive(); bool filterMatchesModAnd(ModInfo::Ptr info, bool enabled) const; bool filterMatchesModOr(ModInfo::Ptr info, bool enabled) const; @@ -169,4 +164,4 @@ private: bool contentMatchesMod(ModInfo::Ptr info, bool enabled, int content) const; }; -#endif // MODLISTSORTPROXY_H +#endif // MODLISTSORTPROXY_H diff --git a/src/modlistversiondelegate.cpp b/src/modlistversiondelegate.cpp index 5ce574a5..fbb4f03e 100644 --- a/src/modlistversiondelegate.cpp +++ b/src/modlistversiondelegate.cpp @@ -1,41 +1,43 @@ #include "modlistversiondelegate.h" -#include "settings.h" -#include "modlistview.h" #include "log.h" +#include "modlistview.h" +#include "settings.h" -ModListVersionDelegate::ModListVersionDelegate(ModListView* view, Settings& settings) : - QItemDelegate(view), m_view(view), m_settings(settings) -{ -} - +ModListVersionDelegate::ModListVersionDelegate(ModListView* view, Settings& settings) + : QItemDelegate(view), m_view(view), m_settings(settings) +{} -void ModListVersionDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const +void ModListVersionDelegate::paint(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const { m_view->itemDelegate()->paint(painter, option, index); - if (m_view->hasCollapsibleSeparators() - && m_view->model()->hasChildren(index) - && m_settings.interface().collapsibleSeparatorsIcons(ModList::COL_VERSION) - && !m_view->isExpanded(index.sibling(index.row(), 0))) { + if (m_view->hasCollapsibleSeparators() && m_view->model()->hasChildren(index) && + m_settings.interface().collapsibleSeparatorsIcons(ModList::COL_VERSION) && + !m_view->isExpanded(index.sibling(index.row(), 0))) { auto* model = m_view->model(); bool downgrade = false, upgrade = false; for (int i = 0; i < model->rowCount(index); ++i) { - const auto mIndex = model->index(i, index.column(), index).data(ModList::IndexRole); + const auto mIndex = + model->index(i, index.column(), index).data(ModList::IndexRole); if (mIndex.isValid()) { auto info = ModInfo::getByIndex(mIndex.toInt()); downgrade = downgrade || info->downgradeAvailable(); - upgrade = upgrade || info->updateAvailable(); + upgrade = upgrade || info->updateAvailable(); } } - const int margin = m_view->style()->pixelMetric(QStyle::PM_FocusFrameHMargin, nullptr, m_view) + 1; + const int margin = + m_view->style()->pixelMetric(QStyle::PM_FocusFrameHMargin, nullptr, m_view) + 1; QStyleOptionViewItem opt(option); - const int sz = m_view->style()->pixelMetric(QStyle::PM_SmallIconSize, nullptr, m_view); - opt.decorationSize = QSize(sz, sz); + const int sz = + m_view->style()->pixelMetric(QStyle::PM_SmallIconSize, nullptr, m_view); + opt.decorationSize = QSize(sz, sz); opt.decorationAlignment = Qt::AlignCenter; if (upgrade) { @@ -60,7 +62,6 @@ void ModListVersionDelegate::paint(QPainter* painter, const QStyleOptionViewItem opt.rect.setRect(opt.rect.x(), opt.rect.y(), pm.width(), opt.rect.height()); drawDecoration(painter, opt, opt.rect, pixmap); - } } } diff --git a/src/modlistversiondelegate.h b/src/modlistversiondelegate.h index d3d0ad3b..53a6e8ba 100644 --- a/src/modlistversiondelegate.h +++ b/src/modlistversiondelegate.h @@ -11,8 +11,8 @@ class ModListVersionDelegate : public QItemDelegate public: ModListVersionDelegate(ModListView* view, Settings& settings); - void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override; - + void paint(QPainter* painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const override; private: ModListView* m_view; diff --git a/src/modlistview.cpp b/src/modlistview.cpp index 7eb06f98..73bbd33d 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -1,7 +1,7 @@ #include "modlistview.h" -#include <QUrl> #include <QMimeData> #include <QProxyStyle> +#include <QUrl> #include <widgetutility.h> @@ -10,26 +10,26 @@ #include "ui_mainwindow.h" +#include "copyeventfilter.h" #include "filterlist.h" -#include "organizercore.h" -#include "modlist.h" -#include "modlistsortproxy.h" -#include "modlistbypriorityproxy.h" +#include "genericicondelegate.h" #include "log.h" -#include "modflagicondelegate.h" +#include "mainwindow.h" #include "modconflicticondelegate.h" #include "modcontenticondelegate.h" +#include "modelutils.h" +#include "modflagicondelegate.h" +#include "modlist.h" +#include "modlistbypriorityproxy.h" +#include "modlistcontextmenu.h" +#include "modlistdropinfo.h" +#include "modlistsortproxy.h" #include "modlistversiondelegate.h" #include "modlistviewactions.h" -#include "modlistdropinfo.h" -#include "modlistcontextmenu.h" -#include "genericicondelegate.h" -#include "copyeventfilter.h" -#include "shared/fileentry.h" +#include "organizercore.h" #include "shared/directoryentry.h" +#include "shared/fileentry.h" #include "shared/filesorigin.h" -#include "mainwindow.h" -#include "modelutils.h" using namespace MOBase; using namespace MOShared; @@ -47,11 +47,11 @@ class ModListStyledItemDelegate : public QStyledItemDelegate ModListView* m_view; public: + ModListStyledItemDelegate(ModListView* view) : QStyledItemDelegate(view), m_view(view) + {} - ModListStyledItemDelegate(ModListView* view) : - QStyledItemDelegate(view), m_view(view) { } - - void initStyleOption(QStyleOptionViewItem* option, const QModelIndex& index) const override + void initStyleOption(QStyleOptionViewItem* option, + const QModelIndex& index) const override { // the parent version always overwrite the background brush, so // we need to save it and restore it @@ -63,7 +63,8 @@ public: } } - void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override + void paint(QPainter* painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const override { QStyleOptionViewItem opt(option); @@ -95,16 +96,19 @@ public: // compute ideal foreground color for some rows if (color.isValid()) { - if (((index.column() == ModList::COL_NAME || index.column() == ModList::COL_PRIORITY) - && ModInfo::getByIndex(index.data(ModList::IndexRole).toInt())->isSeparator()) - || index.column() == ModList::COL_NOTES) { + if (((index.column() == ModList::COL_NAME || + index.column() == ModList::COL_PRIORITY) && + ModInfo::getByIndex(index.data(ModList::IndexRole).toInt()) + ->isSeparator()) || + index.column() == ModList::COL_NOTES) { // combine the color with the background and then find the "ideal" text color const auto a = color.alpha() / 255.; - int r = (1 - a) * bg.red() + a * color.red(), - g = (1 - a) * bg.green() + a * color.green(), - b = (1 - a) * bg.blue() + a * color.blue(); - opt.palette.setBrush(QPalette::Text, ColorSettings::idealTextColor(QColor(r, g, b))); + int r = (1 - a) * bg.red() + a * color.red(), + g = (1 - a) * bg.green() + a * color.green(), + b = (1 - a) * bg.blue() + a * color.blue(); + opt.palette.setBrush(QPalette::Text, + ColorSettings::idealTextColor(QColor(r, g, b))); } } @@ -112,12 +116,14 @@ public: } }; -class ModListViewMarkingScrollBar : public ViewMarkingScrollBar { +class ModListViewMarkingScrollBar : public ViewMarkingScrollBar +{ ModListView* m_view; -public: - ModListViewMarkingScrollBar(ModListView* view) : - ViewMarkingScrollBar(view, ModList::ScrollMarkRole), m_view(view) { } +public: + ModListViewMarkingScrollBar(ModListView* view) + : ViewMarkingScrollBar(view, ModList::ScrollMarkRole), m_view(view) + {} QColor color(const QModelIndex& index) const override { @@ -127,18 +133,13 @@ public: } return color; } - }; ModListView::ModListView(QWidget* parent) - : QTreeView(parent) - , m_core(nullptr) - , m_sortProxy(nullptr) - , m_byPriorityProxy(nullptr) - , m_byCategoryProxy(nullptr) - , m_byNexusIdProxy(nullptr) - , m_markers{ {}, {}, {}, {}, {}, {} } - , m_scrollbar(new ModListViewMarkingScrollBar(this)) + : QTreeView(parent), m_core(nullptr), m_sortProxy(nullptr), + m_byPriorityProxy(nullptr), m_byCategoryProxy(nullptr), + m_byNexusIdProxy(nullptr), m_markers{{}, {}, {}, {}, {}, {}}, + m_scrollbar(new ModListViewMarkingScrollBar(this)) { setVerticalScrollBar(m_scrollbar); MOBase::setCustomizableColumns(this); @@ -147,7 +148,8 @@ ModListView::ModListView(QWidget* parent) setItemDelegate(new ModListStyledItemDelegate(this)); connect(this, &ModListView::doubleClicked, this, &ModListView::onDoubleClicked); - connect(this, &ModListView::customContextMenuRequested, this, &ModListView::onCustomContextMenuRequested); + connect(this, &ModListView::customContextMenuRequested, this, + &ModListView::onCustomContextMenuRequested); // the timeout is pretty small because its main purpose is to avoid // refreshing multiple times when calling expandAll() or collapseAll() @@ -155,18 +157,19 @@ ModListView::ModListView(QWidget* parent) // time window m_refreshMarkersTimer.setInterval(50); m_refreshMarkersTimer.setSingleShot(true); - connect(&m_refreshMarkersTimer, &QTimer::timeout, [=] { refreshMarkersAndPlugins(); }); + connect(&m_refreshMarkersTimer, &QTimer::timeout, [=] { + refreshMarkersAndPlugins(); + }); installEventFilter(new CopyEventFilter(this, [=](auto& index) { QVariant mIndex = index.data(ModList::IndexRole); - QString name = index.data(Qt::DisplayRole).toString(); + QString name = index.data(Qt::DisplayRole).toString(); if (mIndex.isValid() && hasCollapsibleSeparators()) { ModInfo::Ptr info = ModInfo::getByIndex(mIndex.toInt()); if (info->isSeparator()) { name = "[" + name + "]"; } - } - else if (model()->hasChildren(index)) { + } else if (model()->hasChildren(index)) { name = "[" + name + "]"; } return name; @@ -181,20 +184,23 @@ void ModListView::refresh() void ModListView::onProfileChanged(Profile* oldProfile, Profile* newProfile) { const auto perProfileSeparators = - m_core->settings().interface().collapsibleSeparatorsPerProfile(); + m_core->settings().interface().collapsibleSeparatorsPerProfile(); // save expanded/collapsed state of separators if (oldProfile && perProfileSeparators) { auto& collapsed = m_collapsed[m_byPriorityProxy]; - oldProfile->storeSetting("UserInterface", "collapsed_separators", QStringList(collapsed.begin(), collapsed.end())); + oldProfile->storeSetting("UserInterface", "collapsed_separators", + QStringList(collapsed.begin(), collapsed.end())); } m_sortProxy->setProfile(newProfile); m_byPriorityProxy->setProfile(newProfile); if (newProfile && perProfileSeparators) { - auto collapsed = newProfile->setting("UserInterface", "collapsed_separators", QStringList()).toStringList(); - m_collapsed[m_byPriorityProxy] = { collapsed.begin(), collapsed.end() }; + auto collapsed = + newProfile->setting("UserInterface", "collapsed_separators", QStringList()) + .toStringList(); + m_collapsed[m_byPriorityProxy] = {collapsed.begin(), collapsed.end()}; } } @@ -222,17 +228,13 @@ ModListView::GroupByMode ModListView::groupByMode() const { if (m_sortProxy == nullptr) { return GroupByMode::NONE; - } - else if (m_sortProxy->sourceModel() == m_byPriorityProxy) { + } else if (m_sortProxy->sourceModel() == m_byPriorityProxy) { return GroupByMode::SEPARATOR; - } - else if (m_sortProxy->sourceModel() == m_byCategoryProxy) { + } else if (m_sortProxy->sourceModel() == m_byCategoryProxy) { return GroupByMode::CATEGORY; - } - else if (m_sortProxy->sourceModel() == m_byNexusIdProxy) { + } else if (m_sortProxy->sourceModel() == m_byNexusIdProxy) { return GroupByMode::NEXUS_ID; - } - else { + } else { return GroupByMode::NONE; } } @@ -271,7 +273,7 @@ std::optional<unsigned int> ModListView::nextMod(unsigned int modIndex) const return {}; } -std::optional<unsigned int> ModListView::prevMod(unsigned int modIndex) const +std::optional<unsigned int> ModListView::prevMod(unsigned int modIndex) const { const QModelIndex start = indexModelToView(m_core->modList()->index(modIndex, 0)); @@ -304,24 +306,28 @@ void ModListView::invalidateFilter() m_sortProxy->invalidate(); } -void ModListView::setFilterCriteria(const std::vector<ModListSortProxy::Criteria>& criteria) +void ModListView::setFilterCriteria( + const std::vector<ModListSortProxy::Criteria>& criteria) { m_sortProxy->setCriteria(criteria); } -void ModListView::setFilterOptions(ModListSortProxy::FilterMode mode, ModListSortProxy::SeparatorsMode sep) +void ModListView::setFilterOptions(ModListSortProxy::FilterMode mode, + ModListSortProxy::SeparatorsMode sep) { m_sortProxy->setOptions(mode, sep); } bool ModListView::isModVisible(unsigned int index) const { - return m_sortProxy->filterMatchesMod(ModInfo::getByIndex(index), m_core->currentProfile()->modEnabled(index)); + return m_sortProxy->filterMatchesMod(ModInfo::getByIndex(index), + m_core->currentProfile()->modEnabled(index)); } bool ModListView::isModVisible(ModInfo::Ptr mod) const { - return m_sortProxy->filterMatchesMod(mod, m_core->currentProfile()->modEnabled(ModInfo::getIndex(mod->name()))); + return m_sortProxy->filterMatchesMod( + mod, m_core->currentProfile()->modEnabled(ModInfo::getIndex(mod->name()))); } QModelIndex ModListView::indexModelToView(const QModelIndex& index) const @@ -358,13 +364,15 @@ QModelIndex ModListView::nextIndex(const QModelIndex& index) const if (index.parent().isValid()) { if (index.row() + 1 < model->rowCount(index.parent())) { return index.model()->index(index.row() + 1, index.column(), index.parent()); + } else { + return index.model()->index((index.parent().row() + 1) % + model->rowCount(index.parent().parent()), + index.column(), index.parent().parent()); + ; } - else { - return index.model()->index((index.parent().row() + 1) % model->rowCount(index.parent().parent()), index.column(), index.parent().parent());; - } - } - else { - return index.model()->index((index.row() + 1) % model->rowCount(index.parent()), index.column(), index.parent()); + } else { + return index.model()->index((index.row() + 1) % model->rowCount(index.parent()), + index.column(), index.parent()); } } @@ -379,7 +387,8 @@ QModelIndex ModListView::prevIndex(const QModelIndex& index) const return {}; } - auto prev = model->index((index.row() - 1) % model->rowCount(index.parent()), index.column(), index.parent()); + auto prev = model->index((index.row() - 1) % model->rowCount(index.parent()), + index.column(), index.parent()); if (model->rowCount(prev) > 0) { return model->index(model->rowCount(prev) - 1, index.column(), prev); @@ -390,14 +399,17 @@ QModelIndex ModListView::prevIndex(const QModelIndex& index) const std::pair<QModelIndex, QModelIndexList> ModListView::selected() const { - return { indexViewToModel(currentIndex()), indexViewToModel(selectionModel()->selectedRows()) }; + return {indexViewToModel(currentIndex()), + indexViewToModel(selectionModel()->selectedRows())}; } -void ModListView::setSelected(const QModelIndex& current, const QModelIndexList& selected) +void ModListView::setSelected(const QModelIndex& current, + const QModelIndexList& selected) { setCurrentIndex(indexModelToView(current)); for (auto idx : selected) { - selectionModel()->select(indexModelToView(idx), QItemSelectionModel::Select | QItemSelectionModel::Rows); + selectionModel()->select(indexModelToView(idx), + QItemSelectionModel::Select | QItemSelectionModel::Rows); } } @@ -406,7 +418,8 @@ void ModListView::scrollToAndSelect(const QModelIndex& index) scrollToAndSelect(QModelIndexList{index}); } -void ModListView::scrollToAndSelect(const QModelIndexList& indexes, const QModelIndex& current) +void ModListView::scrollToAndSelect(const QModelIndexList& indexes, + const QModelIndex& current) { // focus, scroll to and select if (!current.isValid() && indexes.isEmpty()) { @@ -418,8 +431,11 @@ void ModListView::scrollToAndSelect(const QModelIndexList& indexes, const QModel for (auto& idx : indexes) { selection.select(idx, idx); } - selectionModel()->select(selection, QItemSelectionModel::Select | QItemSelectionModel::Rows); - QTimer::singleShot(50, [=] { setFocus(); }); + selectionModel()->select(selection, + QItemSelectionModel::Select | QItemSelectionModel::Rows); + QTimer::singleShot(50, [=] { + setFocus(); + }); } void ModListView::refreshExpandedItems() @@ -472,12 +488,10 @@ void ModListView::onModFilterActive(bool filterActive) if (filterActive) { setStyleSheet("QTreeView { border: 2px ridge #f00; }"); ui.counter->setStyleSheet("QLCDNumber { border: 2px ridge #f00; }"); - } - else if (ui.groupBy->currentIndex() != GroupBy::NONE) { + } else if (ui.groupBy->currentIndex() != GroupBy::NONE) { setStyleSheet("QTreeView { border: 2px ridge #337733; }"); ui.counter->setStyleSheet(""); - } - else { + } else { setStyleSheet(""); ui.counter->setStyleSheet(""); } @@ -491,9 +505,8 @@ ModListView::ModCounters ModListView::counters() const return std::find(flags.begin(), flags.end(), filter) != flags.end(); }; - for (unsigned int index = 0; index < ModInfo::getNumMods(); ++index) { - auto info = ModInfo::getByIndex(index); + auto info = ModInfo::getByIndex(index); const auto flags = info->getFlags(); const bool enabled = m_core->currentProfile()->modEnabled(index); @@ -501,22 +514,24 @@ ModListView::ModCounters ModListView::counters() const if (info->isBackup()) { c.backup++; - if (visible) c.visible.backup++; - } - else if (info->isForeign()) { + if (visible) + c.visible.backup++; + } else if (info->isForeign()) { c.foreign++; - if (visible) c.visible.foreign++; - } - else if (info->isSeparator()) { + if (visible) + c.visible.foreign++; + } else if (info->isSeparator()) { c.separator++; - if (visible) c.visible.separator++; - } - else if (!info->isOverwrite()) { + if (visible) + c.visible.separator++; + } else if (!info->isOverwrite()) { c.regular++; - if (visible) c.visible.regular++; + if (visible) + c.visible.regular++; if (enabled) { c.active++; - if (visible) c.visible.active++; + if (visible) + c.visible.active++; } } } @@ -530,23 +545,26 @@ void ModListView::updateModCount() ui.counter->display(c.visible.active); ui.counter->setToolTip(tr("<table cellspacing=\"5\">" - "<tr><th>Type</th><th>All</th><th>Visible</th>" - "<tr><td>Enabled mods: </td><td align=right>%1 / %2</td><td align=right>%3 / %4</td></tr>" - "<tr><td>Unmanaged/DLCs: </td><td align=right>%5</td><td align=right>%6</td></tr>" - "<tr><td>Mod backups: </td><td align=right>%7</td><td align=right>%8</td></tr>" - "<tr><td>Separators: </td><td align=right>%9</td><td align=right>%10</td></tr>" - "</table>") - .arg(c.active) - .arg(c.regular) - .arg(c.visible.active) - .arg(c.visible.regular) - .arg(c.foreign) - .arg(c.visible.foreign) - .arg(c.backup) - .arg(c.visible.backup) - .arg(c.separator) - .arg(c.visible.separator) - ); + "<tr><th>Type</th><th>All</th><th>Visible</th>" + "<tr><td>Enabled mods: </td><td align=right>%1 / " + "%2</td><td align=right>%3 / %4</td></tr>" + "<tr><td>Unmanaged/DLCs: </td><td " + "align=right>%5</td><td align=right>%6</td></tr>" + "<tr><td>Mod backups: </td><td align=right>%7</td><td " + "align=right>%8</td></tr>" + "<tr><td>Separators: </td><td align=right>%9</td><td " + "align=right>%10</td></tr>" + "</table>") + .arg(c.active) + .arg(c.regular) + .arg(c.visible.active) + .arg(c.visible.regular) + .arg(c.foreign) + .arg(c.visible.foreign) + .arg(c.backup) + .arg(c.visible.backup) + .arg(c.separator) + .arg(c.visible.separator)); } void ModListView::refreshFilters() @@ -571,10 +589,13 @@ void ModListView::onExternalFolderDropped(const QUrl& url, int priority) do { bool ok; - name.update(QInputDialog::getText(this, tr("Copy Folder..."), - tr("This will copy the content of %1 to a new mod.\n" - "Please enter the name:").arg(fileInfo.fileName()), QLineEdit::Normal, name, &ok), - GUESS_USER); + name.update( + QInputDialog::getText(this, tr("Copy Folder..."), + tr("This will copy the content of %1 to a new mod.\n" + "Please enter the name:") + .arg(fileInfo.fileName()), + QLineEdit::Normal, name, &ok), + GUESS_USER); if (!ok) { return; } @@ -634,23 +655,23 @@ bool ModListView::toggleSelectionState() if (!selectionModel()->hasSelection()) { return true; } - return m_core->modList()->toggleState(indexViewToModel(selectionModel()->selectedRows())); + return m_core->modList()->toggleState( + indexViewToModel(selectionModel()->selectedRows())); } void ModListView::updateGroupByProxy() { - int groupIndex = ui.groupBy->currentIndex(); + int groupIndex = ui.groupBy->currentIndex(); auto* previousModel = m_sortProxy->sourceModel(); QAbstractItemModel* nextModel = m_core->modList(); if (groupIndex == GroupBy::CATEGORY) { nextModel = m_byCategoryProxy; - } - else if (groupIndex == GroupBy::NEXUS_ID) { + } else if (groupIndex == GroupBy::NEXUS_ID) { nextModel = m_byNexusIdProxy; - } - else if (m_core->settings().interface().collapsibleSeparators(m_sortProxy->sortOrder()) - && m_sortProxy->sortColumn() == ModList::COL_PRIORITY) { + } else if (m_core->settings().interface().collapsibleSeparators( + m_sortProxy->sortOrder()) && + m_sortProxy->sortColumn() == ModList::COL_PRIORITY) { m_byPriorityProxy->setSortOrder(m_sortProxy->sortOrder()); nextModel = m_byPriorityProxy; } @@ -675,98 +696,127 @@ void ModListView::updateGroupByProxy() if (hasCollapsibleSeparators()) { ui.filterSeparators->setCurrentIndex(ModListSortProxy::SeparatorFilter); ui.filterSeparators->setEnabled(false); - } - else { + } else { ui.filterSeparators->setEnabled(true); } - } } -void ModListView::setup(OrganizerCore& core, CategoryFactory& factory, MainWindow* mw, Ui::MainWindow* mwui) +void ModListView::setup(OrganizerCore& core, CategoryFactory& factory, MainWindow* mw, + Ui::MainWindow* mwui) { // attributes m_core = &core; m_filters.reset(new FilterList(mwui, core, factory)); m_categories = &factory; - m_actions = new ModListViewActions(core, *m_filters, factory, this, mwui->espList, mw); - ui = { - mwui->groupCombo, mwui->activeModsCounter, mwui->modFilterEdit, - mwui->currentCategoryLabel, mwui->clearFiltersButton, mwui->filtersSeparators, - mwui->espList - }; - + m_actions = + new ModListViewActions(core, *m_filters, factory, this, mwui->espList, mw); + ui = {mwui->groupCombo, + mwui->activeModsCounter, + mwui->modFilterEdit, + mwui->currentCategoryLabel, + mwui->clearFiltersButton, + mwui->filtersSeparators, + mwui->espList}; - connect(m_core, &OrganizerCore::modInstalled, [=](auto&& name) { onModInstalled(name); }); + connect(m_core, &OrganizerCore::modInstalled, [=](auto&& name) { + onModInstalled(name); + }); connect(m_core, &OrganizerCore::profileChanged, this, &ModListView::onProfileChanged); - connect(core.modList(), &ModList::modPrioritiesChanged, [=](auto&& indices) { onModPrioritiesChanged(indices); }); - connect(core.modList(), &ModList::clearOverwrite, [=] { m_actions->clearOverwrite(); }); + connect(core.modList(), &ModList::modPrioritiesChanged, [=](auto&& indices) { + onModPrioritiesChanged(indices); + }); + connect(core.modList(), &ModList::clearOverwrite, [=] { + m_actions->clearOverwrite(); + }); connect(core.modList(), &ModList::modStatesChanged, [=] { updateModCount(); setOverwriteMarkers(selectionModel()->selectedRows()); }); - connect(core.modList(), &ModList::modelReset, [=] { clearOverwriteMarkers(); }); + connect(core.modList(), &ModList::modelReset, [=] { + clearOverwriteMarkers(); + }); // proxy for various group by m_byPriorityProxy = new ModListByPriorityProxy(core.currentProfile(), core, this); - m_byCategoryProxy = new QtGroupingProxy(QModelIndex(), ModList::COL_CATEGORY, ModList::GroupingRole, 0, ModList::AggrRole); - m_byNexusIdProxy = new QtGroupingProxy(QModelIndex(), ModList::COL_MODID, ModList::GroupingRole, - QtGroupingProxy::FLAG_NOGROUPNAME | QtGroupingProxy::FLAG_NOSINGLE, ModList::AggrRole); + m_byCategoryProxy = new QtGroupingProxy(QModelIndex(), ModList::COL_CATEGORY, + ModList::GroupingRole, 0, ModList::AggrRole); + m_byNexusIdProxy = new QtGroupingProxy( + QModelIndex(), ModList::COL_MODID, ModList::GroupingRole, + QtGroupingProxy::FLAG_NOGROUPNAME | QtGroupingProxy::FLAG_NOSINGLE, + ModList::AggrRole); // we need to store the expanded/collapsed state of all items and restore them 1) when // switching proxies, 2) when filtering and 3) when reseting the mod list. connect(this, &QTreeView::expanded, [=](const QModelIndex& index) { - auto it = m_collapsed[m_sortProxy->sourceModel()].find(index.data(Qt::DisplayRole).toString()); + auto it = m_collapsed[m_sortProxy->sourceModel()].find( + index.data(Qt::DisplayRole).toString()); if (it != m_collapsed[m_sortProxy->sourceModel()].end()) { m_collapsed[m_sortProxy->sourceModel()].erase(it); } }); connect(this, &QTreeView::collapsed, [=](const QModelIndex& index) { - m_collapsed[m_sortProxy->sourceModel()].insert(index.data(Qt::DisplayRole).toString()); + m_collapsed[m_sortProxy->sourceModel()].insert( + index.data(Qt::DisplayRole).toString()); }); // the top-level proxy m_sortProxy = new ModListSortProxy(core.currentProfile(), &core); setModel(m_sortProxy); - connect(m_sortProxy, &ModList::modelReset, [=] { refreshExpandedItems(); }); + connect(m_sortProxy, &ModList::modelReset, [=] { + refreshExpandedItems(); + }); // update the proxy when changing the sort column/direction and the group - connect(m_sortProxy, &QAbstractItemModel::layoutAboutToBeChanged, [this](auto&& parents, auto&& hint) { - if (hint == QAbstractItemModel::VerticalSortHint) { - updateGroupByProxy(); - } - }); - connect(ui.groupBy, QOverload<int>::of(&QComboBox::currentIndexChanged), [=](int index) { - updateGroupByProxy(); - onModFilterActive(m_sortProxy->isFilterActive()); - }); + connect(m_sortProxy, &QAbstractItemModel::layoutAboutToBeChanged, + [this](auto&& parents, auto&& hint) { + if (hint == QAbstractItemModel::VerticalSortHint) { + updateGroupByProxy(); + } + }); + connect(ui.groupBy, QOverload<int>::of(&QComboBox::currentIndexChanged), + [=](int index) { + updateGroupByProxy(); + onModFilterActive(m_sortProxy->isFilterActive()); + }); sortByColumn(ModList::COL_PRIORITY, Qt::AscendingOrder); // inform the mod list about the type of item being dropped at the beginning of a drag // and the position of the drop indicator at the end (only for by-priority) connect(this, &ModListView::dragEntered, core.modList(), &ModList::onDragEnter); - connect(this, &ModListView::dropEntered, m_byPriorityProxy, &ModListByPriorityProxy::onDropEnter); + connect(this, &ModListView::dropEntered, m_byPriorityProxy, + &ModListByPriorityProxy::onDropEnter); - connect(m_sortProxy, &ModListSortProxy::filterInvalidated, this, &ModListView::updateModCount); + connect(m_sortProxy, &ModListSortProxy::filterInvalidated, this, + &ModListView::updateModCount); - connect(header(), &QHeaderView::sortIndicatorChanged, [=](int, Qt::SortOrder) { verticalScrollBar()->repaint(); }); - connect(header(), &QHeaderView::sectionResized, [=](int logicalIndex, int oldSize, int newSize) { - m_sortProxy->setColumnVisible(logicalIndex, newSize != 0); }); + connect(header(), &QHeaderView::sortIndicatorChanged, [=](int, Qt::SortOrder) { + verticalScrollBar()->repaint(); + }); + connect(header(), &QHeaderView::sectionResized, + [=](int logicalIndex, int oldSize, int newSize) { + m_sortProxy->setColumnVisible(logicalIndex, newSize != 0); + }); - setItemDelegateForColumn(ModList::COL_FLAGS, new ModFlagIconDelegate(this, ModList::COL_FLAGS, 120)); - setItemDelegateForColumn(ModList::COL_CONFLICTFLAGS, new ModConflictIconDelegate(this, ModList::COL_CONFLICTFLAGS, 80)); - setItemDelegateForColumn(ModList::COL_CONTENT, new ModContentIconDelegate(this, ModList::COL_CONTENT, 150)); - setItemDelegateForColumn(ModList::COL_VERSION, new ModListVersionDelegate(this, core.settings())); + setItemDelegateForColumn(ModList::COL_FLAGS, + new ModFlagIconDelegate(this, ModList::COL_FLAGS, 120)); + setItemDelegateForColumn( + ModList::COL_CONFLICTFLAGS, + new ModConflictIconDelegate(this, ModList::COL_CONFLICTFLAGS, 80)); + setItemDelegateForColumn(ModList::COL_CONTENT, + new ModContentIconDelegate(this, ModList::COL_CONTENT, 150)); + setItemDelegateForColumn(ModList::COL_VERSION, + new ModListVersionDelegate(this, core.settings())); if (m_core->settings().geometry().restoreState(header())) { - // hack: force the resize-signal to be triggered because restoreState doesn't seem to do that + // hack: force the resize-signal to be triggered because restoreState doesn't seem + // to do that for (int column = 0; column <= ModList::COL_LASTCOLUMN; ++column) { int sectionSize = header()->sectionSize(column); header()->resizeSection(column, sectionSize + 1); header()->resizeSection(column, sectionSize); } - } - else { + } else { // hide these columns by default header()->setSectionHidden(ModList::COL_CONTENT, true); header()->setSectionHidden(ModList::COL_MODID, true); @@ -788,28 +838,47 @@ void ModListView::setup(OrganizerCore& core, CategoryFactory& factory, MainWindo // we need QueuedConnection for the download/archive dropped otherwise the // installation starts within the drop-event and it's not possible to drag&drop // in the manual installer - connect(m_core->modList(), &ModList::downloadArchiveDropped, this, [=](int row, int priority) { - m_core->installDownload(row, priority); - }, Qt::QueuedConnection); - connect(m_core->modList(), &ModList::externalArchiveDropped, this, [=](const QUrl& url, int priority) { - setWindowState(Qt::WindowActive); - m_core->installArchive(url.toLocalFile(), priority, false, nullptr); - }, Qt::QueuedConnection); - connect(m_core->modList(), &ModList::externalFolderDropped, this, &ModListView::onExternalFolderDropped); + connect( + m_core->modList(), &ModList::downloadArchiveDropped, this, + [=](int row, int priority) { + m_core->installDownload(row, priority); + }, + Qt::QueuedConnection); + connect( + m_core->modList(), &ModList::externalArchiveDropped, this, + [=](const QUrl& url, int priority) { + setWindowState(Qt::WindowActive); + m_core->installArchive(url.toLocalFile(), priority, false, nullptr); + }, + Qt::QueuedConnection); + connect(m_core->modList(), &ModList::externalFolderDropped, this, + &ModListView::onExternalFolderDropped); - connect(selectionModel(), &QItemSelectionModel::selectionChanged, [=] { m_refreshMarkersTimer.start(); }); - connect(this, &QTreeView::collapsed, [=] { m_refreshMarkersTimer.start(); }); - connect(this, &QTreeView::expanded, [=] { m_refreshMarkersTimer.start(); }); + connect(selectionModel(), &QItemSelectionModel::selectionChanged, [=] { + m_refreshMarkersTimer.start(); + }); + connect(this, &QTreeView::collapsed, [=] { + m_refreshMarkersTimer.start(); + }); + connect(this, &QTreeView::expanded, [=] { + m_refreshMarkersTimer.start(); + }); // filters - connect(m_sortProxy, &ModListSortProxy::filterActive, this, &ModListView::onModFilterActive); - connect(m_filters.get(), &FilterList::criteriaChanged, [=](auto&& v) { onFiltersCriteria(v); }); - connect(m_filters.get(), &FilterList::optionsChanged, [=](auto&& mode, auto&& sep) { setFilterOptions(mode, sep); }); - connect(ui.filter, &QLineEdit::textChanged, m_sortProxy, &ModListSortProxy::updateFilter); + connect(m_sortProxy, &ModListSortProxy::filterActive, this, + &ModListView::onModFilterActive); + connect(m_filters.get(), &FilterList::criteriaChanged, [=](auto&& v) { + onFiltersCriteria(v); + }); + connect(m_filters.get(), &FilterList::optionsChanged, [=](auto&& mode, auto&& sep) { + setFilterOptions(mode, sep); + }); + connect(ui.filter, &QLineEdit::textChanged, m_sortProxy, + &ModListSortProxy::updateFilter); connect(ui.clearFilters, &QPushButton::clicked, [=]() { - ui.filter->clear(); - m_filters->clearSelection(); - }); + ui.filter->clear(); + m_filters->clearSelection(); + }); connect(m_sortProxy, &ModListSortProxy::filterInvalidated, [=]() { if (hasCollapsibleSeparators()) { refreshExpandedItems(); @@ -842,25 +911,26 @@ QRect ModListView::visualRect(const QModelIndex& index) const // this shift the visualRect() from QTreeView to match the new actual // zone after removing indentation (see the ModListStyledItemDelegate) QRect rect = QTreeView::visualRect(index); - if (hasCollapsibleSeparators() - && index.column() == 0 && index.isValid() - && index.parent().isValid()) { + if (hasCollapsibleSeparators() && index.column() == 0 && index.isValid() && + index.parent().isValid()) { rect.adjust(-indentation(), 0, 0, 0); } return rect; } -void ModListView::drawBranches(QPainter* painter, const QRect& rect, const QModelIndex& index) const +void ModListView::drawBranches(QPainter* painter, const QRect& rect, + const QModelIndex& index) const { - // the branches are the small indicator left to the row (there are none in the default style, and - // the VS dark style only has background for these) + // the branches are the small indicator left to the row (there are none in the default + // style, and the VS dark style only has background for these) // - // the branches are not shifted left with the visualRect() change and since MO2 uses stylesheet, - // it is not possible to shift those in the proxy style so we have to shift it here. + // the branches are not shifted left with the visualRect() change and since MO2 uses + // stylesheet, it is not possible to shift those in the proxy style so we have to + // shift it here. // QRect r(rect); if (hasCollapsibleSeparators() && index.parent().isValid()) { - r.adjust(-indentation(), 0, 0 -indentation(), 0); + r.adjust(-indentation(), 0, 0 - indentation(), 0); } QTreeView::drawBranches(painter, r, index); } @@ -872,8 +942,7 @@ void ModListView::commitData(QWidget* editor) auto [current, selected] = this->selected(); QTreeView::commitData(editor); setSelected(current, selected); - } - else { + } else { QTreeView::commitData(editor); } } @@ -900,15 +969,13 @@ void ModListView::onCustomContextMenuRequested(const QPoint& pos) if (!contextIdx.isValid()) { // no selection ModListGlobalContextMenu(*m_core, this).exec(viewport()->mapToGlobal(pos)); + } else { + ModListContextMenu(contextIdx, *m_core, *m_categories, this) + .exec(viewport()->mapToGlobal(pos)); } - else { - ModListContextMenu(contextIdx, *m_core, *m_categories, this).exec(viewport()->mapToGlobal(pos)); - } - } - catch (const std::exception& e) { + } catch (const std::exception& e) { reportError(tr("Exception: ").arg(e.what())); - } - catch (...) { + } catch (...) { reportError(tr("Unknown exception")); } } @@ -919,7 +986,8 @@ void ModListView::onDoubleClicked(const QModelIndex& index) return; } - if (m_core->modList()->timeElapsedSinceLastChecked() <= QApplication::doubleClickInterval()) { + if (m_core->modList()->timeElapsedSinceLastChecked() <= + QApplication::doubleClickInterval()) { // don't interpret double click if we only just checked a mod return; } @@ -937,38 +1005,44 @@ void ModListView::onDoubleClicked(const QModelIndex& index) if (modifiers.testFlag(Qt::ControlModifier)) { try { shell::Explore(modInfo->absolutePath()); - } - catch (const std::exception& e) { + } catch (const std::exception& e) { reportError(e.what()); } - } - else if (modifiers.testFlag(Qt::ShiftModifier)) { + } else if (modifiers.testFlag(Qt::ShiftModifier)) { try { - actions().visitNexusOrWebPage({ indexViewToModel(index) }); - } - catch (const std::exception& e) { + actions().visitNexusOrWebPage({indexViewToModel(index)}); + } catch (const std::exception& e) { reportError(e.what()); } - } - else if (hasCollapsibleSeparators() && modInfo->isSeparator()) { + } else if (hasCollapsibleSeparators() && modInfo->isSeparator()) { setExpanded(index, !isExpanded(index)); - } - else { + } else { try { auto tab = ModInfoTabIDs::None; switch (index.column()) { - case ModList::COL_NOTES: tab = ModInfoTabIDs::Notes; break; - case ModList::COL_VERSION: tab = ModInfoTabIDs::Nexus; break; - case ModList::COL_MODID: tab = ModInfoTabIDs::Nexus; break; - case ModList::COL_GAME: tab = ModInfoTabIDs::Nexus; break; - case ModList::COL_CATEGORY: tab = ModInfoTabIDs::Categories; break; - case ModList::COL_CONFLICTFLAGS: tab = ModInfoTabIDs::Conflicts; break; + case ModList::COL_NOTES: + tab = ModInfoTabIDs::Notes; + break; + case ModList::COL_VERSION: + tab = ModInfoTabIDs::Nexus; + break; + case ModList::COL_MODID: + tab = ModInfoTabIDs::Nexus; + break; + case ModList::COL_GAME: + tab = ModInfoTabIDs::Nexus; + break; + case ModList::COL_CATEGORY: + tab = ModInfoTabIDs::Categories; + break; + case ModList::COL_CONFLICTFLAGS: + tab = ModInfoTabIDs::Conflicts; + break; } actions().displayModInformation(modIndex, tab); - } - catch (const std::exception& e) { + } catch (const std::exception& e) { reportError(e.what()); } } @@ -1006,7 +1080,8 @@ void ModListView::setOverwriteMarkers(const QModelIndexList& indexes) insert(m_markers.archiveLooseOverwritten, info->getModArchiveLooseOverwritten()); } } - dataChanged(model()->index(0, 0), model()->index(model()->rowCount(), model()->columnCount())); + dataChanged(model()->index(0, 0), + model()->index(model()->rowCount(), model()->columnCount())); verticalScrollBar()->repaint(); } @@ -1016,9 +1091,7 @@ void ModListView::refreshMarkersAndPlugins() if (m_core->settings().interface().collapsibleSeparatorsHighlightFrom()) { for (auto& idx : selectionModel()->selectedRows()) { - if (hasCollapsibleSeparators() - && model()->hasChildren(idx) - && !isExpanded(idx)) { + if (hasCollapsibleSeparators() && model()->hasChildren(idx) && !isExpanded(idx)) { for (int i = 0; i < model()->rowCount(idx); ++i) { indexes.append(model()->index(i, idx.column(), idx)); } @@ -1037,7 +1110,6 @@ void ModListView::refreshMarkersAndPlugins() ui.pluginList->verticalScrollBar()->repaint(); } - void ModListView::setHighlightedMods(const std::vector<unsigned int>& pluginIndices) { m_markers.highlight.clear(); @@ -1045,16 +1117,19 @@ void ModListView::setHighlightedMods(const std::vector<unsigned int>& pluginIndi for (auto idx : pluginIndices) { QString pluginName = m_core->pluginList()->getName(idx); - const MOShared::FileEntryPtr fileEntry = directoryEntry.findFile(pluginName.toStdWString()); + const MOShared::FileEntryPtr fileEntry = + directoryEntry.findFile(pluginName.toStdWString()); if (fileEntry.get() != nullptr) { - QString originName = QString::fromStdWString(directoryEntry.getOriginByID(fileEntry->getOrigin()).getName()); + QString originName = QString::fromStdWString( + directoryEntry.getOriginByID(fileEntry->getOrigin()).getName()); const auto index = ModInfo::getIndex(originName); if (index != UINT_MAX) { m_markers.highlight.insert(index); } } } - dataChanged(model()->index(0, 0), model()->index(model()->rowCount(), model()->columnCount())); + dataChanged(model()->index(0, 0), + model()->index(model()->rowCount(), model()->columnCount())); verticalScrollBar()->repaint(); } @@ -1063,33 +1138,34 @@ QColor ModListView::markerColor(const QModelIndex& index) const unsigned int modIndex = index.data(ModList::IndexRole).toInt(); bool highligth = m_markers.highlight.find(modIndex) != m_markers.highlight.end(); bool overwrite = m_markers.overwrite.find(modIndex) != m_markers.overwrite.end(); - bool archiveOverwrite = m_markers.archiveOverwrite.find(modIndex) != m_markers.archiveOverwrite.end(); - bool archiveLooseOverwrite = m_markers.archiveLooseOverwrite.find(modIndex) != m_markers.archiveLooseOverwrite.end(); - bool overwritten = m_markers.overwritten.find(modIndex) != m_markers.overwritten.end(); - bool archiveOverwritten = m_markers.archiveOverwritten.find(modIndex) != m_markers.archiveOverwritten.end(); - bool archiveLooseOverwritten = m_markers.archiveLooseOverwritten.find(modIndex) != m_markers.archiveLooseOverwritten.end(); + bool archiveOverwrite = + m_markers.archiveOverwrite.find(modIndex) != m_markers.archiveOverwrite.end(); + bool archiveLooseOverwrite = m_markers.archiveLooseOverwrite.find(modIndex) != + m_markers.archiveLooseOverwrite.end(); + bool overwritten = + m_markers.overwritten.find(modIndex) != m_markers.overwritten.end(); + bool archiveOverwritten = + m_markers.archiveOverwritten.find(modIndex) != m_markers.archiveOverwritten.end(); + bool archiveLooseOverwritten = m_markers.archiveLooseOverwritten.find(modIndex) != + m_markers.archiveLooseOverwritten.end(); if (highligth) { return Settings::instance().colors().modlistContainsPlugin(); - } - else if (overwritten || archiveLooseOverwritten) { + } else if (overwritten || archiveLooseOverwritten) { return Settings::instance().colors().modlistOverwritingLoose(); - } - else if (overwrite || archiveLooseOverwrite) { + } else if (overwrite || archiveLooseOverwrite) { return Settings::instance().colors().modlistOverwrittenLoose(); - } - else if (archiveOverwritten) { + } else if (archiveOverwritten) { return Settings::instance().colors().modlistOverwritingArchive(); - } - else if (archiveOverwrite) { + } else if (archiveOverwrite) { return Settings::instance().colors().modlistOverwrittenArchive(); } // collapsed separator auto rowIndex = index.sibling(index.row(), 0); - if (hasCollapsibleSeparators() - && m_core->settings().interface().collapsibleSeparatorsHighlightTo() - && model()->hasChildren(rowIndex) && !isExpanded(rowIndex)) { + if (hasCollapsibleSeparators() && + m_core->settings().interface().collapsibleSeparatorsHighlightTo() && + model()->hasChildren(rowIndex) && !isExpanded(rowIndex)) { std::vector<QColor> colors; for (int i = 0; i < model()->rowCount(rowIndex); ++i) { @@ -1111,31 +1187,33 @@ QColor ModListView::markerColor(const QModelIndex& index) const a += color.alpha(); } - return QColor(r / colors.size(), g / colors.size(), b / colors.size(), a / colors.size()); + return QColor(r / colors.size(), g / colors.size(), b / colors.size(), + a / colors.size()); } return QColor(); } -std::vector<ModInfo::EFlag> ModListView::modFlags(const QModelIndex& index, bool* forceCompact) const +std::vector<ModInfo::EFlag> ModListView::modFlags(const QModelIndex& index, + bool* forceCompact) const { ModInfo::Ptr info = ModInfo::getByIndex(index.data(ModList::IndexRole).toInt()); - auto flags = info->getFlags(); + auto flags = info->getFlags(); bool compact = false; - if (info->isSeparator() - && hasCollapsibleSeparators() - && m_core->settings().interface().collapsibleSeparatorsIcons(ModList::COL_FLAGS) - && !isExpanded(index.sibling(index.row(), 0))) { + if (info->isSeparator() && hasCollapsibleSeparators() && + m_core->settings().interface().collapsibleSeparatorsIcons(ModList::COL_FLAGS) && + !isExpanded(index.sibling(index.row(), 0))) { // combine the child conflicts std::set eFlags(flags.begin(), flags.end()); for (int i = 0; i < model()->rowCount(index); ++i) { - auto cIndex = model()->index(i, index.column(), index).data(ModList::IndexRole).toInt(); + auto cIndex = + model()->index(i, index.column(), index).data(ModList::IndexRole).toInt(); auto cFlags = ModInfo::getByIndex(cIndex)->getFlags(); eFlags.insert(cFlags.begin(), cFlags.end()); } - flags = { eFlags.begin(), eFlags.end() }; + flags = {eFlags.begin(), eFlags.end()}; // force compact because there can be a lots of flags here compact = true; @@ -1148,25 +1226,27 @@ std::vector<ModInfo::EFlag> ModListView::modFlags(const QModelIndex& index, bool return flags; } -std::vector<ModInfo::EConflictFlag> ModListView::conflictFlags(const QModelIndex& index, bool* forceCompact) const +std::vector<ModInfo::EConflictFlag> ModListView::conflictFlags(const QModelIndex& index, + bool* forceCompact) const { ModInfo::Ptr info = ModInfo::getByIndex(index.data(ModList::IndexRole).toInt()); - auto flags = info->getConflictFlags(); + auto flags = info->getConflictFlags(); bool compact = false; - if (info->isSeparator() - && hasCollapsibleSeparators() - && m_core->settings().interface().collapsibleSeparatorsIcons(ModList::COL_CONFLICTFLAGS) - && !isExpanded(index.sibling(index.row(), 0))) { + if (info->isSeparator() && hasCollapsibleSeparators() && + m_core->settings().interface().collapsibleSeparatorsIcons( + ModList::COL_CONFLICTFLAGS) && + !isExpanded(index.sibling(index.row(), 0))) { // combine the child conflicts std::set<ModInfo::EConflictFlag> eFlags(flags.begin(), flags.end()); for (int i = 0; i < model()->rowCount(index); ++i) { - auto cIndex = model()->index(i, index.column(), index).data(ModList::IndexRole).toInt(); + auto cIndex = + model()->index(i, index.column(), index).data(ModList::IndexRole).toInt(); auto cFlags = ModInfo::getByIndex(cIndex)->getConflictFlags(); eFlags.insert(cFlags.begin(), cFlags.end()); } - flags = { eFlags.begin(), eFlags.end() }; + flags = {eFlags.begin(), eFlags.end()}; // force compact because there can be a lots of flags here compact = true; @@ -1179,29 +1259,30 @@ std::vector<ModInfo::EConflictFlag> ModListView::conflictFlags(const QModelIndex return flags; } -std::set<int> ModListView::contents(const QModelIndex& index, bool* includeChildren) const +std::set<int> ModListView::contents(const QModelIndex& index, + bool* includeChildren) const { auto modIndex = index.data(ModList::IndexRole); if (!modIndex.isValid()) { return {}; } ModInfo::Ptr info = ModInfo::getByIndex(index.data(ModList::IndexRole).toInt()); - auto contents = info->getContents(); - bool children = false; + auto contents = info->getContents(); + bool children = false; - if (info->isSeparator() - && hasCollapsibleSeparators() - && m_core->settings().interface().collapsibleSeparatorsIcons(ModList::COL_CONTENT) - && !isExpanded(index.sibling(index.row(), 0))) { + if (info->isSeparator() && hasCollapsibleSeparators() && + m_core->settings().interface().collapsibleSeparatorsIcons(ModList::COL_CONTENT) && + !isExpanded(index.sibling(index.row(), 0))) { // combine the child contents std::set eContents(contents.begin(), contents.end()); for (int i = 0; i < model()->rowCount(index); ++i) { - auto cIndex = model()->index(i, index.column(), index).data(ModList::IndexRole).toInt(); + auto cIndex = + model()->index(i, index.column(), index).data(ModList::IndexRole).toInt(); auto cContents = ModInfo::getByIndex(cIndex)->getContents(); eContents.insert(cContents.begin(), cContents.end()); } - contents = { eContents.begin(), eContents.end() }; + contents = {eContents.begin(), eContents.end()}; children = true; } @@ -1212,14 +1293,19 @@ std::set<int> ModListView::contents(const QModelIndex& index, bool* includeChild return contents; } -QList<QString> ModListView::contentsIcons(const QModelIndex& index, bool* forceCompact) const +QList<QString> ModListView::contentsIcons(const QModelIndex& index, + bool* forceCompact) const { auto contents = this->contents(index, forceCompact); QList<QString> result; m_core->modDataContents().forEachContentInOrOut( - contents, - [&result](auto const& content) { result.append(content.icon()); }, - [&result](auto const&) { result.append(QString()); }); + contents, + [&result](auto const& content) { + result.append(content.icon()); + }, + [&result](auto const&) { + result.append(QString()); + }); return result; } @@ -1232,14 +1318,16 @@ QString ModListView::contentsTooltip(const QModelIndex& index) const QString result("<table cellspacing=7>"); m_core->modDataContents().forEachContentIn(contents, [&result](auto const& content) { result.append(QString("<tr><td><img src=\"%1\" width=32/></td>" - "<td valign=\"middle\">%2</td></tr>") - .arg(content.icon()).arg(content.name())); - }); + "<td valign=\"middle\">%2</td></tr>") + .arg(content.icon()) + .arg(content.name())); + }); result.append("</table>"); return result; } -void ModListView::onFiltersCriteria(const std::vector<ModListSortProxy::Criteria>& criteria) +void ModListView::onFiltersCriteria( + const std::vector<ModListSortProxy::Criteria>& criteria) { setFilterCriteria(criteria); @@ -1247,23 +1335,20 @@ void ModListView::onFiltersCriteria(const std::vector<ModListSortProxy::Criteria if (criteria.empty()) { label = ""; - } - else if (criteria.size() == 1) { + } else if (criteria.size() == 1) { const auto& c = criteria[0]; if (c.type == ModListSortProxy::TypeContent) { const auto* content = m_core->modDataContents().findById(c.id); - label = content ? content->name() : QString(); - } - else { + label = content ? content->name() : QString(); + } else { label = m_categories->getCategoryNameByID(c.id); } if (label.isEmpty()) { log::error("category {}:{} not found", c.type, c.id); } - } - else { + } else { label = tr("<Multiple>"); } @@ -1282,8 +1367,8 @@ void ModListView::dragEnterEvent(QDragEnterEvent* event) // returns false, so we notify user on drag enter ModListDropInfo dropInfo(event->mimeData(), *m_core); - if (dropInfo.isValid() && !dropInfo.isLocalFileDrop() - && sortColumn() != ModList::COL_PRIORITY) { + if (dropInfo.isValid() && !dropInfo.isLocalFileDrop() && + sortColumn() != ModList::COL_PRIORITY) { log::warn("Drag&Drop is only supported when sorting by priority."); } } @@ -1315,7 +1400,8 @@ void ModListView::dropEvent(QDropEvent* event) // this event is used by the byPriorityProxy to know if allow // dropping mod between a separator and its first mod (there // is no way to deduce this except using dropIndicatorPosition()) - emit dropEntered(event->mimeData(), isExpanded(index), static_cast<DropPosition>(dropIndicatorPosition())); + emit dropEntered(event->mimeData(), isExpanded(index), + static_cast<DropPosition>(dropIndicatorPosition())); // see selectedIndexes() m_inDragMoveEvent = true; @@ -1328,14 +1414,14 @@ void ModListView::timerEvent(QTimerEvent* event) // prevent auto-collapse, see dragMoveEvent() if (event->timerId() == m_openTimer.timerId()) { QPoint pos = viewport()->mapFromGlobal(QCursor::pos()); - if (state() == QAbstractItemView::DraggingState - && viewport()->rect().contains(pos)) { + if (state() == QAbstractItemView::DraggingState && + viewport()->rect().contains(pos)) { QModelIndex index = indexAt(pos); - setExpanded(index, !m_core->settings().interface().autoCollapseOnHover() || !isExpanded(index)); + setExpanded(index, !m_core->settings().interface().autoCollapseOnHover() || + !isExpanded(index)); } m_openTimer.stop(); - } - else { + } else { QTreeView::timerEvent(event); } } @@ -1363,16 +1449,16 @@ void ModListView::mousePressEvent(QMouseEvent* event) const auto index = indexAt(event->pos()); - if (event->isAccepted() - && hasCollapsibleSeparators() - && index.isValid() && model()->hasChildren(indexAt(event->pos())) - && (event->modifiers() & Qt::AltModifier)) { + if (event->isAccepted() && hasCollapsibleSeparators() && index.isValid() && + model()->hasChildren(indexAt(event->pos())) && + (event->modifiers() & Qt::AltModifier)) { - const auto flag = selectionModel()->isSelected(index) ? - QItemSelectionModel::Select : QItemSelectionModel::Deselect; + const auto flag = selectionModel()->isSelected(index) + ? QItemSelectionModel::Select + : QItemSelectionModel::Deselect; const QItemSelection selection( - model()->index(0, index.column(), index), - model()->index(model()->rowCount(index) - 1, index.column(), index)); + model()->index(0, index.column(), index), + model()->index(model()->rowCount(index) - 1, index.column(), index)); selectionModel()->select(selection, flag | QItemSelectionModel::Rows); } } @@ -1399,25 +1485,24 @@ void ModListView::mouseReleaseEvent(QMouseEvent* event) // restore triggers setEditTriggers(triggers); - if (event->isAccepted() - && hasCollapsibleSeparators() - && index.isValid() && model()->hasChildren(indexAt(event->pos())) - && (event->modifiers() & Qt::AltModifier)) { + if (event->isAccepted() && hasCollapsibleSeparators() && index.isValid() && + model()->hasChildren(indexAt(event->pos())) && + (event->modifiers() & Qt::AltModifier)) { - const auto flag = selectionModel()->isSelected(index) ? - QItemSelectionModel::Select : QItemSelectionModel::Deselect; + const auto flag = selectionModel()->isSelected(index) + ? QItemSelectionModel::Select + : QItemSelectionModel::Deselect; const QItemSelection selection( - model()->index(0, index.column(), index), - model()->index(model()->rowCount(index) - 1, index.column(), index)); + model()->index(0, index.column(), index), + model()->index(model()->rowCount(index) - 1, index.column(), index)); selectionModel()->select(selection, flag | QItemSelectionModel::Rows); } } bool ModListView::event(QEvent* event) { - if (event->type() == QEvent::KeyPress - && m_core->currentProfile() - && selectionModel()->hasSelection()) { + if (event->type() == QEvent::KeyPress && m_core->currentProfile() && + selectionModel()->hasSelection()) { QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event); auto index = selectionModel()->currentIndex(); @@ -1426,36 +1511,32 @@ bool ModListView::event(QEvent* event) // ctrl+enter open explorer if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) { if (selectionModel()->selectedRows().count() == 1) { - m_actions->openExplorer({ indexViewToModel(index) }); + m_actions->openExplorer({indexViewToModel(index)}); return true; } } // ctrl+up/down move selection - else if (sortColumn() == ModList::COL_PRIORITY - && (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down)) { + else if (sortColumn() == ModList::COL_PRIORITY && + (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down)) { return moveSelection(keyEvent->key()); } - } - else if (keyEvent->modifiers() == Qt::ShiftModifier) { + } else if (keyEvent->modifiers() == Qt::ShiftModifier) { // shift+enter expand - if ((keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) - && selectionModel()->selectedRows().count() == 1) { + if ((keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) && + selectionModel()->selectedRows().count() == 1) { if (model()->hasChildren(index)) { setExpanded(index, !isExpanded(index)); - } - else if (index.parent().isValid()) { + } else if (index.parent().isValid()) { setExpanded(index.parent(), false); - selectionModel()->select(index.parent(), - QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); + selectionModel()->select(index.parent(), QItemSelectionModel::SelectCurrent | + QItemSelectionModel::Rows); setCurrentIndex(index.parent()); } } - } - else { + } else { if (keyEvent->key() == Qt::Key_Delete) { return removeSelection(); - } - else if (keyEvent->key() == Qt::Key_Space) { + } else if (keyEvent->key() == Qt::Key_Space) { return toggleSelectionState(); } } diff --git a/src/modlistview.h b/src/modlistview.h index aaef97af..f4b4e398 100644 --- a/src/modlistview.h +++ b/src/modlistview.h @@ -5,16 +5,19 @@ #include <set> #include <vector> -#include <QLabel> -#include <QTreeView> #include <QDragEnterEvent> #include <QLCDNumber> +#include <QLabel> +#include <QTreeView> +#include "modlistsortproxy.h" #include "qtgroupingproxy.h" #include "viewmarkingscrollbar.h" -#include "modlistsortproxy.h" -namespace Ui { class MainWindow; } +namespace Ui +{ +class MainWindow; +} class CategoryFactory; class FilterList; @@ -30,17 +33,18 @@ class ModListView : public QTreeView Q_OBJECT public: - // this is a public version of DropIndicatorPosition - enum DropPosition { - OnItem = DropIndicatorPosition::OnItem, - AboveItem = DropIndicatorPosition::AboveItem, - BelowItem = DropIndicatorPosition::BelowItem, + enum DropPosition + { + OnItem = DropIndicatorPosition::OnItem, + AboveItem = DropIndicatorPosition::AboveItem, + BelowItem = DropIndicatorPosition::BelowItem, OnViewport = DropIndicatorPosition::OnViewport }; // indiucate the groupby mode - enum class GroupByMode { + enum class GroupByMode + { NONE, SEPARATOR, CATEGORY, @@ -50,7 +54,8 @@ public: public: explicit ModListView(QWidget* parent = 0); - void setup(OrganizerCore& core, CategoryFactory& factory, MainWindow* mw, Ui::MainWindow* mwui); + void setup(OrganizerCore& core, CategoryFactory& factory, MainWindow* mw, + Ui::MainWindow* mwui); // restore/save the state between session // @@ -93,7 +98,8 @@ public: // focus the view, select the given index and scroll to it // void scrollToAndSelect(const QModelIndex& index); - void scrollToAndSelect(const QModelIndexList& indexes, const QModelIndex& current = QModelIndex()); + void scrollToAndSelect(const QModelIndexList& indexes, + const QModelIndex& current = QModelIndex()); // refresh the view (to call when settings have been changed) // @@ -119,7 +125,8 @@ public slots: // set the filter criteria/options for mods // void setFilterCriteria(const std::vector<ModListSortProxy::Criteria>& criteria); - void setFilterOptions(ModListSortProxy::FilterMode mode, ModListSortProxy::SeparatorsMode sep); + void setFilterOptions(ModListSortProxy::FilterMode mode, + ModListSortProxy::SeparatorsMode sep); // update the mod counter // @@ -134,7 +141,6 @@ public slots: void setHighlightedMods(const std::vector<unsigned int>& pluginIndices); protected: - // map from/to the view indexes to the model // QModelIndex indexModelToView(const QModelIndex& index) const; @@ -165,7 +171,8 @@ protected: // re-implemented to fix indentation with collapsible separators // QRect visualRect(const QModelIndex& index) const override; - void drawBranches(QPainter* painter, const QRect& rect, const QModelIndex& index) const override; + void drawBranches(QPainter* painter, const QRect& rect, + const QModelIndex& index) const override; void timerEvent(QTimerEvent* event) override; void dragEnterEvent(QDragEnterEvent* event) override; @@ -184,8 +191,7 @@ protected slots: void commitData(QWidget* editor) override; -private: // friend classes - +private: // friend classes friend class ModConflictIconDelegate; friend class ModContentIconDelegate; friend class ModFlagIconDelegate; @@ -194,9 +200,9 @@ private: // friend classes friend class ModListViewActions; friend class ModListViewMarkingScrollBar; -private: // private structures - - struct ModListViewUi { +private: // private structures + struct ModListViewUi + { // the group by combo box QComboBox* groupBy; @@ -213,7 +219,8 @@ private: // private structures PluginListView* pluginList; }; - struct MarkerInfos { + struct MarkerInfos + { // conflicts std::set<unsigned int> overwrite; std::set<unsigned int> overwritten; @@ -226,32 +233,34 @@ private: // private structures std::set<unsigned int> highlight; }; - struct ModCounters { - int active = 0; - int backup = 0; - int foreign = 0; + struct ModCounters + { + int active = 0; + int backup = 0; + int foreign = 0; int separator = 0; - int regular = 0; + int regular = 0; - struct { - int active = 0; - int backup = 0; - int foreign = 0; + struct + { + int active = 0; + int backup = 0; + int foreign = 0; int separator = 0; - int regular = 0; + int regular = 0; } visible; }; // index in the groupby combo // - enum GroupBy { - NONE = 0, + enum GroupBy + { + NONE = 0, CATEGORY = 1, NEXUS_ID = 2 }; -private: // private functions - +private: // private functions void onModPrioritiesChanged(const QModelIndexList& indices); void onModInstalled(const QString& modName); void onModFilterActive(bool filterActive); @@ -276,18 +285,19 @@ private: // private functions // retrieve the mod flags for the given index // - std::vector<ModInfo::EFlag> modFlags( - const QModelIndex& index, bool* forceCompact = nullptr) const; + std::vector<ModInfo::EFlag> modFlags(const QModelIndex& index, + bool* forceCompact = nullptr) const; // retrieve the conflicts flags for the given index // - std::vector<ModInfo::EConflictFlag> conflictFlags( - const QModelIndex& index, bool* forceCompact = nullptr) const; + std::vector<ModInfo::EConflictFlag> conflictFlags(const QModelIndex& index, + bool* forceCompact = nullptr) const; // retrieve the content icons and tooltip for the given index // std::set<int> contents(const QModelIndex& index, bool* includeChildren) const; - QList<QString> contentsIcons(const QModelIndex& index, bool* forceCompact = nullptr) const; + QList<QString> contentsIcons(const QModelIndex& index, + bool* forceCompact = nullptr) const; QString contentsTooltip(const QModelIndex& index) const; // compute the counters for mods according to the current filter @@ -309,8 +319,7 @@ private: // private functions // void updateGroupByProxy(); -public: // member variables - +public: // member variables OrganizerCore* m_core; std::unique_ptr<FilterList> m_filters; CategoryFactory* m_categories; @@ -338,7 +347,6 @@ public: // member variables // replace the auto-expand timer from QTreeView to avoid // auto-collapsing QBasicTimer m_openTimer; - }; -#endif // MODLISTVIEW_H +#endif // MODLISTVIEW_H diff --git a/src/modlistviewactions.cpp b/src/modlistviewactions.cpp index 272d2ec6..a6f0f07e 100644 --- a/src/modlistviewactions.cpp +++ b/src/modlistviewactions.cpp @@ -5,57 +5,50 @@ #include <QInputDialog> #include <QLabel> +#include "filesystemutilities.h" #include <log.h> #include <report.h> -#include "filesystemutilities.h" #include "categories.h" +#include "csvbuilder.h" +#include "directoryrefresher.h" #include "filedialogmemory.h" #include "filterlist.h" #include "listdialog.h" +#include "messagedialog.h" +#include "modelutils.h" #include "modinfodialog.h" #include "modlist.h" #include "modlistview.h" -#include "modelutils.h" -#include "messagedialog.h" #include "nexusinterface.h" #include "nxmaccessmanager.h" -#include "savetextasdialog.h" #include "organizercore.h" #include "overwriteinfodialog.h" -#include "csvbuilder.h" #include "pluginlistview.h" -#include "shared/filesorigin.h" +#include "savetextasdialog.h" #include "shared/directoryentry.h" #include "shared/fileregister.h" -#include "directoryrefresher.h" +#include "shared/filesorigin.h" using namespace MOBase; using namespace MOShared; - -ModListViewActions::ModListViewActions( - OrganizerCore& core, FilterList& filters, CategoryFactory& categoryFactory, - ModListView* view, PluginListView* pluginView, QObject* nxmReceiver) : - QObject(view) - , m_core(core) - , m_filters(filters) - , m_categories(categoryFactory) - , m_view(view) - , m_pluginView(pluginView) - , m_parent(view->topLevelWidget()) - , m_receiver(nxmReceiver) -{ - -} +ModListViewActions::ModListViewActions(OrganizerCore& core, FilterList& filters, + CategoryFactory& categoryFactory, + ModListView* view, PluginListView* pluginView, + QObject* nxmReceiver) + : QObject(view), m_core(core), m_filters(filters), m_categories(categoryFactory), + m_view(view), m_pluginView(pluginView), m_parent(view->topLevelWidget()), + m_receiver(nxmReceiver) +{} int ModListViewActions::findInstallPriority(const QModelIndex& index) const { int newPriority = -1; - if (index.isValid() && index.data(ModList::IndexRole).isValid() - && m_view->sortColumn() == ModList::COL_PRIORITY) { + if (index.isValid() && index.data(ModList::IndexRole).isValid() && + m_view->sortColumn() == ModList::COL_PRIORITY) { auto mIndex = index.data(ModList::IndexRole).toInt(); - auto info = ModInfo::getByIndex(mIndex); + auto info = ModInfo::getByIndex(mIndex); newPriority = m_core.currentProfile()->getModPriority(mIndex); if (info->isSeparator()) { @@ -71,17 +64,15 @@ int ModListViewActions::findInstallPriority(const QModelIndex& index) const auto it = std::find_if(ibp.find(newPriority + 1), ibp.end(), isSeparator); if (it != ibp.end()) { newPriority = it->first; - } - else { + } else { newPriority = -1; } - } - else { - auto it = std::find_if(std::reverse_iterator{ ibp.find(newPriority - 1) }, ibp.rend(), isSeparator); + } else { + auto it = std::find_if(std::reverse_iterator{ibp.find(newPriority - 1)}, + ibp.rend(), isSeparator); if (it != ibp.rend()) { newPriority = it->first + 1; - } - else { + } else { // create "before" priority 0, i.e. at the end in descending priority. newPriority = 0; } @@ -92,7 +83,8 @@ int ModListViewActions::findInstallPriority(const QModelIndex& index) const return newPriority; } -void ModListViewActions::installMod(const QString& archivePath, const QModelIndex& index) const +void ModListViewActions::installMod(const QString& archivePath, + const QModelIndex& index) const { try { QString path = archivePath; @@ -102,18 +94,17 @@ void ModListViewActions::installMod(const QString& archivePath, const QModelInde *iter = "*." + *iter; } - path = FileDialogMemory::getOpenFileName("installMod", m_parent, tr("Choose Mod"), QString(), - tr("Mod Archive").append(QString(" (%1)").arg(extensions.join(" ")))); + path = FileDialogMemory::getOpenFileName( + "installMod", m_parent, tr("Choose Mod"), QString(), + tr("Mod Archive").append(QString(" (%1)").arg(extensions.join(" ")))); } if (path.isEmpty()) { return; - } - else { + } else { m_core.installMod(path, findInstallPriority(index), false, nullptr, QString()); } - } - catch (const std::exception& e) { + } catch (const std::exception& e) { reportError(e.what()); } } @@ -126,9 +117,10 @@ void ModListViewActions::createEmptyMod(const QModelIndex& index) const while (name->isEmpty()) { bool ok; name.update(QInputDialog::getText(m_parent, tr("Create Mod..."), - tr("This will create an empty mod.\n" - "Please enter a name:"), QLineEdit::Normal, "", &ok), - GUESS_USER); + tr("This will create an empty mod.\n" + "Please enter a name:"), + QLineEdit::Normal, "", &ok), + GUESS_USER); if (!ok) { return; } @@ -139,7 +131,6 @@ void ModListViewActions::createEmptyMod(const QModelIndex& index) const return; } - if (m_core.createMod(name) == nullptr) { return; } @@ -153,7 +144,8 @@ void ModListViewActions::createEmptyMod(const QModelIndex& index) const m_core.modList()->changeModPriority(mIndex, newPriority); } - m_view->scrollToAndSelect(m_view->indexModelToView(m_core.modList()->index(mIndex, 0))); + m_view->scrollToAndSelect( + m_view->indexModelToView(m_core.modList()->index(mIndex, 0))); } void ModListViewActions::createSeparator(const QModelIndex& index) const @@ -163,10 +155,13 @@ void ModListViewActions::createSeparator(const QModelIndex& index) const while (name->isEmpty()) { bool ok; name.update(QInputDialog::getText(m_parent, tr("Create Separator..."), - tr("This will create a new separator.\n" - "Please enter a name:"), QLineEdit::Normal, "", &ok), - GUESS_USER); - if (!ok) { return; } + tr("This will create a new separator.\n" + "Please enter a name:"), + QLineEdit::Normal, "", &ok), + GUESS_USER); + if (!ok) { + return; + } } if (m_core.modList()->getMod(name) != nullptr) { reportError(tr("A separator with this name already exists")); @@ -179,7 +174,8 @@ void ModListViewActions::createSeparator(const QModelIndex& index) const int newPriority = -1; if (index.isValid() && m_view->sortColumn() == ModList::COL_PRIORITY) { - newPriority = m_core.currentProfile()->getModPriority(index.data(ModList::IndexRole).toInt()); + newPriority = + m_core.currentProfile()->getModPriority(index.data(ModList::IndexRole).toInt()); // descending order, we need to fix the priority if (m_view->sortOrder() == Qt::DescendingOrder) { @@ -202,22 +198,23 @@ void ModListViewActions::createSeparator(const QModelIndex& index) const ModInfo::getByIndex(mIndex)->setColor(*c); } - m_view->scrollToAndSelect(m_view->indexModelToView(m_core.modList()->index(mIndex, 0))); + m_view->scrollToAndSelect( + m_view->indexModelToView(m_core.modList()->index(mIndex, 0))); } void ModListViewActions::setAllMatchingModsEnabled(bool enabled) const { // number of mods to enable / disable const auto counters = m_view->counters(); - const auto count = enabled ? - counters.visible.regular - counters.visible.active : counters.visible.active; + const auto count = enabled ? counters.visible.regular - counters.visible.active + : counters.visible.active; // retrieve visible mods from the model view const auto allIndex = m_view->indexViewToModel(flatIndex(m_view->model())); - const QString message = enabled ? - tr("Really enable %1 mod(s)?") : tr("Really disable %1 mod(s)?"); + const QString message = + enabled ? tr("Really enable %1 mod(s)?") : tr("Really disable %1 mod(s)?"); if (QMessageBox::question(m_parent, tr("Confirm"), message.arg(count), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { m_core.modList()->setActive(allIndex, enabled); } } @@ -226,16 +223,21 @@ void ModListViewActions::checkModsForUpdates() const { bool checkingModsForUpdate = false; if (NexusInterface::instance().getAccessManager()->validated()) { - checkingModsForUpdate = ModInfo::checkAllForUpdate(&m_core.pluginContainer(), m_receiver); - NexusInterface::instance().requestEndorsementInfo(m_receiver, QVariant(), QString()); + checkingModsForUpdate = + ModInfo::checkAllForUpdate(&m_core.pluginContainer(), m_receiver); + NexusInterface::instance().requestEndorsementInfo(m_receiver, QVariant(), + QString()); NexusInterface::instance().requestTrackingInfo(m_receiver, QVariant(), QString()); } else { QString apiKey; if (GlobalSettings::nexusApiKey(apiKey)) { - m_core.doAfterLogin([=] () { checkModsForUpdates(); }); + m_core.doAfterLogin([=]() { + checkModsForUpdates(); + }); NexusInterface::instance().getAccessManager()->apiCheck(apiKey); } else { - log::warn("{}", tr("You are not currently authenticated with Nexus. Please do so under Settings -> Nexus.")); + log::warn("{}", tr("You are not currently authenticated with Nexus. Please do so " + "under Settings -> Nexus.")); } } @@ -249,21 +251,16 @@ void ModListViewActions::checkModsForUpdates() const } if (updatesAvailable || checkingModsForUpdate) { - m_view->setFilterCriteria({{ - ModListSortProxy::TypeSpecial, - CategoryFactory::UpdateAvailable, - false} - }); + m_view->setFilterCriteria( + {{ModListSortProxy::TypeSpecial, CategoryFactory::UpdateAvailable, false}}); - m_filters.setSelection({{ - ModListSortProxy::TypeSpecial, - CategoryFactory::UpdateAvailable, - false - }}); + m_filters.setSelection( + {{ModListSortProxy::TypeSpecial, CategoryFactory::UpdateAvailable, false}}); } } -void ModListViewActions::checkModsForUpdates(std::multimap<QString, int> const& IDs) const +void ModListViewActions::checkModsForUpdates( + std::multimap<QString, int> const& IDs) const { if (m_core.settings().network().offlineMode()) { return; @@ -271,15 +268,16 @@ void ModListViewActions::checkModsForUpdates(std::multimap<QString, int> const& if (NexusInterface::instance().getAccessManager()->validated()) { ModInfo::manualUpdateCheck(m_receiver, IDs); - } - else { + } else { QString apiKey; if (GlobalSettings::nexusApiKey(apiKey)) { - m_core.doAfterLogin([=]() { checkModsForUpdates(IDs); }); + m_core.doAfterLogin([=]() { + checkModsForUpdates(IDs); + }); NexusInterface::instance().getAccessManager()->apiCheck(apiKey); - } - else - log::warn("{}", tr("You are not currently authenticated with Nexus. Please do so under Settings -> Nexus.")); + } else + log::warn("{}", tr("You are not currently authenticated with Nexus. Please do so " + "under Settings -> Nexus.")); } } @@ -300,13 +298,18 @@ void ModListViewActions::exportModListCSV() const selection.setWindowTitle(tr("Export to csv")); QLabel* csvDescription = new QLabel(); - csvDescription->setText(tr("CSV (Comma Separated Values) is a format that can be imported in programs like Excel to create a spreadsheet.\nYou can also use online editors and converters instead.")); + csvDescription->setText( + tr("CSV (Comma Separated Values) is a format that can be imported in programs " + "like Excel to create a spreadsheet.\nYou can also use online editors and " + "converters instead.")); grid->addWidget(csvDescription); QGroupBox* groupBoxRows = new QGroupBox(tr("Select what mods you want export:")); - QRadioButton* all = new QRadioButton(tr("All installed mods")); - QRadioButton* active = new QRadioButton(tr("Only active (checked) mods from your current profile")); - QRadioButton* visible = new QRadioButton(tr("All currently visible mods in the mod list")); + QRadioButton* all = new QRadioButton(tr("All installed mods")); + QRadioButton* active = + new QRadioButton(tr("Only active (checked) mods from your current profile")); + QRadioButton* visible = + new QRadioButton(tr("All currently visible mods in the mod list")); QVBoxLayout* vbox = new QVBoxLayout; vbox->addWidget(all); @@ -330,14 +333,14 @@ void ModListViewActions::exportModListCSV() const mod_Priority->setChecked(true); QCheckBox* mod_Name = new QCheckBox(tr("Mod_Name")); mod_Name->setChecked(true); - QCheckBox* mod_Note = new QCheckBox(tr("Notes_column")); + QCheckBox* mod_Note = new QCheckBox(tr("Notes_column")); QCheckBox* mod_Status = new QCheckBox(tr("Mod_Status")); mod_Status->setChecked(true); - QCheckBox* primary_Category = new QCheckBox(tr("Primary_Category")); - QCheckBox* nexus_ID = new QCheckBox(tr("Nexus_ID")); - QCheckBox* mod_Nexus_URL = new QCheckBox(tr("Mod_Nexus_URL")); - QCheckBox* mod_Version = new QCheckBox(tr("Mod_Version")); - QCheckBox* install_Date = new QCheckBox(tr("Install_Date")); + QCheckBox* primary_Category = new QCheckBox(tr("Primary_Category")); + QCheckBox* nexus_ID = new QCheckBox(tr("Nexus_ID")); + QCheckBox* mod_Nexus_URL = new QCheckBox(tr("Mod_Nexus_URL")); + QCheckBox* mod_Version = new QCheckBox(tr("Mod_Version")); + QCheckBox* install_Date = new QCheckBox(tr("Install_Date")); QCheckBox* download_File_Name = new QCheckBox(tr("Download_File_Name")); QVBoxLayout* vbox1 = new QVBoxLayout; @@ -355,9 +358,10 @@ void ModListViewActions::exportModListCSV() const grid->addWidget(groupBoxColumns); - QPushButton* ok = new QPushButton("Ok"); + QPushButton* ok = new QPushButton("Ok"); QPushButton* cancel = new QPushButton("Cancel"); - QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + QDialogButtonBox* buttons = + new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); connect(buttons, SIGNAL(accepted()), &selection, SLOT(accept())); connect(buttons, SIGNAL(rejected()), &selection, SLOT(reject())); @@ -366,38 +370,45 @@ void ModListViewActions::exportModListCSV() const selection.setLayout(grid); - if (selection.exec() == QDialog::Accepted) { unsigned int numMods = ModInfo::getNumMods(); - int selectedRowID = buttonGroupRows->checkedId(); + int selectedRowID = buttonGroupRows->checkedId(); try { QBuffer buffer; buffer.open(QIODevice::ReadWrite); CSVBuilder builder(&buffer); builder.setEscapeMode(CSVBuilder::TYPE_STRING, CSVBuilder::QUOTE_ALWAYS); - std::vector<std::pair<QString, CSVBuilder::EFieldType> > fields; + std::vector<std::pair<QString, CSVBuilder::EFieldType>> fields; if (mod_Priority->isChecked()) - fields.push_back(std::make_pair(QString("#Mod_Priority"), CSVBuilder::TYPE_STRING)); + fields.push_back( + std::make_pair(QString("#Mod_Priority"), CSVBuilder::TYPE_STRING)); if (mod_Status->isChecked()) - fields.push_back(std::make_pair(QString("#Mod_Status"), CSVBuilder::TYPE_STRING)); + fields.push_back( + std::make_pair(QString("#Mod_Status"), CSVBuilder::TYPE_STRING)); if (mod_Name->isChecked()) fields.push_back(std::make_pair(QString("#Mod_Name"), CSVBuilder::TYPE_STRING)); if (mod_Note->isChecked()) fields.push_back(std::make_pair(QString("#Note"), CSVBuilder::TYPE_STRING)); if (primary_Category->isChecked()) - fields.push_back(std::make_pair(QString("#Primary_Category"), CSVBuilder::TYPE_STRING)); + fields.push_back( + std::make_pair(QString("#Primary_Category"), CSVBuilder::TYPE_STRING)); if (nexus_ID->isChecked()) - fields.push_back(std::make_pair(QString("#Nexus_ID"), CSVBuilder::TYPE_INTEGER)); + fields.push_back( + std::make_pair(QString("#Nexus_ID"), CSVBuilder::TYPE_INTEGER)); if (mod_Nexus_URL->isChecked()) - fields.push_back(std::make_pair(QString("#Mod_Nexus_URL"), CSVBuilder::TYPE_STRING)); + fields.push_back( + std::make_pair(QString("#Mod_Nexus_URL"), CSVBuilder::TYPE_STRING)); if (mod_Version->isChecked()) - fields.push_back(std::make_pair(QString("#Mod_Version"), CSVBuilder::TYPE_STRING)); + fields.push_back( + std::make_pair(QString("#Mod_Version"), CSVBuilder::TYPE_STRING)); if (install_Date->isChecked()) - fields.push_back(std::make_pair(QString("#Install_Date"), CSVBuilder::TYPE_STRING)); + fields.push_back( + std::make_pair(QString("#Install_Date"), CSVBuilder::TYPE_STRING)); if (download_File_Name->isChecked()) - fields.push_back(std::make_pair(QString("#Download_File_Name"), CSVBuilder::TYPE_STRING)); + fields.push_back( + std::make_pair(QString("#Download_File_Name"), CSVBuilder::TYPE_STRING)); builder.setFields(fields); @@ -406,34 +417,46 @@ void ModListViewActions::exportModListCSV() const auto indexesByPriority = m_core.currentProfile()->getAllIndexesByPriority(); for (auto& iter : indexesByPriority) { ModInfo::Ptr info = ModInfo::getByIndex(iter.second); - bool enabled = m_core.currentProfile()->modEnabled(iter.second); + bool enabled = m_core.currentProfile()->modEnabled(iter.second); if ((selectedRowID == 1) && !enabled) { continue; - } - else if ((selectedRowID == 2) && !m_view->isModVisible(iter.second)) { + } else if ((selectedRowID == 2) && !m_view->isModVisible(iter.second)) { continue; } std::vector<ModInfo::EFlag> flags = info->getFlags(); - if ((std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) == flags.end()) && - (std::find(flags.begin(), flags.end(), ModInfo::FLAG_BACKUP) == flags.end())) { + if ((std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) == + flags.end()) && + (std::find(flags.begin(), flags.end(), ModInfo::FLAG_BACKUP) == + flags.end())) { if (mod_Priority->isChecked()) - builder.setRowField("#Mod_Priority", QString("%1").arg(iter.first, 4, 10, QChar('0'))); + builder.setRowField("#Mod_Priority", + QString("%1").arg(iter.first, 4, 10, QChar('0'))); if (mod_Status->isChecked()) builder.setRowField("#Mod_Status", (enabled) ? "+" : "-"); if (mod_Name->isChecked()) builder.setRowField("#Mod_Name", info->name()); if (mod_Note->isChecked()) - builder.setRowField("#Note", QString("%1").arg(info->comments().remove(','))); + builder.setRowField("#Note", + QString("%1").arg(info->comments().remove(','))); if (primary_Category->isChecked()) - builder.setRowField("#Primary_Category", (m_categories.categoryExists(info->primaryCategory())) ? m_categories.getCategoryNameByID(info->primaryCategory()) : ""); + builder.setRowField( + "#Primary_Category", + (m_categories.categoryExists(info->primaryCategory())) + ? m_categories.getCategoryNameByID(info->primaryCategory()) + : ""); if (nexus_ID->isChecked()) builder.setRowField("#Nexus_ID", info->nexusId()); if (mod_Nexus_URL->isChecked()) - builder.setRowField("#Mod_Nexus_URL", (info->nexusId() > 0) ? NexusInterface::instance().getModURL(info->nexusId(), info->gameName()) : ""); + builder.setRowField("#Mod_Nexus_URL", + (info->nexusId() > 0) + ? NexusInterface::instance().getModURL( + info->nexusId(), info->gameName()) + : ""); if (mod_Version->isChecked()) builder.setRowField("#Mod_Version", info->version().canonicalString()); if (install_Date->isChecked()) - builder.setRowField("#Install_Date", info->creationTime().toString("yyyy/MM/dd HH:mm:ss")); + builder.setRowField("#Install_Date", + info->creationTime().toString("yyyy/MM/dd HH:mm:ss")); if (download_File_Name->isChecked()) builder.setRowField("#Download_File_Name", info->installationFile()); @@ -444,14 +467,14 @@ void ModListViewActions::exportModListCSV() const SaveTextAsDialog saveDialog(m_parent); saveDialog.setText(buffer.data()); saveDialog.exec(); - } - catch (const std::exception& e) { + } catch (const std::exception& e) { reportError(tr("export failed: %1").arg(e.what())); } } } -void ModListViewActions::displayModInformation(const QString& modName, ModInfoTabIDs tab) const +void ModListViewActions::displayModInformation(const QString& modName, + ModInfoTabIDs tab) const { unsigned int index = ModInfo::getIndex(modName); if (index == UINT_MAX) { @@ -463,16 +486,20 @@ void ModListViewActions::displayModInformation(const QString& modName, ModInfoTa displayModInformation(modInfo, index, tab); } -void ModListViewActions::displayModInformation(unsigned int index, ModInfoTabIDs tab) const +void ModListViewActions::displayModInformation(unsigned int index, + ModInfoTabIDs tab) const { ModInfo::Ptr modInfo = ModInfo::getByIndex(index); displayModInformation(modInfo, index, tab); } -void ModListViewActions::displayModInformation(ModInfo::Ptr modInfo, unsigned int modIndex, ModInfoTabIDs tab) const +void ModListViewActions::displayModInformation(ModInfo::Ptr modInfo, + unsigned int modIndex, + ModInfoTabIDs tab) const { if (!m_core.modList()->modInfoAboutToChange(modInfo)) { - log::debug("a different mod information dialog is open. If this is incorrect, please restart MO"); + log::debug("a different mod information dialog is open. If this is incorrect, " + "please restart MO"); return; } std::vector<ModInfo::EFlag> flags = modInfo->getFlags(); @@ -482,8 +509,7 @@ void ModListViewActions::displayModInformation(ModInfo::Ptr modInfo, unsigned in if (dialog == nullptr) { dialog = new OverwriteInfoDialog(modInfo, m_parent); dialog->setObjectName("__overwriteDialog"); - } - else { + } else { qobject_cast<OverwriteInfoDialog*>(dialog)->setModInfo(modInfo); } @@ -495,23 +521,23 @@ void ModListViewActions::displayModInformation(ModInfo::Ptr modInfo, unsigned in dialog->deleteLater(); m_core.refreshDirectoryStructure(); }); - } - catch (const std::exception& e) { + } catch (const std::exception& e) { reportError(tr("Failed to display overwrite dialog: %1").arg(e.what())); } - } - else { + } else { modInfo->saveMeta(); ModInfoDialog dialog(m_core, m_core.pluginContainer(), modInfo, m_view, m_parent); - connect(&dialog, &ModInfoDialog::originModified, this, &ModListViewActions::originModified); + connect(&dialog, &ModInfoDialog::originModified, this, + &ModListViewActions::originModified); connect(&dialog, &ModInfoDialog::modChanged, [=](unsigned int index) { auto idx = m_view->indexModelToView(m_core.modList()->index(index, 0)); - m_view->selectionModel()->select(idx, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); + m_view->selectionModel()->select(idx, QItemSelectionModel::ClearAndSelect | + QItemSelectionModel::Rows); m_view->scrollTo(idx); }); - //Open the tab first if we want to use the standard indexes of the tabs. + // Open the tab first if we want to use the standard indexes of the tabs. if (tab != ModInfoTabIDs::None) { dialog.selectTab(tab); } @@ -524,19 +550,19 @@ void ModListViewActions::displayModInformation(ModInfo::Ptr modInfo, unsigned in } if (m_core.currentProfile()->modEnabled(modIndex) && !modInfo->isForeign()) { - FilesOrigin& origin = m_core.directoryStructure()->getOriginByName(ToWString(modInfo->name())); + FilesOrigin& origin = + m_core.directoryStructure()->getOriginByName(ToWString(modInfo->name())); origin.enable(false); if (m_core.directoryStructure()->originExists(ToWString(modInfo->name()))) { - FilesOrigin& origin = m_core.directoryStructure()->getOriginByName(ToWString(modInfo->name())); + FilesOrigin& origin = + m_core.directoryStructure()->getOriginByName(ToWString(modInfo->name())); origin.enable(false); - m_core.directoryRefresher()->addModToStructure(m_core.directoryStructure() - , modInfo->name() - , m_core.currentProfile()->getModPriority(modIndex) - , modInfo->absolutePath() - , modInfo->stealFiles() - , modInfo->archives()); + m_core.directoryRefresher()->addModToStructure( + m_core.directoryStructure(), modInfo->name(), + m_core.currentProfile()->getModPriority(modIndex), modInfo->absolutePath(), + modInfo->stealFiles(), modInfo->archives()); DirectoryRefresher::cleanStructure(m_core.directoryStructure()); m_core.directoryStructure()->getFileRegister()->sortOrigins(); m_core.refreshLists(); @@ -557,10 +583,11 @@ void ModListViewActions::sendModsToBottom(const QModelIndexList& indexes) const void ModListViewActions::sendModsToPriority(const QModelIndexList& indexes) const { bool ok; - int priority = QInputDialog::getInt(m_parent, - tr("Set Priority"), tr("Set the priority of the selected mods"), - 0, 0, std::numeric_limits<int>::max(), 1, &ok); - if (!ok) return; + int priority = QInputDialog::getInt(m_parent, tr("Set Priority"), + tr("Set the priority of the selected mods"), 0, 0, + std::numeric_limits<int>::max(), 1, &ok); + if (!ok) + return; m_core.modList()->changeModsPriority(indexes, priority); } @@ -573,7 +600,8 @@ void ModListViewActions::sendModsToSeparator(const QModelIndexList& indexes) con if (index < ModInfo::getNumMods()) { ModInfo::Ptr modInfo = ModInfo::getByIndex(index); if (modInfo->isSeparator()) { - separators << modInfo->name().chopped(10); // chops the "_separator" away from the name + separators << modInfo->name().chopped( + 10); // chops the "_separator" away from the name } } } @@ -596,14 +624,13 @@ void ModListViewActions::sendModsToSeparator(const QModelIndexList& indexes) con return; } - const auto sepPriority = m_core.currentProfile()->getModPriority( - ModInfo::getIndex(result + "_separator")); + const auto sepPriority = + m_core.currentProfile()->getModPriority(ModInfo::getIndex(result + "_separator")); auto isSeparator = [](const auto& p) { return ModInfo::getByIndex(p.second)->isSeparator(); }; - // start right after/before the current priority and look for the next // separator int priority = -1; @@ -611,17 +638,15 @@ void ModListViewActions::sendModsToSeparator(const QModelIndexList& indexes) con auto it = std::find_if(ibp.find(sepPriority + 1), ibp.end(), isSeparator); if (it != ibp.end()) { priority = it->first; - } - else { + } else { priority = Profile::MaximumPriority; } - } - else { - auto it = std::find_if(--std::reverse_iterator{ ibp.find(sepPriority - 1) }, ibp.rend(), isSeparator); + } else { + auto it = std::find_if(--std::reverse_iterator{ibp.find(sepPriority - 1)}, + ibp.rend(), isSeparator); if (it != ibp.rend()) { priority = it->first + 1; - } - else { + } else { // create "before" priority 0, i.e. at the end in descending priority. priority = Profile::MinimumPriority; } @@ -629,7 +654,8 @@ void ModListViewActions::sendModsToSeparator(const QModelIndexList& indexes) con // when the priority of a single mod is incremented, we need to shift the // target priority, otherwise we will miss the target by one - if (indexes.size() == 1 && indexes[0].data(ModList::PriorityRole).toInt() < sepPriority) { + if (indexes.size() == 1 && + indexes[0].data(ModList::PriorityRole).toInt() < sepPriority) { priority--; } @@ -649,9 +675,10 @@ void ModListViewActions::sendModsToFirstConflict(const QModelIndexList& indexes) } std::set<int> priorities; - std::transform(conflicts.begin(), conflicts.end(), std::inserter(priorities, priorities.end()), [=](auto index) { - return m_core.currentProfile()->getModPriority(index); - }); + std::transform(conflicts.begin(), conflicts.end(), + std::inserter(priorities, priorities.end()), [=](auto index) { + return m_core.currentProfile()->getModPriority(index); + }); if (!priorities.empty()) { m_core.modList()->changeModsPriority(indexes, *priorities.begin()); @@ -667,13 +694,15 @@ void ModListViewActions::sendModsToLastConflict(const QModelIndexList& indexes) continue; } auto info = ModInfo::getByIndex(idx.data(ModList::IndexRole).toInt()); - conflicts.insert(info->getModOverwritten().begin(), info->getModOverwritten().end()); + conflicts.insert(info->getModOverwritten().begin(), + info->getModOverwritten().end()); } std::set<int> priorities; - std::transform(conflicts.begin(), conflicts.end(), std::inserter(priorities, priorities.end()), [=](auto index) { - return m_core.currentProfile()->getModPriority(index); - }); + std::transform(conflicts.begin(), conflicts.end(), + std::inserter(priorities, priorities.end()), [=](auto index) { + return m_core.currentProfile()->getModPriority(index); + }); if (!priorities.empty()) { m_core.modList()->changeModsPriority(indexes, *priorities.rbegin()); @@ -684,8 +713,7 @@ void ModListViewActions::renameMod(const QModelIndex& index) const { try { m_view->edit(m_view->indexModelToView(index)); - } - catch (const std::exception& e) { + } catch (const std::exception& e) { reportError(tr("failed to rename mod: %1").arg(e.what())); } } @@ -712,32 +740,33 @@ void ModListViewActions::removeMods(const QModelIndexList& indices) const if (i < max_items) { mods += "<li>" + name + "</li>"; - } - else if (i == max_items) { + } else if (i == max_items) { mods += "<li>...</li>"; } - modNames.append(ModInfo::getByIndex(idx.data(ModList::IndexRole).toInt())->name()); + modNames.append( + ModInfo::getByIndex(idx.data(ModList::IndexRole).toInt())->name()); ++i; } - if (QMessageBox::question(m_parent, tr("Confirm"), - tr("Remove the following mods?<br><ul>%1</ul>").arg(mods), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - // use mod names instead of indexes because those become invalid during the removal + if (QMessageBox::question( + m_parent, tr("Confirm"), + tr("Remove the following mods?<br><ul>%1</ul>").arg(mods), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + // use mod names instead of indexes because those become invalid during the + // removal DownloadManager::startDisableDirWatcher(); for (QString name : modNames) { m_core.modList()->removeRowForce(ModInfo::getIndex(name), QModelIndex()); } DownloadManager::endDisableDirWatcher(); } - } - else if (!indices.isEmpty()) { - m_core.modList()->removeRow(indices[0].data(ModList::IndexRole).toInt(), QModelIndex()); + } else if (!indices.isEmpty()) { + m_core.modList()->removeRow(indices[0].data(ModList::IndexRole).toInt(), + QModelIndex()); } m_view->updateModCount(); m_pluginView->updatePluginCount(); - } - catch (const std::exception& e) { + } catch (const std::exception& e) { reportError(tr("failed to remove mod: %1").arg(e.what())); } } @@ -745,36 +774,44 @@ void ModListViewActions::removeMods(const QModelIndexList& indices) const void ModListViewActions::ignoreMissingData(const QModelIndexList& indices) const { for (auto& idx : indices) { - int row_idx = idx.data(ModList::IndexRole).toInt(); + int row_idx = idx.data(ModList::IndexRole).toInt(); ModInfo::Ptr info = ModInfo::getByIndex(row_idx); info->markValidated(true); m_core.modList()->notifyChange(row_idx); } } -void ModListViewActions::setIgnoreUpdate(const QModelIndexList& indices, bool ignore) const +void ModListViewActions::setIgnoreUpdate(const QModelIndexList& indices, + bool ignore) const { for (auto& idx : indices) { - int modIdx = idx.data(ModList::IndexRole).toInt(); + int modIdx = idx.data(ModList::IndexRole).toInt(); ModInfo::Ptr info = ModInfo::getByIndex(modIdx); info->ignoreUpdate(ignore); m_core.modList()->notifyChange(modIdx); } } -void ModListViewActions::changeVersioningScheme(const QModelIndex& index) const { - if (QMessageBox::question(m_parent, tr("Continue?"), - tr("The versioning scheme decides which version is considered newer than another.\n" - "This function will guess the versioning scheme under the assumption that the installed version is outdated."), - QMessageBox::Yes | QMessageBox::Cancel) == QMessageBox::Yes) { +void ModListViewActions::changeVersioningScheme(const QModelIndex& index) const +{ + if (QMessageBox::question( + m_parent, tr("Continue?"), + tr("The versioning scheme decides which version is considered newer than " + "another.\n" + "This function will guess the versioning scheme under the assumption that " + "the installed version is outdated."), + QMessageBox::Yes | QMessageBox::Cancel) == QMessageBox::Yes) { ModInfo::Ptr info = ModInfo::getByIndex(index.data(ModList::IndexRole).toInt()); bool success = false; - static VersionInfo::VersionScheme schemes[] = { VersionInfo::SCHEME_REGULAR, VersionInfo::SCHEME_DECIMALMARK, VersionInfo::SCHEME_NUMBERSANDLETTERS }; + static VersionInfo::VersionScheme schemes[] = { + VersionInfo::SCHEME_REGULAR, VersionInfo::SCHEME_DECIMALMARK, + VersionInfo::SCHEME_NUMBERSANDLETTERS}; - for (int i = 0; i < sizeof(schemes) / sizeof(VersionInfo::VersionScheme) && !success; ++i) { + for (int i = 0; + i < sizeof(schemes) / sizeof(VersionInfo::VersionScheme) && !success; ++i) { VersionInfo verOld(info->version().canonicalString(), schemes[i]); VersionInfo verNew(info->newestVersion().canonicalString(), schemes[i]); if (verOld < verNew) { @@ -784,9 +821,12 @@ void ModListViewActions::changeVersioningScheme(const QModelIndex& index) const } } if (!success) { - QMessageBox::information(m_parent, tr("Sorry"), - tr("I don't know a versioning scheme where %1 is newer than %2.").arg(info->newestVersion().canonicalString()).arg(info->version().canonicalString()), - QMessageBox::Ok); + QMessageBox::information( + m_parent, tr("Sorry"), + tr("I don't know a versioning scheme where %1 is newer than %2.") + .arg(info->newestVersion().canonicalString()) + .arg(info->version().canonicalString()), + QMessageBox::Ok); } } } @@ -794,7 +834,7 @@ void ModListViewActions::changeVersioningScheme(const QModelIndex& index) const void ModListViewActions::markConverted(const QModelIndexList& indices) const { for (auto& idx : indices) { - int modIdx = idx.data(ModList::IndexRole).toInt(); + int modIdx = idx.data(ModList::IndexRole).toInt(); ModInfo::Ptr info = ModInfo::getByIndex(modIdx); info->markConverted(true); m_core.modList()->notifyChange(modIdx); @@ -805,20 +845,21 @@ void ModListViewActions::visitOnNexus(const QModelIndexList& indices) const { if (indices.size() > 10) { if (QMessageBox::question(m_parent, tr("Opening Nexus Links"), - tr("You are trying to open %1 links to Nexus Mods. Are you sure you want to do this?").arg(indices.size()), - QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { + tr("You are trying to open %1 links to Nexus Mods. Are " + "you sure you want to do this?") + .arg(indices.size()), + QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { return; } } for (auto& idx : indices) { ModInfo::Ptr info = ModInfo::getByIndex(idx.data(ModList::IndexRole).toInt()); - int modID = info->nexusId(); - QString gameName = info->gameName(); + int modID = info->nexusId(); + QString gameName = info->gameName(); if (modID > 0) { shell::Open(QUrl(NexusInterface::instance().getModURL(modID, gameName))); - } - else { + } else { log::error("mod '{}' has no nexus id", info->name()); } } @@ -828,8 +869,10 @@ void ModListViewActions::visitWebPage(const QModelIndexList& indices) const { if (indices.size() > 10) { if (QMessageBox::question(m_parent, tr("Opening Web Pages"), - tr("You are trying to open %1 Web Pages. Are you sure you want to do this?").arg(indices.size()), - QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { + tr("You are trying to open %1 Web Pages. Are you sure " + "you want to do this?") + .arg(indices.size()), + QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { return; } } @@ -848,8 +891,10 @@ void ModListViewActions::visitNexusOrWebPage(const QModelIndexList& indices) con { if (indices.size() > 10) { if (QMessageBox::question(m_parent, tr("Opening Web Pages"), - tr("You are trying to open %1 Web Pages. Are you sure you want to do this?").arg(indices.size()), - QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { + tr("You are trying to open %1 Web Pages. Are you sure " + "you want to do this?") + .arg(indices.size()), + QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { return; } } @@ -861,17 +906,15 @@ void ModListViewActions::visitNexusOrWebPage(const QModelIndexList& indices) con continue; } - int modID = info->nexusId(); + int modID = info->nexusId(); QString gameName = info->gameName(); - const auto url = info->parseCustomURL(); + const auto url = info->parseCustomURL(); if (modID > 0) { shell::Open(QUrl(NexusInterface::instance().getModURL(modID, gameName))); - } - else if (url.isValid()) { + } else if (url.isValid()) { shell::Open(url); - } - else { + } else { log::error("mod '{}' has no valid link", info->name()); } } @@ -887,34 +930,34 @@ void ModListViewActions::reinstallMod(const QModelIndex& index) const if (fileInfo.isAbsolute()) { if (fileInfo.exists()) { fullInstallationFile = installationFile; + } else { + fullInstallationFile = + m_core.downloadManager()->getOutputDirectory() + "/" + fileInfo.fileName(); } - else { - fullInstallationFile = m_core.downloadManager()->getOutputDirectory() + "/" + fileInfo.fileName(); - } - } - else { - fullInstallationFile = m_core.downloadManager()->getOutputDirectory() + "/" + installationFile; + } else { + fullInstallationFile = + m_core.downloadManager()->getOutputDirectory() + "/" + installationFile; } if (QFile::exists(fullInstallationFile)) { m_core.installMod(fullInstallationFile, -1, true, modInfo, modInfo->name()); + } else { + QMessageBox::information(m_parent, tr("Failed"), + tr("Installation file no longer exists")); } - else { - QMessageBox::information(m_parent, tr("Failed"), tr("Installation file no longer exists")); - } - } - else { - QMessageBox::information(m_parent, tr("Failed"), - tr("Mods installed with old versions of MO can't be reinstalled in this way.")); + } else { + QMessageBox::information( + m_parent, tr("Failed"), + tr("Mods installed with old versions of MO can't be reinstalled in this way.")); } } void ModListViewActions::createBackup(const QModelIndex& index) const { ModInfo::Ptr modInfo = ModInfo::getByIndex(index.data(ModList::IndexRole).toInt()); - QString backupDirectory = m_core.installationManager()->generateBackupName(modInfo->absolutePath()); + QString backupDirectory = + m_core.installationManager()->generateBackupName(modInfo->absolutePath()); if (!copyDir(modInfo->absolutePath(), backupDirectory, false)) { - QMessageBox::information(m_parent, tr("Failed"), - tr("Failed to create backup.")); + QMessageBox::information(m_parent, tr("Failed"), tr("Failed to create backup.")); } m_core.refresh(); m_view->updateModCount(); @@ -938,10 +981,11 @@ void ModListViewActions::restoreHiddenFiles(const QModelIndexList& indices) cons for (auto& idx : indices) { ModInfo::Ptr modInfo = ModInfo::getByIndex(idx.data(ModList::IndexRole).toInt()); - const auto flags = modInfo->getFlags(); + const auto flags = modInfo->getFlags(); if (!modInfo->isRegular() || - std::find(flags.begin(), flags.end(), ModInfo::FLAG_HIDDEN_FILES) == flags.end()) { + std::find(flags.begin(), flags.end(), ModInfo::FLAG_HIDDEN_FILES) == + flags.end()) { continue; } @@ -953,16 +997,20 @@ void ModListViewActions::restoreHiddenFiles(const QModelIndexList& indices) cons mods += "<li>...</li>"; } - if (QMessageBox::question(m_parent, tr("Confirm"), - tr("Restore all hidden files in the following mods?<br><ul>%1</ul>").arg(mods), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + if (QMessageBox::question( + m_parent, tr("Confirm"), + tr("Restore all hidden files in the following mods?<br><ul>%1</ul>") + .arg(mods), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { for (auto& idx : indices) { - ModInfo::Ptr modInfo = ModInfo::getByIndex(idx.data(ModList::IndexRole).toInt()); + ModInfo::Ptr modInfo = + ModInfo::getByIndex(idx.data(ModList::IndexRole).toInt()); const auto flags = modInfo->getFlags(); - if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_HIDDEN_FILES) != flags.end()) { + if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_HIDDEN_FILES) != + flags.end()) { const QString modDir = modInfo->absolutePath(); auto partialResult = restoreHiddenFilesRecursive(renamer, modDir); @@ -972,31 +1020,33 @@ void ModListViewActions::restoreHiddenFiles(const QModelIndexList& indices) cons break; } emit originModified((m_core.directoryStructure()->getOriginByName( - ToWString(modInfo->internalName()))).getID()); + ToWString(modInfo->internalName()))) + .getID()); } } } - } - else if (!indices.isEmpty()) { - //single selection - ModInfo::Ptr modInfo = ModInfo::getByIndex(indices[0].data(ModList::IndexRole).toInt()); + } else if (!indices.isEmpty()) { + // single selection + ModInfo::Ptr modInfo = + ModInfo::getByIndex(indices[0].data(ModList::IndexRole).toInt()); const QString modDir = modInfo->absolutePath(); - if (QMessageBox::question(m_parent, tr("Are you sure?"), - tr("About to restore all hidden files in:\n") + modInfo->name(), - QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { + if (QMessageBox::question( + m_parent, tr("Are you sure?"), + tr("About to restore all hidden files in:\n") + modInfo->name(), + QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { result = restoreHiddenFilesRecursive(renamer, modDir); emit originModified((m_core.directoryStructure()->getOriginByName( - ToWString(modInfo->internalName()))).getID()); + ToWString(modInfo->internalName()))) + .getID()); } } if (result == FileRenamer::RESULT_CANCEL) { log::debug("Restoring hidden files operation cancelled"); - } - else { + } else { log::debug("Finished restoring hidden files"); } } @@ -1010,11 +1060,13 @@ void ModListViewActions::setTracked(const QModelIndexList& indices, bool tracked }); } -void ModListViewActions::setEndorsed(const QModelIndexList& indices, bool endorsed) const +void ModListViewActions::setEndorsed(const QModelIndexList& indices, + bool endorsed) const { m_core.loggedInAction(m_parent, [=] { if (indices.size() > 1) { - MessageDialog::showMessage(tr("Endorsing multiple mods will take a while. Please wait..."), m_parent); + MessageDialog::showMessage( + tr("Endorsing multiple mods will take a while. Please wait..."), m_parent); } for (auto& idx : indices) { @@ -1030,9 +1082,10 @@ void ModListViewActions::willNotEndorsed(const QModelIndexList& indices) const } } -void ModListViewActions::setColor(const QModelIndexList& indices, const QModelIndex& refIndex) const +void ModListViewActions::setColor(const QModelIndexList& indices, + const QModelIndex& refIndex) const { - auto& settings = m_core.settings(); + auto& settings = m_core.settings(); ModInfo::Ptr modInfo = ModInfo::getByIndex(refIndex.data(ModList::IndexRole).toInt()); QColorDialog dialog(m_parent); @@ -1041,8 +1094,7 @@ void ModListViewActions::setColor(const QModelIndexList& indices, const QModelIn QColor currentColor = modInfo->color(); if (currentColor.isValid()) { dialog.setCurrentColor(currentColor); - } - else if (auto c = settings.colors().previousSeparatorColor()) { + } else if (auto c = settings.colors().previousSeparatorColor()) { dialog.setCurrentColor(*c); } @@ -1059,7 +1111,6 @@ void ModListViewActions::setColor(const QModelIndexList& indices, const QModelIn ModInfo::Ptr info = ModInfo::getByIndex(idx.data(ModList::IndexRole).toInt()); info->setColor(currentColor); } - } void ModListViewActions::resetColor(const QModelIndexList& indices) const @@ -1071,14 +1122,17 @@ void ModListViewActions::resetColor(const QModelIndexList& indices) const m_core.settings().colors().removePreviousSeparatorColor(); } -void ModListViewActions::setCategories(ModInfo::Ptr mod, const std::vector<std::pair<int, bool>>& categories) const +void ModListViewActions::setCategories( + ModInfo::Ptr mod, const std::vector<std::pair<int, bool>>& categories) const { for (auto& [id, enabled] : categories) { mod->setCategory(id, enabled); } } -void ModListViewActions::setCategoriesIf(ModInfo::Ptr mod, ModInfo::Ptr ref, const std::vector<std::pair<int, bool>>& categories) const +void ModListViewActions::setCategoriesIf( + ModInfo::Ptr mod, ModInfo::Ptr ref, + const std::vector<std::pair<int, bool>>& categories) const { for (auto& [id, enabled] : categories) { if (ref->categorySet(id) != enabled) { @@ -1087,21 +1141,20 @@ void ModListViewActions::setCategoriesIf(ModInfo::Ptr mod, ModInfo::Ptr ref, con } } -void ModListViewActions::setCategories(const QModelIndexList& selected, const QModelIndex& ref, - const std::vector<std::pair<int, bool>>& categories) const +void ModListViewActions::setCategories( + const QModelIndexList& selected, const QModelIndex& ref, + const std::vector<std::pair<int, bool>>& categories) const { ModInfo::Ptr refMod = ModInfo::getByIndex(ref.data(ModList::IndexRole).toInt()); if (selected.size() > 1) { for (auto& idx : selected) { if (idx.row() != ref.row()) { - setCategoriesIf( - ModInfo::getByIndex(idx.data(ModList::IndexRole).toInt()), - refMod, categories); + setCategoriesIf(ModInfo::getByIndex(idx.data(ModList::IndexRole).toInt()), + refMod, categories); } } setCategories(refMod, categories); - } - else if (!selected.isEmpty()) { + } else if (!selected.isEmpty()) { // for single mod selections, just do a replace setCategories(refMod, categories); } @@ -1113,11 +1166,13 @@ void ModListViewActions::setCategories(const QModelIndexList& selected, const QM // reset the selection manually - still needed auto viewIndices = m_view->indexModelToView(selected); for (auto& idx : viewIndices) { - m_view->selectionModel()->select(idx, QItemSelectionModel::Select | QItemSelectionModel::Rows); + m_view->selectionModel()->select(idx, QItemSelectionModel::Select | + QItemSelectionModel::Rows); } } -void ModListViewActions::setPrimaryCategory(const QModelIndexList& selected, int category, bool force) +void ModListViewActions::setPrimaryCategory(const QModelIndexList& selected, + int category, bool force) { for (auto& idx : selected) { ModInfo::Ptr info = ModInfo::getByIndex(idx.data(ModList::IndexRole).toInt()); @@ -1130,7 +1185,8 @@ void ModListViewActions::setPrimaryCategory(const QModelIndexList& selected, int // reset the selection manually - still needed auto viewIndices = m_view->indexModelToView(selected); for (auto& idx : viewIndices) { - m_view->selectionModel()->select(idx, QItemSelectionModel::Select | QItemSelectionModel::Rows); + m_view->selectionModel()->select(idx, QItemSelectionModel::Select | + QItemSelectionModel::Rows); } } @@ -1148,21 +1204,26 @@ void ModListViewActions::restoreBackup(const QModelIndex& index) const { QRegularExpression backupRegEx("(.*)_backup[0-9]*$"); ModInfo::Ptr modInfo = ModInfo::getByIndex(index.data(ModList::IndexRole).toInt()); - auto match = backupRegEx.match(modInfo->name()); + auto match = backupRegEx.match(modInfo->name()); if (match.hasMatch()) { QString regName = match.captured(1); QDir modDir(QDir::fromNativeSeparators(m_core.settings().paths().mods())); if (!modDir.exists(regName) || - (QMessageBox::question(m_parent, tr("Overwrite?"), - tr("This will replace the existing mod \"%1\". Continue?").arg(regName), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)) { - if (modDir.exists(regName) && !shellDelete(QStringList(modDir.absoluteFilePath(regName)))) { + (QMessageBox::question( + m_parent, tr("Overwrite?"), + tr("This will replace the existing mod \"%1\". Continue?").arg(regName), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)) { + if (modDir.exists(regName) && + !shellDelete(QStringList(modDir.absoluteFilePath(regName)))) { reportError(tr("failed to remove mod \"%1\"").arg(regName)); - } - else { - QString destinationPath = QDir::fromNativeSeparators(m_core.settings().paths().mods()) + "/" + regName; + } else { + QString destinationPath = + QDir::fromNativeSeparators(m_core.settings().paths().mods()) + "/" + + regName; if (!modDir.rename(modInfo->absolutePath(), destinationPath)) { - reportError(tr("failed to rename \"%1\" to \"%2\"").arg(modInfo->absolutePath()).arg(destinationPath)); + reportError(tr("failed to rename \"%1\" to \"%2\"") + .arg(modInfo->absolutePath()) + .arg(destinationPath)); } m_core.refresh(); m_view->updateModCount(); @@ -1174,13 +1235,13 @@ void ModListViewActions::restoreBackup(const QModelIndex& index) const void ModListViewActions::moveOverwriteContentsTo(const QString& absolutePath) const { ModInfo::Ptr overwriteInfo = ModInfo::getOverwrite(); - bool successful = shellMove((QDir::toNativeSeparators(overwriteInfo->absolutePath()) + "\\*"), - (QDir::toNativeSeparators(absolutePath)), false, m_parent); + bool successful = + shellMove((QDir::toNativeSeparators(overwriteInfo->absolutePath()) + "\\*"), + (QDir::toNativeSeparators(absolutePath)), false, m_parent); if (successful) { MessageDialog::showMessage(tr("Move successful."), m_parent); - } - else { + } else { const auto e = GetLastError(); log::error("Move operation failed: {}", formatSystemMessage(e)); } @@ -1195,10 +1256,13 @@ void ModListViewActions::createModFromOverwrite() const while (name->isEmpty()) { bool ok; - name.update(QInputDialog::getText(m_parent, tr("Create Mod..."), - tr("This will move all files from overwrite into a new, regular mod.\n" - "Please enter a name:"), QLineEdit::Normal, "", &ok), - GUESS_USER); + name.update( + QInputDialog::getText( + m_parent, tr("Create Mod..."), + tr("This will move all files from overwrite into a new, regular mod.\n" + "Please enter a name:"), + QLineEdit::Normal, "", &ok), + GUESS_USER); if (!ok) { return; } @@ -1243,7 +1307,7 @@ void ModListViewActions::moveOverwriteContentToExistingMod() const for (const auto& mod : m_core.modList()->allModsByProfilePriority()) { if (result.compare(mod) == 0) { ModInfo::Ptr modInfo = ModInfo::getByIndex(ModInfo::getIndex(mod)); - modAbsolutePath = modInfo->absolutePath(); + modAbsolutePath = modInfo->absolutePath(); break; } } @@ -1261,21 +1325,20 @@ void ModListViewActions::moveOverwriteContentToExistingMod() const void ModListViewActions::clearOverwrite() const { ModInfo::Ptr modInfo = ModInfo::getOverwrite(); - if (modInfo) - { + if (modInfo) { QDir overwriteDir(modInfo->absolutePath()); - if (QMessageBox::question(m_parent, tr("Are you sure?"), - tr("About to recursively delete:\n") + overwriteDir.absolutePath(), - QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) - { + if (QMessageBox::question( + m_parent, tr("Are you sure?"), + tr("About to recursively delete:\n") + overwriteDir.absolutePath(), + QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { QStringList delList; - for (auto f : overwriteDir.entryList(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot)) + for (auto f : + overwriteDir.entryList(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot)) delList.push_back(overwriteDir.absoluteFilePath(f)); if (shellDelete(delList, true)) { emit overwriteCleared(); m_core.refresh(); - } - else { + } else { const auto e = GetLastError(); log::error("Delete operation failed: {}", formatSystemMessage(e)); } diff --git a/src/modlistviewactions.h b/src/modlistviewactions.h index de7bdaba..5927654f 100644 --- a/src/modlistviewactions.h +++ b/src/modlistviewactions.h @@ -19,17 +19,12 @@ class ModListViewActions : public QObject Q_OBJECT public: - // currently passing the main window itself because a lots of stuff needs it but // it would be nice to avoid passing it at some point // - ModListViewActions( - OrganizerCore& core, - FilterList& filters, - CategoryFactory& categoryFactory, - ModListView* view, - PluginListView* pluginView, - QObject* nxmReceiver); + ModListViewActions(OrganizerCore& core, FilterList& filters, + CategoryFactory& categoryFactory, ModListView* view, + PluginListView* pluginView, QObject* nxmReceiver); // install mod, create an empty mod or a separator with at priority based on the // index and the current sorting of the view @@ -44,7 +39,8 @@ public: // if the archivePath is empty for installMod, ask the user for the archive // to install // - void installMod(const QString& archivePath = "", const QModelIndex& index = QModelIndex()) const; + void installMod(const QString& archivePath = "", + const QModelIndex& index = QModelIndex()) const; void createEmptyMod(const QModelIndex& index = QModelIndex()) const; void createSeparator(const QModelIndex& index = QModelIndex()) const; @@ -63,11 +59,15 @@ public: // display mod information // - void displayModInformation(const QString& modName, ModInfoTabIDs tabID = ModInfoTabIDs::None) const; - void displayModInformation(unsigned int index, ModInfoTabIDs tab = ModInfoTabIDs::None) const; - void displayModInformation(ModInfo::Ptr modInfo, unsigned int modIndex, ModInfoTabIDs tabID = ModInfoTabIDs::None) const; + void displayModInformation(const QString& modName, + ModInfoTabIDs tabID = ModInfoTabIDs::None) const; + void displayModInformation(unsigned int index, + ModInfoTabIDs tab = ModInfoTabIDs::None) const; + void displayModInformation(ModInfo::Ptr modInfo, unsigned int modIndex, + ModInfoTabIDs tabID = ModInfoTabIDs::None) const; - // move mods to top/bottom, start the "Send to priority" and "Send to separator" dialog + // move mods to top/bottom, start the "Send to priority" and "Send to separator" + // dialog // void sendModsToTop(const QModelIndexList& index) const; void sendModsToBottom(const QModelIndexList& index) const; @@ -106,13 +106,14 @@ public: // on the reference is different // void setCategories(const QModelIndexList& selected, const QModelIndex& ref, - const std::vector<std::pair<int, bool>>& categories) const; + const std::vector<std::pair<int, bool>>& categories) const; // set the primary category of the mods in the given list, adding the appropriate // category to the mods unless force is false, in which case the primary category // is set only on mods that have this category // - void setPrimaryCategory(const QModelIndexList& selected, int category, bool force = true); + void setPrimaryCategory(const QModelIndexList& selected, int category, + bool force = true); // open the Windows explorer for the specified mods // @@ -143,7 +144,6 @@ signals: void modInfoDisplayed() const; private: - // find the priority where to install or create a mod for the // given index (e.g. above, below, inside separator or at the end) // @@ -155,19 +155,20 @@ private: // set the category of the given mod based on the given array // - void setCategories(ModInfo::Ptr mod, const std::vector<std::pair<int, bool>>& categories) const; + void setCategories(ModInfo::Ptr mod, + const std::vector<std::pair<int, bool>>& categories) const; - // set the category of the given mod if the category from the reference mod does not match - // the one in the array of categories + // set the category of the given mod if the category from the reference mod does not + // match the one in the array of categories // - void setCategoriesIf(ModInfo::Ptr mod, ModInfo::Ptr ref, const std::vector<std::pair<int, bool>>& categories) const; + void setCategoriesIf(ModInfo::Ptr mod, ModInfo::Ptr ref, + const std::vector<std::pair<int, bool>>& categories) const; // check the given mods from update, the map should map game names to nexus ID // void checkModsForUpdates(std::multimap<QString, int> const& IDs) const; private: - OrganizerCore& m_core; FilterList& m_filters; CategoryFactory& m_categories; diff --git a/src/moshortcut.cpp b/src/moshortcut.cpp index 0f5ae74e..76caf0f9 100644 --- a/src/moshortcut.cpp +++ b/src/moshortcut.cpp @@ -1,22 +1,20 @@ #include "moshortcut.h" MOShortcut::MOShortcut(const QString& link) - : m_valid(link.startsWith("moshortcut://")) - , m_hasInstance(false) - , m_hasExecutable(false) + : m_valid(link.startsWith("moshortcut://")), m_hasInstance(false), + m_hasExecutable(false) { if (m_valid) { int start = (int)strlen("moshortcut://"); - int sep = link.indexOf(':', start); + int sep = link.indexOf(':', start); if (sep >= 0) { m_hasInstance = true; - m_instance = link.mid(start, sep - start); - m_executable = link.mid(sep + 1); - } - else + m_instance = link.mid(start, sep - start); + m_executable = link.mid(sep + 1); + } else m_executable = link.mid(start); - if(!(m_executable=="")) - m_hasExecutable=true; + if (!(m_executable == "")) + m_hasExecutable = true; } } diff --git a/src/moshortcut.h b/src/moshortcut.h index a6cf7fb5..2bfd1a4f 100644 --- a/src/moshortcut.h +++ b/src/moshortcut.h @@ -1,13 +1,13 @@ #ifndef MODORGANIZER_MOSHORTCUT_INCLUDED #define MODORGANIZER_MOSHORTCUT_INCLUDED -#include <QString> #include "instancemanager.h" +#include <QString> class MOShortcut { public: - MOShortcut(const QString& link={}); + MOShortcut(const QString& link = {}); // true if initialized using a valid moshortcut link // diff --git a/src/motddialog.cpp b/src/motddialog.cpp index 94a34d58..979649cb 100644 --- a/src/motddialog.cpp +++ b/src/motddialog.cpp @@ -19,16 +19,16 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "motddialog.h" #include "bbcode.h" -#include "utility.h" -#include "ui_motddialog.h" #include "organizercore.h" -#include <utility.h> +#include "ui_motddialog.h" +#include "utility.h" #include <Shlwapi.h> +#include <utility.h> using namespace MOBase; -MotDDialog::MotDDialog(const QString &message, QWidget *parent) - : QDialog(parent), ui(new Ui::MotDDialog) +MotDDialog::MotDDialog(const QString& message, QWidget* parent) + : QDialog(parent), ui(new Ui::MotDDialog) { ui->setupUi(this); ui->motdView->setHtml(BBCode::convertToHTML(message)); @@ -45,7 +45,7 @@ void MotDDialog::on_okButton_clicked() this->close(); } -void MotDDialog::linkClicked(const QUrl &url) +void MotDDialog::linkClicked(const QUrl& url) { shell::Open(url); } diff --git a/src/motddialog.h b/src/motddialog.h index 929a51e5..4e0175d3 100644 --- a/src/motddialog.h +++ b/src/motddialog.h @@ -23,24 +23,25 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QDialog> #include <QUrl> -namespace Ui { +namespace Ui +{ class MotDDialog; } class MotDDialog : public QDialog { Q_OBJECT - + public: - explicit MotDDialog(const QString &message, QWidget *parent = 0); + explicit MotDDialog(const QString& message, QWidget* parent = 0); ~MotDDialog(); - + private slots: void on_okButton_clicked(); - void linkClicked(const QUrl &url); + void linkClicked(const QUrl& url); private: - Ui::MotDDialog *ui; + Ui::MotDDialog* ui; }; -#endif // MOTDDIALOG_H +#endif // MOTDDIALOG_H diff --git a/src/multiprocess.cpp b/src/multiprocess.cpp index 7da2468d..fb7f8d4d 100644 --- a/src/multiprocess.cpp +++ b/src/multiprocess.cpp @@ -1,16 +1,16 @@ #include "multiprocess.h" #include "utility.h" -#include <report.h> -#include <log.h> #include <QLocalSocket> +#include <log.h> +#include <report.h> -static const char s_Key[] = "mo-43d1a3ad-eeb0-4818-97c9-eda5216c29b5"; +static const char s_Key[] = "mo-43d1a3ad-eeb0-4818-97c9-eda5216c29b5"; static const int s_Timeout = 5000; using MOBase::reportError; -MOMultiProcess::MOMultiProcess(bool allowMultiple, QObject *parent) : - QObject(parent), m_Ephemeral(false), m_OwnsSM(false) +MOMultiProcess::MOMultiProcess(bool allowMultiple, QObject* parent) + : QObject(parent), m_Ephemeral(false), m_OwnsSM(false) { m_SharedMem.setKey(s_Key); @@ -31,15 +31,15 @@ MOMultiProcess::MOMultiProcess(bool allowMultiple, QObject *parent) : } if (m_OwnsSM) { - connect(&m_Server, SIGNAL(newConnection()), this, SLOT(receiveMessage()), Qt::QueuedConnection); + connect(&m_Server, SIGNAL(newConnection()), this, SLOT(receiveMessage()), + Qt::QueuedConnection); // has to be called before listen m_Server.setSocketOptions(QLocalServer::WorldAccessOption); m_Server.listen(s_Key); } } - -void MOMultiProcess::sendMessage(const QString &message) +void MOMultiProcess::sendMessage(const QString& message) { if (m_OwnsSM) { // nobody there to receive the message @@ -48,7 +48,7 @@ void MOMultiProcess::sendMessage(const QString &message) QLocalSocket socket(this); bool connected = false; - for(int i = 0; i < 2 && !connected; ++i) { + for (int i = 0; i < 2 && !connected; ++i) { if (i > 0) { Sleep(250); } @@ -59,13 +59,15 @@ void MOMultiProcess::sendMessage(const QString &message) } if (!connected) { - reportError(tr("failed to connect to running process: %1").arg(socket.errorString())); + reportError( + tr("failed to connect to running process: %1").arg(socket.errorString())); return; } socket.write(message.toUtf8()); if (!socket.waitForBytesWritten(s_Timeout)) { - reportError(tr("failed to communicate with running process: %1").arg(socket.errorString())); + reportError( + tr("failed to communicate with running process: %1").arg(socket.errorString())); return; } @@ -75,7 +77,7 @@ void MOMultiProcess::sendMessage(const QString &message) void MOMultiProcess::receiveMessage() { - QLocalSocket *socket = m_Server.nextPendingConnection(); + QLocalSocket* socket = m_Server.nextPendingConnection(); if (!socket) { return; } @@ -87,11 +89,11 @@ void MOMultiProcess::receiveMessage() const auto av = socket->bytesAvailable(); if (av <= 0) { - MOBase::log::error( - "failed to receive data from secondary process: {}", - socket->errorString()); + MOBase::log::error("failed to receive data from secondary process: {}", + socket->errorString()); - reportError(tr("failed to receive data from secondary process: %1").arg(socket->errorString())); + reportError(tr("failed to receive data from secondary process: %1") + .arg(socket->errorString())); return; } } diff --git a/src/multiprocess.h b/src/multiprocess.h index 3cb5f52a..3c641faa 100644 --- a/src/multiprocess.h +++ b/src/multiprocess.h @@ -1,10 +1,9 @@ #ifndef MODORGANIZER_MOMULTIPROCESS_INCLUDED #define MODORGANIZER_MOMULTIPROCESS_INCLUDED +#include <QLocalServer> #include <QObject> #include <QSharedMemory> -#include <QLocalServer> - /** * used to ensure only a single process of Mod Organizer is started and to @@ -18,31 +17,25 @@ class MOMultiProcess : public QObject public: // `allowMultiple`: if another process is running, run this one // disconnected from the shared memory - explicit MOMultiProcess(bool allowMultiple, QObject *parent = 0); + explicit MOMultiProcess(bool allowMultiple, QObject* parent = 0); /** * @return true if this process's job is to forward data to the primary * process through shared memory **/ - bool ephemeral() const - { - return m_Ephemeral; - } + bool ephemeral() const { return m_Ephemeral; } // returns true if this is not the primary process, but was allowed because // of the AllowMultiple flag // - bool secondary() const - { - return !m_Ephemeral && !m_OwnsSM; - } + bool secondary() const { return !m_Ephemeral && !m_OwnsSM; } /** * send a message to the primary process. This can be used to transmit download urls * * @param message message to send **/ - void sendMessage(const QString &message); + void sendMessage(const QString& message); signals: @@ -51,7 +44,7 @@ signals: * * @param message the message we received **/ - void messageSent(const QString &message); + void messageSent(const QString& message); public slots: @@ -64,7 +57,6 @@ private: bool m_OwnsSM; QSharedMemory m_SharedMem; QLocalServer m_Server; - }; -#endif // MODORGANIZER_MOMULTIPROCESS_INCLUDED +#endif // MODORGANIZER_MOMULTIPROCESS_INCLUDED diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp index 069a2256..2c536b14 100644 --- a/src/nexusinterface.cpp +++ b/src/nexusinterface.cpp @@ -19,75 +19,81 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "nexusinterface.h" +#include "bbcode.h" #include "iplugingame.h" #include "nxmaccessmanager.h" #include "selectiondialog.h" -#include "bbcode.h" #include "settings.h" -#include <utility.h> #include "shared/util.h" #include <log.h> #include <moassert.h> +#include <utility.h> #include <QApplication> -#include <QNetworkCookieJar> #include <QJsonDocument> +#include <QNetworkCookieJar> #include <QRegularExpression> #include <regex> - using namespace MOBase; using namespace MOShared; - void throttledWarning(const APIUserAccount& user) { - log::error( - "You have fewer than {} requests remaining ({}). Only downloads and " - "login validation are being allowed.", - APIUserAccount::ThrottleThreshold, - user.remainingRequests()); + log::error("You have fewer than {} requests remaining ({}). Only downloads and " + "login validation are being allowed.", + APIUserAccount::ThrottleThreshold, user.remainingRequests()); } - -NexusBridge::NexusBridge(PluginContainer *pluginContainer, const QString &subModule) - : m_Interface(&NexusInterface::instance()) - , m_SubModule(subModule) -{ -} +NexusBridge::NexusBridge(PluginContainer* pluginContainer, const QString& subModule) + : m_Interface(&NexusInterface::instance()), m_SubModule(subModule) +{} void NexusBridge::requestDescription(QString gameName, int modID, QVariant userData) { - m_RequestIDs.insert(m_Interface->requestDescription(gameName, modID, this, userData, m_SubModule)); + m_RequestIDs.insert( + m_Interface->requestDescription(gameName, modID, this, userData, m_SubModule)); } void NexusBridge::requestFiles(QString gameName, int modID, QVariant userData) { - m_RequestIDs.insert(m_Interface->requestFiles(gameName, modID, this, userData, m_SubModule)); + m_RequestIDs.insert( + m_Interface->requestFiles(gameName, modID, this, userData, m_SubModule)); } -void NexusBridge::requestFileInfo(QString gameName, int modID, int fileID, QVariant userData) +void NexusBridge::requestFileInfo(QString gameName, int modID, int fileID, + QVariant userData) { - m_RequestIDs.insert(m_Interface->requestFileInfo(gameName, modID, fileID, this, userData, m_SubModule)); + m_RequestIDs.insert(m_Interface->requestFileInfo(gameName, modID, fileID, this, + userData, m_SubModule)); } -void NexusBridge::requestDownloadURL(QString gameName, int modID, int fileID, QVariant userData) +void NexusBridge::requestDownloadURL(QString gameName, int modID, int fileID, + QVariant userData) { - m_RequestIDs.insert(m_Interface->requestDownloadURL(gameName, modID, fileID, this, userData, m_SubModule)); + m_RequestIDs.insert(m_Interface->requestDownloadURL(gameName, modID, fileID, this, + userData, m_SubModule)); } -void NexusBridge::requestToggleEndorsement(QString gameName, int modID, QString modVersion, bool endorse, QVariant userData) +void NexusBridge::requestToggleEndorsement(QString gameName, int modID, + QString modVersion, bool endorse, + QVariant userData) { - m_RequestIDs.insert(m_Interface->requestToggleEndorsement(gameName, modID, modVersion, endorse, this, userData, m_SubModule)); + m_RequestIDs.insert(m_Interface->requestToggleEndorsement( + gameName, modID, modVersion, endorse, this, userData, m_SubModule)); } -void NexusBridge::requestToggleTracking(QString gameName, int modID, bool track, QVariant userData) +void NexusBridge::requestToggleTracking(QString gameName, int modID, bool track, + QVariant userData) { - m_RequestIDs.insert(m_Interface->requestToggleTracking(gameName, modID, track, this, userData, m_SubModule)); + m_RequestIDs.insert(m_Interface->requestToggleTracking(gameName, modID, track, this, + userData, m_SubModule)); } -void NexusBridge::nxmDescriptionAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID) +void NexusBridge::nxmDescriptionAvailable(QString gameName, int modID, + QVariant userData, QVariant resultData, + int requestID) { std::set<int>::iterator iter = m_RequestIDs.find(requestID); if (iter != m_RequestIDs.end()) { @@ -97,7 +103,8 @@ void NexusBridge::nxmDescriptionAvailable(QString gameName, int modID, QVariant } } -void NexusBridge::nxmFilesAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID) +void NexusBridge::nxmFilesAvailable(QString gameName, int modID, QVariant userData, + QVariant resultData, int requestID) { std::set<int>::iterator iter = m_RequestIDs.find(requestID); if (iter != m_RequestIDs.end()) { @@ -106,18 +113,18 @@ void NexusBridge::nxmFilesAvailable(QString gameName, int modID, QVariant userDa QList<ModRepositoryFileInfo*> fileInfoList; QVariantMap resultInfo = resultData.toMap(); - QList resultList = resultInfo["files"].toList(); + QList resultList = resultInfo["files"].toList(); - for (const QVariant &file : resultList) { + for (const QVariant& file : resultList) { ModRepositoryFileInfo temp; QVariantMap fileInfo = file.toMap(); - temp.uri = fileInfo["file_name"].toString(); - temp.name = fileInfo["name"].toString(); - temp.description = BBCode::convertToHTML(fileInfo["description"].toString()); - temp.version = VersionInfo(fileInfo["version"].toString()); - temp.categoryID = fileInfo["category_id"].toInt(); - temp.fileID = fileInfo["file_id"].toInt(); - temp.fileSize = fileInfo["size"].toInt(); + temp.uri = fileInfo["file_name"].toString(); + temp.name = fileInfo["name"].toString(); + temp.description = BBCode::convertToHTML(fileInfo["description"].toString()); + temp.version = VersionInfo(fileInfo["version"].toString()); + temp.categoryID = fileInfo["category_id"].toInt(); + temp.fileID = fileInfo["file_id"].toInt(); + temp.fileSize = fileInfo["size"].toInt(); fileInfoList.append(&temp); } @@ -125,7 +132,9 @@ void NexusBridge::nxmFilesAvailable(QString gameName, int modID, QVariant userDa } } -void NexusBridge::nxmFileInfoAvailable(QString gameName, int modID, int fileID, QVariant userData, QVariant resultData, int requestID) +void NexusBridge::nxmFileInfoAvailable(QString gameName, int modID, int fileID, + QVariant userData, QVariant resultData, + int requestID) { std::set<int>::iterator iter = m_RequestIDs.find(requestID); if (iter != m_RequestIDs.end()) { @@ -134,7 +143,9 @@ void NexusBridge::nxmFileInfoAvailable(QString gameName, int modID, int fileID, } } -void NexusBridge::nxmDownloadURLsAvailable(QString gameName, int modID, int fileID, QVariant userData, QVariant resultData, int requestID) +void NexusBridge::nxmDownloadURLsAvailable(QString gameName, int modID, int fileID, + QVariant userData, QVariant resultData, + int requestID) { std::set<int>::iterator iter = m_RequestIDs.find(requestID); if (iter != m_RequestIDs.end()) { @@ -143,7 +154,8 @@ void NexusBridge::nxmDownloadURLsAvailable(QString gameName, int modID, int file } } -void NexusBridge::nxmEndorsementsAvailable(QVariant userData, QVariant resultData, int requestID) +void NexusBridge::nxmEndorsementsAvailable(QVariant userData, QVariant resultData, + int requestID) { std::set<int>::iterator iter = m_RequestIDs.find(requestID); if (iter != m_RequestIDs.end()) { @@ -152,7 +164,8 @@ void NexusBridge::nxmEndorsementsAvailable(QVariant userData, QVariant resultDat } } -void NexusBridge::nxmEndorsementToggled(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID) +void NexusBridge::nxmEndorsementToggled(QString gameName, int modID, QVariant userData, + QVariant resultData, int requestID) { std::set<int>::iterator iter = m_RequestIDs.find(requestID); if (iter != m_RequestIDs.end()) { @@ -161,7 +174,8 @@ void NexusBridge::nxmEndorsementToggled(QString gameName, int modID, QVariant us } } -void NexusBridge::nxmTrackedModsAvailable(QVariant userData, QVariant resultData, int requestID) +void NexusBridge::nxmTrackedModsAvailable(QVariant userData, QVariant resultData, + int requestID) { std::set<int>::iterator iter = m_RequestIDs.find(requestID); if (iter != m_RequestIDs.end()) { @@ -170,7 +184,8 @@ void NexusBridge::nxmTrackedModsAvailable(QVariant userData, QVariant resultData } } -void NexusBridge::nxmTrackingToggled(QString gameName, int modID, QVariant userData, bool tracked, int requestID) +void NexusBridge::nxmTrackingToggled(QString gameName, int modID, QVariant userData, + bool tracked, int requestID) { std::set<int>::iterator iter = m_RequestIDs.find(requestID); if (iter != m_RequestIDs.end()) { @@ -179,7 +194,9 @@ void NexusBridge::nxmTrackingToggled(QString gameName, int modID, QVariant userD } } -void NexusBridge::nxmRequestFailed(QString gameName, int modID, int fileID, QVariant userData, int requestID, int errorCode, const QString &errorMessage) +void NexusBridge::nxmRequestFailed(QString gameName, int modID, int fileID, + QVariant userData, int requestID, int errorCode, + const QString& errorMessage) { std::set<int>::iterator iter = m_RequestIDs.find(requestID); if (iter != m_RequestIDs.end()) { @@ -188,21 +205,19 @@ void NexusBridge::nxmRequestFailed(QString gameName, int modID, int fileID, QVar } } - QAtomicInt NexusInterface::NXMRequestInfo::s_NextID(0); - APILimits NexusInterface::defaultAPILimits() { // https://app.swaggerhub.com/apis-docs/NexusMods/nexus-mods_public_api_params_in_form_data/1.0#/ - const int MaxDaily = 2500; + const int MaxDaily = 2500; const int MaxHourly = 100; APILimits limits; - limits.maxDailyRequests = MaxDaily; - limits.remainingDailyRequests = MaxDaily; - limits.maxHourlyRequests = MaxHourly; + limits.maxDailyRequests = MaxDaily; + limits.remainingDailyRequests = MaxDaily; + limits.maxHourlyRequests = MaxHourly; limits.remainingHourlyRequests = MaxHourly; return limits; @@ -213,8 +228,8 @@ APILimits NexusInterface::parseLimits(const QNetworkReply* reply) return parseLimits(reply->rawHeaderPairs()); } -APILimits NexusInterface::parseLimits( - const QList<QNetworkReply::RawHeaderPair>& headers) +APILimits +NexusInterface::parseLimits(const QList<QNetworkReply::RawHeaderPair>& headers) { APILimits limits; @@ -235,11 +250,9 @@ APILimits NexusInterface::parseLimits( return limits; } - static NexusInterface* g_instance = nullptr; -NexusInterface::NexusInterface(Settings* s) - : m_PluginContainer(nullptr) +NexusInterface::NexusInterface(Settings* s) : m_PluginContainer(nullptr) { MO_ASSERT(!g_instance); g_instance = this; @@ -247,12 +260,12 @@ NexusInterface::NexusInterface(Settings* s) m_User.limits(defaultAPILimits()); m_MOVersion = createVersionInfo(); - m_AccessManager = new NXMAccessManager( - this, s, m_MOVersion.displayString(3)); + m_AccessManager = new NXMAccessManager(this, s, m_MOVersion.displayString(3)); m_DiskCache = new QNetworkDiskCache(this); - connect(m_AccessManager, SIGNAL(requestNXMDownload(QString)), this, SLOT(downloadRequestedNXM(QString))); + connect(m_AccessManager, SIGNAL(requestNXMDownload(QString)), this, + SLOT(downloadRequestedNXM(QString))); } NexusInterface::~NexusInterface() @@ -263,7 +276,7 @@ NexusInterface::~NexusInterface() g_instance = nullptr; } -NXMAccessManager *NexusInterface::getAccessManager() +NXMAccessManager* NexusInterface::getAccessManager() { return m_AccessManager; } @@ -274,7 +287,7 @@ NexusInterface& NexusInterface::instance() return *g_instance; } -void NexusInterface::setCacheDirectory(const QString &directory) +void NexusInterface::setCacheDirectory(const QString& directory) { m_DiskCache->setCacheDirectory(directory); m_AccessManager->setCache(m_DiskCache); @@ -291,20 +304,22 @@ void NexusInterface::setUserAccount(const APIUserAccount& user) emit requestsChanged(getAPIStats(), m_User); } -void NexusInterface::interpretNexusFileName(const QString &fileName, QString &modName, int &modID, bool query) +void NexusInterface::interpretNexusFileName(const QString& fileName, QString& modName, + int& modID, bool query) { // guess the mod name from the file name - static const QRegularExpression complex(R"(^([a-zA-Z0-9_'"\-.() ]*?)([-_ ][VvRr]+[0-9]+(?:(?:[\.][0-9]+){0,2}|(?:[_][0-9]+){0,2}|(?:[-.][0-9]+){0,2})?[ab]?)??-([1-9][0-9]+)?-.*?\.(zip|rar|7z))"); - //complex regex explanation: - //group 1: modname. - //group 2: optional version, + static const QRegularExpression complex( + R"(^([a-zA-Z0-9_'"\-.() ]*?)([-_ ][VvRr]+[0-9]+(?:(?:[\.][0-9]+){0,2}|(?:[_][0-9]+){0,2}|(?:[-.][0-9]+){0,2})?[ab]?)??-([1-9][0-9]+)?-.*?\.(zip|rar|7z))"); + // complex regex explanation: + // group 1: modname. + // group 2: optional version, // assumed to start with v (empty most of the time). - //group 3: NexusId, + // group 3: NexusId, // assumed wrapped in "-", will miss single digit IDs for better accuracy. - //If no id is present the whole regex does not match. + // If no id is present the whole regex does not match. static const QRegularExpression simple(R"(^[^a-zA-Z]*([a-zA-Z_ ]+))"); auto complexMatch = complex.match(fileName); - auto simpleMatch = simple.match(fileName); + auto simpleMatch = simple.match(fileName); // assume not found modID = -1; @@ -314,20 +329,18 @@ void NexusInterface::interpretNexusFileName(const QString &fileName, QString &mo if (!query && !complexMatch.captured(3).isNull()) { modID = complexMatch.captured(3).toInt(); } - } - else if (simpleMatch.hasMatch()) { + } else if (simpleMatch.hasMatch()) { modName = simpleMatch.captured(0); - } - else { + } else { modName.clear(); } if (query) { SelectionDialog selection(tr("Please pick the mod ID for \"%1\"").arg(fileName)); - int index = 0; + int index = 0; auto splits = fileName.split(QRegularExpression("[^0-9]"), Qt::KeepEmptyParts); for (auto substr : splits) { - bool ok = false; + bool ok = false; int value = substr.toInt(&ok); if (ok) { QString highlight(fileName); @@ -345,22 +358,20 @@ void NexusInterface::interpretNexusFileName(const QString &fileName, QString &mo if (selection.numChoices() > 0) { if (selection.exec() == QDialog::Accepted) { auto choice = selection.getChoiceData().toStringList(); - modID = choice.at(0).toInt(); - modName = choice.at(1); - modName = modName.replace('_', ' ').trimmed(); + modID = choice.at(0).toInt(); + modName = choice.at(1); + modName = modName.replace('_', ' ').trimmed(); log::debug("user selected mod ID {} and mod name \"{}\"", modID, modName); - } - else { + } else { log::debug("user canceled mod ID selection"); } - } - else { + } else { log::debug("no possible mod IDs found in file name"); } } } -bool NexusInterface::isURLGameRelated(const QUrl &url) const +bool NexusInterface::isURLGameRelated(const QUrl& url) const { QString const name(url.toString()); return name.startsWith(getGameURL("") + "/") || @@ -369,13 +380,12 @@ bool NexusInterface::isURLGameRelated(const QUrl &url) const QString NexusInterface::getGameURL(QString gameName) const { - IPluginGame *game = getGame(gameName); + IPluginGame* game = getGame(gameName); if (game != nullptr) { QString gameNexusName = game->gameNexusName().toLower(); if (gameNexusName.isEmpty()) { return ""; - } - else { + } else { return "https://www.nexusmods.com/" + gameNexusName; } } else { @@ -386,7 +396,7 @@ QString NexusInterface::getGameURL(QString gameName) const QString NexusInterface::getOldModsURL(QString gameName) const { - IPluginGame *game = getGame(gameName); + IPluginGame* game = getGame(gameName); if (game != nullptr) { return "https://" + game->gameNexusName().toLower() + ".nexusmods.com/mods"; } else { @@ -395,20 +405,22 @@ QString NexusInterface::getOldModsURL(QString gameName) const } } - QString NexusInterface::getModURL(int modID, QString gameName = "") const { return QString("%1/mods/%2").arg(getGameURL(gameName)).arg(modID); } -std::vector<std::pair<QString, QString>> NexusInterface::getGameChoices(const MOBase::IPluginGame *game) +std::vector<std::pair<QString, QString>> +NexusInterface::getGameChoices(const MOBase::IPluginGame* game) { std::vector<std::pair<QString, QString>> choices; - choices.push_back(std::pair<QString, QString>(game->gameShortName(), game->gameName())); + choices.push_back( + std::pair<QString, QString>(game->gameShortName(), game->gameName())); for (QString gameName : game->validShortNames()) { for (auto gamePlugin : m_PluginContainer->plugins<IPluginGame>()) { if (gamePlugin->gameShortName().compare(gameName, Qt::CaseInsensitive) == 0) { - choices.push_back(std::pair<QString, QString>(gamePlugin->gameShortName(), gamePlugin->gameName())); + choices.push_back(std::pair<QString, QString>(gamePlugin->gameShortName(), + gamePlugin->gameName())); break; } } @@ -416,268 +428,334 @@ std::vector<std::pair<QString, QString>> NexusInterface::getGameChoices(const MO return choices; } -bool NexusInterface::isModURL(int modID, const QString &url) const +bool NexusInterface::isModURL(int modID, const QString& url) const { if (QUrl(url) == QUrl(getModURL(modID))) { return true; } - //Try the alternate (old style) mod name + // Try the alternate (old style) mod name QString alt = QString("%1/%2").arg(getOldModsURL("")).arg(modID); return QUrl(alt) == QUrl(url); } -void NexusInterface::setPluginContainer(PluginContainer *pluginContainer) +void NexusInterface::setPluginContainer(PluginContainer* pluginContainer) { m_PluginContainer = pluginContainer; } -int NexusInterface::requestDescription(QString gameName, int modID, QObject *receiver, QVariant userData, - const QString &subModule, MOBase::IPluginGame const *game) +int NexusInterface::requestDescription(QString gameName, int modID, QObject* receiver, + QVariant userData, const QString& subModule, + MOBase::IPluginGame const* game) { - NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_DESCRIPTION, userData, subModule, game); + NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_DESCRIPTION, userData, + subModule, game); m_RequestQueue.enqueue(requestInfo); connect(this, SIGNAL(nxmDescriptionAvailable(QString, int, QVariant, QVariant, int)), - receiver, SLOT(nxmDescriptionAvailable(QString, int, QVariant, QVariant, int)), Qt::UniqueConnection); + receiver, + SLOT(nxmDescriptionAvailable(QString, int, QVariant, QVariant, int)), + Qt::UniqueConnection); - connect(this, SIGNAL(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), - receiver, SLOT(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), Qt::UniqueConnection); + connect( + this, SIGNAL(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), + receiver, SLOT(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), + Qt::UniqueConnection); nextRequest(); return requestInfo.m_ID; } -int NexusInterface::requestModInfo(QString gameName, int modID, QObject *receiver, QVariant userData, - const QString &subModule, MOBase::IPluginGame const *game) +int NexusInterface::requestModInfo(QString gameName, int modID, QObject* receiver, + QVariant userData, const QString& subModule, + MOBase::IPluginGame const* game) { if (m_User.shouldThrottle()) { throttledWarning(m_User); return -1; } - NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_MODINFO, userData, subModule, game); + NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_MODINFO, userData, subModule, + game); m_RequestQueue.enqueue(requestInfo); connect(this, SIGNAL(nxmModInfoAvailable(QString, int, QVariant, QVariant, int)), - receiver, SLOT(nxmModInfoAvailable(QString, int, QVariant, QVariant, int)), Qt::UniqueConnection); + receiver, SLOT(nxmModInfoAvailable(QString, int, QVariant, QVariant, int)), + Qt::UniqueConnection); - connect(this, SIGNAL(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), - receiver, SLOT(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), Qt::UniqueConnection); + connect( + this, SIGNAL(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), + receiver, SLOT(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), + Qt::UniqueConnection); nextRequest(); return requestInfo.m_ID; } -int NexusInterface::requestUpdateInfo(QString gameName, NexusInterface::UpdatePeriod period, QObject *receiver, QVariant userData, - const QString &subModule, const MOBase::IPluginGame *game) +int NexusInterface::requestUpdateInfo(QString gameName, + NexusInterface::UpdatePeriod period, + QObject* receiver, QVariant userData, + const QString& subModule, + const MOBase::IPluginGame* game) { if (m_User.shouldThrottle()) { throttledWarning(m_User); return -1; } - NXMRequestInfo requestInfo(period, NXMRequestInfo::TYPE_CHECKUPDATES, userData, subModule, game); + NXMRequestInfo requestInfo(period, NXMRequestInfo::TYPE_CHECKUPDATES, userData, + subModule, game); m_RequestQueue.enqueue(requestInfo); connect(this, SIGNAL(nxmUpdateInfoAvailable(QString, QVariant, QVariant, int)), - receiver, SLOT(nxmUpdateInfoAvailable(QString, QVariant, QVariant, int)), Qt::UniqueConnection); + receiver, SLOT(nxmUpdateInfoAvailable(QString, QVariant, QVariant, int)), + Qt::UniqueConnection); - connect(this, SIGNAL(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), - receiver, SLOT(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), Qt::UniqueConnection); + connect( + this, SIGNAL(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), + receiver, SLOT(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), + Qt::UniqueConnection); nextRequest(); return requestInfo.m_ID; } -int NexusInterface::requestUpdates(const int &modID, QObject *receiver, QVariant userData, - QString gameName, const QString &subModule) +int NexusInterface::requestUpdates(const int& modID, QObject* receiver, + QVariant userData, QString gameName, + const QString& subModule) { if (m_User.shouldThrottle()) { throttledWarning(m_User); return -1; } - IPluginGame *game = getGame(gameName); + IPluginGame* game = getGame(gameName); if (game == nullptr) { log::error("requestUpdates can't find plugin for {}", gameName); return -1; } - NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_GETUPDATES, userData, subModule, game); + NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_GETUPDATES, userData, + subModule, game); m_RequestQueue.enqueue(requestInfo); connect(this, SIGNAL(nxmUpdatesAvailable(QString, int, QVariant, QVariant, int)), - receiver, SLOT(nxmUpdatesAvailable(QString, int, QVariant, QVariant, int)), Qt::UniqueConnection); + receiver, SLOT(nxmUpdatesAvailable(QString, int, QVariant, QVariant, int)), + Qt::UniqueConnection); - connect(this, SIGNAL(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), - receiver, SLOT(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), Qt::UniqueConnection); + connect( + this, SIGNAL(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), + receiver, SLOT(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), + Qt::UniqueConnection); nextRequest(); return requestInfo.m_ID; } - void NexusInterface::fakeFiles() { static int id = 42; QVariantList result; QVariantMap fileMap; - fileMap["uri"] = "fakeURI"; - fileMap["name"] = "fakeName"; + fileMap["uri"] = "fakeURI"; + fileMap["name"] = "fakeName"; fileMap["description"] = "fakeDescription"; - fileMap["version"] = "1.0.0"; + fileMap["version"] = "1.0.0"; fileMap["category_id"] = "1"; - fileMap["id"] = "1"; - fileMap["size"] = "512"; + fileMap["id"] = "1"; + fileMap["size"] = "512"; result.append(fileMap); emit nxmFilesAvailable("fakeGame", 1234, "fake", result, id++); } - -int NexusInterface::requestFiles(QString gameName, int modID, QObject *receiver, QVariant userData, - const QString &subModule, MOBase::IPluginGame const *game) +int NexusInterface::requestFiles(QString gameName, int modID, QObject* receiver, + QVariant userData, const QString& subModule, + MOBase::IPluginGame const* game) { - NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_FILES, userData, subModule, game); + NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_FILES, userData, subModule, + game); m_RequestQueue.enqueue(requestInfo); connect(this, SIGNAL(nxmFilesAvailable(QString, int, QVariant, QVariant, int)), - receiver, SLOT(nxmFilesAvailable(QString, int, QVariant, QVariant, int)), Qt::UniqueConnection); + receiver, SLOT(nxmFilesAvailable(QString, int, QVariant, QVariant, int)), + Qt::UniqueConnection); - connect(this, SIGNAL(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), - receiver, SLOT(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), Qt::UniqueConnection); + connect( + this, SIGNAL(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), + receiver, SLOT(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), + Qt::UniqueConnection); nextRequest(); return requestInfo.m_ID; } - -int NexusInterface::requestFileInfo(QString gameName, int modID, int fileID, QObject *receiver, QVariant userData, const QString &subModule) +int NexusInterface::requestFileInfo(QString gameName, int modID, int fileID, + QObject* receiver, QVariant userData, + const QString& subModule) { - IPluginGame *gamePlugin = getGame(gameName); + IPluginGame* gamePlugin = getGame(gameName); if (gamePlugin == nullptr) { log::error("requestFileInfo can't find plugin for {}", gameName); return -1; } - NXMRequestInfo requestInfo(modID, fileID, NXMRequestInfo::TYPE_FILEINFO, userData, subModule, gamePlugin); + NXMRequestInfo requestInfo(modID, fileID, NXMRequestInfo::TYPE_FILEINFO, userData, + subModule, gamePlugin); m_RequestQueue.enqueue(requestInfo); - connect(this, SIGNAL(nxmFileInfoAvailable(QString, int, int, QVariant, QVariant, int)), - receiver, SLOT(nxmFileInfoAvailable(QString, int, int, QVariant, QVariant, int)), Qt::UniqueConnection); + connect( + this, SIGNAL(nxmFileInfoAvailable(QString, int, int, QVariant, QVariant, int)), + receiver, SLOT(nxmFileInfoAvailable(QString, int, int, QVariant, QVariant, int)), + Qt::UniqueConnection); - connect(this, SIGNAL(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), - receiver, SLOT(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), Qt::UniqueConnection); + connect( + this, SIGNAL(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), + receiver, SLOT(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), + Qt::UniqueConnection); nextRequest(); return requestInfo.m_ID; } - -int NexusInterface::requestDownloadURL(QString gameName, int modID, int fileID, QObject *receiver, QVariant userData, - const QString &subModule, MOBase::IPluginGame const *game) +int NexusInterface::requestDownloadURL(QString gameName, int modID, int fileID, + QObject* receiver, QVariant userData, + const QString& subModule, + MOBase::IPluginGame const* game) { - NXMRequestInfo requestInfo(modID, fileID, NXMRequestInfo::TYPE_DOWNLOADURL, userData, subModule, game); + NXMRequestInfo requestInfo(modID, fileID, NXMRequestInfo::TYPE_DOWNLOADURL, userData, + subModule, game); m_RequestQueue.enqueue(requestInfo); - connect(this, SIGNAL(nxmDownloadURLsAvailable(QString,int,int,QVariant,QVariant,int)), - receiver, SLOT(nxmDownloadURLsAvailable(QString,int,int,QVariant,QVariant,int)), Qt::UniqueConnection); + connect(this, + SIGNAL(nxmDownloadURLsAvailable(QString, int, int, QVariant, QVariant, int)), + receiver, + SLOT(nxmDownloadURLsAvailable(QString, int, int, QVariant, QVariant, int)), + Qt::UniqueConnection); - connect(this, SIGNAL(nxmRequestFailed(QString,int,int,QVariant,int,int,QString)), - receiver, SLOT(nxmRequestFailed(QString,int,int,QVariant,int,int,QString)), Qt::UniqueConnection); + connect( + this, SIGNAL(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), + receiver, SLOT(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), + Qt::UniqueConnection); nextRequest(); return requestInfo.m_ID; } -int NexusInterface::requestEndorsementInfo(QObject *receiver, QVariant userData, const QString &subModule) +int NexusInterface::requestEndorsementInfo(QObject* receiver, QVariant userData, + const QString& subModule) { NXMRequestInfo requestInfo(NXMRequestInfo::TYPE_ENDORSEMENTS, userData, subModule); m_RequestQueue.enqueue(requestInfo); - connect(this, SIGNAL(nxmEndorsementsAvailable(QVariant, QVariant, int)), - receiver, SLOT(nxmEndorsementsAvailable(QVariant, QVariant, int)), Qt::UniqueConnection); + connect(this, SIGNAL(nxmEndorsementsAvailable(QVariant, QVariant, int)), receiver, + SLOT(nxmEndorsementsAvailable(QVariant, QVariant, int)), + Qt::UniqueConnection); - connect(this, SIGNAL(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), - receiver, SLOT(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), Qt::UniqueConnection); + connect( + this, SIGNAL(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), + receiver, SLOT(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), + Qt::UniqueConnection); nextRequest(); return requestInfo.m_ID; } -int NexusInterface::requestToggleEndorsement(QString gameName, int modID, QString modVersion, bool endorse, QObject *receiver, QVariant userData, - const QString &subModule, MOBase::IPluginGame const *game) +int NexusInterface::requestToggleEndorsement(QString gameName, int modID, + QString modVersion, bool endorse, + QObject* receiver, QVariant userData, + const QString& subModule, + MOBase::IPluginGame const* game) { if (m_User.shouldThrottle()) { throttledWarning(m_User); return -1; } - NXMRequestInfo requestInfo(modID, modVersion, NXMRequestInfo::TYPE_TOGGLEENDORSEMENT, userData, subModule, game); + NXMRequestInfo requestInfo(modID, modVersion, NXMRequestInfo::TYPE_TOGGLEENDORSEMENT, + userData, subModule, game); requestInfo.m_Endorse = endorse; m_RequestQueue.enqueue(requestInfo); connect(this, SIGNAL(nxmEndorsementToggled(QString, int, QVariant, QVariant, int)), - receiver, SLOT(nxmEndorsementToggled(QString, int, QVariant, QVariant, int)), Qt::UniqueConnection); + receiver, SLOT(nxmEndorsementToggled(QString, int, QVariant, QVariant, int)), + Qt::UniqueConnection); - connect(this, SIGNAL(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), - receiver, SLOT(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), Qt::UniqueConnection); + connect( + this, SIGNAL(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), + receiver, SLOT(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), + Qt::UniqueConnection); nextRequest(); return requestInfo.m_ID; } -int NexusInterface::requestTrackingInfo(QObject *receiver, QVariant userData, const QString &subModule) +int NexusInterface::requestTrackingInfo(QObject* receiver, QVariant userData, + const QString& subModule) { NXMRequestInfo requestInfo(NXMRequestInfo::TYPE_TRACKEDMODS, userData, subModule); m_RequestQueue.enqueue(requestInfo); - connect(this, SIGNAL(nxmTrackedModsAvailable(QVariant, QVariant, int)), - receiver, SLOT(nxmTrackedModsAvailable(QVariant, QVariant, int)), Qt::UniqueConnection); + connect(this, SIGNAL(nxmTrackedModsAvailable(QVariant, QVariant, int)), receiver, + SLOT(nxmTrackedModsAvailable(QVariant, QVariant, int)), Qt::UniqueConnection); - connect(this, SIGNAL(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), - receiver, SLOT(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), Qt::UniqueConnection); + connect( + this, SIGNAL(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), + receiver, SLOT(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), + Qt::UniqueConnection); nextRequest(); return requestInfo.m_ID; } -int NexusInterface::requestToggleTracking(QString gameName, int modID, bool track, QObject *receiver, QVariant userData, - const QString &subModule, MOBase::IPluginGame const *game) +int NexusInterface::requestToggleTracking(QString gameName, int modID, bool track, + QObject* receiver, QVariant userData, + const QString& subModule, + MOBase::IPluginGame const* game) { if (m_User.shouldThrottle()) { throttledWarning(m_User); return -1; } - NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_TOGGLETRACKING, userData, subModule, game); + NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_TOGGLETRACKING, userData, + subModule, game); requestInfo.m_Track = track; m_RequestQueue.enqueue(requestInfo); - connect(this, SIGNAL(nxmTrackingToggled(QString, int, QVariant, bool, int)), - receiver, SLOT(nxmTrackingToggled(QString, int, QVariant, bool, int)), Qt::UniqueConnection); + connect(this, SIGNAL(nxmTrackingToggled(QString, int, QVariant, bool, int)), receiver, + SLOT(nxmTrackingToggled(QString, int, QVariant, bool, int)), + Qt::UniqueConnection); - connect(this, SIGNAL(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), - receiver, SLOT(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), Qt::UniqueConnection); + connect( + this, SIGNAL(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), + receiver, SLOT(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), + Qt::UniqueConnection); nextRequest(); return requestInfo.m_ID; } -int NexusInterface::requestInfoFromMd5(QString gameName, QByteArray &hash, QObject *receiver, QVariant userData, - const QString &subModule, MOBase::IPluginGame const *game) +int NexusInterface::requestInfoFromMd5(QString gameName, QByteArray& hash, + QObject* receiver, QVariant userData, + const QString& subModule, + MOBase::IPluginGame const* game) { - NXMRequestInfo requestInfo(hash, NXMRequestInfo::TYPE_FILEINFO_MD5, userData, subModule, game); + NXMRequestInfo requestInfo(hash, NXMRequestInfo::TYPE_FILEINFO_MD5, userData, + subModule, game); requestInfo.m_Hash = hash; - requestInfo.m_AllowedErrors[QNetworkReply::NetworkError::ContentNotFoundError].append(404); + requestInfo.m_AllowedErrors[QNetworkReply::NetworkError::ContentNotFoundError].append( + 404); requestInfo.m_IgnoreGenericErrorHandler = true; m_RequestQueue.enqueue(requestInfo); connect(this, SIGNAL(nxmFileInfoFromMd5Available(QString, QVariant, QVariant, int)), - receiver, SLOT(nxmFileInfoFromMd5Available(QString, QVariant, QVariant, int)), Qt::UniqueConnection); + receiver, SLOT(nxmFileInfoFromMd5Available(QString, QVariant, QVariant, int)), + Qt::UniqueConnection); - connect(this, SIGNAL(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), - receiver, SLOT(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), Qt::UniqueConnection); + connect( + this, SIGNAL(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), + receiver, SLOT(nxmRequestFailed(QString, int, int, QVariant, int, int, QString)), + Qt::UniqueConnection); nextRequest(); return requestInfo.m_ID; @@ -685,10 +763,11 @@ int NexusInterface::requestInfoFromMd5(QString gameName, QByteArray &hash, QObje IPluginGame* NexusInterface::getGame(QString gameName) const { - auto gamePlugins = m_PluginContainer->plugins<IPluginGame>(); - IPluginGame *gamePlugin = qApp->property("managed_game").value<IPluginGame*>(); + auto gamePlugins = m_PluginContainer->plugins<IPluginGame>(); + IPluginGame* gamePlugin = qApp->property("managed_game").value<IPluginGame*>(); for (auto plugin : gamePlugins) { - if (plugin != nullptr && plugin->gameShortName().compare(gameName, Qt::CaseInsensitive) == 0) { + if (plugin != nullptr && + plugin->gameShortName().compare(gameName, Qt::CaseInsensitive) == 0) { gamePlugin = plugin; break; } @@ -699,7 +778,7 @@ IPluginGame* NexusInterface::getGame(QString gameName) const void NexusInterface::cleanup() { m_AccessManager = nullptr; - m_DiskCache = nullptr; + m_DiskCache = nullptr; } void NexusInterface::clearCache() @@ -710,8 +789,7 @@ void NexusInterface::clearCache() void NexusInterface::nextRequest() { - if ((m_ActiveRequest.size() >= MAX_ACTIVE_DOWNLOADS) - || m_RequestQueue.isEmpty()) { + if ((m_ActiveRequest.size() >= MAX_ACTIVE_DOWNLOADS) || m_RequestQueue.isEmpty()) { return; } @@ -722,7 +800,9 @@ void NexusInterface::nextRequest() } else if (getAccessManager()->validateWaiting()) { return; } else { - log::error("{}", tr("You must authorize MO2 in Settings -> Nexus to use the Nexus API.")); + log::error( + "{}", + tr("You must authorize MO2 in Settings -> Nexus to use the Nexus API.")); } } @@ -731,18 +811,19 @@ void NexusInterface::nextRequest() QTime time = QTime::currentTime(); QTime targetTime; targetTime.setHMS((time.hour() + 1) % 23, 5, 0); - QString warning = tr( - "You've exceeded the Nexus API rate limit and requests are now being throttled. " - "Your next batch of requests will be available in approximately %1 minutes and %2 seconds.") - .arg(time.secsTo(targetTime) / 60) - .arg(time.secsTo(targetTime) % 60); + QString warning = tr("You've exceeded the Nexus API rate limit and requests are " + "now being throttled. " + "Your next batch of requests will be available in " + "approximately %1 minutes and %2 seconds.") + .arg(time.secsTo(targetTime) / 60) + .arg(time.secsTo(targetTime) % 60); log::warn("{}", warning); return; } NXMRequestInfo info = m_RequestQueue.dequeue(); - info.m_Timeout = new QTimer(this); + info.m_Timeout = new QTimer(this); info.m_Timeout->setInterval(60000); QJsonObject postObject; @@ -753,79 +834,118 @@ void NexusInterface::nextRequest() if (!info.m_Reroute) { bool hasParams = false; switch (info.m_Type) { - case NXMRequestInfo::TYPE_DESCRIPTION: - case NXMRequestInfo::TYPE_MODINFO: { - url = QString("%1/games/%2/mods/%3").arg(info.m_URL).arg(info.m_GameName).arg(info.m_ModID); - } break; - case NXMRequestInfo::TYPE_CHECKUPDATES: { - QString period; - switch (info.m_UpdatePeriod) { - case UpdatePeriod::DAY: - period = "1d"; - break; - case UpdatePeriod::WEEK: - period = "1w"; - break; - case UpdatePeriod::MONTH: - period = "1m"; - break; - } - url = QString("%1/games/%2/mods/updated?period=%3").arg(info.m_URL).arg(info.m_GameName).arg(period); - } break; - case NXMRequestInfo::TYPE_FILES: - case NXMRequestInfo::TYPE_GETUPDATES: { - url = QString("%1/games/%2/mods/%3/files").arg(info.m_URL).arg(info.m_GameName).arg(info.m_ModID); - } break; - case NXMRequestInfo::TYPE_FILEINFO: { - url = QString("%1/games/%2/mods/%3/files/%4").arg(info.m_URL).arg(info.m_GameName).arg(info.m_ModID).arg(info.m_FileID); - } break; - case NXMRequestInfo::TYPE_DOWNLOADURL: { - ModRepositoryFileInfo *fileInfo = qobject_cast<ModRepositoryFileInfo*>(qvariant_cast<QObject*>(info.m_UserData)); - if (m_User.type() == APIUserAccountTypes::Premium) { - url = QString("%1/games/%2/mods/%3/files/%4/download_link").arg(info.m_URL).arg(info.m_GameName).arg(info.m_ModID).arg(info.m_FileID); - } else if (!fileInfo->nexusKey.isEmpty() && fileInfo->nexusExpires && fileInfo->nexusDownloadUser == m_User.id().toInt()) { - url = QString("%1/games/%2/mods/%3/files/%4/download_link?key=%5&expires=%6") - .arg(info.m_URL).arg(info.m_GameName).arg(info.m_ModID).arg(info.m_FileID).arg(fileInfo->nexusKey).arg(fileInfo->nexusExpires); - } else { - log::warn("{}", tr("Aborting download: Either you clicked on a premium-only link and your account is not premium, " - "or the download link was generated by a different account than the one stored in Mod Organizer.")); - return; - } - } break; - case NXMRequestInfo::TYPE_ENDORSEMENTS: { - url = QString("%1/user/endorsements").arg(info.m_URL); - } break; - case NXMRequestInfo::TYPE_TOGGLEENDORSEMENT: { - QString endorse = info.m_Endorse ? "endorse" : "abstain"; - url = QString("%1/games/%2/mods/%3/%4").arg(info.m_URL).arg(info.m_GameName).arg(info.m_ModID).arg(endorse); - postObject.insert("Version", info.m_ModVersion); - postData.setObject(postObject); - } break; - case NXMRequestInfo::TYPE_TOGGLETRACKING: { - url = QStringLiteral("%1/user/tracked_mods?domain_name=%2").arg(info.m_URL).arg(info.m_GameName); - postObject.insert("mod_id", info.m_ModID); - postData.setObject(postObject); - requestIsDelete = !info.m_Track; - } break; - case NXMRequestInfo::TYPE_TRACKEDMODS: { - url = QStringLiteral("%1/user/tracked_mods").arg(info.m_URL); - } break; - case NXMRequestInfo::TYPE_FILEINFO_MD5: { - url = QStringLiteral("%1/games/%2/mods/md5_search/%3").arg(info.m_URL).arg(info.m_GameName).arg(QString(info.m_Hash.toHex())); + case NXMRequestInfo::TYPE_DESCRIPTION: + case NXMRequestInfo::TYPE_MODINFO: { + url = QString("%1/games/%2/mods/%3") + .arg(info.m_URL) + .arg(info.m_GameName) + .arg(info.m_ModID); + } break; + case NXMRequestInfo::TYPE_CHECKUPDATES: { + QString period; + switch (info.m_UpdatePeriod) { + case UpdatePeriod::DAY: + period = "1d"; + break; + case UpdatePeriod::WEEK: + period = "1w"; + break; + case UpdatePeriod::MONTH: + period = "1m"; + break; + } + url = QString("%1/games/%2/mods/updated?period=%3") + .arg(info.m_URL) + .arg(info.m_GameName) + .arg(period); + } break; + case NXMRequestInfo::TYPE_FILES: + case NXMRequestInfo::TYPE_GETUPDATES: { + url = QString("%1/games/%2/mods/%3/files") + .arg(info.m_URL) + .arg(info.m_GameName) + .arg(info.m_ModID); + } break; + case NXMRequestInfo::TYPE_FILEINFO: { + url = QString("%1/games/%2/mods/%3/files/%4") + .arg(info.m_URL) + .arg(info.m_GameName) + .arg(info.m_ModID) + .arg(info.m_FileID); + } break; + case NXMRequestInfo::TYPE_DOWNLOADURL: { + ModRepositoryFileInfo* fileInfo = qobject_cast<ModRepositoryFileInfo*>( + qvariant_cast<QObject*>(info.m_UserData)); + if (m_User.type() == APIUserAccountTypes::Premium) { + url = QString("%1/games/%2/mods/%3/files/%4/download_link") + .arg(info.m_URL) + .arg(info.m_GameName) + .arg(info.m_ModID) + .arg(info.m_FileID); + } else if (!fileInfo->nexusKey.isEmpty() && fileInfo->nexusExpires && + fileInfo->nexusDownloadUser == m_User.id().toInt()) { + url = QString("%1/games/%2/mods/%3/files/%4/download_link?key=%5&expires=%6") + .arg(info.m_URL) + .arg(info.m_GameName) + .arg(info.m_ModID) + .arg(info.m_FileID) + .arg(fileInfo->nexusKey) + .arg(fileInfo->nexusExpires); + } else { + log::warn("{}", tr("Aborting download: Either you clicked on a premium-only " + "link and your account is not premium, " + "or the download link was generated by a different account " + "than the one stored in Mod Organizer.")); + return; } + } break; + case NXMRequestInfo::TYPE_ENDORSEMENTS: { + url = QString("%1/user/endorsements").arg(info.m_URL); + } break; + case NXMRequestInfo::TYPE_TOGGLEENDORSEMENT: { + QString endorse = info.m_Endorse ? "endorse" : "abstain"; + url = QString("%1/games/%2/mods/%3/%4") + .arg(info.m_URL) + .arg(info.m_GameName) + .arg(info.m_ModID) + .arg(endorse); + postObject.insert("Version", info.m_ModVersion); + postData.setObject(postObject); + } break; + case NXMRequestInfo::TYPE_TOGGLETRACKING: { + url = QStringLiteral("%1/user/tracked_mods?domain_name=%2") + .arg(info.m_URL) + .arg(info.m_GameName); + postObject.insert("mod_id", info.m_ModID); + postData.setObject(postObject); + requestIsDelete = !info.m_Track; + } break; + case NXMRequestInfo::TYPE_TRACKEDMODS: { + url = QStringLiteral("%1/user/tracked_mods").arg(info.m_URL); + } break; + case NXMRequestInfo::TYPE_FILEINFO_MD5: { + url = QStringLiteral("%1/games/%2/mods/md5_search/%3") + .arg(info.m_URL) + .arg(info.m_GameName) + .arg(QString(info.m_Hash.toHex())); + } } } else { url = info.m_URL; } QNetworkRequest request(url); request.setAttribute(QNetworkRequest::CacheSaveControlAttribute, false); - request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); + request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, + QNetworkRequest::AlwaysNetwork); request.setRawHeader("APIKEY", m_User.apiKey().toUtf8()); - request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, m_AccessManager->userAgent(info.m_SubModule)); - request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json"); + request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, + m_AccessManager->userAgent(info.m_SubModule)); + request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, + "application/json"); request.setRawHeader("Protocol-Version", "1.0.0"); request.setRawHeader("Application-Name", "MO2"); - request.setRawHeader("Application-Version", QApplication::applicationVersion().toUtf8()); + request.setRawHeader("Application-Version", + QApplication::applicationVersion().toUtf8()); if (postData.object().isEmpty()) { if (!requestIsDelete) { @@ -836,42 +956,46 @@ void NexusInterface::nextRequest() } else if (!requestIsDelete) { info.m_Reply = m_AccessManager->post(request, postData.toJson()); } else { - // Qt doesn't support DELETE with a payload as that's technically against the HTTP standard... - info.m_Reply = m_AccessManager->sendCustomRequest(request, "DELETE", postData.toJson()); + // Qt doesn't support DELETE with a payload as that's technically against the HTTP + // standard... + info.m_Reply = + m_AccessManager->sendCustomRequest(request, "DELETE", postData.toJson()); } connect(info.m_Reply, SIGNAL(finished()), this, SLOT(requestFinished())); if (!info.m_IgnoreGenericErrorHandler) - connect(info.m_Reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(requestError(QNetworkReply::NetworkError))); + connect(info.m_Reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, + SLOT(requestError(QNetworkReply::NetworkError))); connect(info.m_Timeout, SIGNAL(timeout()), this, SLOT(requestTimeout())); info.m_Timeout->start(); m_ActiveRequest.push_back(info); } - -void NexusInterface::downloadRequestedNXM(const QString &url) +void NexusInterface::downloadRequestedNXM(const QString& url) { emit requestNXMDownload(url); } void NexusInterface::requestFinished(std::list<NXMRequestInfo>::iterator iter) { - QNetworkReply *reply = iter->m_Reply; + QNetworkReply* reply = iter->m_Reply; auto error = reply->error(); if (error != QNetworkReply::NoError) { int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); QString errorMsg = reply->errorString(); - if (iter->m_AllowedErrors.contains(error) && iter->m_AllowedErrors[error].contains(statusCode)) { - // These errors are allows to silently happen. They should be handled in nxmRequestFailed below. + if (iter->m_AllowedErrors.contains(error) && + iter->m_AllowedErrors[error].contains(statusCode)) { + // These errors are allows to silently happen. They should be handled in + // nxmRequestFailed below. } else if (statusCode == 429) { m_User.limits(parseLimits(reply)); if (!m_User.exhausted()) { - log::warn("You appear to be making requests to the Nexus API too quickly and are being throttled. Please inform the MO2 team."); - } - else { + log::warn("You appear to be making requests to the Nexus API too quickly and " + "are being throttled. Please inform the MO2 team."); + } else { log::warn("All API requests have been consumed and are now being denied."); } @@ -883,21 +1007,23 @@ void NexusInterface::requestFinished(std::list<NXMRequestInfo>::iterator iter) QJsonDocument responseDoc = QJsonDocument::fromJson(data); if (!responseDoc.isNull()) { auto result = responseDoc.toVariant().toMap(); - auto error = result.find("error"); + auto error = result.find("error"); if (error != result.end()) errorMsg = result.value("error").toString(); } } } - emit nxmRequestFailed(iter->m_GameName, iter->m_ModID, iter->m_FileID, iter->m_UserData, iter->m_ID, statusCode, errorMsg); + emit nxmRequestFailed(iter->m_GameName, iter->m_ModID, iter->m_FileID, + iter->m_UserData, iter->m_ID, statusCode, errorMsg); } else { int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); if (statusCode == 301) { // redirect request, return request to queue - iter->m_URL = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toString(); + iter->m_URL = + reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toString(); iter->m_Reroute = true; m_RequestQueue.enqueue(*iter); - //nextRequest(); + // nextRequest(); return; } QByteArray data = reply->readAll(); @@ -907,72 +1033,90 @@ void NexusInterface::requestFinished(std::list<NXMRequestInfo>::iterator iter) nexusError = tr("empty response"); } log::debug("nexus error: {}", nexusError); - emit nxmRequestFailed(iter->m_GameName, iter->m_ModID, iter->m_FileID, iter->m_UserData, iter->m_ID, reply->error(), nexusError); + emit nxmRequestFailed(iter->m_GameName, iter->m_ModID, iter->m_FileID, + iter->m_UserData, iter->m_ID, reply->error(), nexusError); } else { QJsonDocument responseDoc = QJsonDocument::fromJson(data); if (!responseDoc.isNull()) { QVariant result = responseDoc.toVariant(); switch (iter->m_Type) { - case NXMRequestInfo::TYPE_DESCRIPTION: { - emit nxmDescriptionAvailable(iter->m_GameName, iter->m_ModID, iter->m_UserData, result, iter->m_ID); - } break; - case NXMRequestInfo::TYPE_MODINFO: { - emit nxmModInfoAvailable(iter->m_GameName, iter->m_ModID, iter->m_UserData, result, iter->m_ID); - } break; - case NXMRequestInfo::TYPE_CHECKUPDATES: { - emit nxmUpdateInfoAvailable(iter->m_GameName, iter->m_UserData, result, iter->m_ID); - } break; - case NXMRequestInfo::TYPE_FILES: { - emit nxmFilesAvailable(iter->m_GameName, iter->m_ModID, iter->m_UserData, result, iter->m_ID); - } break; - case NXMRequestInfo::TYPE_GETUPDATES: { - emit nxmUpdatesAvailable(iter->m_GameName, iter->m_ModID, iter->m_UserData, result, iter->m_ID); - } break; - case NXMRequestInfo::TYPE_FILEINFO: { - emit nxmFileInfoAvailable(iter->m_GameName, iter->m_ModID, iter->m_FileID, iter->m_UserData, result, iter->m_ID); - } break; - case NXMRequestInfo::TYPE_DOWNLOADURL: { - emit nxmDownloadURLsAvailable(iter->m_GameName, iter->m_ModID, iter->m_FileID, iter->m_UserData, result, iter->m_ID); - } break; - case NXMRequestInfo::TYPE_ENDORSEMENTS: { - emit nxmEndorsementsAvailable(iter->m_UserData, result, iter->m_ID); - } break; - case NXMRequestInfo::TYPE_TOGGLEENDORSEMENT: { - emit nxmEndorsementToggled(iter->m_GameName, iter->m_ModID, iter->m_UserData, result, iter->m_ID); - } break; - case NXMRequestInfo::TYPE_TOGGLETRACKING: { - auto results = result.toMap(); - auto message = results["message"].toString(); - if (message.contains(QRegularExpression("User [0-9]+ is already Tracking Mod: [0-9]+")) || - message.contains(QRegularExpression("User [0-9]+ is now Tracking Mod: [0-9]+"))) { - emit nxmTrackingToggled(iter->m_GameName, iter->m_ModID, iter->m_UserData, true, iter->m_ID); - } else if (message.contains(QRegularExpression("User [0-9]+ is no longer tracking [0-9]+")) || - message.contains(QRegularExpression("Users is not tracking mod. Unable to untrack."))) { - emit nxmTrackingToggled(iter->m_GameName, iter->m_ModID, iter->m_UserData, false, iter->m_ID); - } - } break; - case NXMRequestInfo::TYPE_TRACKEDMODS: { - emit nxmTrackedModsAvailable(iter->m_UserData, result, iter->m_ID); - } break; - case NXMRequestInfo::TYPE_FILEINFO_MD5: { - emit nxmFileInfoFromMd5Available(iter->m_GameName, iter->m_UserData, result, iter->m_ID); - } break; + case NXMRequestInfo::TYPE_DESCRIPTION: { + emit nxmDescriptionAvailable(iter->m_GameName, iter->m_ModID, + iter->m_UserData, result, iter->m_ID); + } break; + case NXMRequestInfo::TYPE_MODINFO: { + emit nxmModInfoAvailable(iter->m_GameName, iter->m_ModID, iter->m_UserData, + result, iter->m_ID); + } break; + case NXMRequestInfo::TYPE_CHECKUPDATES: { + emit nxmUpdateInfoAvailable(iter->m_GameName, iter->m_UserData, result, + iter->m_ID); + } break; + case NXMRequestInfo::TYPE_FILES: { + emit nxmFilesAvailable(iter->m_GameName, iter->m_ModID, iter->m_UserData, + result, iter->m_ID); + } break; + case NXMRequestInfo::TYPE_GETUPDATES: { + emit nxmUpdatesAvailable(iter->m_GameName, iter->m_ModID, iter->m_UserData, + result, iter->m_ID); + } break; + case NXMRequestInfo::TYPE_FILEINFO: { + emit nxmFileInfoAvailable(iter->m_GameName, iter->m_ModID, iter->m_FileID, + iter->m_UserData, result, iter->m_ID); + } break; + case NXMRequestInfo::TYPE_DOWNLOADURL: { + emit nxmDownloadURLsAvailable(iter->m_GameName, iter->m_ModID, iter->m_FileID, + iter->m_UserData, result, iter->m_ID); + } break; + case NXMRequestInfo::TYPE_ENDORSEMENTS: { + emit nxmEndorsementsAvailable(iter->m_UserData, result, iter->m_ID); + } break; + case NXMRequestInfo::TYPE_TOGGLEENDORSEMENT: { + emit nxmEndorsementToggled(iter->m_GameName, iter->m_ModID, iter->m_UserData, + result, iter->m_ID); + } break; + case NXMRequestInfo::TYPE_TOGGLETRACKING: { + auto results = result.toMap(); + auto message = results["message"].toString(); + if (message.contains( + QRegularExpression("User [0-9]+ is already Tracking Mod: [0-9]+")) || + message.contains( + QRegularExpression("User [0-9]+ is now Tracking Mod: [0-9]+"))) { + emit nxmTrackingToggled(iter->m_GameName, iter->m_ModID, iter->m_UserData, + true, iter->m_ID); + } else if (message.contains(QRegularExpression( + "User [0-9]+ is no longer tracking [0-9]+")) || + message.contains(QRegularExpression( + "Users is not tracking mod. Unable to untrack."))) { + emit nxmTrackingToggled(iter->m_GameName, iter->m_ModID, iter->m_UserData, + false, iter->m_ID); + } + } break; + case NXMRequestInfo::TYPE_TRACKEDMODS: { + emit nxmTrackedModsAvailable(iter->m_UserData, result, iter->m_ID); + } break; + case NXMRequestInfo::TYPE_FILEINFO_MD5: { + emit nxmFileInfoFromMd5Available(iter->m_GameName, iter->m_UserData, result, + iter->m_ID); + } break; } m_User.limits(parseLimits(reply)); emit requestsChanged(getAPIStats(), m_User); } else { - emit nxmRequestFailed(iter->m_GameName, iter->m_ModID, iter->m_FileID, iter->m_UserData, iter->m_ID, reply->error(), tr("invalid response")); + emit nxmRequestFailed(iter->m_GameName, iter->m_ModID, iter->m_FileID, + iter->m_UserData, iter->m_ID, reply->error(), + tr("invalid response")); } } } } - void NexusInterface::requestFinished() { - QNetworkReply *reply = static_cast<QNetworkReply*>(sender()); - for (std::list<NXMRequestInfo>::iterator iter = m_ActiveRequest.begin(); iter != m_ActiveRequest.end(); ++iter) { + QNetworkReply* reply = static_cast<QNetworkReply*>(sender()); + for (std::list<NXMRequestInfo>::iterator iter = m_ActiveRequest.begin(); + iter != m_ActiveRequest.end(); ++iter) { if (iter->m_Reply == reply) { iter->m_Timeout->stop(); iter->m_Timeout->deleteLater(); @@ -985,29 +1129,27 @@ void NexusInterface::requestFinished() } } - void NexusInterface::requestError(QNetworkReply::NetworkError) { - QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender()); + QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender()); if (reply == nullptr) { log::warn("invalid sender type"); return; } - log::error( - "request ({}) error: {} ({})", - reply->url().toString(), reply->errorString(), reply->error()); + log::error("request ({}) error: {} ({})", reply->url().toString(), + reply->errorString(), reply->error()); } - void NexusInterface::requestTimeout() { - QTimer *timer = qobject_cast<QTimer*>(sender()); + QTimer* timer = qobject_cast<QTimer*>(sender()); if (timer == nullptr) { log::warn("invalid sender type"); return; } - for (std::list<NXMRequestInfo>::iterator iter = m_ActiveRequest.begin(); iter != m_ActiveRequest.end(); ++iter) { + for (std::list<NXMRequestInfo>::iterator iter = m_ActiveRequest.begin(); + iter != m_ActiveRequest.end(); ++iter) { if (iter->m_Timeout == timer) { // this abort causes a "request failed" which cleans up the rest iter->m_Reply->abort(); @@ -1029,163 +1171,74 @@ APIStats NexusInterface::getAPIStats() const return stats; } - -namespace { - QString get_management_url() - { - return "https://api.nexusmods.com/v1"; - } -} - -NexusInterface::NXMRequestInfo::NXMRequestInfo(int modID - , NexusInterface::NXMRequestInfo::Type type - , QVariant userData - , const QString &subModule - , MOBase::IPluginGame const *game - ) - : m_ModID(modID) - , m_ModVersion("0") - , m_FileID(0) - , m_Reply(nullptr) - , m_Type(type) - , m_UpdatePeriod(UpdatePeriod::NONE) - , m_UserData(userData) - , m_Timeout(nullptr) - , m_Reroute(false) - , m_ID(s_NextID.fetchAndAddAcquire(1)) - , m_URL(get_management_url()) - , m_SubModule(subModule) - , m_NexusGameID(game->nexusGameID()) - , m_GameName(game->gameNexusName()) - , m_Endorse(false) - , m_Track(false) - , m_Hash(QByteArray()) +namespace { +QString get_management_url() +{ + return "https://api.nexusmods.com/v1"; } +} // namespace -NexusInterface::NXMRequestInfo::NXMRequestInfo(int modID - , QString modVersion - , NexusInterface::NXMRequestInfo::Type type - , QVariant userData - , const QString &subModule - , MOBase::IPluginGame const *game -) - : m_ModID(modID) - , m_ModVersion(modVersion) - , m_FileID(0) - , m_Reply(nullptr) - , m_Type(type) - , m_UpdatePeriod(UpdatePeriod::NONE) - , m_UserData(userData) - , m_Timeout(nullptr) - , m_Reroute(false) - , m_ID(s_NextID.fetchAndAddAcquire(1)) - , m_URL(get_management_url()) - , m_SubModule(subModule) - , m_NexusGameID(game->nexusGameID()) - , m_GameName(game->gameNexusName()) - , m_Endorse(false) - , m_Track(false) - , m_Hash(QByteArray()) +NexusInterface::NXMRequestInfo::NXMRequestInfo( + int modID, NexusInterface::NXMRequestInfo::Type type, QVariant userData, + const QString& subModule, MOBase::IPluginGame const* game) + : m_ModID(modID), m_ModVersion("0"), m_FileID(0), m_Reply(nullptr), m_Type(type), + m_UpdatePeriod(UpdatePeriod::NONE), m_UserData(userData), m_Timeout(nullptr), + m_Reroute(false), m_ID(s_NextID.fetchAndAddAcquire(1)), + m_URL(get_management_url()), m_SubModule(subModule), + m_NexusGameID(game->nexusGameID()), m_GameName(game->gameNexusName()), + m_Endorse(false), m_Track(false), m_Hash(QByteArray()) {} -NexusInterface::NXMRequestInfo::NXMRequestInfo(int modID - , int fileID - , NexusInterface::NXMRequestInfo::Type type - , QVariant userData - , const QString &subModule - , MOBase::IPluginGame const *game -) - : m_ModID(modID) - , m_ModVersion("0") - , m_FileID(fileID) - , m_Reply(nullptr) - , m_Type(type) - , m_UpdatePeriod(UpdatePeriod::NONE) - , m_UserData(userData) - , m_Timeout(nullptr) - , m_Reroute(false) - , m_ID(s_NextID.fetchAndAddAcquire(1)) - , m_URL(get_management_url()) - , m_SubModule(subModule) - , m_NexusGameID(game->nexusGameID()) - , m_GameName(game->gameNexusName()) - , m_Endorse(false) - , m_Track(false) - , m_Hash(QByteArray()) +NexusInterface::NXMRequestInfo::NXMRequestInfo( + int modID, QString modVersion, NexusInterface::NXMRequestInfo::Type type, + QVariant userData, const QString& subModule, MOBase::IPluginGame const* game) + : m_ModID(modID), m_ModVersion(modVersion), m_FileID(0), m_Reply(nullptr), + m_Type(type), m_UpdatePeriod(UpdatePeriod::NONE), m_UserData(userData), + m_Timeout(nullptr), m_Reroute(false), m_ID(s_NextID.fetchAndAddAcquire(1)), + m_URL(get_management_url()), m_SubModule(subModule), + m_NexusGameID(game->nexusGameID()), m_GameName(game->gameNexusName()), + m_Endorse(false), m_Track(false), m_Hash(QByteArray()) {} -NexusInterface::NXMRequestInfo::NXMRequestInfo(Type type - , QVariant userData - , const QString &subModule -) - : m_ModID(0) - , m_ModVersion("0") - , m_FileID(0) - , m_Reply(nullptr) - , m_Type(type) - , m_UpdatePeriod(UpdatePeriod::NONE) - , m_UserData(userData) - , m_Timeout(nullptr) - , m_Reroute(false) - , m_ID(s_NextID.fetchAndAddAcquire(1)) - , m_URL(get_management_url()) - , m_SubModule(subModule) - , m_NexusGameID(0) - , m_GameName("") - , m_Endorse(false) - , m_Track(false) - , m_Hash(QByteArray()) +NexusInterface::NXMRequestInfo::NXMRequestInfo( + int modID, int fileID, NexusInterface::NXMRequestInfo::Type type, QVariant userData, + const QString& subModule, MOBase::IPluginGame const* game) + : m_ModID(modID), m_ModVersion("0"), m_FileID(fileID), m_Reply(nullptr), + m_Type(type), m_UpdatePeriod(UpdatePeriod::NONE), m_UserData(userData), + m_Timeout(nullptr), m_Reroute(false), m_ID(s_NextID.fetchAndAddAcquire(1)), + m_URL(get_management_url()), m_SubModule(subModule), + m_NexusGameID(game->nexusGameID()), m_GameName(game->gameNexusName()), + m_Endorse(false), m_Track(false), m_Hash(QByteArray()) {} - -NexusInterface::NXMRequestInfo::NXMRequestInfo(UpdatePeriod period - , NexusInterface::NXMRequestInfo::Type type - , QVariant userData - , const QString &subModule - , MOBase::IPluginGame const *game -) - : m_ModID(0) - , m_ModVersion("0") - , m_FileID(0) - , m_Reply(nullptr) - , m_Type(type) - , m_UpdatePeriod(period) - , m_UserData(userData) - , m_Timeout(nullptr) - , m_Reroute(false) - , m_ID(s_NextID.fetchAndAddAcquire(1)) - , m_URL(get_management_url()) - , m_SubModule(subModule) - , m_NexusGameID(game->nexusGameID()) - , m_GameName(game->gameNexusName()) - , m_Endorse(false) - , m_Track(false) - , m_Hash(QByteArray()) +NexusInterface::NXMRequestInfo::NXMRequestInfo(Type type, QVariant userData, + const QString& subModule) + : m_ModID(0), m_ModVersion("0"), m_FileID(0), m_Reply(nullptr), m_Type(type), + m_UpdatePeriod(UpdatePeriod::NONE), m_UserData(userData), m_Timeout(nullptr), + m_Reroute(false), m_ID(s_NextID.fetchAndAddAcquire(1)), + m_URL(get_management_url()), m_SubModule(subModule), m_NexusGameID(0), + m_GameName(""), m_Endorse(false), m_Track(false), m_Hash(QByteArray()) {} +NexusInterface::NXMRequestInfo::NXMRequestInfo( + UpdatePeriod period, NexusInterface::NXMRequestInfo::Type type, QVariant userData, + const QString& subModule, MOBase::IPluginGame const* game) + : m_ModID(0), m_ModVersion("0"), m_FileID(0), m_Reply(nullptr), m_Type(type), + m_UpdatePeriod(period), m_UserData(userData), m_Timeout(nullptr), + m_Reroute(false), m_ID(s_NextID.fetchAndAddAcquire(1)), + m_URL(get_management_url()), m_SubModule(subModule), + m_NexusGameID(game->nexusGameID()), m_GameName(game->gameNexusName()), + m_Endorse(false), m_Track(false), m_Hash(QByteArray()) +{} -NexusInterface::NXMRequestInfo::NXMRequestInfo(QByteArray &hash - , NexusInterface::NXMRequestInfo::Type type - , QVariant userData - , const QString &subModule - , MOBase::IPluginGame const *game -) - : m_ModID(0) - , m_ModVersion("0") - , m_FileID(0) - , m_Reply(nullptr) - , m_Type(type) - , m_UpdatePeriod(UpdatePeriod::NONE) - , m_UserData(userData) - , m_Timeout(nullptr) - , m_Reroute(false) - , m_ID(s_NextID.fetchAndAddAcquire(1)) - , m_URL(get_management_url()) - , m_SubModule(subModule) - , m_NexusGameID(game->nexusGameID()) - , m_GameName(game->gameNexusName()) - , m_Endorse(false) - , m_Track(false) - , m_Hash(hash) +NexusInterface::NXMRequestInfo::NXMRequestInfo( + QByteArray& hash, NexusInterface::NXMRequestInfo::Type type, QVariant userData, + const QString& subModule, MOBase::IPluginGame const* game) + : m_ModID(0), m_ModVersion("0"), m_FileID(0), m_Reply(nullptr), m_Type(type), + m_UpdatePeriod(UpdatePeriod::NONE), m_UserData(userData), m_Timeout(nullptr), + m_Reroute(false), m_ID(s_NextID.fetchAndAddAcquire(1)), + m_URL(get_management_url()), m_SubModule(subModule), + m_NexusGameID(game->nexusGameID()), m_GameName(game->gameNexusName()), + m_Endorse(false), m_Track(false), m_Hash(hash) {} diff --git a/src/nexusinterface.h b/src/nexusinterface.h index 8e33d51f..331ce55d 100644 --- a/src/nexusinterface.h +++ b/src/nexusinterface.h @@ -23,20 +23,23 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "apiuseraccount.h" #include "plugincontainer.h" +#include <imodrepositorybridge.h> #include <utility.h> #include <versioninfo.h> -#include <imodrepositorybridge.h> -#include <QNetworkReply> #include <QNetworkDiskCache> +#include <QNetworkReply> #include <QQueue> -#include <QVariant> #include <QTimer> +#include <QVariant> #include <list> #include <set> -namespace MOBase { class IPluginGame; } +namespace MOBase +{ +class IPluginGame; +} class NexusInterface; class NXMAccessManager; @@ -45,10 +48,9 @@ class Settings; /** * @brief convenience class to make nxm requests easier * usually, all objects that started a nxm request will be signaled if one finished. - * Therefore, the objects need to store the id of the requests they started and then filter - * the result. - * NexusBridge does this automatically. Users connect to the signals of NexusBridge they intend - * to handle and only receive the signals the caused + * Therefore, the objects need to store the id of the requests they started and then + *filter the result. NexusBridge does this automatically. Users connect to the signals + *of NexusBridge they intend to handle and only receive the signals the caused **/ class NexusBridge : public MOBase::IModRepositoryBridge { @@ -56,7 +58,7 @@ class NexusBridge : public MOBase::IModRepositoryBridge Q_OBJECT public: - NexusBridge(PluginContainer *pluginContainer, const QString &subModule = ""); + NexusBridge(PluginContainer* pluginContainer, const QString& subModule = ""); /** * @brief request description for a mod @@ -82,7 +84,8 @@ public: * @param fileID id of the file the caller is interested in * @param userData user data to be returned with the result **/ - virtual void requestFileInfo(QString gameName, int modID, int fileID, QVariant userData); + virtual void requestFileInfo(QString gameName, int modID, int fileID, + QVariant userData); /** * @brief request the download url of a file @@ -91,73 +94,85 @@ public: * @param fileID id of the file the caller is interested in * @param userData user data to be returned with the result **/ - virtual void requestDownloadURL(QString gameName, int modID, int fileID, QVariant userData); + virtual void requestDownloadURL(QString gameName, int modID, int fileID, + QVariant userData); /** * @brief requestToggleEndorsement * @param modID id of the mod caller is interested in * @param userData user data to be returned with the result */ - virtual void requestToggleEndorsement(QString gameName, int modID, QString modVersion, bool endorse, QVariant userData); + virtual void requestToggleEndorsement(QString gameName, int modID, QString modVersion, + bool endorse, QVariant userData); /** * @brief requestToggleTracking * @param modID id of the mod caller is interested in * @param userData user data to be returned with the result */ - virtual void requestToggleTracking(QString gameName, int modID, bool track, QVariant userData); + virtual void requestToggleTracking(QString gameName, int modID, bool track, + QVariant userData); public slots: - void nxmDescriptionAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID); - void nxmFilesAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID); - void nxmFileInfoAvailable(QString gameName, int modID, int fileID, QVariant userData, QVariant resultData, int requestID); - void nxmDownloadURLsAvailable(QString gameName, int modID, int fileID, QVariant userData, QVariant resultData, int requestID); + void nxmDescriptionAvailable(QString gameName, int modID, QVariant userData, + QVariant resultData, int requestID); + void nxmFilesAvailable(QString gameName, int modID, QVariant userData, + QVariant resultData, int requestID); + void nxmFileInfoAvailable(QString gameName, int modID, int fileID, QVariant userData, + QVariant resultData, int requestID); + void nxmDownloadURLsAvailable(QString gameName, int modID, int fileID, + QVariant userData, QVariant resultData, int requestID); void nxmEndorsementsAvailable(QVariant userData, QVariant resultData, int requestID); - void nxmEndorsementToggled(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID); + void nxmEndorsementToggled(QString gameName, int modID, QVariant userData, + QVariant resultData, int requestID); void nxmTrackedModsAvailable(QVariant userData, QVariant resultData, int requestID); - void nxmTrackingToggled(QString gameName, int modID, QVariant userData, bool tracked, int requestID); - void nxmRequestFailed(QString gameName, int modID, int fileID, QVariant userData, int requestID, int errorCode, const QString &errorMessage); + void nxmTrackingToggled(QString gameName, int modID, QVariant userData, bool tracked, + int requestID); + void nxmRequestFailed(QString gameName, int modID, int fileID, QVariant userData, + int requestID, int errorCode, const QString& errorMessage); private: - - NexusInterface *m_Interface; + NexusInterface* m_Interface; QString m_SubModule; std::set<int> m_RequestIDs; - }; - /** * @brief Makes asynchronous requests to the nexus API * * This class can be used to make asynchronous requests to the Nexus API. - * Currently, responses are sent to all receivers that have sent a request of the relevant type, so the - * recipient has to filter the response by the id returned when making the request + * Currently, responses are sent to all receivers that have sent a request of the + *relevant type, so the recipient has to filter the response by the id returned when + *making the request **/ class NexusInterface : public QObject { Q_OBJECT public: - - enum UpdatePeriod { + enum UpdatePeriod + { NONE, DAY, WEEK, MONTH }; - // Nexus file category IDs (MAIN, OLD etc), not to be confused with mod categories (Armors, Texture etc). - enum FileStatus { - MAIN = 1, - UPDATE = 2, - OPTIONAL_FILE = 3, // actual string version is "OPTIONAL", but that is already defined as a macro in minwindef.h - OLD_VERSION = 4, - MISCELLANEOUS = 5, - REMOVED = 6, - ARCHIVED = 7, - ARCHIVED_HIDDEN = 1000 // Archived files can be hidden by authors so if they aren't listed we can assume they were hidden. + // Nexus file category IDs (MAIN, OLD etc), not to be confused with mod categories + // (Armors, Texture etc). + enum FileStatus + { + MAIN = 1, + UPDATE = 2, + OPTIONAL_FILE = 3, // actual string version is "OPTIONAL", but that is already + // defined as a macro in minwindef.h + OLD_VERSION = 4, + MISCELLANEOUS = 5, + REMOVED = 6, + ARCHIVED = 7, + ARCHIVED_HIDDEN = 1000 // Archived files can be hidden by authors so if they aren't + // listed we can assume they were hidden. }; public: @@ -173,10 +188,11 @@ public: /** * @return the access manager object used to connect to nexus **/ - NXMAccessManager *getAccessManager(); + NXMAccessManager* getAccessManager(); /** - * @brief cleanup this interface. this is destructive, afterwards it can't be used again + * @brief cleanup this interface. this is destructive, afterwards it can't be used + * again */ void cleanup(); @@ -189,14 +205,18 @@ public: * @brief request description for a mod * * @param gameName the game short name to support multiple game sources - * @param modID id of the mod caller is interested in (assumed to be for the current game) - * @param receiver the object to receive the result asynchronously via a signal (nxmDescriptionAvailable) + * @param modID id of the mod caller is interested in (assumed to be for the current + *game) + * @param receiver the object to receive the result asynchronously via a signal + *(nxmDescriptionAvailable) * @param userData user data to be returned with the result * @return int an id to identify the request **/ - int requestDescription(QString gameName, int modID, QObject *receiver, QVariant userData, const QString &subModule) + int requestDescription(QString gameName, int modID, QObject* receiver, + QVariant userData, const QString& subModule) { - return requestDescription(gameName, modID, receiver, userData, subModule, getGame(gameName)); + return requestDescription(gameName, modID, receiver, userData, subModule, + getGame(gameName)); } /** @@ -204,26 +224,32 @@ public: * * @param gameName the game short name to support multiple game sources * @param modID id of the mod caller is interested in - * @param receiver the object to receive the result asynchronously via a signal (nxmDescriptionAvailable) + * @param receiver the object to receive the result asynchronously via a signal + *(nxmDescriptionAvailable) * @param userData user data to be returned with the result * @param game Game with which the mod is associated * @return int an id to identify the request **/ - int requestDescription(QString gameName, int modID, QObject *receiver, QVariant userData, const QString &subModule, - MOBase::IPluginGame const *game); + int requestDescription(QString gameName, int modID, QObject* receiver, + QVariant userData, const QString& subModule, + MOBase::IPluginGame const* game); /** * @brief request description for a mod * * @param gameName the game short name to support multiple game sources - * @param modID id of the mod caller is interested in (assumed to be for the current game) - * @param receiver the object to receive the result asynchronously via a signal (nxmModInfoAvailable) + * @param modID id of the mod caller is interested in (assumed to be for the current + *game) + * @param receiver the object to receive the result asynchronously via a signal + *(nxmModInfoAvailable) * @param userData user data to be returned with the result * @return int an id to identify the request **/ - int requestModInfo(QString gameName, int modID, QObject *receiver, QVariant userData, const QString &subModule) + int requestModInfo(QString gameName, int modID, QObject* receiver, QVariant userData, + const QString& subModule) { - return requestModInfo(gameName, modID, receiver, userData, subModule, getGame(gameName)); + return requestModInfo(gameName, modID, receiver, userData, subModule, + getGame(gameName)); } /** @@ -231,86 +257,102 @@ public: * * @param gameName the game short name to support multiple game sources * @param modID id of the mod caller is interested in - * @param receiver the object to receive the result asynchronously via a signal (nxmModInfoAvailable) + * @param receiver the object to receive the result asynchronously via a signal + *(nxmModInfoAvailable) * @param userData user data to be returned with the result * @param game Game with which the mod is associated * @return int an id to identify the request **/ - int requestModInfo(QString gameName, int modID, QObject *receiver, QVariant userData, const QString &subModule, - MOBase::IPluginGame const *game); + int requestModInfo(QString gameName, int modID, QObject* receiver, QVariant userData, + const QString& subModule, MOBase::IPluginGame const* game); - int requestUpdateInfo(QString gameName, NexusInterface::UpdatePeriod period, QObject *receiver, QVariant userData, - const QString &subModule) + int requestUpdateInfo(QString gameName, NexusInterface::UpdatePeriod period, + QObject* receiver, QVariant userData, const QString& subModule) { - return requestUpdateInfo(gameName, period, receiver, userData, subModule, getGame(gameName)); + return requestUpdateInfo(gameName, period, receiver, userData, subModule, + getGame(gameName)); } - int requestUpdateInfo(QString gameName, NexusInterface::UpdatePeriod period, QObject *receiver, QVariant userData, - const QString &subModule, const MOBase::IPluginGame *game); + int requestUpdateInfo(QString gameName, NexusInterface::UpdatePeriod period, + QObject* receiver, QVariant userData, const QString& subModule, + const MOBase::IPluginGame* game); /** * @brief request nexus descriptions for multiple mods at once * @param modID id of the mod the caller is interested in - * @param receiver the object to receive the result asynchronously via a signal (nxmDescriptionAvailable) + * @param receiver the object to receive the result asynchronously via a signal + * (nxmDescriptionAvailable) * @param userData user data to be returned with the result * @param gameName the game with which the mods are associated * @return int an id to identify the request */ - int requestUpdates(const int &modID, QObject *receiver, QVariant userData, QString gameName, const QString &subModule); + int requestUpdates(const int& modID, QObject* receiver, QVariant userData, + QString gameName, const QString& subModule); /** * @brief request a list of the files belonging to a mod * * @param gameName the game short name to support multiple game sources - * @param modID id of the mod caller is interested in (assumed to be for the current game) - * @param receiver the object to receive the result asynchronously via a signal (nxmFilesAvailable) + * @param modID id of the mod caller is interested in (assumed to be for the current + *game) + * @param receiver the object to receive the result asynchronously via a signal + *(nxmFilesAvailable) * @param userData user data to be returned with the result * @return int an id to identify the request **/ - int requestFiles(QString gameName, int modID, QObject *receiver, QVariant userData, const QString &subModule) + int requestFiles(QString gameName, int modID, QObject* receiver, QVariant userData, + const QString& subModule) { - return requestFiles(gameName, modID, receiver, userData, subModule, getGame(gameName)); + return requestFiles(gameName, modID, receiver, userData, subModule, + getGame(gameName)); } - /** * @brief request a list of the files belonging to a mod * * @param gameName the game short name to support multiple game sources * @param modID id of the mod caller is interested in - * @param receiver the object to receive the result asynchronously via a signal (nxmFilesAvailable) + * @param receiver the object to receive the result asynchronously via a signal + *(nxmFilesAvailable) * @param userData user data to be returned with the result * @param game the game with which the mods are associated * @return int an id to identify the request **/ - int requestFiles(QString gameName, int modID, QObject *receiver, QVariant userData, const QString &subModule, - MOBase::IPluginGame const *game); + int requestFiles(QString gameName, int modID, QObject* receiver, QVariant userData, + const QString& subModule, MOBase::IPluginGame const* game); /** * @brief request info about a single file of a mod * * @param gameName name of the game short name to request the download from - * @param modID id of the mod caller is interested in (assumed to be for the current game) + * @param modID id of the mod caller is interested in (assumed to be for the current + *game) * @param fileID id of the file the caller is interested in - * @param receiver the object to receive the result asynchronously via a signal (nxmFilesAvailable) + * @param receiver the object to receive the result asynchronously via a signal + *(nxmFilesAvailable) * @param userData user data to be returned with the result * @return int an id to identify the request **/ - int requestFileInfo(QString gameName, int modID, int fileID, QObject *receiver, QVariant userData, const QString &subModule); + int requestFileInfo(QString gameName, int modID, int fileID, QObject* receiver, + QVariant userData, const QString& subModule); /** * @brief request the download url of a file * * @param gameName the game short name to support multiple game sources - * @param modID id of the mod caller is interested in (assumed to be for the current game) + * @param modID id of the mod caller is interested in (assumed to be for the current + *game) * @param fileID id of the file the caller is interested in - * @param receiver the object to receive the result asynchronously via a signal (nxmFilesAvailable) + * @param receiver the object to receive the result asynchronously via a signal + *(nxmFilesAvailable) * @param userData user data to be returned with the result * @return int an id to identify the request **/ - int requestDownloadURL(QString gameName, int modID, int fileID, QObject *receiver, QVariant userData, const QString &subModule) + int requestDownloadURL(QString gameName, int modID, int fileID, QObject* receiver, + QVariant userData, const QString& subModule) { - return requestDownloadURL(gameName, modID, fileID, receiver, userData, subModule, getGame(gameName)); + return requestDownloadURL(gameName, modID, fileID, receiver, userData, subModule, + getGame(gameName)); } /** @@ -319,29 +361,35 @@ public: * @param gameName the game short name to support multiple game sources * @param modID id of the mod caller is interested in * @param fileID id of the file the caller is interested in - * @param receiver the object to receive the result asynchronously via a signal (nxmFilesAvailable) + * @param receiver the object to receive the result asynchronously via a signal + *(nxmFilesAvailable) * @param userData user data to be returned with the result * @param game the game with which the mods are associated * @return int an id to identify the request **/ - int requestDownloadURL(QString gameName, int modID, int fileID, QObject *receiver, QVariant userData, const QString &subModule, MOBase::IPluginGame const *game); - - - int requestEndorsementInfo(QObject *receiver, QVariant userData, const QString &subModule); + int requestDownloadURL(QString gameName, int modID, int fileID, QObject* receiver, + QVariant userData, const QString& subModule, + MOBase::IPluginGame const* game); + int requestEndorsementInfo(QObject* receiver, QVariant userData, + const QString& subModule); /** * @param gameName the game short name to support multiple game sources * @brief toggle endorsement state of the mod * @param modID id of the mod (assumed to be for the current game) * @param endorse true if the mod should be endorsed, false for un-endorse - * @param receiver the object to receive the result asynchronously via a signal (nxmFilesAvailable) + * @param receiver the object to receive the result asynchronously via a signal + * (nxmFilesAvailable) * @param userData user data to be returned with the result * @return int an id to identify the request */ - int requestToggleEndorsement(QString gameName, int modID, QString modVersion, bool endorse, QObject *receiver, QVariant userData, const QString &subModule) + int requestToggleEndorsement(QString gameName, int modID, QString modVersion, + bool endorse, QObject* receiver, QVariant userData, + const QString& subModule) { - return requestToggleEndorsement(gameName, modID, modVersion, endorse, receiver, userData, subModule, getGame(gameName)); + return requestToggleEndorsement(gameName, modID, modVersion, endorse, receiver, + userData, subModule, getGame(gameName)); } /** @@ -349,94 +397,109 @@ public: * @brief toggle endorsement state of the mod * @param modID id of the mod * @param endorse true if the mod should be endorsed, false for un-endorse - * @param receiver the object to receive the result asynchronously via a signal (nxmFilesAvailable) + * @param receiver the object to receive the result asynchronously via a signal + * (nxmFilesAvailable) * @param userData user data to be returned with the result * @param game the game with which the mods are associated * @return int an id to identify the request */ - int requestToggleEndorsement(QString gameName, int modID, QString modVersion, bool endorse, QObject *receiver, QVariant userData, const QString &subModule, - MOBase::IPluginGame const *game); + int requestToggleEndorsement(QString gameName, int modID, QString modVersion, + bool endorse, QObject* receiver, QVariant userData, + const QString& subModule, + MOBase::IPluginGame const* game); - int requestTrackingInfo(QObject *receiver, QVariant userData, const QString &subModule); + int requestTrackingInfo(QObject* receiver, QVariant userData, + const QString& subModule); /** - * @param gameName the game short name to support multiple game sources - * @brief toggle tracking state of the mod - * @param modID id of the mod - * @param track true if the mod should be tracked, false for not tracked - * @param receiver the object to receive the result asynchronously via a signal (nxmFilesAvailable) - * @param userData user data to be returned with the result - * @param game the game with which the mods are associated - * @return int an id to identify the request - */ - int requestToggleTracking(QString gameName, int modID, bool track, QObject *receiver, QVariant userData, const QString &subModule) + * @param gameName the game short name to support multiple game sources + * @brief toggle tracking state of the mod + * @param modID id of the mod + * @param track true if the mod should be tracked, false for not tracked + * @param receiver the object to receive the result asynchronously via a signal + * (nxmFilesAvailable) + * @param userData user data to be returned with the result + * @param game the game with which the mods are associated + * @return int an id to identify the request + */ + int requestToggleTracking(QString gameName, int modID, bool track, QObject* receiver, + QVariant userData, const QString& subModule) { - return requestToggleTracking(gameName, modID, track, receiver, userData, subModule, getGame(gameName)); + return requestToggleTracking(gameName, modID, track, receiver, userData, subModule, + getGame(gameName)); } /** - * @param gameName the game short name to support multiple game sources - * @brief toggle tracking state of the mod - * @param modID id of the mod - * @param track true if the mod should be tracked, false for not tracked - * @param receiver the object to receive the result asynchronously via a signal (nxmFilesAvailable) - * @param userData user data to be returned with the result - * @param game the game with which the mods are associated - * @return int an id to identify the request - */ - int requestToggleTracking(QString gameName, int modID, bool track, QObject *receiver, QVariant userData, const QString &subModule, - MOBase::IPluginGame const *game); + * @param gameName the game short name to support multiple game sources + * @brief toggle tracking state of the mod + * @param modID id of the mod + * @param track true if the mod should be tracked, false for not tracked + * @param receiver the object to receive the result asynchronously via a signal + * (nxmFilesAvailable) + * @param userData user data to be returned with the result + * @param game the game with which the mods are associated + * @return int an id to identify the request + */ + int requestToggleTracking(QString gameName, int modID, bool track, QObject* receiver, + QVariant userData, const QString& subModule, + MOBase::IPluginGame const* game); /** - * - */ - int requestInfoFromMd5(QString gameName, QByteArray &hash, QObject *receiver, QVariant userData, const QString &subModule) + * + */ + int requestInfoFromMd5(QString gameName, QByteArray& hash, QObject* receiver, + QVariant userData, const QString& subModule) { - return requestInfoFromMd5(gameName, hash, receiver, userData, subModule, getGame(gameName)); + return requestInfoFromMd5(gameName, hash, receiver, userData, subModule, + getGame(gameName)); } /** * */ - int requestInfoFromMd5(QString gameName, QByteArray &hash, QObject *receiver, QVariant userData, const QString &subModule, - MOBase::IPluginGame const *game); + int requestInfoFromMd5(QString gameName, QByteArray& hash, QObject* receiver, + QVariant userData, const QString& subModule, + MOBase::IPluginGame const* game); /** * @param directory the directory to store cache files **/ - void setCacheDirectory(const QString &directory); + void setCacheDirectory(const QString& directory); /** - * @brief called when the log-in completes. This was, requests waiting for the log-in can be run + * @brief called when the log-in completes. This was, requests waiting for the log-in + * can be run */ void loginCompleted(); - std::vector<std::pair<QString, QString>> getGameChoices(const MOBase::IPluginGame *game); + std::vector<std::pair<QString, QString>> + getGameChoices(const MOBase::IPluginGame* game); APIUserAccount getAPIUserAccount() const; APIStats getAPIStats() const; public: - /** * @brief guess the mod id from a filename as delivered by Nexus * @param fileName name of the file * @return the guessed mod id - * @note this currently doesn't fit well with the remaining interface but this is the best place for the function + * @note this currently doesn't fit well with the remaining interface but this is the + * best place for the function */ - static void interpretNexusFileName(const QString &fileName, QString &modName, int &modID, bool query); + static void interpretNexusFileName(const QString& fileName, QString& modName, + int& modID, bool query); /** * @brief get the currently managed game */ - MOBase::IPluginGame const *managedGame() const; + MOBase::IPluginGame const* managedGame() const; /** * @brief see if the passed URL is related to the current game * * Arguably, this should optionally take a gameplugin pointer */ - bool isURLGameRelated(QUrl const &url) const; + bool isURLGameRelated(QUrl const& url) const; /** * @brief Get the nexus page for the current game @@ -457,29 +520,40 @@ public: * @param url * @return */ - bool isModURL(int modID, QString const &url) const; + bool isModURL(int modID, QString const& url) const; - void setPluginContainer(PluginContainer *pluginContainer); + void setPluginContainer(PluginContainer* pluginContainer); signals: - void requestNXMDownload(const QString &url); + void requestNXMDownload(const QString& url); void needLogin(); - void nxmDescriptionAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID); - void nxmModInfoAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID); - void nxmUpdateInfoAvailable(QString gameName, QVariant userData, QVariant resultData, int requestID); - void nxmUpdatesAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID); - void nxmFilesAvailable(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID); - void nxmFileInfoAvailable(QString gameName, int modID, int fileID, QVariant userData, QVariant resultData, int requestID); - void nxmFileInfoFromMd5Available(QString gameName, QVariant userData, QVariant resultData, int requestID); - void nxmDownloadURLsAvailable(QString gameName, int modID, int fileID, QVariant userData, QVariant resultData, int requestID); + void nxmDescriptionAvailable(QString gameName, int modID, QVariant userData, + QVariant resultData, int requestID); + void nxmModInfoAvailable(QString gameName, int modID, QVariant userData, + QVariant resultData, int requestID); + void nxmUpdateInfoAvailable(QString gameName, QVariant userData, QVariant resultData, + int requestID); + void nxmUpdatesAvailable(QString gameName, int modID, QVariant userData, + QVariant resultData, int requestID); + void nxmFilesAvailable(QString gameName, int modID, QVariant userData, + QVariant resultData, int requestID); + void nxmFileInfoAvailable(QString gameName, int modID, int fileID, QVariant userData, + QVariant resultData, int requestID); + void nxmFileInfoFromMd5Available(QString gameName, QVariant userData, + QVariant resultData, int requestID); + void nxmDownloadURLsAvailable(QString gameName, int modID, int fileID, + QVariant userData, QVariant resultData, int requestID); void nxmEndorsementsAvailable(QVariant userData, QVariant resultData, int requestID); - void nxmEndorsementToggled(QString gameName, int modID, QVariant userData, QVariant resultData, int requestID); + void nxmEndorsementToggled(QString gameName, int modID, QVariant userData, + QVariant resultData, int requestID); void nxmTrackedModsAvailable(QVariant userData, QVariant resultData, int requestID); - void nxmTrackingToggled(QString gameName, int modID, QVariant userData, bool tracked, int requestID); - void nxmRequestFailed(QString gameName, int modID, int fileID, QVariant userData, int requestID, int errorCode, const QString &errorString); + void nxmTrackingToggled(QString gameName, int modID, QVariant userData, bool tracked, + int requestID); + void nxmRequestFailed(QString gameName, int modID, int fileID, QVariant userData, + int requestID, int errorCode, const QString& errorString); void requestsChanged(const APIStats& stats, const APIUserAccount& user); public slots: @@ -492,19 +566,20 @@ private slots: void requestError(QNetworkReply::NetworkError error); void requestTimeout(); - void downloadRequestedNXM(const QString &url); + void downloadRequestedNXM(const QString& url); void fakeFiles(); private: - - struct NXMRequestInfo { + struct NXMRequestInfo + { int m_ModID; QString m_ModVersion; std::vector<int> m_ModIDList; int m_FileID; - QNetworkReply *m_Reply; - enum Type { + QNetworkReply* m_Reply; + enum Type + { TYPE_DESCRIPTION, TYPE_MODINFO, TYPE_FILES, @@ -520,7 +595,7 @@ private: } m_Type; UpdatePeriod m_UpdatePeriod; QVariant m_UserData; - QTimer *m_Timeout; + QTimer* m_Timeout; QString m_URL; QString m_SubModule; QString m_GameName; @@ -530,15 +605,20 @@ private: int m_Endorse; int m_Track; QByteArray m_Hash; - QMap<QNetworkReply::NetworkError,QList<int>> m_AllowedErrors; + QMap<QNetworkReply::NetworkError, QList<int>> m_AllowedErrors; bool m_IgnoreGenericErrorHandler; - NXMRequestInfo(int modID, Type type, QVariant userData, const QString &subModule, MOBase::IPluginGame const *game); - NXMRequestInfo(int modID, QString modVersion, Type type, QVariant userData, const QString &subModule, MOBase::IPluginGame const *game); - NXMRequestInfo(int modID, int fileID, Type type, QVariant userData, const QString &subModule, MOBase::IPluginGame const *game); - NXMRequestInfo(Type type, QVariant userData, const QString &subModule); - NXMRequestInfo(UpdatePeriod period, Type type, QVariant userData, const QString &subModule, MOBase::IPluginGame const *game); - NXMRequestInfo(QByteArray &hash, Type type, QVariant userData, const QString &subModule, MOBase::IPluginGame const *game); + NXMRequestInfo(int modID, Type type, QVariant userData, const QString& subModule, + MOBase::IPluginGame const* game); + NXMRequestInfo(int modID, QString modVersion, Type type, QVariant userData, + const QString& subModule, MOBase::IPluginGame const* game); + NXMRequestInfo(int modID, int fileID, Type type, QVariant userData, + const QString& subModule, MOBase::IPluginGame const* game); + NXMRequestInfo(Type type, QVariant userData, const QString& subModule); + NXMRequestInfo(UpdatePeriod period, Type type, QVariant userData, + const QString& subModule, MOBase::IPluginGame const* game); + NXMRequestInfo(QByteArray& hash, Type type, QVariant userData, + const QString& subModule, MOBase::IPluginGame const* game); private: static QAtomicInt s_NextID; @@ -549,17 +629,17 @@ private: private: void nextRequest(); void requestFinished(std::list<NXMRequestInfo>::iterator iter); - MOBase::IPluginGame *getGame(QString gameName) const; + MOBase::IPluginGame* getGame(QString gameName) const; QString getOldModsURL(QString gameName) const; private: - QNetworkDiskCache *m_DiskCache; - NXMAccessManager *m_AccessManager; + QNetworkDiskCache* m_DiskCache; + NXMAccessManager* m_AccessManager; std::list<NXMRequestInfo> m_ActiveRequest; QQueue<NXMRequestInfo> m_RequestQueue; MOBase::VersionInfo m_MOVersion; - PluginContainer *m_PluginContainer; + PluginContainer* m_PluginContainer; APIUserAccount m_User; }; -#endif // NEXUSINTERFACE_H +#endif // NEXUSINTERFACE_H diff --git a/src/noeditdelegate.cpp b/src/noeditdelegate.cpp index 671fa427..3e0ebcb0 100644 --- a/src/noeditdelegate.cpp +++ b/src/noeditdelegate.cpp @@ -1,10 +1,9 @@ #include "noeditdelegate.h" -NoEditDelegate::NoEditDelegate(QObject *parent) - : QStyledItemDelegate(parent) -{ -} +NoEditDelegate::NoEditDelegate(QObject* parent) : QStyledItemDelegate(parent) {} -QWidget *NoEditDelegate::createEditor(QWidget*, const QStyleOptionViewItem&, const QModelIndex&) const { +QWidget* NoEditDelegate::createEditor(QWidget*, const QStyleOptionViewItem&, + const QModelIndex&) const +{ return nullptr; } diff --git a/src/noeditdelegate.h b/src/noeditdelegate.h index ff9baa46..88d48aa4 100644 --- a/src/noeditdelegate.h +++ b/src/noeditdelegate.h @@ -3,10 +3,12 @@ #include <QStyledItemDelegate> -class NoEditDelegate: public QStyledItemDelegate { +class NoEditDelegate : public QStyledItemDelegate +{ public: - NoEditDelegate(QObject *parent = nullptr); - virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; + NoEditDelegate(QObject* parent = nullptr); + virtual QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, + const QModelIndex& index) const; }; -#endif // NOEDITDELEGATE_H +#endif // NOEDITDELEGATE_H diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp index f98f2171..3efdcda0 100644 --- a/src/nxmaccessmanager.cpp +++ b/src/nxmaccessmanager.cpp @@ -21,40 +21,44 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "iplugingame.h" #include "nexusinterface.h" #include "nxmurl.h" +#include "persistentcookiejar.h" #include "report.h" -#include "utility.h" #include "selfupdater.h" -#include "persistentcookiejar.h" #include "settings.h" +#include "utility.h" +#include <QCoreApplication> +#include <QDir> +#include <QJsonArray> +#include <QJsonDocument> #include <QMessageBox> -#include <QPushButton> -#include <QNetworkProxy> -#include <QNetworkRequest> #include <QNetworkCookie> #include <QNetworkCookieJar> -#include <QCoreApplication> -#include <QDir> -#include <QUrlQuery> +#include <QNetworkProxy> +#include <QNetworkRequest> +#include <QPushButton> #include <QThread> -#include <QJsonDocument> -#include <QJsonArray> +#include <QUrlQuery> using namespace MOBase; using namespace std::chrono_literals; const QString NexusBaseUrl("https://api.nexusmods.com/v1"); const QString NexusSSO("wss://sso.nexusmods.com"); -const QString NexusSSOPage("https://www.nexusmods.com/sso?id=%1&application=modorganizer2"); - +const QString + NexusSSOPage("https://www.nexusmods.com/sso?id=%1&application=modorganizer2"); ValidationProgressDialog::ValidationProgressDialog(Settings* s, NexusKeyValidator& v) - : m_settings(s), m_validator(v), m_updateTimer(nullptr), m_first(true) + : m_settings(s), m_validator(v), m_updateTimer(nullptr), m_first(true) { ui.reset(new Ui::ValidationProgressDialog); ui->setupUi(this); - connect(ui->hide, &QPushButton::clicked, [&]{ onHide(); }); - connect(ui->cancel, &QPushButton::clicked, [&]{ onCancel(); }); + connect(ui->hide, &QPushButton::clicked, [&] { + onHide(); + }); + connect(ui->cancel, &QPushButton::clicked, [&] { + onCancel(); + }); } void ValidationProgressDialog::setParentWidget(QWidget* w) @@ -75,7 +79,9 @@ void ValidationProgressDialog::start() { if (!m_updateTimer) { m_updateTimer = new QTimer(this); - connect(m_updateTimer, &QTimer::timeout, [&]{ onTimer(); }); + connect(m_updateTimer, &QTimer::timeout, [&] { + onTimer(); + }); m_updateTimer->setInterval(100ms); } @@ -138,7 +144,7 @@ void ValidationProgressDialog::updateProgress() ui->progress->setRange(0, 0); } - if (const auto* a=m_validator.lastAttempt()) { + if (const auto* a = m_validator.lastAttempt()) { ui->label->setText(a->message() + ". " + tr("Trying again...")); } else if (current) { ui->label->setText(tr("Connecting to Nexus...")); @@ -147,77 +153,74 @@ void ValidationProgressDialog::updateProgress() } } - -NexusSSOLogin::NexusSSOLogin() - : m_keyReceived(false), m_active(false) +NexusSSOLogin::NexusSSOLogin() : m_keyReceived(false), m_active(false) { m_timeout.setInterval(10s); m_timeout.setSingleShot(true); - QObject::connect( - &m_socket, &QWebSocket::connected, - [&]{ onConnected(); }); + QObject::connect(&m_socket, &QWebSocket::connected, [&] { + onConnected(); + }); - QObject::connect( - &m_socket, qOverload<QAbstractSocket::SocketError>(&QWebSocket::error), - [&](auto&& e){ onError(e); }); + QObject::connect(&m_socket, + qOverload<QAbstractSocket::SocketError>(&QWebSocket::error), + [&](auto&& e) { + onError(e); + }); - QObject::connect( - &m_socket, &QWebSocket::sslErrors, - [&](auto&& errors){ onSslErrors(errors); }); + QObject::connect(&m_socket, &QWebSocket::sslErrors, [&](auto&& errors) { + onSslErrors(errors); + }); - QObject::connect( - &m_socket, &QWebSocket::textMessageReceived, - [&](auto&& s){ onMessage(s); }); + QObject::connect(&m_socket, &QWebSocket::textMessageReceived, [&](auto&& s) { + onMessage(s); + }); - QObject::connect( - &m_socket, &QWebSocket::disconnected, - [&]{ onDisconnected(); }); + QObject::connect(&m_socket, &QWebSocket::disconnected, [&] { + onDisconnected(); + }); - QObject::connect(&m_timeout, &QTimer::timeout, [&]{ onTimeout(); }); + QObject::connect(&m_timeout, &QTimer::timeout, [&] { + onTimeout(); + }); } QString NexusSSOLogin::stateToString(States s, const QString& e) { - switch (s) - { - case ConnectingToSSO: - return QObject::tr("Connecting to Nexus..."); + switch (s) { + case ConnectingToSSO: + return QObject::tr("Connecting to Nexus..."); - case WaitingForToken: - return QObject::tr("Waiting for Nexus..."); + case WaitingForToken: + return QObject::tr("Waiting for Nexus..."); - case WaitingForBrowser: - return - QObject::tr("Opened Nexus in browser.") + "\n" + - QObject::tr("Switch to your browser and accept the request."); + case WaitingForBrowser: + return QObject::tr("Opened Nexus in browser.") + "\n" + + QObject::tr("Switch to your browser and accept the request."); - case Finished: - return QObject::tr("Finished."); + case Finished: + return QObject::tr("Finished."); - case Timeout: - return - QObject::tr("No answer from Nexus.") + "\n" + - QObject::tr("A firewall might be blocking Mod Organizer."); + case Timeout: + return QObject::tr("No answer from Nexus.") + "\n" + + QObject::tr("A firewall might be blocking Mod Organizer."); - case ClosedByRemote: - return - QObject::tr("Nexus closed the connection.") + "\n" + - QObject::tr("A firewall might be blocking Mod Organizer."); + case ClosedByRemote: + return QObject::tr("Nexus closed the connection.") + "\n" + + QObject::tr("A firewall might be blocking Mod Organizer."); - case Cancelled: - return QObject::tr("Cancelled."); + case Cancelled: + return QObject::tr("Cancelled."); - case Error: // fall-through - default: - { - if (e.isEmpty()) { - return QString("%1").arg(s); - } else { - return e; - } + case Error: // fall-through + default: { + if (e.isEmpty()) { + return QString("%1").arg(s); + } else { + return e; } } + } } void NexusSSOLogin::start() @@ -272,7 +275,7 @@ void NexusSSOLogin::onConnected() boost::uuids::random_generator generator; boost::uuids::uuid sessionId = generator(); - m_guid = boost::uuids::to_string(sessionId).c_str(); + m_guid = boost::uuids::to_string(sessionId).c_str(); QJsonObject data; data.insert(QString("id"), QJsonValue(m_guid)); @@ -285,13 +288,13 @@ void NexusSSOLogin::onConnected() void NexusSSOLogin::onMessage(const QString& s) { const QJsonDocument doc = QJsonDocument::fromJson(s.toUtf8()); - const QVariantMap root = doc.object().toVariantMap(); + const QVariantMap root = doc.object().toVariantMap(); if (!root["success"].toBool()) { close(); setState(Error, QString("There was a problem with SSO initialization: %1") - .arg(root["error"].toString())); + .arg(root["error"].toString())); return; } @@ -355,14 +358,15 @@ void NexusSSOLogin::onTimeout() setState(Timeout); } - ValidationAttempt::ValidationAttempt(std::chrono::seconds timeout) - : m_reply(nullptr), m_result(None) + : m_reply(nullptr), m_result(None) { m_timeout.setSingleShot(true); m_timeout.setInterval(timeout); - QObject::connect(&m_timeout, &QTimer::timeout, [&]{ onTimeout(); }); + QObject::connect(&m_timeout, &QTimer::timeout, [&] { + onTimeout(); + }); } void ValidationAttempt::start(NXMAccessManager& m, const QString& key) @@ -374,19 +378,19 @@ void ValidationAttempt::start(NXMAccessManager& m, const QString& key) m_elapsed.start(); m_timeout.start(); - log::debug( - "nexus: attempt started with timeout of {} seconds", timeout().count()); + log::debug("nexus: attempt started with timeout of {} seconds", timeout().count()); } -bool ValidationAttempt::sendRequest( - NXMAccessManager& m, const QString& key) +bool ValidationAttempt::sendRequest(NXMAccessManager& m, const QString& key) { const QString requestUrl(NexusBaseUrl + "/users/validate"); QNetworkRequest request(requestUrl); request.setRawHeader("APIKEY", key.toUtf8()); - request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, m.userAgent().toUtf8()); - request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json"); + request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, + m.userAgent().toUtf8()); + request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, + "application/json"); request.setRawHeader("Protocol-Version", "1.0.0"); request.setRawHeader("Application-Name", "MO2"); request.setRawHeader("Application-Version", m.MOVersion().toUtf8()); @@ -398,13 +402,13 @@ bool ValidationAttempt::sendRequest( return false; } - QObject::connect( - m_reply, &QNetworkReply::finished, - [&]{ onFinished(); }); + QObject::connect(m_reply, &QNetworkReply::finished, [&] { + onFinished(); + }); - QObject::connect( - m_reply, &QNetworkReply::sslErrors, - [&](auto&& errors){ onSslErrors(errors); }); + QObject::connect(m_reply, &QNetworkReply::sslErrors, [&](auto&& errors) { + onSslErrors(errors); + }); return true; } @@ -443,7 +447,7 @@ const QString& ValidationAttempt::message() const std::chrono::seconds ValidationAttempt::timeout() const { return std::chrono::duration_cast<std::chrono::seconds>( - m_timeout.intervalAsDuration()); + m_timeout.intervalAsDuration()); } QElapsedTimer ValidationAttempt::elapsed() const @@ -466,8 +470,8 @@ void ValidationAttempt::onFinished() return; } - const auto code = m_reply->attribute( - QNetworkRequest::HttpStatusCodeAttribute).toInt(); + const auto code = + m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); if (code == 0) { // request wasn't even sent @@ -476,8 +480,8 @@ void ValidationAttempt::onFinished() return; } - const auto doc = QJsonDocument::fromJson(m_reply->readAll()); - const auto headers = m_reply->rawHeaderPairs(); + const auto doc = QJsonDocument::fromJson(m_reply->readAll()); + const auto headers = m_reply->rawHeaderPairs(); const auto httpError = m_reply->errorString(); const QJsonObject data = doc.object(); @@ -516,8 +520,8 @@ void ValidationAttempt::onFinished() return; } - const int id = data.value("user_id").toInt(); - const QString key = data.value("key").toString(); + const int id = data.value("user_id").toInt(); + const QString key = data.value("key").toString(); const QString name = data.value("name").toString(); const bool premium = data.value("is_premium").toBool(); @@ -526,12 +530,13 @@ void ValidationAttempt::onFinished() return; } - const auto user = APIUserAccount() - .apiKey(key) - .id(QString("%1").arg(id)) - .name(name) - .type(premium ? APIUserAccountTypes::Premium : APIUserAccountTypes::Regular) - .limits(NexusInterface::parseLimits(headers)); + const auto user = + APIUserAccount() + .apiKey(key) + .id(QString("%1").arg(id)) + .name(name) + .type(premium ? APIUserAccountTypes::Premium : APIUserAccountTypes::Regular) + .limits(NexusInterface::parseLimits(headers)); setSuccess(user); } @@ -561,7 +566,7 @@ void ValidationAttempt::setFailure(Result r, const QString& error) cleanup(); - m_result = r; + m_result = r; m_message = error; if (failure) { @@ -574,7 +579,7 @@ void ValidationAttempt::setSuccess(const APIUserAccount& user) log::debug("nexus connection successful"); cleanup(); - m_result = Success; + m_result = Success; m_message = ""; if (success) { @@ -593,11 +598,9 @@ void ValidationAttempt::cleanup() } } - NexusKeyValidator::NexusKeyValidator(Settings* s, NXMAccessManager& am) - : m_settings(s), m_manager(am) -{ -} + : m_settings(s), m_manager(am) +{} NexusKeyValidator::~NexusKeyValidator() { @@ -624,26 +627,23 @@ void NexusKeyValidator::start(const QString& key, Behaviour b) const auto timeouts = getTimeouts(); - switch (b) - { - case OneShot: - { - createAttempts({timeouts[0]}); - break; - } + switch (b) { + case OneShot: { + createAttempts({timeouts[0]}); + break; + } - case Retry: - { - createAttempts(timeouts); - break; - } + case Retry: { + createAttempts(timeouts); + break; + } } nextTry(); } void NexusKeyValidator::createAttempts( - const std::vector<std::chrono::seconds>& timeouts) + const std::vector<std::chrono::seconds>& timeouts) { m_attempts.clear(); @@ -702,8 +702,12 @@ bool NexusKeyValidator::nextTry() { for (auto&& a : m_attempts) { if (!a->done()) { - a->success = [&](auto&& user){ onAttemptSuccess(*a, user); }; - a->failure = [&]{ onAttemptFailure(*a); }; + a->success = [&](auto&& user) { + onAttemptSuccess(*a, user); + }; + a->failure = [&] { + onAttemptFailure(*a); + }; a->start(m_manager, m_key); return true; @@ -714,8 +718,8 @@ bool NexusKeyValidator::nextTry() return false; } -void NexusKeyValidator::onAttemptSuccess( - const ValidationAttempt& a, const APIUserAccount& u) +void NexusKeyValidator::onAttemptSuccess(const ValidationAttempt& a, + const APIUserAccount& u) { if (attemptFinished) { attemptFinished(a); @@ -730,48 +734,40 @@ void NexusKeyValidator::onAttemptFailure(const ValidationAttempt& a) attemptFinished(a); } - switch (a.result()) - { - case ValidationAttempt::SoftError: - { - if (!nextTry()) { - setFinished(a.result(), a.message(), {}); - } - - break; - } - - case ValidationAttempt::HardError: - { - cancel(); + switch (a.result()) { + case ValidationAttempt::SoftError: { + if (!nextTry()) { setFinished(a.result(), a.message(), {}); - break; } - case ValidationAttempt::Cancelled: - { - setFinished(ValidationAttempt::Cancelled, QObject::tr("Cancelled"), {}); - break; - } + break; + } + + case ValidationAttempt::HardError: { + cancel(); + setFinished(a.result(), a.message(), {}); + break; + } + + case ValidationAttempt::Cancelled: { + setFinished(ValidationAttempt::Cancelled, QObject::tr("Cancelled"), {}); + break; + } } } -void NexusKeyValidator::setFinished( - ValidationAttempt::Result r, const QString& message, - std::optional<APIUserAccount> user) +void NexusKeyValidator::setFinished(ValidationAttempt::Result r, const QString& message, + std::optional<APIUserAccount> user) { if (finished) { finished(r, message, user); } } - -NXMAccessManager::NXMAccessManager(QObject *parent, Settings* s, const QString &moVersion) - : QNetworkAccessManager(parent) - , m_Settings(s) - , m_MOVersion(moVersion) - , m_validator(s, *this) - , m_validationState(NotChecked) +NXMAccessManager::NXMAccessManager(QObject* parent, Settings* s, + const QString& moVersion) + : QNetworkAccessManager(parent), m_Settings(s), m_MOVersion(moVersion), + m_validator(s, *this), m_validationState(NotChecked) { m_validator.finished = [&](auto&& r, auto&& m, auto&& u) { onValidatorFinished(r, m, u); @@ -783,7 +779,7 @@ NXMAccessManager::NXMAccessManager(QObject *parent, Settings* s, const QString & if (m_Settings) { setCookieJar(new PersistentCookieJar(QDir::fromNativeSeparators( - m_Settings->paths().cache() + "/nexus_cookies.dat"))); + m_Settings->paths().cache() + "/nexus_cookies.dat"))); } } @@ -799,9 +795,9 @@ void NXMAccessManager::setTopLevelWidget(QWidget* w) } } -QNetworkReply *NXMAccessManager::createRequest( - QNetworkAccessManager::Operation operation, const QNetworkRequest &request, - QIODevice *device) +QNetworkReply* +NXMAccessManager::createRequest(QNetworkAccessManager::Operation operation, + const QNetworkRequest& request, QIODevice* device) { if (request.url().scheme() != "nxm") { return QNetworkAccessManager::createRequest(operation, request, device); @@ -813,7 +809,8 @@ QNetworkReply *NXMAccessManager::createRequest( return QNetworkAccessManager::createRequest(QNetworkAccessManager::GetOperation, QNetworkRequest(QUrl())); } else if (operation == PostOperation) { - return QNetworkAccessManager::createRequest(operation, request, device);; + return QNetworkAccessManager::createRequest(operation, request, device); + ; } else { return QNetworkAccessManager::createRequest(operation, request, device); } @@ -822,16 +819,15 @@ QNetworkReply *NXMAccessManager::createRequest( void NXMAccessManager::showCookies() const { QUrl url(NexusBaseUrl + "/"); - for (const QNetworkCookie &cookie : cookieJar()->cookiesForUrl(url)) { - log::debug("{} - {} (expires: {})", - cookie.name().constData(), cookie.value().constData(), - cookie.expirationDate().toString()); + for (const QNetworkCookie& cookie : cookieJar()->cookiesForUrl(url)) { + log::debug("{} - {} (expires: {})", cookie.name().constData(), + cookie.value().constData(), cookie.expirationDate().toString()); } } void NXMAccessManager::clearCookies() { - PersistentCookieJar *jar = qobject_cast<PersistentCookieJar*>(cookieJar()); + PersistentCookieJar* jar = qobject_cast<PersistentCookieJar*>(cookieJar()); if (jar != nullptr) { jar->clear(); } else { @@ -851,9 +847,9 @@ void NXMAccessManager::startValidationCheck(const QString& key) } } -void NXMAccessManager::onValidatorFinished( - ValidationAttempt::Result r, const QString& message, - std::optional<APIUserAccount> user) +void NXMAccessManager::onValidatorFinished(ValidationAttempt::Result r, + const QString& message, + std::optional<APIUserAccount> user) { stopProgress(); @@ -874,23 +870,20 @@ void NXMAccessManager::onValidatorFinished( void NXMAccessManager::onValidatorAttemptFinished(const ValidationAttempt& a) { if (!m_ProgressDialog) { - switch (a.result()) - { - case ValidationAttempt::SoftError: - case ValidationAttempt::HardError: - { - startProgress(); - break; - } + switch (a.result()) { + case ValidationAttempt::SoftError: + case ValidationAttempt::HardError: { + startProgress(); + break; + } - case ValidationAttempt::None: - case ValidationAttempt::Success: - case ValidationAttempt::Cancelled: - default: - { - // don't show the dialog - break; - } + case ValidationAttempt::None: + case ValidationAttempt::Success: + case ValidationAttempt::Cancelled: + default: { + // don't show the dialog + break; + } } } } @@ -923,7 +916,7 @@ bool NXMAccessManager::validateWaiting() const return m_validator.isActive(); } -void NXMAccessManager::apiCheck(const QString &apiKey, bool force) +void NXMAccessManager::apiCheck(const QString& apiKey, bool force) { if (m_validator.isActive()) { return; @@ -951,21 +944,24 @@ const QString& NXMAccessManager::MOVersion() const return m_MOVersion; } -QString NXMAccessManager::userAgent(const QString &subModule) const +QString NXMAccessManager::userAgent(const QString& subModule) const { QStringList comments; QString os; if (QSysInfo::productType() == "windows") - comments << ((QSysInfo::kernelType() == "winnt") ? "Windows_NT " : "Windows ") + QSysInfo::kernelVersion(); + comments << ((QSysInfo::kernelType() == "winnt") ? "Windows_NT " : "Windows ") + + QSysInfo::kernelVersion(); else comments << QSysInfo::kernelType().left(1).toUpper() + QSysInfo::kernelType().mid(1) - << QSysInfo::productType().left(1).toUpper() + QSysInfo::kernelType().mid(1) + " " + QSysInfo::productVersion(); + << QSysInfo::productType().left(1).toUpper() + + QSysInfo::kernelType().mid(1) + " " + QSysInfo::productVersion(); if (!subModule.isEmpty()) { comments << "module: " + subModule; } comments << ((QSysInfo::buildCpuArchitecture() == "x86_64") ? "x64" : "x86"); - return QString("Mod Organizer/%1 (%2) Qt/%3").arg(m_MOVersion, comments.join("; "), qVersion()); + return QString("Mod Organizer/%1 (%2) Qt/%3") + .arg(m_MOVersion, comments.join("; "), qVersion()); } void NXMAccessManager::clearApiKey() diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h index 0812be40..79371a45 100644 --- a/src/nxmaccessmanager.h +++ b/src/nxmaccessmanager.h @@ -22,16 +22,19 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "apiuseraccount.h" #include "ui_validationprogressdialog.h" +#include <QDialogButtonBox> +#include <QElapsedTimer> #include <QNetworkAccessManager> -#include <QTimer> #include <QNetworkReply> #include <QProgressDialog> -#include <QElapsedTimer> -#include <QDialogButtonBox> +#include <QTimer> #include <QWebSocket> #include <set> -namespace MOBase { class IPluginGame; } +namespace MOBase +{ +class IPluginGame; +} class NXMAccessManager; class Settings; @@ -50,8 +53,8 @@ public: Error }; - std::function<void (QString)> keyChanged; - std::function<void (States, QString)> stateChanged; + std::function<void(QString)> keyChanged; + std::function<void(States, QString)> stateChanged; static QString stateToString(States s, const QString& e); @@ -69,7 +72,7 @@ private: bool m_active; QTimer m_timeout; - void setState(States s, const QString& error={}); + void setState(States s, const QString& error = {}); void close(); void abort(); @@ -82,7 +85,6 @@ private: void onTimeout(); }; - class ValidationAttempt { public: @@ -95,11 +97,11 @@ public: Cancelled }; - std::function<void (APIUserAccount)> success; - std::function<void ()> failure; + std::function<void(APIUserAccount)> success; + std::function<void()> failure; ValidationAttempt(std::chrono::seconds timeout); - ValidationAttempt(const ValidationAttempt&) = delete; + ValidationAttempt(const ValidationAttempt&) = delete; ValidationAttempt& operator=(const ValidationAttempt&) = delete; void start(NXMAccessManager& m, const QString& key); @@ -130,7 +132,6 @@ private: void cleanup(); }; - class NexusKeyValidator { public: @@ -140,12 +141,11 @@ public: Retry }; - using FinishedCallback = void ( - ValidationAttempt::Result, const QString&, - std::optional<APIUserAccount>); + using FinishedCallback = void(ValidationAttempt::Result, const QString&, + std::optional<APIUserAccount>); std::function<FinishedCallback> finished; - std::function<void (const ValidationAttempt&)> attemptFinished; + std::function<void(const ValidationAttempt&)> attemptFinished; NexusKeyValidator(Settings* s, NXMAccessManager& am); ~NexusKeyValidator(); @@ -170,12 +170,10 @@ private: void onAttemptSuccess(const ValidationAttempt& a, const APIUserAccount& u); void onAttemptFailure(const ValidationAttempt& a); - void setFinished( - ValidationAttempt::Result r, const QString& message, - std::optional<APIUserAccount> user); + void setFinished(ValidationAttempt::Result r, const QString& message, + std::optional<APIUserAccount> user); }; - class ValidationProgressDialog : public QDialog { Q_OBJECT; @@ -205,7 +203,6 @@ private: void updateProgress(); }; - /** * @brief access manager extended to handle nxm links **/ @@ -213,7 +210,7 @@ class NXMAccessManager : public QNetworkAccessManager { Q_OBJECT public: - NXMAccessManager(QObject *parent, Settings* s, const QString &moVersion); + NXMAccessManager(QObject* parent, Settings* s, const QString& moVersion); void setTopLevelWidget(QWidget* w); @@ -222,13 +219,13 @@ public: bool validateAttempted() const; bool validateWaiting() const; - void apiCheck(const QString &apiKey, bool force=false); + void apiCheck(const QString& apiKey, bool force = false); void showCookies() const; void clearCookies(); - QString userAgent(const QString &subModule = QString()) const; + QString userAgent(const QString& subModule = QString()) const; const QString& MOVersion() const; void clearApiKey(); @@ -242,22 +239,22 @@ signals: * * @param url the nxm-link **/ - void requestNXMDownload(const QString &url); + void requestNXMDownload(const QString& url); /** * @brief emitted after a successful login or if login was not necessary * - * @param necessary true if a login was necessary and succeeded, false if the user is still logged in + * @param necessary true if a login was necessary and succeeded, false if the user is + *still logged in **/ void validateSuccessful(bool necessary); - void validateFailed(const QString &message); + void validateFailed(const QString& message); void credentialsReceived(const APIUserAccount& user); protected: - - virtual QNetworkReply *createRequest( - QNetworkAccessManager::Operation operation, const QNetworkRequest &request, - QIODevice *device); + virtual QNetworkReply* createRequest(QNetworkAccessManager::Operation operation, + const QNetworkRequest& request, + QIODevice* device); private: enum States @@ -276,9 +273,8 @@ private: void startValidationCheck(const QString& key); - void onValidatorFinished( - ValidationAttempt::Result r, const QString& message, - std::optional<APIUserAccount>); + void onValidatorFinished(ValidationAttempt::Result r, const QString& message, + std::optional<APIUserAccount>); void onValidatorAttemptFinished(const ValidationAttempt& a); @@ -286,4 +282,4 @@ private: void stopProgress(); }; -#endif // NXMACCESSMANAGER_H +#endif // NXMACCESSMANAGER_H diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 3a959cb3..e7b0c748 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1,42 +1,42 @@ #include "organizercore.h" +#include "credentialsdialog.h" #include "delayedfilewriter.h" +#include "directoryrefresher.h" +#include "env.h" +#include "envfs.h" +#include "envmodule.h" +#include "filedialogmemory.h" #include "guessedvalue.h" #include "imodinterface.h" #include "imoinfo.h" +#include "instancemanager.h" #include "iplugingame.h" #include "iuserinterface.h" #include "messagedialog.h" #include "modlistsortproxy.h" #include "modrepositoryfileinfo.h" #include "nexusinterface.h" +#include "nxmaccessmanager.h" #include "plugincontainer.h" +#include "previewdialog.h" #include "profile.h" -#include "credentialsdialog.h" -#include "filedialogmemory.h" +#include "shared/appconfig.h" +#include "shared/directoryentry.h" +#include "shared/fileentry.h" +#include "shared/filesorigin.h" +#include "shared/util.h" #include "spawn.h" #include "syncoverwritedialog.h" -#include "nxmaccessmanager.h" -#include <ipluginmodpage.h> +#include "virtualfiletree.h" #include <dataarchives.h> +#include <ipluginmodpage.h> #include <localsavegames.h> -#include <scopeguard.h> -#include <utility.h> -#include <usvfs.h> -#include "shared/appconfig.h" -#include <report.h> #include <questionboxmemory.h> -#include "instancemanager.h" +#include <report.h> +#include <scopeguard.h> #include <scriptextender.h> -#include "previewdialog.h" -#include "env.h" -#include "envmodule.h" -#include "envfs.h" -#include "directoryrefresher.h" -#include "virtualfiletree.h" -#include "shared/directoryentry.h" -#include "shared/filesorigin.h" -#include "shared/fileentry.h" -#include "shared/util.h" +#include <usvfs.h> +#include <utility.h> #include <QApplication> #include <QCoreApplication> @@ -50,23 +50,23 @@ #include <QWidget> #include <QtDebug> -#include <QtGlobal> // for qUtf8Printable, etc +#include <QtGlobal> // for qUtf8Printable, etc #include <Psapi.h> #include <Shlobj.h> +#include <tchar.h> // for _tcsicmp #include <tlhelp32.h> -#include <tchar.h> // for _tcsicmp #include <limits.h> #include <stddef.h> -#include <string.h> // for memset, wcsrchr +#include <string.h> // for memset, wcsrchr +#include <boost/algorithm/string/predicate.hpp> #include <exception> #include <functional> -#include <boost/algorithm/string/predicate.hpp> #include <memory> #include <set> -#include <string> //for wstring +#include <string> //for wstring #include <tuple> #include <utility> @@ -87,22 +87,18 @@ QStringList toStringList(InputIterator current, InputIterator end) return result; } - -OrganizerCore::OrganizerCore(Settings &settings) - : m_UserInterface(nullptr) - , m_PluginContainer(nullptr) - , m_CurrentProfile(nullptr) - , m_Settings(settings) - , m_Updater(&NexusInterface::instance()) - , m_ModList(m_PluginContainer, this) - , m_PluginList(*this) - , m_DirectoryRefresher(new DirectoryRefresher(settings.refreshThreadCount())) - , m_DirectoryStructure(new DirectoryEntry(L"data", nullptr, 0)) - , m_VirtualFileTree([this]() { return VirtualFileTree::makeTree(m_DirectoryStructure); }) - , m_DownloadManager(&NexusInterface::instance(), this) - , m_DirectoryUpdate(false) - , m_ArchivesInit(false) - , m_PluginListsWriter(std::bind(&OrganizerCore::savePluginList, this)) +OrganizerCore::OrganizerCore(Settings& settings) + : m_UserInterface(nullptr), m_PluginContainer(nullptr), m_CurrentProfile(nullptr), + m_Settings(settings), m_Updater(&NexusInterface::instance()), + m_ModList(m_PluginContainer, this), m_PluginList(*this), + m_DirectoryRefresher(new DirectoryRefresher(settings.refreshThreadCount())), + m_DirectoryStructure(new DirectoryEntry(L"data", nullptr, 0)), + m_VirtualFileTree([this]() { + return VirtualFileTree::makeTree(m_DirectoryStructure); + }), + m_DownloadManager(&NexusInterface::instance(), this), m_DirectoryUpdate(false), + m_ArchivesInit(false), + m_PluginListsWriter(std::bind(&OrganizerCore::savePluginList, this)) { env::setHandleCloserThreadCount(settings.refreshThreadCount()); m_DownloadManager.setOutputDirectory(m_Settings.paths().downloads(), false); @@ -117,10 +113,13 @@ OrganizerCore::OrganizerCore(Settings &settings) connect(m_DirectoryRefresher.get(), SIGNAL(refreshed()), this, SLOT(directory_refreshed())); - connect(&m_ModList, SIGNAL(removeOrigin(QString)), this, - SLOT(removeOrigin(QString))); - connect(&m_ModList, &ModList::modStatesChanged, [=] { currentProfile()->writeModlist(); }); - connect(&m_ModList, &ModList::modPrioritiesChanged, [this](auto&& indexes) { modPrioritiesChanged(indexes); }); + connect(&m_ModList, SIGNAL(removeOrigin(QString)), this, SLOT(removeOrigin(QString))); + connect(&m_ModList, &ModList::modStatesChanged, [=] { + currentProfile()->writeModlist(); + }); + connect(&m_ModList, &ModList::modPrioritiesChanged, [this](auto&& indexes) { + modPrioritiesChanged(indexes); + }); connect(NexusInterface::instance().getAccessManager(), SIGNAL(validateSuccessful(bool)), this, SLOT(loginSuccessful(bool))); @@ -128,23 +127,22 @@ OrganizerCore::OrganizerCore(Settings &settings) SIGNAL(validateFailed(QString)), this, SLOT(loginFailed(QString))); // This seems awfully imperative - connect(this, SIGNAL(managedGameChanged(MOBase::IPluginGame const *)), - &m_Settings, SLOT(managedGameChanged(MOBase::IPluginGame const *))); - connect(this, SIGNAL(managedGameChanged(MOBase::IPluginGame const *)), - &m_DownloadManager, - SLOT(managedGameChanged(MOBase::IPluginGame const *))); - connect(this, SIGNAL(managedGameChanged(MOBase::IPluginGame const *)), - &m_PluginList, SLOT(managedGameChanged(MOBase::IPluginGame const *))); + connect(this, SIGNAL(managedGameChanged(MOBase::IPluginGame const*)), &m_Settings, + SLOT(managedGameChanged(MOBase::IPluginGame const*))); + connect(this, SIGNAL(managedGameChanged(MOBase::IPluginGame const*)), + &m_DownloadManager, SLOT(managedGameChanged(MOBase::IPluginGame const*))); + connect(this, SIGNAL(managedGameChanged(MOBase::IPluginGame const*)), &m_PluginList, + SLOT(managedGameChanged(MOBase::IPluginGame const*))); - connect(this, &OrganizerCore::managedGameChanged, [this](IPluginGame const* gamePlugin) { - ModDataContent* contentFeature = gamePlugin->feature<ModDataContent>(); - if (contentFeature) { - m_Contents = ModDataContentHolder(contentFeature->getAllContents()); - } - else { - m_Contents = ModDataContentHolder(); - } - }); + connect(this, &OrganizerCore::managedGameChanged, + [this](IPluginGame const* gamePlugin) { + ModDataContent* contentFeature = gamePlugin->feature<ModDataContent>(); + if (contentFeature) { + m_Contents = ModDataContentHolder(contentFeature->getAllContents()); + } else { + m_Contents = ModDataContentHolder(); + } + }); connect(&m_PluginList, &PluginList::writePluginsList, &m_PluginListsWriter, &DelayedFileWriterBase::write); @@ -153,9 +151,10 @@ OrganizerCore::OrganizerCore(Settings &settings) m_RefresherThread.start(); m_DirectoryRefresher->moveToThread(&m_RefresherThread); - connect(&settings.plugins(), &PluginSettings::pluginSettingChanged, [this](auto const& ...args) { - m_PluginSettingChanged(args...); - }); + connect(&settings.plugins(), &PluginSettings::pluginSettingChanged, + [this](auto const&... args) { + m_PluginSettingChanged(args...); + }); } OrganizerCore::~OrganizerCore() @@ -203,9 +202,9 @@ void OrganizerCore::storeSettings() } QMessageBox::critical( - qApp->activeWindow(), tr("Failed to write settings"), - tr("An error occurred trying to write back MO settings to %1: %2") - .arg(m_Settings.filename(), reason)); + qApp->activeWindow(), tr("Failed to write settings"), + tr("An error occurred trying to write back MO settings to %1: %2") + .arg(m_Settings.filename(), reason)); } } @@ -219,11 +218,11 @@ void OrganizerCore::updateExecutablesList() m_ExecutablesList.load(managedGame(), m_Settings); } -void OrganizerCore::updateModInfoFromDisc() { - ModInfo::updateFromDisc( - m_Settings.paths().mods(), *this, - m_Settings.interface().displayForeign(), - m_Settings.refreshThreadCount()); +void OrganizerCore::updateModInfoFromDisc() +{ + ModInfo::updateFromDisc(m_Settings.paths().mods(), *this, + m_Settings.interface().displayForeign(), + m_Settings.refreshThreadCount()); } void OrganizerCore::setUserInterface(IUserInterface* ui) @@ -254,7 +253,7 @@ void OrganizerCore::checkForUpdates() } } -void OrganizerCore::connectPlugins(PluginContainer *container) +void OrganizerCore::connectPlugins(PluginContainer* container) { m_PluginContainer = container; m_Updater.setPluginContainer(m_PluginContainer); @@ -267,13 +266,15 @@ void OrganizerCore::connectPlugins(PluginContainer *container) emit managedGameChanged(m_GamePlugin); } - connect(m_PluginContainer, &PluginContainer::pluginEnabled, - [&](IPlugin* plugin) { m_PluginEnabled(plugin); }); - connect(m_PluginContainer, &PluginContainer::pluginDisabled, - [&](IPlugin* plugin) { m_PluginDisabled(plugin); }); + connect(m_PluginContainer, &PluginContainer::pluginEnabled, [&](IPlugin* plugin) { + m_PluginEnabled(plugin); + }); + connect(m_PluginContainer, &PluginContainer::pluginDisabled, [&](IPlugin* plugin) { + m_PluginDisabled(plugin); + }); } -void OrganizerCore::setManagedGame(MOBase::IPluginGame *game) +void OrganizerCore::setManagedGame(MOBase::IPluginGame* game) { m_GameName = game->gameName(); m_GamePlugin = game; @@ -281,7 +282,7 @@ void OrganizerCore::setManagedGame(MOBase::IPluginGame *game) emit managedGameChanged(m_GamePlugin); } -Settings &OrganizerCore::settings() +Settings& OrganizerCore::settings() { return m_Settings; } @@ -290,8 +291,7 @@ bool OrganizerCore::nexusApi(bool retry) { auto* accessManager = NexusInterface::instance().getAccessManager(); - if ((accessManager->validateAttempted() || accessManager->validated()) - && !retry) { + if ((accessManager->validateAttempted() || accessManager->validated()) && !retry) { // previous attempt, maybe even successful return false; } else { @@ -312,13 +312,15 @@ bool OrganizerCore::nexusApi(bool retry) void OrganizerCore::startMOUpdate() { if (nexusApi()) { - m_PostLoginTasks.append([&]() { m_Updater.startUpdate(); }); + m_PostLoginTasks.append([&]() { + m_Updater.startUpdate(); + }); } else { m_Updater.startUpdate(); } } -void OrganizerCore::downloadRequestedNXM(const QString &url) +void OrganizerCore::downloadRequestedNXM(const QString& url) { log::debug("download requested: {}", url); if (nexusApi()) { @@ -338,7 +340,8 @@ void OrganizerCore::profileCreated(MOBase::IProfile* profile) m_ProfileCreated(profile); } -void OrganizerCore::profileRenamed(MOBase::IProfile* profile, QString const& oldName, QString const& newName) +void OrganizerCore::profileRenamed(MOBase::IProfile* profile, QString const& oldName, + QString const& newName) { m_ProfileRenamed(profile, oldName, newName); } @@ -348,38 +351,39 @@ void OrganizerCore::profileRemoved(QString const& profileName) m_ProfileRemoved(profileName); } -void OrganizerCore::downloadRequested(QNetworkReply *reply, QString gameName, int modID, - const QString &fileName) +void OrganizerCore::downloadRequested(QNetworkReply* reply, QString gameName, int modID, + const QString& fileName) { try { - if (m_DownloadManager.addDownload(reply, QStringList(), fileName, gameName, modID, 0, - new ModRepositoryFileInfo(gameName, modID))) { + if (m_DownloadManager.addDownload(reply, QStringList(), fileName, gameName, modID, + 0, new ModRepositoryFileInfo(gameName, modID))) { MessageDialog::showMessage(tr("Download started"), qApp->activeWindow()); } - } catch (const std::exception &e) { + } catch (const std::exception& e) { MessageDialog::showMessage(tr("Download failed"), qApp->activeWindow()); log::error("exception starting download: {}", e.what()); } } -void OrganizerCore::removeOrigin(const QString &name) +void OrganizerCore::removeOrigin(const QString& name) { - FilesOrigin &origin = m_DirectoryStructure->getOriginByName(ToWString(name)); + FilesOrigin& origin = m_DirectoryStructure->getOriginByName(ToWString(name)); origin.enable(false); refreshLists(); } -void OrganizerCore::downloadSpeed(const QString &serverName, int bytesPerSecond) +void OrganizerCore::downloadSpeed(const QString& serverName, int bytesPerSecond) { m_Settings.network().setDownloadSpeed(serverName, bytesPerSecond); } -InstallationManager *OrganizerCore::installationManager() +InstallationManager* OrganizerCore::installationManager() { return &m_InstallationManager; } -bool OrganizerCore::createDirectory(const QString &path) { +bool OrganizerCore::createDirectory(const QString& path) +{ if (!QDir(path).exists() && !QDir().mkpath(path)) { QMessageBox::critical(nullptr, QObject::tr("Error"), QObject::tr("Failed to create \"%1\". Your user " @@ -391,17 +395,19 @@ bool OrganizerCore::createDirectory(const QString &path) { } } -bool OrganizerCore::checkPathSymlinks() { - const bool hasSymlink = ( - QFileInfo(m_Settings.paths().profiles()).isSymLink() || - QFileInfo(m_Settings.paths().mods()).isSymLink() || - QFileInfo(m_Settings.paths().overwrite()).isSymLink()); +bool OrganizerCore::checkPathSymlinks() +{ + const bool hasSymlink = (QFileInfo(m_Settings.paths().profiles()).isSymLink() || + QFileInfo(m_Settings.paths().mods()).isSymLink() || + QFileInfo(m_Settings.paths().overwrite()).isSymLink()); if (hasSymlink) { - log::warn("{}", QObject::tr( - "One of the configured MO2 directories (profiles, mods, or overwrite) " - "is on a path containing a symbolic (or other) link. This is likely to " - "be incompatible with MO2's virtual filesystem.")); + log::warn( + "{}", + QObject::tr( + "One of the configured MO2 directories (profiles, mods, or overwrite) " + "is on a path containing a symbolic (or other) link. This is likely to " + "be incompatible with MO2's virtual filesystem.")); return false; } @@ -411,13 +417,9 @@ bool OrganizerCore::checkPathSymlinks() { bool OrganizerCore::bootstrap() { - const auto dirs = { - m_Settings.paths().profiles(), - m_Settings.paths().mods(), - m_Settings.paths().downloads(), - m_Settings.paths().overwrite(), - QString::fromStdWString(getGlobalCoreDumpPath()) - }; + const auto dirs = {m_Settings.paths().profiles(), m_Settings.paths().mods(), + m_Settings.paths().downloads(), m_Settings.paths().overwrite(), + QString::fromStdWString(getGlobalCoreDumpPath())}; for (auto&& dir : dirs) { if (!createDirectory(dir)) { @@ -434,15 +436,13 @@ bool OrganizerCore::bootstrap() } // log if there are any dmp files - const auto hasCrashDumps = - !QDir(QString::fromStdWString(getGlobalCoreDumpPath())) - .entryList({"*.dmp"}, QDir::Files) - .empty(); + const auto hasCrashDumps = !QDir(QString::fromStdWString(getGlobalCoreDumpPath())) + .entryList({"*.dmp"}, QDir::Files) + .empty(); if (hasCrashDumps) { - log::debug( - "there are crash dumps in '{}'", - QString::fromStdWString(getGlobalCoreDumpPath())); + log::debug("there are crash dumps in '{}'", + QString::fromStdWString(getGlobalCoreDumpPath())); } return true; @@ -452,9 +452,8 @@ void OrganizerCore::createDefaultProfile() { QString profilesPath = settings().paths().profiles(); if (QDir(profilesPath).entryList(QDir::AllDirs | QDir::NoDotAndDotDot).size() == 0) { - Profile newProf( - QString::fromStdWString(AppConfig::defaultProfileName()), - managedGame(), false); + Profile newProf(QString::fromStdWString(AppConfig::defaultProfileName()), + managedGame(), false); m_ProfileCreated(&newProf); } @@ -465,15 +464,16 @@ void OrganizerCore::prepareVFS() m_USVFS.updateMapping(fileMapping(m_CurrentProfile->name(), QString())); } -void OrganizerCore::updateVFSParams( - log::Levels logLevel, env::CoreDumpTypes coreDumpType, - const QString& crashDumpsPath, - std::chrono::seconds spawnDelay, QString executableBlacklist) +void OrganizerCore::updateVFSParams(log::Levels logLevel, + env::CoreDumpTypes coreDumpType, + const QString& crashDumpsPath, + std::chrono::seconds spawnDelay, + QString executableBlacklist) { setGlobalCoreDumpType(coreDumpType); - m_USVFS.updateParams( - logLevel, coreDumpType, crashDumpsPath, spawnDelay, executableBlacklist); + m_USVFS.updateParams(logLevel, coreDumpType, crashDumpsPath, spawnDelay, + executableBlacklist); } void OrganizerCore::setLogLevel(log::Levels level) @@ -481,11 +481,9 @@ void OrganizerCore::setLogLevel(log::Levels level) m_Settings.diagnostics().setLogLevel(level); updateVFSParams( - m_Settings.diagnostics().logLevel(), - m_Settings.diagnostics().coreDumpType(), - QString::fromStdWString(getGlobalCoreDumpPath()), - m_Settings.diagnostics().spawnDelay(), - m_Settings.executablesBlacklist()); + m_Settings.diagnostics().logLevel(), m_Settings.diagnostics().coreDumpType(), + QString::fromStdWString(getGlobalCoreDumpPath()), + m_Settings.diagnostics().spawnDelay(), m_Settings.executablesBlacklist()); log::getDefault().setLevel(m_Settings.diagnostics().logLevel()); } @@ -493,10 +491,10 @@ void OrganizerCore::setLogLevel(log::Levels level) bool OrganizerCore::cycleDiagnostics() { const auto maxDumps = settings().diagnostics().maxCoreDumps(); - const auto path = QString::fromStdWString(getGlobalCoreDumpPath()); + const auto path = QString::fromStdWString(getGlobalCoreDumpPath()); if (maxDumps > 0) { - removeOldFiles(path, "*.dmp", maxDumps, QDir::Time|QDir::Reversed); + removeOldFiles(path, "*.dmp", maxDumps, QDir::Time | QDir::Reversed); } return true; @@ -524,10 +522,9 @@ std::wstring OrganizerCore::getGlobalCoreDumpPath() return {}; } -void OrganizerCore::setCurrentProfile(const QString &profileName) +void OrganizerCore::setCurrentProfile(const QString& profileName) { - if ((m_CurrentProfile != nullptr) - && (profileName == m_CurrentProfile->name())) { + if ((m_CurrentProfile != nullptr) && (profileName == m_CurrentProfile->name())) { return; } @@ -535,8 +532,7 @@ void OrganizerCore::setCurrentProfile(const QString &profileName) QDir profileBaseDir(settings().paths().profiles()); - const auto subdirs = profileBaseDir.entryList( - QDir::AllDirs | QDir::NoDotAndDotDot); + const auto subdirs = profileBaseDir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot); QString profileDir; @@ -563,9 +559,10 @@ void OrganizerCore::setCurrentProfile(const QString &profileName) log::error("picked profile '{}' instead", QDir(profileDir).dirName()); - reportError( - tr("The selected profile '%1' does not exist. The profile '%2' will be used instead") - .arg(profileName).arg(QDir(profileDir).dirName())); + reportError(tr("The selected profile '%1' does not exist. The profile '%2' will be " + "used instead") + .arg(profileName) + .arg(QDir(profileDir).dirName())); } // Keep the old profile to emit signal-changed: @@ -583,8 +580,14 @@ void OrganizerCore::setCurrentProfile(const QString &profileName) m_Settings.game().setSelectedProfileName(m_CurrentProfile->name()); - connect(m_CurrentProfile.get(), qOverload<uint>(&Profile::modStatusChanged), [this](auto&& index) { modStatusChanged(index); }); - connect(m_CurrentProfile.get(), qOverload<QList<uint>>(&Profile::modStatusChanged), [this](auto&& indexes) { modStatusChanged(indexes); }); + connect(m_CurrentProfile.get(), qOverload<uint>(&Profile::modStatusChanged), + [this](auto&& index) { + modStatusChanged(index); + }); + connect(m_CurrentProfile.get(), qOverload<QList<uint>>(&Profile::modStatusChanged), + [this](auto&& indexes) { + modStatusChanged(indexes); + }); refreshDirectoryStructure(); m_CurrentProfile->debugDump(); @@ -593,7 +596,7 @@ void OrganizerCore::setCurrentProfile(const QString &profileName) m_ProfileChanged(oldProfile.get(), m_CurrentProfile.get()); } -MOBase::IModRepositoryBridge *OrganizerCore::createNexusBridge() const +MOBase::IModRepositoryBridge* OrganizerCore::createNexusBridge() const { return new NexusBridge(m_PluginContainer); } @@ -641,16 +644,17 @@ MOBase::VersionInfo OrganizerCore::appVersion() const return m_Updater.getVersion(); } -MOBase::IPluginGame *OrganizerCore::getGame(const QString &name) const +MOBase::IPluginGame* OrganizerCore::getGame(const QString& name) const { - for (IPluginGame *game : m_PluginContainer->plugins<IPluginGame>()) { - if (game != nullptr && game->gameShortName().compare(name, Qt::CaseInsensitive) == 0) + for (IPluginGame* game : m_PluginContainer->plugins<IPluginGame>()) { + if (game != nullptr && + game->gameShortName().compare(name, Qt::CaseInsensitive) == 0) return game; } return nullptr; } -MOBase::IModInterface *OrganizerCore::createMod(GuessedValue<QString> &name) +MOBase::IModInterface* OrganizerCore::createMod(GuessedValue<QString>& name) { auto result = m_InstallationManager.testOverwrite(name); if (!result) { @@ -659,10 +663,8 @@ MOBase::IModInterface *OrganizerCore::createMod(GuessedValue<QString> &name) m_InstallationManager.setModsDirectory(m_Settings.paths().mods()); - QString targetDirectory - = QDir::fromNativeSeparators(m_Settings.paths().mods()) - .append("/") - .append(name); + QString targetDirectory = + QDir::fromNativeSeparators(m_Settings.paths().mods()).append("/").append(name); QSettings settingsFile(targetDirectory + "/meta.ini", QSettings::IniFormat); @@ -678,98 +680,102 @@ MOBase::IModInterface *OrganizerCore::createMod(GuessedValue<QString> &name) settingsFile.endArray(); } - // shouldn't this use the existing mod in case of a merge? also, this does not refresh the indices - // in the ModInfo structure + // shouldn't this use the existing mod in case of a merge? also, this does not refresh + // the indices in the ModInfo structure return ModInfo::createFrom(QDir(targetDirectory), *this).data(); } -void OrganizerCore::modDataChanged(MOBase::IModInterface *) +void OrganizerCore::modDataChanged(MOBase::IModInterface*) { refresh(false); } -QVariant OrganizerCore::pluginSetting(const QString &pluginName, - const QString &key) const +QVariant OrganizerCore::pluginSetting(const QString& pluginName, + const QString& key) const { return m_Settings.plugins().setting(pluginName, key); } -void OrganizerCore::setPluginSetting(const QString &pluginName, - const QString &key, const QVariant &value) +void OrganizerCore::setPluginSetting(const QString& pluginName, const QString& key, + const QVariant& value) { m_Settings.plugins().setSetting(pluginName, key, value); } -QVariant OrganizerCore::persistent(const QString &pluginName, - const QString &key, - const QVariant &def) const +QVariant OrganizerCore::persistent(const QString& pluginName, const QString& key, + const QVariant& def) const { return m_Settings.plugins().persistent(pluginName, key, def); } -void OrganizerCore::setPersistent(const QString &pluginName, const QString &key, - const QVariant &value, bool sync) +void OrganizerCore::setPersistent(const QString& pluginName, const QString& key, + const QVariant& value, bool sync) { m_Settings.plugins().setPersistent(pluginName, key, value, sync); } QString OrganizerCore::pluginDataPath() { - return qApp->applicationDirPath() + "/" + ToQString(AppConfig::pluginPath()) - + "/data"; + return qApp->applicationDirPath() + "/" + ToQString(AppConfig::pluginPath()) + + "/data"; } -MOBase::IModInterface *OrganizerCore::installMod(const QString & archivePath, - int priority, - bool reinstallation, +MOBase::IModInterface* OrganizerCore::installMod(const QString& archivePath, + int priority, bool reinstallation, ModInfo::Ptr currentMod, - const QString &initModName) + const QString& initModName) { - return installArchive(archivePath, reinstallation ? -1 : priority, reinstallation, currentMod, initModName).get(); + return installArchive(archivePath, reinstallation ? -1 : priority, reinstallation, + currentMod, initModName) + .get(); } -std::pair<unsigned int, ModInfo::Ptr> OrganizerCore::doInstall(const QString& archivePath, - GuessedValue<QString> modName, ModInfo::Ptr currentMod, int priority, bool reinstallation) +std::pair<unsigned int, ModInfo::Ptr> +OrganizerCore::doInstall(const QString& archivePath, GuessedValue<QString> modName, + ModInfo::Ptr currentMod, int priority, bool reinstallation) { if (m_CurrentProfile == nullptr) { - return { -1, nullptr }; + return {-1, nullptr}; } if (m_InstallationManager.isRunning()) { - QMessageBox::information( - qApp->activeWindow(), tr("Installation cancelled"), - tr("Another installation is currently in progress."), QMessageBox::Ok); - return { -1, nullptr }; + QMessageBox::information(qApp->activeWindow(), tr("Installation cancelled"), + tr("Another installation is currently in progress."), + QMessageBox::Ok); + return {-1, nullptr}; } bool hasIniTweaks = false; m_CurrentProfile->writeModlistNow(); m_InstallationManager.setModsDirectory(m_Settings.paths().mods()); - m_InstallationManager.notifyInstallationStart(archivePath, reinstallation, currentMod); + m_InstallationManager.notifyInstallationStart(archivePath, reinstallation, + currentMod); auto result = m_InstallationManager.install(archivePath, modName, hasIniTweaks); if (result) { - MessageDialog::showMessage(tr("Installation successful"), - qApp->activeWindow()); + MessageDialog::showMessage(tr("Installation successful"), qApp->activeWindow()); - // we wait for the directory structure to be ready before notifying the mod list, this - // prevents issue with third-party plugins, e.g., if the installed mod is activated before - // the structure is ready + // we wait for the directory structure to be ready before notifying the mod list, + // this prevents issue with third-party plugins, e.g., if the installed mod is + // activated before the structure is ready // - // we need to fetch modIndex() within the call back because the index is only valid after - // the call to refresh(), but we do not want to connect after refresh() + // we need to fetch modIndex() within the call back because the index is only valid + // after the call to refresh(), but we do not want to connect after refresh() // - connect(this, &OrganizerCore::directoryStructureReady, this, [=] { - const int modIndex = ModInfo::getIndex(modName); - if (modIndex != UINT_MAX) { - const auto modInfo = ModInfo::getByIndex(modIndex); - m_ModList.notifyModInstalled(modInfo.get()); - } - }, Qt::SingleShotConnection); + connect( + this, &OrganizerCore::directoryStructureReady, this, + [=] { + const int modIndex = ModInfo::getIndex(modName); + if (modIndex != UINT_MAX) { + const auto modInfo = ModInfo::getByIndex(modIndex); + m_ModList.notifyModInstalled(modInfo.get()); + } + }, + Qt::SingleShotConnection); refresh(); - const auto modIndex = ModInfo::getIndex(modName); + const auto modIndex = ModInfo::getIndex(modName); ModInfo::Ptr modInfo = nullptr; if (modIndex != UINT_MAX) { modInfo = ModInfo::getByIndex(modIndex); @@ -778,46 +784,46 @@ std::pair<unsigned int, ModInfo::Ptr> OrganizerCore::doInstall(const QString& ar m_ModList.changeModPriority(modIndex, priority); } - if (hasIniTweaks && m_UserInterface != nullptr - && (QMessageBox::question(qApp->activeWindow(), tr("Configure Mod"), - tr("This mod contains ini tweaks. Do you " - "want to configure them now?"), - QMessageBox::Yes | QMessageBox::No) - == QMessageBox::Yes)) { - m_UserInterface->displayModInformation( - modInfo, modIndex, ModInfoTabIDs::IniFiles); + if (hasIniTweaks && m_UserInterface != nullptr && + (QMessageBox::question(qApp->activeWindow(), tr("Configure Mod"), + tr("This mod contains ini tweaks. Do you " + "want to configure them now?"), + QMessageBox::Yes | QMessageBox::No) == + QMessageBox::Yes)) { + m_UserInterface->displayModInformation(modInfo, modIndex, + ModInfoTabIDs::IniFiles); } m_InstallationManager.notifyInstallationEnd(result, modInfo); - } - else { + } else { reportError(tr("mod not found: %1").arg(qUtf8Printable(modName))); } emit modInstalled(modName); - return { modIndex, modInfo }; - } - else { + return {modIndex, modInfo}; + } else { m_InstallationManager.notifyInstallationEnd(result, nullptr); if (m_InstallationManager.wasCancelled()) { - QMessageBox::information(qApp->activeWindow(), tr("Extraction cancelled"), - tr("The installation was cancelled while extracting files. " - "If this was prior to a FOMOD setup, this warning may be ignored. " - "However, if this was during installation, the mod will likely be missing files."), - QMessageBox::Ok); + QMessageBox::information( + qApp->activeWindow(), tr("Extraction cancelled"), + tr("The installation was cancelled while extracting files. " + "If this was prior to a FOMOD setup, this warning may be ignored. " + "However, if this was during installation, the mod will likely be missing " + "files."), + QMessageBox::Ok); refresh(); } } - return { -1, nullptr }; + return {-1, nullptr}; } ModInfo::Ptr OrganizerCore::installDownload(int index, int priority) { try { - QString fileName = m_DownloadManager.getFilePath(index); - QString gameName = m_DownloadManager.getGameName(index); - int modID = m_DownloadManager.getModID(index); - int fileID = m_DownloadManager.getFileInfo(index)->fileID; + QString fileName = m_DownloadManager.getFilePath(index); + QString gameName = m_DownloadManager.getGameName(index); + int modID = m_DownloadManager.getModID(index); + int fileID = m_DownloadManager.getFileInfo(index)->fileID; ModInfo::Ptr currentMod = nullptr; GuessedValue<QString> modName; @@ -826,8 +832,8 @@ ModInfo::Ptr OrganizerCore::installDownload(int index, int priority) std::vector<ModInfo::Ptr> modInfo = ModInfo::getByModID(gameName, modID); for (auto iter = modInfo.begin(); iter != modInfo.end(); ++iter) { std::vector<ModInfo::EFlag> flags = (*iter)->getFlags(); - if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_BACKUP) - == flags.end()) { + if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_BACKUP) == + flags.end()) { modName.update((*iter)->name(), GUESS_PRESET); currentMod = *iter; (*iter)->saveMeta(); @@ -835,7 +841,8 @@ ModInfo::Ptr OrganizerCore::installDownload(int index, int priority) } } - const auto [modIndex, modInfo] = doInstall(fileName, modName, currentMod, priority, false); + const auto [modIndex, modInfo] = + doInstall(fileName, modName, currentMod, priority, false); if (modInfo != nullptr) { modInfo->addInstalledFile(modID, fileID); @@ -846,22 +853,23 @@ ModInfo::Ptr OrganizerCore::installDownload(int index, int priority) } return modInfo; - } catch (const std::exception &e) { + } catch (const std::exception& e) { reportError(QString(e.what())); } return nullptr; } -ModInfo::Ptr OrganizerCore::installArchive( - const QString& archivePath, int priority, bool reinstallation, - ModInfo::Ptr currentMod, const QString& initModName) +ModInfo::Ptr OrganizerCore::installArchive(const QString& archivePath, int priority, + bool reinstallation, ModInfo::Ptr currentMod, + const QString& initModName) { GuessedValue<QString> modName; if (!initModName.isEmpty()) { modName.update(initModName, GUESS_USER); } - const auto [modIndex, modInfo] = doInstall(archivePath, modName, currentMod, priority, reinstallation); + const auto [modIndex, modInfo] = + doInstall(archivePath, modName, currentMod, priority, reinstallation); if (m_CurrentProfile == nullptr) { return nullptr; } @@ -869,7 +877,7 @@ ModInfo::Ptr OrganizerCore::installArchive( if (modInfo != nullptr) { auto dlIdx = m_DownloadManager.indexByName(QFileInfo(archivePath).fileName()); if (dlIdx != -1) { - int modId = m_DownloadManager.getModID(dlIdx); + int modId = m_DownloadManager.getModID(dlIdx); int fileId = m_DownloadManager.getFileInfo(dlIdx)->fileID; modInfo->addInstalledFile(modId, fileId); } @@ -878,13 +886,13 @@ ModInfo::Ptr OrganizerCore::installArchive( return modInfo; } -QString OrganizerCore::resolvePath(const QString &fileName) const +QString OrganizerCore::resolvePath(const QString& fileName) const { if (m_DirectoryStructure == nullptr) { return QString(); } - const FileEntryPtr file - = m_DirectoryStructure->searchFile(ToWString(fileName), nullptr); + const FileEntryPtr file = + m_DirectoryStructure->searchFile(ToWString(fileName), nullptr); if (file.get() != nullptr) { return ToQString(file->getFullPath()); } else { @@ -892,10 +900,10 @@ QString OrganizerCore::resolvePath(const QString &fileName) const } } -QStringList OrganizerCore::listDirectories(const QString &directoryName) const +QStringList OrganizerCore::listDirectories(const QString& directoryName) const { QStringList result; - DirectoryEntry *dir = m_DirectoryStructure; + DirectoryEntry* dir = m_DirectoryStructure; if (!directoryName.isEmpty()) dir = dir->findSubDirectoryRecursive(ToWString(directoryName)); if (dir != nullptr) { @@ -906,17 +914,17 @@ QStringList OrganizerCore::listDirectories(const QString &directoryName) const return result; } -QStringList OrganizerCore::findFiles( - const QString &path, - const std::function<bool(const QString &)> &filter) const +QStringList +OrganizerCore::findFiles(const QString& path, + const std::function<bool(const QString&)>& filter) const { QStringList result; - DirectoryEntry *dir = m_DirectoryStructure; + DirectoryEntry* dir = m_DirectoryStructure; if (!path.isEmpty() && path != ".") dir = dir->findSubDirectoryRecursive(ToWString(path)); if (dir != nullptr) { std::vector<FileEntryPtr> files = dir->getFiles(); - for (FileEntryPtr &file: files) { + for (FileEntryPtr& file : files) { QString fullPath = ToQString(file->getFullPath()); if (filter(ToQString(file->getName()))) { result.append(fullPath); @@ -926,14 +934,15 @@ QStringList OrganizerCore::findFiles( return result; } -QStringList OrganizerCore::getFileOrigins(const QString &fileName) const +QStringList OrganizerCore::getFileOrigins(const QString& fileName) const { QStringList result; - const FileEntryPtr file = m_DirectoryStructure->searchFile(ToWString(fileName), nullptr); + const FileEntryPtr file = + m_DirectoryStructure->searchFile(ToWString(fileName), nullptr); if (file.get() != nullptr) { - result.append(ToQString( - m_DirectoryStructure->getOriginByID(file->getOrigin()).getName())); + result.append( + ToQString(m_DirectoryStructure->getOriginByID(file->getOrigin()).getName())); foreach (const auto& i, file->getAlternatives()) { result.append( ToQString(m_DirectoryStructure->getOriginByID(i.originID()).getName())); @@ -943,12 +952,11 @@ QStringList OrganizerCore::getFileOrigins(const QString &fileName) const } QList<MOBase::IOrganizer::FileInfo> OrganizerCore::findFileInfos( - const QString &path, - const std::function<bool(const MOBase::IOrganizer::FileInfo &)> &filter) - const + const QString& path, + const std::function<bool(const MOBase::IOrganizer::FileInfo&)>& filter) const { QList<IOrganizer::FileInfo> result; - DirectoryEntry *dir = m_DirectoryStructure; + DirectoryEntry* dir = m_DirectoryStructure; if (!path.isEmpty() && path != ".") dir = dir->findSubDirectoryRecursive(ToWString(path)); if (dir != nullptr) { @@ -958,8 +966,7 @@ QList<MOBase::IOrganizer::FileInfo> OrganizerCore::findFileInfos( info.filePath = ToQString(file->getFullPath()); bool fromArchive = false; info.origins.append(ToQString( - m_DirectoryStructure->getOriginByID(file->getOrigin(fromArchive)) - .getName())); + m_DirectoryStructure->getOriginByID(file->getOrigin(fromArchive)).getName())); info.archive = fromArchive ? ToQString(file->getArchive().name()) : ""; for (const auto& idx : file->getAlternatives()) { info.origins.append( @@ -974,33 +981,34 @@ QList<MOBase::IOrganizer::FileInfo> OrganizerCore::findFileInfos( return result; } -DownloadManager *OrganizerCore::downloadManager() +DownloadManager* OrganizerCore::downloadManager() { return &m_DownloadManager; } -PluginList *OrganizerCore::pluginList() +PluginList* OrganizerCore::pluginList() { return &m_PluginList; } -ModList *OrganizerCore::modList() +ModList* OrganizerCore::modList() { return &m_ModList; } -bool OrganizerCore::previewFileWithAlternatives( - QWidget* parent, QString fileName, int selectedOrigin) +bool OrganizerCore::previewFileWithAlternatives(QWidget* parent, QString fileName, + int selectedOrigin) { fileName = QDir::fromNativeSeparators(fileName); - // what we have is an absolute path to the file in its actual location (for the primary origin) - // what we want is the path relative to the virtual data directory + // what we have is an absolute path to the file in its actual location (for the + // primary origin) what we want is the path relative to the virtual data directory - // we need to look in the virtual directory for the file to make sure the info is up to date. + // we need to look in the virtual directory for the file to make sure the info is up + // to date. // check if the file comes from the actual data folder instead of a mod - QDir gameDirectory = managedGame()->dataDirectory().absolutePath(); + QDir gameDirectory = managedGame()->dataDirectory().absolutePath(); QString relativePath = gameDirectory.relativeFilePath(fileName); QDir dirRelativePath = gameDirectory.relativeFilePath(fileName); @@ -1008,18 +1016,16 @@ bool OrganizerCore::previewFileWithAlternatives( // absolute path so we make sure that is not the case if (!dirRelativePath.isAbsolute() && !relativePath.startsWith("..")) { fileName = relativePath; - } - else { + } else { // crude: we search for the next slash after the base mod directory to skip // everything up to the data-relative directory int offset = settings().paths().mods().size() + 1; - offset = fileName.indexOf("/", offset); - fileName = fileName.mid(offset + 1); + offset = fileName.indexOf("/", offset); + fileName = fileName.mid(offset + 1); } - - - const FileEntryPtr file = directoryStructure()->searchFile(ToWString(fileName), nullptr); + const FileEntryPtr file = + directoryStructure()->searchFile(ToWString(fileName), nullptr); if (file.get() == nullptr) { reportError(tr("file not found: %1").arg(qUtf8Printable(fileName))); @@ -1030,15 +1036,16 @@ bool OrganizerCore::previewFileWithAlternatives( PreviewDialog preview(fileName, parent); auto addFunc = [&](int originId) { - FilesOrigin &origin = directoryStructure()->getOriginByID(originId); - QString filePath = QDir::fromNativeSeparators(ToQString(origin.getPath())) + "/" + fileName; + FilesOrigin& origin = directoryStructure()->getOriginByID(originId); + QString filePath = + QDir::fromNativeSeparators(ToQString(origin.getPath())) + "/" + fileName; if (QFile::exists(filePath)) { - // it's very possible the file doesn't exist, because it's inside an archive. we don't support that - QWidget *wid = m_PluginContainer->previewGenerator().genPreview(filePath); + // it's very possible the file doesn't exist, because it's inside an archive. we + // don't support that + QWidget* wid = m_PluginContainer->previewGenerator().genPreview(filePath); if (wid == nullptr) { reportError(tr("failed to generate preview for %1").arg(filePath)); - } - else { + } else { preview.addVariant(ToQString(origin.getName()), wid); } } @@ -1072,9 +1079,8 @@ bool OrganizerCore::previewFileWithAlternatives( // sanity check, this shouldn't happen unless the caller passed an // incorrect id - log::warn( - "selected preview origin {} not found in list of alternatives", - selectedOrigin); + log::warn("selected preview origin {} not found in list of alternatives", + selectedOrigin); } for (int id : origins) { @@ -1085,18 +1091,17 @@ bool OrganizerCore::previewFileWithAlternatives( if (preview.numVariants() > 0) { preview.exec(); return true; - } - else { - QMessageBox::information( - parent, tr("Sorry"), - tr("Sorry, can't preview anything. This function currently does not support extracting from bsas.")); + } else { + QMessageBox::information(parent, tr("Sorry"), + tr("Sorry, can't preview anything. This function " + "currently does not support extracting from bsas.")); return false; } } -bool OrganizerCore::previewFile( - QWidget* parent, const QString& originName, const QString& path) +bool OrganizerCore::previewFile(QWidget* parent, const QString& originName, + const QString& path) { if (!QFile::exists(path)) { reportError(tr("File '%1' not found.").arg(path)); @@ -1105,7 +1110,7 @@ bool OrganizerCore::previewFile( PreviewDialog preview(path, parent); - QWidget *wid = m_PluginContainer->previewGenerator().genPreview(path); + QWidget* wid = m_PluginContainer->previewGenerator().genPreview(path); if (wid == nullptr) { reportError(tr("Failed to generate preview for %1").arg(path)); return false; @@ -1117,54 +1122,63 @@ bool OrganizerCore::previewFile( return true; } -boost::signals2::connection OrganizerCore::onAboutToRun( - const std::function<bool(const QString &)> &func) +boost::signals2::connection +OrganizerCore::onAboutToRun(const std::function<bool(const QString&)>& func) { return m_AboutToRun.connect(func); } boost::signals2::connection OrganizerCore::onFinishedRun( - const std::function<void(const QString &, unsigned int)> &func) + const std::function<void(const QString&, unsigned int)>& func) { return m_FinishedRun.connect(func); } -boost::signals2::connection OrganizerCore::onUserInterfaceInitialized(std::function<void(QMainWindow*)> const& func) +boost::signals2::connection +OrganizerCore::onUserInterfaceInitialized(std::function<void(QMainWindow*)> const& func) { return m_UserInterfaceInitialized.connect(func); } -boost::signals2::connection OrganizerCore::onProfileCreated(std::function<void(MOBase::IProfile*)> const& func) +boost::signals2::connection +OrganizerCore::onProfileCreated(std::function<void(MOBase::IProfile*)> const& func) { return m_ProfileCreated.connect(func); } -boost::signals2::connection OrganizerCore::onProfileRenamed(std::function<void(MOBase::IProfile*, QString const&, QString const&)> const& func) +boost::signals2::connection OrganizerCore::onProfileRenamed( + std::function<void(MOBase::IProfile*, QString const&, QString const&)> const& func) { return m_ProfileRenamed.connect(func); } -boost::signals2::connection OrganizerCore::onProfileRemoved(std::function<void(QString const&)> const& func) +boost::signals2::connection +OrganizerCore::onProfileRemoved(std::function<void(QString const&)> const& func) { return m_ProfileRemoved.connect(func); } -boost::signals2::connection OrganizerCore::onProfileChanged(std::function<void(IProfile*, IProfile*)> const& func) +boost::signals2::connection +OrganizerCore::onProfileChanged(std::function<void(IProfile*, IProfile*)> const& func) { return m_ProfileChanged.connect(func); } -boost::signals2::connection OrganizerCore::onPluginSettingChanged(std::function<void(QString const&, const QString& key, const QVariant&, const QVariant&)> const& func) +boost::signals2::connection OrganizerCore::onPluginSettingChanged( + std::function<void(QString const&, const QString& key, const QVariant&, + const QVariant&)> const& func) { return m_PluginSettingChanged.connect(func); } -boost::signals2::connection OrganizerCore::onPluginEnabled(std::function<void(const IPlugin*)> const& func) +boost::signals2::connection +OrganizerCore::onPluginEnabled(std::function<void(const IPlugin*)> const& func) { return m_PluginEnabled.connect(func); } -boost::signals2::connection OrganizerCore::onPluginDisabled(std::function<void(const IPlugin*)> const& func) +boost::signals2::connection +OrganizerCore::onPluginDisabled(std::function<void(const IPlugin*)> const& func) { return m_PluginDisabled.connect(func); } @@ -1202,7 +1216,7 @@ void OrganizerCore::refreshESPList(bool force) try { m_PluginList.refresh(m_CurrentProfile->name(), *m_DirectoryStructure, m_CurrentProfile->getLockedOrderFileName(), force); - } catch (const std::exception &e) { + } catch (const std::exception& e) { reportError(tr("Failed to refresh list of esps: %1").arg(e.what())); } } @@ -1211,7 +1225,7 @@ void OrganizerCore::refreshBSAList() { TimeThis tt("OrganizerCore::refreshBSAList()"); - DataArchives *archives = m_GamePlugin->feature<DataArchives>(); + DataArchives* archives = m_GamePlugin->feature<DataArchives>(); if (archives != nullptr) { m_ArchivesInit = false; @@ -1247,8 +1261,8 @@ void OrganizerCore::refreshLists() if ((m_CurrentProfile != nullptr) && m_DirectoryStructure->isPopulated()) { refreshESPList(true); refreshBSAList(); - } // no point in refreshing lists if no files have been added to the directory - // tree + } // no point in refreshing lists if no files have been added to the directory + // tree } void OrganizerCore::updateModActiveState(int index, bool active) @@ -1258,38 +1272,35 @@ void OrganizerCore::updateModActiveState(int index, bool active) updateModsActiveState(modsToUpdate, active); } -void OrganizerCore::updateModsActiveState(const QList<unsigned int> &modIndices, bool active) +void OrganizerCore::updateModsActiveState(const QList<unsigned int>& modIndices, + bool active) { int enabled = 0; for (auto index : modIndices) { ModInfo::Ptr modInfo = ModInfo::getByIndex(index); QDir dir(modInfo->absolutePath()); - for (const QString &esm : - dir.entryList(QStringList() << "*.esm", QDir::Files)) { + for (const QString& esm : dir.entryList(QStringList() << "*.esm", QDir::Files)) { const FileEntryPtr file = m_DirectoryStructure->findFile(ToWString(esm)); if (file.get() == nullptr) { log::warn("failed to activate {}", esm); continue; } - if (active != m_PluginList.isEnabled(esm) - && file->getAlternatives().empty()) { + if (active != m_PluginList.isEnabled(esm) && file->getAlternatives().empty()) { m_PluginList.blockSignals(true); m_PluginList.enableESP(esm, active); m_PluginList.blockSignals(false); } } - for (const QString &esl : - dir.entryList(QStringList() << "*.esl", QDir::Files)) { + for (const QString& esl : dir.entryList(QStringList() << "*.esl", QDir::Files)) { const FileEntryPtr file = m_DirectoryStructure->findFile(ToWString(esl)); if (file.get() == nullptr) { log::warn("failed to activate {}", esl); continue; } - if (active != m_PluginList.isEnabled(esl) - && file->getAlternatives().empty()) { + if (active != m_PluginList.isEnabled(esl) && file->getAlternatives().empty()) { m_PluginList.blockSignals(true); m_PluginList.enableESP(esl, active); m_PluginList.blockSignals(false); @@ -1297,15 +1308,14 @@ void OrganizerCore::updateModsActiveState(const QList<unsigned int> &modIndices, } } QStringList esps = dir.entryList(QStringList() << "*.esp", QDir::Files); - for (const QString &esp : esps) { + for (const QString& esp : esps) { const FileEntryPtr file = m_DirectoryStructure->findFile(ToWString(esp)); if (file.get() == nullptr) { log::warn("failed to activate {}", esp); continue; } - if (active != m_PluginList.isEnabled(esp) - && file->getAlternatives().empty()) { + if (active != m_PluginList.isEnabled(esp) && file->getAlternatives().empty()) { m_PluginList.blockSignals(true); m_PluginList.enableESP(esp, active); m_PluginList.blockSignals(false); @@ -1315,8 +1325,8 @@ void OrganizerCore::updateModsActiveState(const QList<unsigned int> &modIndices, } if (active && (enabled > 1)) { MessageDialog::showMessage( - tr("Multiple esps/esls activated, please check that they don't conflict."), - qApp->activeWindow()); + tr("Multiple esps/esls activated, please check that they don't conflict."), + qApp->activeWindow()); } m_PluginList.refreshLoadOrder(); // immediately save affected lists @@ -1331,18 +1341,20 @@ void OrganizerCore::updateModInDirectoryStructure(unsigned int index, updateModsInDirectoryStructure(allModInfo); } -void OrganizerCore::updateModsInDirectoryStructure(QMap<unsigned int, ModInfo::Ptr> modInfo) +void OrganizerCore::updateModsInDirectoryStructure( + QMap<unsigned int, ModInfo::Ptr> modInfo) { std::vector<DirectoryRefresher::EntryInfo> entries; for (auto idx : modInfo.keys()) { - entries.push_back({ - modInfo[idx]->name(), modInfo[idx]->absolutePath(), - modInfo[idx]->stealFiles(), {}, m_CurrentProfile->getModPriority(idx)}); + entries.push_back({modInfo[idx]->name(), + modInfo[idx]->absolutePath(), + modInfo[idx]->stealFiles(), + {}, + m_CurrentProfile->getModPriority(idx)}); } - m_DirectoryRefresher->addMultipleModsFilesToStructure( - m_DirectoryStructure, entries); + m_DirectoryRefresher->addMultipleModsFilesToStructure(m_DirectoryStructure, entries); DirectoryRefresher::cleanStructure(m_DirectoryStructure); // need to refresh plugin list now so we can activate esps @@ -1360,27 +1372,28 @@ void OrganizerCore::updateModsInDirectoryStructure(QMap<unsigned int, ModInfo::P } std::vector<QString> archives = enabledArchives(); - m_DirectoryRefresher->setMods( - m_CurrentProfile->getActiveMods(), - std::set<QString>(archives.begin(), archives.end())); + m_DirectoryRefresher->setMods(m_CurrentProfile->getActiveMods(), + std::set<QString>(archives.begin(), archives.end())); // finally also add files from bsas to the directory structure for (auto idx : modInfo.keys()) { m_DirectoryRefresher->addModBSAToStructure( - m_DirectoryStructure, modInfo[idx]->name(), - m_CurrentProfile->getModPriority(idx), modInfo[idx]->absolutePath(), - modInfo[idx]->archives()); + m_DirectoryStructure, modInfo[idx]->name(), + m_CurrentProfile->getModPriority(idx), modInfo[idx]->absolutePath(), + modInfo[idx]->archives()); } } -void OrganizerCore::loggedInAction(QWidget* parent, std::function<void ()> f) +void OrganizerCore::loggedInAction(QWidget* parent, std::function<void()> f) { if (NexusInterface::instance().getAccessManager()->validated()) { f(); } else if (!m_Settings.network().offlineMode()) { QString apiKey; if (GlobalSettings::nexusApiKey(apiKey)) { - doAfterLogin([f]{ f(); }); + doAfterLogin([f] { + f(); + }); NexusInterface::instance().getAccessManager()->apiCheck(apiKey); } else { MessageDialog::showMessage(tr("You need to be logged in with Nexus"), parent); @@ -1388,13 +1401,12 @@ void OrganizerCore::loggedInAction(QWidget* parent, std::function<void ()> f) } } -void OrganizerCore::requestDownload(const QUrl &url, QNetworkReply *reply) +void OrganizerCore::requestDownload(const QUrl& url, QNetworkReply* reply) { if (!m_PluginContainer) { return; } - for (IPluginModPage *modPage : - m_PluginContainer->plugins<MOBase::IPluginModPage>()) { + for (IPluginModPage* modPage : m_PluginContainer->plugins<MOBase::IPluginModPage>()) { if (m_PluginContainer->isEnabled(modPage)) { ModRepositoryFileInfo* fileInfo = new ModRepositoryFileInfo(); if (modPage->handlesDownload(url, reply->url(), *fileInfo)) { @@ -1408,8 +1420,8 @@ void OrganizerCore::requestDownload(const QUrl &url, QNetworkReply *reply) // no mod found that could handle the download. Is it a nexus mod? if (url.host() == "www.nexusmods.com") { QString gameName = ""; - int modID = 0; - int fileID = 0; + int modID = 0; + int fileID = 0; QRegularExpression nameExp("www\\.nexusmods\\.com/(\\a+)/"); auto match = nameExp.match(url.toString()); if (match.hasMatch()) { @@ -1435,8 +1447,7 @@ void OrganizerCore::requestDownload(const QUrl &url, QNetworkReply *reply) "version) will be associated with the " "download.\n" "Continue?"), - QMessageBox::Yes | QMessageBox::No) - == QMessageBox::Yes) { + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { m_DownloadManager.addDownload(reply, new ModRepositoryFileInfo()); } } @@ -1447,7 +1458,7 @@ PluginContainer& OrganizerCore::pluginContainer() const return *m_PluginContainer; } -IPluginGame const *OrganizerCore::managedGame() const +IPluginGame const* OrganizerCore::managedGame() const { return m_GamePlugin; } @@ -1484,10 +1495,10 @@ void OrganizerCore::refreshDirectoryStructure() m_CurrentProfile->writeModlistNow(true); const auto activeModList = m_CurrentProfile->getActiveMods(); - const auto archives = enabledArchives(); + const auto archives = enabledArchives(); - m_DirectoryRefresher->setMods( - activeModList, std::set<QString>(archives.begin(), archives.end())); + m_DirectoryRefresher->setMods(activeModList, + std::set<QString>(archives.begin(), archives.end())); // runs refresh() in a thread QTimer::singleShot(0, m_DirectoryRefresher.get(), SLOT(refresh())); @@ -1498,7 +1509,7 @@ void OrganizerCore::directory_refreshed() log::debug("directory refreshed, finishing up"); TimeThis tt("OrganizerCore::directory_refreshed()"); - DirectoryEntry *newStructure = m_DirectoryRefresher->stealDirectoryStructure(); + DirectoryEntry* newStructure = m_DirectoryRefresher->stealDirectoryStructure(); Q_ASSERT(newStructure != m_DirectoryStructure); if (newStructure == nullptr) { @@ -1514,7 +1525,7 @@ void OrganizerCore::directory_refreshed() m_StructureDeleter.join(); } - m_StructureDeleter = MOShared::startSafeThread([=]{ + m_StructureDeleter = MOShared::startSafeThread([=] { log::debug("structure deleter thread start"); delete newStructure; log::debug("structure deleter thread done"); @@ -1573,8 +1584,7 @@ void OrganizerCore::clearCaches(std::vector<unsigned int> const& indices) const insert(allIndices, modInfo->getModArchiveOverwritten()); insert(allIndices, modInfo->getModArchiveLooseOverwrite()); insert(allIndices, modInfo->getModArchiveLooseOverwritten()); - } - else { + } else { // if the mod is disabled, we need to first fetch the conflicting // mods, and then clear the cache insert(allIndices, modInfo->getModOverwrite()); @@ -1599,7 +1609,9 @@ void OrganizerCore::modPrioritiesChanged(const QModelIndexList& indices) if (currentProfile()->modEnabled(i)) { ModInfo::Ptr modInfo = ModInfo::getByIndex(i); // priorities in the directory structure are one higher because data is 0 - directoryStructure()->getOriginByName(MOBase::ToWString(modInfo->internalName())).setPriority(priority + 1); + directoryStructure() + ->getOriginByName(MOBase::ToWString(modInfo->internalName())) + .setPriority(priority + 1); } } refreshBSAList(); @@ -1624,8 +1636,8 @@ void OrganizerCore::modStatusChanged(unsigned int index) } else { updateModActiveState(index, false); if (m_DirectoryStructure->originExists(ToWString(modInfo->name()))) { - FilesOrigin &origin - = m_DirectoryStructure->getOriginByName(ToWString(modInfo->name())); + FilesOrigin& origin = + m_DirectoryStructure->getOriginByName(ToWString(modInfo->name())); origin.enable(false); } if (m_UserInterface != nullptr) { @@ -1635,7 +1647,7 @@ void OrganizerCore::modStatusChanged(unsigned int index) for (unsigned int i = 0; i < m_CurrentProfile->numMods(); ++i) { ModInfo::Ptr modInfo = ModInfo::getByIndex(i); - int priority = m_CurrentProfile->getModPriority(i); + int priority = m_CurrentProfile->getModPriority(i); if (m_DirectoryStructure->originExists(ToWString(modInfo->name()))) { // priorities in the directory structure are one higher because data is // 0 @@ -1646,15 +1658,16 @@ void OrganizerCore::modStatusChanged(unsigned int index) m_DirectoryStructure->getFileRegister()->sortOrigins(); refreshLists(); - clearCaches({ index }); - m_ModList.notifyModStateChanged({ index }); + clearCaches({index}); + m_ModList.notifyModStateChanged({index}); - } catch (const std::exception &e) { + } catch (const std::exception& e) { reportError(tr("failed to update mod list: %1").arg(e.what())); } } -void OrganizerCore::modStatusChanged(QList<unsigned int> index) { +void OrganizerCore::modStatusChanged(QList<unsigned int> index) +{ try { QMap<unsigned int, ModInfo::Ptr> modsToEnable; QMap<unsigned int, ModInfo::Ptr> modsToDisable; @@ -1674,8 +1687,8 @@ void OrganizerCore::modStatusChanged(QList<unsigned int> index) { updateModsActiveState(modsToDisable.keys(), false); for (auto idx : modsToDisable.keys()) { if (m_DirectoryStructure->originExists(ToWString(modsToDisable[idx]->name()))) { - FilesOrigin &origin - = m_DirectoryStructure->getOriginByName(ToWString(modsToDisable[idx]->name())); + FilesOrigin& origin = m_DirectoryStructure->getOriginByName( + ToWString(modsToDisable[idx]->name())); origin.enable(false); } } @@ -1686,12 +1699,12 @@ void OrganizerCore::modStatusChanged(QList<unsigned int> index) { for (unsigned int i = 0; i < m_CurrentProfile->numMods(); ++i) { ModInfo::Ptr modInfo = ModInfo::getByIndex(i); - int priority = m_CurrentProfile->getModPriority(i); + int priority = m_CurrentProfile->getModPriority(i); if (m_DirectoryStructure->originExists(ToWString(modInfo->name()))) { // priorities in the directory structure are one higher because data is // 0 m_DirectoryStructure->getOriginByName(ToWString(modInfo->name())) - .setPriority(priority + 1); + .setPriority(priority + 1); } } m_DirectoryStructure->getFileRegister()->sortOrigins(); @@ -1700,7 +1713,7 @@ void OrganizerCore::modStatusChanged(QList<unsigned int> index) { clearCaches(vindices); m_ModList.notifyModStateChanged(index); - } catch (const std::exception &e) { + } catch (const std::exception& e) { reportError(tr("failed to update mod list: %1").arg(e.what())); } } @@ -1730,14 +1743,12 @@ void OrganizerCore::loginSuccessfulUpdate(bool necessary) m_Updater.startUpdate(); } -void OrganizerCore::loginFailed(const QString &message) +void OrganizerCore::loginFailed(const QString& message) { - qCritical().nospace().noquote() - << "Nexus API validation failed: " << message; + qCritical().nospace().noquote() << "Nexus API validation failed: " << message; if (QMessageBox::question(qApp->activeWindow(), tr("Login failed"), - tr("Login failed, try again?")) - == QMessageBox::Yes) { + tr("Login failed, try again?")) == QMessageBox::Yes) { if (nexusApi(true)) { return; } @@ -1760,11 +1771,10 @@ void OrganizerCore::loginFailed(const QString &message) NexusInterface::instance().loginCompleted(); } -void OrganizerCore::loginFailedUpdate(const QString &message) +void OrganizerCore::loginFailedUpdate(const QString& message) { MessageDialog::showMessage( - tr("login failed: %1. You need to log-in with Nexus to update MO.") - .arg(message), + tr("login failed: %1. You need to log-in with Nexus to update MO.").arg(message), qApp->activeWindow()); } @@ -1783,8 +1793,9 @@ void OrganizerCore::syncOverwrite() QString OrganizerCore::oldMO1HookDll() const { if (auto extender = managedGame()->feature<ScriptExtender>()) { - QString hookdll = QDir::toNativeSeparators( - managedGame()->dataDirectory().absoluteFilePath(extender->PluginPath() + "/hook.dll")); + QString hookdll = + QDir::toNativeSeparators(managedGame()->dataDirectory().absoluteFilePath( + extender->PluginPath() + "/hook.dll")); if (QFile(hookdll).exists()) return hookdll; } @@ -1796,10 +1807,10 @@ std::vector<unsigned int> OrganizerCore::activeProblems() const std::vector<unsigned int> problems; const auto& hookdll = oldMO1HookDll(); if (!hookdll.isEmpty()) { - // This warning will now be shown every time the problems are checked, which is a bit - // of a "log spam". But since this is a sever error which will most likely make the - // game crash/freeze/etc. and is very hard to diagnose, this "log spam" will make it - // easier for the user to notice the warning. + // This warning will now be shown every time the problems are checked, which is a + // bit of a "log spam". But since this is a sever error which will most likely make + // the game crash/freeze/etc. and is very hard to diagnose, this "log spam" will + // make it easier for the user to notice the warning. log::warn("hook.dll found in game folder: {}", hookdll); problems.push_back(PROBLEM_MO1SCRIPTEXTENDERWORKAROUND); } @@ -1809,28 +1820,34 @@ std::vector<unsigned int> OrganizerCore::activeProblems() const QString OrganizerCore::shortDescription(unsigned int key) const { switch (key) { - case PROBLEM_MO1SCRIPTEXTENDERWORKAROUND: { - return tr("MO1 \"Script Extender\" load mechanism has left hook.dll in your game folder"); - } break; - default: { - return tr("Description missing"); - } break; + case PROBLEM_MO1SCRIPTEXTENDERWORKAROUND: { + return tr( + "MO1 \"Script Extender\" load mechanism has left hook.dll in your game folder"); + } break; + default: { + return tr("Description missing"); + } break; } } QString OrganizerCore::fullDescription(unsigned int key) const { switch (key) { - case PROBLEM_MO1SCRIPTEXTENDERWORKAROUND: { - return tr("<a href=\"%1\">hook.dll</a> has been found in your game folder (right click to copy the full path). " - "This is most likely a leftover of setting the ModOrganizer 1 load mechanism to \"Script Extender\", " - "in which case you must remove this file either by changing the load mechanism in ModOrganizer 1 or " - "manually removing the file, otherwise the game is likely to crash and burn.").arg(oldMO1HookDll()); - break; - } - default: { - return tr("Description missing"); - } break; + case PROBLEM_MO1SCRIPTEXTENDERWORKAROUND: { + return tr("<a href=\"%1\">hook.dll</a> has been found in your game folder (right " + "click to copy the full path). " + "This is most likely a leftover of setting the ModOrganizer 1 load " + "mechanism to \"Script Extender\", " + "in which case you must remove this file either by changing the load " + "mechanism in ModOrganizer 1 or " + "manually removing the file, otherwise the game is likely to crash and " + "burn.") + .arg(oldMO1HookDll()); + break; + } + default: { + return tr("Description missing"); + } break; } } @@ -1839,9 +1856,7 @@ bool OrganizerCore::hasGuidedFix(unsigned int) const return false; } -void OrganizerCore::startGuidedFix(unsigned int) const -{ -} +void OrganizerCore::startGuidedFix(unsigned int) const {} bool OrganizerCore::saveCurrentLists() { @@ -1855,7 +1870,7 @@ bool OrganizerCore::saveCurrentLists() if (m_UserInterface != nullptr) { m_UserInterface->archivesWriter().write(); } - } catch (const std::exception &e) { + } catch (const std::exception& e) { reportError(tr("failed to save load order: %1").arg(e.what())); } @@ -1893,9 +1908,8 @@ ProcessRunner OrganizerCore::processRunner() } bool OrganizerCore::beforeRun( - const QFileInfo& binary, const QString& profileName, - const QString& customOverwrite, - const QList<MOBase::ExecutableForcedLoadSetting>& forcedLibraries) + const QFileInfo& binary, const QString& profileName, const QString& customOverwrite, + const QList<MOBase::ExecutableForcedLoadSetting>& forcedLibraries) { saveCurrentProfile(); @@ -1903,7 +1917,7 @@ bool OrganizerCore::beforeRun( if (m_DirectoryUpdate) { QEventLoop loop; connect(this, &OrganizerCore::directoryStructureReady, &loop, &QEventLoop::quit, - Qt::ConnectionType::QueuedConnection); + Qt::ConnectionType::QueuedConnection); loop.exec(); } @@ -1918,18 +1932,13 @@ bool OrganizerCore::beforeRun( return false; } - try - { + try { m_USVFS.updateMapping(fileMapping(profileName, customOverwrite)); m_USVFS.updateForcedLibraries(forcedLibraries); - } - catch (const UsvfsConnectorException &e) - { + } catch (const UsvfsConnectorException& e) { log::debug(e.what()); return false; - } - catch (const std::exception &e) - { + } catch (const std::exception& e) { QWidget* w = nullptr; if (m_UserInterface) { w = m_UserInterface->mainWindow(); @@ -1946,7 +1955,8 @@ void OrganizerCore::afterRun(const QFileInfo& binary, DWORD exitCode) // need to remove our stored load order because it may be outdated if a // foreign tool changed the file time. After removing that file, // refreshESPList will use the file time as the order - if (managedGame()->loadOrderMechanism() == IPluginGame::LoadOrderMechanism::FileTime) { + if (managedGame()->loadOrderMechanism() == + IPluginGame::LoadOrderMechanism::FileTime) { log::debug("removing loadorder.txt"); QFile::remove(m_CurrentProfile->getLoadOrderFileName()); } @@ -1957,35 +1967,32 @@ void OrganizerCore::afterRun(const QFileInfo& binary, DWORD exitCode) savePluginList(); cycleDiagnostics(); - //These callbacks should not fiddle with directory structure and ESPs. + // These callbacks should not fiddle with directory structure and ESPs. m_FinishedRun(binary.absoluteFilePath(), exitCode); } -ProcessRunner::Results OrganizerCore::waitForAllUSVFSProcesses( - UILocker::Reasons reason) +ProcessRunner::Results OrganizerCore::waitForAllUSVFSProcesses(UILocker::Reasons reason) { return processRunner().waitForAllUSVFSProcessesWithLock(reason); } -std::vector<Mapping> OrganizerCore::fileMapping(const QString &profileName, - const QString &customOverwrite) +std::vector<Mapping> OrganizerCore::fileMapping(const QString& profileName, + const QString& customOverwrite) { // need to wait until directory structure is ready if (m_DirectoryUpdate) { QEventLoop loop; connect(this, &OrganizerCore::directoryStructureReady, &loop, &QEventLoop::quit, - Qt::ConnectionType::QueuedConnection); + Qt::ConnectionType::QueuedConnection); loop.exec(); } - IPluginGame *game = qApp->property("managed_game").value<IPluginGame *>(); - Profile profile(QDir(m_Settings.paths().profiles() + "/" + profileName), - game); + IPluginGame* game = qApp->property("managed_game").value<IPluginGame*>(); + Profile profile(QDir(m_Settings.paths().profiles() + "/" + profileName), game); MappingType result; - QString dataPath - = QDir::toNativeSeparators(game->dataDirectory().absolutePath()); + QString dataPath = QDir::toNativeSeparators(game->dataDirectory().absolutePath()); bool overwriteActive = false; @@ -2002,21 +2009,21 @@ std::vector<Mapping> OrganizerCore::fileMapping(const QString &profileName, overwriteActive |= createTarget; if (modPtr->isRegular()) { - result.insert(result.end(), {QDir::toNativeSeparators(std::get<1>(mod)), - dataPath, true, createTarget}); + result.insert(result.end(), {QDir::toNativeSeparators(std::get<1>(mod)), dataPath, + true, createTarget}); } } if (!overwriteActive && !customOverwrite.isEmpty()) { - throw MyException(tr("The designated write target \"%1\" is not enabled.") - .arg(customOverwrite)); + throw MyException( + tr("The designated write target \"%1\" is not enabled.").arg(customOverwrite)); } if (m_CurrentProfile->localSavesEnabled()) { - LocalSavegames *localSaves = game->feature<LocalSavegames>(); + LocalSavegames* localSaves = game->feature<LocalSavegames>(); if (localSaves != nullptr) { - MappingType saveMap - = localSaves->mappings(currentProfile()->absolutePath() + "/saves"); + MappingType saveMap = + localSaves->mappings(currentProfile()->absolutePath() + "/saves"); result.reserve(result.size() + saveMap.size()); result.insert(result.end(), saveMap.begin(), saveMap.end()); } else { @@ -2024,16 +2031,12 @@ std::vector<Mapping> OrganizerCore::fileMapping(const QString &profileName, } } - result.insert(result.end(), { - QDir::toNativeSeparators(m_Settings.paths().overwrite()), - dataPath, - true, - customOverwrite.isEmpty() - }); + result.insert(result.end(), {QDir::toNativeSeparators(m_Settings.paths().overwrite()), + dataPath, true, customOverwrite.isEmpty()}); - for (MOBase::IPluginFileMapper *mapper : + for (MOBase::IPluginFileMapper* mapper : m_PluginContainer->plugins<MOBase::IPluginFileMapper>()) { - IPlugin *plugin = dynamic_cast<IPlugin *>(mapper); + IPlugin* plugin = dynamic_cast<IPlugin*>(mapper); if (m_PluginContainer->isEnabled(plugin)) { MappingType pluginMap = mapper->mappings(); result.reserve(result.size() + pluginMap.size()); @@ -2044,26 +2047,26 @@ std::vector<Mapping> OrganizerCore::fileMapping(const QString &profileName, return result; } - -std::vector<Mapping> OrganizerCore::fileMapping( - const QString &dataPath, const QString &relPath, const DirectoryEntry *base, - const DirectoryEntry *directoryEntry, int createDestination) +std::vector<Mapping> OrganizerCore::fileMapping(const QString& dataPath, + const QString& relPath, + const DirectoryEntry* base, + const DirectoryEntry* directoryEntry, + int createDestination) { std::vector<Mapping> result; for (FileEntryPtr current : directoryEntry->getFiles()) { bool isArchive = false; - int origin = current->getOrigin(isArchive); + int origin = current->getOrigin(isArchive); if (isArchive || (origin == 0)) { continue; } - QString originPath - = QString::fromStdWString(base->getOriginByID(origin).getPath()); - QString fileName = QString::fromStdWString(current->getName()); -// QString fileName = ToQString(current->getName()); - QString source = originPath + relPath + fileName; - QString target = dataPath + relPath + fileName; + QString originPath = QString::fromStdWString(base->getOriginByID(origin).getPath()); + QString fileName = QString::fromStdWString(current->getName()); + // QString fileName = ToQString(current->getName()); + QString source = originPath + relPath + fileName; + QString target = dataPath + relPath + fileName; if (source != target) { result.push_back({source, target, false, false}); } @@ -2073,18 +2076,16 @@ std::vector<Mapping> OrganizerCore::fileMapping( for (const auto& d : directoryEntry->getSubDirectories()) { int origin = d->anyOrigin(); - QString originPath - = QString::fromStdWString(base->getOriginByID(origin).getPath()); - QString dirName = QString::fromStdWString(d->getName()); - QString source = originPath + relPath + dirName; - QString target = dataPath + relPath + dirName; + QString originPath = QString::fromStdWString(base->getOriginByID(origin).getPath()); + QString dirName = QString::fromStdWString(d->getName()); + QString source = originPath + relPath + dirName; + QString target = dataPath + relPath + dirName; - bool writeDestination - = (base == directoryEntry) && (origin == createDestination); + bool writeDestination = (base == directoryEntry) && (origin == createDestination); result.push_back({source, target, true, writeDestination}); - std::vector<Mapping> subRes = fileMapping( - dataPath, relPath + dirName + "\\", base, d, createDestination); + std::vector<Mapping> subRes = + fileMapping(dataPath, relPath + dirName + "\\", base, d, createDestination); result.insert(result.end(), subRes.begin(), subRes.end()); } return result; diff --git a/src/organizercore.h b/src/organizercore.h index dc287b1f..daeb7a7f 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -1,29 +1,29 @@ #ifndef ORGANIZERCORE_H #define ORGANIZERCORE_H -#include "selfupdater.h" -#include "settings.h" -#include "modlist.h" -#include "modinfo.h" -#include "pluginlist.h" -#include "installationmanager.h" #include "downloadmanager.h" +#include "envdump.h" +#include "executableinfo.h" #include "executableslist.h" -#include "usvfsconnector.h" #include "guessedvalue.h" -#include "moshortcut.h" +#include "installationmanager.h" #include "memoizedlock.h" +#include "moddatacontent.h" +#include "modinfo.h" +#include "modlist.h" +#include "moshortcut.h" +#include "pluginlist.h" #include "processrunner.h" +#include "selfupdater.h" +#include "settings.h" #include "uilocker.h" -#include "envdump.h" +#include "usvfsconnector.h" +#include <boost/signals2.hpp> +#include <delayedfilewriter.h> #include <imoinfo.h> #include <iplugindiagnose.h> -#include <versioninfo.h> -#include <delayedfilewriter.h> -#include <boost/signals2.hpp> -#include "executableinfo.h" -#include "moddatacontent.h" #include <log.h> +#include <versioninfo.h> #include <QDir> #include <QFileInfo> @@ -44,17 +44,17 @@ class DirectoryRefresher; namespace MOBase { - template <typename T> class GuessedValue; - class IModInterface; - class IPluginGame; -} +template <typename T> +class GuessedValue; +class IModInterface; +class IPluginGame; +} // namespace MOBase namespace MOShared { - class DirectoryEntry; +class DirectoryEntry; } - class OrganizerCore : public QObject, public MOBase::IPluginDiagnose { @@ -62,14 +62,13 @@ class OrganizerCore : public QObject, public MOBase::IPluginDiagnose Q_INTERFACES(MOBase::IPluginDiagnose) private: - friend class OrganizerProxy; struct SignalCombinerAnd { using result_type = bool; - template<typename InputIterator> + template <typename InputIterator> bool operator()(InputIterator first, InputIterator last) const { while (first != last) { @@ -83,24 +82,28 @@ private: }; private: - - using SignalAboutToRunApplication = boost::signals2::signal<bool(const QString&), SignalCombinerAnd>; - using SignalFinishedRunApplication = boost::signals2::signal<void(const QString&, unsigned int)>; + using SignalAboutToRunApplication = + boost::signals2::signal<bool(const QString&), SignalCombinerAnd>; + using SignalFinishedRunApplication = + boost::signals2::signal<void(const QString&, unsigned int)>; using SignalUserInterfaceInitialized = boost::signals2::signal<void(QMainWindow*)>; using SignalProfileCreated = boost::signals2::signal<void(MOBase::IProfile*)>; - using SignalProfileRenamed = boost::signals2::signal<void(MOBase::IProfile*, QString const&, QString const&)>; + using SignalProfileRenamed = + boost::signals2::signal<void(MOBase::IProfile*, QString const&, QString const&)>; using SignalProfileRemoved = boost::signals2::signal<void(QString const&)>; - using SignalProfileChanged = boost::signals2::signal<void(MOBase::IProfile *, MOBase::IProfile *)>; - using SignalPluginSettingChanged = boost::signals2::signal<void(QString const&, const QString& key, const QVariant&, const QVariant&)>; + using SignalProfileChanged = + boost::signals2::signal<void(MOBase::IProfile*, MOBase::IProfile*)>; + using SignalPluginSettingChanged = boost::signals2::signal<void( + QString const&, const QString& key, const QVariant&, const QVariant&)>; using SignalPluginEnabled = boost::signals2::signal<void(const MOBase::IPlugin*)>; public: - /** * Small holder for the game content returned by the ModDataContent feature (the * list of all possible contents, not the per-mod content). */ - struct ModDataContentHolder { + struct ModDataContentHolder + { using Content = ModDataContent::Content; @@ -114,8 +117,12 @@ public: * * @return the content with the given ID, or a null pointer if it is not found. */ - const Content* findById(int id) const { - auto it = std::find_if(std::begin(m_Contents), std::end(m_Contents), [&id](auto const& content) { return content.id() == id; }); + const Content* findById(int id) const + { + auto it = std::find_if(std::begin(m_Contents), std::end(m_Contents), + [&id](auto const& content) { + return content.id() == id; + }); return it == std::end(m_Contents) ? nullptr : &(*it); } @@ -124,35 +131,41 @@ public: * * @param ids The set of content IDs. * @param fn The function to apply. - * @param includeFilter true to also apply the function to filter-only contents, false otherwise. + * @param includeFilter true to also apply the function to filter-only contents, + * false otherwise. */ template <class Fn> - void forEachContentIn(std::set<int> const& ids, Fn const& fn, bool includeFilter = false) const { + void forEachContentIn(std::set<int> const& ids, Fn const& fn, + bool includeFilter = false) const + { for (const auto& content : m_Contents) { - if ((includeFilter || !content.isOnlyForFilter()) - && ids.find(content.id()) != ids.end()) { + if ((includeFilter || !content.isOnlyForFilter()) && + ids.find(content.id()) != ids.end()) { fn(content); } } } /** - * @brief Apply fnIn to each content whose ID is in the given set, and fnOut to each content not in the - * given set, excluding filter-only content (from both cases) unless includeFilter is true. + * @brief Apply fnIn to each content whose ID is in the given set, and fnOut to each + * content not in the given set, excluding filter-only content (from both cases) + * unless includeFilter is true. * * @param ids The set of content IDs. * @param fnIn Function to apply to content whose IDs are in ids. * @param fnOut Function to apply to content whose IDs are not in ids. - * @param includeFilter true to also apply the function to filter-only contents, false otherwise. + * @param includeFilter true to also apply the function to filter-only contents, + * false otherwise. */ template <class FnIn, class FnOut> - void forEachContentInOrOut(std::set<int> const& ids, FnIn const& fnIn, FnOut const& fnOut, bool includeFilter = false) const { + void forEachContentInOrOut(std::set<int> const& ids, FnIn const& fnIn, + FnOut const& fnOut, bool includeFilter = false) const + { for (const auto& content : m_Contents) { if ((includeFilter || !content.isOnlyForFilter())) { if (ids.find(content.id()) != ids.end()) { fnIn(content); - } - else { + } else { fnOut(content); } } @@ -163,10 +176,12 @@ public: * Apply the given function to each content. * * @param fn The function to apply. - * @param includeFilter true to also apply the function to filter-only contents, false otherwise. + * @param includeFilter true to also apply the function to filter-only contents, + * false otherwise. */ template <class Fn> - void forEachContent(Fn const& fn, bool includeFilter = false) const { + void forEachContent(Fn const& fn, bool includeFilter = false) const + { for (const auto& content : m_Contents) { if (includeFilter || !content.isOnlyForFilter()) { fn(content); @@ -174,38 +189,37 @@ public: } } - ModDataContentHolder& operator=(ModDataContentHolder const&) = delete; - ModDataContentHolder& operator=(ModDataContentHolder&&) = default; + ModDataContentHolder& operator=(ModDataContentHolder&&) = default; private: - std::vector<Content> m_Contents; /** - * @brief Construct a ModDataContentHolder without any contents (e.g., if the feature is - * missing). + * @brief Construct a ModDataContentHolder without any contents (e.g., if the + * feature is missing). */ - ModDataContentHolder() { } + ModDataContentHolder() {} /** * @brief Construct a ModDataContentHold holding the given list of contents. */ - ModDataContentHolder(std::vector<ModDataContent::Content> contents) : - m_Contents(std::move(contents)) { } + ModDataContentHolder(std::vector<ModDataContent::Content> contents) + : m_Contents(std::move(contents)) + {} friend class OrganizerCore; }; public: - OrganizerCore(Settings &settings); + OrganizerCore(Settings& settings); ~OrganizerCore(); void setUserInterface(IUserInterface* ui); - void connectPlugins(PluginContainer *container); + void connectPlugins(PluginContainer* container); - void setManagedGame(MOBase::IPluginGame *game); + void setManagedGame(MOBase::IPluginGame* game); void updateExecutablesList(); void updateModInfoFromDisc(); @@ -213,18 +227,19 @@ public: void checkForUpdates(); void startMOUpdate(); - Settings &settings(); - SelfUpdater *updater() { return &m_Updater; } - InstallationManager *installationManager(); - MOShared::DirectoryEntry *directoryStructure() { return m_DirectoryStructure; } - DirectoryRefresher *directoryRefresher() { return m_DirectoryRefresher.get(); } - ExecutablesList *executablesList() { return &m_ExecutablesList; } - void setExecutablesList(const ExecutablesList &executablesList) { + Settings& settings(); + SelfUpdater* updater() { return &m_Updater; } + InstallationManager* installationManager(); + MOShared::DirectoryEntry* directoryStructure() { return m_DirectoryStructure; } + DirectoryRefresher* directoryRefresher() { return m_DirectoryRefresher.get(); } + ExecutablesList* executablesList() { return &m_ExecutablesList; } + void setExecutablesList(const ExecutablesList& executablesList) + { m_ExecutablesList = executablesList; } - Profile *currentProfile() const { return m_CurrentProfile.get(); } - void setCurrentProfile(const QString &profileName); + Profile* currentProfile() const { return m_CurrentProfile.get(); } + void setCurrentProfile(const QString& profileName); std::vector<QString> enabledArchives(); @@ -234,7 +249,7 @@ public: // PluginContainer& pluginContainer() const; - MOBase::IPluginGame const *managedGame() const; + MOBase::IPluginGame const* managedGame() const; /** * @brief Retrieve the organizer proxy of the currently managed game. @@ -242,7 +257,6 @@ public: */ MOBase::IOrganizer const* managedGameOrganizer() const; - /** * @return the list of contents for the currently managed game, or an empty vector * if the game plugin does not implement the ModDataContent feature. @@ -255,15 +269,14 @@ public: ProcessRunner processRunner(); - bool beforeRun( - const QFileInfo& binary, const QString& profileName, - const QString& customOverwrite, - const QList<MOBase::ExecutableForcedLoadSetting>& forcedLibraries); + bool beforeRun(const QFileInfo& binary, const QString& profileName, + const QString& customOverwrite, + const QList<MOBase::ExecutableForcedLoadSetting>& forcedLibraries); void afterRun(const QFileInfo& binary, DWORD exitCode); - ProcessRunner::Results waitForAllUSVFSProcesses( - UILocker::Reasons reason=UILocker::PreventExit); + ProcessRunner::Results + waitForAllUSVFSProcesses(UILocker::Reasons reason = UILocker::PreventExit); void refreshESPList(bool force = false); void refreshBSAList(); @@ -272,28 +285,31 @@ public: void updateModInDirectoryStructure(unsigned int index, ModInfo::Ptr modInfo); void updateModsInDirectoryStructure(QMap<unsigned int, ModInfo::Ptr> modInfos); - void doAfterLogin(const std::function<void()> &function) { m_PostLoginTasks.append(function); } - void loggedInAction(QWidget* parent, std::function<void ()> f); + void doAfterLogin(const std::function<void()>& function) + { + m_PostLoginTasks.append(function); + } + void loggedInAction(QWidget* parent, std::function<void()> f); - bool previewFileWithAlternatives(QWidget* parent, QString filename, int selectedOrigin=-1); + bool previewFileWithAlternatives(QWidget* parent, QString filename, + int selectedOrigin = -1); bool previewFile(QWidget* parent, const QString& originName, const QString& path); void loginSuccessfulUpdate(bool necessary); - void loginFailedUpdate(const QString &message); + void loginFailedUpdate(const QString& message); - static bool createAndMakeWritable(const QString &path); + static bool createAndMakeWritable(const QString& path); bool checkPathSymlinks(); bool bootstrap(); void createDefaultProfile(); - MOBase::DelayedFileWriter &pluginsWriter() { return m_PluginListsWriter; } + MOBase::DelayedFileWriter& pluginsWriter() { return m_PluginListsWriter; } void prepareVFS(); - void updateVFSParams( - MOBase::log::Levels logLevel, env::CoreDumpTypes coreDumpType, - const QString& coreDumpsPath, std::chrono::seconds spawnDelay, - QString executableBlacklist); + void updateVFSParams(MOBase::log::Levels logLevel, env::CoreDumpTypes coreDumpType, + const QString& coreDumpsPath, std::chrono::seconds spawnDelay, + QString executableBlacklist); void setLogLevel(MOBase::log::Levels level); @@ -304,7 +320,7 @@ public: static std::wstring getGlobalCoreDumpPath(); public: - MOBase::IModRepositoryBridge *createNexusBridge() const; + MOBase::IModRepositoryBridge* createNexusBridge() const; QString profileName() const; QString profilePath() const; QString downloadsPath() const; @@ -312,38 +328,58 @@ public: QString basePath() const; QString modsPath() const; MOBase::VersionInfo appVersion() const; - MOBase::IPluginGame *getGame(const QString &gameName) const; - MOBase::IModInterface *createMod(MOBase::GuessedValue<QString> &name); - void modDataChanged(MOBase::IModInterface *mod); - QVariant pluginSetting(const QString &pluginName, const QString &key) const; - void setPluginSetting(const QString &pluginName, const QString &key, const QVariant &value); - QVariant persistent(const QString &pluginName, const QString &key, const QVariant &def) const; - void setPersistent(const QString &pluginName, const QString &key, const QVariant &value, bool sync); + MOBase::IPluginGame* getGame(const QString& gameName) const; + MOBase::IModInterface* createMod(MOBase::GuessedValue<QString>& name); + void modDataChanged(MOBase::IModInterface* mod); + QVariant pluginSetting(const QString& pluginName, const QString& key) const; + void setPluginSetting(const QString& pluginName, const QString& key, + const QVariant& value); + QVariant persistent(const QString& pluginName, const QString& key, + const QVariant& def) const; + void setPersistent(const QString& pluginName, const QString& key, + const QVariant& value, bool sync); static QString pluginDataPath(); - virtual MOBase::IModInterface *installMod(const QString &fileName, int priority, bool reinstallation, ModInfo::Ptr currentMod, const QString &initModName); - QString resolvePath(const QString &fileName) const; - QStringList listDirectories(const QString &directoryName) const; - QStringList findFiles(const QString &path, const std::function<bool (const QString &)> &filter) const; - QStringList getFileOrigins(const QString &fileName) const; - QList<MOBase::IOrganizer::FileInfo> findFileInfos(const QString &path, const std::function<bool (const MOBase::IOrganizer::FileInfo &)> &filter) const; - DownloadManager *downloadManager(); - PluginList *pluginList(); - ModList *modList(); + virtual MOBase::IModInterface* installMod(const QString& fileName, int priority, + bool reinstallation, + ModInfo::Ptr currentMod, + const QString& initModName); + QString resolvePath(const QString& fileName) const; + QStringList listDirectories(const QString& directoryName) const; + QStringList findFiles(const QString& path, + const std::function<bool(const QString&)>& filter) const; + QStringList getFileOrigins(const QString& fileName) const; + QList<MOBase::IOrganizer::FileInfo> findFileInfos( + const QString& path, + const std::function<bool(const MOBase::IOrganizer::FileInfo&)>& filter) const; + DownloadManager* downloadManager(); + PluginList* pluginList(); + ModList* modList(); void refresh(bool saveChanges = true); - boost::signals2::connection onAboutToRun(const std::function<bool(const QString&)>& func); - boost::signals2::connection onFinishedRun(const std::function<void(const QString&, unsigned int)>& func); - boost::signals2::connection onUserInterfaceInitialized(std::function<void(QMainWindow*)> const& func); - boost::signals2::connection onProfileCreated(std::function<void(MOBase::IProfile*)> const& func); - boost::signals2::connection onProfileRenamed(std::function<void(MOBase::IProfile*, QString const&, QString const&)> const& func); - boost::signals2::connection onProfileRemoved(std::function<void(QString const&)> const& func); - boost::signals2::connection onProfileChanged(std::function<void(MOBase::IProfile*, MOBase::IProfile*)> const& func); - boost::signals2::connection onPluginSettingChanged(std::function<void(QString const&, const QString& key, const QVariant&, const QVariant&)> const& func); - boost::signals2::connection onPluginEnabled(std::function<void(const MOBase::IPlugin*)> const& func); - boost::signals2::connection onPluginDisabled(std::function<void(const MOBase::IPlugin*)> const& func); - -public: // IPluginDiagnose interface + boost::signals2::connection + onAboutToRun(const std::function<bool(const QString&)>& func); + boost::signals2::connection + onFinishedRun(const std::function<void(const QString&, unsigned int)>& func); + boost::signals2::connection + onUserInterfaceInitialized(std::function<void(QMainWindow*)> const& func); + boost::signals2::connection + onProfileCreated(std::function<void(MOBase::IProfile*)> const& func); + boost::signals2::connection onProfileRenamed( + std::function<void(MOBase::IProfile*, QString const&, QString const&)> const& + func); + boost::signals2::connection + onProfileRemoved(std::function<void(QString const&)> const& func); + boost::signals2::connection onProfileChanged( + std::function<void(MOBase::IProfile*, MOBase::IProfile*)> const& func); + boost::signals2::connection onPluginSettingChanged( + std::function<void(QString const&, const QString& key, const QVariant&, + const QVariant&)> const& func); + boost::signals2::connection + onPluginEnabled(std::function<void(const MOBase::IPlugin*)> const& func); + boost::signals2::connection + onPluginDisabled(std::function<void(const MOBase::IPlugin*)> const& func); +public: // IPluginDiagnose interface virtual std::vector<unsigned int> activeProblems() const; virtual QString shortDescription(unsigned int key) const; virtual QString fullDescription(unsigned int key) const; @@ -361,19 +397,22 @@ public slots: void refreshLists(); ModInfo::Ptr installDownload(int downloadIndex, int priority = -1); - ModInfo::Ptr installArchive(const QString& archivePath, int priority = -1, bool reinstallation = false, - ModInfo::Ptr currentMod = nullptr, const QString& modName = QString()); + ModInfo::Ptr installArchive(const QString& archivePath, int priority = -1, + bool reinstallation = false, + ModInfo::Ptr currentMod = nullptr, + const QString& modName = QString()); void modPrioritiesChanged(QModelIndexList const& indexes); void modStatusChanged(unsigned int index); void modStatusChanged(QList<unsigned int> index); - void requestDownload(const QUrl &url, QNetworkReply *reply); - void downloadRequestedNXM(const QString &url); + void requestDownload(const QUrl& url, QNetworkReply* reply); + void downloadRequestedNXM(const QString& url); void userInterfaceInitialized(); void profileCreated(MOBase::IProfile* profile); - void profileRenamed(MOBase::IProfile* profile, QString const& oldName, QString const& newName); + void profileRenamed(MOBase::IProfile* profile, QString const& oldName, + QString const& newName); void profileRemoved(QString const& profileName); bool nexusApi(bool retry = false); @@ -382,11 +421,11 @@ signals: // emitted after a mod has been installed // - void modInstalled(const QString &modName); + void modInstalled(const QString& modName); // emitted when the managed game changes // - void managedGameChanged(MOBase::IPluginGame const *gamePlugin); + void managedGameChanged(MOBase::IPluginGame const* gamePlugin); // emitted when the profile is changed, before notifying plugins // @@ -400,54 +439,55 @@ signals: void directoryStructureReady(); private: - std::pair<unsigned int, ModInfo::Ptr> doInstall(const QString& archivePath, - MOBase::GuessedValue<QString> modName, ModInfo::Ptr currentMod, int priority, bool reinstallation); + MOBase::GuessedValue<QString> modName, + ModInfo::Ptr currentMod, int priority, + bool reinstallation); void saveCurrentProfile(); void storeSettings(); void updateModActiveState(int index, bool active); - void updateModsActiveState(const QList<unsigned int> &modIndices, bool active); + void updateModsActiveState(const QList<unsigned int>& modIndices, bool active); // clear the conflict caches of all the given mods, and the mods in conflict // with the given mods // void clearCaches(std::vector<unsigned int> const& indices) const; - bool createDirectory(const QString &path); + bool createDirectory(const QString& path); QString oldMO1HookDll() const; /** * @brief return a descriptor of the mappings real file->virtual file */ - std::vector<Mapping> fileMapping(const QString &profile, - const QString &customOverwrite); + std::vector<Mapping> fileMapping(const QString& profile, + const QString& customOverwrite); - std::vector<Mapping> - fileMapping(const QString &dataPath, const QString &relPath, - const MOShared::DirectoryEntry *base, - const MOShared::DirectoryEntry *directoryEntry, - int createDestination); + std::vector<Mapping> fileMapping(const QString& dataPath, const QString& relPath, + const MOShared::DirectoryEntry* base, + const MOShared::DirectoryEntry* directoryEntry, + int createDestination); private slots: void directory_refreshed(); - void downloadRequested(QNetworkReply *reply, QString gameName, int modID, const QString &fileName); - void removeOrigin(const QString &name); - void downloadSpeed(const QString &serverName, int bytesPerSecond); + void downloadRequested(QNetworkReply* reply, QString gameName, int modID, + const QString& fileName); + void removeOrigin(const QString& name); + void downloadSpeed(const QString& serverName, int bytesPerSecond); void loginSuccessful(bool necessary); - void loginFailed(const QString &message); + void loginFailed(const QString& message); private: static const unsigned int PROBLEM_MO1SCRIPTEXTENDERWORKAROUND = 1; private: IUserInterface* m_UserInterface; - PluginContainer *m_PluginContainer; + PluginContainer* m_PluginContainer; QString m_GameName; - MOBase::IPluginGame *m_GamePlugin; + MOBase::IPluginGame* m_GamePlugin; ModDataContentHolder m_Contents; std::unique_ptr<Profile> m_CurrentProfile; @@ -470,7 +510,6 @@ private: ModList m_ModList; PluginList m_PluginList; - QList<std::function<void()>> m_PostLoginTasks; QList<std::function<void()>> m_PostRefreshTasks; @@ -480,7 +519,7 @@ private: QStringList m_ActiveArchives; std::unique_ptr<DirectoryRefresher> m_DirectoryRefresher; - MOShared::DirectoryEntry *m_DirectoryStructure; + MOShared::DirectoryEntry* m_DirectoryStructure; MOBase::MemoizedLocked<std::shared_ptr<const MOBase::IFileTree>> m_VirtualFileTree; DownloadManager m_DownloadManager; @@ -499,4 +538,4 @@ private: UILocker m_UILocker; }; -#endif // ORGANIZERCORE_H +#endif // ORGANIZERCORE_H diff --git a/src/organizerproxy.cpp b/src/organizerproxy.cpp index d5118421..a47e8798 100644 --- a/src/organizerproxy.cpp +++ b/src/organizerproxy.cpp @@ -1,30 +1,32 @@ #include "organizerproxy.h" -#include "shared/appconfig.h" -#include "organizercore.h" -#include "plugincontainer.h" -#include "settings.h" -#include "glob_matching.h" #include "downloadmanagerproxy.h" +#include "glob_matching.h" #include "modlistproxy.h" +#include "organizercore.h" +#include "plugincontainer.h" #include "pluginlistproxy.h" #include "proxyutils.h" +#include "settings.h" +#include "shared/appconfig.h" #include "shared/util.h" -#include <QObject> #include <QApplication> +#include <QObject> using namespace MOBase; using namespace MOShared; - -OrganizerProxy::OrganizerProxy(OrganizerCore* organizer, PluginContainer* pluginContainer, MOBase::IPlugin* plugin) - : m_Proxied(organizer) - , m_PluginContainer(pluginContainer) - , m_Plugin(plugin) - , m_DownloadManagerProxy(std::make_unique<DownloadManagerProxy>(this, organizer->downloadManager())) - , m_ModListProxy(std::make_unique<ModListProxy>(this, organizer->modList())) - , m_PluginListProxy(std::make_unique<PluginListProxy>(this, organizer->pluginList())) { } +OrganizerProxy::OrganizerProxy(OrganizerCore* organizer, + PluginContainer* pluginContainer, + MOBase::IPlugin* plugin) + : m_Proxied(organizer), m_PluginContainer(pluginContainer), m_Plugin(plugin), + m_DownloadManagerProxy( + std::make_unique<DownloadManagerProxy>(this, organizer->downloadManager())), + m_ModListProxy(std::make_unique<ModListProxy>(this, organizer->modList())), + m_PluginListProxy( + std::make_unique<PluginListProxy>(this, organizer->pluginList())) +{} OrganizerProxy::~OrganizerProxy() { @@ -33,17 +35,27 @@ OrganizerProxy::~OrganizerProxy() void OrganizerProxy::connectSignals() { - m_Connections.push_back(m_Proxied->onAboutToRun(callSignalIfPluginActive(this, m_AboutToRun, true))); - m_Connections.push_back(m_Proxied->onFinishedRun(callSignalIfPluginActive(this, m_FinishedRun))); - m_Connections.push_back(m_Proxied->onProfileCreated(callSignalIfPluginActive(this, m_ProfileCreated))); - m_Connections.push_back(m_Proxied->onProfileRenamed(callSignalIfPluginActive(this, m_ProfileRenamed))); - m_Connections.push_back(m_Proxied->onProfileRemoved(callSignalIfPluginActive(this, m_ProfileRemoved))); - m_Connections.push_back(m_Proxied->onProfileChanged(callSignalIfPluginActive(this, m_ProfileChanged))); + m_Connections.push_back( + m_Proxied->onAboutToRun(callSignalIfPluginActive(this, m_AboutToRun, true))); + m_Connections.push_back( + m_Proxied->onFinishedRun(callSignalIfPluginActive(this, m_FinishedRun))); + m_Connections.push_back( + m_Proxied->onProfileCreated(callSignalIfPluginActive(this, m_ProfileCreated))); + m_Connections.push_back( + m_Proxied->onProfileRenamed(callSignalIfPluginActive(this, m_ProfileRenamed))); + m_Connections.push_back( + m_Proxied->onProfileRemoved(callSignalIfPluginActive(this, m_ProfileRemoved))); + m_Connections.push_back( + m_Proxied->onProfileChanged(callSignalIfPluginActive(this, m_ProfileChanged))); - m_Connections.push_back(m_Proxied->onUserInterfaceInitialized(callSignalAlways(m_UserInterfaceInitialized))); - m_Connections.push_back(m_Proxied->onPluginSettingChanged(callSignalAlways(m_PluginSettingChanged))); - m_Connections.push_back(m_Proxied->onPluginEnabled(callSignalAlways(m_PluginEnabled))); - m_Connections.push_back(m_Proxied->onPluginDisabled(callSignalAlways(m_PluginDisabled))); + m_Connections.push_back(m_Proxied->onUserInterfaceInitialized( + callSignalAlways(m_UserInterfaceInitialized))); + m_Connections.push_back( + m_Proxied->onPluginSettingChanged(callSignalAlways(m_PluginSettingChanged))); + m_Connections.push_back( + m_Proxied->onPluginEnabled(callSignalAlways(m_PluginEnabled))); + m_Connections.push_back( + m_Proxied->onPluginDisabled(callSignalAlways(m_PluginDisabled))); // Connect the child proxies. m_DownloadManagerProxy->connectSignals(); @@ -64,7 +76,7 @@ void OrganizerProxy::disconnectSignals() m_Connections.clear(); } -IModRepositoryBridge *OrganizerProxy::createNexusBridge() const +IModRepositoryBridge* OrganizerProxy::createNexusBridge() const { return new NexusBridge(m_PluginContainer, m_Plugin->name()); } @@ -104,17 +116,17 @@ VersionInfo OrganizerProxy::appVersion() const return m_Proxied->appVersion(); } -IPluginGame *OrganizerProxy::getGame(const QString &gameName) const +IPluginGame* OrganizerProxy::getGame(const QString& gameName) const { return m_Proxied->getGame(gameName); } -IModInterface *OrganizerProxy::createMod(MOBase::GuessedValue<QString> &name) +IModInterface* OrganizerProxy::createMod(MOBase::GuessedValue<QString>& name) { return m_Proxied->createMod(name); } -void OrganizerProxy::modDataChanged(IModInterface *mod) +void OrganizerProxy::modDataChanged(IModInterface* mod) { m_Proxied->modDataChanged(mod); } @@ -129,22 +141,26 @@ bool OrganizerProxy::isPluginEnabled(IPlugin* plugin) const return m_PluginContainer->isEnabled(plugin); } -QVariant OrganizerProxy::pluginSetting(const QString &pluginName, const QString &key) const +QVariant OrganizerProxy::pluginSetting(const QString& pluginName, + const QString& key) const { return m_Proxied->pluginSetting(pluginName, key); } -void OrganizerProxy::setPluginSetting(const QString &pluginName, const QString &key, const QVariant &value) +void OrganizerProxy::setPluginSetting(const QString& pluginName, const QString& key, + const QVariant& value) { m_Proxied->setPluginSetting(pluginName, key, value); } -QVariant OrganizerProxy::persistent(const QString &pluginName, const QString &key, const QVariant &def) const +QVariant OrganizerProxy::persistent(const QString& pluginName, const QString& key, + const QVariant& def) const { return m_Proxied->persistent(pluginName, key, def); } -void OrganizerProxy::setPersistent(const QString &pluginName, const QString &key, const QVariant &value, bool sync) +void OrganizerProxy::setPersistent(const QString& pluginName, const QString& key, + const QVariant& value, bool sync) { m_Proxied->setPersistent(pluginName, key, value, sync); } @@ -154,39 +170,37 @@ QString OrganizerProxy::pluginDataPath() const return OrganizerCore::pluginDataPath(); } -HANDLE OrganizerProxy::startApplication( - const QString& exe, const QStringList& args, const QString &cwd, - const QString& profile, const QString &overwrite, bool ignoreOverwrite) +HANDLE OrganizerProxy::startApplication(const QString& exe, const QStringList& args, + const QString& cwd, const QString& profile, + const QString& overwrite, bool ignoreOverwrite) { - log::debug( - "a plugin has requested to start an application:\n" - " . executable: '{}'\n" - " . args: '{}'\n" - " . cwd: '{}'\n" - " . profile: '{}'\n" - " . overwrite: '{}'\n" - " . ignore overwrite: {}", - exe, args.join(" "), cwd, profile, overwrite, ignoreOverwrite); + log::debug("a plugin has requested to start an application:\n" + " . executable: '{}'\n" + " . args: '{}'\n" + " . cwd: '{}'\n" + " . profile: '{}'\n" + " . overwrite: '{}'\n" + " . ignore overwrite: {}", + exe, args.join(" "), cwd, profile, overwrite, ignoreOverwrite); auto runner = m_Proxied->processRunner(); // don't wait for completion - runner - .setFromFileOrExecutable(exe, args, cwd, profile, overwrite, ignoreOverwrite) - .run(); + runner.setFromFileOrExecutable(exe, args, cwd, profile, overwrite, ignoreOverwrite) + .run(); // the plugin is in charge of closing the handle, unless waitForApplication() // is called on it return runner.stealProcessHandle().release(); } -bool OrganizerProxy::waitForApplication(HANDLE handle, bool refresh, LPDWORD exitCode) const +bool OrganizerProxy::waitForApplication(HANDLE handle, bool refresh, + LPDWORD exitCode) const { const auto pid = ::GetProcessId(handle); - log::debug( - "a plugin wants to wait for an application to complete, pid {}{}", - pid, (pid == 0 ? "unknown (probably already completed)" : "")); + log::debug("a plugin wants to wait for an application to complete, pid {}{}", pid, + (pid == 0 ? "unknown (probably already completed)" : "")); auto runner = m_Proxied->processRunner(); @@ -196,28 +210,26 @@ bool OrganizerProxy::waitForApplication(HANDLE handle, bool refresh, LPDWORD exi waitFlags |= ProcessRunner::TriggerRefresh | ProcessRunner::WaitForRefresh; } - const auto r = runner - .setWaitForCompletion(waitFlags, UILocker::OutputRequired) - .attachToProcess(handle); + const auto r = runner.setWaitForCompletion(waitFlags, UILocker::OutputRequired) + .attachToProcess(handle); if (exitCode) { *exitCode = runner.exitCode(); } - switch (r) - { - case ProcessRunner::Completed: - return true; + switch (r) { + case ProcessRunner::Completed: + return true; - case ProcessRunner::Cancelled: // fall-through - case ProcessRunner::ForceUnlocked: - // this is always an error because the application should have run to - // completion - return false; + case ProcessRunner::Cancelled: // fall-through + case ProcessRunner::ForceUnlocked: + // this is always an error because the application should have run to + // completion + return false; - case ProcessRunner::Error: // fall-through - default: - return false; + case ProcessRunner::Error: // fall-through + default: + return false; } } @@ -226,27 +238,31 @@ void OrganizerProxy::refresh(bool saveChanges) m_Proxied->refresh(saveChanges); } -IModInterface *OrganizerProxy::installMod(const QString &fileName, const QString &nameSuggestion) +IModInterface* OrganizerProxy::installMod(const QString& fileName, + const QString& nameSuggestion) { return m_Proxied->installMod(fileName, -1, false, nullptr, nameSuggestion); } -QString OrganizerProxy::resolvePath(const QString &fileName) const +QString OrganizerProxy::resolvePath(const QString& fileName) const { return m_Proxied->resolvePath(fileName); } -QStringList OrganizerProxy::listDirectories(const QString &directoryName) const +QStringList OrganizerProxy::listDirectories(const QString& directoryName) const { return m_Proxied->listDirectories(directoryName); } -QStringList OrganizerProxy::findFiles(const QString &path, const std::function<bool(const QString&)> &filter) const +QStringList +OrganizerProxy::findFiles(const QString& path, + const std::function<bool(const QString&)>& filter) const { return m_Proxied->findFiles(path, filter); } -QStringList OrganizerProxy::findFiles(const QString& path, const QStringList& globFilters) const +QStringList OrganizerProxy::findFiles(const QString& path, + const QStringList& globFilters) const { QList<GlobPattern<QChar>> patterns; for (auto& gfilter : globFilters) { @@ -262,12 +278,14 @@ QStringList OrganizerProxy::findFiles(const QString& path, const QStringList& gl }); } -QStringList OrganizerProxy::getFileOrigins(const QString &fileName) const +QStringList OrganizerProxy::getFileOrigins(const QString& fileName) const { return m_Proxied->getFileOrigins(fileName); } -QList<MOBase::IOrganizer::FileInfo> OrganizerProxy::findFileInfos(const QString &path, const std::function<bool (const MOBase::IOrganizer::FileInfo &)> &filter) const +QList<MOBase::IOrganizer::FileInfo> OrganizerProxy::findFileInfos( + const QString& path, + const std::function<bool(const MOBase::IOrganizer::FileInfo&)>& filter) const { return m_Proxied->findFileInfos(path, filter); } @@ -277,27 +295,27 @@ std::shared_ptr<const MOBase::IFileTree> OrganizerProxy::virtualFileTree() const return m_Proxied->m_VirtualFileTree.value(); } -MOBase::IDownloadManager *OrganizerProxy::downloadManager() const +MOBase::IDownloadManager* OrganizerProxy::downloadManager() const { return m_DownloadManagerProxy.get(); } -MOBase::IPluginList *OrganizerProxy::pluginList() const +MOBase::IPluginList* OrganizerProxy::pluginList() const { return m_PluginListProxy.get(); } -MOBase::IModList *OrganizerProxy::modList() const +MOBase::IModList* OrganizerProxy::modList() const { return m_ModListProxy.get(); } -MOBase::IProfile *OrganizerProxy::profile() const +MOBase::IProfile* OrganizerProxy::profile() const { return m_Proxied->currentProfile(); } -MOBase::IPluginGame const *OrganizerProxy::managedGame() const +MOBase::IPluginGame const* OrganizerProxy::managedGame() const { return m_Proxied->managedGame(); } @@ -306,10 +324,12 @@ MOBase::IPluginGame const *OrganizerProxy::managedGame() const bool OrganizerProxy::onAboutToRun(const std::function<bool(const QString&)>& func) { - return m_Proxied->onAboutToRun(MOShared::callIfPluginActive(this, func, true)).connected(); + return m_Proxied->onAboutToRun(MOShared::callIfPluginActive(this, func, true)) + .connected(); } -bool OrganizerProxy::onFinishedRun(const std::function<void(const QString&, unsigned int)>& func) +bool OrganizerProxy::onFinishedRun( + const std::function<void(const QString&, unsigned int)>& func) { return m_Proxied->onFinishedRun(MOShared::callIfPluginActive(this, func)).connected(); } @@ -319,7 +339,8 @@ bool OrganizerProxy::onProfileCreated(std::function<void(IProfile*)> const& func return m_ProfileCreated.connect(func).connected(); } -bool OrganizerProxy::onProfileRenamed(std::function<void(IProfile*, QString const&, QString const&)> const& func) +bool OrganizerProxy::onProfileRenamed( + std::function<void(IProfile*, QString const&, QString const&)> const& func) { return m_ProfileRenamed.connect(func).connected(); } @@ -329,19 +350,24 @@ bool OrganizerProxy::onProfileRemoved(std::function<void(QString const&)> const& return m_ProfileRemoved.connect(func).connected(); } -bool OrganizerProxy::onProfileChanged(std::function<void(MOBase::IProfile*, MOBase::IProfile*)> const& func) +bool OrganizerProxy::onProfileChanged( + std::function<void(MOBase::IProfile*, MOBase::IProfile*)> const& func) { return m_ProfileChanged.connect(func).connected(); } -bool OrganizerProxy::onUserInterfaceInitialized(std::function<void(QMainWindow*)> const& func) +bool OrganizerProxy::onUserInterfaceInitialized( + std::function<void(QMainWindow*)> const& func) { // Always call this one to allow plugin to initialize themselves even when not active: return m_UserInterfaceInitialized.connect(func).connected(); } -// Always call these one, otherwise plugin cannot detect they are being enabled / disabled: -bool OrganizerProxy::onPluginSettingChanged(std::function<void(QString const&, const QString& key, const QVariant&, const QVariant&)> const& func) +// Always call these one, otherwise plugin cannot detect they are being enabled / +// disabled: +bool OrganizerProxy::onPluginSettingChanged( + std::function<void(QString const&, const QString& key, const QVariant&, + const QVariant&)> const& func) { return m_PluginSettingChanged.connect(func).connected(); } @@ -351,13 +377,14 @@ bool OrganizerProxy::onPluginEnabled(std::function<void(const IPlugin*)> const& return m_PluginEnabled.connect(func).connected(); } -bool OrganizerProxy::onPluginEnabled(const QString& pluginName, std::function<void()> const& func) +bool OrganizerProxy::onPluginEnabled(const QString& pluginName, + std::function<void()> const& func) { return onPluginEnabled([=](const IPlugin* plugin) { if (plugin->name().compare(pluginName, Qt::CaseInsensitive) == 0) { func(); } - }); + }); } bool OrganizerProxy::onPluginDisabled(std::function<void(const IPlugin*)> const& func) @@ -365,7 +392,8 @@ bool OrganizerProxy::onPluginDisabled(std::function<void(const IPlugin*)> const& return m_PluginDisabled.connect(func).connected(); } -bool OrganizerProxy::onPluginDisabled(const QString& pluginName, std::function<void()> const& func) +bool OrganizerProxy::onPluginDisabled(const QString& pluginName, + std::function<void()> const& func) { return onPluginDisabled([=](const IPlugin* plugin) { if (plugin->name().compare(pluginName, Qt::CaseInsensitive) == 0) { diff --git a/src/organizerproxy.h b/src/organizerproxy.h index 60e891ed..771d0981 100644 --- a/src/organizerproxy.h +++ b/src/organizerproxy.h @@ -3,8 +3,8 @@ #include <memory> -#include <iplugin.h> #include <imoinfo.h> +#include <iplugin.h> #include "organizercore.h" @@ -17,20 +17,18 @@ class OrganizerProxy : public MOBase::IOrganizer { public: - - OrganizerProxy(OrganizerCore *organizer, PluginContainer *pluginContainer, MOBase::IPlugin *plugin); + OrganizerProxy(OrganizerCore* organizer, PluginContainer* pluginContainer, + MOBase::IPlugin* plugin); ~OrganizerProxy(); public: - /** * @return the plugin corresponding to this proxy. */ - MOBase::IPlugin* plugin() const { return m_Plugin; } + MOBase::IPlugin* plugin() const { return m_Plugin; } -public: // IOrganizer interface - - virtual MOBase::IModRepositoryBridge *createNexusBridge() const; +public: // IOrganizer interface + virtual MOBase::IModRepositoryBridge* createNexusBridge() const; virtual QString profileName() const; virtual QString profilePath() const; virtual QString downloadsPath() const; @@ -38,75 +36,100 @@ public: // IOrganizer interface virtual QString basePath() const; virtual QString modsPath() const; virtual MOBase::VersionInfo appVersion() const; - virtual MOBase::IPluginGame *getGame(const QString &gameName) const; - virtual MOBase::IModInterface *createMod(MOBase::GuessedValue<QString> &name); - virtual void modDataChanged(MOBase::IModInterface *mod); - virtual QVariant persistent(const QString &pluginName, const QString &key, const QVariant &def = QVariant()) const; - virtual void setPersistent(const QString &pluginName, const QString &key, const QVariant &value, bool sync = true); + virtual MOBase::IPluginGame* getGame(const QString& gameName) const; + virtual MOBase::IModInterface* createMod(MOBase::GuessedValue<QString>& name); + virtual void modDataChanged(MOBase::IModInterface* mod); + virtual QVariant persistent(const QString& pluginName, const QString& key, + const QVariant& def = QVariant()) const; + virtual void setPersistent(const QString& pluginName, const QString& key, + const QVariant& value, bool sync = true); virtual QString pluginDataPath() const; - virtual MOBase::IModInterface *installMod(const QString &fileName, const QString &nameSuggestion = QString()); - virtual QString resolvePath(const QString &fileName) const; - virtual QStringList listDirectories(const QString &directoryName) const; - virtual QStringList findFiles(const QString &path, const std::function<bool(const QString &)> &filter) const override; - virtual QStringList findFiles(const QString &path, const QStringList &globFilters) const override; - virtual QStringList getFileOrigins(const QString &fileName) const override; - virtual QList<FileInfo> findFileInfos(const QString &path, const std::function<bool(const FileInfo&)> &filter) const override; + virtual MOBase::IModInterface* installMod(const QString& fileName, + const QString& nameSuggestion = QString()); + virtual QString resolvePath(const QString& fileName) const; + virtual QStringList listDirectories(const QString& directoryName) const; + virtual QStringList + findFiles(const QString& path, + const std::function<bool(const QString&)>& filter) const override; + virtual QStringList findFiles(const QString& path, + const QStringList& globFilters) const override; + virtual QStringList getFileOrigins(const QString& fileName) const override; + virtual QList<FileInfo> + findFileInfos(const QString& path, + const std::function<bool(const FileInfo&)>& filter) const override; virtual std::shared_ptr<const MOBase::IFileTree> virtualFileTree() const override; - virtual MOBase::IDownloadManager *downloadManager() const; - virtual MOBase::IPluginList *pluginList() const; - virtual MOBase::IModList *modList() const; - virtual MOBase::IProfile *profile() const override; - virtual HANDLE startApplication(const QString &executable, const QStringList &args = QStringList(), const QString &cwd = "", - const QString &profile = "", const QString &forcedCustomOverwrite = "", bool ignoreCustomOverwrite = false); - virtual bool waitForApplication(HANDLE handle, bool refresh = true, LPDWORD exitCode = nullptr) const; + virtual MOBase::IDownloadManager* downloadManager() const; + virtual MOBase::IPluginList* pluginList() const; + virtual MOBase::IModList* modList() const; + virtual MOBase::IProfile* profile() const override; + virtual HANDLE startApplication(const QString& executable, + const QStringList& args = QStringList(), + const QString& cwd = "", const QString& profile = "", + const QString& forcedCustomOverwrite = "", + bool ignoreCustomOverwrite = false); + virtual bool waitForApplication(HANDLE handle, bool refresh = true, + LPDWORD exitCode = nullptr) const; virtual void refresh(bool saveChanges); - virtual bool onAboutToRun(const std::function<bool(const QString&)> &func) override; - virtual bool onFinishedRun(const std::function<void (const QString&, unsigned int)> &func) override; - virtual bool onUserInterfaceInitialized(std::function<void(QMainWindow*)> const& func) override; - virtual bool onProfileCreated(std::function<void(MOBase::IProfile*)> const& func) override; - virtual bool onProfileRenamed(std::function<void(MOBase::IProfile*, QString const&, QString const&)> const& func) override; - virtual bool onProfileRemoved(std::function<void(QString const&)> const& func) override; - virtual bool onProfileChanged(std::function<void(MOBase::IProfile*, MOBase::IProfile*)> const& func) override; + virtual bool onAboutToRun(const std::function<bool(const QString&)>& func) override; + virtual bool + onFinishedRun(const std::function<void(const QString&, unsigned int)>& func) override; + virtual bool + onUserInterfaceInitialized(std::function<void(QMainWindow*)> const& func) override; + virtual bool + onProfileCreated(std::function<void(MOBase::IProfile*)> const& func) override; + virtual bool onProfileRenamed( + std::function<void(MOBase::IProfile*, QString const&, QString const&)> const& + func) override; + virtual bool + onProfileRemoved(std::function<void(QString const&)> const& func) override; + virtual bool onProfileChanged( + std::function<void(MOBase::IProfile*, MOBase::IProfile*)> const& func) override; // Plugin related: virtual bool isPluginEnabled(QString const& pluginName) const override; virtual bool isPluginEnabled(MOBase::IPlugin* plugin) const override; - virtual QVariant pluginSetting(const QString& pluginName, const QString& key) const override; - virtual void setPluginSetting(const QString& pluginName, const QString& key, const QVariant& value) override; - virtual bool onPluginSettingChanged(std::function<void(QString const&, const QString& key, const QVariant&, const QVariant&)> const& func) override; - virtual bool onPluginEnabled(std::function<void(const MOBase::IPlugin*)> const& func) override; - virtual bool onPluginEnabled(const QString& pluginName, std::function<void()> const& func) override; - virtual bool onPluginDisabled(std::function<void(const MOBase::IPlugin*)> const& func) override; - virtual bool onPluginDisabled(const QString& pluginName, std::function<void()> const& func) override; + virtual QVariant pluginSetting(const QString& pluginName, + const QString& key) const override; + virtual void setPluginSetting(const QString& pluginName, const QString& key, + const QVariant& value) override; + virtual bool onPluginSettingChanged( + std::function<void(QString const&, const QString& key, const QVariant&, + const QVariant&)> const& func) override; + virtual bool + onPluginEnabled(std::function<void(const MOBase::IPlugin*)> const& func) override; + virtual bool onPluginEnabled(const QString& pluginName, + std::function<void()> const& func) override; + virtual bool + onPluginDisabled(std::function<void(const MOBase::IPlugin*)> const& func) override; + virtual bool onPluginDisabled(const QString& pluginName, + std::function<void()> const& func) override; - virtual MOBase::IPluginGame const *managedGame() const; + virtual MOBase::IPluginGame const* managedGame() const; protected: - // The container needs access to some callbacks to simulate startup. friend class PluginContainer; /** - * @brief Connect the signals from this proxy and all the child proxies (plugin list, mod - * list, etc.) to the actual implementation. Before this call, plugins can register signals - * but they won't be triggered. + * @brief Connect the signals from this proxy and all the child proxies (plugin list, + * mod list, etc.) to the actual implementation. Before this call, plugins can + * register signals but they won't be triggered. */ void connectSignals(); /** - * @brief Disconnect the signals from this proxy and all the child proxies (plugin list, mod - * list, etc.) from the actual implementation. + * @brief Disconnect the signals from this proxy and all the child proxies (plugin + * list, mod list, etc.) from the actual implementation. */ void disconnectSignals(); private: + OrganizerCore* m_Proxied; + PluginContainer* m_PluginContainer; - OrganizerCore *m_Proxied; - PluginContainer *m_PluginContainer; - - MOBase::IPlugin *m_Plugin; + MOBase::IPlugin* m_Plugin; OrganizerCore::SignalAboutToRunApplication m_AboutToRun; OrganizerCore::SignalFinishedRunApplication m_FinishedRun; @@ -124,7 +147,6 @@ private: std::unique_ptr<DownloadManagerProxy> m_DownloadManagerProxy; std::unique_ptr<ModListProxy> m_ModListProxy; std::unique_ptr<PluginListProxy> m_PluginListProxy; - }; -#endif // ORGANIZERPROXY_H +#endif // ORGANIZERPROXY_H diff --git a/src/overwriteinfodialog.cpp b/src/overwriteinfodialog.cpp index 5bd07d3a..366671e7 100644 --- a/src/overwriteinfodialog.cpp +++ b/src/overwriteinfodialog.cpp @@ -18,20 +18,20 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ #include "overwriteinfodialog.h" -#include "ui_overwriteinfodialog.h" +#include "organizercore.h" #include "report.h" +#include "ui_overwriteinfodialog.h" #include "utility.h" -#include "organizercore.h" -#include <QMessageBox> #include <QMenu> +#include <QMessageBox> #include <QShortcut> #include <Shlwapi.h> using namespace MOBase; -OverwriteInfoDialog::OverwriteInfoDialog(ModInfo::Ptr modInfo, QWidget *parent) - : QDialog(parent), ui(new Ui::OverwriteInfoDialog), m_FileSystemModel(nullptr), - m_DeleteAction(nullptr), m_RenameAction(nullptr), m_OpenAction(nullptr) +OverwriteInfoDialog::OverwriteInfoDialog(ModInfo::Ptr modInfo, QWidget* parent) + : QDialog(parent), ui(new Ui::OverwriteInfoDialog), m_FileSystemModel(nullptr), + m_DeleteAction(nullptr), m_RenameAction(nullptr), m_OpenAction(nullptr) { ui->setupUi(this); @@ -44,9 +44,9 @@ OverwriteInfoDialog::OverwriteInfoDialog(ModInfo::Ptr modInfo, QWidget *parent) ui->filesView->setRootIndex(m_FileSystemModel->index(modInfo->absolutePath())); ui->filesView->setColumnWidth(0, 250); - m_DeleteAction = new QAction(tr("&Delete"), ui->filesView); - m_RenameAction = new QAction(tr("&Rename"), ui->filesView); - m_OpenAction = new QAction(tr("&Open"), ui->filesView); + m_DeleteAction = new QAction(tr("&Delete"), ui->filesView); + m_RenameAction = new QAction(tr("&Rename"), ui->filesView); + m_OpenAction = new QAction(tr("&Open"), ui->filesView); m_NewFolderAction = new QAction(tr("&New Folder"), ui->filesView); new QShortcut(QKeySequence::Delete, this, SLOT(delete_activated())); @@ -54,7 +54,8 @@ OverwriteInfoDialog::OverwriteInfoDialog(ModInfo::Ptr modInfo, QWidget *parent) QObject::connect(m_DeleteAction, SIGNAL(triggered()), this, SLOT(deleteTriggered())); QObject::connect(m_RenameAction, SIGNAL(triggered()), this, SLOT(renameTriggered())); QObject::connect(m_OpenAction, SIGNAL(triggered()), this, SLOT(openTriggered())); - QObject::connect(m_NewFolderAction, SIGNAL(triggered()), this, SLOT(createDirectoryTriggered())); + QObject::connect(m_NewFolderAction, SIGNAL(triggered()), this, + SLOT(createDirectoryTriggered())); } OverwriteInfoDialog::~OverwriteInfoDialog() @@ -91,11 +92,12 @@ void OverwriteInfoDialog::setModInfo(ModInfo::Ptr modInfo) if (QDir(modInfo->absolutePath()).exists()) { m_FileSystemModel->setRootPath(modInfo->absolutePath()); } else { - throw MyException(tr("mod not found: %1").arg(qUtf8Printable(modInfo->absolutePath()))); + throw MyException( + tr("mod not found: %1").arg(qUtf8Printable(modInfo->absolutePath()))); } } -bool OverwriteInfoDialog::recursiveDelete(const QModelIndex &index) +bool OverwriteInfoDialog::recursiveDelete(const QModelIndex& index) { for (int childRow = 0; childRow < m_FileSystemModel->rowCount(index); ++childRow) { QModelIndex childIndex = m_FileSystemModel->index(childRow, 0, index); @@ -118,8 +120,7 @@ bool OverwriteInfoDialog::recursiveDelete(const QModelIndex &index) return true; } - -void OverwriteInfoDialog::deleteFile(const QModelIndex &index) +void OverwriteInfoDialog::deleteFile(const QModelIndex& index) { bool res = m_FileSystemModel->isDir(index) ? recursiveDelete(index) @@ -132,33 +133,35 @@ void OverwriteInfoDialog::deleteFile(const QModelIndex &index) void OverwriteInfoDialog::delete_activated() { - if (ui->filesView->hasFocus()) { - QItemSelectionModel *selection = ui->filesView->selectionModel(); + if (ui->filesView->hasFocus()) { + QItemSelectionModel* selection = ui->filesView->selectionModel(); - if (selection->hasSelection() && selection->selectedRows().count() >= 1) { + if (selection->hasSelection() && selection->selectedRows().count() >= 1) { - if (selection->selectedRows().count() == 0) { - return; - } - else if (selection->selectedRows().count() == 1) { - QString fileName = m_FileSystemModel->fileName(selection->selectedRows().at(0)); - if (QMessageBox::question(this, tr("Confirm"), tr("Are you sure you want to delete \"%1\"?").arg(fileName), - QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { - return; - } - } - else { - if (QMessageBox::question(this, tr("Confirm"), tr("Are you sure you want to delete the selected files?"), - QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { - return; - } - } + if (selection->selectedRows().count() == 0) { + return; + } else if (selection->selectedRows().count() == 1) { + QString fileName = m_FileSystemModel->fileName(selection->selectedRows().at(0)); + if (QMessageBox::question( + this, tr("Confirm"), + tr("Are you sure you want to delete \"%1\"?").arg(fileName), + QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { + return; + } + } else { + if (QMessageBox::question( + this, tr("Confirm"), + tr("Are you sure you want to delete the selected files?"), + QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { + return; + } + } - foreach(QModelIndex index, selection->selectedRows()) { - deleteFile(index); - } - } - } + foreach (QModelIndex index, selection->selectedRows()) { + deleteFile(index); + } + } + } } void OverwriteInfoDialog::deleteTriggered() @@ -167,44 +170,44 @@ void OverwriteInfoDialog::deleteTriggered() return; } else if (m_FileSelection.count() == 1) { QString fileName = m_FileSystemModel->fileName(m_FileSelection.at(0)); - if (QMessageBox::question(this, tr("Confirm"), tr("Are you sure you want to delete \"%1\"?").arg(fileName), - QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { + if (QMessageBox::question( + this, tr("Confirm"), + tr("Are you sure you want to delete \"%1\"?").arg(fileName), + QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { return; } } else { - if (QMessageBox::question(this, tr("Confirm"), tr("Are you sure you want to delete the selected files?"), + if (QMessageBox::question(this, tr("Confirm"), + tr("Are you sure you want to delete the selected files?"), QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { return; } } - foreach(QModelIndex index, m_FileSelection) { + foreach (QModelIndex index, m_FileSelection) { deleteFile(index); } } - void OverwriteInfoDialog::renameTriggered() { QModelIndex selection = m_FileSelection.at(0); - QModelIndex index = selection.sibling(selection.row(), 0); + QModelIndex index = selection.sibling(selection.row(), 0); if (!index.isValid() || m_FileSystemModel->isReadOnly()) { - return; + return; } ui->filesView->edit(index); } - -void OverwriteInfoDialog::openFile(const QModelIndex &index) +void OverwriteInfoDialog::openFile(const QModelIndex& index) { shell::Open(m_FileSystemModel->filePath(index)); } - void OverwriteInfoDialog::openTriggered() { - foreach(QModelIndex idx, m_FileSelection) { + foreach (QModelIndex idx, m_FileSelection) { openFile(idx); } } @@ -213,17 +216,17 @@ void OverwriteInfoDialog::createDirectoryTriggered() { QModelIndex selection = m_FileSelection.at(0); - QModelIndex index = m_FileSystemModel->isDir(selection) ? selection - : selection.parent(); + QModelIndex index = + m_FileSystemModel->isDir(selection) ? selection : selection.parent(); index = index.sibling(index.row(), 0); QString name = tr("New Folder"); QString path = m_FileSystemModel->filePath(index).append("/"); QModelIndex existingIndex = m_FileSystemModel->index(path + name); - int suffix = 1; + int suffix = 1; while (existingIndex.isValid()) { - name = tr("New Folder") + QString::number(suffix++); + name = tr("New Folder") + QString::number(suffix++); existingIndex = m_FileSystemModel->index(path + name); } @@ -242,10 +245,10 @@ void OverwriteInfoDialog::on_explorerButton_clicked() shell::Explore(m_ModInfo->absolutePath()); } -void OverwriteInfoDialog::on_filesView_customContextMenuRequested(const QPoint &pos) +void OverwriteInfoDialog::on_filesView_customContextMenuRequested(const QPoint& pos) { - QItemSelectionModel *selectionModel = ui->filesView->selectionModel(); - m_FileSelection = selectionModel->selectedRows(0); + QItemSelectionModel* selectionModel = ui->filesView->selectionModel(); + m_FileSelection = selectionModel->selectedRows(0); QMenu menu(ui->filesView); @@ -253,7 +256,7 @@ void OverwriteInfoDialog::on_filesView_customContextMenuRequested(const QPoint & bool hasFiles = false; - foreach(QModelIndex idx, m_FileSelection) { + foreach (QModelIndex idx, m_FileSelection) { if (m_FileSystemModel->fileInfo(idx).isFile()) { hasFiles = true; break; diff --git a/src/overwriteinfodialog.h b/src/overwriteinfodialog.h index c62455fe..e9fa3439 100644 --- a/src/overwriteinfodialog.h +++ b/src/overwriteinfodialog.h @@ -24,7 +24,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QDialog> #include <QFileSystemModel> -namespace Ui { +namespace Ui +{ class OverwriteInfoDialog; } @@ -33,17 +34,19 @@ class OverwriteFileSystemModel : public QFileSystemModel Q_OBJECT; public: - OverwriteFileSystemModel(QObject *parent) - : QFileSystemModel(parent), m_RegularColumnCount(0) {} + OverwriteFileSystemModel(QObject* parent) + : QFileSystemModel(parent), m_RegularColumnCount(0) + {} - virtual int columnCount(const QModelIndex &parent) const { + virtual int columnCount(const QModelIndex& parent) const + { m_RegularColumnCount = QFileSystemModel::columnCount(parent); return m_RegularColumnCount; } - virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const { - if ((orientation == Qt::Horizontal) && - (section >= m_RegularColumnCount)) { + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const + { + if ((orientation == Qt::Horizontal) && (section >= m_RegularColumnCount)) { if (role == Qt::DisplayRole) { return tr("Overwrites"); } else { @@ -54,7 +57,8 @@ public: } } - virtual QVariant data(const QModelIndex &index, int role) const { + virtual QVariant data(const QModelIndex& index, int role) const + { if (index.column() == m_RegularColumnCount + 0) { if (role == Qt::DisplayRole) { return tr("not implemented"); @@ -70,14 +74,12 @@ private: mutable int m_RegularColumnCount; }; - class OverwriteInfoDialog : public QDialog { Q_OBJECT public: - - explicit OverwriteInfoDialog(ModInfo::Ptr modInfo, QWidget *parent = 0); + explicit OverwriteInfoDialog(ModInfo::Ptr modInfo, QWidget* parent = 0); ~OverwriteInfoDialog(); ModInfo::Ptr modInfo() const { return m_ModInfo; } @@ -94,10 +96,9 @@ protected: void showEvent(QShowEvent* e) override; private: - - void openFile(const QModelIndex &index); - bool recursiveDelete(const QModelIndex &index); - void deleteFile(const QModelIndex &index); + void openFile(const QModelIndex& index); + bool recursiveDelete(const QModelIndex& index); + void deleteFile(const QModelIndex& index); private slots: @@ -109,20 +110,18 @@ private slots: void createDirectoryTriggered(); void on_explorerButton_clicked(); - void on_filesView_customContextMenuRequested(const QPoint &pos); + void on_filesView_customContextMenuRequested(const QPoint& pos); private: - - Ui::OverwriteInfoDialog *ui; - QFileSystemModel *m_FileSystemModel; + Ui::OverwriteInfoDialog* ui; + QFileSystemModel* m_FileSystemModel; QModelIndexList m_FileSelection; - QAction *m_DeleteAction; - QAction *m_RenameAction; - QAction *m_OpenAction; - QAction *m_NewFolderAction; + QAction* m_DeleteAction; + QAction* m_RenameAction; + QAction* m_OpenAction; + QAction* m_NewFolderAction; ModInfo::Ptr m_ModInfo; - }; -#endif // OVERWRITEINFODIALOG_H +#endif // OVERWRITEINFODIALOG_H @@ -7,8 +7,8 @@ #include <ctime> #include <deque> #include <exception> -#include <functional> #include <fstream> +#include <functional> #include <iomanip> #include <iostream> #include <limits.h> @@ -32,14 +32,14 @@ #include <wchar.h> // windows -#include <Windows.h> #include <DbgHelp.h> -#include <eh.h> #include <LMCons.h> #include <Psapi.h> #include <Shellapi.h> -#include <shlobj.h> #include <Shlwapi.h> +#include <Windows.h> +#include <eh.h> +#include <shlobj.h> #include <tchar.h> #include <wincred.h> #include <windowsx.h> @@ -55,6 +55,7 @@ #include <boost/fusion/include/at_key.hpp> #include <boost/fusion/include/for_each.hpp> #include <boost/fusion/sequence/intrinsic/at_key.hpp> +#include <boost/program_options.hpp> #include <boost/ptr_container/ptr_vector.hpp> #include <boost/range/adaptor/reversed.hpp> #include <boost/scoped_array.hpp> @@ -64,7 +65,6 @@ #include <boost/thread.hpp> #include <boost/uuid/uuid_generators.hpp> #include <boost/uuid/uuid_io.hpp> -#include <boost/program_options.hpp> // openssl #include <tlhelp32.h> @@ -263,4 +263,3 @@ #include <QtGui/QtGui> #include <QtPlugin> #include <QtTest/QtTest> -#include <QStandardPaths> diff --git a/src/persistentcookiejar.cpp b/src/persistentcookiejar.cpp index 104a441a..4afd9891 100644 --- a/src/persistentcookiejar.cpp +++ b/src/persistentcookiejar.cpp @@ -1,29 +1,32 @@ #include "persistentcookiejar.h" -#include <log.h> -#include <QTemporaryFile> #include <QDataStream> #include <QNetworkCookie> +#include <QTemporaryFile> +#include <log.h> using namespace MOBase; -PersistentCookieJar::PersistentCookieJar(const QString &fileName, QObject *parent) -: QNetworkCookieJar(parent), m_FileName(fileName) +PersistentCookieJar::PersistentCookieJar(const QString& fileName, QObject* parent) + : QNetworkCookieJar(parent), m_FileName(fileName) { restore(); } -PersistentCookieJar::~PersistentCookieJar() { +PersistentCookieJar::~PersistentCookieJar() +{ log::debug("save {}", m_FileName); save(); } -void PersistentCookieJar::clear() { - for (const QNetworkCookie &cookie : allCookies()) { +void PersistentCookieJar::clear() +{ + for (const QNetworkCookie& cookie : allCookies()) { deleteCookie(cookie); } } -void PersistentCookieJar::save() { +void PersistentCookieJar::save() +{ QTemporaryFile file; if (!file.open()) { log::error("failed to save cookies: couldn't create temporary file"); @@ -34,7 +37,7 @@ void PersistentCookieJar::save() { QList<QNetworkCookie> cookies = allCookies(); data << static_cast<quint32>(cookies.size()); - for (const QNetworkCookie &cookie : allCookies()) { + for (const QNetworkCookie& cookie : allCookies()) { data << cookie.toRawForm(); } @@ -45,7 +48,7 @@ void PersistentCookieJar::save() { log::error("failed to save cookies: failed to remove {}", m_FileName); return; } - } // if it doesn't exists that's fine + } // if it doesn't exists that's fine } if (!file.copy(m_FileName)) { @@ -53,7 +56,8 @@ void PersistentCookieJar::save() { } } -void PersistentCookieJar::restore() { +void PersistentCookieJar::restore() +{ QFile file(m_FileName); if (!file.open(QIODevice::ReadOnly)) { // not necessarily a problem, the file may just not exist (yet) diff --git a/src/persistentcookiejar.h b/src/persistentcookiejar.h index fcf645f4..483886ab 100644 --- a/src/persistentcookiejar.h +++ b/src/persistentcookiejar.h @@ -3,28 +3,24 @@ #include <QNetworkCookieJar> - -class PersistentCookieJar : public QNetworkCookieJar { +class PersistentCookieJar : public QNetworkCookieJar +{ Q_OBJECT public: - PersistentCookieJar(const QString &fileName, QObject *parent = 0); + PersistentCookieJar(const QString& fileName, QObject* parent = 0); virtual ~PersistentCookieJar(); void clear(); private: - void save(); void restore(); private: - QString m_FileName; - }; - -#endif // PERSISTENTCOOKIEJAR_H +#endif // PERSISTENTCOOKIEJAR_H diff --git a/src/plugincontainer.cpp b/src/plugincontainer.cpp index a6455e96..157d3399 100644 --- a/src/plugincontainer.cpp +++ b/src/plugincontainer.cpp @@ -1,20 +1,20 @@ #include "plugincontainer.h" +#include "iuserinterface.h" #include "organizercore.h" #include "organizerproxy.h" #include "report.h" -#include <ipluginproxy.h> -#include "iuserinterface.h" -#include <idownloadmanager.h> #include "shared/appconfig.h" #include <QAction> -#include <QToolButton> #include <QCoreApplication> -#include <QMessageBox> #include <QDirIterator> -#include <boost/fusion/sequence/intrinsic/at_key.hpp> -#include <boost/fusion/include/at_key.hpp> +#include <QMessageBox> +#include <QToolButton> #include <boost/fusion/algorithm/iteration/for_each.hpp> +#include <boost/fusion/include/at_key.hpp> #include <boost/fusion/include/for_each.hpp> +#include <boost/fusion/sequence/intrinsic/at_key.hpp> +#include <idownloadmanager.h> +#include <ipluginproxy.h> using namespace MOBase; using namespace MOShared; @@ -30,19 +30,23 @@ namespace bf = boost::fusion; // IPluginDiagnose and IPluginFileMapper. It is not possible for a class to implement // two full plugin types (e.g. IPluginPreview and IPluginTool). // -// Plugins are fetch as QObject initially and must be "qobject-casted" to the right type. +// Plugins are fetch as QObject initially and must be "qobject-casted" to the right +// type. // -// Plugins are stored in the PluginContainer class in various C++ containers: there is a vector -// that stores all the plugin as QObject, multiple vectors that stores the plugin of each types, -// a map to find IPlugin object from their names or from IPluginDiagnose or IFileMapper (since -// these do not inherit IPlugin, they cannot be downcasted). +// Plugins are stored in the PluginContainer class in various C++ containers: there is a +// vector that stores all the plugin as QObject, multiple vectors that stores the plugin +// of each types, a map to find IPlugin object from their names or from IPluginDiagnose +// or IFileMapper (since these do not inherit IPlugin, they cannot be downcasted). // // Requirements for plugins are stored in m_Requirements: -// - IPluginGame cannot be enabled by user. A game plugin is considered enable only if it is +// - IPluginGame cannot be enabled by user. A game plugin is considered enable only if +// it is // the one corresponding to the currently managed games. -// - If a plugin has a master plugin (IPlugin::master()), it cannot be enabled/disabled by users, +// - If a plugin has a master plugin (IPlugin::master()), it cannot be enabled/disabled +// by users, // and will follow the enabled/disabled state of its parent. -// - Each plugin has an "enabled" setting stored in persistence. If the setting does not exist, +// - Each plugin has an "enabled" setting stored in persistence. If the setting does +// not exist, // the plugin's enabledByDefault is used instead. // - A plugin is considered disabled if the setting is false. // - If the setting is true, a plugin is considered disabled if one of its @@ -51,38 +55,79 @@ namespace bf = boost::fusion; // // Now let's move to the Proxy side... Or the as of now, the Python side. // -// Proxied plugins are much more annoying because they can implement all interfaces, and are -// given to MO2 as separate plugins... A Python class implementing IPluginGame and IPluginDiagnose -// will be seen by MO2 as two separate QObject, and they will all have the same name. +// Proxied plugins are much more annoying because they can implement all interfaces, and +// are given to MO2 as separate plugins... A Python class implementing IPluginGame and +// IPluginDiagnose will be seen by MO2 as two separate QObject, and they will all have +// the same name. // // When a proxied plugin is registered, a few things must be taken care of: -// - There can only be one plugin mapped to a name in the PluginContainer class, so we keep the -// plugin corresponding to the most relevant class (see PluginTypeOrder), e.g. if the class -// inherits both IPluginGame and IPluginFileMapper, we map the name to the C++ QObject corresponding -// to the IPluginGame. -// - When a proxied plugin implements multiple interfaces, the IPlugin corresponding to the most -// important interface is set as the parent (hidden) of the other IPlugin through PluginRequirements. -// This way, the plugin are managed together (enabled/disabled state). The "fake" children plugins -// will not be returned by PluginRequirements::children(). -// - Since each interface corresponds to a different QObject, we need to take care not to call +// - There can only be one plugin mapped to a name in the PluginContainer class, so we +// keep the +// plugin corresponding to the most relevant class (see PluginTypeOrder), e.g. if the +// class inherits both IPluginGame and IPluginFileMapper, we map the name to the C++ +// QObject corresponding to the IPluginGame. +// - When a proxied plugin implements multiple interfaces, the IPlugin corresponding to +// the most +// important interface is set as the parent (hidden) of the other IPlugin through +// PluginRequirements. This way, the plugin are managed together (enabled/disabled +// state). The "fake" children plugins will not be returned by +// PluginRequirements::children(). +// - Since each interface corresponds to a different QObject, we need to take care not +// to call // IPlugin::init() on each QObject, but only on the first one. // -// All the proxied plugins are linked to the proxy plugin by PluginRequirements. If the proxy plugin -// is disabled, the proxied plugins are not even loaded so not visible in the plugin management tab. +// All the proxied plugins are linked to the proxy plugin by PluginRequirements. If the +// proxy plugin is disabled, the proxied plugins are not even loaded so not visible in +// the plugin management tab. template <class T> struct PluginTypeName; -template <> struct PluginTypeName<MOBase::IPlugin> { static QString value() { return QT_TR_NOOP("Plugin"); } }; -template <> struct PluginTypeName<MOBase::IPluginDiagnose> { static QString value() { return QT_TR_NOOP("Diagnose"); } }; -template <> struct PluginTypeName<MOBase::IPluginGame> { static QString value() { return QT_TR_NOOP("Game"); } }; -template <> struct PluginTypeName<MOBase::IPluginInstaller> { static QString value() { return QT_TR_NOOP("Installer"); } }; -template <> struct PluginTypeName<MOBase::IPluginModPage> { static QString value() { return QT_TR_NOOP("Mod Page"); } }; -template <> struct PluginTypeName<MOBase::IPluginPreview> { static QString value() { return QT_TR_NOOP("Preview"); } }; -template <> struct PluginTypeName<MOBase::IPluginTool> { static QString value() { return QT_TR_NOOP("Tool"); } }; -template <> struct PluginTypeName<MOBase::IPluginProxy> { static QString value() { return QT_TR_NOOP("Proxy"); } }; -template <> struct PluginTypeName<MOBase::IPluginFileMapper> { static QString value() { return QT_TR_NOOP("File Mapper"); } }; - +template <> +struct PluginTypeName<MOBase::IPlugin> +{ + static QString value() { return QT_TR_NOOP("Plugin"); } +}; +template <> +struct PluginTypeName<MOBase::IPluginDiagnose> +{ + static QString value() { return QT_TR_NOOP("Diagnose"); } +}; +template <> +struct PluginTypeName<MOBase::IPluginGame> +{ + static QString value() { return QT_TR_NOOP("Game"); } +}; +template <> +struct PluginTypeName<MOBase::IPluginInstaller> +{ + static QString value() { return QT_TR_NOOP("Installer"); } +}; +template <> +struct PluginTypeName<MOBase::IPluginModPage> +{ + static QString value() { return QT_TR_NOOP("Mod Page"); } +}; +template <> +struct PluginTypeName<MOBase::IPluginPreview> +{ + static QString value() { return QT_TR_NOOP("Preview"); } +}; +template <> +struct PluginTypeName<MOBase::IPluginTool> +{ + static QString value() { return QT_TR_NOOP("Tool"); } +}; +template <> +struct PluginTypeName<MOBase::IPluginProxy> +{ + static QString value() { return QT_TR_NOOP("Proxy"); } +}; +template <> +struct PluginTypeName<MOBase::IPluginFileMapper> +{ + static QString value() { return QT_TR_NOOP("File Mapper"); } +}; QStringList PluginContainer::pluginInterfaces() { @@ -90,7 +135,7 @@ QStringList PluginContainer::pluginInterfaces() QStringList names; boost::mp11::mp_for_each<PluginTypeOrder>([&names](const auto* p) { using plugin_type = std::decay_t<decltype(*p)>; - auto name = PluginTypeName<plugin_type>::value(); + auto name = PluginTypeName<plugin_type>::value(); if (!name.isEmpty()) { names.append(name); } @@ -99,27 +144,22 @@ QStringList PluginContainer::pluginInterfaces() return names; } - // PluginRequirementProxy -const std::set<QString> PluginRequirements::s_CorePlugins{ - "INI Bakery" -}; +const std::set<QString> PluginRequirements::s_CorePlugins{"INI Bakery"}; -PluginRequirements::PluginRequirements( - PluginContainer* pluginContainer, MOBase::IPlugin* plugin, OrganizerProxy* proxy, - MOBase::IPluginProxy* pluginProxy) - : m_PluginContainer(pluginContainer) - , m_Plugin(plugin) - , m_PluginProxy(pluginProxy) - , m_Master(nullptr) - , m_Organizer(proxy) +PluginRequirements::PluginRequirements(PluginContainer* pluginContainer, + MOBase::IPlugin* plugin, OrganizerProxy* proxy, + MOBase::IPluginProxy* pluginProxy) + : m_PluginContainer(pluginContainer), m_Plugin(plugin), m_PluginProxy(pluginProxy), + m_Master(nullptr), m_Organizer(proxy) { // There are a lots of things we cannot set here (e.g. m_Master) because we do not // know the order plugins are loaded. } -void PluginRequirements::fetchRequirements() { +void PluginRequirements::fetchRequirements() +{ m_Requirements = m_Plugin->requirements(); } @@ -171,9 +211,8 @@ std::vector<IPlugin*> PluginRequirements::children() const // masters. // If the master has the same name as the plugin, this is a "hidden" // master, we do not add it here. - if (plugin - && m_PluginContainer->requirements(plugin).master() == m_Plugin - && plugin->name() != m_Plugin->name()) { + if (plugin && m_PluginContainer->requirements(plugin).master() == m_Plugin && + plugin->name() != m_Plugin->name()) { children.push_back(plugin); } } @@ -216,7 +255,8 @@ QStringList PluginRequirements::requiredGames() const // We look for a "GameDependencyRequirement" - There can be only one since otherwise // it'd mean that the plugin requires two games at once. for (auto& requirement : m_Requirements) { - if (auto* gdep = dynamic_cast<const GameDependencyRequirement*>(requirement.get())) { + if (auto* gdep = + dynamic_cast<const GameDependencyRequirement*>(requirement.get())) { return gdep->gameNames(); } } @@ -232,8 +272,8 @@ std::vector<MOBase::IPlugin*> PluginRequirements::requiredFor() const return required; } - -void PluginRequirements::requiredFor(std::vector<MOBase::IPlugin*> &required, std::set<MOBase::IPlugin*>& visited) const +void PluginRequirements::requiredFor(std::vector<MOBase::IPlugin*>& required, + std::set<MOBase::IPlugin*>& visited) const { // Handle cyclic dependencies. if (visited.contains(m_Plugin)) { @@ -241,7 +281,6 @@ void PluginRequirements::requiredFor(std::vector<MOBase::IPlugin*> &required, st } visited.insert(m_Plugin); - for (auto& [plugin, requirements] : m_PluginContainer->m_Requirements) { // If the plugin is not enabled, discard: @@ -253,13 +292,15 @@ void PluginRequirements::requiredFor(std::vector<MOBase::IPlugin*> &required, st for (auto& requirement : requirements.m_Requirements) { // We check for plugin dependency. Game dependency are not checked this way. - if (auto* pdep = dynamic_cast<const PluginDependencyRequirement*>(requirement.get())) { + if (auto* pdep = + dynamic_cast<const PluginDependencyRequirement*>(requirement.get())) { - // Check if at least one of the plugin in the requirements is enabled (except this - // one): + // Check if at least one of the plugin in the requirements is enabled (except + // this one): bool oneEnabled = false; for (auto& pluginName : pdep->pluginNames()) { - if (pluginName != m_Plugin->name() && m_PluginContainer->isEnabled(pluginName)) { + if (pluginName != m_Plugin->name() && + m_PluginContainer->isEnabled(pluginName)) { oneEnabled = true; break; } @@ -278,19 +319,17 @@ void PluginRequirements::requiredFor(std::vector<MOBase::IPlugin*> &required, st // PluginContainer -PluginContainer::PluginContainer(OrganizerCore *organizer) - : m_Organizer(organizer) - , m_UserInterface(nullptr) - , m_PreviewGenerator(*this) -{ -} +PluginContainer::PluginContainer(OrganizerCore* organizer) + : m_Organizer(organizer), m_UserInterface(nullptr), m_PreviewGenerator(*this) +{} -PluginContainer::~PluginContainer() { +PluginContainer::~PluginContainer() +{ m_Organizer = nullptr; unloadPlugins(); } -void PluginContainer::startPlugins(IUserInterface *userInterface) +void PluginContainer::startPlugins(IUserInterface* userInterface) { m_UserInterface = userInterface; startPluginsImpl(plugins<QObject>()); @@ -308,7 +347,7 @@ QStringList PluginContainer::implementedInterfaces(IPlugin* plugin) const return implementedInterfaces(oPlugin); } -QStringList PluginContainer::implementedInterfaces(QObject * oPlugin) const +QStringList PluginContainer::implementedInterfaces(QObject* oPlugin) const { // Find all the names: QStringList names; @@ -320,7 +359,7 @@ QStringList PluginContainer::implementedInterfaces(QObject * oPlugin) const names.append(name); } } - }); + }); // If the plugin implements at least one interface other than IPlugin, remove IPlugin: if (names.size() > 1) { @@ -355,13 +394,14 @@ bool PluginContainer::isBetterInterface(QObject* lhs, QObject* rhs) const QStringList PluginContainer::pluginFileNames() const { QStringList result; - for (QPluginLoader *loader : m_PluginLoaders) { + for (QPluginLoader* loader : m_PluginLoaders) { result.append(loader->fileName()); } - std::vector<IPluginProxy *> proxyList = bf::at_key<IPluginProxy>(m_Plugins); - for (IPluginProxy *proxy : proxyList) { - QStringList proxiedPlugins = proxy->pluginList( - QCoreApplication::applicationDirPath() + "/" + ToQString(AppConfig::pluginPath())); + std::vector<IPluginProxy*> proxyList = bf::at_key<IPluginProxy>(m_Plugins); + for (IPluginProxy* proxy : proxyList) { + QStringList proxiedPlugins = + proxy->pluginList(QCoreApplication::applicationDirPath() + "/" + + ToQString(AppConfig::pluginPath())); result.append(proxiedPlugins); } return result; @@ -371,9 +411,10 @@ QObject* PluginContainer::as_qobject(MOBase::IPlugin* plugin) const { // Find the correspond QObject - Can this be done safely with a cast? auto& objects = bf::at_key<QObject>(m_Plugins); - auto it = std::find_if(std::begin(objects), std::end(objects), [plugin](QObject* obj) { - return qobject_cast<IPlugin*>(obj) == plugin; - }); + auto it = + std::find_if(std::begin(objects), std::end(objects), [plugin](QObject* obj) { + return qobject_cast<IPlugin*>(obj) == plugin; + }); if (it == std::end(objects)) { return nullptr; @@ -382,7 +423,8 @@ QObject* PluginContainer::as_qobject(MOBase::IPlugin* plugin) const return *it; } -bool PluginContainer::initPlugin(IPlugin *plugin, IPluginProxy *pluginProxy, bool skipInit) +bool PluginContainer::initPlugin(IPlugin* plugin, IPluginProxy* pluginProxy, + bool skipInit) { // when MO has no instance loaded, init() is not called on plugins, except // for proxy plugins, where init() is called with a null IOrganizer @@ -404,7 +446,8 @@ bool PluginContainer::initPlugin(IPlugin *plugin, IPluginProxy *pluginProxy, boo // Check if it is a proxy plugin: bool isProxy = dynamic_cast<IPluginProxy*>(plugin); - auto [it, bl] = m_Requirements.emplace(plugin, PluginRequirements(this, plugin, proxy, pluginProxy)); + auto [it, bl] = m_Requirements.emplace( + plugin, PluginRequirements(this, plugin, proxy, pluginProxy)); if (!m_Organizer && !isProxy) { return true; @@ -425,9 +468,9 @@ bool PluginContainer::initPlugin(IPlugin *plugin, IPluginProxy *pluginProxy, boo return true; } -void PluginContainer::registerGame(IPluginGame *game) +void PluginContainer::registerGame(IPluginGame* game) { - m_SupportedGames.insert({ game->gameName(), game }); + m_SupportedGames.insert({game->gameName(), game}); } void PluginContainer::unregisterGame(MOBase::IPluginGame* game) @@ -435,44 +478,47 @@ void PluginContainer::unregisterGame(MOBase::IPluginGame* game) m_SupportedGames.erase(game->gameName()); } -IPlugin* PluginContainer::registerPlugin(QObject *plugin, const QString& filepath, MOBase::IPluginProxy* pluginProxy) +IPlugin* PluginContainer::registerPlugin(QObject* plugin, const QString& filepath, + MOBase::IPluginProxy* pluginProxy) { // generic treatment for all plugins - IPlugin *pluginObj = qobject_cast<IPlugin*>(plugin); + IPlugin* pluginObj = qobject_cast<IPlugin*>(plugin); if (pluginObj == nullptr) { log::debug("PluginContainer::registerPlugin() called with a non IPlugin QObject."); return nullptr; } // If we already a plugin with this name: - bool skipInit = false; + bool skipInit = false; auto& mapNames = bf::at_key<QString>(m_AccessPlugins); if (mapNames.contains(pluginObj->name())) { IPlugin* other = mapNames[pluginObj->name()]; // If both plugins are from the same proxy and the same file, this is usually - // ok (in theory some one could write two different classes from the same Python file/module): - if (pluginProxy && m_Requirements.at(other).proxy() == pluginProxy - && this->filepath(other) == QDir::cleanPath(filepath)) { + // ok (in theory some one could write two different classes from the same Python + // file/module): + if (pluginProxy && m_Requirements.at(other).proxy() == pluginProxy && + this->filepath(other) == QDir::cleanPath(filepath)) { // Plugin has already been initialized: skipInit = true; if (isBetterInterface(plugin, as_qobject(other))) { - log::debug("replacing plugin '{}' with interfaces [{}] by one with interfaces [{}]", - pluginObj->name(), implementedInterfaces(other).join(", "), implementedInterfaces(plugin).join(", ")); + log::debug( + "replacing plugin '{}' with interfaces [{}] by one with interfaces [{}]", + pluginObj->name(), implementedInterfaces(other).join(", "), + implementedInterfaces(plugin).join(", ")); bf::at_key<QString>(m_AccessPlugins)[pluginObj->name()] = pluginObj; } - } - else { - log::warn("Trying to register two plugins with the name '{}' (from {} and {}), the second one will not be registered.", - pluginObj->name(), this->filepath(other), QDir::cleanPath(filepath)); + } else { + log::warn("Trying to register two plugins with the name '{}' (from {} and {}), " + "the second one will not be registered.", + pluginObj->name(), this->filepath(other), QDir::cleanPath(filepath)); return nullptr; } - } - else { + } else { bf::at_key<QString>(m_AccessPlugins)[pluginObj->name()] = pluginObj; } @@ -487,31 +533,33 @@ IPlugin* PluginContainer::registerPlugin(QObject *plugin, const QString& filepat m_Organizer->settings().plugins().registerPlugin(pluginObj); } - { // diagnosis plugin - IPluginDiagnose *diagnose = qobject_cast<IPluginDiagnose*>(plugin); + { // diagnosis plugin + IPluginDiagnose* diagnose = qobject_cast<IPluginDiagnose*>(plugin); if (diagnose != nullptr) { bf::at_key<IPluginDiagnose>(m_Plugins).push_back(diagnose); bf::at_key<IPluginDiagnose>(m_AccessPlugins)[diagnose] = pluginObj; - diagnose->onInvalidated([&]() { emit diagnosisUpdate(); }); + diagnose->onInvalidated([&]() { + emit diagnosisUpdate(); + }); } } - { // file mapper plugin - IPluginFileMapper *mapper = qobject_cast<IPluginFileMapper*>(plugin); + { // file mapper plugin + IPluginFileMapper* mapper = qobject_cast<IPluginFileMapper*>(plugin); if (mapper != nullptr) { bf::at_key<IPluginFileMapper>(m_Plugins).push_back(mapper); bf::at_key<IPluginFileMapper>(m_AccessPlugins)[mapper] = pluginObj; } } - { // mod page plugin - IPluginModPage *modPage = qobject_cast<IPluginModPage*>(plugin); + { // mod page plugin + IPluginModPage* modPage = qobject_cast<IPluginModPage*>(plugin); if (initPlugin(modPage, pluginProxy, skipInit)) { bf::at_key<IPluginModPage>(m_Plugins).push_back(modPage); emit pluginRegistered(modPage); return modPage; } } - { // game plugin - IPluginGame *game = qobject_cast<IPluginGame*>(plugin); + { // game plugin + IPluginGame* game = qobject_cast<IPluginGame*>(plugin); if (game) { game->detectGame(); if (initPlugin(game, pluginProxy, skipInit)) { @@ -522,16 +570,16 @@ IPlugin* PluginContainer::registerPlugin(QObject *plugin, const QString& filepat } } } - { // tool plugins - IPluginTool *tool = qobject_cast<IPluginTool*>(plugin); + { // tool plugins + IPluginTool* tool = qobject_cast<IPluginTool*>(plugin); if (initPlugin(tool, pluginProxy, skipInit)) { bf::at_key<IPluginTool>(m_Plugins).push_back(tool); emit pluginRegistered(tool); return tool; } } - { // installer plugins - IPluginInstaller *installer = qobject_cast<IPluginInstaller*>(plugin); + { // installer plugins + IPluginInstaller* installer = qobject_cast<IPluginInstaller*>(plugin); if (initPlugin(installer, pluginProxy, skipInit)) { bf::at_key<IPluginInstaller>(m_Plugins).push_back(installer); if (m_Organizer) { @@ -541,21 +589,22 @@ IPlugin* PluginContainer::registerPlugin(QObject *plugin, const QString& filepat return installer; } } - { // preview plugins - IPluginPreview *preview = qobject_cast<IPluginPreview*>(plugin); + { // preview plugins + IPluginPreview* preview = qobject_cast<IPluginPreview*>(plugin); if (initPlugin(preview, pluginProxy, skipInit)) { bf::at_key<IPluginPreview>(m_Plugins).push_back(preview); return preview; } } - { // proxy plugins - IPluginProxy *proxy = qobject_cast<IPluginProxy*>(plugin); + { // proxy plugins + IPluginProxy* proxy = qobject_cast<IPluginProxy*>(plugin); if (initPlugin(proxy, pluginProxy, skipInit)) { bf::at_key<IPluginProxy>(m_Plugins).push_back(proxy); emit pluginRegistered(proxy); - QStringList filepaths = proxy->pluginList( - QCoreApplication::applicationDirPath() + "/" + ToQString(AppConfig::pluginPath())); + QStringList filepaths = + proxy->pluginList(QCoreApplication::applicationDirPath() + "/" + + ToQString(AppConfig::pluginPath())); for (const QString& filepath : filepaths) { loadProxied(filepath, proxy); } @@ -563,9 +612,9 @@ IPlugin* PluginContainer::registerPlugin(QObject *plugin, const QString& filepat } } - { // dummy plugins + { // dummy plugins // only initialize these, no processing otherwise - IPlugin *dummy = qobject_cast<IPlugin*>(plugin); + IPlugin* dummy = qobject_cast<IPlugin*>(plugin); if (initPlugin(dummy, pluginProxy, skipInit)) { bf::at_key<IPlugin>(m_Plugins).push_back(dummy); emit pluginRegistered(dummy); @@ -599,7 +648,8 @@ bool PluginContainer::isEnabled(IPlugin* plugin) const } // Check if the plugin is enabled: - if (!m_Organizer->persistent(plugin->name(), "enabled", plugin->enabledByDefault()).toBool()) { + if (!m_Organizer->persistent(plugin->name(), "enabled", plugin->enabledByDefault()) + .toBool()) { return false; } @@ -607,12 +657,15 @@ bool PluginContainer::isEnabled(IPlugin* plugin) const return m_Requirements.at(plugin).canEnable(); } -void PluginContainer::setEnabled(MOBase::IPlugin* plugin, bool enable, bool dependencies) +void PluginContainer::setEnabled(MOBase::IPlugin* plugin, bool enable, + bool dependencies) { // If required, disable dependencies: if (!enable && dependencies) { for (auto* p : requirements(plugin).requiredFor()) { - setEnabled(p, false, false); // No need to "recurse" here since requiredFor already does it. + setEnabled( + p, false, + false); // No need to "recurse" here since requiredFor already does it. } } @@ -626,8 +679,7 @@ void PluginContainer::setEnabled(MOBase::IPlugin* plugin, bool enable, bool depe if (enable) { emit pluginEnabled(plugin); - } - else { + } else { emit pluginDisabled(plugin); } } @@ -635,7 +687,7 @@ void PluginContainer::setEnabled(MOBase::IPlugin* plugin, bool enable, bool depe MOBase::IPlugin* PluginContainer::plugin(QString const& pluginName) const { auto& map = bf::at_key<QString>(m_AccessPlugins); - auto it = map.find(pluginName); + auto it = map.find(pluginName); if (it == std::end(map)) { return nullptr; } @@ -645,7 +697,7 @@ MOBase::IPlugin* PluginContainer::plugin(QString const& pluginName) const MOBase::IPlugin* PluginContainer::plugin(MOBase::IPluginDiagnose* diagnose) const { auto& map = bf::at_key<IPluginDiagnose>(m_AccessPlugins); - auto it = map.find(diagnose); + auto it = map.find(diagnose); if (it == std::end(map)) { return nullptr; } @@ -655,22 +707,25 @@ MOBase::IPlugin* PluginContainer::plugin(MOBase::IPluginDiagnose* diagnose) cons MOBase::IPlugin* PluginContainer::plugin(MOBase::IPluginFileMapper* mapper) const { auto& map = bf::at_key<IPluginFileMapper>(m_AccessPlugins); - auto it = map.find(mapper); + auto it = map.find(mapper); if (it == std::end(map)) { return nullptr; } return it->second; } -bool PluginContainer::isEnabled(QString const& pluginName) const { +bool PluginContainer::isEnabled(QString const& pluginName) const +{ IPlugin* p = plugin(pluginName); return p ? isEnabled(p) : false; } -bool PluginContainer::isEnabled(MOBase::IPluginDiagnose* diagnose) const { +bool PluginContainer::isEnabled(MOBase::IPluginDiagnose* diagnose) const +{ IPlugin* p = plugin(diagnose); return p ? isEnabled(p) : false; } -bool PluginContainer::isEnabled(MOBase::IPluginFileMapper* mapper) const { +bool PluginContainer::isEnabled(MOBase::IPluginFileMapper* mapper) const +{ IPlugin* p = plugin(mapper); return p ? isEnabled(p) : false; } @@ -695,7 +750,7 @@ QString PluginContainer::filepath(MOBase::IPlugin* plugin) const return as_qobject(plugin)->property("filepath").toString(); } -IPluginGame *PluginContainer::game(const QString &name) const +IPluginGame* PluginContainer::game(const QString& name) const { auto iter = m_SupportedGames.find(name); if (iter != m_SupportedGames.end()) { @@ -705,7 +760,7 @@ IPluginGame *PluginContainer::game(const QString &name) const } } -const PreviewGenerator &PluginContainer::previewGenerator() const +const PreviewGenerator& PluginContainer::previewGenerator() const { return m_PreviewGenerator; } @@ -745,7 +800,8 @@ void PluginContainer::startPluginsImpl(const std::vector<QObject*>& plugins) con } } -std::vector<QObject*> PluginContainer::loadProxied(const QString& filepath, IPluginProxy* proxy) +std::vector<QObject*> PluginContainer::loadProxied(const QString& filepath, + IPluginProxy* proxy) { std::vector<QObject*> proxiedPlugins; @@ -760,19 +816,20 @@ std::vector<QObject*> PluginContainer::loadProxied(const QString& filepath, IPlu for (QObject* proxiedPlugin : matchingPlugins) { if (proxiedPlugin != nullptr) { - if (IPlugin* proxied = registerPlugin(proxiedPlugin, filepath, proxy); proxied) { - log::debug("loaded plugin '{}' from '{}' - [{}]", - proxied->name(), QFileInfo(filepath).fileName(), implementedInterfaces(proxied).join(", ")); + if (IPlugin* proxied = registerPlugin(proxiedPlugin, filepath, proxy); + proxied) { + log::debug("loaded plugin '{}' from '{}' - [{}]", proxied->name(), + QFileInfo(filepath).fileName(), + implementedInterfaces(proxied).join(", ")); // Store the plugin for later: proxiedPlugins.push_back(proxiedPlugin); proxiedByNames[proxied->name()].push_back(proxied); - } - else { - log::warn( - "plugin \"{}\" failed to load. If this plugin is for an older version of MO " - "you have to update it or delete it if no update exists.", - filepath); + } else { + log::warn("plugin \"{}\" failed to load. If this plugin is for an older " + "version of MO " + "you have to update it or delete it if no update exists.", + filepath); } } } @@ -781,9 +838,10 @@ std::vector<QObject*> PluginContainer::loadProxied(const QString& filepath, IPlu for (auto& [name, proxiedPlugins] : proxiedByNames) { if (proxiedPlugins.size() > 1) { auto it = std::min_element(std::begin(proxiedPlugins), std::end(proxiedPlugins), - [&](auto const& lhs, auto const& rhs) { - return isBetterInterface(as_qobject(lhs), as_qobject(rhs)); - }); + [&](auto const& lhs, auto const& rhs) { + return isBetterInterface(as_qobject(lhs), + as_qobject(rhs)); + }); for (auto& proxiedPlugin : proxiedPlugins) { if (proxiedPlugin != *it) { @@ -792,9 +850,9 @@ std::vector<QObject*> PluginContainer::loadProxied(const QString& filepath, IPlu } } } - } - catch (const std::exception& e) { - reportError(QObject::tr("failed to initialize plugin %1: %2").arg(filepath).arg(e.what())); + } catch (const std::exception& e) { + reportError( + QObject::tr("failed to initialize plugin %1: %2").arg(filepath).arg(e.what())); } return proxiedPlugins; @@ -806,16 +864,15 @@ QObject* PluginContainer::loadQtPlugin(const QString& filepath) if (pluginLoader->instance() == nullptr) { m_FailedPlugins.push_back(filepath); log::error("failed to load plugin {}: {}", filepath, pluginLoader->errorString()); - } - else { + } else { QObject* object = pluginLoader->instance(); if (IPlugin* plugin = registerPlugin(object, filepath, nullptr); plugin) { - log::debug("loaded plugin '{}' from '{}' - [{}]", - plugin->name(), QFileInfo(filepath).fileName(), implementedInterfaces(plugin).join(", ")); + log::debug("loaded plugin '{}' from '{}' - [{}]", plugin->name(), + QFileInfo(filepath).fileName(), + implementedInterfaces(plugin).join(", ")); m_PluginLoaders.push_back(pluginLoader.release()); return object; - } - else { + } else { m_FailedPlugins.push_back(filepath); log::warn("plugin '{}' failed to load (may be outdated)", filepath); } @@ -823,7 +880,8 @@ QObject* PluginContainer::loadQtPlugin(const QString& filepath) return nullptr; } -std::optional<QString> PluginContainer::isQtPluginFolder(const QString& filepath) const { +std::optional<QString> PluginContainer::isQtPluginFolder(const QString& filepath) const +{ if (!QFileInfo(filepath).isDir()) { return {}; @@ -839,8 +897,8 @@ std::optional<QString> PluginContainer::isQtPluginFolder(const QString& filepath continue; } - // check if we have proper metadata - this does not load the plugin (metaData() should - // be very lightweight) + // check if we have proper metadata - this does not load the plugin (metaData() + // should be very lightweight) const QPluginLoader loader(filePath); if (!loader.metaData().isEmpty()) { return filePath; @@ -858,18 +916,16 @@ void PluginContainer::loadPlugin(QString const& filepath) if (plugin) { plugins.push_back(plugin); } - } - else if (auto p = isQtPluginFolder(filepath)) { + } else if (auto p = isQtPluginFolder(filepath)) { QObject* plugin = loadQtPlugin(*p); if (plugin) { plugins.push_back(plugin); } - } - else { + } else { // We need to check if this can be handled by a proxy. for (auto* proxy : this->plugins<IPluginProxy>()) { - auto filepaths = proxy->pluginList( - QCoreApplication::applicationDirPath() + "/" + ToQString(AppConfig::pluginPath())); + auto filepaths = proxy->pluginList(QCoreApplication::applicationDirPath() + "/" + + ToQString(AppConfig::pluginPath())); if (filepaths.contains(filepath)) { plugins = loadProxied(filepath, proxy); break; @@ -902,7 +958,8 @@ void PluginContainer::unloadPlugin(MOBase::IPlugin* plugin, QObject* object) // We do not want to remove from QObject since we are iterating over them. if constexpr (!std::is_same<type, QObject*>{}) { - auto itp = std::find(t.second.begin(), t.second.end(), qobject_cast<type>(object)); + auto itp = + std::find(t.second.begin(), t.second.end(), qobject_cast<type>(object)); if (itp != t.second.end()) { t.second.erase(itp); } @@ -936,23 +993,22 @@ void PluginContainer::unloadPlugin(MOBase::IPlugin* plugin, QObject* object) if (proxy) { proxy->unload(filepath(plugin)); - } - else { + } else { // We need to find the loader. auto it = std::find_if(m_PluginLoaders.begin(), m_PluginLoaders.end(), - [object](auto* loader) { return loader->instance() == object; }); + [object](auto* loader) { + return loader->instance() == object; + }); if (it != m_PluginLoaders.end()) { if (!(*it)->unload()) { log::error("failed to unload {}: {}", (*it)->fileName(), (*it)->errorString()); } - delete* it; + delete *it; m_PluginLoaders.erase(it); - } - else { + } else { log::error("loader for plugin {} does not exist, cannot unload", plugin->name()); } - } object->deleteLater(); @@ -966,14 +1022,13 @@ void PluginContainer::unloadPlugin(QString const& filepath) // We need to find all the plugins from the given path and // unload them: QString cleanPath = QDir::cleanPath(filepath); - auto &objects = bf::at_key<QObject>(m_Plugins); - for (auto it = objects.begin(); it != objects.end(); ) { + auto& objects = bf::at_key<QObject>(m_Plugins); + for (auto it = objects.begin(); it != objects.end();) { auto* plugin = qobject_cast<IPlugin*>(*it); if (this->filepath(plugin) == filepath) { unloadPlugin(plugin, *it); it = objects.erase(it); - } - else { + } else { ++it; } } @@ -997,8 +1052,12 @@ void PluginContainer::unloadPlugins() m_Organizer->settings().plugins().clearPlugins(); } - bf::for_each(m_Plugins, [](auto& t) { t.second.clear(); }); - bf::for_each(m_AccessPlugins, [](auto& t) { t.second.clear(); }); + bf::for_each(m_Plugins, [](auto& t) { + t.second.clear(); + }); + bf::for_each(m_AccessPlugins, [](auto& t) { + t.second.clear(); + }); m_Requirements.clear(); while (!m_PluginLoaders.empty()) { @@ -1017,7 +1076,7 @@ void PluginContainer::loadPlugins() unloadPlugins(); - for (QObject *plugin : QPluginLoader::staticInstances()) { + for (QObject* plugin : QPluginLoader::staticInstances()) { registerPlugin(plugin, "", nullptr); } @@ -1025,10 +1084,12 @@ void PluginContainer::loadPlugins() QString skipPlugin; if (m_Organizer) { - loadCheck.setFileName(qApp->property("dataPath").toString() + "/plugin_loadcheck.tmp"); + loadCheck.setFileName(qApp->property("dataPath").toString() + + "/plugin_loadcheck.tmp"); if (loadCheck.exists() && loadCheck.open(QIODevice::ReadOnly)) { - // oh, there was a failed plugin load last time. Find out which plugin was loaded last + // oh, there was a failed plugin load last time. Find out which plugin was loaded + // last QString fileName; while (!loadCheck.atEnd()) { fileName = QString::fromUtf8(loadCheck.readLine().constData()).trimmed(); @@ -1038,40 +1099,39 @@ void PluginContainer::loadPlugins() MOBase::TaskDialog dlg; - const auto Skip = QMessageBox::Ignore; + const auto Skip = QMessageBox::Ignore; const auto Blacklist = QMessageBox::Cancel; - const auto Load = QMessageBox::Ok; + const auto Load = QMessageBox::Ok; - const auto r = dlg - .title(tr("Plugin error")) - .main(tr( - "Mod Organizer failed to load the plugin '%1' last time it was started.") - .arg(fileName)) - .content(tr( - "The plugin can be skipped for this session, blacklisted, " - "or loaded normally, in which case it might fail again. Blacklisted " - "plugins can be re-enabled later in the settings.")) - .icon(QMessageBox::Warning) - .button({tr("Skip this plugin"), Skip}) - .button({tr("Blacklist this plugin"), Blacklist}) - .button({tr("Load this plugin"), Load}) - .exec(); + const auto r = + dlg.title(tr("Plugin error")) + .main(tr("Mod Organizer failed to load the plugin '%1' last time it was " + "started.") + .arg(fileName)) + .content(tr( + "The plugin can be skipped for this session, blacklisted, " + "or loaded normally, in which case it might fail again. Blacklisted " + "plugins can be re-enabled later in the settings.")) + .icon(QMessageBox::Warning) + .button({tr("Skip this plugin"), Skip}) + .button({tr("Blacklist this plugin"), Blacklist}) + .button({tr("Load this plugin"), Load}) + .exec(); - switch (r) - { - case Skip: - log::warn("user wants to skip plugin '{}'", fileName); - skipPlugin = fileName; - break; + switch (r) { + case Skip: + log::warn("user wants to skip plugin '{}'", fileName); + skipPlugin = fileName; + break; - case Blacklist: - log::warn("user wants to blacklist plugin '{}'", fileName); - m_Organizer->settings().plugins().addBlacklist(fileName); - break; + case Blacklist: + log::warn("user wants to blacklist plugin '{}'", fileName); + m_Organizer->settings().plugins().addBlacklist(fileName); + break; - case Load: - log::warn("user wants to load plugin '{}' anyway", fileName); - break; + case Load: + log::warn("user wants to load plugin '{}' anyway", fileName); + break; } loadCheck.close(); @@ -1080,7 +1140,8 @@ void PluginContainer::loadPlugins() loadCheck.open(QIODevice::WriteOnly); } - QString pluginPath = qApp->applicationDirPath() + "/" + ToQString(AppConfig::pluginPath()); + QString pluginPath = + qApp->applicationDirPath() + "/" + ToQString(AppConfig::pluginPath()); log::debug("looking for plugins in {}", QDir::toNativeSeparators(pluginPath)); QDirIterator iter(pluginPath, QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); @@ -1108,8 +1169,7 @@ void PluginContainer::loadPlugins() QString filepath = iter.filePath(); if (QLibrary::isLibrary(filepath)) { loadQtPlugin(filepath); - } - else if (auto p = isQtPluginFolder(filepath)) { + } else if (auto p = isQtPluginFolder(filepath)) { loadQtPlugin(*p); } } @@ -1132,7 +1192,6 @@ void PluginContainer::loadPlugins() loadCheck.flush(); } - bf::at_key<IPluginDiagnose>(m_Plugins).push_back(this); if (m_Organizer) { @@ -1153,30 +1212,32 @@ std::vector<unsigned int> PluginContainer::activeProblems() const QString PluginContainer::shortDescription(unsigned int key) const { switch (key) { - case PROBLEM_PLUGINSNOTLOADED: { - return tr("Some plugins could not be loaded"); - } break; - default: { - return tr("Description missing"); - } break; + case PROBLEM_PLUGINSNOTLOADED: { + return tr("Some plugins could not be loaded"); + } break; + default: { + return tr("Description missing"); + } break; } } QString PluginContainer::fullDescription(unsigned int key) const { switch (key) { - case PROBLEM_PLUGINSNOTLOADED: { - QString result = tr("The following plugins could not be loaded. The reason may be missing " - "dependencies (i.e. python) or an outdated version:") + "<ul>"; - for (const QString &plugin : m_FailedPlugins) { - result += "<li>" + plugin + "</li>"; - } - result += "<ul>"; - return result; - } break; - default: { - return tr("Description missing"); - } break; + case PROBLEM_PLUGINSNOTLOADED: { + QString result = + tr("The following plugins could not be loaded. The reason may be missing " + "dependencies (i.e. python) or an outdated version:") + + "<ul>"; + for (const QString& plugin : m_FailedPlugins) { + result += "<li>" + plugin + "</li>"; + } + result += "<ul>"; + return result; + } break; + default: { + return tr("Description missing"); + } break; } } @@ -1185,6 +1246,4 @@ bool PluginContainer::hasGuidedFix(unsigned int) const return false; } -void PluginContainer::startGuidedFix(unsigned int) const -{ -} +void PluginContainer::startGuidedFix(unsigned int) const {} diff --git a/src/plugincontainer.h b/src/plugincontainer.h index 688c9f10..d5ceca72 100644 --- a/src/plugincontainer.h +++ b/src/plugincontainer.h @@ -6,24 +6,23 @@ class OrganizerCore; class IUserInterface; +#include <QFile> +#include <QPluginLoader> +#include <QtPlugin> #include <iplugindiagnose.h> -#include <ipluginmodpage.h> +#include <ipluginfilemapper.h> #include <iplugingame.h> -#include <iplugintool.h> -#include <ipluginproxy.h> #include <iplugininstaller.h> -#include <ipluginfilemapper.h> -#include <QtPlugin> -#include <QPluginLoader> -#include <QFile> +#include <ipluginmodpage.h> +#include <ipluginproxy.h> +#include <iplugintool.h> #ifndef Q_MOC_RUN #include <boost/fusion/container.hpp> #include <boost/fusion/include/at_key.hpp> #include <boost/mp11.hpp> -#endif // Q_MOC_RUN -#include <vector> +#endif // Q_MOC_RUN #include <memory> - +#include <vector> class OrganizerProxy; @@ -31,9 +30,9 @@ class OrganizerProxy; * @brief Class that wrap multiple requirements for a plugin together. THis * class owns the requirements. */ -class PluginRequirements { +class PluginRequirements +{ public: - /** * @return true if the plugin can be enabled (all requirements are met). */ @@ -76,8 +75,8 @@ public: std::vector<MOBase::IPluginRequirement::Problem> problems() const; /** - * @return the name of the games (gameName()) this plugin can be used with, or an empty - * list if this plugin does not require particular games. + * @return the name of the games (gameName()) this plugin can be used with, or an + * empty list if this plugin does not require particular games. */ QStringList requiredGames() const; @@ -88,19 +87,20 @@ public: std::vector<MOBase::IPlugin*> requiredFor() const; private: - // The list of "Core" plugins. static const std::set<QString> s_CorePlugins; // Accumulator version for requiredFor() to avoid infinite recursion. - void requiredFor(std::vector<MOBase::IPlugin*>& required, std::set<MOBase::IPlugin*>& visited) const; + void requiredFor(std::vector<MOBase::IPlugin*>& required, + std::set<MOBase::IPlugin*>& visited) const; // Retrieve the requirements from the underlying plugin, take ownership on them // and store them. We cannot do this in the constructor because we want to have a // constructed object before calling init(). void fetchRequirements(); - // Set the master for this plugin. This is required to "fake" masters for proxied plugins. + // Set the master for this plugin. This is required to "fake" masters for proxied + // plugins. void setMaster(MOBase::IPlugin* master); friend class OrganizerCore; @@ -114,13 +114,10 @@ private: OrganizerProxy* m_Organizer; std::vector<MOBase::IPlugin*> m_RequiredFor; - PluginRequirements( - PluginContainer* pluginContainer, MOBase::IPlugin* plugin, - OrganizerProxy* proxy, MOBase::IPluginProxy* pluginProxy); - + PluginRequirements(PluginContainer* pluginContainer, MOBase::IPlugin* plugin, + OrganizerProxy* proxy, MOBase::IPluginProxy* pluginProxy); }; - /** * */ @@ -131,52 +128,50 @@ class PluginContainer : public QObject, public MOBase::IPluginDiagnose Q_INTERFACES(MOBase::IPluginDiagnose) private: - using PluginMap = boost::fusion::map< - boost::fusion::pair<QObject, std::vector<QObject*>>, - boost::fusion::pair<MOBase::IPlugin, std::vector<MOBase::IPlugin*>>, - boost::fusion::pair<MOBase::IPluginDiagnose, std::vector<MOBase::IPluginDiagnose*>>, - boost::fusion::pair<MOBase::IPluginGame, std::vector<MOBase::IPluginGame*>>, - boost::fusion::pair<MOBase::IPluginInstaller, std::vector<MOBase::IPluginInstaller*>>, - boost::fusion::pair<MOBase::IPluginModPage, std::vector<MOBase::IPluginModPage*>>, - boost::fusion::pair<MOBase::IPluginPreview, std::vector<MOBase::IPluginPreview*>>, - boost::fusion::pair<MOBase::IPluginTool, std::vector<MOBase::IPluginTool*>>, - boost::fusion::pair<MOBase::IPluginProxy, std::vector<MOBase::IPluginProxy*>>, - boost::fusion::pair<MOBase::IPluginFileMapper, std::vector<MOBase::IPluginFileMapper*>> - >; + boost::fusion::pair<QObject, std::vector<QObject*>>, + boost::fusion::pair<MOBase::IPlugin, std::vector<MOBase::IPlugin*>>, + boost::fusion::pair<MOBase::IPluginDiagnose, + std::vector<MOBase::IPluginDiagnose*>>, + boost::fusion::pair<MOBase::IPluginGame, std::vector<MOBase::IPluginGame*>>, + boost::fusion::pair<MOBase::IPluginInstaller, + std::vector<MOBase::IPluginInstaller*>>, + boost::fusion::pair<MOBase::IPluginModPage, std::vector<MOBase::IPluginModPage*>>, + boost::fusion::pair<MOBase::IPluginPreview, std::vector<MOBase::IPluginPreview*>>, + boost::fusion::pair<MOBase::IPluginTool, std::vector<MOBase::IPluginTool*>>, + boost::fusion::pair<MOBase::IPluginProxy, std::vector<MOBase::IPluginProxy*>>, + boost::fusion::pair<MOBase::IPluginFileMapper, + std::vector<MOBase::IPluginFileMapper*>>>; using AccessPluginMap = boost::fusion::map< - boost::fusion::pair<MOBase::IPluginDiagnose, std::map<MOBase::IPluginDiagnose*, MOBase::IPlugin*>>, - boost::fusion::pair<MOBase::IPluginFileMapper, std::map<MOBase::IPluginFileMapper*, MOBase::IPlugin*>>, - boost::fusion::pair<QString, std::map<QString, MOBase::IPlugin*>> - >; + boost::fusion::pair<MOBase::IPluginDiagnose, + std::map<MOBase::IPluginDiagnose*, MOBase::IPlugin*>>, + boost::fusion::pair<MOBase::IPluginFileMapper, + std::map<MOBase::IPluginFileMapper*, MOBase::IPlugin*>>, + boost::fusion::pair<QString, std::map<QString, MOBase::IPlugin*>>>; static const unsigned int PROBLEM_PLUGINSNOTLOADED = 1; /** - * This typedefs defines the order of plugin interface. This is increasing order of - * importance". - * - * @note IPlugin is the less important interface, followed by IPluginDiagnose and - * IPluginFileMapper as those are usually implemented together with another interface. - * Other interfaces are in a alphabetical order since it is unlikely a plugin will - * implement multiple ones. - */ - using PluginTypeOrder = - boost::mp11::mp_transform< + * This typedefs defines the order of plugin interface. This is increasing order of + * importance". + * + * @note IPlugin is the less important interface, followed by IPluginDiagnose and + * IPluginFileMapper as those are usually implemented together with another + * interface. Other interfaces are in a alphabetical order since it is unlikely a + * plugin will implement multiple ones. + */ + using PluginTypeOrder = boost::mp11::mp_transform< std::add_pointer_t, boost::mp11::mp_list< - MOBase::IPluginGame, MOBase::IPluginInstaller, MOBase::IPluginModPage, MOBase::IPluginPreview, - MOBase::IPluginProxy, MOBase::IPluginTool, MOBase::IPluginDiagnose, MOBase::IPluginFileMapper, - MOBase::IPlugin - > - >; + MOBase::IPluginGame, MOBase::IPluginInstaller, MOBase::IPluginModPage, + MOBase::IPluginPreview, MOBase::IPluginProxy, MOBase::IPluginTool, + MOBase::IPluginDiagnose, MOBase::IPluginFileMapper, MOBase::IPlugin>>; - static_assert( - boost::mp11::mp_size<PluginTypeOrder>::value == boost::mp11::mp_size<PluginContainer::PluginMap>::value - 1); + static_assert(boost::mp11::mp_size<PluginTypeOrder>::value == + boost::mp11::mp_size<PluginContainer::PluginMap>::value - 1); public: - /** * @brief Retrieved the (localized) names of the various plugin interfaces. * @@ -185,7 +180,6 @@ public: static QStringList pluginInterfaces(); public: - PluginContainer(OrganizerCore* organizer); virtual ~PluginContainer(); @@ -226,8 +220,10 @@ public: * @tparam T The type of plugin to retrieve. */ template <typename T> - const std::vector<T*> &plugins() const { - typename boost::fusion::result_of::at_key<const PluginMap, T>::type temp = boost::fusion::at_key<T>(m_Plugins); + const std::vector<T*>& plugins() const + { + typename boost::fusion::result_of::at_key<const PluginMap, T>::type temp = + boost::fusion::at_key<T>(m_Plugins); return temp; } @@ -241,7 +237,8 @@ public: * @tparam The interface type. */ template <typename T> - bool implementInterface(MOBase::IPlugin* plugin) const { + bool implementInterface(MOBase::IPlugin* plugin) const + { // We need a QObject to be able to qobject_cast<> to the plugin types: QObject* oPlugin = as_qobject(plugin); @@ -335,22 +332,22 @@ public: * * @param plugin The plugin to retrieve the interface for. * - * @return the (localized) name of the most important interface implemented by this plugin. + * @return the (localized) name of the most important interface implemented by this + * plugin. */ QString topImplementedInterface(MOBase::IPlugin* plugin) const; /** * @return the preview generator. */ - const PreviewGenerator &previewGenerator() const; + const PreviewGenerator& previewGenerator() const; /** * @return the list of plugin file names, including proxied plugins. */ QStringList pluginFileNames() const; -public: // IPluginDiagnose interface - +public: // IPluginDiagnose interface virtual std::vector<unsigned int> activeProblems() const; virtual QString shortDescription(unsigned int key) const; virtual QString fullDescription(unsigned int key) const; @@ -374,7 +371,6 @@ signals: void diagnosisUpdate(); private: - friend class PluginRequirements; // Unload all the plugins. @@ -391,7 +387,8 @@ private: QString filepath(MOBase::IPlugin* plugin) const; // Load plugins from the given filepath using the given proxy. - std::vector<QObject*> loadProxied(const QString& filepath, MOBase::IPluginProxy* proxy); + std::vector<QObject*> loadProxied(const QString& filepath, + MOBase::IPluginProxy* proxy); // Load the Qt plugin from the given file. QObject* loadQtPlugin(const QString& filepath); @@ -399,8 +396,8 @@ private: // check if a plugin is folder containing a Qt plugin, it is, return the path to the // DLL containing the plugin in the folder, otherwise return an empty optional // - // a Qt plugin folder is a folder with a DLL containing a library (not in a subdirectory), - // if multiple plugins are present, only the first one is returned + // a Qt plugin folder is a folder with a DLL containing a library (not in a + // subdirectory), if multiple plugins are present, only the first one is returned // // extra DLLs are ignored by Qt so can be present in the folder // @@ -465,18 +462,19 @@ private: * * @return true if the plugin was initialized correctly, false otherwise. */ - bool initPlugin(MOBase::IPlugin *plugin, MOBase::IPluginProxy* proxy, bool skipInit); + bool initPlugin(MOBase::IPlugin* plugin, MOBase::IPluginProxy* proxy, bool skipInit); - void registerGame(MOBase::IPluginGame *game); + void registerGame(MOBase::IPluginGame* game); void unregisterGame(MOBase::IPluginGame* game); - MOBase::IPlugin* registerPlugin(QObject *pluginObj, const QString &fileName, MOBase::IPluginProxy *proxy); + MOBase::IPlugin* registerPlugin(QObject* pluginObj, const QString& fileName, + MOBase::IPluginProxy* proxy); // Core organizer, can be null (e.g. on first MO2 startup). - OrganizerCore *m_Organizer; + OrganizerCore* m_Organizer; // Main user interface, can be null until MW has been initialized. - IUserInterface *m_UserInterface; + IUserInterface* m_UserInterface; PluginMap m_Plugins; @@ -494,5 +492,4 @@ private: QFile m_PluginsCheck; }; - -#endif // PLUGINCONTAINER_H +#endif // PLUGINCONTAINER_H diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index a4742529..6e54b46d 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -18,41 +18,40 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ #include "pluginlist.h" -#include "settings.h" -#include "scopeguard.h" #include "modinfo.h" #include "modlist.h" -#include "viewmarkingscrollbar.h" +#include "scopeguard.h" +#include "settings.h" #include "shared/directoryentry.h" -#include "shared/filesorigin.h" #include "shared/fileentry.h" +#include "shared/filesorigin.h" +#include "viewmarkingscrollbar.h" -#include <utility.h> -#include <iplugingame.h> +#include "shared/windows_error.h" #include <espfile.h> +#include <gameplugins.h> +#include <iplugingame.h> #include <report.h> -#include "shared/windows_error.h" #include <safewritefile.h> -#include <gameplugins.h> +#include <utility.h> -#include <QtDebug> -#include <QMessageBox> -#include <QMimeData> +#include <QApplication> #include <QCoreApplication> #include <QDateTime> #include <QDir> #include <QFile> #include <QFileInfo> -#include <QFileInfo> +#include <QKeyEvent> #include <QListWidgetItem> +#include <QMessageBox> +#include <QMimeData> #include <QRegularExpression> -#include <QString> -#include <QApplication> -#include <QKeyEvent> #include <QSortFilterProxyModel> +#include <QString> +#include <QtDebug> -#include <ctime> #include <algorithm> +#include <ctime> #include <stdexcept> #include "organizercore.h" @@ -60,7 +59,6 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. using namespace MOBase; using namespace MOShared; - static QString TruncateString(const QString& text) { QString new_text = text; @@ -73,11 +71,8 @@ static QString TruncateString(const QString& text) return new_text; } - PluginList::PluginList(OrganizerCore& organizer) - : QAbstractItemModel(&organizer) - , m_Organizer(organizer) - , m_FontMetrics(QFont()) + : QAbstractItemModel(&organizer), m_Organizer(organizer), m_FontMetrics(QFont()) { connect(this, SIGNAL(writePluginsList()), this, SLOT(generatePluginIndexes())); m_LastCheck.start(); @@ -93,34 +88,43 @@ PluginList::~PluginList() QString PluginList::getColumnName(int column) { switch (column) { - case COL_NAME: return tr("Name"); - case COL_PRIORITY: return tr("Priority"); - case COL_MODINDEX: return tr("Mod Index"); - case COL_FLAGS: return tr("Flags"); - default: return tr("unknown"); + case COL_NAME: + return tr("Name"); + case COL_PRIORITY: + return tr("Priority"); + case COL_MODINDEX: + return tr("Mod Index"); + case COL_FLAGS: + return tr("Flags"); + default: + return tr("unknown"); } } - QString PluginList::getColumnToolTip(int column) { switch (column) { - case COL_NAME: return tr("Name of the plugin"); - case COL_FLAGS: return tr("Emblems to highlight things that might require attention."); - case COL_PRIORITY: return tr("Load priority of plugins. The higher, the more \"important\" it is and thus " - "overwrites data from plugins with lower priority."); - case COL_MODINDEX: return tr("Determines the formids of objects originating from this mods."); - default: return tr("unknown"); + case COL_NAME: + return tr("Name of the plugin"); + case COL_FLAGS: + return tr("Emblems to highlight things that might require attention."); + case COL_PRIORITY: + return tr( + "Load priority of plugins. The higher, the more \"important\" it is and thus " + "overwrites data from plugins with lower priority."); + case COL_MODINDEX: + return tr("Determines the formids of objects originating from this mods."); + default: + return tr("unknown"); } } -void PluginList::highlightPlugins( - const std::vector<unsigned int>& modIndices, - const MOShared::DirectoryEntry &directoryEntry) +void PluginList::highlightPlugins(const std::vector<unsigned int>& modIndices, + const MOShared::DirectoryEntry& directoryEntry) { auto* profile = m_Organizer.currentProfile(); - for (auto &esp : m_ESPs) { + for (auto& esp : m_ESPs) { esp.modSelected = false; } @@ -128,14 +132,20 @@ void PluginList::highlightPlugins( ModInfo::Ptr selectedMod = ModInfo::getByIndex(modIndex); if (!selectedMod.isNull() && profile->modEnabled(modIndex)) { QDir dir(selectedMod->absolutePath()); - QStringList plugins = dir.entryList(QStringList() << "*.esp" << "*.esm" << "*.esl"); - const MOShared::FilesOrigin& origin = directoryEntry.getOriginByName(selectedMod->internalName().toStdWString()); + QStringList plugins = dir.entryList(QStringList() << "*.esp" + << "*.esm" + << "*.esl"); + const MOShared::FilesOrigin& origin = + directoryEntry.getOriginByName(selectedMod->internalName().toStdWString()); if (plugins.size() > 0) { for (auto plugin : plugins) { MOShared::FileEntryPtr file = directoryEntry.findFile(plugin.toStdWString()); if (file && file->getOrigin() != origin.getID()) { const auto alternatives = file->getAlternatives(); - if (std::find_if(alternatives.begin(), alternatives.end(), [&](const FileAlternative& element) { return element.originID() == origin.getID(); }) == alternatives.end()) + if (std::find_if(alternatives.begin(), alternatives.end(), + [&](const FileAlternative& element) { + return element.originID() == origin.getID(); + }) == alternatives.end()) continue; } std::map<QString, int>::iterator iter = m_ESPsByName.find(plugin); @@ -147,13 +157,13 @@ void PluginList::highlightPlugins( } } - emit dataChanged(this->index(0, 0), this->index(static_cast<int>(m_ESPs.size()) - 1, this->columnCount() - 1)); + emit dataChanged(this->index(0, 0), this->index(static_cast<int>(m_ESPs.size()) - 1, + this->columnCount() - 1)); } -void PluginList::refresh(const QString &profileName - , const DirectoryEntry &baseDirectory - , const QString &lockedOrderFile - , bool force) +void PluginList::refresh(const QString& profileName, + const DirectoryEntry& baseDirectory, + const QString& lockedOrderFile, bool force) { TimeThis tt("PluginList::refresh()"); @@ -166,8 +176,9 @@ void PluginList::refresh(const QString &profileName ChangeBracket<PluginList> layoutChange(this); QStringList primaryPlugins = m_GamePlugin->primaryPlugins(); - GamePlugins *gamePlugins = m_GamePlugin->feature<GamePlugins>(); - const bool lightPluginsAreSupported = gamePlugins ? gamePlugins->lightPluginsAreSupported() : false; + GamePlugins* gamePlugins = m_GamePlugin->feature<GamePlugins>(); + const bool lightPluginsAreSupported = + gamePlugins ? gamePlugins->lightPluginsAreSupported() : false; m_CurrentProfile = profileName; @@ -191,51 +202,57 @@ void PluginList::refresh(const QString &profileName } bool forceEnabled = Settings::instance().game().forceEnableCoreFiles() && - primaryPlugins.contains(filename, Qt::CaseInsensitive); + primaryPlugins.contains(filename, Qt::CaseInsensitive); bool archive = false; try { - FilesOrigin &origin = baseDirectory.getOriginByID(current->getOrigin(archive)); + FilesOrigin& origin = baseDirectory.getOriginByID(current->getOrigin(archive)); - //name without extension + // name without extension QString baseName = QFileInfo(filename).completeBaseName(); QString iniPath = baseName + ".ini"; - bool hasIni = baseDirectory.findFile(ToWString(iniPath)).get() != nullptr; + bool hasIni = baseDirectory.findFile(ToWString(iniPath)).get() != nullptr; std::set<QString> loadedArchives; QString candidateName; for (FileEntryPtr archiveCandidate : files) { candidateName = ToQString(archiveCandidate->getName()); if (candidateName.startsWith(baseName, Qt::CaseInsensitive) && - (candidateName.endsWith(".bsa", Qt::CaseInsensitive) || - candidateName.endsWith(".ba2", Qt::CaseInsensitive))) { + (candidateName.endsWith(".bsa", Qt::CaseInsensitive) || + candidateName.endsWith(".ba2", Qt::CaseInsensitive))) { loadedArchives.insert(candidateName); } } - QString originName = ToQString(origin.getName()); + QString originName = ToQString(origin.getName()); unsigned int modIndex = ModInfo::getIndex(originName); if (modIndex != UINT_MAX) { ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex); - originName = modInfo->name(); + originName = modInfo->name(); } - m_ESPs.push_back(ESPInfo(filename, forceEnabled, originName, ToQString(current->getFullPath()), hasIni, loadedArchives, lightPluginsAreSupported)); + m_ESPs.push_back(ESPInfo(filename, forceEnabled, originName, + ToQString(current->getFullPath()), hasIni, + loadedArchives, lightPluginsAreSupported)); m_ESPs.rbegin()->priority = -1; - } catch (const std::exception &e) { - reportError(tr("failed to update esp info for file %1 (source id: %2), error: %3").arg(filename).arg(current->getOrigin(archive)).arg(e.what())); + } catch (const std::exception& e) { + reportError( + tr("failed to update esp info for file %1 (source id: %2), error: %3") + .arg(filename) + .arg(current->getOrigin(archive)) + .arg(e.what())); } } } - for (const auto &espName : m_ESPsByName) { + for (const auto& espName : m_ESPsByName) { if (!availablePlugins.contains(espName.first, Qt::CaseInsensitive)) { m_ESPs[espName.second].name = ""; } } m_ESPs.erase(std::remove_if(m_ESPs.begin(), m_ESPs.end(), - [](const ESPInfo &info) -> bool { + [](const ESPInfo& info) -> bool { return info.name.isEmpty(); }), m_ESPs.end()); @@ -276,8 +293,8 @@ void PluginList::fixPrimaryPlugins() // This function ensures that the primary plugins are first and in the correct order QStringList primaryPlugins = m_Organizer.managedGame()->primaryPlugins(); - int prio = 0; - bool somethingChanged = false; + int prio = 0; + bool somethingChanged = false; for (QString plugin : primaryPlugins) { std::map<QString, int>::iterator iter = m_ESPsByName.find(plugin); // Plugin is present? @@ -304,8 +321,7 @@ void PluginList::fixPluginRelationships() // Count the types of plugins int masterCount = 0; for (auto plugin : m_ESPs) { - if (plugin.hasLightExtension || - plugin.hasMasterExtension || + if (plugin.hasLightExtension || plugin.hasMasterExtension || plugin.isMasterFlagged) { masterCount++; } @@ -314,15 +330,13 @@ void PluginList::fixPluginRelationships() // Ensure masters are up top and normal plugins are down below for (int i = 0; i < m_ESPs.size(); i++) { ESPInfo& plugin = m_ESPs[i]; - if (plugin.hasLightExtension || - plugin.hasMasterExtension || + if (plugin.hasLightExtension || plugin.hasMasterExtension || plugin.isMasterFlagged) { if (plugin.priority > masterCount) { int newPriority = masterCount + 1; setPluginPriority(i, newPriority); } - } - else { + } else { if (plugin.priority < masterCount) { int newPriority = masterCount + 1; setPluginPriority(i, newPriority); @@ -359,7 +373,7 @@ void PluginList::fixPriorities() } std::sort(espPrios.begin(), espPrios.end(), - [](const std::pair<int, int> &lhs, const std::pair<int, int> &rhs) { + [](const std::pair<int, int>& lhs, const std::pair<int, int>& rhs) { return lhs.first < rhs.first; }); @@ -368,18 +382,17 @@ void PluginList::fixPriorities() } } -void PluginList::enableESP(const QString &name, bool enable) +void PluginList::enableESP(const QString& name, bool enable) { std::map<QString, int>::iterator iter = m_ESPsByName.find(name); if (iter != m_ESPsByName.end()) { - auto enabled = m_ESPs[iter->second].enabled; - m_ESPs[iter->second].enabled = - enable || m_ESPs[iter->second].forceEnabled; + auto enabled = m_ESPs[iter->second].enabled; + m_ESPs[iter->second].enabled = enable || m_ESPs[iter->second].forceEnabled; emit writePluginsList(); if (enabled != m_ESPs[iter->second].enabled) { - pluginStatesChanged({ name }, state(name)); + pluginStatesChanged({name}, state(name)); } } else { reportError(tr("Plugin not found: %1").arg(qUtf8Printable(name))); @@ -388,7 +401,7 @@ void PluginList::enableESP(const QString &name, bool enable) int PluginList::findPluginByPriority(int priority) { - for (int i = 0; i < m_ESPs.size(); i++ ) { + for (int i = 0; i < m_ESPs.size(); i++) { if (m_ESPs[i].priority == priority) { return i; } @@ -408,15 +421,15 @@ void PluginList::setEnabled(const QModelIndexList& indices, bool enabled) } if (!dirty.isEmpty()) { emit writePluginsList(); - pluginStatesChanged(dirty, - enabled ? IPluginList::PluginState::STATE_ACTIVE : IPluginList::PluginState::STATE_INACTIVE); + pluginStatesChanged(dirty, enabled ? IPluginList::PluginState::STATE_ACTIVE + : IPluginList::PluginState::STATE_INACTIVE); } } void PluginList::setEnabledAll(bool enabled) { QStringList dirty; - for (ESPInfo &info : m_ESPs) { + for (ESPInfo& info : m_ESPs) { if (info.enabled != enabled) { info.enabled = enabled; dirty.append(info.name); @@ -424,8 +437,8 @@ void PluginList::setEnabledAll(bool enabled) } if (!dirty.isEmpty()) { emit writePluginsList(); - pluginStatesChanged(dirty, - enabled ? IPluginList::PluginState::STATE_ACTIVE : IPluginList::PluginState::STATE_INACTIVE); + pluginStatesChanged(dirty, enabled ? IPluginList::PluginState::STATE_ACTIVE + : IPluginList::PluginState::STATE_INACTIVE); } } @@ -453,7 +466,7 @@ void PluginList::shiftPluginsPriority(const QModelIndexList& indices, int offset std::sort(allIndex.begin(), allIndex.end(), [=](int lhs, int rhs) { bool cmp = m_ESPs[lhs].priority < m_ESPs[rhs].priority; return offset > 0 ? !cmp : cmp; - }); + }); for (auto index : allIndex) { int newPriority = m_ESPs[index].priority + offset; @@ -476,13 +489,14 @@ void PluginList::toggleState(const QModelIndexList& indices) maxRow = idx; } int oldState = idx.data(Qt::CheckStateRole).toInt(); - setData(idx, oldState == Qt::Unchecked ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole); + setData(idx, oldState == Qt::Unchecked ? Qt::Checked : Qt::Unchecked, + Qt::CheckStateRole); } emit dataChanged(minRow, maxRow); } -bool PluginList::isEnabled(const QString &name) +bool PluginList::isEnabled(const QString& name) { std::map<QString, int>::iterator iter = m_ESPsByName.find(name); @@ -493,7 +507,7 @@ bool PluginList::isEnabled(const QString &name) } } -void PluginList::clearInformation(const QString &name) +void PluginList::clearInformation(const QString& name) { std::map<QString, int>::iterator iter = m_ESPsByName.find(name); @@ -507,7 +521,7 @@ void PluginList::clearAdditionalInformation() m_AdditionalInfo.clear(); } -void PluginList::addInformation(const QString &name, const QString &message) +void PluginList::addInformation(const QString& name, const QString& message) { std::map<QString, int>::iterator iter = m_ESPsByName.find(name); @@ -534,7 +548,7 @@ bool PluginList::isEnabled(int index) return m_ESPs.at(index).enabled; } -void PluginList::readLockedOrderFrom(const QString &fileName) +void PluginList::readLockedOrderFrom(const QString& fileName) { m_LockedOrder.clear(); @@ -546,39 +560,36 @@ void PluginList::readLockedOrderFrom(const QString &fileName) file.open(QIODevice::ReadOnly); int lineNumber = 0; - while (!file.atEnd()) - { + while (!file.atEnd()) { QByteArray line = file.readLine(); ++lineNumber; // Skip empty lines or commented out lines (#) - if ((line.size() <= 0) || (line.at(0) == '#')) - { + if ((line.size() <= 0) || (line.at(0) == '#')) { continue; } QList<QByteArray> fields = line.split('|'); - if (fields.count() != 2) - { + if (fields.count() != 2) { // Don't know how to parse this so run away - log::error("locked order file: invalid line #{}: {}", lineNumber, QString::fromUtf8(line).trimmed()); + log::error("locked order file: invalid line #{}: {}", lineNumber, + QString::fromUtf8(line).trimmed()); continue; } // Read the plugin name and priority QString pluginName = QString::fromUtf8(fields.at(0)); - int priority = fields.at(1).trimmed().toInt(); - if (priority < 0) - { + int priority = fields.at(1).trimmed().toInt(); + if (priority < 0) { // WTF do you mean a negative priority? - log::error("locked order file: invalid line #{}: {}", lineNumber, QString::fromUtf8(line).trimmed()); + log::error("locked order file: invalid line #{}: {}", lineNumber, + QString::fromUtf8(line).trimmed()); continue; } // Determine the index of the plugin auto it = m_ESPsByName.find(pluginName); - if (it == m_ESPsByName.end()) - { + if (it == m_ESPsByName.end()) { // Plugin does not exist in the current set of plugins m_LockedOrder[pluginName] = priority; continue; @@ -586,42 +597,41 @@ void PluginList::readLockedOrderFrom(const QString &fileName) int pluginIndex = it->second; // Do not allow locking forced plugins - if (m_ESPs[pluginIndex].forceEnabled) - { + if (m_ESPs[pluginIndex].forceEnabled) { continue; } // If the priority is larger than the number of plugins, just keep it locked - if (priority >= m_ESPsByPriority.size()) - { + if (priority >= m_ESPsByPriority.size()) { m_LockedOrder[pluginName] = priority; continue; } // These are some helper functions for figuring out what is already locked - auto findLocked = [&](const std::pair<QString, int>& a) { return a.second == priority; }; - auto alreadyLocked = [&](){ return std::find_if(m_LockedOrder.begin(), m_LockedOrder.end(), findLocked) != m_LockedOrder.end(); }; + auto findLocked = [&](const std::pair<QString, int>& a) { + return a.second == priority; + }; + auto alreadyLocked = [&]() { + return std::find_if(m_LockedOrder.begin(), m_LockedOrder.end(), findLocked) != + m_LockedOrder.end(); + }; // See if we can just set the given priority - if (!m_ESPs[m_ESPsByPriority.at(priority)].forceEnabled && !alreadyLocked()) - { + if (!m_ESPs[m_ESPsByPriority.at(priority)].forceEnabled && !alreadyLocked()) { m_LockedOrder[pluginName] = priority; continue; } // Find the next higher priority we can set the plugin to - while (++priority < m_ESPs.size()) - { - if (!m_ESPs[m_ESPsByPriority.at(priority)].forceEnabled && !alreadyLocked()) - { + while (++priority < m_ESPs.size()) { + if (!m_ESPs[m_ESPsByPriority.at(priority)].forceEnabled && !alreadyLocked()) { m_LockedOrder[pluginName] = priority; break; } } // See if we walked off the end of the plugin list - if (priority >= m_ESPs.size()) - { + if (priority >= m_ESPs.size()) { // I guess go ahead and lock it here at the end of the list? m_LockedOrder[pluginName] = priority; continue; @@ -630,21 +640,22 @@ void PluginList::readLockedOrderFrom(const QString &fileName) file.close(); } -void PluginList::writeLockedOrder(const QString &fileName) const +void PluginList::writeLockedOrder(const QString& fileName) const { SafeWriteFile file(fileName); file->resize(0); - file->write(QString("# This file was automatically generated by Mod Organizer.\r\n").toUtf8()); + file->write(QString("# This file was automatically generated by Mod Organizer.\r\n") + .toUtf8()); for (auto iter = m_LockedOrder.begin(); iter != m_LockedOrder.end(); ++iter) { file->write(QString("%1|%2\r\n").arg(iter->first).arg(iter->second).toUtf8()); } file.commit(); } -void PluginList::saveTo(const QString &lockedOrderFileName) const +void PluginList::saveTo(const QString& lockedOrderFileName) const { - GamePlugins *gamePlugins = m_GamePlugin->feature<GamePlugins>(); + GamePlugins* gamePlugins = m_GamePlugin->feature<GamePlugins>(); if (gamePlugins) { gamePlugins->writePluginLists(m_Organizer.managedGameOrganizer()->pluginList()); } @@ -652,8 +663,7 @@ void PluginList::saveTo(const QString &lockedOrderFileName) const writeLockedOrder(lockedOrderFileName); } - -bool PluginList::saveLoadOrder(DirectoryEntry &directoryStructure) +bool PluginList::saveLoadOrder(DirectoryEntry& directoryStructure) { if (m_GamePlugin->loadOrderMechanism() != IPluginGame::LoadOrderMechanism::FileTime) { // nothing to do @@ -662,8 +672,8 @@ bool PluginList::saveLoadOrder(DirectoryEntry &directoryStructure) log::debug("setting file times on esps"); - for (ESPInfo &esp : m_ESPs) { - std::wstring espName = ToWString(esp.name); + for (ESPInfo& esp : m_ESPs) { + std::wstring espName = ToWString(esp.name); const FileEntryPtr fileEntry = directoryStructure.findFile(espName); if (fileEntry.get() != nullptr) { QString fileName; @@ -671,31 +681,37 @@ bool PluginList::saveLoadOrder(DirectoryEntry &directoryStructure) int originid = fileEntry->getOrigin(archive); fileName = QString("%1\\%2") - .arg(QDir::toNativeSeparators(ToQString(directoryStructure.getOriginByID(originid).getPath()))) - .arg(esp.name); + .arg(QDir::toNativeSeparators(ToQString( + directoryStructure.getOriginByID(originid).getPath()))) + .arg(esp.name); - HANDLE file = ::CreateFile(ToWString(fileName).c_str(), GENERIC_READ | GENERIC_WRITE, - 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + HANDLE file = + ::CreateFile(ToWString(fileName).c_str(), GENERIC_READ | GENERIC_WRITE, 0, + nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); if (file == INVALID_HANDLE_VALUE) { if (::GetLastError() == ERROR_SHARING_VIOLATION) { // file is locked, probably the game is running return false; } else { - throw windows_error(QObject::tr("failed to access %1").arg(fileName).toUtf8().constData()); + throw windows_error( + QObject::tr("failed to access %1").arg(fileName).toUtf8().constData()); } } ULONGLONG temp = 0; - temp = (145731ULL + esp.priority) * 24 * 60 * 60 * 10000000ULL; + temp = (145731ULL + esp.priority) * 24 * 60 * 60 * 10000000ULL; FILETIME newWriteTime; newWriteTime.dwLowDateTime = (DWORD)(temp & 0xFFFFFFFF); newWriteTime.dwHighDateTime = (DWORD)(temp >> 32); - esp.time = newWriteTime; + esp.time = newWriteTime; fileEntry->setFileTime(newWriteTime); if (!::SetFileTime(file, nullptr, nullptr, &newWriteTime)) { - throw windows_error(QObject::tr("failed to set file time %1").arg(fileName).toUtf8().constData()); + throw windows_error(QObject::tr("failed to set file time %1") + .arg(fileName) + .toUtf8() + .constData()); } CloseHandle(file); @@ -707,7 +723,7 @@ bool PluginList::saveLoadOrder(DirectoryEntry &directoryStructure) int PluginList::enabledCount() const { int enabled = 0; - for (const auto &info : m_ESPs) { + for (const auto& info : m_ESPs) { if (info.enabled) { ++enabled; } @@ -762,10 +778,11 @@ void PluginList::refreshLoadOrder() // set priorities according to locked load order std::map<int, QString> lockedLoadOrder; std::for_each(m_LockedOrder.begin(), m_LockedOrder.end(), - [&lockedLoadOrder] (const std::pair<QString, int> &ele) { - lockedLoadOrder[ele.second] = ele.first; }); + [&lockedLoadOrder](const std::pair<QString, int>& ele) { + lockedLoadOrder[ele.second] = ele.first; + }); - int targetPrio = 0; + int targetPrio = 0; bool savePluginsList = false; // this is guaranteed to iterate from lowest key (load order) to highest for (auto iter = lockedLoadOrder.begin(); iter != lockedLoadOrder.end(); ++iter) { @@ -783,7 +800,7 @@ void PluginList::refreshLoadOrder() continue; } - int temp = targetPrio; + int temp = targetPrio; int index = nameIter->second; if (m_ESPs[index].priority != temp) { setPluginPriority(index, temp); @@ -798,7 +815,8 @@ void PluginList::refreshLoadOrder() } } -void PluginList::disconnectSlots() { +void PluginList::disconnectSlots() +{ m_PluginMoved.disconnect_all_slots(); m_Refreshed.disconnect_all_slots(); m_PluginStateChanged.disconnect_all_slots(); @@ -813,48 +831,50 @@ QStringList PluginList::pluginNames() const { QStringList result; - for (const ESPInfo &info : m_ESPs) { + for (const ESPInfo& info : m_ESPs) { result.append(info.name); } return result; } -IPluginList::PluginStates PluginList::state(const QString &name) const +IPluginList::PluginStates PluginList::state(const QString& name) const { auto iter = m_ESPsByName.find(name); if (iter == m_ESPsByName.end()) { return IPluginList::STATE_MISSING; } else { - return m_ESPs[iter->second].enabled ? IPluginList::STATE_ACTIVE : IPluginList::STATE_INACTIVE; + return m_ESPs[iter->second].enabled ? IPluginList::STATE_ACTIVE + : IPluginList::STATE_INACTIVE; } } -void PluginList::setState(const QString &name, PluginStates state) { +void PluginList::setState(const QString& name, PluginStates state) +{ auto iter = m_ESPsByName.find(name); if (iter != m_ESPsByName.end()) { - m_ESPs[iter->second].enabled = (state == IPluginList::STATE_ACTIVE) || - m_ESPs[iter->second].forceEnabled; + m_ESPs[iter->second].enabled = + (state == IPluginList::STATE_ACTIVE) || m_ESPs[iter->second].forceEnabled; } else { log::warn("Plugin not found: {}", name); } } -void PluginList::setLoadOrder(const QStringList &pluginList) +void PluginList::setLoadOrder(const QStringList& pluginList) { - for (ESPInfo &info : m_ESPs) { + for (ESPInfo& info : m_ESPs) { info.priority = -1; } int maxPriority = 0; - for (const QString &plugin : pluginList) { + for (const QString& plugin : pluginList) { auto iter = m_ESPsByName.find(plugin); - if (iter !=m_ESPsByName.end()) { + if (iter != m_ESPsByName.end()) { m_ESPs[iter->second].priority = maxPriority++; } } // use old priorities - for (ESPInfo &info : m_ESPs) { + for (ESPInfo& info : m_ESPs) { if (info.priority == -1) { info.priority = maxPriority++; } @@ -862,7 +882,7 @@ void PluginList::setLoadOrder(const QStringList &pluginList) updateIndices(); } -int PluginList::priority(const QString &name) const +int PluginList::priority(const QString& name) const { auto iter = m_ESPsByName.find(name); if (iter == m_ESPsByName.end()) { @@ -872,7 +892,8 @@ int PluginList::priority(const QString &name) const } } -bool PluginList::setPriority(const QString& name, int newPriority) { +bool PluginList::setPriority(const QString& name, int newPriority) +{ if (newPriority < 0 || newPriority >= static_cast<int>(m_ESPsByPriority.size())) { return false; @@ -890,12 +911,12 @@ bool PluginList::setPriority(const QString& name, int newPriority) { if (oldPriority < newPriority) { newPriority += 1; } - changePluginPriority({ rowIndex }, newPriority); + changePluginPriority({rowIndex}, newPriority); return true; } -int PluginList::loadOrder(const QString &name) const +int PluginList::loadOrder(const QString& name) const { auto iter = m_ESPsByName.find(name); if (iter == m_ESPsByName.end()) { @@ -905,21 +926,21 @@ int PluginList::loadOrder(const QString &name) const } } -QStringList PluginList::masters(const QString &name) const +QStringList PluginList::masters(const QString& name) const { auto iter = m_ESPsByName.find(name); if (iter == m_ESPsByName.end()) { return QStringList(); } else { QStringList result; - for (const QString &master : m_ESPs[iter->second].masters) { + for (const QString& master : m_ESPs[iter->second].masters) { result.append(master); } return result; } } -QString PluginList::origin(const QString &name) const +QString PluginList::origin(const QString& name) const { auto iter = m_ESPsByName.find(name); if (iter == m_ESPsByName.end()) { @@ -934,8 +955,7 @@ bool PluginList::hasMasterExtension(const QString& name) const auto iter = m_ESPsByName.find(name); if (iter == m_ESPsByName.end()) { return false; - } - else { + } else { return m_ESPs[iter->second].hasMasterExtension; } } @@ -945,8 +965,7 @@ bool PluginList::hasLightExtension(const QString& name) const auto iter = m_ESPsByName.find(name); if (iter == m_ESPsByName.end()) { return false; - } - else { + } else { return m_ESPs[iter->second].hasLightExtension; } } @@ -956,8 +975,7 @@ bool PluginList::isMasterFlagged(const QString& name) const auto iter = m_ESPsByName.find(name); if (iter == m_ESPsByName.end()) { return false; - } - else { + } else { return m_ESPs[iter->second].isMasterFlagged; } } @@ -967,18 +985,20 @@ bool PluginList::isLightFlagged(const QString& name) const auto iter = m_ESPsByName.find(name); if (iter == m_ESPsByName.end()) { return false; - } - else { + } else { return m_ESPs[iter->second].isLightFlagged; } } -boost::signals2::connection PluginList::onPluginStateChanged(const std::function<void(const std::map<QString, PluginStates>&)>& func) +boost::signals2::connection PluginList::onPluginStateChanged( + const std::function<void(const std::map<QString, PluginStates>&)>& func) { return m_PluginStateChanged.connect(func); } -void PluginList::pluginStatesChanged(QStringList const& pluginNames, PluginStates state) const { +void PluginList::pluginStatesChanged(QStringList const& pluginNames, + PluginStates state) const +{ if (pluginNames.isEmpty()) { return; } @@ -989,12 +1009,14 @@ void PluginList::pluginStatesChanged(QStringList const& pluginNames, PluginState m_PluginStateChanged(infos); } -boost::signals2::connection PluginList::onRefreshed(const std::function<void ()> &callback) +boost::signals2::connection +PluginList::onRefreshed(const std::function<void()>& callback) { return m_Refreshed.connect(callback); } -boost::signals2::connection PluginList::onPluginMoved(const std::function<void (const QString &, int, int)> &func) +boost::signals2::connection +PluginList::onPluginMoved(const std::function<void(const QString&, int, int)>& func) { return m_PluginMoved.connect(func); } @@ -1012,7 +1034,7 @@ void PluginList::updateIndices() log::error("invalid plugin priority: {}", m_ESPs[i].priority); continue; } - m_ESPsByName[m_ESPs[i].name] = i; + m_ESPsByName[m_ESPs[i].name] = i; m_ESPsByPriority.at(static_cast<size_t>(m_ESPs[i].priority)) = i; } @@ -1021,11 +1043,12 @@ void PluginList::updateIndices() void PluginList::generatePluginIndexes() { - int numESLs = 0; + int numESLs = 0; int numSkipped = 0; GamePlugins* gamePlugins = m_GamePlugin->feature<GamePlugins>(); - const bool lightPluginsSupported = gamePlugins ? gamePlugins->lightPluginsAreSupported() : false; + const bool lightPluginsSupported = + gamePlugins ? gamePlugins->lightPluginsAreSupported() : false; for (int l = 0; l < m_ESPs.size(); ++l) { int i = m_ESPsByPriority.at(l); @@ -1034,18 +1057,23 @@ void PluginList::generatePluginIndexes() ++numSkipped; continue; } - if (lightPluginsSupported && (m_ESPs[i].hasLightExtension || m_ESPs[i].isLightFlagged)) { - int ESLpos = 254 + ((numESLs + 1) / 4096); - m_ESPs[i].index = QString("%1:%2").arg(ESLpos, 2, 16, QChar('0')).arg((numESLs) % 4096, 3, 16, QChar('0')).toUpper(); + if (lightPluginsSupported && + (m_ESPs[i].hasLightExtension || m_ESPs[i].isLightFlagged)) { + int ESLpos = 254 + ((numESLs + 1) / 4096); + m_ESPs[i].index = QString("%1:%2") + .arg(ESLpos, 2, 16, QChar('0')) + .arg((numESLs) % 4096, 3, 16, QChar('0')) + .toUpper(); ++numESLs; } else { - m_ESPs[i].index = QString("%1").arg(l - numESLs - numSkipped, 2, 16, QChar('0')).toUpper(); + m_ESPs[i].index = + QString("%1").arg(l - numESLs - numSkipped, 2, 16, QChar('0')).toUpper(); } } emit esplist_changed(); } -int PluginList::rowCount(const QModelIndex &parent) const +int PluginList::rowCount(const QModelIndex& parent) const { if (!parent.isValid()) { return static_cast<int>(m_ESPs.size()); @@ -1054,7 +1082,7 @@ int PluginList::rowCount(const QModelIndex &parent) const } } -int PluginList::columnCount(const QModelIndex &) const +int PluginList::columnCount(const QModelIndex&) const { return COL_LASTCOLUMN + 1; } @@ -1062,16 +1090,16 @@ int PluginList::columnCount(const QModelIndex &) const void PluginList::testMasters() { std::set<QString, FileNameComparator> enabledMasters; - for (const auto& iter: m_ESPs) { + for (const auto& iter : m_ESPs) { if (iter.enabled) { enabledMasters.insert(iter.name); } } - for (auto& iter: m_ESPs) { + for (auto& iter : m_ESPs) { iter.masterUnset.clear(); if (iter.enabled) { - for (const auto& master: iter.masters) { + for (const auto& master : iter.masters) { if (enabledMasters.find(master) == enabledMasters.end()) { iter.masterUnset.insert(master); } @@ -1080,7 +1108,7 @@ void PluginList::testMasters() } } -QVariant PluginList::data(const QModelIndex &modelIndex, int role) const +QVariant PluginList::data(const QModelIndex& modelIndex, int role) const { int index = modelIndex.row(); @@ -1104,27 +1132,26 @@ QVariant PluginList::data(const QModelIndex &modelIndex, int role) const return QVariant(); } -QVariant PluginList::displayData(const QModelIndex &modelIndex) const +QVariant PluginList::displayData(const QModelIndex& modelIndex) const { const int index = modelIndex.row(); - switch (modelIndex.column()) - { - case COL_NAME: - return m_ESPs[index].name; + switch (modelIndex.column()) { + case COL_NAME: + return m_ESPs[index].name; - case COL_PRIORITY: - return m_ESPs[index].priority; + case COL_PRIORITY: + return m_ESPs[index].priority; - case COL_MODINDEX: - return m_ESPs[index].index; + case COL_MODINDEX: + return m_ESPs[index].index; - default: - return {}; + default: + return {}; } } -QVariant PluginList::checkstateData(const QModelIndex &modelIndex) const +QVariant PluginList::checkstateData(const QModelIndex& modelIndex) const { const int index = modelIndex.row(); @@ -1135,7 +1162,7 @@ QVariant PluginList::checkstateData(const QModelIndex &modelIndex) const return m_ESPs[index].enabled ? Qt::Checked : Qt::Unchecked; } -QVariant PluginList::foregroundData(const QModelIndex &modelIndex) const +QVariant PluginList::foregroundData(const QModelIndex& modelIndex) const { const int index = modelIndex.row(); @@ -1146,7 +1173,7 @@ QVariant PluginList::foregroundData(const QModelIndex &modelIndex) const return {}; } -QVariant PluginList::backgroundData(const QModelIndex &modelIndex) const +QVariant PluginList::backgroundData(const QModelIndex& modelIndex) const { const int index = modelIndex.row(); @@ -1157,14 +1184,13 @@ QVariant PluginList::backgroundData(const QModelIndex &modelIndex) const return {}; } -QVariant PluginList::fontData(const QModelIndex &modelIndex) const +QVariant PluginList::fontData(const QModelIndex& modelIndex) const { const int index = modelIndex.row(); QFont result; - if (m_ESPs[index].hasMasterExtension || - m_ESPs[index].isMasterFlagged || + if (m_ESPs[index].hasMasterExtension || m_ESPs[index].isMasterFlagged || m_ESPs[index].hasLightExtension) { result.setItalic(true); result.setWeight(QFont::Bold); @@ -1175,7 +1201,7 @@ QVariant PluginList::fontData(const QModelIndex &modelIndex) const return result; } -QVariant PluginList::alignmentData(const QModelIndex &modelIndex) const +QVariant PluginList::alignmentData(const QModelIndex& modelIndex) const { const int index = modelIndex.row(); @@ -1186,7 +1212,7 @@ QVariant PluginList::alignmentData(const QModelIndex &modelIndex) const } } -QVariant PluginList::tooltipData(const QModelIndex &modelIndex) const +QVariant PluginList::tooltipData(const QModelIndex& modelIndex) const { const int index = modelIndex.row(); const auto& esp = m_ESPs[index]; @@ -1196,69 +1222,65 @@ QVariant PluginList::tooltipData(const QModelIndex &modelIndex) const toolTip += "<b>" + tr("Origin") + "</b>: " + esp.originName; if (esp.forceEnabled) { - toolTip += - "<br><b><i>" + - tr("This plugin can't be disabled (enforced by the game).") + - "</i></b>"; + toolTip += "<br><b><i>" + + tr("This plugin can't be disabled (enforced by the game).") + "</i></b>"; } else { if (!esp.author.isEmpty()) { - toolTip += - "<br><b>" + tr("Author") + "</b>: " + - TruncateString(esp.author); + toolTip += "<br><b>" + tr("Author") + "</b>: " + TruncateString(esp.author); } if (esp.description.size() > 0) { toolTip += - "<br><b>" + tr("Description") + "</b>: " + - TruncateString(esp.description); + "<br><b>" + tr("Description") + "</b>: " + TruncateString(esp.description); } if (esp.masterUnset.size() > 0) { toolTip += - "<br><b>" + tr("Missing Masters") + "</b>: " + - "<b>" + TruncateString(QStringList(esp.masterUnset.begin(), esp.masterUnset.end()).join(", ")) + "</b>"; + "<br><b>" + tr("Missing Masters") + "</b>: " + "<b>" + + TruncateString( + QStringList(esp.masterUnset.begin(), esp.masterUnset.end()).join(", ")) + + "</b>"; } std::set<QString> enabledMasters; - std::set_difference(esp.masters.begin(), esp.masters.end(), - esp.masterUnset.begin(), esp.masterUnset.end(), - std::inserter(enabledMasters, enabledMasters.end())); + std::set_difference(esp.masters.begin(), esp.masters.end(), esp.masterUnset.begin(), + esp.masterUnset.end(), + std::inserter(enabledMasters, enabledMasters.end())); if (!enabledMasters.empty()) { - toolTip += - "<br><b>" + tr("Enabled Masters") + "</b>: " + - TruncateString(SetJoin(enabledMasters, ", ")); + toolTip += "<br><b>" + tr("Enabled Masters") + + "</b>: " + TruncateString(SetJoin(enabledMasters, ", ")); } if (!esp.archives.empty()) { toolTip += - "<br><b>" + tr("Loads Archives") + "</b>: " + - TruncateString(QStringList(esp.archives.begin(), esp.archives.end()).join(", ")) + - "<br>" + tr( - "There are Archives connected to this plugin. Their assets will be " - "added to your game, overwriting in case of conflicts following the " - "plugin order. Loose files will always overwrite assets from " - "Archives. (This flag only checks for Archives from the same mod as " - "the plugin)"); + "<br><b>" + tr("Loads Archives") + "</b>: " + + TruncateString( + QStringList(esp.archives.begin(), esp.archives.end()).join(", ")) + + "<br>" + + tr("There are Archives connected to this plugin. Their assets will be " + "added to your game, overwriting in case of conflicts following the " + "plugin order. Loose files will always overwrite assets from " + "Archives. (This flag only checks for Archives from the same mod as " + "the plugin)"); } if (esp.hasIni) { toolTip += - "<br><b>" + tr("Loads INI settings") + "</b>: " - "<br>" + tr( - "There is an ini file connected to this plugin. Its settings will " - "be added to your game settings, overwriting in case of conflicts."); + "<br><b>" + tr("Loads INI settings") + + "</b>: " + "<br>" + + tr("There is an ini file connected to this plugin. Its settings will " + "be added to your game settings, overwriting in case of conflicts."); } if (esp.isLightFlagged && !esp.hasLightExtension) { - toolTip += - "<br><br>" + tr( - "This ESP is flagged as an ESL. It will adhere to the ESP load " - "order but the records will be loaded in ESL space."); + toolTip += "<br><br>" + + tr("This ESP is flagged as an ESL. It will adhere to the ESP load " + "order but the records will be loaded in ESL space."); } } - // additional info auto itor = m_AdditionalInfo.find(esp.name); @@ -1285,10 +1307,10 @@ QString PluginList::makeLootTooltip(const Loot::Plugin& loot) const QString s; for (auto&& f : loot.incompatibilities) { - s += - "<li>" + tr("Incompatible with %1") - .arg(f.displayName.isEmpty() ? f.name : f.displayName) + - "</li>"; + s += "<li>" + + tr("Incompatible with %1") + .arg(f.displayName.isEmpty() ? f.name : f.displayName) + + "</li>"; } for (auto&& m : loot.missingMasters) { @@ -1298,21 +1320,20 @@ QString PluginList::makeLootTooltip(const Loot::Plugin& loot) const for (auto&& m : loot.messages) { s += "<li>"; - switch (m.type) - { - case log::Warning: - s += tr("Warning") + ": "; - break; + switch (m.type) { + case log::Warning: + s += tr("Warning") + ": "; + break; - case log::Error: - s += tr("Error") + ": "; - break; + case log::Error: + s += tr("Error") + ": "; + break; - case log::Info: // fall-through - case log::Debug: - default: - // nothing - break; + case log::Info: // fall-through + case log::Debug: + default: + // nothing + break; } s += m.text + "</li>"; @@ -1327,17 +1348,16 @@ QString PluginList::makeLootTooltip(const Loot::Plugin& loot) const } if (!s.isEmpty()) { - s = - "<hr>" - "<ul style=\"margin-top:0px; padding-top:0px; margin-left:15px; -qt-list-indent: 0;\">" + - s + - "</ul>"; + s = "<hr>" + "<ul style=\"margin-top:0px; padding-top:0px; margin-left:15px; " + "-qt-list-indent: 0;\">" + + s + "</ul>"; } return s; } -QVariant PluginList::iconData(const QModelIndex &modelIndex) const +QVariant PluginList::iconData(const QModelIndex& modelIndex) const { int index = modelIndex.row(); @@ -1417,9 +1437,9 @@ bool PluginList::hasInfo(const ESPInfo& esp, const AdditionalInfo* info) const return false; } -bool PluginList::setData(const QModelIndex &modIndex, const QVariant &value, int role) +bool PluginList::setData(const QModelIndex& modIndex, const QVariant& value, int role) { - QString modName = modIndex.data().toString(); + QString modName = modIndex.data().toString(); IPluginList::PluginStates oldState = state(modName); bool result = false; @@ -1436,7 +1456,7 @@ bool PluginList::setData(const QModelIndex &modIndex, const QVariant &value, int result = true; } else if (role == Qt::EditRole) { if (modIndex.column() == COL_PRIORITY) { - bool ok = false; + bool ok = false; int newPriority = value.toInt(&ok); if (ok) { setPluginPriority(modIndex.row(), newPriority); @@ -1450,12 +1470,11 @@ bool PluginList::setData(const QModelIndex &modIndex, const QVariant &value, int IPluginList::PluginStates newState = state(modName); if (oldState != newState) { try { - pluginStatesChanged({ modName }, newState); + pluginStatesChanged({modName}, newState); testMasters(); - emit dataChanged( - this->index(0, 0), - this->index(static_cast<int>(m_ESPs.size()), columnCount())); - } catch (const std::exception &e) { + emit dataChanged(this->index(0, 0), + this->index(static_cast<int>(m_ESPs.size()), columnCount())); + } catch (const std::exception& e) { log::error("failed to invoke state changed notification: {}", e.what()); } catch (...) { log::error("failed to invoke state changed notification: unknown exception"); @@ -1466,7 +1485,7 @@ bool PluginList::setData(const QModelIndex &modIndex, const QVariant &value, int } QVariant PluginList::headerData(int section, Qt::Orientation orientation, - int role) const + int role) const { if (orientation == Qt::Horizontal) { if (role == Qt::DisplayRole) { @@ -1478,12 +1497,12 @@ QVariant PluginList::headerData(int section, Qt::Orientation orientation, return QAbstractItemModel::headerData(section, orientation, role); } -Qt::ItemFlags PluginList::flags(const QModelIndex &modelIndex) const +Qt::ItemFlags PluginList::flags(const QModelIndex& modelIndex) const { - int index = modelIndex.row(); + int index = modelIndex.row(); Qt::ItemFlags result = QAbstractItemModel::flags(modelIndex); - if (modelIndex.isValid()) { + if (modelIndex.isValid()) { if (!m_ESPs[index].forceEnabled) { result |= Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled; } @@ -1498,7 +1517,7 @@ Qt::ItemFlags PluginList::flags(const QModelIndex &modelIndex) const return result; } -void PluginList::setPluginPriority(int row, int &newPriority, bool isForced) +void PluginList::setPluginPriority(int row, int& newPriority, bool isForced) { int newPriorityTemp = newPriority; @@ -1508,14 +1527,13 @@ void PluginList::setPluginPriority(int row, int &newPriority, bool isForced) else if (newPriorityTemp >= static_cast<int>(m_ESPsByPriority.size())) newPriorityTemp = static_cast<int>(m_ESPsByPriority.size()) - 1; - if (!m_ESPs[row].isMasterFlagged && - !m_ESPs[row].hasLightExtension && + if (!m_ESPs[row].isMasterFlagged && !m_ESPs[row].hasLightExtension && !m_ESPs[row].hasMasterExtension) { // don't allow esps to be moved above esms while ((newPriorityTemp < static_cast<int>(m_ESPsByPriority.size() - 1)) && - (m_ESPs.at(m_ESPsByPriority.at(newPriorityTemp)).isMasterFlagged || - m_ESPs.at(m_ESPsByPriority.at(newPriorityTemp)).hasLightExtension || - m_ESPs.at(m_ESPsByPriority.at(newPriorityTemp)).hasMasterExtension)) { + (m_ESPs.at(m_ESPsByPriority.at(newPriorityTemp)).isMasterFlagged || + m_ESPs.at(m_ESPsByPriority.at(newPriorityTemp)).hasLightExtension || + m_ESPs.at(m_ESPsByPriority.at(newPriorityTemp)).hasMasterExtension)) { ++newPriorityTemp; } } else { @@ -1534,20 +1552,18 @@ void PluginList::setPluginPriority(int row, int &newPriority, bool isForced) } int oldPriority = m_ESPs.at(row).priority; - if (newPriorityTemp < oldPriority) { // moving up + if (newPriorityTemp < oldPriority) { // moving up // don't allow plugins to be moved above their masters for (auto master : m_ESPs[row].masters) { auto iter = m_ESPsByName.find(master); if (iter != m_ESPsByName.end()) { int masterPriority = m_ESPs[iter->second].priority; - if (masterPriority >= newPriorityTemp) - { + if (masterPriority >= newPriorityTemp) { newPriorityTemp = masterPriority + 1; } } } - } - else if (newPriorityTemp > oldPriority) { // moving down + } else if (newPriorityTemp > oldPriority) { // moving down // don't allow masters to be moved below their children for (int i = oldPriority + 1; i <= newPriorityTemp; i++) { PluginList::ESPInfo* otherInfo = &m_ESPs.at(m_ESPsByPriority[i]); @@ -1567,13 +1583,14 @@ void PluginList::setPluginPriority(int row, int &newPriority, bool isForced) for (int i = oldPriority + 1; i <= newPriorityTemp; ++i) { --m_ESPs.at(m_ESPsByPriority.at(i)).priority; } - emit dataChanged(index(oldPriority + 1, 0), index(newPriorityTemp, columnCount())); - } - else { + emit dataChanged(index(oldPriority + 1, 0), + index(newPriorityTemp, columnCount())); + } else { for (int i = newPriorityTemp; i < oldPriority; ++i) { ++m_ESPs.at(m_ESPsByPriority.at(i)).priority; } - emit dataChanged(index(newPriorityTemp, 0), index(oldPriority - 1, columnCount())); + emit dataChanged(index(newPriorityTemp, 0), + index(oldPriority - 1, columnCount())); ++newPriority; } @@ -1591,14 +1608,14 @@ void PluginList::setPluginPriority(int row, int &newPriority, bool isForced) void PluginList::changePluginPriority(std::vector<int> rows, int newPriority) { ChangeBracket<PluginList> layoutChange(this); - const std::vector<ESPInfo> &esp = m_ESPs; + const std::vector<ESPInfo>& esp = m_ESPs; int minPriority = INT_MAX; int maxPriority = INT_MIN; // don't try to move plugins before force-enabled plugins - for (std::vector<ESPInfo>::const_iterator iter = m_ESPs.begin(); - iter != m_ESPs.end(); ++iter) { + for (std::vector<ESPInfo>::const_iterator iter = m_ESPs.begin(); iter != m_ESPs.end(); + ++iter) { if (iter->forceEnabled) { newPriority = std::max(newPriority, iter->priority + 1); } @@ -1611,22 +1628,22 @@ void PluginList::changePluginPriority(std::vector<int> rows, int newPriority) newPriority = std::max(newPriority, minPriority); // sort the moving plugins by ascending priorities - std::sort(rows.begin(), rows.end(), - [&esp](const int &LHS, const int &RHS) { + std::sort(rows.begin(), rows.end(), [&esp](const int& LHS, const int& RHS) { return esp[LHS].priority < esp[RHS].priority; }); // if at least on plugin is increasing in priority, the target index is // that of the row BELOW the dropped location, otherwise it's the one above - for (std::vector<int>::const_iterator iter = rows.begin(); - iter != rows.end(); ++iter) { + for (std::vector<int>::const_iterator iter = rows.begin(); iter != rows.end(); + ++iter) { if (m_ESPs[*iter].priority < newPriority) { --newPriority; break; } } - for (std::vector<int>::const_iterator iter = rows.begin(); iter != rows.end(); ++iter) { + for (std::vector<int>::const_iterator iter = rows.begin(); iter != rows.end(); + ++iter) { setPluginPriority(*iter, newPriority); } @@ -1635,7 +1652,8 @@ void PluginList::changePluginPriority(std::vector<int> rows, int newPriority) emit writePluginsList(); } -bool PluginList::dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int row, int, const QModelIndex &parent) +bool PluginList::dropMimeData(const QMimeData* mimeData, Qt::DropAction action, int row, + int, const QModelIndex& parent) { if (action == Qt::IgnoreAction) { return true; @@ -1648,9 +1666,9 @@ bool PluginList::dropMimeData(const QMimeData *mimeData, Qt::DropAction action, while (!stream.atEnd()) { int sourceRow, col; - QMap<int, QVariant> roleDataMap; + QMap<int, QVariant> roleDataMap; stream >> sourceRow >> col >> roleDataMap; - if (col == 0) { // only add each row once + if (col == 0) { // only add each row once sourceRows.push_back(sourceRow); } } @@ -1661,8 +1679,7 @@ bool PluginList::dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int newPriority; - if ((row < 0) || - (row >= static_cast<int>(m_ESPs.size()))) { + if ((row < 0) || (row >= static_cast<int>(m_ESPs.size()))) { newPriority = static_cast<int>(m_ESPs.size()); } else { newPriority = m_ESPs[row].priority; @@ -1685,37 +1702,38 @@ QModelIndex PluginList::parent(const QModelIndex&) const return QModelIndex(); } -PluginList::ESPInfo::ESPInfo(const QString &name, bool enabled, - const QString &originName, const QString &fullPath, - bool hasIni, std::set<QString> archives, bool lightPluginsAreSupported) - : name(name), fullPath(fullPath), enabled(enabled), forceEnabled(enabled), - priority(0), loadOrder(-1), originName(originName), hasIni(hasIni), - archives(archives.begin(), archives.end()), modSelected(false) +PluginList::ESPInfo::ESPInfo(const QString& name, bool enabled, + const QString& originName, const QString& fullPath, + bool hasIni, std::set<QString> archives, + bool lightPluginsAreSupported) + : name(name), fullPath(fullPath), enabled(enabled), forceEnabled(enabled), + priority(0), loadOrder(-1), originName(originName), hasIni(hasIni), + archives(archives.begin(), archives.end()), modSelected(false) { try { ESP::File file(ToWString(fullPath)); - auto extension = name.right(3).toLower(); + auto extension = name.right(3).toLower(); hasMasterExtension = (extension == "esm"); - hasLightExtension = lightPluginsAreSupported && (extension == "esl"); - isMasterFlagged = file.isMaster(); - isLightFlagged = lightPluginsAreSupported && file.isLight(); + hasLightExtension = lightPluginsAreSupported && (extension == "esl"); + isMasterFlagged = file.isMaster(); + isLightFlagged = lightPluginsAreSupported && file.isLight(); - author = QString::fromLatin1(file.author().c_str()); + author = QString::fromLatin1(file.author().c_str()); description = QString::fromLatin1(file.description().c_str()); for (auto&& m : file.masters()) { masters.insert(QString::fromStdString(m)); } - } catch (const std::exception &e) { + } catch (const std::exception& e) { log::error("failed to parse plugin file {}: {}", fullPath, e.what()); hasMasterExtension = false; - hasLightExtension = false; - isMasterFlagged = false; - isLightFlagged = false; + hasLightExtension = false; + isMasterFlagged = false; + isLightFlagged = false; } } -void PluginList::managedGameChanged(const IPluginGame *gamePlugin) +void PluginList::managedGameChanged(const IPluginGame* gamePlugin) { m_GamePlugin = gamePlugin; } diff --git a/src/pluginlist.h b/src/pluginlist.h index c21a6cee..e7a65c81 100644 --- a/src/pluginlist.h +++ b/src/pluginlist.h @@ -20,40 +20,42 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef PLUGINLIST_H #define PLUGINLIST_H +#include "loot.h" +#include "profile.h" #include <ifiletree.h> #include <ipluginlist.h> -#include "profile.h" -#include "loot.h" -namespace MOBase { class IPluginGame; } +namespace MOBase +{ +class IPluginGame; +} -#include <QString> -#include <QListWidget> -#include <QTimer> -#include <QTime> #include <QElapsedTimer> +#include <QListWidget> +#include <QString> #include <QTemporaryFile> +#include <QTime> +#include <QTimer> #pragma warning(push) -#pragma warning(disable: 4100) +#pragma warning(disable : 4100) #ifndef Q_MOC_RUN -#include <boost/signals2.hpp> #include <boost/ptr_container/ptr_vector.hpp> +#include <boost/signals2.hpp> #endif -#include <vector> #include <map> +#include <vector> class OrganizerCore; - template <class C> -class ChangeBracket { +class ChangeBracket +{ public: - ChangeBracket(C *model) - : m_Model(nullptr) + ChangeBracket(C* model) : m_Model(nullptr) { - QVariant var = model->property("__aboutToChange"); + QVariant var = model->property("__aboutToChange"); bool aboutToChange = var.isValid() && var.toBool(); if (!aboutToChange) { model->layoutAboutToBeChanged(); @@ -61,11 +63,10 @@ public: m_Model = model; } } - ~ChangeBracket() { - finish(); - } + ~ChangeBracket() { finish(); } - void finish() { + void finish() + { if (m_Model != nullptr) { m_Model->layoutChanged(); m_Model->setProperty("__aboutToChange", false); @@ -74,11 +75,9 @@ public: } private: - C *m_Model; + C* m_Model; }; - - /** * @brief model representing the plugins (.esp/.esm) in the current virtual data folder **/ @@ -86,9 +85,10 @@ class PluginList : public QAbstractItemModel { Q_OBJECT friend class ChangeBracket<PluginList>; -public: - enum EColumn { +public: + enum EColumn + { COL_NAME, COL_FLAGS, COL_PRIORITY, @@ -101,18 +101,18 @@ public: friend class PluginListProxy; - using SignalRefreshed = boost::signals2::signal<void ()>; - using SignalPluginMoved = boost::signals2::signal<void (const QString &, int, int)>; - using SignalPluginStateChanged = boost::signals2::signal<void (const std::map<QString, PluginStates>&)>; + using SignalRefreshed = boost::signals2::signal<void()>; + using SignalPluginMoved = boost::signals2::signal<void(const QString&, int, int)>; + using SignalPluginStateChanged = + boost::signals2::signal<void(const std::map<QString, PluginStates>&)>; public: - /** * @brief constructor * * @param parent parent object **/ - PluginList(OrganizerCore &organizer); + PluginList(OrganizerCore& organizer); ~PluginList(); @@ -120,14 +120,14 @@ public: * @brief does a complete refresh of the list * * @param profileName name of the current profile - * @param baseDirectory the root directory structure representing the virtual data directory + * @param baseDirectory the root directory structure representing the virtual data + *directory * @param lockedOrderFile list of plugins that shouldn't change load order * @todo the profile is not used? If it was, we should pass the Profile-object instead **/ - void refresh(const QString &profileName - , const MOShared::DirectoryEntry &baseDirectory - , const QString &lockedOrderFile - , bool refresh); + void refresh(const QString& profileName, + const MOShared::DirectoryEntry& baseDirectory, + const QString& lockedOrderFile, bool refresh); /** * @brief enable a plugin based on its name @@ -135,7 +135,7 @@ public: * @param name name of the plugin to enable * @param enable set to true to enable the esp, false to disable it **/ - void enableESP(const QString &name, bool enable = true); + void enableESP(const QString& name, bool enable = true); /** * @brief test if a plugin is enabled @@ -143,7 +143,7 @@ public: * @param name name of the plugin to look up * @return true if the plugin is enabled, false otherwise **/ - bool isEnabled(const QString &name); + bool isEnabled(const QString& name); /** * @brief clear all additional information we stored on plugins @@ -154,14 +154,14 @@ public: * @brief reset additional information on a mod * @param name name of the plugin to clear the information of */ - void clearInformation(const QString &name); + void clearInformation(const QString& name); /** * @brief add additional information on a mod (i.e. from loot) * @param name name of the plugin to add information about * @param message the message to add to the plugin */ - void addInformation(const QString &name, const QString &message); + void addInformation(const QString& name, const QString& message); /** * adds information from a loot report @@ -182,21 +182,24 @@ public: * * @param lockedOrderFileName path of the lockedorder.txt to write to **/ - void saveTo(const QString &lockedOrderFileName) const; + void saveTo(const QString& lockedOrderFileName) const; /** * @brief save the current load order * * the load order used by the game is defined by the last modification time which this - * function sets. An exception is newer version of skyrim where the load order is defined - * by the order of files in plugins.txt - * @param directoryStructure the root directory structure representing the virtual data directory - * @return true on success or if there was nothing to save, false if the load order can't be saved, i.e. because files are locked - * @todo since this works on actual files the load order can't be configured per-profile. Files of the same name - * in different mods can also have different load orders which makes this very intransparent + * function sets. An exception is newer version of skyrim where the load order is + *defined by the order of files in plugins.txt + * @param directoryStructure the root directory structure representing the virtual + *data directory + * @return true on success or if there was nothing to save, false if the load order + *can't be saved, i.e. because files are locked + * @todo since this works on actual files the load order can't be configured + *per-profile. Files of the same name in different mods can also have different load + *orders which makes this very intransparent * @note also stores to disk the list of locked esps **/ - bool saveLoadOrder(MOShared::DirectoryEntry &directoryStructure); + bool saveLoadOrder(MOShared::DirectoryEntry& directoryStructure); /** * @return number of enabled plugins in the list @@ -216,24 +219,22 @@ public: // highlight plugins contained in the mods at the given indices // - void highlightPlugins( - const std::vector<unsigned int>& modIndices, - const MOShared::DirectoryEntry &directoryEntry); + void highlightPlugins(const std::vector<unsigned int>& modIndices, + const MOShared::DirectoryEntry& directoryEntry); void refreshLoadOrder(); void disconnectSlots(); public: - QStringList pluginNames() const; - PluginStates state(const QString &name) const; - void setState(const QString &name, PluginStates state); - int priority(const QString &name) const; - int loadOrder(const QString &name) const; + PluginStates state(const QString& name) const; + void setState(const QString& name, PluginStates state); + int priority(const QString& name) const; + int loadOrder(const QString& name) const; bool setPriority(const QString& name, int newPriority); - QStringList masters(const QString &name) const; - QString origin(const QString &name) const; + QStringList masters(const QString& name) const; + QString origin(const QString& name) const; void setLoadOrder(const QStringList& pluginList); bool hasMasterExtension(const QString& name) const; @@ -242,21 +243,26 @@ public: bool isLightFlagged(const QString& name) const; boost::signals2::connection onRefreshed(const std::function<void()>& callback); - boost::signals2::connection onPluginMoved(const std::function<void(const QString&, int, int)>& func); - boost::signals2::connection onPluginStateChanged(const std::function<void (const std::map<QString, PluginStates>&)> &func); - -public: // implementation of the QAbstractTableModel interface + boost::signals2::connection + onPluginMoved(const std::function<void(const QString&, int, int)>& func); + boost::signals2::connection onPluginStateChanged( + const std::function<void(const std::map<QString, PluginStates>&)>& func); - virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; - virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; - virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); - virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - virtual Qt::ItemFlags flags(const QModelIndex &index) const; +public: // implementation of the QAbstractTableModel interface + virtual int rowCount(const QModelIndex& parent = QModelIndex()) const; + virtual int columnCount(const QModelIndex& parent = QModelIndex()) const; + virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; + virtual bool setData(const QModelIndex& index, const QVariant& value, + int role = Qt::EditRole); + virtual QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + virtual Qt::ItemFlags flags(const QModelIndex& index) const; virtual Qt::DropActions supportedDropActions() const { return Qt::MoveAction; } - virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); - virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; - virtual QModelIndex parent(const QModelIndex &child) const; + virtual bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, + int column, const QModelIndex& parent); + virtual QModelIndex index(int row, int column, + const QModelIndex& parent = QModelIndex()) const; + virtual QModelIndex parent(const QModelIndex& child) const; public slots: @@ -284,7 +290,7 @@ public slots: * @brief The currently managed game has changed * @param gamePlugin */ - void managedGameChanged(MOBase::IPluginGame const *gamePlugin); + void managedGameChanged(MOBase::IPluginGame const* gamePlugin); /** * @brief Generate the plugin indexes because something was changed @@ -293,24 +299,22 @@ public slots: signals: - /** - * @brief emitted when the plugin list changed, i.e. the load order was modified or a plugin was checked/unchecked - * @note this is currently only used to signal that there are changes that can be saved, it does - * not immediately cause anything to be written to disc - **/ - void esplist_changed(); - - void writePluginsList(); + /** + * @brief emitted when the plugin list changed, i.e. the load order was modified or a + *plugin was checked/unchecked + * @note this is currently only used to signal that there are changes that can be + *saved, it does not immediately cause anything to be written to disc + **/ + void esplist_changed(); + void writePluginsList(); private: - struct ESPInfo { - ESPInfo( - const QString &name, bool enabled, const QString &originName, - const QString &fullPath, bool hasIni, std::set<QString> archives, - bool lightSupported); + ESPInfo(const QString& name, bool enabled, const QString& originName, + const QString& fullPath, bool hasIni, std::set<QString> archives, + bool lightSupported); QString name; QString fullPath; @@ -333,26 +337,23 @@ private: std::set<QString, MOBase::FileNameComparator> masters; mutable std::set<QString, MOBase::FileNameComparator> masterUnset; - bool operator < (const ESPInfo& str) const - { - return (loadOrder < str.loadOrder); - } + bool operator<(const ESPInfo& str) const { return (loadOrder < str.loadOrder); } }; - struct AdditionalInfo { + struct AdditionalInfo + { QStringList messages; Loot::Plugin loot; }; private: - void syncLoadOrder(); void updateIndices(); - void writeLockedOrder(const QString &fileName) const; + void writeLockedOrder(const QString& fileName) const; - void readLockedOrderFrom(const QString &fileName); - void setPluginPriority(int row, int &newPriority, bool isForced=false); + void readLockedOrderFrom(const QString& fileName); + void setPluginPriority(int row, int& newPriority, bool isForced = false); void changePluginPriority(std::vector<int> rows, int newPriority); void testMasters(); @@ -364,7 +365,8 @@ private: int findPluginByPriority(int priority); /** - * @brief Notify MO2 plugins that the states of the given plugins have changed to the given state. + * @brief Notify MO2 plugins that the states of the given plugins have changed to the + * given state. * * @param pluginNames Names of the plugin. * @param state New state of the plugin. @@ -373,7 +375,6 @@ private: void pluginStatesChanged(QStringList const& pluginNames, PluginStates state) const; private: - OrganizerCore& m_Organizer; std::vector<ESPInfo> m_ESPs; @@ -384,7 +385,8 @@ private: std::map<QString, int, MOBase::FileNameComparator> m_LockedOrder; - std::map<QString, AdditionalInfo, MOBase::FileNameComparator> m_AdditionalInfo; // maps esp names to boss information + std::map<QString, AdditionalInfo, MOBase::FileNameComparator> + m_AdditionalInfo; // maps esp names to boss information QString m_CurrentProfile; QFontMetrics m_FontMetrics; @@ -397,17 +399,16 @@ private: QElapsedTimer m_LastCheck; - const MOBase::IPluginGame *m_GamePlugin; - + const MOBase::IPluginGame* m_GamePlugin; - QVariant displayData(const QModelIndex &modelIndex) const; - QVariant checkstateData(const QModelIndex &modelIndex) const; - QVariant foregroundData(const QModelIndex &modelIndex) const; - QVariant backgroundData(const QModelIndex &modelIndex) const; - QVariant fontData(const QModelIndex &modelIndex) const; - QVariant alignmentData(const QModelIndex &modelIndex) const; - QVariant tooltipData(const QModelIndex &modelIndex) const; - QVariant iconData(const QModelIndex &modelIndex) const; + QVariant displayData(const QModelIndex& modelIndex) const; + QVariant checkstateData(const QModelIndex& modelIndex) const; + QVariant foregroundData(const QModelIndex& modelIndex) const; + QVariant backgroundData(const QModelIndex& modelIndex) const; + QVariant fontData(const QModelIndex& modelIndex) const; + QVariant alignmentData(const QModelIndex& modelIndex) const; + QVariant tooltipData(const QModelIndex& modelIndex) const; + QVariant iconData(const QModelIndex& modelIndex) const; QString makeLootTooltip(const Loot::Plugin& loot) const; bool isProblematic(const ESPInfo& esp, const AdditionalInfo* info) const; @@ -416,4 +417,4 @@ private: #pragma warning(pop) -#endif // PLUGINLIST_H +#endif // PLUGINLIST_H diff --git a/src/pluginlistcontextmenu.cpp b/src/pluginlistcontextmenu.cpp index c6d4ecec..80ad75f3 100644 --- a/src/pluginlistcontextmenu.cpp +++ b/src/pluginlistcontextmenu.cpp @@ -3,43 +3,45 @@ #include <report.h> #include <utility.h> -#include "pluginlistview.h" #include "organizercore.h" +#include "pluginlistview.h" using namespace MOBase; -PluginListContextMenu::PluginListContextMenu( - const QModelIndex& index, OrganizerCore& core, PluginListView* view) : - QMenu(view) - , m_core(core) - , m_index(index.model() == view->model() ? view->indexViewToModel(index) : index) - , m_view(view) +PluginListContextMenu::PluginListContextMenu(const QModelIndex& index, + OrganizerCore& core, PluginListView* view) + : QMenu(view), m_core(core), + m_index(index.model() == view->model() ? view->indexViewToModel(index) : index), + m_view(view) { if (view->selectionModel()->hasSelection()) { m_selected = view->indexViewToModel(view->selectionModel()->selectedRows()); - } - else if (index.isValid()) { - m_selected = { index }; + } else if (index.isValid()) { + m_selected = {index}; } if (!m_selected.isEmpty()) { - addAction(tr("Enable selected"), [=]() { m_core.pluginList()->setEnabled(m_selected, true); }); - addAction(tr("Disable selected"), [=]() { m_core.pluginList()->setEnabled(m_selected, false); }); + addAction(tr("Enable selected"), [=]() { + m_core.pluginList()->setEnabled(m_selected, true); + }); + addAction(tr("Disable selected"), [=]() { + m_core.pluginList()->setEnabled(m_selected, false); + }); addSeparator(); } addAction(tr("Enable all"), [=]() { - if (QMessageBox::question( - m_view->topLevelWidget(), tr("Confirm"), tr("Really enable all plugins?"), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + if (QMessageBox::question(m_view->topLevelWidget(), tr("Confirm"), + tr("Really enable all plugins?"), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { m_core.pluginList()->setEnabledAll(true); } }); addAction(tr("Disable all"), [=]() { - if (QMessageBox::question( - m_view->topLevelWidget(), tr("Confirm"), tr("Really disable all plugins?"), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + if (QMessageBox::question(m_view->topLevelWidget(), tr("Confirm"), + tr("Really disable all plugins?"), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { m_core.pluginList()->setEnabledAll(false); } }); @@ -50,63 +52,77 @@ PluginListContextMenu::PluginListContextMenu( addSeparator(); - bool hasLocked = false; + bool hasLocked = false; bool hasUnlocked = false; for (auto& idx : m_selected) { if (m_core.pluginList()->isEnabled(idx.row())) { if (m_core.pluginList()->isESPLocked(idx.row())) { hasLocked = true; - } - else { + } else { hasUnlocked = true; } } } if (hasLocked) { - addAction(tr("Unlock load order"), [=]() { setESPLock(m_selected, false); }); + addAction(tr("Unlock load order"), [=]() { + setESPLock(m_selected, false); + }); } if (hasUnlocked) { - addAction(tr("Lock load order"), [=]() { setESPLock(m_selected, true); }); + addAction(tr("Lock load order"), [=]() { + setESPLock(m_selected, true); + }); } } if (m_index.isValid()) { addSeparator(); - unsigned int modInfoIndex = ModInfo::getIndex(m_core.pluginList()->origin(m_index.data().toString())); + unsigned int modInfoIndex = + ModInfo::getIndex(m_core.pluginList()->origin(m_index.data().toString())); // this is to avoid showing the option on game files like skyrim.esm if (modInfoIndex != UINT_MAX) { - addAction(tr("Open Origin in Explorer"), [=]() { openOriginExplorer(m_selected); }); - ModInfo::Ptr modInfo = ModInfo::getByIndex(modInfoIndex); + addAction(tr("Open Origin in Explorer"), [=]() { + openOriginExplorer(m_selected); + }); + ModInfo::Ptr modInfo = ModInfo::getByIndex(modInfoIndex); std::vector<ModInfo::EFlag> flags = modInfo->getFlags(); if (!modInfo->isForeign() && m_selected.size() == 1) { - QAction* infoAction = addAction(tr("Open Origin Info..."), [=]() { openOriginInformation(index); }); + QAction* infoAction = addAction(tr("Open Origin Info..."), [=]() { + openOriginInformation(index); + }); setDefaultAction(infoAction); } } } - } QMenu* PluginListContextMenu::createSendToContextMenu() { QMenu* menu = new QMenu(m_view); menu->setTitle(tr("Send to... ")); - menu->addAction(tr("Top"), [=]() { m_core.pluginList()->sendToPriority(m_selected, 0); }); - menu->addAction(tr("Bottom"), [=]() { m_core.pluginList()->sendToPriority(m_selected, INT_MAX); }); - menu->addAction(tr("Priority..."), [=]() { sendPluginsToPriority(m_selected); }); + menu->addAction(tr("Top"), [=]() { + m_core.pluginList()->sendToPriority(m_selected, 0); + }); + menu->addAction(tr("Bottom"), [=]() { + m_core.pluginList()->sendToPriority(m_selected, INT_MAX); + }); + menu->addAction(tr("Priority..."), [=]() { + sendPluginsToPriority(m_selected); + }); return menu; } void PluginListContextMenu::sendPluginsToPriority(const QModelIndexList& indices) { bool ok; - int newPriority = QInputDialog::getInt(m_view->topLevelWidget(), - tr("Set Priority"), tr("Set the priority of the selected plugins"), - 0, 0, INT_MAX, 1, &ok); - if (!ok) return; + int newPriority = QInputDialog::getInt(m_view->topLevelWidget(), tr("Set Priority"), + tr("Set the priority of the selected plugins"), + 0, 0, INT_MAX, 1, &ok); + if (!ok) + return; m_core.pluginList()->sendToPriority(m_selected, newPriority); } @@ -123,7 +139,7 @@ void PluginListContextMenu::setESPLock(const QModelIndexList& indices, bool lock void PluginListContextMenu::openOriginExplorer(const QModelIndexList& indices) { for (auto& idx : indices) { - QString fileName = idx.data().toString(); + QString fileName = idx.data().toString(); unsigned int modIndex = ModInfo::getIndex(m_core.pluginList()->origin(fileName)); if (modIndex == UINT_MAX) { continue; @@ -136,15 +152,14 @@ void PluginListContextMenu::openOriginExplorer(const QModelIndexList& indices) void PluginListContextMenu::openOriginInformation(const QModelIndex& index) { try { - QString fileName = index.data().toString(); + QString fileName = index.data().toString(); unsigned int modIndex = ModInfo::getIndex(m_core.pluginList()->origin(fileName)); - ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex); + ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex); if (modInfo->isRegular() || modInfo->isOverwrite()) { emit openModInformation(modIndex); } - } - catch (const std::exception& e) { + } catch (const std::exception& e) { reportError(e.what()); } } diff --git a/src/pluginlistcontextmenu.h b/src/pluginlistcontextmenu.h index 0a9a01fe..f7d9757f 100644 --- a/src/pluginlistcontextmenu.h +++ b/src/pluginlistcontextmenu.h @@ -15,11 +15,11 @@ class PluginListContextMenu : public QMenu Q_OBJECT public: - - // creates a new context menu, the given index is the one for the click and should be valid + // creates a new context menu, the given index is the one for the click and should be + // valid // - PluginListContextMenu( - const QModelIndex& index, OrganizerCore& core, PluginListView* modListView); + PluginListContextMenu(const QModelIndex& index, OrganizerCore& core, + PluginListView* modListView); signals: @@ -28,7 +28,6 @@ signals: void openModInformation(unsigned int modIndex); public: - // create the "Send to... " context menu // QMenu* createSendToContextMenu(); @@ -43,12 +42,10 @@ public: void openOriginExplorer(const QModelIndexList& indices); void openOriginInformation(const QModelIndex& index); - OrganizerCore& m_core; QModelIndex m_index; QModelIndexList m_selected; PluginListView* m_view; - }; #endif diff --git a/src/pluginlistproxy.cpp b/src/pluginlistproxy.cpp index 604aab3e..e5fa5e01 100644 --- a/src/pluginlistproxy.cpp +++ b/src/pluginlistproxy.cpp @@ -5,8 +5,9 @@ using namespace MOBase; using namespace MOShared; -PluginListProxy::PluginListProxy(OrganizerProxy* oproxy, PluginList* pluginlist) : - m_OrganizerProxy(oproxy), m_Proxied(pluginlist) { } +PluginListProxy::PluginListProxy(OrganizerProxy* oproxy, PluginList* pluginlist) + : m_OrganizerProxy(oproxy), m_Proxied(pluginlist) +{} PluginListProxy::~PluginListProxy() { @@ -15,9 +16,12 @@ PluginListProxy::~PluginListProxy() void PluginListProxy::connectSignals() { - m_Connections.push_back(m_Proxied->onRefreshed(callSignalIfPluginActive(m_OrganizerProxy, m_Refreshed))); - m_Connections.push_back(m_Proxied->onPluginMoved(callSignalIfPluginActive(m_OrganizerProxy, m_PluginMoved))); - m_Connections.push_back(m_Proxied->onPluginStateChanged(callSignalIfPluginActive(m_OrganizerProxy, m_PluginStateChanged))); + m_Connections.push_back( + m_Proxied->onRefreshed(callSignalIfPluginActive(m_OrganizerProxy, m_Refreshed))); + m_Connections.push_back(m_Proxied->onPluginMoved( + callSignalIfPluginActive(m_OrganizerProxy, m_PluginMoved))); + m_Connections.push_back(m_Proxied->onPluginStateChanged( + callSignalIfPluginActive(m_OrganizerProxy, m_PluginStateChanged))); } void PluginListProxy::disconnectSignals() @@ -83,12 +87,14 @@ bool PluginListProxy::onRefreshed(const std::function<void()>& func) return m_Refreshed.connect(func).connected(); } -bool PluginListProxy::onPluginMoved(const std::function<void(const QString&, int, int)>& func) +bool PluginListProxy::onPluginMoved( + const std::function<void(const QString&, int, int)>& func) { return m_PluginMoved.connect(func).connected(); } -bool PluginListProxy::onPluginStateChanged(const std::function<void(const std::map<QString, PluginStates>&)> &func) +bool PluginListProxy::onPluginStateChanged( + const std::function<void(const std::map<QString, PluginStates>&)>& func) { return m_PluginStateChanged.connect(func).connected(); } diff --git a/src/pluginlistproxy.h b/src/pluginlistproxy.h index 202b8484..63602043 100644 --- a/src/pluginlistproxy.h +++ b/src/pluginlistproxy.h @@ -1,15 +1,14 @@ #ifndef PLUGINLISTPROXY_H #define PLUGINLISTPROXY_H -#include <ipluginlist.h> #include "pluginlist.h" +#include <ipluginlist.h> class OrganizerProxy; class PluginListProxy : public MOBase::IPluginList { public: - PluginListProxy(OrganizerProxy* oproxy, PluginList* pluginlist); virtual ~PluginListProxy(); @@ -25,8 +24,10 @@ public: QString origin(const QString& name) const override; bool onRefreshed(const std::function<void()>& callback) override; - bool onPluginMoved(const std::function<void(const QString&, int, int)>& func) override; - bool onPluginStateChanged(const std::function<void(const std::map<QString, PluginStates>&)>& func) override; + bool + onPluginMoved(const std::function<void(const QString&, int, int)>& func) override; + bool onPluginStateChanged( + const std::function<void(const std::map<QString, PluginStates>&)>& func) override; bool hasMasterExtension(const QString& name) const override; bool hasLightExtension(const QString& name) const override; @@ -34,7 +35,6 @@ public: bool isLightFlagged(const QString& name) const override; private: - friend class OrganizerProxy; // See OrganizerProxy::connectSignals(). @@ -51,4 +51,4 @@ private: std::vector<boost::signals2::connection> m_Connections; }; -#endif // ORGANIZERPROXY_H +#endif // ORGANIZERPROXY_H diff --git a/src/pluginlistsortproxy.cpp b/src/pluginlistsortproxy.cpp index 3c10cfa5..5083af3f 100644 --- a/src/pluginlistsortproxy.cpp +++ b/src/pluginlistsortproxy.cpp @@ -19,16 +19,14 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "pluginlistsortproxy.h" #include "messagedialog.h" -#include <QMenu> -#include <QCheckBox> #include <QApplication> -#include <QWidgetAction> +#include <QCheckBox> +#include <QMenu> #include <QTreeView> +#include <QWidgetAction> - -PluginListSortProxy::PluginListSortProxy(QObject *parent) - : QSortFilterProxyModel(parent), - m_SortIndex(0), m_SortOrder(Qt::AscendingOrder) +PluginListSortProxy::PluginListSortProxy(QObject* parent) + : QSortFilterProxyModel(parent), m_SortIndex(0), m_SortOrder(Qt::AscendingOrder) { m_EnabledColumns.set(PluginList::COL_NAME); m_EnabledColumns.set(PluginList::COL_PRIORITY); @@ -45,7 +43,7 @@ void PluginListSortProxy::setEnabledColumns(unsigned int columns) emit layoutChanged(); } -void PluginListSortProxy::updateFilter(const QString &filter) +void PluginListSortProxy::updateFilter(const QString& filter) { m_CurrentFilter = filter; invalidateFilter(); @@ -53,85 +51,89 @@ void PluginListSortProxy::updateFilter(const QString &filter) bool PluginListSortProxy::filterAcceptsRow(int row, const QModelIndex&) const { - return filterMatchesPlugin(sourceModel()->data(sourceModel()->index(row, 0)).toString()); + return filterMatchesPlugin( + sourceModel()->data(sourceModel()->index(row, 0)).toString()); } -bool PluginListSortProxy::lessThan(const QModelIndex &left, - const QModelIndex &right) const +bool PluginListSortProxy::lessThan(const QModelIndex& left, + const QModelIndex& right) const { - PluginList *plugins = qobject_cast<PluginList*>(sourceModel()); + PluginList* plugins = qobject_cast<PluginList*>(sourceModel()); switch (left.column()) { - case PluginList::COL_NAME: { - return QString::compare(plugins->getName(left.row()), plugins->getName(right.row()), Qt::CaseInsensitive) < 0; - } break; - case PluginList::COL_FLAGS: { - QVariantList lhsList = left.data(Qt::UserRole + 1).toList(); - QVariantList rhsList = right.data(Qt::UserRole + 1).toList(); - if (lhsList.size() != rhsList.size()) { - return lhsList.size() < rhsList.size(); - } else { - for (int i = 0; i < lhsList.size(); ++i) { - if (lhsList.at(i) != rhsList.at(i)) { - return lhsList.at(i).toString() < rhsList.at(i).toString(); - } + case PluginList::COL_NAME: { + return QString::compare(plugins->getName(left.row()), plugins->getName(right.row()), + Qt::CaseInsensitive) < 0; + } break; + case PluginList::COL_FLAGS: { + QVariantList lhsList = left.data(Qt::UserRole + 1).toList(); + QVariantList rhsList = right.data(Qt::UserRole + 1).toList(); + if (lhsList.size() != rhsList.size()) { + return lhsList.size() < rhsList.size(); + } else { + for (int i = 0; i < lhsList.size(); ++i) { + if (lhsList.at(i) != rhsList.at(i)) { + return lhsList.at(i).toString() < rhsList.at(i).toString(); } - return false; } - } break; - case PluginList::COL_MODINDEX: { - QString leftVal = plugins->getIndexPriority(left.row()); - QString rightVal = plugins->getIndexPriority(right.row()); - return leftVal < rightVal; - } break; - default: { - return plugins->getPriority(left.row()) < plugins->getPriority(right.row()); - } break; + return false; + } + } break; + case PluginList::COL_MODINDEX: { + QString leftVal = plugins->getIndexPriority(left.row()); + QString rightVal = plugins->getIndexPriority(right.row()); + return leftVal < rightVal; + } break; + default: { + return plugins->getPriority(left.row()) < plugins->getPriority(right.row()); + } break; } } -bool PluginListSortProxy::dropMimeData(const QMimeData *data, Qt::DropAction action, - int row, int column, const QModelIndex &parent) +bool PluginListSortProxy::dropMimeData(const QMimeData* data, Qt::DropAction action, + int row, int column, const QModelIndex& parent) { - if ((sortColumn() != PluginList::COL_PRIORITY) - && (sortColumn() != PluginList::COL_MODINDEX)) { - QWidget *wid = qApp->activeWindow()->findChild<QTreeView*>("espList"); - MessageDialog::showMessage(tr("Drag&Drop is only supported when sorting by priority or mod index"), wid); - return false; - } + if ((sortColumn() != PluginList::COL_PRIORITY) && + (sortColumn() != PluginList::COL_MODINDEX)) { + QWidget* wid = qApp->activeWindow()->findChild<QTreeView*>("espList"); + MessageDialog::showMessage( + tr("Drag&Drop is only supported when sorting by priority or mod index"), wid); + return false; + } - if ((row == -1) && (column == -1)) { - return this->sourceModel()->dropMimeData(data, action, -1, -1, mapToSource(parent)); - } - // in the regular model, when dropping between rows, the row-value passed to - // the sourceModel is inconsistent between ascending and descending ordering. - // This should fix that - if (sortOrder() == Qt::DescendingOrder) { - --row; - } + if ((row == -1) && (column == -1)) { + return this->sourceModel()->dropMimeData(data, action, -1, -1, mapToSource(parent)); + } + // in the regular model, when dropping between rows, the row-value passed to + // the sourceModel is inconsistent between ascending and descending ordering. + // This should fix that + if (sortOrder() == Qt::DescendingOrder) { + --row; + } - QModelIndex proxyIndex = index(row, column, parent); - QModelIndex sourceIndex = mapToSource(proxyIndex); - return this->sourceModel()->dropMimeData(data, action, sourceIndex.row(), sourceIndex.column(), - sourceIndex.parent()); + QModelIndex proxyIndex = index(row, column, parent); + QModelIndex sourceIndex = mapToSource(proxyIndex); + return this->sourceModel()->dropMimeData(data, action, sourceIndex.row(), + sourceIndex.column(), sourceIndex.parent()); } -bool PluginListSortProxy::filterMatchesPlugin(const QString &plugin) const +bool PluginListSortProxy::filterMatchesPlugin(const QString& plugin) const { if (!m_CurrentFilter.isEmpty()) { - bool display = false; + bool display = false; QString filterCopy = QString(m_CurrentFilter); filterCopy.replace("||", ";").replace("OR", ";").replace("|", ";"); QStringList ORList = filterCopy.split(";", Qt::SkipEmptyParts); bool segmentGood = true; - //split in ORSegments that internally use AND logic + // split in ORSegments that internally use AND logic for (auto& ORSegment : ORList) { QStringList ANDKeywords = ORSegment.split(" ", Qt::SkipEmptyParts); - segmentGood = true; + segmentGood = true; - //check each word in the segment for match, each word needs to be matched but it doesn't matter where. + // check each word in the segment for match, each word needs to be matched but it + // doesn't matter where. for (auto& currentKeyword : ANDKeywords) { if (!plugin.contains(currentKeyword, Qt::CaseInsensitive)) { segmentGood = false; @@ -140,14 +142,14 @@ bool PluginListSortProxy::filterMatchesPlugin(const QString &plugin) const } if (segmentGood) { - //the last AND loop didn't break so the ORSegments is true so mod matches filter + // the last AND loop didn't break so the ORSegments is true so mod matches + // filter return true; } - }//for ORList loop + } // for ORList loop return false; - } - else + } else return true; } diff --git a/src/pluginlistsortproxy.h b/src/pluginlistsortproxy.h index 85e0d135..6a65c21d 100644 --- a/src/pluginlistsortproxy.h +++ b/src/pluginlistsortproxy.h @@ -20,49 +20,44 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef PLUGINLISTSORTPROXY_H #define PLUGINLISTSORTPROXY_H - -#include <bitset> -#include <QSortFilterProxyModel> #include "pluginlist.h" - +#include <QSortFilterProxyModel> +#include <bitset> class PluginListSortProxy : public QSortFilterProxyModel { Q_OBJECT public: - - enum ESorting { + enum ESorting + { SORT_ASCENDING, SORT_DESCENDING }; public: - - explicit PluginListSortProxy(QObject *parent = 0); + explicit PluginListSortProxy(QObject* parent = 0); void setEnabledColumns(unsigned int columns); - virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); + virtual bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, + int column, const QModelIndex& parent); - bool filterMatchesPlugin(const QString &plugin) const; + bool filterMatchesPlugin(const QString& plugin) const; public slots: - void updateFilter(const QString &filter); + void updateFilter(const QString& filter); protected: - - virtual bool filterAcceptsRow(int row, const QModelIndex &parent) const; - virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const; + virtual bool filterAcceptsRow(int row, const QModelIndex& parent) const; + virtual bool lessThan(const QModelIndex& left, const QModelIndex& right) const; private: - int m_SortIndex; Qt::SortOrder m_SortOrder; std::bitset<PluginList::COL_LASTCOLUMN + 1> m_EnabledColumns; QString m_CurrentFilter; - }; -#endif // PLUGINLISTSORTPROXY_H +#endif // PLUGINLISTSORTPROXY_H diff --git a/src/pluginlistview.cpp b/src/pluginlistview.cpp index c7183d0b..a0a0162f 100644 --- a/src/pluginlistview.cpp +++ b/src/pluginlistview.cpp @@ -1,29 +1,28 @@ #include "pluginlistview.h" -#include <QUrl> #include <QMimeData> +#include <QUrl> #include <report.h> #include <widgetutility.h> -#include "mainwindow.h" -#include "ui_mainwindow.h" -#include "organizercore.h" -#include "pluginlistsortproxy.h" -#include "pluginlistcontextmenu.h" -#include "modlistview.h" #include "copyeventfilter.h" -#include "modlistviewactions.h" #include "genericicondelegate.h" +#include "mainwindow.h" #include "modelutils.h" +#include "modlistview.h" +#include "modlistviewactions.h" +#include "organizercore.h" +#include "pluginlistcontextmenu.h" +#include "pluginlistsortproxy.h" +#include "ui_mainwindow.h" using namespace MOBase; -PluginListView::PluginListView(QWidget *parent) - : QTreeView(parent) - , m_sortProxy(nullptr) - , m_Scrollbar(new ViewMarkingScrollBar(this, Qt::BackgroundRole)) - , m_didUpdateMasterList(false) +PluginListView::PluginListView(QWidget* parent) + : QTreeView(parent), m_sortProxy(nullptr), + m_Scrollbar(new ViewMarkingScrollBar(this, Qt::BackgroundRole)), + m_didUpdateMasterList(false) { setVerticalScrollBar(m_Scrollbar); MOBase::setCustomizableColumns(this); @@ -57,31 +56,29 @@ QModelIndexList PluginListView::indexViewToModel(const QModelIndexList& index) c void PluginListView::updatePluginCount() { - int activeMasterCount = 0; + int activeMasterCount = 0; int activeLightMasterCount = 0; - int activeRegularCount = 0; - int masterCount = 0; - int lightMasterCount = 0; - int regularCount = 0; - int activeVisibleCount = 0; + int activeRegularCount = 0; + int masterCount = 0; + int lightMasterCount = 0; + int regularCount = 0; + int activeVisibleCount = 0; PluginList* list = m_core->pluginList(); - QString filter = ui.filter->text(); + QString filter = ui.filter->text(); for (QString plugin : list->pluginNames()) { - bool active = list->isEnabled(plugin); + bool active = list->isEnabled(plugin); bool visible = m_sortProxy->filterMatchesPlugin(plugin); if (list->hasLightExtension(plugin) || list->isLightFlagged(plugin)) { lightMasterCount++; activeLightMasterCount += active; activeVisibleCount += visible && active; - } - else if (list->hasMasterExtension(plugin) || list->isMasterFlagged(plugin)) { + } else if (list->hasMasterExtension(plugin) || list->isMasterFlagged(plugin)) { masterCount++; activeMasterCount += active; activeVisibleCount += visible && active; - } - else { + } else { regularCount++; activeRegularCount += active; activeVisibleCount += visible && active; @@ -89,23 +86,30 @@ void PluginListView::updatePluginCount() } int activeCount = activeMasterCount + activeLightMasterCount + activeRegularCount; - int totalCount = masterCount + lightMasterCount + regularCount; + int totalCount = masterCount + lightMasterCount + regularCount; ui.counter->display(activeVisibleCount); - ui.counter->setToolTip(tr("<table cellspacing=\"6\">" - "<tr><th>Type</th><th>Active </th><th>Total</th></tr>" - "<tr><td>All plugins:</td><td align=right>%1 </td><td align=right>%2</td></tr>" - "<tr><td>ESMs:</td><td align=right>%3 </td><td align=right>%4</td></tr>" - "<tr><td>ESPs:</td><td align=right>%7 </td><td align=right>%8</td></tr>" - "<tr><td>ESMs+ESPs:</td><td align=right>%9 </td><td align=right>%10</td></tr>" - "<tr><td>ESLs:</td><td align=right>%5 </td><td align=right>%6</td></tr>" - "</table>") - .arg(activeCount).arg(totalCount) - .arg(activeMasterCount).arg(masterCount) - .arg(activeLightMasterCount).arg(lightMasterCount) - .arg(activeRegularCount).arg(regularCount) - .arg(activeMasterCount + activeRegularCount).arg(masterCount + regularCount) - ); + ui.counter->setToolTip( + tr("<table cellspacing=\"6\">" + "<tr><th>Type</th><th>Active </th><th>Total</th></tr>" + "<tr><td>All plugins:</td><td align=right>%1 </td><td " + "align=right>%2</td></tr>" + "<tr><td>ESMs:</td><td align=right>%3 </td><td align=right>%4</td></tr>" + "<tr><td>ESPs:</td><td align=right>%7 </td><td align=right>%8</td></tr>" + "<tr><td>ESMs+ESPs:</td><td align=right>%9 </td><td " + "align=right>%10</td></tr>" + "<tr><td>ESLs:</td><td align=right>%5 </td><td align=right>%6</td></tr>" + "</table>") + .arg(activeCount) + .arg(totalCount) + .arg(activeMasterCount) + .arg(masterCount) + .arg(activeLightMasterCount) + .arg(lightMasterCount) + .arg(activeRegularCount) + .arg(regularCount) + .arg(activeMasterCount + activeRegularCount) + .arg(masterCount + regularCount)); } void PluginListView::onFilterChanged(const QString& filter) @@ -113,8 +117,7 @@ void PluginListView::onFilterChanged(const QString& filter) if (!filter.isEmpty()) { setStyleSheet("QTreeView { border: 2px ridge #f00; }"); ui.counter->setStyleSheet("QLCDNumber { border: 2px ridge #f00; }"); - } - else { + } else { setStyleSheet(""); ui.counter->setStyleSheet(""); } @@ -128,17 +131,16 @@ void PluginListView::onSortButtonClicked() auto r = QMessageBox::No; if (offline) { - r = QMessageBox::question( - topLevelWidget(), tr("Sorting plugins"), - tr("Are you sure you want to sort your plugins list?") + "\r\n\r\n" + - tr("Note: You are currently in offline mode and LOOT will not update the master list."), - QMessageBox::Yes | QMessageBox::No); - } - else { - r = QMessageBox::question( - topLevelWidget(), tr("Sorting plugins"), - tr("Are you sure you want to sort your plugins list?"), - QMessageBox::Yes | QMessageBox::No); + r = QMessageBox::question(topLevelWidget(), tr("Sorting plugins"), + tr("Are you sure you want to sort your plugins list?") + + "\r\n\r\n" + + tr("Note: You are currently in offline mode and LOOT " + "will not update the master list."), + QMessageBox::Yes | QMessageBox::No); + } else { + r = QMessageBox::question(topLevelWidget(), tr("Sorting plugins"), + tr("Are you sure you want to sort your plugins list?"), + QMessageBox::Yes | QMessageBox::No); } if (r != QMessageBox::Yes) { @@ -148,7 +150,9 @@ void PluginListView::onSortButtonClicked() m_core->savePluginList(); topLevelWidget()->setEnabled(false); - Guard g([=]() { topLevelWidget()->setEnabled(true); }); + Guard g([=]() { + topLevelWidget()->setEnabled(true); + }); // don't try to update the master list in offline mode const bool didUpdateMasterList = offline ? true : m_didUpdateMasterList; @@ -166,22 +170,24 @@ void PluginListView::onSortButtonClicked() std::pair<QModelIndex, QModelIndexList> PluginListView::selected() const { - return { indexViewToModel(currentIndex()), indexViewToModel(selectionModel()->selectedRows()) }; + return {indexViewToModel(currentIndex()), + indexViewToModel(selectionModel()->selectedRows())}; } -void PluginListView::setSelected(const QModelIndex& current, const QModelIndexList& selected) +void PluginListView::setSelected(const QModelIndex& current, + const QModelIndexList& selected) { setCurrentIndex(indexModelToView(current)); for (auto idx : selected) { - selectionModel()->select(indexModelToView(idx), QItemSelectionModel::Select | QItemSelectionModel::Rows); + selectionModel()->select(indexModelToView(idx), + QItemSelectionModel::Select | QItemSelectionModel::Rows); } } - void PluginListView::setup(OrganizerCore& core, MainWindow* mw, Ui::MainWindow* mwui) { - m_core = &core; - ui = { mwui->activePluginsCounter, mwui->espFilterEdit }; + m_core = &core; + ui = {mwui->activePluginsCounter, mwui->espFilterEdit}; m_modActions = &mwui->modList->actions(); m_sortProxy = new PluginListSortProxy(&core); @@ -192,28 +198,40 @@ void PluginListView::setup(OrganizerCore& core, MainWindow* mw, Ui::MainWindow* setItemDelegateForColumn(PluginList::COL_FLAGS, new GenericIconDelegate(this)); // counter - connect(core.pluginList(), &PluginList::writePluginsList, [=]{ updatePluginCount(); }); - connect(core.pluginList(), &PluginList::esplist_changed, [=]{ updatePluginCount(); }); + connect(core.pluginList(), &PluginList::writePluginsList, [=] { + updatePluginCount(); + }); + connect(core.pluginList(), &PluginList::esplist_changed, [=] { + updatePluginCount(); + }); // sort - connect(mwui->bossButton, &QPushButton::clicked, [=]{ onSortButtonClicked(); }); + connect(mwui->bossButton, &QPushButton::clicked, [=] { + onSortButtonClicked(); + }); // filter - connect(ui.filter, &QLineEdit::textChanged, m_sortProxy, &PluginListSortProxy::updateFilter); + connect(ui.filter, &QLineEdit::textChanged, m_sortProxy, + &PluginListSortProxy::updateFilter); connect(ui.filter, &QLineEdit::textChanged, this, &PluginListView::onFilterChanged); // highligth mod list when selected - connect(selectionModel(), &QItemSelectionModel::selectionChanged, [=](auto&& selected) { - std::vector<unsigned int> pluginIndices; - for (auto& idx : indexViewToModel(selectionModel()->selectedRows())) { - pluginIndices.push_back(idx.row()); - } - mwui->modList->setHighlightedMods(pluginIndices); - }); + connect(selectionModel(), &QItemSelectionModel::selectionChanged, + [=](auto&& selected) { + std::vector<unsigned int> pluginIndices; + for (auto& idx : indexViewToModel(selectionModel()->selectedRows())) { + pluginIndices.push_back(idx.row()); + } + mwui->modList->setHighlightedMods(pluginIndices); + }); // using a lambda here to avoid storing the mod list actions - connect(this, &QTreeView::customContextMenuRequested, [=](auto&& pos) { onCustomContextMenuRequested(pos); }); - connect(this, &QTreeView::doubleClicked, [=](auto&& index) { onDoubleClicked(index); }); + connect(this, &QTreeView::customContextMenuRequested, [=](auto&& pos) { + onCustomContextMenuRequested(pos); + }); + connect(this, &QTreeView::doubleClicked, [=](auto&& index) { + onDoubleClicked(index); + }); } void PluginListView::onCustomContextMenuRequested(const QPoint& pos) @@ -221,13 +239,12 @@ void PluginListView::onCustomContextMenuRequested(const QPoint& pos) try { PluginListContextMenu menu(indexViewToModel(indexAt(pos)), *m_core, this); connect(&menu, &PluginListContextMenu::openModInformation, [=](auto&& modIndex) { - m_modActions->displayModInformation(modIndex); }); + m_modActions->displayModInformation(modIndex); + }); menu.exec(viewport()->mapToGlobal(pos)); - } - catch (const std::exception& e) { + } catch (const std::exception& e) { reportError(tr("Exception: ").arg(e.what())); - } - catch (...) { + } catch (...) { reportError(tr("Unknown exception")); } } @@ -238,32 +255,34 @@ void PluginListView::onDoubleClicked(const QModelIndex& index) return; } - if (m_core->pluginList()->timeElapsedSinceLastChecked() <= QApplication::doubleClickInterval()) { + if (m_core->pluginList()->timeElapsedSinceLastChecked() <= + QApplication::doubleClickInterval()) { // don't interpret double click if we only just checked a plugin return; } try { - if (selectionModel()->hasSelection() && selectionModel()->selectedRows().count() == 1) { + if (selectionModel()->hasSelection() && + selectionModel()->selectedRows().count() == 1) { - QModelIndex idx = selectionModel()->currentIndex(); + QModelIndex idx = selectionModel()->currentIndex(); QString fileName = idx.data().toString(); if (ModInfo::getIndex(m_core->pluginList()->origin(fileName)) == UINT_MAX) { return; } - auto modIndex = ModInfo::getIndex(m_core->pluginList()->origin(fileName)); + auto modIndex = ModInfo::getIndex(m_core->pluginList()->origin(fileName)); ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex); if (modInfo->isRegular() || modInfo->isOverwrite()) { Qt::KeyboardModifiers modifiers = QApplication::queryKeyboardModifiers(); if (modifiers.testFlag(Qt::ControlModifier)) { - m_modActions->openExplorer({ m_core->modList()->index(modIndex, 0) }); - } - else { - m_modActions->displayModInformation(ModInfo::getIndex(m_core->pluginList()->origin(fileName))); + m_modActions->openExplorer({m_core->modList()->index(modIndex, 0)}); + } else { + m_modActions->displayModInformation( + ModInfo::getIndex(m_core->pluginList()->origin(fileName))); } // workaround to cancel the editor that might have opened because of @@ -271,8 +290,7 @@ void PluginListView::onDoubleClicked(const QModelIndex& index) closePersistentEditor(index); } } - } - catch (const std::exception& e) { + } catch (const std::exception& e) { reportError(e.what()); } } @@ -308,10 +326,11 @@ bool PluginListView::event(QEvent* event) if (event->type() == QEvent::KeyPress) { QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event); - if (keyEvent->modifiers() == Qt::ControlModifier - && (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter)) { - if (selectionModel()->hasSelection() && selectionModel()->selectedRows().count() == 1) { - QModelIndex idx = selectionModel()->currentIndex(); + if (keyEvent->modifiers() == Qt::ControlModifier && + (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter)) { + if (selectionModel()->hasSelection() && + selectionModel()->selectedRows().count() == 1) { + QModelIndex idx = selectionModel()->currentIndex(); QString fileName = idx.data().toString(); if (ModInfo::getIndex(m_core->pluginList()->origin(fileName)) == UINT_MAX) { @@ -319,16 +338,15 @@ bool PluginListView::event(QEvent* event) } auto modIndex = ModInfo::getIndex(m_core->pluginList()->origin(fileName)); - m_modActions->openExplorer({ m_core->modList()->index(modIndex, 0) }); + m_modActions->openExplorer({m_core->modList()->index(modIndex, 0)}); return true; } - } - else if (keyEvent->modifiers() == Qt::ControlModifier - && (sortColumn() == PluginList::COL_PRIORITY || sortColumn() == PluginList::COL_MODINDEX) - && (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down)) { + } else if (keyEvent->modifiers() == Qt::ControlModifier && + (sortColumn() == PluginList::COL_PRIORITY || + sortColumn() == PluginList::COL_MODINDEX) && + (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down)) { return moveSelection(keyEvent->key()); - } - else if (keyEvent->key() == Qt::Key_Space) { + } else if (keyEvent->key() == Qt::Key_Space) { return toggleSelectionState(); } return QTreeView::event(event); diff --git a/src/pluginlistview.h b/src/pluginlistview.h index ed6458da..642976e3 100644 --- a/src/pluginlistview.h +++ b/src/pluginlistview.h @@ -1,12 +1,13 @@ #ifndef PLUGINLISTVIEW_H #define PLUGINLISTVIEW_H -#include <QTreeView> -#include <QDragEnterEvent> #include "viewmarkingscrollbar.h" +#include <QDragEnterEvent> +#include <QTreeView> -namespace Ui { - class MainWindow; +namespace Ui +{ +class MainWindow; } class OrganizerCore; @@ -39,7 +40,6 @@ protected slots: void onSortButtonClicked(); protected: - friend class PluginListContextMenu; // map from/to the view indexes to the model @@ -63,7 +63,6 @@ protected: bool event(QEvent* event) override; private: - struct PluginListViewUi { // the plguin counter @@ -83,4 +82,4 @@ private: bool m_didUpdateMasterList; }; -#endif // PLUGINLISTVIEW_H +#endif // PLUGINLISTVIEW_H diff --git a/src/previewdialog.cpp b/src/previewdialog.cpp index 350f2980..5d40885d 100644 --- a/src/previewdialog.cpp +++ b/src/previewdialog.cpp @@ -1,11 +1,10 @@ #include "previewdialog.h" -#include "ui_previewdialog.h" #include "settings.h" +#include "ui_previewdialog.h" #include <QFileInfo> -PreviewDialog::PreviewDialog(const QString &fileName, QWidget *parent) : - QDialog(parent), - ui(new Ui::PreviewDialog) +PreviewDialog::PreviewDialog(const QString& fileName, QWidget* parent) + : QDialog(parent), ui(new Ui::PreviewDialog) { ui->setupUi(this); ui->nameLabel->setText(QFileInfo(fileName).fileName()); @@ -24,7 +23,7 @@ int PreviewDialog::exec() return QDialog::exec(); } -void PreviewDialog::addVariant(const QString &modName, QWidget *widget) +void PreviewDialog::addVariant(const QString& modName, QWidget* widget) { widget->setProperty("modName", modName); ui->variantsStack->addWidget(widget); @@ -41,7 +40,8 @@ int PreviewDialog::numVariants() const void PreviewDialog::on_variantsStack_currentChanged(int index) { - ui->modLabel->setText(ui->variantsStack->widget(index)->property("modName").toString()); + ui->modLabel->setText( + ui->variantsStack->widget(index)->property("modName").toString()); } void PreviewDialog::on_closeButton_clicked() @@ -60,5 +60,6 @@ void PreviewDialog::on_previousButton_clicked() void PreviewDialog::on_nextButton_clicked() { - ui->variantsStack->setCurrentIndex((ui->variantsStack->currentIndex() + 1) % ui->variantsStack->count()); + ui->variantsStack->setCurrentIndex((ui->variantsStack->currentIndex() + 1) % + ui->variantsStack->count()); } diff --git a/src/previewdialog.h b/src/previewdialog.h index 213bf078..fd214188 100644 --- a/src/previewdialog.h +++ b/src/previewdialog.h @@ -3,7 +3,8 @@ #include <QDialog> -namespace Ui { +namespace Ui +{ class PreviewDialog; } @@ -12,14 +13,14 @@ class PreviewDialog : public QDialog Q_OBJECT public: - explicit PreviewDialog(const QString &fileName, QWidget *parent = 0); + explicit PreviewDialog(const QString& fileName, QWidget* parent = 0); ~PreviewDialog(); // also saves and restores geometry // int exec() override; - void addVariant(const QString &modName, QWidget *widget); + void addVariant(const QString& modName, QWidget* widget); int numVariants() const; private slots: @@ -33,8 +34,7 @@ private slots: void on_nextButton_clicked(); private: - - Ui::PreviewDialog *ui; + Ui::PreviewDialog* ui; }; -#endif // PREVIEWDIALOG_H +#endif // PREVIEWDIALOG_H diff --git a/src/previewgenerator.cpp b/src/previewgenerator.cpp index 7006ad1b..ba73c065 100644 --- a/src/previewgenerator.cpp +++ b/src/previewgenerator.cpp @@ -20,8 +20,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "previewgenerator.h" #include <QFileInfo> -#include <QLabel> #include <QImageReader> +#include <QLabel> #include <QTextEdit> #include <utility.h> @@ -29,12 +29,13 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. using namespace MOBase; -PreviewGenerator::PreviewGenerator(const PluginContainer& pluginContainer) : - m_PluginContainer(pluginContainer) { +PreviewGenerator::PreviewGenerator(const PluginContainer& pluginContainer) + : m_PluginContainer(pluginContainer) +{ m_MaxSize = QGuiApplication::primaryScreen()->size() * 0.8; } -bool PreviewGenerator::previewSupported(const QString &fileExtension) const +bool PreviewGenerator::previewSupported(const QString& fileExtension) const { auto& previews = m_PluginContainer.plugins<IPluginPreview>(); for (auto* preview : previews) { @@ -45,12 +46,13 @@ bool PreviewGenerator::previewSupported(const QString &fileExtension) const return false; } -QWidget *PreviewGenerator::genPreview(const QString &fileName) const +QWidget* PreviewGenerator::genPreview(const QString& fileName) const { const QString ext = QFileInfo(fileName).suffix().toLower(); - auto& previews = m_PluginContainer.plugins<IPluginPreview>(); + auto& previews = m_PluginContainer.plugins<IPluginPreview>(); for (auto* preview : previews) { - if (m_PluginContainer.isEnabled(preview) && preview->supportedExtensions().contains(ext)) { + if (m_PluginContainer.isEnabled(preview) && + preview->supportedExtensions().contains(ext)) { return preview->genFilePreview(fileName, m_MaxSize); } } diff --git a/src/previewgenerator.h b/src/previewgenerator.h index 3b0076b6..dd0d2cd4 100644 --- a/src/previewgenerator.h +++ b/src/previewgenerator.h @@ -22,9 +22,9 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QString> #include <QWidget> -#include <map> #include <functional> #include <ipluginpreview.h> +#include <map> class PluginContainer; @@ -33,15 +33,13 @@ class PreviewGenerator public: PreviewGenerator(const PluginContainer& pluginContainer); - bool previewSupported(const QString &fileExtension) const; + bool previewSupported(const QString& fileExtension) const; - QWidget *genPreview(const QString &fileName) const; + QWidget* genPreview(const QString& fileName) const; private: - const PluginContainer& m_PluginContainer; QSize m_MaxSize; - }; -#endif // PREVIEWGENERATOR_H +#endif // PREVIEWGENERATOR_H diff --git a/src/problemsdialog.cpp b/src/problemsdialog.cpp index f099f533..f6b23a10 100644 --- a/src/problemsdialog.cpp +++ b/src/problemsdialog.cpp @@ -1,30 +1,30 @@ #include "problemsdialog.h" -#include "ui_problemsdialog.h" #include "organizercore.h" -#include <utility.h> -#include <iplugin.h> -#include <iplugindiagnose.h> +#include "ui_problemsdialog.h" #include <QPushButton> #include <Shellapi.h> +#include <iplugin.h> +#include <iplugindiagnose.h> +#include <utility.h> #include "plugincontainer.h" using namespace MOBase; - -ProblemsDialog::ProblemsDialog(const PluginContainer& pluginContainer, QWidget *parent) : - QDialog(parent), ui(new Ui::ProblemsDialog), m_PluginContainer(pluginContainer), - m_hasProblems(false) +ProblemsDialog::ProblemsDialog(const PluginContainer& pluginContainer, QWidget* parent) + : QDialog(parent), ui(new Ui::ProblemsDialog), m_PluginContainer(pluginContainer), + m_hasProblems(false) { ui->setupUi(this); runDiagnosis(); - connect(ui->problemsWidget, SIGNAL(itemSelectionChanged()), this, SLOT(selectionChanged())); - connect(ui->descriptionText, SIGNAL(anchorClicked(QUrl)), this, SLOT(urlClicked(QUrl))); + connect(ui->problemsWidget, SIGNAL(itemSelectionChanged()), this, + SLOT(selectionChanged())); + connect(ui->descriptionText, SIGNAL(anchorClicked(QUrl)), this, + SLOT(urlClicked(QUrl))); } - ProblemsDialog::~ProblemsDialog() { delete ui; @@ -41,14 +41,14 @@ void ProblemsDialog::runDiagnosis() m_hasProblems = false; ui->problemsWidget->clear(); - for (IPluginDiagnose *diagnose : m_PluginContainer.plugins<IPluginDiagnose>()) { + for (IPluginDiagnose* diagnose : m_PluginContainer.plugins<IPluginDiagnose>()) { if (!m_PluginContainer.isEnabled(diagnose)) { continue; } std::vector<unsigned int> activeProblems = diagnose->activeProblems(); foreach (unsigned int key, activeProblems) { - QTreeWidgetItem *newItem = new QTreeWidgetItem(); + QTreeWidgetItem* newItem = new QTreeWidgetItem(); newItem->setText(0, diagnose->shortDescription(key)); newItem->setData(0, Qt::UserRole, diagnose->fullDescription(key)); @@ -57,8 +57,9 @@ void ProblemsDialog::runDiagnosis() if (diagnose->hasGuidedFix(key)) { newItem->setText(1, tr("Fix")); - QPushButton *fixButton = new QPushButton(tr("Fix")); - fixButton->setProperty("fix", QVariant::fromValue(reinterpret_cast<void*>(diagnose))); + QPushButton* fixButton = new QPushButton(tr("Fix")); + fixButton->setProperty("fix", + QVariant::fromValue(reinterpret_cast<void*>(diagnose))); fixButton->setProperty("key", key); connect(fixButton, SIGNAL(clicked()), this, SLOT(startFix())); ui->problemsWidget->setItemWidget(newItem, 1, fixButton); @@ -92,22 +93,24 @@ void ProblemsDialog::selectionChanged() { QString text = ui->problemsWidget->currentItem()->data(0, Qt::UserRole).toString(); ui->descriptionText->setText(text); - ui->descriptionText->setLineWrapMode(text.contains('\n') ? QTextEdit::NoWrap : QTextEdit::WidgetWidth); + ui->descriptionText->setLineWrapMode(text.contains('\n') ? QTextEdit::NoWrap + : QTextEdit::WidgetWidth); } void ProblemsDialog::startFix() { - QObject *fixButton = QObject::sender(); + QObject* fixButton = QObject::sender(); if (fixButton == NULL) { log::warn("no button"); return; } - IPluginDiagnose *plugin = reinterpret_cast<IPluginDiagnose*>(fixButton ->property("fix").value<void*>()); - plugin->startGuidedFix(fixButton ->property("key").toUInt()); + IPluginDiagnose* plugin = + reinterpret_cast<IPluginDiagnose*>(fixButton->property("fix").value<void*>()); + plugin->startGuidedFix(fixButton->property("key").toUInt()); runDiagnosis(); } -void ProblemsDialog::urlClicked(const QUrl &url) +void ProblemsDialog::urlClicked(const QUrl& url) { shell::Open(url); } diff --git a/src/problemsdialog.h b/src/problemsdialog.h index 9fe5acd0..288f5049 100644 --- a/src/problemsdialog.h +++ b/src/problemsdialog.h @@ -1,13 +1,12 @@ #ifndef PROBLEMSDIALOG_H #define PROBLEMSDIALOG_H - #include <QDialog> #include <QUrl> #include <iplugindiagnose.h> - -namespace Ui { +namespace Ui +{ class ProblemsDialog; } @@ -18,7 +17,7 @@ class ProblemsDialog : public QDialog Q_OBJECT public: - explicit ProblemsDialog(PluginContainer const& pluginContainer, QWidget *parent = 0); + explicit ProblemsDialog(PluginContainer const& pluginContainer, QWidget* parent = 0); ~ProblemsDialog(); // also saves and restores geometry @@ -32,14 +31,14 @@ private: private slots: void selectionChanged(); - void urlClicked(const QUrl &url); + void urlClicked(const QUrl& url); void startFix(); private: - Ui::ProblemsDialog *ui; + Ui::ProblemsDialog* ui; const PluginContainer& m_PluginContainer; bool m_hasProblems; }; -#endif // PROBLEMSDIALOG_H +#endif // PROBLEMSDIALOG_H diff --git a/src/processrunner.cpp b/src/processrunner.cpp index 4a954dee..f748f490 100644 --- a/src/processrunner.cpp +++ b/src/processrunner.cpp @@ -1,17 +1,17 @@ #include "processrunner.h" -#include "organizercore.h" +#include "env.h" +#include "envmodule.h" #include "instancemanager.h" #include "iuserinterface.h" -#include "envmodule.h" -#include "env.h" -#include <report.h> +#include "organizercore.h" #include <iplugingame.h> #include <log.h> +#include <report.h> using namespace MOBase; -void adjustForVirtualized( - const IPluginGame* game, spawn::SpawnParameters& sp, const Settings& settings) +void adjustForVirtualized(const IPluginGame* game, spawn::SpawnParameters& sp, + const Settings& settings) { const QString modsPath = settings.paths().mods(); @@ -19,38 +19,36 @@ void adjustForVirtualized( // under our mods folder then will start the process in a virtualized // "environment" with the appropriate paths fixed: // (i.e. mods\FNIS\path\exe => game\data\path\exe) - QString cwdPath = sp.currentDirectory.absolutePath(); + QString cwdPath = sp.currentDirectory.absolutePath(); QString trailedModsPath = modsPath; if (!trailedModsPath.endsWith('/')) { trailedModsPath = trailedModsPath + '/'; } bool virtualizedCwd = cwdPath.startsWith(trailedModsPath, Qt::CaseInsensitive); - QString binPath = sp.binary.absoluteFilePath(); + QString binPath = sp.binary.absoluteFilePath(); bool virtualizedBin = binPath.startsWith(trailedModsPath, Qt::CaseInsensitive); if (virtualizedCwd || virtualizedBin) { if (virtualizedCwd) { - int cwdOffset = cwdPath.indexOf('/', trailedModsPath.length()); + int cwdOffset = cwdPath.indexOf('/', trailedModsPath.length()); QString adjustedCwd = cwdPath.mid(cwdOffset, -1); - cwdPath = game->dataDirectory().absolutePath(); + cwdPath = game->dataDirectory().absolutePath(); if (cwdOffset >= 0) cwdPath += adjustedCwd; - } if (virtualizedBin) { - int binOffset = binPath.indexOf('/', trailedModsPath.length()); + int binOffset = binPath.indexOf('/', trailedModsPath.length()); QString adjustedBin = binPath.mid(binOffset, -1); - binPath = game->dataDirectory().absolutePath(); + binPath = game->dataDirectory().absolutePath(); if (binOffset >= 0) binPath += adjustedBin; } - QString cmdline - = QString("launch \"%1\" \"%2\" %3") - .arg(QDir::toNativeSeparators(cwdPath), - QDir::toNativeSeparators(binPath), sp.arguments); + QString cmdline = QString("launch \"%1\" \"%2\" %3") + .arg(QDir::toNativeSeparators(cwdPath), + QDir::toNativeSeparators(binPath), sp.arguments); - sp.binary = QFileInfo(QCoreApplication::applicationFilePath()); + sp.binary = QFileInfo(QCoreApplication::applicationFilePath()); sp.arguments = cmdline; sp.currentDirectory.setPath(QCoreApplication::applicationDirPath()); } @@ -64,28 +62,24 @@ std::optional<ProcessRunner::Results> singleWait(HANDLE handle, DWORD pid) const auto res = WaitForSingleObject(handle, 50); - switch (res) - { - case WAIT_OBJECT_0: - { - log::debug("process {} completed", pid); - return ProcessRunner::Completed; - } + switch (res) { + case WAIT_OBJECT_0: { + log::debug("process {} completed", pid); + return ProcessRunner::Completed; + } - case WAIT_TIMEOUT: - { - // still running - return {}; - } + case WAIT_TIMEOUT: { + // still running + return {}; + } - case WAIT_FAILED: // fall-through - default: - { - // error - const auto e = ::GetLastError(); - log::error("failed waiting for {}, {}", pid, formatSystemMessage(e)); - return ProcessRunner::Error; - } + case WAIT_FAILED: // fall-through + default: { + // error + const auto e = ::GetLastError(); + log::error("failed waiting for {}, {}", pid, formatSystemMessage(e)); + return ProcessRunner::Error; + } } } @@ -98,21 +92,19 @@ enum class Interest QString toString(Interest i) { - switch (i) - { - case Interest::Weak: - return "weak"; + switch (i) { + case Interest::Weak: + return "weak"; - case Interest::Strong: - return "strong"; + case Interest::Strong: + return "strong"; - case Interest::None: // fall-through - default: - return "no"; + case Interest::None: // fall-through + default: + return "no"; } } - struct InterestingProcess { env::Process p; @@ -120,7 +112,6 @@ struct InterestingProcess env::HandlePtr handle; }; - InterestingProcess findRandomProcess(const env::Process& root) { for (auto&& c : root.children()) { @@ -145,9 +136,7 @@ InterestingProcess findInterestingProcessInTrees(const env::Process& root) { // Certain process names we wish to "hide" for aesthetic reason: static const std::vector<QString> hiddenList = { - QFileInfo(QCoreApplication::applicationFilePath()).fileName(), - "conhost.exe" - }; + QFileInfo(QCoreApplication::applicationFilePath()).fileName(), "conhost.exe"}; if (root.children().empty()) { return {}; @@ -163,7 +152,6 @@ InterestingProcess findInterestingProcessInTrees(const env::Process& root) return false; }; - for (auto&& p : root.children()) { if (!isHidden(p)) { env::HandlePtr h = p.openHandleForWait(); @@ -184,9 +172,8 @@ InterestingProcess findInterestingProcessInTrees(const env::Process& root) void dump(const env::Process& p, int indent) { - log::debug( - "{}{}, pid={}, ppid={}", - std::string(indent * 4, ' '), p.name(), p.pid(), p.ppid()); + log::debug("{}{}, pid={}, ppid={}", std::string(indent * 4, ' '), p.name(), p.pid(), + p.ppid()); for (auto&& c : p.children()) { dump(c, indent + 1); @@ -228,9 +215,10 @@ const std::chrono::milliseconds Infinite(-1); // waits for completion, times out after `wait` if not Infinite // -std::optional<ProcessRunner::Results> timedWait( - HANDLE handle, DWORD pid, UILocker::Session* ls, - std::chrono::milliseconds wait, std::atomic<bool>& interrupt) +std::optional<ProcessRunner::Results> timedWait(HANDLE handle, DWORD pid, + UILocker::Session* ls, + std::chrono::milliseconds wait, + std::atomic<bool>& interrupt) { using namespace std::chrono; @@ -253,35 +241,29 @@ std::optional<ProcessRunner::Results> timedWait( // check the lock widget; the session can be null when running shortcuts // with locking disabled, in which case the user cannot force unlock if (ls) { - switch (ls->result()) - { - case UILocker::StillLocked: - { - break; - } + switch (ls->result()) { + case UILocker::StillLocked: { + break; + } - case UILocker::ForceUnlocked: - { - log::debug("waiting for {} force unlocked by user", pid); - return ProcessRunner::ForceUnlocked; - } + case UILocker::ForceUnlocked: { + log::debug("waiting for {} force unlocked by user", pid); + return ProcessRunner::ForceUnlocked; + } - case UILocker::Cancelled: - { - log::debug("waiting for {} cancelled by user", pid); - return ProcessRunner::Cancelled; - } + case UILocker::Cancelled: { + log::debug("waiting for {} cancelled by user", pid); + return ProcessRunner::Cancelled; + } - case UILocker::NoResult: // fall-through - default: - { - // shouldn't happen - log::debug( - "unexpected result {} while waiting for {}", - static_cast<int>(ls->result()), pid); + case UILocker::NoResult: // fall-through + default: { + // shouldn't happen + log::debug("unexpected result {} while waiting for {}", + static_cast<int>(ls->result()), pid); - return ProcessRunner::Error; - } + return ProcessRunner::Error; + } } } @@ -299,8 +281,8 @@ std::optional<ProcessRunner::Results> timedWait( return ProcessRunner::ForceUnlocked; } -ProcessRunner::Results waitForProcessesThreadImpl( - HANDLE job, UILocker::Session* ls, std::atomic<bool>& interrupt) +ProcessRunner::Results waitForProcessesThreadImpl(HANDLE job, UILocker::Session* ls, + std::atomic<bool>& interrupt) { using namespace std::chrono; @@ -329,9 +311,8 @@ ProcessRunner::Results waitForProcessesThreadImpl( // log any change in the process being waited for currentPID = ip.p.pid(); - log::debug( - "waiting for completion on {} ({}), {} interest", - ip.p.name(), ip.p.pid(), toString(ip.interest)); + log::debug("waiting for completion on {} ({}), {} interest", ip.p.name(), + ip.p.pid(), toString(ip.interest)); } if (ip.interest == Interest::Strong) { @@ -360,9 +341,8 @@ ProcessRunner::Results waitForProcessesThreadImpl( return ProcessRunner::ForceUnlocked; } -void waitForProcessesThread( - ProcessRunner::Results& result, HANDLE job, UILocker::Session* ls, - std::atomic<bool>& interrupt) +void waitForProcessesThread(ProcessRunner::Results& result, HANDLE job, + UILocker::Session* ls, std::atomic<bool>& interrupt) { result = waitForProcessesThreadImpl(job, ls, interrupt); @@ -372,8 +352,8 @@ void waitForProcessesThread( } } -ProcessRunner::Results waitForProcesses( - const std::vector<HANDLE>& initialProcesses, UILocker::Session* ls) +ProcessRunner::Results waitForProcesses(const std::vector<HANDLE>& initialProcesses, + UILocker::Session* ls) { if (initialProcesses.empty()) { // nothing to wait for @@ -386,9 +366,8 @@ ProcessRunner::Results waitForProcesses( if (!job) { const auto e = GetLastError(); - log::error( - "failed to create job to wait for processes, {}", - formatSystemMessage(e)); + log::error("failed to create job to wait for processes, {}", + formatSystemMessage(e)); return ProcessRunner::Error; } @@ -404,7 +383,7 @@ ProcessRunner::Results waitForProcesses( // this happens when closing MO while multiple processes are running, // so the logging is disabled until it gets fixed - //log::error( + // log::error( // "can't assign process to job to wait for processes, {}", // formatSystemMessage(e)); @@ -424,12 +403,11 @@ ProcessRunner::Results waitForProcesses( auto results = ProcessRunner::Running; std::atomic<bool> interrupt(false); - auto* t = QThread::create( - waitForProcessesThread, - std::ref(results), monitor, ls, std::ref(interrupt)); + auto* t = QThread::create(waitForProcessesThread, std::ref(results), monitor, ls, + std::ref(interrupt)); QEventLoop events; - QObject::connect(t, &QThread::finished, [&]{ + QObject::connect(t, &QThread::finished, [&] { events.quit(); }); @@ -446,8 +424,8 @@ ProcessRunner::Results waitForProcesses( return results; } -ProcessRunner::Results waitForProcess( - HANDLE initialProcess, LPDWORD exitCode, UILocker::Session* ls) +ProcessRunner::Results waitForProcess(HANDLE initialProcess, LPDWORD exitCode, + UILocker::Session* ls) { std::vector<HANDLE> processes = {initialProcess}; @@ -457,25 +435,22 @@ ProcessRunner::Results waitForProcess( if (exitCode && r != ProcessRunner::Running) { if (!::GetExitCodeProcess(initialProcess, exitCode)) { const auto e = ::GetLastError(); - log::warn( - "failed to get exit code of process, {}", - formatSystemMessage(e)); + log::warn("failed to get exit code of process, {}", formatSystemMessage(e)); } } return r; } - -ProcessRunner::ProcessRunner(OrganizerCore& core, IUserInterface* ui) : - m_core(core), m_ui(ui), m_lockReason(UILocker::NoReason), - m_waitFlags(NoFlags), m_handle(INVALID_HANDLE_VALUE), m_exitCode(-1) +ProcessRunner::ProcessRunner(OrganizerCore& core, IUserInterface* ui) + : m_core(core), m_ui(ui), m_lockReason(UILocker::NoReason), m_waitFlags(NoFlags), + m_handle(INVALID_HANDLE_VALUE), m_exitCode(-1) { // all processes started in ProcessRunner are hooked by default setHooked(true); } -ProcessRunner& ProcessRunner::setBinary(const QFileInfo &binary) +ProcessRunner& ProcessRunner::setBinary(const QFileInfo& binary) { m_sp.binary = binary; return *this; @@ -517,16 +492,15 @@ ProcessRunner& ProcessRunner::setProfileName(const QString& profileName) return *this; } -ProcessRunner& ProcessRunner::setWaitForCompletion( - WaitFlags flags, UILocker::Reasons reason) +ProcessRunner& ProcessRunner::setWaitForCompletion(WaitFlags flags, + UILocker::Reasons reason) { - m_waitFlags = flags; + m_waitFlags = flags; m_lockReason = reason; if (m_waitFlags.testFlag(WaitForRefresh) && !m_waitFlags.testFlag(TriggerRefresh)) { - log::warn( - "process runner: WaitForRefresh without TriggerRefresh " - "makes no sense, will be ignored"); + log::warn("process runner: WaitForRefresh without TriggerRefresh " + "makes no sense, will be ignored"); } return *this; @@ -538,8 +512,7 @@ ProcessRunner& ProcessRunner::setHooked(bool b) return *this; } -ProcessRunner& ProcessRunner::setFromFile( - QWidget* parent, const QFileInfo& targetInfo) +ProcessRunner& ProcessRunner::setFromFile(QWidget* parent, const QFileInfo& targetInfo) { if (!parent && m_ui) { parent = m_ui->mainWindow(); @@ -550,23 +523,20 @@ ProcessRunner& ProcessRunner::setFromFile( const auto fec = spawn::getFileExecutionContext(parent, targetInfo); - switch (fec.type) - { - case spawn::FileExecutionTypes::Executable: - { - setBinary(fec.binary); - setArguments(fec.arguments); - setCurrentDirectory(targetInfo.absoluteDir()); - break; - } + switch (fec.type) { + case spawn::FileExecutionTypes::Executable: { + setBinary(fec.binary); + setArguments(fec.arguments); + setCurrentDirectory(targetInfo.absoluteDir()); + break; + } - case spawn::FileExecutionTypes::Other: // fall-through - default: - { - m_shellOpen = targetInfo; - setHooked(false); - break; - } + case spawn::FileExecutionTypes::Other: // fall-through + default: { + m_shellOpen = targetInfo; + setHooked(false); + break; + } } return *this; @@ -579,8 +549,8 @@ ProcessRunner& ProcessRunner::setFromExecutable(const Executable& exe) throw MyException(QObject::tr("No profile set")); } - const QString customOverwrite = profile->setting( - "custom_overwrites", exe.title()).toString(); + const QString customOverwrite = + profile->setting("custom_overwrites", exe.title()).toString(); ForcedLibraries forcedLibraries; if (profile->forcedLibrariesEnabled(exe.title())) { @@ -606,29 +576,29 @@ ProcessRunner& ProcessRunner::setFromShortcut(const MOShortcut& shortcut) { const auto currentInstance = InstanceManager::singleton().currentInstance(); - if (currentInstance) - { + if (currentInstance) { if (shortcut.hasInstance() && !shortcut.isForInstance(*currentInstance)) { - MOBase::reportError(QObject::tr( - "This shortcut is for instance '%1' but Mod Organizer is currently " - "running for '%2'. Exit Mod Organizer before running the shortcut or " - "change the active instance.") - .arg(shortcut.instanceDisplayName()) - .arg(currentInstance->displayName())); + MOBase::reportError( + QObject::tr( + "This shortcut is for instance '%1' but Mod Organizer is currently " + "running for '%2'. Exit Mod Organizer before running the shortcut or " + "change the active instance.") + .arg(shortcut.instanceDisplayName()) + .arg(currentInstance->displayName())); throw std::exception(); } } const auto* exes = m_core.executablesList(); - const auto exe = exes->find(shortcut.executableName()); + const auto exe = exes->find(shortcut.executableName()); if (exe != exes->end()) { setFromExecutable(*exe); } else { - MOBase::reportError(QObject::tr( - "Executable '%1' does not exist in instance '%2'.") - .arg(shortcut.executableName()).arg(currentInstance->displayName())); + MOBase::reportError(QObject::tr("Executable '%1' does not exist in instance '%2'.") + .arg(shortcut.executableName()) + .arg(currentInstance->displayName())); throw std::exception(); } @@ -637,12 +607,9 @@ ProcessRunner& ProcessRunner::setFromShortcut(const MOShortcut& shortcut) } ProcessRunner& ProcessRunner::setFromFileOrExecutable( - const QString &executable, - const QStringList &args, - const QString &cwd, - const QString &profileOverride, - const QString &forcedCustomOverwrite, - bool ignoreCustomOverwrite) + const QString& executable, const QStringList& args, const QString& cwd, + const QString& profileOverride, const QString& forcedCustomOverwrite, + bool ignoreCustomOverwrite) { const auto* profile = m_core.currentProfile(); if (!profile) { @@ -659,7 +626,8 @@ ProcessRunner& ProcessRunner::setFromFileOrExecutable( if (m_sp.binary.isRelative()) { // relative path, should be relative to game directory - setBinary(QFileInfo(m_core.managedGame()->gameDirectory().absoluteFilePath(executable))); + setBinary(QFileInfo( + m_core.managedGame()->gameDirectory().absoluteFilePath(executable))); } if (cwd == "") { @@ -675,13 +643,13 @@ ProcessRunner& ProcessRunner::setFromFileOrExecutable( if (profile->forcedLibrariesEnabled(exe.title())) { setForcedLibraries(profile->determineForcedLibraries(exe.title())); } - } catch (const std::runtime_error &) { + } catch (const std::runtime_error&) { // nop } } else { // only a file name, search executables list try { - const Executable &exe = m_core.executablesList()->get(executable); + const Executable& exe = m_core.executablesList()->get(executable); setSteamID(exe.steamAppID()); setCustomOverwrite(profile->setting("custom_overwrites", exe.title()).toString()); @@ -699,7 +667,7 @@ ProcessRunner& ProcessRunner::setFromFileOrExecutable( if (cwd == "") { setCurrentDirectory(exe.workingDirectory()); } - } catch (const std::runtime_error &) { + } catch (const std::runtime_error&) { log::warn("\"{}\" not set up as executable", executable); } } @@ -744,7 +712,6 @@ ProcessRunner::Results ProcessRunner::run() m_shellOpen = m_sp.binary; } - std::optional<Results> r; if (shouldRunShell()) { @@ -801,7 +768,8 @@ std::optional<ProcessRunner::Results> ProcessRunner::runBinary() // saves profile, sets up usvfs, notifies plugins, etc.; can return false if // a plugin doesn't want the program to run (such as when checkFNIS fails to // run FNIS and the user clicks cancel) - if (!m_core.beforeRun(m_sp.binary, m_profileName, m_customOverwrite, m_forcedLibraries)) { + if (!m_core.beforeRun(m_sp.binary, m_profileName, m_customOverwrite, + m_forcedLibraries)) { return Error; } @@ -809,7 +777,7 @@ std::optional<ProcessRunner::Results> ProcessRunner::runBinary() QWidget* parent = (m_ui ? m_ui->mainWindow() : nullptr); const auto* game = m_core.managedGame(); - auto& settings = m_core.settings(); + auto& settings = m_core.settings(); // start steam if needed if (!checkSteam(parent, m_sp, game->gameDirectory(), m_sp.steamAppID, settings)) { @@ -852,27 +820,23 @@ bool ProcessRunner::shouldRefresh(Results r) const return false; } - switch (r) - { - case Completed: - { - log::debug("process runner: refreshing because the process completed"); - return true; - } + switch (r) { + case Completed: { + log::debug("process runner: refreshing because the process completed"); + return true; + } - case ForceUnlocked: - { - log::debug("process runner: refreshing because the ui was force unlocked"); - return true; - } + case ForceUnlocked: { + log::debug("process runner: refreshing because the ui was force unlocked"); + return true; + } - case Error: // fall-through - case Cancelled: - case Running: - default: - { - return false; - } + case Error: // fall-through + case Cancelled: + case Running: + default: { + return false; + } } } @@ -887,9 +851,8 @@ ProcessRunner::Results ProcessRunner::postRun() if (mustWait && m_lockReason == UILocker::NoReason) { // never lock the ui without an escape hatch for the user - log::debug( - "the ForceWait flag is set but the lock reason wasn't, " - "defaulting to LockUI"); + log::debug("the ForceWait flag is set but the lock reason wasn't, " + "defaulting to LockUI"); m_lockReason = UILocker::LockUI; } @@ -899,9 +862,8 @@ ProcessRunner::Results ProcessRunner::postRun() if (mustWait) { if (!lockEnabled) { // at least tell the user what's going on - log::debug( - "locking is disabled, but the output of the application is required; " - "overriding this setting and locking the ui"); + log::debug("locking is disabled, but the output of the application is required; " + "overriding this setting and locking the ui"); } } else { // no force wait @@ -913,9 +875,8 @@ ProcessRunner::Results ProcessRunner::postRun() if (!lockEnabled) { // disabling locking is like clicking on unlock immediately - log::debug( - "process runner: not waiting for process because " - "locking is disabled"); + log::debug("process runner: not waiting for process because " + "locking is disabled"); return ForceUnlocked; } @@ -946,10 +907,8 @@ ProcessRunner::Results ProcessRunner::postRun() const bool wait = m_waitFlags.testFlag(WaitForRefresh); if (wait) { - QObject::connect( - &m_core, &OrganizerCore::directoryStructureReady, - &loop, &QEventLoop::quit, - Qt::ConnectionType::QueuedConnection); + QObject::connect(&m_core, &OrganizerCore::directoryStructureReady, &loop, + &QEventLoop::quit, Qt::ConnectionType::QueuedConnection); } m_core.afterRun(m_sp.binary, m_exitCode); @@ -959,7 +918,7 @@ ProcessRunner::Results ProcessRunner::postRun() loop.exec(); log::debug("process runner: refresh is done"); } -} + } return r; } @@ -987,8 +946,8 @@ env::HandlePtr ProcessRunner::stealProcessHandle() return env::HandlePtr(h); } -ProcessRunner::Results ProcessRunner::waitForAllUSVFSProcessesWithLock( - UILocker::Reasons reason) +ProcessRunner::Results +ProcessRunner::waitForAllUSVFSProcessesWithLock(UILocker::Reasons reason) { m_lockReason = reason; @@ -1026,7 +985,7 @@ ProcessRunner::Results ProcessRunner::waitForAllUSVFSProcessesWithLock( return r; } -void ProcessRunner::withLock(std::function<void (UILocker::Session&)> f) +void ProcessRunner::withLock(std::function<void(UILocker::Session&)> f) { auto ls = UILocker::instance().lock(m_lockReason); f(*ls); diff --git a/src/processrunner.h b/src/processrunner.h index b8c8935c..c5b6bbe9 100644 --- a/src/processrunner.h +++ b/src/processrunner.h @@ -1,9 +1,9 @@ #ifndef PROCESSRUNNER_H #define PROCESSRUNNER_H +#include "envmodule.h" #include "spawn.h" #include "uilocker.h" -#include "envmodule.h" #include <executableinfo.h> class OrganizerCore; @@ -37,10 +37,10 @@ public: enum WaitFlag { - NoFlags = 0x00, + NoFlags = 0x00, // the directory structure will be refreshed once the process has completed - TriggerRefresh = 0x01, + TriggerRefresh = 0x01, // the process will be waited for even if locking is disabled or the // process is not hooked @@ -65,26 +65,26 @@ public: ForCommandLine = TriggerRefresh | WaitForRefresh | ForceWait }; - using WaitFlags = QFlags<WaitFlag>; + using WaitFlags = QFlags<WaitFlag>; using ForcedLibraries = QList<MOBase::ExecutableForcedLoadSetting>; ProcessRunner(OrganizerCore& core, IUserInterface* ui); // move only - ProcessRunner(ProcessRunner&&) = default; + ProcessRunner(ProcessRunner&&) = default; ProcessRunner& operator=(const ProcessRunner&) = delete; - ProcessRunner(const ProcessRunner&) = delete; - ProcessRunner& operator=(ProcessRunner&&) = delete; + ProcessRunner(const ProcessRunner&) = delete; + ProcessRunner& operator=(ProcessRunner&&) = delete; - ProcessRunner& setBinary(const QFileInfo &binary); + ProcessRunner& setBinary(const QFileInfo& binary); ProcessRunner& setArguments(const QString& arguments); ProcessRunner& setCurrentDirectory(const QDir& directory); ProcessRunner& setSteamID(const QString& steamID); ProcessRunner& setCustomOverwrite(const QString& customOverwrite); ProcessRunner& setForcedLibraries(const ForcedLibraries& forcedLibraries); ProcessRunner& setProfileName(const QString& profileName); - ProcessRunner& setWaitForCompletion( - WaitFlags flags=NoFlags, UILocker::Reasons reason=UILocker::LockUI); + ProcessRunner& setWaitForCompletion(WaitFlags flags = NoFlags, + UILocker::Reasons reason = UILocker::LockUI); ProcessRunner& setHooked(bool b); // - if the target is an executable file, runs it hooked @@ -113,13 +113,12 @@ public: // if the executable is not found in the list, the binary is run solely // based on the parameters given // - ProcessRunner& setFromFileOrExecutable( - const QString &executable, - const QStringList &args, - const QString &cwd={}, - const QString &profile={}, - const QString &forcedCustomOverwrite={}, - bool ignoreCustomOverwrite=false); + ProcessRunner& setFromFileOrExecutable(const QString& executable, + const QStringList& args, + const QString& cwd = {}, + const QString& profile = {}, + const QString& forcedCustomOverwrite = {}, + bool ignoreCustomOverwrite = false); // spawns the process and waits for it if required // @@ -172,7 +171,6 @@ private: env::HandlePtr m_handle; DWORD m_exitCode; - bool shouldRunShell() const; bool shouldRefresh(Results r) const; @@ -190,9 +188,9 @@ private: // creates the lock widget and calls f() // - void withLock(std::function<void (UILocker::Session&)> f); + void withLock(std::function<void(UILocker::Session&)> f); }; Q_DECLARE_OPERATORS_FOR_FLAGS(ProcessRunner::WaitFlags); -#endif // PROCESSRUNNER_H +#endif // PROCESSRUNNER_H diff --git a/src/profile.cpp b/src/profile.cpp index b4b0ddcb..c5ea5eec 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -19,44 +19,44 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "profile.h" +#include "filesystemutilities.h" #include "modinfo.h" +#include "modinfoforeign.h" +#include "registry.h" #include "settings.h" -#include "filesystemutilities.h" #include "shared/appconfig.h" -#include <iplugingame.h> -#include <report.h> -#include <safewritefile.h> +#include "shared/util.h" #include <bsainvalidation.h> #include <dataarchives.h> -#include "shared/util.h" -#include "registry.h" -#include "modinfoforeign.h" +#include <iplugingame.h> #include <questionboxmemory.h> +#include <report.h> +#include <safewritefile.h> #include <QApplication> -#include <QFile> // for QFile -#include <QFlags> // for operator|, QFlags -#include <QIODevice> // for QIODevice, etc -#include <QMessageBox> -#include <QScopedArrayPointer> -#include <QStringList> // for QStringList -#include <QtGlobal> // for qUtf8Printable #include <QBuffer> #include <QDirIterator> +#include <QFile> // for QFile +#include <QFlags> // for operator|, QFlags +#include <QIODevice> // for QIODevice, etc +#include <QMessageBox> +#include <QScopedArrayPointer> +#include <QStringList> // for QStringList +#include <QtGlobal> // for qUtf8Printable #include <Windows.h> -#include <assert.h> // for assert -#include <limits.h> // for UINT_MAX, INT_MAX, etc -#include <stddef.h> // for size_t -#include <string.h> // for wcslen +#include <assert.h> // for assert +#include <limits.h> // for UINT_MAX, INT_MAX, etc +#include <stddef.h> // for size_t +#include <string.h> // for wcslen -#include <algorithm> // for max, min -#include <exception> // for exception +#include <algorithm> // for max, min +#include <exception> // for exception #include <functional> -#include <set> // for set -#include <utility> // for find +#include <set> // for set #include <stdexcept> +#include <utility> // for find using namespace MOBase; using namespace MOShared; @@ -65,13 +65,17 @@ void Profile::touchFile(QString fileName) { QFile modList(m_Directory.filePath(fileName)); if (!modList.open(QIODevice::ReadWrite)) { - throw std::runtime_error(QObject::tr("failed to create %1").arg(m_Directory.filePath(fileName)).toUtf8().constData()); + throw std::runtime_error(QObject::tr("failed to create %1") + .arg(m_Directory.filePath(fileName)) + .toUtf8() + .constData()); } } -Profile::Profile(const QString &name, IPluginGame const *gamePlugin, bool useDefaultSettings) - : m_ModListWriter(std::bind(&Profile::doWriteModlist, this)) - , m_GamePlugin(gamePlugin) +Profile::Profile(const QString& name, IPluginGame const* gamePlugin, + bool useDefaultSettings) + : m_ModListWriter(std::bind(&Profile::doWriteModlist, this)), + m_GamePlugin(gamePlugin) { QString profilesDir = Settings::instance().paths().profiles(); QDir profileBase(profilesDir); @@ -84,18 +88,17 @@ Profile::Profile(const QString &name, IPluginGame const *gamePlugin, bool useDef throw MyException(tr("failed to create %1").arg(fixedName).toUtf8().constData()); } QString fullPath = profilesDir + "/" + fixedName; - m_Directory = QDir(fullPath); - m_Settings = new QSettings(m_Directory.absoluteFilePath("settings.ini"), - QSettings::IniFormat); + m_Directory = QDir(fullPath); + m_Settings = + new QSettings(m_Directory.absoluteFilePath("settings.ini"), QSettings::IniFormat); try { // create files. Needs to happen after m_Directory was set! touchFile("modlist.txt"); touchFile("archives.txt"); - IPluginGame::ProfileSettings settings = IPluginGame::CONFIGURATION - | IPluginGame::MODS - | IPluginGame::SAVEGAMES; + IPluginGame::ProfileSettings settings = + IPluginGame::CONFIGURATION | IPluginGame::MODS | IPluginGame::SAVEGAMES; if (useDefaultSettings) { settings |= IPluginGame::PREFER_DEFAULTS; @@ -111,16 +114,14 @@ Profile::Profile(const QString &name, IPluginGame const *gamePlugin, bool useDef refreshModStatus(); } - -Profile::Profile(const QDir &directory, IPluginGame const *gamePlugin) - : m_Directory(directory) - , m_GamePlugin(gamePlugin) - , m_ModListWriter(std::bind(&Profile::doWriteModlist, this)) +Profile::Profile(const QDir& directory, IPluginGame const* gamePlugin) + : m_Directory(directory), m_GamePlugin(gamePlugin), + m_ModListWriter(std::bind(&Profile::doWriteModlist, this)) { assert(gamePlugin != nullptr); - m_Settings = new QSettings(directory.absoluteFilePath("settings.ini"), - QSettings::IniFormat); + m_Settings = + new QSettings(directory.absoluteFilePath("settings.ini"), QSettings::IniFormat); findProfileSettings(); if (!QFile::exists(m_Directory.filePath("modlist.txt"))) { @@ -128,27 +129,24 @@ Profile::Profile(const QDir &directory, IPluginGame const *gamePlugin) touchFile(m_Directory.filePath("modlist.txt")); } - IPluginGame::ProfileSettings settings = IPluginGame::MODS - | IPluginGame::SAVEGAMES; + IPluginGame::ProfileSettings settings = IPluginGame::MODS | IPluginGame::SAVEGAMES; gamePlugin->initializeProfile(directory, settings); refreshModStatus(); } - -Profile::Profile(const Profile &reference) - : m_Directory(reference.m_Directory) - , m_ModListWriter(std::bind(&Profile::doWriteModlist, this)) - , m_GamePlugin(reference.m_GamePlugin) +Profile::Profile(const Profile& reference) + : m_Directory(reference.m_Directory), + m_ModListWriter(std::bind(&Profile::doWriteModlist, this)), + m_GamePlugin(reference.m_GamePlugin) { - m_Settings = new QSettings(m_Directory.absoluteFilePath("settings.ini"), - QSettings::IniFormat); + m_Settings = + new QSettings(m_Directory.absoluteFilePath("settings.ini"), QSettings::IniFormat); findProfileSettings(); refreshModStatus(); } - Profile::~Profile() { delete m_Settings; @@ -179,11 +177,11 @@ void Profile::findProfileSettings() } if (setting("", "AutomaticArchiveInvalidation") == QVariant()) { - BSAInvalidation *invalidation = m_GamePlugin->feature<BSAInvalidation>(); - DataArchives *dataArchives = m_GamePlugin->feature<DataArchives>(); - bool found = false; + BSAInvalidation* invalidation = m_GamePlugin->feature<BSAInvalidation>(); + DataArchives* dataArchives = m_GamePlugin->feature<DataArchives>(); + bool found = false; if ((invalidation != nullptr) && (dataArchives != nullptr)) { - for (const QString &archive : dataArchives->archives(this)) { + for (const QString& archive : dataArchives->archives(this)) { if (invalidation->isInvalidationBSA(archive)) { storeSetting("", "AutomaticArchiveInvalidation", true); found = true; @@ -219,20 +217,23 @@ void Profile::cancelModlistWrite() void Profile::doWriteModlist() { - if (!m_Directory.exists()) return; + if (!m_Directory.exists()) + return; try { QString fileName = getModlistFileName(); SafeWriteFile file(fileName); - file->write(QString("# This file was automatically generated by Mod Organizer.\r\n").toUtf8()); + file->write(QString("# This file was automatically generated by Mod Organizer.\r\n") + .toUtf8()); if (m_ModStatus.empty()) { return; } - for (auto iter = m_ModIndexByPriority.crbegin(); iter != m_ModIndexByPriority.crend(); iter++) { + for (auto iter = m_ModIndexByPriority.crbegin(); + iter != m_ModIndexByPriority.crend(); iter++) { // the priority order was inverted on load so it has to be inverted again - const auto index = iter->second; + const auto index = iter->second; ModInfo::Ptr modInfo = ModInfo::getByIndex(index); if (!modInfo->hasAutomaticPriority()) { if (modInfo->isForeign()) { @@ -248,22 +249,20 @@ void Profile::doWriteModlist() } file.commitIfDifferent(m_LastModlistHash); - } catch (const std::exception &e) { + } catch (const std::exception& e) { reportError(tr("failed to write mod list: %1").arg(e.what())); return; } } - void Profile::createTweakedIniFile() { QString tweakedIni = m_Directory.absoluteFilePath("initweaks.ini"); if (QFile::exists(tweakedIni) && !shellDeleteQuiet(tweakedIni)) { const auto e = GetLastError(); - reportError( - tr("failed to update tweaked ini file, wrong settings may be used: %1") - .arg(QString::fromStdWString(formatSystemMessage(e)))); + reportError(tr("failed to update tweaked ini file, wrong settings may be used: %1") + .arg(QString::fromStdWString(formatSystemMessage(e)))); return; } @@ -277,14 +276,15 @@ void Profile::createTweakedIniFile() mergeTweak(getProfileTweaks(), tweakedIni); bool error = false; - if (!MOBase::WriteRegistryValue(L"Archive", L"bInvalidateOlderFiles", L"1", ToWString(tweakedIni).c_str())) { + if (!MOBase::WriteRegistryValue(L"Archive", L"bInvalidateOlderFiles", L"1", + ToWString(tweakedIni).c_str())) { error = true; } if (error) { const auto e = ::GetLastError(); reportError(tr("failed to create tweaked ini: %1") - .arg(QString::fromStdWString(formatSystemMessage(e)))); + .arg(QString::fromStdWString(formatSystemMessage(e)))); } } @@ -305,7 +305,8 @@ void Profile::renameModInAllProfiles(const QString& oldName, const QString& newN } // static -void Profile::renameModInList(QFile &modList, const QString &oldName, const QString &newName) +void Profile::renameModInList(QFile& modList, const QString& oldName, + const QString& newName) { if (!modList.open(QIODevice::ReadOnly)) { reportError(tr("failed to open %1").arg(modList.fileName())); @@ -357,9 +358,8 @@ void Profile::renameModInList(QFile &modList, const QString &oldName, const QStr } if (renamed) - log::debug( - "Renamed {} \"{}\" mod to \"{}\" in {}", - renamed, oldName, newName, modList.fileName()); + log::debug("Renamed {} \"{}\" mod to \"{}\" in {}", renamed, oldName, newName, + modList.fileName()); } void Profile::refreshModStatus() @@ -396,11 +396,12 @@ void Profile::refreshModStatus() // N-1 overwrite (N = number of mods) // - writeModlistNow(true); // if there are pending changes write them first + writeModlistNow(true); // if there are pending changes write them first QFile file(getModlistFileName()); if (!file.open(QIODevice::ReadOnly)) { - throw MyException(tr("\"%1\" is missing or inaccessible").arg(getModlistFileName())); + throw MyException( + tr("\"%1\" is missing or inaccessible").arg(getModlistFileName())); } bool modStatusModified = false; @@ -450,9 +451,7 @@ void Profile::refreshModStatus() unsigned int modIndex = ModInfo::getIndex(modName); if (modIndex == UINT_MAX) { - log::debug( - "mod not found: \"{}\" (profile \"{}\")", - modName, m_Directory.path()); + log::debug("mod not found: \"{}\" (profile \"{}\")", modName, m_Directory.path()); // need to rewrite the modlist to fix this modStatusModified = true; continue; @@ -469,19 +468,18 @@ void Profile::refreshModStatus() m_ModStatus[modIndex].m_Priority = index++; } } else { - log::warn( - "no mod state for \"{}\" (profile \"{}\")", - modName, m_Directory.path()); + log::warn("no mod state for \"{}\" (profile \"{}\")", modName, + m_Directory.path()); // need to rewrite the modlist to fix this modStatusModified = true; } - } // while (!file.atEnd()) + } // while (!file.atEnd()) file.close(); const int numKnownMods = index; - int topInsert = 0; + int topInsert = 0; // invert priority order to match that of the pluginlist, also // give priorities to mods not referenced in the profile and @@ -521,8 +519,8 @@ void Profile::refreshModStatus() } } - // to support insertion of new mods at the top we may now have mods with negative priority, - // so shift them all up to align priority with 0 + // to support insertion of new mods at the top we may now have mods with negative + // priority, so shift them all up to align priority with 0 if (topInsert < 0) { int offset = topInsert * -1; for (size_t i = 0; i < m_ModStatus.size(); ++i) { @@ -548,7 +546,8 @@ void Profile::refreshModStatus() // User has a mod named some variation of "overwrite". Tell them about it. if (warnAboutOverwrite) { - reportError(tr("A mod named \"overwrite\" was detected, disabled, and moved to the highest priority on the mod list. " + reportError(tr("A mod named \"overwrite\" was detected, disabled, and moved to the " + "highest priority on the mod list. " "You may want to rename this mod and enable it again.")); // also, mark the mod-list as changed modStatusModified = true; @@ -559,36 +558,32 @@ void Profile::refreshModStatus() } } - void Profile::dumpModStatus() const { for (unsigned int i = 0; i < m_ModStatus.size(); ++i) { ModInfo::Ptr info = ModInfo::getByIndex(i); - log::warn( - "{}: {} - {} ({})", - i, info->name(), m_ModStatus[i].m_Priority, - m_ModStatus[i].m_Enabled ? "enabled" : "disabled"); + log::warn("{}: {} - {} ({})", i, info->name(), m_ModStatus[i].m_Priority, + m_ModStatus[i].m_Enabled ? "enabled" : "disabled"); } } - void Profile::updateIndices() { m_ModIndexByPriority.clear(); for (unsigned int i = 0; i < m_ModStatus.size(); ++i) { - int priority = m_ModStatus[i].m_Priority; + int priority = m_ModStatus[i].m_Priority; m_ModIndexByPriority[priority] = i; } } - -std::vector<std::tuple<QString, QString, int> > Profile::getActiveMods() +std::vector<std::tuple<QString, QString, int>> Profile::getActiveMods() { - std::vector<std::tuple<QString, QString, int> > result; + std::vector<std::tuple<QString, QString, int>> result; for (const auto& [priority, index] : m_ModIndexByPriority) { if (m_ModStatus[index].m_Enabled) { ModInfo::Ptr modInfo = ModInfo::getByIndex(index); - result.push_back(std::make_tuple(modInfo->internalName(), modInfo->absolutePath(), m_ModStatus[index].m_Priority)); + result.push_back(std::make_tuple(modInfo->internalName(), modInfo->absolutePath(), + m_ModStatus[index].m_Priority)); } } @@ -618,7 +613,8 @@ void Profile::setModEnabled(unsigned int index, bool enabled) } } -void Profile::setModsEnabled(const QList<unsigned int>& modsToEnable, const QList<unsigned int>& modsToDisable) +void Profile::setModsEnabled(const QList<unsigned int>& modsToEnable, + const QList<unsigned int>& modsToDisable) { QList<unsigned int> dirtyMods; for (auto idx : modsToEnable) { @@ -661,7 +657,6 @@ bool Profile::modEnabled(unsigned int index) const return m_ModStatus[index].m_Enabled; } - int Profile::getModPriority(unsigned int index) const { if (index >= m_ModStatus.size()) { @@ -671,8 +666,7 @@ int Profile::getModPriority(unsigned int index) const return m_ModStatus[index].m_Priority; } - -bool Profile::setModPriority(unsigned int index, int &newPriority) +bool Profile::setModPriority(unsigned int index, int& newPriority) { if (ModInfo::getByIndex(index)->hasAutomaticPriority()) { // can't change priority of overwrite/backups @@ -681,7 +675,7 @@ bool Profile::setModPriority(unsigned int index, int &newPriority) newPriority = std::clamp(newPriority, 0, static_cast<int>(m_NumRegularMods) - 1); - int oldPriority = m_ModStatus.at(index).m_Priority; + int oldPriority = m_ModStatus.at(index).m_Priority; int lastPriority = INT_MIN; if (newPriority == oldPriority) { @@ -690,16 +684,17 @@ bool Profile::setModPriority(unsigned int index, int &newPriority) } for (const auto& [priority, index] : m_ModIndexByPriority) { - if (newPriority < oldPriority && priority >= newPriority && priority < oldPriority) { + if (newPriority < oldPriority && priority >= newPriority && + priority < oldPriority) { m_ModStatus.at(index).m_Priority += 1; - } - else if (newPriority > oldPriority && priority <= newPriority && priority > oldPriority) { + } else if (newPriority > oldPriority && priority <= newPriority && + priority > oldPriority) { m_ModStatus.at(index).m_Priority -= 1; } lastPriority = std::max(lastPriority, priority); } - newPriority = std::min(newPriority, lastPriority); + newPriority = std::min(newPriority, lastPriority); m_ModStatus.at(index).m_Priority = std::min(newPriority, lastPriority); updateIndices(); @@ -708,23 +703,24 @@ bool Profile::setModPriority(unsigned int index, int &newPriority) return true; } -Profile *Profile::createPtrFrom(const QString &name, const Profile &reference, MOBase::IPluginGame const *gamePlugin) +Profile* Profile::createPtrFrom(const QString& name, const Profile& reference, + MOBase::IPluginGame const* gamePlugin) { QString profileDirectory = Settings::instance().paths().profiles() + "/" + name; reference.copyFilesTo(profileDirectory); return new Profile(QDir(profileDirectory), gamePlugin); } -void Profile::copyFilesTo(QString &target) const +void Profile::copyFilesTo(QString& target) const { copyDir(m_Directory.absolutePath(), target, false); } -std::vector<std::wstring> Profile::splitDZString(const wchar_t *buffer) const +std::vector<std::wstring> Profile::splitDZString(const wchar_t* buffer) const { std::vector<std::wstring> result; - const wchar_t *pos = buffer; - size_t length = wcslen(pos); + const wchar_t* pos = buffer; + size_t length = wcslen(pos); while (length != 0U) { result.push_back(pos); pos += length + 1; @@ -733,7 +729,7 @@ std::vector<std::wstring> Profile::splitDZString(const wchar_t *buffer) const return result; } -void Profile::mergeTweak(const QString &tweakName, const QString &tweakedIni) const +void Profile::mergeTweak(const QString& tweakName, const QString& tweakedIni) const { static const int bufferSize = 32768; @@ -742,14 +738,15 @@ void Profile::mergeTweak(const QString &tweakName, const QString &tweakedIni) co QScopedArrayPointer<wchar_t> buffer(new wchar_t[bufferSize]); // retrieve a list of sections - DWORD size = ::GetPrivateProfileSectionNamesW( - buffer.data(), bufferSize, tweakNameW.c_str()); + DWORD size = + ::GetPrivateProfileSectionNamesW(buffer.data(), bufferSize, tweakNameW.c_str()); if (size == bufferSize - 2) { // unfortunately there is no good way to find the required size // of the buffer throw MyException(QString("Buffer too small. Please report this as a bug. " - "For now you might want to split up %1").arg(tweakName)); + "For now you might want to split up %1") + .arg(tweakName)); } std::vector<std::wstring> sections = splitDZString(buffer.data()); @@ -762,36 +759,37 @@ void Profile::mergeTweak(const QString &tweakName, const QString &tweakedIni) co bufferSize, tweakNameW.c_str()); if (size == bufferSize - 2) { throw MyException(QString("Buffer too small. Please report this as a bug. " - "For now you might want to split up %1").arg(tweakName)); + "For now you might want to split up %1") + .arg(tweakName)); } std::vector<std::wstring> keys = splitDZString(buffer.data()); for (std::vector<std::wstring>::iterator keyIter = keys.begin(); keyIter != keys.end(); ++keyIter) { - //TODO this treats everything as strings but how could I differentiate the type? - ::GetPrivateProfileStringW(iter->c_str(), keyIter->c_str(), - nullptr, buffer.data(), bufferSize, ToWString(tweakName).c_str()); - MOBase::WriteRegistryValue(iter->c_str(), keyIter->c_str(), - buffer.data(), tweakedIniW.c_str()); + // TODO this treats everything as strings but how could I differentiate the type? + ::GetPrivateProfileStringW(iter->c_str(), keyIter->c_str(), nullptr, + buffer.data(), bufferSize, + ToWString(tweakName).c_str()); + MOBase::WriteRegistryValue(iter->c_str(), keyIter->c_str(), buffer.data(), + tweakedIniW.c_str()); } } } -void Profile::mergeTweaks(ModInfo::Ptr modInfo, const QString &tweakedIni) const +void Profile::mergeTweaks(ModInfo::Ptr modInfo, const QString& tweakedIni) const { std::vector<QString> iniTweaks = modInfo->getIniTweaks(); - for (std::vector<QString>::iterator iter = iniTweaks.begin(); - iter != iniTweaks.end(); ++iter) { + for (std::vector<QString>::iterator iter = iniTweaks.begin(); iter != iniTweaks.end(); + ++iter) { mergeTweak(*iter, tweakedIni); } } - -bool Profile::invalidationActive(bool *supported) const +bool Profile::invalidationActive(bool* supported) const { - BSAInvalidation *invalidation = m_GamePlugin->feature<BSAInvalidation>(); - DataArchives *dataArchives = m_GamePlugin->feature<DataArchives>(); + BSAInvalidation* invalidation = m_GamePlugin->feature<BSAInvalidation>(); + DataArchives* dataArchives = m_GamePlugin->feature<DataArchives>(); if (supported != nullptr) { *supported = ((invalidation != nullptr) && (dataArchives != nullptr)); @@ -800,10 +798,9 @@ bool Profile::invalidationActive(bool *supported) const return setting("", "AutomaticArchiveInvalidation", false).toBool(); } - void Profile::deactivateInvalidation() { - BSAInvalidation *invalidation = m_GamePlugin->feature<BSAInvalidation>(); + BSAInvalidation* invalidation = m_GamePlugin->feature<BSAInvalidation>(); if (invalidation != nullptr) { invalidation->deactivate(this); @@ -812,10 +809,9 @@ void Profile::deactivateInvalidation() storeSetting("", "AutomaticArchiveInvalidation", false); } - void Profile::activateInvalidation() { - BSAInvalidation *invalidation = m_GamePlugin->feature<BSAInvalidation>(); + BSAInvalidation* invalidation = m_GamePlugin->feature<BSAInvalidation>(); if (invalidation != nullptr) { invalidation->activate(this); @@ -824,26 +820,28 @@ void Profile::activateInvalidation() storeSetting("", "AutomaticArchiveInvalidation", true); } - bool Profile::localSavesEnabled() const { return setting("", "LocalSaves", false).toBool(); } - bool Profile::enableLocalSaves(bool enable) { if (enable) { if (!m_Directory.exists("saves")) { m_Directory.mkdir("saves"); } - } else { + } else { QDialogButtonBox::StandardButton res; - res = QuestionBoxMemory::query(QApplication::activeModalWidget(), "deleteSavesQuery", - tr("Delete profile-specific save games?"), - tr("Do you want to delete the profile-specific save games? (If you select \"No\", the " - "save games will show up again if you re-enable profile-specific save games)"), - QDialogButtonBox::No | QDialogButtonBox::Yes | QDialogButtonBox::Cancel, QDialogButtonBox::No); + res = QuestionBoxMemory::query( + QApplication::activeModalWidget(), "deleteSavesQuery", + tr("Delete profile-specific save games?"), + tr("Do you want to delete the profile-specific save games? (If you select " + "\"No\", the " + "save games will show up again if you re-enable profile-specific save " + "games)"), + QDialogButtonBox::No | QDialogButtonBox::Yes | QDialogButtonBox::Cancel, + QDialogButtonBox::No); if (res == QMessageBox::Yes) { shellDelete(QStringList(m_Directory.absoluteFilePath("saves"))); } else if (res == QMessageBox::No) { @@ -854,7 +852,6 @@ bool Profile::enableLocalSaves(bool enable) } storeSetting("", "LocalSaves", enable); return true; - } bool Profile::localSettingsEnabled() const @@ -871,12 +868,15 @@ bool Profile::localSettingsEnabled() const } if (!missingFiles.empty()) { m_GamePlugin->initializeProfile(m_Directory, IPluginGame::CONFIGURATION); - QMessageBox::StandardButton res = QMessageBox::warning( - QApplication::activeModalWidget(), tr("Missing profile-specific game INI files!"), - tr("Some of your profile-specific game INI files were missing. They will now be copied " - "from the vanilla game folder. You might want to double-check your settings.\n\n" - "Missing files:\n") + missingFiles.join("\n") - ); + QMessageBox::StandardButton res = + QMessageBox::warning(QApplication::activeModalWidget(), + tr("Missing profile-specific game INI files!"), + tr("Some of your profile-specific game INI files were " + "missing. They will now be copied " + "from the vanilla game folder. You might want to " + "double-check your settings.\n\n" + "Missing files:\n") + + missingFiles.join("\n")); } } return enabled; @@ -885,14 +885,19 @@ bool Profile::localSettingsEnabled() const bool Profile::enableLocalSettings(bool enable) { if (enable) { - m_GamePlugin->initializeProfile(m_Directory.absolutePath(), IPluginGame::CONFIGURATION); + m_GamePlugin->initializeProfile(m_Directory.absolutePath(), + IPluginGame::CONFIGURATION); } else { QDialogButtonBox::StandardButton res; res = QuestionBoxMemory::query(QApplication::activeModalWidget(), "deleteINIQuery", - tr("Delete profile-specific game INI files?"), - tr("Do you want to delete the profile-specific game INI files? (If you select \"No\", the " - "INI files will be used again if you re-enable profile-specific game INI files.)"), - QDialogButtonBox::No | QDialogButtonBox::Yes | QDialogButtonBox::Cancel, QDialogButtonBox::No); + tr("Delete profile-specific game INI files?"), + tr("Do you want to delete the profile-specific game " + "INI files? (If you select \"No\", the " + "INI files will be used again if you re-enable " + "profile-specific game INI files.)"), + QDialogButtonBox::No | QDialogButtonBox::Yes | + QDialogButtonBox::Cancel, + QDialogButtonBox::No); if (res == QMessageBox::Yes) { QStringList filesToDelete; for (QString file : m_GamePlugin->iniFiles()) { @@ -970,7 +975,8 @@ QString Profile::absoluteIniFilePath(QString iniFile) const QString Profile::getProfileTweaks() const { - return QDir::cleanPath(m_Directory.absoluteFilePath(ToQString(AppConfig::profileTweakIni()))); + return QDir::cleanPath( + m_Directory.absoluteFilePath(ToQString(AppConfig::profileTweakIni()))); } QString Profile::absolutePath() const @@ -981,17 +987,16 @@ QString Profile::absolutePath() const QString Profile::savePath() const { return QDir::cleanPath(m_Directory.absoluteFilePath("saves")); - } -void Profile::rename(const QString &newName) +void Profile::rename(const QString& newName) { QDir profileDir(Settings::instance().paths().profiles()); profileDir.rename(name(), newName); m_Directory.setPath(profileDir.absoluteFilePath(newName)); } -QString keyName(const QString §ion, const QString &name) +QString keyName(const QString& section, const QString& name) { QString key = section; @@ -1006,24 +1011,24 @@ QString keyName(const QString §ion, const QString &name) return key; } -QVariant Profile::setting(const QString §ion, const QString &name, - const QVariant &fallback) const +QVariant Profile::setting(const QString& section, const QString& name, + const QVariant& fallback) const { return m_Settings->value(keyName(section, name), fallback); } -void Profile::storeSetting(const QString §ion, const QString &name, - const QVariant &value) +void Profile::storeSetting(const QString& section, const QString& name, + const QVariant& value) { m_Settings->setValue(keyName(section, name), value); } -void Profile::removeSetting(const QString §ion, const QString &name) +void Profile::removeSetting(const QString& section, const QString& name) { - m_Settings->remove(keyName(section, name)); + m_Settings->remove(keyName(section, name)); } -QVariantMap Profile::settingsByGroup(const QString §ion) const +QVariantMap Profile::settingsByGroup(const QString& section) const { QVariantMap results; m_Settings->beginGroup(section); @@ -1034,7 +1039,7 @@ QVariantMap Profile::settingsByGroup(const QString §ion) const return results; } -void Profile::storeSettingsByGroup(const QString §ion, const QVariantMap &values) +void Profile::storeSettingsByGroup(const QString& section, const QVariantMap& values) { m_Settings->beginGroup(section); for (auto key : values.keys()) { @@ -1043,7 +1048,7 @@ void Profile::storeSettingsByGroup(const QString §ion, const QVariantMap &va m_Settings->endGroup(); } -QList<QVariantMap> Profile::settingsByArray(const QString &prefix) const +QList<QVariantMap> Profile::settingsByArray(const QString& prefix) const { QList<QVariantMap> results; int size = m_Settings->beginReadArray(prefix); @@ -1059,7 +1064,8 @@ QList<QVariantMap> Profile::settingsByArray(const QString &prefix) const return results; } -void Profile::storeSettingsByArray(const QString &prefix, const QList<QVariantMap> &values) +void Profile::storeSettingsByArray(const QString& prefix, + const QList<QVariantMap>& values) { m_Settings->beginWriteArray(prefix); for (int i = 0; i < values.length(); i++) { @@ -1071,17 +1077,18 @@ void Profile::storeSettingsByArray(const QString &prefix, const QList<QVariantMa m_Settings->endArray(); } -bool Profile::forcedLibrariesEnabled(const QString &executable) const +bool Profile::forcedLibrariesEnabled(const QString& executable) const { return setting("forced_libraries", executable + "/enabled", true).toBool(); } -void Profile::setForcedLibrariesEnabled(const QString &executable, bool enabled) +void Profile::setForcedLibrariesEnabled(const QString& executable, bool enabled) { storeSetting("forced_libraries", executable + "/enabled", enabled); } -QList<ExecutableForcedLoadSetting> Profile::determineForcedLibraries(const QString &executable) const +QList<ExecutableForcedLoadSetting> +Profile::determineForcedLibraries(const QString& executable) const { QList<ExecutableForcedLoadSetting> results; @@ -1092,10 +1099,12 @@ QList<ExecutableForcedLoadSetting> Profile::determineForcedLibraries(const QStri for (auto forcedLoad : forcedLoads) { bool found = false; for (auto rawSetting : rawSettings) { - if ((rawSetting.value("process").toString().compare(forcedLoad.process(), Qt::CaseInsensitive) == 0) - && (rawSetting.value("library").toString().compare(forcedLoad.library(), Qt::CaseInsensitive) == 0)) - { - results.append(forcedLoad.withEnabled(rawSetting.value("enabled", false).toBool())); + if ((rawSetting.value("process").toString().compare(forcedLoad.process(), + Qt::CaseInsensitive) == 0) && + (rawSetting.value("library").toString().compare(forcedLoad.library(), + Qt::CaseInsensitive) == 0)) { + results.append( + forcedLoad.withEnabled(rawSetting.value("enabled", false).toBool())); found = true; } } @@ -1108,26 +1117,25 @@ QList<ExecutableForcedLoadSetting> Profile::determineForcedLibraries(const QStri for (auto rawSetting : rawSettings) { bool add = true; for (auto forcedLoad : forcedLoads) { - if ((rawSetting.value("process").toString().compare(forcedLoad.process(), Qt::CaseInsensitive) == 0) - && (rawSetting.value("library").toString().compare(forcedLoad.library(), Qt::CaseInsensitive) == 0)) - { + if ((rawSetting.value("process").toString().compare(forcedLoad.process(), + Qt::CaseInsensitive) == 0) && + (rawSetting.value("library").toString().compare(forcedLoad.library(), + Qt::CaseInsensitive) == 0)) { add = false; } } if (add) { - results.append( - ExecutableForcedLoadSetting( - rawSetting.value("process").toString(), - rawSetting.value("library").toString() - ).withEnabled(rawSetting.value("enabled", false).toBool()) - ); + results.append(ExecutableForcedLoadSetting(rawSetting.value("process").toString(), + rawSetting.value("library").toString()) + .withEnabled(rawSetting.value("enabled", false).toBool())); } } return results; } -void Profile::storeForcedLibraries(const QString &executable, const QList<ExecutableForcedLoadSetting> &values) +void Profile::storeForcedLibraries(const QString& executable, + const QList<ExecutableForcedLoadSetting>& values) { QList<QVariantMap> rawSettings; for (auto setting : values) { @@ -1140,7 +1148,7 @@ void Profile::storeForcedLibraries(const QString &executable, const QList<Execut storeSettingsByArray("forced_libraries/" + executable, rawSettings); } -void Profile::removeForcedLibraries(const QString &executable) +void Profile::removeForcedLibraries(const QString& executable) { m_Settings->remove("forced_libraries/" + executable); } @@ -1149,8 +1157,8 @@ void Profile::debugDump() const { struct Pair { - std::size_t enabled=0; - std::size_t total=0; + std::size_t enabled = 0; + std::size_t total = 0; }; Pair total; @@ -1169,7 +1177,6 @@ void Profile::debugDump() const } }; - for (const auto& status : m_ModStatus) { auto index = m_ModIndexByPriority.find(status.m_Priority); if (index == m_ModIndexByPriority.end()) { @@ -1179,7 +1186,8 @@ void Profile::debugDump() const auto m = ModInfo::getByIndex(index->second); if (!m) { - log::error("mod index {} with priority {} not found", index->second, status.m_Priority); + log::error("mod index {} with priority {} not found", index->second, + status.m_Priority); continue; } @@ -1199,43 +1207,34 @@ void Profile::debugDump() const if (m->hasFlag(ModInfo::FLAG_FOREIGN)) { if (auto* f = dynamic_cast<ModInfoForeign*>(m.get())) { - switch (f->modType()) - { - case ModInfo::MOD_DLC: - add(dlc, status); - break; + switch (f->modType()) { + case ModInfo::MOD_DLC: + add(dlc, status); + break; - case ModInfo::MOD_CC: - add(cc, status); - break; + case ModInfo::MOD_CC: + add(cc, status); + break; - default: - add(unmanaged, status); - break; + default: + add(unmanaged, status); + break; } } } - if (!m->hasAnyOfTheseFlags({ - ModInfo::FLAG_BACKUP, ModInfo::FLAG_FOREIGN, - ModInfo::FLAG_SEPARATOR, ModInfo::FLAG_OVERWRITE })) - { + if (!m->hasAnyOfTheseFlags({ModInfo::FLAG_BACKUP, ModInfo::FLAG_FOREIGN, + ModInfo::FLAG_SEPARATOR, ModInfo::FLAG_OVERWRITE})) { add(real, status); } } - log::debug( - "profile '{}' in '{}': " - "mods={}/{} backup={}/{} separators={}/{} real={}/{} dlc={}/{} " - "cc={}/{} unmanaged={}/{} localsaves={}, localsettings={}", - name(), absolutePath(), - total.enabled, total.total, - backup.enabled, backup.total, - separators.enabled, separators.total, - real.enabled, real.total, - dlc.enabled, dlc.total, - cc.enabled, cc.total, - unmanaged.enabled, unmanaged.total, - localSavesEnabled() ? "yes" : "no", - localSettingsEnabled() ? "yes" : "no"); + log::debug("profile '{}' in '{}': " + "mods={}/{} backup={}/{} separators={}/{} real={}/{} dlc={}/{} " + "cc={}/{} unmanaged={}/{} localsaves={}, localsettings={}", + name(), absolutePath(), total.enabled, total.total, backup.enabled, + backup.total, separators.enabled, separators.total, real.enabled, + real.total, dlc.enabled, dlc.total, cc.enabled, cc.total, + unmanaged.enabled, unmanaged.total, localSavesEnabled() ? "yes" : "no", + localSettingsEnabled() ? "yes" : "no"); } diff --git a/src/profile.h b/src/profile.h index 457d8015..0adb4d0f 100644 --- a/src/profile.h +++ b/src/profile.h @@ -20,18 +20,17 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef PROFILE_H #define PROFILE_H - +#include "executableinfo.h" #include "modinfo.h" -#include <iprofile.h> #include <delayedfilewriter.h> -#include "executableinfo.h" +#include <iprofile.h> #include <QByteArray> #include <QDir> +#include <QList> #include <QObject> -#include <QString> #include <QSettings> -#include <QList> +#include <QString> #include <boost/shared_ptr.hpp> @@ -39,8 +38,10 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <tuple> #include <vector> - -namespace MOBase { class IPluginGame; } +namespace MOBase +{ +class IPluginGame; +} /** * @brief represents a profile @@ -51,18 +52,15 @@ class Profile : public QObject, public MOBase::IProfile Q_OBJECT public: - using Ptr = boost::shared_ptr<Profile>; public: - // the minimum and maximum priority achievable by mods // static constexpr int MinimumPriority = 0; static constexpr int MaximumPriority = std::numeric_limits<int>::max(); public: - /** * @brief constructor * @@ -71,25 +69,27 @@ public: * @param name name of the new profile * @param filter save game filter. Defaults to <no filter>. **/ - Profile(const QString &name, MOBase::IPluginGame const *gamePlugin, bool useDefaultSettings); + Profile(const QString& name, MOBase::IPluginGame const* gamePlugin, + bool useDefaultSettings); /** * @brief constructor * - * This constructor is used to open an existing profile though it will also try to repair - * the profile if important files are missing (including the directory itself) so technically, - * invoking this should always produce a working profile + * This constructor is used to open an existing profile though it will also try to + *repair the profile if important files are missing (including the directory itself) + *so technically, invoking this should always produce a working profile * @param directory directory to read the profile from **/ - Profile(const QDir &directory, MOBase::IPluginGame const *gamePlugin); + Profile(const QDir& directory, MOBase::IPluginGame const* gamePlugin); - Profile(const Profile &reference); + Profile(const Profile& reference); ~Profile(); /** - * Determines the default settings for the profile based on the current state of the profile's - * files. This function should remain backwards compatible as much as possible. + * Determines the default settings for the profile based on the current state of the + *profile's files. This function should remain backwards compatible as much as + *possible. **/ void findProfileSettings(void); @@ -103,25 +103,27 @@ public: * @param name of the new profile * @param reference profile to copy from **/ - static Profile *createPtrFrom(const QString &name, const Profile &reference, MOBase::IPluginGame const *gamePlugin); - + static Profile* createPtrFrom(const QString& name, const Profile& reference, + MOBase::IPluginGame const* gamePlugin); static void renameModInAllProfiles(const QString& oldName, const QString& newName); void writeModlist(); - void writeModlistNow(bool onlyIfPending=false); + void writeModlistNow(bool onlyIfPending = false); void cancelModlistWrite(); /** * @brief test if this profile uses archive invalidation * - * @param supported if this is not null, the parameter will be set to false if invalidation is not supported in this profile + * @param supported if this is not null, the parameter will be set to false if + *invalidation is not supported in this profile * @return true if archive invalidation is active - * @note currently, invalidation is not supported if the relevant entry in the ini file does not exist + * @note currently, invalidation is not supported if the relevant entry in the ini + *file does not exist **/ - bool invalidationActive(bool *supported) const; + bool invalidationActive(bool* supported) const; /** * @brief deactivate archive invalidation if it was active @@ -165,7 +167,8 @@ public: /** * @return the path of the plugins file in this profile - * @todo is this required? can the functionality using this function be moved to the Profile-class? + * @todo is this required? can the functionality using this function be moved to the + *Profile-class? **/ QString getPluginsFileName() const; @@ -191,8 +194,8 @@ public: /** * @return the path of the ini file in this profile - * @todo since the game can contain multiple ini files (i.e. skyrim.ini skyrimprefs.ini) - * the concept of this function is somewhat broken + * @todo since the game can contain multiple ini files (i.e. skyrim.ini + *skyrimprefs.ini) the concept of this function is somewhat broken **/ QString getIniFileName() const; @@ -225,7 +228,7 @@ public: * @brief rename profile * @param newName new name of profile */ - void rename(const QString &newName); + void rename(const QString& newName); /** * @brief create the ini file to be used by the game @@ -242,7 +245,8 @@ public: /** * @brief retrieve a list of mods that are enabled in this profile * - * @return list of active mods sorted by priority (ascending). "first" is the mod name, "second" is its path + * @return list of active mods sorted by priority (ascending). "first" is the mod + *name, "second" is its path **/ std::vector<std::tuple<QString, QString, int>> getActiveMods(); @@ -251,7 +255,10 @@ public: * * @return map of indexes by priority **/ - const std::map<int, unsigned int>& getAllIndexesByPriority() { return m_ModIndexByPriority; } + const std::map<int, unsigned int>& getAllIndexesByPriority() + { + return m_ModIndexByPriority; + } /** * retrieve the number of mods for which this object has status information. @@ -278,7 +285,8 @@ public: * @param modsToEnable list of mod indicies to enable * @param modsToDisable list of mod indicies to disable **/ - void setModsEnabled(const QList<unsigned int> &modsToEnable, const QList<unsigned int> &modsToDisable); + void setModsEnabled(const QList<unsigned int>& modsToEnable, + const QList<unsigned int>& modsToDisable); // set the priority of a mod, and the priority of other mods in the range // [old priority, new priority] such that no gaps are possible @@ -311,30 +319,30 @@ public: void dumpModStatus() const; - QVariant setting( - const QString §ion, const QString &name, - const QVariant &fallback={}) const; + QVariant setting(const QString& section, const QString& name, + const QVariant& fallback = {}) const; - void storeSetting( - const QString §ion, const QString &name, const QVariant &value={}); + void storeSetting(const QString& section, const QString& name, + const QVariant& value = {}); - void removeSetting(const QString §ion, const QString &name); + void removeSetting(const QString& section, const QString& name); - QVariantMap settingsByGroup(const QString §ion) const; - void storeSettingsByGroup(const QString §ion, const QVariantMap &values); + QVariantMap settingsByGroup(const QString& section) const; + void storeSettingsByGroup(const QString& section, const QVariantMap& values); - QList<QVariantMap> settingsByArray(const QString &prefix) const; - void storeSettingsByArray(const QString &prefix, const QList<QVariantMap> &values); + QList<QVariantMap> settingsByArray(const QString& prefix) const; + void storeSettingsByArray(const QString& prefix, const QList<QVariantMap>& values); - bool forcedLibrariesEnabled(const QString &executable) const; - void setForcedLibrariesEnabled(const QString &executable, bool enabled); - QList<MOBase::ExecutableForcedLoadSetting> determineForcedLibraries(const QString &executable) const; - void storeForcedLibraries(const QString &executable, const QList<MOBase::ExecutableForcedLoadSetting> &values); - void removeForcedLibraries(const QString &executable); + bool forcedLibrariesEnabled(const QString& executable) const; + void setForcedLibrariesEnabled(const QString& executable, bool enabled); + QList<MOBase::ExecutableForcedLoadSetting> + determineForcedLibraries(const QString& executable) const; + void storeForcedLibraries(const QString& executable, + const QList<MOBase::ExecutableForcedLoadSetting>& values); + void removeForcedLibraries(const QString& executable); void debugDump() const; - Profile& operator=(const Profile& reference) = delete; signals: @@ -355,40 +363,42 @@ signals: protected slots: - // should only be called by DelayedFileWriter, use writeModlist() and writeModlistNow() instead + // should only be called by DelayedFileWriter, use writeModlist() and + // writeModlistNow() instead void doWriteModlist(); private: - - class ModStatus { + class ModStatus + { friend class Profile; + public: ModStatus() : m_Enabled(false), m_Priority(-1) {} + private: bool m_Enabled; int m_Priority; }; private: - void updateIndices(); - void copyFilesTo(QString &target) const; + void copyFilesTo(QString& target) const; - std::vector<std::wstring> splitDZString(const wchar_t *buffer) const; - void mergeTweak(const QString &tweakName, const QString &tweakedIni) const; - void mergeTweaks(ModInfo::Ptr modInfo, const QString &tweakedIni) const; + std::vector<std::wstring> splitDZString(const wchar_t* buffer) const; + void mergeTweak(const QString& tweakName, const QString& tweakedIni) const; + void mergeTweaks(ModInfo::Ptr modInfo, const QString& tweakedIni) const; void touchFile(QString fileName); - static void renameModInList(QFile &modList, const QString &oldName, const QString &newName); + static void renameModInList(QFile& modList, const QString& oldName, + const QString& newName); private: - QDir m_Directory; - QSettings *m_Settings; + QSettings* m_Settings; - const MOBase::IPluginGame *m_GamePlugin; + const MOBase::IPluginGame* m_GamePlugin; std::vector<ModStatus> m_ModStatus; std::map<int, unsigned int> m_ModIndexByPriority; @@ -399,8 +409,6 @@ private: mutable QByteArray m_LastModlistHash; MOBase::DelayedFileWriter m_ModListWriter; - }; - -#endif // PROFILE_H +#endif // PROFILE_H diff --git a/src/profileinputdialog.cpp b/src/profileinputdialog.cpp index bac04586..31155819 100644 --- a/src/profileinputdialog.cpp +++ b/src/profileinputdialog.cpp @@ -18,12 +18,11 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ #include "profileinputdialog.h" -#include "ui_profileinputdialog.h" #include "filesystemutilities.h" +#include "ui_profileinputdialog.h" -ProfileInputDialog::ProfileInputDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::ProfileInputDialog) +ProfileInputDialog::ProfileInputDialog(QWidget* parent) + : QDialog(parent), ui(new Ui::ProfileInputDialog) { ui->setupUi(this); } @@ -40,9 +39,7 @@ QString ProfileInputDialog::getName() const return result; } - bool ProfileInputDialog::getPreferDefaultSettings() const { return ui->defaultSettingsBox->checkState() == Qt::Checked; } - diff --git a/src/profileinputdialog.h b/src/profileinputdialog.h index a114b9b0..d75e11b8 100644 --- a/src/profileinputdialog.h +++ b/src/profileinputdialog.h @@ -22,23 +22,24 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QDialog> -namespace Ui { +namespace Ui +{ class ProfileInputDialog; } class ProfileInputDialog : public QDialog { Q_OBJECT - + public: - explicit ProfileInputDialog(QWidget *parent = 0); + explicit ProfileInputDialog(QWidget* parent = 0); ~ProfileInputDialog(); QString getName() const; bool getPreferDefaultSettings() const; - + private: - Ui::ProfileInputDialog *ui; + Ui::ProfileInputDialog* ui; }; -#endif // PROFILEINPUTDIALOG_H +#endif // PROFILEINPUTDIALOG_H diff --git a/src/profilesdialog.cpp b/src/profilesdialog.cpp index 4abd95ac..674a7780 100644 --- a/src/profilesdialog.cpp +++ b/src/profilesdialog.cpp @@ -20,17 +20,17 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "profilesdialog.h" #include "ui_profilesdialog.h" -#include "shared/appconfig.h" #include "bsainvalidation.h" +#include "filesystemutilities.h" #include "iplugingame.h" +#include "localsavegames.h" #include "organizercore.h" #include "profile.h" #include "profileinputdialog.h" #include "report.h" -#include "transfersavesdialog.h" -#include "filesystemutilities.h" #include "settings.h" -#include "localsavegames.h" +#include "shared/appconfig.h" +#include "transfersavesdialog.h" #include <QDir> #include <QDirIterator> @@ -49,13 +49,10 @@ using namespace MOShared; Q_DECLARE_METATYPE(Profile::Ptr) - -ProfilesDialog::ProfilesDialog(const QString &profileName, OrganizerCore &organizer, QWidget *parent) - : TutorableDialog("Profiles", parent) - , ui(new Ui::ProfilesDialog) - , m_FailState(false) - , m_Game(organizer.managedGame()) - , m_ActiveProfileName("") +ProfilesDialog::ProfilesDialog(const QString& profileName, OrganizerCore& organizer, + QWidget* parent) + : TutorableDialog("Profiles", parent), ui(new Ui::ProfilesDialog), + m_FailState(false), m_Game(organizer.managedGame()), m_ActiveProfileName("") { ui->setupUi(this); @@ -66,28 +63,33 @@ ProfilesDialog::ProfilesDialog(const QString &profileName, OrganizerCore &organi while (profileIter.hasNext()) { profileIter.next(); - QListWidgetItem *item = addItem(profileIter.filePath()); + QListWidgetItem* item = addItem(profileIter.filePath()); if (profileName == profileIter.fileName()) { ui->profilesList->setCurrentItem(item); m_ActiveProfileName = profileName; } } - BSAInvalidation *invalidation = m_Game->feature<BSAInvalidation>(); + BSAInvalidation* invalidation = m_Game->feature<BSAInvalidation>(); if (invalidation == nullptr) { - ui->invalidationBox->setToolTip(tr("Archive invalidation isn't required for this game.")); + ui->invalidationBox->setToolTip( + tr("Archive invalidation isn't required for this game.")); ui->invalidationBox->setEnabled(false); } if (!m_Game->feature<LocalSavegames>()) { - ui->localSavesBox->setToolTip(tr("This game does not support profile-specific game saves.")); + ui->localSavesBox->setToolTip( + tr("This game does not support profile-specific game saves.")); ui->localSavesBox->setEnabled(false); } - connect(this, &ProfilesDialog::profileCreated, &organizer, &OrganizerCore::profileCreated); - connect(this, &ProfilesDialog::profileRenamed, &organizer, &OrganizerCore::profileRenamed); - connect(this, &ProfilesDialog::profileRemoved, &organizer, &OrganizerCore::profileRemoved); + connect(this, &ProfilesDialog::profileCreated, &organizer, + &OrganizerCore::profileCreated); + connect(this, &ProfilesDialog::profileRenamed, &organizer, + &OrganizerCore::profileRenamed); + connect(this, &ProfilesDialog::profileRemoved, &organizer, + &OrganizerCore::profileRemoved); } ProfilesDialog::~ProfilesDialog() @@ -101,7 +103,7 @@ int ProfilesDialog::exec() return QDialog::exec(); } -void ProfilesDialog::showEvent(QShowEvent *event) +void ProfilesDialog::showEvent(QShowEvent* event) { TutorableDialog::showEvent(event); @@ -109,9 +111,12 @@ void ProfilesDialog::showEvent(QShowEvent *event) QPoint pos = ui->profilesList->mapToGlobal(QPoint(0, 0)); pos.rx() += ui->profilesList->width() / 2; pos.ry() += (ui->profilesList->height() / 2) - 20; - QWhatsThis::showText(pos, - QObject::tr("Before you can use ModOrganizer, you need to create at least one profile. " - "ATTENTION: Run the game at least once before creating a profile!"), ui->profilesList); + QWhatsThis::showText( + pos, + QObject::tr( + "Before you can use ModOrganizer, you need to create at least one profile. " + "ATTENTION: Run the game at least once before creating a profile!"), + ui->profilesList); } } @@ -122,9 +127,8 @@ void ProfilesDialog::on_close_clicked() void ProfilesDialog::on_select_clicked() { - const Profile::Ptr currentProfile = ui->profilesList->currentItem() - ->data(Qt::UserRole) - .value<Profile::Ptr>(); + const Profile::Ptr currentProfile = + ui->profilesList->currentItem()->data(Qt::UserRole).value<Profile::Ptr>(); if (!currentProfile) { return; @@ -139,12 +143,14 @@ std::optional<QString> ProfilesDialog::selectedProfile() const return m_Selected; } -QListWidgetItem *ProfilesDialog::addItem(const QString &name) +QListWidgetItem* ProfilesDialog::addItem(const QString& name) { QDir profileDir(name); - QListWidgetItem *newItem = new QListWidgetItem(profileDir.dirName(), ui->profilesList); + QListWidgetItem* newItem = + new QListWidgetItem(profileDir.dirName(), ui->profilesList); try { - newItem->setData(Qt::UserRole, QVariant::fromValue(Profile::Ptr(new Profile(profileDir, m_Game)))); + newItem->setData(Qt::UserRole, QVariant::fromValue( + Profile::Ptr(new Profile(profileDir, m_Game)))); m_FailState = false; } catch (const std::exception& e) { reportError(tr("failed to create profile: %1").arg(e.what())); @@ -152,10 +158,10 @@ QListWidgetItem *ProfilesDialog::addItem(const QString &name) return newItem; } -void ProfilesDialog::createProfile(const QString &name, bool useDefaultSettings) +void ProfilesDialog::createProfile(const QString& name, bool useDefaultSettings) { try { - QListWidgetItem *newItem = new QListWidgetItem(name, ui->profilesList); + QListWidgetItem* newItem = new QListWidgetItem(name, ui->profilesList); auto profile = Profile::Ptr(new Profile(name, m_Game, useDefaultSettings)); newItem->setData(Qt::UserRole, QVariant::fromValue(profile)); ui->profilesList->addItem(newItem); @@ -168,10 +174,10 @@ void ProfilesDialog::createProfile(const QString &name, bool useDefaultSettings) } } -void ProfilesDialog::createProfile(const QString &name, const Profile &reference) +void ProfilesDialog::createProfile(const QString& name, const Profile& reference) { try { - QListWidgetItem *newItem = new QListWidgetItem(name, ui->profilesList); + QListWidgetItem* newItem = new QListWidgetItem(name, ui->profilesList); auto profile = Profile::Ptr(Profile::createPtrFrom(name, reference, m_Game)); newItem->setData(Qt::UserRole, QVariant::fromValue(profile)); ui->profilesList->addItem(newItem); @@ -188,12 +194,12 @@ void ProfilesDialog::on_addProfileButton_clicked() { ProfileInputDialog dialog(this); bool okClicked = dialog.exec(); - QString name = dialog.getName(); + QString name = dialog.getName(); if (okClicked && (name.size() > 0)) { try { createProfile(name, dialog.getPreferDefaultSettings()); - } catch (const std::exception &e) { + } catch (const std::exception& e) { reportError(tr("failed to create profile: %1").arg(e.what())); } } @@ -202,47 +208,53 @@ void ProfilesDialog::on_addProfileButton_clicked() void ProfilesDialog::on_copyProfileButton_clicked() { bool okClicked; - QString name = QInputDialog::getText( - this, tr("Name"), tr("Please enter a name for the new profile"), - QLineEdit::Normal, QString(), &okClicked); + QString name = QInputDialog::getText(this, tr("Name"), + tr("Please enter a name for the new profile"), + QLineEdit::Normal, QString(), &okClicked); fixDirectoryName(name); if (okClicked) { if (name.size() > 0) { try { - const Profile::Ptr currentProfile = ui->profilesList->currentItem() - ->data(Qt::UserRole) - .value<Profile::Ptr>(); + const Profile::Ptr currentProfile = + ui->profilesList->currentItem()->data(Qt::UserRole).value<Profile::Ptr>(); createProfile(name, *currentProfile); - } catch (const std::exception &e) { + } catch (const std::exception& e) { reportError(tr("failed to copy profile: %1").arg(e.what())); } } else { - QMessageBox::warning(this, tr("Invalid name"), - tr("Invalid profile name")); + QMessageBox::warning(this, tr("Invalid name"), tr("Invalid profile name")); } } } void ProfilesDialog::on_removeProfileButton_clicked() { - Profile::Ptr profileToDelete = ui->profilesList->currentItem()->data(Qt::UserRole).value<Profile::Ptr>(); + Profile::Ptr profileToDelete = + ui->profilesList->currentItem()->data(Qt::UserRole).value<Profile::Ptr>(); if (profileToDelete->name() == m_ActiveProfileName) { QMessageBox::warning(this, tr("Deleting active profile"), - tr("Unable to delete active profile. Please change to a different profile first.")); + tr("Unable to delete active profile. Please change to a " + "different profile first.")); return; } - QMessageBox confirmBox(QMessageBox::Question, tr("Confirm"), tr("Are you sure you want to remove this profile (including profile-specific save games, if any)?"), + QMessageBox confirmBox(QMessageBox::Question, tr("Confirm"), + tr("Are you sure you want to remove this profile (including " + "profile-specific save games, if any)?"), QMessageBox::Yes | QMessageBox::No, this); if (confirmBox.exec() == QMessageBox::Yes) { QString profilePath; if (profileToDelete.get() == nullptr) { - profilePath = Settings::instance().paths().profiles() - + "/" + ui->profilesList->currentItem()->text(); - if (QMessageBox::question(this, tr("Profile broken"), - tr("This profile you're about to delete seems to be broken or the path is invalid. " - "I'm about to delete the following folder: \"%1\". Proceed?").arg(profilePath), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) { + profilePath = Settings::instance().paths().profiles() + "/" + + ui->profilesList->currentItem()->text(); + if (QMessageBox::question( + this, tr("Profile broken"), + tr("This profile you're about to delete seems to be broken or the path " + "is invalid. " + "I'm about to delete the following folder: \"%1\". Proceed?") + .arg(profilePath), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) { return; } } else { @@ -255,7 +267,8 @@ void ProfilesDialog::on_removeProfileButton_clicked() delete item; } if (!shellDelete(QStringList(profilePath))) { - log::warn("Failed to shell-delete \"{}\" (errorcode {}), trying regular delete", profilePath, ::GetLastError()); + log::warn("Failed to shell-delete \"{}\" (errorcode {}), trying regular delete", + profilePath, ::GetLastError()); if (!removeDir(profilePath)) { log::warn("regular delete failed too"); } @@ -265,14 +278,15 @@ void ProfilesDialog::on_removeProfileButton_clicked() } } - void ProfilesDialog::on_renameButton_clicked() { - Profile::Ptr currentProfile = ui->profilesList->currentItem()->data(Qt::UserRole).value<Profile::Ptr>(); + Profile::Ptr currentProfile = + ui->profilesList->currentItem()->data(Qt::UserRole).value<Profile::Ptr>(); if (currentProfile->name() == m_ActiveProfileName) { QMessageBox::warning(this, tr("Renaming active profile"), - tr("The active profile cannot be renamed. Please change to a different profile first.")); + tr("The active profile cannot be renamed. Please change to a " + "different profile first.")); return; } @@ -281,10 +295,9 @@ void ProfilesDialog::on_renameButton_clicked() while (!valid) { bool ok = false; - name = QInputDialog::getText(this, tr("Rename Profile"), tr("New Name"), - QLineEdit::Normal, currentProfile->name(), - &ok); - valid = fixDirectoryName(name); + name = QInputDialog::getText(this, tr("Rename Profile"), tr("New Name"), + QLineEdit::Normal, currentProfile->name(), &ok); + valid = fixDirectoryName(name); if (!ok) { return; } @@ -298,10 +311,9 @@ void ProfilesDialog::on_renameButton_clicked() emit profileRenamed(currentProfile.get(), oldName, name); } - void ProfilesDialog::on_invalidationBox_stateChanged(int state) { - QListWidgetItem *currentItem = ui->profilesList->currentItem(); + QListWidgetItem* currentItem = ui->profilesList->currentItem(); if (currentItem == nullptr) { return; } @@ -313,35 +325,39 @@ void ProfilesDialog::on_invalidationBox_stateChanged(int state) if (!currentProfileVariant.isValid() || currentProfileVariant.isNull()) { return; } - const Profile::Ptr currentProfile = currentItem->data(Qt::UserRole).value<Profile::Ptr>(); + const Profile::Ptr currentProfile = + currentItem->data(Qt::UserRole).value<Profile::Ptr>(); if (state == Qt::Unchecked) { currentProfile->deactivateInvalidation(); } else { currentProfile->activateInvalidation(); } - } catch (const std::exception &e) { + } catch (const std::exception& e) { reportError(tr("failed to change archive invalidation state: %1").arg(e.what())); } } - -void ProfilesDialog::on_profilesList_currentItemChanged(QListWidgetItem *current, QListWidgetItem*) +void ProfilesDialog::on_profilesList_currentItemChanged(QListWidgetItem* current, + QListWidgetItem*) { if (current != nullptr) { - if (!current->data(Qt::UserRole).isValid()) return; - const Profile::Ptr currentProfile = current->data(Qt::UserRole).value<Profile::Ptr>(); + if (!current->data(Qt::UserRole).isValid()) + return; + const Profile::Ptr currentProfile = + current->data(Qt::UserRole).value<Profile::Ptr>(); try { bool invalidationSupported = false; ui->invalidationBox->blockSignals(true); - ui->invalidationBox->setChecked(currentProfile->invalidationActive(&invalidationSupported)); + ui->invalidationBox->setChecked( + currentProfile->invalidationActive(&invalidationSupported)); ui->invalidationBox->setEnabled(invalidationSupported); ui->invalidationBox->blockSignals(false); bool localSaves = currentProfile->localSavesEnabled(); ui->transferButton->setEnabled(localSaves); - // prevent the stateChanged-event for the saves-box from triggering, otherwise it may think local saves - // were disabled and delete the files/rename the dir + // prevent the stateChanged-event for the saves-box from triggering, otherwise it + // may think local saves were disabled and delete the files/rename the dir ui->localSavesBox->blockSignals(true); ui->localSavesBox->setChecked(localSaves); ui->localSavesBox->blockSignals(false); @@ -354,7 +370,8 @@ void ProfilesDialog::on_profilesList_currentItemChanged(QListWidgetItem *current ui->localIniFilesBox->setChecked(currentProfile->localSettingsEnabled()); ui->localIniFilesBox->blockSignals(false); } catch (const std::exception& E) { - reportError(tr("failed to determine if invalidation is active: %1").arg(E.what())); + reportError( + tr("failed to determine if invalidation is active: %1").arg(E.what())); ui->copyProfileButton->setEnabled(false); ui->removeProfileButton->setEnabled(false); ui->renameButton->setEnabled(false); @@ -375,7 +392,8 @@ void ProfilesDialog::on_profilesList_itemActivated(QListWidgetItem* item) void ProfilesDialog::on_localSavesBox_stateChanged(int state) { - Profile::Ptr currentProfile = ui->profilesList->currentItem()->data(Qt::UserRole).value<Profile::Ptr>(); + Profile::Ptr currentProfile = + ui->profilesList->currentItem()->data(Qt::UserRole).value<Profile::Ptr>(); if (currentProfile->enableLocalSaves(state == Qt::Checked)) { ui->transferButton->setEnabled(state == Qt::Checked); @@ -387,14 +405,16 @@ void ProfilesDialog::on_localSavesBox_stateChanged(int state) void ProfilesDialog::on_transferButton_clicked() { - const Profile::Ptr currentProfile = ui->profilesList->currentItem()->data(Qt::UserRole).value<Profile::Ptr>(); + const Profile::Ptr currentProfile = + ui->profilesList->currentItem()->data(Qt::UserRole).value<Profile::Ptr>(); TransferSavesDialog transferDialog(*currentProfile, m_Game, this); transferDialog.exec(); } void ProfilesDialog::on_localIniFilesBox_stateChanged(int state) { - Profile::Ptr currentProfile = ui->profilesList->currentItem()->data(Qt::UserRole).value<Profile::Ptr>(); + Profile::Ptr currentProfile = + ui->profilesList->currentItem()->data(Qt::UserRole).value<Profile::Ptr>(); if (!currentProfile->enableLocalSettings(state == Qt::Checked)) { // revert checkbox-state diff --git a/src/profilesdialog.h b/src/profilesdialog.h index 37fedb67..dc8329a2 100644 --- a/src/profilesdialog.h +++ b/src/profilesdialog.h @@ -29,10 +29,15 @@ class QListWidgetItem; #include <QObject> class QString; -namespace Ui { class ProfilesDialog; } - -namespace MOBase { class IPluginGame; } +namespace Ui +{ +class ProfilesDialog; +} +namespace MOBase +{ +class IPluginGame; +} /** * @brief Dialog that can be used to create/delete/modify profiles @@ -42,15 +47,15 @@ class ProfilesDialog : public MOBase::TutorableDialog Q_OBJECT public: - - /** - * @brief constructor - * - * @param profileName currently enabled profile - * @param organizer - * @param parent parent widget - **/ - explicit ProfilesDialog(const QString &profileName, OrganizerCore &organizer, QWidget *parent = 0); + /** + * @brief constructor + * + * @param profileName currently enabled profile + * @param organizer + * @param parent parent widget + **/ + explicit ProfilesDialog(const QString& profileName, OrganizerCore& organizer, + QWidget* parent = 0); ~ProfilesDialog(); // also saves and restores geometry @@ -86,17 +91,15 @@ signals: void profileRemoved(QString const& profileName); protected: - - virtual void showEvent(QShowEvent *event); + virtual void showEvent(QShowEvent* event); private slots: void on_localIniFilesBox_stateChanged(int state); private: - - QListWidgetItem *addItem(const QString &name); - void createProfile(const QString &name, bool useDefaultSettings); - void createProfile(const QString &name, const Profile &reference); + QListWidgetItem* addItem(const QString& name); + void createProfile(const QString& name, bool useDefaultSettings); + void createProfile(const QString& name, const Profile& reference); private slots: @@ -109,7 +112,8 @@ private slots: void on_copyProfileButton_clicked(); - void on_profilesList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous); + void on_profilesList_currentItemChanged(QListWidgetItem* current, + QListWidgetItem* previous); void on_profilesList_itemActivated(QListWidgetItem* item); void on_removeProfileButton_clicked(); @@ -121,12 +125,12 @@ private slots: void on_renameButton_clicked(); private: - Ui::ProfilesDialog *ui; - QListWidget *m_ProfilesList; + Ui::ProfilesDialog* ui; + QListWidget* m_ProfilesList; bool m_FailState; - MOBase::IPluginGame const *m_Game; + MOBase::IPluginGame const* m_Game; QString m_ActiveProfileName; std::optional<QString> m_Selected; }; -#endif // PROFILESDIALOG_H +#endif // PROFILESDIALOG_H diff --git a/src/proxyutils.h b/src/proxyutils.h index 6c85ba14..7aebf315 100644 --- a/src/proxyutils.h +++ b/src/proxyutils.h @@ -5,37 +5,46 @@ #include "organizerproxy.h" -namespace MOShared { +namespace MOShared +{ - template <class Fn, class T = int> - auto callIfPluginActive(OrganizerProxy* proxy, Fn&& callback, T defaultReturn = T{}) { - return [fn = std::forward<Fn>(callback), proxy, defaultReturn](auto&& ...args) { - if (proxy->isPluginEnabled(proxy->plugin())) { - return fn(std::forward<decltype(args)>(args)...); +template <class Fn, class T = int> +auto callIfPluginActive(OrganizerProxy* proxy, Fn&& callback, T defaultReturn = T{}) +{ + return [fn = std::forward<Fn>(callback), proxy, defaultReturn](auto&&... args) { + if (proxy->isPluginEnabled(proxy->plugin())) { + return fn(std::forward<decltype(args)>(args)...); + } else { + if constexpr (!std::is_same_v< + std::invoke_result_t<std::decay_t<Fn>, decltype(args)...>, + void>) { + return defaultReturn; } - else { - if constexpr (!std::is_same_v<std::invoke_result_t<std::decay_t<Fn>, decltype(args)... >, void>) { - return defaultReturn; - } - } - }; - } - - // We need to connect to the organizer. - template <class Signal, class T = int> - auto callSignalIfPluginActive(OrganizerProxy* proxy, const Signal& signal, T defaultReturn = T{}) { - return callIfPluginActive(proxy, [&signal](auto&&... args) { - return signal(std::forward<decltype(args)>(args)...); - }, defaultReturn); - } + } + }; +} - template <class Signal, class T = int> - auto callSignalAlways(const Signal& signal) { - return [&signal](auto&&... args) { - return signal(std::forward<decltype(args)>(args)...); - }; - } +// We need to connect to the organizer. +template <class Signal, class T = int> +auto callSignalIfPluginActive(OrganizerProxy* proxy, const Signal& signal, + T defaultReturn = T{}) +{ + return callIfPluginActive( + proxy, + [&signal](auto&&... args) { + return signal(std::forward<decltype(args)>(args)...); + }, + defaultReturn); +} +template <class Signal, class T = int> +auto callSignalAlways(const Signal& signal) +{ + return [&signal](auto&&... args) { + return signal(std::forward<decltype(args)>(args)...); + }; } +} // namespace MOShared + #endif diff --git a/src/qdirfiletree.cpp b/src/qdirfiletree.cpp index 6fd370bf..f7bb11a7 100644 --- a/src/qdirfiletree.cpp +++ b/src/qdirfiletree.cpp @@ -4,31 +4,51 @@ using namespace MOBase; -class QDirFileTreeImpl : public QDirFileTree { +class QDirFileTreeImpl : public QDirFileTree +{ public: - - QDirFileTreeImpl(std::shared_ptr<const IFileTree> parent, QDir dir) : - FileTreeEntry(parent, dir.dirName()), QDirFileTree(), qDir(dir) { } + QDirFileTreeImpl(std::shared_ptr<const IFileTree> parent, QDir dir) + : FileTreeEntry(parent, dir.dirName()), QDirFileTree(), qDir(dir) + {} protected: - /** * No mutable operations allowed. */ - bool beforeReplace(IFileTree const* dstTree, FileTreeEntry const* destination, FileTreeEntry const* source) override { return false; } - bool beforeInsert(IFileTree const* entry, FileTreeEntry const* name) override { return false; } - bool beforeRemove(IFileTree const* entry, FileTreeEntry const* name) override { return false; } - std::shared_ptr<FileTreeEntry> makeFile(std::shared_ptr<const IFileTree> parent, QString name) const override { return nullptr; } - std::shared_ptr<IFileTree> makeDirectory(std::shared_ptr<const IFileTree> parent, QString name) const override { return nullptr; } + bool beforeReplace(IFileTree const* dstTree, FileTreeEntry const* destination, + FileTreeEntry const* source) override + { + return false; + } + bool beforeInsert(IFileTree const* entry, FileTreeEntry const* name) override + { + return false; + } + bool beforeRemove(IFileTree const* entry, FileTreeEntry const* name) override + { + return false; + } + std::shared_ptr<FileTreeEntry> makeFile(std::shared_ptr<const IFileTree> parent, + QString name) const override + { + return nullptr; + } + std::shared_ptr<IFileTree> makeDirectory(std::shared_ptr<const IFileTree> parent, + QString name) const override + { + return nullptr; + } - bool doPopulate(std::shared_ptr<const IFileTree> parent, std::vector<std::shared_ptr<FileTreeEntry>>& entries) const override + bool doPopulate(std::shared_ptr<const IFileTree> parent, + std::vector<std::shared_ptr<FileTreeEntry>>& entries) const override { - auto infoList = qDir.entryInfoList(qDir.filter() | QDir::NoDotAndDotDot, QDir::Name | QDir::DirsFirst | QDir::IgnoreCase); + auto infoList = qDir.entryInfoList(qDir.filter() | QDir::NoDotAndDotDot, + QDir::Name | QDir::DirsFirst | QDir::IgnoreCase); for (auto& info : infoList) { if (info.isDir()) { - entries.push_back(std::make_shared<QDirFileTreeImpl>(parent, QDir(info.absoluteFilePath()))); - } - else { + entries.push_back( + std::make_shared<QDirFileTreeImpl>(parent, QDir(info.absoluteFilePath()))); + } else { entries.push_back(createFileEntry(parent, info.fileName())); } } @@ -44,28 +64,29 @@ protected: protected: QDir qDir; - }; // subclass of QDirFileTreeImpl that ignores meta.ini // // only used for the root folder, subdirectories are actually QDirFileTreeImpl -class QDirRootFileTreeImpl : public QDirFileTreeImpl { +class QDirRootFileTreeImpl : public QDirFileTreeImpl +{ public: - - - QDirRootFileTreeImpl(QDir dir) : FileTreeEntry(nullptr, dir.dirName()), QDirFileTreeImpl(nullptr, dir) { } + QDirRootFileTreeImpl(QDir dir) + : FileTreeEntry(nullptr, dir.dirName()), QDirFileTreeImpl(nullptr, dir) + {} protected: - - bool doPopulate(std::shared_ptr<const IFileTree> parent, std::vector<std::shared_ptr<FileTreeEntry>>& entries) const override + bool doPopulate(std::shared_ptr<const IFileTree> parent, + std::vector<std::shared_ptr<FileTreeEntry>>& entries) const override { - auto infoList = qDir.entryInfoList(qDir.filter() | QDir::NoDotAndDotDot, QDir::Name | QDir::DirsFirst | QDir::IgnoreCase); + auto infoList = qDir.entryInfoList(qDir.filter() | QDir::NoDotAndDotDot, + QDir::Name | QDir::DirsFirst | QDir::IgnoreCase); for (auto& info : infoList) { if (info.isDir()) { - entries.push_back(std::make_shared<QDirFileTreeImpl>(parent, QDir(info.absoluteFilePath()))); - } - else if (info.fileName().compare("meta.ini", Qt::CaseInsensitive) != 0) { + entries.push_back( + std::make_shared<QDirFileTreeImpl>(parent, QDir(info.absoluteFilePath()))); + } else if (info.fileName().compare("meta.ini", Qt::CaseInsensitive) != 0) { entries.push_back(createFileEntry(parent, info.fileName())); } } @@ -78,18 +99,17 @@ protected: { return std::make_shared<QDirRootFileTreeImpl>(qDir); } - }; /** * */ -std::shared_ptr<const QDirFileTree> QDirFileTree::makeTree(QDir directory, bool ignoreRootMeta) +std::shared_ptr<const QDirFileTree> QDirFileTree::makeTree(QDir directory, + bool ignoreRootMeta) { if (ignoreRootMeta) { return std::make_shared<QDirRootFileTreeImpl>(directory); - } - else { + } else { return std::make_shared<QDirFileTreeImpl>(nullptr, directory); } } diff --git a/src/qdirfiletree.h b/src/qdirfiletree.h index e9229bf5..1b3f7294 100644 --- a/src/qdirfiletree.h +++ b/src/qdirfiletree.h @@ -24,19 +24,19 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "ifiletree.h" - /** - * @brief Class that expose a directory on the drive, using QDir, as a `MOBase::IFileTree`. + * @brief Class that expose a directory on the drive, using QDir, as a + * `MOBase::IFileTree`. * - * The tree is lazily populated: each subtree is only populated (from the disk) when needed, - * as specified by IFileTree. + * The tree is lazily populated: each subtree is only populated (from the disk) when + * needed, as specified by IFileTree. * * This class does not expose mutable operations, so any mutable operations will * fail. */ -class QDirFileTree : public MOBase::IFileTree { +class QDirFileTree : public MOBase::IFileTree +{ public: - /** * @brief Create a new file tree representing the given directory. * @@ -46,13 +46,15 @@ public: * * @return a file tree representing the given directory. */ - static std::shared_ptr<const QDirFileTree> makeTree(QDir directory, bool ignoreRootMeta = true); + static std::shared_ptr<const QDirFileTree> makeTree(QDir directory, + bool ignoreRootMeta = true); protected: - using IFileTree::IFileTree; - virtual bool doPopulate(std::shared_ptr<const IFileTree> parent, std::vector<std::shared_ptr<FileTreeEntry>>& entries) const = 0; + virtual bool + doPopulate(std::shared_ptr<const IFileTree> parent, + std::vector<std::shared_ptr<FileTreeEntry>>& entries) const = 0; }; #endif diff --git a/src/qtgroupingproxy.cpp b/src/qtgroupingproxy.cpp index bfbf955c..54f8b66e 100644 --- a/src/qtgroupingproxy.cpp +++ b/src/qtgroupingproxy.cpp @@ -1,22 +1,21 @@ /**************************************************************************************** - * Copyright (c) 2007-2011 Bart Cerneels <bart.cerneels@kde.org> * + * Copyright (c) 2007-2011 Bart Cerneels <bart.cerneels@kde.org> * * * - * 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; either version 2 of the License, or (at your option) any later * - * version. * + * 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; either version 2 of the License, or (at your option) any later * version. + ** * * - * 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. * + * 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 <http://www.gnu.org/licenses/>. * + * You should have received a copy of the GNU General Public License along with * this + *program. If not, see <http://www.gnu.org/licenses/>. * ****************************************************************************************/ // Modifications 2013-03-27 to 2013-03-29 by Sebastian Herbord - #include "qtgroupingproxy.h" #include <log.h> @@ -28,28 +27,22 @@ using namespace MOBase; /*! \class QtGroupingProxy - \brief The QtGroupingProxy class will group source model rows by adding a new top tree-level. - The source model can be flat or tree organized, but only the original top level rows are used - for determining the grouping. - \ingroup model-view + \brief The QtGroupingProxy class will group source model rows by adding a new top + tree-level. The source model can be flat or tree organized, but only the original top + level rows are used for determining the grouping. \ingroup model-view */ -QtGroupingProxy::QtGroupingProxy(QModelIndex rootNode, int groupedColumn, int groupedRole, unsigned int flags, int aggregateRole) - : QAbstractProxyModel() - , m_rootNode(rootNode) - , m_groupedColumn(0) - , m_groupedRole(groupedRole) - , m_aggregateRole(aggregateRole) - , m_flags(flags) +QtGroupingProxy::QtGroupingProxy(QModelIndex rootNode, int groupedColumn, + int groupedRole, unsigned int flags, int aggregateRole) + : QAbstractProxyModel(), m_rootNode(rootNode), m_groupedColumn(0), + m_groupedRole(groupedRole), m_aggregateRole(aggregateRole), m_flags(flags) { if (groupedColumn != -1) { setGroupedColumn(groupedColumn); } } -QtGroupingProxy::~QtGroupingProxy() -{ -} +QtGroupingProxy::~QtGroupingProxy() {} void QtGroupingProxy::setSourceModel(QAbstractItemModel* model) { @@ -62,45 +55,44 @@ void QtGroupingProxy::setSourceModel(QAbstractItemModel* model) if (sourceModel()) { // signal proxies connect(sourceModel(), SIGNAL(rowsInserted(const QModelIndex&, int, int)), - SLOT(modelRowsInserted(const QModelIndex&, int, int))); + SLOT(modelRowsInserted(const QModelIndex&, int, int))); connect(sourceModel(), SIGNAL(rowsAboutToBeInserted(const QModelIndex&, int, int)), - SLOT(modelRowsAboutToBeInserted(const QModelIndex&, int, int))); + SLOT(modelRowsAboutToBeInserted(const QModelIndex&, int, int))); connect(sourceModel(), SIGNAL(rowsRemoved(const QModelIndex&, int, int)), - SLOT(modelRowsRemoved(const QModelIndex&, int, int))); + SLOT(modelRowsRemoved(const QModelIndex&, int, int))); connect(sourceModel(), SIGNAL(rowsAboutToBeRemoved(const QModelIndex&, int, int)), - SLOT(modelRowsAboutToBeRemoved(QModelIndex, int, int))); + SLOT(modelRowsAboutToBeRemoved(QModelIndex, int, int))); connect(sourceModel(), SIGNAL(layoutChanged()), SLOT(buildTree())); connect(sourceModel(), SIGNAL(dataChanged(QModelIndex, QModelIndex)), - SLOT(modelDataChanged(QModelIndex, QModelIndex))); + SLOT(modelDataChanged(QModelIndex, QModelIndex))); connect(sourceModel(), SIGNAL(modelReset()), this, SLOT(resetModel())); buildTree(); } } -void -QtGroupingProxy::setGroupedColumn( int groupedColumn ) +void QtGroupingProxy::setGroupedColumn(int groupedColumn) { m_groupedColumn = groupedColumn; buildTree(); } /** Maps to what groups the source row belongs by returning the data of those groups. - * - * @returns a list of data for the rows the argument belongs to. In common cases this list will - * contain only one entry. An empty list means that the source item will be placed in the root of - * this proxyModel. There is no support for hiding source items. - * - * Group data can be pre-loaded in the return value so it's added to the cache maintained by this - * class. This is required if you want to have data that is not present in the source model. - */ -QList<RowData> -QtGroupingProxy::belongsTo( const QModelIndex &idx ) + * + * @returns a list of data for the rows the argument belongs to. In common cases this + * list will contain only one entry. An empty list means that the source item will be + * placed in the root of this proxyModel. There is no support for hiding source items. + * + * Group data can be pre-loaded in the return value so it's added to the cache + * maintained by this class. This is required if you want to have data that is not + * present in the source model. + */ +QList<RowData> QtGroupingProxy::belongsTo(const QModelIndex& idx) { QList<RowData> rowDataList; - //get all the data for this index from the model - ItemData itemData = sourceModel()->itemData( idx ); + // get all the data for this index from the model + ItemData itemData = sourceModel()->itemData(idx); if (m_groupedRole != Qt::DisplayRole) { itemData[Qt::DisplayRole] = itemData[m_groupedRole]; } @@ -110,40 +102,34 @@ QtGroupingProxy::belongsTo( const QModelIndex &idx ) return rowDataList; } - QMapIterator<int, QVariant> i( itemData ); - while( i.hasNext() ) - { + QMapIterator<int, QVariant> i(itemData); + while (i.hasNext()) { i.next(); - int role = i.key(); + int role = i.key(); QVariant variant = i.value(); - if ( variant.type() == QVariant::List ) - { - //a list of variants get's expanded to multiple rows + if (variant.type() == QVariant::List) { + // a list of variants get's expanded to multiple rows QVariantList list = variant.toList(); - for( int i = 0; i < list.length(); i++ ) - { - //take an existing row data or create a new one - RowData rowData = (rowDataList.count() > i) ? rowDataList.takeAt( i ) - : RowData(); + for (int i = 0; i < list.length(); i++) { + // take an existing row data or create a new one + RowData rowData = (rowDataList.count() > i) ? rowDataList.takeAt(i) : RowData(); - //we only gather data for the first column - ItemData indexData = rowData.contains( 0 ) ? rowData.take( 0 ) : ItemData(); - indexData.insert( role, list.value( i ) ); - rowData.insert( 0, indexData ); - //for the grouped column the data should not be gathered from the children - //this will allow filtering on the content of this column with a - //QSortFilterProxyModel - rowData.insert( m_groupedColumn, indexData ); - rowDataList.insert( i, rowData ); + // we only gather data for the first column + ItemData indexData = rowData.contains(0) ? rowData.take(0) : ItemData(); + indexData.insert(role, list.value(i)); + rowData.insert(0, indexData); + // for the grouped column the data should not be gathered from the children + // this will allow filtering on the content of this column with a + // QSortFilterProxyModel + rowData.insert(m_groupedColumn, indexData); + rowDataList.insert(i, rowData); } break; - } - else if( !variant.isNull() ) - { - //it's just a normal item. Copy all the data and break this loop. + } else if (!variant.isNull()) { + // it's just a normal item. Copy all the data and break this loop. RowData rowData; - rowData.insert( 0, itemData ); + rowData.insert(0, itemData); rowDataList << rowData; break; } @@ -153,47 +139,45 @@ QtGroupingProxy::belongsTo( const QModelIndex &idx ) } /* m_groupMap layout -* key : index of the group in m_groupMaps -* value : a QList of the original rows in sourceModel() for the children of this group -* -* key = -1 contains a QList of the non-grouped indexes -* -* TODO: sub-groups -*/ -void -QtGroupingProxy::buildTree() + * key : index of the group in m_groupMaps + * value : a QList of the original rows in sourceModel() for the children of this group + * + * key = -1 contains a QList of the non-grouped indexes + * + * TODO: sub-groups + */ +void QtGroupingProxy::buildTree() { - if( !sourceModel() ) + if (!sourceModel()) return; beginResetModel(); m_groupMap.clear(); - //don't clear the data maps since most of it will probably be needed again. + // don't clear the data maps since most of it will probably be needed again. m_parentCreateList.clear(); - int max = sourceModel()->rowCount( m_rootNode ); + int max = sourceModel()->rowCount(m_rootNode); - //WARNING: these have to be added in order because the addToGroups function is optimized for - //modelRowsInserted(). Failure to do so will result in wrong data shown in the view at best. - for( int row = 0; row < max; row++ ) - { - QModelIndex idx = sourceModel()->index( row, m_groupedColumn, m_rootNode ); - addSourceRow( idx ); + // WARNING: these have to be added in order because the addToGroups function is + // optimized for modelRowsInserted(). Failure to do so will result in wrong data shown + // in the view at best. + for (int row = 0; row < max; row++) { + QModelIndex idx = sourceModel()->index(row, m_groupedColumn, m_rootNode); + addSourceRow(idx); } - //dumpGroups(); + // dumpGroups(); if (m_flags & FLAG_NOSINGLE) { // awkward: flatten single-item groups as a post-processing steps. - int currentKey = 0; + int currentKey = 0; quint32 quint32max = std::numeric_limits<quint32>::max(); std::vector<int> rmgroups; - QMap<quint32, QList<int> > temp; + QMap<quint32, QList<int>> temp; for (auto iter = m_groupMap.begin(); iter != m_groupMap.end(); ++iter) { - if ((iter.key() == quint32max) || - (iter->count() < 2)) { + if ((iter.key() == quint32max) || (iter->count() < 2)) { temp[quint32max].append(iter.value()); if (iter.key() != quint32max) { rmgroups.push_back(iter.key()); @@ -204,9 +188,11 @@ QtGroupingProxy::buildTree() } m_groupMap = temp; - // second loop is necessary because qt containers can't be iterated from end to front - // and removing by index from begin to end is ugly - std::sort(rmgroups.begin(), rmgroups.end(), [] (int lhs, int rhs) { return rhs < lhs; }); + // second loop is necessary because qt containers can't be iterated from end to + // front and removing by index from begin to end is ugly + std::sort(rmgroups.begin(), rmgroups.end(), [](int lhs, int rhs) { + return rhs < lhs; + }); for (auto iter = rmgroups.begin(); iter != rmgroups.end(); ++iter) { m_groupMaps.removeAt(*iter); } @@ -215,78 +201,66 @@ QtGroupingProxy::buildTree() endResetModel(); } -QList<int> -QtGroupingProxy::addSourceRow( const QModelIndex &idx ) +QList<int> QtGroupingProxy::addSourceRow(const QModelIndex& idx) { QList<int> updatedGroups; - QList<RowData> groupData = belongsTo( idx ); + QList<RowData> groupData = belongsTo(idx); - //an empty list here means it's supposed to go in root. - if( groupData.isEmpty() ) - { + // an empty list here means it's supposed to go in root. + if (groupData.isEmpty()) { updatedGroups << -1; - if( !m_groupMap.keys().contains( std::numeric_limits<quint32>::max() ) ) - m_groupMap.insert( std::numeric_limits<quint32>::max(), QList<int>() ); //add an empty placeholder + if (!m_groupMap.keys().contains(std::numeric_limits<quint32>::max())) + m_groupMap.insert(std::numeric_limits<quint32>::max(), + QList<int>()); // add an empty placeholder } - //an item can be in multiple groups - foreach( RowData data, groupData ) - { + // an item can be in multiple groups + foreach (RowData data, groupData) { int updatedGroup = -1; - if( !data.isEmpty() ) - { - foreach( const RowData &cachedData, m_groupMaps ) - { - //when this matches the index belongs to an existing group - if( data[0][Qt::DisplayRole] == cachedData[0][Qt::DisplayRole] ) - { + if (!data.isEmpty()) { + foreach (const RowData& cachedData, m_groupMaps) { + // when this matches the index belongs to an existing group + if (data[0][Qt::DisplayRole] == cachedData[0][Qt::DisplayRole]) { data = cachedData; break; } } - updatedGroup = m_groupMaps.indexOf( data ); + updatedGroup = m_groupMaps.indexOf(data); //-1 means not found - if( updatedGroup == -1 ) - { - //new groups are added to the end of the existing list + if (updatedGroup == -1) { + // new groups are added to the end of the existing list m_groupMaps << data; updatedGroup = m_groupMaps.count() - 1; } - if( !m_groupMap.keys().contains( updatedGroup ) ) - m_groupMap.insert( updatedGroup, QList<int>() ); //add an empty placeholder + if (!m_groupMap.keys().contains(updatedGroup)) + m_groupMap.insert(updatedGroup, QList<int>()); // add an empty placeholder } - if( !updatedGroups.contains( updatedGroup ) ) + if (!updatedGroups.contains(updatedGroup)) updatedGroups << updatedGroup; } - //update m_groupMap to the new source-model layout (one row added) - QMutableMapIterator<quint32, QList<int> > i( m_groupMap ); - while( i.hasNext() ) - { + // update m_groupMap to the new source-model layout (one row added) + QMutableMapIterator<quint32, QList<int>> i(m_groupMap); + while (i.hasNext()) { i.next(); - QList<int> &groupList = i.value(); - int insertedProxyRow = groupList.count(); - for( ; insertedProxyRow > 0 ; insertedProxyRow-- ) - { - int &rowValue = groupList[insertedProxyRow-1]; - if( idx.row() <= rowValue ) - { - //increment the rows that come after the new row since they moved one place up. + QList<int>& groupList = i.value(); + int insertedProxyRow = groupList.count(); + for (; insertedProxyRow > 0; insertedProxyRow--) { + int& rowValue = groupList[insertedProxyRow - 1]; + if (idx.row() <= rowValue) { + // increment the rows that come after the new row since they moved one place up. rowValue++; - } - else - { + } else { break; } } - if( updatedGroups.contains( i.key() ) ) - { - //the row needs to be added to this group - groupList.insert( insertedProxyRow, idx.row() ); + if (updatedGroups.contains(i.key())) { + // the row needs to be added to this group + groupList.insert(insertedProxyRow, idx.row()); } } @@ -294,103 +268,95 @@ QtGroupingProxy::addSourceRow( const QModelIndex &idx ) } /** Each ModelIndex has in it's internalId a position in the parentCreateList. - * struct ParentCreate are the instructions to recreate the parent index. - * It contains the proxy row number of the parent and the postion in this list of the grandfather. - * This function creates the ParentCreate structs and saves them in a list. - */ -int -QtGroupingProxy::indexOfParentCreate( const QModelIndex &parent ) const + * struct ParentCreate are the instructions to recreate the parent index. + * It contains the proxy row number of the parent and the postion in this list of the + * grandfather. This function creates the ParentCreate structs and saves them in a list. + */ +int QtGroupingProxy::indexOfParentCreate(const QModelIndex& parent) const { - if( !parent.isValid() ) + if (!parent.isValid()) return -1; struct ParentCreate pc; - for( int i = 0 ; i < m_parentCreateList.size() ; i++ ) - { + for (int i = 0; i < m_parentCreateList.size(); i++) { pc = m_parentCreateList[i]; - if( pc.parentCreateIndex == parent.internalId() && pc.row == parent.row() ) + if (pc.parentCreateIndex == parent.internalId() && pc.row == parent.row()) return i; } - //there is no parentCreate yet for this index, so let's create one. + // there is no parentCreate yet for this index, so let's create one. pc.parentCreateIndex = parent.internalId(); - pc.row = parent.row(); + pc.row = parent.row(); m_parentCreateList << pc; return m_parentCreateList.size() - 1; } -QModelIndex -QtGroupingProxy::index( int row, int column, const QModelIndex &parent ) const +QModelIndex QtGroupingProxy::index(int row, int column, const QModelIndex& parent) const { - if( !hasIndex(row, column, parent) ) { + if (!hasIndex(row, column, parent)) { return QModelIndex(); } - if( parent.column() > 0 ) { + if (parent.column() > 0) { return QModelIndex(); } /* We save the instructions to make the parent of the index in a struct. - * The place of the struct in the list is stored in the internalId - */ - int parentCreateIndex = indexOfParentCreate( parent ); + * The place of the struct in the list is stored in the internalId + */ + int parentCreateIndex = indexOfParentCreate(parent); - return createIndex( row, column, parentCreateIndex ); + return createIndex(row, column, parentCreateIndex); } -QModelIndex -QtGroupingProxy::parent( const QModelIndex &index ) const +QModelIndex QtGroupingProxy::parent(const QModelIndex& index) const { - if( !index.isValid() ) + if (!index.isValid()) return QModelIndex(); int parentCreateIndex = index.internalId(); - if( parentCreateIndex == -1 || parentCreateIndex >= m_parentCreateList.count() ) + if (parentCreateIndex == -1 || parentCreateIndex >= m_parentCreateList.count()) return QModelIndex(); struct ParentCreate pc = m_parentCreateList[parentCreateIndex]; - //only items at column 0 have children - return createIndex( pc.row, 0, pc.parentCreateIndex ); + // only items at column 0 have children + return createIndex(pc.row, 0, pc.parentCreateIndex); } -int -QtGroupingProxy::rowCount( const QModelIndex &index ) const +int QtGroupingProxy::rowCount(const QModelIndex& index) const { - if( !index.isValid() ) - { - //the number of top level groups + the number of non-grouped items - int rows = m_groupMaps.count() + m_groupMap.value( std::numeric_limits<quint32>::max() ).count(); + if (!index.isValid()) { + // the number of top level groups + the number of non-grouped items + int rows = m_groupMaps.count() + + m_groupMap.value(std::numeric_limits<quint32>::max()).count(); return rows; } - //TODO:group in group support. - if( isGroup( index ) ) - { + // TODO:group in group support. + if (isGroup(index)) { qint64 groupIndex = index.row(); - int rows = m_groupMap.value( groupIndex ).count(); + int rows = m_groupMap.value(groupIndex).count(); return rows; } else { - QModelIndex originalIndex = mapToSource( index ); - int rowCount = sourceModel()->rowCount( originalIndex ); + QModelIndex originalIndex = mapToSource(index); + int rowCount = sourceModel()->rowCount(originalIndex); return rowCount; } } -int -QtGroupingProxy::columnCount( const QModelIndex &index ) const +int QtGroupingProxy::columnCount(const QModelIndex& index) const { - if( !index.isValid() ) - return sourceModel()->columnCount( m_rootNode ); + if (!index.isValid()) + return sourceModel()->columnCount(m_rootNode); - if( index.column() != 0 ) + if (index.column() != 0) return 0; - return sourceModel()->columnCount( mapToSource( index ) ); + return sourceModel()->columnCount(mapToSource(index)); } - -static bool variantLess(const QVariant &LHS, const QVariant &RHS) +static bool variantLess(const QVariant& LHS, const QVariant& RHS) { if ((LHS.type() == RHS.type()) && ((LHS.type() == QVariant::Int) || (LHS.type() == QVariant::UInt))) { @@ -402,11 +368,10 @@ static bool variantLess(const QVariant &LHS, const QVariant &RHS) return LHS.toString() < RHS.toString(); } - -static QVariant variantMax(const QVariantList &variants) +static QVariant variantMax(const QVariantList& variants) { QVariant result = variants.first(); - foreach (const QVariant &iter, variants) { + foreach (const QVariant& iter, variants) { if (variantLess(result, iter)) { result = iter; } @@ -414,11 +379,10 @@ static QVariant variantMax(const QVariantList &variants) return result; } - -static QVariant variantMin(const QVariantList &variants) +static QVariant variantMin(const QVariantList& variants) { QVariant result = variants.first(); - foreach (const QVariant &iter, variants) { + foreach (const QVariant& iter, variants) { if (variantLess(iter, result)) { result = iter; } @@ -426,425 +390,396 @@ static QVariant variantMin(const QVariantList &variants) return result; } - -QVariant -QtGroupingProxy::data( const QModelIndex &index, int role ) const +QVariant QtGroupingProxy::data(const QModelIndex& index, int role) const { - if( !index.isValid() ) + if (!index.isValid()) return QVariant(); - int row = index.row(); + int row = index.row(); int column = index.column(); - if( isGroup( index ) ) - { + if (isGroup(index)) { if ((role != Qt::DisplayRole) && (role != Qt::EditRole)) { switch (role) { - case Qt::ForegroundRole: { - return QBrush(Qt::gray); - } break; - case Qt::FontRole: { - QFont font(m_groupMaps[row][column].value(Qt::FontRole).value<QFont>()); - font.setItalic(true); - return font; - } break; - case Qt::TextAlignmentRole: { - return Qt::AlignHCenter; - } break; - case Qt::UserRole: { - return m_groupMaps[row][column].value( Qt::DisplayRole ).toString(); - } break; - case Qt::CheckStateRole: { - if (column != 0) return QVariant(); - int childCount = m_groupMap.value( row ).count(); - int checked = 0; - QModelIndex parentIndex = this->index( row, 0, index.parent() ); - for( int childRow = 0; childRow < childCount; ++childRow ) - { - QModelIndex childIndex = this->index( childRow, 0, parentIndex ); - QVariant data = mapToSource( childIndex ).data( Qt::CheckStateRole ); - if (data.toInt() == 2) ++checked; - } - if (checked == childCount) return Qt::Checked; - else if (checked == 0) return Qt::Unchecked; - else return Qt::PartiallyChecked; - } break; - default: { - QModelIndex parentIndex = this->index( row, 0, index.parent() ); - if (m_groupMap.value( row ).count() > 0) { - return this->index(0, column, parentIndex).data(role); - } else { - return QVariant(); - } - // return m_groupMaps[row][column].value( role ); - } break; + case Qt::ForegroundRole: { + return QBrush(Qt::gray); + } break; + case Qt::FontRole: { + QFont font(m_groupMaps[row][column].value(Qt::FontRole).value<QFont>()); + font.setItalic(true); + return font; + } break; + case Qt::TextAlignmentRole: { + return Qt::AlignHCenter; + } break; + case Qt::UserRole: { + return m_groupMaps[row][column].value(Qt::DisplayRole).toString(); + } break; + case Qt::CheckStateRole: { + if (column != 0) + return QVariant(); + int childCount = m_groupMap.value(row).count(); + int checked = 0; + QModelIndex parentIndex = this->index(row, 0, index.parent()); + for (int childRow = 0; childRow < childCount; ++childRow) { + QModelIndex childIndex = this->index(childRow, 0, parentIndex); + QVariant data = mapToSource(childIndex).data(Qt::CheckStateRole); + if (data.toInt() == 2) + ++checked; + } + if (checked == childCount) + return Qt::Checked; + else if (checked == 0) + return Qt::Unchecked; + else + return Qt::PartiallyChecked; + } break; + default: { + QModelIndex parentIndex = this->index(row, 0, index.parent()); + if (m_groupMap.value(row).count() > 0) { + return this->index(0, column, parentIndex).data(role); + } else { + return QVariant(); + } + // return m_groupMaps[row][column].value( role ); + } break; } } - //use cached or precalculated data - if( m_groupMaps[row][column].contains( Qt::DisplayRole ) ) - { + // use cached or precalculated data + if (m_groupMaps[row][column].contains(Qt::DisplayRole)) { if ((m_flags & FLAG_NOGROUPNAME) != 0) { - QModelIndex parentIndex = this->index( row, 0, index.parent() ); - QModelIndex childIndex = this->index( 0, column, parentIndex ); + QModelIndex parentIndex = this->index(row, 0, index.parent()); + QModelIndex childIndex = this->index(0, column, parentIndex); return childIndex.data(role).toString(); } else { - return m_groupMaps[row][column].value( role ).toString(); + return m_groupMaps[row][column].value(role).toString(); } } - //for column 0 we gather data from the grouped column instead - if( column == 0 ) + // for column 0 we gather data from the grouped column instead + if (column == 0) column = m_groupedColumn; - //map all data from children to columns of group to allow grouping one level up + // map all data from children to columns of group to allow grouping one level up QVariantList variantsOfChildren; - int childCount = m_groupMap.value( row ).count(); - if( childCount == 0 ) + int childCount = m_groupMap.value(row).count(); + if (childCount == 0) return QVariant(); int function = AGGR_NONE; if (m_aggregateRole >= Qt::UserRole) { - QModelIndex parentIndex = this->index( row, 0, index.parent() ); - QModelIndex childIndex = this->index( 0, column, parentIndex ); - function = mapToSource(childIndex).data(m_aggregateRole).toInt(); + QModelIndex parentIndex = this->index(row, 0, index.parent()); + QModelIndex childIndex = this->index(0, column, parentIndex); + function = mapToSource(childIndex).data(m_aggregateRole).toInt(); } - //Need a parentIndex with column == 0 because only those have children. - QModelIndex parentIndex = this->index( row, 0, index.parent() ); - for( int childRow = 0; childRow < childCount; childRow++ ) - { - QModelIndex childIndex = this->index( childRow, column, parentIndex ); - QVariant data = mapToSource( childIndex ).data( role ); + // Need a parentIndex with column == 0 because only those have children. + QModelIndex parentIndex = this->index(row, 0, index.parent()); + for (int childRow = 0; childRow < childCount; childRow++) { + QModelIndex childIndex = this->index(childRow, column, parentIndex); + QVariant data = mapToSource(childIndex).data(role); - if( data.isValid() && !variantsOfChildren.contains( data ) ) + if (data.isValid() && !variantsOfChildren.contains(data)) variantsOfChildren << data; } - //saving in cache - ItemData roleMap = m_groupMaps[row].value( column ); - foreach( const QVariant &variant, variantsOfChildren ) - { - if( roleMap[ role ] != variant ) { - roleMap.insert( role, variantsOfChildren ); + // saving in cache + ItemData roleMap = m_groupMaps[row].value(column); + foreach (const QVariant& variant, variantsOfChildren) { + if (roleMap[role] != variant) { + roleMap.insert(role, variantsOfChildren); } } - if( variantsOfChildren.count() == 0 ) + if (variantsOfChildren.count() == 0) return QVariant(); - //only one unique variant? No need to return a list + // only one unique variant? No need to return a list switch (function) { - case AGGR_EMPTY: return QVariant(); - case AGGR_FIRST: return variantsOfChildren.first(); - case AGGR_MAX: return variantMax(variantsOfChildren); - case AGGR_MIN: return variantMin(variantsOfChildren); - default: { - if( variantsOfChildren.count() == 1 ) - return variantsOfChildren.first(); + case AGGR_EMPTY: + return QVariant(); + case AGGR_FIRST: + return variantsOfChildren.first(); + case AGGR_MAX: + return variantMax(variantsOfChildren); + case AGGR_MIN: + return variantMin(variantsOfChildren); + default: { + if (variantsOfChildren.count() == 1) + return variantsOfChildren.first(); - return variantsOfChildren; - } break; + return variantsOfChildren; + } break; } } - return mapToSource( index ).data( role ); + return mapToSource(index).data(role); } -bool -QtGroupingProxy::setData( const QModelIndex &idx, const QVariant &value, int role ) +bool QtGroupingProxy::setData(const QModelIndex& idx, const QVariant& value, int role) { - if( !idx.isValid() ) + if (!idx.isValid()) return false; - //no need to set data to exactly the same value - if( idx.data( role ) == value ) + // no need to set data to exactly the same value + if (idx.data(role) == value) return false; - if( isGroup( idx ) ) - { + if (isGroup(idx)) { ItemData columnData = m_groupMaps[idx.row()][idx.column()]; - columnData.insert( role, value ); - //QItemDelegate will always use Qt::EditRole - if( role == Qt::EditRole ) - columnData.insert( Qt::DisplayRole, value ); + columnData.insert(role, value); + // QItemDelegate will always use Qt::EditRole + if (role == Qt::EditRole) + columnData.insert(Qt::DisplayRole, value); - //and make sure it's stored in the map - m_groupMaps[idx.row()].insert( idx.column(), columnData ); + // and make sure it's stored in the map + m_groupMaps[idx.row()].insert(idx.column(), columnData); int columnToChange = idx.column() ? idx.column() : m_groupedColumn; - foreach( int originalRow, m_groupMap.value( idx.row() ) ) - { - QModelIndex childIdx = sourceModel()->index( originalRow, columnToChange, - m_rootNode ); - if( childIdx.isValid() ) - sourceModel()->setData( childIdx, value, role ); + foreach (int originalRow, m_groupMap.value(idx.row())) { + QModelIndex childIdx = + sourceModel()->index(originalRow, columnToChange, m_rootNode); + if (childIdx.isValid()) + sourceModel()->setData(childIdx, value, role); } - //TODO: we might need to reload the data from the children at this point + // TODO: we might need to reload the data from the children at this point - emit dataChanged( idx, idx ); + emit dataChanged(idx, idx); return true; } - return sourceModel()->setData( mapToSource( idx ), value, role ); + return sourceModel()->setData(mapToSource(idx), value, role); } -bool -QtGroupingProxy::isGroup( const QModelIndex &index ) const +bool QtGroupingProxy::isGroup(const QModelIndex& index) const { int parentCreateIndex = index.internalId(); - if( parentCreateIndex == -1 && index.row() < m_groupMaps.count() ) + if (parentCreateIndex == -1 && index.row() < m_groupMaps.count()) return true; return false; } -QModelIndex -QtGroupingProxy::mapToSource( const QModelIndex &index ) const +QModelIndex QtGroupingProxy::mapToSource(const QModelIndex& index) const { - if( !index.isValid() ) { + if (!index.isValid()) { return m_rootNode; } - if( isGroup( index ) ) - { + if (isGroup(index)) { return m_rootNode; } - QModelIndex proxyParent = index.parent(); - QModelIndex originalParent = mapToSource( proxyParent ); + QModelIndex proxyParent = index.parent(); + QModelIndex originalParent = mapToSource(proxyParent); int originalRow = index.row(); - if( originalParent == m_rootNode ) - { + if (originalParent == m_rootNode) { int indexInGroup = index.row(); - if( !proxyParent.isValid() ) + if (!proxyParent.isValid()) indexInGroup -= m_groupMaps.count(); - QList<int> childRows = m_groupMap.value( proxyParent.row() ); - if( childRows.isEmpty() || indexInGroup >= childRows.count() || indexInGroup < 0 ) + QList<int> childRows = m_groupMap.value(proxyParent.row()); + if (childRows.isEmpty() || indexInGroup >= childRows.count() || indexInGroup < 0) return QModelIndex(); - originalRow = childRows.at( indexInGroup ); + originalRow = childRows.at(indexInGroup); } - return sourceModel()->index( originalRow, index.column(), originalParent ); + return sourceModel()->index(originalRow, index.column(), originalParent); } -QModelIndexList -QtGroupingProxy::mapToSource( const QModelIndexList& list ) const +QModelIndexList QtGroupingProxy::mapToSource(const QModelIndexList& list) const { QModelIndexList originalList; - foreach( const QModelIndex &index, list ) - { - QModelIndex originalIndex = mapToSource( index ); - if( originalIndex.isValid() ) + foreach (const QModelIndex& index, list) { + QModelIndex originalIndex = mapToSource(index); + if (originalIndex.isValid()) originalList << originalIndex; } return originalList; } -QModelIndex -QtGroupingProxy::mapFromSource( const QModelIndex &idx ) const +QModelIndex QtGroupingProxy::mapFromSource(const QModelIndex& idx) const { - if( !idx.isValid() ) + if (!idx.isValid()) return QModelIndex(); QModelIndex proxyParent; QModelIndex sourceParent = idx.parent(); - int proxyRow = idx.row(); + int proxyRow = idx.row(); int sourceRow = idx.row(); - if( sourceParent.isValid() && ( sourceParent != m_rootNode ) ) - { - //idx is a child of one of the items in the source model - proxyParent = mapFromSource( sourceParent ); - } - else - { - //idx is an item in the top level of the source model (child of the rootnode) + if (sourceParent.isValid() && (sourceParent != m_rootNode)) { + // idx is a child of one of the items in the source model + proxyParent = mapFromSource(sourceParent); + } else { + // idx is an item in the top level of the source model (child of the rootnode) int groupRow = -1; - QMapIterator<quint32, QList<int> > iterator( m_groupMap ); - while( iterator.hasNext() ) - { + QMapIterator<quint32, QList<int>> iterator(m_groupMap); + while (iterator.hasNext()) { iterator.next(); - if( iterator.value().contains( sourceRow ) ) - { + if (iterator.value().contains(sourceRow)) { groupRow = iterator.key(); break; } } - if( groupRow != -1 ) //it's in a group, let's find the correct row. - { - proxyParent = this->index( groupRow, 0, QModelIndex() ); - proxyRow = m_groupMap.value( groupRow ).indexOf( sourceRow ); - } - else + if (groupRow != -1) // it's in a group, let's find the correct row. { + proxyParent = this->index(groupRow, 0, QModelIndex()); + proxyRow = m_groupMap.value(groupRow).indexOf(sourceRow); + } else { proxyParent = QModelIndex(); // if the proxy item is not in a group it will be below the groups. int groupLength = m_groupMaps.count(); - int i = m_groupMap.value( std::numeric_limits<quint32>::max() ).indexOf( sourceRow ); + int i = m_groupMap.value(std::numeric_limits<quint32>::max()).indexOf(sourceRow); proxyRow = groupLength + i; } } - return this->index( proxyRow, idx.column(), proxyParent ); + return this->index(proxyRow, idx.column(), proxyParent); } -Qt::ItemFlags -QtGroupingProxy::flags( const QModelIndex &idx ) const +Qt::ItemFlags QtGroupingProxy::flags(const QModelIndex& idx) const { - if( !idx.isValid() ) - { - Qt::ItemFlags rootFlags = sourceModel()->flags( m_rootNode ); - if( rootFlags.testFlag( Qt::ItemIsDropEnabled ) ) - return Qt::ItemFlags( Qt::ItemIsDropEnabled ); + if (!idx.isValid()) { + Qt::ItemFlags rootFlags = sourceModel()->flags(m_rootNode); + if (rootFlags.testFlag(Qt::ItemIsDropEnabled)) + return Qt::ItemFlags(Qt::ItemIsDropEnabled); return Qt::ItemFlags(0); } - //only if the grouped column has the editable flag set allow the - //actions leading to setData on the source (edit & drop) - if( isGroup( idx ) ) - { + // only if the grouped column has the editable flag set allow the + // actions leading to setData on the source (edit & drop) + if (isGroup(idx)) { // dumpGroups(); - Qt::ItemFlags defaultFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable ); - //Qt::ItemFlags defaultFlags(Qt::ItemIsEnabled); + Qt::ItemFlags defaultFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); + // Qt::ItemFlags defaultFlags(Qt::ItemIsEnabled); bool groupIsEditable = true; if (idx.column() == 0) { bool checkable = true; - foreach ( int originalRow, m_groupMap.value( idx.row() ) ) - { - QModelIndex originalIdx = sourceModel()->index( originalRow, 0, - m_rootNode.parent() ); - if ( (originalIdx.flags() & Qt::ItemIsUserCheckable) == 0 ) - { + foreach (int originalRow, m_groupMap.value(idx.row())) { + QModelIndex originalIdx = + sourceModel()->index(originalRow, 0, m_rootNode.parent()); + if ((originalIdx.flags() & Qt::ItemIsUserCheckable) == 0) { checkable = false; } } - if ( checkable ) { + if (checkable) { defaultFlags |= Qt::ItemIsUserCheckable; } } - //it's possible to have empty groups - if( m_groupMap.value( idx.row() ).count() == 0 ) - { - //check the flags of this column with the root node - QModelIndex originalRootNode = sourceModel()->index( m_rootNode.row(), m_groupedColumn, - m_rootNode.parent() ); - groupIsEditable = originalRootNode.flags().testFlag( Qt::ItemIsEditable ); - } - else - { - foreach( int originalRow, m_groupMap.value( idx.row() ) ) - { - QModelIndex originalIdx = sourceModel()->index( originalRow, m_groupedColumn, - m_rootNode ); + // it's possible to have empty groups + if (m_groupMap.value(idx.row()).count() == 0) { + // check the flags of this column with the root node + QModelIndex originalRootNode = + sourceModel()->index(m_rootNode.row(), m_groupedColumn, m_rootNode.parent()); + groupIsEditable = originalRootNode.flags().testFlag(Qt::ItemIsEditable); + } else { + foreach (int originalRow, m_groupMap.value(idx.row())) { + QModelIndex originalIdx = + sourceModel()->index(originalRow, m_groupedColumn, m_rootNode); - groupIsEditable = groupIsEditable - ? originalIdx.flags().testFlag( Qt::ItemIsEditable ) - : false; - if( !groupIsEditable ) //all children need to have an editable grouped column + groupIsEditable = + groupIsEditable ? originalIdx.flags().testFlag(Qt::ItemIsEditable) : false; + if (!groupIsEditable) // all children need to have an editable grouped column break; } } - if( groupIsEditable ) - return ( defaultFlags | Qt::ItemIsEditable | Qt::ItemIsDropEnabled ); + if (groupIsEditable) + return (defaultFlags | Qt::ItemIsEditable | Qt::ItemIsDropEnabled); return defaultFlags; } - QModelIndex originalIdx = mapToSource( idx ); - Qt::ItemFlags originalItemFlags = sourceModel()->flags( originalIdx ); + QModelIndex originalIdx = mapToSource(idx); + Qt::ItemFlags originalItemFlags = sourceModel()->flags(originalIdx); - //check the source model to see if the grouped column is editable; + // check the source model to see if the grouped column is editable; QModelIndex groupedColumnIndex = - sourceModel()->index( originalIdx.row(), m_groupedColumn, originalIdx.parent() ); - bool groupIsEditable = sourceModel()->flags( groupedColumnIndex ).testFlag( Qt::ItemIsEditable ); + sourceModel()->index(originalIdx.row(), m_groupedColumn, originalIdx.parent()); + bool groupIsEditable = + sourceModel()->flags(groupedColumnIndex).testFlag(Qt::ItemIsEditable); - if( groupIsEditable ) + if (groupIsEditable) return originalItemFlags | Qt::ItemIsDragEnabled; return originalItemFlags; } -QVariant -QtGroupingProxy::headerData( int section, Qt::Orientation orientation, int role ) const +QVariant QtGroupingProxy::headerData(int section, Qt::Orientation orientation, + int role) const { - return sourceModel()->headerData( section, orientation, role ); + return sourceModel()->headerData(section, orientation, role); } -bool -QtGroupingProxy::canFetchMore( const QModelIndex &parent ) const +bool QtGroupingProxy::canFetchMore(const QModelIndex& parent) const { - if( !parent.isValid() ) + if (!parent.isValid()) return false; - if( isGroup( parent ) ) + if (isGroup(parent)) return false; - return sourceModel()->canFetchMore( mapToSource( parent ) ); + return sourceModel()->canFetchMore(mapToSource(parent)); } -void -QtGroupingProxy::fetchMore ( const QModelIndex & parent ) +void QtGroupingProxy::fetchMore(const QModelIndex& parent) { - if( !parent.isValid() ) + if (!parent.isValid()) return; - if( isGroup( parent ) ) + if (isGroup(parent)) return; - return sourceModel()->fetchMore( mapToSource( parent ) ); + return sourceModel()->fetchMore(mapToSource(parent)); } -QModelIndex -QtGroupingProxy::addEmptyGroup( const RowData &data ) +QModelIndex QtGroupingProxy::addEmptyGroup(const RowData& data) { int newRow = m_groupMaps.count(); - beginInsertRows( QModelIndex(), newRow, newRow ); + beginInsertRows(QModelIndex(), newRow, newRow); m_groupMaps << data; endInsertRows(); - return index( newRow, 0, QModelIndex() ); + return index(newRow, 0, QModelIndex()); } -bool -QtGroupingProxy::removeGroup( const QModelIndex &idx ) +bool QtGroupingProxy::removeGroup(const QModelIndex& idx) { - beginRemoveRows( idx.parent(), idx.row(), idx.row() ); - m_groupMap.remove( idx.row() ); - m_groupMaps.removeAt( idx.row() ); - m_parentCreateList.removeAt( idx.internalId() ); + beginRemoveRows(idx.parent(), idx.row(), idx.row()); + m_groupMap.remove(idx.row()); + m_groupMaps.removeAt(idx.row()); + m_parentCreateList.removeAt(idx.internalId()); endRemoveRows(); - //TODO: only true if all data could be unset. + // TODO: only true if all data could be unset. return true; } -bool -QtGroupingProxy::hasChildren( const QModelIndex &parent ) const +bool QtGroupingProxy::hasChildren(const QModelIndex& parent) const { - if( !parent.isValid() ) { + if (!parent.isValid()) { return true; } - if( isGroup( parent ) ) { - return !m_groupMap.value( parent.row() ).isEmpty(); + if (isGroup(parent)) { + return !m_groupMap.value(parent.row()).isEmpty(); } - return sourceModel()->hasChildren( mapToSource( parent ) ); + return sourceModel()->hasChildren(mapToSource(parent)); } -bool -QtGroupingProxy::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) +bool QtGroupingProxy::dropMimeData(const QMimeData* data, Qt::DropAction action, + int row, int column, const QModelIndex& parent) { QModelIndex idx = index(row, column, parent); if (isGroup(idx)) { QList<int> childRows = m_groupMap.value(idx.row()); - int max = *std::max_element(childRows.begin(), childRows.end()); + int max = *std::max_element(childRows.begin(), childRows.end()); QModelIndex newIdx = mapToSource(index(max, column, idx)); return sourceModel()->dropMimeData(data, action, max, column, newIdx); @@ -853,186 +788,161 @@ QtGroupingProxy::dropMimeData(const QMimeData *data, Qt::DropAction action, int return sourceModel()->dropMimeData(data, action, -1, -1, mapToSource(parent)); } else { QModelIndex idx = mapToSource(index(row, column, parent)); - return sourceModel()->dropMimeData(data, action, idx.row(), idx.column(), idx.parent()); + return sourceModel()->dropMimeData(data, action, idx.row(), idx.column(), + idx.parent()); } } } -void -QtGroupingProxy::modelRowsAboutToBeInserted( const QModelIndex &parent, int start, int end ) +void QtGroupingProxy::modelRowsAboutToBeInserted(const QModelIndex& parent, int start, + int end) { - if( parent != m_rootNode ) - { - //an item will be added to an original index, remap and pass it on - QModelIndex proxyParent = mapFromSource( parent ); - beginInsertRows( proxyParent, start, end ); + if (parent != m_rootNode) { + // an item will be added to an original index, remap and pass it on + QModelIndex proxyParent = mapFromSource(parent); + beginInsertRows(proxyParent, start, end); } } -void -QtGroupingProxy::modelRowsInserted( const QModelIndex &parent, int start, int end ) +void QtGroupingProxy::modelRowsInserted(const QModelIndex& parent, int start, int end) { - if( parent == m_rootNode ) - { - //top level of the model changed, these new rows need to be put in groups - for( int modelRow = start; modelRow <= end ; modelRow++ ) - { - addSourceRow( sourceModel()->index( modelRow, m_groupedColumn, m_rootNode ) ); + if (parent == m_rootNode) { + // top level of the model changed, these new rows need to be put in groups + for (int modelRow = start; modelRow <= end; modelRow++) { + addSourceRow(sourceModel()->index(modelRow, m_groupedColumn, m_rootNode)); } - } - else - { - //an item was added to an original index, remap and pass it on - QModelIndex proxyParent = mapFromSource( parent ); + } else { + // an item was added to an original index, remap and pass it on + QModelIndex proxyParent = mapFromSource(parent); QString s; QDebug debug(&s); debug << proxyParent; log::debug("{}", s); - //beginInsertRows had to be called in modelRowsAboutToBeInserted() + // beginInsertRows had to be called in modelRowsAboutToBeInserted() endInsertRows(); } } -void -QtGroupingProxy::modelRowsAboutToBeRemoved( const QModelIndex &parent, int start, int end ) +void QtGroupingProxy::modelRowsAboutToBeRemoved(const QModelIndex& parent, int start, + int end) { - if( parent == m_rootNode ) - { - QMap<quint32, QList<int> >::const_iterator i; - //HACK, we are going to call beginRemoveRows() multiple times without + if (parent == m_rootNode) { + QMap<quint32, QList<int>>::const_iterator i; + // HACK, we are going to call beginRemoveRows() multiple times without // endRemoveRows() if a source index is in multiple groups. // This can be a problem for some views/proxies, but Q*Views can handle it. // TODO: investigate a queue for applying proxy model changes in the correct order - for( i = m_groupMap.constBegin(); i != m_groupMap.constEnd(); ++i ) - { - int groupIndex = i.key(); - const QList<int> &groupList = i.value(); - QModelIndex proxyParent = index( groupIndex, 0 ); - foreach( int originalRow, groupList ) - { - if( originalRow >= start && originalRow <= end ) - { - int proxyRow = groupList.indexOf( originalRow ); - if( groupIndex == -1 ) //adjust for non-grouped (root level) original items + for (i = m_groupMap.constBegin(); i != m_groupMap.constEnd(); ++i) { + int groupIndex = i.key(); + const QList<int>& groupList = i.value(); + QModelIndex proxyParent = index(groupIndex, 0); + foreach (int originalRow, groupList) { + if (originalRow >= start && originalRow <= end) { + int proxyRow = groupList.indexOf(originalRow); + if (groupIndex == -1) // adjust for non-grouped (root level) original items proxyRow += m_groupMaps.count(); - //TODO: optimize for continues original rows in the same group - beginRemoveRows( proxyParent, proxyRow, proxyRow ); + // TODO: optimize for continues original rows in the same group + beginRemoveRows(proxyParent, proxyRow, proxyRow); } } } - } - else - { - //child item(s) of an original item will be removed, remap and pass it on - QModelIndex proxyParent = mapFromSource( parent ); - beginRemoveRows( proxyParent, start, end ); + } else { + // child item(s) of an original item will be removed, remap and pass it on + QModelIndex proxyParent = mapFromSource(parent); + beginRemoveRows(proxyParent, start, end); } } -void -QtGroupingProxy::modelRowsRemoved( const QModelIndex &parent, int start, int end ) +void QtGroupingProxy::modelRowsRemoved(const QModelIndex& parent, int start, int end) { - if( parent == m_rootNode ) - { - //TODO: can be optimised by iterating over m_groupMap and checking start <= r < end + if (parent == m_rootNode) { + // TODO: can be optimised by iterating over m_groupMap and checking start <= r < end - //rather than increasing i we change the stored sourceRows in-place and reuse argument start - //X-times (where X = end - start). - for( int i = start; i <= end; i++ ) - { - //HACK: we are going to iterate the hash in reverse so calls to endRemoveRows() + // rather than increasing i we change the stored sourceRows in-place and reuse + // argument start X-times (where X = end - start). + for (int i = start; i <= end; i++) { + // HACK: we are going to iterate the hash in reverse so calls to endRemoveRows() // are matched up with the beginRemoveRows() in modelRowsAboutToBeRemoved() - //NOTE: easier to do reverse with java style iterator - QMutableMapIterator<quint32, QList<int> > iter( m_groupMap ); + // NOTE: easier to do reverse with java style iterator + QMutableMapIterator<quint32, QList<int>> iter(m_groupMap); iter.toBack(); - while( iter.hasPrevious() ) - { + while (iter.hasPrevious()) { iter.previous(); int groupIndex = iter.key(); - //has to be a modifiable reference for remove and replace operations - QList<int> &groupList = iter.value(); - int rowIndex = groupList.indexOf( start ); - if( rowIndex != -1 ) - { - QModelIndex proxyParent = index( groupIndex, 0 ); - groupList.removeAt( rowIndex ); + // has to be a modifiable reference for remove and replace operations + QList<int>& groupList = iter.value(); + int rowIndex = groupList.indexOf(start); + if (rowIndex != -1) { + QModelIndex proxyParent = index(groupIndex, 0); + groupList.removeAt(rowIndex); } - //Now decrement all source rows that are after the removed row - for( int j = 0; j < groupList.count(); j++ ) - { - int sourceRow = groupList.at( j ); - if( sourceRow > start ) - groupList.replace( j, sourceRow-1 ); + // Now decrement all source rows that are after the removed row + for (int j = 0; j < groupList.count(); j++) { + int sourceRow = groupList.at(j); + if (sourceRow > start) + groupList.replace(j, sourceRow - 1); } - if( rowIndex != -1) - endRemoveRows(); //end remove operation only after group was updated. + if (rowIndex != -1) + endRemoveRows(); // end remove operation only after group was updated. } } return; } - //beginRemoveRows had to be called in modelRowsAboutToBeRemoved(); + // beginRemoveRows had to be called in modelRowsAboutToBeRemoved(); endRemoveRows(); } -void -QtGroupingProxy::resetModel() +void QtGroupingProxy::resetModel() { buildTree(); } -void -QtGroupingProxy::modelDataChanged( const QModelIndex &topLeft, const QModelIndex &bottomRight ) +void QtGroupingProxy::modelDataChanged(const QModelIndex& topLeft, + const QModelIndex& bottomRight) { - //TODO: need to look in the groupedColumn and see if it changed and changed grouping accordingly - QModelIndex proxyTopLeft = mapFromSource( topLeft ); - if( !proxyTopLeft.isValid() ) + // TODO: need to look in the groupedColumn and see if it changed and changed grouping + // accordingly + QModelIndex proxyTopLeft = mapFromSource(topLeft); + if (!proxyTopLeft.isValid()) return; - if( topLeft == bottomRight ) - { - emit dataChanged( proxyTopLeft, proxyTopLeft ); - } - else - { - QModelIndex proxyBottomRight = mapFromSource( bottomRight ); - emit dataChanged( proxyTopLeft, proxyBottomRight ); + if (topLeft == bottomRight) { + emit dataChanged(proxyTopLeft, proxyTopLeft); + } else { + QModelIndex proxyBottomRight = mapFromSource(bottomRight); + emit dataChanged(proxyTopLeft, proxyBottomRight); } } -bool -QtGroupingProxy::isAGroupSelected( const QModelIndexList& list ) const +bool QtGroupingProxy::isAGroupSelected(const QModelIndexList& list) const { - foreach( const QModelIndex &index, list ) - { - if( isGroup( index ) ) + foreach (const QModelIndex& index, list) { + if (isGroup(index)) return true; } return false; } -void -QtGroupingProxy::dumpGroups() const +void QtGroupingProxy::dumpGroups() const { QString s; QDebug debug(&s); debug << "m_groupMap:\n"; - for( int groupIndex = -1; groupIndex < m_groupMap.keys().count() - 1; groupIndex++ ) - { - debug << groupIndex << " : " << m_groupMap.value( groupIndex ) << "\n"; + for (int groupIndex = -1; groupIndex < m_groupMap.keys().count() - 1; groupIndex++) { + debug << groupIndex << " : " << m_groupMap.value(groupIndex) << "\n"; } debug << "m_groupMaps:\n"; - for( int groupIndex = 0; groupIndex < m_groupMaps.count(); groupIndex++ ) - { - debug << m_groupMaps[groupIndex] << ": " << m_groupMap.value( groupIndex ) << "\n"; + for (int groupIndex = 0; groupIndex < m_groupMaps.count(); groupIndex++) { + debug << m_groupMaps[groupIndex] << ": " << m_groupMap.value(groupIndex) << "\n"; } - debug << m_groupMap.value( std::numeric_limits<quint32>::max() ); + debug << m_groupMap.value(std::numeric_limits<quint32>::max()); log::debug("{}", s); } diff --git a/src/qtgroupingproxy.h b/src/qtgroupingproxy.h index 80ca4eec..aeef9f4b 100644 --- a/src/qtgroupingproxy.h +++ b/src/qtgroupingproxy.h @@ -1,17 +1,17 @@ /**************************************************************************************** - * Copyright (c) 2007-2010 Bart Cerneels <bart.cerneels@kde.org> * + * Copyright (c) 2007-2010 Bart Cerneels <bart.cerneels@kde.org> * * * - * 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; either version 2 of the License, or (at your option) any later * - * version. * + * 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; either version 2 of the License, or (at your option) any later * version. + ** * * - * 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. * + * 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 <http://www.gnu.org/licenses/>. * + * You should have received a copy of the GNU General Public License along with * this + *program. If not, see <http://www.gnu.org/licenses/>. * ****************************************************************************************/ // Modifications 2013-03-27 to 2013-03-28 by Sebastian Herbord @@ -20,11 +20,11 @@ #define GROUPINGPROXY_H #include <QAbstractProxyModel> +#include <QIcon> #include <QModelIndex> #include <QMultiHash> -#include <QStringList> -#include <QIcon> #include <QSet> +#include <QStringList> typedef QMap<int, QVariant> ItemData; typedef QMap<int, ItemData> RowData; @@ -34,11 +34,11 @@ class QtGroupingProxy : public QAbstractProxyModel Q_OBJECT public: - - static const unsigned int FLAG_NOSINGLE = 1; + static const unsigned int FLAG_NOSINGLE = 1; static const unsigned int FLAG_NOGROUPNAME = 2; - enum EAggregateFunction { + enum EAggregateFunction + { AGGR_NONE, // no aggregation, return child elements as list AGGR_EMPTY, // display nothing AGGR_FIRST, // return value of the topmost item @@ -47,92 +47,93 @@ public: }; public: - explicit QtGroupingProxy( QModelIndex rootNode = QModelIndex(), - int groupedColumn = -1, int groupedRole = Qt::DisplayRole, - unsigned int flags = 0, - int aggregateRole = Qt::DisplayRole); + explicit QtGroupingProxy(QModelIndex rootNode = QModelIndex(), int groupedColumn = -1, + int groupedRole = Qt::DisplayRole, unsigned int flags = 0, + int aggregateRole = Qt::DisplayRole); ~QtGroupingProxy(); void setSourceModel(QAbstractItemModel* model) override; - void setGroupedColumn( int groupedColumn ); + void setGroupedColumn(int groupedColumn); /* QAbstractProxyModel methods */ - virtual QModelIndex index( int, int c = 0, - const QModelIndex& parent = QModelIndex() ) const; - virtual Qt::ItemFlags flags( const QModelIndex &idx ) const; - virtual QModelIndex parent( const QModelIndex &idx ) const; - virtual int rowCount( const QModelIndex &idx = QModelIndex() ) const; - virtual int columnCount( const QModelIndex &idx ) const; - virtual QModelIndex mapToSource( const QModelIndex &idx ) const; - virtual QModelIndexList mapToSource( const QModelIndexList &list ) const; - virtual QModelIndex mapFromSource( const QModelIndex &idx ) const; - virtual QVariant data( const QModelIndex &idx, int role ) const; - virtual bool setData( const QModelIndex &index, const QVariant &value, - int role = Qt::EditRole ); - virtual QVariant headerData ( int section, Qt::Orientation orientation, - int role ) const; - virtual bool canFetchMore( const QModelIndex &parent ) const; - virtual void fetchMore( const QModelIndex &parent ); - virtual bool hasChildren( const QModelIndex &parent = QModelIndex() ) const; - virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); + virtual QModelIndex index(int, int c = 0, + const QModelIndex& parent = QModelIndex()) const; + virtual Qt::ItemFlags flags(const QModelIndex& idx) const; + virtual QModelIndex parent(const QModelIndex& idx) const; + virtual int rowCount(const QModelIndex& idx = QModelIndex()) const; + virtual int columnCount(const QModelIndex& idx) const; + virtual QModelIndex mapToSource(const QModelIndex& idx) const; + virtual QModelIndexList mapToSource(const QModelIndexList& list) const; + virtual QModelIndex mapFromSource(const QModelIndex& idx) const; + virtual QVariant data(const QModelIndex& idx, int role) const; + virtual bool setData(const QModelIndex& index, const QVariant& value, + int role = Qt::EditRole); + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + virtual bool canFetchMore(const QModelIndex& parent) const; + virtual void fetchMore(const QModelIndex& parent); + virtual bool hasChildren(const QModelIndex& parent = QModelIndex()) const; + virtual bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, + int column, const QModelIndex& parent); /* QtGroupingProxy methods */ - virtual QModelIndex addEmptyGroup( const RowData &data ); - virtual bool removeGroup( const QModelIndex &idx ); + virtual QModelIndex addEmptyGroup(const RowData& data); + virtual bool removeGroup(const QModelIndex& idx); protected slots: virtual void buildTree(); private slots: - void modelDataChanged( const QModelIndex &, const QModelIndex & ); - void modelRowsAboutToBeInserted( const QModelIndex &, int ,int ); - void modelRowsInserted( const QModelIndex &, int, int ); - void modelRowsAboutToBeRemoved( const QModelIndex &, int ,int ); - void modelRowsRemoved( const QModelIndex &, int, int ); + void modelDataChanged(const QModelIndex&, const QModelIndex&); + void modelRowsAboutToBeInserted(const QModelIndex&, int, int); + void modelRowsInserted(const QModelIndex&, int, int); + void modelRowsAboutToBeRemoved(const QModelIndex&, int, int); + void modelRowsRemoved(const QModelIndex&, int, int); void resetModel(); protected: /** Maps an item to a group. - * The return value is a list because an item can put in multiple groups. - * Inside the list is a 2 dimensional map. - * Mapped to column-number is another map of role-number to QVariant. - * This data prepolulates the group-data cache. The rest is gathered on demand - * from the children of the group. - */ - virtual QList<RowData> belongsTo( const QModelIndex &idx ); + * The return value is a list because an item can put in multiple groups. + * Inside the list is a 2 dimensional map. + * Mapped to column-number is another map of role-number to QVariant. + * This data prepolulates the group-data cache. The rest is gathered on demand + * from the children of the group. + */ + virtual QList<RowData> belongsTo(const QModelIndex& idx); /** - * calls belongsTo(), checks cached data and adds the index to existing or new groups. - * @returns the groups this index was added to where -1 means it was added to the root. - */ - QList<int> addSourceRow( const QModelIndex &idx ); + * calls belongsTo(), checks cached data and adds the index to existing or new groups. + * @returns the groups this index was added to where -1 means it was added to the + * root. + */ + QList<int> addSourceRow(const QModelIndex& idx); - bool isGroup( const QModelIndex &index ) const; - bool isAGroupSelected( const QModelIndexList &list ) const; + bool isGroup(const QModelIndex& index) const; + bool isAGroupSelected(const QModelIndexList& list) const; /** Maintains the group -> sourcemodel row mapping - * The reason a QList<int> is use instead of a QMultiHash is that the values have to be - * reordered when rows are inserted or removed. - * TODO:use some auto-incrementing container class (steveire's?) for the list - */ - QMap<quint32, QList<int> > m_groupMap; + * The reason a QList<int> is use instead of a QMultiHash is that the values have to + * be reordered when rows are inserted or removed. + * TODO:use some auto-incrementing container class (steveire's?) for the list + */ + QMap<quint32, QList<int>> m_groupMap; /** The data cache of the groups. - * This can be pre-loaded with data in belongsTo() - */ + * This can be pre-loaded with data in belongsTo() + */ QList<RowData> m_groupMaps; /** "instuctions" how to create an item in the tree. - * This is used by parent( QModelIndex ) - */ + * This is used by parent( QModelIndex ) + */ struct ParentCreate { int parentCreateIndex; int row; }; mutable QList<struct ParentCreate> m_parentCreateList; - /** @returns index of the "instructions" to recreate the parent. Will create new if it doesn't exist yet. - */ - int indexOfParentCreate( const QModelIndex &parent ) const; + /** @returns index of the "instructions" to recreate the parent. Will create new if it + * doesn't exist yet. + */ + int indexOfParentCreate(const QModelIndex& parent) const; QModelIndexList m_selectedGroups; @@ -147,7 +148,6 @@ private: int m_groupedRole; int m_aggregateRole; - }; -#endif //GROUPINGPROXY_H +#endif // GROUPINGPROXY_H diff --git a/src/queryoverwritedialog.cpp b/src/queryoverwritedialog.cpp index 5e42a57c..2f1a24d5 100644 --- a/src/queryoverwritedialog.cpp +++ b/src/queryoverwritedialog.cpp @@ -22,15 +22,13 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QStyle> -QueryOverwriteDialog::QueryOverwriteDialog(QWidget *parent, Backup b) - : QDialog(parent), ui(new Ui::QueryOverwriteDialog), - m_Action(ACT_NONE) +QueryOverwriteDialog::QueryOverwriteDialog(QWidget* parent, Backup b) + : QDialog(parent), ui(new Ui::QueryOverwriteDialog), m_Action(ACT_NONE) { ui->setupUi(this); ui->backupBox->setChecked(b == BACKUP_YES); QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxQuestion); ui->iconLabel->setPixmap(icon.pixmap(128)); - } QueryOverwriteDialog::~QueryOverwriteDialog() diff --git a/src/queryoverwritedialog.h b/src/queryoverwritedialog.h index a98f23ef..a8769ea8 100644 --- a/src/queryoverwritedialog.h +++ b/src/queryoverwritedialog.h @@ -22,7 +22,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QDialog> -namespace Ui { +namespace Ui +{ class QueryOverwriteDialog; } @@ -30,20 +31,22 @@ class QueryOverwriteDialog : public QDialog { Q_OBJECT public: - enum Action { + enum Action + { ACT_NONE, ACT_MERGE, ACT_REPLACE, ACT_RENAME }; - enum Backup { + enum Backup + { BACKUP_NO, BACKUP_YES }; public: - QueryOverwriteDialog(QWidget *parent, Backup b); + QueryOverwriteDialog(QWidget* parent, Backup b); ~QueryOverwriteDialog(); bool backup() const; Action action() const { return m_Action; } @@ -54,8 +57,8 @@ private slots: void on_cancelBtn_clicked(); private: - Ui::QueryOverwriteDialog *ui; + Ui::QueryOverwriteDialog* ui; Action m_Action; }; -#endif // QUERYOVERWRITEDIALOG_H +#endif // QUERYOVERWRITEDIALOG_H diff --git a/src/sanitychecks.cpp b/src/sanitychecks.cpp index 2f7126ea..4aa5dc7c 100644 --- a/src/sanitychecks.cpp +++ b/src/sanitychecks.cpp @@ -13,51 +13,54 @@ using namespace MOBase; enum class SecurityZone { - NoZone = -1, + NoZone = -1, MyComputer = 0, - Intranet = 1, - Trusted = 2, - Internet = 3, - Untrusted = 4, + Intranet = 1, + Trusted = 2, + Internet = 3, + Untrusted = 4, }; QString toCodeName(SecurityZone z) { - switch (z) - { - case SecurityZone::NoZone: return "NoZone"; - case SecurityZone::MyComputer: return "MyComputer"; - case SecurityZone::Intranet: return "Intranet"; - case SecurityZone::Trusted: return "Trusted"; - case SecurityZone::Internet: return "Internet"; - case SecurityZone::Untrusted: return "Untrusted"; - default: return "Unknown zone"; + switch (z) { + case SecurityZone::NoZone: + return "NoZone"; + case SecurityZone::MyComputer: + return "MyComputer"; + case SecurityZone::Intranet: + return "Intranet"; + case SecurityZone::Trusted: + return "Trusted"; + case SecurityZone::Internet: + return "Internet"; + case SecurityZone::Untrusted: + return "Untrusted"; + default: + return "Unknown zone"; } } QString toString(SecurityZone z) { - return QString("%1 (%2)") - .arg(toCodeName(z)) - .arg(static_cast<int>(z)); + return QString("%1 (%2)").arg(toCodeName(z)).arg(static_cast<int>(z)); } // whether the given zone is considered blocked // bool isZoneBlocked(SecurityZone z) { - switch (z) - { - case SecurityZone::Internet: - case SecurityZone::Untrusted: - return true; + switch (z) { + case SecurityZone::Internet: + case SecurityZone::Untrusted: + return true; - case SecurityZone::NoZone: - case SecurityZone::MyComputer: - case SecurityZone::Intranet: - case SecurityZone::Trusted: - default: - return false; + case SecurityZone::NoZone: + case SecurityZone::MyComputer: + case SecurityZone::Intranet: + case SecurityZone::Trusted: + default: + return false; } } @@ -72,7 +75,7 @@ bool isFileBlocked(const QFileInfo& fi) const auto key = "ZoneTransfer/ZoneId"; // the path to the ADS is always `filename:Zone.Identifier` - const auto path = fi.absoluteFilePath(); + const auto path = fi.absoluteFilePath(); const auto adsPath = path + ":" + ads; QFile f(adsPath); @@ -99,7 +102,7 @@ bool isFileBlocked(const QFileInfo& fi) } // should be an int - bool ok = false; + bool ok = false; const auto z = static_cast<SecurityZone>(v.toInt(&ok)); if (!ok) { @@ -114,10 +117,7 @@ bool isFileBlocked(const QFileInfo& fi) } // file is blocked - log::warn("{}", QObject::tr( - "'%1': file is blocked (%2)") - .arg(path) - .arg(toString(z))); + log::warn("{}", QObject::tr("'%1': file is blocked (%2)").arg(path).arg(toString(z))); return true; } @@ -129,9 +129,8 @@ int checkBlockedFiles(const QDir& dir) if (!dir.exists()) { // shouldn't happen - log::error( - "while checking for blocked files, directory '{}' not found", - dir.absolutePath()); + log::error("while checking for blocked files, directory '{}' not found", + dir.absolutePath()); return 1; } @@ -139,9 +138,8 @@ int checkBlockedFiles(const QDir& dir) const auto files = dir.entryInfoList(FileTypes, QDir::Files); if (files.empty()) { // shouldn't happen - log::error( - "while checking for blocked files, directory '{}' is empty", - dir.absolutePath()); + log::error("while checking for blocked files, directory '{}' is empty", + dir.absolutePath()); return 1; } @@ -162,14 +160,7 @@ int checkBlocked() { // directories that contain executables; these need to be explicit because // portable instances might add billions of files in MO's directory - const QString dirs[] = { - ".", - "/dlls", - "/loot", - "/NCC", - "/platforms", - "/plugins" - }; + const QString dirs[] = {".", "/dlls", "/loot", "/NCC", "/platforms", "/plugins"}; log::debug(" . blocked files"); const QString appDir = QCoreApplication::applicationDirPath(); @@ -187,16 +178,9 @@ int checkBlocked() int checkMissingFiles() { // files that are likely to be eaten - static const QStringList files({ - "helper.exe", - "nxmhandler.exe", - "usvfs_proxy_x64.exe", - "usvfs_proxy_x86.exe", - "usvfs_x64.dll", - "usvfs_x86.dll", - "loot/loot.dll", - "loot/lootcli.exe" - }); + static const QStringList files( + {"helper.exe", "nxmhandler.exe", "usvfs_proxy_x64.exe", "usvfs_proxy_x86.exe", + "usvfs_x64.dll", "usvfs_x86.dll", "loot/loot.dll", "loot/lootcli.exe"}); log::debug(" . missing files"); const auto dir = QCoreApplication::applicationDirPath(); @@ -208,8 +192,8 @@ int checkMissingFiles() if (!file.exists()) { log::warn("{}", QObject::tr( - "'%1' seems to be missing, an antivirus may have deleted it") - .arg(file.absoluteFilePath())); + "'%1' seems to be missing, an antivirus may have deleted it") + .arg(file.absoluteFilePath())); ++n; } @@ -228,29 +212,27 @@ int checkBadOSDs(const env::Module& m) // where they got loaded later, so this is also called every time a new module // is loaded into this process - const std::string nahimic = - "Nahimic (also known as SonicSuite, SonicRadar, " - "SteelSeries, A-Volute, etc.)"; + const std::string nahimic = "Nahimic (also known as SonicSuite, SonicRadar, " + "SteelSeries, A-Volute, etc.)"; auto p = [](std::string re, std::string s) { return std::make_pair(std::regex(re, std::regex::icase), s); }; static const std::vector<std::pair<std::regex, std::string>> list = { - p("nahimic(.*)osd\\.dll", nahimic), - p("cassini(.*)osd\\.dll", nahimic), - p(".+devprops.*.dll", nahimic), - p("ss2osd\\.dll", nahimic), - p("RTSSHooks64\\.dll", "RivaTuner Statistics Server"), - p("SSAudioOSD\\.dll", "SteelSeries Audio"), - p("specialk64\\.dll", "SpecialK"), - p("corsairosdhook\\.x64\\.dll", "Corsair Utility Engine"), - p("gtii-osd64-vk\\.dll", "ASUS GPU Tweak 2"), - p("easyhook64\\.dll", "Razer Cortex"), - p("k_fps64\\.dll", "Razer Cortex"), - p("fw1fontwrapper\\.dll", "Gigabyte 3D OSD"), - p("gfxhook64\\.dll", "Gigabyte 3D OSD") - }; + p("nahimic(.*)osd\\.dll", nahimic), + p("cassini(.*)osd\\.dll", nahimic), + p(".+devprops.*.dll", nahimic), + p("ss2osd\\.dll", nahimic), + p("RTSSHooks64\\.dll", "RivaTuner Statistics Server"), + p("SSAudioOSD\\.dll", "SteelSeries Audio"), + p("specialk64\\.dll", "SpecialK"), + p("corsairosdhook\\.x64\\.dll", "Corsair Utility Engine"), + p("gtii-osd64-vk\\.dll", "ASUS GPU Tweak 2"), + p("easyhook64\\.dll", "Razer Cortex"), + p("k_fps64\\.dll", "Razer Cortex"), + p("fw1fontwrapper\\.dll", "Gigabyte 3D OSD"), + p("gfxhook64\\.dll", "Gigabyte 3D OSD")}; const QFileInfo file(m.path()); int n = 0; @@ -261,10 +243,10 @@ int checkBadOSDs(const env::Module& m) if (std::regex_match(filename, m, p.first)) { log::warn("{}", QObject::tr( - "%1 is loaded.\nThis program is known to cause issues with " - "Mod Organizer, such as freezing or blank windows. Consider " - "uninstalling it.") - .arg(QString::fromStdString(p.second))); + "%1 is loaded.\nThis program is known to cause issues with " + "Mod Organizer, such as freezing or blank windows. Consider " + "uninstalling it.") + .arg(QString::fromStdString(p.second))); log::warn("{}", file.absoluteFilePath()); ++n; @@ -279,20 +261,19 @@ int checkUsvfsIncompatibilites(const env::Module& m) // these dlls seems to interfere with usvfs static const std::map<QString, QString> names = { - {"mactype64.dll", "Mactype"}, - {"epclient64.dll", "Citrix ICA Client"} - }; + {"mactype64.dll", "Mactype"}, {"epclient64.dll", "Citrix ICA Client"}}; const QFileInfo file(m.path()); int n = 0; for (auto&& p : names) { if (file.fileName().compare(p.first, Qt::CaseInsensitive) == 0) { - log::warn("{}", QObject::tr( - "%1 is loaded. This program is known to cause issues with " - "Mod Organizer and its virtual filesystem, such script extenders " - "or others programs refusing to run. Consider uninstalling it.") - .arg(p.second)); + log::warn( + "{}", + QObject::tr("%1 is loaded. This program is known to cause issues with " + "Mod Organizer and its virtual filesystem, such script extenders " + "or others programs refusing to run. Consider uninstalling it.") + .arg(p.second)); log::warn("{}", file.absoluteFilePath()); @@ -330,13 +311,12 @@ std::vector<std::pair<QString, QString>> getSystemDirectories() { // folder ids and display names for logging const std::vector<std::pair<GUID, QString>> systemFolderIDs = { - {FOLDERID_ProgramFiles, "in Program Files"}, - {FOLDERID_ProgramFilesX86, "in Program Files"}, - {FOLDERID_Desktop, "on the desktop"}, - {FOLDERID_OneDrive, "in OneDrive"}, - {FOLDERID_Documents, "in Documents"}, - {FOLDERID_Downloads, "in Downloads"} - }; + {FOLDERID_ProgramFiles, "in Program Files"}, + {FOLDERID_ProgramFilesX86, "in Program Files"}, + {FOLDERID_Desktop, "on the desktop"}, + {FOLDERID_OneDrive, "in OneDrive"}, + {FOLDERID_Documents, "in Documents"}, + {FOLDERID_Downloads, "in Downloads"}}; std::vector<std::pair<QString, QString>> systemDirs; @@ -366,10 +346,9 @@ int checkProtected(const QDir& d, const QString& what) for (auto&& sd : systemDirs) { if (path.startsWith(sd.first)) { - log::warn( - "{} is {}; this may cause issues because it's a special " - "system folder", - what, sd.second); + log::warn("{} is {}; this may cause issues because it's a special " + "system folder", + what, sd.second); log::debug("path '{}' starts with '{}'", path, sd.first); @@ -383,12 +362,11 @@ int checkProtected(const QDir& d, const QString& what) int checkMicrosoftStore(const QDir& gameDir) { const QStringList pathsToCheck = { - "/ModifiableWindowsApps/", - "/WindowsApps/", + "/ModifiableWindowsApps/", + "/WindowsApps/", }; for (auto badPath : pathsToCheck) { - if (gameDir.path().contains(badPath)) - { + if (gameDir.path().contains(badPath)) { log::error("This game is not supported by Mod Organizer."); log::error("Games installed through the Microsoft Store will not work properly."); return 1; @@ -431,9 +409,8 @@ void checkEnvironment(const env::Environment& e) n += checkMissingFiles(); n += checkIncompatibilities(e); - log::debug( - "sanity checks done, {}", - (n > 0 ? "problems were found" : "everything looks okay")); + log::debug("sanity checks done, {}", + (n > 0 ? "problems were found" : "everything looks okay")); } -} // namespace +} // namespace sanity diff --git a/src/sanitychecks.h b/src/sanitychecks.h index 8786ee78..bfafa015 100644 --- a/src/sanitychecks.h +++ b/src/sanitychecks.h @@ -3,18 +3,17 @@ namespace env { - class Environment; - class Module; -} +class Environment; +class Module; +} // namespace env namespace MOBase { - class IPluginGame; +class IPluginGame; } class Settings; - namespace sanity { @@ -22,6 +21,6 @@ void checkEnvironment(const env::Environment& env); int checkIncompatibleModule(const env::Module& m); int checkPaths(MOBase::IPluginGame& game, const Settings& s); -} // namespace +} // namespace sanity #endif // MODORGANIZER_SANITYCHECKS_INCLUDED diff --git a/src/savestab.cpp b/src/savestab.cpp index 5b0b5275..c6ab645f 100644 --- a/src/savestab.cpp +++ b/src/savestab.cpp @@ -1,15 +1,16 @@ #include "savestab.h" -#include "ui_mainwindow.h" -#include "organizercore.h" #include "activatemodsdialog.h" +#include "organizercore.h" +#include "ui_mainwindow.h" #include <iplugingame.h> #include <isavegameinfowidget.h> using namespace MOBase; SavesTab::SavesTab(QWidget* window, OrganizerCore& core, Ui::MainWindow* mwui) - : m_window(window), m_core(core), m_CurrentSaveView(nullptr), ui{ - mwui->tabWidget, mwui->savesTab, mwui->savegameList} + : m_window(window), m_core(core), + m_CurrentSaveView(nullptr), ui{mwui->tabWidget, mwui->savesTab, + mwui->savegameList} { m_SavesWatcherTimer.setSingleShot(true); m_SavesWatcherTimer.setInterval(500); @@ -17,21 +18,21 @@ SavesTab::SavesTab(QWidget* window, OrganizerCore& core, Ui::MainWindow* mwui) ui.list->installEventFilter(this); ui.list->setMouseTracking(true); - connect( - &m_SavesWatcher, &QFileSystemWatcher::directoryChanged, - [&]{ m_SavesWatcherTimer.start(); }); + connect(&m_SavesWatcher, &QFileSystemWatcher::directoryChanged, [&] { + m_SavesWatcherTimer.start(); + }); - connect( - &m_SavesWatcherTimer, &QTimer::timeout, - [&]{ refreshSavesIfOpen(); }); + connect(&m_SavesWatcherTimer, &QTimer::timeout, [&] { + refreshSavesIfOpen(); + }); - connect( - ui.list, &QWidget::customContextMenuRequested, - [&](auto pos){ onContextMenu(pos); }); + connect(ui.list, &QWidget::customContextMenuRequested, [&](auto pos) { + onContextMenu(pos); + }); - connect( - ui.list, &QTreeWidget::itemEntered, - [&](auto* item){ saveSelectionChanged(item); }); + connect(ui.list, &QTreeWidget::itemEntered, [&](auto* item) { + saveSelectionChanged(item); + }); } bool SavesTab::eventFilter(QObject* object, QEvent* e) @@ -40,7 +41,7 @@ bool SavesTab::eventFilter(QObject* object, QEvent* e) if (e->type() == QEvent::Leave || e->type() == QEvent::WindowDeactivate) { hideSaveGameInfo(); } else if (e->type() == QEvent::KeyPress) { - QKeyEvent *keyEvent = static_cast<QKeyEvent*>(e); + QKeyEvent* keyEvent = static_cast<QKeyEvent*>(e); if (keyEvent->key() == Qt::Key_Delete) { deleteSavegame(); } @@ -50,19 +51,19 @@ bool SavesTab::eventFilter(QObject* object, QEvent* e) return false; } -void SavesTab::displaySaveGameInfo(QTreeWidgetItem *newItem) +void SavesTab::displaySaveGameInfo(QTreeWidgetItem* newItem) { // don't display the widget if the main window doesn't have focus // // this goes against the standard behaviour for tooltips, which are displayed // on hover regardless of focus, but this widget is so large and busy that // it's probably better this way - if (!m_window->isActiveWindow()){ + if (!m_window->isActiveWindow()) { return; } if (m_CurrentSaveView == nullptr) { - const IPluginGame* game = m_core.managedGame(); + const IPluginGame* game = m_core.managedGame(); const SaveGameInfo* info = game->feature<SaveGameInfo>(); if (info != nullptr) { @@ -76,7 +77,7 @@ void SavesTab::displaySaveGameInfo(QTreeWidgetItem *newItem) m_CurrentSaveView->setSave(*m_SaveGames[ui.list->indexOfTopLevelItem(newItem)]); - QWindow *window = m_CurrentSaveView->window()->windowHandle(); + QWindow* window = m_CurrentSaveView->window()->windowHandle(); QRect screenRect; if (window == nullptr) screenRect = QGuiApplication::primaryScreen()->geometry(); @@ -98,20 +99,20 @@ void SavesTab::displaySaveGameInfo(QTreeWidgetItem *newItem) m_CurrentSaveView->move(pos); m_CurrentSaveView->show(); - m_CurrentSaveView->setProperty("displayItem", QVariant::fromValue(static_cast<void *>(newItem))); + m_CurrentSaveView->setProperty("displayItem", + QVariant::fromValue(static_cast<void*>(newItem))); } - -void SavesTab::saveSelectionChanged(QTreeWidgetItem *newItem) +void SavesTab::saveSelectionChanged(QTreeWidgetItem* newItem) { if (newItem == nullptr) { hideSaveGameInfo(); - } else if (m_CurrentSaveView == nullptr || newItem != m_CurrentSaveView->property("displayItem").value<void*>()) { + } else if (m_CurrentSaveView == nullptr || + newItem != m_CurrentSaveView->property("displayItem").value<void*>()) { displaySaveGameInfo(newItem); } } - void SavesTab::hideSaveGameInfo() { if (m_CurrentSaveView != nullptr) { @@ -142,14 +143,11 @@ QDir SavesTab::currentSavesDir() const QString iniPath = m_core.currentProfile()->absoluteIniFilePath(iniFiles[0]); wchar_t path[MAX_PATH]; - if (::GetPrivateProfileStringW( - L"General", L"SLocalSavePath", L"", - path, MAX_PATH, - iniPath.toStdWString().c_str() - )) { - savesDir.setPath(m_core.managedGame()->documentsDirectory().absoluteFilePath(QString::fromWCharArray(path))); - } - else { + if (::GetPrivateProfileStringW(L"General", L"SLocalSavePath", L"", path, MAX_PATH, + iniPath.toStdWString().c_str())) { + savesDir.setPath(m_core.managedGame()->documentsDirectory().absoluteFilePath( + QString::fromWCharArray(path))); + } else { savesDir = m_core.managedGame()->savesDirectory(); } } @@ -177,26 +175,24 @@ void SavesTab::refreshSaveList() { TimeThis tt("MainWindow::refreshSaveList()"); - startMonitorSaves(); // re-starts monitoring + startMonitorSaves(); // re-starts monitoring - try - { + try { QDir savesDir = currentSavesDir(); MOBase::log::debug("reading save games from {}", savesDir.absolutePath()); m_SaveGames = m_core.managedGame()->listSaves(savesDir); - std::sort(m_SaveGames.begin(), m_SaveGames.end(), [](auto const& lhs, auto const& rhs) { - return lhs->getCreationTime() > rhs->getCreationTime(); - }); + std::sort(m_SaveGames.begin(), m_SaveGames.end(), + [](auto const& lhs, auto const& rhs) { + return lhs->getCreationTime() > rhs->getCreationTime(); + }); ui.list->clear(); - for (auto& save: m_SaveGames) { + for (auto& save : m_SaveGames) { auto relpath = savesDir.relativeFilePath(save->getFilepath()); auto display = save->getName(); - ui.list->addTopLevelItem(new QTreeWidgetItem(ui.list, { display, relpath })); + ui.list->addTopLevelItem(new QTreeWidgetItem(ui.list, {display, relpath})); } - } - catch(std::exception& e) - { + } catch (std::exception& e) { // listSaves() can throw log::error("{}", e.what()); } @@ -204,19 +200,20 @@ void SavesTab::refreshSaveList() void SavesTab::deleteSavegame() { - SaveGameInfo const *info = m_core.managedGame()->feature<SaveGameInfo>(); + SaveGameInfo const* info = m_core.managedGame()->feature<SaveGameInfo>(); QString savesMsgLabel; QStringList deleteFiles; int count = 0; - for (const QModelIndex &idx : ui.list->selectionModel()->selectedRows()) { + for (const QModelIndex& idx : ui.list->selectionModel()->selectedRows()) { auto& saveGame = m_SaveGames[idx.row()]; if (count < 10) { - savesMsgLabel += "<li>" + QFileInfo(saveGame->getFilepath()).completeBaseName() + "</li>"; + savesMsgLabel += + "<li>" + QFileInfo(saveGame->getFilepath()).completeBaseName() + "</li>"; } ++count; @@ -227,18 +224,19 @@ void SavesTab::deleteSavegame() savesMsgLabel += "<li><i>... " + tr("%1 more").arg(count - 10) + "</i></li>"; } - if (QMessageBox::question(m_window, tr("Confirm"), - tr("Are you sure you want to remove the following %n save(s)?<br>" - "<ul>%1</ul><br>" - "Removed saves will be sent to the Recycle Bin.", "", count) - .arg(savesMsgLabel), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - shellDelete(deleteFiles, true); // recycle bin delete. + if (QMessageBox::question( + m_window, tr("Confirm"), + tr("Are you sure you want to remove the following %n save(s)?<br>" + "<ul>%1</ul><br>" + "Removed saves will be sent to the Recycle Bin.", + "", count) + .arg(savesMsgLabel), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + shellDelete(deleteFiles, true); // recycle bin delete. refreshSaveList(); } } - void SavesTab::onContextMenu(const QPoint& pos) { QItemSelectionModel* selection = ui.list->selectionModel(); @@ -257,27 +255,35 @@ void SavesTab::onContextMenu(const QPoint& pos) auto& save = m_SaveGames[selection->selectedRows()[0].row()]; SaveGameInfo::MissingAssets missing = info->getMissingAssets(*save); if (missing.size() != 0) { - connect(action, &QAction::triggered, this, [this, missing] { fixMods(missing); }); + connect(action, &QAction::triggered, this, [this, missing] { + fixMods(missing); + }); action->setEnabled(true); } } } - QString deleteMenuLabel = tr("Delete %n save(s)", "", selection->selectedRows().count()); - menu.addAction(deleteMenuLabel, [&]{ deleteSavegame(); }); + QString deleteMenuLabel = + tr("Delete %n save(s)", "", selection->selectedRows().count()); + menu.addAction(deleteMenuLabel, [&] { + deleteSavegame(); + }); - menu.addAction(tr("Open in Explorer..."), [&]{ openInExplorer(); }); + menu.addAction(tr("Open in Explorer..."), [&] { + openInExplorer(); + }); menu.exec(ui.list->viewport()->mapToGlobal(pos)); } -void SavesTab::fixMods(SaveGameInfo::MissingAssets const &missingAssets) +void SavesTab::fixMods(SaveGameInfo::MissingAssets const& missingAssets) { ActivateModsDialog dialog(missingAssets, m_window); if (dialog.exec() == QDialog::Accepted) { // activate the required mods, then enable all esps std::set<QString> modsToActivate = dialog.getModsToActivate(); - for (std::set<QString>::iterator iter = modsToActivate.begin(); iter != modsToActivate.end(); ++iter) { + for (std::set<QString>::iterator iter = modsToActivate.begin(); + iter != modsToActivate.end(); ++iter) { if ((*iter != "<data>") && (*iter != "<overwrite>")) { unsigned int modIndex = ModInfo::getIndex(*iter); m_core.currentProfile()->setModEnabled(modIndex, true); @@ -288,7 +294,8 @@ void SavesTab::fixMods(SaveGameInfo::MissingAssets const &missingAssets) m_core.refreshLists(); std::set<QString> espsToActivate = dialog.getESPsToActivate(); - for (std::set<QString>::iterator iter = espsToActivate.begin(); iter != espsToActivate.end(); ++iter) { + for (std::set<QString>::iterator iter = espsToActivate.begin(); + iter != espsToActivate.end(); ++iter) { m_core.pluginList()->enableESP(*iter); } diff --git a/src/savestab.h b/src/savestab.h index 5ab8c55b..a903e4fb 100644 --- a/src/savestab.h +++ b/src/savestab.h @@ -4,18 +4,20 @@ #include "savegameinfo.h" #include <filterwidget.h> -namespace Ui { class MainWindow; } +namespace Ui +{ +class MainWindow; +} namespace MOBase { - class ISaveGame; - class ISaveGameInfoWidget; -} +class ISaveGame; +class ISaveGameInfoWidget; +} // namespace MOBase class MainWindow; class OrganizerCore; - class SavesTab : public QObject { Q_OBJECT; @@ -24,7 +26,7 @@ public: SavesTab(QWidget* window, OrganizerCore& core, Ui::MainWindow* ui); void refreshSaveList(); - void displaySaveGameInfo(QTreeWidgetItem *newItem); + void displaySaveGameInfo(QTreeWidgetItem* newItem); QDir currentSavesDir() const; @@ -48,17 +50,17 @@ private: SavesTabUi ui; MOBase::FilterWidget m_filter; std::vector<std::shared_ptr<const MOBase::ISaveGame>> m_SaveGames; - MOBase::ISaveGameInfoWidget *m_CurrentSaveView; + MOBase::ISaveGameInfoWidget* m_CurrentSaveView; QTimer m_SavesWatcherTimer; QFileSystemWatcher m_SavesWatcher; - void onContextMenu(const QPoint &pos); + void onContextMenu(const QPoint& pos); void deleteSavegame(); - void saveSelectionChanged(QTreeWidgetItem *newItem); - void fixMods(SaveGameInfo::MissingAssets const &missingAssets); + void saveSelectionChanged(QTreeWidgetItem* newItem); + void fixMods(SaveGameInfo::MissingAssets const& missingAssets); void refreshSavesIfOpen(); void openInExplorer(); }; -#endif // MODORGANIZER_SAVESTAB_INCLUDED +#endif // MODORGANIZER_SAVESTAB_INCLUDED diff --git a/src/savetextasdialog.cpp b/src/savetextasdialog.cpp index c2026ac4..9be7fdf2 100644 --- a/src/savetextasdialog.cpp +++ b/src/savetextasdialog.cpp @@ -1,15 +1,13 @@ #include "savetextasdialog.h" #include "ui_savetextasdialog.h" -#include <report.h> #include <QClipboard> #include <QFileDialog> - +#include <report.h> using MOBase::reportError; - -SaveTextAsDialog::SaveTextAsDialog(QWidget *parent) - : QDialog(parent), ui(new Ui::SaveTextAsDialog) +SaveTextAsDialog::SaveTextAsDialog(QWidget* parent) + : QDialog(parent), ui(new Ui::SaveTextAsDialog) { ui->setupUi(this); } @@ -19,7 +17,7 @@ SaveTextAsDialog::~SaveTextAsDialog() delete ui; } -void SaveTextAsDialog::setText(const QString &text) +void SaveTextAsDialog::setText(const QString& text) { ui->textEdit->setPlainText(text); } @@ -31,13 +29,14 @@ void SaveTextAsDialog::on_closeBtn_clicked() void SaveTextAsDialog::on_clipboardBtn_clicked() { - QClipboard *clipboard = QApplication::clipboard(); + QClipboard* clipboard = QApplication::clipboard(); clipboard->setText(ui->textEdit->toPlainText()); } void SaveTextAsDialog::on_saveAsBtn_clicked() { - QString fileName = QFileDialog::getSaveFileName(this, tr("Save CSV"), QString(), tr("Text Files") + " (*.txt *.csv)"); + QString fileName = QFileDialog::getSaveFileName(this, tr("Save CSV"), QString(), + tr("Text Files") + " (*.txt *.csv)"); if (!fileName.isEmpty()) { QFile file(fileName); if (!file.open(QIODevice::WriteOnly)) { diff --git a/src/savetextasdialog.h b/src/savetextasdialog.h index d93bd21d..0d4423fe 100644 --- a/src/savetextasdialog.h +++ b/src/savetextasdialog.h @@ -3,19 +3,20 @@ #include <QDialog> -namespace Ui { +namespace Ui +{ class SaveTextAsDialog; } class SaveTextAsDialog : public QDialog { Q_OBJECT - + public: - explicit SaveTextAsDialog(QWidget *parent = 0); + explicit SaveTextAsDialog(QWidget* parent = 0); ~SaveTextAsDialog(); - void setText(const QString &text); + void setText(const QString& text); private slots: void on_closeBtn_clicked(); @@ -25,7 +26,7 @@ private slots: void on_saveAsBtn_clicked(); private: - Ui::SaveTextAsDialog *ui; + Ui::SaveTextAsDialog* ui; }; -#endif // SAVETEXTASDIALOG_H +#endif // SAVETEXTASDIALOG_H diff --git a/src/selectiondialog.cpp b/src/selectiondialog.cpp index c65ffaa9..ec190ca9 100644 --- a/src/selectiondialog.cpp +++ b/src/selectiondialog.cpp @@ -22,8 +22,10 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QCommandLinkButton> -SelectionDialog::SelectionDialog(const QString &description, QWidget *parent, const QSize &iconSize) - : QDialog(parent), ui(new Ui::SelectionDialog), m_Choice(nullptr), m_ValidateByData(false), m_IconSize(iconSize) +SelectionDialog::SelectionDialog(const QString& description, QWidget* parent, + const QSize& iconSize) + : QDialog(parent), ui(new Ui::SelectionDialog), m_Choice(nullptr), + m_ValidateByData(false), m_IconSize(iconSize) { ui->setupUi(this); @@ -35,27 +37,33 @@ SelectionDialog::~SelectionDialog() delete ui; } -void SelectionDialog::addChoice(const QString &buttonText, const QString &description, const QVariant &data) +void SelectionDialog::addChoice(const QString& buttonText, const QString& description, + const QVariant& data) { - QAbstractButton *button = new QCommandLinkButton(buttonText, description, ui->buttonBox); + QAbstractButton* button = + new QCommandLinkButton(buttonText, description, ui->buttonBox); if (m_IconSize.isValid()) { button->setIconSize(m_IconSize); } button->setProperty("data", data); ui->buttonBox->addButton(button, QDialogButtonBox::AcceptRole); - if (data.isValid()) m_ValidateByData = true; + if (data.isValid()) + m_ValidateByData = true; } -void SelectionDialog::addChoice(const QIcon &icon, const QString &buttonText, const QString &description, const QVariant &data) +void SelectionDialog::addChoice(const QIcon& icon, const QString& buttonText, + const QString& description, const QVariant& data) { - QAbstractButton *button = new QCommandLinkButton(buttonText, description, ui->buttonBox); + QAbstractButton* button = + new QCommandLinkButton(buttonText, description, ui->buttonBox); if (m_IconSize.isValid()) { button->setIconSize(m_IconSize); } button->setIcon(icon); button->setProperty("data", data); ui->buttonBox->addButton(button, QDialogButtonBox::AcceptRole); - if (data.isValid()) m_ValidateByData = true; + if (data.isValid()) + m_ValidateByData = true; } int SelectionDialog::numChoices() const @@ -68,7 +76,6 @@ QVariant SelectionDialog::getChoiceData() return m_Choice->property("data"); } - QString SelectionDialog::getChoiceString() { if ((m_Choice == nullptr) || @@ -93,7 +100,7 @@ void SelectionDialog::disableCancel() ui->cancelButton->setHidden(true); } -void SelectionDialog::on_buttonBox_clicked(QAbstractButton *button) +void SelectionDialog::on_buttonBox_clicked(QAbstractButton* button) { m_Choice = button; if (!m_ValidateByData || m_Choice->property("data").isValid()) { diff --git a/src/selectiondialog.h b/src/selectiondialog.h index 472baa19..8c333d3d 100644 --- a/src/selectiondialog.h +++ b/src/selectiondialog.h @@ -20,33 +20,38 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef SELECTIONDIALOG_H #define SELECTIONDIALOG_H -#include <QDialog> #include <QAbstractButton> +#include <QDialog> -namespace Ui { +namespace Ui +{ class SelectionDialog; } class SelectionDialog : public QDialog { Q_OBJECT - -public: - explicit SelectionDialog(const QString &description, QWidget *parent = 0, const QSize &iconSize = QSize()); +public: + explicit SelectionDialog(const QString& description, QWidget* parent = 0, + const QSize& iconSize = QSize()); ~SelectionDialog(); /** * @brief add a choice to the dialog * @param buttonText the text to be displayed on the button - * @param description the description that shows up under in small letters inside the button - * @param data data to be stored with the button. Please note that as soon as one choice has data associated with it (non-invalid QVariant) - * all buttons that contain no data will be treated as "cancel" buttons + * @param description the description that shows up under in small letters inside the + * button + * @param data data to be stored with the button. Please note that as soon as one + * choice has data associated with it (non-invalid QVariant) all buttons that contain + * no data will be treated as "cancel" buttons */ - void addChoice(const QString &buttonText, const QString &description, const QVariant &data); + void addChoice(const QString& buttonText, const QString& description, + const QVariant& data); - void addChoice(const QIcon &icon, const QString &buttonText, const QString &description, const QVariant &data); + void addChoice(const QIcon& icon, const QString& buttonText, + const QString& description, const QVariant& data); int numChoices() const; @@ -58,17 +63,15 @@ public: private slots: - void on_buttonBox_clicked(QAbstractButton *button); + void on_buttonBox_clicked(QAbstractButton* button); void on_cancelButton_clicked(); private: - - Ui::SelectionDialog *ui; - QAbstractButton *m_Choice; + Ui::SelectionDialog* ui; + QAbstractButton* m_Choice; bool m_ValidateByData; QSize m_IconSize; - }; -#endif // SELECTIONDIALOG_H +#endif // SELECTIONDIALOG_H diff --git a/src/selfupdater.cpp b/src/selfupdater.cpp index 50100faa..7762c900 100644 --- a/src/selfupdater.cpp +++ b/src/selfupdater.cpp @@ -19,21 +19,22 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "selfupdater.h" -#include "utility.h" +#include "bbcode.h" +#include "downloadmanager.h" #include "iplugingame.h" #include "messagedialog.h" -#include "downloadmanager.h" #include "nexusinterface.h" #include "nxmaccessmanager.h" -#include "settings.h" -#include "bbcode.h" -#include "plugincontainer.h" #include "organizercore.h" -#include <versioninfo.h> -#include <report.h> +#include "plugincontainer.h" +#include "settings.h" #include "shared/util.h" #include "updatedialog.h" +#include "utility.h" +#include <report.h> +#include <versioninfo.h> +#include <QAbstractButton> #include <QApplication> #include <QCoreApplication> #include <QDir> @@ -41,8 +42,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QLibrary> #include <QMessageBox> #include <QNetworkAccessManager> -#include <QNetworkRequest> #include <QNetworkReply> +#include <QNetworkRequest> #include <QProcess> #include <QProgressDialog> #include <QStringList> @@ -50,44 +51,37 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QUrl> #include <QVariantList> #include <QVariantMap> -#include <QAbstractButton> #include <Qt> -#include <QtDebug> #include <QtAlgorithms> +#include <QtDebug> #include <boost/bind/bind.hpp> -#include <Windows.h> //for VS_FIXEDFILEINFO, GetLastError +#include <Windows.h> //for VS_FIXEDFILEINFO, GetLastError #include <exception> #include <map> -#include <stddef.h> //for size_t +#include <stddef.h> //for size_t #include <stdexcept> using namespace MOBase; using namespace MOShared; -SelfUpdater::SelfUpdater(NexusInterface *nexusInterface) - : m_Parent(nullptr) - , m_Interface(nexusInterface) - , m_Reply(nullptr) - , m_Attempts(3) +SelfUpdater::SelfUpdater(NexusInterface* nexusInterface) + : m_Parent(nullptr), m_Interface(nexusInterface), m_Reply(nullptr), m_Attempts(3) { m_MOVersion = createVersionInfo(); } +SelfUpdater::~SelfUpdater() {} -SelfUpdater::~SelfUpdater() -{ -} - -void SelfUpdater::setUserInterface(QWidget *widget) +void SelfUpdater::setUserInterface(QWidget* widget) { m_Parent = widget; } -void SelfUpdater::setPluginContainer(PluginContainer *pluginContainer) +void SelfUpdater::setPluginContainer(PluginContainer* pluginContainer) { m_Interface->setPluginContainer(pluginContainer); } @@ -107,53 +101,52 @@ void SelfUpdater::testForUpdate(const Settings& settings) // TODO: if prereleases are disabled we could just request the latest release // directly try { - m_GitHub.releases(GitHub::Repository("Modorganizer2", "modorganizer"), - [this](const QJsonArray &releases) { - if (releases.isEmpty()) { - // error message already logged - return; - } + m_GitHub.releases( + GitHub::Repository("Modorganizer2", "modorganizer"), + [this](const QJsonArray& releases) { + if (releases.isEmpty()) { + // error message already logged + return; + } - // We store all releases: - CandidatesMap mreleases; - for (const QJsonValue &releaseVal : releases) { - QJsonObject release = releaseVal.toObject(); - if (!release["draft"].toBool() && (Settings::instance().usePrereleases() - || !release["prerelease"].toBool())) { - auto version = VersionInfo(release["tag_name"].toString()); - mreleases[version] = release; - } - } + // We store all releases: + CandidatesMap mreleases; + for (const QJsonValue& releaseVal : releases) { + QJsonObject release = releaseVal.toObject(); + if (!release["draft"].toBool() && (Settings::instance().usePrereleases() || + !release["prerelease"].toBool())) { + auto version = VersionInfo(release["tag_name"].toString()); + mreleases[version] = release; + } + } - if (!mreleases.empty()) { - auto lastKey = mreleases.begin()->first; - if (lastKey > this->m_MOVersion) { + if (!mreleases.empty()) { + auto lastKey = mreleases.begin()->first; + if (lastKey > this->m_MOVersion) { - // Fill m_UpdateCandidates with version strictly greater than the - // current version: - m_UpdateCandidates.clear(); - for (auto p : mreleases) { - if (p.first > this->m_MOVersion) { - m_UpdateCandidates.insert(p); + // Fill m_UpdateCandidates with version strictly greater than the + // current version: + m_UpdateCandidates.clear(); + for (auto p : mreleases) { + if (p.first > this->m_MOVersion) { + m_UpdateCandidates.insert(p); + } + } + log::info("update available: {} -> {}", + this->m_MOVersion.displayString(3), lastKey.displayString(3)); + emit updateAvailable(); + } else if (lastKey < this->m_MOVersion) { + // this could happen if the user switches from using prereleases to + // stable builds. Should we downgrade? + log::debug("This version is newer than the latest released one: {} -> {}", + this->m_MOVersion.displayString(3), lastKey.displayString(3)); } } - log::info("update available: {} -> {}", - this->m_MOVersion.displayString(3), - lastKey.displayString(3)); - emit updateAvailable(); - } else if (lastKey < this->m_MOVersion) { - // this could happen if the user switches from using prereleases to - // stable builds. Should we downgrade? - log::debug("This version is newer than the latest released one: {} -> {}", - this->m_MOVersion.displayString(3), - lastKey.displayString(3)); - } - } - }); + }); } - //Catch all is bad by design, should be improved + // Catch all is bad by design, should be improved catch (...) { - log::debug("Unable to connect to github.com to check version"); + log::debug("Unable to connect to github.com to check version"); } } @@ -165,10 +158,8 @@ void SelfUpdater::startUpdate() auto latestRelease = m_UpdateCandidates.begin()->second; UpdateDialog dialog(m_Parent); - dialog.setVersions( - MOShared::createVersionInfo().displayString(3), - latestRelease["tag_name"].toString() - ); + dialog.setVersions(MOShared::createVersionInfo().displayString(3), + latestRelease["tag_name"].toString()); // We concatenate release details. We only include pre-release if those are // the latest release: @@ -191,14 +182,15 @@ void SelfUpdater::startUpdate() details += release["body"].toString(); } - // Need to call setDetailedText to create the QTextEdit and then be able to retrieve it: + // Need to call setDetailedText to create the QTextEdit and then be able to retrieve + // it: dialog.setChangeLogs(details); int res = dialog.exec(); if (dialog.result() == QDialog::Accepted) { bool found = false; - for (const QJsonValue &assetVal : latestRelease["assets"].toArray()) { + for (const QJsonValue& assetVal : latestRelease["assets"].toArray()) { QJsonObject asset = assetVal.toObject(); if (asset["content_type"].toString() == "application/x-msdownload") { openOutputFile(asset["name"].toString()); @@ -215,7 +207,6 @@ void SelfUpdater::startUpdate() } } - void SelfUpdater::showProgress() { if (m_Progress == nullptr) { @@ -238,29 +229,31 @@ void SelfUpdater::closeProgress() } } -void SelfUpdater::openOutputFile(const QString &fileName) +void SelfUpdater::openOutputFile(const QString& fileName) { - QString outputPath = QDir::fromNativeSeparators(qApp->property("dataPath").toString()) + "/" + fileName; + QString outputPath = + QDir::fromNativeSeparators(qApp->property("dataPath").toString()) + "/" + + fileName; log::debug("downloading to {}", outputPath); m_UpdateFile.setFileName(outputPath); m_UpdateFile.open(QIODevice::WriteOnly); } -void SelfUpdater::download(const QString &downloadLink) +void SelfUpdater::download(const QString& downloadLink) { - QNetworkAccessManager *accessManager = m_Interface->getAccessManager(); + QNetworkAccessManager* accessManager = m_Interface->getAccessManager(); QUrl dlUrl(downloadLink); QNetworkRequest request(dlUrl); m_Canceled = false; - m_Reply = accessManager->get(request); + m_Reply = accessManager->get(request); showProgress(); - connect(m_Reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(downloadProgress(qint64, qint64))); + connect(m_Reply, SIGNAL(downloadProgress(qint64, qint64)), this, + SLOT(downloadProgress(qint64, qint64))); connect(m_Reply, SIGNAL(finished()), this, SLOT(downloadFinished())); connect(m_Reply, SIGNAL(readyRead()), this, SLOT(downloadReadyRead())); } - void SelfUpdater::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) { if (m_Reply != nullptr) { @@ -276,7 +269,6 @@ void SelfUpdater::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) } } - void SelfUpdater::downloadReadyRead() { if (m_Reply != nullptr) { @@ -284,14 +276,14 @@ void SelfUpdater::downloadReadyRead() } } - void SelfUpdater::downloadFinished() { int error = QNetworkReply::NoError; if (m_Reply != nullptr) { if (m_Reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 302) { - QUrl url = m_Reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); + QUrl url = + m_Reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); m_UpdateFile.reset(); download(url.toString()); return; @@ -300,7 +292,9 @@ void SelfUpdater::downloadFinished() error = m_Reply->error(); - if (m_Reply->header(QNetworkRequest::ContentTypeHeader).toString().startsWith("text", Qt::CaseInsensitive)) { + if (m_Reply->header(QNetworkRequest::ContentTypeHeader) + .toString() + .startsWith("text", Qt::CaseInsensitive)) { m_Canceled = true; } @@ -313,9 +307,7 @@ void SelfUpdater::downloadFinished() m_UpdateFile.close(); - if ((m_UpdateFile.size() == 0) || - (error != QNetworkReply::NoError) || - m_Canceled) { + if ((m_UpdateFile.size() == 0) || (error != QNetworkReply::NoError) || m_Canceled) { if (!m_Canceled) { reportError(tr("Download failed: %1").arg(error)); } @@ -327,35 +319,32 @@ void SelfUpdater::downloadFinished() try { installUpdate(); - } catch (const std::exception &e) { + } catch (const std::exception& e) { reportError(tr("Failed to install update: %1").arg(e.what())); } } - void SelfUpdater::downloadCancel() { m_Canceled = true; } - void SelfUpdater::installUpdate() { const QString parameters = "/DIR=\"" + qApp->applicationDirPath() + "\" "; - const auto r = shell::Execute(m_UpdateFile.fileName(), parameters); + const auto r = shell::Execute(m_UpdateFile.fileName(), parameters); if (r.success()) { QCoreApplication::quit(); } else { - reportError(tr("Failed to start %1: %2") - .arg(m_UpdateFile.fileName()) - .arg(r.toString())); + reportError( + tr("Failed to start %1: %2").arg(m_UpdateFile.fileName()).arg(r.toString())); } m_UpdateFile.remove(); } -void SelfUpdater::report7ZipError(QString const &errorMessage) +void SelfUpdater::report7ZipError(QString const& errorMessage) { QMessageBox::critical(m_Parent, tr("Error"), errorMessage); } diff --git a/src/selfupdater.h b/src/selfupdater.h index baf830d1..cc68ad27 100644 --- a/src/selfupdater.h +++ b/src/selfupdater.h @@ -22,19 +22,22 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <map> -#include <versioninfo.h> #include <github.h> +#include <versioninfo.h> class Archive; class NexusInterface; class PluginContainer; -namespace MOBase { class IPluginGame; } +namespace MOBase +{ +class IPluginGame; +} #include <QFile> #include <QObject> #include <QString> #include <QVariant> -#include <QtGlobal> //for qint64 +#include <QtGlobal> //for qint64 class QNetworkReply; class QProgressDialog; @@ -48,14 +51,15 @@ class Settings; * 2. if the updateAvailable() signal is received, allow the user to start the update * 3. if the user start the update, call startUpdate() * 4. startUpdate() will first query a list of files, try to determine if there is an - * incremental update. If not, the user will have to confirm the download of a full download. - * Once the correct file is selected, it is downloaded. - * 5. before the downloaded file is extracted, existing files that are going to be replaced are - * moved to "update_backup" on because files that are currently open can't be replaced. + * incremental update. If not, the user will have to confirm the download of a full + *download. Once the correct file is selected, it is downloaded. + * 5. before the downloaded file is extracted, existing files that are going to be + *replaced are moved to "update_backup" on because files that are currently open can't + *be replaced. * 6. the update is extracted and then deleted * 7. finally, a restart is requested via signal. - * 8. at restart, Mod Organizer will remove the update_backup directory since none of the files - * should now be open + * 8. at restart, Mod Organizer will remove the update_backup directory since none of + *the files should now be open * * @todo use NexusBridge **/ @@ -65,7 +69,6 @@ class SelfUpdater : public QObject Q_OBJECT public: - /** * @brief constructor * @@ -73,17 +76,17 @@ public: * @param parent parent widget * @todo passing the nexus interface is unneccessary **/ - explicit SelfUpdater(NexusInterface *nexusInterface); + explicit SelfUpdater(NexusInterface* nexusInterface); virtual ~SelfUpdater(); - void setUserInterface(QWidget *widget); + void setUserInterface(QWidget* widget); - void setPluginContainer(PluginContainer *pluginContainer); + void setPluginContainer(PluginContainer* pluginContainer); /** - * @brief request information about the current version - **/ + * @brief request information about the current version + **/ void testForUpdate(const Settings& settings); /** @@ -112,14 +115,13 @@ signals: /** * @brief emitted if a message of the day was received **/ - void motdAvailable(const QString &motd); + void motdAvailable(const QString& motd); private: - - void openOutputFile(const QString &fileName); - void download(const QString &downloadLink); + void openOutputFile(const QString& fileName); + void download(const QString& downloadLink); void installUpdate(); - void report7ZipError(const QString &errorMessage); + void report7ZipError(const QString& errorMessage); void showProgress(); void closeProgress(); @@ -131,23 +133,21 @@ private slots: void downloadCancel(); private: - - QWidget *m_Parent; + QWidget* m_Parent; MOBase::VersionInfo m_MOVersion; - NexusInterface *m_Interface; + NexusInterface* m_Interface; QFile m_UpdateFile; - QNetworkReply *m_Reply; - QProgressDialog *m_Progress { nullptr }; + QNetworkReply* m_Reply; + QProgressDialog* m_Progress{nullptr}; bool m_Canceled; int m_Attempts; GitHub m_GitHub; - // Map from version to release, in decreasing order (first element is the latest release): + // Map from version to release, in decreasing order (first element is the latest + // release): using CandidatesMap = std::map<MOBase::VersionInfo, QJsonObject, std::greater<>>; CandidatesMap m_UpdateCandidates; - }; - -#endif // SELFUPDATER_H +#endif // SELFUPDATER_H diff --git a/src/serverinfo.cpp b/src/serverinfo.cpp index 8d8c98fe..4d99f6db 100644 --- a/src/serverinfo.cpp +++ b/src/serverinfo.cpp @@ -5,17 +5,12 @@ using namespace MOBase; const std::size_t MaxDownloadCount = 5; +ServerInfo::ServerInfo() : ServerInfo({}, false, {}, 0, {}) {} -ServerInfo::ServerInfo() - : ServerInfo({}, false, {}, 0, {}) -{ -} - -ServerInfo::ServerInfo( - QString name, bool premium, QDate last, int preferred, - SpeedList lastDownloads) : - m_name(std::move(name)), m_premium(premium), m_lastSeen(std::move(last)), - m_preferred(preferred), m_lastDownloads(std::move(lastDownloads)) +ServerInfo::ServerInfo(QString name, bool premium, QDate last, int preferred, + SpeedList lastDownloads) + : m_name(std::move(name)), m_premium(premium), m_lastSeen(std::move(last)), + m_preferred(preferred), m_lastDownloads(std::move(lastDownloads)) { if (m_lastDownloads.size() > MaxDownloadCount) { m_lastDownloads.resize(MaxDownloadCount); @@ -84,18 +79,15 @@ int ServerInfo::averageSpeed() const void ServerInfo::addDownload(int bytesPerSecond) { if (bytesPerSecond <= 0) { - log::error( - "trying to add download with {} B/s to server '{}'; ignoring", - bytesPerSecond, m_name); + log::error("trying to add download with {} B/s to server '{}'; ignoring", + bytesPerSecond, m_name); return; } if (m_lastDownloads.size() == MaxDownloadCount) { - std::rotate( - m_lastDownloads.begin(), - m_lastDownloads.begin() + 1, - m_lastDownloads.end()); + std::rotate(m_lastDownloads.begin(), m_lastDownloads.begin() + 1, + m_lastDownloads.end()); m_lastDownloads.back() = bytesPerSecond; } else { @@ -105,12 +97,11 @@ void ServerInfo::addDownload(int bytesPerSecond) log::debug("added download at {} B/s to server '{}'", bytesPerSecond, m_name); } - void ServerList::add(ServerInfo s) { m_servers.push_back(std::move(s)); - std::sort(m_servers.begin(), m_servers.end(), [](auto&& a, auto&& b){ + std::sort(m_servers.begin(), m_servers.end(), [](auto&& a, auto&& b) { return (a.preferred() < b.preferred()); }); } @@ -162,13 +153,13 @@ void ServerList::cleanup() { QDate now = QDate::currentDate(); - for (auto itor=m_servers.begin(); itor!=m_servers.end(); ) { + for (auto itor = m_servers.begin(); itor != m_servers.end();) { const QDate lastSeen = itor->lastSeen(); if (lastSeen.daysTo(now) > 30) { - log::debug( - "removing server {} since it hasn't been available for downloads " - "in over a month", itor->name()); + log::debug("removing server {} since it hasn't been available for downloads " + "in over a month", + itor->name()); itor = m_servers.erase(itor); } else { diff --git a/src/serverinfo.h b/src/serverinfo.h index 0bec89cc..00b47643 100644 --- a/src/serverinfo.h +++ b/src/serverinfo.h @@ -1,9 +1,9 @@ #ifndef SERVERINFO_H #define SERVERINFO_H -#include <QString> #include <QDate> #include <QMetaType> +#include <QString> class ServerInfo { @@ -11,9 +11,8 @@ public: using SpeedList = std::vector<int>; ServerInfo(); - ServerInfo( - QString name, bool premium, QDate lastSeen, int preferred, - SpeedList lastDownloads); + ServerInfo(QString name, bool premium, QDate lastSeen, int preferred, + SpeedList lastDownloads); const QString& name() const; @@ -40,12 +39,11 @@ private: Q_DECLARE_METATYPE(ServerInfo) - class ServerList { public: - using container = std::vector<ServerInfo>; - using iterator = container::iterator; + using container = std::vector<ServerInfo>; + using iterator = container::iterator; using const_iterator = container::const_iterator; void add(ServerInfo s); @@ -67,4 +65,4 @@ private: container m_servers; }; -#endif // SERVERINFO_H +#endif // SERVERINFO_H diff --git a/src/settings.cpp b/src/settings.cpp index c0eb80ca..fc9985f4 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -18,22 +18,21 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ #include "settings.h" -#include "settingsutilities.h" -#include "serverinfo.h" +#include "env.h" +#include "envmetrics.h" #include "executableslist.h" #include "instancemanager.h" -#include "shared/appconfig.h" -#include "env.h" #include "modelutils.h" -#include "envmetrics.h" +#include "serverinfo.h" +#include "settingsutilities.h" +#include "shared/appconfig.h" #include <expanderwidget.h> -#include <utility.h> #include <iplugingame.h> +#include <utility.h> using namespace MOBase; using namespace MOShared; - EndorsementState endorsementStateFromString(const QString& s) { if (s == "Endorsed") { @@ -47,31 +46,27 @@ EndorsementState endorsementStateFromString(const QString& s) QString toString(EndorsementState s) { - switch (s) - { + switch (s) { case EndorsementState::Accepted: return "Endorsed"; case EndorsementState::Refused: return "Abstained"; - case EndorsementState::NoDecision: // fall-through + case EndorsementState::NoDecision: // fall-through default: return {}; } } +Settings* Settings::s_Instance = nullptr; -Settings *Settings::s_Instance = nullptr; - -Settings::Settings(const QString& path, bool globalInstance) : - m_Settings(path, QSettings::IniFormat), - m_Game(m_Settings), m_Geometry(m_Settings), - m_Widgets(m_Settings, globalInstance), m_Colors(m_Settings), - m_Plugins(m_Settings), m_Paths(m_Settings), - m_Network(m_Settings, globalInstance), - m_Nexus(*this, m_Settings), m_Steam(*this, m_Settings), - m_Interface(m_Settings), m_Diagnostics(m_Settings) +Settings::Settings(const QString& path, bool globalInstance) + : m_Settings(path, QSettings::IniFormat), m_Game(m_Settings), + m_Geometry(m_Settings), m_Widgets(m_Settings, globalInstance), + m_Colors(m_Settings), m_Plugins(m_Settings), m_Paths(m_Settings), + m_Network(m_Settings, globalInstance), m_Nexus(*this, m_Settings), + m_Steam(*this, m_Settings), m_Interface(m_Settings), m_Diagnostics(m_Settings) { if (globalInstance) { if (s_Instance != nullptr) { @@ -104,8 +99,8 @@ Settings* Settings::maybeInstance() return s_Instance; } -void Settings::processUpdates( - const QVersionNumber& currentVersion, const QVersionNumber& lastVersion) +void Settings::processUpdates(const QVersionNumber& currentVersion, + const QVersionNumber& lastVersion) { if (firstStart()) { set(m_Settings, "General", "version", currentVersion.toString()); @@ -116,9 +111,8 @@ void Settings::processUpdates( return; } - log::info( - "updating from {} to {}", - lastVersion.toString(), currentVersion.toString()); + log::info("updating from {} to {}", lastVersion.toString(), + currentVersion.toString()); auto version = [&](const QVersionNumber& v, auto&& f) { if (lastVersion < v) { @@ -127,7 +121,7 @@ void Settings::processUpdates( } }; - version({2, 2, 0}, [&]{ + version({2, 2, 0}, [&] { remove(m_Settings, "Settings", "steam_password"); remove(m_Settings, "Settings", "nexus_username"); remove(m_Settings, "Settings", "nexus_password"); @@ -139,7 +133,7 @@ void Settings::processUpdates( removeSection(m_Settings, "Servers"); }); - version({2, 2, 1}, [&]{ + version({2, 2, 1}, [&] { remove(m_Settings, "General", "mod_info_tabs"); remove(m_Settings, "General", "mod_info_conflict_expanders"); remove(m_Settings, "General", "mod_info_conflicts"); @@ -149,7 +143,7 @@ void Settings::processUpdates( remove(m_Settings, "General", "mod_info_conflicts_overwritten"); }); - version({2, 2, 2}, [&]{ + version({2, 2, 2}, [&] { // log splitter is gone, it's a dock now remove(m_Settings, "General", "log_split"); @@ -183,13 +177,13 @@ void Settings::processUpdates( m_Network.updateFromOldMap(); }); - version({ 2, 4, 0 }, [&] { + version({2, 4, 0}, [&] { // removed remove(m_Settings, "Settings", "hide_unchecked_plugins"); remove(m_Settings, "Settings", "load_mechanism"); }); - //save version in all case + // save version in all case set(m_Settings, "General", "version", currentVersion.toString()); log::debug("updating done"); @@ -242,7 +236,7 @@ void Settings::setRefreshThreadCount(std::size_t n) const std::optional<QVersionNumber> Settings::version() const { - if (auto v=getOptional<QString>(m_Settings, "General", "version")) { + if (auto v = getOptional<QString>(m_Settings, "General", "version")) { return QVersionNumber::fromString(*v).normalized(); } @@ -261,18 +255,17 @@ void Settings::setFirstStart(bool b) QString Settings::executablesBlacklist() const { - static const QString def = (QStringList() - << "Chrome.exe" - << "Firefox.exe" - << "TSVNCache.exe" - << "TGitCache.exe" - << "Steam.exe" - << "GameOverlayUI.exe" - << "Discord.exe" - << "GalaxyClient.exe" - << "Spotify.exe" - << "Brave.exe" - ).join(";"); + static const QString def = (QStringList() << "Chrome.exe" + << "Firefox.exe" + << "TSVNCache.exe" + << "TGitCache.exe" + << "Steam.exe" + << "GameOverlayUI.exe" + << "Discord.exe" + << "GalaxyClient.exe" + << "Spotify.exe" + << "Brave.exe") + .join(";"); return get<QString>(m_Settings, "Settings", "executable_blacklist", def); } @@ -318,7 +311,7 @@ std::vector<std::map<QString, QVariant>> Settings::executables() const ScopedReadArray sra(m_Settings, "customExecutables"); std::vector<std::map<QString, QVariant>> v; - sra.for_each([&]{ + sra.for_each([&] { std::map<QString, QVariant> map; for (auto&& key : sra.keys()) { @@ -516,11 +509,9 @@ QSettings::Status Settings::iniStatus() const void Settings::dump() const { - static const QStringList ignore({ - "username", "password", - "nexus_api_key", "nexus_username", "nexus_password", - "steam_username" - }); + static const QStringList ignore({"username", "password", "nexus_api_key", + "nexus_username", "nexus_password", + "steam_username"}); log::debug("settings:"); @@ -540,16 +531,14 @@ void Settings::dump() const m_Nexus.dump(); } -void Settings::managedGameChanged(IPluginGame const *gamePlugin) +void Settings::managedGameChanged(IPluginGame const* gamePlugin) { m_Game.setPlugin(gamePlugin); } - GameSettings::GameSettings(QSettings& settings) - : m_Settings(settings), m_GamePlugin(nullptr) -{ -} + : m_Settings(settings), m_GamePlugin(nullptr) +{} const MOBase::IPluginGame* GameSettings::plugin() { @@ -573,7 +562,7 @@ void GameSettings::setForceEnableCoreFiles(bool b) std::optional<QString> GameSettings::directory() const { - if (auto v=getOptional<QByteArray>(m_Settings, "General", "gamePath")) { + if (auto v = getOptional<QByteArray>(m_Settings, "General", "gamePath")) { return QString::fromUtf8(*v); } @@ -607,7 +596,7 @@ void GameSettings::setEdition(const QString& name) std::optional<QString> GameSettings::selectedProfileName() const { - if (auto v=getOptional<QByteArray>(m_Settings, "General", "selected_profile")) { + if (auto v = getOptional<QByteArray>(m_Settings, "General", "selected_profile")) { return QString::fromUtf8(*v); } @@ -619,10 +608,7 @@ void GameSettings::setSelectedProfileName(const QString& name) set(m_Settings, "General", "selected_profile", name.toUtf8()); } -GeometrySettings::GeometrySettings(QSettings& s) - : m_Settings(s), m_Reset(false) -{ -} +GeometrySettings::GeometrySettings(QSettings& s) : m_Settings(s), m_Reset(false) {} void GeometrySettings::requestReset() { @@ -671,7 +657,7 @@ void GeometrySettings::saveWindowGeometry(const QWidget* w) bool GeometrySettings::restoreWindowGeometry(QWidget* w) const { - if (auto v=getOptional<QByteArray>(m_Settings, "Geometry", geoSettingName(w))) { + if (auto v = getOptional<QByteArray>(m_Settings, "Geometry", geoSettingName(w))) { w->restoreGeometry(*v); ensureWindowOnScreen(w); return true; @@ -701,14 +687,13 @@ void GeometrySettings::ensureWindowOnScreen(QWidget* w) const // desktop geometry, made smaller to make sure there isn't just a few pixels const auto originalDg = env::Environment().metrics().desktopGeometry(); - const auto dg = originalDg.adjusted(borders, borders, -borders, -borders); + const auto dg = originalDg.adjusted(borders, borders, -borders, -borders); const auto g = w->geometry(); if (!dg.intersects(g)) { - log::warn( - "window '{}' is offscreen, moving to main monitor; geo={}, desktop={}", - w->objectName(), g, originalDg); + log::warn("window '{}' is offscreen, moving to main monitor; geo={}, desktop={}", + w->objectName(), g, originalDg); // widget is off-screen, center it on main monitor centerOnMonitor(w, -1); @@ -725,7 +710,7 @@ void GeometrySettings::saveState(const QMainWindow* w) bool GeometrySettings::restoreState(QMainWindow* w) const { - if (auto v=getOptional<QByteArray>(m_Settings, "Geometry", stateSettingName(w))) { + if (auto v = getOptional<QByteArray>(m_Settings, "Geometry", stateSettingName(w))) { w->restoreState(*v); return true; } @@ -740,7 +725,7 @@ void GeometrySettings::saveState(const QHeaderView* w) bool GeometrySettings::restoreState(QHeaderView* w) const { - if (auto v=getOptional<QByteArray>(m_Settings, "Geometry", stateSettingName(w))) { + if (auto v = getOptional<QByteArray>(m_Settings, "Geometry", stateSettingName(w))) { w->restoreState(*v); return true; } @@ -755,7 +740,7 @@ void GeometrySettings::saveState(const QSplitter* w) bool GeometrySettings::restoreState(QSplitter* w) const { - if (auto v=getOptional<QByteArray>(m_Settings, "Geometry", stateSettingName(w))) { + if (auto v = getOptional<QByteArray>(m_Settings, "Geometry", stateSettingName(w))) { w->restoreState(*v); return true; } @@ -770,7 +755,8 @@ void GeometrySettings::saveState(const ExpanderWidget* expander) bool GeometrySettings::restoreState(ExpanderWidget* expander) const { - if (auto v=getOptional<QByteArray>(m_Settings, "Geometry", stateSettingName(expander))) { + if (auto v = + getOptional<QByteArray>(m_Settings, "Geometry", stateSettingName(expander))) { expander->restoreState(*v); return true; } @@ -785,7 +771,8 @@ void GeometrySettings::saveVisibility(const QWidget* w) bool GeometrySettings::restoreVisibility(QWidget* w, std::optional<bool> def) const { - if (auto v=getOptional<bool>(m_Settings, "Geometry", visibilitySettingName(w), def)) { + if (auto v = + getOptional<bool>(m_Settings, "Geometry", visibilitySettingName(w), def)) { w->setVisible(*v); return true; } @@ -796,7 +783,7 @@ bool GeometrySettings::restoreVisibility(QWidget* w, std::optional<bool> def) co void GeometrySettings::restoreToolbars(QMainWindow* w) const { // all toolbars have the same size and button style settings - const auto size = getOptional<QSize>(m_Settings, "Geometry", "toolbar_size"); + const auto size = getOptional<QSize>(m_Settings, "Geometry", "toolbar_size"); const auto style = getOptional<int>(m_Settings, "Geometry", "toolbar_button_style"); for (auto* tb : w->findChildren<QToolBar*>()) { @@ -827,7 +814,8 @@ void GeometrySettings::saveToolbars(const QMainWindow* w) const auto* tb = tbs[0]; set(m_Settings, "Geometry", "toolbar_size", tb->iconSize()); - set(m_Settings, "Geometry", "toolbar_button_style", static_cast<int>(tb->toolButtonStyle())); + set(m_Settings, "Geometry", "toolbar_button_style", + static_cast<int>(tb->toolButtonStyle())); } } @@ -842,7 +830,7 @@ QStringList GeometrySettings::modInfoTabOrder() const int count = 0; stream >> count; - for (int i=0; i<count; ++i) { + for (int i = 0; i < count; ++i) { QString s; stream >> s; v.push_back(s); @@ -879,8 +867,8 @@ void GeometrySettings::setCenterDialogs(bool b) void GeometrySettings::centerOnMainWindowMonitor(QWidget* w) const { - const auto monitor = getOptional<int>( - m_Settings, "Geometry", "MainWindow_monitor").value_or(-1); + const auto monitor = + getOptional<int>(m_Settings, "Geometry", "MainWindow_monitor").value_or(-1); centerOnMonitor(w, monitor); } @@ -916,7 +904,7 @@ void GeometrySettings::centerOnParent(QWidget* w, QWidget* parent) void GeometrySettings::saveMainWindowMonitor(const QMainWindow* w) { - if (auto* handle=w->windowHandle()) { + if (auto* handle = w->windowHandle()) { if (auto* screen = handle->screen()) { const int screenId = QGuiApplication::screens().indexOf(screen); set(m_Settings, "Geometry", "MainWindow_monitor", screenId); @@ -927,8 +915,7 @@ void GeometrySettings::saveMainWindowMonitor(const QMainWindow* w) Qt::Orientation dockOrientation(const QMainWindow* mw, const QDockWidget* d) { // docks in these areas are horizontal - const auto horizontalAreas = - Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea; + const auto horizontalAreas = Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea; if (mw->dockWidgetArea(const_cast<QDockWidget*>(d)) & horizontalAreas) { return Qt::Horizontal; @@ -986,7 +973,7 @@ void GeometrySettings::restoreDocks(QMainWindow* mw) const // for each dock for (auto* dock : mw->findChildren<QDockWidget*>()) { - if (auto size=getOptional<int>(m_Settings, "Geometry", dockSettingName(dock))) { + if (auto size = getOptional<int>(m_Settings, "Geometry", dockSettingName(dock))) { // remember this dock, its size and orientation dockInfos.push_back({dock, *size, dockOrientation(mw, dock)}); } @@ -1001,18 +988,22 @@ void GeometrySettings::restoreDocks(QMainWindow* mw) const for (const auto& info : dockInfos) { mw->resizeDocks({info.d}, {info.size}, info.ori); } - }); + }); } - -WidgetSettings::WidgetSettings(QSettings& s, bool globalInstance) - : m_Settings(s) +WidgetSettings::WidgetSettings(QSettings& s, bool globalInstance) : m_Settings(s) { if (globalInstance) { MOBase::QuestionBoxMemory::setCallbacks( - [this](auto&& w, auto&& f){ return questionButton(w, f); }, - [this](auto&& w, auto&& b){ setQuestionWindowButton(w, b); }, - [this](auto&& w, auto&& f, auto&& b){ setQuestionFileButton(w, f, b); }); + [this](auto&& w, auto&& f) { + return questionButton(w, f); + }, + [this](auto&& w, auto&& b) { + setQuestionWindowButton(w, b); + }, + [this](auto&& w, auto&& f, auto&& b) { + setQuestionFileButton(w, f, b); + }); } } @@ -1027,9 +1018,11 @@ void WidgetSettings::saveTreeCheckState(const QTreeView* tv, int role) void WidgetSettings::restoreTreeCheckState(QTreeView* tv, int role) const { - if (auto states = getOptional<QVariantList>(m_Settings, "Widgets", indexSettingName(tv))) { + if (auto states = + getOptional<QVariantList>(m_Settings, "Widgets", indexSettingName(tv))) { auto allIndex = flatIndex(tv->model()); - MOBase::log::debug("restoreTreeCheckState: {}, {}", states->size(), allIndex.size()); + MOBase::log::debug("restoreTreeCheckState: {}, {}", states->size(), + allIndex.size()); if (states->size() != allIndex.size()) { return; } @@ -1052,7 +1045,8 @@ void WidgetSettings::saveTreeExpandState(const QTreeView* tv, int role) void WidgetSettings::restoreTreeExpandState(QTreeView* tv, int role) const { - if (auto expanded = getOptional<QVariantList>(m_Settings, "Widgets", indexSettingName(tv))) { + if (auto expanded = + getOptional<QVariantList>(m_Settings, "Widgets", indexSettingName(tv))) { tv->collapseAll(); for (auto index : flatIndex(tv->model())) { if (expanded->contains(index.data(role))) { @@ -1074,7 +1068,7 @@ void WidgetSettings::saveIndex(const QComboBox* cb) void WidgetSettings::restoreIndex(QComboBox* cb, std::optional<int> def) const { - if (auto v=getOptional<int>(m_Settings, "Widgets", indexSettingName(cb), def)) { + if (auto v = getOptional<int>(m_Settings, "Widgets", indexSettingName(cb), def)) { cb->setCurrentIndex(*v); } } @@ -1091,7 +1085,7 @@ void WidgetSettings::saveIndex(const QTabWidget* w) void WidgetSettings::restoreIndex(QTabWidget* w, std::optional<int> def) const { - if (auto v=getOptional<int>(m_Settings, "Widgets", indexSettingName(w), def)) { + if (auto v = getOptional<int>(m_Settings, "Widgets", indexSettingName(w), def)) { w->setCurrentIndex(*v); } } @@ -1112,32 +1106,32 @@ void WidgetSettings::restoreChecked(QAbstractButton* w, std::optional<bool> def) { warnIfNotCheckable(w); - if (auto v=getOptional<bool>(m_Settings, "Widgets", checkedSettingName(w), def)) { + if (auto v = getOptional<bool>(m_Settings, "Widgets", checkedSettingName(w), def)) { w->setChecked(*v); } } -QuestionBoxMemory::Button WidgetSettings::questionButton( - const QString& windowName, const QString& filename) const +QuestionBoxMemory::Button WidgetSettings::questionButton(const QString& windowName, + const QString& filename) const { const QString sectionName("DialogChoices"); if (!filename.isEmpty()) { const auto fileSetting = windowName + "/" + filename; - if (auto v=getOptional<int>(m_Settings, sectionName, fileSetting)) { + if (auto v = getOptional<int>(m_Settings, sectionName, fileSetting)) { return static_cast<QuestionBoxMemory::Button>(*v); } } - if (auto v=getOptional<int>(m_Settings, sectionName, windowName)) { + if (auto v = getOptional<int>(m_Settings, sectionName, windowName)) { return static_cast<QuestionBoxMemory::Button>(*v); } return QuestionBoxMemory::NoButton; } -void WidgetSettings::setQuestionWindowButton( - const QString& windowName, QuestionBoxMemory::Button button) +void WidgetSettings::setQuestionWindowButton(const QString& windowName, + QuestionBoxMemory::Button button) { const QString sectionName("DialogChoices"); @@ -1148,9 +1142,9 @@ void WidgetSettings::setQuestionWindowButton( } } -void WidgetSettings::setQuestionFileButton( - const QString& windowName, const QString& filename, - QuestionBoxMemory::Button button) +void WidgetSettings::setQuestionFileButton(const QString& windowName, + const QString& filename, + QuestionBoxMemory::Button button) { const QString sectionName("DialogChoices"); const QString settingName(windowName + "/" + filename); @@ -1167,17 +1161,12 @@ void WidgetSettings::resetQuestionButtons() removeSection(m_Settings, "DialogChoices"); } - -ColorSettings::ColorSettings(QSettings& s) - : m_Settings(s) -{ -} +ColorSettings::ColorSettings(QSettings& s) : m_Settings(s) {} QColor ColorSettings::modlistOverwrittenLoose() const { - return get<QColor>( - m_Settings, "Settings", "overwrittenLooseFilesColor", - QColor(0, 255, 0, 64)); + return get<QColor>(m_Settings, "Settings", "overwrittenLooseFilesColor", + QColor(0, 255, 0, 64)); } void ColorSettings::setModlistOverwrittenLoose(const QColor& c) @@ -1187,9 +1176,8 @@ void ColorSettings::setModlistOverwrittenLoose(const QColor& c) QColor ColorSettings::modlistOverwritingLoose() const { - return get<QColor>( - m_Settings, "Settings", "overwritingLooseFilesColor", - QColor(255, 0, 0, 64)); + return get<QColor>(m_Settings, "Settings", "overwritingLooseFilesColor", + QColor(255, 0, 0, 64)); } void ColorSettings::setModlistOverwritingLoose(const QColor& c) @@ -1199,9 +1187,8 @@ void ColorSettings::setModlistOverwritingLoose(const QColor& c) QColor ColorSettings::modlistOverwrittenArchive() const { - return get<QColor>( - m_Settings, "Settings", "overwrittenArchiveFilesColor", - QColor(0, 255, 255, 64)); + return get<QColor>(m_Settings, "Settings", "overwrittenArchiveFilesColor", + QColor(0, 255, 255, 64)); } void ColorSettings::setModlistOverwrittenArchive(const QColor& c) @@ -1211,9 +1198,8 @@ void ColorSettings::setModlistOverwrittenArchive(const QColor& c) QColor ColorSettings::modlistOverwritingArchive() const { - return get<QColor>( - m_Settings, "Settings", "overwritingArchiveFilesColor", - QColor(255, 0, 255, 64)); + return get<QColor>(m_Settings, "Settings", "overwritingArchiveFilesColor", + QColor(255, 0, 255, 64)); } void ColorSettings::setModlistOverwritingArchive(const QColor& c) @@ -1223,9 +1209,8 @@ void ColorSettings::setModlistOverwritingArchive(const QColor& c) QColor ColorSettings::modlistContainsPlugin() const { - return get<QColor>( - m_Settings, "Settings", "containsPluginColor", - QColor(0, 0, 255, 64)); + return get<QColor>(m_Settings, "Settings", "containsPluginColor", + QColor(0, 0, 255, 64)); } void ColorSettings::setModlistContainsPlugin(const QColor& c) @@ -1235,9 +1220,7 @@ void ColorSettings::setModlistContainsPlugin(const QColor& c) QColor ColorSettings::pluginListContained() const { - return get<QColor>( - m_Settings, "Settings", "containedColor", - QColor(0, 0, 255, 64)); + return get<QColor>(m_Settings, "Settings", "containedColor", QColor(0, 0, 255, 64)); } void ColorSettings::setPluginListContained(const QColor& c) @@ -1281,16 +1264,13 @@ QColor ColorSettings::idealTextColor(const QColor& rBackgroundColor) return QColor(Qt::black); // "inverse' of luminance of the background - int iLuminance = (rBackgroundColor.red() * 0.299) + (rBackgroundColor.green() * 0.587) + (rBackgroundColor.blue() * 0.114); + int iLuminance = (rBackgroundColor.red() * 0.299) + + (rBackgroundColor.green() * 0.587) + + (rBackgroundColor.blue() * 0.114); return QColor(iLuminance >= 128 ? Qt::black : Qt::white); } - - -PluginSettings::PluginSettings(QSettings& settings) - : m_Settings(settings) -{ -} +PluginSettings::PluginSettings(QSettings& settings) : m_Settings(settings) {} void PluginSettings::clearPlugins() { @@ -1301,17 +1281,16 @@ void PluginSettings::clearPlugins() m_PluginBlacklist = readBlacklist(); } -void PluginSettings::registerPlugin(IPlugin *plugin) +void PluginSettings::registerPlugin(IPlugin* plugin) { m_Plugins.push_back(plugin); m_PluginSettings.insert(plugin->name(), QVariantMap()); m_PluginDescriptions.insert(plugin->name(), QVariantMap()); - for (const PluginSetting &setting : plugin->settings()) { + for (const PluginSetting& setting : plugin->settings()) { const QString settingName = plugin->name() + "/" + setting.key; - QVariant temp = get<QVariant>( - m_Settings, "Plugins", settingName, QVariant()); + QVariant temp = get<QVariant>(m_Settings, "Plugins", settingName, QVariant()); // No previous enabled? Skip. if (setting.key == "enabled" && (!temp.isValid() || !temp.canConvert<bool>())) { @@ -1320,25 +1299,26 @@ void PluginSettings::registerPlugin(IPlugin *plugin) if (!temp.isValid()) { temp = setting.defaultValue; - } - else if (!temp.convert(setting.defaultValue.type())) { - log::warn( - "failed to interpret \"{}\" as correct type for \"{}\" in plugin \"{}\", using default", - temp.toString(), setting.key, plugin->name()); + } else if (!temp.convert(setting.defaultValue.type())) { + log::warn("failed to interpret \"{}\" as correct type for \"{}\" in plugin " + "\"{}\", using default", + temp.toString(), setting.key, plugin->name()); temp = setting.defaultValue; } m_PluginSettings[plugin->name()][setting.key] = temp; - m_PluginDescriptions[plugin->name()][setting.key] = QString("%1 (default: %2)") - .arg(setting.description) - .arg(setting.defaultValue.toString()); + m_PluginDescriptions[plugin->name()][setting.key] = + QString("%1 (default: %2)") + .arg(setting.description) + .arg(setting.defaultValue.toString()); } // Handle previous "enabled" settings: if (m_PluginSettings[plugin->name()].contains("enabled")) { - setPersistent(plugin->name(), "enabled", m_PluginSettings[plugin->name()]["enabled"].toBool(), true); + setPersistent(plugin->name(), "enabled", + m_PluginSettings[plugin->name()]["enabled"].toBool(), true); m_PluginSettings[plugin->name()].remove("enabled"); m_PluginDescriptions[plugin->name()].remove("enabled"); @@ -1363,7 +1343,7 @@ std::vector<MOBase::IPlugin*> PluginSettings::plugins() const return m_Plugins; } -QVariant PluginSettings::setting(const QString &pluginName, const QString &key) const +QVariant PluginSettings::setting(const QString& pluginName, const QString& key) const { auto iterPlugin = m_PluginSettings.find(pluginName); if (iterPlugin == m_PluginSettings.end()) { @@ -1378,14 +1358,14 @@ QVariant PluginSettings::setting(const QString &pluginName, const QString &key) return *iterSetting; } -void PluginSettings::setSetting(const QString &pluginName, const QString &key, const QVariant &value) +void PluginSettings::setSetting(const QString& pluginName, const QString& key, + const QVariant& value) { auto iterPlugin = m_PluginSettings.find(pluginName); if (iterPlugin == m_PluginSettings.end()) { - throw MyException( - QObject::tr("attempt to store setting for unknown plugin \"%1\"") - .arg(pluginName)); + throw MyException(QObject::tr("attempt to store setting for unknown plugin \"%1\"") + .arg(pluginName)); } QVariant oldValue = m_PluginSettings[pluginName][key]; @@ -1398,22 +1378,21 @@ void PluginSettings::setSetting(const QString &pluginName, const QString &key, c emit pluginSettingChanged(pluginName, key, oldValue, value); } -QVariantMap PluginSettings::settings(const QString &pluginName) const +QVariantMap PluginSettings::settings(const QString& pluginName) const { return m_PluginSettings[pluginName]; } -void PluginSettings::setSettings(const QString &pluginName, const QVariantMap& map) +void PluginSettings::setSettings(const QString& pluginName, const QVariantMap& map) { auto iterPlugin = m_PluginSettings.find(pluginName); if (iterPlugin == m_PluginSettings.end()) { - throw MyException( - QObject::tr("attempt to store setting for unknown plugin \"%1\"") - .arg(pluginName)); + throw MyException(QObject::tr("attempt to store setting for unknown plugin \"%1\"") + .arg(pluginName)); } - QVariantMap oldSettings = m_PluginSettings[pluginName]; + QVariantMap oldSettings = m_PluginSettings[pluginName]; m_PluginSettings[pluginName] = map; // Emit signals for settings that have been changed or added: @@ -1433,17 +1412,18 @@ void PluginSettings::setSettings(const QString &pluginName, const QVariantMap& m } } -QVariantMap PluginSettings::descriptions(const QString &pluginName) const +QVariantMap PluginSettings::descriptions(const QString& pluginName) const { return m_PluginDescriptions[pluginName]; } -void PluginSettings::setDescriptions(const QString &pluginName, const QVariantMap& map) +void PluginSettings::setDescriptions(const QString& pluginName, const QVariantMap& map) { m_PluginDescriptions[pluginName] = map; } -QVariant PluginSettings::persistent(const QString &pluginName, const QString &key, const QVariant &def) const +QVariant PluginSettings::persistent(const QString& pluginName, const QString& key, + const QVariant& def) const { if (!m_PluginSettings.contains(pluginName)) { return def; @@ -1452,13 +1432,12 @@ QVariant PluginSettings::persistent(const QString &pluginName, const QString &ke return get<QVariant>(m_Settings, "PluginPersistance", pluginName + "/" + key, def); } -void PluginSettings::setPersistent( - const QString &pluginName, const QString &key, const QVariant &value, bool sync) +void PluginSettings::setPersistent(const QString& pluginName, const QString& key, + const QVariant& value, bool sync) { if (!m_PluginSettings.contains(pluginName)) { - throw MyException( - QObject::tr("attempt to store setting for unknown plugin \"%1\"") - .arg(pluginName)); + throw MyException(QObject::tr("attempt to store setting for unknown plugin \"%1\"") + .arg(pluginName)); } set(m_Settings, "PluginPersistance", pluginName + "/" + key, value); @@ -1468,13 +1447,13 @@ void PluginSettings::setPersistent( } } -void PluginSettings::addBlacklist(const QString &fileName) +void PluginSettings::addBlacklist(const QString& fileName) { m_PluginBlacklist.insert(fileName); writeBlacklist(); } -bool PluginSettings::blacklisted(const QString &fileName) const +bool PluginSettings::blacklisted(const QString& fileName) const { return m_PluginBlacklist.contains(fileName); } @@ -1495,8 +1474,10 @@ const QSet<QString>& PluginSettings::blacklist() const void PluginSettings::save() { - for (auto iterPlugins=m_PluginSettings.begin(); iterPlugins!=m_PluginSettings.end(); ++iterPlugins) { - for (auto iterSettings=iterPlugins->begin(); iterSettings!=iterPlugins->end(); ++iterSettings) { + for (auto iterPlugins = m_PluginSettings.begin(); + iterPlugins != m_PluginSettings.end(); ++iterPlugins) { + for (auto iterSettings = iterPlugins->begin(); iterSettings != iterPlugins->end(); + ++iterSettings) { const auto key = iterPlugins.key() + "/" + iterSettings.key(); set(m_Settings, "Plugins", key, iterSettings.value()); } @@ -1516,7 +1497,7 @@ void PluginSettings::writeBlacklist() ScopedWriteArray swa(m_Settings, "pluginBlacklist", m_PluginBlacklist.size()); - for (const QString &plugin : m_PluginBlacklist) { + for (const QString& plugin : m_PluginBlacklist) { swa.next(); swa.set("name", plugin); } @@ -1527,20 +1508,16 @@ QSet<QString> PluginSettings::readBlacklist() const QSet<QString> set; ScopedReadArray sra(m_Settings, "pluginBlacklist"); - sra.for_each([&]{ + sra.for_each([&] { set.insert(sra.get<QString>("name")); - }); + }); return set; } - const QString PathSettings::BaseDirVariable = "%BASE_DIR%"; -PathSettings::PathSettings(QSettings& settings) - : m_Settings(settings) -{ -} +PathSettings::PathSettings(QSettings& settings) : m_Settings(settings) {} std::map<QString, QString> PathSettings::recent() const { @@ -1550,7 +1527,7 @@ std::map<QString, QString> PathSettings::recent() const sra.for_each([&] { const QVariant name = sra.get<QVariant>("name"); - const QVariant dir = sra.get<QVariant>("directory"); + const QVariant dir = sra.get<QVariant>("directory"); if (name.isValid() && dir.isValid()) { map.emplace(name.toString(), dir.toString()); @@ -1579,12 +1556,11 @@ void PathSettings::setRecent(const std::map<QString, QString>& map) } } -QString PathSettings::getConfigurablePath(const QString &key, - const QString &def, - bool resolve) const +QString PathSettings::getConfigurablePath(const QString& key, const QString& def, + bool resolve) const { QString result = QDir::fromNativeSeparators( - get<QString>(m_Settings, "Settings", key, makeDefaultPath(def))); + get<QString>(m_Settings, "Settings", key, makeDefaultPath(def))); if (resolve) { result = PathSettings::resolve(result, base()); @@ -1593,7 +1569,7 @@ QString PathSettings::getConfigurablePath(const QString &key, return result; } -void PathSettings::setConfigurablePath(const QString &key, const QString& path) +void PathSettings::setConfigurablePath(const QString& key, const QString& path) { if (path.isEmpty()) { remove(m_Settings, "Settings", key); @@ -1618,48 +1594,38 @@ QString PathSettings::base() const { const QString dataPath = QFileInfo(m_Settings.fileName()).dir().path(); - return QDir::fromNativeSeparators(get<QString>(m_Settings, - "Settings", "base_directory", dataPath)); + return QDir::fromNativeSeparators( + get<QString>(m_Settings, "Settings", "base_directory", dataPath)); } QString PathSettings::downloads(bool resolve) const { - return getConfigurablePath( - "download_directory", - ToQString(AppConfig::downloadPath()), - resolve); + return getConfigurablePath("download_directory", ToQString(AppConfig::downloadPath()), + resolve); } QString PathSettings::cache(bool resolve) const { - return getConfigurablePath( - "cache_directory", - ToQString(AppConfig::cachePath()), - resolve); + return getConfigurablePath("cache_directory", ToQString(AppConfig::cachePath()), + resolve); } QString PathSettings::mods(bool resolve) const { - return getConfigurablePath( - "mod_directory", - ToQString(AppConfig::modsPath()), - resolve); + return getConfigurablePath("mod_directory", ToQString(AppConfig::modsPath()), + resolve); } QString PathSettings::profiles(bool resolve) const { - return getConfigurablePath( - "profiles_directory", - ToQString(AppConfig::profilesPath()), - resolve); + return getConfigurablePath("profiles_directory", ToQString(AppConfig::profilesPath()), + resolve); } QString PathSettings::overwrite(bool resolve) const { - return getConfigurablePath( - "overwrite_directory", - ToQString(AppConfig::overwritePath()), - resolve); + return getConfigurablePath("overwrite_directory", + ToQString(AppConfig::overwritePath()), resolve); } void PathSettings::setBase(const QString& path) @@ -1696,9 +1662,8 @@ void PathSettings::setOverwrite(const QString& path) setConfigurablePath("overwrite_directory", path); } - NetworkSettings::NetworkSettings(QSettings& settings, bool globalInstance) - : m_Settings(settings) + : m_Settings(settings) { if (globalInstance) { updateCustomBrowser(); @@ -1746,9 +1711,8 @@ void NetworkSettings::setDownloadSpeed(const QString& name, int bytesPerSecond) } } - log::error( - "server '{}' not found while trying to add a download with bps {}", - name, bytesPerSecond); + log::error("server '{}' not found while trying to add a download with bps {}", name, + bytesPerSecond); } ServerList NetworkSettings::servers() const @@ -1771,14 +1735,12 @@ ServerList NetworkSettings::servers() const } ServerInfo server( - sra.get<QString>("name", ""), - sra.get<bool>("premium", false), - QDate::fromString(sra.get<QString>("lastSeen", ""), Qt::ISODate), - sra.get<int>("preferred", 0), - lastDownloads); + sra.get<QString>("name", ""), sra.get<bool>("premium", false), + QDate::fromString(sra.get<QString>("lastSeen", ""), Qt::ISODate), + sra.get<int>("preferred", 0), lastDownloads); list.add(std::move(server)); - }); + }); } return list; @@ -1796,7 +1758,6 @@ void NetworkSettings::updateServers(ServerList newServers) removeSection(m_Settings, "Servers"); } - ScopedWriteArray swa(m_Settings, "Servers", newServers.size()); for (const auto& server : newServers) { @@ -1875,12 +1836,8 @@ ServerList NetworkSettings::serversFromOldMap() const sg.for_each([&](auto&& serverKey) { QVariantMap data = sg.get<QVariantMap>(serverKey); - ServerInfo server( - serverKey, - data["premium"].toBool(), - data["lastSeen"].toDate(), - data["preferred"].toInt(), - {}); + ServerInfo server(serverKey, data["premium"].toBool(), data["lastSeen"].toDate(), + data["preferred"].toInt(), {}); // ignoring download count and speed, it's now a list of values instead of // a total @@ -1901,21 +1858,16 @@ void NetworkSettings::dump() const lastDownloads += QString("%1 ").arg(speed); } - log::debug( - " . {} premium={} lastSeen={} preferred={} lastDownloads={}", - server.name(), - server.isPremium() ? "yes" : "no", - server.lastSeen().toString(Qt::ISODate), - server.preferred(), - lastDownloads.trimmed()); + log::debug(" . {} premium={} lastSeen={} preferred={} lastDownloads={}", + server.name(), server.isPremium() ? "yes" : "no", + server.lastSeen().toString(Qt::ISODate), server.preferred(), + lastDownloads.trimmed()); } } - NexusSettings::NexusSettings(Settings& parent, QSettings& settings) - : m_Parent(parent), m_Settings(settings) -{ -} + : m_Parent(parent), m_Settings(settings) +{} bool NexusSettings::endorsementIntegration() const { @@ -1930,7 +1882,7 @@ void NexusSettings::setEndorsementIntegration(bool b) const EndorsementState NexusSettings::endorsementState() const { return endorsementStateFromString( - get<QString>(m_Settings, "General", "endorse_state", "")); + get<QString>(m_Settings, "General", "endorse_state", "")); } void NexusSettings::setEndorsementState(EndorsementState s) @@ -1956,13 +1908,12 @@ void NexusSettings::setTrackedIntegration(bool b) const void NexusSettings::registerAsNXMHandler(bool force) { - const auto nxmPath = - QCoreApplication::applicationDirPath() + "/" + - QString::fromStdWString(AppConfig::nxmHandlerExe()); + const auto nxmPath = QCoreApplication::applicationDirPath() + "/" + + QString::fromStdWString(AppConfig::nxmHandlerExe()); const auto executable = QCoreApplication::applicationFilePath(); - QString mode = force ? "forcereg" : "reg"; + QString mode = force ? "forcereg" : "reg"; QString parameters = mode + " " + m_Parent.game().plugin()->gameShortName(); for (const QString& altGame : m_Parent.game().plugin()->validShortNames()) { parameters += "," + altGame; @@ -1973,50 +1924,46 @@ void NexusSettings::registerAsNXMHandler(bool force) if (!r.success()) { QMessageBox::critical( - nullptr, QObject::tr("Failed"), - QObject::tr("Failed to start the helper application: %1").arg(r.toString())); + nullptr, QObject::tr("Failed"), + QObject::tr("Failed to start the helper application: %1").arg(r.toString())); } } std::vector<std::chrono::seconds> NexusSettings::validationTimeouts() const { - using namespace std::chrono_literals; - - const auto s = get<QString>( - m_Settings, "Settings", "validation_timeouts", ""); + using namespace std::chrono_literals; - const auto numbers = s.split(" "); - std::vector<std::chrono::seconds> v; + const auto s = get<QString>(m_Settings, "Settings", "validation_timeouts", ""); - for (auto ns : numbers) - { - ns = ns.trimmed(); - if (ns.isEmpty()) - continue; + const auto numbers = s.split(" "); + std::vector<std::chrono::seconds> v; - bool ok = false; - const auto n = ns.toInt(&ok); + for (auto ns : numbers) { + ns = ns.trimmed(); + if (ns.isEmpty()) + continue; - if (!ok || n < 0 || n > 100) - { - log::error("bad validation_timeouts number '{}'", ns); - continue; - } + bool ok = false; + const auto n = ns.toInt(&ok); - v.push_back(std::chrono::seconds(n)); + if (!ok || n < 0 || n > 100) { + log::error("bad validation_timeouts number '{}'", ns); + continue; } - if (v.empty()) - v = {10s, 15s, 20s}; + v.push_back(std::chrono::seconds(n)); + } + + if (v.empty()) + v = {10s, 15s, 20s}; - return v; + return v; } void NexusSettings::dump() const { - const auto iniPath = - InstanceManager::singleton().globalInstancesRootPath() + "/" + - QString::fromStdWString(AppConfig::nxmHandlerIni()); + const auto iniPath = InstanceManager::singleton().globalInstancesRootPath() + "/" + + QString::fromStdWString(AppConfig::nxmHandlerIni()); if (!QFileInfo(iniPath).exists()) { log::debug("nxm ini not found at {}", iniPath); @@ -2024,14 +1971,15 @@ void NexusSettings::dump() const } QSettings s(iniPath, QSettings::IniFormat); - if (const auto st=s.status(); st != QSettings::NoError) { + if (const auto st = s.status(); st != QSettings::NoError) { log::debug("can't read nxm ini from {}", iniPath); return; } log::debug("nxmhandler settings:"); - QSettings handler("HKEY_CURRENT_USER\\Software\\Classes\\nxm\\", QSettings::NativeFormat); + QSettings handler("HKEY_CURRENT_USER\\Software\\Classes\\nxm\\", + QSettings::NativeFormat); log::debug(" . primary: {}", handler.value("shell/open/command/Default").toString()); const auto noregister = getOptional<bool>(s, "General", "noregister"); @@ -2045,9 +1993,9 @@ void NexusSettings::dump() const ScopedReadArray sra(s, "handlers"); sra.for_each([&] { - const auto games = sra.get<QVariant>("games"); + const auto games = sra.get<QVariant>("games"); const auto executable = sra.get<QVariant>("executable"); - const auto arguments = sra.get<QVariant>("arguments"); + const auto arguments = sra.get<QVariant>("arguments"); log::debug(" . handler:"); log::debug(" . games: {}", games.toString()); @@ -2056,16 +2004,14 @@ void NexusSettings::dump() const }); } - SteamSettings::SteamSettings(Settings& parent, QSettings& settings) - : m_Parent(parent), m_Settings(settings) -{ -} + : m_Parent(parent), m_Settings(settings) +{} QString SteamSettings::appID() const { - return get<QString>( - m_Settings, "Settings", "app_id", m_Parent.game().plugin()->steamAPPId()); + return get<QString>(m_Settings, "Settings", "app_id", + m_Parent.game().plugin()->steamAPPId()); } void SteamSettings::setAppID(const QString& id) @@ -2077,7 +2023,7 @@ void SteamSettings::setAppID(const QString& id) } } -bool SteamSettings::login(QString &username, QString &password) const +bool SteamSettings::login(QString& username, QString& password) const { username = get<QString>(m_Settings, "Settings", "steam_username", ""); password = getWindowsCredential("steam_password"); @@ -2100,11 +2046,7 @@ void SteamSettings::setLogin(QString username, QString password) } } - -InterfaceSettings::InterfaceSettings(QSettings& settings) - : m_Settings(settings) -{ -} +InterfaceSettings::InterfaceSettings(QSettings& settings) : m_Settings(settings) {} bool InterfaceSettings::lockGUI() const { @@ -2129,7 +2071,9 @@ void InterfaceSettings::setStyleName(const QString& name) bool InterfaceSettings::collapsibleSeparators(Qt::SortOrder order) const { return get<bool>(m_Settings, "Settings", - order == Qt::AscendingOrder ? "collapsible_separators_asc" : "collapsible_separators_dsc", true); + order == Qt::AscendingOrder ? "collapsible_separators_asc" + : "collapsible_separators_dsc", + true); } void InterfaceSettings::setCollapsibleSeparators(bool ascending, bool descending) @@ -2150,7 +2094,8 @@ void InterfaceSettings::setCollapsibleSeparatorsHighlightTo(bool b) bool InterfaceSettings::collapsibleSeparatorsHighlightFrom() const { - return get<bool>(m_Settings, "Settings", "collapsible_separators_conflicts_from", true); + return get<bool>(m_Settings, "Settings", "collapsible_separators_conflicts_from", + true); } void InterfaceSettings::setCollapsibleSeparatorsHighlightFrom(bool b) @@ -2160,12 +2105,14 @@ void InterfaceSettings::setCollapsibleSeparatorsHighlightFrom(bool b) bool InterfaceSettings::collapsibleSeparatorsIcons(int column) const { - return get<bool>(m_Settings, "Settings", QString("collapsible_separators_icons_%1").arg(column), true); + return get<bool>(m_Settings, "Settings", + QString("collapsible_separators_icons_%1").arg(column), true); } void InterfaceSettings::setCollapsibleSeparatorsIcons(int column, bool show) { - set(m_Settings, "Settings", QString("collapsible_separators_icons_%1").arg(column), show); + set(m_Settings, "Settings", QString("collapsible_separators_icons_%1").arg(column), + show); } bool InterfaceSettings::collapsibleSeparatorsPerProfile() const @@ -2327,9 +2274,11 @@ FilterWidget::Options InterfaceSettings::filterOptions() const FilterWidget::Options o; o.useRegex = get<bool>(m_Settings, "Settings", "filter_regex", false); - o.regexCaseSensitive = get<bool>(m_Settings, "Settings", "regex_case_sensitive", false); + o.regexCaseSensitive = + get<bool>(m_Settings, "Settings", "regex_case_sensitive", false); o.regexExtended = get<bool>(m_Settings, "Settings", "regex_extended", false); - o.scrollToSelection = get<bool>(m_Settings, "Settings", "filter_scroll_to_selection", false); + o.scrollToSelection = + get<bool>(m_Settings, "Settings", "filter_scroll_to_selection", false); return o; } @@ -2342,11 +2291,7 @@ void InterfaceSettings::setFilterOptions(const FilterWidget::Options& o) set(m_Settings, "Settings", "filter_scroll_to_selection", o.scrollToSelection); } - -DiagnosticsSettings::DiagnosticsSettings(QSettings& settings) - : m_Settings(settings) -{ -} +DiagnosticsSettings::DiagnosticsSettings(QSettings& settings) : m_Settings(settings) {} log::Levels DiagnosticsSettings::logLevel() const { @@ -2360,8 +2305,8 @@ void DiagnosticsSettings::setLogLevel(log::Levels level) lootcli::LogLevels DiagnosticsSettings::lootLogLevel() const { - return get<lootcli::LogLevels>( - m_Settings, "Settings", "loot_log_level", lootcli::LogLevels::Info); + return get<lootcli::LogLevels>(m_Settings, "Settings", "loot_log_level", + lootcli::LogLevels::Info); } void DiagnosticsSettings::setLootLogLevel(lootcli::LogLevels level) @@ -2371,8 +2316,8 @@ void DiagnosticsSettings::setLootLogLevel(lootcli::LogLevels level) env::CoreDumpTypes DiagnosticsSettings::coreDumpType() const { - return get<env::CoreDumpTypes>(m_Settings, - "Settings", "crash_dumps_type", env::CoreDumpTypes::Mini); + return get<env::CoreDumpTypes>(m_Settings, "Settings", "crash_dumps_type", + env::CoreDumpTypes::Mini); } void DiagnosticsSettings::setCoreDumpType(env::CoreDumpTypes type) @@ -2392,8 +2337,7 @@ void DiagnosticsSettings::setMaxCoreDumps(int n) std::chrono::seconds DiagnosticsSettings::spawnDelay() const { - return std::chrono::seconds( - get<int>(m_Settings, "Settings", "spawn_delay", 0)); + return std::chrono::seconds(get<int>(m_Settings, "Settings", "spawn_delay", 0)); } void DiagnosticsSettings::setSpawnDelay(std::chrono::seconds t) @@ -2401,11 +2345,10 @@ void DiagnosticsSettings::setSpawnDelay(std::chrono::seconds t) set(m_Settings, "Settings", "spawn_delay", t.count()); } - void GlobalSettings::updateRegistryKey() { - const QString OldOrganization = "Tannin"; - const QString OldApplication = "Mod Organizer"; + const QString OldOrganization = "Tannin"; + const QString OldApplication = "Mod Organizer"; const QString OldInstanceValue = "CurrentInstance"; const QString OldRootKey = "Software\\" + OldOrganization; @@ -2432,7 +2375,7 @@ void GlobalSettings::setCurrentInstance(const QString& s) QSettings GlobalSettings::settings() { const QString Organization = "Mod Organizer Team"; - const QString Application = "Mod Organizer"; + const QString Application = "Mod Organizer"; return QSettings(Organization, Application); } diff --git a/src/settings.h b/src/settings.h index d886e806..6a11d662 100644 --- a/src/settings.h +++ b/src/settings.h @@ -22,28 +22,27 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "envdump.h" #include <filterwidget.h> +#include <log.h> #include <lootcli/lootcli.h> #include <questionboxmemory.h> -#include <log.h> #include <usvfsparameters.h> #ifdef interface - #undef interface +#undef interface #endif -namespace MOBase { - class IPlugin; - class IPluginGame; - class ExpanderWidget; -} +namespace MOBase +{ +class IPlugin; +class IPluginGame; +class ExpanderWidget; +} // namespace MOBase class QSplitter; class ServerList; class Settings; - - // setting for the currently managed game // class GameSettings @@ -87,7 +86,6 @@ private: const MOBase::IPluginGame* m_GamePlugin; }; - // geometry settings for various widgets; this should contain any setting that // can get invalid through UI changes or when users change display settings // (resolution, monitors, etc.); see WidgetSettings for the counterpart @@ -111,7 +109,6 @@ public: void requestReset(); void resetIfNeeded(); - void saveGeometry(const QMainWindow* w); bool restoreGeometry(QMainWindow* w) const; @@ -131,7 +128,7 @@ public: bool restoreState(MOBase::ExpanderWidget* expander) const; void saveVisibility(const QWidget* w); - bool restoreVisibility(QWidget* w, std::optional<bool> def={}) const; + bool restoreVisibility(QWidget* w, std::optional<bool> def = {}) const; void saveToolbars(const QMainWindow* w); void restoreToolbars(QMainWindow* w) const; @@ -167,10 +164,9 @@ private: void ensureWindowOnScreen(QWidget* w) const; static void centerOnMonitor(QWidget* w, int monitor); - static void centerOnParent(QWidget* w, QWidget* parent=nullptr); + static void centerOnParent(QWidget* w, QWidget* parent = nullptr); }; - // widget settings that should stay valid regardless of UI changes or when users // change display settings (resolution, monitors, etc.); see GeometrySettings // for the counterpart @@ -198,36 +194,35 @@ public: // std::optional<int> index(const QComboBox* cb) const; void saveIndex(const QComboBox* cb); - void restoreIndex(QComboBox* cb, std::optional<int> def={}) const; + void restoreIndex(QComboBox* cb, std::optional<int> def = {}) const; // selected tab index for a tab widget // std::optional<int> index(const QTabWidget* w) const; void saveIndex(const QTabWidget* w); - void restoreIndex(QTabWidget* w, std::optional<int> def={}) const; + void restoreIndex(QTabWidget* w, std::optional<int> def = {}) const; // check state for a checkable button // std::optional<bool> checked(const QAbstractButton* w) const; void saveChecked(const QAbstractButton* w); - void restoreChecked(QAbstractButton* w, std::optional<bool> def={}) const; + void restoreChecked(QAbstractButton* w, std::optional<bool> def = {}) const; // returns the remembered button for a question dialog, or NoButton if the // user hasn't saved the choice // - MOBase::QuestionBoxMemory::Button questionButton( - const QString& windowName, const QString& filename) const; + MOBase::QuestionBoxMemory::Button questionButton(const QString& windowName, + const QString& filename) const; // sets the button to be remembered for the given window // - void setQuestionWindowButton( - const QString& windowName, MOBase::QuestionBoxMemory::Button button); + void setQuestionWindowButton(const QString& windowName, + MOBase::QuestionBoxMemory::Button button); // sets the button to be remembered for the given file // - void setQuestionFileButton( - const QString& windowName, const QString& filename, - MOBase::QuestionBoxMemory::Button choice); + void setQuestionFileButton(const QString& windowName, const QString& filename, + MOBase::QuestionBoxMemory::Button choice); // wipes all the remembered buttons // @@ -237,7 +232,6 @@ private: QSettings& m_Settings; }; - // various color settings // class ColorSettings @@ -261,7 +255,7 @@ public: void setModlistContainsPlugin(const QColor& c); QColor pluginListContained() const; - void setPluginListContained(const QColor& c) ; + void setPluginListContained(const QColor& c); std::optional<QColor> previousSeparatorColor() const; void setPreviousSeparatorColor(const QColor& c) const; @@ -281,68 +275,65 @@ private: QSettings& m_Settings; }; - // settings about plugins // -class PluginSettings: public QObject +class PluginSettings : public QObject { Q_OBJECT public: PluginSettings(QSettings& settings); - // forgets all the plugins // void clearPlugins(); // adds/removes the given plugin to the list and loads all of its settings // - void registerPlugin(MOBase::IPlugin *plugin); + void registerPlugin(MOBase::IPlugin* plugin); void unregisterPlugin(MOBase::IPlugin* plugin); // returns all the registered plugins // std::vector<MOBase::IPlugin*> plugins() const; - // returns the plugin setting for the given key // - QVariant setting(const QString &pluginName, const QString &key) const; + QVariant setting(const QString& pluginName, const QString& key) const; // sets the plugin setting for the given key // - void setSetting(const QString &pluginName, const QString &key, const QVariant &value); + void setSetting(const QString& pluginName, const QString& key, const QVariant& value); // returns all settings // - QVariantMap settings(const QString &pluginName) const; + QVariantMap settings(const QString& pluginName) const; // overwrites all settings // - void setSettings(const QString &pluginName, const QVariantMap& map); + void setSettings(const QString& pluginName, const QVariantMap& map); // returns all descriptions // - QVariantMap descriptions(const QString &pluginName) const; + QVariantMap descriptions(const QString& pluginName) const; // overwrites all descriptions // - void setDescriptions(const QString &pluginName, const QVariantMap& map); - + void setDescriptions(const QString& pluginName, const QVariantMap& map); // ? - QVariant persistent(const QString &pluginName, const QString &key, const QVariant &def) const; - void setPersistent(const QString &pluginName, const QString &key, const QVariant &value, bool sync); - + QVariant persistent(const QString& pluginName, const QString& key, + const QVariant& def) const; + void setPersistent(const QString& pluginName, const QString& key, + const QVariant& value, bool sync); // adds the given plugin to the blacklist // - void addBlacklist(const QString &fileName); + void addBlacklist(const QString& fileName); // returns whether the given plugin is blacklisted // - bool blacklisted(const QString &fileName) const; + bool blacklisted(const QString& fileName) const; // overwrites the whole blacklist // @@ -352,7 +343,6 @@ public: // const QSet<QString>& blacklist() const; - // commits all the settings to the ini // void save(); @@ -362,7 +352,8 @@ Q_SIGNALS: /** * Emitted when a plugin setting changes. */ - void pluginSettingChanged(QString const& pluginName, const QString& key, const QVariant& oldValue, const QVariant& newValue); + void pluginSettingChanged(QString const& pluginName, const QString& key, + const QVariant& oldValue, const QVariant& newValue); private: QSettings& m_Settings; @@ -380,7 +371,6 @@ private: QSet<QString> readBlacklist() const; }; - // paths for the game and various components // // if the 'resolve' parameter is true, %BASE_DIR% is expanded; it's set to @@ -412,14 +402,12 @@ public: QString overwrite(bool resolve = true) const; void setOverwrite(const QString& path); - // map of names to directories, used to remember the last directory used in // various file pickers // std::map<QString, QString> recent() const; void setRecent(const std::map<QString, QString>& map); - // resolves %BASE_DIR% // static QString resolve(const QString& path, const QString& baseDir); @@ -431,11 +419,11 @@ public: private: QSettings& m_Settings; - QString getConfigurablePath(const QString &key, const QString &def, bool resolve) const; - void setConfigurablePath(const QString &key, const QString& path); + QString getConfigurablePath(const QString& key, const QString& def, + bool resolve) const; + void setConfigurablePath(const QString& key, const QString& path); }; - class NetworkSettings { public: @@ -458,7 +446,7 @@ public: // remembers the last couple of download speeds and displays the average in // the network settings // - void setDownloadSpeed(const QString &serverName, int bytesPerSecond); + void setDownloadSpeed(const QString& serverName, int bytesPerSecond); // known servers // @@ -496,7 +484,6 @@ private: void updateCustomBrowser(); }; - enum class EndorsementState { Accepted = 1, @@ -507,7 +494,6 @@ enum class EndorsementState EndorsementState endorsementStateFromString(const QString& s); QString toString(EndorsementState s); - class NexusSettings { public: @@ -546,7 +532,6 @@ private: QSettings& m_Settings; }; - class SteamSettings { public: @@ -573,7 +558,7 @@ public: // // returns whether _both_ the username and password have a value // - bool login(QString &username, QString &password) const; + bool login(QString& username, QString& password) const; // sets the steam login; the username is saved in the ini file and the // password in the credentials store @@ -587,7 +572,6 @@ private: QSettings& m_Settings; }; - class InterfaceSettings { public: @@ -681,7 +665,7 @@ public: // whether the given tutorial has been completed // bool isTutorialCompleted(const QString& windowName) const; - void setTutorialCompleted(const QString& windowName, bool b=true); + void setTutorialCompleted(const QString& windowName, bool b = true); // whether to show the confirmation when switching instances // @@ -707,7 +691,6 @@ private: QSettings& m_Settings; }; - class DiagnosticsSettings { public: @@ -739,7 +722,6 @@ private: QSettings& m_Settings; }; - // manages the settings for MO; the settings are accessed directly through a // QSettings and so are not cached here // @@ -762,10 +744,9 @@ public: // @param globalInsance whether this is the global instance; creates the // singleton and asserts if it already exists // - Settings(const QString& path, bool globalInstance=false); + Settings(const QString& path, bool globalInstance = false); ~Settings(); - // throws if there is no global Settings instance // static Settings& instance(); @@ -774,7 +755,6 @@ public: // static Settings* maybeInstance(); - // name of the ini file // QString filename() const; @@ -886,16 +866,16 @@ public: public slots: // this slot is connected to by various parts of MO // - void managedGameChanged(MOBase::IPluginGame const *gamePlugin); + void managedGameChanged(MOBase::IPluginGame const* gamePlugin); signals: // these are fired from outside the settings, mostly by the settings dialog // - void languageChanged(const QString &newLanguage); - void styleChanged(const QString &newStyle); + void languageChanged(const QString& newLanguage); + void styleChanged(const QString& newStyle); private: - static Settings *s_Instance; + static Settings* s_Instance; mutable QSettings m_Settings; GameSettings m_Game; @@ -911,7 +891,6 @@ private: DiagnosticsSettings m_Diagnostics; }; - // manages global settings in the registry // class GlobalSettings @@ -954,7 +933,6 @@ private: static QSettings settings(); }; - // helper class that calls restoreGeometry() in the constructor and // saveGeometry() in the destructor // @@ -962,20 +940,16 @@ template <class W> class GeometrySaver { public: - GeometrySaver(Settings& s, W* w) - : m_settings(s), m_widget(w) + GeometrySaver(Settings& s, W* w) : m_settings(s), m_widget(w) { m_settings.geometry().restoreGeometry(m_widget); } - ~GeometrySaver() - { - m_settings.geometry().saveGeometry(m_widget); - } + ~GeometrySaver() { m_settings.geometry().saveGeometry(m_widget); } private: Settings& m_settings; W* m_widget; }; -#endif // SETTINGS_H +#endif // SETTINGS_H diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index b14deafa..425a1cb8 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -18,35 +18,38 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ #include "settingsdialog.h" -#include "ui_settingsdialog.h" #include "settingsdialogdiagnostics.h" #include "settingsdialoggeneral.h" +#include "settingsdialogmodlist.h" #include "settingsdialognexus.h" #include "settingsdialogpaths.h" #include "settingsdialogplugins.h" -#include "settingsdialogmodlist.h" #include "settingsdialogtheme.h" #include "settingsdialogworkarounds.h" +#include "ui_settingsdialog.h" using namespace MOBase; -SettingsDialog::SettingsDialog(PluginContainer *pluginContainer, Settings& settings, QWidget *parent) - : TutorableDialog("SettingsDialog", parent) - , ui(new Ui::SettingsDialog) - , m_settings(settings) - , m_exit(Exit::None) - , m_pluginContainer(pluginContainer) +SettingsDialog::SettingsDialog(PluginContainer* pluginContainer, Settings& settings, + QWidget* parent) + : TutorableDialog("SettingsDialog", parent), ui(new Ui::SettingsDialog), + m_settings(settings), m_exit(Exit::None), m_pluginContainer(pluginContainer) { ui->setupUi(this); - m_tabs.push_back(std::unique_ptr<SettingsTab>(new GeneralSettingsTab(settings, *this))); + m_tabs.push_back( + std::unique_ptr<SettingsTab>(new GeneralSettingsTab(settings, *this))); m_tabs.push_back(std::unique_ptr<SettingsTab>(new ThemeSettingsTab(settings, *this))); - m_tabs.push_back(std::unique_ptr<SettingsTab>(new ModListSettingsTab(settings, *this))); + m_tabs.push_back( + std::unique_ptr<SettingsTab>(new ModListSettingsTab(settings, *this))); m_tabs.push_back(std::unique_ptr<SettingsTab>(new PathsSettingsTab(settings, *this))); - m_tabs.push_back(std::unique_ptr<SettingsTab>(new DiagnosticsSettingsTab(settings, *this))); + m_tabs.push_back( + std::unique_ptr<SettingsTab>(new DiagnosticsSettingsTab(settings, *this))); m_tabs.push_back(std::unique_ptr<SettingsTab>(new NexusSettingsTab(settings, *this))); - m_tabs.push_back(std::unique_ptr<SettingsTab>(new PluginsSettingsTab(settings, m_pluginContainer, *this))); - m_tabs.push_back(std::unique_ptr<SettingsTab>(new WorkaroundsSettingsTab(settings, *this))); + m_tabs.push_back(std::unique_ptr<SettingsTab>( + new PluginsSettingsTab(settings, m_pluginContainer, *this))); + m_tabs.push_back( + std::unique_ptr<SettingsTab>(new WorkaroundsSettingsTab(settings, *this))); } PluginContainer* SettingsDialog::pluginContainer() @@ -89,7 +92,7 @@ int SettingsDialog::exec() } // update settings for each tab - for (std::unique_ptr<SettingsTab> const &tab: m_tabs) { + for (std::unique_ptr<SettingsTab> const& tab : m_tabs) { tab->update(); } } @@ -106,23 +109,22 @@ SettingsDialog::~SettingsDialog() QString SettingsDialog::getColoredButtonStyleSheet() const { return QString("QPushButton {" - "background-color: %1;" - "color: %2;" - "border: 1px solid;" - "padding: 3px;" - "}"); + "background-color: %1;" + "color: %2;" + "border: 1px solid;" + "padding: 3px;" + "}"); } void SettingsDialog::accept() { QString newModPath = ui->modDirEdit->text(); - newModPath = PathSettings::resolve(newModPath, ui->baseDirEdit->text()); + newModPath = PathSettings::resolve(newModPath, ui->baseDirEdit->text()); if ((QDir::fromNativeSeparators(newModPath) != - QDir::fromNativeSeparators( - Settings::instance().paths().mods(true))) && + QDir::fromNativeSeparators(Settings::instance().paths().mods(true))) && (QMessageBox::question( - parentWidgetForDialogs(), tr("Confirm"), + parentWidgetForDialogs(), tr("Confirm"), tr("Changing the mod directory affects all your profiles! " "Mods not present (or named differently) in the new location " "will be disabled in all profiles. " @@ -135,11 +137,9 @@ void SettingsDialog::accept() TutorableDialog::accept(); } - SettingsTab::SettingsTab(Settings& s, SettingsDialog& d) - : ui(d.ui), m_settings(s), m_dialog(d) -{ -} + : ui(d.ui), m_settings(s), m_dialog(d) +{} SettingsTab::~SettingsTab() = default; diff --git a/src/settingsdialog.h b/src/settingsdialog.h index 160f0748..eca0b266 100644 --- a/src/settingsdialog.h +++ b/src/settingsdialog.h @@ -20,14 +20,16 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef SETTINGSDIALOG_H #define SETTINGSDIALOG_H -#include "tutorabledialog.h" #include "shared/util.h" +#include "tutorabledialog.h" class PluginContainer; class Settings; class SettingsDialog; -namespace Ui { class SettingsDialog; } - +namespace Ui +{ +class SettingsDialog; +} class SettingsTab { @@ -50,7 +52,6 @@ private: SettingsDialog& m_dialog; }; - /** * dialog used to change settings for Mod Organizer. On top of the * settings managed by the "Settings" class, this offers a button to open the @@ -58,19 +59,19 @@ private: **/ class SettingsDialog : public MOBase::TutorableDialog { - Q_OBJECT; - friend class SettingsTab; + Q_OBJECT; + friend class SettingsTab; public: - explicit SettingsDialog( - PluginContainer* pluginContainer, Settings& settings, QWidget* parent = 0); + explicit SettingsDialog(PluginContainer* pluginContainer, Settings& settings, + QWidget* parent = 0); ~SettingsDialog(); /** - * @brief get stylesheet of settings buttons with colored background - * @return string of stylesheet - */ + * @brief get stylesheet of settings buttons with colored background + * @return string of stylesheet + */ QString getColoredButtonStyleSheet() const; PluginContainer* pluginContainer(); @@ -92,4 +93,4 @@ private: PluginContainer* m_pluginContainer; }; -#endif // SETTINGSDIALOG_H +#endif // SETTINGSDIALOG_H diff --git a/src/settingsdialogdiagnostics.cpp b/src/settingsdialogdiagnostics.cpp index 33175a66..012a3348 100644 --- a/src/settingsdialogdiagnostics.cpp +++ b/src/settingsdialogdiagnostics.cpp @@ -1,13 +1,13 @@ #include "settingsdialogdiagnostics.h" -#include "ui_settingsdialog.h" -#include "shared/appconfig.h" #include "organizercore.h" +#include "shared/appconfig.h" +#include "ui_settingsdialog.h" #include <log.h> using namespace MOBase; DiagnosticsSettingsTab::DiagnosticsSettingsTab(Settings& s, SettingsDialog& d) - : SettingsTab(s, d) + : SettingsTab(s, d) { setLogLevel(); setLootLogLevel(); @@ -15,16 +15,16 @@ DiagnosticsSettingsTab::DiagnosticsSettingsTab(Settings& s, SettingsDialog& d) ui->dumpsMaxEdit->setValue(settings().diagnostics().maxCoreDumps()); - QString logsPath = qApp->property("dataPath").toString() - + "/" + QString::fromStdWString(AppConfig::logPath()); + QString logsPath = qApp->property("dataPath").toString() + "/" + + QString::fromStdWString(AppConfig::logPath()); ui->diagnosticsExplainedLabel->setText( - ui->diagnosticsExplainedLabel->text() - .replace("LOGS_FULL_PATH", logsPath) - .replace("LOGS_DIR", QString::fromStdWString(AppConfig::logPath())) - .replace("DUMPS_FULL_PATH", QString::fromStdWString(OrganizerCore::getGlobalCoreDumpPath())) - .replace("DUMPS_DIR", QString::fromStdWString(AppConfig::dumpsDir())) - ); + ui->diagnosticsExplainedLabel->text() + .replace("LOGS_FULL_PATH", logsPath) + .replace("LOGS_DIR", QString::fromStdWString(AppConfig::logPath())) + .replace("DUMPS_FULL_PATH", + QString::fromStdWString(OrganizerCore::getGlobalCoreDumpPath())) + .replace("DUMPS_DIR", QString::fromStdWString(AppConfig::dumpsDir()))); } void DiagnosticsSettingsTab::setLogLevel() @@ -38,7 +38,7 @@ void DiagnosticsSettingsTab::setLogLevel() const auto sel = settings().diagnostics().logLevel(); - for (int i=0; i<ui->logLevelBox->count(); ++i) { + for (int i = 0; i < ui->logLevelBox->count(); ++i) { if (ui->logLevelBox->itemData(i) == sel) { ui->logLevelBox->setCurrentIndex(i); break; @@ -50,7 +50,9 @@ void DiagnosticsSettingsTab::setLootLogLevel() { using L = lootcli::LogLevels; - auto v = [](L level) { return QVariant(static_cast<int>(level)); }; + auto v = [](L level) { + return QVariant(static_cast<int>(level)); + }; ui->lootLogLevel->clear(); @@ -62,7 +64,7 @@ void DiagnosticsSettingsTab::setLootLogLevel() const auto sel = settings().diagnostics().lootLogLevel(); - for (int i=0; i<ui->lootLogLevel->count(); ++i) { + for (int i = 0; i < ui->lootLogLevel->count(); ++i) { if (ui->lootLogLevel->itemData(i) == v(sel)) { ui->lootLogLevel->setCurrentIndex(i); break; @@ -83,10 +85,9 @@ void DiagnosticsSettingsTab::setCrashDumpTypesBox() add(QObject::tr("Data"), env::CoreDumpTypes::Data); add(QObject::tr("Full"), env::CoreDumpTypes::Full); - const auto current = static_cast<int>( - settings().diagnostics().coreDumpType()); + const auto current = static_cast<int>(settings().diagnostics().coreDumpType()); - for (int i=0; i<ui->dumpsTypeBox->count(); ++i) { + for (int i = 0; i < ui->dumpsTypeBox->count(); ++i) { if (ui->dumpsTypeBox->itemData(i) == current) { ui->dumpsTypeBox->setCurrentIndex(i); break; @@ -97,13 +98,13 @@ void DiagnosticsSettingsTab::setCrashDumpTypesBox() void DiagnosticsSettingsTab::update() { settings().diagnostics().setLogLevel( - static_cast<log::Levels>(ui->logLevelBox->currentData().toInt())); + static_cast<log::Levels>(ui->logLevelBox->currentData().toInt())); settings().diagnostics().setCoreDumpType( - static_cast<env::CoreDumpTypes>(ui->dumpsTypeBox->currentData().toInt())); + static_cast<env::CoreDumpTypes>(ui->dumpsTypeBox->currentData().toInt())); settings().diagnostics().setMaxCoreDumps(ui->dumpsMaxEdit->value()); settings().diagnostics().setLootLogLevel( - static_cast<lootcli::LogLevels>(ui->lootLogLevel->currentData().toInt())); + static_cast<lootcli::LogLevels>(ui->lootLogLevel->currentData().toInt())); } diff --git a/src/settingsdialogdiagnostics.h b/src/settingsdialogdiagnostics.h index e01ee22f..7818d4bf 100644 --- a/src/settingsdialogdiagnostics.h +++ b/src/settingsdialogdiagnostics.h @@ -17,4 +17,4 @@ private: void setCrashDumpTypesBox(); }; -#endif // SETTINGSDIALOGDIAGNOSTICS_H +#endif // SETTINGSDIALOGDIAGNOSTICS_H diff --git a/src/settingsdialoggeneral.cpp b/src/settingsdialoggeneral.cpp index 48045245..95655ac8 100644 --- a/src/settingsdialoggeneral.cpp +++ b/src/settingsdialoggeneral.cpp @@ -1,15 +1,15 @@ #include "settingsdialoggeneral.h" -#include "ui_settingsdialog.h" -#include "shared/appconfig.h" #include "categoriesdialog.h" #include "colortable.h" -#include <utility.h> +#include "shared/appconfig.h" +#include "ui_settingsdialog.h" #include <questionboxmemory.h> +#include <utility.h> using namespace MOBase; GeneralSettingsTab::GeneralSettingsTab(Settings& s, SettingsDialog& d) - : SettingsTab(s, d) + : SettingsTab(s, d) { // language addLanguages(); @@ -18,7 +18,8 @@ GeneralSettingsTab::GeneralSettingsTab(Settings& s, SettingsDialog& d) // download list ui->compactBox->setChecked(settings().interface().compactDownloads()); ui->showMetaBox->setChecked(settings().interface().metaDownloads()); - ui->hideDownloadInstallBox->setChecked(settings().interface().hideDownloadsAfterInstallation()); + ui->hideDownloadInstallBox->setChecked( + settings().interface().hideDownloadsAfterInstallation()); // updates ui->checkForUpdates->setChecked(settings().checkForUpdates()); @@ -26,23 +27,27 @@ GeneralSettingsTab::GeneralSettingsTab(Settings& s, SettingsDialog& d) // miscellaneous ui->centerDialogs->setChecked(settings().geometry().centerDialogs()); - ui->changeGameConfirmation->setChecked(settings().interface().showChangeGameConfirmation()); + ui->changeGameConfirmation->setChecked( + settings().interface().showChangeGameConfirmation()); ui->showMenubarOnAlt->setChecked(settings().interface().showMenubarOnAlt()); - ui->doubleClickPreviews->setChecked(settings().interface().doubleClicksOpenPreviews()); + ui->doubleClickPreviews->setChecked( + settings().interface().doubleClicksOpenPreviews()); - QObject::connect( - ui->categoriesBtn, &QPushButton::clicked, [&]{ onEditCategories(); }); + QObject::connect(ui->categoriesBtn, &QPushButton::clicked, [&] { + onEditCategories(); + }); - QObject::connect( - ui->resetDialogsButton, &QPushButton::clicked, [&]{ onResetDialogs(); }); + QObject::connect(ui->resetDialogsButton, &QPushButton::clicked, [&] { + onResetDialogs(); + }); } void GeneralSettingsTab::update() { // language const QString oldLanguage = settings().interface().language(); - const QString newLanguage = ui->languageBox->itemData( - ui->languageBox->currentIndex()).toString(); + const QString newLanguage = + ui->languageBox->itemData(ui->languageBox->currentIndex()).toString(); if (newLanguage != oldLanguage) { settings().interface().setLanguage(newLanguage); @@ -52,7 +57,8 @@ void GeneralSettingsTab::update() // download list settings().interface().setCompactDownloads(ui->compactBox->isChecked()); settings().interface().setMetaDownloads(ui->showMetaBox->isChecked()); - settings().interface().setHideDownloadsAfterInstallation(ui->hideDownloadInstallBox->isChecked()); + settings().interface().setHideDownloadsAfterInstallation( + ui->hideDownloadInstallBox->isChecked()); // updates settings().setCheckForUpdates(ui->checkForUpdates->isChecked()); @@ -60,23 +66,23 @@ void GeneralSettingsTab::update() // miscellaneous settings().geometry().setCenterDialogs(ui->centerDialogs->isChecked()); - settings().interface().setShowChangeGameConfirmation(ui->changeGameConfirmation->isChecked()); + settings().interface().setShowChangeGameConfirmation( + ui->changeGameConfirmation->isChecked()); settings().interface().setShowMenubarOnAlt(ui->showMenubarOnAlt->isChecked()); - settings().interface().setDoubleClicksOpenPreviews(ui->doubleClickPreviews->isChecked()); + settings().interface().setDoubleClicksOpenPreviews( + ui->doubleClickPreviews->isChecked()); } void GeneralSettingsTab::addLanguages() { // matches the end of filenames for something like "_en.qm" or "_zh_CN.qm" - const QString pattern = - QString::fromStdWString(AppConfig::translationPrefix()) + - "_([a-z]{2,3}(_[A-Z]{2,2})?).qm"; + const QString pattern = QString::fromStdWString(AppConfig::translationPrefix()) + + "_([a-z]{2,3}(_[A-Z]{2,2})?).qm"; const QRegularExpression exp(QRegularExpression::anchoredPattern(pattern)); - QDirIterator iter( - QCoreApplication::applicationDirPath() + "/translations", - QDir::Files); + QDirIterator iter(QCoreApplication::applicationDirPath() + "/translations", + QDir::Files); std::vector<std::pair<QString, QString>> languages; @@ -84,7 +90,7 @@ void GeneralSettingsTab::addLanguages() iter.next(); const QString file = iter.fileName(); - auto match = exp.match(file); + auto match = exp.match(file); if (!match.hasMatch()) { continue; } @@ -93,8 +99,8 @@ void GeneralSettingsTab::addLanguages() const QLocale locale(languageCode); QString languageString = QString("%1 (%2)") - .arg(locale.nativeLanguageName()) - .arg(locale.nativeCountryName()); + .arg(locale.nativeLanguageName()) + .arg(locale.nativeCountryName()); if (locale.language() == QLocale::Chinese) { if (languageCode == "zh_TW") { @@ -152,12 +158,11 @@ void GeneralSettingsTab::onEditCategories() void GeneralSettingsTab::onResetDialogs() { const auto r = QMessageBox::question( - parentWidget(), - QObject::tr("Confirm?"), - QObject::tr( - "This will reset all the choices you made to dialogs and make them all " - "visible again. Continue?"), - QMessageBox::Yes | QMessageBox::No); + parentWidget(), QObject::tr("Confirm?"), + QObject::tr( + "This will reset all the choices you made to dialogs and make them all " + "visible again. Continue?"), + QMessageBox::Yes | QMessageBox::No); if (r == QMessageBox::Yes) { resetDialogs(); diff --git a/src/settingsdialoggeneral.h b/src/settingsdialoggeneral.h index 8d82564d..61938190 100644 --- a/src/settingsdialoggeneral.h +++ b/src/settingsdialoggeneral.h @@ -1,8 +1,8 @@ #ifndef SETTINGSDIALOGGENERAL_H #define SETTINGSDIALOGGENERAL_H -#include "settingsdialog.h" #include "settings.h" +#include "settingsdialog.h" class GeneralSettingsTab : public SettingsTab { @@ -21,4 +21,4 @@ private: void onResetDialogs(); }; -#endif // SETTINGSDIALOGGENERAL_H +#endif // SETTINGSDIALOGGENERAL_H diff --git a/src/settingsdialogmodlist.cpp b/src/settingsdialogmodlist.cpp index 4c04e3f5..394111bd 100644 --- a/src/settingsdialogmodlist.cpp +++ b/src/settingsdialogmodlist.cpp @@ -1,42 +1,50 @@ #include "settingsdialogmodlist.h" -#include "ui_settingsdialog.h" -#include "shared/appconfig.h" #include "categoriesdialog.h" #include "colortable.h" #include "modlist.h" -#include <utility.h> +#include "shared/appconfig.h" +#include "ui_settingsdialog.h" #include <questionboxmemory.h> +#include <utility.h> using namespace MOBase; ModListSettingsTab::ModListSettingsTab(Settings& s, SettingsDialog& d) - : SettingsTab(s, d), - m_columnToBox{ - { ModList::COL_CONFLICTFLAGS, ui->collapsibleSeparatorsIconsConflictsBox }, - { ModList::COL_FLAGS, ui->collapsibleSeparatorsIconsFlagsBox }, - { ModList::COL_CONTENT, ui->collapsibleSeparatorsIconsContentsBox}, - { ModList::COL_VERSION, ui->collapsibleSeparatorsIconsVersionBox } - } + : SettingsTab(s, d), + m_columnToBox{ + {ModList::COL_CONFLICTFLAGS, ui->collapsibleSeparatorsIconsConflictsBox}, + {ModList::COL_FLAGS, ui->collapsibleSeparatorsIconsFlagsBox}, + {ModList::COL_CONTENT, ui->collapsibleSeparatorsIconsContentsBox}, + {ModList::COL_VERSION, ui->collapsibleSeparatorsIconsVersionBox}} { // connect before setting to trigger - QObject::connect(ui->collapsibleSeparatorsAscBox, &QCheckBox::toggled, [=] { updateCollapsibleSeparatorsGroup(); }); - QObject::connect(ui->collapsibleSeparatorsDscBox, &QCheckBox::toggled, [=] { updateCollapsibleSeparatorsGroup(); }); + QObject::connect(ui->collapsibleSeparatorsAscBox, &QCheckBox::toggled, [=] { + updateCollapsibleSeparatorsGroup(); + }); + QObject::connect(ui->collapsibleSeparatorsDscBox, &QCheckBox::toggled, [=] { + updateCollapsibleSeparatorsGroup(); + }); ui->colorSeparatorsBox->setChecked(settings().colors().colorSeparatorScrollbar()); ui->displayForeignBox->setChecked(settings().interface().displayForeign()); - ui->collapsibleSeparatorsAscBox->setChecked(settings().interface().collapsibleSeparators(Qt::AscendingOrder)); - ui->collapsibleSeparatorsDscBox->setChecked(settings().interface().collapsibleSeparators(Qt::DescendingOrder)); - ui->collapsibleSeparatorsHighlightFromBox->setChecked(settings().interface().collapsibleSeparatorsHighlightFrom()); - ui->collapsibleSeparatorsHighlightToBox->setChecked(settings().interface().collapsibleSeparatorsHighlightTo()); - ui->collapsibleSeparatorsPerProfileBox->setChecked(settings().interface().collapsibleSeparatorsPerProfile()); + ui->collapsibleSeparatorsAscBox->setChecked( + settings().interface().collapsibleSeparators(Qt::AscendingOrder)); + ui->collapsibleSeparatorsDscBox->setChecked( + settings().interface().collapsibleSeparators(Qt::DescendingOrder)); + ui->collapsibleSeparatorsHighlightFromBox->setChecked( + settings().interface().collapsibleSeparatorsHighlightFrom()); + ui->collapsibleSeparatorsHighlightToBox->setChecked( + settings().interface().collapsibleSeparatorsHighlightTo()); + ui->collapsibleSeparatorsPerProfileBox->setChecked( + settings().interface().collapsibleSeparatorsPerProfile()); ui->saveFiltersBox->setChecked(settings().interface().saveFilters()); ui->autoCollapseDelayBox->setChecked(settings().interface().autoCollapseOnHover()); - ui->checkUpdateInstallBox->setChecked(settings().interface().checkUpdateAfterInstallation()); + ui->checkUpdateInstallBox->setChecked( + settings().interface().checkUpdateAfterInstallation()); for (auto& p : m_columnToBox) { p.second->setChecked(settings().interface().collapsibleSeparatorsIcons(p.first)); } - } void ModListSettingsTab::update() @@ -45,23 +53,29 @@ void ModListSettingsTab::update() settings().colors().setColorSeparatorScrollbar(ui->colorSeparatorsBox->isChecked()); settings().interface().setDisplayForeign(ui->displayForeignBox->isChecked()); settings().interface().setCollapsibleSeparators( - ui->collapsibleSeparatorsAscBox->isChecked(), ui->collapsibleSeparatorsDscBox->isChecked()); - settings().interface().setCollapsibleSeparatorsHighlightFrom(ui->collapsibleSeparatorsHighlightFromBox->isChecked()); - settings().interface().setCollapsibleSeparatorsHighlightTo(ui->collapsibleSeparatorsHighlightToBox->isChecked()); - settings().interface().setCollapsibleSeparatorsPerProfile(ui->collapsibleSeparatorsPerProfileBox->isChecked()); + ui->collapsibleSeparatorsAscBox->isChecked(), + ui->collapsibleSeparatorsDscBox->isChecked()); + settings().interface().setCollapsibleSeparatorsHighlightFrom( + ui->collapsibleSeparatorsHighlightFromBox->isChecked()); + settings().interface().setCollapsibleSeparatorsHighlightTo( + ui->collapsibleSeparatorsHighlightToBox->isChecked()); + settings().interface().setCollapsibleSeparatorsPerProfile( + ui->collapsibleSeparatorsPerProfileBox->isChecked()); settings().interface().setSaveFilters(ui->saveFiltersBox->isChecked()); settings().interface().setAutoCollapseOnHover(ui->autoCollapseDelayBox->isChecked()); - settings().interface().setCheckUpdateAfterInstallation(ui->checkUpdateInstallBox->isChecked()); + settings().interface().setCheckUpdateAfterInstallation( + ui->checkUpdateInstallBox->isChecked()); for (auto& p : m_columnToBox) { - settings().interface().setCollapsibleSeparatorsIcons(p.first, p.second->isChecked()); + settings().interface().setCollapsibleSeparatorsIcons(p.first, + p.second->isChecked()); } } void ModListSettingsTab::updateCollapsibleSeparatorsGroup() { const auto checked = ui->collapsibleSeparatorsAscBox->isChecked() || - ui->collapsibleSeparatorsDscBox->isChecked(); + ui->collapsibleSeparatorsDscBox->isChecked(); for (auto* widget : ui->collapsibleSeparatorsWidget->findChildren<QWidget*>()) { widget->setEnabled(checked); } diff --git a/src/settingsdialogmodlist.h b/src/settingsdialogmodlist.h index 0c0510b5..4489eacd 100644 --- a/src/settingsdialogmodlist.h +++ b/src/settingsdialogmodlist.h @@ -3,8 +3,8 @@ #include <QCheckBox> -#include "settingsdialog.h" #include "settings.h" +#include "settingsdialog.h" class ModListSettingsTab : public SettingsTab { @@ -20,8 +20,7 @@ protected slots: void updateCollapsibleSeparatorsGroup(); private: - const std::map<int, QCheckBox*> m_columnToBox; }; -#endif // SETTINGSDIALOGGENERAL_H +#endif // SETTINGSDIALOGGENERAL_H diff --git a/src/settingsdialognexus.cpp b/src/settingsdialognexus.cpp index 364c6aa7..2e706e42 100644 --- a/src/settingsdialognexus.cpp +++ b/src/settingsdialognexus.cpp @@ -1,39 +1,49 @@ #include "settingsdialognexus.h" -#include "ui_settingsdialog.h" -#include "ui_nexusmanualkey.h" +#include "log.h" #include "nexusinterface.h" #include "serverinfo.h" -#include "log.h" +#include "ui_nexusmanualkey.h" +#include "ui_settingsdialog.h" #include <utility.h> using namespace MOBase; template <typename T> -class ServerItem : public QListWidgetItem { +class ServerItem : public QListWidgetItem +{ public: - ServerItem(const QString &text, int sortRole = Qt::DisplayRole, QListWidget *parent = 0, int type = Type) - : QListWidgetItem(text, parent, type), m_SortRole(sortRole) {} + ServerItem(const QString& text, int sortRole = Qt::DisplayRole, + QListWidget* parent = 0, int type = Type) + : QListWidgetItem(text, parent, type), m_SortRole(sortRole) + {} - virtual bool operator< ( const QListWidgetItem & other ) const { + virtual bool operator<(const QListWidgetItem& other) const + { return this->data(m_SortRole).value<T>() < other.data(m_SortRole).value<T>(); } + private: int m_SortRole; }; - class NexusManualKeyDialog : public QDialog { public: NexusManualKeyDialog(QWidget* parent) - : QDialog(parent), ui(new Ui::NexusManualKeyDialog) + : QDialog(parent), ui(new Ui::NexusManualKeyDialog) { ui->setupUi(this); ui->key->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); - connect(ui->openBrowser, &QPushButton::clicked, [&]{ openBrowser(); }); - connect(ui->paste, &QPushButton::clicked, [&]{ paste(); }); - connect(ui->clear, &QPushButton::clicked, [&]{ clear(); }); + connect(ui->openBrowser, &QPushButton::clicked, [&] { + openBrowser(); + }); + connect(ui->paste, &QPushButton::clicked, [&] { + paste(); + }); + connect(ui->clear, &QPushButton::clicked, [&] { + clear(); + }); } void accept() override @@ -42,10 +52,7 @@ public: QDialog::accept(); } - const QString& key() const - { - return m_key; - } + const QString& key() const { return m_key; } void openBrowser() { @@ -60,41 +67,37 @@ public: } } - void clear() - { - ui->key->clear(); - } + void clear() { ui->key->clear(); } private: std::unique_ptr<Ui::NexusManualKeyDialog> ui; QString m_key; }; - -NexusConnectionUI::NexusConnectionUI( - QWidget* parent, - Settings* s, - QAbstractButton* connectButton, - QAbstractButton* disconnectButton, - QAbstractButton* manualButton, - QListWidget* logList) : - m_parent(parent), - m_settings(s), - m_connect(connectButton), - m_disconnect(disconnectButton), - m_manual(manualButton), - m_log(logList) +NexusConnectionUI::NexusConnectionUI(QWidget* parent, Settings* s, + QAbstractButton* connectButton, + QAbstractButton* disconnectButton, + QAbstractButton* manualButton, + QListWidget* logList) + : m_parent(parent), m_settings(s), m_connect(connectButton), + m_disconnect(disconnectButton), m_manual(manualButton), m_log(logList) { if (m_connect) { - QObject::connect(m_connect, &QPushButton::clicked, [&]{ connect(); }); + QObject::connect(m_connect, &QPushButton::clicked, [&] { + connect(); + }); } if (m_disconnect) { - QObject::connect(m_disconnect, &QPushButton::clicked, [&]{ disconnect(); }); + QObject::connect(m_disconnect, &QPushButton::clicked, [&] { + disconnect(); + }); } if (m_manual) { - QObject::connect(manualButton, &QPushButton::clicked, [&]{ manual(); }); + QObject::connect(manualButton, &QPushButton::clicked, [&] { + manual(); + }); } if (GlobalSettings::hasNexusApiKey()) { @@ -116,11 +119,11 @@ void NexusConnectionUI::connect() if (!m_nexusLogin) { m_nexusLogin.reset(new NexusSSOLogin); - m_nexusLogin->keyChanged = [&](auto&& s){ + m_nexusLogin->keyChanged = [&](auto&& s) { onSSOKeyChanged(s); }; - m_nexusLogin->stateChanged = [&](auto&& s, auto&& e){ + m_nexusLogin->stateChanged = [&](auto&& s, auto&& e) { onSSOStateChanged(s, e); }; } @@ -163,7 +166,7 @@ void NexusConnectionUI::validateKey(const QString& key) { if (!m_nexusValidator) { m_nexusValidator.reset(new NexusKeyValidator( - m_settings, *NexusInterface::instance().getAccessManager())); + m_settings, *NexusInterface::instance().getAccessManager())); m_nexusValidator->finished = [&](auto&& r, auto&& m, auto&& u) { onValidatorFinished(r, m, u); @@ -184,8 +187,7 @@ void NexusConnectionUI::onSSOKeyChanged(const QString& key) } } -void NexusConnectionUI::onSSOStateChanged( - NexusSSOLogin::States s, const QString& e) +void NexusConnectionUI::onSSOStateChanged(NexusSSOLogin::States s, const QString& e) { if (s != NexusSSOLogin::Finished) { // finished state is handled in onSSOKeyChanged() @@ -199,9 +201,9 @@ void NexusConnectionUI::onSSOStateChanged( updateState(); } -void NexusConnectionUI::onValidatorFinished( - ValidationAttempt::Result r, const QString& message, - std::optional<APIUserAccount> user) +void NexusConnectionUI::onValidatorFinished(ValidationAttempt::Result r, + const QString& message, + std::optional<APIUserAccount> user) { if (user) { NexusInterface::instance().setUserAccount(*user); @@ -254,7 +256,7 @@ bool NexusConnectionUI::clearKey() void NexusConnectionUI::updateState() { - auto setButton = [&](QAbstractButton* b, bool enabled, QString caption={}) { + auto setButton = [&](QAbstractButton* b, bool enabled, QString caption = {}) { if (b) { b->setEnabled(enabled); if (!caption.isEmpty()) { @@ -267,15 +269,13 @@ void NexusConnectionUI::updateState() // api key is in the process of being retrieved setButton(m_connect, true, QObject::tr("Cancel")); setButton(m_disconnect, false); - setButton(m_manual, false,QObject::tr("Enter API Key Manually")); - } - else if (m_nexusValidator && m_nexusValidator->isActive()) { + setButton(m_manual, false, QObject::tr("Enter API Key Manually")); + } else if (m_nexusValidator && m_nexusValidator->isActive()) { // api key is in the process of being tested setButton(m_connect, false, QObject::tr("Connect to Nexus")); setButton(m_disconnect, false); setButton(m_manual, true, QObject::tr("Cancel")); - } - else if (GlobalSettings::hasNexusApiKey()) { + } else if (GlobalSettings::hasNexusApiKey()) { // api key is present setButton(m_connect, false, QObject::tr("Connect to Nexus")); setButton(m_disconnect, true); @@ -290,10 +290,7 @@ void NexusConnectionUI::updateState() emit stateChanged(); } - - -NexusSettingsTab::NexusSettingsTab(Settings& s, SettingsDialog& d) - : SettingsTab(s, d) +NexusSettingsTab::NexusSettingsTab(Settings& s, SettingsDialog& d) : SettingsTab(s, d) { ui->endorsementBox->setChecked(settings().nexus().endorsementIntegration()); ui->trackedBox->setChecked(settings().nexus().trackedIntegration()); @@ -312,7 +309,7 @@ NexusSettingsTab::NexusSettingsTab(Settings& s, SettingsDialog& d) descriptor += QString(" (%1)").arg(MOBase::localizedByteSpeed(averageSpeed)); } - QListWidgetItem *newItem = new ServerItem<int>(descriptor, Qt::UserRole + 1); + QListWidgetItem* newItem = new ServerItem<int>(descriptor, Qt::UserRole + 1); newItem->setData(Qt::UserRole, server.name()); newItem->setData(Qt::UserRole + 1, server.preferred()); @@ -326,27 +323,33 @@ NexusSettingsTab::NexusSettingsTab(Settings& s, SettingsDialog& d) ui->preferredServersList->sortItems(Qt::DescendingOrder); } - m_connectionUI.reset(new NexusConnectionUI( - &dialog(), - &settings(), - ui->nexusConnect, - ui->nexusDisconnect, - ui->nexusManualKey, - ui->nexusLog)); - - QObject::connect( - m_connectionUI.get(), &NexusConnectionUI::stateChanged, &d, - [&]{ updateNexusData(); }, Qt::QueuedConnection); + m_connectionUI.reset(new NexusConnectionUI(&dialog(), &settings(), ui->nexusConnect, + ui->nexusDisconnect, ui->nexusManualKey, + ui->nexusLog)); QObject::connect( - m_connectionUI.get(), &NexusConnectionUI::keyChanged, &d, - [&]{ dialog().setExitNeeded(Exit::Restart); }); + m_connectionUI.get(), &NexusConnectionUI::stateChanged, &d, + [&] { + updateNexusData(); + }, + Qt::QueuedConnection); + QObject::connect(m_connectionUI.get(), &NexusConnectionUI::keyChanged, &d, [&] { + dialog().setExitNeeded(Exit::Restart); + }); - QObject::connect(ui->clearCacheButton, &QPushButton::clicked, [&]{ clearCache(); }); - QObject::connect(ui->associateButton, &QPushButton::clicked, [&]{ associate(); }); - QObject::connect(ui->useCustomBrowser, &QCheckBox::clicked, [&]{ updateCustomBrowser(); }); - QObject::connect(ui->browseCustomBrowser, &QPushButton::clicked, [&]{ browseCustomBrowser(); }); + QObject::connect(ui->clearCacheButton, &QPushButton::clicked, [&] { + clearCache(); + }); + QObject::connect(ui->associateButton, &QPushButton::clicked, [&] { + associate(); + }); + QObject::connect(ui->useCustomBrowser, &QCheckBox::clicked, [&] { + updateCustomBrowser(); + }); + QObject::connect(ui->browseCustomBrowser, &QPushButton::clicked, [&] { + browseCustomBrowser(); + }); updateNexusData(); updateCustomBrowser(); @@ -382,7 +385,8 @@ void NexusSettingsTab::update() const int count = ui->preferredServersList->count(); for (int i = 0; i < count; ++i) { - const QString key = ui->preferredServersList->item(i)->data(Qt::UserRole).toString(); + const QString key = + ui->preferredServersList->item(i)->data(Qt::UserRole).toString(); const int newPreferred = count - i; bool found = false; @@ -397,9 +401,8 @@ void NexusSettingsTab::update() } if (!found) { - log::error( - "while setting preference to {}, server '{}' not found", - newPreferred, key); + log::error("while setting preference to {}, server '{}' not found", newPreferred, + key); } } @@ -427,12 +430,12 @@ void NexusSettingsTab::updateNexusData() ui->nexusAccount->setText(localizedUserAccountType(user.type())); ui->nexusDailyRequests->setText(QString("%1/%2") - .arg(user.limits().remainingDailyRequests) - .arg(user.limits().maxDailyRequests)); + .arg(user.limits().remainingDailyRequests) + .arg(user.limits().maxDailyRequests)); ui->nexusHourlyRequests->setText(QString("%1/%2") - .arg(user.limits().remainingHourlyRequests) - .arg(user.limits().maxHourlyRequests)); + .arg(user.limits().remainingHourlyRequests) + .arg(user.limits().maxHourlyRequests)); } else { ui->nexusUserID->setText(QObject::tr("N/A")); ui->nexusName->setText(QObject::tr("N/A")); @@ -447,15 +450,14 @@ void NexusSettingsTab::updateCustomBrowser() ui->browserCommand->setEnabled(ui->useCustomBrowser->isChecked()); } -void NexusSettingsTab::browseCustomBrowser () +void NexusSettingsTab::browseCustomBrowser() { const QString Filters = - QObject::tr("Executables (*.exe)") + ";;" + - QObject::tr("All Files (*.*)"); + QObject::tr("Executables (*.exe)") + ";;" + QObject::tr("All Files (*.*)"); QString file = QFileDialog::getOpenFileName( - parentWidget(), QObject::tr("Select the browser executable"), - ui->browserCommand->text(), Filters); + parentWidget(), QObject::tr("Select the browser executable"), + ui->browserCommand->text(), Filters); if (file.isNull() || file == "") { return; diff --git a/src/settingsdialognexus.h b/src/settingsdialognexus.h index a9bd46c7..41ab207a 100644 --- a/src/settingsdialognexus.h +++ b/src/settingsdialognexus.h @@ -1,9 +1,9 @@ #ifndef SETTINGSDIALOGNEXUS_H #define SETTINGSDIALOGNEXUS_H +#include "nxmaccessmanager.h" #include "settings.h" #include "settingsdialog.h" -#include "nxmaccessmanager.h" // used by the settings dialog and the create instance dialog // @@ -12,13 +12,9 @@ class NexusConnectionUI : public QObject Q_OBJECT; public: - NexusConnectionUI( - QWidget* parent, - Settings* s, - QAbstractButton* connectButton, - QAbstractButton* disconnectButton, - QAbstractButton* manualButton, - QListWidget* logList); + NexusConnectionUI(QWidget* parent, Settings* s, QAbstractButton* connectButton, + QAbstractButton* disconnectButton, QAbstractButton* manualButton, + QListWidget* logList); void connect(); void manual(); @@ -50,12 +46,10 @@ private: void onSSOKeyChanged(const QString& key); void onSSOStateChanged(NexusSSOLogin::States s, const QString& e); - void onValidatorFinished( - ValidationAttempt::Result r, const QString& message, - std::optional<APIUserAccount> useR); + void onValidatorFinished(ValidationAttempt::Result r, const QString& message, + std::optional<APIUserAccount> useR); }; - class NexusSettingsTab : public SettingsTab { public: @@ -73,4 +67,4 @@ private: void browseCustomBrowser(); }; -#endif // SETTINGSDIALOGNEXUS_H +#endif // SETTINGSDIALOGNEXUS_H diff --git a/src/settingsdialogpaths.cpp b/src/settingsdialogpaths.cpp index aafa750c..1907b7fa 100644 --- a/src/settingsdialogpaths.cpp +++ b/src/settingsdialogpaths.cpp @@ -1,89 +1,121 @@ #include "settingsdialogpaths.h" -#include "ui_settingsdialog.h" #include "shared/appconfig.h" +#include "ui_settingsdialog.h" #include <iplugingame.h> PathsSettingsTab::PathsSettingsTab(Settings& s, SettingsDialog& d) - : SettingsTab(s, d), m_gameDir(settings().game().plugin()->gameDirectory()) + : SettingsTab(s, d), m_gameDir(settings().game().plugin()->gameDirectory()) { ui->baseDirEdit->setText(settings().paths().base()); - ui->managedGameDirEdit->setText( - QDir::toNativeSeparators(m_gameDir.absoluteFilePath(settings().game().plugin()->binaryName()))); + ui->managedGameDirEdit->setText(QDir::toNativeSeparators( + m_gameDir.absoluteFilePath(settings().game().plugin()->binaryName()))); QString basePath = settings().paths().base(); QDir baseDir(basePath); - for (const auto &dir : { - std::make_pair(ui->downloadDirEdit, settings().paths().downloads(false)), - std::make_pair(ui->modDirEdit, settings().paths().mods(false)), - std::make_pair(ui->cacheDirEdit, settings().paths().cache(false)), - std::make_pair(ui->profilesDirEdit, settings().paths().profiles(false)), - std::make_pair(ui->overwriteDirEdit, settings().paths().overwrite(false)) - }) { + for (const auto& dir : + {std::make_pair(ui->downloadDirEdit, settings().paths().downloads(false)), + std::make_pair(ui->modDirEdit, settings().paths().mods(false)), + std::make_pair(ui->cacheDirEdit, settings().paths().cache(false)), + std::make_pair(ui->profilesDirEdit, settings().paths().profiles(false)), + std::make_pair(ui->overwriteDirEdit, settings().paths().overwrite(false))}) { QString storePath = baseDir.relativeFilePath(dir.second); - storePath = dir.second; + storePath = dir.second; dir.first->setText(storePath); } - QObject::connect(ui->browseBaseDirBtn, &QPushButton::clicked, [&]{ on_browseBaseDirBtn_clicked(); }); - QObject::connect(ui->browseCacheDirBtn, &QPushButton::clicked, [&]{ on_browseCacheDirBtn_clicked(); }); - QObject::connect(ui->browseDownloadDirBtn, &QPushButton::clicked, [&]{ on_browseDownloadDirBtn_clicked(); }); - QObject::connect(ui->browseGameDirBtn, &QPushButton::clicked, [&]{ on_browseGameDirBtn_clicked(); }); - QObject::connect(ui->browseModDirBtn, &QPushButton::clicked, [&]{ on_browseModDirBtn_clicked(); }); - QObject::connect(ui->browseOverwriteDirBtn, &QPushButton::clicked, [&]{ on_browseOverwriteDirBtn_clicked(); }); - QObject::connect(ui->browseProfilesDirBtn, &QPushButton::clicked, [&]{ on_browseProfilesDirBtn_clicked(); }); + QObject::connect(ui->browseBaseDirBtn, &QPushButton::clicked, [&] { + on_browseBaseDirBtn_clicked(); + }); + QObject::connect(ui->browseCacheDirBtn, &QPushButton::clicked, [&] { + on_browseCacheDirBtn_clicked(); + }); + QObject::connect(ui->browseDownloadDirBtn, &QPushButton::clicked, [&] { + on_browseDownloadDirBtn_clicked(); + }); + QObject::connect(ui->browseGameDirBtn, &QPushButton::clicked, [&] { + on_browseGameDirBtn_clicked(); + }); + QObject::connect(ui->browseModDirBtn, &QPushButton::clicked, [&] { + on_browseModDirBtn_clicked(); + }); + QObject::connect(ui->browseOverwriteDirBtn, &QPushButton::clicked, [&] { + on_browseOverwriteDirBtn_clicked(); + }); + QObject::connect(ui->browseProfilesDirBtn, &QPushButton::clicked, [&] { + on_browseProfilesDirBtn_clicked(); + }); - QObject::connect(ui->baseDirEdit, &QLineEdit::editingFinished, [&]{ on_baseDirEdit_editingFinished(); }); - QObject::connect(ui->cacheDirEdit, &QLineEdit::editingFinished, [&]{ on_cacheDirEdit_editingFinished(); }); - QObject::connect(ui->downloadDirEdit, &QLineEdit::editingFinished, [&]{ on_downloadDirEdit_editingFinished(); }); - QObject::connect(ui->modDirEdit, &QLineEdit::editingFinished, [&]{ on_modDirEdit_editingFinished(); }); - QObject::connect(ui->overwriteDirEdit, &QLineEdit::editingFinished, [&]{ on_overwriteDirEdit_editingFinished(); }); - QObject::connect(ui->profilesDirEdit, &QLineEdit::editingFinished, [&]{ on_profilesDirEdit_editingFinished(); }); + QObject::connect(ui->baseDirEdit, &QLineEdit::editingFinished, [&] { + on_baseDirEdit_editingFinished(); + }); + QObject::connect(ui->cacheDirEdit, &QLineEdit::editingFinished, [&] { + on_cacheDirEdit_editingFinished(); + }); + QObject::connect(ui->downloadDirEdit, &QLineEdit::editingFinished, [&] { + on_downloadDirEdit_editingFinished(); + }); + QObject::connect(ui->modDirEdit, &QLineEdit::editingFinished, [&] { + on_modDirEdit_editingFinished(); + }); + QObject::connect(ui->overwriteDirEdit, &QLineEdit::editingFinished, [&] { + on_overwriteDirEdit_editingFinished(); + }); + QObject::connect(ui->profilesDirEdit, &QLineEdit::editingFinished, [&] { + on_profilesDirEdit_editingFinished(); + }); } void PathsSettingsTab::update() { - using Setter = void (PathSettings::*)(const QString&); + using Setter = void (PathSettings::*)(const QString&); using Directory = std::tuple<QString, Setter, std::wstring>; QString basePath = settings().paths().base(); - for (const Directory &dir :{ - Directory{ui->downloadDirEdit->text(), &PathSettings::setDownloads, AppConfig::downloadPath()}, - Directory{ui->cacheDirEdit->text(), &PathSettings::setCache, AppConfig::cachePath()}, - Directory{ui->modDirEdit->text(), &PathSettings::setMods, AppConfig::modsPath()}, - Directory{ui->overwriteDirEdit->text(), &PathSettings::setOverwrite, AppConfig::overwritePath()}, - Directory{ui->profilesDirEdit->text(), &PathSettings::setProfiles, AppConfig::profilesPath()} - }) { + for (const Directory& dir : + {Directory{ui->downloadDirEdit->text(), &PathSettings::setDownloads, + AppConfig::downloadPath()}, + Directory{ui->cacheDirEdit->text(), &PathSettings::setCache, + AppConfig::cachePath()}, + Directory{ui->modDirEdit->text(), &PathSettings::setMods, + AppConfig::modsPath()}, + Directory{ui->overwriteDirEdit->text(), &PathSettings::setOverwrite, + AppConfig::overwritePath()}, + Directory{ui->profilesDirEdit->text(), &PathSettings::setProfiles, + AppConfig::profilesPath()}}) { QString path; Setter setter; std::wstring defaultName; std::tie(path, setter, defaultName) = dir; QString realPath = path; - realPath = PathSettings::resolve(realPath, ui->baseDirEdit->text()); + realPath = PathSettings::resolve(realPath, ui->baseDirEdit->text()); if (!QDir(realPath).exists()) { if (!QDir().mkpath(realPath)) { - QMessageBox::warning(parentWidget(), QObject::tr("Error"), - QObject::tr("Failed to create \"%1\", you may not have the " - "necessary permissions. Path remains unchanged.") - .arg(realPath)); + QMessageBox::warning( + parentWidget(), QObject::tr("Error"), + QObject::tr("Failed to create \"%1\", you may not have the " + "necessary permissions. Path remains unchanged.") + .arg(realPath)); continue; } } - if (QFileInfo(realPath) != QFileInfo(basePath + "/" + QString::fromStdWString(defaultName))) { + if (QFileInfo(realPath) != + QFileInfo(basePath + "/" + QString::fromStdWString(defaultName))) { (settings().paths().*setter)(path); } else { (settings().paths().*setter)(""); } } - if (QFileInfo(ui->baseDirEdit->text()) != QFileInfo(qApp->property("dataPath").toString())) { + if (QFileInfo(ui->baseDirEdit->text()) != + QFileInfo(qApp->property("dataPath").toString())) { settings().paths().setBase(ui->baseDirEdit->text()); } else { settings().paths().setBase(""); @@ -97,7 +129,7 @@ void PathsSettingsTab::update() void PathsSettingsTab::on_browseBaseDirBtn_clicked() { QString temp = QFileDialog::getExistingDirectory( - &dialog(), QObject::tr("Select base directory"), ui->baseDirEdit->text()); + &dialog(), QObject::tr("Select base directory"), ui->baseDirEdit->text()); if (!temp.isEmpty()) { ui->baseDirEdit->setText(temp); } @@ -106,9 +138,10 @@ void PathsSettingsTab::on_browseBaseDirBtn_clicked() void PathsSettingsTab::on_browseDownloadDirBtn_clicked() { QString searchPath = ui->downloadDirEdit->text(); - searchPath = PathSettings::resolve(searchPath, ui->baseDirEdit->text()); + searchPath = PathSettings::resolve(searchPath, ui->baseDirEdit->text()); - QString temp = QFileDialog::getExistingDirectory(&dialog(), QObject::tr("Select download directory"), searchPath); + QString temp = QFileDialog::getExistingDirectory( + &dialog(), QObject::tr("Select download directory"), searchPath); if (!temp.isEmpty()) { ui->downloadDirEdit->setText(temp); } @@ -117,9 +150,10 @@ void PathsSettingsTab::on_browseDownloadDirBtn_clicked() void PathsSettingsTab::on_browseModDirBtn_clicked() { QString searchPath = ui->modDirEdit->text(); - searchPath = PathSettings::resolve(searchPath, ui->baseDirEdit->text()); + searchPath = PathSettings::resolve(searchPath, ui->baseDirEdit->text()); - QString temp = QFileDialog::getExistingDirectory(&dialog(), QObject::tr("Select mod directory"), searchPath); + QString temp = QFileDialog::getExistingDirectory( + &dialog(), QObject::tr("Select mod directory"), searchPath); if (!temp.isEmpty()) { ui->modDirEdit->setText(temp); } @@ -128,9 +162,10 @@ void PathsSettingsTab::on_browseModDirBtn_clicked() void PathsSettingsTab::on_browseCacheDirBtn_clicked() { QString searchPath = ui->cacheDirEdit->text(); - searchPath = PathSettings::resolve(searchPath, ui->baseDirEdit->text()); + searchPath = PathSettings::resolve(searchPath, ui->baseDirEdit->text()); - QString temp = QFileDialog::getExistingDirectory(&dialog(), QObject::tr("Select cache directory"), searchPath); + QString temp = QFileDialog::getExistingDirectory( + &dialog(), QObject::tr("Select cache directory"), searchPath); if (!temp.isEmpty()) { ui->cacheDirEdit->setText(temp); } @@ -139,9 +174,10 @@ void PathsSettingsTab::on_browseCacheDirBtn_clicked() void PathsSettingsTab::on_browseProfilesDirBtn_clicked() { QString searchPath = ui->profilesDirEdit->text(); - searchPath = PathSettings::resolve(searchPath, ui->baseDirEdit->text()); + searchPath = PathSettings::resolve(searchPath, ui->baseDirEdit->text()); - QString temp = QFileDialog::getExistingDirectory(&dialog(), QObject::tr("Select profiles directory"), searchPath); + QString temp = QFileDialog::getExistingDirectory( + &dialog(), QObject::tr("Select profiles directory"), searchPath); if (!temp.isEmpty()) { ui->profilesDirEdit->setText(temp); } @@ -150,9 +186,10 @@ void PathsSettingsTab::on_browseProfilesDirBtn_clicked() void PathsSettingsTab::on_browseOverwriteDirBtn_clicked() { QString searchPath = ui->overwriteDirEdit->text(); - searchPath = PathSettings::resolve(searchPath, ui->baseDirEdit->text()); + searchPath = PathSettings::resolve(searchPath, ui->baseDirEdit->text()); - QString temp = QFileDialog::getExistingDirectory(&dialog(), QObject::tr("Select overwrite directory"), searchPath); + QString temp = QFileDialog::getExistingDirectory( + &dialog(), QObject::tr("Select overwrite directory"), searchPath); if (!temp.isEmpty()) { ui->overwriteDirEdit->setText(temp); } @@ -162,7 +199,9 @@ void PathsSettingsTab::on_browseGameDirBtn_clicked() { QFileInfo oldGameExe(ui->managedGameDirEdit->text()); - QString temp = QFileDialog::getOpenFileName(&dialog(), QObject::tr("Select game executable"), oldGameExe.absolutePath(), oldGameExe.fileName()); + QString temp = + QFileDialog::getOpenFileName(&dialog(), QObject::tr("Select game executable"), + oldGameExe.absolutePath(), oldGameExe.fileName()); if (temp.isEmpty()) { return; @@ -177,23 +216,23 @@ void PathsSettingsTab::on_browseGameDirBtn_clicked() // QFileInfo newExe(temp); const auto binaryPath = settings().game().plugin()->binaryName(); - QDir folder = newExe.absoluteDir(); - while (folder.exists() && !folder.isRoot() - && QFileInfo(folder.filePath(binaryPath)) != newExe) { + QDir folder = newExe.absoluteDir(); + while (folder.exists() && !folder.isRoot() && + QFileInfo(folder.filePath(binaryPath)) != newExe) { folder.cdUp(); } if (folder.exists(binaryPath)) { m_gameDir = folder; - ui->managedGameDirEdit->setText( - QDir::toNativeSeparators(m_gameDir.absoluteFilePath(settings().game().plugin()->binaryName()))); - } - else { - QMessageBox::warning(parentWidget(), QObject::tr("Error"), - QObject::tr("The given path was not recognized as a valid game installation. " - "The current game plugin requires the executable to be in a \"%1\" subfolder of the game directory.") - .arg(QFileInfo(binaryPath).path())); - + ui->managedGameDirEdit->setText(QDir::toNativeSeparators( + m_gameDir.absoluteFilePath(settings().game().plugin()->binaryName()))); + } else { + QMessageBox::warning( + parentWidget(), QObject::tr("Error"), + QObject::tr("The given path was not recognized as a valid game installation. " + "The current game plugin requires the executable to be in a \"%1\" " + "subfolder of the game directory.") + .arg(QFileInfo(binaryPath).path())); } } @@ -227,7 +266,7 @@ void PathsSettingsTab::on_overwriteDirEdit_editingFinished() normalizePath(ui->overwriteDirEdit); } -void PathsSettingsTab::normalizePath(QLineEdit *lineEdit) +void PathsSettingsTab::normalizePath(QLineEdit* lineEdit) { QString text = lineEdit->text(); while (text.endsWith('/') || text.endsWith('\\')) { diff --git a/src/settingsdialogpaths.h b/src/settingsdialogpaths.h index 9562289b..239c79c7 100644 --- a/src/settingsdialogpaths.h +++ b/src/settingsdialogpaths.h @@ -26,9 +26,9 @@ private: void on_overwriteDirEdit_editingFinished(); void on_profilesDirEdit_editingFinished(); - void normalizePath(QLineEdit *lineEdit); + void normalizePath(QLineEdit* lineEdit); QDir m_gameDir; }; -#endif // SETTINGSDIALOGPATHS_H +#endif // SETTINGSDIALOGPATHS_H diff --git a/src/settingsdialogplugins.cpp b/src/settingsdialogplugins.cpp index 2f7f3985..db00ca08 100644 --- a/src/settingsdialogplugins.cpp +++ b/src/settingsdialogplugins.cpp @@ -1,6 +1,6 @@ #include "settingsdialogplugins.h" -#include "ui_settingsdialog.h" #include "noeditdelegate.h" +#include "ui_settingsdialog.h" #include <iplugin.h> #include "disableproxyplugindialog.h" @@ -9,8 +9,9 @@ using namespace MOBase; -PluginsSettingsTab::PluginsSettingsTab(Settings& s, PluginContainer* pluginContainer, SettingsDialog& d) - : SettingsTab(s, d), m_pluginContainer(pluginContainer) +PluginsSettingsTab::PluginsSettingsTab(Settings& s, PluginContainer* pluginContainer, + SettingsDialog& d) + : SettingsTab(s, d), m_pluginContainer(pluginContainer) { ui->pluginSettingsList->setStyleSheet("QTreeWidget::item {padding-right: 10px;}"); @@ -19,7 +20,7 @@ PluginsSettingsTab::PluginsSettingsTab(Settings& s, PluginContainer* pluginConta pluginInterfaces.sort(Qt::CaseInsensitive); std::map<QString, QTreeWidgetItem*> topItems; for (QString interfaceName : pluginInterfaces) { - auto* item = new QTreeWidgetItem(ui->pluginsList, { interfaceName }); + auto* item = new QTreeWidgetItem(ui->pluginsList, {interfaceName}); item->setFlags(item->flags() & ~Qt::ItemIsSelectable); auto font = item->font(0); font.setBold(true); @@ -33,16 +34,18 @@ PluginsSettingsTab::PluginsSettingsTab(Settings& s, PluginContainer* pluginConta // display plugin settings QSet<QString> handledNames; for (IPlugin* plugin : settings().plugins().plugins()) { - if (handledNames.contains(plugin->name()) || m_pluginContainer->requirements(plugin).master()) { + if (handledNames.contains(plugin->name()) || + m_pluginContainer->requirements(plugin).master()) { continue; } QTreeWidgetItem* listItem = new QTreeWidgetItem( - topItems.at(m_pluginContainer->topImplementedInterface(plugin))); + topItems.at(m_pluginContainer->topImplementedInterface(plugin))); listItem->setData(0, Qt::DisplayRole, plugin->localizedName()); listItem->setData(0, PluginRole, QVariant::fromValue((void*)plugin)); listItem->setData(0, SettingsRole, settings().plugins().settings(plugin->name())); - listItem->setData(0, DescriptionsRole, settings().plugins().descriptions(plugin->name())); + listItem->setData(0, DescriptionsRole, + settings().plugins().descriptions(plugin->name())); // Handle child item: auto children = m_pluginContainer->requirements(plugin).children(); @@ -51,7 +54,8 @@ PluginsSettingsTab::PluginsSettingsTab(Settings& s, PluginContainer* pluginConta childItem->setData(0, Qt::DisplayRole, child->localizedName()); childItem->setData(0, PluginRole, QVariant::fromValue((void*)child)); childItem->setData(0, SettingsRole, settings().plugins().settings(child->name())); - childItem->setData(0, DescriptionsRole, settings().plugins().descriptions(child->name())); + childItem->setData(0, DescriptionsRole, + settings().plugins().descriptions(child->name())); handledNames.insert(child->name()); } @@ -68,23 +72,28 @@ PluginsSettingsTab::PluginsSettingsTab(Settings& s, PluginContainer* pluginConta ui->pluginsList->sortByColumn(0, Qt::AscendingOrder); // display plugin blacklist - for (const QString &pluginName : settings().plugins().blacklist()) { + for (const QString& pluginName : settings().plugins().blacklist()) { ui->pluginBlacklist->addItem(pluginName); } m_filter.setEdit(ui->pluginFilterEdit); - QObject::connect( - ui->pluginsList, &QTreeWidget::currentItemChanged, - [&](auto* current, auto* previous) { on_pluginsList_currentItemChanged(current, previous); }); - QObject::connect( - ui->enabledCheckbox, &QCheckBox::clicked, - [&](bool checked) { on_checkboxEnabled_clicked(checked); }); + QObject::connect(ui->pluginsList, &QTreeWidget::currentItemChanged, + [&](auto* current, auto* previous) { + on_pluginsList_currentItemChanged(current, previous); + }); + QObject::connect(ui->enabledCheckbox, &QCheckBox::clicked, [&](bool checked) { + on_checkboxEnabled_clicked(checked); + }); - QShortcut *delShortcut = new QShortcut( - QKeySequence(Qt::Key_Delete), ui->pluginBlacklist); - QObject::connect(delShortcut, &QShortcut::activated, &dialog(), [&] { deleteBlacklistItem(); }); - QObject::connect(&m_filter, &FilterWidget::changed, [&] { filterPluginList(); }); + QShortcut* delShortcut = + new QShortcut(QKeySequence(Qt::Key_Delete), ui->pluginBlacklist); + QObject::connect(delShortcut, &QShortcut::activated, &dialog(), [&] { + deleteBlacklistItem(); + }); + QObject::connect(&m_filter, &FilterWidget::changed, [&] { + filterPluginList(); + }); updateListItems(); filterPluginList(); @@ -95,11 +104,11 @@ void PluginsSettingsTab::updateListItems() for (auto i = 0; i < ui->pluginsList->topLevelItemCount(); ++i) { auto* topLevelItem = ui->pluginsList->topLevelItem(i); for (auto j = 0; j < topLevelItem->childCount(); ++j) { - auto* item = topLevelItem->child(j); + auto* item = topLevelItem->child(j); auto* plugin = this->plugin(item); - bool inactive = !m_pluginContainer->implementInterface<IPluginGame>(plugin) - && !m_pluginContainer->isEnabled(plugin); + bool inactive = !m_pluginContainer->implementInterface<IPluginGame>(plugin) && + !m_pluginContainer->isEnabled(plugin); auto font = item->font(0); font.setItalic(inactive); @@ -109,12 +118,11 @@ void PluginsSettingsTab::updateListItems() } } } - } void PluginsSettingsTab::filterPluginList() { - auto selectedItems = ui->pluginsList->selectedItems(); + auto selectedItems = ui->pluginsList->selectedItems(); QTreeWidgetItem* firstNotHidden = nullptr; for (auto i = 0; i < ui->pluginsList->topLevelItemCount(); ++i) { @@ -122,7 +130,7 @@ void PluginsSettingsTab::filterPluginList() bool found = false; for (auto j = 0; j < topLevelItem->childCount(); ++j) { - auto* item = topLevelItem->child(j); + auto* item = topLevelItem->child(j); auto* plugin = this->plugin(item); // Check the item or the child - If any match (item or child), the whole @@ -143,8 +151,7 @@ void PluginsSettingsTab::filterPluginList() if (firstNotHidden == nullptr) { firstNotHidden = item; } - } - else { + } else { item->setHidden(true); } } @@ -159,17 +166,14 @@ void PluginsSettingsTab::filterPluginList() ui->noPluginLabel->setVisible(false); if (selectedItems.isEmpty()) { ui->pluginsList->setCurrentItem(firstNotHidden); - } - else if (selectedItems[0]->isHidden()) { + } else if (selectedItems[0]->isHidden()) { ui->pluginsList->setCurrentItem(firstNotHidden); } - } - else { + } else { ui->pluginDescription->setVisible(false); ui->pluginSettingsList->setVisible(false); ui->noPluginLabel->setVisible(true); } - } IPlugin* PluginsSettingsTab::plugin(QTreeWidgetItem* pluginItem) const @@ -181,17 +185,17 @@ void PluginsSettingsTab::update() { // transfer plugin settings to in-memory structure for (int i = 0; i < ui->pluginsList->topLevelItemCount(); ++i) { - auto *topLevelItem = ui->pluginsList->topLevelItem(i); + auto* topLevelItem = ui->pluginsList->topLevelItem(i); for (int j = 0; j < topLevelItem->childCount(); ++j) { auto* item = topLevelItem->child(j); - settings().plugins().setSettings( - plugin(item)->name(), item->data(0, SettingsRole).toMap()); + settings().plugins().setSettings(plugin(item)->name(), + item->data(0, SettingsRole).toMap()); } } // set plugin blacklist QStringList names; - for (QListWidgetItem *item : ui->pluginBlacklist->findItems("*", Qt::MatchWildcard)) { + for (QListWidgetItem* item : ui->pluginBlacklist->findItems("*", Qt::MatchWildcard)) { names.push_back(item->text()); } @@ -208,28 +212,28 @@ void PluginsSettingsTab::closing() void PluginsSettingsTab::on_checkboxEnabled_clicked(bool checked) { // Retrieve the plugin: - auto *item = ui->pluginsList->currentItem(); + auto* item = ui->pluginsList->currentItem(); if (!item || !item->data(0, PluginRole).isValid()) { return; } - IPlugin* plugin = this->plugin(item); + IPlugin* plugin = this->plugin(item); const auto& requirements = m_pluginContainer->requirements(plugin); // User wants to enable: if (checked) { m_pluginContainer->setEnabled(plugin, true, false); - } - else { + } else { // Custom check for proxy + current game: if (m_pluginContainer->implementInterface<IPluginProxy>(plugin)) { // Current game: auto* game = m_pluginContainer->managedGame(); if (m_pluginContainer->requirements(game).proxy() == plugin) { - QMessageBox::warning( - parentWidget(), QObject::tr("Cannot disable plugin"), - QObject::tr("The '%1' plugin is used by the current game plugin and cannot disabled.") - .arg(plugin->localizedName()), QMessageBox::Ok); + QMessageBox::warning(parentWidget(), QObject::tr("Cannot disable plugin"), + QObject::tr("The '%1' plugin is used by the current game " + "plugin and cannot disabled.") + .arg(plugin->localizedName()), + QMessageBox::Ok); ui->enabledCheckbox->setChecked(true); return; } @@ -253,12 +257,14 @@ void PluginsSettingsTab::on_checkboxEnabled_clicked(bool checked) pluginNames.append(p->localizedName()); } pluginNames.sort(); - QString message = QObject::tr( - "<p>Disabling the '%1' plugin will also disable the following plugins:</p><ul>%1</ul><p>Do you want to continue?</p>") - .arg(plugin->localizedName()).arg("<li>" + pluginNames.join("</li><li>") + "</li>"); - if (QMessageBox::warning( - parentWidget(), QObject::tr("Really disable plugin?"), message, - QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) { + QString message = + QObject::tr("<p>Disabling the '%1' plugin will also disable the following " + "plugins:</p><ul>%1</ul><p>Do you want to continue?</p>") + .arg(plugin->localizedName()) + .arg("<li>" + pluginNames.join("</li><li>") + "</li>"); + if (QMessageBox::warning(parentWidget(), QObject::tr("Really disable plugin?"), + message, + QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) { ui->enabledCheckbox->setChecked(true); return; } @@ -274,7 +280,8 @@ void PluginsSettingsTab::on_checkboxEnabled_clicked(bool checked) updateListItems(); } -void PluginsSettingsTab::on_pluginsList_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous) +void PluginsSettingsTab::on_pluginsList_currentItemChanged(QTreeWidgetItem* current, + QTreeWidgetItem* previous) { storeSettings(previous); @@ -291,17 +298,18 @@ void PluginsSettingsTab::on_pluginsList_currentItemChanged(QTreeWidgetItem *curr // Checkbox, do not show for children or game plugins, disable // if the plugin cannot be enabled. ui->enabledCheckbox->setVisible( - !m_pluginContainer->implementInterface<IPluginGame>(plugin) - && plugin->master().isEmpty()); + !m_pluginContainer->implementInterface<IPluginGame>(plugin) && + plugin->master().isEmpty()); - bool enabled = m_pluginContainer->isEnabled(plugin); + bool enabled = m_pluginContainer->isEnabled(plugin); auto& requirements = m_pluginContainer->requirements(plugin); - auto problems = requirements.problems(); + auto problems = requirements.problems(); if (m_pluginContainer->requirements(plugin).isCorePlugin()) { ui->enabledCheckbox->setDisabled(true); ui->enabledCheckbox->setToolTip( - QObject::tr("This plugin is required for Mod Organizer to work properly and cannot be disabled.")); + QObject::tr("This plugin is required for Mod Organizer to work properly and " + "cannot be disabled.")); } // Plugin is enable or can be enabled. else if (enabled || problems.empty()) { @@ -315,22 +323,22 @@ void PluginsSettingsTab::on_pluginsList_currentItemChanged(QTreeWidgetItem *curr ui->enabledCheckbox->setChecked(false); if (problems.size() == 1) { ui->enabledCheckbox->setToolTip(problems[0].shortDescription()); - } - else { + } else { QStringList descriptions; for (auto& problem : problems) { descriptions.append(problem.shortDescription()); } - ui->enabledCheckbox->setToolTip("<ul><li>" + descriptions.join("</li><li>") + "</li></ul>"); + ui->enabledCheckbox->setToolTip("<ul><li>" + descriptions.join("</li><li>") + + "</li></ul>"); } } - QVariantMap settings = current->data(0, SettingsRole).toMap(); + QVariantMap settings = current->data(0, SettingsRole).toMap(); QVariantMap descriptions = current->data(0, DescriptionsRole).toMap(); ui->pluginSettingsList->setEnabled(settings.count() != 0); for (auto iter = settings.begin(); iter != settings.end(); ++iter) { - QTreeWidgetItem *newItem = new QTreeWidgetItem(QStringList(iter.key())); - QVariant value = *iter; + QTreeWidgetItem* newItem = new QTreeWidgetItem(QStringList(iter.key())); + QVariant value = *iter; QString description; { auto descriptionIter = descriptions.find(iter.key()); @@ -357,14 +365,14 @@ void PluginsSettingsTab::deleteBlacklistItem() ui->pluginBlacklist->takeItem(ui->pluginBlacklist->currentIndex().row()); } -void PluginsSettingsTab::storeSettings(QTreeWidgetItem *pluginItem) +void PluginsSettingsTab::storeSettings(QTreeWidgetItem* pluginItem) { if (pluginItem != nullptr && pluginItem->data(0, PluginRole).isValid()) { QVariantMap settings = pluginItem->data(0, SettingsRole).toMap(); for (int i = 0; i < ui->pluginSettingsList->topLevelItemCount(); ++i) { - const QTreeWidgetItem *item = ui->pluginSettingsList->topLevelItem(i); - settings[item->text(0)] = item->data(1, Qt::DisplayRole); + const QTreeWidgetItem* item = ui->pluginSettingsList->topLevelItem(i); + settings[item->text(0)] = item->data(1, Qt::DisplayRole); } pluginItem->setData(0, SettingsRole, settings); diff --git a/src/settingsdialogplugins.h b/src/settingsdialogplugins.h index c784b83e..416f457a 100644 --- a/src/settingsdialogplugins.h +++ b/src/settingsdialogplugins.h @@ -9,16 +9,18 @@ class PluginsSettingsTab : public SettingsTab { public: - PluginsSettingsTab(Settings& settings, PluginContainer* pluginContainer, SettingsDialog& dialog); + PluginsSettingsTab(Settings& settings, PluginContainer* pluginContainer, + SettingsDialog& dialog); void update(); void closing() override; private: - void on_pluginsList_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); + void on_pluginsList_currentItemChanged(QTreeWidgetItem* current, + QTreeWidgetItem* previous); void on_checkboxEnabled_clicked(bool checked); void deleteBlacklistItem(); - void storeSettings(QTreeWidgetItem *pluginItem); + void storeSettings(QTreeWidgetItem* pluginItem); private slots: @@ -37,19 +39,19 @@ private slots: * @brief Retrieve the plugin associated to the given item in the list. * */ - MOBase::IPlugin* plugin(QTreeWidgetItem *pluginItem) const; + MOBase::IPlugin* plugin(QTreeWidgetItem* pluginItem) const; - enum { - PluginRole = Qt::UserRole, - SettingsRole = Qt::UserRole + 1, + enum + { + PluginRole = Qt::UserRole, + SettingsRole = Qt::UserRole + 1, DescriptionsRole = Qt::UserRole + 2 }; private: - PluginContainer* m_pluginContainer; MOBase::FilterWidget m_filter; }; -#endif // SETTINGSDIALOGPLUGINS_H +#endif // SETTINGSDIALOGPLUGINS_H diff --git a/src/settingsdialogtheme.cpp b/src/settingsdialogtheme.cpp index 9b32773b..75bcdb59 100644 --- a/src/settingsdialogtheme.cpp +++ b/src/settingsdialogtheme.cpp @@ -1,16 +1,15 @@ #include "settingsdialogtheme.h" -#include "ui_settingsdialog.h" -#include "shared/appconfig.h" #include "categoriesdialog.h" #include "colortable.h" #include "modlist.h" -#include <utility.h> +#include "shared/appconfig.h" +#include "ui_settingsdialog.h" #include <questionboxmemory.h> +#include <utility.h> using namespace MOBase; -ThemeSettingsTab::ThemeSettingsTab(Settings& s, SettingsDialog& d) - : SettingsTab(s, d) +ThemeSettingsTab::ThemeSettingsTab(Settings& s, SettingsDialog& d) : SettingsTab(s, d) { // style addStyles(); @@ -19,17 +18,21 @@ ThemeSettingsTab::ThemeSettingsTab(Settings& s, SettingsDialog& d) // colors ui->colorTable->load(s); - QObject::connect(ui->resetColorsBtn, &QPushButton::clicked, [&] { ui->colorTable->resetColors(); }); + QObject::connect(ui->resetColorsBtn, &QPushButton::clicked, [&] { + ui->colorTable->resetColors(); + }); - QObject::connect(ui->exploreStyles, &QPushButton::clicked, [&] { onExploreStyles(); }); + QObject::connect(ui->exploreStyles, &QPushButton::clicked, [&] { + onExploreStyles(); + }); } void ThemeSettingsTab::update() { // style const QString oldStyle = settings().interface().styleName().value_or(""); - const QString newStyle = ui->styleBox->itemData( - ui->styleBox->currentIndex()).toString(); + const QString newStyle = + ui->styleBox->itemData(ui->styleBox->currentIndex()).toString(); if (oldStyle != newStyle) { settings().interface().setStyleName(newStyle); @@ -49,25 +52,21 @@ void ThemeSettingsTab::addStyles() ui->styleBox->insertSeparator(ui->styleBox->count()); - QDirIterator iter( - QCoreApplication::applicationDirPath() + "/" + - QString::fromStdWString(AppConfig::stylesheetsPath()), - QStringList("*.qss"), - QDir::Files); + QDirIterator iter(QCoreApplication::applicationDirPath() + "/" + + QString::fromStdWString(AppConfig::stylesheetsPath()), + QStringList("*.qss"), QDir::Files); while (iter.hasNext()) { iter.next(); - ui->styleBox->addItem( - iter.fileInfo().completeBaseName(), - iter.fileName()); + ui->styleBox->addItem(iter.fileInfo().completeBaseName(), iter.fileName()); } } void ThemeSettingsTab::selectStyle() { - const int currentID = ui->styleBox->findData( - settings().interface().styleName().value_or("")); + const int currentID = + ui->styleBox->findData(settings().interface().styleName().value_or("")); if (currentID != -1) { ui->styleBox->setCurrentIndex(currentID); @@ -76,7 +75,7 @@ void ThemeSettingsTab::selectStyle() void ThemeSettingsTab::onExploreStyles() { - QString ssPath = QCoreApplication::applicationDirPath() + "/" + ToQString(AppConfig::stylesheetsPath()); + QString ssPath = QCoreApplication::applicationDirPath() + "/" + + ToQString(AppConfig::stylesheetsPath()); shell::Explore(ssPath); } - diff --git a/src/settingsdialogtheme.h b/src/settingsdialogtheme.h index 61334c0b..2a53dc38 100644 --- a/src/settingsdialogtheme.h +++ b/src/settingsdialogtheme.h @@ -3,8 +3,8 @@ #include <QCheckBox> -#include "settingsdialog.h" #include "settings.h" +#include "settingsdialog.h" class ThemeSettingsTab : public SettingsTab { @@ -14,11 +14,9 @@ public: void update() override; private: - void addStyles(); void selectStyle(); void onExploreStyles(); - }; -#endif // SETTINGSDIALOGGENERAL_H +#endif // SETTINGSDIALOGGENERAL_H diff --git a/src/settingsdialogworkarounds.cpp b/src/settingsdialogworkarounds.cpp index cf54908a..36e5dd44 100644 --- a/src/settingsdialogworkarounds.cpp +++ b/src/settingsdialogworkarounds.cpp @@ -1,13 +1,13 @@ #include "settingsdialogworkarounds.h" -#include "ui_settingsdialog.h" -#include "spawn.h" #include "settings.h" -#include <report.h> +#include "spawn.h" +#include "ui_settingsdialog.h" #include <iplugingame.h> #include <log.h> +#include <report.h> WorkaroundsSettingsTab::WorkaroundsSettingsTab(Settings& s, SettingsDialog& d) - : SettingsTab(s, d) + : SettingsTab(s, d) { // options ui->forceEnableBox->setChecked(settings().game().forceEnableCoreFiles()); @@ -35,9 +35,15 @@ WorkaroundsSettingsTab::WorkaroundsSettingsTab(Settings& s, SettingsDialog& d) // buttons m_ExecutableBlacklist = settings().executablesBlacklist(); - QObject::connect(ui->bsaDateBtn, &QPushButton::clicked, [&]{ on_bsaDateBtn_clicked(); }); - QObject::connect(ui->execBlacklistBtn, &QPushButton::clicked, [&]{ on_execBlacklistBtn_clicked(); }); - QObject::connect(ui->resetGeometryBtn, &QPushButton::clicked, [&]{ on_resetGeometryBtn_clicked(); }); + QObject::connect(ui->bsaDateBtn, &QPushButton::clicked, [&] { + on_bsaDateBtn_clicked(); + }); + QObject::connect(ui->execBlacklistBtn, &QPushButton::clicked, [&] { + on_execBlacklistBtn_clicked(); + }); + QObject::connect(ui->resetGeometryBtn, &QPushButton::clicked, [&] { + on_resetGeometryBtn_clicked(); + }); } void WorkaroundsSettingsTab::update() @@ -65,12 +71,11 @@ void WorkaroundsSettingsTab::update() settings().setExecutablesBlacklist(m_ExecutableBlacklist); } -bool WorkaroundsSettingsTab::changeBlacklistNow( - QWidget* parent, Settings& settings) +bool WorkaroundsSettingsTab::changeBlacklistNow(QWidget* parent, Settings& settings) { const auto current = settings.executablesBlacklist(); - if (auto s=changeBlacklistLater(parent, current)) { + if (auto s = changeBlacklistLater(parent, current)) { settings.setExecutablesBlacklist(*s); return true; } @@ -78,23 +83,22 @@ bool WorkaroundsSettingsTab::changeBlacklistNow( return false; } -std::optional<QString> WorkaroundsSettingsTab::changeBlacklistLater( - QWidget* parent, const QString& current) +std::optional<QString> +WorkaroundsSettingsTab::changeBlacklistLater(QWidget* parent, const QString& current) { bool ok = false; QString result = QInputDialog::getMultiLineText( - parent, - QObject::tr("Executables Blacklist"), - QObject::tr("Enter one executable per line to be blacklisted from the virtual file system.\n" - "Mods and other virtualized files will not be visible to these executables and\n" - "any executables launched by them.\n\n" - "Example:\n" - " Chrome.exe\n" - " Firefox.exe"), - current.split(";").join("\n"), - &ok - ); + parent, QObject::tr("Executables Blacklist"), + QObject::tr("Enter one executable per line to be blacklisted from the virtual " + "file system.\n" + "Mods and other virtualized files will not be visible to these " + "executables and\n" + "any executables launched by them.\n\n" + "Example:\n" + " Chrome.exe\n" + " Firefox.exe"), + current.split(";").join("\n"), &ok); if (!ok) { return {}; @@ -112,7 +116,7 @@ std::optional<QString> WorkaroundsSettingsTab::changeBlacklistLater( void WorkaroundsSettingsTab::on_execBlacklistBtn_clicked() { - if (auto s=changeBlacklistLater(parentWidget(), m_ExecutableBlacklist)) { + if (auto s = changeBlacklistLater(parentWidget(), m_ExecutableBlacklist)) { m_ExecutableBlacklist = *s; } } @@ -120,24 +124,23 @@ void WorkaroundsSettingsTab::on_execBlacklistBtn_clicked() void WorkaroundsSettingsTab::on_bsaDateBtn_clicked() { const auto* game = qApp->property("managed_game").value<MOBase::IPluginGame*>(); - QDir dir = game->dataDirectory(); + QDir dir = game->dataDirectory(); - helper::backdateBSAs( - parentWidget(), - qApp->applicationDirPath().toStdWString(), - dir.absolutePath().toStdWString()); + helper::backdateBSAs(parentWidget(), qApp->applicationDirPath().toStdWString(), + dir.absolutePath().toStdWString()); } void WorkaroundsSettingsTab::on_resetGeometryBtn_clicked() { - const auto r = MOBase::TaskDialog(parentWidget()) - .title(QObject::tr("Restart Mod Organizer")) - .main(QObject::tr("Restart Mod Organizer")) - .content(QObject::tr("Geometries will be reset to their default values.")) - .icon(QMessageBox::Question) - .button({QObject::tr("Restart Mod Organizer"), QMessageBox::Ok}) - .button({QObject::tr("Cancel"), QMessageBox::Cancel}) - .exec(); + const auto r = + MOBase::TaskDialog(parentWidget()) + .title(QObject::tr("Restart Mod Organizer")) + .main(QObject::tr("Restart Mod Organizer")) + .content(QObject::tr("Geometries will be reset to their default values.")) + .icon(QMessageBox::Question) + .button({QObject::tr("Restart Mod Organizer"), QMessageBox::Ok}) + .button({QObject::tr("Cancel"), QMessageBox::Cancel}) + .exec(); if (r == QMessageBox::Ok) { settings().geometry().requestReset(); diff --git a/src/settingsdialogworkarounds.h b/src/settingsdialogworkarounds.h index cffc54a0..8c86fd69 100644 --- a/src/settingsdialogworkarounds.h +++ b/src/settingsdialogworkarounds.h @@ -17,8 +17,8 @@ public: // shows the blacklist dialog from the given string and returns the new // blacklist if the user accepted it // - static std::optional<QString> changeBlacklistLater( - QWidget* parent, const QString& current); + static std::optional<QString> changeBlacklistLater(QWidget* parent, + const QString& current); void update(); @@ -30,4 +30,4 @@ private: void on_resetGeometryBtn_clicked(); }; -#endif // SETTINGSDIALOGWORKAROUNDS_H +#endif // SETTINGSDIALOGWORKAROUNDS_H diff --git a/src/settingsutilities.cpp b/src/settingsutilities.cpp index db7c1818..698649e6 100644 --- a/src/settingsutilities.cpp +++ b/src/settingsutilities.cpp @@ -27,7 +27,6 @@ void logRemoval(const QString& name) log::debug("setting '{}' removed", name); } - QString settingName(const QString& section, const QString& key) { if (section.isEmpty()) { @@ -43,9 +42,8 @@ QString settingName(const QString& section, const QString& key) } } -void removeImpl( - QSettings& settings, const QString& displayName, - const QString& section, const QString& key) +void removeImpl(QSettings& settings, const QString& displayName, const QString& section, + const QString& key) { if (key.isEmpty()) { if (!settings.childGroups().contains(section, Qt::CaseInsensitive)) { @@ -73,9 +71,8 @@ void removeSection(QSettings& settings, const QString& section) removeImpl(settings, section, section, ""); } - ScopedGroup::ScopedGroup(QSettings& s, const QString& name) - : m_settings(s), m_name(name) + : m_settings(s), m_name(name) { m_settings.beginGroup(m_name); } @@ -95,9 +92,8 @@ QStringList ScopedGroup::keys() const return m_settings.childKeys(); } - ScopedReadArray::ScopedReadArray(QSettings& s, const QString& section) - : m_settings(s), m_count(0) + : m_settings(s), m_count(0) { m_count = m_settings.beginReadArray(section); } @@ -117,13 +113,11 @@ QStringList ScopedReadArray::keys() const return m_settings.childKeys(); } - -ScopedWriteArray::ScopedWriteArray( - QSettings& s, const QString& section, std::size_t size) +ScopedWriteArray::ScopedWriteArray(QSettings& s, const QString& section, + std::size_t size) : m_settings(s), m_section(section), m_i(0) { - m_settings.beginWriteArray( - section, size == NoSize ? -1 : static_cast<int>(size)); + m_settings.beginWriteArray(section, size == NoSize ? -1 : static_cast<int>(size)); } ScopedWriteArray::~ScopedWriteArray() @@ -137,7 +131,6 @@ void ScopedWriteArray::next() ++m_i; } - QString widgetNameWithTopLevel(const QWidget* widget) { QStringList components; @@ -206,13 +199,12 @@ QString checkedSettingName(const QAbstractButton* b) void warnIfNotCheckable(const QAbstractButton* b) { if (!b->isCheckable()) { - log::warn( - "button '{}' used in the settings as a checkbox or radio button " - "but is not checkable", b->objectName()); + log::warn("button '{}' used in the settings as a checkbox or radio button " + "but is not checkable", + b->objectName()); } } - QString credentialName(const QString& key) { return "ModOrganizer2_" + key; @@ -232,9 +224,8 @@ bool deleteWindowsCredential(const QString& key) return true; } - log::error( - "failed to delete windows credential {}, {}", - credName, formatSystemMessage(e)); + log::error("failed to delete windows credential {}, {}", credName, + formatSystemMessage(e)); return false; } @@ -250,23 +241,22 @@ bool addWindowsCredential(const QString& key, const QString& data) const auto wname = credName.toStdWString(); const auto wdata = data.toStdWString(); - const auto* blob = reinterpret_cast<const BYTE*>(wdata.data()); + const auto* blob = reinterpret_cast<const BYTE*>(wdata.data()); const auto blobSize = wdata.size() * sizeof(decltype(wdata)::value_type); - CREDENTIALW cred = {}; - cred.Flags = 0; - cred.Type = CRED_TYPE_GENERIC; - cred.TargetName = const_cast<wchar_t*>(wname.c_str()); - cred.CredentialBlob = const_cast<BYTE*>(blob); + CREDENTIALW cred = {}; + cred.Flags = 0; + cred.Type = CRED_TYPE_GENERIC; + cred.TargetName = const_cast<wchar_t*>(wname.c_str()); + cred.CredentialBlob = const_cast<BYTE*>(blob); cred.CredentialBlobSize = static_cast<DWORD>(blobSize); - cred.Persist = CRED_PERSIST_LOCAL_MACHINE; + cred.Persist = CRED_PERSIST_LOCAL_MACHINE; if (!CredWriteW(&cred, 0)) { const auto e = GetLastError(); - log::error( - "failed to delete windows credential {}, {}", - credName, formatSystemMessage(e)); + log::error("failed to delete windows credential {}, {}", credName, + formatSystemMessage(e)); return false; } @@ -294,8 +284,8 @@ QString getWindowsCredential(const QString& key) CREDENTIALW* rawCreds = nullptr; - const auto ret = CredReadW( - credName.toStdWString().c_str(), CRED_TYPE_GENERIC, 0, &rawCreds); + const auto ret = + CredReadW(credName.toStdWString().c_str(), CRED_TYPE_GENERIC, 0, &rawCreds); CredentialPtr creds(rawCreds); @@ -303,9 +293,8 @@ QString getWindowsCredential(const QString& key) const auto e = GetLastError(); if (e != ERROR_NOT_FOUND) { - log::error( - "failed to retrieve windows credential {}: {}", - credName, formatSystemMessage(e)); + log::error("failed to retrieve windows credential {}: {}", credName, + formatSystemMessage(e)); } return {}; @@ -313,9 +302,9 @@ QString getWindowsCredential(const QString& key) QString value; if (creds->CredentialBlob) { - value = QString::fromWCharArray( - reinterpret_cast<const wchar_t*>(creds->CredentialBlob), - creds->CredentialBlobSize / sizeof(wchar_t)); + value = + QString::fromWCharArray(reinterpret_cast<const wchar_t*>(creds->CredentialBlob), + creds->CredentialBlobSize / sizeof(wchar_t)); } return value; diff --git a/src/settingsutilities.h b/src/settingsutilities.h index 53eeff87..11b2af1c 100644 --- a/src/settingsutilities.h +++ b/src/settingsutilities.h @@ -3,17 +3,15 @@ #include <log.h> -namespace MOBase { - class ExpanderWidget; +namespace MOBase +{ +class ExpanderWidget; } -template <class T, class=void> +template <class T, class = void> struct ValueConverter { - static const T& convert(const T& t) - { - return t; - } + static const T& convert(const T& t) { return t; } }; template <class T> @@ -37,8 +35,7 @@ struct ValueConverter<QVariantList> bool shouldLogSetting(const QString& displayName); template <class T> -void logChange( - const QString& displayName, std::optional<T> oldValue, const T& newValue) +void logChange(const QString& displayName, std::optional<T> oldValue, const T& newValue) { if (!shouldLogSetting(displayName)) { return; @@ -47,25 +44,20 @@ void logChange( using VC = ValueConverter<T>; if (oldValue) { - MOBase::log::debug( - "setting '{}' changed from '{}' to '{}'", - displayName, VC::convert(*oldValue), VC::convert(newValue)); + MOBase::log::debug("setting '{}' changed from '{}' to '{}'", displayName, + VC::convert(*oldValue), VC::convert(newValue)); } else { - MOBase::log::debug( - "setting '{}' set to '{}'", - displayName, VC::convert(newValue)); + MOBase::log::debug("setting '{}' set to '{}'", displayName, VC::convert(newValue)); } } void logRemoval(const QString& name); - QString settingName(const QString& section, const QString& key); template <class T> -void setImpl( - QSettings& settings, const QString& displayName, - const QString& section, const QString& key, const T& value) +void setImpl(QSettings& settings, const QString& displayName, const QString& section, + const QString& key, const T& value) { const auto current = getOptional<T>(settings, section, key); @@ -79,22 +71,18 @@ void setImpl( logChange(displayName, current, value); if constexpr (std::is_enum_v<T>) { - settings.setValue( - name, static_cast<std::underlying_type_t<T>>(value)); + settings.setValue(name, static_cast<std::underlying_type_t<T>>(value)); } else { settings.setValue(name, value); } } -void removeImpl( - QSettings& settings, const QString& displayName, - const QString& section, const QString& key); - +void removeImpl(QSettings& settings, const QString& displayName, const QString& section, + const QString& key); template <class T> -std::optional<T> getOptional( - const QSettings& settings, - const QString& section, const QString& key, std::optional<T> def={}) +std::optional<T> getOptional(const QSettings& settings, const QString& section, + const QString& key, std::optional<T> def = {}) { if (settings.contains(settingName(section, key))) { const auto v = settings.value(settingName(section, key)); @@ -110,11 +98,9 @@ std::optional<T> getOptional( } template <class T> -T get( - const QSettings& settings, - const QString& section, const QString& key, T def) +T get(const QSettings& settings, const QString& section, const QString& key, T def) { - if (auto v=getOptional<T>(settings, section, key)) { + if (auto v = getOptional<T>(settings, section, key)) { return *v; } else { return def; @@ -122,9 +108,8 @@ T get( } template <class T> -void set( - QSettings& settings, - const QString& section, const QString& key, const T& value) +void set(QSettings& settings, const QString& section, const QString& key, + const T& value) { setImpl(settings, settingName(section, key), section, key, value); } @@ -132,14 +117,13 @@ void set( void remove(QSettings& settings, const QString& section, const QString& key); void removeSection(QSettings& settings, const QString& section); - class ScopedGroup { public: ScopedGroup(QSettings& s, const QString& name); ~ScopedGroup(); - ScopedGroup(const ScopedGroup&) = delete; + ScopedGroup(const ScopedGroup&) = delete; ScopedGroup& operator=(const ScopedGroup&) = delete; template <class T> @@ -161,13 +145,13 @@ public: } template <class T> - std::optional<T> getOptional(const QString& key, std::optional<T> def={}) const + std::optional<T> getOptional(const QString& key, std::optional<T> def = {}) const { return ::getOptional<T>(m_settings, "", key, def); } template <class T> - T get(const QString& key, T def={}) const + T get(const QString& key, T def = {}) const { return ::get<T>(m_settings, "", key, def); } @@ -177,33 +161,32 @@ private: QString m_name; }; - class ScopedReadArray { public: ScopedReadArray(QSettings& s, const QString& section); ~ScopedReadArray(); - ScopedReadArray(const ScopedReadArray&) = delete; + ScopedReadArray(const ScopedReadArray&) = delete; ScopedReadArray& operator=(const ScopedReadArray&) = delete; template <class F> void for_each(F&& f) const { - for (int i=0; i<count(); ++i) { + for (int i = 0; i < count(); ++i) { m_settings.setArrayIndex(i); f(); } } template <class T> - std::optional<T> getOptional(const QString& key, std::optional<T> def={}) const + std::optional<T> getOptional(const QString& key, std::optional<T> def = {}) const { return ::getOptional<T>(m_settings, "", key, def); } template <class T> - T get(const QString& key, T def={}) const + T get(const QString& key, T def = {}) const { return ::get<T>(m_settings, "", key, def); } @@ -216,16 +199,15 @@ private: int m_count; }; - class ScopedWriteArray { public: static const auto NoSize = std::numeric_limits<std::size_t>::max(); - ScopedWriteArray(QSettings& s, const QString& section, std::size_t size=NoSize); + ScopedWriteArray(QSettings& s, const QString& section, std::size_t size = NoSize); ~ScopedWriteArray(); - ScopedWriteArray(const ScopedWriteArray&) = delete; + ScopedWriteArray(const ScopedWriteArray&) = delete; ScopedWriteArray& operator=(const ScopedWriteArray&) = delete; void next(); @@ -233,10 +215,7 @@ public: template <class T> void set(const QString& key, const T& value) { - const auto displayName = QString("%1/%2\\%3") - .arg(m_section) - .arg(m_i) - .arg(key); + const auto displayName = QString("%1/%2\\%3").arg(m_section).arg(m_i).arg(key); setImpl(m_settings, displayName, "", key, value); } @@ -247,7 +226,6 @@ private: int m_i; }; - QString widgetNameWithTopLevel(const QWidget* widget); QString widgetName(const QMainWindow* w); QString widgetName(const QHeaderView* w); @@ -281,4 +259,4 @@ void warnIfNotCheckable(const QAbstractButton* b); bool setWindowsCredential(const QString& key, const QString& data); QString getWindowsCredential(const QString& key); -#endif // SETTINGSUTILITIES_H +#endif // SETTINGSUTILITIES_H diff --git a/src/shared/appconfig.cpp b/src/shared/appconfig.cpp index d2fc386c..221732de 100644 --- a/src/shared/appconfig.cpp +++ b/src/shared/appconfig.cpp @@ -19,15 +19,21 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "appconfig.h" -namespace AppConfig { +namespace AppConfig +{ #define PARWSTRING wstring -#define APPPARAM(partype, parid, value) partype parid () { return value; } +#define APPPARAM(partype, parid, value) \ + partype parid() \ + { \ + return value; \ + } #include "appconfig.inc" -namespace MOShared { +namespace MOShared +{ #undef PARWSTRING #undef APPPARAM -} -} // namespace MOShared +} // namespace MOShared +} // namespace AppConfig diff --git a/src/shared/appconfig.h b/src/shared/appconfig.h index cca5b0f5..598ee19c 100644 --- a/src/shared/appconfig.h +++ b/src/shared/appconfig.h @@ -22,19 +22,20 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <string> -namespace AppConfig { - +namespace AppConfig +{ #define PARWSTRING wstring -#define APPPARAM(partype, parid, value) partype parid (); +#define APPPARAM(partype, parid, value) partype parid(); #include "appconfig.inc" -namespace MOShared { +namespace MOShared +{ #undef PARWSTRING #undef APPPARAM -} +} // namespace MOShared -} // namespace MOShared +} // namespace AppConfig -#endif // APPCONFIG_H +#endif // APPCONFIG_H diff --git a/src/shared/directoryentry.cpp b/src/shared/directoryentry.cpp index 48ff7aa3..84da66e2 100644 --- a/src/shared/directoryentry.cpp +++ b/src/shared/directoryentry.cpp @@ -18,10 +18,10 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ #include "directoryentry.h" -#include "originconnection.h" -#include "filesorigin.h" -#include "fileentry.h" #include "../envfs.h" +#include "fileentry.h" +#include "filesorigin.h" +#include "originconnection.h" #include "util.h" #include "windows_error.h" #include <log.h> @@ -49,46 +49,45 @@ void elapsedImpl(std::chrono::nanoseconds& out, F&& f) // elapsed() is not optimized out when EnableInstrumentation is false even // though it's equivalent that this macro #define elapsed(OUT, F) (F)(); -//#define elapsed(OUT, F) elapsedImpl(OUT, F); +// #define elapsed(OUT, F) elapsedImpl(OUT, F); static bool SupportOptimizedFind() { - // large fetch and basic info for FindFirstFileEx is supported on win server 2008 r2, win 7 and newer + // large fetch and basic info for FindFirstFileEx is supported on win server 2008 r2, + // win 7 and newer OSVERSIONINFOEX versionInfo; versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - versionInfo.dwMajorVersion = 6; - versionInfo.dwMinorVersion = 1; + versionInfo.dwMajorVersion = 6; + versionInfo.dwMinorVersion = 1; ULONGLONG mask = ::VerSetConditionMask( - ::VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL), - VER_MINORVERSION, VER_GREATER_EQUAL); + ::VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL), VER_MINORVERSION, + VER_GREATER_EQUAL); - return (::VerifyVersionInfo(&versionInfo, VER_MAJORVERSION | VER_MINORVERSION, mask) == TRUE); + return (::VerifyVersionInfo(&versionInfo, VER_MAJORVERSION | VER_MINORVERSION, + mask) == TRUE); } -bool DirCompareByName::operator()( - const DirectoryEntry* lhs, const DirectoryEntry* rhs) const +bool DirCompareByName::operator()(const DirectoryEntry* lhs, + const DirectoryEntry* rhs) const { return _wcsicmp(lhs->getName().c_str(), rhs->getName().c_str()) < 0; } - -DirectoryEntry::DirectoryEntry( - std::wstring name, DirectoryEntry* parent, int originID) : - m_OriginConnection(new OriginConnection), - m_Name(std::move(name)), m_Parent(parent), m_Populated(false), m_TopLevel(true) +DirectoryEntry::DirectoryEntry(std::wstring name, DirectoryEntry* parent, int originID) + : m_OriginConnection(new OriginConnection), m_Name(std::move(name)), + m_Parent(parent), m_Populated(false), m_TopLevel(true) { m_FileRegister.reset(new FileRegister(m_OriginConnection)); m_Origins.insert(originID); } -DirectoryEntry::DirectoryEntry( - std::wstring name, DirectoryEntry* parent, int originID, - boost::shared_ptr<FileRegister> fileRegister, - boost::shared_ptr<OriginConnection> originConnection) : - m_FileRegister(fileRegister), m_OriginConnection(originConnection), - m_Name(std::move(name)), m_Parent(parent), m_Populated(false), m_TopLevel(false) +DirectoryEntry::DirectoryEntry(std::wstring name, DirectoryEntry* parent, int originID, + boost::shared_ptr<FileRegister> fileRegister, + boost::shared_ptr<OriginConnection> originConnection) + : m_FileRegister(fileRegister), m_OriginConnection(originConnection), + m_Name(std::move(name)), m_Parent(parent), m_Populated(false), m_TopLevel(false) { m_Origins.insert(originID); } @@ -100,7 +99,7 @@ DirectoryEntry::~DirectoryEntry() void DirectoryEntry::clear() { - for (auto itor=m_SubDirectories.rbegin(); itor!=m_SubDirectories.rend(); ++itor) { + for (auto itor = m_SubDirectories.rbegin(); itor != m_SubDirectories.rend(); ++itor) { delete *itor; } @@ -110,19 +109,20 @@ void DirectoryEntry::clear() m_SubDirectoriesLookup.clear(); } -void DirectoryEntry::addFromOrigin( - const std::wstring &originName, const std::wstring &directory, int priority, - DirectoryStats& stats) +void DirectoryEntry::addFromOrigin(const std::wstring& originName, + const std::wstring& directory, int priority, + DirectoryStats& stats) { env::DirectoryWalker walker; addFromOrigin(walker, originName, directory, priority, stats); } -void DirectoryEntry::addFromOrigin( - env::DirectoryWalker& walker, const std::wstring &originName, - const std::wstring &directory, int priority, DirectoryStats& stats) +void DirectoryEntry::addFromOrigin(env::DirectoryWalker& walker, + const std::wstring& originName, + const std::wstring& directory, int priority, + DirectoryStats& stats) { - FilesOrigin &origin = createOrigin(originName, directory, priority, stats); + FilesOrigin& origin = createOrigin(originName, directory, priority, stats); if (!directory.empty()) { addFiles(walker, origin, directory, stats); @@ -131,27 +131,27 @@ void DirectoryEntry::addFromOrigin( m_Populated = true; } -void DirectoryEntry::addFromList( - const std::wstring &originName, const std::wstring &directory, - env::Directory& root, int priority, DirectoryStats& stats) +void DirectoryEntry::addFromList(const std::wstring& originName, + const std::wstring& directory, env::Directory& root, + int priority, DirectoryStats& stats) { stats = {}; - FilesOrigin &origin = createOrigin(originName, directory, priority, stats); + FilesOrigin& origin = createOrigin(originName, directory, priority, stats); addDir(origin, root, stats); } -void DirectoryEntry::addDir( - FilesOrigin& origin, env::Directory& d, DirectoryStats& stats) +void DirectoryEntry::addDir(FilesOrigin& origin, env::Directory& d, + DirectoryStats& stats) { - elapsed(stats.dirTimes, [&]{ + elapsed(stats.dirTimes, [&] { for (auto& sd : d.dirs) { auto* sdirEntry = getSubDirectory(sd, true, stats, origin.getID()); sdirEntry->addDir(origin, sd, stats); } }); - elapsed(stats.fileTimes, [&]{ + elapsed(stats.fileTimes, [&] { for (auto& f : d.files) { insert(f, origin, L"", -1, stats); } @@ -160,12 +160,12 @@ void DirectoryEntry::addDir( m_Populated = true; } -void DirectoryEntry::addFromAllBSAs( - const std::wstring& originName, const std::wstring& directory, - int priority, const std::vector<std::wstring>& archives, - const std::set<std::wstring>& enabledArchives, - const std::vector<std::wstring>& loadOrder, - DirectoryStats& stats) +void DirectoryEntry::addFromAllBSAs(const std::wstring& originName, + const std::wstring& directory, int priority, + const std::vector<std::wstring>& archives, + const std::set<std::wstring>& enabledArchives, + const std::vector<std::wstring>& loadOrder, + DirectoryStats& stats) { for (const auto& archive : archives) { const std::filesystem::path archivePath(archive); @@ -179,10 +179,9 @@ void DirectoryEntry::addFromAllBSAs( int order = -1; - for (auto plugin : loadOrder) - { + for (auto plugin : loadOrder) { const auto pluginNameLc = - ToLowerCopy(std::filesystem::path(plugin).stem().native()); + ToLowerCopy(std::filesystem::path(plugin).stem().native()); if (filenameLc.starts_with(pluginNameLc + L" - ") || filenameLc.starts_with(pluginNameLc + L".")) { @@ -193,17 +192,16 @@ void DirectoryEntry::addFromAllBSAs( } } - addFromBSA( - originName, directory, archivePath.native(), - priority, order, stats); + addFromBSA(originName, directory, archivePath.native(), priority, order, stats); } } -void DirectoryEntry::addFromBSA( - const std::wstring& originName, const std::wstring& directory, - const std::wstring& archivePath, int priority, int order, DirectoryStats& stats) +void DirectoryEntry::addFromBSA(const std::wstring& originName, + const std::wstring& directory, + const std::wstring& archivePath, int priority, + int order, DirectoryStats& stats) { - FilesOrigin& origin = createOrigin(originName, directory, priority, stats); + FilesOrigin& origin = createOrigin(originName, directory, priority, stats); const auto archiveName = std::filesystem::path(archivePath).filename().native(); if (containsArchive(archiveName)) { @@ -213,14 +211,11 @@ void DirectoryEntry::addFromBSA( BSA::Archive archive; BSA::EErrorCode res = BSA::ERROR_NONE; - try - { + try { // read() can return an error, but it can also throw if the file is not a // valid bsa res = archive.read(ToString(archivePath, false).c_str(), false); - } - catch(std::exception& e) - { + } catch (std::exception& e) { log::error("invalid bsa '{}', error {}", archivePath, e.what()); return; } @@ -232,12 +227,11 @@ void DirectoryEntry::addFromBSA( std::error_code ec; const auto lwt = std::filesystem::last_write_time(archivePath, ec); - FILETIME ft = {}; + FILETIME ft = {}; if (ec) { - log::warn( - "failed to get last modified date for '{}', {}", - archivePath, ec.message()); + log::warn("failed to get last modified date for '{}', {}", archivePath, + ec.message()); } else { ft = ToFILETIME(lwt); } @@ -259,17 +253,17 @@ void DirectoryEntry::propagateOrigin(int origin) } } -bool DirectoryEntry::originExists(const std::wstring &name) const +bool DirectoryEntry::originExists(const std::wstring& name) const { return m_OriginConnection->exists(name); } -FilesOrigin &DirectoryEntry::getOriginByID(int ID) const +FilesOrigin& DirectoryEntry::getOriginByID(int ID) const { return m_OriginConnection->getByID(ID); } -FilesOrigin &DirectoryEntry::getOriginByName(const std::wstring &name) const +FilesOrigin& DirectoryEntry::getOriginByName(const std::wstring& name) const { return m_OriginConnection->getByName(name); } @@ -290,11 +284,11 @@ int DirectoryEntry::anyOrigin() const } } - // if we got here, no file directly within this directory is a valid indicator for a mod, thus - // we continue looking in subdirectories + // if we got here, no file directly within this directory is a valid indicator for a + // mod, thus we continue looking in subdirectories for (DirectoryEntry* entry : m_SubDirectories) { int res = entry->anyOrigin(); - if (res != InvalidOriginID){ + if (res != InvalidOriginID) { return res; } } @@ -313,8 +307,8 @@ std::vector<FileEntryPtr> DirectoryEntry::getFiles() const return result; } -DirectoryEntry* DirectoryEntry::findSubDirectory( - const std::wstring &name, bool alreadyLowerCase) const +DirectoryEntry* DirectoryEntry::findSubDirectory(const std::wstring& name, + bool alreadyLowerCase) const { SubDirectoriesLookup::const_iterator itor; @@ -331,14 +325,14 @@ DirectoryEntry* DirectoryEntry::findSubDirectory( return itor->second; } -DirectoryEntry* DirectoryEntry::findSubDirectoryRecursive(const std::wstring &path) +DirectoryEntry* DirectoryEntry::findSubDirectoryRecursive(const std::wstring& path) { DirectoryStats dummy; return getSubDirectoryRecursive(path, false, dummy, InvalidOriginID); } -const FileEntryPtr DirectoryEntry::findFile( - const std::wstring &name, bool alreadyLowerCase) const +const FileEntryPtr DirectoryEntry::findFile(const std::wstring& name, + bool alreadyLowerCase) const { FilesLookup::const_iterator iter; @@ -383,8 +377,8 @@ bool DirectoryEntry::containsArchive(std::wstring archiveName) return false; } -const FileEntryPtr DirectoryEntry::searchFile( - const std::wstring &path, const DirectoryEntry** directory) const +const FileEntryPtr DirectoryEntry::searchFile(const std::wstring& path, + const DirectoryEntry** directory) const { if (directory != nullptr) { *directory = nullptr; @@ -399,7 +393,7 @@ const FileEntryPtr DirectoryEntry::searchFile( return FileEntryPtr(); } - const size_t len = path.find_first_of(L"\\/"); + const size_t len = path.find_first_of(L"\\/"); if (len == std::string::npos) { // no more path components @@ -416,7 +410,7 @@ const FileEntryPtr DirectoryEntry::searchFile( } else { // file is in a subdirectory, recurse into the matching subdirectory std::wstring pathComponent = path.substr(0, len); - DirectoryEntry* temp = findSubDirectory(pathComponent); + DirectoryEntry* temp = findSubDirectory(pathComponent); if (temp != nullptr) { if (len >= path.size()) { @@ -436,7 +430,7 @@ void DirectoryEntry::removeFile(FileIndex index) removeFileFromList(index); } -bool DirectoryEntry::removeFile(const std::wstring &filePath, int* origin) +bool DirectoryEntry::removeFile(const std::wstring& filePath, int* origin) { size_t pos = filePath.find_first_of(L"\\/"); @@ -445,7 +439,7 @@ bool DirectoryEntry::removeFile(const std::wstring &filePath, int* origin) } std::wstring dirName = filePath.substr(0, pos); - std::wstring rest = filePath.substr(pos + 1); + std::wstring rest = filePath.substr(pos + 1); DirectoryStats dummy; DirectoryEntry* entry = getSubDirectoryRecursive(dirName, false, dummy); @@ -457,7 +451,7 @@ bool DirectoryEntry::removeFile(const std::wstring &filePath, int* origin) } } -void DirectoryEntry::removeDir(const std::wstring &path) +void DirectoryEntry::removeDir(const std::wstring& path) { size_t pos = path.find_first_of(L"\\/"); @@ -474,7 +468,7 @@ void DirectoryEntry::removeDir(const std::wstring &path) } } else { std::wstring dirName = path.substr(0, pos); - std::wstring rest = path.substr(pos + 1); + std::wstring rest = path.substr(pos + 1); DirectoryStats dummy; DirectoryEntry* entry = getSubDirectoryRecursive(dirName, false, dummy); @@ -485,12 +479,12 @@ void DirectoryEntry::removeDir(const std::wstring &path) } } -bool DirectoryEntry::remove(const std::wstring &fileName, int* origin) +bool DirectoryEntry::remove(const std::wstring& fileName, int* origin) { const auto lcFileName = ToLowerCopy(fileName); auto iter = m_Files.find(lcFileName); - bool b = false; + bool b = false; if (iter != m_Files.end()) { if (origin != nullptr) { @@ -512,13 +506,12 @@ bool DirectoryEntry::hasContentsFromOrigin(int originID) const return m_Origins.find(originID) != m_Origins.end(); } -FilesOrigin &DirectoryEntry::createOrigin( - const std::wstring &originName, const std::wstring &directory, int priority, - DirectoryStats& stats) +FilesOrigin& DirectoryEntry::createOrigin(const std::wstring& originName, + const std::wstring& directory, int priority, + DirectoryStats& stats) { - auto r = m_OriginConnection->getOrCreate( - originName, directory, priority, - m_FileRegister, m_OriginConnection, stats); + auto r = m_OriginConnection->getOrCreate(originName, directory, priority, + m_FileRegister, m_OriginConnection, stats); if (r.second) { ++stats.originCreate; @@ -529,14 +522,14 @@ FilesOrigin &DirectoryEntry::createOrigin( return r.first; } -void DirectoryEntry::removeFiles(const std::set<FileIndex> &indices) +void DirectoryEntry::removeFiles(const std::set<FileIndex>& indices) { removeFilesFromList(indices); } -FileEntryPtr DirectoryEntry::insert( - std::wstring_view fileName, FilesOrigin &origin, FILETIME fileTime, - std::wstring_view archive, int order, DirectoryStats& stats) +FileEntryPtr DirectoryEntry::insert(std::wstring_view fileName, FilesOrigin& origin, + FILETIME fileTime, std::wstring_view archive, + int order, DirectoryStats& stats) { std::wstring fileNameLower = ToLowerCopy(fileName); FileEntryPtr fe; @@ -548,7 +541,7 @@ FileEntryPtr DirectoryEntry::insert( FilesLookup::iterator itor; - elapsed(stats.filesLookupTimes, [&]{ + elapsed(stats.filesLookupTimes, [&] { itor = m_FilesLookup.find(key); }); @@ -558,8 +551,8 @@ FileEntryPtr DirectoryEntry::insert( fe = m_FileRegister->getFile(itor->second); } else { ++stats.fileCreate; - fe = m_FileRegister->createFile( - std::wstring(fileName.begin(), fileName.end()), this, stats); + fe = m_FileRegister->createFile(std::wstring(fileName.begin(), fileName.end()), + this, stats); elapsed(stats.addFileTimes, [&] { addFileToList(std::move(key.value), fe->getIndex()); @@ -569,20 +562,20 @@ FileEntryPtr DirectoryEntry::insert( } } - elapsed(stats.addOriginToFileTimes, [&]{ + elapsed(stats.addOriginToFileTimes, [&] { fe->addOrigin(origin.getID(), fileTime, archive, order); }); - elapsed(stats.addFileToOriginTimes, [&]{ + elapsed(stats.addFileToOriginTimes, [&] { origin.addFile(fe->getIndex()); }); return fe; } -FileEntryPtr DirectoryEntry::insert( - env::File& file, FilesOrigin &origin, std::wstring_view archive, int order, - DirectoryStats& stats) +FileEntryPtr DirectoryEntry::insert(env::File& file, FilesOrigin& origin, + std::wstring_view archive, int order, + DirectoryStats& stats) { FileEntryPtr fe; @@ -591,7 +584,7 @@ FileEntryPtr DirectoryEntry::insert( FilesMap::iterator itor; - elapsed(stats.filesLookupTimes, [&]{ + elapsed(stats.filesLookupTimes, [&] { itor = m_Files.find(file.lcname); }); @@ -604,7 +597,7 @@ FileEntryPtr DirectoryEntry::insert( fe = m_FileRegister->createFile(std::move(file.name), this, stats); // file.name has been moved from this point - elapsed(stats.addFileTimes, [&]{ + elapsed(stats.addFileTimes, [&] { addFileToList(std::move(file.lcname), fe->getIndex()); }); @@ -612,11 +605,11 @@ FileEntryPtr DirectoryEntry::insert( } } - elapsed(stats.addOriginToFileTimes, [&]{ + elapsed(stats.addOriginToFileTimes, [&] { fe->addOrigin(origin.getID(), file.lastModified, archive, order); }); - elapsed(stats.addFileToOriginTimes, [&]{ + elapsed(stats.addFileToOriginTimes, [&] { origin.addFile(fe->getIndex()); }); @@ -630,36 +623,32 @@ struct DirectoryEntry::Context std::stack<DirectoryEntry*> current; }; -void DirectoryEntry::addFiles( - env::DirectoryWalker& walker, FilesOrigin &origin, - const std::wstring& path, DirectoryStats& stats) +void DirectoryEntry::addFiles(env::DirectoryWalker& walker, FilesOrigin& origin, + const std::wstring& path, DirectoryStats& stats) { Context cx = {origin, stats}; cx.current.push(this); - walker.forEachEntry(path, &cx, - [](void* pcx, std::wstring_view path) - { - onDirectoryStart((Context*)pcx, path); - }, + walker.forEachEntry( + path, &cx, + [](void* pcx, std::wstring_view path) { + onDirectoryStart((Context*)pcx, path); + }, - [](void* pcx, std::wstring_view path) - { - onDirectoryEnd((Context*)pcx, path); - }, + [](void* pcx, std::wstring_view path) { + onDirectoryEnd((Context*)pcx, path); + }, - [](void* pcx, std::wstring_view path, FILETIME ft, uint64_t) - { - onFile((Context*)pcx, path, ft); - } - ); + [](void* pcx, std::wstring_view path, FILETIME ft, uint64_t) { + onFile((Context*)pcx, path, ft); + }); } void DirectoryEntry::onDirectoryStart(Context* cx, std::wstring_view path) { elapsed(cx->stats.dirTimes, [&] { - auto* sd = cx->current.top()->getSubDirectory( - path, true, cx->stats, cx->origin.getID()); + auto* sd = + cx->current.top()->getSubDirectory(path, true, cx->stats, cx->origin.getID()); cx->current.push(sd); }); @@ -674,23 +663,22 @@ void DirectoryEntry::onDirectoryEnd(Context* cx, std::wstring_view path) void DirectoryEntry::onFile(Context* cx, std::wstring_view path, FILETIME ft) { - elapsed(cx->stats.fileTimes, [&]{ + elapsed(cx->stats.fileTimes, [&] { cx->current.top()->insert(path, cx->origin, ft, L"", -1, cx->stats); }); } -void DirectoryEntry::addFiles( - FilesOrigin& origin, const BSA::Folder::Ptr archiveFolder, FILETIME fileTime, - const std::wstring& archiveName, int order, DirectoryStats& stats) +void DirectoryEntry::addFiles(FilesOrigin& origin, const BSA::Folder::Ptr archiveFolder, + FILETIME fileTime, const std::wstring& archiveName, + int order, DirectoryStats& stats) { // add files const auto fileCount = archiveFolder->getNumFiles(); - for (unsigned int i=0; i<fileCount; ++i) { + for (unsigned int i = 0; i < fileCount; ++i) { const BSA::File::Ptr file = archiveFolder->getFile(i); - auto f = insert( - ToWString(file->getName(), true), origin, fileTime, - archiveName, order, stats); + auto f = insert(ToWString(file->getName(), true), origin, fileTime, archiveName, + order, stats); if (f) { if (file->getUncompressedFileSize() > 0) { @@ -703,18 +691,18 @@ void DirectoryEntry::addFiles( // recurse into subdirectories const auto dirCount = archiveFolder->getNumSubFolders(); - for (unsigned int i=0; i<dirCount; ++i) { + for (unsigned int i = 0; i < dirCount; ++i) { const BSA::Folder::Ptr folder = archiveFolder->getSubFolder(i); DirectoryEntry* folderEntry = getSubDirectoryRecursive( - ToWString(folder->getName(), true), true, stats, origin.getID()); + ToWString(folder->getName(), true), true, stats, origin.getID()); folderEntry->addFiles(origin, folder, fileTime, archiveName, order, stats); } } -DirectoryEntry* DirectoryEntry::getSubDirectory( - std::wstring_view name, bool create, DirectoryStats& stats, int originID) +DirectoryEntry* DirectoryEntry::getSubDirectory(std::wstring_view name, bool create, + DirectoryStats& stats, int originID) { std::wstring nameLc = ToLowerCopy(name); @@ -733,9 +721,8 @@ DirectoryEntry* DirectoryEntry::getSubDirectory( if (create) { ++stats.subdirCreate; - auto* entry = new DirectoryEntry( - std::wstring(name.begin(), name.end()), this, originID, - m_FileRegister, m_OriginConnection); + auto* entry = new DirectoryEntry(std::wstring(name.begin(), name.end()), this, + originID, m_FileRegister, m_OriginConnection); elapsed(stats.addDirectoryTimes, [&] { addDirectoryToList(entry, std::move(nameLc)); @@ -748,8 +735,8 @@ DirectoryEntry* DirectoryEntry::getSubDirectory( } } -DirectoryEntry* DirectoryEntry::getSubDirectory( - env::Directory& dir, bool create, DirectoryStats& stats, int originID) +DirectoryEntry* DirectoryEntry::getSubDirectory(env::Directory& dir, bool create, + DirectoryStats& stats, int originID) { SubDirectoriesLookup::iterator itor; @@ -767,12 +754,11 @@ DirectoryEntry* DirectoryEntry::getSubDirectory( if (create) { ++stats.subdirCreate; - auto* entry = new DirectoryEntry( - std::move(dir.name), this, originID, - m_FileRegister, m_OriginConnection); + auto* entry = new DirectoryEntry(std::move(dir.name), this, originID, + m_FileRegister, m_OriginConnection); // dir.name is moved from this point - elapsed(stats.addDirectoryTimes, [&]{ + elapsed(stats.addDirectoryTimes, [&] { addDirectoryToList(entry, std::move(dir.lcname)); }); @@ -784,8 +770,10 @@ DirectoryEntry* DirectoryEntry::getSubDirectory( } } -DirectoryEntry* DirectoryEntry::getSubDirectoryRecursive( - const std::wstring& path, bool create, DirectoryStats& stats, int originID) +DirectoryEntry* DirectoryEntry::getSubDirectoryRecursive(const std::wstring& path, + bool create, + DirectoryStats& stats, + int originID) { if (path.length() == 0) { // path ended with a backslash? @@ -797,14 +785,14 @@ DirectoryEntry* DirectoryEntry::getSubDirectoryRecursive( if (pos == std::wstring::npos) { return getSubDirectory(path, create, stats); } else { - DirectoryEntry* nextChild = getSubDirectory( - path.substr(0, pos), create, stats, originID); + DirectoryEntry* nextChild = + getSubDirectory(path.substr(0, pos), create, stats, originID); if (nextChild == nullptr) { return nullptr; } else { - return nextChild->getSubDirectoryRecursive( - path.substr(pos + 1), create, stats, originID); + return nextChild->getSubDirectoryRecursive(path.substr(pos + 1), create, stats, + originID); } } } @@ -837,9 +825,10 @@ void DirectoryEntry::removeDirectoryFromList(SubDirectories::iterator itor) const auto* entry = *itor; { - auto itor2 = std::find_if( - m_SubDirectoriesLookup.begin(), m_SubDirectoriesLookup.end(), - [&](auto&& d) { return (d.second == entry); }); + auto itor2 = std::find_if(m_SubDirectoriesLookup.begin(), + m_SubDirectoriesLookup.end(), [&](auto&& d) { + return (d.second == entry); + }); if (itor2 == m_SubDirectoriesLookup.end()) { log::error("entry {} not in sub directories map", entry->getName()); @@ -854,23 +843,20 @@ void DirectoryEntry::removeDirectoryFromList(SubDirectories::iterator itor) void DirectoryEntry::removeFileFromList(FileIndex index) { auto removeFrom = [&](auto& list) { - auto iter = std::find_if( - list.begin(), list.end(), - [&index](auto&& pair) { return (pair.second == index); } - ); + auto iter = std::find_if(list.begin(), list.end(), [&index](auto&& pair) { + return (pair.second == index); + }); if (iter == list.end()) { auto f = m_FileRegister->getFile(index); if (f) { - log::error( - "can't remove file '{}', not in directory entry '{}'", - f->getName(), getName()); + log::error("can't remove file '{}', not in directory entry '{}'", f->getName(), + getName()); } else { - log::error( - "can't remove file with index {}, not in directory entry '{}' and " - "not in register", - index, getName()); + log::error("can't remove file with index {}, not in directory entry '{}' and " + "not in register", + index, getName()); } } else { list.erase(iter); @@ -914,25 +900,22 @@ struct DumpFailed : public std::runtime_error void DirectoryEntry::dump(const std::wstring& file) const { - try - { + try { std::FILE* f = nullptr; - auto e = _wfopen_s(&f, file.c_str(), L"wb"); + auto e = _wfopen_s(&f, file.c_str(), L"wb"); if (e != 0 || !f) { - throw DumpFailed(fmt::format( - "failed to open, {} ({})", std::strerror(e), e)); + throw DumpFailed(fmt::format("failed to open, {} ({})", std::strerror(e), e)); } - Guard g([&]{ std::fclose(f); }); + Guard g([&] { + std::fclose(f); + }); dump(f, L"Data"); - } - catch(DumpFailed& e) - { - log::error( - "failed to write list to '{}': {}", - QString::fromStdWString(file).toStdString(), e.what()); + } catch (DumpFailed& e) { + log::error("failed to write list to '{}': {}", + QString::fromStdWString(file).toStdString(), e.what()); } } @@ -952,7 +935,7 @@ void DirectoryEntry::dump(std::FILE* f, const std::wstring& parentPath) const continue; } - const auto& o = m_OriginConnection->getByID(file->getOrigin()); + const auto& o = m_OriginConnection->getByID(file->getOrigin()); const auto path = parentPath + L"\\" + file->getName(); const auto line = path + L"\t(" + o.getName() + L")\r\n"; @@ -960,8 +943,7 @@ void DirectoryEntry::dump(std::FILE* f, const std::wstring& parentPath) const if (std::fwrite(lineu8.data(), lineu8.size(), 1, f) != 1) { const auto e = errno; - throw DumpFailed(fmt::format( - "failed to write, {} ({})", std::strerror(e), e)); + throw DumpFailed(fmt::format("failed to write, {} ({})", std::strerror(e), e)); } } } @@ -975,4 +957,4 @@ void DirectoryEntry::dump(std::FILE* f, const std::wstring& parentPath) const } } -} // namespace MOShared +} // namespace MOShared diff --git a/src/shared/directoryentry.h b/src/shared/directoryentry.h index f7ab2b90..42aef8c7 100644 --- a/src/shared/directoryentry.h +++ b/src/shared/directoryentry.h @@ -25,116 +25,87 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. namespace env { - class DirectoryWalker; - struct Directory; - struct File; -} +class DirectoryWalker; +struct Directory; +struct File; +} // namespace env namespace std { - template <> - struct hash<MOShared::DirectoryEntryFileKey> - { - using argument_type = MOShared::DirectoryEntryFileKey; - using result_type = std::size_t; - - inline result_type operator()(const argument_type& key) const; - }; -} +template <> +struct hash<MOShared::DirectoryEntryFileKey> +{ + using argument_type = MOShared::DirectoryEntryFileKey; + using result_type = std::size_t; + inline result_type operator()(const argument_type& key) const; +}; +} // namespace std namespace MOShared { struct DirCompareByName { - bool operator()(const DirectoryEntry* a, const DirectoryEntry* b) const; + bool operator()(const DirectoryEntry* a, const DirectoryEntry* b) const; }; - class DirectoryEntry { public: - using SubDirectories = std::set<DirectoryEntry*, DirCompareByName>; + using SubDirectories = std::set<DirectoryEntry*, DirCompareByName>; - DirectoryEntry( - std::wstring name, DirectoryEntry* parent, OriginID originID); + DirectoryEntry(std::wstring name, DirectoryEntry* parent, OriginID originID); - DirectoryEntry( - std::wstring name, DirectoryEntry* parent, OriginID originID, - boost::shared_ptr<FileRegister> fileRegister, - boost::shared_ptr<OriginConnection> originConnection); + DirectoryEntry(std::wstring name, DirectoryEntry* parent, OriginID originID, + boost::shared_ptr<FileRegister> fileRegister, + boost::shared_ptr<OriginConnection> originConnection); ~DirectoryEntry(); // noncopyable - DirectoryEntry(const DirectoryEntry&) = delete; + DirectoryEntry(const DirectoryEntry&) = delete; DirectoryEntry& operator=(const DirectoryEntry&) = delete; void clear(); - bool isPopulated() const - { - return m_Populated; - } + bool isPopulated() const { return m_Populated; } - bool isTopLevel() const - { - return m_TopLevel; - } + bool isTopLevel() const { return m_TopLevel; } - bool isEmpty() const - { - return m_Files.empty() && m_SubDirectories.empty(); - } + bool isEmpty() const { return m_Files.empty() && m_SubDirectories.empty(); } - bool hasFiles() const - { - return !m_Files.empty(); - } + bool hasFiles() const { return !m_Files.empty(); } - const DirectoryEntry* getParent() const - { - return m_Parent; - } + const DirectoryEntry* getParent() const { return m_Parent; } // add files to this directory (and subdirectories) from the specified origin. // That origin may exist or not - void addFromOrigin( - const std::wstring& originName, - const std::wstring& directory, int priority, DirectoryStats& stats); + void addFromOrigin(const std::wstring& originName, const std::wstring& directory, + int priority, DirectoryStats& stats); - void addFromOrigin( - env::DirectoryWalker& walker, const std::wstring& originName, - const std::wstring& directory, int priority, DirectoryStats& stats); + void addFromOrigin(env::DirectoryWalker& walker, const std::wstring& originName, + const std::wstring& directory, int priority, + DirectoryStats& stats); - void addFromAllBSAs( - const std::wstring& originName, const std::wstring& directory, - int priority, const std::vector<std::wstring>& archives, - const std::set<std::wstring>& enabledArchives, - const std::vector<std::wstring>& loadOrder, - DirectoryStats& stats); + void addFromAllBSAs(const std::wstring& originName, const std::wstring& directory, + int priority, const std::vector<std::wstring>& archives, + const std::set<std::wstring>& enabledArchives, + const std::vector<std::wstring>& loadOrder, + DirectoryStats& stats); - void addFromBSA( - const std::wstring& originName, const std::wstring& directory, - const std::wstring& archivePath, int priority, int order, - DirectoryStats& stats); + void addFromBSA(const std::wstring& originName, const std::wstring& directory, + const std::wstring& archivePath, int priority, int order, + DirectoryStats& stats); - void addFromList( - const std::wstring& originName, const std::wstring& directory, - env::Directory& root, int priority, DirectoryStats& stats); + void addFromList(const std::wstring& originName, const std::wstring& directory, + env::Directory& root, int priority, DirectoryStats& stats); void propagateOrigin(OriginID origin); - const std::wstring& getName() const - { - return m_Name; - } + const std::wstring& getName() const { return m_Name; } - boost::shared_ptr<FileRegister> getFileRegister() - { - return m_FileRegister; - } + boost::shared_ptr<FileRegister> getFileRegister() { return m_FileRegister; } bool originExists(const std::wstring& name) const; FilesOrigin& getOriginByID(OriginID ID) const; @@ -145,10 +116,7 @@ public: std::vector<FileEntryPtr> getFiles() const; - const SubDirectories& getSubDirectories() const - { - return m_SubDirectories; - } + const SubDirectories& getSubDirectories() const { return m_SubDirectories; } template <class F> void forEachDirectory(F&& f) const @@ -164,7 +132,7 @@ public: void forEachFile(F&& f) const { for (auto&& p : m_Files) { - if (auto file=m_FileRegister->getFile(p.second)) { + if (auto file = m_FileRegister->getFile(p.second)) { if (!f(*file)) { break; } @@ -187,16 +155,17 @@ public: return m_FileRegister->getFile(index); } - DirectoryEntry* findSubDirectory( - const std::wstring& name, bool alreadyLowerCase=false) const; + DirectoryEntry* findSubDirectory(const std::wstring& name, + bool alreadyLowerCase = false) const; DirectoryEntry* findSubDirectoryRecursive(const std::wstring& path); /** retrieve a file in this directory by name. - * @param name name of the file - * @return fileentry object for the file or nullptr if no file matches - */ - const FileEntryPtr findFile(const std::wstring& name, bool alreadyLowerCase=false) const; + * @param name name of the file + * @return fileentry object for the file or nullptr if no file matches + */ + const FileEntryPtr findFile(const std::wstring& name, + bool alreadyLowerCase = false) const; const FileEntryPtr findFile(const DirectoryEntryFileKey& key) const; bool hasFile(const std::wstring& name) const; @@ -208,8 +177,8 @@ public: // if directory is not nullptr, the referenced variable will be set to the // path containing the file // - const FileEntryPtr searchFile( - const std::wstring& path, const DirectoryEntry** directory=nullptr) const; + const FileEntryPtr searchFile(const std::wstring& path, + const DirectoryEntry** directory = nullptr) const; void removeFile(FileIndex index); @@ -227,17 +196,17 @@ public: bool hasContentsFromOrigin(OriginID originID) const; - FilesOrigin& createOrigin( - const std::wstring& originName, - const std::wstring& directory, int priority, DirectoryStats& stats); + FilesOrigin& createOrigin(const std::wstring& originName, + const std::wstring& directory, int priority, + DirectoryStats& stats); void removeFiles(const std::set<FileIndex>& indices); void dump(const std::wstring& file) const; private: - using FilesMap = std::map<std::wstring, FileIndex>; - using FilesLookup = std::unordered_map<DirectoryEntryFileKey, FileIndex>; + using FilesMap = std::map<std::wstring, FileIndex>; + using FilesLookup = std::unordered_map<DirectoryEntryFileKey, FileIndex>; using SubDirectoriesLookup = std::unordered_map<std::wstring, DirectoryEntry*>; boost::shared_ptr<FileRegister> m_FileRegister; @@ -257,36 +226,32 @@ private: mutable std::mutex m_FilesMutex; mutable std::mutex m_OriginsMutex; + FileEntryPtr insert(std::wstring_view fileName, FilesOrigin& origin, + FILETIME fileTime, std::wstring_view archive, int order, + DirectoryStats& stats); - FileEntryPtr insert( - std::wstring_view fileName, FilesOrigin& origin, FILETIME fileTime, - std::wstring_view archive, int order, DirectoryStats& stats); + FileEntryPtr insert(env::File& file, FilesOrigin& origin, std::wstring_view archive, + int order, DirectoryStats& stats); - FileEntryPtr insert( - env::File& file, FilesOrigin& origin, - std::wstring_view archive, int order, DirectoryStats& stats); + void addFiles(env::DirectoryWalker& walker, FilesOrigin& origin, + const std::wstring& path, DirectoryStats& stats); - void addFiles( - env::DirectoryWalker& walker, FilesOrigin& origin, - const std::wstring& path, DirectoryStats& stats); - - void addFiles( - FilesOrigin& origin, BSA::Folder::Ptr archiveFolder, FILETIME fileTime, - const std::wstring& archiveName, int order, DirectoryStats& stats); + void addFiles(FilesOrigin& origin, BSA::Folder::Ptr archiveFolder, FILETIME fileTime, + const std::wstring& archiveName, int order, DirectoryStats& stats); void addDir(FilesOrigin& origin, env::Directory& d, DirectoryStats& stats); - DirectoryEntry* getSubDirectory( - std::wstring_view name, bool create, DirectoryStats& stats, - OriginID originID = InvalidOriginID); + DirectoryEntry* getSubDirectory(std::wstring_view name, bool create, + DirectoryStats& stats, + OriginID originID = InvalidOriginID); - DirectoryEntry* getSubDirectory( - env::Directory& dir, bool create, DirectoryStats& stats, - OriginID originID = InvalidOriginID); + DirectoryEntry* getSubDirectory(env::Directory& dir, bool create, + DirectoryStats& stats, + OriginID originID = InvalidOriginID); - DirectoryEntry* getSubDirectoryRecursive( - const std::wstring& path, bool create, DirectoryStats& stats, - OriginID originID = InvalidOriginID); + DirectoryEntry* getSubDirectoryRecursive(const std::wstring& path, bool create, + DirectoryStats& stats, + OriginID originID = InvalidOriginID); void removeDirRecursive(); @@ -305,17 +270,15 @@ private: void dump(std::FILE* f, const std::wstring& parentPath) const; }; -} // namespace MOShared - +} // namespace MOShared namespace std { - hash<MOShared::DirectoryEntryFileKey>::result_type - hash<MOShared::DirectoryEntryFileKey>::operator()( - const argument_type& key) const - { - return key.hash; - } +hash<MOShared::DirectoryEntryFileKey>::result_type +hash<MOShared::DirectoryEntryFileKey>::operator()(const argument_type& key) const +{ + return key.hash; } +} // namespace std -#endif // MO_REGISTER_DIRECTORYENTRY_INCLUDED +#endif // MO_REGISTER_DIRECTORYENTRY_INCLUDED diff --git a/src/shared/fileentry.cpp b/src/shared/fileentry.cpp index 5be9a9dc..48670617 100644 --- a/src/shared/fileentry.cpp +++ b/src/shared/fileentry.cpp @@ -5,20 +5,18 @@ namespace MOShared { -FileEntry::FileEntry() : - m_Index(InvalidFileIndex), m_Name(), m_Origin(-1), m_Parent(nullptr), - m_FileSize(NoFileSize), m_CompressedFileSize(NoFileSize) -{ -} +FileEntry::FileEntry() + : m_Index(InvalidFileIndex), m_Name(), m_Origin(-1), m_Parent(nullptr), + m_FileSize(NoFileSize), m_CompressedFileSize(NoFileSize) +{} -FileEntry::FileEntry(FileIndex index, std::wstring name, DirectoryEntry *parent) : - m_Index(index), m_Name(std::move(name)), m_Origin(-1), m_Archive(L"", -1), m_Parent(parent), - m_FileSize(NoFileSize), m_CompressedFileSize(NoFileSize) -{ -} +FileEntry::FileEntry(FileIndex index, std::wstring name, DirectoryEntry* parent) + : m_Index(index), m_Name(std::move(name)), m_Origin(-1), m_Archive(L"", -1), + m_Parent(parent), m_FileSize(NoFileSize), m_CompressedFileSize(NoFileSize) +{} -void FileEntry::addOrigin( - OriginID origin, FILETIME fileTime, std::wstring_view archive, int order) +void FileEntry::addOrigin(OriginID origin, FILETIME fileTime, std::wstring_view archive, + int order) { std::scoped_lock lock(m_OriginsMutex); @@ -29,32 +27,30 @@ void FileEntry::addOrigin( if (m_Origin == -1) { // If this file has no previous origin, this mod is now the origin with no // alternatives - m_Origin = origin; + m_Origin = origin; m_FileTime = fileTime; - m_Archive = DataArchiveOrigin(std::wstring(archive.begin(), archive.end()), order); - } - else if ( - (m_Parent != nullptr) && ( - (m_Parent->getOriginByID(origin).getPriority() > m_Parent->getOriginByID(m_Origin).getPriority()) || - (archive.size() == 0 && m_Archive.isValid())) - ) { + m_Archive = DataArchiveOrigin(std::wstring(archive.begin(), archive.end()), order); + } else if ((m_Parent != nullptr) && + ((m_Parent->getOriginByID(origin).getPriority() > + m_Parent->getOriginByID(m_Origin).getPriority()) || + (archive.size() == 0 && m_Archive.isValid()))) { // If this mod has a higher priority than the origin mod OR // this mod has a loose file and the origin mod has an archived file, // this mod is now the origin and the previous origin is the first alternative - auto itor = std::find_if( - m_Alternatives.begin(), m_Alternatives.end(), - [&](auto&& i) { return i.originID() == m_Origin; }); + auto itor = + std::find_if(m_Alternatives.begin(), m_Alternatives.end(), [&](auto&& i) { + return i.originID() == m_Origin; + }); if (itor == m_Alternatives.end()) { m_Alternatives.push_back({m_Origin, m_Archive}); } - m_Origin = origin; + m_Origin = origin; m_FileTime = fileTime; - m_Archive = DataArchiveOrigin(std::wstring(archive.begin(), archive.end()), order); - } - else { + m_Archive = DataArchiveOrigin(std::wstring(archive.begin(), archive.end()), order); + } else { // This mod is just an alternative bool found = false; @@ -70,15 +66,18 @@ void FileEntry::addOrigin( } if ((m_Parent != nullptr) && - (m_Parent->getOriginByID(iter->originID()).getPriority() < m_Parent->getOriginByID(origin).getPriority())) { - m_Alternatives.insert(iter, {origin, {std::wstring(archive.begin(), archive.end()), order}}); + (m_Parent->getOriginByID(iter->originID()).getPriority() < + m_Parent->getOriginByID(origin).getPriority())) { + m_Alternatives.insert( + iter, {origin, {std::wstring(archive.begin(), archive.end()), order}}); found = true; break; } } if (!found) { - m_Alternatives.push_back({origin, {std::wstring(archive.begin(), archive.end()), order}}); + m_Alternatives.push_back( + {origin, {std::wstring(archive.begin(), archive.end()), order}}); } } } @@ -93,21 +92,21 @@ bool FileEntry::removeOrigin(OriginID origin) auto currentIter = m_Alternatives.begin(); for (auto iter = m_Alternatives.begin(); iter != m_Alternatives.end(); ++iter) { if (iter->originID() != origin) { - //Both files are not from archives. + // Both files are not from archives. if (!iter->isFromArchive() && !currentIter->isFromArchive()) { - if ((m_Parent->getOriginByID(iter->originID()).getPriority() > m_Parent->getOriginByID(currentIter->originID()).getPriority())) { + if ((m_Parent->getOriginByID(iter->originID()).getPriority() > + m_Parent->getOriginByID(currentIter->originID()).getPriority())) { currentIter = iter; } - } - else { - //Both files are from archives + } else { + // Both files are from archives if (iter->isFromArchive() && currentIter->isFromArchive()) { if (iter->archive().order() > currentIter->archive().order()) { currentIter = iter; } - } - else { - //Only one of the two is an archive, so we change currentIter only if he is the archive one. + } else { + // Only one of the two is an archive, so we change currentIter only if he + // is the archive one. if (currentIter->isFromArchive()) { currentIter = iter; } @@ -117,19 +116,20 @@ bool FileEntry::removeOrigin(OriginID origin) } OriginID currentID = currentIter->originID(); - m_Archive = currentIter->archive(); + m_Archive = currentIter->archive(); m_Alternatives.erase(currentIter); m_Origin = currentID; } else { - m_Origin = -1; + m_Origin = -1; m_Archive = DataArchiveOrigin(L"", -1); return true; } } else { - auto newEnd = std::remove_if( - m_Alternatives.begin(), m_Alternatives.end(), - [&](auto &i) { return i.originID() == origin; }); + auto newEnd = + std::remove_if(m_Alternatives.begin(), m_Alternatives.end(), [&](auto& i) { + return i.originID() == origin; + }); if (newEnd != m_Alternatives.end()) { m_Alternatives.erase(newEnd, m_Alternatives.end()); @@ -160,8 +160,12 @@ void FileEntry::sortOrigins() } if (LHS.isFromArchive() && RHS.isFromArchive()) { - int l = LHS.archive().order(); if (l < 0) l = INT_MAX; - int r = RHS.archive().order(); if (r < 0) r = INT_MAX; + int l = LHS.archive().order(); + if (l < 0) + l = INT_MAX; + int r = RHS.archive().order(); + if (r < 0) + r = INT_MAX; return l < r; } @@ -171,10 +175,10 @@ void FileEntry::sortOrigins() } return true; - }); + }); if (!m_Alternatives.empty()) { - m_Origin = m_Alternatives.back().originID(); + m_Origin = m_Alternatives.back().originID(); m_Archive = m_Alternatives.back().archive(); m_Alternatives.pop_back(); } @@ -207,7 +211,7 @@ std::wstring FileEntry::getFullPath(OriginID originID) const if (originID == InvalidOriginID) { bool ignore = false; - originID = getOrigin(ignore); + originID = getOrigin(ignore); } // base directory for origin @@ -234,7 +238,7 @@ std::wstring FileEntry::getRelativePath() const return result + L"\\" + m_Name; } -bool FileEntry::recurseParents(std::wstring &path, const DirectoryEntry *parent) const +bool FileEntry::recurseParents(std::wstring& path, const DirectoryEntry* parent) const { if (parent == nullptr) { return false; @@ -248,4 +252,4 @@ bool FileEntry::recurseParents(std::wstring &path, const DirectoryEntry *parent) } } -} // namespace +} // namespace MOShared diff --git a/src/shared/fileentry.h b/src/shared/fileentry.h index 31655bb1..80d8b292 100644 --- a/src/shared/fileentry.h +++ b/src/shared/fileentry.h @@ -9,23 +9,19 @@ namespace MOShared class FileEntry { public: - static constexpr uint64_t NoFileSize = - std::numeric_limits<uint64_t>::max(); + static constexpr uint64_t NoFileSize = std::numeric_limits<uint64_t>::max(); FileEntry(); - FileEntry(FileIndex index, std::wstring name, DirectoryEntry *parent); + FileEntry(FileIndex index, std::wstring name, DirectoryEntry* parent); // noncopyable - FileEntry(const FileEntry&) = delete; + FileEntry(const FileEntry&) = delete; FileEntry& operator=(const FileEntry&) = delete; - FileIndex getIndex() const - { - return m_Index; - } + FileIndex getIndex() const { return m_Index; } - void addOrigin( - OriginID origin, FILETIME fileTime, std::wstring_view archive, int order); + void addOrigin(OriginID origin, FILETIME fileTime, std::wstring_view archive, + int order); // remove the specified origin from the list of origins that contain this // file. if no origin is left, the file is effectively deleted and true is @@ -37,71 +33,44 @@ public: // gets the list of alternative origins (origins with lower priority than // the primary one). if sortOrigins has been called, it is sorted by priority // (ascending) - const AlternativesVector &getAlternatives() const - { - return m_Alternatives; - } + const AlternativesVector& getAlternatives() const { return m_Alternatives; } - const std::wstring &getName() const - { - return m_Name; - } + const std::wstring& getName() const { return m_Name; } - OriginID getOrigin() const - { - return m_Origin; - } + OriginID getOrigin() const { return m_Origin; } - OriginID getOrigin(bool &archive) const + OriginID getOrigin(bool& archive) const { archive = m_Archive.isValid(); return m_Origin; } - const DataArchiveOrigin &getArchive() const - { - return m_Archive; - } + const DataArchiveOrigin& getArchive() const { return m_Archive; } bool isFromArchive(std::wstring archiveName = L"") const; // if originID is -1, uses the main origin; if this file doesn't exist in the // given origin, returns an empty string // - std::wstring getFullPath(OriginID originID=InvalidOriginID) const; + std::wstring getFullPath(OriginID originID = InvalidOriginID) const; std::wstring getRelativePath() const; - DirectoryEntry *getParent() - { - return m_Parent; - } + DirectoryEntry* getParent() { return m_Parent; } - void setFileTime(FILETIME fileTime) const - { - m_FileTime = fileTime; - } + void setFileTime(FILETIME fileTime) const { m_FileTime = fileTime; } - FILETIME getFileTime() const - { - return m_FileTime; - } + FILETIME getFileTime() const { return m_FileTime; } void setFileSize(uint64_t size, uint64_t compressedSize) { - m_FileSize = size; + m_FileSize = size; m_CompressedFileSize = compressedSize; } - uint64_t getFileSize() const - { - return m_FileSize; - } + uint64_t getFileSize() const { return m_FileSize; } - uint64_t getCompressedFileSize() const - { - return m_CompressedFileSize; - } + uint64_t getCompressedFileSize() const { return m_CompressedFileSize; } private: FileIndex m_Index; @@ -109,14 +78,14 @@ private: OriginID m_Origin; DataArchiveOrigin m_Archive; AlternativesVector m_Alternatives; - DirectoryEntry *m_Parent; + DirectoryEntry* m_Parent; mutable FILETIME m_FileTime; uint64_t m_FileSize, m_CompressedFileSize; mutable std::mutex m_OriginsMutex; - bool recurseParents(std::wstring &path, const DirectoryEntry *parent) const; + bool recurseParents(std::wstring& path, const DirectoryEntry* parent) const; }; -} // namespace +} // namespace MOShared -#endif // MO_REGISTER_FILEENTRY_INCLUDED +#endif // MO_REGISTER_FILEENTRY_INCLUDED diff --git a/src/shared/fileregister.cpp b/src/shared/fileregister.cpp index 98e49452..ab94367f 100644 --- a/src/shared/fileregister.cpp +++ b/src/shared/fileregister.cpp @@ -1,8 +1,8 @@ #include "fileregister.h" -#include "fileentry.h" #include "directoryentry.h" -#include "originconnection.h" +#include "fileentry.h" #include "filesorigin.h" +#include "originconnection.h" #include <log.h> namespace MOShared @@ -11,9 +11,8 @@ namespace MOShared using namespace MOBase; FileRegister::FileRegister(boost::shared_ptr<OriginConnection> originConnection) - : m_OriginConnection(originConnection), m_NextIndex(0) -{ -} + : m_OriginConnection(originConnection), m_NextIndex(0) +{} bool FileRegister::indexValid(FileIndex index) const { @@ -26,11 +25,11 @@ bool FileRegister::indexValid(FileIndex index) const return false; } -FileEntryPtr FileRegister::createFile( - std::wstring name, DirectoryEntry *parent, DirectoryStats& stats) +FileEntryPtr FileRegister::createFile(std::wstring name, DirectoryEntry* parent, + DirectoryStats& stats) { const auto index = generateIndex(); - auto p = FileEntryPtr(new FileEntry(index, std::move(name), parent)); + auto p = FileEntryPtr(new FileEntry(index, std::move(name), parent)); { std::scoped_lock lock(m_Mutex); @@ -96,18 +95,19 @@ void FileRegister::removeOrigin(FileIndex index, OriginID originID) } } - log::error(QObject::tr("invalid file index for remove (for origin): {}").toStdString(), index); + log::error( + QObject::tr("invalid file index for remove (for origin): {}").toStdString(), + index); } -void FileRegister::removeOriginMulti( - std::set<FileIndex> indices, OriginID originID) +void FileRegister::removeOriginMulti(std::set<FileIndex> indices, OriginID originID) { std::vector<FileEntryPtr> removedFiles; { std::scoped_lock lock(m_Mutex); - for (auto iter = indices.begin(); iter != indices.end(); ) { + for (auto iter = indices.begin(); iter != indices.end();) { const auto index = *iter; if (index < m_Files.size()) { @@ -140,13 +140,13 @@ void FileRegister::removeOriginMulti( // frequently the case std::set<DirectoryEntry*> parents; - for (const FileEntryPtr &file : removedFiles) { + for (const FileEntryPtr& file : removedFiles) { if (file->getParent() != nullptr) { parents.insert(file->getParent()); } } - for (DirectoryEntry *parent : parents) { + for (DirectoryEntry* parent : parents) { parent->removeFiles(indices); } } @@ -181,4 +181,4 @@ void FileRegister::unregisterFile(FileEntryPtr file) } } -} // namespace +} // namespace MOShared diff --git a/src/shared/fileregister.h b/src/shared/fileregister.h index c27dc93b..aeb2c5b7 100644 --- a/src/shared/fileregister.h +++ b/src/shared/fileregister.h @@ -2,8 +2,8 @@ #define MO_REGISTER_FILESREGISTER_INCLUDED #include "fileregisterfwd.h" -#include <mutex> #include <boost/shared_ptr.hpp> +#include <mutex> namespace MOShared { @@ -14,13 +14,13 @@ public: FileRegister(boost::shared_ptr<OriginConnection> originConnection); // noncopyable - FileRegister(const FileRegister&) = delete; + FileRegister(const FileRegister&) = delete; FileRegister& operator=(const FileRegister&) = delete; bool indexValid(FileIndex index) const; - FileEntryPtr createFile( - std::wstring name, DirectoryEntry *parent, DirectoryStats& stats); + FileEntryPtr createFile(std::wstring name, DirectoryEntry* parent, + DirectoryStats& stats); FileEntryPtr getFile(FileIndex index) const; @@ -48,6 +48,6 @@ private: FileIndex generateIndex(); }; -} // namespace +} // namespace MOShared -#endif // MO_REGISTER_FILESREGISTER_INCLUDED +#endif // MO_REGISTER_FILESREGISTER_INCLUDED diff --git a/src/shared/fileregisterfwd.h b/src/shared/fileregisterfwd.h index 57b3715a..dce40ab5 100644 --- a/src/shared/fileregisterfwd.h +++ b/src/shared/fileregisterfwd.h @@ -8,15 +8,9 @@ namespace MOShared struct DirectoryEntryFileKey { - DirectoryEntryFileKey(std::wstring v) - : value(std::move(v)), hash(getHash(value)) - { - } + DirectoryEntryFileKey(std::wstring v) : value(std::move(v)), hash(getHash(value)) {} - bool operator==(const DirectoryEntryFileKey& o) const - { - return (value == o.value); - } + bool operator==(const DirectoryEntryFileKey& o) const { return (value == o.value); } static std::size_t getHash(const std::wstring& value) { @@ -27,7 +21,6 @@ struct DirectoryEntryFileKey const std::size_t hash; }; - class DirectoryEntry; class OriginConnection; class FileRegister; @@ -36,11 +29,11 @@ class FileEntry; struct DirectoryStats; using FileEntryPtr = boost::shared_ptr<FileEntry>; -using FileIndex = unsigned int; -using OriginID = int; +using FileIndex = unsigned int; +using OriginID = int; constexpr FileIndex InvalidFileIndex = UINT_MAX; -constexpr OriginID InvalidOriginID = -1; +constexpr OriginID InvalidOriginID = -1; // if a file is in an archive, name is the name of the bsa and order // is the order of the associated plugin in the plugins list @@ -49,19 +42,17 @@ constexpr OriginID InvalidOriginID = -1; class DataArchiveOrigin { std::wstring name_ = L""; - int order_ = -1; - -public: + int order_ = -1; +public: int order() const { return order_; } const std::wstring& name() const { return name_; } - - bool isValid() const { - return name_.size() > 0; - } + + bool isValid() const { return name_.size() > 0; } DataArchiveOrigin(std::wstring name, int order) - : name_(std::move(name)), order_(order) {} + : name_(std::move(name)), order_(order) + {} DataArchiveOrigin() = default; }; @@ -72,18 +63,16 @@ class FileAlternative DataArchiveOrigin archive_; public: - OriginID originID() const { return originID_; } const DataArchiveOrigin& archive() const { return archive_; } - bool isFromArchive() const { - return archive_.isValid(); - } + bool isFromArchive() const { return archive_.isValid(); } FileAlternative() = default; - FileAlternative(OriginID originID, DataArchiveOrigin archive) - : originID_(originID), archive_(std::move(archive)) {} + FileAlternative(OriginID originID, DataArchiveOrigin archive) + : originID_(originID), archive_(std::move(archive)) + {} }; using AlternativesVector = std::vector<FileAlternative>; @@ -127,6 +116,6 @@ struct DirectoryStats std::string toCsv() const; }; -} // namespace +} // namespace MOShared -#endif // MO_REGISTER_FILEREGISTERFWD_INCLUDED +#endif // MO_REGISTER_FILEREGISTERFWD_INCLUDED diff --git a/src/shared/filesorigin.cpp b/src/shared/filesorigin.cpp index 049e4258..dd1aec61 100644 --- a/src/shared/filesorigin.cpp +++ b/src/shared/filesorigin.cpp @@ -1,12 +1,12 @@ #include "filesorigin.h" -#include "originconnection.h" -#include "fileregister.h" #include "fileentry.h" +#include "fileregister.h" +#include "originconnection.h" namespace MOShared { -std::wstring tail(const std::wstring &source, const size_t count) +std::wstring tail(const std::wstring& source, const size_t count) { if (count >= source.length()) { return source; @@ -15,28 +15,24 @@ std::wstring tail(const std::wstring &source, const size_t count) return source.substr(source.length() - count); } - FilesOrigin::FilesOrigin() - : m_ID(0), m_Disabled(false), m_Name(), m_Path(), m_Priority(0) -{ -} + : m_ID(0), m_Disabled(false), m_Name(), m_Path(), m_Priority(0) +{} -FilesOrigin::FilesOrigin( - OriginID ID, const std::wstring &name, const std::wstring &path, int priority, - boost::shared_ptr<MOShared::FileRegister> fileRegister, - boost::shared_ptr<MOShared::OriginConnection> originConnection) : - m_ID(ID), m_Disabled(false), m_Name(name), m_Path(path), - m_Priority(priority), m_FileRegister(fileRegister), - m_OriginConnection(originConnection) -{ -} +FilesOrigin::FilesOrigin(OriginID ID, const std::wstring& name, + const std::wstring& path, int priority, + boost::shared_ptr<MOShared::FileRegister> fileRegister, + boost::shared_ptr<MOShared::OriginConnection> originConnection) + : m_ID(ID), m_Disabled(false), m_Name(name), m_Path(path), m_Priority(priority), + m_FileRegister(fileRegister), m_OriginConnection(originConnection) +{} void FilesOrigin::setPriority(int priority) { m_Priority = priority; } -void FilesOrigin::setName(const std::wstring &name) +void FilesOrigin::setName(const std::wstring& name) { m_OriginConnection.lock()->changeNameLookup(m_Name, name); @@ -121,4 +117,4 @@ bool FilesOrigin::containsArchive(std::wstring archiveName) return false; } -} // namespace +} // namespace MOShared diff --git a/src/shared/filesorigin.h b/src/shared/filesorigin.h index 1aa4c645..92fe12ef 100644 --- a/src/shared/filesorigin.h +++ b/src/shared/filesorigin.h @@ -12,40 +12,26 @@ class FilesOrigin public: FilesOrigin(); - FilesOrigin( - OriginID ID, const std::wstring &name, const std::wstring &path, - int priority, - boost::shared_ptr<FileRegister> fileRegister, - boost::shared_ptr<OriginConnection> originConnection); + FilesOrigin(OriginID ID, const std::wstring& name, const std::wstring& path, + int priority, boost::shared_ptr<FileRegister> fileRegister, + boost::shared_ptr<OriginConnection> originConnection); // noncopyable - FilesOrigin(const FilesOrigin&) = delete; + FilesOrigin(const FilesOrigin&) = delete; FilesOrigin& operator=(const FilesOrigin&) = delete; // sets priority for this origin (does not automatically refresh // the structure) void setPriority(int priority); - int getPriority() const - { - return m_Priority; - } + int getPriority() const { return m_Priority; } - void setName(const std::wstring &name); - const std::wstring &getName() const - { - return m_Name; - } + void setName(const std::wstring& name); + const std::wstring& getName() const { return m_Name; } - OriginID getID() const - { - return m_ID; - } + OriginID getID() const { return m_ID; } - const std::wstring &getPath() const - { - return m_Path; - } + const std::wstring& getPath() const { return m_Path; } std::vector<FileEntryPtr> getFiles() const; FileEntryPtr findFile(FileIndex index) const; @@ -53,10 +39,7 @@ public: void enable(bool enabled, DirectoryStats& stats); void enable(bool enabled); - bool isDisabled() const - { - return m_Disabled; - } + bool isDisabled() const { return m_Disabled; } void addFile(FileIndex index) { @@ -80,6 +63,6 @@ private: mutable std::mutex m_Mutex; }; -} // namespace +} // namespace MOShared -#endif // MO_REGISTER_FILESORIGIN_INCLUDED +#endif // MO_REGISTER_FILESORIGIN_INCLUDED diff --git a/src/shared/originconnection.cpp b/src/shared/originconnection.cpp index 2830e8e3..e433891c 100644 --- a/src/shared/originconnection.cpp +++ b/src/shared/originconnection.cpp @@ -8,24 +8,20 @@ namespace MOShared using namespace MOBase; -OriginConnection::OriginConnection() - : m_NextID(0) -{ -} +OriginConnection::OriginConnection() : m_NextID(0) {} std::pair<FilesOrigin&, bool> OriginConnection::getOrCreate( - const std::wstring &originName, const std::wstring &directory, int priority, - const boost::shared_ptr<FileRegister>& fileRegister, - const boost::shared_ptr<OriginConnection>& originConnection, - DirectoryStats& stats) + const std::wstring& originName, const std::wstring& directory, int priority, + const boost::shared_ptr<FileRegister>& fileRegister, + const boost::shared_ptr<OriginConnection>& originConnection, DirectoryStats& stats) { std::unique_lock lock(m_Mutex); auto itor = m_OriginsNameMap.find(originName); if (itor == m_OriginsNameMap.end()) { - FilesOrigin& origin = createOriginNoLock( - originName, directory, priority, fileRegister, originConnection); + FilesOrigin& origin = createOriginNoLock(originName, directory, priority, + fileRegister, originConnection); return {origin, true}; } else { @@ -37,18 +33,19 @@ std::pair<FilesOrigin&, bool> OriginConnection::getOrCreate( } } -FilesOrigin& OriginConnection::createOrigin( - const std::wstring &originName, const std::wstring &directory, int priority, - boost::shared_ptr<FileRegister> fileRegister, - boost::shared_ptr<OriginConnection> originConnection) +FilesOrigin& +OriginConnection::createOrigin(const std::wstring& originName, + const std::wstring& directory, int priority, + boost::shared_ptr<FileRegister> fileRegister, + boost::shared_ptr<OriginConnection> originConnection) { std::scoped_lock lock(m_Mutex); - return createOriginNoLock( - originName, directory, priority, fileRegister, originConnection); + return createOriginNoLock(originName, directory, priority, fileRegister, + originConnection); } -bool OriginConnection::exists(const std::wstring &name) +bool OriginConnection::exists(const std::wstring& name) { std::scoped_lock lock(m_Mutex); return m_OriginsNameMap.find(name) != m_OriginsNameMap.end(); @@ -73,7 +70,7 @@ const FilesOrigin* OriginConnection::findByID(OriginID ID) const } } -FilesOrigin& OriginConnection::getByName(const std::wstring &name) +FilesOrigin& OriginConnection::getByName(const std::wstring& name) { std::scoped_lock lock(m_Mutex); @@ -83,12 +80,14 @@ FilesOrigin& OriginConnection::getByName(const std::wstring &name) return m_Origins[iter->second]; } else { std::ostringstream stream; - stream << QObject::tr("invalid origin name: ").toStdString() << ToString(name, true); + stream << QObject::tr("invalid origin name: ").toStdString() + << ToString(name, true); throw std::runtime_error(stream.str()); } } -void OriginConnection::changeNameLookup(const std::wstring &oldName, const std::wstring &newName) +void OriginConnection::changeNameLookup(const std::wstring& oldName, + const std::wstring& newName) { std::scoped_lock lock(m_Mutex); @@ -99,7 +98,8 @@ void OriginConnection::changeNameLookup(const std::wstring &oldName, const std:: m_OriginsNameMap.erase(iter); m_OriginsNameMap[newName] = idx; } else { - log::error(QObject::tr("failed to change name lookup from {} to {}").toStdString(), oldName, newName); + log::error(QObject::tr("failed to change name lookup from {} to {}").toStdString(), + oldName, newName); } } @@ -109,23 +109,21 @@ OriginID OriginConnection::createID() } FilesOrigin& OriginConnection::createOriginNoLock( - const std::wstring &originName, const std::wstring &directory, int priority, - boost::shared_ptr<FileRegister> fileRegister, - boost::shared_ptr<OriginConnection> originConnection) + const std::wstring& originName, const std::wstring& directory, int priority, + boost::shared_ptr<FileRegister> fileRegister, + boost::shared_ptr<OriginConnection> originConnection) { OriginID newID = createID(); - auto itor = m_Origins.emplace( - std::piecewise_construct, - std::forward_as_tuple(newID), - std::forward_as_tuple( - newID, originName, directory, priority, - fileRegister, originConnection)) - .first; + auto itor = m_Origins + .emplace(std::piecewise_construct, std::forward_as_tuple(newID), + std::forward_as_tuple(newID, originName, directory, priority, + fileRegister, originConnection)) + .first; m_OriginsNameMap.insert({originName, newID}); return itor->second; } -} // namespace +} // namespace MOShared diff --git a/src/shared/originconnection.h b/src/shared/originconnection.h index ef8692bb..d8a67648 100644 --- a/src/shared/originconnection.h +++ b/src/shared/originconnection.h @@ -12,29 +12,29 @@ public: OriginConnection(); // noncopyable - OriginConnection(const OriginConnection&) = delete; + OriginConnection(const OriginConnection&) = delete; OriginConnection& operator=(const OriginConnection&) = delete; - std::pair<FilesOrigin&, bool> getOrCreate( - const std::wstring &originName, const std::wstring &directory, int priority, - const boost::shared_ptr<FileRegister>& fileRegister, - const boost::shared_ptr<OriginConnection>& originConnection, - DirectoryStats& stats); + std::pair<FilesOrigin&, bool> + getOrCreate(const std::wstring& originName, const std::wstring& directory, + int priority, const boost::shared_ptr<FileRegister>& fileRegister, + const boost::shared_ptr<OriginConnection>& originConnection, + DirectoryStats& stats); - FilesOrigin& createOrigin( - const std::wstring &originName, const std::wstring &directory, int priority, - boost::shared_ptr<FileRegister> fileRegister, - boost::shared_ptr<OriginConnection> originConnection); + FilesOrigin& createOrigin(const std::wstring& originName, + const std::wstring& directory, int priority, + boost::shared_ptr<FileRegister> fileRegister, + boost::shared_ptr<OriginConnection> originConnection); - bool exists(const std::wstring &name); + bool exists(const std::wstring& name); - FilesOrigin &getByID(OriginID ID); + FilesOrigin& getByID(OriginID ID); const FilesOrigin* findByID(OriginID ID) const; - FilesOrigin &getByName(const std::wstring &name); + FilesOrigin& getByName(const std::wstring& name); void changePriorityLookup(int oldPriority, int newPriority); - void changeNameLookup(const std::wstring &oldName, const std::wstring &newName); + void changeNameLookup(const std::wstring& oldName, const std::wstring& newName); private: std::atomic<OriginID> m_NextID; @@ -44,12 +44,12 @@ private: OriginID createID(); - FilesOrigin& createOriginNoLock( - const std::wstring &originName, const std::wstring &directory, int priority, - boost::shared_ptr<FileRegister> fileRegister, - boost::shared_ptr<OriginConnection> originConnection); + FilesOrigin& createOriginNoLock(const std::wstring& originName, + const std::wstring& directory, int priority, + boost::shared_ptr<FileRegister> fileRegister, + boost::shared_ptr<OriginConnection> originConnection); }; -} // namespace +} // namespace MOShared -#endif // MO_REGISTER_ORIGINCONNECTION_INCLUDED +#endif // MO_REGISTER_ORIGINCONNECTION_INCLUDED diff --git a/src/shared/util.cpp b/src/shared/util.cpp index e2faaec5..c3b4d7aa 100644 --- a/src/shared/util.cpp +++ b/src/shared/util.cpp @@ -18,9 +18,9 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ #include "util.h" -#include "windows_error.h" -#include "../mainwindow.h" #include "../env.h" +#include "../mainwindow.h" +#include "windows_error.h" #include <log.h> #include <usvfs.h> #include <usvfs_version.h> @@ -30,28 +30,28 @@ using namespace MOBase; namespace MOShared { -bool FileExists(const std::string &filename) +bool FileExists(const std::string& filename) { DWORD dwAttrib = ::GetFileAttributesA(filename.c_str()); return (dwAttrib != INVALID_FILE_ATTRIBUTES); } -bool FileExists(const std::wstring &filename) +bool FileExists(const std::wstring& filename) { DWORD dwAttrib = ::GetFileAttributesW(filename.c_str()); return (dwAttrib != INVALID_FILE_ATTRIBUTES); } -bool FileExists(const std::wstring &searchPath, const std::wstring &filename) +bool FileExists(const std::wstring& searchPath, const std::wstring& filename) { std::wstringstream stream; stream << searchPath << "\\" << filename; return FileExists(stream.str()); } -std::string ToString(const std::wstring &source, bool utf8) +std::string ToString(const std::wstring& source, bool utf8) { std::string result; if (source.length() > 0) { @@ -59,20 +59,23 @@ std::string ToString(const std::wstring &source, bool utf8) if (!utf8) { codepage = AreFileApisANSI() ? GetACP() : GetOEMCP(); } - int sizeRequired = ::WideCharToMultiByte(codepage, 0, &source[0], -1, nullptr, 0, nullptr, nullptr); + int sizeRequired = ::WideCharToMultiByte(codepage, 0, &source[0], -1, nullptr, 0, + nullptr, nullptr); if (sizeRequired == 0) { throw windows_error("failed to convert string to multibyte"); } - // the size returned by WideCharToMultiByte contains zero termination IF -1 is specified for the length. - // we don't want that \0 in the string because then the length field would be wrong. Because madness + // the size returned by WideCharToMultiByte contains zero termination IF -1 is + // specified for the length. we don't want that \0 in the string because then the + // length field would be wrong. Because madness result.resize(sizeRequired - 1, '\0'); - ::WideCharToMultiByte(codepage, 0, &source[0], (int)source.size(), &result[0], sizeRequired, nullptr, nullptr); + ::WideCharToMultiByte(codepage, 0, &source[0], (int)source.size(), &result[0], + sizeRequired, nullptr, nullptr); } return result; } -std::wstring ToWString(const std::string &source, bool utf8) +std::wstring ToWString(const std::string& source, bool utf8) { std::wstring result; if (source.length() > 0) { @@ -80,53 +83,51 @@ std::wstring ToWString(const std::string &source, bool utf8) if (!utf8) { codepage = AreFileApisANSI() ? GetACP() : GetOEMCP(); } - int sizeRequired - = ::MultiByteToWideChar(codepage, 0, source.c_str(), - static_cast<int>(source.length()), nullptr, 0); + int sizeRequired = ::MultiByteToWideChar( + codepage, 0, source.c_str(), static_cast<int>(source.length()), nullptr, 0); if (sizeRequired == 0) { throw windows_error("failed to convert string to wide character"); } result.resize(sizeRequired, L'\0'); ::MultiByteToWideChar(codepage, 0, source.c_str(), - static_cast<int>(source.length()), &result[0], - sizeRequired); + static_cast<int>(source.length()), &result[0], sizeRequired); } return result; } static std::locale loc(""); -static auto locToLowerW = [] (wchar_t in) -> wchar_t { +static auto locToLowerW = [](wchar_t in) -> wchar_t { return std::tolower(in, loc); }; -static auto locToLower = [] (char in) -> char { +static auto locToLower = [](char in) -> char { return std::tolower(in, loc); }; std::string& ToLowerInPlace(std::string& text) { - CharLowerBuffA(const_cast<CHAR *>(text.c_str()), static_cast<DWORD>(text.size())); + CharLowerBuffA(const_cast<CHAR*>(text.c_str()), static_cast<DWORD>(text.size())); return text; } std::string ToLowerCopy(const std::string& text) { std::string result(text); - CharLowerBuffA(const_cast<CHAR *>(result.c_str()), static_cast<DWORD>(result.size())); + CharLowerBuffA(const_cast<CHAR*>(result.c_str()), static_cast<DWORD>(result.size())); return result; } std::wstring& ToLowerInPlace(std::wstring& text) { - CharLowerBuffW(const_cast<WCHAR *>(text.c_str()), static_cast<DWORD>(text.size())); + CharLowerBuffW(const_cast<WCHAR*>(text.c_str()), static_cast<DWORD>(text.size())); return text; } std::wstring ToLowerCopy(const std::wstring& text) { std::wstring result(text); - CharLowerBuffW(const_cast<WCHAR *>(result.c_str()), static_cast<DWORD>(result.size())); + CharLowerBuffW(const_cast<WCHAR*>(result.c_str()), static_cast<DWORD>(result.size())); return result; } @@ -142,20 +143,19 @@ bool CaseInsenstiveComparePred(wchar_t lhs, wchar_t rhs) return std::tolower(lhs, loc) == std::tolower(rhs, loc); } -bool CaseInsensitiveEqual(const std::wstring &lhs, const std::wstring &rhs) +bool CaseInsensitiveEqual(const std::wstring& lhs, const std::wstring& rhs) { - return (lhs.length() == rhs.length()) - && std::equal(lhs.begin(), lhs.end(), - rhs.begin(), - [] (wchar_t lhs, wchar_t rhs) -> bool { + return (lhs.length() == rhs.length()) && + std::equal(lhs.begin(), lhs.end(), rhs.begin(), + [](wchar_t lhs, wchar_t rhs) -> bool { return std::tolower(lhs, loc) == std::tolower(rhs, loc); }); } -VS_FIXEDFILEINFO GetFileVersion(const std::wstring &fileName) +VS_FIXEDFILEINFO GetFileVersion(const std::wstring& fileName) { DWORD handle = 0UL; - DWORD size = ::GetFileVersionInfoSizeW(fileName.c_str(), &handle); + DWORD size = ::GetFileVersionInfoSizeW(fileName.c_str(), &handle); if (size == 0) { throw windows_error("failed to determine file version info size"); } @@ -167,7 +167,7 @@ VS_FIXEDFILEINFO GetFileVersion(const std::wstring &fileName) throw windows_error("failed to determine file version info"); } - void *versionInfoPtr = nullptr; + void* versionInfoPtr = nullptr; UINT versionInfoLength = 0; if (!::VerQueryValue(buffer.get(), L"\\", &versionInfoPtr, &versionInfoLength)) { throw windows_error("failed to determine file version"); @@ -180,10 +180,10 @@ VS_FIXEDFILEINFO GetFileVersion(const std::wstring &fileName) } } -std::wstring GetFileVersionString(const std::wstring &fileName) +std::wstring GetFileVersionString(const std::wstring& fileName) { DWORD handle = 0UL; - DWORD size = ::GetFileVersionInfoSizeW(fileName.c_str(), &handle); + DWORD size = ::GetFileVersionInfoSizeW(fileName.c_str(), &handle); if (size == 0) { throw windows_error("failed to determine file version info size"); } @@ -196,14 +196,14 @@ std::wstring GetFileVersionString(const std::wstring &fileName) } LPVOID strBuffer = nullptr; - UINT strLength = 0; - if (!::VerQueryValue(buffer.get(), L"\\StringFileInfo\\040904B0\\ProductVersion", &strBuffer, &strLength)) { + UINT strLength = 0; + if (!::VerQueryValue(buffer.get(), L"\\StringFileInfo\\040904B0\\ProductVersion", + &strBuffer, &strLength)) { throw windows_error("failed to determine file version"); } return std::wstring((LPCTSTR)strBuffer); - } - catch (...) { + } catch (...) { throw; } } @@ -212,45 +212,35 @@ VersionInfo createVersionInfo() { VS_FIXEDFILEINFO version = GetFileVersion(env::thisProcessPath().native()); - if (version.dwFileFlags & VS_FF_PRERELEASE) - { + if (version.dwFileFlags & VS_FF_PRERELEASE) { // Pre-release builds need annotating - QString versionString = QString::fromStdWString( - GetFileVersionString(env::thisProcessPath().native())); + QString versionString = + QString::fromStdWString(GetFileVersionString(env::thisProcessPath().native())); - // The pre-release flag can be set without the string specifying what type of pre-release + // The pre-release flag can be set without the string specifying what type of + // pre-release bool noLetters = true; - for (QChar character : versionString) - { - if (character.isLetter()) - { + for (QChar character : versionString) { + if (character.isLetter()) { noLetters = false; break; } } - if (noLetters) - { + if (noLetters) { // Default to pre-alpha when release type is unspecified - return VersionInfo(version.dwFileVersionMS >> 16, - version.dwFileVersionMS & 0xFFFF, - version.dwFileVersionLS >> 16, - version.dwFileVersionLS & 0xFFFF, - VersionInfo::RELEASE_PREALPHA); - } - else - { + return VersionInfo( + version.dwFileVersionMS >> 16, version.dwFileVersionMS & 0xFFFF, + version.dwFileVersionLS >> 16, version.dwFileVersionLS & 0xFFFF, + VersionInfo::RELEASE_PREALPHA); + } else { // Trust the string to make sense return VersionInfo(versionString); } - } - else - { + } else { // Non-pre-release builds just need their version numbers reading - return VersionInfo(version.dwFileVersionMS >> 16, - version.dwFileVersionMS & 0xFFFF, - version.dwFileVersionLS >> 16, - version.dwFileVersionLS & 0xFFFF); + return VersionInfo(version.dwFileVersionMS >> 16, version.dwFileVersionMS & 0xFFFF, + version.dwFileVersionLS >> 16, version.dwFileVersionLS & 0xFFFF); } } @@ -260,7 +250,7 @@ QString getUsvfsDLLVersion() // directly; until then, using GetProcAddress() allows for mixing up devbuilds // and usvfs dlls - using USVFSVersionStringType = const char* WINAPI (); + using USVFSVersionStringType = const char* WINAPI(); QString s; @@ -268,7 +258,7 @@ QString getUsvfsDLLVersion() if (m) { auto* f = reinterpret_cast<USVFSVersionStringType*>( - ::GetProcAddress(m, "USVFSVersionString")); + ::GetProcAddress(m, "USVFSVersionString")); if (f) { s = f(); @@ -286,7 +276,7 @@ QString getUsvfsDLLVersion() QString getUsvfsVersionString() { - const QString dll = getUsvfsDLLVersion(); + const QString dll = getUsvfsDLLVersion(); const QString header = USVFS_VERSION_STRING; QString usvfsVersion; @@ -300,10 +290,7 @@ QString getUsvfsVersionString() void SetThisThreadName(const QString& s) { - using SetThreadDescriptionType = HRESULT ( - HANDLE hThread, - PCWSTR lpThreadDescription - ); + using SetThreadDescriptionType = HRESULT(HANDLE hThread, PCWSTR lpThreadDescription); static SetThreadDescriptionType* SetThreadDescription = [] { SetThreadDescriptionType* p = nullptr; @@ -314,7 +301,7 @@ void SetThisThreadName(const QString& s) } p = reinterpret_cast<SetThreadDescriptionType*>( - GetProcAddress(kernel32.get(), "SetThreadDescription")); + GetProcAddress(kernel32.get(), "SetThreadDescription")); return p; }(); @@ -324,13 +311,12 @@ void SetThisThreadName(const QString& s) } } - char shortcutChar(const QAction* a) { const auto text = a->text(); - char shortcut = 0; + char shortcut = 0; - for (int i=0; i<text.size(); ++i) { + for (int i = 0; i < text.size(); ++i) { const auto c = text[i]; if (c == '&') { if (i >= (text.size() - 1)) { @@ -350,7 +336,7 @@ void checkDuplicateShortcuts(const QMenu& m) { const auto actions = m.actions(); - for (int i=0; i<actions.size(); ++i) { + for (int i = 0; i < actions.size(); ++i) { const auto* action1 = actions[i]; if (action1->isSeparator()) { continue; @@ -361,7 +347,7 @@ void checkDuplicateShortcuts(const QMenu& m) continue; } - for (int j=i+1; j<actions.size(); ++j) { + for (int j = i + 1; j < actions.size(); ++j) { const auto* action2 = actions[j]; if (action2->isSeparator()) { continue; @@ -370,9 +356,8 @@ void checkDuplicateShortcuts(const QMenu& m) const char shortcut2 = shortcutChar(action2); if (shortcut1 == shortcut2) { - log::error( - "duplicate shortcut {} for {} and {}", - shortcut1, action1->text(), action2->text()); + log::error("duplicate shortcut {} for {} and {}", shortcut1, action1->text(), + action2->text()); break; } @@ -380,16 +365,15 @@ void checkDuplicateShortcuts(const QMenu& m) } } -} // namespace MOShared - +} // namespace MOShared -static bool g_exiting = false; +static bool g_exiting = false; static bool g_canClose = false; MainWindow* findMainWindow() { for (auto* tl : qApp->topLevelWidgets()) { - if (auto* mw=dynamic_cast<MainWindow*>(tl)) { + if (auto* mw = dynamic_cast<MainWindow*>(tl)) { return mw; } } @@ -404,10 +388,12 @@ bool ExitModOrganizer(ExitFlags e) } g_exiting = true; - Guard g([&]{ g_exiting = false; }); + Guard g([&] { + g_exiting = false; + }); if (!e.testFlag(Exit::Force)) { - if (auto* mw=findMainWindow()) { + if (auto* mw = findMainWindow()) { if (!mw->canExit()) { return false; } @@ -437,7 +423,6 @@ void ResetExitFlag() g_exiting = false; } - bool isNxmLink(const QString& link) { return link.startsWith("nxm://", Qt::CaseInsensitive); diff --git a/src/shared/util.h b/src/shared/util.h index 87ec5bf2..1bc6bd47 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -20,23 +20,24 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef UTIL_H #define UTIL_H +#include <filesystem> #include <log.h> #include <string> -#include <filesystem> #include <versioninfo.h> class Executable; -namespace MOShared { +namespace MOShared +{ /// Test if a file (or directory) by the specified name exists -bool FileExists(const std::string &filename); -bool FileExists(const std::wstring &filename); +bool FileExists(const std::string& filename); +bool FileExists(const std::wstring& filename); -bool FileExists(const std::wstring &searchPath, const std::wstring &filename); +bool FileExists(const std::wstring& searchPath, const std::wstring& filename); -std::string ToString(const std::wstring &source, bool utf8); -std::wstring ToWString(const std::string &source, bool utf8); +std::string ToString(const std::wstring& source, bool utf8); +std::wstring ToWString(const std::string& source, bool utf8); std::string& ToLowerInPlace(std::string& text); std::string ToLowerCopy(const std::string& text); @@ -45,7 +46,7 @@ std::wstring& ToLowerInPlace(std::wstring& text); std::wstring ToLowerCopy(const std::wstring& text); std::wstring ToLowerCopy(std::wstring_view text); -bool CaseInsensitiveEqual(const std::wstring &lhs, const std::wstring &rhs); +bool CaseInsensitiveEqual(const std::wstring& lhs, const std::wstring& rhs); MOBase::VersionInfo createVersionInfo(); QString getUsvfsVersionString(); @@ -62,8 +63,7 @@ inline FILETIME ToFILETIME(std::filesystem::file_time_type t) return ft; } -} // namespace MOShared - +} // namespace MOShared enum class Exit { @@ -73,17 +73,17 @@ enum class Exit Force = 0x04 }; -const int RestartExitCode = INT_MAX; +const int RestartExitCode = INT_MAX; const int ReselectExitCode = INT_MAX - 1; using ExitFlags = QFlags<Exit>; Q_DECLARE_OPERATORS_FOR_FLAGS(ExitFlags); -bool ExitModOrganizer(ExitFlags e=Exit::Normal); +bool ExitModOrganizer(ExitFlags e = Exit::Normal); bool ModOrganizerExiting(); bool ModOrganizerCanCloseNow(); void ResetExitFlag(); bool isNxmLink(const QString& link); -#endif // UTIL_H +#endif // UTIL_H diff --git a/src/shared/windows_error.cpp b/src/shared/windows_error.cpp index 49fb9bc7..f0add1da 100644 --- a/src/shared/windows_error.cpp +++ b/src/shared/windows_error.cpp @@ -20,7 +20,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "windows_error.h" #include <sstream> -namespace MOShared { +namespace MOShared +{ std::string windows_error::constructMessage(const std::string& input, int inErrorCode) { @@ -33,17 +34,19 @@ std::string windows_error::constructMessage(const std::string& input, int inErro // TODO: the message is not english? if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - nullptr, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buffer, 0, nullptr) == 0) { + nullptr, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&buffer, 0, nullptr) == 0) { finalMessage << " (errorcode " << errorCode << ")"; } else { LPSTR lastChar = buffer + strlen(buffer) - 2; - *lastChar = '\0'; + *lastChar = '\0'; finalMessage << " (" << buffer << " [" << errorCode << "])"; - LocalFree(buffer); // allocated by FormatMessage + LocalFree(buffer); // allocated by FormatMessage } - ::SetLastError(errorCode); // restore error code because FormatMessage might have modified it + ::SetLastError( + errorCode); // restore error code because FormatMessage might have modified it return finalMessage.str(); } -} // namespace MOShared +} // namespace MOShared diff --git a/src/shared/windows_error.h b/src/shared/windows_error.h index ea506dc1..2bdd6392 100644 --- a/src/shared/windows_error.h +++ b/src/shared/windows_error.h @@ -20,25 +20,28 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef WINDOWS_ERROR_H #define WINDOWS_ERROR_H - #include <stdexcept> #define WIN32_LEAN_AND_MEAN #include <windows.h> -namespace MOShared { +namespace MOShared +{ -class windows_error : public std::runtime_error { +class windows_error : public std::runtime_error +{ public: windows_error(const std::string& message, int errorcode = ::GetLastError()) - : runtime_error(constructMessage(message, errorcode)), m_ErrorCode(errorcode) + : runtime_error(constructMessage(message, errorcode)), m_ErrorCode(errorcode) {} int getErrorCode() const { return m_ErrorCode; } + private: std::string constructMessage(const std::string& input, int errorcode); + private: int m_ErrorCode; }; -} // namespace MOShared +} // namespace MOShared -#endif // WINDOWS_ERROR_H +#endif // WINDOWS_ERROR_H diff --git a/src/spawn.cpp b/src/spawn.cpp index 858c3061..05f796a5 100644 --- a/src/spawn.cpp +++ b/src/spawn.cpp @@ -19,27 +19,26 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "spawn.h" -#include "report.h" -#include "utility.h" #include "env.h" -#include "envwindows.h" -#include "envsecurity.h" #include "envmodule.h" +#include "envsecurity.h" +#include "envwindows.h" +#include "report.h" #include "settings.h" #include "settingsdialogworkarounds.h" -#include <errorcodes.h> -#include <report.h> -#include <log.h> -#include <usvfs.h> -#include <Shellapi.h> #include "shared/appconfig.h" #include "shared/windows_error.h" +#include "utility.h" #include <QApplication> #include <QMessageBox> #include <QtDebug> #include <Shellapi.h> +#include <errorcodes.h> #include <fmt/format.h> #include <fmt/xchar.h> +#include <log.h> +#include <report.h> +#include <usvfs.h> using namespace MOBase; using namespace MOShared; @@ -65,7 +64,7 @@ std::wstring makeRightsDetails(const env::FileSecurity& fs) return s; } -QString makeDetails(const SpawnParameters& sp, DWORD code, const QString& more={}) +QString makeDetails(const SpawnParameters& sp, DWORD code, const QString& more = {}) { std::wstring owner, rights; @@ -73,77 +72,76 @@ QString makeDetails(const SpawnParameters& sp, DWORD code, const QString& more={ const auto fs = env::getFileSecurity(sp.binary.absoluteFilePath()); if (fs.error.isEmpty()) { - owner = fs.owner.toStdWString(); + owner = fs.owner.toStdWString(); rights = makeRightsDetails(fs); } else { - owner = fs.error.toStdWString(); + owner = fs.error.toStdWString(); rights = fs.error.toStdWString(); } } else { - owner = L"(file not found)"; + owner = L"(file not found)"; rights = L"(file not found)"; } - const bool cwdExists = (sp.currentDirectory.isEmpty() ? - true : sp.currentDirectory.exists()); + const bool cwdExists = + (sp.currentDirectory.isEmpty() ? true : sp.currentDirectory.exists()); const auto appDir = QCoreApplication::applicationDirPath(); - const auto sep = QDir::separator(); + const auto sep = QDir::separator(); const std::wstring usvfs_x86_dll = - QFileInfo(appDir + sep + "usvfs_x86.dll").isFile() ? L"ok" : L"not found"; + QFileInfo(appDir + sep + "usvfs_x86.dll").isFile() ? L"ok" : L"not found"; const std::wstring usvfs_x64_dll = - QFileInfo(appDir + sep + "usvfs_x64.dll").isFile() ? L"ok" : L"not found"; + QFileInfo(appDir + sep + "usvfs_x64.dll").isFile() ? L"ok" : L"not found"; const std::wstring usvfs_x86_proxy = - QFileInfo(appDir + sep + "usvfs_proxy_x86.exe").isFile() ? L"ok" : L"not found"; + QFileInfo(appDir + sep + "usvfs_proxy_x86.exe").isFile() ? L"ok" : L"not found"; const std::wstring usvfs_x64_proxy = - QFileInfo(appDir + sep + "usvfs_proxy_x64.exe").isFile() ? L"ok" : L"not found"; + QFileInfo(appDir + sep + "usvfs_proxy_x64.exe").isFile() ? L"ok" : L"not found"; std::wstring elevated; - if (auto b=env::Environment().windowsInfo().isElevated()) { + if (auto b = env::Environment().windowsInfo().isElevated()) { elevated = (*b ? L"yes" : L"no"); } else { elevated = L"(not available)"; } - std::wstring f = - L"Error {code} {codename}{more}: {error}\n" - L" . binary: '{bin}'\n" - L" . owner: {owner}\n" - L" . rights: {rights}\n" - L" . arguments: '{args}'\n" - L" . cwd: '{cwd}'{cwdexists}\n" - L" . stdout: {stdout}, stderr: {stderr}, hooked: {hooked}\n" - L" . MO elevated: {elevated}"; + std::wstring f = L"Error {code} {codename}{more}: {error}\n" + L" . binary: '{bin}'\n" + L" . owner: {owner}\n" + L" . rights: {rights}\n" + L" . arguments: '{args}'\n" + L" . cwd: '{cwd}'{cwdexists}\n" + L" . stdout: {stdout}, stderr: {stderr}, hooked: {hooked}\n" + L" . MO elevated: {elevated}"; if (sp.hooked) { - f += L"\n . usvfs x86:{x86_dll} x64:{x64_dll} proxy_x86:{x86_proxy} proxy_x64:{x64_proxy}"; + f += L"\n . usvfs x86:{x86_dll} x64:{x64_dll} proxy_x86:{x86_proxy} " + L"proxy_x64:{x64_proxy}"; } const std::wstring wmore = (more.isEmpty() ? L"" : (", " + more).toStdWString()); - const auto s = fmt::format(f, - fmt::arg(L"code", code), - fmt::arg(L"codename", errorCodeName(code)), - fmt::arg(L"more", wmore), - fmt::arg(L"bin", QDir::toNativeSeparators(sp.binary.absoluteFilePath()).toStdWString()), - fmt::arg(L"owner", owner), - fmt::arg(L"rights", rights), - fmt::arg(L"error", formatSystemMessage(code)), - fmt::arg(L"args", sp.arguments.toStdWString()), - fmt::arg(L"cwd", QDir::toNativeSeparators(sp.currentDirectory.absolutePath()).toStdWString()), - fmt::arg(L"cwdexists", (cwdExists ? L"" : L" (not found)")), - fmt::arg(L"stdout", (sp.stdOut == INVALID_HANDLE_VALUE ? L"no" : L"yes")), - fmt::arg(L"stderr", (sp.stdErr == INVALID_HANDLE_VALUE ? L"no" : L"yes")), - fmt::arg(L"hooked", (sp.hooked ? L"yes" : L"no")), - fmt::arg(L"x86_dll", usvfs_x86_dll), - fmt::arg(L"x64_dll", usvfs_x64_dll), - fmt::arg(L"x86_proxy", usvfs_x86_proxy), - fmt::arg(L"x64_proxy", usvfs_x64_proxy), - fmt::arg(L"elevated", elevated)); + const auto s = fmt::format( + f, fmt::arg(L"code", code), fmt::arg(L"codename", errorCodeName(code)), + fmt::arg(L"more", wmore), + fmt::arg(L"bin", + QDir::toNativeSeparators(sp.binary.absoluteFilePath()).toStdWString()), + fmt::arg(L"owner", owner), fmt::arg(L"rights", rights), + fmt::arg(L"error", formatSystemMessage(code)), + fmt::arg(L"args", sp.arguments.toStdWString()), + fmt::arg( + L"cwd", + QDir::toNativeSeparators(sp.currentDirectory.absolutePath()).toStdWString()), + fmt::arg(L"cwdexists", (cwdExists ? L"" : L" (not found)")), + fmt::arg(L"stdout", (sp.stdOut == INVALID_HANDLE_VALUE ? L"no" : L"yes")), + fmt::arg(L"stderr", (sp.stdErr == INVALID_HANDLE_VALUE ? L"no" : L"yes")), + fmt::arg(L"hooked", (sp.hooked ? L"yes" : L"no")), + fmt::arg(L"x86_dll", usvfs_x86_dll), fmt::arg(L"x64_dll", usvfs_x64_dll), + fmt::arg(L"x86_proxy", usvfs_x86_proxy), fmt::arg(L"x64_proxy", usvfs_x64_proxy), + fmt::arg(L"elevated", elevated)); return QString::fromStdWString(s); } @@ -152,82 +150,73 @@ QString makeContent(const SpawnParameters& sp, DWORD code) { if (code == ERROR_INVALID_PARAMETER) { return QObject::tr( - "This error typically happens because an antivirus has deleted critical " - "files from Mod Organizer's installation folder or has made them " - "generally inaccessible. Add an exclusion for Mod Organizer's " - "installation folder in your antivirus, reinstall Mod Organizer and try " - "again."); + "This error typically happens because an antivirus has deleted critical " + "files from Mod Organizer's installation folder or has made them " + "generally inaccessible. Add an exclusion for Mod Organizer's " + "installation folder in your antivirus, reinstall Mod Organizer and try " + "again."); } else if (code == ERROR_ACCESS_DENIED) { return QObject::tr( - "This error typically happens because an antivirus is preventing Mod " - "Organizer from starting programs. Add an exclusion for Mod Organizer's " - "installation folder in your antivirus and try again."); + "This error typically happens because an antivirus is preventing Mod " + "Organizer from starting programs. Add an exclusion for Mod Organizer's " + "installation folder in your antivirus and try again."); } else if (code == ERROR_FILE_NOT_FOUND) { return QObject::tr("The file '%1' does not exist.") - .arg(QDir::toNativeSeparators(sp.binary.absoluteFilePath())); + .arg(QDir::toNativeSeparators(sp.binary.absoluteFilePath())); } else if (code == ERROR_DIRECTORY) { if (!sp.currentDirectory.exists()) { return QObject::tr("The working directory '%1' does not exist.") - .arg(QDir::toNativeSeparators(sp.currentDirectory.absolutePath())); + .arg(QDir::toNativeSeparators(sp.currentDirectory.absolutePath())); } } return QString::fromStdWString(formatSystemMessage(code)); } -QMessageBox::StandardButton badSteamReg( - QWidget* parent, const QString& keyName, const QString& valueName) +QMessageBox::StandardButton badSteamReg(QWidget* parent, const QString& keyName, + const QString& valueName) { - const auto details = QString( - "can't start steam, registry value at '%1' is empty or doesn't exist") - .arg(keyName + "\\" + valueName); + const auto details = + QString("can't start steam, registry value at '%1' is empty or doesn't exist") + .arg(keyName + "\\" + valueName); log::error("{}", details); return MOBase::TaskDialog(parent, QObject::tr("Cannot start Steam")) - .main(QObject::tr("Cannot start Steam")) - .content(QObject::tr( - "The path to the Steam executable cannot be found. You might try " - "reinstalling Steam.")) - .details(details) - .icon(QMessageBox::Critical) - .button({ - QObject::tr("Continue without starting Steam"), - QObject::tr("The program may fail to launch."), - QMessageBox::Yes}) - .button({ - QObject::tr("Cancel"), - QMessageBox::Cancel}) - .exec(); + .main(QObject::tr("Cannot start Steam")) + .content( + QObject::tr("The path to the Steam executable cannot be found. You might try " + "reinstalling Steam.")) + .details(details) + .icon(QMessageBox::Critical) + .button({QObject::tr("Continue without starting Steam"), + QObject::tr("The program may fail to launch."), QMessageBox::Yes}) + .button({QObject::tr("Cancel"), QMessageBox::Cancel}) + .exec(); } -QMessageBox::StandardButton startSteamFailed( - QWidget* parent, - const QString& keyName, const QString& valueName, const QString& exe, - const SpawnParameters& sp, DWORD e) +QMessageBox::StandardButton startSteamFailed(QWidget* parent, const QString& keyName, + const QString& valueName, + const QString& exe, + const SpawnParameters& sp, DWORD e) { - auto details = QString( - "a steam install was found in the registry at '%1': '%2'\n\n") - .arg(keyName + "\\" + valueName) - .arg(exe); + auto details = QString("a steam install was found in the registry at '%1': '%2'\n\n") + .arg(keyName + "\\" + valueName) + .arg(exe); details += makeDetails(sp, e); log::error("{}", details); return MOBase::TaskDialog(parent, QObject::tr("Cannot start Steam")) - .main(QObject::tr("Cannot start Steam")) - .content(makeContent(sp, e)) - .details(details) - .icon(QMessageBox::Critical) - .button({ - QObject::tr("Continue without starting Steam"), - QObject::tr("The program may fail to launch."), - QMessageBox::Yes}) - .button({ - QObject::tr("Cancel"), - QMessageBox::Cancel}) - .exec(); + .main(QObject::tr("Cannot start Steam")) + .content(makeContent(sp, e)) + .details(details) + .icon(QMessageBox::Critical) + .button({QObject::tr("Continue without starting Steam"), + QObject::tr("The program may fail to launch."), QMessageBox::Yes}) + .button({QObject::tr("Cancel"), QMessageBox::Cancel}) + .exec(); } void spawnFailed(QWidget* parent, const SpawnParameters& sp, DWORD code) @@ -237,20 +226,19 @@ void spawnFailed(QWidget* parent, const SpawnParameters& sp, DWORD code) const auto title = QObject::tr("Cannot launch program"); - const auto mainText = QObject::tr("Cannot start %1") - .arg(sp.binary.fileName()); + const auto mainText = QObject::tr("Cannot start %1").arg(sp.binary.fileName()); MOBase::TaskDialog(parent, title) - .main(mainText) - .content(makeContent(sp, code)) - .details(details) - .icon(QMessageBox::Critical) - .exec(); + .main(mainText) + .content(makeContent(sp, code)) + .details(details) + .icon(QMessageBox::Critical) + .exec(); } -void helperFailed( - QWidget* parent, DWORD code, const QString& why, const std::wstring& binary, - const std::wstring& cwd, const std::wstring& args) +void helperFailed(QWidget* parent, DWORD code, const QString& why, + const std::wstring& binary, const std::wstring& cwd, + const std::wstring& args) { SpawnParameters sp; sp.binary = QFileInfo(QString::fromStdWString(binary)); @@ -262,15 +250,14 @@ void helperFailed( const auto title = QObject::tr("Cannot launch helper"); - const auto mainText = QObject::tr("Cannot start %1") - .arg(sp.binary.fileName()); + const auto mainText = QObject::tr("Cannot start %1").arg(sp.binary.fileName()); MOBase::TaskDialog(parent, title) - .main(mainText) - .content(makeContent(sp, code)) - .details(details) - .icon(QMessageBox::Critical) - .exec(); + .main(mainText) + .content(makeContent(sp, code)) + .details(details) + .icon(QMessageBox::Critical) + .exec(); } bool confirmRestartAsAdmin(QWidget* parent, const SpawnParameters& sp) @@ -281,155 +268,135 @@ bool confirmRestartAsAdmin(QWidget* parent, const SpawnParameters& sp) const auto title = QObject::tr("Elevation required"); - const auto mainText = QObject::tr("Cannot start %1") - .arg(sp.binary.fileName()); + const auto mainText = QObject::tr("Cannot start %1").arg(sp.binary.fileName()); const auto content = QObject::tr( - "This program is requesting to run as administrator but Mod Organizer " - "itself is not running as administrator. Running programs as administrator " - "is typically unnecessary as long as the game and Mod Organizer have been " - "installed outside \"Program Files\".\r\n\r\n" - "You can restart Mod Organizer as administrator and try launching the " - "program again."); + "This program is requesting to run as administrator but Mod Organizer " + "itself is not running as administrator. Running programs as administrator " + "is typically unnecessary as long as the game and Mod Organizer have been " + "installed outside \"Program Files\".\r\n\r\n" + "You can restart Mod Organizer as administrator and try launching the " + "program again."); log::debug("asking user to restart MO as administrator"); - const auto r = MOBase::TaskDialog(parent, title) - .main(mainText) - .content(content) - .details(details) - .icon(QMessageBox::Question) - .button({ - QObject::tr("Restart Mod Organizer as administrator"), - QObject::tr("You must allow \"helper.exe\" to make changes to the system."), - QMessageBox::Yes}) - .button({ - QObject::tr("Cancel"), - QMessageBox::Cancel}) - .exec(); + const auto r = + MOBase::TaskDialog(parent, title) + .main(mainText) + .content(content) + .details(details) + .icon(QMessageBox::Question) + .button({QObject::tr("Restart Mod Organizer as administrator"), + QObject::tr( + "You must allow \"helper.exe\" to make changes to the system."), + QMessageBox::Yes}) + .button({QObject::tr("Cancel"), QMessageBox::Cancel}) + .exec(); return (r == QMessageBox::Yes); } -QMessageBox::StandardButton confirmStartSteam( - QWidget* parent, const SpawnParameters& sp, const QString& details) +QMessageBox::StandardButton +confirmStartSteam(QWidget* parent, const SpawnParameters& sp, const QString& details) { - const auto title = QObject::tr("Launch Steam"); + const auto title = QObject::tr("Launch Steam"); const auto mainText = QObject::tr("This program requires Steam"); - const auto content = QObject::tr( - "Mod Organizer has detected that this program likely requires Steam to be " - "running to function properly."); + const auto content = QObject::tr( + "Mod Organizer has detected that this program likely requires Steam to be " + "running to function properly."); return MOBase::TaskDialog(parent, title) - .main(mainText) - .content(content) - .details(details) - .icon(QMessageBox::Question) - .button({ - QObject::tr("Start Steam"), - QMessageBox::Yes}) - .button({ - QObject::tr("Continue without starting Steam"), - QObject::tr("The program might fail to run."), - QMessageBox::No}) - .button({ - QObject::tr("Cancel"), - QMessageBox::Cancel}) - .remember("steamQuery", sp.binary.fileName()) - .exec(); + .main(mainText) + .content(content) + .details(details) + .icon(QMessageBox::Question) + .button({QObject::tr("Start Steam"), QMessageBox::Yes}) + .button({QObject::tr("Continue without starting Steam"), + QObject::tr("The program might fail to run."), QMessageBox::No}) + .button({QObject::tr("Cancel"), QMessageBox::Cancel}) + .remember("steamQuery", sp.binary.fileName()) + .exec(); } -QMessageBox::StandardButton confirmRestartAsAdminForSteam( - QWidget* parent, const SpawnParameters& sp) +QMessageBox::StandardButton confirmRestartAsAdminForSteam(QWidget* parent, + const SpawnParameters& sp) { - const auto title = QObject::tr("Elevation required"); + const auto title = QObject::tr("Elevation required"); const auto mainText = QObject::tr("Steam is running as administrator"); - const auto content = QObject::tr( - "Running Steam as administrator is typically unnecessary and can cause " - "problems when Mod Organizer itself is not running as administrator." - "\r\n\r\n" - "You can restart Mod Organizer as administrator and try launching the " - "program again."); + const auto content = QObject::tr( + "Running Steam as administrator is typically unnecessary and can cause " + "problems when Mod Organizer itself is not running as administrator." + "\r\n\r\n" + "You can restart Mod Organizer as administrator and try launching the " + "program again."); return MOBase::TaskDialog(parent, title) - .main(mainText) - .content(content) - .icon(QMessageBox::Question) - .button({ - QObject::tr("Restart Mod Organizer as administrator"), - QObject::tr("You must allow \"helper.exe\" to make changes to the system."), - QMessageBox::Yes}) - .button({ - QObject::tr("Continue"), - QObject::tr("The program might fail to run."), - QMessageBox::No}) - .button({ - QObject::tr("Cancel"), - QMessageBox::Cancel}) - .remember("steamAdminQuery", sp.binary.fileName()) - .exec(); + .main(mainText) + .content(content) + .icon(QMessageBox::Question) + .button( + {QObject::tr("Restart Mod Organizer as administrator"), + QObject::tr("You must allow \"helper.exe\" to make changes to the system."), + QMessageBox::Yes}) + .button({QObject::tr("Continue"), QObject::tr("The program might fail to run."), + QMessageBox::No}) + .button({QObject::tr("Cancel"), QMessageBox::Cancel}) + .remember("steamAdminQuery", sp.binary.fileName()) + .exec(); } -bool eventLogNotRunning( - QWidget* parent, const env::Service& s, const SpawnParameters& sp) +bool eventLogNotRunning(QWidget* parent, const env::Service& s, + const SpawnParameters& sp) { - const auto title = QObject::tr("Event Log not running"); + const auto title = QObject::tr("Event Log not running"); const auto mainText = QObject::tr("The Event Log service is not running"); - const auto content = QObject::tr( - "The Windows Event Log service is not running. This can prevent USVFS from " - "running properly and your mods may not be recognized by the program being " - "launched."); + const auto content = QObject::tr( + "The Windows Event Log service is not running. This can prevent USVFS from " + "running properly and your mods may not be recognized by the program being " + "launched."); - const auto r = MOBase::TaskDialog(parent, title) - .main(mainText) - .content(content) - .details(s.toString()) - .icon(QMessageBox::Question) - .remember("eventLogService", sp.binary.fileName()) - .button({ - QObject::tr("Continue"), - QObject::tr("Your mods might not work."), - QMessageBox::Yes}) - .button({ - QObject::tr("Cancel"), - QMessageBox::Cancel}) - .exec(); + const auto r = + MOBase::TaskDialog(parent, title) + .main(mainText) + .content(content) + .details(s.toString()) + .icon(QMessageBox::Question) + .remember("eventLogService", sp.binary.fileName()) + .button({QObject::tr("Continue"), QObject::tr("Your mods might not work."), + QMessageBox::Yes}) + .button({QObject::tr("Cancel"), QMessageBox::Cancel}) + .exec(); return (r == QMessageBox::Yes); } -QMessageBox::StandardButton confirmBlacklisted( - QWidget* parent, const SpawnParameters& sp, Settings& settings) +QMessageBox::StandardButton +confirmBlacklisted(QWidget* parent, const SpawnParameters& sp, Settings& settings) { const auto title = QObject::tr("Blacklisted program"); - const auto mainText = QObject::tr("The program %1 is blacklisted") - .arg(sp.binary.fileName()); + const auto mainText = + QObject::tr("The program %1 is blacklisted").arg(sp.binary.fileName()); const auto content = QObject::tr( - "The program you are attempting to launch is blacklisted in the virtual " - "filesystem. This will likely prevent it from seeing any mods, INI files " - "or any other virtualized files."); + "The program you are attempting to launch is blacklisted in the virtual " + "filesystem. This will likely prevent it from seeing any mods, INI files " + "or any other virtualized files."); - const auto details = - "Executable: " + sp.binary.fileName() + "\n" - "Current blacklist: " + settings.executablesBlacklist(); + const auto details = "Executable: " + sp.binary.fileName() + + "\n" + "Current blacklist: " + + settings.executablesBlacklist(); auto r = MOBase::TaskDialog(parent, title) - .main(mainText) - .content(content) - .details(details) - .icon(QMessageBox::Question) - .remember("blacklistedExecutable", sp.binary.fileName()) - .button({ - QObject::tr("Continue"), - QObject::tr("Your mods might not work."), - QMessageBox::Yes}) - .button({ - QObject::tr("Change the blacklist"), - QMessageBox::Retry}) - .button({ - QObject::tr("Cancel"), - QMessageBox::Cancel}) - .exec(); + .main(mainText) + .content(content) + .details(details) + .icon(QMessageBox::Question) + .remember("blacklistedExecutable", sp.binary.fileName()) + .button({QObject::tr("Continue"), + QObject::tr("Your mods might not work."), QMessageBox::Yes}) + .button({QObject::tr("Change the blacklist"), QMessageBox::Retry}) + .button({QObject::tr("Cancel"), QMessageBox::Cancel}) + .exec(); if (r == QMessageBox::Retry) { if (!WorkaroundsSettingsTab::changeBlacklistNow(parent, settings)) { @@ -440,29 +407,26 @@ QMessageBox::StandardButton confirmBlacklisted( return r; } -} // namespace - +} // namespace spawn::dialogs namespace spawn { void logSpawning(const SpawnParameters& sp, const QString& realCmd) { - log::debug( - "spawning binary:\n" - " . exe: '{}'\n" - " . args: '{}'\n" - " . cwd: '{}'\n" - " . steam id: '{}'\n" - " . hooked: {}\n" - " . stdout: {}\n" - " . stderr: {}\n" - " . real cmd: '{}'", - sp.binary.absoluteFilePath(), sp.arguments, - sp.currentDirectory.absolutePath(), sp.steamAppID, sp.hooked, - (sp.stdOut == INVALID_HANDLE_VALUE ? "no" : "yes"), - (sp.stdErr == INVALID_HANDLE_VALUE ? "no" : "yes"), - realCmd); + log::debug("spawning binary:\n" + " . exe: '{}'\n" + " . args: '{}'\n" + " . cwd: '{}'\n" + " . steam id: '{}'\n" + " . hooked: {}\n" + " . stdout: {}\n" + " . stderr: {}\n" + " . real cmd: '{}'", + sp.binary.absoluteFilePath(), sp.arguments, + sp.currentDirectory.absolutePath(), sp.steamAppID, sp.hooked, + (sp.stdOut == INVALID_HANDLE_VALUE ? "no" : "yes"), + (sp.stdErr == INVALID_HANDLE_VALUE ? "no" : "yes"), realCmd); } DWORD spawn(const SpawnParameters& sp, HANDLE& processHandle) @@ -470,17 +434,17 @@ DWORD spawn(const SpawnParameters& sp, HANDLE& processHandle) BOOL inheritHandles = FALSE; STARTUPINFO si = {}; - si.cb = sizeof(si); + si.cb = sizeof(si); // inherit handles if we plan to use stdout or stderr reroute if (sp.stdOut != INVALID_HANDLE_VALUE) { - si.hStdOutput = sp.stdOut; + si.hStdOutput = sp.stdOut; inheritHandles = TRUE; si.dwFlags |= STARTF_USESTDHANDLES; } if (sp.stdErr != INVALID_HANDLE_VALUE) { - si.hStdError = sp.stdErr; + si.hStdError = sp.stdErr; inheritHandles = TRUE; si.dwFlags |= STARTF_USESTDHANDLES; } @@ -490,30 +454,30 @@ DWORD spawn(const SpawnParameters& sp, HANDLE& processHandle) QString commandLine = "\"" + bin + "\""; if (!sp.arguments.isEmpty()) { - commandLine += " " + sp.arguments; + commandLine += " " + sp.arguments; } const QString moPath = QCoreApplication::applicationDirPath(); - const auto oldPath = env::appendToPath(QDir::toNativeSeparators(moPath)); + const auto oldPath = env::appendToPath(QDir::toNativeSeparators(moPath)); PROCESS_INFORMATION pi = {}; - BOOL success = FALSE; + BOOL success = FALSE; logSpawning(sp, commandLine); const auto wcommandLine = commandLine.toStdWString(); - const auto wcwd = cwd.toStdWString(); + const auto wcwd = cwd.toStdWString(); const DWORD flags = CREATE_BREAKAWAY_FROM_JOB; if (sp.hooked) { - success = ::CreateProcessHooked( - nullptr, const_cast<wchar_t*>(wcommandLine.c_str()), nullptr, nullptr, - inheritHandles, flags, nullptr, wcwd.c_str(), &si, &pi); + success = ::CreateProcessHooked(nullptr, const_cast<wchar_t*>(wcommandLine.c_str()), + nullptr, nullptr, inheritHandles, flags, nullptr, + wcwd.c_str(), &si, &pi); } else { - success = ::CreateProcess( - nullptr, const_cast<wchar_t*>(wcommandLine.c_str()), nullptr, nullptr, - inheritHandles, flags, nullptr, wcwd.c_str(), &si, &pi); + success = ::CreateProcess(nullptr, const_cast<wchar_t*>(wcommandLine.c_str()), + nullptr, nullptr, inheritHandles, flags, nullptr, + wcwd.c_str(), &si, &pi); } const auto e = GetLastError(); @@ -536,12 +500,9 @@ bool restartAsAdmin(QWidget* parent) cwd[0] = L'\0'; } - if (!helper::adminLaunch( - parent, - qApp->applicationDirPath().toStdWString(), - qApp->applicationFilePath().toStdWString(), - std::wstring(cwd))) - { + if (!helper::adminLaunch(parent, qApp->applicationDirPath().toStdWString(), + qApp->applicationFilePath().toStdWString(), + std::wstring(cwd))) { log::error("admin launch failed"); return false; } @@ -565,8 +526,8 @@ void startBinaryAdmin(QWidget* parent, const SpawnParameters& sp) struct SteamStatus { - bool running=false; - bool accessible=false; + bool running = false; + bool accessible = false; }; SteamStatus getSteamStatus() @@ -577,14 +538,12 @@ SteamStatus getSteamStatus() for (const auto& p : ps) { if ((p.name().compare("Steam.exe", Qt::CaseInsensitive) == 0) || - (p.name().compare("SteamService.exe", Qt::CaseInsensitive) == 0)) - { - ss.running = true; + (p.name().compare("SteamService.exe", Qt::CaseInsensitive) == 0)) { + ss.running = true; ss.accessible = p.canAccess(); - log::debug( - "'{}' is running, accessible={}", - p.name(), (ss.accessible ? "yes" : "no")); + log::debug("'{}' is running, accessible={}", p.name(), + (ss.accessible ? "yes" : "no")); break; } @@ -610,7 +569,7 @@ QString makeSteamArguments(const QString& username, const QString& password) bool startSteam(QWidget* parent) { - const QString keyName = "HKEY_CURRENT_USER\\Software\\Valve\\Steam"; + const QString keyName = "HKEY_CURRENT_USER\\Software\\Valve\\Steam"; const QString valueName = "SteamExe"; const QSettings steamSettings(keyName, QSettings::NativeFormat); @@ -627,50 +586,45 @@ bool startSteam(QWidget* parent) QString username, password; if (Settings::instance().steam().login(username, password)) { if (username.length() > 0) - MOBase::log::getDefault().addToBlacklist(username.toStdString(), "STEAM_USERNAME"); + MOBase::log::getDefault().addToBlacklist(username.toStdString(), + "STEAM_USERNAME"); if (password.length() > 0) - MOBase::log::getDefault().addToBlacklist(password.toStdString(), "STEAM_PASSWORD"); + MOBase::log::getDefault().addToBlacklist(password.toStdString(), + "STEAM_PASSWORD"); sp.arguments = makeSteamArguments(username, password); } - log::debug( - "starting steam process:\n" - " . program: '{}'\n" - " . username={}, password={}", - sp.binary.filePath().toStdString(), - (username.isEmpty() ? "no" : "yes"), - (password.isEmpty() ? "no" : "yes")); + log::debug("starting steam process:\n" + " . program: '{}'\n" + " . username={}, password={}", + sp.binary.filePath().toStdString(), (username.isEmpty() ? "no" : "yes"), + (password.isEmpty() ? "no" : "yes")); - HANDLE ph = INVALID_HANDLE_VALUE; + HANDLE ph = INVALID_HANDLE_VALUE; const auto e = spawn(sp, ph); ::CloseHandle(ph); if (e != ERROR_SUCCESS) { // make sure username and passwords are not shown - sp.arguments = makeSteamArguments( - (username.isEmpty() ? "" : "USERNAME"), - (password.isEmpty() ? "" : "PASSWORD")); + sp.arguments = makeSteamArguments((username.isEmpty() ? "" : "USERNAME"), + (password.isEmpty() ? "" : "PASSWORD")); - const auto r = dialogs::startSteamFailed( - parent, keyName, valueName, exe, sp, e); + const auto r = dialogs::startSteamFailed(parent, keyName, valueName, exe, sp, e); return (r == QMessageBox::Yes); } QMessageBox::information( - parent, QObject::tr("Waiting"), - QObject::tr("Please press OK once you're logged into steam.")); + parent, QObject::tr("Waiting"), + QObject::tr("Please press OK once you're logged into steam.")); return true; } -bool checkSteam( - QWidget* parent, const SpawnParameters& sp, - const QDir& gameDirectory, const QString &steamAppID, const Settings& settings) +bool checkSteam(QWidget* parent, const SpawnParameters& sp, const QDir& gameDirectory, + const QString& steamAppID, const Settings& settings) { - static const std::vector<QString> steamFiles = { - "steam_api.dll", "steam_api64.dll" - }; + static const std::vector<QString> steamFiles = {"steam_api.dll", "steam_api64.dll"}; log::debug("checking steam"); @@ -680,17 +634,15 @@ bool checkSteam( env::set("SteamAPPId", settings.steam().appID()); } - bool steamRequired = false; QString details; for (const auto& file : steamFiles) { const QFileInfo fi(gameDirectory.absoluteFilePath(file)); if (fi.exists()) { - details = QString( - "managed game is located at '%1' and file '%2' exists") - .arg(gameDirectory.absolutePath()) - .arg(fi.absoluteFilePath()); + details = QString("managed game is located at '%1' and file '%2' exists") + .arg(gameDirectory.absolutePath()) + .arg(fi.absoluteFilePath()); log::debug("{}", details); steamRequired = true; @@ -704,7 +656,6 @@ bool checkSteam( return true; } - auto ss = getSteamStatus(); if (!ss.running) { @@ -754,8 +705,7 @@ bool checkSteam( return true; } -bool checkBlacklist( - QWidget* parent, const SpawnParameters& sp, Settings& settings) +bool checkBlacklist(QWidget* parent, const SpawnParameters& sp, Settings& settings) { for (;;) { if (!settings.isExecutableBlacklisted(sp.binary.fileName())) { @@ -773,26 +723,22 @@ bool checkBlacklist( HANDLE startBinary(QWidget* parent, const SpawnParameters& sp) { HANDLE handle = INVALID_HANDLE_VALUE; - const auto e = spawn::spawn(sp, handle); + const auto e = spawn::spawn(sp, handle); - switch (e) - { - case ERROR_SUCCESS: - { - return handle; - } + switch (e) { + case ERROR_SUCCESS: { + return handle; + } - case ERROR_ELEVATION_REQUIRED: - { - startBinaryAdmin(parent, sp); - return INVALID_HANDLE_VALUE; - } + case ERROR_ELEVATION_REQUIRED: { + startBinaryAdmin(parent, sp); + return INVALID_HANDLE_VALUE; + } - default: - { - dialogs::spawnFailed(parent, sp, e); - return INVALID_HANDLE_VALUE; - } + default: { + dialogs::spawnFailed(parent, sp, e); + return INVALID_HANDLE_VALUE; + } } } @@ -803,13 +749,12 @@ QString getExecutableForJarFile(const QString& jarFile) WCHAR buffer[MAX_PATH]; const auto hinst = ::FindExecutableW(jarFileW.c_str(), nullptr, buffer); - const auto r = static_cast<int>(reinterpret_cast<std::uintptr_t>(hinst)); + const auto r = static_cast<int>(reinterpret_cast<std::uintptr_t>(hinst)); // anything <= 32 signals failure if (r <= 32) { - log::warn( - "failed to find executable associated with file '{}', {}", - jarFile, shell::formatError(r)); + log::warn("failed to find executable associated with file '{}', {}", jarFile, + shell::formatError(r)); return {}; } @@ -819,17 +764,15 @@ QString getExecutableForJarFile(const QString& jarFile) if (!::GetBinaryTypeW(buffer, &binaryType)) { const auto e = ::GetLastError(); - log::warn( - "failed to determine binary type of '{}', {}", - QString::fromWCharArray(buffer), formatSystemMessage(e)); + log::warn("failed to determine binary type of '{}', {}", + QString::fromWCharArray(buffer), formatSystemMessage(e)); return {}; } if (binaryType != SCS_32BIT_BINARY && binaryType != SCS_64BIT_BINARY) { - log::warn( - "unexpected binary type {} for file '{}'", - binaryType, QString::fromWCharArray(buffer)); + log::warn("unexpected binary type {} for file '{}'", binaryType, + QString::fromWCharArray(buffer)); return {}; } @@ -839,7 +782,8 @@ QString getExecutableForJarFile(const QString& jarFile) QString getJavaHome() { - const QString key = "HKEY_LOCAL_MACHINE\\Software\\JavaSoft\\Java Runtime Environment"; + const QString key = + "HKEY_LOCAL_MACHINE\\Software\\JavaSoft\\Java Runtime Environment"; const QString value = "CurrentVersion"; QSettings reg(key, QSettings::NativeFormat); @@ -850,12 +794,11 @@ QString getJavaHome() } const QString currentVersion = reg.value("CurrentVersion").toString(); - const QString javaHome = QString("%1/JavaHome").arg(currentVersion); + const QString javaHome = QString("%1/JavaHome").arg(currentVersion); if (!reg.contains(javaHome)) { - log::warn( - "java version '{}' was found at '{}\\{}', but '{}\\{}' doesn't exist", - currentVersion, key, value, key, javaHome); + log::warn("java version '{}' was found at '{}\\{}', but '{}\\{}' doesn't exist", + currentVersion, key, value, key, javaHome); return {}; } @@ -917,7 +860,7 @@ QFileInfo getCmdPath() QString systemDirectory; - const std::size_t buffer_size = 1000; + const std::size_t buffer_size = 1000; wchar_t buffer[buffer_size + 1] = {}; const auto length = ::GetSystemDirectoryW(buffer, buffer_size); @@ -943,56 +886,46 @@ FileExecutionTypes getFileExecutionType(const QFileInfo& target) return FileExecutionTypes::Other; } -FileExecutionContext getFileExecutionContext( - QWidget* parent, const QFileInfo& target) +FileExecutionContext getFileExecutionContext(QWidget* parent, const QFileInfo& target) { if (isExeFile(target)) { - return { - target, - "", - FileExecutionTypes::Executable - }; + return {target, "", FileExecutionTypes::Executable}; } if (isBatchFile(target)) { return { - getCmdPath(), - QString("/C \"%1\"").arg(QDir::toNativeSeparators(target.absoluteFilePath())), - FileExecutionTypes::Executable - }; + getCmdPath(), + QString("/C \"%1\"").arg(QDir::toNativeSeparators(target.absoluteFilePath())), + FileExecutionTypes::Executable}; } if (isJavaFile(target)) { auto java = findJavaInstallation(target.absoluteFilePath()); if (java.isEmpty()) { - java = QFileDialog::getOpenFileName( - parent, QObject::tr("Select binary"), - QString(), QObject::tr("Binary") + " (*.exe)"); + java = + QFileDialog::getOpenFileName(parent, QObject::tr("Select binary"), QString(), + QObject::tr("Binary") + " (*.exe)"); } if (!java.isEmpty()) { - return { - QFileInfo(java), - QString("-jar \"%1\"").arg(QDir::toNativeSeparators(target.absoluteFilePath())), - FileExecutionTypes::Executable - }; + return {QFileInfo(java), + QString("-jar \"%1\"") + .arg(QDir::toNativeSeparators(target.absoluteFilePath())), + FileExecutionTypes::Executable}; } } return {{}, {}, FileExecutionTypes::Other}; } -} // namespace - - +} // namespace spawn namespace helper { -bool helperExec( - QWidget* parent, - const std::wstring& moDirectory, const std::wstring& commandLine, BOOL async) +bool helperExec(QWidget* parent, const std::wstring& moDirectory, + const std::wstring& commandLine, BOOL async) { const std::wstring fileName = moDirectory + L"\\helper.exe"; @@ -1005,20 +938,20 @@ bool helperExec( if (!async) flags |= SEE_MASK_NOCLOSEPROCESS; - execInfo.cbSize = sizeof(SHELLEXECUTEINFOW); - execInfo.fMask = flags; - execInfo.hwnd = 0; - execInfo.lpVerb = L"runas"; - execInfo.lpFile = fileName.c_str(); + execInfo.cbSize = sizeof(SHELLEXECUTEINFOW); + execInfo.fMask = flags; + execInfo.hwnd = 0; + execInfo.lpVerb = L"runas"; + execInfo.lpFile = fileName.c_str(); execInfo.lpParameters = commandLine.c_str(); - execInfo.lpDirectory = moDirectory.c_str(); - execInfo.nShow = SW_SHOW; + execInfo.lpDirectory = moDirectory.c_str(); + execInfo.nShow = SW_SHOW; if (!::ShellExecuteExW(&execInfo) && execInfo.hProcess == 0) { const auto e = GetLastError(); - spawn::dialogs::helperFailed( - parent, e, "ShellExecuteExW()", fileName, moDirectory, commandLine); + spawn::dialogs::helperFailed(parent, e, "ShellExecuteExW()", fileName, + moDirectory, commandLine); return false; } @@ -1036,12 +969,10 @@ bool helperExec( // for WAIT_ABANDONED, the documentation doesn't mention that GetLastError() // returns something meaningful, but code ERROR_ABANDONED_WAIT_0 exists, so // use that instead - const auto code = (r == WAIT_ABANDONED ? - ERROR_ABANDONED_WAIT_0 : GetLastError()); + const auto code = (r == WAIT_ABANDONED ? ERROR_ABANDONED_WAIT_0 : GetLastError()); - spawn::dialogs::helperFailed( - parent, code, "WaitForSingleObject()", - fileName, moDirectory, commandLine); + spawn::dialogs::helperFailed(parent, code, "WaitForSingleObject()", fileName, + moDirectory, commandLine); return false; } @@ -1050,8 +981,8 @@ bool helperExec( if (!GetExitCodeProcess(process.get(), &exitCode)) { const auto e = GetLastError(); - spawn::dialogs::helperFailed( - parent, e, "GetExitCodeProcess()", fileName, moDirectory, commandLine); + spawn::dialogs::helperFailed(parent, e, "GetExitCodeProcess()", fileName, + moDirectory, commandLine); return false; } @@ -1059,24 +990,21 @@ bool helperExec( return (exitCode == 0); } -bool backdateBSAs( - QWidget* parent, const std::wstring &moPath, const std::wstring &dataPath) +bool backdateBSAs(QWidget* parent, const std::wstring& moPath, + const std::wstring& dataPath) { - const std::wstring commandLine = fmt::format( - L"backdateBSA \"{}\"", dataPath); + const std::wstring commandLine = fmt::format(L"backdateBSA \"{}\"", dataPath); return helperExec(parent, moPath, commandLine, FALSE); } -bool adminLaunch( - QWidget* parent, const std::wstring &moPath, - const std::wstring &moFile, const std::wstring &workingDir) +bool adminLaunch(QWidget* parent, const std::wstring& moPath, + const std::wstring& moFile, const std::wstring& workingDir) { const std::wstring commandLine = fmt::format( - L"adminLaunch {} \"{}\" \"{}\"", - ::GetCurrentProcessId(), moFile, workingDir); + L"adminLaunch {} \"{}\" \"{}\"", ::GetCurrentProcessId(), moFile, workingDir); return helperExec(parent, moPath, commandLine, true); } -} // namespace +} // namespace helper diff --git a/src/spawn.h b/src/spawn.h index 44f690b0..7bca84c9 100644 --- a/src/spawn.h +++ b/src/spawn.h @@ -21,10 +21,10 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #define SPAWN_H #define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <tchar.h> -#include <QFileInfo> #include <QDir> +#include <QFileInfo> +#include <tchar.h> +#include <windows.h> class Settings; @@ -38,27 +38,26 @@ namespace spawn * @param currentDirectory the directory to use as the working directory to run in * @param logLevel log level to be used by the hook library. Ignored if hooked is false * @param hooked if set, the binary is started with mo injected - * @param stdout if not equal to INVALID_HANDLE_VALUE, this is used as stdout for the process - * @param stderr if not equal to INVALID_HANDLE_VALUE, this is used as stderr for the process -*/ + * @param stdout if not equal to INVALID_HANDLE_VALUE, this is used as stdout for the + * process + * @param stderr if not equal to INVALID_HANDLE_VALUE, this is used as stderr for the + * process + */ struct SpawnParameters { QFileInfo binary; QString arguments; QDir currentDirectory; QString steamAppID; - bool hooked = false; + bool hooked = false; HANDLE stdOut = INVALID_HANDLE_VALUE; HANDLE stdErr = INVALID_HANDLE_VALUE; }; +bool checkSteam(QWidget* parent, const SpawnParameters& sp, const QDir& gameDirectory, + const QString& steamAppID, const Settings& settings); -bool checkSteam( - QWidget* parent, const SpawnParameters& sp, - const QDir& gameDirectory, const QString &steamAppID, const Settings& settings); - -bool checkBlacklist( - QWidget* parent, const SpawnParameters& sp, Settings& settings); +bool checkBlacklist(QWidget* parent, const SpawnParameters& sp, Settings& settings); /** * @brief spawn a binary with Mod Organizer injected @@ -66,7 +65,6 @@ bool checkBlacklist( **/ HANDLE startBinary(QWidget* parent, const SpawnParameters& sp); - enum class FileExecutionTypes { Executable = 1, @@ -82,13 +80,11 @@ struct FileExecutionContext QString findJavaInstallation(const QString& jarFile); -FileExecutionContext getFileExecutionContext( - QWidget* parent, const QFileInfo& target); +FileExecutionContext getFileExecutionContext(QWidget* parent, const QFileInfo& target); FileExecutionTypes getFileExecutionType(const QFileInfo& target); -} // namespace - +} // namespace spawn // convenience functions to work with the external helper program, which is used // to make changes on the system that require administrative rights, so that @@ -98,24 +94,24 @@ namespace helper { /** -* @brief sets the last modified time for all .bsa-files in the target directory well into the past -* @param moPath absolute path to the modOrganizer base directory -* @param dataPath the path taht contains the .bsa-files, usually the data directory of the game -**/ -bool backdateBSAs( - QWidget* parent, const std::wstring &moPath, const std::wstring &dataPath); + * @brief sets the last modified time for all .bsa-files in the target directory well + *into the past + * @param moPath absolute path to the modOrganizer base directory + * @param dataPath the path taht contains the .bsa-files, usually the data directory of + *the game + **/ +bool backdateBSAs(QWidget* parent, const std::wstring& moPath, + const std::wstring& dataPath); /** -* @brief waits for the current process to exit and restarts it as an administrator -* @param moPath absolute path to the modOrganizer base directory -* @param moFile file name of modOrganizer -* @param workingDir current working directory -**/ -bool adminLaunch( - QWidget* parent, const std::wstring &moPath, - const std::wstring &moFile, const std::wstring &workingDir); - -} // namespace + * @brief waits for the current process to exit and restarts it as an administrator + * @param moPath absolute path to the modOrganizer base directory + * @param moFile file name of modOrganizer + * @param workingDir current working directory + **/ +bool adminLaunch(QWidget* parent, const std::wstring& moPath, + const std::wstring& moFile, const std::wstring& workingDir); -#endif // SPAWN_H +} // namespace helper +#endif // SPAWN_H diff --git a/src/statusbar.cpp b/src/statusbar.cpp index 094aa743..3b26dd91 100644 --- a/src/statusbar.cpp +++ b/src/statusbar.cpp @@ -1,23 +1,22 @@ #include "statusbar.h" +#include "instancemanager.h" #include "nexusinterface.h" -#include "settings.h" #include "organizercore.h" -#include "instancemanager.h" +#include "settings.h" #include "ui_mainwindow.h" -StatusBar::StatusBar(QWidget* parent) : - QStatusBar(parent), ui(nullptr), m_normal(new QLabel), - m_progress(new QProgressBar), m_progressSpacer1(new QWidget), - m_progressSpacer2(new QWidget), m_notifications(nullptr), m_update(nullptr), - m_api(new QLabel) -{ -} +StatusBar::StatusBar(QWidget* parent) + : QStatusBar(parent), ui(nullptr), m_normal(new QLabel), + m_progress(new QProgressBar), m_progressSpacer1(new QWidget), + m_progressSpacer2(new QWidget), m_notifications(nullptr), m_update(nullptr), + m_api(new QLabel) +{} void StatusBar::setup(Ui::MainWindow* mainWindowUI, const Settings& settings) { - ui = mainWindowUI; + ui = mainWindowUI; m_notifications = new StatusBarAction(ui->actionNotifications); - m_update = new StatusBarAction(ui->actionUpdate); + m_update = new StatusBarAction(ui->actionUpdate); addWidget(m_normal); @@ -26,13 +25,12 @@ void StatusBar::setup(Ui::MainWindow* mainWindowUI, const Settings& settings) addPermanentWidget(m_progress); m_progressSpacer2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - addPermanentWidget(m_progressSpacer2,0); + addPermanentWidget(m_progressSpacer2, 0); addPermanentWidget(m_notifications); addPermanentWidget(m_update); addPermanentWidget(m_api); - m_progress->setTextVisible(true); m_progress->setRange(0, 100); m_progress->setMaximumWidth(300); @@ -43,12 +41,12 @@ void StatusBar::setup(Ui::MainWindow* mainWindowUI, const Settings& settings) m_api->setObjectName("apistats"); m_api->setToolTip(QObject::tr( - "This tracks the number of queued Nexus API requests, as well as the " - "remaining daily and hourly requests. The Nexus API limits you to a pool " - "of requests per day and requests per hour. It is dynamically updated " - "every time a request is completed. If you run out of requests, you will " - "be unable to queue downloads, check updates, parse mod info, or even log " - "in. Both pools must be consumed before this happens.")); + "This tracks the number of queued Nexus API requests, as well as the " + "remaining daily and hourly requests. The Nexus API limits you to a pool " + "of requests per day and requests per hour. It is dynamically updated " + "every time a request is completed. If you run out of requests, you will " + "be unable to queue downloads, check updates, parse mod info, or even log " + "in. Both pools must be consumed before this happens.")); clearMessage(); setProgress(-1); @@ -59,7 +57,7 @@ void StatusBar::setup(Ui::MainWindow* mainWindowUI, const Settings& settings) void StatusBar::setProgress(int percent) { - bool visible =true; + bool visible = true; if (percent < 0 || percent >= 100) { clearMessage(); @@ -88,23 +86,23 @@ void StatusBar::setAPI(const APIStats& stats, const APIUserAccount& user) QString backgroundColor; if (user.type() == APIUserAccountTypes::None) { - text = "API: not logged in"; - textColor = ""; + text = "API: not logged in"; + textColor = ""; backgroundColor = ""; } else { text = QString("API: Queued: %1 | Daily: %2 | Hourly: %3") - .arg(stats.requestsQueued) - .arg(user.limits().remainingDailyRequests) - .arg(user.limits().remainingHourlyRequests); + .arg(stats.requestsQueued) + .arg(user.limits().remainingDailyRequests) + .arg(user.limits().remainingHourlyRequests); if (user.remainingRequests() > 500) { - textColor = "white"; + textColor = "white"; backgroundColor = "darkgreen"; } else if (user.remainingRequests() > 200) { - textColor = "black"; + textColor = "black"; backgroundColor = "rgb(226, 192, 0)"; // yellow } else { - textColor = "white"; + textColor = "white"; backgroundColor = "darkred"; } } @@ -154,15 +152,12 @@ void StatusBar::updateNormalMessage(OrganizerCore& core) } QString instance = "?"; - if (auto i=InstanceManager::singleton().currentInstance()) + if (auto i = InstanceManager::singleton().currentInstance()) instance = i->displayName(); QString profile = core.profileName(); - const auto s = QString("%1 - %2 - %3") - .arg(game) - .arg(instance) - .arg(profile); + const auto s = QString("%1 - %2 - %3").arg(game).arg(instance).arg(profile); m_normal->setText(s); } @@ -198,9 +193,8 @@ void StatusBar::visibilityChanged(bool visible) ui->centralWidget->layout()->setContentsMargins(m); } - StatusBarAction::StatusBarAction(QAction* action) - : m_action(action), m_icon(new QLabel), m_text(new QLabel) + : m_action(action), m_icon(new QLabel), m_text(new QLabel) { setLayout(new QHBoxLayout); layout()->setContentsMargins(0, 0, 0, 0); @@ -230,7 +224,7 @@ QString StatusBarAction::cleanupActionText(const QString& original) const QString s = original; s.replace(QRegularExpression("\\&([^&])"), "\\1"); // &Item -> Item - s.replace("&&", "&"); // &&Item -> &Item + s.replace("&&", "&"); // &&Item -> &Item if (s.endsWith("...")) { s = s.left(s.size() - 3); diff --git a/src/statusbar.h b/src/statusbar.h index 6e033cbd..9e3bf3b0 100644 --- a/src/statusbar.h +++ b/src/statusbar.h @@ -1,16 +1,18 @@ #ifndef MO_STATUSBAR_H #define MO_STATUSBAR_H -#include <QStatusBar> #include <QProgressBar> +#include <QStatusBar> struct APIStats; class APIUserAccount; class Settings; class OrganizerCore; -namespace Ui { class MainWindow; } - +namespace Ui +{ +class MainWindow; +} class StatusBarAction : public QWidget { @@ -30,13 +32,12 @@ private: QString cleanupActionText(const QString& s) const; }; - class StatusBar : public QStatusBar { Q_OBJECT; public: - StatusBar(QWidget* parent=nullptr); + StatusBar(QWidget* parent = nullptr); void setup(Ui::MainWindow* ui, const Settings& settings); @@ -64,4 +65,4 @@ private: void visibilityChanged(bool visible); }; -#endif // MO_STATUSBAR_H +#endif // MO_STATUSBAR_H diff --git a/src/syncoverwritedialog.cpp b/src/syncoverwritedialog.cpp index 1966463b..d3e2905c 100644 --- a/src/syncoverwritedialog.cpp +++ b/src/syncoverwritedialog.cpp @@ -23,29 +23,29 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "shared/filesorigin.h" #include "ui_syncoverwritedialog.h" -#include <utility.h> -#include <report.h> #include <log.h> +#include <report.h> +#include <utility.h> +#include <QComboBox> #include <QDir> #include <QDirIterator> -#include <QComboBox> #include <QStringList> - using namespace MOBase; using namespace MOShared; - -SyncOverwriteDialog::SyncOverwriteDialog(const QString &path, DirectoryEntry *directoryStructure, QWidget *parent) - : TutorableDialog("SyncOverwrite", parent), - ui(new Ui::SyncOverwriteDialog), m_SourcePath(path), m_DirectoryStructure(directoryStructure) +SyncOverwriteDialog::SyncOverwriteDialog(const QString& path, + DirectoryEntry* directoryStructure, + QWidget* parent) + : TutorableDialog("SyncOverwrite", parent), ui(new Ui::SyncOverwriteDialog), + m_SourcePath(path), m_DirectoryStructure(directoryStructure) { ui->setupUi(this); refresh(path); - QHeaderView *headerView = ui->syncTree->header(); -#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) + QHeaderView* headerView = ui->syncTree->header(); +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) headerView->setSectionResizeMode(0, QHeaderView::Stretch); headerView->setSectionResizeMode(1, QHeaderView::Interactive); #else @@ -54,22 +54,21 @@ SyncOverwriteDialog::SyncOverwriteDialog(const QString &path, DirectoryEntry *di #endif } - SyncOverwriteDialog::~SyncOverwriteDialog() { delete ui; } - -static void addToComboBox(QComboBox *box, const QString &name, const QVariant &userData) +static void addToComboBox(QComboBox* box, const QString& name, const QVariant& userData) { if (QString::compare(name, "overwrite", Qt::CaseInsensitive) != 0) { box->addItem(name, userData); } } - -void SyncOverwriteDialog::readTree(const QString &path, DirectoryEntry *directoryStructure, QTreeWidgetItem *subTree) +void SyncOverwriteDialog::readTree(const QString& path, + DirectoryEntry* directoryStructure, + QTreeWidgetItem* subTree) { QDir overwrite(path); overwrite.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); @@ -83,10 +82,10 @@ void SyncOverwriteDialog::readTree(const QString &path, DirectoryEntry *director continue; } - QTreeWidgetItem *newItem = new QTreeWidgetItem(subTree, QStringList(file)); + QTreeWidgetItem* newItem = new QTreeWidgetItem(subTree, QStringList(file)); if (fileInfo.isDir()) { - DirectoryEntry *subDir = directoryStructure->findSubDirectory(ToWString(file)); + DirectoryEntry* subDir = directoryStructure->findSubDirectory(ToWString(file)); if (subDir != nullptr) { readTree(fileInfo.absoluteFilePath(), subDir, newItem); } else { @@ -96,15 +95,20 @@ void SyncOverwriteDialog::readTree(const QString &path, DirectoryEntry *director } } else { const FileEntryPtr entry = directoryStructure->findFile(ToWString(file)); - QComboBox* combo = new QComboBox(ui->syncTree); + QComboBox* combo = new QComboBox(ui->syncTree); combo->addItem(tr("<don't sync>"), -1); if (entry.get() != nullptr) { bool ignore; int origin = entry->getOrigin(ignore); - addToComboBox(combo, ToQString(m_DirectoryStructure->getOriginByID(origin).getName()), origin); - const auto &alternatives = entry->getAlternatives(); + addToComboBox(combo, + ToQString(m_DirectoryStructure->getOriginByID(origin).getName()), + origin); + const auto& alternatives = entry->getAlternatives(); for (const auto& alt : alternatives) { - addToComboBox(combo, ToQString(m_DirectoryStructure->getOriginByID(alt.originID()).getName()), alt.originID()); + addToComboBox( + combo, + ToQString(m_DirectoryStructure->getOriginByID(alt.originID()).getName()), + alt.originID()); } combo->setCurrentIndex(combo->count() - 1); } else { @@ -118,20 +122,19 @@ void SyncOverwriteDialog::readTree(const QString &path, DirectoryEntry *director } } - -void SyncOverwriteDialog::refresh(const QString &path) +void SyncOverwriteDialog::refresh(const QString& path) { - QTreeWidgetItem *rootItem = new QTreeWidgetItem(ui->syncTree, QStringList("<data>")); + QTreeWidgetItem* rootItem = new QTreeWidgetItem(ui->syncTree, QStringList("<data>")); readTree(path, m_DirectoryStructure, rootItem); ui->syncTree->addTopLevelItem(rootItem); ui->syncTree->expandAll(); } - -void SyncOverwriteDialog::applyTo(QTreeWidgetItem *item, const QString &path, const QString &modDirectory) +void SyncOverwriteDialog::applyTo(QTreeWidgetItem* item, const QString& path, + const QString& modDirectory) { for (int i = 0; i < item->childCount(); ++i) { - QTreeWidgetItem *child = item->child(i); + QTreeWidgetItem* child = item->child(i); QString filePath; if (path.length() != 0) { filePath = path + "/" + child->text(0); @@ -141,13 +144,16 @@ void SyncOverwriteDialog::applyTo(QTreeWidgetItem *item, const QString &path, co if (child->childCount() != 0) { applyTo(child, filePath, modDirectory); } else { - QComboBox *comboBox = qobject_cast<QComboBox*>(ui->syncTree->itemWidget(child, 1)); + QComboBox* comboBox = + qobject_cast<QComboBox*>(ui->syncTree->itemWidget(child, 1)); if (comboBox != nullptr) { - int originID = comboBox->itemData(comboBox->currentIndex(), Qt::UserRole).toInt(); + int originID = + comboBox->itemData(comboBox->currentIndex(), Qt::UserRole).toInt(); if (originID != -1) { - FilesOrigin &origin = m_DirectoryStructure->getOriginByID(originID); - QString source = m_SourcePath + "/" + filePath; - QString destination = modDirectory + "/" + ToQString(origin.getName()) + "/" + filePath; + FilesOrigin& origin = m_DirectoryStructure->getOriginByID(originID); + QString source = m_SourcePath + "/" + filePath; + QString destination = + modDirectory + "/" + ToQString(origin.getName()) + "/" + filePath; if (!QFile::remove(destination)) { reportError(tr("failed to remove %1").arg(destination)); } else if (!QFile::rename(source, destination)) { @@ -164,8 +170,7 @@ void SyncOverwriteDialog::applyTo(QTreeWidgetItem *item, const QString &path, co } } - -void SyncOverwriteDialog::apply(const QString &modDirectory) +void SyncOverwriteDialog::apply(const QString& modDirectory) { applyTo(ui->syncTree->topLevelItem(0), "", modDirectory); } diff --git a/src/syncoverwritedialog.h b/src/syncoverwritedialog.h index e05c2072..f3d1ae8e 100644 --- a/src/syncoverwritedialog.h +++ b/src/syncoverwritedialog.h @@ -20,11 +20,12 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef SYNCOVERWRITEDIALOG_H #define SYNCOVERWRITEDIALOG_H -#include "tutorabledialog.h" #include "shared/fileregisterfwd.h" +#include "tutorabledialog.h" #include <QTreeWidgetItem> -namespace Ui { +namespace Ui +{ class SyncOverwriteDialog; } @@ -33,24 +34,24 @@ class SyncOverwriteDialog : public MOBase::TutorableDialog Q_OBJECT public: - explicit SyncOverwriteDialog( - const QString &path, MOShared::DirectoryEntry *directoryStructure, - QWidget *parent = 0); + explicit SyncOverwriteDialog(const QString& path, + MOShared::DirectoryEntry* directoryStructure, + QWidget* parent = 0); ~SyncOverwriteDialog(); - void apply(const QString &modDirectory); -private: - void refresh(const QString &path); - void readTree(const QString &path, MOShared::DirectoryEntry *directoryStructure, QTreeWidgetItem *subTree); - void applyTo(QTreeWidgetItem *item, const QString &path, const QString &modDirectory); + void apply(const QString& modDirectory); private: + void refresh(const QString& path); + void readTree(const QString& path, MOShared::DirectoryEntry* directoryStructure, + QTreeWidgetItem* subTree); + void applyTo(QTreeWidgetItem* item, const QString& path, const QString& modDirectory); - Ui::SyncOverwriteDialog *ui; +private: + Ui::SyncOverwriteDialog* ui; QString m_SourcePath; - MOShared::DirectoryEntry *m_DirectoryStructure; - + MOShared::DirectoryEntry* m_DirectoryStructure; }; -#endif // SYNCOVERWRITEDIALOG_H +#endif // SYNCOVERWRITEDIALOG_H diff --git a/src/texteditor.cpp b/src/texteditor.cpp index 7f62a6ef..281a545d 100644 --- a/src/texteditor.cpp +++ b/src/texteditor.cpp @@ -1,16 +1,15 @@ #include "texteditor.h" #include "utility.h" -#include <log.h> #include <QSplitter> +#include <log.h> using namespace MOBase; -TextEditor::TextEditor(QWidget* parent) : - QPlainTextEdit(parent), - m_toolbar(nullptr), m_lineNumbers(nullptr), m_highlighter(nullptr), - m_dirty(false), m_loading(false) +TextEditor::TextEditor(QWidget* parent) + : QPlainTextEdit(parent), m_toolbar(nullptr), m_lineNumbers(nullptr), + m_highlighter(nullptr), m_dirty(false), m_loading(false) { - m_toolbar = new TextEditorToolbar(*this); + m_toolbar = new TextEditorToolbar(*this); m_lineNumbers = new TextEditorLineNumbers(*this); m_highlighter = new TextEditorHighlighter(document()); @@ -19,13 +18,13 @@ TextEditor::TextEditor(QWidget* parent) : emit modified(false); - connect( - document(), &QTextDocument::modificationChanged, - [&](bool b){ onModified(b); }); + connect(document(), &QTextDocument::modificationChanged, [&](bool b) { + onModified(b); + }); - connect( - this, &QPlainTextEdit::cursorPositionChanged, - [&]{ highlightCurrentLine(); }); + connect(this, &QPlainTextEdit::cursorPositionChanged, [&] { + highlightCurrentLine(); + }); } void TextEditor::setDefaultStyle() @@ -42,12 +41,12 @@ void TextEditor::setDefaultStyle() { auto w = std::make_unique<QWidget>(); - if (auto* s=style()) { + if (auto* s = style()) { s->polish(w.get()); } - textColor = w->palette().color(QPalette::WindowText); - altTextColor = w->palette().color(QPalette::Disabled, QPalette::WindowText); + textColor = w->palette().color(QPalette::WindowText); + altTextColor = w->palette().color(QPalette::Disabled, QPalette::WindowText); backgroundColor = w->palette().color(QPalette::Window); } @@ -170,10 +169,10 @@ void TextEditor::setBackgroundColor(const QColor& c) m_highlighter->setBackgroundColor(c); setStyleSheet(QString("QPlainTextEdit{ background-color: rgba(%1, %2, %3, %4); }") - .arg(c.redF() * 255) - .arg(c.greenF() * 255) - .arg(c.blueF() * 255) - .arg(c.alphaF())); + .arg(c.redF() * 255) + .arg(c.greenF() * 255) + .arg(c.blueF() * 255) + .arg(c.alphaF())); } QColor TextEditor::textColor() const @@ -245,20 +244,19 @@ QWidget* TextEditor::wrapEditWidget() // wrapping the QPlainTextEdit into a new widget so the toolbar can be // displayed above it - if (auto* parentLayout=parentWidget()->layout()) { + if (auto* parentLayout = parentWidget()->layout()) { // the edit's parent has a regular layout, replace the edit by the new // widget and delete the QLayoutItem that's returned as it's not needed delete parentLayout->replaceWidget(this, widget.get()); - } else if (auto* splitter=qobject_cast<QSplitter*>(parentWidget())) { + } else if (auto* splitter = qobject_cast<QSplitter*>(parentWidget())) { // the edit's parent is a QSplitter, which doesn't have a layout; replace // the edit by using its index in the splitter auto index = splitter->indexOf(this); if (index == -1) { - log::error( - "TextEditor: cannot wrap edit widget to display a toolbar, " - "parent is a splitter, but widget isn't in it"); + log::error("TextEditor: cannot wrap edit widget to display a toolbar, " + "parent is a splitter, but widget isn't in it"); return nullptr; } @@ -267,9 +265,8 @@ QWidget* TextEditor::wrapEditWidget() } else { // unknown parent - log::error( - "TextEditor: cannot wrap edit widget to display a toolbar, " - "no parent or parent has no layout"); + log::error("TextEditor: cannot wrap edit widget to display a toolbar, " + "no parent or parent has no layout"); return nullptr; } @@ -282,7 +279,8 @@ void TextEditor::resizeEvent(QResizeEvent* e) QPlainTextEdit::resizeEvent(e); QRect cr = contentsRect(); - m_lineNumbers->setGeometry(QRect(cr.left(), cr.top(), m_lineNumbers->areaWidth(), cr.height())); + m_lineNumbers->setGeometry( + QRect(cr.left(), cr.top(), m_lineNumbers->areaWidth(), cr.height())); } void TextEditor::paintLineNumbers(QPaintEvent* e, const QColor& textColor) @@ -293,23 +291,22 @@ void TextEditor::paintLineNumbers(QPaintEvent* e, const QColor& textColor) QPainter painter(m_lineNumbers); QTextBlock block = firstVisibleBlock(); - int blockNumber = block.blockNumber(); - int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top(); - int bottom = top + (int) blockBoundingRect(block).height(); + int blockNumber = block.blockNumber(); + int top = (int)blockBoundingGeometry(block).translated(contentOffset()).top(); + int bottom = top + (int)blockBoundingRect(block).height(); while (block.isValid() && top <= e->rect().bottom()) { if (block.isVisible() && bottom >= e->rect().top()) { QString number = QString::number(blockNumber + 1); painter.setPen(textColor); - painter.drawText( - 0, top, m_lineNumbers->width() - 3, fontMetrics().height(), - Qt::AlignRight, number); + painter.drawText(0, top, m_lineNumbers->width() - 3, fontMetrics().height(), + Qt::AlignRight, number); } - block = block.next(); - top = bottom; - bottom = top + (int) blockBoundingRect(block).height(); + block = block.next(); + top = bottom; + bottom = top + (int)blockBoundingRect(block).height(); ++blockNumber; } } @@ -333,13 +330,10 @@ void TextEditor::highlightCurrentLine() setExtraSelections(extraSelections); } - -TextEditorHighlighter::TextEditorHighlighter(QTextDocument* doc) : - QSyntaxHighlighter(doc), - m_background(QColor("transparent")), - m_text(QColor("black")) -{ -} +TextEditorHighlighter::TextEditorHighlighter(QTextDocument* doc) + : QSyntaxHighlighter(doc), m_background(QColor("transparent")), + m_text(QColor("black")) +{} QColor TextEditorHighlighter::backgroundColor() const { @@ -377,14 +371,17 @@ void TextEditorHighlighter::changed() rehighlight(); } - TextEditorLineNumbers::TextEditorLineNumbers(TextEditor& editor) - : QFrame(&editor), m_editor(editor) + : QFrame(&editor), m_editor(editor) { setFont(editor.font()); - connect(&m_editor, &QPlainTextEdit::blockCountChanged, [&]{ updateAreaWidth(); }); - connect(&m_editor, &QPlainTextEdit::updateRequest, [&](auto&& rect, int dy){ updateArea(rect, dy); }); + connect(&m_editor, &QPlainTextEdit::blockCountChanged, [&] { + updateAreaWidth(); + }); + connect(&m_editor, &QPlainTextEdit::updateRequest, [&](auto&& rect, int dy) { + updateArea(rect, dy); + }); updateAreaWidth(); } @@ -397,7 +394,7 @@ QSize TextEditorLineNumbers::sizeHint() const int TextEditorLineNumbers::areaWidth() const { int digits = 1; - int max = std::max(1, m_editor.blockCount()); + int max = std::max(1, m_editor.blockCount()); while (max >= 10) { max /= 10; @@ -447,7 +444,7 @@ void TextEditorLineNumbers::updateAreaWidth() m_editor.setViewportMargins(areaWidth(), 0, 0, 0); } -void TextEditorLineNumbers::updateArea(const QRect &rect, int dy) +void TextEditorLineNumbers::updateArea(const QRect& rect, int dy) { if (dy) { scroll(0, dy); @@ -460,32 +457,35 @@ void TextEditorLineNumbers::updateArea(const QRect &rect, int dy) } } - -TextEditorToolbar::TextEditorToolbar(TextEditor& editor) : - m_editor(editor), m_save(nullptr), m_wordWrap(nullptr), m_explore(nullptr), - m_path(nullptr) +TextEditorToolbar::TextEditorToolbar(TextEditor& editor) + : m_editor(editor), m_save(nullptr), m_wordWrap(nullptr), m_explore(nullptr), + m_path(nullptr) { - m_save = new QAction( - QIcon(":/MO/gui/save"), QObject::tr("&Save"), &editor); + m_save = new QAction(QIcon(":/MO/gui/save"), QObject::tr("&Save"), &editor); m_save->setShortcutContext(Qt::WidgetWithChildrenShortcut); m_save->setShortcut(Qt::CTRL + Qt::Key_S); m_editor.addAction(m_save); - m_wordWrap = new QAction( - QIcon(":/MO/gui/word-wrap"), QObject::tr("&Word wrap"), &editor); + m_wordWrap = + new QAction(QIcon(":/MO/gui/word-wrap"), QObject::tr("&Word wrap"), &editor); m_wordWrap->setCheckable(true); - m_explore = new QAction( - QObject::tr("&Open in Explorer"), &editor); + m_explore = new QAction(QObject::tr("&Open in Explorer"), &editor); m_path = new QLineEdit; m_path->setReadOnly(true); - QObject::connect(m_save, &QAction::triggered, [&]{ m_editor.save(); }); - QObject::connect(m_wordWrap, &QAction::triggered, [&]{ m_editor.toggleWordWrap(); }); - QObject::connect(m_explore, &QAction::triggered, [&]{ m_editor.explore(); }); + QObject::connect(m_save, &QAction::triggered, [&] { + m_editor.save(); + }); + QObject::connect(m_wordWrap, &QAction::triggered, [&] { + m_editor.toggleWordWrap(); + }); + QObject::connect(m_explore, &QAction::triggered, [&] { + m_editor.explore(); + }); auto* layout = new QHBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); @@ -505,9 +505,15 @@ TextEditorToolbar::TextEditorToolbar(TextEditor& editor) : layout->addWidget(m_path); - QObject::connect(&m_editor, &TextEditor::modified, [&](bool b){ onTextModified(b); }); - QObject::connect(&m_editor, &TextEditor::wordWrapChanged, [&](bool b){ onWordWrap(b); }); - QObject::connect(&m_editor, &TextEditor::loaded, [&](QString f){ onLoaded(f); }); + QObject::connect(&m_editor, &TextEditor::modified, [&](bool b) { + onTextModified(b); + }); + QObject::connect(&m_editor, &TextEditor::wordWrapChanged, [&](bool b) { + onWordWrap(b); + }); + QObject::connect(&m_editor, &TextEditor::loaded, [&](QString f) { + onLoaded(f); + }); } void TextEditorToolbar::onTextModified(bool b) diff --git a/src/texteditor.h b/src/texteditor.h index dc53f1c4..7f6adcdb 100644 --- a/src/texteditor.h +++ b/src/texteditor.h @@ -24,7 +24,6 @@ private: void onLoaded(const QString& s); }; - // mostly from https://doc.qt.io/qt-5/qtwidgets-widgets-codeeditor-example.html // class TextEditorLineNumbers : public QFrame @@ -46,17 +45,16 @@ public: void setBackgroundColor(const QColor& c); protected: - void paintEvent(QPaintEvent *event) override; + void paintEvent(QPaintEvent* event) override; private: TextEditor& m_editor; QColor m_background, m_text; void updateAreaWidth(); - void updateArea(const QRect &rect, int dy); + void updateArea(const QRect& rect, int dy); }; - class TextEditorHighlighter : public QSyntaxHighlighter { Q_OBJECT; @@ -79,18 +77,18 @@ private: void changed(); }; - class TextEditor : public QPlainTextEdit { Q_OBJECT; Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor); Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor); - Q_PROPERTY(QColor highlightBackgroundColor READ highlightBackgroundColor WRITE setHighlightBackgroundColor); + Q_PROPERTY(QColor highlightBackgroundColor READ highlightBackgroundColor WRITE + setHighlightBackgroundColor); friend class TextEditorLineNumbers; public: - TextEditor(QWidget* parent=nullptr); + TextEditor(QWidget* parent = nullptr); void setupToolbar(); @@ -145,7 +143,6 @@ private: void paintLineNumbers(QPaintEvent* e, const QColor& textColor); }; - class HTMLEditor : public QTextEdit { Q_OBJECT; @@ -162,4 +159,4 @@ protected: private: }; -#endif // MO_TEXTEDITOR_H +#endif // MO_TEXTEDITOR_H diff --git a/src/thread_utils.h b/src/thread_utils.h index e816a4e2..1eec83a6 100644 --- a/src/thread_utils.h +++ b/src/thread_utils.h @@ -1,16 +1,16 @@ #ifndef MO2_THREAD_UTILS_H #define MO2_THREAD_UTILS_H -#include <log.h> #include <functional> +#include <log.h> #include <mutex> #include <thread> // in main.cpp void setExceptionHandlers(); - -namespace MOShared { +namespace MOShared +{ // starts an std::thread with an unhandled exception handler for core dumps // and a top-level catch @@ -18,7 +18,7 @@ namespace MOShared { template <class F> std::thread startSafeThread(F&& f) { - return std::thread([f=std::forward<F>(f)] { + return std::thread([f = std::forward<F>(f)] { setExceptionHandlers(); f(); }); @@ -47,7 +47,7 @@ void parallelMap(It begin, It end, Callable callable, std::size_t nThreads) // Create the thread: // - The mutex is only used to fetch/increment the iterator. // - The callable is copied in each thread to avoid conflicts. - for (auto &thread: threads) { + for (auto& thread : threads) { thread = startSafeThread([&m, &begin, end, callable]() { while (true) { decltype(begin) it; @@ -71,6 +71,6 @@ void parallelMap(It begin, It end, Callable callable, std::size_t nThreads) } } -} +} // namespace MOShared #endif diff --git a/src/transfersavesdialog.cpp b/src/transfersavesdialog.cpp index e7c84e0a..2761ed1d 100644 --- a/src/transfersavesdialog.cpp +++ b/src/transfersavesdialog.cpp @@ -19,14 +19,13 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "transfersavesdialog.h" -#include "ui_transfersavesdialog.h" #include "iplugingame.h" #include "isavegame.h" #include "savegameinfo.h" -#include <utility.h> +#include "ui_transfersavesdialog.h" #include <log.h> +#include <utility.h> -#include <QtDebug> #include <QDateTime> #include <QDir> #include <QFile> @@ -38,15 +37,15 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QMessageBox> #include <QPushButton> #include <QStringList> +#include <QtDebug> using namespace MOBase; using namespace MOShared; -TransferSavesDialog::TransferSavesDialog(const Profile &profile, IPluginGame const *gamePlugin, QWidget *parent) - : TutorableDialog("TransferSaves", parent) - , ui(new Ui::TransferSavesDialog) - , m_Profile(profile) - , m_GamePlugin(gamePlugin) +TransferSavesDialog::TransferSavesDialog(const Profile& profile, + IPluginGame const* gamePlugin, QWidget* parent) + : TutorableDialog("TransferSaves", parent), ui(new Ui::TransferSavesDialog), + m_Profile(profile), m_GamePlugin(gamePlugin) { ui->setupUi(this); ui->label_2->setText(tr("Characters for profile %1").arg(m_Profile.name())); @@ -66,59 +65,59 @@ void TransferSavesDialog::refreshGlobalSaves() refreshSaves(m_GlobalSaves, m_GamePlugin->savesDirectory().absolutePath()); } - void TransferSavesDialog::refreshLocalSaves() { refreshSaves(m_LocalSaves, m_Profile.savePath()); } - void TransferSavesDialog::refreshGlobalCharacters() { - refreshCharacters(m_GlobalSaves, ui->globalCharacterList, ui->copyToLocalBtn, ui->moveToLocalBtn); + refreshCharacters(m_GlobalSaves, ui->globalCharacterList, ui->copyToLocalBtn, + ui->moveToLocalBtn); } - void TransferSavesDialog::refreshLocalCharacters() { - refreshCharacters(m_LocalSaves, ui->localCharacterList, ui->copyToGlobalBtn, ui->moveToGlobalBtn); + refreshCharacters(m_LocalSaves, ui->localCharacterList, ui->copyToGlobalBtn, + ui->moveToGlobalBtn); } - -bool TransferSavesDialog::testOverwrite(OverwriteMode &overwriteMode, const QString &destinationFile) +bool TransferSavesDialog::testOverwrite(OverwriteMode& overwriteMode, + const QString& destinationFile) { - QMessageBox::StandardButton res = overwriteMode == OVERWRITE_YES ? QMessageBox::Yes : QMessageBox::No; + QMessageBox::StandardButton res = + overwriteMode == OVERWRITE_YES ? QMessageBox::Yes : QMessageBox::No; if (overwriteMode == OVERWRITE_ASK) { res = QMessageBox::question(this, tr("Overwrite"), tr("Overwrite the file \"%1\"").arg(destinationFile), - QMessageBox::Yes | QMessageBox::No | QMessageBox::YesToAll | QMessageBox::NoToAll); + QMessageBox::Yes | QMessageBox::No | + QMessageBox::YesToAll | QMessageBox::NoToAll); if (res == QMessageBox::YesToAll) { overwriteMode = OVERWRITE_YES; - res = QMessageBox::Yes; + res = QMessageBox::Yes; } else if (res == QMessageBox::NoToAll) { overwriteMode = OVERWRITE_NO; - res = QMessageBox::No; + res = QMessageBox::No; } } return res == QMessageBox::Yes; } - -#define MOVE_SAVES "Move all save games of character \"%1\"" -#define COPY_SAVES "Copy all save games of character \"%1\"" +#define MOVE_SAVES "Move all save games of character \"%1\"" +#define COPY_SAVES "Copy all save games of character \"%1\"" #define TO_PROFILE "to the profile?" -#define TO_GLOBAL "to the global location? Please be aware that this will mess up the running number of save games." +#define TO_GLOBAL \ + "to the global location? Please be aware that this will mess up the running number " \ + "of save games." void TransferSavesDialog::on_moveToLocalBtn_clicked() { QString character = ui->globalCharacterList->currentItem()->text(); if (transferCharacters( - character, MOVE_SAVES TO_PROFILE, - m_GamePlugin->savesDirectory(), - m_GlobalSaves[character], - m_Profile.savePath(), - [this](const QString &source, const QString &destination) -> bool { + character, MOVE_SAVES TO_PROFILE, m_GamePlugin->savesDirectory(), + m_GlobalSaves[character], m_Profile.savePath(), + [this](const QString& source, const QString& destination) -> bool { return shellMove(source, destination, this); }, "Failed to move {} to {}")) { @@ -133,11 +132,9 @@ void TransferSavesDialog::on_copyToLocalBtn_clicked() { QString character = ui->globalCharacterList->currentItem()->text(); if (transferCharacters( - character, COPY_SAVES TO_PROFILE, - m_GamePlugin->savesDirectory(), - m_GlobalSaves[character], - m_Profile.savePath(), - [this](const QString &source, const QString &destination) -> bool { + character, COPY_SAVES TO_PROFILE, m_GamePlugin->savesDirectory(), + m_GlobalSaves[character], m_Profile.savePath(), + [this](const QString& source, const QString& destination) -> bool { return shellCopy(source, destination, this); }, "Failed to copy {} to {}")) { @@ -150,11 +147,9 @@ void TransferSavesDialog::on_moveToGlobalBtn_clicked() { QString character = ui->localCharacterList->currentItem()->text(); if (transferCharacters( - character, MOVE_SAVES TO_GLOBAL, - m_Profile.savePath(), - m_LocalSaves[character], - m_GamePlugin->savesDirectory().absolutePath(), - [this](const QString &source, const QString &destination) -> bool { + character, MOVE_SAVES TO_GLOBAL, m_Profile.savePath(), + m_LocalSaves[character], m_GamePlugin->savesDirectory().absolutePath(), + [this](const QString& source, const QString& destination) -> bool { return shellMove(source, destination, this); }, "Failed to move {} to {}")) { @@ -169,11 +164,9 @@ void TransferSavesDialog::on_copyToGlobalBtn_clicked() { QString character = ui->localCharacterList->currentItem()->text(); if (transferCharacters( - character, COPY_SAVES TO_GLOBAL, - m_Profile.savePath(), - m_LocalSaves[character], - m_GamePlugin->savesDirectory().absolutePath(), - [this](const QString &source, const QString &destination) -> bool { + character, COPY_SAVES TO_GLOBAL, m_Profile.savePath(), + m_LocalSaves[character], m_GamePlugin->savesDirectory().absolutePath(), + [this](const QString& source, const QString& destination) -> bool { return shellCopy(source, destination, this); }, "Failed to copy {} to {}")) { @@ -187,51 +180,55 @@ void TransferSavesDialog::on_doneButton_clicked() close(); } -void TransferSavesDialog::on_globalCharacterList_currentTextChanged(const QString ¤tText) +void TransferSavesDialog::on_globalCharacterList_currentTextChanged( + const QString& currentText) { ui->globalSavesList->clear(); - //sadly this can get called while we're resetting the list, with an invalid - //name, so we have to check. + // sadly this can get called while we're resetting the list, with an invalid + // name, so we have to check. SaveCollection::const_iterator saveList = m_GlobalSaves.find(currentText); if (saveList != m_GlobalSaves.end()) { - for (SaveListItem const &save : saveList->second) { + for (SaveListItem const& save : saveList->second) { ui->globalSavesList->addItem(QFileInfo(save->getFilepath()).fileName()); } } } -void TransferSavesDialog::on_localCharacterList_currentTextChanged(const QString ¤tText) +void TransferSavesDialog::on_localCharacterList_currentTextChanged( + const QString& currentText) { ui->localSavesList->clear(); - //sadly this can get called while we're resetting the list, with an invalid - //name, so we have to check. + // sadly this can get called while we're resetting the list, with an invalid + // name, so we have to check. SaveCollection::const_iterator saveList = m_LocalSaves.find(currentText); if (saveList != m_LocalSaves.end()) { - for (SaveListItem const &save : saveList->second) { + for (SaveListItem const& save : saveList->second) { ui->localSavesList->addItem(QFileInfo(save->getFilepath()).fileName()); } } } -void TransferSavesDialog::refreshSaves(SaveCollection &saveCollection, QString const &savedir) +void TransferSavesDialog::refreshSaves(SaveCollection& saveCollection, + QString const& savedir) { saveCollection.clear(); auto saves = m_GamePlugin->listSaves(savedir); std::sort(saves.begin(), saves.end(), [](auto const& lhs, auto const& rhs) { return lhs->getCreationTime() > rhs->getCreationTime(); - }); + }); - for (auto& save: saves) { + for (auto& save : saves) { saveCollection[save->getSaveGroupIdentifier()].push_back(save); } } -void TransferSavesDialog::refreshCharacters(const SaveCollection &saveCollection, - QListWidget *charList, QPushButton *copy, QPushButton *move) +void TransferSavesDialog::refreshCharacters(const SaveCollection& saveCollection, + QListWidget* charList, QPushButton* copy, + QPushButton* move) { charList->clear(); - for (SaveCollection::value_type const &val : saveCollection) { + for (SaveCollection::value_type const& val : saveCollection) { charList->addItem(val.first); } if (charList->count() > 0) { @@ -245,32 +242,30 @@ void TransferSavesDialog::refreshCharacters(const SaveCollection &saveCollection } bool TransferSavesDialog::transferCharacters( - QString const &character, char const *message, - QDir const& sourceDirectory, - SaveList &saves, - QDir const& destination, - const std::function<bool(const QString &, const QString &)> &method, - char const *errmsg) + QString const& character, char const* message, QDir const& sourceDirectory, + SaveList& saves, QDir const& destination, + const std::function<bool(const QString&, const QString&)>& method, + char const* errmsg) { - if (QMessageBox::question(this, tr("Confirm"), - tr(message).arg(character), - QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { - return false; + if (QMessageBox::question(this, tr("Confirm"), tr(message).arg(character), + QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { + return false; } OverwriteMode overwriteMode = OVERWRITE_ASK; - for (SaveListItem const &save : saves) { + for (SaveListItem const& save : saves) { for (QString source : save->allFiles()) { QFileInfo sourceFile(source); - QString destinationFile(destination.absoluteFilePath(sourceDirectory.relativeFilePath(source))); + QString destinationFile( + destination.absoluteFilePath(sourceDirectory.relativeFilePath(source))); - //If the file is already there, let them skip (or not). + // If the file is already there, let them skip (or not). if (QFile::exists(destinationFile)) { - if (! testOverwrite(overwriteMode, destinationFile)) { + if (!testOverwrite(overwriteMode, destinationFile)) { continue; } - //OK, they want to remove it. + // OK, they want to remove it. QFile::remove(destinationFile); } diff --git a/src/transfersavesdialog.h b/src/transfersavesdialog.h index 98d99f9e..5559b1d6 100644 --- a/src/transfersavesdialog.h +++ b/src/transfersavesdialog.h @@ -20,8 +20,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef TRANSFERSAVESDIALOG_H #define TRANSFERSAVESDIALOG_H -#include "tutorabledialog.h" #include "profile.h" +#include "tutorabledialog.h" class QListWidget; #include <QObject> @@ -29,21 +29,31 @@ class QPushButton; #include <QString> class QWidget; -#include <memory> #include <map> +#include <memory> #include <vector> -namespace Ui { class TransferSavesDialog; } -namespace MOBase { class IPluginGame; } -namespace MOBase { class ISaveGame; } +namespace Ui +{ +class TransferSavesDialog; +} +namespace MOBase +{ +class IPluginGame; +} +namespace MOBase +{ +class ISaveGame; +} -class TransferSavesDialog : public MOBase::TutorableDialog { +class TransferSavesDialog : public MOBase::TutorableDialog +{ Q_OBJECT public: - explicit TransferSavesDialog(const Profile &profile, - MOBase::IPluginGame const *gamePlugin, - QWidget *parent = 0); + explicit TransferSavesDialog(const Profile& profile, + MOBase::IPluginGame const* gamePlugin, + QWidget* parent = 0); ~TransferSavesDialog(); private slots: @@ -52,9 +62,9 @@ private slots: void on_doneButton_clicked(); - void on_globalCharacterList_currentTextChanged(const QString ¤tText); + void on_globalCharacterList_currentTextChanged(const QString& currentText); - void on_localCharacterList_currentTextChanged(const QString ¤tText); + void on_localCharacterList_currentTextChanged(const QString& currentText); void on_copyToLocalBtn_clicked(); @@ -63,41 +73,43 @@ private slots: void on_copyToGlobalBtn_clicked(); private: - enum OverwriteMode { OVERWRITE_ASK, OVERWRITE_YES, OVERWRITE_NO }; + enum OverwriteMode + { + OVERWRITE_ASK, + OVERWRITE_YES, + OVERWRITE_NO + }; private: void refreshGlobalCharacters(); void refreshLocalCharacters(); void refreshGlobalSaves(); void refreshLocalSaves(); - bool testOverwrite(OverwriteMode &overwriteMode, - const QString &destinationFile); + bool testOverwrite(OverwriteMode& overwriteMode, const QString& destinationFile); private: - Ui::TransferSavesDialog *ui; + Ui::TransferSavesDialog* ui; Profile m_Profile; - MOBase::IPluginGame const *m_GamePlugin; + MOBase::IPluginGame const* m_GamePlugin; - using SaveListItem = std::shared_ptr<const MOBase::ISaveGame>; - using SaveList = std::vector<SaveListItem>; + using SaveListItem = std::shared_ptr<const MOBase::ISaveGame>; + using SaveList = std::vector<SaveListItem>; using SaveCollection = std::map<QString, SaveList>; SaveCollection m_GlobalSaves; SaveCollection m_LocalSaves; - void refreshSaves(SaveCollection &saveCollection, const QString &savedir); - void refreshCharacters(SaveCollection const &saveCollection, - QListWidget *charList, QPushButton *copy, - QPushButton *move); + void refreshSaves(SaveCollection& saveCollection, const QString& savedir); + void refreshCharacters(SaveCollection const& saveCollection, QListWidget* charList, + QPushButton* copy, QPushButton* move); - bool transferCharacters( - QString const &character, char const *message, - QDir const& sourceDirectory, SaveList &saves, - QDir const& dest, - const std::function<bool(const QString &, const QString &)> &method, - char const *errmsg); + bool + transferCharacters(QString const& character, char const* message, + QDir const& sourceDirectory, SaveList& saves, QDir const& dest, + const std::function<bool(const QString&, const QString&)>& method, + char const* errmsg); }; -#endif // TRANSFERSAVESDIALOG_H +#endif // TRANSFERSAVESDIALOG_H diff --git a/src/uilocker.cpp b/src/uilocker.cpp index 3dba6738..eb3033f1 100644 --- a/src/uilocker.cpp +++ b/src/uilocker.cpp @@ -7,12 +7,14 @@ class UILockerInterface { public: - UILockerInterface(QWidget* mainUI) : - m_mainUI(mainUI), m_target(nullptr), m_message(nullptr), m_info(nullptr), - m_buttons(nullptr), m_reason(UILocker::NoReason) + UILockerInterface(QWidget* mainUI) + : m_mainUI(mainUI), m_target(nullptr), m_message(nullptr), m_info(nullptr), + m_buttons(nullptr), m_reason(UILocker::NoReason) { m_timer.reset(new QTimer); - QObject::connect(m_timer.get(), &QTimer::timeout, [&]{ checkTarget(); }); + QObject::connect(m_timer.get(), &QTimer::timeout, [&] { + checkTarget(); + }); m_timer->start(200); set(); @@ -93,17 +95,14 @@ public: m_info->setText(s); } - QWidget* topLevel() - { - return m_topLevel.data(); - } + QWidget* topLevel() { return m_topLevel.data(); } private: class Filter : public QObject { public: - std::function<void ()> resized; - std::function<void ()> closed; + std::function<void()> resized; + std::function<void()> closed; protected: bool eventFilter(QObject* o, QEvent* e) override @@ -122,7 +121,6 @@ private: } }; - std::unique_ptr<QTimer> m_timer; QWidget* m_mainUI; QWidget* m_target; @@ -134,11 +132,7 @@ private: std::unique_ptr<Filter> m_filter; UILocker::Reasons m_reason; - - bool hasMainUI() const - { - return (m_target != nullptr); - } + bool hasMainUI() const { return (m_target != nullptr); } QWidget* findTarget() { @@ -161,7 +155,6 @@ private: return true; }; - // find a modal dialog QWidget* w = QApplication::activeModalWidget(); @@ -189,7 +182,7 @@ private: return m_mainUI; } - QWidget* createTransparentWidget(QWidget* parent=nullptr) + QWidget* createTransparentWidget(QWidget* parent = nullptr) { auto* w = new QWidget(parent); @@ -212,8 +205,12 @@ private: m_topLevel->setGeometry(mainUI->rect()); m_filter.reset(new Filter); - m_filter->resized = [=]{ m_topLevel->setGeometry(mainUI->rect()); }; - m_filter->closed = [=]{ checkTarget(); }; + m_filter->resized = [=] { + m_topLevel->setGeometry(mainUI->rect()); + }; + m_filter->closed = [=] { + checkTarget(); + }; mainUI->installEventFilter(m_filter.get()); @@ -235,7 +232,7 @@ private: QFrame* createFrame() { auto* frame = new QFrame; - auto* ly = new QVBoxLayout(frame); + auto* ly = new QVBoxLayout(frame); if (hasMainUI()) { frame->setFrameStyle(QFrame::StyledPanel); @@ -288,43 +285,37 @@ private: m_buttons->setLayout(new QHBoxLayout); } - void updateMessage(UILocker::Reasons reason) { - switch (reason) - { - case UILocker::LockUI: - { - QString s; + switch (reason) { + case UILocker::LockUI: { + QString s; - if (hasMainUI()) { - s = QObject::tr( - "Mod Organizer is locked while the application is running."); - } else { - s = QObject::tr("Mod Organizer is currently running an application."); - } + if (hasMainUI()) { + s = QObject::tr("Mod Organizer is locked while the application is running."); + } else { + s = QObject::tr("Mod Organizer is currently running an application."); + } - m_message->setText(s); + m_message->setText(s); - break; - } + break; + } - case UILocker::OutputRequired: - { - m_message->setText(QObject::tr( - "The application must run to completion because its output is " - "required.")); + case UILocker::OutputRequired: { + m_message->setText( + QObject::tr("The application must run to completion because its output is " + "required.")); - break; - } + break; + } - case UILocker::PreventExit: - { - m_message->setText(QObject::tr( + case UILocker::PreventExit: { + m_message->setText(QObject::tr( "Mod Organizer is waiting on an application to close before exiting.")); - break; - } + break; + } } } @@ -333,40 +324,37 @@ private: MOBase::deleteChildWidgets(m_buttons); auto* ly = m_buttons->layout(); - switch (reason) - { - case UILocker::LockUI: // fall-through - case UILocker::OutputRequired: - { - auto* unlock = new QPushButton(QObject::tr("Unlock")); + switch (reason) { + case UILocker::LockUI: // fall-through + case UILocker::OutputRequired: { + auto* unlock = new QPushButton(QObject::tr("Unlock")); - QObject::connect(unlock, &QPushButton::clicked, [&]{ - UILocker::instance().onForceUnlock(); - }); + QObject::connect(unlock, &QPushButton::clicked, [&] { + UILocker::instance().onForceUnlock(); + }); - ly->addWidget(unlock); + ly->addWidget(unlock); - break; - } + break; + } - case UILocker::PreventExit: - { - auto* exit = new QPushButton(QObject::tr("Exit Now")); - QObject::connect(exit, &QPushButton::clicked, [&]{ - UILocker::instance().onForceUnlock(); - }); + case UILocker::PreventExit: { + auto* exit = new QPushButton(QObject::tr("Exit Now")); + QObject::connect(exit, &QPushButton::clicked, [&] { + UILocker::instance().onForceUnlock(); + }); - ly->addWidget(exit); + ly->addWidget(exit); - auto* cancel = new QPushButton(QObject::tr("Cancel")); - QObject::connect(cancel, &QPushButton::clicked, [&]{ - UILocker::instance().onCancel(); - }); + auto* cancel = new QPushButton(QObject::tr("Cancel")); + QObject::connect(cancel, &QPushButton::clicked, [&] { + UILocker::instance().onCancel(); + }); - ly->addWidget(cancel); + ly->addWidget(cancel); - break; - } + break; + } } } }; @@ -378,7 +366,7 @@ UILocker::Session::~Session() void UILocker::Session::unlock() { - QMetaObject::invokeMethod(qApp, [this]{ + QMetaObject::invokeMethod(qApp, [this] { UILocker::instance().unlock(this); }); } @@ -387,11 +375,11 @@ void UILocker::Session::setInfo(DWORD pid, const QString& name) { { std::scoped_lock lock(m_mutex); - m_pid = pid; + m_pid = pid; m_name = name; } - QMetaObject::invokeMethod(qApp, [this]{ + QMetaObject::invokeMethod(qApp, [this] { UILocker::instance().updateLabel(); }); } @@ -413,12 +401,9 @@ UILocker::Results UILocker::Session::result() const return UILocker::instance().result(); } - static UILocker* g_instance = nullptr; - -UILocker::UILocker() - : m_parent(nullptr), m_result(NoResult) +UILocker::UILocker() : m_parent(nullptr), m_result(NoResult) { Q_ASSERT(!g_instance); g_instance = this; @@ -429,7 +414,7 @@ UILocker::~UILocker() const auto v = m_sessions; for (auto& wp : v) { - if (auto s=wp.lock()) { + if (auto s = wp.lock()) { unlock(s.get()); } } @@ -474,7 +459,7 @@ void UILocker::unlock(Session* s) break; } - if (auto ss=itor->lock()) { + if (auto ss = itor->lock()) { if (ss.get() == s) { itor = m_sessions.erase(itor); continue; @@ -520,8 +505,8 @@ void UILocker::updateLabel() QStringList labels; - for (auto itor=m_sessions.rbegin(); itor!=m_sessions.rend(); ++itor) { - if (auto ss=itor->lock()) { + for (auto itor = m_sessions.rbegin(); itor != m_sessions.rend(); ++itor) { + if (auto ss = itor->lock()) { labels.push_back(QString("%1 (%2)").arg(ss->name()).arg(ss->pid())); } } @@ -573,7 +558,7 @@ void UILocker::disableAll() // top level widgets include the main window and dialogs for (auto* w : QApplication::topLevelWidgets()) { - if (auto* mw=dynamic_cast<QMainWindow*>(w)) { + if (auto* mw = dynamic_cast<QMainWindow*>(w)) { // this is the main window, disable the central widgets and the stuff // around it @@ -592,8 +577,7 @@ void UILocker::disableAll() } } - - if (auto* d=dynamic_cast<QDialog*>(w)) { + if (auto* d = dynamic_cast<QDialog*>(w)) { // this is a dialog if (d == m_ui->topLevel()) { diff --git a/src/uilocker.h b/src/uilocker.h index 44d9d8a2..ec188f1a 100644 --- a/src/uilocker.h +++ b/src/uilocker.h @@ -43,7 +43,6 @@ public: Cancelled }; - class Session { public: @@ -62,7 +61,6 @@ public: QString m_name; }; - UILocker(); ~UILocker(); diff --git a/src/updatedialog.cpp b/src/updatedialog.cpp index d3336e93..41e0801b 100644 --- a/src/updatedialog.cpp +++ b/src/updatedialog.cpp @@ -1,21 +1,26 @@ #include "updatedialog.h" #include "ui_updatedialog.h" -#include "lootdialog.h" // for MarkdownPage +#include "lootdialog.h" // for MarkdownPage #include <QWebChannel> using namespace MOBase; -UpdateDialog::UpdateDialog(QWidget* parent) : - QDialog(parent, Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint), ui(new Ui::UpdateDialog) +UpdateDialog::UpdateDialog(QWidget* parent) + : QDialog(parent, Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint), + ui(new Ui::UpdateDialog) { // Basic UI stuff ui->setupUi(this); - connect(ui->installButton, &QPushButton::pressed, this, [&]{ done(QDialog::Accepted); }); - connect(ui->cancelButton, &QPushButton::pressed, this, [&]{ done(QDialog::Rejected); }); + connect(ui->installButton, &QPushButton::pressed, this, [&] { + done(QDialog::Accepted); + }); + connect(ui->cancelButton, &QPushButton::pressed, this, [&] { + done(QDialog::Rejected); + }); // Replace a label with an icon - QIcon icon = style()->standardIcon(QStyle::SP_MessageBoxQuestion); + QIcon icon = style()->standardIcon(QStyle::SP_MessageBoxQuestion); QPixmap pixmap = icon.pixmap(QSize(32, 32)); ui->iconLabel->setPixmap(pixmap); ui->iconLabel->setScaledContents(true); @@ -44,7 +49,9 @@ UpdateDialog::UpdateDialog(QWidget* parent) : // Setting up the expander m_expander.set(ui->detailsButton, ui->detailsWidget); - connect(&m_expander, &ExpanderWidget::toggled, this, [&]{ adjustSize(); }); + connect(&m_expander, &ExpanderWidget::toggled, this, [&] { + adjustSize(); + }); // Adjust sizes after the expander hides stuff adjustSize(); @@ -59,9 +66,8 @@ void UpdateDialog::setChangeLogs(const QString& text) void UpdateDialog::setVersions(const QString& oldVersion, const QString& newVersion) { - ui->updateLabel->setText( - tr("Mod Organizer %1 is available. The current version is %2. Updating will not affect your mods or profiles.") - .arg(newVersion) - .arg(oldVersion) - ); + ui->updateLabel->setText(tr("Mod Organizer %1 is available. The current version is " + "%2. Updating will not affect your mods or profiles.") + .arg(newVersion) + .arg(oldVersion)); } diff --git a/src/updatedialog.h b/src/updatedialog.h index 1dd5e0b1..798fbee2 100644 --- a/src/updatedialog.h +++ b/src/updatedialog.h @@ -3,10 +3,13 @@ #include <QDialog> +#include "lootdialog.h" // for MarkdownDocument #include <expanderwidget.h> -#include "lootdialog.h" // for MarkdownDocument -namespace Ui { class UpdateDialog; } +namespace Ui +{ +class UpdateDialog; +} class UpdateDialog : public QDialog { @@ -25,4 +28,4 @@ private: MarkdownDocument m_changeLogs; }; -#endif // MODORGANIZER_UPDATEDIALOG_H +#endif // MODORGANIZER_UPDATEDIALOG_H diff --git a/src/usvfsconnector.cpp b/src/usvfsconnector.cpp index 611b905b..940d0942 100644 --- a/src/usvfsconnector.cpp +++ b/src/usvfsconnector.cpp @@ -18,26 +18,26 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ #include "usvfsconnector.h" -#include "settings.h" -#include "organizercore.h" #include "envmodule.h" +#include "organizercore.h" +#include "settings.h" #include "shared/util.h" +#include <QCoreApplication> +#include <QDateTime> +#include <QProgressDialog> +#include <QTemporaryFile> +#include <iomanip> #include <memory> +#include <qstandardpaths.h> #include <sstream> -#include <iomanip> #include <usvfs.h> -#include <QTemporaryFile> -#include <QProgressDialog> -#include <QDateTime> -#include <QCoreApplication> -#include <qstandardpaths.h> static const char SHMID[] = "mod_organizer_instance"; using namespace MOBase; -std::string to_hex(void *bufferIn, size_t bufferSize) +std::string to_hex(void* bufferIn, size_t bufferSize) { - unsigned char *buffer = static_cast<unsigned char *>(bufferIn); + unsigned char* buffer = static_cast<unsigned char*>(bufferIn); std::ostringstream temp; temp << std::hex; for (size_t i = 0; i < bufferSize; ++i) { @@ -51,22 +51,18 @@ std::string to_hex(void *bufferIn, size_t bufferSize) return temp.str(); } - LogWorker::LogWorker() - : m_Buffer(1024, '\0') - , m_QuitRequested(false) - , m_LogFile(qApp->property("dataPath").toString() - + QString("/logs/usvfs-%1.log") - .arg(QDateTime::currentDateTimeUtc().toString( - "yyyy-MM-dd_hh-mm-ss"))) + : m_Buffer(1024, '\0'), m_QuitRequested(false), + m_LogFile( + qApp->property("dataPath").toString() + + QString("/logs/usvfs-%1.log") + .arg(QDateTime::currentDateTimeUtc().toString("yyyy-MM-dd_hh-mm-ss"))) { m_LogFile.open(QIODevice::WriteOnly); log::debug("usvfs log messages are written to {}", m_LogFile.fileName()); } -LogWorker::~LogWorker() -{ -} +LogWorker::~LogWorker() {} void LogWorker::process() { @@ -95,34 +91,33 @@ void LogWorker::exit() LogLevel toUsvfsLogLevel(log::Levels level) { switch (level) { - case log::Info: - return LogLevel::Info; - case log::Warning: - return LogLevel::Warning; - case log::Error: - return LogLevel::Error; - case log::Debug: // fall-through - default: - return LogLevel::Debug; + case log::Info: + return LogLevel::Info; + case log::Warning: + return LogLevel::Warning; + case log::Error: + return LogLevel::Error; + case log::Debug: // fall-through + default: + return LogLevel::Debug; } } CrashDumpsType toUsvfsCrashDumpsType(env::CoreDumpTypes type) { - switch (type) - { - case env::CoreDumpTypes::None: - return CrashDumpsType::None; + switch (type) { + case env::CoreDumpTypes::None: + return CrashDumpsType::None; - case env::CoreDumpTypes::Data: - return CrashDumpsType::Data; + case env::CoreDumpTypes::Data: + return CrashDumpsType::Data; - case env::CoreDumpTypes::Full: - return CrashDumpsType::Full; + case env::CoreDumpTypes::Full: + return CrashDumpsType::Full; - case env::CoreDumpTypes::Mini: - default: - return CrashDumpsType::Mini; + case env::CoreDumpTypes::Mini: + default: + return CrashDumpsType::Mini; } } @@ -133,9 +128,10 @@ UsvfsConnector::UsvfsConnector() const auto& s = Settings::instance(); const LogLevel logLevel = toUsvfsLogLevel(s.diagnostics().logLevel()); - const auto dumpType = toUsvfsCrashDumpsType(s.diagnostics().coreDumpType()); - const auto delay = duration_cast<milliseconds>(s.diagnostics().spawnDelay()); - std::string dumpPath = MOShared::ToString(OrganizerCore::getGlobalCoreDumpPath(), true); + const auto dumpType = toUsvfsCrashDumpsType(s.diagnostics().coreDumpType()); + const auto delay = duration_cast<milliseconds>(s.diagnostics().spawnDelay()); + std::string dumpPath = + MOShared::ToString(OrganizerCore::getGlobalCoreDumpPath(), true); usvfsParameters* params = usvfsCreateParameters(); @@ -148,15 +144,12 @@ UsvfsConnector::UsvfsConnector() InitLogging(false); - log::debug( - "initializing usvfs:\n" - " . instance: {}\n" - " . log: {}\n" - " . dump: {} ({})", - SHMID, - usvfsLogLevelToString(logLevel), - dumpPath.c_str(), - usvfsCrashDumpTypeToString(dumpType)); + log::debug("initializing usvfs:\n" + " . instance: {}\n" + " . log: {}\n" + " . dump: {} ({})", + SHMID, usvfsLogLevelToString(logLevel), dumpPath.c_str(), + usvfsCrashDumpTypeToString(dumpType)); usvfsCreateVFS(params); usvfsFreeParameters(params); @@ -185,8 +178,7 @@ UsvfsConnector::~UsvfsConnector() m_WorkerThread.wait(); } - -void UsvfsConnector::updateMapping(const MappingType &mapping) +void UsvfsConnector::updateMapping(const MappingType& mapping) { const auto start = std::chrono::high_resolution_clock::now(); @@ -197,7 +189,7 @@ void UsvfsConnector::updateMapping(const MappingType &mapping) int value = 0; int files = 0; - int dirs = 0; + int dirs = 0; log::debug("Updating VFS mappings..."); @@ -214,11 +206,9 @@ void UsvfsConnector::updateMapping(const MappingType &mapping) } if (map.isDirectory) { - VirtualLinkDirectoryStatic(map.source.toStdWString().c_str(), - map.destination.toStdWString().c_str(), - (map.createTarget ? LINKFLAG_CREATETARGET : 0) - | LINKFLAG_RECURSIVE - ); + VirtualLinkDirectoryStatic( + map.source.toStdWString().c_str(), map.destination.toStdWString().c_str(), + (map.createTarget ? LINKFLAG_CREATETARGET : 0) | LINKFLAG_RECURSIVE); ++dirs; } else { VirtualLinkFile(map.source.toStdWString().c_str(), @@ -227,18 +217,18 @@ void UsvfsConnector::updateMapping(const MappingType &mapping) } } - const auto end = std::chrono::high_resolution_clock::now(); + const auto end = std::chrono::high_resolution_clock::now(); const auto time = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); - log::debug( - "VFS mappings updated, linked {} dirs and {} files in {}ms", - dirs, files, time.count()); + log::debug("VFS mappings updated, linked {} dirs and {} files in {}ms", dirs, files, + time.count()); } -void UsvfsConnector::updateParams( - MOBase::log::Levels logLevel, env::CoreDumpTypes coreDumpType, - const QString& crashDumpsPath, std::chrono::seconds spawnDelay, - QString executableBlacklist) +void UsvfsConnector::updateParams(MOBase::log::Levels logLevel, + env::CoreDumpTypes coreDumpType, + const QString& crashDumpsPath, + std::chrono::seconds spawnDelay, + QString executableBlacklist) { using namespace std::chrono; @@ -260,26 +250,24 @@ void UsvfsConnector::updateParams( } } -void UsvfsConnector::updateForcedLibraries(const QList<MOBase::ExecutableForcedLoadSetting> &forcedLibraries) +void UsvfsConnector::updateForcedLibraries( + const QList<MOBase::ExecutableForcedLoadSetting>& forcedLibraries) { ClearLibraryForceLoads(); for (auto setting : forcedLibraries) { if (setting.enabled()) { - ForceLoadLibrary( - setting.process().toStdWString().data(), - setting.library().toStdWString().data() - ); + ForceLoadLibrary(setting.process().toStdWString().data(), + setting.library().toStdWString().data()); } } } - std::vector<HANDLE> getRunningUSVFSProcesses() { std::vector<DWORD> pids; { - size_t count = 0; + size_t count = 0; DWORD* buffer = nullptr; if (!::GetVFSProcessList2(&count, &buffer)) { log::error("failed to get usvfs process list"); @@ -296,13 +284,13 @@ std::vector<HANDLE> getRunningUSVFSProcesses() std::vector<HANDLE> v; const auto rights = - PROCESS_QUERY_LIMITED_INFORMATION | // exit code, image name, etc. - SYNCHRONIZE | // wait functions - PROCESS_SET_QUOTA | PROCESS_TERMINATE; // add to job + PROCESS_QUERY_LIMITED_INFORMATION | // exit code, image name, etc. + SYNCHRONIZE | // wait functions + PROCESS_SET_QUOTA | PROCESS_TERMINATE; // add to job for (auto&& pid : pids) { if (pid == thisPid) { - continue; // obviously don't wait for MO process + continue; // obviously don't wait for MO process } HANDLE handle = ::OpenProcess(rights, FALSE, pid); @@ -310,9 +298,7 @@ std::vector<HANDLE> getRunningUSVFSProcesses() if (handle == INVALID_HANDLE_VALUE) { const auto e = GetLastError(); - log::warn( - "failed to open usvfs process {}: {}", - pid, formatSystemMessage(e)); + log::warn("failed to open usvfs process {}: {}", pid, formatSystemMessage(e)); continue; } diff --git a/src/usvfsconnector.h b/src/usvfsconnector.h index bf5d49ce..798d5983 100644 --- a/src/usvfsconnector.h +++ b/src/usvfsconnector.h @@ -17,29 +17,27 @@ You should have received a copy of the GNU General Public License along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ - #ifndef USVFSCONNECTOR_H #define USVFSCONNECTOR_H -#include <exception> -#include <filemapping.h> -#include <QString> -#include <QThread> -#include <QFile> +#include "envdump.h" +#include "executableinfo.h" #include <QDebug> +#include <QFile> #include <QList> -#include <usvfsparameters.h> +#include <QString> +#include <QThread> +#include <exception> +#include <filemapping.h> #include <log.h> -#include "executableinfo.h" -#include "envdump.h" - +#include <usvfsparameters.h> -class LogWorker : public QThread { +class LogWorker : public QThread +{ Q_OBJECT public: - LogWorker(); ~LogWorker(); @@ -50,60 +48,54 @@ public slots: signals: - void outputLog(const QString &message); + void outputLog(const QString& message); void finished(); private: - std::string m_Buffer; bool m_QuitRequested; QFile m_LogFile; - }; - -class UsvfsConnectorException : public std::exception { +class UsvfsConnectorException : public std::exception +{ public: - UsvfsConnectorException(const QString &text) - : std::exception(), m_Message(text.toLocal8Bit()) {} + UsvfsConnectorException(const QString& text) + : std::exception(), m_Message(text.toLocal8Bit()) + {} + + virtual const char* what() const throw() { return m_Message.constData(); } - virtual const char* what() const throw() - { return m_Message.constData(); } private: QByteArray m_Message; - }; - -class UsvfsConnector : public QObject { +class UsvfsConnector : public QObject +{ Q_OBJECT public: - UsvfsConnector(); ~UsvfsConnector(); - void updateMapping(const MappingType &mapping); + void updateMapping(const MappingType& mapping); - void updateParams( - MOBase::log::Levels logLevel, env::CoreDumpTypes coreDumpType, - const QString& crashDumpsPath, std::chrono::seconds spawnDelay, - QString executableBlacklist); + void updateParams(MOBase::log::Levels logLevel, env::CoreDumpTypes coreDumpType, + const QString& crashDumpsPath, std::chrono::seconds spawnDelay, + QString executableBlacklist); void updateForcedLibraries( - const QList<MOBase::ExecutableForcedLoadSetting> &forcedLibraries); + const QList<MOBase::ExecutableForcedLoadSetting>& forcedLibraries); private: - LogWorker m_LogWorker; QThread m_WorkerThread; - }; CrashDumpsType crashDumpsType(int type); std::vector<HANDLE> getRunningUSVFSProcesses(); -#endif // USVFSCONNECTOR_H +#endif // USVFSCONNECTOR_H diff --git a/src/viewmarkingscrollbar.cpp b/src/viewmarkingscrollbar.cpp index 5cd6d042..7fe5c1c3 100644 --- a/src/viewmarkingscrollbar.cpp +++ b/src/viewmarkingscrollbar.cpp @@ -1,15 +1,13 @@ #include "viewmarkingscrollbar.h" #include "modelutils.h" +#include <QPainter> #include <QStyle> #include <QStyleOptionSlider> -#include <QPainter> using namespace MOShared; ViewMarkingScrollBar::ViewMarkingScrollBar(QTreeView* view, int role) - : QScrollBar(view) - , m_view(view) - , m_role(role) + : QScrollBar(view), m_view(view), m_role(role) { // not implemented for horizontal sliders Q_ASSERT(this->orientation() == Qt::Vertical); @@ -36,13 +34,16 @@ void ViewMarkingScrollBar::paintEvent(QPaintEvent* event) QPainter painter(this); - QRect handleRect = style()->subControlRect(QStyle::CC_ScrollBar, &styleOption, QStyle::SC_ScrollBarSlider, this); - QRect innerRect = style()->subControlRect(QStyle::CC_ScrollBar, &styleOption, QStyle::SC_ScrollBarGroove, this); + QRect handleRect = style()->subControlRect(QStyle::CC_ScrollBar, &styleOption, + QStyle::SC_ScrollBarSlider, this); + QRect innerRect = style()->subControlRect(QStyle::CC_ScrollBar, &styleOption, + QStyle::SC_ScrollBarGroove, this); auto indices = visibleIndex(m_view, 0); painter.translate(innerRect.topLeft() + QPoint(0, 3)); - qreal scale = static_cast<qreal>(innerRect.height() - 3) / static_cast<qreal>(indices.size()); + qreal scale = + static_cast<qreal>(innerRect.height() - 3) / static_cast<qreal>(indices.size()); for (int i = 0; i < indices.size(); ++i) { QColor color = this->color(indices[i]); diff --git a/src/viewmarkingscrollbar.h b/src/viewmarkingscrollbar.h index 3ffd4e97..8fff05e9 100644 --- a/src/viewmarkingscrollbar.h +++ b/src/viewmarkingscrollbar.h @@ -1,9 +1,8 @@ #ifndef VIEWMARKINGSCROLLBAR_H #define VIEWMARKINGSCROLLBAR_H -#include <QTreeView> #include <QScrollBar> - +#include <QTreeView> class ViewMarkingScrollBar : public QScrollBar { @@ -11,7 +10,7 @@ public: ViewMarkingScrollBar(QTreeView* view, int role); protected: - void paintEvent(QPaintEvent *event) override; + void paintEvent(QPaintEvent* event) override; // retrieve the color of the marker for the given index // @@ -22,5 +21,4 @@ private: int m_role; }; - -#endif // VIEWMARKINGSCROLLBAR_H +#endif // VIEWMARKINGSCROLLBAR_H diff --git a/src/virtualfiletree.cpp b/src/virtualfiletree.cpp index 983523e6..dcc129af 100644 --- a/src/virtualfiletree.cpp +++ b/src/virtualfiletree.cpp @@ -1,49 +1,70 @@ #include "virtualfiletree.h" #include "shared/directoryentry.h" -#include "shared/filesorigin.h" #include "shared/fileentry.h" +#include "shared/filesorigin.h" // #include "shared/util.h" using namespace MOBase; using namespace MOShared; -class VirtualFileTreeImpl : public VirtualFileTree { +class VirtualFileTreeImpl : public VirtualFileTree +{ public: - - /** * */ - VirtualFileTreeImpl(std::shared_ptr<const IFileTree> parent, const DirectoryEntry* dir) : - FileTreeEntry(parent, parent ? QString::fromStdWString(dir->getName()) : ""), - VirtualFileTree(), - m_dirEntry(dir) { } + VirtualFileTreeImpl(std::shared_ptr<const IFileTree> parent, + const DirectoryEntry* dir) + : FileTreeEntry(parent, parent ? QString::fromStdWString(dir->getName()) : ""), + VirtualFileTree(), m_dirEntry(dir) + {} protected: - /** * No mutable operations allowed. */ - bool beforeReplace(IFileTree const* dstTree, FileTreeEntry const* destination, FileTreeEntry const* source) override { return false; } - bool beforeInsert(IFileTree const* entry, FileTreeEntry const* name) override { return false; } - bool beforeRemove(IFileTree const* entry, FileTreeEntry const* name) override { return false; } - std::shared_ptr<FileTreeEntry> makeFile(std::shared_ptr<const IFileTree> parent, QString name) const override { return nullptr; } - std::shared_ptr<IFileTree> makeDirectory(std::shared_ptr<const IFileTree> parent, QString name) const override { return nullptr; } + bool beforeReplace(IFileTree const* dstTree, FileTreeEntry const* destination, + FileTreeEntry const* source) override + { + return false; + } + bool beforeInsert(IFileTree const* entry, FileTreeEntry const* name) override + { + return false; + } + bool beforeRemove(IFileTree const* entry, FileTreeEntry const* name) override + { + return false; + } + std::shared_ptr<FileTreeEntry> makeFile(std::shared_ptr<const IFileTree> parent, + QString name) const override + { + return nullptr; + } + std::shared_ptr<IFileTree> makeDirectory(std::shared_ptr<const IFileTree> parent, + QString name) const override + { + return nullptr; + } - bool doPopulate(std::shared_ptr<const IFileTree> parent, std::vector<std::shared_ptr<FileTreeEntry>>& entries) const override { + bool doPopulate(std::shared_ptr<const IFileTree> parent, + std::vector<std::shared_ptr<FileTreeEntry>>& entries) const override + { for (auto* subdirEntry : m_dirEntry->getSubDirectories()) { entries.push_back(std::make_shared<VirtualFileTreeImpl>(parent, subdirEntry)); } for (auto& file : m_dirEntry->getFiles()) { - entries.push_back(createFileEntry(parent, QString::fromStdWString(file->getName()))); + entries.push_back( + createFileEntry(parent, QString::fromStdWString(file->getName()))); } // Vector is already sorted: return true; } - std::shared_ptr<IFileTree> doClone() const { + std::shared_ptr<IFileTree> doClone() const + { return std::make_shared<VirtualFileTreeImpl>(nullptr, m_dirEntry); } @@ -54,6 +75,8 @@ private: /** * */ -std::shared_ptr<const VirtualFileTree> VirtualFileTree::makeTree(const DirectoryEntry* rootEntry) { +std::shared_ptr<const VirtualFileTree> +VirtualFileTree::makeTree(const DirectoryEntry* rootEntry) +{ return std::make_shared<VirtualFileTreeImpl>(nullptr, rootEntry); } diff --git a/src/virtualfiletree.h b/src/virtualfiletree.h index ebce5486..de3e6f71 100644 --- a/src/virtualfiletree.h +++ b/src/virtualfiletree.h @@ -26,7 +26,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. namespace MOShared { - class DirectoryEntry; +class DirectoryEntry; } /** @@ -38,9 +38,9 @@ namespace MOShared * This class does not expose mutable operations, so any mutable operations will * fail. */ -class VirtualFileTree : public MOBase::IFileTree { +class VirtualFileTree : public MOBase::IFileTree +{ public: - /** * @brief Create a new file tree representing the given VFS directory. * @@ -48,13 +48,15 @@ public: * * @return a file tree representing the VFS directory. */ - static std::shared_ptr<const VirtualFileTree> makeTree(const MOShared::DirectoryEntry* root); + static std::shared_ptr<const VirtualFileTree> + makeTree(const MOShared::DirectoryEntry* root); protected: - using IFileTree::IFileTree; - virtual bool doPopulate(std::shared_ptr<const IFileTree> parent, std::vector<std::shared_ptr<FileTreeEntry>>& entries) const = 0; + virtual bool + doPopulate(std::shared_ptr<const IFileTree> parent, + std::vector<std::shared_ptr<FileTreeEntry>>& entries) const = 0; }; #endif |
