From aa9a1fc07fb612547c1d1c5074d669b2dd258af9 Mon Sep 17 00:00:00 2001 From: Silarn Date: Wed, 3 Jul 2019 13:04:27 -0500 Subject: Refactor obsolete methods --- src/modlist.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modlist.cpp') diff --git a/src/modlist.cpp b/src/modlist.cpp index e2398cd6..abe4fd5d 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -1322,7 +1322,7 @@ bool ModList::moveSelection(QAbstractItemView *itemView, int direction) QModelIndexList rows = selectionModel->selectedRows(); if (direction > 0) { for (int i = 0; i < rows.size() / 2; ++i) { - rows.swap(i, rows.size() - i - 1); + rows.swapItemsAt(i, rows.size() - i - 1); } } for (QModelIndex idx : rows) { -- cgit v1.3.1 From aae6d6a5aa8d6b101fcc38388222a8a6e7ee2ec6 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 19 Jul 2019 01:09:19 -0400 Subject: replaced qWarning() --- src/bbcode.cpp | 9 ++++---- src/categories.cpp | 3 ++- src/directoryrefresher.cpp | 4 ++-- src/downloadmanager.cpp | 21 +++++++++--------- src/editexecutablesdialog.cpp | 19 ++++++++-------- src/executableslist.cpp | 6 +++--- src/filerenamer.cpp | 7 ++++-- src/icondelegate.cpp | 4 +++- src/installationmanager.cpp | 2 +- src/instancemanager.cpp | 14 +++++++----- src/mainwindow.cpp | 50 +++++++++++++++++++++++-------------------- src/moapplication.cpp | 5 +++-- src/modflagicondelegate.cpp | 4 +++- src/modinfo.cpp | 2 +- src/modinfodialogesps.cpp | 7 +++--- src/modlist.cpp | 7 +++--- src/modlistsortproxy.cpp | 6 ++++-- src/nexusinterface.cpp | 27 +++++++++++++---------- src/nxmaccessmanager.cpp | 2 +- src/organizercore.cpp | 46 +++++++++++++++++++-------------------- src/plugincontainer.cpp | 11 +++++----- src/pluginlist.cpp | 4 ++-- src/problemsdialog.cpp | 2 +- src/profile.cpp | 21 ++++++++++-------- src/profilesdialog.cpp | 4 ++-- src/settings.cpp | 5 +++-- 26 files changed, 161 insertions(+), 131 deletions(-) (limited to 'src/modlist.cpp') diff --git a/src/bbcode.cpp b/src/bbcode.cpp index 323dd128..d9b7debd 100644 --- a/src/bbcode.cpp +++ b/src/bbcode.cpp @@ -18,13 +18,13 @@ along with Mod Organizer. If not, see . */ #include "bbcode.h" - +#include #include #include - namespace BBCode { +namespace log = MOBase::log; class BBCodeMap { @@ -88,7 +88,7 @@ public: return temp.replace(tagIter->second.first, QString("%2").arg(color, content)); } } else { - qWarning("don't know how to deal with tag %s", qUtf8Printable(tagName)); + log::warn("don't know how to deal with tag {}", tagName); } } else { if (tagName == "*") { @@ -99,8 +99,7 @@ public: } else { // expression doesn't match. either the input string is invalid // or the expression is - qWarning("%s doesn't match the expression for %s", - qUtf8Printable(temp), qUtf8Printable(tagName)); + log::warn("{} doesn't match the expression for {}", temp, tagName); length = 0; return QString(); } diff --git a/src/categories.cpp b/src/categories.cpp index 9e5fa9f7..8f9d3ad8 100644 --- a/src/categories.cpp +++ b/src/categories.cpp @@ -21,6 +21,7 @@ along with Mod Organizer. If not, see . #include #include +#include #include #include @@ -294,7 +295,7 @@ bool CategoryFactory::isDecendantOf(int id, int parentID) const return isDecendantOf(m_Categories[index].m_ParentID, parentID); } } else { - qWarning("%d is no valid category id", id); + log::warn("{} is no valid category id", id); return false; } } diff --git a/src/directoryrefresher.cpp b/src/directoryrefresher.cpp index 3ce4691b..87305599 100644 --- a/src/directoryrefresher.cpp +++ b/src/directoryrefresher.cpp @@ -127,7 +127,7 @@ void DirectoryRefresher::addModFilesToStructure(DirectoryEntry *directoryStructu FilesOrigin &origin = directoryStructure->createOrigin(ToWString(modName), directoryW, priority); for (const QString &filename : stealFiles) { if (filename.isEmpty()) { - qWarning("Trying to find file with no name"); + log::warn("Trying to find file with no name"); continue; } QFileInfo fileInfo(filename); @@ -143,7 +143,7 @@ void DirectoryRefresher::addModFilesToStructure(DirectoryEntry *directoryStructu QString warnStr = fileInfo.absolutePath(); if (warnStr.isEmpty()) warnStr = filename; - qWarning("file not found: %s", qUtf8Printable(warnStr)); + log::warn("file not found: {}", warnStr); } } } else { diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index 648b102a..e3ceb261 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -924,7 +924,7 @@ void DownloadManager::queryInfo(int index) DownloadInfo *info = m_ActiveDownloads[index]; if (info->m_FileInfo->repository != "Nexus") { - qWarning("re-querying file info is currently only possible with Nexus"); + log::warn("re-querying file info is currently only possible with Nexus"); return; } @@ -976,7 +976,7 @@ void DownloadManager::queryInfoMd5(int index) DownloadInfo *info = m_ActiveDownloads[index]; if (info->m_FileInfo->repository != "Nexus") { - qWarning("re-querying file info is currently only possible with Nexus"); + log::warn("re-querying file info is currently only possible with Nexus"); return; } @@ -1016,7 +1016,7 @@ void DownloadManager::visitOnNexus(int index) DownloadInfo *info = m_ActiveDownloads[index]; if (info->m_FileInfo->repository != "Nexus") { - qWarning("Visiting mod page is currently only possible with Nexus"); + log::warn("Visiting mod page is currently only possible with Nexus"); return; } @@ -1614,8 +1614,9 @@ void DownloadManager::nxmFilesAvailable(QString, int, QVariant userData, QVarian } } else { if (info->m_FileInfo->fileID == 0) { - qWarning("could not determine file id for %s (state %d)", - qUtf8Printable(info->m_FileName), info->m_State); + log::warn( + "could not determine file id for {} (state {})", + info->m_FileName, info->m_State); } } @@ -1999,7 +2000,7 @@ void DownloadManager::downloadFinished(int index) resumeDownloadInt(index); } } else { - qWarning("no download index %d", index); + log::warn("no download index {}", index); } } @@ -2008,9 +2009,9 @@ void DownloadManager::downloadError(QNetworkReply::NetworkError error) { if (error != QNetworkReply::OperationCanceledError) { QNetworkReply *reply = qobject_cast(sender()); - qWarning("%s (%d)", reply != nullptr ? qUtf8Printable(reply->errorString()) - : "Download error occured", - error); + log::warn("{} ({})", + reply != nullptr ? reply->errorString() : "Download error occured", + error); } } @@ -2033,7 +2034,7 @@ void DownloadManager::metaDataChanged() } } } else { - qWarning("meta data event for unknown download"); + log::warn("meta data event for unknown download"); } } diff --git a/src/editexecutablesdialog.cpp b/src/editexecutablesdialog.cpp index 8929d207..3ec3d64f 100644 --- a/src/editexecutablesdialog.cpp +++ b/src/editexecutablesdialog.cpp @@ -101,9 +101,7 @@ ExecutablesList EditExecutablesDialog::getExecutablesList() const auto itor = m_executablesList.find(title); if (itor == m_executablesList.end()) { - qWarning().nospace() - << "getExecutablesList(): executable '" << title << "' not found"; - + log::warn("getExecutablesList(): executable '{}' not found", title); continue; } @@ -293,9 +291,10 @@ void EditExecutablesDialog::setEdits(const Executable& e) modIndex = ui->mods->findText(modName->value); if (modIndex == -1) { - qWarning().nospace() - << "executable '" << e.title() << "' uses mod '" << modName->value << "' " - << "as a custom overwrite, but that mod doesn't exist"; + log::warn( + "executable '{}' uses mod '{}' as a custom overwrite, but that mod " + "doesn't exist", + e.title(), modName->value); } } @@ -335,7 +334,7 @@ void EditExecutablesDialog::save() auto* e = selectedExe(); if (!e) { - qWarning("trying to save but nothing is selected"); + log::warn("trying to save but nothing is selected"); return; } @@ -475,13 +474,13 @@ void EditExecutablesDialog::on_remove_clicked() { auto* item = selectedItem(); if (!item) { - qWarning("trying to remove entry but nothing is selected"); + log::warn("trying to remove entry but nothing is selected"); return; } auto* exe = selectedExe(); if (!exe) { - qWarning("trying to remove entry but nothing is selected"); + log::warn("trying to remove entry but nothing is selected"); return; } @@ -646,7 +645,7 @@ void EditExecutablesDialog::on_configureLibraries_clicked() { auto* e = selectedExe(); if (!e) { - qWarning("trying to configure libraries but nothing is selected"); + log::warn("trying to configure libraries but nothing is selected"); return; } diff --git a/src/executableslist.cpp b/src/executableslist.cpp index 0ca880cd..fbb96bd4 100644 --- a/src/executableslist.cpp +++ b/src/executableslist.cpp @@ -250,9 +250,9 @@ void ExecutablesList::setExecutable(const Executable &exe, SetFlags flags) return; } - qWarning().nospace() - << "executable '" << itor->title() << "' was in the way and was " - << "renamed to '" << *newTitle << "'"; + log::warn( + "executable '{}' was in the way and was renamed to '{}'", + itor->title(), *newTitle); itor->title(*newTitle); itor = end(); diff --git a/src/filerenamer.cpp b/src/filerenamer.cpp index c5c6782b..b516c902 100644 --- a/src/filerenamer.cpp +++ b/src/filerenamer.cpp @@ -1,7 +1,10 @@ #include "filerenamer.h" +#include #include #include +using namespace MOBase; + FileRenamer::FileRenamer(QWidget* parent, QFlags flags) : m_parent(parent), m_flags(flags) { @@ -34,7 +37,7 @@ FileRenamer::RenameResults FileRenamer::rename(const QString& oldName, const QSt qDebug().nospace() << "removing " << newName; // user wants to replace the file, so remove it if (!QFile(newName).remove()) { - qWarning().nospace() << "failed to remove " << newName; + log::warn("failed to remove '{}'", newName); // removal failed, warn the user and allow canceling if (!removeFailed(newName)) { qDebug().nospace() << "canceling " << oldName; @@ -62,7 +65,7 @@ FileRenamer::RenameResults FileRenamer::rename(const QString& oldName, const QSt // target either didn't exist or was removed correctly if (!QFile::rename(oldName, newName)) { - qWarning().nospace() << "failed to rename " << oldName << " to " << newName; + log::warn("failed to rename '{}' to '{}'", oldName, newName); // renaming failed, warn the user and allow canceling if (!renameFailed(oldName, newName)) { diff --git a/src/icondelegate.cpp b/src/icondelegate.cpp index 249dae6f..39038f3c 100644 --- a/src/icondelegate.cpp +++ b/src/icondelegate.cpp @@ -18,12 +18,14 @@ along with Mod Organizer. If not, see . */ #include "icondelegate.h" +#include #include #include #include #include #include +using namespace MOBase; IconDelegate::IconDelegate(QObject *parent) : QStyledItemDelegate(parent) @@ -54,7 +56,7 @@ void IconDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, if (!QPixmapCache::find(fullIconId, &icon)) { icon = QIcon(iconId).pixmap(iconWidth, iconWidth); if (icon.isNull()) { - qWarning("failed to load icon %s", qUtf8Printable(iconId)); + log::warn("failed to load icon {}", iconId); } QPixmapCache::insert(fullIconId, icon); } diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp index e443a8f2..0e50de52 100644 --- a/src/installationmanager.cpp +++ b/src/installationmanager.cpp @@ -693,7 +693,7 @@ void InstallationManager::postInstallCleanup() QFile::setPermissions(fileInfo.absoluteFilePath(), QFile::ReadOther | QFile::WriteOther); } if (!QFile::remove(fileInfo.absoluteFilePath())) { - qWarning() << "Unable to delete " << fileInfo.absoluteFilePath(); + log::warn("Unable to delete {}", fileInfo.absoluteFilePath()); } } directoriesToRemove.insert(fileInfo.absolutePath()); diff --git a/src/instancemanager.cpp b/src/instancemanager.cpp index ddc2d067..55ef3fc8 100644 --- a/src/instancemanager.cpp +++ b/src/instancemanager.cpp @@ -21,6 +21,7 @@ along with Mod Organizer. If not, see . #include "instancemanager.h" #include "selectiondialog.h" #include +#include #include #include #include @@ -29,13 +30,13 @@ along with Mod Organizer. If not, see . #include #include +using namespace MOBase; static const char COMPANY_NAME[] = "Tannin"; static const char APPLICATION_NAME[] = "Mod Organizer"; static const char INSTANCE_KEY[] = "CurrentInstance"; - InstanceManager::InstanceManager() : m_AppSettings(COMPANY_NAME, APPLICATION_NAME) { @@ -86,10 +87,13 @@ bool InstanceManager::deleteLocalInstance(const QString &instanceId) const if (!MOBase::shellDelete(QStringList(instancePath),true)) { - qWarning("Failed to shell-delete \"%s\" (errorcode %lu), trying regular delete", qUtf8Printable(instancePath), ::GetLastError()); + log::warn( + "Failed to shell-delete \"{}\" (errorcode {}), trying regular delete", + instancePath, ::GetLastError()); + if (!MOBase::removeDir(instancePath)) { - qWarning("regular delete failed too"); + log::warn("regular delete failed too"); result = false; } } @@ -153,7 +157,7 @@ QString InstanceManager::queryInstanceName(const QStringList &instanceList) cons dialogText = dialog.textValue(); instanceId = sanitizeInstanceName(dialogText); if (instanceId != dialogText) { - if (QMessageBox::question( nullptr, + if (QMessageBox::question( nullptr, QObject::tr("Invalid instance name"), QObject::tr("The instance name \"%1\" is invalid. Use the name \"%2\" instead?").arg(dialogText,instanceId), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) { @@ -323,7 +327,7 @@ QString InstanceManager::sanitizeInstanceName(const QString &name) const // Don't end in spaces and periods new_name = new_name.remove(QRegExp("\\.*$")); new_name = new_name.remove(QRegExp(" *$")); - + // Recurse until stuff stops changing if (new_name != name) { return sanitizeInstanceName(new_name); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 9dbada1c..70ace8f1 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -800,7 +800,7 @@ void MainWindow::setupToolbar() ui->toolBar->insertWidget(m_linksSeparator, spacer); } else { - qWarning("no separator found on the toolbar, icons won't be right-aligned"); + log::warn("no separator found on the toolbar, icons won't be right-aligned"); } } @@ -1646,9 +1646,7 @@ void MainWindow::startExeAction() auto itor = list.find(title); if (itor == list.end()) { - qWarning().nospace() - << "startExeAction(): executable '" << title << "' not found"; - + log::warn("startExeAction(): executable '{}' not found", title); return; } @@ -1874,17 +1872,18 @@ void MainWindow::expandDataTreeItem(QTreeWidgetItem *item) if ((item->childCount() == 1) && (item->child(0)->data(0, Qt::UserRole).toString() == "__loaded_on_demand__")) { // read the data we need from the sub-item, then dispose of it QTreeWidgetItem *onDemandDataItem = item->child(0); - std::wstring path = ToWString(onDemandDataItem->data(0, Qt::UserRole + 1).toString()); + const QString path = onDemandDataItem->data(0, Qt::UserRole + 1).toString(); + std::wstring wspath = path.toStdWString(); bool conflictsOnly = onDemandDataItem->data(0, Qt::UserRole + 2).toBool(); - std::wstring virtualPath = (path + L"\\").substr(6) + ToWString(item->text(0)); + std::wstring virtualPath = (wspath + L"\\").substr(6) + ToWString(item->text(0)); DirectoryEntry *dir = m_OrganizerCore.directoryStructure()->findSubDirectoryRecursive(virtualPath); if (dir != nullptr) { QIcon folderIcon = (new QFileIconProvider())->icon(QFileIconProvider::Folder); QIcon fileIcon = (new QFileIconProvider())->icon(QFileIconProvider::File); - updateTo(item, path, *dir, conflictsOnly, &fileIcon, &folderIcon); + updateTo(item, wspath, *dir, conflictsOnly, &fileIcon, &folderIcon); } else { - qWarning("failed to update view of %ls", path.c_str()); + log::warn("failed to update view of {}", path); } m_RemoveWidget.push_back(item); QTimer::singleShot(5, this, SLOT(delayedRemove())); @@ -2380,10 +2379,17 @@ void MainWindow::processUpdates() { if (currentVersion > lastVersion) { //NOP - } else if (currentVersion < lastVersion) - qWarning() << 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()).toStdWString(); + } else 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()); + + log::warn("{}", text); + } + //save version in all case settings.setValue("version", currentVersion.toString()); } @@ -2924,7 +2930,7 @@ void MainWindow::refreshFilters() while (currentID != 0) { categoriesUsed.insert(currentID); if (!cycleTest.insert(currentID).second) { - qWarning("cycle in categories: %s", qUtf8Printable(SetJoin(cycleTest, ", "))); + log::warn("cycle in categories: {}", SetJoin(cycleTest, ", ")); break; } currentID = m_CategoryFactory.getParentID(m_CategoryFactory.getCategoryIndex(currentID)); @@ -4008,7 +4014,7 @@ void MainWindow::moveOverwriteContentToExistingMod() } if (modAbsolutePath.isNull()) { - qWarning("Mod %s has not been found, for some reason", qUtf8Printable(result)); + log::warn("Mod {} has not been found, for some reason", result); return; } @@ -4404,7 +4410,7 @@ void MainWindow::saveArchiveList() qDebug("%s saved", qUtf8Printable(QDir::toNativeSeparators(m_OrganizerCore.currentProfile()->getArchivesFileName()))); } } else { - qWarning("archive list not initialised"); + log::warn("archive list not initialised"); } } @@ -4421,7 +4427,7 @@ void MainWindow::checkModsForUpdates() m_OrganizerCore.doAfterLogin([this] () { this->checkModsForUpdates(); }); NexusInterface::instance(&m_PluginContainer)->getAccessManager()->apiCheck(apiKey); } else { - qWarning("You are not currently authenticated with Nexus. Please do so under Settings -> Nexus."); + log::warn("You are not currently authenticated with Nexus. Please do so under Settings -> Nexus."); } } @@ -5802,7 +5808,7 @@ void MainWindow::modUpdateCheck(std::multimap IDs) m_OrganizerCore.doAfterLogin([=]() { this->modUpdateCheck(IDs); }); NexusInterface::instance(&m_PluginContainer)->getAccessManager()->apiCheck(apiKey); } else - qWarning("You are not currently authenticated with Nexus. Please do so under Settings -> Nexus."); + log::warn("You are not currently authenticated with Nexus. Please do so under Settings -> Nexus."); } } @@ -5918,7 +5924,7 @@ void MainWindow::finishUpdateInfo() } if (!finalMods.empty() && organizedGames.empty()) - qWarning("All of your mods have been checked recently. We restrict update checks to help preserve your available API requests."); + log::warn("All of your mods have been checked recently. We restrict update checks to help preserve your available API requests."); for (auto game : organizedGames) NexusInterface::instance(&m_PluginContainer)->requestUpdates(game.second, this, QVariant(), game.first, QString()); @@ -6368,9 +6374,7 @@ void MainWindow::removeFromToolbar() auto itor = list.find(title); if (itor == list.end()) { - qWarning().nospace() - << "removeFromToolbar(): executable '" << title << "' not found"; - + log::warn("removeFromToolbar(): executable '{}' not found", title); return; } @@ -6570,7 +6574,7 @@ void MainWindow::processLOOTOut(const std::string &lootOut, std::string &errorMe if (progidx != std::string::npos) { dialog.setLabelText(line.substr(progidx + 11).c_str()); } else if (erroridx != std::string::npos) { - qWarning("%s", line.c_str()); + log::warn("{}", line); errorMessages.append(boost::algorithm::trim_copy(line.substr(erroridx + 8)) + "\n"); } else { std::smatch match; @@ -6928,7 +6932,7 @@ void MainWindow::dropLocalFile(const QUrl &url, const QString &outputDir, bool m { QFileInfo file(url.toLocalFile()); if (!file.exists()) { - qWarning("invalid source file: %s", qUtf8Printable(file.absoluteFilePath())); + log::warn("invalid source file: {}", file.absoluteFilePath()); return; } QString target = outputDir + "/" + file.fileName(); diff --git a/src/moapplication.cpp b/src/moapplication.cpp index 5652833a..3d55b28d 100644 --- a/src/moapplication.cpp +++ b/src/moapplication.cpp @@ -20,6 +20,7 @@ along with Mod Organizer. If not, see . #include "moapplication.h" #include #include +#include #include #include #include @@ -36,7 +37,7 @@ along with Mod Organizer. If not, see . #include -using MOBase::reportError; +using namespace MOBase; class ProxyStyle : public QProxyStyle { @@ -137,7 +138,7 @@ void MOApplication::updateStyle(const QString &fileName) if (QFile::exists(fileName)) { setStyleSheet(QString("file:///%1").arg(fileName)); } else { - qWarning("invalid stylesheet: %s", qUtf8Printable(fileName)); + log::warn("invalid stylesheet: {}", fileName); } } } diff --git a/src/modflagicondelegate.cpp b/src/modflagicondelegate.cpp index c3142962..7110a590 100644 --- a/src/modflagicondelegate.cpp +++ b/src/modflagicondelegate.cpp @@ -1,6 +1,8 @@ #include "modflagicondelegate.h" +#include #include +using namespace MOBase; ModInfo::EFlag ModFlagIconDelegate::m_ConflictFlags[4] = { ModInfo::FLAG_CONFLICT_MIXED , ModInfo::FLAG_CONFLICT_OVERWRITE @@ -117,7 +119,7 @@ QString ModFlagIconDelegate::getFlagIcon(ModInfo::EFlag flag) const case ModInfo::FLAG_PLUGIN_SELECTED: return QString(); case ModInfo::FLAG_TRACKED: return QStringLiteral(":/MO/gui/tracked"); default: - qWarning("ModInfo flag %d has no defined icon", flag); + log::warn("ModInfo flag {} has no defined icon", flag); return QString(); } } diff --git a/src/modinfo.cpp b/src/modinfo.cpp index 92c7366c..ca6e8046 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -320,7 +320,7 @@ bool ModInfo::checkAllForUpdate(PluginContainer *pluginContainer, QObject *recei } if (organizedGames.empty()) { - qWarning() << 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( diff --git a/src/modinfodialogesps.cpp b/src/modinfodialogesps.cpp index fba5d39a..3130b4bd 100644 --- a/src/modinfodialogesps.cpp +++ b/src/modinfodialogesps.cpp @@ -3,8 +3,9 @@ #include "modinfodialog.h" #include "settings.h" #include +#include -using MOBase::reportError; +using namespace MOBase; class ESPItem { @@ -297,7 +298,7 @@ void ESPsTab::onActivate() } if (esp->isActive()) { - qWarning("ESPsTab::onActive(): item is already active"); + log::warn("ESPsTab::onActive(): item is already active"); return; } @@ -348,7 +349,7 @@ void ESPsTab::onDeactivate() } if (!esp->isActive()) { - qWarning("ESPsTab::onDeactivate(): item is already inactive"); + log::warn("ESPsTab::onDeactivate(): item is already inactive"); return; } diff --git a/src/modlist.cpp b/src/modlist.cpp index 7b71355c..df25df0d 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -275,7 +275,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const return QString(); } } else { - qWarning("category %d doesn't exist (may have been removed)", category); + log::warn("category {} doesn't exist (may have been removed)", category); modInfo->setCategory(category, false); return QString(); } @@ -618,8 +618,9 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role) result = true; } break; default: { - qWarning("edit on column \"%s\" not supported", - getColumnName(index.column()).toUtf8().constData()); + log::warn( + "edit on column \"{}\" not supported", + getColumnName(index.column()).toUtf8().constData()); result = false; } break; } diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp index 2d9ea4a5..1127c7d4 100644 --- a/src/modlistsortproxy.cpp +++ b/src/modlistsortproxy.cpp @@ -22,6 +22,7 @@ along with Mod Organizer. If not, see . #include "profile.h" #include "messagedialog.h" #include "qtgroupingproxy.h" +#include #include #include #include @@ -30,6 +31,7 @@ along with Mod Organizer. If not, see . #include #include +using namespace MOBase; ModListSortProxy::ModListSortProxy(Profile* profile, QObject *parent) : QSortFilterProxyModel(parent) @@ -240,7 +242,7 @@ bool ModListSortProxy::lessThan(const QModelIndex &left, // nop, already compared by priority } break; default: { - qWarning() << "Sorting is not defined for column " << left.column(); + log::warn("Sorting is not defined for column {}", left.column()); } break; } return lt; @@ -474,7 +476,7 @@ bool ModListSortProxy::filterAcceptsRow(int row, const QModelIndex &parent) cons } if (row >= static_cast(m_Profile->numMods())) { - qWarning("invalid row index: %d", row); + log::warn("invalid row index: {}", row); return false; } diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp index 2bcd72f3..008f3c0d 100644 --- a/src/nexusinterface.cpp +++ b/src/nexusinterface.cpp @@ -25,6 +25,7 @@ along with Mod Organizer. If not, see . #include "bbcode.h" #include #include +#include #include #include @@ -695,9 +696,13 @@ 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."); - qWarning() << warning.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; } @@ -747,8 +752,8 @@ void NexusInterface::nextRequest() 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 { - qWarning() << 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."); + 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; @@ -828,16 +833,16 @@ void NexusInterface::requestFinished(std::list::iterator iter) m_User.limits(parseLimits(reply)); if (!m_User.exhausted()) { - qWarning("You appear to be making requests to the Nexus API too quickly and are being throttled. Please inform the MO2 team."); + log::warn("You appear to be making requests to the Nexus API too quickly and are being throttled. Please inform the MO2 team."); } else { - qWarning("All API requests have been consumed and are now being denied."); + log::warn("All API requests have been consumed and are now being denied."); } emit requestsChanged(getAPIStats(), m_User); - qWarning("Error: %s", reply->errorString().toUtf8().constData()); + log::warn("Error: {}", reply->errorString()); } else { - qWarning("request failed: %s", reply->errorString().toUtf8().constData()); + log::warn("request failed: {}", reply->errorString()); } emit nxmRequestFailed(iter->m_GameName, iter->m_ModID, iter->m_FileID, iter->m_UserData, iter->m_ID, reply->error(), reply->errorString()); } else { @@ -940,7 +945,7 @@ void NexusInterface::requestError(QNetworkReply::NetworkError) { QNetworkReply *reply = qobject_cast(sender()); if (reply == nullptr) { - qWarning("invalid sender type"); + log::warn("invalid sender type"); return; } @@ -955,7 +960,7 @@ void NexusInterface::requestTimeout() { QTimer *timer = qobject_cast(sender()); if (timer == nullptr) { - qWarning("invalid sender type"); + log::warn("invalid sender type"); return; } for (std::list::iterator iter = m_ActiveRequest.begin(); iter != m_ActiveRequest.end(); ++iter) { diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp index c413e156..9f40894e 100644 --- a/src/nxmaccessmanager.cpp +++ b/src/nxmaccessmanager.cpp @@ -612,7 +612,7 @@ void NXMAccessManager::clearCookies() if (jar != nullptr) { jar->clear(); } else { - qWarning("failed to clear cookies, invalid cookie jar"); + log::warn("failed to clear cookies, invalid cookie jar"); } } diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 400f5391..dbff1a2a 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -200,26 +200,26 @@ bool checkService() try { serviceManagerHandle = OpenSCManager(NULL, NULL, SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG); if (!serviceManagerHandle) { - qWarning("failed to open service manager (query status) (error %d)", GetLastError()); + log::warn("failed to open service manager (query status) (error {})", GetLastError()); throw 1; } serviceHandle = OpenService(serviceManagerHandle, L"EventLog", SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG); if (!serviceHandle) { - qWarning("failed to open EventLog service (query status) (error %d)", GetLastError()); + log::warn("failed to open EventLog service (query status) (error {})", GetLastError()); throw 2; } if (QueryServiceConfig(serviceHandle, NULL, 0, &bytesNeeded) || (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) { - qWarning("failed to get size of service config (error %d)", GetLastError()); + log::warn("failed to get size of service config (error {})", GetLastError()); throw 3; } DWORD serviceConfigSize = bytesNeeded; serviceConfig = (LPQUERY_SERVICE_CONFIG)LocalAlloc(LMEM_FIXED, serviceConfigSize); if (!QueryServiceConfig(serviceHandle, serviceConfig, serviceConfigSize, &bytesNeeded)) { - qWarning("failed to query service config (error %d)", GetLastError()); + log::warn("failed to query service config (error {})", GetLastError()); throw 4; } @@ -230,14 +230,14 @@ bool checkService() if (QueryServiceStatusEx(serviceHandle, SC_STATUS_PROCESS_INFO, NULL, 0, &bytesNeeded) || (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) { - qWarning("failed to get size of service status (error %d)", GetLastError()); + log::warn("failed to get size of service status (error {})", GetLastError()); throw 5; } DWORD serviceStatusSize = bytesNeeded; serviceStatus = (LPSERVICE_STATUS_PROCESS)LocalAlloc(LMEM_FIXED, serviceStatusSize); if (!QueryServiceStatusEx(serviceHandle, SC_STATUS_PROCESS_INFO, (LPBYTE)serviceStatus, serviceStatusSize, &bytesNeeded)) { - qWarning("failed to query service status (error %d)", GetLastError()); + log::warn("failed to query service status (error {})", GetLastError()); throw 6; } @@ -402,8 +402,9 @@ void OrganizerCore::storeSettings() if (result == QSettings::NoError) { QString errMsg = commitSettings(iniFile); if (!errMsg.isEmpty()) { - qWarning("settings file not writable, may be locked by another " - "application, trying direct write"); + log::warn( + "settings file not writable, may be locked by another " + "application, trying direct write"); writeTarget = iniFile; result = storeSettings(iniFile); } @@ -1381,9 +1382,9 @@ bool OrganizerCore::previewFileWithAlternatives( // sanity check, this shouldn't happen unless the caller passed an // incorrect id - qWarning().nospace() - << "selected preview origin " << selectedOrigin << " not found in " - << "list of alternatives"; + log::warn( + "selected preview origin {} not found in list of alternatives", + selectedOrigin); } for (int id : origins) { @@ -1798,8 +1799,7 @@ HANDLE OrganizerCore::startApplication(const QString &executable, currentDirectory = exe.workingDirectory(); } } catch (const std::runtime_error &) { - qWarning("\"%s\" not set up as executable", - qUtf8Printable(executable)); + log::warn("\"{}\" not set up as executable", executable); binary = QFileInfo(executable); } } @@ -1881,7 +1881,7 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode, IL // Wait for a an event on the handle, a key press, mouse click or timeout res = MsgWaitForMultipleObjects(1, &handle, FALSE, 200, QS_KEY | QS_MOUSEBUTTON); if (res == WAIT_FAILED) { - qWarning() << "Failed waiting for process completion : MsgWaitForMultipleObjects WAIT_FAILED" << GetLastError(); + log::warn("Failed waiting for process completion : MsgWaitForMultipleObjects WAIT_FAILED {}", GetLastError()); break; } @@ -1897,7 +1897,7 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode, IL if (res == WAIT_OBJECT_0) { // process we were waiting on has completed if (originalHandle && exitCode && !::GetExitCodeProcess(handle, exitCode)) - qWarning() << "Failed getting exit code of complete process :" << GetLastError(); + log::warn("Failed getting exit code of complete process: {}", GetLastError()); CloseHandle(handle); handle = INVALID_HANDLE_VALUE; originalHandle = false; @@ -1962,7 +1962,7 @@ HANDLE OrganizerCore::findAndOpenAUSVFSProcess(const std::vector& hidde DWORD pids[querySize]; size_t found = querySize; if (!::GetVFSProcessList(&found, pids)) { - qWarning() << "Failed seeking USVFS processes : GetVFSProcessList failed?!"; + log::warn("Failed seeking USVFS processes : GetVFSProcessList failed?!"); return INVALID_HANDLE_VALUE; } @@ -1974,7 +1974,7 @@ HANDLE OrganizerCore::findAndOpenAUSVFSProcess(const std::vector& hidde HANDLE handle = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | SYNCHRONIZE, FALSE, pids[i]); if (handle == INVALID_HANDLE_VALUE) { - qWarning() << "Failed openning USVFS process " << pids[i] << " : OpenProcess failed" << GetLastError(); + log::warn("Failed opening USVFS process {}: OpenProcess failed {}", pids[i], GetLastError()); continue; } @@ -2118,7 +2118,7 @@ void OrganizerCore::updateModsActiveState(const QList &modIndices, dir.entryList(QStringList() << "*.esm", QDir::Files)) { const FileEntry::Ptr file = m_DirectoryStructure->findFile(ToWString(esm)); if (file.get() == nullptr) { - qWarning("failed to activate %s", qUtf8Printable(esm)); + log::warn("failed to activate {}", esm); continue; } @@ -2134,7 +2134,7 @@ void OrganizerCore::updateModsActiveState(const QList &modIndices, dir.entryList(QStringList() << "*.esl", QDir::Files)) { const FileEntry::Ptr file = m_DirectoryStructure->findFile(ToWString(esl)); if (file.get() == nullptr) { - qWarning("failed to activate %s", qUtf8Printable(esl)); + log::warn("failed to activate {}", esl); continue; } @@ -2150,7 +2150,7 @@ void OrganizerCore::updateModsActiveState(const QList &modIndices, for (const QString &esp : esps) { const FileEntry::Ptr file = m_DirectoryStructure->findFile(ToWString(esp)); if (file.get() == nullptr) { - qWarning("failed to activate %s", qUtf8Printable(esp)); + log::warn("failed to activate {}", esp); continue; } @@ -2558,7 +2558,7 @@ std::vector OrganizerCore::activeProblems() const // of a "log spam". But since this is a sevre 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. - qWarning("hook.dll found in game folder: %s", qUtf8Printable(hookdll)); + log::warn("hook.dll found in game folder: {}", hookdll); problems.push_back(PROBLEM_MO1SCRIPTEXTENDERWORKAROUND); } return problems; @@ -2604,7 +2604,7 @@ void OrganizerCore::startGuidedFix(unsigned int) const bool OrganizerCore::saveCurrentLists() { if (m_DirectoryUpdate) { - qWarning("not saving lists during directory update"); + log::warn("not saving lists during directory update"); return false; } @@ -2698,7 +2698,7 @@ std::vector OrganizerCore::fileMapping(const QString &profileName, result.reserve(result.size() + saveMap.size()); result.insert(result.end(), saveMap.begin(), saveMap.end()); } else { - qWarning("local save games not supported by this game plugin"); + log::warn("local save games not supported by this game plugin"); } } diff --git a/src/plugincontainer.cpp b/src/plugincontainer.cpp index 2126c5ef..d47fa2c6 100644 --- a/src/plugincontainer.cpp +++ b/src/plugincontainer.cpp @@ -69,7 +69,7 @@ bool PluginContainer::verifyPlugin(IPlugin *plugin) if (plugin == nullptr) { return false; } else if (!plugin->init(new OrganizerProxy(m_Organizer, this, plugin->name()))) { - qWarning("plugin failed to initialize"); + log::warn("plugin failed to initialize"); return false; } return true; @@ -167,9 +167,10 @@ bool PluginContainer::registerPlugin(QObject *plugin, const QString &fileName) qDebug("loaded plugin \"%s\"", qUtf8Printable(QFileInfo(pluginName).fileName())); } else { - qWarning("plugin \"%s\" 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.", - qUtf8Printable(pluginName)); + 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.", + pluginName); } } } @@ -298,7 +299,7 @@ void PluginContainer::loadPlugins() m_PluginLoaders.push_back(pluginLoader.release()); } else { m_FailedPlugins.push_back(pluginName); - qWarning("plugin \"%s\" failed to load (may be outdated)", qUtf8Printable(pluginName)); + log::warn("plugin \"{}\" failed to load (may be outdated)", pluginName); } } } diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index 2edb92f5..2fb743d0 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -417,7 +417,7 @@ void PluginList::addInformation(const QString &name, const QString &message) if (iter != m_ESPsByName.end()) { m_AdditionalInfo[name.toLower()].m_Messages.append(message); } else { - qWarning("failed to associate message for \"%s\"", qUtf8Printable(name)); + log::warn("failed to associate message for \"{}\"", name); } } @@ -694,7 +694,7 @@ void PluginList::setState(const QString &name, PluginStates state) { m_ESPs[iter->second].m_Enabled = (state == IPluginList::STATE_ACTIVE) || m_ESPs[iter->second].m_ForceEnabled; } else { - qWarning("Plugin not found: %s", qUtf8Printable(name)); + log::warn("Plugin not found: {}", name); } } diff --git a/src/problemsdialog.cpp b/src/problemsdialog.cpp index 1e8e800f..da09935b 100644 --- a/src/problemsdialog.cpp +++ b/src/problemsdialog.cpp @@ -96,7 +96,7 @@ void ProblemsDialog::startFix() { QObject *fixButton = QObject::sender(); if (fixButton == NULL) { - qWarning("no button"); + log::warn("no button"); return; } IPluginDiagnose *plugin = reinterpret_cast(fixButton ->property("fix").value()); diff --git a/src/profile.cpp b/src/profile.cpp index 01906903..d4778305 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -125,7 +125,7 @@ Profile::Profile(const QDir &directory, IPluginGame const *gamePlugin) findProfileSettings(); if (!QFile::exists(m_Directory.filePath("modlist.txt"))) { - qWarning("missing modlist.txt in %s", qUtf8Printable(directory.path())); + log::warn("missing modlist.txt in {}", directory.path()); touchFile(m_Directory.filePath("modlist.txt")); } @@ -307,7 +307,7 @@ void Profile::renameModInAllProfiles(const QString& oldName, const QString& newN if (modList.exists()) renameModInList(modList, oldName, newName); else - qWarning("Profile has no modlist.txt : %s", qUtf8Printable(profileIter.filePath())); + log::warn("Profile has no modlist.txt: {}", profileIter.filePath()); } } @@ -328,7 +328,7 @@ void Profile::renameModInList(QFile &modList, const QString &oldName, const QStr if (line.length() == 0) { // ignore empty lines - qWarning("mod list contained invalid data: empty line"); + log::warn("mod list contained invalid data: empty line"); continue; } @@ -343,7 +343,7 @@ void Profile::renameModInList(QFile &modList, const QString &oldName, const QStr if (modName.isEmpty()) { // file broken? - qWarning("mod list contained invalid data: missing mod name"); + log::warn("mod list contained invalid data: missing mod name"); continue; } @@ -424,8 +424,9 @@ void Profile::refreshModStatus() m_ModStatus[modIndex].m_Priority = index++; } } else { - qWarning("no mod state for \"%s\" (profile \"%s\")", - qUtf8Printable(modName), qUtf8Printable(m_Directory.path())); + log::warn( + "no mod state for \"{}\" (profile \"{}\")", + modName, m_Directory.path()); // need to rewrite the modlist to fix this modStatusModified = true; } @@ -495,8 +496,10 @@ void Profile::dumpModStatus() const { for (unsigned int i = 0; i < m_ModStatus.size(); ++i) { ModInfo::Ptr info = ModInfo::getByIndex(i); - qWarning("%d: %s - %d (%s)", i, info->name().toUtf8().constData(), 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"); } } @@ -803,7 +806,7 @@ bool Profile::localSettingsEnabled() const QStringList missingFiles; for (QString file : m_GamePlugin->iniFiles()) { if (!QFile::exists(m_Directory.filePath(file))) { - qWarning("missing %s in %s", qUtf8Printable(file), qUtf8Printable(m_Directory.path())); + log::warn("missing {} in {}", file, m_Directory.path()); missingFiles << file; } } diff --git a/src/profilesdialog.cpp b/src/profilesdialog.cpp index f9ea655f..d7863fc8 100644 --- a/src/profilesdialog.cpp +++ b/src/profilesdialog.cpp @@ -214,9 +214,9 @@ void ProfilesDialog::on_removeProfileButton_clicked() delete item; } if (!shellDelete(QStringList(profilePath))) { - qWarning("Failed to shell-delete \"%s\" (errorcode %lu), trying regular delete", qUtf8Printable(profilePath), ::GetLastError()); + log::warn("Failed to shell-delete \"{}\" (errorcode {}), trying regular delete", profilePath, ::GetLastError()); if (!removeDir(profilePath)) { - qWarning("regular delete failed too"); + log::warn("regular delete failed too"); } } } diff --git a/src/settings.cpp b/src/settings.cpp index e622d632..92ae2251 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -165,8 +165,9 @@ void Settings::registerPlugin(IPlugin *plugin) for (const PluginSetting &setting : plugin->settings()) { QVariant temp = m_Settings.value("Plugins/" + plugin->name() + "/" + setting.key, setting.defaultValue); if (!temp.convert(setting.defaultValue.type())) { - qWarning("failed to interpret \"%s\" as correct type for \"%s\" in plugin \"%s\", using default", - qUtf8Printable(temp.toString()), qUtf8Printable(setting.key), qUtf8Printable(plugin->name())); + 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; -- cgit v1.3.1 From e071dfdfaa369a475a2d93df623c1696feee56ba Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 19 Jul 2019 02:47:13 -0400 Subject: changed qCritical() to log::error() removed now unused vlog() --- src/browserdialog.cpp | 12 ++++---- src/categories.cpp | 10 +++---- src/downloadlist.cpp | 5 ++-- src/downloadmanager.cpp | 10 +++++-- src/envmodule.cpp | 66 +++++++++++++++++------------------------- src/envsecurity.cpp | 58 +++++++++++++------------------------ src/envshortcut.cpp | 56 +++++++++++++++++------------------ src/envshortcut.h | 9 ------ src/envwindows.cpp | 19 ++++++------ src/executableslist.cpp | 10 +++---- src/filerenamer.cpp | 2 +- src/filterwidget.cpp | 5 +++- src/forcedloaddialogwidget.cpp | 9 +++--- src/installationmanager.cpp | 7 ++--- src/loglist.cpp | 18 ------------ src/mainwindow.cpp | 34 +++++++++++----------- src/moapplication.cpp | 10 ++++--- src/modinfo.cpp | 5 +--- src/modinfodialog.cpp | 12 ++++---- src/modinfodialogconflicts.cpp | 6 ++-- src/modinfodialogfiletree.cpp | 9 +++--- src/modinfodialogimages.cpp | 9 +++--- src/modinforegular.cpp | 20 ++++++------- src/modlist.cpp | 12 ++++---- src/modlistsortproxy.cpp | 2 +- src/nexusinterface.cpp | 28 +++++++++--------- src/organizercore.cpp | 22 +++++++------- src/overwriteinfodialog.cpp | 6 ++-- src/persistentcookiejar.cpp | 8 +++-- src/plugincontainer.cpp | 5 ++-- src/pluginlist.cpp | 10 +++---- src/profile.cpp | 4 +-- src/settings.cpp | 14 ++------- src/settingsdialog.cpp | 1 - src/shared/directoryentry.cpp | 23 ++++++++------- src/shared/error_report.h | 2 -- src/syncoverwritedialog.cpp | 3 +- src/texteditor.cpp | 7 +++-- src/transfersavesdialog.cpp | 13 ++++----- 39 files changed, 251 insertions(+), 310 deletions(-) (limited to 'src/modlist.cpp') diff --git a/src/browserdialog.cpp b/src/browserdialog.cpp index e186ad63..1fde7f15 100644 --- a/src/browserdialog.cpp +++ b/src/browserdialog.cpp @@ -24,9 +24,10 @@ along with Mod Organizer. If not, see . #include "messagedialog.h" #include "report.h" #include "persistentcookiejar.h" +#include "settings.h" #include -#include "settings.h" +#include #include #include @@ -38,6 +39,7 @@ along with Mod Organizer. If not, see . #include #include +using namespace MOBase; BrowserDialog::BrowserDialog(QWidget *parent) @@ -192,12 +194,12 @@ void BrowserDialog::unsupportedContent(QNetworkReply *reply) try { QWebEnginePage *page = qobject_cast(sender()); if (page == nullptr) { - qCritical("sender not a page"); + log::error("sender not a page"); return; } BrowserView *view = qobject_cast(page->view()); if (view == nullptr) { - qCritical("no view?"); + log::error("no view?"); return; } @@ -206,14 +208,14 @@ void BrowserDialog::unsupportedContent(QNetworkReply *reply) if (isVisible()) { MessageDialog::showMessage(tr("failed to start download"), this); } - qCritical("exception downloading unsupported content: %s", e.what()); + log::error("exception downloading unsupported content: {}", e.what()); } } void BrowserDialog::downloadRequested(const QNetworkRequest &request) { - qCritical("download request %s ignored", request.url().toString().toUtf8().constData()); + log::error("download request {} ignored", request.url().toString()); } diff --git a/src/categories.cpp b/src/categories.cpp index 8f9d3ad8..7acf6ff5 100644 --- a/src/categories.cpp +++ b/src/categories.cpp @@ -62,8 +62,9 @@ void CategoryFactory::loadCategories() ++lineNum; QList cells = line.split('|'); if (cells.count() != 4) { - qCritical("invalid category line %d: %s (%d cells)", - lineNum, line.constData(), cells.count()); + log::error( + "invalid category line {}: {} ({} cells)", + lineNum, line.constData(), cells.count()); } else { std::vector nexusIDs; if (cells[2].length() > 0) { @@ -73,7 +74,7 @@ void CategoryFactory::loadCategories() bool ok = false; int temp = iter->toInt(&ok); if (!ok) { - qCritical("invalid category id %s", iter->constData()); + log::error("invalid category id {}", iter->constData()); } nexusIDs.push_back(temp); } @@ -83,8 +84,7 @@ void CategoryFactory::loadCategories() int id = cells[0].toInt(&cell0Ok); int parentID = cells[3].trimmed().toInt(&cell3Ok); if (!cell0Ok || !cell3Ok) { - qCritical("invalid category line %d: %s", - lineNum, line.constData()); + log::error("invalid category line {}: {}", lineNum, line.constData()); } addCategory(id, QString::fromUtf8(cells[1].constData()), nexusIDs, parentID); } diff --git a/src/downloadlist.cpp b/src/downloadlist.cpp index 5e698e0e..36bc2b7f 100644 --- a/src/downloadlist.cpp +++ b/src/downloadlist.cpp @@ -19,12 +19,13 @@ along with Mod Organizer. If not, see . #include "downloadlist.h" #include "downloadmanager.h" +#include #include #include #include - #include +using namespace MOBase; DownloadList::DownloadList(DownloadManager *manager, QObject *parent) : QAbstractTableModel(parent), m_Manager(manager) @@ -192,7 +193,7 @@ void DownloadList::update(int row) else if (row < this->rowCount()) emit dataChanged(this->index(row, 0, QModelIndex()), this->index(row, this->columnCount(QModelIndex())-1, QModelIndex())); else - qCritical("invalid row %d in download list, update failed", row); + log::error("invalid row {} in download list, update failed", row); } QString DownloadList::sizeFormat(quint64 size) const diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index e3ceb261..348b2108 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -660,7 +660,7 @@ void DownloadManager::removeFile(int index, bool deleteFile) if ((download->m_State == STATE_STARTED) || (download->m_State == STATE_DOWNLOADING)) { // shouldn't have been possible - qCritical("tried to remove active download"); + log::error("tried to remove active download"); endDisableDirWatcher(); return; } @@ -798,7 +798,7 @@ void DownloadManager::removeDownload(int index, bool deleteFile) emit update(-1); endDisableDirWatcher(); } catch (const std::exception &e) { - qCritical("failed to remove download: %s", e.what()); + log::error("failed to remove download: {}", e.what()); } refreshList(); } @@ -2069,7 +2069,11 @@ void DownloadManager::writeData(DownloadInfo *info) if (ret < info->m_Reply->size()) { QString fileName = info->m_FileName; // m_FileName may be destroyed after setState setState(info, DownloadState::STATE_CANCELED); - qCritical(QString("Unable to write download \"%2\" to drive (return %1)").arg(ret).arg(info->m_FileName).toLocal8Bit()); + + 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)); diff --git a/src/envmodule.cpp b/src/envmodule.cpp index 1717da15..aae4e0b1 100644 --- a/src/envmodule.cpp +++ b/src/envmodule.cpp @@ -1,6 +1,7 @@ #include "envmodule.h" #include "env.h" #include +#include namespace env { @@ -114,9 +115,9 @@ Module::FileInfo Module::getFileInfo() const return {}; } - qCritical().nospace().noquote() - << "GetFileVersionInfoSizeW() failed on '" << m_path << "', " - << formatSystemMessageQ(e); + log::error( + "GetFileVersionInfoSizeW() failed on '{}', {}", + m_path, formatSystemMessageQ(e)); return {}; } @@ -127,9 +128,9 @@ Module::FileInfo Module::getFileInfo() const if (!GetFileVersionInfoW(wspath.c_str(), 0, size, buffer.get())) { const auto e = GetLastError(); - qCritical().nospace().noquote() - << "GetFileVersionInfoW() failed on '" << m_path << "', " - << formatSystemMessageQ(e); + log::error( + "GetFileVersionInfoW() failed on '{}', {}", + m_path, formatSystemMessageQ(e)); return {}; } @@ -161,9 +162,9 @@ VS_FIXEDFILEINFO Module::getFixedFileInfo(std::byte* buffer) const // signature is always 0xfeef04bd if (fi->dwSignature != 0xfeef04bd) { - qCritical().nospace().noquote() - << "bad file info signature 0x" << hex << fi->dwSignature << " for " - << "'" << m_path << "'"; + log::error( + "bad file info signature {:#x} for '{}'", + fi->dwSignature, m_path); return {}; } @@ -187,9 +188,7 @@ QString Module::getFileDescription(std::byte* buffer) const buffer, L"\\VarFileInfo\\Translation", &valuePointer, &valueSize); if (!ret || !valuePointer || valueSize == 0) { - qCritical().nospace().noquote() - << "VerQueryValueW() for translations failed on '" << m_path << "'"; - + log::error("VerQueryValueW() for translations failed on '{}'", m_path); return {}; } @@ -254,9 +253,9 @@ QDateTime Module::getTimestamp(const VS_FIXEDFILEINFO& fi) const if (h.get() == INVALID_HANDLE_VALUE) { const auto e = GetLastError(); - qCritical().nospace().noquote() - << "can't open file '" << m_path << "' for timestamp, " - << formatSystemMessageQ(e); + log::error( + "can't open file '{}' for timestamp, {}", + m_path, formatSystemMessageQ(e)); return {}; } @@ -264,9 +263,10 @@ QDateTime Module::getTimestamp(const VS_FIXEDFILEINFO& fi) const // getting the file time if (!GetFileTime(h.get(), &ft, nullptr, nullptr)) { const auto e = GetLastError(); - qCritical().nospace().noquote() - << "can't get file time for '" << m_path << "', " - << formatSystemMessageQ(e); + + log::error( + "can't get file time for '{}', {}", + m_path, formatSystemMessageQ(e)); return {}; } @@ -281,11 +281,9 @@ QDateTime Module::getTimestamp(const VS_FIXEDFILEINFO& fi) const SYSTEMTIME utc = {}; if (!FileTimeToSystemTime(&ft, &utc)) { - qCritical().nospace().noquote() - << "FileTimeToSystemTime() failed on timestamp " - << "high=0x" << hex << ft.dwHighDateTime << " " - << "low=0x" << hex << ft.dwLowDateTime << " for " - << "'" << m_path << "'"; + log::error( + "FileTimeToSystemTime() failed on timestamp high={:#x} low={:#x} for '{}'", + ft.dwHighDateTime, ft.dwLowDateTime, m_path); return {}; } @@ -307,18 +305,14 @@ QString Module::getMD5() const QFile f(m_path); if (!f.open(QFile::ReadOnly)) { - qCritical().nospace().noquote() - << "failed to open file '" << m_path << "' for md5"; - + log::error("failed to open file '{}' for md5", m_path); return {}; } // hashing QCryptographicHash hash(QCryptographicHash::Md5); if (!hash.addData(&f)) { - qCritical().nospace().noquote() - << "failed to calculate md5 for '" << m_path << "'"; - + log::error("failed to calculate md5 for '{}'", m_path); return {}; } @@ -334,11 +328,7 @@ std::vector getLoadedModules() if (snapshot.get() == INVALID_HANDLE_VALUE) { const auto e = GetLastError(); - - qCritical().nospace().noquote() - << "CreateToolhelp32Snapshot() failed, " - << formatSystemMessageQ(e); - + log::error("CreateToolhelp32Snapshot() failed, {}", formatSystemMessageQ(e)); return {}; } @@ -349,10 +339,7 @@ std::vector getLoadedModules() if (!Module32First(snapshot.get(), &me)) { const auto e = GetLastError(); - - qCritical().nospace().noquote() - << "Module32First() failed, " << formatSystemMessageQ(e); - + log::error("Module32First() failed, {}", formatSystemMessageQ(e)); return {}; } @@ -371,8 +358,7 @@ std::vector getLoadedModules() // no more modules is not an error if (e != ERROR_NO_MORE_FILES) { - qCritical().nospace().noquote() - << "Module32Next() failed, " << formatSystemMessageQ(e); + log::error("Module32Next() failed, {}", formatSystemMessageQ(e)); } break; diff --git a/src/envsecurity.cpp b/src/envsecurity.cpp index 559ce4ad..015e4000 100644 --- a/src/envsecurity.cpp +++ b/src/envsecurity.cpp @@ -1,6 +1,7 @@ #include "envsecurity.h" #include "env.h" #include +#include #include #include @@ -57,8 +58,7 @@ public: } if (FAILED(ret)) { - qCritical() - << "enumerator->next() failed, " << formatSystemMessageQ(ret); + log::error("enum->next() failed, {}", formatSystemMessageQ(ret)); break; } @@ -82,9 +82,9 @@ private: IID_IWbemLocator, &rawLocator); if (FAILED(ret) || !rawLocator) { - qCritical() - << "CoCreateInstance for WbemLocator failed, " - << formatSystemMessageQ(ret); + log::error( + "CoCreateInstance for WbemLocator failed, {}", + formatSystemMessageQ(ret)); throw failed(); } @@ -102,10 +102,9 @@ private: &rawService); if (FAILED(res) || !rawService) { - qCritical() - << "locator->ConnectServer() failed for namespace " - << "'" << QString::fromStdString(ns) << "', " - << formatSystemMessageQ(res); + log::error( + "locator->ConnectServer() failed for namespace '{}', {}", + ns, formatSystemMessageQ(res)); throw failed(); } @@ -121,9 +120,7 @@ private: if (FAILED(ret)) { - qCritical() - << "CoSetProxyBlanket() failed, " << formatSystemMessageQ(ret); - + log::error("CoSetProxyBlanket() failed, {}", formatSystemMessageQ(ret)); throw failed(); } } @@ -142,10 +139,7 @@ private: if (FAILED(ret) || !rawEnumerator) { - qCritical() - << "query '" << QString::fromStdString(query) << "' failed, " - << formatSystemMessageQ(ret); - + log::error("query '{}' failed, {}", query, formatSystemMessageQ(ret)); return {}; } @@ -256,15 +250,12 @@ std::vector getSecurityProductsFromWMI() // display name auto ret = o->Get(L"displayName", 0, &prop, 0, 0); if (FAILED(ret)) { - qCritical() - << "failed to get displayName, " - << formatSystemMessageQ(ret); - + log::error("failed to get displayName, {}", formatSystemMessageQ(ret)); return; } if (prop.vt != VT_BSTR) { - qCritical() << "displayName is a " << prop.vt << ", not a bstr"; + log::error("displayName is a {}, not a bstr", prop.vt); return; } @@ -274,15 +265,12 @@ std::vector getSecurityProductsFromWMI() // product state ret = o->Get(L"productState", 0, &prop, 0, 0); if (FAILED(ret)) { - qCritical() - << "failed to get productState, " - << formatSystemMessageQ(ret); - + log::error("failed to get productState, {}", formatSystemMessageQ(ret)); return; } if (prop.vt != VT_UI4 && prop.vt != VT_I4) { - qCritical() << "productState is a " << prop.vt << ", is not a VT_UI4"; + log::error("productState is a {}, is not a VT_UI4", prop.vt); return; } @@ -298,15 +286,12 @@ std::vector getSecurityProductsFromWMI() // guid ret = o->Get(L"instanceGuid", 0, &prop, 0, 0); if (FAILED(ret)) { - qCritical() - << "failed to get instanceGuid, " - << formatSystemMessageQ(ret); - + log::error("failed to get instanceGuid, {}", formatSystemMessageQ(ret)); return; } if (prop.vt != VT_BSTR) { - qCritical() << "instanceGuid is a " << prop.vt << ", is not a bstr"; + log::error("instanceGuid is a {}, is not a bstr", prop.vt); return; } @@ -362,9 +347,9 @@ std::optional getWindowsFirewall() __uuidof(INetFwPolicy2), &rawPolicy); if (FAILED(hr) || !rawPolicy) { - qCritical() - << "CoCreateInstance for NetFwPolicy2 failed, " - << formatSystemMessageQ(hr); + log::error( + "CoCreateInstance for NetFwPolicy2 failed, {}", + formatSystemMessageQ(hr)); return {}; } @@ -378,10 +363,7 @@ std::optional getWindowsFirewall() hr = policy->get_FirewallEnabled(NET_FW_PROFILE2_PUBLIC, &enabledVariant); if (FAILED(hr)) { - qCritical() - << "get_FirewallEnabled failed, " - << formatSystemMessageQ(hr); - + log::error("get_FirewallEnabled failed, {}", formatSystemMessageQ(hr)); return {}; } } diff --git a/src/envshortcut.cpp b/src/envshortcut.cpp index 30ef4633..1deb9dad 100644 --- a/src/envshortcut.cpp +++ b/src/envshortcut.cpp @@ -3,6 +3,7 @@ #include "executableslist.h" #include "instancemanager.h" #include +#include namespace env { @@ -218,17 +219,24 @@ bool Shortcut::toggle(Locations loc) bool Shortcut::add(Locations loc) { - debug() - << "adding shortcut to " << toString(loc) << ":\n" - << " . name: '" << m_name << "'\n" - << " . target: '" << m_target << "'\n" - << " . arguments: '" << m_arguments << "'\n" - << " . description: '" << m_description << "'\n" - << " . icon: '" << m_icon << "' @ " << m_iconIndex << "\n" - << " . working directory: '" << 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()) { - critical() << "target is empty"; + log::error("shortcut: target is empty"); return false; } @@ -237,7 +245,7 @@ bool Shortcut::add(Locations loc) return false; } - debug() << "shorcut file will be saved at '" << path << "'"; + log::debug("shorcut file will be saved at '{}'", path); try { @@ -255,7 +263,7 @@ bool Shortcut::add(Locations loc) } catch(ShellLinkException& e) { - critical() << e.what() << "\nshortcut file was not saved"; + log::error("{}\nshortcut file was not saved", e.what()); } return false; @@ -263,26 +271,26 @@ bool Shortcut::add(Locations loc) bool Shortcut::remove(Locations loc) { - debug() << "removing shortcut for '" << m_name << "' from " << toString(loc); + log::debug("removing shortcut for '{}' from {}", m_name, toString(loc)); const auto path = shortcutPath(loc); if (path.isEmpty()) { return false; } - debug() << "path to shortcut file is '" << path << "'"; + log::debug("path to shortcut file is '{}'", path); if (!QFile::exists(path)) { - critical() << "can't remove '" << path << "', file not found"; + log::error("can't remove shortcut '{}', file not found", path); return false; } if (!MOBase::shellDelete({path})) { const auto e = ::GetLastError(); - critical() - << "failed to remove '" << path << "', " - << formatSystemMessageQ(e); + log::error( + "failed to remove shortcut '{}', {}", + path, formatSystemMessageQ(e)); return false; } @@ -323,7 +331,7 @@ QString Shortcut::shortcutDirectory(Locations loc) const case None: default: - critical() << "bad location " << loc; + log::error("shortcut: bad location {}", loc); break; } } @@ -337,23 +345,13 @@ QString Shortcut::shortcutDirectory(Locations loc) const QString Shortcut::shortcutFilename() const { if (m_name.isEmpty()) { - critical() << "name is empty"; + log::error("shortcut name is empty"); return {}; } return m_name + ".lnk"; } -QDebug Shortcut::debug() const -{ - return qDebug().noquote().nospace() << "system shortcut: "; -} - -QDebug Shortcut::critical() const -{ - return qCritical().noquote().nospace() << "system shortcut: "; -} - QString toString(Shortcut::Locations loc) { diff --git a/src/envshortcut.h b/src/envshortcut.h index 904b3ab7..82eea191 100644 --- a/src/envshortcut.h +++ b/src/envshortcut.h @@ -84,15 +84,6 @@ private: int m_iconIndex; QString m_workingDirectory; - // returns a qCritical() logger with a prefix already logged - // - QDebug critical() const; - - // returns a qDebug() logger with a prefix already logged - // - QDebug debug() const; - - // returns the path where the shortcut file should be saved // QString shortcutPath(Locations loc) const; diff --git a/src/envwindows.cpp b/src/envwindows.cpp index 4fbd788a..8a98036a 100644 --- a/src/envwindows.cpp +++ b/src/envwindows.cpp @@ -1,6 +1,7 @@ #include "envwindows.h" #include "env.h" #include +#include namespace env { @@ -13,7 +14,7 @@ WindowsInfo::WindowsInfo() LibraryPtr ntdll(LoadLibraryW(L"ntdll.dll")); if (!ntdll) { - qCritical() << "failed to load ntdll.dll while getting version"; + log::error("failed to load ntdll.dll while getting version"); return; } else { m_reported = getReportedVersion(ntdll.get()); @@ -122,7 +123,7 @@ WindowsInfo::Version WindowsInfo::getReportedVersion(HINSTANCE ntdll) const GetProcAddress(ntdll, "RtlGetVersion")); if (!RtlGetVersion) { - qCritical() << "RtlGetVersion() not found in ntdll.dll"; + log::error("RtlGetVersion() not found in ntdll.dll"); return {}; } @@ -149,7 +150,7 @@ WindowsInfo::Version WindowsInfo::getRealVersion(HINSTANCE ntdll) const GetProcAddress(ntdll, "RtlGetNtVersionNumbers")); if (!RtlGetNtVersionNumbers) { - qCritical() << "RtlGetNtVersionNumbers not found in ntdll.dll"; + log::error("RtlGetNtVersionNumbers not found in ntdll.dll"); return {}; } @@ -207,9 +208,9 @@ std::optional WindowsInfo::getElevated() const if (!OpenProcessToken(GetCurrentProcess( ), TOKEN_QUERY, &rawToken)) { const auto e = GetLastError(); - qCritical() - << "while trying to check if process is elevated, " - << "OpenProcessToken() failed: " << formatSystemMessageQ(e); + log::error( + "while trying to check if process is elevated, " + "OpenProcessToken() failed: {}", formatSystemMessageQ(e)); return {}; } @@ -223,9 +224,9 @@ std::optional WindowsInfo::getElevated() const if (!GetTokenInformation(token.get(), TokenElevation, &e, sizeof(e), &size)) { const auto e = GetLastError(); - qCritical() - << "while trying to check if process is elevated, " - << "GetTokenInformation() failed: " << formatSystemMessageQ(e); + log::error( + "while trying to check if process is elevated, " + "GetTokenInformation() failed: {}", formatSystemMessageQ(e)); return {}; } diff --git a/src/executableslist.cpp b/src/executableslist.cpp index fbb96bd4..2408e8f3 100644 --- a/src/executableslist.cpp +++ b/src/executableslist.cpp @@ -243,9 +243,9 @@ void ExecutablesList::setExecutable(const Executable &exe, SetFlags flags) if (flags == MoveExisting) { const auto newTitle = makeNonConflictingTitle(exe.title()); if (!newTitle) { - qCritical().nospace() - << "executable '" << exe.title() << "' was in the way but could " - << "not be renamed"; + log::error( + "executable '{}' was in the way but could not be renamed", + exe.title()); return; } @@ -289,9 +289,7 @@ std::optional ExecutablesList::makeNonConflictingTitle( title = prefix + QString(" (%1)").arg(i); } - qCritical().nospace() - << "ran out of executable titles for prefix '" << prefix << "'"; - + log::error("ran out of executable titles for prefix '{}'", prefix); return {}; } diff --git a/src/filerenamer.cpp b/src/filerenamer.cpp index b516c902..8835f52f 100644 --- a/src/filerenamer.cpp +++ b/src/filerenamer.cpp @@ -10,7 +10,7 @@ FileRenamer::FileRenamer(QWidget* parent, QFlags flags) { // sanity check for flags if ((m_flags & (HIDE|UNHIDE)) == 0) { - qCritical("renameFile() missing hide flag"); + log::error("renameFile() missing hide flag"); // doesn't really matter, it's just for text m_flags = HIDE; } diff --git a/src/filterwidget.cpp b/src/filterwidget.cpp index 44cbb274..0638add3 100644 --- a/src/filterwidget.cpp +++ b/src/filterwidget.cpp @@ -1,5 +1,8 @@ #include "filterwidget.h" #include "eventfilter.h" +#include + +using namespace MOBase; FilterWidgetProxyModel::FilterWidgetProxyModel(FilterWidget& fw, QWidget* parent) : QSortFilterProxyModel(parent), m_filter(fw) @@ -80,7 +83,7 @@ QModelIndex FilterWidget::map(const QModelIndex& index) if (m_proxy) { return m_proxy->mapToSource(index); } else { - qCritical() << "FilterWidget::map() called, but proxy isn't set up"; + log::error("FilterWidget::map() called, but proxy isn't set up"); return index; } } diff --git a/src/forcedloaddialogwidget.cpp b/src/forcedloaddialogwidget.cpp index b92838c3..b84f785f 100644 --- a/src/forcedloaddialogwidget.cpp +++ b/src/forcedloaddialogwidget.cpp @@ -1,9 +1,8 @@ #include "forcedloaddialogwidget.h" #include "ui_forcedloaddialogwidget.h" - -#include - #include "executableinfo.h" +#include +#include using namespace MOBase; @@ -85,7 +84,7 @@ void ForcedLoadDialogWidget::on_libraryPathBrowseButton_clicked() if (fileInfo.exists()) { ui->libraryPathEdit->setText(filePath); } else { - qCritical("%ls does not exist", filePath.toStdWString().c_str()); + log::error("{} does not exist", filePath); } } } @@ -102,7 +101,7 @@ void ForcedLoadDialogWidget::on_processBrowseButton_clicked() if (fileInfo.exists()) { ui->processEdit->setText(fileName); } else { - qCritical("%ls does not exist", fileInfo.filePath().toStdWString().c_str()); + log::error("{} does not exist", fileInfo.filePath()); } } } diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp index 0e50de52..fd971f47 100644 --- a/src/installationmanager.cpp +++ b/src/installationmanager.cpp @@ -263,7 +263,7 @@ QStringList InstallationManager::extractFiles(const QStringList &filesOrig, bool targetFile = wcsrchr(origFile/*data[i]->getFileName()*/, '/'); } if (targetFile == nullptr) { - qCritical() << "Failed to find backslash in " << data[i]->getFileName(); + log::error("Failed to find backslash in {}", data[i]->getFileName()); continue; } else { // skip the slash @@ -527,7 +527,7 @@ bool InstallationManager::testOverwrite(GuessedValue &modName, bool *me settingsFile.write(originalSettings); settingsFile.close(); } else { - qCritical("failed to restore original settings: %s", qUtf8Printable(metaFilename)); + log::error("failed to restore original settings: {}", metaFilename); } return true; } else if (overwriteDialog.action() == QueryOverwriteDialog::ACT_MERGE) { @@ -856,8 +856,7 @@ bool InstallationManager::install(const QString &fileName, } } } catch (const IncompatibilityException &e) { - qCritical("plugin \"%s\" incompatible: %s", - qUtf8Printable(installer->name()), e.what()); + log::error("plugin \"{}\" incompatible: {}", installer->name(), e.what()); } // act upon the installation result. at this point the files have already been diff --git a/src/loglist.cpp b/src/loglist.cpp index 207f412b..c34ac76e 100644 --- a/src/loglist.cpp +++ b/src/loglist.cpp @@ -196,21 +196,3 @@ void LogList::copyToClipboard() QApplication::clipboard()->setText(QString::fromStdString(s)); } - - -void vlog(const char *format, ...) -{ - va_list argList; - va_start(argList, format); - - static const int BUFFERSIZE = 1000; - - char buffer[BUFFERSIZE + 1]; - buffer[BUFFERSIZE] = '\0'; - - vsnprintf(buffer, BUFFERSIZE, format, argList); - - qCritical("%s", buffer); - - va_end(argList); -} diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 70ace8f1..ad87ba03 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1212,14 +1212,14 @@ void MainWindow::createHelpMenu() QFile file(dirIter.filePath()); if (!file.open(QIODevice::ReadOnly)) { - qCritical() << "Failed to open " << fileName; + log::error("Failed to open {}", fileName); continue; } QString firstLine = QString::fromUtf8(file.readLine()); if (firstLine.startsWith("//TL")) { QStringList params = firstLine.mid(4).trimmed().split('#'); if (params.size() != 2) { - qCritical() << "invalid header line for tutorial " << fileName << " expected 2 parameters"; + log::error("invalid header line for tutorial {}, expected 2 parameters", fileName); continue; } QAction *tutAction = new QAction(params.at(0), tutorialMenu); @@ -1323,7 +1323,7 @@ void MainWindow::hookUpWindowTutorials() QString fileName = dirIter.fileName(); QFile file(dirIter.filePath()); if (!file.open(QIODevice::ReadOnly)) { - qCritical() << "Failed to open " << fileName; + log::error("Failed to open {}", fileName); continue; } QString firstLine = QString::fromUtf8(file.readLine()); @@ -1369,7 +1369,7 @@ void MainWindow::showEvent(QShowEvent *event) TutorialManager::instance().activateTutorial("MainWindow", firstStepsTutorial); } } else { - qCritical() << firstStepsTutorial << " missing"; + log::error("{} missing", firstStepsTutorial); QPoint pos = ui->toolBar->mapToGlobal(QPoint()); pos.rx() += ui->toolBar->width() / 2; pos.ry() += ui->toolBar->height(); @@ -1636,7 +1636,7 @@ void MainWindow::startExeAction() QAction *action = qobject_cast(sender()); if (action == nullptr) { - qCritical("not an action?"); + log::error("not an action?"); return; } @@ -3415,7 +3415,7 @@ void MainWindow::displayModInformation(const QString &modName, ModInfoTabIDs tab { unsigned int index = ModInfo::getIndex(modName); if (index == UINT_MAX) { - qCritical("failed to resolve mod name %s", qUtf8Printable(modName)); + log::error("failed to resolve mod name {}", modName); return; } @@ -3500,7 +3500,7 @@ void MainWindow::visitOnNexus_clicked() if (modID > 0) { linkClicked(NexusInterface::instance(&m_PluginContainer)->getModURL(modID, gameName)); } else { - qCritical() << "mod '" << info->name() << "' has no nexus id"; + log::error("mod '{}' has no nexus id", info->name()); } } } @@ -4038,7 +4038,7 @@ void MainWindow::doMoveOverwriteContentToMod(const QString &modAbsolutePath) MessageDialog::showMessage(tr("Move successful."), this); } else { - qCritical("Move operation failed: %s", qUtf8Printable(windowsErrorString(::GetLastError()))); + log::error("Move operation failed: {}", windowsErrorString(::GetLastError())); } m_OrganizerCore.refreshModList(); @@ -4067,7 +4067,7 @@ void MainWindow::clearOverwrite() updateProblemsButton(); m_OrganizerCore.refreshModList(); } else { - qCritical("Delete operation failed: %s", qUtf8Printable(windowsErrorString(::GetLastError()))); + log::error("Delete operation failed: {}", windowsErrorString(::GetLastError())); } } } @@ -4311,7 +4311,7 @@ void MainWindow::addRemoveCategoriesFromMenu(QMenu *menu, int modRow, int refere void MainWindow::addRemoveCategories_MenuHandler() { QMenu *menu = qobject_cast(sender()); if (menu == nullptr) { - qCritical("not a menu?"); + log::error("not a menu?"); return; } @@ -4352,7 +4352,7 @@ void MainWindow::addRemoveCategories_MenuHandler() { void MainWindow::replaceCategories_MenuHandler() { QMenu *menu = qobject_cast(sender()); if (menu == nullptr) { - qCritical("not a menu?"); + log::error("not a menu?"); return; } @@ -4547,7 +4547,7 @@ void MainWindow::addPrimaryCategoryCandidates(QMenu *primaryCategoryMenu, categoryBox->setChecked(categoryID == info->getPrimaryCategory()); action->setDefaultWidget(categoryBox); } catch (const std::exception &e) { - qCritical("failed to create category checkbox: %s", e.what()); + log::error("failed to create category checkbox: {}", e.what()); } action->setData(categoryID); @@ -4559,7 +4559,7 @@ void MainWindow::addPrimaryCategoryCandidates() { QMenu *menu = qobject_cast(sender()); if (menu == nullptr) { - qCritical("not a menu?"); + log::error("not a menu?"); return; } menu->clear(); @@ -6067,7 +6067,7 @@ void MainWindow::nxmEndorsementToggled(QString, int, QVariant, QVariant resultDa toggleMO2EndorseState(); if (!disconnect(sender(), SIGNAL(nxmEndorsementToggled(QString, int, QVariant, QVariant, int)), this, SLOT(nxmEndorsementToggled(QString, int, QVariant, QVariant, int)))) { - qCritical("failed to disconnect endorsement slot"); + log::error("failed to disconnect endorsement slot"); } } @@ -6527,11 +6527,11 @@ void MainWindow::createStdoutPipe(HANDLE *stdOutRead, HANDLE *stdOutWrite) secAttributes.lpSecurityDescriptor = nullptr; if (!::CreatePipe(stdOutRead, stdOutWrite, &secAttributes, 0)) { - qCritical("failed to create stdout reroute"); + log::error("failed to create stdout reroute"); } if (!::SetHandleInformation(*stdOutRead, HANDLE_FLAG_INHERIT, 0)) { - qCritical("failed to correctly set up the stdout reroute"); + log::error("failed to correctly set up the stdout reroute"); *stdOutWrite = *stdOutRead = INVALID_HANDLE_VALUE; } } @@ -6965,7 +6965,7 @@ void MainWindow::dropLocalFile(const QUrl &url, const QString &outputDir, bool m success = shellCopy(file.absoluteFilePath(), target, true, this); } if (!success) { - qCritical("file operation failed: %s", qUtf8Printable(windowsErrorString(::GetLastError()))); + log::error("file operation failed: {}", windowsErrorString(::GetLastError())); } } diff --git a/src/moapplication.cpp b/src/moapplication.cpp index 3d55b28d..370a23b5 100644 --- a/src/moapplication.cpp +++ b/src/moapplication.cpp @@ -115,13 +115,15 @@ bool MOApplication::notify(QObject *receiver, QEvent *event) try { return QApplication::notify(receiver, event); } catch (const std::exception &e) { - qCritical("uncaught exception in handler (object %s, eventtype %d): %s", - receiver->objectName().toUtf8().constData(), event->type(), e.what()); + 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 (...) { - qCritical("uncaught non-std exception in handler (object %s, eventtype %d)", - receiver->objectName().toUtf8().constData(), event->type()); + log::error( + "uncaught non-std exception in handler (object {}, eventtype {})", + receiver->objectName(), event->type()); reportError(tr("an error occurred")); return false; } diff --git a/src/modinfo.cpp b/src/modinfo.cpp index ca6e8046..5a05e7ca 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -530,10 +530,7 @@ QUrl ModInfo::parseCustomURL() const const auto url = QUrl::fromUserInput(getCustomURL()); if (!url.isValid()) { - qCritical() - << "mod '" << name() << "' has an invalid custom url " - << "'" << getCustomURL() << "'"; - + log::error("mod '{}' has an invalid custom url '{}'", name(), getCustomURL()); return {}; } diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 47ac84be..a7a6b0d7 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -176,7 +176,7 @@ void ModInfoDialog::createTabs() // check for tabs in the ui not having a corresponding tab in the list int count = ui->tabWidget->count(); if (count < 0 || count > static_cast(m_tabs.size())) { - qCritical() << "mod info dialog has more tabs than expected"; + log::error("mod info dialog has more tabs than expected"); count = static_cast(m_tabs.size()); } @@ -239,13 +239,13 @@ void ModInfoDialog::setMod(const QString& name) { unsigned int index = ModInfo::getIndex(name); if (index == UINT_MAX) { - qCritical() << "failed to resolve mod name " << name; + log::error("failed to resolve mod name {}", name); return; } auto mod = ModInfo::getByIndex(index); if (!mod) { - qCritical() << "mod by index " << index << " is null"; + log::error("mod by index {} is null", index); return; } @@ -307,7 +307,7 @@ void ModInfoDialog::update(bool firstTime) // changed tabInfo->tab->activated(); } else { - qCritical() << "tab index " << oldTab << " not found"; + log::error("tab index {} not found", oldTab); } } } @@ -400,7 +400,7 @@ void ModInfoDialog::reAddTabs( if (itor == orderedNames.end()) { // this shouldn't happen, it means there's a tab in the UI that's no // in the list - qCritical() << "can't sort tabs, '" << objectName << "' not found"; + log::error("can't sort tabs, '{}' not found", objectName); canSort = false; } } @@ -753,7 +753,7 @@ void ModInfoDialog::onTabMoved() } if (!found) { - qCritical() << "unknown tab at index " << i; + log::error("unknown tab at index {}", i); } } } diff --git a/src/modinfodialogconflicts.cpp b/src/modinfodialogconflicts.cpp index 511d48ad..d16d548c 100644 --- a/src/modinfodialogconflicts.cpp +++ b/src/modinfodialogconflicts.cpp @@ -365,7 +365,7 @@ void for_each_in_selection(QTreeView* tree, F&& f) const auto* model = dynamic_cast(tree->model()); if (!model) { - qCritical() << "tree doesn't have a ConflictListModel"; + log::error("tree doesn't have a ConflictListModel"); return; } @@ -454,7 +454,7 @@ void ConflictsTab::changeItemsVisibility(QTreeView* tree, bool visible) auto* model = dynamic_cast(tree->model()); if (!model) { - qCritical() << "list doesn't have a ConflictListModel"; + log::error("list doesn't have a ConflictListModel"); return; } @@ -633,7 +633,7 @@ ConflictsTab::Actions ConflictsTab::createMenuActions(QTreeView* tree) const auto* model = dynamic_cast(tree->model()); if (!model) { - qCritical() << "tree doesn't have a ConflictListModel"; + log::error("tree doesn't have a ConflictListModel"); return {}; } diff --git a/src/modinfodialogfiletree.cpp b/src/modinfodialogfiletree.cpp index 0b519932..219ddf35 100644 --- a/src/modinfodialogfiletree.cpp +++ b/src/modinfodialogfiletree.cpp @@ -5,8 +5,9 @@ #include "filerenamer.h" #include #include +#include -using MOBase::reportError; +using namespace MOBase; namespace shell = MOBase::shell; // if there are more than 50 selected items in the filetree, don't bother @@ -230,19 +231,19 @@ bool FileTreeTab::deleteFileRecursive(const QModelIndex& parent) if (m_fs->isDir(index)) { if (!deleteFileRecursive(index)) { - qCritical() << "failed to delete" << m_fs->fileName(index); + log::error("failed to delete {}", m_fs->fileName(index)); return false; } } else { if (!m_fs->remove(index)) { - qCritical() << "failed to delete", m_fs->fileName(index); + log::error("failed to delete {}", m_fs->fileName(index)); return false; } } } if (!m_fs->remove(parent)) { - qCritical() << "failed to delete" << m_fs->fileName(parent); + log::error("failed to delete {}", m_fs->fileName(parent)); return false; } diff --git a/src/modinfodialogimages.cpp b/src/modinfodialogimages.cpp index 69866902..10362058 100644 --- a/src/modinfodialogimages.cpp +++ b/src/modinfodialogimages.cpp @@ -2,7 +2,9 @@ #include "ui_modinfodialog.h" #include "settings.h" #include "utility.h" +#include +using namespace MOBase; using namespace ImagesTabHelpers; QSize resizeWithAspectRatio(const QSize& original, const QSize& available) @@ -896,10 +898,9 @@ void File::ensureOriginalLoaded() QImageReader reader(m_path); if (!reader.read(&m_original)) { - qCritical().noquote().nospace() - << "failed to load '" << m_path << "'\n" - << reader.errorString() << " " - << "(error " << static_cast(reader.error()) << ")"; + log::error( + "failed to load '{}'\n{} (error {})", + m_path, reader.errorString(), static_cast(reader.error())); m_failed = true; } diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index 448447e1..074fa9e2 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -68,8 +68,7 @@ ModInfoRegular::~ModInfoRegular() try { saveMeta(); } catch (const std::exception &e) { - qCritical("failed to save meta information for \"%s\": %s", - qUtf8Printable(m_Name), e.what()); + log::error("failed to save meta information for \"{}\": {}", m_Name, e.what()); } } @@ -258,14 +257,14 @@ void ModInfoRegular::saveMeta() if (metaFile.status() == QSettings::NoError) { m_MetaInfoChanged = false; } else { - qCritical() - << QString("failed to write %1/meta.ini: error %2") - .arg(absolutePath()).arg(metaFile.status()); + log::error( + "failed to write {}/meta.ini: error {}", + absolutePath(), metaFile.status()); } } else { - qCritical() - << QString("failed to write %1/meta.ini: error %2") - .arg(absolutePath()).arg(metaFile.status()); + log::error( + "failed to write {}/meta.ini: error {}", + absolutePath(), metaFile.status()); } } } @@ -425,14 +424,13 @@ bool ModInfoRegular::setName(const QString &name) return false; } if (!modDir.rename(tempName, name)) { - qCritical("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; } } else { if (!shellRename(modDir.absoluteFilePath(m_Name), modDir.absoluteFilePath(name))) { - qCritical("failed to rename mod %s (errorcode %d)", - qUtf8Printable(name), ::GetLastError()); + log::error("failed to rename mod {} (errorcode {})", name, ::GetLastError()); return false; } } diff --git a/src/modlist.cpp b/src/modlist.cpp index df25df0d..6ebd0e8b 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -271,7 +271,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const int categoryIdx = categoryFactory.getCategoryIndex(category); return categoryFactory.getCategoryName(categoryIdx); } catch (const std::exception &e) { - qCritical("failed to retrieve category name: %s", e.what()); + log::error("failed to retrieve category name: {}", e.what()); return QString(); } } else { @@ -449,7 +449,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const try { return modInfo->getDescription(); } catch (const std::exception &e) { - qCritical("invalid mod description: %s", e.what()); + log::error("invalid mod description: {}", e.what()); return QString(); } } else if (column == COL_VERSION) { @@ -488,7 +488,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const try { categoryString << "" << ToWString(categoryFactory.getCategoryName(categoryFactory.getCategoryIndex(*catIter))) << ""; } catch (const std::exception &e) { - qCritical("failed to generate tooltip: %s", e.what()); + log::error("failed to generate tooltip: {}", e.what()); return QString(); } } @@ -636,9 +636,9 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role) try { m_ModStateChanged(info->name(), newState); } catch (const std::exception &e) { - qCritical("failed to invoke state changed notification: %s", e.what()); + log::error("failed to invoke state changed notification: {}", e.what()); } catch (...) { - qCritical("failed to invoke state changed notification: unknown exception"); + log::error("failed to invoke state changed notification: unknown exception"); } } @@ -834,7 +834,7 @@ void ModList::modInfoChanged(ModInfo::Ptr info) emit dataChanged(index(row, 0), index(row, columnCount())); emit postDataChanged(); } else { - qCritical("modInfoChanged not called after modInfoAboutToChange"); + log::error("modInfoChanged not called after modInfoAboutToChange"); } m_ChangeInfo.name = QString(); } diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp index 1127c7d4..d330e0c2 100644 --- a/src/modlistsortproxy.cpp +++ b/src/modlistsortproxy.cpp @@ -196,7 +196,7 @@ bool ModListSortProxy::lessThan(const QModelIndex &left, QString rightCatName = categories.getCategoryName(categories.getCategoryIndex(rightMod->getPrimaryCategory())); lt = leftCatName < rightCatName; } catch (const std::exception &e) { - qCritical("failed to compare categories: %s", e.what()); + log::error("failed to compare categories: {}", e.what()); } } } diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp index 008f3c0d..c797aed6 100644 --- a/src/nexusinterface.cpp +++ b/src/nexusinterface.cpp @@ -41,12 +41,11 @@ using namespace MOShared; void throttledWarning(const APIUserAccount& user) { - qCritical() << - QString( - "You have fewer than %1 requests remaining (%2). Only downloads and " - "login validation are being allowed.") - .arg(APIUserAccount::ThrottleThreshold) - .arg(user.remainingRequests()); + log::error( + "You have fewer than {} requests remaining ({}). Only downloads and " + "login validation are being allowed.", + APIUserAccount::ThrottleThreshold, + user.remainingRequests()); } @@ -344,7 +343,7 @@ QString NexusInterface::getGameURL(QString gameName) const if (game != nullptr) { return "https://www.nexusmods.com/" + game->gameNexusName().toLower(); } else { - qCritical("getGameURL can't find plugin for %s", qUtf8Printable(gameName)); + log::error("getGameURL can't find plugin for {}", gameName); return ""; } } @@ -355,7 +354,7 @@ QString NexusInterface::getOldModsURL(QString gameName) const if (game != nullptr) { return "https://" + game->gameNexusName().toLower() + ".nexusmods.com/mods"; } else { - qCritical("getOldModsURL can't find plugin for %s", qUtf8Printable(gameName)); + log::error("getOldModsURL can't find plugin for {}", gameName); return ""; } } @@ -464,7 +463,7 @@ int NexusInterface::requestUpdates(const int &modID, QObject *receiver, QVariant IPluginGame *game = getGame(gameName); if (game == nullptr) { - qCritical("requestUpdates can't find plugin for %s", qUtf8Printable(gameName)); + log::error("requestUpdates can't find plugin for {}", gameName); return -1; } @@ -521,7 +520,7 @@ int NexusInterface::requestFileInfo(QString gameName, int modID, int fileID, QOb { IPluginGame *gamePlugin = getGame(gameName); if (gamePlugin == nullptr) { - qCritical("requestFileInfo can't find plugin for %s", qUtf8Printable(gameName)); + log::error("requestFileInfo can't find plugin for {}", gameName); return -1; } @@ -687,7 +686,7 @@ void NexusInterface::nextRequest() } else if (getAccessManager()->validateWaiting()) { return; } else { - qCritical() << 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.")); } } @@ -949,10 +948,9 @@ void NexusInterface::requestError(QNetworkReply::NetworkError) return; } - qCritical("request (%s) error: %s (%d)", - qUtf8Printable(reply->url().toString()), - qUtf8Printable(reply->errorString()), - reply->error()); + log::error( + "request ({}) error: {} ({})", + reply->url().toString(), reply->errorString(), reply->error()); } diff --git a/src/organizercore.cpp b/src/organizercore.cpp index dbff1a2a..725371e9 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -224,7 +224,7 @@ bool checkService() } if (serviceConfig->dwStartType == SERVICE_DISABLED) { - qCritical("Windows Event Log service is disabled!"); + log::error("Windows Event Log service is disabled!"); serviceRunning = false; } @@ -242,7 +242,7 @@ bool checkService() } if (serviceStatus->dwCurrentState != SERVICE_RUNNING) { - qCritical("Windows Event Log service is not running"); + log::error("Windows Event Log service is not running"); serviceRunning = false; } } @@ -437,7 +437,7 @@ bool OrganizerCore::testForSteam(bool *found, bool *access) hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hProcessSnap == INVALID_HANDLE_VALUE) { lastError = GetLastError(); - qCritical("unable to get snapshot of processes (error %d)", lastError); + log::error("unable to get snapshot of processes (error {})", lastError); return false; } @@ -446,7 +446,7 @@ bool OrganizerCore::testForSteam(bool *found, bool *access) pe32.dwSize = sizeof(PROCESSENTRY32); if (!Process32First(hProcessSnap, &pe32)) { lastError = GetLastError(); - qCritical("unable to get first process (error %d)", lastError); + log::error("unable to get first process (error {})", lastError); CloseHandle(hProcessSnap); return false; } @@ -486,7 +486,7 @@ return true; void OrganizerCore::updateExecutablesList(QSettings &settings) { if (m_PluginContainer == nullptr) { - qCritical("can't update executables list now"); + log::error("can't update executables list now"); return; } @@ -657,7 +657,7 @@ void OrganizerCore::downloadRequested(QNetworkReply *reply, QString gameName, in } } catch (const std::exception &e) { MessageDialog::showMessage(tr("Download failed"), qApp->activeWindow()); - qCritical("exception starting download: %s", e.what()); + log::error("exception starting download: {}", e.what()); } } @@ -1552,7 +1552,7 @@ HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary, bool steamFound = true; bool steamAccess = true; if (!testForSteam(&steamFound, &steamAccess)) { - qCritical("unable to determine state of Steam"); + log::error("unable to determine state of Steam"); } if (!steamFound) { @@ -1569,9 +1569,9 @@ HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary, steamFound = true; steamAccess = true; if (!testForSteam(&steamFound, &steamAccess)) { - qCritical("unable to determine state of Steam"); + log::error("unable to determine state of Steam"); } else if (!steamFound) { - qCritical("could not find Steam"); + log::error("could not find Steam"); } } else if (result == QDialogButtonBox::Cancel) { @@ -1592,14 +1592,14 @@ HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary, if (result == QDialogButtonBox::Yes) { WCHAR cwd[MAX_PATH]; if (!GetCurrentDirectory(MAX_PATH, cwd)) { - qCritical("unable to get current directory (error %d)", GetLastError()); + log::error("unable to get current directory (error {})", GetLastError()); cwd[0] = L'\0'; } if (!Helper::adminLaunch( qApp->applicationDirPath().toStdWString(), qApp->applicationFilePath().toStdWString(), std::wstring(cwd))) { - qCritical("unable to relaunch MO as admin"); + log::error("unable to relaunch MO as admin"); return INVALID_HANDLE_VALUE; } qApp->exit(0); diff --git a/src/overwriteinfodialog.cpp b/src/overwriteinfodialog.cpp index 5ee8d76c..cc4ae849 100644 --- a/src/overwriteinfodialog.cpp +++ b/src/overwriteinfodialog.cpp @@ -121,18 +121,18 @@ bool OverwriteInfoDialog::recursiveDelete(const QModelIndex &index) QModelIndex childIndex = m_FileSystemModel->index(childRow, 0, index); if (m_FileSystemModel->isDir(childIndex)) { if (!recursiveDelete(childIndex)) { - qCritical("failed to delete %s", m_FileSystemModel->fileName(childIndex).toUtf8().constData()); + log::error("failed to delete {}", m_FileSystemModel->fileName(childIndex)); return false; } } else { if (!m_FileSystemModel->remove(childIndex)) { - qCritical("failed to delete %s", m_FileSystemModel->fileName(childIndex).toUtf8().constData()); + log::error("failed to delete {}", m_FileSystemModel->fileName(childIndex)); return false; } } } if (!m_FileSystemModel->remove(index)) { - qCritical("failed to delete %s", m_FileSystemModel->fileName(index).toUtf8().constData()); + log::error("failed to delete {}", m_FileSystemModel->fileName(index)); return false; } return true; diff --git a/src/persistentcookiejar.cpp b/src/persistentcookiejar.cpp index 1ed463c6..670bf382 100644 --- a/src/persistentcookiejar.cpp +++ b/src/persistentcookiejar.cpp @@ -1,8 +1,10 @@ #include "persistentcookiejar.h" +#include #include #include #include +using namespace MOBase; PersistentCookieJar::PersistentCookieJar(const QString &fileName, QObject *parent) : QNetworkCookieJar(parent), m_FileName(fileName) @@ -24,7 +26,7 @@ void PersistentCookieJar::clear() { void PersistentCookieJar::save() { QTemporaryFile file; if (!file.open()) { - qCritical("failed to save cookies: couldn't create temporary file"); + log::error("failed to save cookies: couldn't create temporary file"); return; } QDataStream data(&file); @@ -40,14 +42,14 @@ void PersistentCookieJar::save() { QFile oldCookies(m_FileName); if (oldCookies.exists()) { if (!oldCookies.remove()) { - qCritical("failed to save cookies: failed to remove %s", qUtf8Printable(m_FileName)); + log::error("failed to save cookies: failed to remove {}", m_FileName); return; } } // if it doesn't exists that's fine } if (!file.copy(m_FileName)) { - qCritical("failed to save cookies: failed to write %s", qUtf8Printable(m_FileName)); + log::error("failed to save cookies: failed to write {}", m_FileName); } } diff --git a/src/plugincontainer.cpp b/src/plugincontainer.cpp index d47fa2c6..36daec52 100644 --- a/src/plugincontainer.cpp +++ b/src/plugincontainer.cpp @@ -291,8 +291,9 @@ void PluginContainer::loadPlugins() std::unique_ptr pluginLoader(new QPluginLoader(pluginName, this)); if (pluginLoader->instance() == nullptr) { m_FailedPlugins.push_back(pluginName); - qCritical("failed to load plugin %s: %s", - qUtf8Printable(pluginName), qUtf8Printable(pluginLoader->errorString())); + log::error( + "failed to load plugin {}: {}", + pluginName, pluginLoader->errorString()); } else { if (registerPlugin(pluginLoader->instance(), pluginName)) { qDebug("loaded plugin \"%s\"", qUtf8Printable(QFileInfo(pluginName).fileName())); diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index 2fb743d0..e436d7f6 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -309,7 +309,7 @@ int PluginList::findPluginByPriority(int priority) return i; } } - qCritical(QString("No plugin with priority %1").arg(priority).toLocal8Bit()); + log::error("No plugin with priority {}", priority); return -1; } @@ -824,7 +824,7 @@ void PluginList::updateIndices() continue; } if (m_ESPs[i].m_Priority >= static_cast(m_ESPs.size())) { - qCritical("invalid plugin priority: %d", m_ESPs[i].m_Priority); + log::error("invalid plugin priority: {}", m_ESPs[i].m_Priority); continue; } m_ESPsByName[m_ESPs[i].m_Name.toLower()] = i; @@ -1067,9 +1067,9 @@ bool PluginList::setData(const QModelIndex &modIndex, const QVariant &value, int this->index(0, 0), this->index(static_cast(m_ESPs.size()), columnCount())); } catch (const std::exception &e) { - qCritical("failed to invoke state changed notification: %s", e.what()); + log::error("failed to invoke state changed notification: {}", e.what()); } catch (...) { - qCritical("failed to invoke state changed notification: unknown exception"); + log::error("failed to invoke state changed notification: unknown exception"); } } @@ -1368,7 +1368,7 @@ PluginList::ESPInfo::ESPInfo(const QString &name, bool enabled, m_Masters.insert(QString(iter->c_str())); } } catch (const std::exception &e) { - qCritical("failed to parse plugin file %s: %s", qUtf8Printable(fullPath), e.what()); + log::error("failed to parse plugin file {}: {}", fullPath, e.what()); m_IsMaster = false; m_IsLight = false; m_IsLightFlagged = false; diff --git a/src/profile.cpp b/src/profile.cpp index d4778305..555de89a 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -572,7 +572,7 @@ void Profile::setModsEnabled(const QList &modsToEnable, const QLis QList dirtyMods; for (auto idx : modsToEnable) { if (idx >= m_ModStatus.size()) { - qCritical() << tr("invalid mod index: %1").arg(idx); + log::error("invalid mod index: {}", idx); continue; } if (!m_ModStatus[idx].m_Enabled) { @@ -582,7 +582,7 @@ void Profile::setModsEnabled(const QList &modsToEnable, const QLis } for (auto idx : modsToDisable) { if (idx >= m_ModStatus.size()) { - qCritical() << tr("invalid mod index: %1").arg(idx); + log::error("invalid mod index: {}", idx); continue; } if (ModInfo::getByIndex(idx)->alwaysEnabled()) { diff --git a/src/settings.cpp b/src/settings.cpp index 92ae2251..9c303442 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -221,9 +221,7 @@ QString Settings::deObfuscate(const QString key) } else { const auto e = GetLastError(); if (e != ERROR_NOT_FOUND) { - qCritical().nospace() - << "Retrieving encrypted data failed: " - << formatSystemMessageQ(e); + log::error("Retrieving encrypted data failed: {}", formatSystemMessageQ(e)); } } delete[] keyData; @@ -368,11 +366,7 @@ bool Settings::setNexusApiKey(const QString& apiKey) { if (!obfuscate("APIKEY", apiKey)) { const auto e = GetLastError(); - - qCritical().nospace() - << "Storing API key failed: " - << formatSystemMessageQ(e); - + log::error("Storing API key failed: {}", formatSystemMessageQ(e)); return false; } @@ -493,9 +487,7 @@ void Settings::setSteamLogin(QString username, QString password) } if (!obfuscate("steam_password", password)) { const auto e = GetLastError(); - qCritical().nospace() - << "Storing or deleting password failed: " - << formatSystemMessageQ(e); + log::error("Storing or deleting password failed: {}", formatSystemMessageQ(e)); } } diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index 0dae31ac..99943d04 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -485,7 +485,6 @@ void SettingsDialog::onValidatorStateChanged( for (auto&& line : log.split("\n")) { addNexusLog(line); } - } updateNexusState(); } diff --git a/src/shared/directoryentry.cpp b/src/shared/directoryentry.cpp index 9d9edd85..2cdbac74 100644 --- a/src/shared/directoryentry.cpp +++ b/src/shared/directoryentry.cpp @@ -21,6 +21,7 @@ along with Mod Organizer. If not, see . #include "windows_error.h" #include "leaktrace.h" #include "error_report.h" +#include #include #include #include @@ -35,6 +36,8 @@ along with Mod Organizer. If not, see . namespace MOShared { +namespace log = MOBase::log; + static const int MAXPATH_UNICODE = 32767; class OriginConnection { @@ -103,7 +106,7 @@ public: m_OriginsNameMap.erase(iter); m_OriginsNameMap[newName] = idx; } else { - vlog("failed to change name lookup from %ls to %ls", oldName.c_str(), newName.c_str()); + log::error("failed to change name lookup from {} to {}", oldName, newName); } } @@ -714,14 +717,14 @@ void DirectoryEntry::removeFile(FileEntry::Index index) if (iter != m_Files.end()) { m_Files.erase(iter); } else { - vlog("file \"%ls\" not in directory \"%ls\"", - m_FileRegister->getFile(index)->getName().c_str(), - this->getName().c_str()); + log::error( + "file \"{}\" not in directory \"{}\"", + m_FileRegister->getFile(index)->getName(), this->getName()); } } else { - vlog("file \"%ls\" not in directory \"%ls\", directory empty", - m_FileRegister->getFile(index)->getName().c_str(), - this->getName().c_str()); + log::error( + "file \"{}\" not in directory \"{}\", directory empty", + m_FileRegister->getFile(index)->getName(), this->getName()); } } @@ -844,7 +847,7 @@ const FileEntry::Ptr DirectoryEntry::searchFile(const std::wstring &path, const DirectoryEntry *temp = findSubDirectory(pathComponent); if (temp != nullptr) { if (len >= path.size()) { - vlog("unexpected end of path"); + log::error("unexpected end of path"); return FileEntry::Ptr(); } return temp->searchFile(path.substr(len + 1), directory); @@ -988,7 +991,7 @@ bool FileRegister::removeFile(FileEntry::Index index) m_Files.erase(index); return true; } else { - vlog("invalid file index for remove: %lu", index); + log::error("invalid file index for remove: {}", index); return false; } } @@ -1002,7 +1005,7 @@ void FileRegister::removeOrigin(FileEntry::Index index, int originID) m_Files.erase(iter); } } else { - vlog("invalid file index for remove (for origin): %lu", index); + log::error("invalid file index for remove (for origin): {}", index); } } diff --git a/src/shared/error_report.h b/src/shared/error_report.h index a003ee09..17b25645 100644 --- a/src/shared/error_report.h +++ b/src/shared/error_report.h @@ -30,5 +30,3 @@ void reportError(LPCSTR format, ...); void reportError(LPCWSTR format, ...); } // namespace MOShared - -void vlog(const char* format, ...); diff --git a/src/syncoverwritedialog.cpp b/src/syncoverwritedialog.cpp index 4ee4716e..b1643b2d 100644 --- a/src/syncoverwritedialog.cpp +++ b/src/syncoverwritedialog.cpp @@ -22,6 +22,7 @@ along with Mod Organizer. If not, see . #include "ui_syncoverwritedialog.h" #include #include +#include #include #include @@ -86,7 +87,7 @@ void SyncOverwriteDialog::readTree(const QString &path, DirectoryEntry *director if (subDir != nullptr) { readTree(fileInfo.absoluteFilePath(), subDir, newItem); } else { - qCritical("no directory structure for %s?", qUtf8Printable(file)); + log::error("no directory structure for {}?", file); delete newItem; newItem = nullptr; } diff --git a/src/texteditor.cpp b/src/texteditor.cpp index 130cd76f..0c0eb1cc 100644 --- a/src/texteditor.cpp +++ b/src/texteditor.cpp @@ -1,7 +1,10 @@ #include "texteditor.h" #include "utility.h" +#include #include +using namespace MOBase; + TextEditor::TextEditor(QWidget* parent) : QPlainTextEdit(parent), m_toolbar(nullptr), m_lineNumbers(nullptr), m_highlighter(nullptr), @@ -249,7 +252,7 @@ QWidget* TextEditor::wrapEditWidget() auto index = splitter->indexOf(this); if (index == -1) { - qCritical( + log::error( "TextEditor: cannot wrap edit widget to display a toolbar, " "parent is a splitter, but widget isn't in it"); @@ -260,7 +263,7 @@ QWidget* TextEditor::wrapEditWidget() } else { // unknown parent - qCritical( + log::error( "TextEditor: cannot wrap edit widget to display a toolbar, " "no parent or parent has no layout"); diff --git a/src/transfersavesdialog.cpp b/src/transfersavesdialog.cpp index 130df14f..1b211fd3 100644 --- a/src/transfersavesdialog.cpp +++ b/src/transfersavesdialog.cpp @@ -24,6 +24,7 @@ along with Mod Organizer. If not, see . #include "isavegame.h" #include "savegameinfo.h" #include +#include #include #include @@ -186,7 +187,7 @@ void TransferSavesDialog::on_moveToLocalBtn_clicked() [this](const QString &source, const QString &destination) -> bool { return shellMove(source, destination, this); }, - "Failed to move %s to %s")) { + "Failed to move {} to {}")) { refreshGlobalSaves(); refreshGlobalCharacters(); refreshLocalSaves(); @@ -203,7 +204,7 @@ void TransferSavesDialog::on_copyToLocalBtn_clicked() [this](const QString &source, const QString &destination) -> bool { return shellCopy(source, destination, this); }, - "Failed to copy %s to %s")) { + "Failed to copy {} to {}")) { refreshLocalSaves(); refreshLocalCharacters(); } @@ -218,7 +219,7 @@ void TransferSavesDialog::on_moveToGlobalBtn_clicked() [this](const QString &source, const QString &destination) -> bool { return shellMove(source, destination, this); }, - "Failed to move %s to %s")) { + "Failed to move {} to {}")) { refreshGlobalSaves(); refreshGlobalCharacters(); refreshLocalSaves(); @@ -235,7 +236,7 @@ void TransferSavesDialog::on_copyToGlobalBtn_clicked() [this](const QString &source, const QString &destination) -> bool { return shellCopy(source, destination, this); }, - "Failed to copy %s to %s")) { + "Failed to copy {} to {}")) { refreshGlobalSaves(); refreshGlobalCharacters(); } @@ -340,9 +341,7 @@ bool TransferSavesDialog::transferCharacters( } if (!method(sourceFile.absoluteFilePath(), destinationFile)) { - qCritical(errmsg, - sourceFile.absoluteFilePath().toUtf8().constData(), - qUtf8Printable(destinationFile)); + log::error(errmsg, sourceFile.absoluteFilePath(), destinationFile); } } } -- cgit v1.3.1 From b3d0ddb0b75da4abd59cae1508d983945c8e235d Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 19 Jul 2019 04:21:45 -0400 Subject: changed qDebug() to log::debug() removed some commented out logging --- src/categories.cpp | 4 +- src/downloadlistwidget.cpp | 5 ++- src/downloadmanager.cpp | 35 ++++++++--------- src/executableslist.cpp | 4 +- src/filerenamer.cpp | 43 +++++++++++---------- src/installationmanager.cpp | 16 ++++---- src/instancemanager.cpp | 2 +- src/loadmechanism.cpp | 13 ++++--- src/mainwindow.cpp | 37 +++++++----------- src/messagedialog.cpp | 6 ++- src/modinfodialog.cpp | 4 +- src/modinfodialogconflicts.cpp | 24 ++++++++---- src/modinfodialogfiletree.cpp | 12 +++--- src/modinforegular.cpp | 5 ++- src/modlist.cpp | 7 ++-- src/modlistsortproxy.cpp | 2 +- src/nexusinterface.cpp | 8 ++-- src/nxmaccessmanager.cpp | 4 +- src/organizercore.cpp | 41 +++++++++++--------- src/persistentcookiejar.cpp | 2 +- src/plugincontainer.cpp | 14 +++---- src/pluginlist.cpp | 6 +-- src/profile.cpp | 16 ++++---- src/qtgroupingproxy.cpp | 87 +++++++++++++++++------------------------- src/selfupdater.cpp | 18 ++++----- src/settings.cpp | 7 ++-- src/usvfsconnector.cpp | 19 ++++----- 27 files changed, 213 insertions(+), 228 deletions(-) (limited to 'src/modlist.cpp') diff --git a/src/categories.cpp b/src/categories.cpp index 7acf6ff5..12b18998 100644 --- a/src/categories.cpp +++ b/src/categories.cpp @@ -360,10 +360,10 @@ unsigned int CategoryFactory::resolveNexusID(int nexusID) const { std::map::const_iterator iter = m_NexusMap.find(nexusID); if (iter != m_NexusMap.end()) { - qDebug("nexus category id %d maps to internal %d", nexusID, iter->second); + log::debug("nexus category id {} maps to internal {}", nexusID, iter->second); return iter->second; } else { - qDebug("nexus category id %d not mapped", nexusID); + log::debug("nexus category id {} not mapped", nexusID); return 0U; } } diff --git a/src/downloadlistwidget.cpp b/src/downloadlistwidget.cpp index e2a6f321..85d27831 100644 --- a/src/downloadlistwidget.cpp +++ b/src/downloadlistwidget.cpp @@ -19,6 +19,7 @@ along with Mod Organizer. If not, see . #include "downloadlist.h" #include "downloadlistwidget.h" +#include #include #include #include @@ -29,6 +30,8 @@ along with Mod Organizer. If not, see . #include #include +using namespace MOBase; + void DownloadProgressDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QModelIndex sourceIndex = m_SortProxy->mapToSource(index); @@ -286,7 +289,7 @@ void DownloadListWidget::issueDelete() void DownloadListWidget::issueRemoveFromView() { - qDebug() << "removing from view: " << m_ContextRow; + log::debug("removing from view: {}", m_ContextRow); emit removeDownload(m_ContextRow, false); } diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index 348b2108..d2556faa 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -352,7 +352,7 @@ void DownloadManager::refreshList() } } if (orphans.size() > 0) { - qDebug("%d orphaned meta files will be deleted", orphans.size()); + log::debug("{} orphaned meta files will be deleted", orphans.size()); shellDelete(orphans, true); } @@ -379,7 +379,7 @@ void DownloadManager::refreshList() } //if (m_ActiveDownloads.size() != downloadsBefore) { - qDebug("Downloads after refresh: %d", m_ActiveDownloads.size()); + log::debug("Downloads after refresh: {}", m_ActiveDownloads.size()); //} emit update(-1); @@ -401,7 +401,7 @@ bool DownloadManager::addDownload(const QStringList &URLs, QString gameName, } QUrl preferredUrl = QUrl::fromEncoded(URLs.first().toLocal8Bit()); - qDebug("selected download url: %s", qUtf8Printable(preferredUrl.toString())); + log::debug("selected download url: {}", preferredUrl.toString()); QNetworkRequest request(preferredUrl); request.setHeader(QNetworkRequest::UserAgentHeader, m_NexusInterface->getAccessManager()->userAgent()); return addDownload(m_NexusInterface->getAccessManager()->get(request), URLs, fileName, gameName, modID, fileID, fileInfo); @@ -562,9 +562,9 @@ void DownloadManager::addNXMDownload(const QString &url) break; } } - qDebug("add nxm download: %s", qUtf8Printable(url)); + log::debug("add nxm download: {}", url); if (foundGame == nullptr) { - qDebug("download requested for wrong game (game: %s, url: %s)", qUtf8Printable(m_ManagedGame->gameShortName()), qUtf8Printable(nxmInfo.game())); + log::debug("download requested for wrong game (game: {}, url: {})", m_ManagedGame->gameShortName(), nxmInfo.game()); QMessageBox::information(nullptr, 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; @@ -572,13 +572,14 @@ void DownloadManager::addNXMDownload(const QString &url) 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()) { - QString debugStr("download requested is already queued (mod: %1, file: %2)"); - QString infoStr(tr("There is already a download queued for this file.\n\nMod %1\nFile %2")); + const auto infoStr = + tr("There is already a download queued for this file.\n\nMod %1\nFile %2") + .arg(nxmInfo.modId()).arg(nxmInfo.fileId()); - debugStr = debugStr.arg(nxmInfo.modId()).arg(nxmInfo.fileId()); - infoStr = infoStr.arg(nxmInfo.modId()).arg(nxmInfo.fileId()); + log::debug( + "download requested is already queued (mod: {}, file: {})", + nxmInfo.modId(), nxmInfo.fileId()); - qDebug(qUtf8Printable(debugStr)); QMessageBox::information(nullptr, tr("Already Queued"), infoStr, QMessageBox::Ok); return; } @@ -622,7 +623,7 @@ void DownloadManager::addNXMDownload(const QString &url) infoStr = infoStr.arg(QStringLiteral("")); } - qDebug(qUtf8Printable(debugStr)); + log::debug("{}", debugStr); QMessageBox::information(nullptr, tr("Already Started"), infoStr, QMessageBox::Ok); return; } @@ -883,7 +884,7 @@ void DownloadManager::resumeDownloadInt(int index) if (info->m_State == STATE_ERROR) { info->m_CurrentUrl = (info->m_CurrentUrl + 1) % info->m_Urls.count(); } - qDebug("request resume from url %s", qUtf8Printable(info->currentURL())); + log::debug("request resume from url {}", info->currentURL()); QNetworkRequest request(QUrl::fromEncoded(info->currentURL().toLocal8Bit())); request.setHeader(QNetworkRequest::UserAgentHeader, m_NexusInterface->getAccessManager()->userAgent()); if (info->m_State != STATE_ERROR) { @@ -896,7 +897,7 @@ void DownloadManager::resumeDownloadInt(int index) std::get<2>(info->m_SpeedDiff) = 0; std::get<3>(info->m_SpeedDiff) = 0; std::get<4>(info->m_SpeedDiff) = 0; - qDebug("resume at %lld bytes", info->m_ResumePos); + log::debug("resume at {} bytes", info->m_ResumePos); startDownload(m_NexusInterface->getAccessManager()->get(request), info, true); } emit update(index); @@ -993,11 +994,11 @@ void DownloadManager::queryInfoMd5(int index) downloadFile.setFileName(m_OrganizerCore->downloadsPath() + "\\" + info->m_FileName); } if (!downloadFile.exists()) { - qDebug("Can't find download file %s", info->m_FileName); + log::debug("Can't find download file {}", info->m_FileName); return; } if (!downloadFile.open(QIODevice::ReadOnly)) { - qDebug("Can't open download file %s", info->m_FileName); + log::debug("Can't open download file {}", info->m_FileName); return; } info->m_Hash = QCryptographicHash::hash(downloadFile.readAll(), QCryptographicHash::Md5); @@ -1384,7 +1385,7 @@ void DownloadManager::setState(DownloadManager::DownloadInfo *info, DownloadMana m_RequestIDs.insert(m_NexusInterface->requestFiles(info->m_FileInfo->gameName, info->m_FileInfo->modID, this, info->m_DownloadID, QString())); } break; case STATE_FETCHINGMODINFO_MD5: { - qDebug(qUtf8Printable(QString("Searching %1 for MD5 of %2").arg(info->m_GamesToQuery[0]).arg(QString(info->m_Hash.toHex())))); + 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: { @@ -1780,7 +1781,7 @@ void DownloadManager::nxmFileInfoFromMd5Available(QString gameName, QVariant use if (chosenIdx < 0) { chosenIdx = i; //intentional to not break in order to check other results } else { - qDebug("Multiple active files found during MD5 search. Defaulting to time stamps..."); + log::debug("Multiple active files found during MD5 search. Defaulting to time stamps..."); chosenIdx = -1; break; } diff --git a/src/executableslist.cpp b/src/executableslist.cpp index 2408e8f3..3f76bb6f 100644 --- a/src/executableslist.cpp +++ b/src/executableslist.cpp @@ -166,7 +166,7 @@ std::vector ExecutablesList::getPluginExecutables( void ExecutablesList::resetFromPlugin(MOBase::IPluginGame const *game) { - qDebug("resetting plugin executables"); + log::debug("resetting plugin executables"); Q_ASSERT(game != nullptr); @@ -295,7 +295,7 @@ std::optional ExecutablesList::makeNonConflictingTitle( void ExecutablesList::upgradeFromCustom(MOBase::IPluginGame const *game) { - qDebug() << "upgrading executables list"; + log::debug("upgrading executables list"); Q_ASSERT(game != nullptr); diff --git a/src/filerenamer.cpp b/src/filerenamer.cpp index 8835f52f..a97d7742 100644 --- a/src/filerenamer.cpp +++ b/src/filerenamer.cpp @@ -18,10 +18,10 @@ FileRenamer::FileRenamer(QWidget* parent, QFlags flags) FileRenamer::RenameResults FileRenamer::rename(const QString& oldName, const QString& newName) { - qDebug().nospace() << "renaming " << oldName << " to " << newName; + log::debug("renaming {} to {}", oldName, newName); if (QFileInfo(newName).exists()) { - qDebug().nospace() << newName << " already exists"; + log::debug("{} already exists", newName); // target file already exists, confirm replacement auto answer = confirmReplace(newName); @@ -29,24 +29,25 @@ FileRenamer::RenameResults FileRenamer::rename(const QString& oldName, const QSt switch (answer) { case DECISION_SKIP: { // user wants to skip this file - qDebug().nospace() << "skipping " << oldName; + log::debug("skipping {}", oldName); return RESULT_SKIP; } case DECISION_REPLACE: { - qDebug().nospace() << "removing " << newName; + log::debug("removing {}", newName); + // user wants to replace the file, so remove it if (!QFile(newName).remove()) { log::warn("failed to remove '{}'", newName); // removal failed, warn the user and allow canceling if (!removeFailed(newName)) { - qDebug().nospace() << "canceling " << oldName; + log::debug("canceling {}", oldName); // user wants to cancel return RESULT_CANCEL; } // ignore this file and continue on - qDebug().nospace() << "skipping " << oldName; + log::debug("skipping {}", oldName); return RESULT_SKIP; } @@ -56,7 +57,7 @@ FileRenamer::RenameResults FileRenamer::rename(const QString& oldName, const QSt case DECISION_CANCEL: // fall-through default: { // user wants to stop - qDebug().nospace() << "canceling"; + log::debug("canceling"); return RESULT_CANCEL; } } @@ -70,17 +71,17 @@ FileRenamer::RenameResults FileRenamer::rename(const QString& oldName, const QSt // renaming failed, warn the user and allow canceling if (!renameFailed(oldName, newName)) { // user wants to cancel - qDebug().nospace() << "canceling"; + log::debug("canceling"); return RESULT_CANCEL; } // ignore this file and continue on - qDebug().nospace() << "skipping " << oldName; + log::debug("skipping {}", oldName); return RESULT_SKIP; } // everything worked - qDebug().nospace() << "successfully renamed " << oldName << " to " << newName; + log::debug("successfully renamed {} to {}", oldName, newName); return RESULT_OK; } @@ -88,12 +89,12 @@ FileRenamer::RenameDecision FileRenamer::confirmReplace(const QString& newName) { if (m_flags & REPLACE_ALL) { // user wants to silently replace all - qDebug().nospace() << "user has selected replace all"; + log::debug("user has selected replace all"); return DECISION_REPLACE; } else if (m_flags & REPLACE_NONE) { // user wants to silently skip all - qDebug().nospace() << "user has selected replace none"; + log::debug("user has selected replace none"); return DECISION_SKIP; } @@ -117,28 +118,28 @@ FileRenamer::RenameDecision FileRenamer::confirmReplace(const QString& newName) switch (answer) { case QMessageBox::Yes: - qDebug().nospace() << "user wants to replace"; + log::debug("user wants to replace"); return DECISION_REPLACE; case QMessageBox::No: - qDebug().nospace() << "user wants to skip"; + log::debug("user wants to skip"); return DECISION_SKIP; case QMessageBox::YesToAll: - qDebug().nospace() << "user wants to replace all"; + log::debug("user wants to replace all"); // remember the answer m_flags |= REPLACE_ALL; return DECISION_REPLACE; case QMessageBox::NoToAll: - qDebug().nospace() << "user wants to replace none"; + log::debug("user wants to replace none"); // remember the answer m_flags |= REPLACE_NONE; return DECISION_SKIP; case QMessageBox::Cancel: // fall-through default: - qDebug().nospace() << "user wants to cancel"; + log::debug("user wants to cancel"); return DECISION_CANCEL; } } @@ -158,12 +159,12 @@ bool FileRenamer::removeFailed(const QString& name) if (answer == QMessageBox::Cancel) { // user wants to stop - qDebug().nospace() << "user wants to cancel"; + log::debug("user wants to cancel"); return false; } // skip this one and continue - qDebug().nospace() << "user wants to skip"; + log::debug("user wants to skip"); return true; } @@ -182,11 +183,11 @@ bool FileRenamer::renameFailed(const QString& oldName, const QString& newName) if (answer == QMessageBox::Cancel) { // user wants to stop - qDebug().nospace() << "user wants to cancel"; + log::debug("user wants to cancel"); return false; } // skip this one and continue - qDebug().nospace() << "user wants to skip"; + log::debug("user wants to skip"); return true; } diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp index fd971f47..89d0079f 100644 --- a/src/installationmanager.cpp +++ b/src/installationmanager.cpp @@ -398,7 +398,7 @@ bool InstallationManager::isSimpleArchiveTopLayer(const DirectoryTree::Node *nod for (DirectoryTree::const_node_iterator iter = node->nodesBegin(); iter != node->nodesEnd(); ++iter) { if ((bainStyle && InstallationTester::isTopLevelDirectoryBain((*iter)->getData().name)) || (!bainStyle && InstallationTester::isTopLevelDirectory((*iter)->getData().name))) { - qDebug("%s on the top level", (*iter)->getData().name.toUtf8().constData()); + log::debug("{} on the top level", (*iter)->getData().name.toQString()); return true; } } @@ -424,7 +424,7 @@ DirectoryTree::Node *InstallationManager::getSimpleArchiveBase(DirectoryTree *da (currentNode->numNodes() == 1)) { currentNode = *currentNode->nodesBegin(); } else { - qDebug("not a simple archive"); + log::debug("not a simple archive"); return nullptr; } } @@ -576,7 +576,7 @@ bool InstallationManager::doInstall(GuessedValue &modName, QString game QString targetDirectory = QDir(m_ModsDirectory + "/" + modName).canonicalPath(); QString targetDirectoryNative = QDir::toNativeSeparators(targetDirectory); - qDebug("installing to \"%s\"", qUtf8Printable(targetDirectoryNative)); + log::debug("installing to \"{}\"", targetDirectoryNative); m_InstallationProgress = new QProgressDialog(m_ParentWidget); ON_BLOCK_EXIT([this] () { @@ -764,7 +764,7 @@ bool InstallationManager::install(const QString &fileName, if ((modID == 0) && (guessedModID != -1)) { modID = guessedModID; } else if (modID != guessedModID) { - qDebug("passed mod id: %d, guessed id: %d", modID, guessedModID); + log::debug("passed mod id: {}, guessed id: {}", modID, guessedModID); } modName.update(guessedModName, GUESS_GOOD); @@ -774,7 +774,7 @@ bool InstallationManager::install(const QString &fileName, if (fileInfo.dir() == QDir(m_DownloadsDirectory)) { m_CurrentFile = fileInfo.fileName(); } - qDebug("using mod name \"%s\" (id %d) -> %s", qUtf8Printable(modName), modID, qUtf8Printable(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 @@ -785,9 +785,9 @@ bool InstallationManager::install(const QString &fileName, bool archiveOpen = m_ArchiveHandler->open(fileName, new MethodCallback(this, &InstallationManager::queryPassword)); if (!archiveOpen) { - qDebug("integrated archiver can't open %s: %s (%d)", - qUtf8Printable(fileName), - qUtf8Printable(getErrorString(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)); diff --git a/src/instancemanager.cpp b/src/instancemanager.cpp index 55ef3fc8..fdc30e22 100644 --- a/src/instancemanager.cpp +++ b/src/instancemanager.cpp @@ -224,7 +224,7 @@ QString InstanceManager::chooseInstance(const QStringList &instanceList) const selection.setWindowFlags(selection.windowFlags() | Qt::WindowStaysOnTopHint); if (selection.exec() == QDialog::Rejected) { - qDebug("rejected"); + log::debug("rejected"); throw MOBase::MyException(QObject::tr("Canceled")); } diff --git a/src/loadmechanism.cpp b/src/loadmechanism.cpp index 8f0529ce..4d6cebd4 100644 --- a/src/loadmechanism.cpp +++ b/src/loadmechanism.cpp @@ -23,6 +23,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include #include #include @@ -141,7 +142,7 @@ void LoadMechanism::deactivateScriptExtender() { vfsDLLName = ToQString(AppConfig::vfs64DLLName()); } - qDebug("USVFS DLL Name: " + vfsDLLName.toLatin1()); + log::debug("USVFS DLL Name: {}", vfsDLLName); if (vfsDLLName != "") { if (QFile(pluginsDir.absoluteFilePath(vfsDLLName)).exists()) { // remove dll from SE plugins directory @@ -215,8 +216,8 @@ void LoadMechanism::activateScriptExtender() QString targetPath = pluginsDir.absoluteFilePath(ToQString(vfsDLL)); QString vfsDLLPath = qApp->applicationDirPath() + "/" + QString::fromStdWString(vfsDLL); - qDebug("DLL USVFS Target Path: " + targetPath.toLatin1()); - qDebug("DLL USVFS VFS DLL Path: " + vfsDLLPath.toLatin1()); + log::debug("DLL USVFS Target Path: {}", targetPath); + log::debug("DLL USVFS VFS DLL Path: {}", vfsDLLPath); QFile dllFile(targetPath); @@ -297,17 +298,17 @@ void LoadMechanism::activate(EMechanism mechanism) { switch (mechanism) { case LOAD_MODORGANIZER: { - qDebug("Load Mechanism: Mod Organizer"); + log::debug("Load Mechanism: Mod Organizer"); deactivateProxyDLL(); deactivateScriptExtender(); } break; case LOAD_SCRIPTEXTENDER: { - qDebug("Load Mechanism: ScriptExtender"); + log::debug("Load Mechanism: ScriptExtender"); deactivateProxyDLL(); activateScriptExtender(); } break; case LOAD_PROXYDLL: { - qDebug("Load Mechanism: Proxy DLL"); + log::debug("Load Mechanism: Proxy DLL"); deactivateScriptExtender(); activateProxyDLL(); } break; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index ad87ba03..e502bdb1 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -867,7 +867,7 @@ void MainWindow::updatePinnedExecutables() exeAction->setStatusTip(exe.binaryInfo().filePath()); if (!connect(exeAction, SIGNAL(triggered()), this, SLOT(startExeAction()))) { - qDebug("failed to connect trigger?"); + log::debug("failed to connect trigger?"); } if (m_linksSeparator) { @@ -1711,7 +1711,7 @@ void MainWindow::on_profileBox_currentIndexChanged(int index) // ensure the new index is valid if (index < 0 || index >= ui->profileBox->count()) { - qDebug("invalid profile index, using last profile"); + log::debug("invalid profile index, using last profile"); ui->profileBox->setCurrentIndex(ui->profileBox->count() - 1); } @@ -2060,7 +2060,7 @@ void MainWindow::refreshSaveList() QDir savesDir = currentSavesDir(); savesDir.setNameFilters(filters); - qDebug("reading save games from %s", qUtf8Printable(savesDir.absolutePath())); + log::debug("reading save games from {}", savesDir.absolutePath()); QFileInfoList files = savesDir.entryInfoList(QDir::Files, QDir::Time); for (const QFileInfo &file : files) { @@ -2261,15 +2261,6 @@ void MainWindow::fixCategories() void MainWindow::setupNetworkProxy(bool activate) { QNetworkProxyFactory::setUseSystemConfiguration(activate); -/* QNetworkProxyQuery query(QUrl("http://www.google.com"), QNetworkProxyQuery::UrlRequest); - query.setProtocolTag("http"); - QList proxies = QNetworkProxyFactory::systemProxyForQuery(query); - if ((proxies.size() > 0) && (proxies.at(0).type() != QNetworkProxy::NoProxy)) { - qDebug("Using proxy: %s", qUtf8Printable(proxies.at(0).hostName())); - QNetworkProxy::setApplicationProxy(proxies[0]); - } else { - qDebug("Not using proxy"); - }*/ } @@ -2456,7 +2447,7 @@ void MainWindow::unlock() { //If you come through here with a null lock pointer, it's a bug! if (m_LockDialog == nullptr) { - qDebug("Unlocking main window when already unlocked"); + log::debug("Unlocking main window when already unlocked"); return; } --m_LockCount; @@ -3259,7 +3250,7 @@ void MainWindow::displayModInformation( ModInfo::Ptr modInfo, unsigned int modIndex, ModInfoTabIDs tabID) { if (!m_OrganizerCore.modList()->modInfoAboutToChange(modInfo)) { - qDebug("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 flags = modInfo->getFlags(); @@ -4325,7 +4316,7 @@ void MainWindow::addRemoveCategories_MenuHandler() { int maxRow = -1; for (const QPersistentModelIndex &idx : selected) { - qDebug("change categories on: %s", qUtf8Printable(idx.data().toString())); + log::debug("change categories on: {}", idx.data().toString()); QModelIndex modIdx = mapToModel(m_OrganizerCore.modList(), idx); if (modIdx.row() != m_ContextIdx.row()) { addRemoveCategoriesFromMenu(menu, modIdx.row(), m_ContextIdx.row()); @@ -4407,7 +4398,7 @@ void MainWindow::saveArchiveList() } } if (archiveFile.commitIfDifferent(m_ArchiveListHash)) { - qDebug("%s saved", qUtf8Printable(QDir::toNativeSeparators(m_OrganizerCore.currentProfile()->getArchivesFileName()))); + log::debug("{} saved", QDir::toNativeSeparators(m_OrganizerCore.currentProfile()->getArchivesFileName())); } } else { log::warn("archive list not initialised"); @@ -5364,7 +5355,7 @@ void MainWindow::installTranslator(const QString &name) QString fileName = name + "_" + m_CurrentLanguage; if (!translator->load(fileName, qApp->applicationDirPath() + "/translations")) { if (m_CurrentLanguage.contains(QRegularExpression("^.*_(EN|en)(-.*)?$"))) { - qDebug("localization file %s not found", qUtf8Printable(fileName)); + 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) } @@ -5389,7 +5380,7 @@ void MainWindow::languageChange(const QString &newLanguage) installTranslator(QFileInfo(fileName).baseName()); } ui->retranslateUi(this); - qDebug("loaded language %s", qUtf8Printable(newLanguage)); + log::debug("loaded language {}", newLanguage); ui->profileBox->setItemText(0, QObject::tr("")); @@ -5634,7 +5625,7 @@ void MainWindow::openDataOriginExplorer_clicked() const auto fullPath = m_ContextItem->data(0, Qt::UserRole).toString(); - qDebug().nospace() << "opening in explorer: " << fullPath; + log::debug("opening in explorer: {}", fullPath); shell::ExploreFile(fullPath); } @@ -6120,7 +6111,7 @@ void MainWindow::nxmDownloadURLs(QString, int, int, QVariant, QVariant resultDat void MainWindow::nxmRequestFailed(QString gameName, int modID, int, QVariant, int, QNetworkReply::NetworkError error, const QString &errorString) { if (error == QNetworkReply::ContentAccessDenied || error == QNetworkReply::ContentNotFoundError) { - qDebug(qUtf8Printable(tr("Mod ID %1 no longer seems to be available on Nexus.").arg(modID))); + log::debug("{}", tr("Mod ID %1 no longer seems to be available on Nexus.").arg(modID)); } else { MessageDialog::showMessage(tr("Request to Nexus failed: %1").arg(errorString), this); } @@ -6587,7 +6578,7 @@ void MainWindow::processLOOTOut(const std::string &lootOut, std::string &errorMe std::string dependency(match[2].first, match[2].second); m_OrganizerCore.pluginList()->addInformation(modName.c_str(), tr("incompatible with \"%1\"").arg(dependency.c_str())); } else { - qDebug("[loot] %s", line.c_str()); + log::debug("[loot] {}", line); } } } @@ -6632,7 +6623,7 @@ void MainWindow::on_bossButton_clicked() try { m_OrganizerCore.prepareVFS(); } catch (const UsvfsConnectorException &e) { - qDebug(e.what()); + log::debug("{}", e.what()); return; } catch (const std::exception &e) { QMessageBox::warning(qApp->activeWindow(), tr("Error"), e.what()); @@ -6662,7 +6653,7 @@ void MainWindow::on_bossButton_clicked() if (isJobHandle) { if (::QueryInformationJobObject(loot, JobObjectBasicProcessIdList, &info, sizeof(info), &retLen) > 0) { if (info.NumberOfProcessIdsInList == 0) { - qDebug("no more processes in job"); + log::debug("no more processes in job"); break; } else { if (lastProcessID != info.ProcessIdList[0]) { diff --git a/src/messagedialog.cpp b/src/messagedialog.cpp index 6c6de3e7..78a5dd4d 100644 --- a/src/messagedialog.cpp +++ b/src/messagedialog.cpp @@ -19,10 +19,13 @@ along with Mod Organizer. If not, see . #include "messagedialog.h" #include "ui_messagedialog.h" +#include #include #include #include +using namespace MOBase; + MessageDialog::MessageDialog(const QString &text, QWidget *reference) : QDialog(reference), ui(new Ui::MessageDialog) @@ -81,7 +84,8 @@ void MessageDialog::resizeEvent(QResizeEvent *event) void MessageDialog::showMessage(const QString &text, QWidget *reference, bool bringToFront) { - qDebug("%s", qUtf8Printable(text)); + log::debug("{}", text); + if (reference != nullptr) { if (bringToFront || (qApp->activeWindow() != nullptr)) { MessageDialog *dialog = new MessageDialog(text, reference); diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index a7a6b0d7..4b1e2f76 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -556,9 +556,7 @@ void ModInfoDialog::switchToTab(ModInfoTabIDs id) } // this could happen if the tab is not visible right now - qDebug() - << "can't switch to tab ID " << static_cast(id) - << ", not available"; + log::debug("can't switch to tab ID {}, not available", static_cast(id)); } MOShared::FilesOrigin* ModInfoDialog::getOrigin() diff --git a/src/modinfodialogconflicts.cpp b/src/modinfodialogconflicts.cpp index d16d548c..9a5d9d8d 100644 --- a/src/modinfodialogconflicts.cpp +++ b/src/modinfodialogconflicts.cpp @@ -438,10 +438,18 @@ void ConflictsTab::changeItemsVisibility(QTreeView* tree, bool visible) const auto n = smallSelectionSize(tree); - qDebug().nospace().noquote() - << (visible ? "unhiding" : "hiding") << " " - << (n > max_small_selection ? "a lot of" : QString("%1").arg(n)) - << " conflict files"; + // logging + { + const QString action = (visible ? "unhiding" : "hiding"); + + QString files; + if (n > max_small_selection) + files = "a lot of"; + else + files = QString("%1").arg(n); + + log::debug("{} {} conflict files", action, files); + } QFlags flags = (visible ? FileRenamer::UNHIDE : FileRenamer::HIDE); @@ -467,7 +475,7 @@ void ConflictsTab::changeItemsVisibility(QTreeView* tree, bool visible) if (visible) { if (!item->canUnhide()) { - qDebug().nospace() << "cannot unhide " << item->relativeName() << ", skipping"; + log::debug("cannot unhide {}, skipping", item->relativeName()); return true; } @@ -475,7 +483,7 @@ void ConflictsTab::changeItemsVisibility(QTreeView* tree, bool visible) } else { if (!item->canHide()) { - qDebug().nospace() << "cannot hide " << item->relativeName() << ", skipping"; + log::debug("cannot hide {}, skipping", item->relativeName()); return true; } @@ -504,10 +512,10 @@ void ConflictsTab::changeItemsVisibility(QTreeView* tree, bool visible) return true; }); - qDebug().nospace() << (visible ? "unhiding" : "hiding") << " conflict files done"; + log::debug("{} conflict files done", (visible ? "unhiding" : "hiding")); if (changed) { - qDebug().nospace() << "triggering refresh"; + log::debug("triggering refresh"); if (origin()) { emitOriginModified(); diff --git a/src/modinfodialogfiletree.cpp b/src/modinfodialogfiletree.cpp index 219ddf35..207c792d 100644 --- a/src/modinfodialogfiletree.cpp +++ b/src/modinfodialogfiletree.cpp @@ -257,9 +257,9 @@ void FileTreeTab::changeVisibility(bool visible) bool changed = false; bool stop = false; - qDebug().nospace() - << (visible ? "unhiding" : "hiding") << " " - << selection.size() << " filetree files"; + log::debug( + "{} {} filetree files", + (visible ? "unhiding" : "hiding"), selection.size()); QFlags flags = (visible ? FileRenamer::UNHIDE : FileRenamer::HIDE); @@ -280,13 +280,13 @@ void FileTreeTab::changeVisibility(bool visible) if (visible) { if (!canUnhideFile(false, path)) { - qDebug().nospace() << "cannot unhide " << path << ", skipping"; + log::debug("cannot unhide {}, skipping", path); continue; } result = unhideFile(renamer, path); } else { if (!canHideFile(false, path)) { - qDebug().nospace() << "cannot hide " << path << ", skipping"; + log::debug("cannot hide {}, skipping", path); continue; } result = hideFile(renamer, path); @@ -312,7 +312,7 @@ void FileTreeTab::changeVisibility(bool visible) } } - qDebug().nospace() << (visible ? "unhiding" : "hiding") << " filetree files done"; + log::debug("{} filetree files done", (visible ? "unhiding" : "hiding")); if (changed) { if (origin()) { diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index 074fa9e2..6e11befc 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -883,8 +883,9 @@ std::vector ModInfoRegular::getIniTweaks() const int numTweaks = metaFile.beginReadArray("INI Tweaks"); if (numTweaks != 0) { - qDebug("%d active ini tweaks in %s", - numTweaks, QDir::toNativeSeparators(metaFileName).toUtf8().constData()); + log::debug( + "{} active ini tweaks in {}", + numTweaks, QDir::toNativeSeparators(metaFileName)); } for (int i = 0; i < numTweaks; ++i) { diff --git a/src/modlist.cpp b/src/modlist.cpp index 6ebd0e8b..39f51d72 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -1013,9 +1013,8 @@ bool ModList::dropURLs(const QMimeData *mimeData, int row, const QModelIndex &pa QString overwriteName = ModInfo::getByIndex(overwriteIndex)->name(); for (auto url : mimeData->urls()) { - //qDebug("URL drop requested: %s -> %s", qUtf8Printable(url.url()), qUtf8Printable(modDir.canonicalPath())); if (!url.isLocalFile()) { - qDebug("URL drop ignored: \"%s\" is not a local file", qUtf8Printable(url.url())); + log::debug("URL drop ignored: \"{}\" is not a local file", url.url()); continue; } @@ -1035,7 +1034,7 @@ bool ModList::dropURLs(const QMimeData *mimeData, int row, const QModelIndex &pa originName = overwriteName; relativePath = overwriteDir.relativeFilePath(sourceFile); } else { - qDebug("URL drop ignored: \"%s\" is not a known file to MO", qUtf8Printable(sourceFile)); + log::debug("URL drop ignored: \"{}\" is not a known file to MO", sourceFile); continue; } @@ -1047,7 +1046,7 @@ bool ModList::dropURLs(const QMimeData *mimeData, int row, const QModelIndex &pa if (sourceList.count()) { if (!shellMove(sourceList, targetList)) { - qDebug("Failed to move file (error %d)", ::GetLastError()); + log::debug("Failed to move file (error {})", ::GetLastError()); return false; } } diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp index d330e0c2..77ffad96 100644 --- a/src/modlistsortproxy.cpp +++ b/src/modlistsortproxy.cpp @@ -482,7 +482,7 @@ bool ModListSortProxy::filterAcceptsRow(int row, const QModelIndex &parent) cons QModelIndex idx = sourceModel()->index(row, 0, parent); if (!idx.isValid()) { - qDebug("invalid mod index"); + log::debug("invalid mod index"); return false; } if (sourceModel()->hasChildren(idx)) { diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp index c797aed6..0e2bb45b 100644 --- a/src/nexusinterface.cpp +++ b/src/nexusinterface.cpp @@ -316,15 +316,15 @@ void NexusInterface::interpretNexusFileName(const QString &fileName, QString &mo } else { modID = strtol(candidate.c_str(), nullptr, 10); } - qDebug("mod id guessed: %s -> %d", qUtf8Printable(fileName), modID); + log::debug("mod id guessed: {} -> {}", fileName, modID); } else if (std::regex_search(fileNameUTF8.constData(), result, simpleexp)) { - qDebug("simple expression matched, using name only"); + log::debug("simple expression matched, using name only"); modName = QString::fromUtf8(result[1].str().c_str()); modName = modName.replace('_', ' ').trimmed(); modID = -1; } else { - qDebug("no expression matched!"); + log::debug("no expression matched!"); modName.clear(); modID = -1; } @@ -860,7 +860,7 @@ void NexusInterface::requestFinished(std::list::iterator iter) if (nexusError.length() == 0) { nexusError = tr("empty response"); } - qDebug("nexus error: %s", qUtf8Printable(nexusError)); + 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); } else { QJsonDocument responseDoc = QJsonDocument::fromJson(data); diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp index 9f40894e..fd1dc0c1 100644 --- a/src/nxmaccessmanager.cpp +++ b/src/nxmaccessmanager.cpp @@ -600,9 +600,9 @@ void NXMAccessManager::showCookies() const { QUrl url(NexusBaseUrl + "/"); for (const QNetworkCookie &cookie : cookieJar()->cookiesForUrl(url)) { - qDebug("%s - %s (expires: %s)", + log::debug("{} - {} (expires: {})", cookie.name().constData(), cookie.value().constData(), - qUtf8Printable(cookie.expirationDate().toString())); + cookie.expirationDate().toString()); } } diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 725371e9..f6802673 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -89,9 +89,9 @@ static bool isOnline() if (addresses.count() == 0) { continue; } - qDebug("interface %s seems to be up (address: %s)", - qUtf8Printable(iter->humanReadableName()), - qUtf8Printable(addresses[0].ip().toString())); + log::debug("interface {} seems to be up (address: {})", + iter->humanReadableName(), + addresses[0].ip().toString()); connected = true; } } @@ -543,7 +543,7 @@ void OrganizerCore::setUserInterface(IUserInterface *userInterface, if (isOnline() && !m_Settings.offlineMode()) { m_Updater.testForUpdate(); } else { - qDebug("user doesn't seem to be connected to the internet"); + log::debug("user doesn't seem to be connected to the internet"); } } } @@ -605,7 +605,7 @@ bool OrganizerCore::nexusApi(bool retry) QString apiKey; if (m_Settings.getNexusApiKey(apiKey)) { // credentials stored or user entered them manually - qDebug("attempt to verify nexus api key"); + log::debug("attempt to verify nexus api key"); accessManager->apiCheck(apiKey); return true; } else { @@ -627,7 +627,7 @@ void OrganizerCore::startMOUpdate() void OrganizerCore::downloadRequestedNXM(const QString &url) { - qDebug("download requested: %s", qUtf8Printable(url)); + log::debug("download requested: {}", url); if (nexusApi()) { m_PendingDownloads.append(url); } else { @@ -1208,7 +1208,9 @@ QString OrganizerCore::findJavaInstallation(const QString& jarFile) if (::FindExecutableW(jarFileW.c_str(), nullptr, buffer) > (HINSTANCE)32) { DWORD binaryType = 0UL; if (!::GetBinaryTypeW(buffer, &binaryType)) { - qDebug("failed to determine binary type of \"%ls\": %lu", buffer, ::GetLastError()); + log::debug( + "failed to determine binary type of \"{}\": {}", + QString::fromWCharArray(buffer), ::GetLastError()); } else if (binaryType == SCS_32BIT_BINARY || binaryType == SCS_64BIT_BINARY) { return QString::fromWCharArray(buffer); } @@ -1459,7 +1461,7 @@ void OrganizerCore::spawnBinary(const QFileInfo &binary, // 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) { - qDebug("removing loadorder.txt"); + log::debug("removing loadorder.txt"); QFile::remove(m_CurrentProfile->getLoadOrderFileName()); } refreshDirectoryStructure(); @@ -1627,7 +1629,7 @@ HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary, m_USVFS.updateForcedLibraries(forcedLibraries); } catch (const UsvfsConnectorException &e) { - qDebug(e.what()); + log::debug(e.what()); return INVALID_HANDLE_VALUE; } catch (const std::exception &e) { QMessageBox::warning(window, tr("Error"), e.what()); @@ -1694,17 +1696,16 @@ HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary, .arg(QDir::toNativeSeparators(cwdPath), QDir::toNativeSeparators(binPath), arguments); - qDebug() << "Spawning proxyed process <" << cmdline << ">"; + log::debug("Spawning proxyed process <{}>", cmdline); return startBinary(QFileInfo(QCoreApplication::applicationFilePath()), cmdline, QCoreApplication::applicationDirPath(), true); } else { - qDebug() << "Spawning direct process <" << binPath << "," << arguments << "," << cwdPath << ">"; + log::debug("Spawning direct process <{}, {}, {}>", binPath, arguments, cwdPath); return startBinary(binary, arguments, currentDirectory, true); } } else { - qDebug("start of \"%s\" canceled by plugin", - qUtf8Printable(binary.absoluteFilePath())); + log::debug("start of \"{}\" canceled by plugin", binary.absoluteFilePath()); return INVALID_HANDLE_VALUE; } } @@ -1872,9 +1873,11 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode, IL processName += QString(" (%1)").arg(currentPID); if (uilock) uilock->setProcessName(processName); - qDebug() << "Waiting for" - << (originalHandle ? "spawned" : "usvfs") - << "process completion :" << qUtf8Printable(processName); + + log::debug( + "Waiting for {} process completion: {}", + (originalHandle ? "spawned" : "usvfs"), processName); + newHandle = false; } @@ -1943,11 +1946,11 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode, IL } if (res == WAIT_OBJECT_0) - qDebug() << "Waiting for process completion successfull"; + log::debug("Waiting for process completion successfull"); else if (uiunlocked) - qDebug() << "Waiting for process completion aborted by UI"; + log::debug("Waiting for process completion aborted by UI"); else - qDebug() << "Waiting for process completion not successfull :" << res; + log::debug("Waiting for process completion not successfull: {}", res); if (handle != INVALID_HANDLE_VALUE) ::CloseHandle(handle); diff --git a/src/persistentcookiejar.cpp b/src/persistentcookiejar.cpp index 670bf382..8657f356 100644 --- a/src/persistentcookiejar.cpp +++ b/src/persistentcookiejar.cpp @@ -13,7 +13,7 @@ PersistentCookieJar::PersistentCookieJar(const QString &fileName, QObject *paren } PersistentCookieJar::~PersistentCookieJar() { - qDebug("save %s", qUtf8Printable(m_FileName)); + log::debug("save {}", m_FileName); save(); } diff --git a/src/plugincontainer.cpp b/src/plugincontainer.cpp index 36daec52..62cdff1e 100644 --- a/src/plugincontainer.cpp +++ b/src/plugincontainer.cpp @@ -91,7 +91,7 @@ bool PluginContainer::registerPlugin(QObject *plugin, const QString &fileName) { // generic treatment for all plugins IPlugin *pluginObj = qobject_cast(plugin); if (pluginObj == nullptr) { - qDebug("not an IPlugin"); + log::debug("not an IPlugin"); return false; } plugin->setProperty("filename", fileName); @@ -164,7 +164,7 @@ bool PluginContainer::registerPlugin(QObject *plugin, const QString &fileName) for (QObject *proxiedPlugin : matchingPlugins) { if (proxiedPlugin != nullptr) { if (registerPlugin(proxiedPlugin, pluginName)) { - qDebug("loaded plugin \"%s\"", qUtf8Printable(QFileInfo(pluginName).fileName())); + log::debug("loaded plugin \"{}\"", QFileInfo(pluginName).fileName()); } else { log::warn( @@ -191,7 +191,7 @@ bool PluginContainer::registerPlugin(QObject *plugin, const QString &fileName) } } - qDebug("no matching plugin interface"); + log::debug("no matching plugin interface"); return false; } @@ -225,7 +225,7 @@ void PluginContainer::unloadPlugins() QPluginLoader *loader = m_PluginLoaders.back(); m_PluginLoaders.pop_back(); if ((loader != nullptr) && !loader->unload()) { - qDebug("failed to unload %s: %s", qUtf8Printable(loader->fileName()), qUtf8Printable(loader->errorString())); + log::debug("failed to unload {}: {}", loader->fileName(), loader->errorString()); } delete loader; } @@ -274,13 +274,13 @@ void PluginContainer::loadPlugins() loadCheck.open(QIODevice::WriteOnly); QString pluginPath = qApp->applicationDirPath() + "/" + ToQString(AppConfig::pluginPath()); - qDebug("looking for plugins in %s", QDir::toNativeSeparators(pluginPath).toUtf8().constData()); + log::debug("looking for plugins in {}", QDir::toNativeSeparators(pluginPath)); QDirIterator iter(pluginPath, QDir::Files | QDir::NoDotAndDotDot); while (iter.hasNext()) { iter.next(); if (m_Organizer->settings().pluginBlacklisted(iter.fileName())) { - qDebug("plugin \"%s\" blacklisted", qUtf8Printable(iter.fileName())); + log::debug("plugin \"{}\" blacklisted", iter.fileName()); continue; } loadCheck.write(iter.fileName().toUtf8()); @@ -296,7 +296,7 @@ void PluginContainer::loadPlugins() pluginName, pluginLoader->errorString()); } else { if (registerPlugin(pluginLoader->instance(), pluginName)) { - qDebug("loaded plugin \"%s\"", qUtf8Printable(QFileInfo(pluginName).fileName())); + log::debug("loaded plugin \"{}\"", QFileInfo(pluginName).fileName()); m_PluginLoaders.push_back(pluginLoader.release()); } else { m_FailedPlugins.push_back(pluginName); diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index e436d7f6..6718641f 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -481,7 +481,7 @@ void PluginList::writeLockedOrder(const QString &fileName) const file->write(QString("%1|%2\r\n").arg(iter->first).arg(iter->second).toUtf8()); } file.commit(); - qDebug("%s saved", qUtf8Printable(QDir::toNativeSeparators(fileName))); + log::debug("{} saved", QDir::toNativeSeparators(fileName)); } @@ -506,7 +506,7 @@ void PluginList::saveTo(const QString &lockedOrderFileName } } if (deleterFile.commitIfDifferent(m_LastSaveHash[deleterFileName])) { - qDebug("%s saved", qUtf8Printable(QDir::toNativeSeparators(deleterFileName))); + log::debug("{} saved", QDir::toNativeSeparators(deleterFileName)); } } else if (QFile::exists(deleterFileName)) { shellDelete(QStringList() << deleterFileName); @@ -521,7 +521,7 @@ bool PluginList::saveLoadOrder(DirectoryEntry &directoryStructure) return true; } - qDebug("setting file times on esps"); + log::debug("setting file times on esps"); for (ESPInfo &esp : m_ESPs) { std::wstring espName = ToWString(esp.m_Name); diff --git a/src/profile.cpp b/src/profile.cpp index 555de89a..27616986 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -40,7 +40,6 @@ along with Mod Organizer. If not, see . #include #include #include // for QStringList -#include // for qDebug, qWarning, etc #include // for qUtf8Printable #include #include @@ -232,7 +231,6 @@ void Profile::doWriteModlist() } for (std::map::const_reverse_iterator iter = m_ModIndexByPriority.crbegin(); iter != m_ModIndexByPriority.crend(); iter++ ) { - //qDebug(QString("write mod %1 to priority %2").arg(iter->first).arg(iter->second).toLocal8Bit()); // the priority order was inverted on load so it has to be inverted again unsigned int index = iter->second; if (index != UINT_MAX) { @@ -253,7 +251,7 @@ void Profile::doWriteModlist() } if (file.commitIfDifferent(m_LastModlistHash)) { - qDebug("%s saved", qUtf8Printable(QDir::toNativeSeparators(fileName))); + log::debug("{} saved", QDir::toNativeSeparators(fileName)); } } catch (const std::exception &e) { reportError(tr("failed to write mod list: %1").arg(e.what())); @@ -292,7 +290,7 @@ void Profile::createTweakedIniFile() .arg(formatSystemMessageQ(e))); } - qDebug("%s saved", qUtf8Printable(QDir::toNativeSeparators(tweakedIni))); + log::debug("{} saved", QDir::toNativeSeparators(tweakedIni)); } // static @@ -364,8 +362,9 @@ void Profile::renameModInList(QFile &modList, const QString &oldName, const QStr } if (renamed) - qDebug("Renamed %d \"%s\" mod to \"%s\" in %s", - renamed, qUtf8Printable(oldName), qUtf8Printable(newName), qUtf8Printable(modList.fileName())); + log::debug( + "Renamed {} \"{}\" mod to \"{}\" in {}", + renamed, oldName, newName, modList.fileName()); } void Profile::refreshModStatus() @@ -431,8 +430,9 @@ void Profile::refreshModStatus() modStatusModified = true; } } else { - qDebug("mod not found: \"%s\" (profile \"%s\")", - qUtf8Printable(modName), qUtf8Printable(m_Directory.path())); + log::debug( + "mod not found: \"{}\" (profile \"{}\")", + modName, m_Directory.path()); // need to rewrite the modlist to fix this modStatusModified = true; } diff --git a/src/qtgroupingproxy.cpp b/src/qtgroupingproxy.cpp index 5fcb84d3..ff9539d7 100644 --- a/src/qtgroupingproxy.cpp +++ b/src/qtgroupingproxy.cpp @@ -18,11 +18,14 @@ #include "qtgroupingproxy.h" +#include #include #include #include +using namespace MOBase; + /*! \class QtGroupingProxy \brief The QtGroupingProxy class will group source model rows by adding a new top tree-level. @@ -86,7 +89,6 @@ QtGroupingProxy::setGroupedColumn( int groupedColumn ) QList QtGroupingProxy::belongsTo( const QModelIndex &idx ) { - //qDebug() << __FILE__ << __FUNCTION__; QList rowDataList; //get all the data for this index from the model @@ -106,7 +108,7 @@ QtGroupingProxy::belongsTo( const QModelIndex &idx ) i.next(); int role = i.key(); QVariant variant = i.value(); - // qDebug() << "role " << role << " : (" << variant.typeName() << ") : "<< variant; + if ( variant.type() == QVariant::List ) { //a list of variants get's expanded to multiple rows @@ -162,7 +164,7 @@ QtGroupingProxy::buildTree() m_parentCreateList.clear(); int max = sourceModel()->rowCount( m_rootNode ); - //qDebug() << QString("building tree with %1 leafs.").arg( max ); + //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++ ) @@ -232,9 +234,6 @@ QtGroupingProxy::addSourceRow( const QModelIndex &idx ) int updatedGroup = -1; if( !data.isEmpty() ) { - // qDebug() << QString("index %1 belongs to group %2").arg( row ) - // .arg( data[0][Qt::DisplayRole].toString() ); - foreach( const RowData &cachedData, m_groupMaps ) { //when this matches the index belongs to an existing group @@ -316,21 +315,12 @@ QtGroupingProxy::indexOfParentCreate( const QModelIndex &parent ) const pc.row = parent.row(); m_parentCreateList << pc; - //dumpParentCreateList(); - // qDebug() << QString( "m_parentCreateList: (%1)" ).arg( m_parentCreateList.size() ); - // for( int i = 0 ; i < m_parentCreateList.size() ; i++ ) - // { - // qDebug() << i << " : " << m_parentCreateList[i].parentCreateIndex << - // " | " << m_parentCreateList[i].row; - // } - return m_parentCreateList.size() - 1; } QModelIndex QtGroupingProxy::index( int row, int column, const QModelIndex &parent ) const { - // qDebug() << "index requested for: (" << row << "," << column << "), " << parent; if( !hasIndex(row, column, parent) ) { return QModelIndex(); } @@ -350,17 +340,15 @@ QtGroupingProxy::index( int row, int column, const QModelIndex &parent ) const QModelIndex QtGroupingProxy::parent( const QModelIndex &index ) const { - //qDebug() << "parent: " << index; if( !index.isValid() ) return QModelIndex(); int parentCreateIndex = index.internalId(); - //qDebug() << "parentCreateIndex: " << parentCreateIndex; if( parentCreateIndex == -1 || parentCreateIndex >= m_parentCreateList.count() ) return QModelIndex(); struct ParentCreate pc = m_parentCreateList[parentCreateIndex]; - //qDebug() << "parentCreate: (" << pc.parentCreateIndex << "," << pc.row << ")"; + //only items at column 0 have children return createIndex( pc.row, 0, pc.parentCreateIndex ); } @@ -368,12 +356,10 @@ QtGroupingProxy::parent( const QModelIndex &index ) const int QtGroupingProxy::rowCount( const QModelIndex &index ) const { - //qDebug() << "rowCount: " << index; if( !index.isValid() ) { //the number of top level groups + the number of non-grouped items int rows = m_groupMaps.count() + m_groupHash.value( std::numeric_limits::max() ).count(); - //qDebug() << rows << " in root group"; return rows; } @@ -382,12 +368,10 @@ QtGroupingProxy::rowCount( const QModelIndex &index ) const { qint64 groupIndex = index.row(); int rows = m_groupHash.value( groupIndex ).count(); - //qDebug() << rows << " in group " << m_groupMaps[groupIndex]; return rows; } else { QModelIndex originalIndex = mapToSource( index ); int rowCount = sourceModel()->rowCount( originalIndex ); - //qDebug() << "original item: rowCount == " << rowCount; return rowCount; } } @@ -447,7 +431,7 @@ QtGroupingProxy::data( const QModelIndex &index, int role ) const { if( !index.isValid() ) return QVariant(); - // qDebug() << __FUNCTION__ << index << " role: " << role; + int row = index.row(); int column = index.column(); if( isGroup( index ) ) @@ -495,11 +479,9 @@ QtGroupingProxy::data( const QModelIndex &index, int role ) const } } - //qDebug() << __FUNCTION__ << "is a group"; //use cached or precalculated data if( m_groupMaps[row][column].contains( Qt::DisplayRole ) ) { - // qDebug() << "Using cached data for " << row << "x" << column << ": " << m_groupMaps[row][column].value(Qt::DisplayRole).toString(); if ((m_flags & FLAG_NOGROUPNAME) != 0) { QModelIndex parentIndex = this->index( row, 0, index.parent() ); QModelIndex childIndex = this->index( 0, column, parentIndex ); @@ -526,18 +508,17 @@ QtGroupingProxy::data( const QModelIndex &index, int role ) const function = mapToSource(childIndex).data(m_aggregateRole).toInt(); } - //qDebug() << __FUNCTION__ << "childCount: " << childCount; //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 ); - //qDebug() << __FUNCTION__ << data << QVariant::typeToName(data.type()); + if( data.isValid() && !variantsOfChildren.contains( data ) ) variantsOfChildren << data; } - //qDebug() << "gathered this data from children: " << variantsOfChildren; + //saving in cache ItemData roleMap = m_groupMaps[row].value( column ); foreach( const QVariant &variant, variantsOfChildren ) @@ -547,8 +528,6 @@ QtGroupingProxy::data( const QModelIndex &index, int role ) const } } - //qDebug() << QString("roleMap[%1]:").arg(role) << roleMap[role]; - if( variantsOfChildren.count() == 0 ) return QVariant(); @@ -621,34 +600,30 @@ QtGroupingProxy::isGroup( const QModelIndex &index ) const QModelIndex QtGroupingProxy::mapToSource( const QModelIndex &index ) const { - //qDebug() << "mapToSource: " << index; if( !index.isValid() ) { return m_rootNode; } if( isGroup( index ) ) { - //qDebug() << "is a group: " << index.data( Qt::DisplayRole ).toString(); return m_rootNode; } QModelIndex proxyParent = index.parent(); - //qDebug() << "parent: " << proxyParent; QModelIndex originalParent = mapToSource( proxyParent ); - //qDebug() << "originalParent: " << originalParent; + int originalRow = index.row(); if( originalParent == m_rootNode ) { int indexInGroup = index.row(); if( !proxyParent.isValid() ) indexInGroup -= m_groupMaps.count(); - //qDebug() << "indexInGroup" << indexInGroup; + QList childRows = m_groupHash.value( proxyParent.row() ); if( childRows.isEmpty() || indexInGroup >= childRows.count() || indexInGroup < 0 ) return QModelIndex(); originalRow = childRows.at( indexInGroup ); - //qDebug() << "originalRow: " << originalRow; } return sourceModel()->index( originalRow, index.column(), originalParent ); } @@ -674,7 +649,7 @@ QtGroupingProxy::mapFromSource( const QModelIndex &idx ) const QModelIndex proxyParent; QModelIndex sourceParent = idx.parent(); - //qDebug() << "sourceParent: " << sourceParent; + int proxyRow = idx.row(); int sourceRow = idx.row(); @@ -708,15 +683,12 @@ QtGroupingProxy::mapFromSource( const QModelIndex &idx ) const proxyParent = QModelIndex(); // if the proxy item is not in a group it will be below the groups. int groupLength = m_groupMaps.count(); - //qDebug() << "groupNames length: " << groupLength; int i = m_groupHash.value( std::numeric_limits::max() ).indexOf( sourceRow ); - //qDebug() << "index in hash: " << i; + proxyRow = groupLength + i; } } - //qDebug() << "proxyParent: " << proxyParent; - //qDebug() << "proxyRow: " << proxyRow; return this->index( proxyRow, idx.column(), proxyParent ); } @@ -731,9 +703,9 @@ QtGroupingProxy::flags( const QModelIndex &idx ) const return 0; } + //only if the grouped column has the editable flag set allow the //actions leading to setData on the source (edit & drop) - // qDebug() << idx; if( isGroup( idx ) ) { // dumpGroups(); @@ -749,7 +721,7 @@ QtGroupingProxy::flags( const QModelIndex &idx ) const m_rootNode.parent() ); if ( (originalIdx.flags() & Qt::ItemIsUserCheckable) == 0 ) { - qDebug("row %d is not checkable", originalRow); + log::debug("row {} is not checkable", originalRow); checkable = false; } } @@ -892,9 +864,7 @@ QtGroupingProxy::modelRowsAboutToBeInserted( const QModelIndex &parent, int star if( parent != m_rootNode ) { //an item will be added to an original index, remap and pass it on - // qDebug() << parent; QModelIndex proxyParent = mapFromSource( parent ); - // qDebug() << proxyParent; beginInsertRows( proxyParent, start, end ); } } @@ -914,7 +884,12 @@ QtGroupingProxy::modelRowsInserted( const QModelIndex &parent, int start, int en { //an item was added to an original index, remap and pass it on QModelIndex proxyParent = mapFromSource( parent ); - qDebug() << proxyParent; + + QString s; + QDebug debug(&s); + debug << proxyParent; + log::debug("{}", s); + //beginInsertRows had to be called in modelRowsAboutToBeInserted() endInsertRows(); } @@ -951,9 +926,7 @@ QtGroupingProxy::modelRowsAboutToBeRemoved( const QModelIndex &parent, int start else { //child item(s) of an original item will be removed, remap and pass it on - // qDebug() << parent; QModelIndex proxyParent = mapFromSource( parent ); - // qDebug() << proxyParent; beginRemoveRows( proxyParent, start, end ); } } @@ -1044,16 +1017,24 @@ QtGroupingProxy::isAGroupSelected( const QModelIndexList& list ) const void QtGroupingProxy::dumpGroups() const { - qDebug() << "m_groupHash: "; + QString s; + QDebug debug(&s); + + debug << "m_groupHash:\n"; for( int groupIndex = -1; groupIndex < m_groupHash.keys().count() - 1; groupIndex++ ) { - qDebug() << groupIndex << " : " << m_groupHash.value( groupIndex ); + debug << groupIndex << " : " << m_groupHash.value( groupIndex ) << "\n"; } - qDebug() << "m_groupMaps: "; + debug << "m_groupMaps:\n"; for( int groupIndex = 0; groupIndex < m_groupMaps.count(); groupIndex++ ) - qDebug() << m_groupMaps[groupIndex] << ": " << m_groupHash.value( groupIndex ); - qDebug() << m_groupHash.value( std::numeric_limits::max() ); + { + debug << m_groupMaps[groupIndex] << ": " << m_groupHash.value( groupIndex ) << "\n"; + } + + debug << m_groupHash.value( std::numeric_limits::max() ); + + log::debug("{}", s); } diff --git a/src/selfupdater.cpp b/src/selfupdater.cpp index e967b27c..0ca39b19 100644 --- a/src/selfupdater.cpp +++ b/src/selfupdater.cpp @@ -150,23 +150,23 @@ void SelfUpdater::testForUpdate() VersionInfo newestVer(newest["tag_name"].toString()); if (newestVer > this->m_MOVersion) { m_UpdateCandidate = newest; - qDebug("update available: %s -> %s", - qUtf8Printable(this->m_MOVersion.displayString(3)), - qUtf8Printable(newestVer.displayString(3))); + log::debug("update available: {} -> {}", + this->m_MOVersion.displayString(3), + newestVer.displayString(3)); emit updateAvailable(); } else if (newestVer < this->m_MOVersion) { // this could happen if the user switches from using prereleases to // stable builds. Should we downgrade? - qDebug("This version is newer than the latest released one: %s -> %s", - qUtf8Printable(this->m_MOVersion.displayString(3)), - qUtf8Printable(newestVer.displayString(3))); + log::debug("This version is newer than the latest released one: {} -> {}", + this->m_MOVersion.displayString(3), + newestVer.displayString(3)); } } }); } //Catch all is bad by design, should be improved catch (...) { - qDebug("Unable to connect to github.com to check version"); + log::debug("Unable to connect to github.com to check version"); } } @@ -230,7 +230,7 @@ void SelfUpdater::closeProgress() void SelfUpdater::openOutputFile(const QString &fileName) { QString outputPath = QDir::fromNativeSeparators(qApp->property("dataPath").toString()) + "/" + fileName; - qDebug("downloading to %s", qUtf8Printable(outputPath)); + log::debug("downloading to {}", outputPath); m_UpdateFile.setFileName(outputPath); m_UpdateFile.open(QIODevice::WriteOnly); } @@ -312,7 +312,7 @@ void SelfUpdater::downloadFinished() return; } - qDebug("download: %s", m_UpdateFile.fileName().toUtf8().constData()); + log::debug("download: {}", m_UpdateFile.fileName()); try { installUpdate(); diff --git a/src/settings.cpp b/src/settings.cpp index 9c303442..ff5b9976 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -54,7 +54,6 @@ along with Mod Organizer. If not, see . #include #include // for Qt::UserRole, etc -#include // for qDebug, qWarning #include // For ShellExecuteW, HINSTANCE, etc #include // For storage @@ -635,7 +634,7 @@ void Settings::updateServers(const QList &servers) QVariantMap val = m_Settings.value(key).toMap(); QDate lastSeen = val["lastSeen"].toDate(); if (lastSeen.daysTo(now) > 30) { - qDebug("removing server %s since it hasn't been available for downloads in over a month", qUtf8Printable(key)); + log::debug("removing server {} since it hasn't been available for downloads in over a month", key); m_Settings.remove(key); } } @@ -758,10 +757,10 @@ void Settings::query(PluginContainer *pluginContainer, QWidget *parent) if (m_Settings.value(k).toString() != before[k] && !k.contains("username") && !k.contains("password")) { if (first_update) { - qDebug("Changed settings:"); + log::debug("Changed settings:"); first_update = false; } - qDebug(" %s=%s", k.toUtf8().data(), m_Settings.value(k).toString().toUtf8().data()); + log::debug(" {}={}", k, m_Settings.value(k).toString()); } m_Settings.endGroup(); } diff --git a/src/usvfsconnector.cpp b/src/usvfsconnector.cpp index 197955b8..5918c8a5 100644 --- a/src/usvfsconnector.cpp +++ b/src/usvfsconnector.cpp @@ -60,8 +60,7 @@ LogWorker::LogWorker() "yyyy-MM-dd_hh-mm-ss"))) { m_LogFile.open(QIODevice::WriteOnly); - qDebug("usvfs log messages are written to %s", - qUtf8Printable(m_LogFile.fileName())); + log::debug("usvfs log messages are written to {}", m_LogFile.fileName()); } LogWorker::~LogWorker() @@ -129,7 +128,10 @@ UsvfsConnector::UsvfsConnector() USVFSInitParameters(¶ms, SHMID, false, level, dumpType, dumpPath.c_str()); InitLogging(false); - qDebug("Initializing VFS <%s, %d, %d, %s>", params.instanceName, params.logLevel, params.crashDumpsType, params.crashDumpsPath); + log::debug( + "Initializing VFS <{}, {}, {}, {}>", + params.instanceName, static_cast(params.logLevel), + static_cast(params.crashDumpsType), params.crashDumpsPath); CreateVFS(¶ms); @@ -168,7 +170,7 @@ void UsvfsConnector::updateMapping(const MappingType &mapping) int files = 0; int dirs = 0; - qDebug("Updating VFS mappings..."); + log::debug("Updating VFS mappings..."); ClearVirtualMappings(); @@ -196,14 +198,7 @@ void UsvfsConnector::updateMapping(const MappingType &mapping) } } - qDebug("VFS mappings updated ", dirs, files); - /* - size_t dumpSize = 0; - CreateVFSDump(nullptr, &dumpSize); - std::unique_ptr buffer(new char[dumpSize]); - CreateVFSDump(buffer.get(), &dumpSize); - qDebug(buffer.get()); - */ + log::debug("VFS mappings updated ", dirs, files); } void UsvfsConnector::updateParams( -- cgit v1.3.1 From 4f1b15f0a1b2e6cbca4b420608d81570af489067 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sat, 24 Aug 2019 16:07:07 -0400 Subject: changed crash dump type to use enum instead of int added ColorSettings settings dialog general and diag tabs don't use qsettings anymore removed logging of setting changes, will be added back to Settings class --- src/modinfo.cpp | 1 - src/modlist.cpp | 10 +-- src/organizercore.cpp | 6 +- src/organizercore.h | 4 +- src/pluginlist.cpp | 2 +- src/settings.cpp | 160 ++++++++++++++++++++++++++++++-------- src/settings.h | 70 ++++++++++------- src/settingsdialog.cpp | 26 +------ src/settingsdialog.ui | 20 ----- src/settingsdialogdiagnostics.cpp | 38 ++++++++- src/settingsdialogdiagnostics.h | 1 + src/settingsdialoggeneral.cpp | 66 ++++++++-------- src/usvfsconnector.cpp | 7 +- src/usvfsconnector.h | 2 +- 14 files changed, 259 insertions(+), 154 deletions(-) (limited to 'src/modlist.cpp') diff --git a/src/modinfo.cpp b/src/modinfo.cpp index 5a05e7ca..e3daa4fd 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -42,7 +42,6 @@ along with Mod Organizer. If not, see . #include #include #include -#include using namespace MOBase; using namespace MOShared; diff --git a/src/modlist.cpp b/src/modlist.cpp index c591c49b..94b4a387 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -416,15 +416,15 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const bool archiveOverwritten = m_ArchiveOverwritten.find(modIndex) != m_ArchiveOverwritten.end(); bool archiveLooseOverwritten = m_ArchiveLooseOverwritten.find(modIndex) != m_ArchiveLooseOverwritten.end(); if (modInfo->getHighlight() & ModInfo::HIGHLIGHT_PLUGIN) { - return Settings::instance().modlistContainsPluginColor(); + return Settings::instance().colors().modlistContainsPlugin(); } else if (overwritten || archiveLooseOverwritten) { - return Settings::instance().modlistOverwritingLooseColor(); + return Settings::instance().colors().modlistOverwritingLoose(); } else if (overwrite || archiveLooseOverwrite) { - return Settings::instance().modlistOverwrittenLooseColor(); + return Settings::instance().colors().modlistOverwrittenLoose(); } else if (archiveOverwritten) { - return Settings::instance().modlistOverwritingArchiveColor(); + return Settings::instance().colors().modlistOverwritingArchive(); } else if (archiveOverwrite) { - return Settings::instance().modlistOverwrittenArchiveColor(); + return Settings::instance().colors().modlistOverwrittenArchive(); } else if (modInfo->hasFlag(ModInfo::FLAG_SEPARATOR) && modInfo->getColor().isValid() && ((role != ViewMarkingScrollBar::DEFAULT_ROLE) diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 73d0abac..5a8ee4c2 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -667,7 +667,7 @@ void OrganizerCore::prepareVFS() } void OrganizerCore::updateVFSParams( - log::Levels logLevel, int crashDumpsType, QString executableBlacklist) + log::Levels logLevel, CrashDumpsType crashDumpsType, QString executableBlacklist) { setGlobalCrashDumpsType(crashDumpsType); m_USVFS.updateParams(logLevel, crashDumpsType, executableBlacklist); @@ -692,8 +692,8 @@ bool OrganizerCore::cycleDiagnostics() { } //static -void OrganizerCore::setGlobalCrashDumpsType(int crashDumpsType) { - m_globalCrashDumpsType = ::crashDumpsType(crashDumpsType); +void OrganizerCore::setGlobalCrashDumpsType(CrashDumpsType type) { + m_globalCrashDumpsType = type; } //static diff --git a/src/organizercore.h b/src/organizercore.h index 4bcfe745..a14d79a9 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -193,7 +193,7 @@ public: void prepareVFS(); void updateVFSParams( - MOBase::log::Levels logLevel, int crashDumpsType, + MOBase::log::Levels logLevel, CrashDumpsType crashDumpsType, QString executableBlacklist); void setLogLevel(MOBase::log::Levels level); @@ -201,7 +201,7 @@ public: bool cycleDiagnostics(); static CrashDumpsType getGlobalCrashDumpsType() { return m_globalCrashDumpsType; } - static void setGlobalCrashDumpsType(int crashDumpsType); + static void setGlobalCrashDumpsType(CrashDumpsType crashDumpsType); static std::wstring crashDumpsPath(); public: diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index 8637f546..ddfe492e 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -931,7 +931,7 @@ QVariant PluginList::data(const QModelIndex &modelIndex, int role) const } else if (role == Qt::BackgroundRole || (role == ViewMarkingScrollBar::DEFAULT_ROLE)) { if (m_ESPs[index].m_ModSelected) { - return Settings::instance().pluginListContainedColor(); + return Settings::instance().colors().pluginListContained(); } else { return QVariant(); } diff --git a/src/settings.cpp b/src/settings.cpp index 844ee81e..2236fc9d 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -24,7 +24,6 @@ along with Mod Organizer. If not, see . #include "expanderwidget.h" #include #include -#include using namespace MOBase; @@ -33,7 +32,13 @@ std::optional getOptional( const QSettings& s, const QString& name, std::optional def={}) { if (s.contains(name)) { - return s.value(name).value(); + const auto v = s.value(name); + + if constexpr (std::is_enum_v) { + return static_cast(v.value>()); + } else { + return v.value(); + } } return def; @@ -160,10 +165,12 @@ void warnIfNotCheckable(const QAbstractButton* b) } } + Settings *Settings::s_Instance = nullptr; -Settings::Settings(const QString& path) - : m_Settings(path, QSettings::IniFormat), m_Geometry(m_Settings) +Settings::Settings(const QString& path) : + m_Settings(path, QSettings::IniFormat), + m_Geometry(m_Settings), m_Colors(m_Settings) { if (s_Instance != nullptr) { throw std::runtime_error("second instance of \"Settings\" created"); @@ -280,6 +287,11 @@ bool Settings::colorSeparatorScrollbar() const return m_Settings.value("Settings/colorSeparatorScrollbars", true).toBool(); } +void Settings::setColorSeparatorScrollbar(bool b) +{ + m_Settings.setValue("Settings/colorSeparatorScrollbars", b); +} + void Settings::managedGameChanged(IPluginGame const *gamePlugin) { m_GamePlugin = gamePlugin; @@ -397,6 +409,11 @@ bool Settings::usePrereleases() const return m_Settings.value("Settings/use_prereleases", false).toBool(); } +void Settings::setUsePrereleases(bool b) +{ + m_Settings.setValue("Settings/use_prereleases", b); +} + void Settings::setDownloadSpeed(const QString &serverName, int bytesPerSecond) { m_Settings.beginGroup("Servers"); @@ -615,16 +632,27 @@ bool Settings::getSteamLogin(QString &username, QString &password) const return !username.isEmpty() && !password.isEmpty(); } + bool Settings::compactDownloads() const { return m_Settings.value("Settings/compact_downloads", false).toBool(); } +void Settings::setCompactDownloads(bool b) +{ + m_Settings.setValue("Settings/compact_downloads", b); +} + bool Settings::metaDownloads() const { return m_Settings.value("Settings/meta_downloads", false).toBool(); } +void Settings::setMetaDownloads(bool b) +{ + m_Settings.setValue("Settings/meta_downloads", b); +} + bool Settings::offlineMode() const { return m_Settings.value("Settings/offline_mode", false).toBool(); @@ -640,44 +668,25 @@ void Settings::setLogLevel(log::Levels level) m_Settings.setValue("Settings/log_level", static_cast(level)); } -int Settings::crashDumpsType() const +CrashDumpsType Settings::crashDumpsType() const { - return m_Settings.value("Settings/crash_dumps_type", static_cast(CrashDumpsType::Mini)).toInt(); + const auto v = getOptional(m_Settings, "Settings/crash_dumps_type"); + return v.value_or(CrashDumpsType::Mini); } -int Settings::crashDumpsMax() const +void Settings::setCrashDumpsType(CrashDumpsType type) { - return m_Settings.value("Settings/crash_dumps_max", 5).toInt(); + m_Settings.setValue("Settings/crash_dumps_type", static_cast(type)); } -QColor Settings::modlistOverwrittenLooseColor() const -{ - return m_Settings.value("Settings/overwrittenLooseFilesColor", QColor(0, 255, 0, 64)).value(); -} - -QColor Settings::modlistOverwritingLooseColor() const -{ - return m_Settings.value("Settings/overwritingLooseFilesColor", QColor(255, 0, 0, 64)).value(); -} - -QColor Settings::modlistOverwrittenArchiveColor() const -{ - return m_Settings.value("Settings/overwrittenArchiveFilesColor", QColor(0, 255, 255, 64)).value(); -} - -QColor Settings::modlistOverwritingArchiveColor() const -{ - return m_Settings.value("Settings/overwritingArchiveFilesColor", QColor(255, 0, 255, 64)).value(); -} - -QColor Settings::modlistContainsPluginColor() const +int Settings::crashDumpsMax() const { - return m_Settings.value("Settings/containsPluginColor", QColor(0, 0, 255, 64)).value(); + return m_Settings.value("Settings/crash_dumps_max", 5).toInt(); } -QColor Settings::pluginListContainedColor() const +void Settings::setCrashDumpsMax(int n) { - return m_Settings.value("Settings/containedColor", QColor(0, 0, 255, 64)).value(); + return m_Settings.setValue("Settings/crash_dumps_max", n); } QString Settings::executablesBlacklist() const @@ -850,6 +859,11 @@ QString Settings::language() return result; } +void Settings::setLanguage(const QString& name) +{ + m_Settings.setValue("Settings/language", name); +} + void Settings::updateServers(const QList &servers) { m_Settings.beginGroup("Servers"); @@ -1132,6 +1146,16 @@ const GeometrySettings& Settings::geometry() const return m_Geometry; } +ColorSettings& Settings::colors() +{ + return m_Colors; +} + +const ColorSettings& Settings::colors() const +{ + return m_Colors; +} + QSettings::Status Settings::sync() const { m_Settings.sync(); @@ -1451,6 +1475,78 @@ void GeometrySettings::restoreDocks(QMainWindow* mw) const } +ColorSettings::ColorSettings(QSettings& s) + : m_Settings(s) +{ +} + +QColor ColorSettings::modlistOverwrittenLoose() const +{ + return getOptional(m_Settings, "Settings/overwrittenLooseFilesColor") + .value_or(QColor(0, 255, 0, 64)); +} + +void ColorSettings::setModlistOverwrittenLoose(const QColor& c) +{ + m_Settings.setValue("Settings/overwrittenLooseFilesColor", c); +} + +QColor ColorSettings::modlistOverwritingLoose() const +{ + return getOptional(m_Settings, "Settings/overwritingLooseFilesColor") + .value_or(QColor(255, 0, 0, 64)); +} + +void ColorSettings::setModlistOverwritingLoose(const QColor& c) +{ + m_Settings.setValue("Settings/overwritingLooseFilesColor", c); +} + +QColor ColorSettings::modlistOverwrittenArchive() const +{ + return getOptional(m_Settings, "Settings/overwrittenArchiveFilesColor") + .value_or(QColor(0, 255, 255, 64)); +} + +void ColorSettings::setModlistOverwrittenArchive(const QColor& c) +{ + m_Settings.setValue("Settings/overwrittenArchiveFilesColor", c); +} + +QColor ColorSettings::modlistOverwritingArchive() const +{ + return getOptional(m_Settings, "Settings/overwritingArchiveFilesColor") + .value_or(QColor(255, 0, 255, 64)); +} + +void ColorSettings::setModlistOverwritingArchive(const QColor& c) +{ + m_Settings.setValue("Settings/overwritingArchiveFilesColor", c); +} + +QColor ColorSettings::modlistContainsPlugin() const +{ + return getOptional(m_Settings, "Settings/containsPluginColor") + .value_or(QColor(0, 0, 255, 64)); +} + +void ColorSettings::setModlistContainsPlugin(const QColor& c) +{ + m_Settings.setValue("Settings/containsPluginColor", c); +} + +QColor ColorSettings::pluginListContained() const +{ + return getOptional(m_Settings, "Settings/containedColor") + .value_or(QColor(0, 0, 255, 64)); +} + +void ColorSettings::setPluginListContained(const QColor& c) +{ + m_Settings.setValue("Settings/containedColor", c); +} + + GeometrySaver::GeometrySaver(Settings& s, QDialog* dialog) : m_settings(s), m_dialog(dialog) { diff --git a/src/settings.h b/src/settings.h index b25af15f..5b1d7bfc 100644 --- a/src/settings.h +++ b/src/settings.h @@ -23,6 +23,7 @@ along with Mod Organizer. If not, see . #include "loadmechanism.h" #include #include +#include namespace MOBase { class IPlugin; @@ -96,6 +97,36 @@ private: }; +class ColorSettings +{ +public: + ColorSettings(QSettings& s); + + void setCrashDumpsMax(int i) const; + + QColor modlistOverwrittenLoose() const; + void setModlistOverwrittenLoose(const QColor& c); + + QColor modlistOverwritingLoose() const; + void setModlistOverwritingLoose(const QColor& c); + + QColor modlistOverwrittenArchive() const; + void setModlistOverwrittenArchive(const QColor& c); + + QColor modlistOverwritingArchive() const; + void setModlistOverwritingArchive(const QColor& c); + + QColor modlistContainsPlugin() const; + void setModlistContainsPlugin(const QColor& c); + + QColor pluginListContained() const; + void setPluginListContained(const QColor& c) ; + +private: + QSettings& m_Settings; +}; + + enum class EndorsementState { Accepted = 1, @@ -268,6 +299,10 @@ public: GeometrySettings& geometry(); const GeometrySettings& geometry() const; + ColorSettings& colors(); + const ColorSettings& colors() const; + + /** * retrieve the directory where profiles stored (with native separators) **/ @@ -329,43 +364,22 @@ public: * @return true if the user chose compact downloads */ bool compactDownloads() const; + void setCompactDownloads(bool b); /** * @return true if the user chose meta downloads */ bool metaDownloads() const; + void setMetaDownloads(bool b); - /** - * @return the configured log level - */ MOBase::log::Levels logLevel() const; - - /** - * sets the log level setting - */ void setLogLevel(MOBase::log::Levels level); - /** - * @return the configured crash dumps type - */ - int crashDumpsType() const; + CrashDumpsType crashDumpsType() const; + void setCrashDumpsType(CrashDumpsType type); - /** - * @return the configured crash dumps max - */ int crashDumpsMax() const; - - QColor modlistOverwrittenLooseColor() const; - - QColor modlistOverwritingLooseColor() const; - - QColor modlistOverwrittenArchiveColor() const; - - QColor modlistOverwritingArchiveColor() const; - - QColor modlistContainsPluginColor() const; - - QColor pluginListContainedColor() const; + void setCrashDumpsMax(int n); QString executablesBlacklist() const; @@ -473,6 +487,7 @@ public: * @return short code of the configured language (corresponding to the translation files) */ QString language(); + void setLanguage(const QString& name); /** * @brief updates the list of known servers @@ -499,6 +514,7 @@ public: std::vector plugins() const { return m_Plugins; } bool usePrereleases() const; + void setUsePrereleases(bool b); /** * @brief register MO as the handler for nxm links @@ -512,6 +528,7 @@ public: * @return the state of the setting */ bool colorSeparatorScrollbar() const; + void setColorSeparatorScrollbar(bool b); static QColor getIdealTextColor(const QColor& rBackgroundColor); @@ -540,6 +557,7 @@ private: MOBase::IPluginGame const *m_GamePlugin; mutable QSettings m_Settings; GeometrySettings m_Geometry; + ColorSettings m_Colors; LoadMechanism m_LoadMechanism; std::vector m_Plugins; diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index 097dafc8..9d031785 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -51,43 +51,19 @@ int SettingsDialog::exec() { GeometrySaver gs(m_settings, this); - auto& qsettings = m_settings.directInterface(); auto ret = TutorableDialog::exec(); if (ret == QDialog::Accepted) { - for (auto&& tab : m_tabs) { tab->closing(); } - // remember settings before change - QMap before; - qsettings.beginGroup("Settings"); - for (auto k : qsettings.allKeys()) - before[k] = qsettings.value(k).toString(); - qsettings.endGroup(); - - // transfer modified settings to configuration file + // update settings for each tab for (std::unique_ptr const &tab: m_tabs) { tab->update(); } - - // print "changed" settings - qsettings.beginGroup("Settings"); - bool first_update = true; - for (auto k : qsettings.allKeys()) - if (qsettings.value(k).toString() != before[k] && !k.contains("username") && !k.contains("password")) - { - if (first_update) { - log::debug("Changed settings:"); - first_update = false; - } - log::debug(" {}={}", k, qsettings.value(k).toString()); - } - qsettings.endGroup(); } - // These changes happen regardless of accepted or rejected bool restartNeeded = false; if (getApiKeyChanged()) { restartNeeded = true; diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index e7676387..af230bc0 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -1346,26 +1346,6 @@ programs you are intentionally running. "Full" Even larger dumps with a full memory dump of the process. - - - None - - - - - Mini (recommended) - - - - - Data - - - - - Full - - diff --git a/src/settingsdialogdiagnostics.cpp b/src/settingsdialogdiagnostics.cpp index 227d1dfa..278da0bf 100644 --- a/src/settingsdialogdiagnostics.cpp +++ b/src/settingsdialogdiagnostics.cpp @@ -10,10 +10,13 @@ DiagnosticsSettingsTab::DiagnosticsSettingsTab(Settings& s, SettingsDialog& d) : SettingsTab(s, d) { setLevelsBox(); - ui->dumpsTypeBox->setCurrentIndex(settings().crashDumpsType()); + setCrashDumpTypesBox(); + ui->dumpsMaxEdit->setValue(settings().crashDumpsMax()); + QString logsPath = qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath()); + ui->diagnosticsExplainedLabel->setText( ui->diagnosticsExplainedLabel->text() .replace("LOGS_FULL_PATH", logsPath) @@ -40,9 +43,36 @@ void DiagnosticsSettingsTab::setLevelsBox() } } +void DiagnosticsSettingsTab::setCrashDumpTypesBox() +{ + ui->dumpsTypeBox->clear(); + + auto add = [&](auto&& text, auto&& type) { + ui->dumpsTypeBox->addItem(text, static_cast(type)); + }; + + add(QObject::tr("None"), CrashDumpsType::None); + add(QObject::tr("Mini (recommended)"), CrashDumpsType::Mini); + add(QObject::tr("Data"), CrashDumpsType::Data); + add(QObject::tr("Full"), CrashDumpsType::Full); + + const auto current = static_cast(settings().crashDumpsType()); + + for (int i=0; idumpsTypeBox->count(); ++i) { + if (ui->dumpsTypeBox->itemData(i) == current) { + ui->dumpsTypeBox->setCurrentIndex(i); + break; + } + } +} + void DiagnosticsSettingsTab::update() { - qsettings().setValue("Settings/log_level", ui->logLevelBox->currentData().toInt()); - qsettings().setValue("Settings/crash_dumps_type", ui->dumpsTypeBox->currentIndex()); - qsettings().setValue("Settings/crash_dumps_max", ui->dumpsMaxEdit->value()); + settings().setLogLevel( + static_cast(ui->logLevelBox->currentData().toInt())); + + settings().setCrashDumpsType( + static_cast(ui->dumpsTypeBox->currentData().toInt())); + + settings().setCrashDumpsMax(ui->dumpsMaxEdit->value()); } diff --git a/src/settingsdialogdiagnostics.h b/src/settingsdialogdiagnostics.h index f20413f8..f0fbf770 100644 --- a/src/settingsdialogdiagnostics.h +++ b/src/settingsdialogdiagnostics.h @@ -13,6 +13,7 @@ public: private: void setLevelsBox(); + void setCrashDumpTypesBox(); }; #endif // SETTINGSDIALOGDIAGNOSTICS_H diff --git a/src/settingsdialoggeneral.cpp b/src/settingsdialoggeneral.cpp index 35012db7..e3d73037 100644 --- a/src/settingsdialoggeneral.cpp +++ b/src/settingsdialoggeneral.cpp @@ -26,28 +26,30 @@ GeneralSettingsTab::GeneralSettingsTab(Settings& s, SettingsDialog& d) } addStyles(); + { - int currentID = ui->styleBox->findData( - qsettings().value("Settings/style", "").toString()); + const int currentID = ui->styleBox->findData( + settings().getStyleName().value_or("")); + if (currentID != -1) { ui->styleBox->setCurrentIndex(currentID); } } //version with stylesheet - setButtonColor(ui->overwritingBtn, settings().modlistOverwritingLooseColor()); - setButtonColor(ui->overwrittenBtn, settings().modlistOverwrittenLooseColor()); - setButtonColor(ui->overwritingArchiveBtn, settings().modlistOverwritingArchiveColor()); - setButtonColor(ui->overwrittenArchiveBtn, settings().modlistOverwrittenArchiveColor()); - setButtonColor(ui->containsBtn, settings().modlistContainsPluginColor()); - setButtonColor(ui->containedBtn, settings().pluginListContainedColor()); - - setOverwritingColor(settings().modlistOverwritingLooseColor()); - setOverwrittenColor(settings().modlistOverwrittenLooseColor()); - setOverwritingArchiveColor(settings().modlistOverwritingArchiveColor()); - setOverwrittenArchiveColor(settings().modlistOverwrittenArchiveColor()); - setContainsColor(settings().modlistContainsPluginColor()); - setContainedColor(settings().pluginListContainedColor()); + setButtonColor(ui->overwritingBtn, settings().colors().modlistOverwritingLoose()); + setButtonColor(ui->overwrittenBtn, settings().colors().modlistOverwrittenLoose()); + setButtonColor(ui->overwritingArchiveBtn, settings().colors().modlistOverwritingArchive()); + setButtonColor(ui->overwrittenArchiveBtn, settings().colors().modlistOverwrittenArchive()); + setButtonColor(ui->containsBtn, settings().colors().modlistContainsPlugin()); + setButtonColor(ui->containedBtn, settings().colors().pluginListContained()); + + setOverwritingColor(settings().colors().modlistOverwritingLoose()); + setOverwrittenColor(settings().colors().modlistOverwrittenLoose()); + setOverwritingArchiveColor(settings().colors().modlistOverwritingArchive()); + setOverwrittenArchiveColor(settings().colors().modlistOverwrittenArchive()); + setContainsColor(settings().colors().modlistContainsPlugin()); + setContainedColor(settings().colors().pluginListContained()); ui->compactBox->setChecked(settings().compactDownloads()); ui->showMetaBox->setChecked(settings().metaDownloads()); @@ -67,30 +69,32 @@ GeneralSettingsTab::GeneralSettingsTab(Settings& s, SettingsDialog& d) void GeneralSettingsTab::update() { - QString oldLanguage = settings().language(); - QString newLanguage = ui->languageBox->itemData(ui->languageBox->currentIndex()).toString(); + const QString oldLanguage = settings().language(); + const QString newLanguage = ui->languageBox->itemData(ui->languageBox->currentIndex()).toString(); + if (newLanguage != oldLanguage) { - qsettings().setValue("Settings/language", newLanguage); + settings().setLanguage(newLanguage); emit settings().languageChanged(newLanguage); } - QString oldStyle = qsettings().value("Settings/style", "").toString(); - QString newStyle = ui->styleBox->itemData(ui->styleBox->currentIndex()).toString(); + const QString oldStyle = settings().getStyleName().value_or(""); + const QString newStyle = ui->styleBox->itemData(ui->styleBox->currentIndex()).toString(); if (oldStyle != newStyle) { - qsettings().setValue("Settings/style", newStyle); + settings().setStyleName(newStyle); emit settings().styleChanged(newStyle); } - qsettings().setValue("Settings/overwritingLooseFilesColor", getOverwritingColor()); - qsettings().setValue("Settings/overwrittenLooseFilesColor", getOverwrittenColor()); - qsettings().setValue("Settings/overwritingArchiveFilesColor", getOverwritingArchiveColor()); - qsettings().setValue("Settings/overwrittenArchiveFilesColor", getOverwrittenArchiveColor()); - qsettings().setValue("Settings/containsPluginColor", getContainsColor()); - qsettings().setValue("Settings/containedColor", getContainedColor()); - qsettings().setValue("Settings/compact_downloads", ui->compactBox->isChecked()); - qsettings().setValue("Settings/meta_downloads", ui->showMetaBox->isChecked()); - qsettings().setValue("Settings/use_prereleases", ui->usePrereleaseBox->isChecked()); - qsettings().setValue("Settings/colorSeparatorScrollbars", ui->colorSeparatorsBox->isChecked()); + settings().colors().setModlistOverwritingLoose(getOverwritingColor()); + settings().colors().setModlistOverwrittenLoose(getOverwrittenColor()); + settings().colors().setModlistOverwritingArchive(getOverwritingArchiveColor()); + settings().colors().setModlistOverwrittenArchive(getOverwrittenArchiveColor()); + settings().colors().setModlistContainsPlugin(getContainsColor()); + settings().colors().setPluginListContained(getContainedColor()); + + settings().setCompactDownloads(ui->compactBox->isChecked()); + settings().setMetaDownloads(ui->showMetaBox->isChecked()); + settings().setUsePrereleases(ui->usePrereleaseBox->isChecked()); + settings().setColorSeparatorScrollbar(ui->colorSeparatorsBox->isChecked()); } void GeneralSettingsTab::addLanguages() diff --git a/src/usvfsconnector.cpp b/src/usvfsconnector.cpp index b5e6edb1..41f58308 100644 --- a/src/usvfsconnector.cpp +++ b/src/usvfsconnector.cpp @@ -164,7 +164,7 @@ UsvfsConnector::UsvfsConnector() { USVFSParameters params; LogLevel level = toUsvfsLogLevel(Settings::instance().logLevel()); - CrashDumpsType dumpType = crashDumpsType(Settings::instance().crashDumpsType()); + CrashDumpsType dumpType = Settings::instance().crashDumpsType(); std::string dumpPath = MOShared::ToString(OrganizerCore::crashDumpsPath(), true); USVFSInitParameters(¶ms, SHMID, false, level, dumpType, dumpPath.c_str()); @@ -249,9 +249,10 @@ void UsvfsConnector::updateMapping(const MappingType &mapping) } void UsvfsConnector::updateParams( - MOBase::log::Levels logLevel, int crashDumpsType, QString executableBlacklist) + MOBase::log::Levels logLevel, CrashDumpsType crashDumpsType, + QString executableBlacklist) { - USVFSUpdateParams(toUsvfsLogLevel(logLevel), ::crashDumpsType(crashDumpsType)); + USVFSUpdateParams(toUsvfsLogLevel(logLevel), crashDumpsType); ClearExecutableBlacklist(); for (auto exec : executableBlacklist.split(";")) { std::wstring buf = exec.toStdWString(); diff --git a/src/usvfsconnector.h b/src/usvfsconnector.h index b0bd320c..cd5d56b2 100644 --- a/src/usvfsconnector.h +++ b/src/usvfsconnector.h @@ -87,7 +87,7 @@ public: void updateMapping(const MappingType &mapping); void updateParams( - MOBase::log::Levels logLevel, int crashDumpsType, + MOBase::log::Levels logLevel, CrashDumpsType crashDumpsType, QString executableBlacklist); void updateForcedLibraries(const QList &forcedLibraries); -- cgit v1.3.1 From e9dba260cb9548dd5863ac66da18c295f6499b92 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Mon, 2 Sep 2019 14:52:02 -0400 Subject: split settings into a bunch of classes removed "get" from the getters that had it --- src/browserdialog.cpp | 2 +- src/downloadlistsortproxy.cpp | 2 +- src/downloadmanager.cpp | 2 +- src/executableslist.cpp | 2 +- src/filedialogmemory.cpp | 4 +- src/main.cpp | 26 +- src/mainwindow.cpp | 121 +-- src/modinfodialog.cpp | 2 +- src/modinfodialogconflicts.cpp | 16 +- src/modinfodialogimages.cpp | 4 +- src/modinfodialognexus.cpp | 2 +- src/modinfooverwrite.cpp | 2 +- src/modinforegular.cpp | 2 +- src/modlist.cpp | 8 +- src/nxmaccessmanager.cpp | 2 +- src/organizercore.cpp | 112 +- src/pluginlist.cpp | 2 +- src/profile.cpp | 8 +- src/profilesdialog.cpp | 4 +- src/settings.cpp | 2075 ++++++++++++++++++++----------------- src/settings.h | 569 ++++++---- src/settingsdialog.cpp | 6 +- src/settingsdialogdiagnostics.cpp | 13 +- src/settingsdialoggeneral.cpp | 28 +- src/settingsdialognexus.cpp | 32 +- src/settingsdialogpaths.cpp | 52 +- src/settingsdialogsteam.cpp | 4 +- src/settingsdialogworkarounds.cpp | 30 +- src/statusbar.cpp | 2 +- src/usvfsconnector.cpp | 4 +- 30 files changed, 1712 insertions(+), 1426 deletions(-) (limited to 'src/modlist.cpp') diff --git a/src/browserdialog.cpp b/src/browserdialog.cpp index 70da0b9c..72cb8862 100644 --- a/src/browserdialog.cpp +++ b/src/browserdialog.cpp @@ -49,7 +49,7 @@ BrowserDialog::BrowserDialog(QWidget *parent) ui->setupUi(this); m_AccessManager->setCookieJar(new PersistentCookieJar( - QDir::fromNativeSeparators(Settings::instance().getCacheDirectory() + "/cookies.dat"))); + QDir::fromNativeSeparators(Settings::instance().paths().cache() + "/cookies.dat"))); Qt::WindowFlags flags = windowFlags() | Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint; Qt::WindowFlags helpFlag = Qt::WindowContextHelpButtonHint; diff --git a/src/downloadlistsortproxy.cpp b/src/downloadlistsortproxy.cpp index 7bda139b..a69993c0 100644 --- a/src/downloadlistsortproxy.cpp +++ b/src/downloadlistsortproxy.cpp @@ -110,7 +110,7 @@ bool DownloadListSortProxy::filterAcceptsRow(int sourceRow, const QModelIndex&) if (m_CurrentFilter.length() == 0) { return true; } else if (sourceRow < m_Manager->numTotalDownloads()) { - QString displayedName = Settings::instance().metaDownloads() + QString displayedName = Settings::instance().interface().metaDownloads() ? m_Manager->getDisplayName(sourceRow) : m_Manager->getFileName(sourceRow); return displayedName.contains(m_CurrentFilter, Qt::CaseInsensitive); diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index a5dc164c..56238ef3 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -1731,7 +1731,7 @@ void DownloadManager::nxmDownloadURLsAvailable(QString gameName, int modID, int return; } - const auto servers = m_OrganizerCore->settings().getServers(); + const auto servers = m_OrganizerCore->settings().network().servers(); std::sort( resultList.begin(), diff --git a/src/executableslist.cpp b/src/executableslist.cpp index f2df2d6d..dce9181b 100644 --- a/src/executableslist.cpp +++ b/src/executableslist.cpp @@ -75,7 +75,7 @@ void ExecutablesList::load(const MOBase::IPluginGame* game, const Settings& s) // executables from 2.2.0, see upgradeFromCustom() bool needsUpgrade = false; - for (auto& map : s.getExecutables()) { + for (auto& map : s.executables()) { Executable::Flags flags; if (map["toolbar"].toBool()) diff --git a/src/filedialogmemory.cpp b/src/filedialogmemory.cpp index 96587ac7..8cfeb6b5 100644 --- a/src/filedialogmemory.cpp +++ b/src/filedialogmemory.cpp @@ -25,12 +25,12 @@ static std::map g_Cache; void FileDialogMemory::save(Settings& s) { - s.setRecentDirectories(g_Cache); + s.paths().setRecent(g_Cache); } void FileDialogMemory::restore(const Settings& s) { - g_Cache = s.getRecentDirectories(); + g_Cache = s.paths().recent(); } QString FileDialogMemory::getOpenFileName( diff --git a/src/main.cpp b/src/main.cpp index aa781c19..b5568fec 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -246,7 +246,7 @@ static bool HaveWriteAccess(const std::wstring &path) QString determineProfile(QStringList &arguments, const Settings &settings) { - auto selectedProfileName = settings.getSelectedProfileName(); + auto selectedProfileName = settings.game().selectedProfileName(); { // see if there is a profile on the command line int profileIndex = arguments.indexOf("-p", 1); @@ -271,12 +271,12 @@ QString determineProfile(QStringList &arguments, const Settings &settings) MOBase::IPluginGame *selectGame( Settings &settings, QDir const &gamePath, MOBase::IPluginGame *game) { - settings.setManagedGameName(game->gameName()); + settings.game().setName(game->gameName()); QString gameDir = gamePath.absolutePath(); game->setGamePath(gameDir); - settings.setManagedGameDirectory(gameDir); + settings.game().setDirectory(gameDir); return game; } @@ -289,7 +289,7 @@ MOBase::IPluginGame *determineCurrentGame( //user has done something odd. //If the game name has been set up, try to use that. - const auto gameName = settings.getManagedGameName(); + const auto gameName = settings.game().name(); const bool gameConfigured = (gameName.has_value() && *gameName != ""); if (gameConfigured) { @@ -299,7 +299,7 @@ MOBase::IPluginGame *determineCurrentGame( return nullptr; } - auto gamePath = settings.getManagedGameDirectory(); + auto gamePath = settings.game().directory(); if (!gamePath || *gamePath == "") { gamePath = game->gameDirectory().absolutePath(); } @@ -320,7 +320,7 @@ MOBase::IPluginGame *determineCurrentGame( //If we've made it this far and the instance is already configured for a game, something has gone wrong. //Tell the user about it. if (gameConfigured) { - const auto gamePath = settings.getManagedGameDirectory(); + const auto gamePath = settings.game().directory(); reportError( QObject::tr("Could not use configuration settings for game \"%1\", path \"%2\".") @@ -570,11 +570,11 @@ int runApplication(MOApplication &application, SingleInstance &instance, log::info("working directory: {}", QDir::currentPath()); Settings settings(dataPath + "/" + QString::fromStdWString(AppConfig::iniFileName())); - log::getDefault().setLevel(settings.logLevel()); + log::getDefault().setLevel(settings.diagnostics().logLevel()); // global crashDumpType sits in OrganizerCore to make a bit less ugly to // update it when the settings are changed during runtime - OrganizerCore::setGlobalCrashDumpsType(settings.crashDumpsType()); + OrganizerCore::setGlobalCrashDumpsType(settings.diagnostics().crashDumpsType()); env::Environment env; @@ -621,7 +621,7 @@ int runApplication(MOApplication &application, SingleInstance &instance, QString edition; - if (auto v=settings.getManagedGameEdition()) { + if (auto v=settings.game().edition()) { edition = *v; } else { QStringList editions = game->gameVariants(); @@ -640,7 +640,7 @@ int runApplication(MOApplication &application, SingleInstance &instance, return 1; } else { edition = selection.getChoiceString(); - settings.setManagedGameEdition(edition); + settings.game().setEdition(edition); } } } @@ -702,7 +702,7 @@ int runApplication(MOApplication &application, SingleInstance &instance, splash.activateWindow(); QString apiKey; - if (settings.getNexusApiKey(apiKey)) { + if (settings.nexus().apiKey(apiKey)) { NexusInterface::instance(&pluginContainer)->getAccessManager()->apiCheck(apiKey); } @@ -712,9 +712,9 @@ int runApplication(MOApplication &application, SingleInstance &instance, + QString::fromStdWString(AppConfig::tutorialsPath()) + "/", &organizer); - if (!application.setStyleFile(settings.getStyleName().value_or(""))) { + if (!application.setStyleFile(settings.interface().styleName().value_or(""))) { // disable invalid stylesheet - settings.setStyleName(""); + settings.interface().setStyleName(""); } int res = 1; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 42b19cb7..657c1a27 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -222,8 +222,8 @@ MainWindow::MainWindow(Settings &settings { QWebEngineProfile::defaultProfile()->setPersistentCookiesPolicy(QWebEngineProfile::NoPersistentCookies); QWebEngineProfile::defaultProfile()->setHttpCacheMaximumSize(52428800); - QWebEngineProfile::defaultProfile()->setCachePath(settings.getCacheDirectory()); - QWebEngineProfile::defaultProfile()->setPersistentStoragePath(settings.getCacheDirectory()); + QWebEngineProfile::defaultProfile()->setCachePath(settings.paths().cache()); + QWebEngineProfile::defaultProfile()->setPersistentStoragePath(settings.paths().cache()); ui->setupUi(this); ui->statusBar->setup(ui); @@ -253,7 +253,7 @@ MainWindow::MainWindow(Settings &settings ui->statusBar->setAPI(ni->getAPIStats(), ni->getAPIUserAccount()); } - languageChange(settings.language()); + languageChange(settings.interface().language()); m_CategoryFactory.loadCategories(); @@ -1194,7 +1194,7 @@ void MainWindow::hookUpWindowTutorials() QString firstLine = QString::fromUtf8(file.readLine()); if (firstLine.startsWith("//WIN")) { QString windowName = firstLine.mid(6).trimmed(); - if (!m_OrganizerCore.settings().isTutorialCompleted(windowName)) { + if (!m_OrganizerCore.settings().interface().isTutorialCompleted(windowName)) { TutorialManager::instance().activateTutorial(windowName, fileName); } } @@ -1225,7 +1225,7 @@ void MainWindow::showEvent(QShowEvent *event) hookUpWindowTutorials(); - if (m_OrganizerCore.settings().getFirstStart()) { + if (m_OrganizerCore.settings().firstStart()) { QString firstStepsTutorial = ToQString(AppConfig::firstStepsTutorial()); if (TutorialManager::instance().hasTutorial(firstStepsTutorial)) { if (QMessageBox::question(this, tr("Show tutorial?"), @@ -1247,11 +1247,11 @@ void MainWindow::showEvent(QShowEvent *event) m_OrganizerCore.settings().setFirstStart(false); } - m_OrganizerCore.settings().restoreIndex(ui->groupCombo); + m_OrganizerCore.settings().widgets().restoreIndex(ui->groupCombo); allowListResize(); - m_OrganizerCore.settings().registerAsNXMHandler(false); + m_OrganizerCore.settings().nexus().registerAsNXMHandler(false); m_WasVisible = true; updateProblemsButton(); } @@ -1751,7 +1751,7 @@ bool MainWindow::refreshProfiles(bool selectProfile) profileBox->clear(); profileBox->addItem(QObject::tr("")); - QDir profilesDir(Settings::instance().getProfileDirectory()); + QDir profilesDir(Settings::instance().paths().profiles()); profilesDir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot); QDirIterator profileIter(profilesDir); @@ -1990,7 +1990,7 @@ void MainWindow::updateBSAList(const QStringList &defaultArchives, const QString 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().forceEnableCoreFiles() + if (m_OrganizerCore.settings().game().forceEnableCoreFiles() && defaultArchives.contains(fileInfo.fileName())) { newItem->setCheckState(0, Qt::Checked); newItem->setDisabled(true); @@ -2140,7 +2140,7 @@ void MainWindow::readSettings(const Settings& settings) { // special case in case someone puts 0 in the INI - auto v = settings.getIndex(ui->executablesListBox); + auto v = settings.widgets().index(ui->executablesListBox); if (!v || v == 0) { v = 1; } @@ -2148,7 +2148,7 @@ void MainWindow::readSettings(const Settings& settings) ui->executablesListBox->setCurrentIndex(*v); } - settings.restoreIndex(ui->groupCombo); + settings.widgets().restoreIndex(ui->groupCombo); { settings.geometry().restoreVisibility(ui->categoriesGroup, false); @@ -2157,7 +2157,7 @@ void MainWindow::readSettings(const Settings& settings) ui->displayCategoriesBtn->setChecked(v); } - if (settings.getUseProxy()) { + if (settings.network().useProxy()) { activateProxy(true); } } @@ -2165,12 +2165,12 @@ void MainWindow::readSettings(const Settings& settings) void MainWindow::processUpdates(Settings& settings) { const auto earliest = QVersionNumber::fromString("2.1.2").normalized(); - const auto lastVersion = settings.getVersion().value_or(earliest); + const auto lastVersion = settings.version().value_or(earliest); const auto currentVersion = m_OrganizerCore.getVersion().asQVersionNumber(); settings.processUpdates(currentVersion, lastVersion); - if (!settings.getFirstStart()) { + if (!settings.firstStart()) { if (lastVersion < QVersionNumber(2, 1, 3)) { bool lastHidden = true; for (int i = ModList::COL_GAME; i < ui->modList->model()->columnCount(); ++i) { @@ -2222,8 +2222,8 @@ void MainWindow::storeSettings(Settings& s) s.geometry().saveState(ui->downloadView->header()); s.geometry().saveState(ui->modList->header()); - s.saveIndex(ui->groupCombo); - s.saveIndex(ui->executablesListBox); + s.widgets().saveIndex(ui->groupCombo); + s.widgets().saveIndex(ui->executablesListBox); } ILockedWaitingForProcess* MainWindow::lock() @@ -2751,7 +2751,7 @@ void MainWindow::restoreBackup_clicked() ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ContextRow); if (backupRegEx.indexIn(modInfo->name()) != -1) { QString regName = backupRegEx.cap(1); - QDir modDir(QDir::fromNativeSeparators(m_OrganizerCore.settings().getModDirectory())); + QDir modDir(QDir::fromNativeSeparators(m_OrganizerCore.settings().paths().mods())); if (!modDir.exists(regName) || (QMessageBox::question(this, tr("Overwrite?"), tr("This will replace the existing mod \"%1\". Continue?").arg(regName), @@ -2759,7 +2759,7 @@ void MainWindow::restoreBackup_clicked() if (modDir.exists(regName) && !shellDelete(QStringList(modDir.absoluteFilePath(regName)))) { reportError(tr("failed to remove mod \"%1\"").arg(regName)); } else { - QString destinationPath = QDir::fromNativeSeparators(m_OrganizerCore.settings().getModDirectory()) + "/" + regName; + QString destinationPath = QDir::fromNativeSeparators(m_OrganizerCore.settings().paths().mods()) + "/" + regName; if (!modDir.rename(modInfo->absolutePath(), destinationPath)) { reportError(tr("failed to rename \"%1\" to \"%2\"").arg(modInfo->absolutePath()).arg(destinationPath)); } @@ -3015,7 +3015,7 @@ void MainWindow::untrack_clicked() void MainWindow::windowTutorialFinished(const QString &windowName) { - m_OrganizerCore.settings().setTutorialCompleted(windowName); + m_OrganizerCore.settings().interface().setTutorialCompleted(windowName); } void MainWindow::overwriteClosed(int) @@ -3645,7 +3645,7 @@ void MainWindow::createSeparator_clicked() m_OrganizerCore.modList()->changeModPriority(ModInfo::getIndex(name), newPriority); } - if (auto c=m_OrganizerCore.settings().getPreviousSeparatorColor()) { + if (auto c=m_OrganizerCore.settings().colors().previousSeparatorColor()) { ModInfo::getByIndex(ModInfo::getIndex(name))->setColor(*c); } } @@ -3662,7 +3662,7 @@ void MainWindow::setColor_clicked() if (currentColor.isValid()) { dialog.setCurrentColor(currentColor); } - else if (auto c=settings.getPreviousSeparatorColor()) { + else if (auto c=settings.colors().previousSeparatorColor()) { dialog.setCurrentColor(*c); } @@ -3673,7 +3673,7 @@ void MainWindow::setColor_clicked() if (!currentColor.isValid()) return; - settings.setPreviousSeparatorColor(currentColor); + settings.colors().setPreviousSeparatorColor(currentColor); QItemSelectionModel *selection = ui->modList->selectionModel(); if (selection->hasSelection() && selection->selectedRows().count() > 1) { @@ -3710,7 +3710,7 @@ void MainWindow::resetColor_clicked() modInfo->setColor(color); } - m_OrganizerCore.settings().removePreviousSeparatorColor(); + m_OrganizerCore.settings().colors().removePreviousSeparatorColor(); } void MainWindow::createModFromOverwrite() @@ -4184,7 +4184,7 @@ void MainWindow::checkModsForUpdates() NexusInterface::instance(&m_PluginContainer)->requestTrackingInfo(this, QVariant(), QString()); } else { QString apiKey; - if (m_OrganizerCore.settings().getNexusApiKey(apiKey)) { + if (m_OrganizerCore.settings().nexus().apiKey(apiKey)) { m_OrganizerCore.doAfterLogin([this] () { this->checkModsForUpdates(); }); NexusInterface::instance(&m_PluginContainer)->getAccessManager()->apiCheck(apiKey); } else { @@ -4387,12 +4387,12 @@ void MainWindow::openIniFolder() void MainWindow::openDownloadsFolder() { - shell::ExploreFile(m_OrganizerCore.settings().getDownloadDirectory()); + shell::ExploreFile(m_OrganizerCore.settings().paths().downloads()); } void MainWindow::openModsFolder() { - shell::ExploreFile(m_OrganizerCore.settings().getModDirectory()); + shell::ExploreFile(m_OrganizerCore.settings().paths().mods()); } void MainWindow::openGameFolder() @@ -4758,7 +4758,7 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos) menu.addSeparator(); - if (info->getNexusID() > 0 && Settings::instance().endorsementIntegration()) { + if (info->getNexusID() > 0 && Settings::instance().nexus().endorsementIntegration()) { switch (info->endorsedState()) { case ModInfo::ENDORSED_TRUE: { menu.addAction(tr("Un-Endorse"), this, SLOT(unendorse_clicked())); @@ -5007,19 +5007,19 @@ void MainWindow::on_actionSettings_triggered() { Settings &settings = m_OrganizerCore.settings(); - QString oldModDirectory(settings.getModDirectory()); - QString oldCacheDirectory(settings.getCacheDirectory()); - QString oldProfilesDirectory(settings.getProfileDirectory()); - QString oldManagedGameDirectory(settings.getManagedGameDirectory().value_or("")); - bool oldDisplayForeign(settings.displayForeign()); - bool proxy = settings.getUseProxy(); + QString oldModDirectory(settings.paths().mods()); + QString oldCacheDirectory(settings.paths().cache()); + QString oldProfilesDirectory(settings.paths().profiles()); + QString oldManagedGameDirectory(settings.game().directory().value_or("")); + bool oldDisplayForeign(settings.interface().displayForeign()); + bool proxy = settings.network().useProxy(); DownloadManager *dlManager = m_OrganizerCore.downloadManager(); SettingsDialog dialog(&m_PluginContainer, settings, this); dialog.exec(); - if (oldManagedGameDirectory != settings.getManagedGameDirectory()) { + if (oldManagedGameDirectory != settings.game().directory()) { QMessageBox::about(this, tr("Restarting MO"), tr("Changing the managed game directory requires restarting MO.\n" "Any pending downloads will be paused.\n\n" @@ -5029,28 +5029,28 @@ void MainWindow::on_actionSettings_triggered() } InstallationManager *instManager = m_OrganizerCore.installationManager(); - instManager->setModsDirectory(settings.getModDirectory()); - instManager->setDownloadDirectory(settings.getDownloadDirectory()); + instManager->setModsDirectory(settings.paths().mods()); + instManager->setDownloadDirectory(settings.paths().downloads()); fixCategories(); refreshFilters(); - if (settings.getProfileDirectory() != oldProfilesDirectory) { + if (settings.paths().profiles() != oldProfilesDirectory) { refreshProfiles(); } - if (dlManager->getOutputDirectory() != settings.getDownloadDirectory()) { + if (dlManager->getOutputDirectory() != settings.paths().downloads()) { if (dlManager->downloadsInProgress()) { MessageDialog::showMessage(tr("Can't change download directory while " "downloads are in progress!"), this); } else { - dlManager->setOutputDirectory(settings.getDownloadDirectory()); + dlManager->setOutputDirectory(settings.paths().downloads()); } } - if ((settings.getModDirectory() != oldModDirectory) - || (settings.displayForeign() != oldDisplayForeign)) { + if ((settings.paths().mods() != oldModDirectory) + || (settings.interface().displayForeign() != oldDisplayForeign)) { m_OrganizerCore.profileRefresh(); } @@ -5075,18 +5075,19 @@ void MainWindow::on_actionSettings_triggered() m_OrganizerCore.refreshLists(); } - if (settings.getCacheDirectory() != oldCacheDirectory) { - NexusInterface::instance(&m_PluginContainer)->setCacheDirectory(settings.getCacheDirectory()); + if (settings.paths().cache() != oldCacheDirectory) { + NexusInterface::instance(&m_PluginContainer)->setCacheDirectory( + settings.paths().cache()); } - if (proxy != settings.getUseProxy()) { - activateProxy(settings.getUseProxy()); + if (proxy != settings.network().useProxy()) { + activateProxy(settings.network().useProxy()); } ui->statusBar->checkSettings(m_OrganizerCore.settings()); updateDownloadView(); - m_OrganizerCore.setLogLevel(settings.logLevel()); + m_OrganizerCore.setLogLevel(settings.diagnostics().logLevel()); m_OrganizerCore.cycleDiagnostics(); toggleMO2EndorseState(); @@ -5402,10 +5403,10 @@ void MainWindow::motdReceived(const QString &motd) // internet connection is faster next time if (m_StartTime.secsTo(QTime::currentTime()) < 5) { uint hash = qHash(motd); - if (hash != m_OrganizerCore.settings().getMotDHash()) { + if (hash != m_OrganizerCore.settings().motdHash()) { MotDDialog dialog(motd); dialog.exec(); - m_OrganizerCore.settings().setMotDHash(hash); + m_OrganizerCore.settings().setMotdHash(hash); } } } @@ -5528,7 +5529,7 @@ void MainWindow::initDownloadView() void MainWindow::updateDownloadView() { // set the view attribute and default row sizes - if (m_OrganizerCore.settings().compactDownloads()) { + if (m_OrganizerCore.settings().interface().compactDownloads()) { ui->downloadView->setProperty("downloadView", "compact"); setStyleSheet("DownloadListWidget::item { padding: 4px 2px; }"); } else { @@ -5541,7 +5542,7 @@ void MainWindow::updateDownloadView() // reapply global stylesheet on the widget level (!) to override the defaults //ui->downloadView->setStyleSheet(styleSheet()); - ui->downloadView->setMetaDisplay(m_OrganizerCore.settings().metaDownloads()); + ui->downloadView->setMetaDisplay(m_OrganizerCore.settings().interface().metaDownloads()); ui->downloadView->style()->unpolish(ui->downloadView); ui->downloadView->style()->polish(ui->downloadView); qobject_cast(ui->downloadView->header())->customResizeSections(); @@ -5554,7 +5555,7 @@ void MainWindow::modUpdateCheck(std::multimap IDs) ModInfo::manualUpdateCheck(&m_PluginContainer, this, IDs); } else { QString apiKey; - if (m_OrganizerCore.settings().getNexusApiKey(apiKey)) { + if (m_OrganizerCore.settings().nexus().apiKey(apiKey)) { m_OrganizerCore.doAfterLogin([=]() { this->modUpdateCheck(IDs); }); NexusInterface::instance(&m_PluginContainer)->getAccessManager()->apiCheck(apiKey); } else @@ -5566,7 +5567,7 @@ void MainWindow::toggleMO2EndorseState() { const auto& s = m_OrganizerCore.settings(); - if (!s.endorsementIntegration()) { + if (!s.nexus().endorsementIntegration()) { ui->actionEndorseMO->setVisible(false); return; } @@ -5576,7 +5577,7 @@ void MainWindow::toggleMO2EndorseState() bool enabled = false; QString text; - switch (s.endorsementState()) + switch (s.nexus().endorsementState()) { case EndorsementState::Accepted: { @@ -5631,9 +5632,9 @@ void MainWindow::nxmEndorsementsAvailable(QVariant userData, QVariant resultData mod->setIsEndorsed(false); } - if (Settings::instance().endorsementIntegration()) { + if (Settings::instance().nexus().endorsementIntegration()) { if (result->first == "skyrimspecialedition" && result->second.first == gamePlugin->nexusModOrganizerID()) { - m_OrganizerCore.settings().setEndorsementState( + m_OrganizerCore.settings().nexus().setEndorsementState( endorsementStateFromString(result->second.second)); toggleMO2EndorseState(); @@ -5642,13 +5643,13 @@ void MainWindow::nxmEndorsementsAvailable(QVariant userData, QVariant resultData } } - if (!searchedMO2NexusGame && Settings::instance().endorsementIntegration()) { + if (!searchedMO2NexusGame && Settings::instance().nexus().endorsementIntegration()) { auto gamePlugin = m_OrganizerCore.getGame("SkyrimSE"); if (gamePlugin) { auto iter = sorted.equal_range(gamePlugin->gameNexusName()); for (auto result = iter.first; result != iter.second; ++result) { if (result->second.first == gamePlugin->nexusModOrganizerID()) { - m_OrganizerCore.settings().setEndorsementState( + m_OrganizerCore.settings().nexus().setEndorsementState( endorsementStateFromString(result->second.second)); toggleMO2EndorseState(); @@ -5862,7 +5863,7 @@ void MainWindow::nxmEndorsementToggled(QString, int, QVariant, QVariant resultDa } } - m_OrganizerCore.settings().setEndorsementState(s); + m_OrganizerCore.settings().nexus().setEndorsementState(s); toggleMO2EndorseState(); if (!disconnect(sender(), SIGNAL(nxmEndorsementToggled(QString, int, QVariant, QVariant, int)), @@ -5901,7 +5902,7 @@ void MainWindow::nxmTrackedModsAvailable(QVariant userData, QVariant resultData, void MainWindow::nxmDownloadURLs(QString, int, int, QVariant, QVariant resultData, int) { - auto servers = m_OrganizerCore.settings().getServers(); + auto servers = m_OrganizerCore.settings().network().servers(); for (const QVariant &var : resultData.toList()) { const QVariantMap map = var.toMap(); @@ -5929,7 +5930,7 @@ void MainWindow::nxmDownloadURLs(QString, int, int, QVariant, QVariant resultDat } } - m_OrganizerCore.settings().updateServers(servers); + m_OrganizerCore.settings().network().updateServers(servers); } diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index f3840230..2178ef34 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -381,7 +381,7 @@ void ModInfoDialog::reAddTabs( Q_ASSERT(visibility.size() == m_tabs.size()); // ordered tab names from settings - const auto orderedNames = m_core->settings().geometry().getModInfoTabOrder(); + const auto orderedNames = m_core->settings().geometry().modInfoTabOrder(); // whether the tabs can be sorted; if the object name of a tab widget is not // found in orderedNames, the list cannot be sorted safely diff --git a/src/modinfodialogconflicts.cpp b/src/modinfodialogconflicts.cpp index 7840269d..3a71b405 100644 --- a/src/modinfodialogconflicts.cpp +++ b/src/modinfodialogconflicts.cpp @@ -409,7 +409,7 @@ void ConflictsTab::clear() void ConflictsTab::saveState(Settings& s) { - s.saveIndex(ui->tabConflictsTabs); + s.widgets().saveIndex(ui->tabConflictsTabs); m_general.saveState(s); m_advanced.saveState(s); @@ -417,7 +417,7 @@ void ConflictsTab::saveState(Settings& s) void ConflictsTab::restoreState(const Settings& s) { - s.restoreIndex(ui->tabConflictsTabs, 0); + s.widgets().restoreIndex(ui->tabConflictsTabs, 0); m_general.restoreState(s); m_advanced.restoreState(s); @@ -1014,17 +1014,17 @@ void AdvancedConflictsTab::clear() void AdvancedConflictsTab::saveState(Settings& s) { s.geometry().saveState(ui->conflictsAdvancedList->header()); - s.saveChecked(ui->conflictsAdvancedShowNoConflict); - s.saveChecked(ui->conflictsAdvancedShowAll); - s.saveChecked(ui->conflictsAdvancedShowNearest); + s.widgets().saveChecked(ui->conflictsAdvancedShowNoConflict); + s.widgets().saveChecked(ui->conflictsAdvancedShowAll); + s.widgets().saveChecked(ui->conflictsAdvancedShowNearest); } void AdvancedConflictsTab::restoreState(const Settings& s) { s.geometry().restoreState(ui->conflictsAdvancedList->header()); - s.restoreChecked(ui->conflictsAdvancedShowNoConflict); - s.restoreChecked(ui->conflictsAdvancedShowAll); - s.restoreChecked(ui->conflictsAdvancedShowNearest); + s.widgets().restoreChecked(ui->conflictsAdvancedShowNoConflict); + s.widgets().restoreChecked(ui->conflictsAdvancedShowAll); + s.widgets().restoreChecked(ui->conflictsAdvancedShowNearest); } void AdvancedConflictsTab::update() diff --git a/src/modinfodialogimages.cpp b/src/modinfodialogimages.cpp index 38c12d8a..9d347f57 100644 --- a/src/modinfodialogimages.cpp +++ b/src/modinfodialogimages.cpp @@ -130,13 +130,13 @@ void ImagesTab::update() void ImagesTab::saveState(Settings& s) { - s.saveChecked(ui->imagesShowDDS); + s.widgets().saveChecked(ui->imagesShowDDS); s.geometry().saveState(ui->tabImagesSplitter); } void ImagesTab::restoreState(const Settings& s) { - s.restoreChecked(ui->imagesShowDDS); + s.widgets().restoreChecked(ui->imagesShowDDS); s.geometry().restoreState(ui->tabImagesSplitter); } diff --git a/src/modinfodialognexus.cpp b/src/modinfodialognexus.cpp index 6d28cbe3..95e62328 100644 --- a/src/modinfodialognexus.cpp +++ b/src/modinfodialognexus.cpp @@ -19,7 +19,7 @@ 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().endorsementIntegration()); + ui->endorse->setVisible(core().settings().nexus().endorsementIntegration()); connect(ui->modID, &QLineEdit::editingFinished, [&]{ onModIDChanged(); }); connect( diff --git a/src/modinfooverwrite.cpp b/src/modinfooverwrite.cpp index 37c8c650..fb110abb 100644 --- a/src/modinfooverwrite.cpp +++ b/src/modinfooverwrite.cpp @@ -23,7 +23,7 @@ bool ModInfoOverwrite::isEmpty() const QString ModInfoOverwrite::absolutePath() const { - return Settings::instance().getOverwriteDirectory(); + return Settings::instance().paths().overwrite(); } std::vector ModInfoOverwrite::getFlags() const diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index ce29e11e..3cff914a 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -631,7 +631,7 @@ std::vector ModInfoRegular::getFlags() const std::vector result = ModInfoWithConflictInfo::getFlags(); if ((m_NexusID > 0) && (endorsedState() == ENDORSED_FALSE) && - Settings::instance().endorsementIntegration()) { + Settings::instance().nexus().endorsementIntegration()) { result.push_back(ModInfo::FLAG_NOTENDORSED); } if ((m_NexusID > 0) && diff --git a/src/modlist.cpp b/src/modlist.cpp index 94b4a387..6018d3d4 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -390,7 +390,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const return QVariant(); } else if (role == Qt::ForegroundRole) { if (modInfo->hasFlag(ModInfo::FLAG_SEPARATOR) && modInfo->getColor().isValid()) { - return Settings::getIdealTextColor(modInfo->getColor()); + return ColorSettings::idealTextColor(modInfo->getColor()); } else if (column == COL_NAME) { int highlight = modInfo->getHighlight(); if (highlight & ModInfo::HIGHLIGHT_IMPORTANT) @@ -428,7 +428,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const } else if (modInfo->hasFlag(ModInfo::FLAG_SEPARATOR) && modInfo->getColor().isValid() && ((role != ViewMarkingScrollBar::DEFAULT_ROLE) - || Settings::instance().colorSeparatorScrollbar())) { + || Settings::instance().colors().colorSeparatorScrollbar())) { return modInfo->getColor(); } else { return QVariant(); @@ -999,8 +999,8 @@ bool ModList::dropURLs(const QMimeData *mimeData, int row, const QModelIndex &pa ModInfo::Ptr modInfo = ModInfo::getByIndex(row); QDir modDir = QDir(modInfo->absolutePath()); - QDir allModsDir(Settings::instance().getModDirectory()); - QDir overwriteDir(Settings::instance().getOverwriteDirectory()); + QDir allModsDir(Settings::instance().paths().mods()); + QDir overwriteDir(Settings::instance().paths().overwrite()); QStringList sourceList; QStringList targetList; diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp index 16190ca4..c6ef7bc7 100644 --- a/src/nxmaccessmanager.cpp +++ b/src/nxmaccessmanager.cpp @@ -572,7 +572,7 @@ NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion) m_validator.finished = [&](auto&& user){ onValidatorFinished(user); }; setCookieJar(new PersistentCookieJar(QDir::fromNativeSeparators( - Settings::instance().getCacheDirectory() + "/nexus_cookies.dat"))); + Settings::instance().paths().cache() + "/nexus_cookies.dat"))); if (networkAccessible() == QNetworkAccessManager::UnknownAccessibility) { // why is this necessary all of a sudden? diff --git a/src/organizercore.cpp b/src/organizercore.cpp index af0cf969..1a89641d 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -146,7 +146,7 @@ static void startSteam(QWidget *widget) QStringList args; QString username; QString password; - if (Settings::instance().getSteamLogin(username, password)) { + if (Settings::instance().steam().login(username, password)) { args << "-login"; args << username; if (password != "") { @@ -275,12 +275,13 @@ OrganizerCore::OrganizerCore(Settings &settings) , m_ArchivesInit(false) , m_PluginListsWriter(std::bind(&OrganizerCore::savePluginList, this)) { - m_DownloadManager.setOutputDirectory(m_Settings.getDownloadDirectory()); + m_DownloadManager.setOutputDirectory(m_Settings.paths().downloads()); - NexusInterface::instance(m_PluginContainer)->setCacheDirectory(m_Settings.getCacheDirectory()); + NexusInterface::instance(m_PluginContainer)->setCacheDirectory( + m_Settings.paths().cache()); - m_InstallationManager.setModsDirectory(m_Settings.getModDirectory()); - m_InstallationManager.setDownloadDirectory(m_Settings.getDownloadDirectory()); + m_InstallationManager.setModsDirectory(m_Settings.paths().mods()); + m_InstallationManager.setDownloadDirectory(m_Settings.paths().downloads()); connect(&m_DownloadManager, SIGNAL(downloadSpeed(QString, int)), this, SLOT(downloadSpeed(QString, int))); @@ -333,7 +334,7 @@ OrganizerCore::~OrganizerCore() void OrganizerCore::storeSettings() { if (m_CurrentProfile != nullptr) { - m_Settings.setSelectedProfileName(m_CurrentProfile->name()); + m_Settings.game().setSelectedProfileName(m_CurrentProfile->name()); } m_ExecutablesList.store(m_Settings); @@ -356,7 +357,7 @@ 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.getFilename(), reason)); + .arg(m_Settings.filename(), reason)); } } @@ -432,8 +433,9 @@ void OrganizerCore::updateExecutablesList() // TODO this has nothing to do with executables list move to an appropriate // function! - ModInfo::updateFromDisc(m_Settings.getModDirectory(), &m_DirectoryStructure, - m_PluginContainer, m_Settings.displayForeign(), managedGame()); + ModInfo::updateFromDisc( + m_Settings.paths().mods(), &m_DirectoryStructure, + m_PluginContainer, m_Settings.interface().displayForeign(), managedGame()); } void OrganizerCore::setUserInterface(IUserInterface *userInterface, @@ -478,7 +480,7 @@ void OrganizerCore::setUserInterface(IUserInterface *userInterface, if (userInterface != nullptr) { // this currently wouldn't work reliably if the ui isn't initialized yet to // display the result - if (isOnline() && !m_Settings.offlineMode()) { + if (isOnline() && !m_Settings.network().offlineMode()) { m_Updater.testForUpdate(); } else { log::debug("user doesn't seem to be connected to the internet"); @@ -541,7 +543,7 @@ bool OrganizerCore::nexusApi(bool retry) return false; } else { QString apiKey; - if (m_Settings.getNexusApiKey(apiKey)) { + if (m_Settings.nexus().apiKey(apiKey)) { // credentials stored or user entered them manually log::debug("attempt to verify nexus api key"); accessManager->apiCheck(apiKey); @@ -608,7 +610,7 @@ void OrganizerCore::removeOrigin(const QString &name) void OrganizerCore::downloadSpeed(const QString &serverName, int bytesPerSecond) { - m_Settings.setDownloadSpeed(serverName, bytesPerSecond); + m_Settings.network().setDownloadSpeed(serverName, bytesPerSecond); } InstallationManager *OrganizerCore::installationManager() @@ -629,9 +631,9 @@ bool OrganizerCore::createDirectory(const QString &path) { } bool OrganizerCore::checkPathSymlinks() { - bool hasSymlink = (QFileInfo(m_Settings.getProfileDirectory()).isSymLink() || - QFileInfo(m_Settings.getModDirectory()).isSymLink() || - QFileInfo(m_Settings.getOverwriteDirectory()).isSymLink()); + bool hasSymlink = (QFileInfo(m_Settings.paths().profiles()).isSymLink() || + QFileInfo(m_Settings.paths().mods()).isSymLink() || + QFileInfo(m_Settings.paths().overwrite()).isSymLink()); if (hasSymlink) { QMessageBox::critical(nullptr, QObject::tr("Error"), QObject::tr("One of the configured MO2 directories (profiles, mods, or overwrite) " @@ -643,17 +645,17 @@ bool OrganizerCore::checkPathSymlinks() { } bool OrganizerCore::bootstrap() { - return createDirectory(m_Settings.getProfileDirectory()) && - createDirectory(m_Settings.getModDirectory()) && - createDirectory(m_Settings.getDownloadDirectory()) && - createDirectory(m_Settings.getOverwriteDirectory()) && + return createDirectory(m_Settings.paths().profiles()) && + createDirectory(m_Settings.paths().mods()) && + createDirectory(m_Settings.paths().downloads()) && + createDirectory(m_Settings.paths().overwrite()) && createDirectory(QString::fromStdWString(crashDumpsPath())) && checkPathSymlinks() && cycleDiagnostics(); } void OrganizerCore::createDefaultProfile() { - QString profilesPath = settings().getProfileDirectory(); + QString profilesPath = settings().paths().profiles(); if (QDir(profilesPath).entryList(QDir::AllDirs | QDir::NoDotAndDotDot).size() == 0) { Profile newProf("Default", managedGame(), false); @@ -674,18 +676,18 @@ void OrganizerCore::updateVFSParams( void OrganizerCore::setLogLevel(log::Levels level) { - m_Settings.setLogLevel(level); + m_Settings.diagnostics().setLogLevel(level); updateVFSParams( - m_Settings.logLevel(), - m_Settings.crashDumpsType(), + m_Settings.diagnostics().logLevel(), + m_Settings.diagnostics().crashDumpsType(), m_Settings.executablesBlacklist()); - log::getDefault().setLevel(m_Settings.logLevel()); + log::getDefault().setLevel(m_Settings.diagnostics().logLevel()); } bool OrganizerCore::cycleDiagnostics() { - if (int maxDumps = settings().crashDumpsMax()) + if (int maxDumps = settings().diagnostics().crashDumpsMax()) removeOldFiles(QString::fromStdWString(crashDumpsPath()), "*.dmp", maxDumps, QDir::Time|QDir::Reversed); return true; } @@ -720,7 +722,7 @@ void OrganizerCore::setCurrentProfile(const QString &profileName) return; } - QDir profileBaseDir(settings().getProfileDirectory()); + QDir profileBaseDir(settings().paths().profiles()); QString profileDir = profileBaseDir.absoluteFilePath(profileName); if (!QDir(profileDir).exists()) { @@ -744,7 +746,7 @@ void OrganizerCore::setCurrentProfile(const QString &profileName) m_CurrentProfile->deactivateInvalidation(); } - m_Settings.setSelectedProfileName(m_CurrentProfile->name()); + m_Settings.game().setSelectedProfileName(m_CurrentProfile->name()); connect(m_CurrentProfile, SIGNAL(modStatusChanged(uint)), this, SLOT(modStatusChanged(uint))); connect(m_CurrentProfile, SIGNAL(modStatusChanged(QList)), this, SLOT(modStatusChanged(QList))); @@ -776,22 +778,22 @@ QString OrganizerCore::profilePath() const QString OrganizerCore::downloadsPath() const { - return QDir::fromNativeSeparators(m_Settings.getDownloadDirectory()); + return QDir::fromNativeSeparators(m_Settings.paths().downloads()); } QString OrganizerCore::overwritePath() const { - return QDir::fromNativeSeparators(m_Settings.getOverwriteDirectory()); + return QDir::fromNativeSeparators(m_Settings.paths().overwrite()); } QString OrganizerCore::basePath() const { - return QDir::fromNativeSeparators(m_Settings.getBaseDirectory()); + return QDir::fromNativeSeparators(m_Settings.paths().base()); } QString OrganizerCore::modsPath() const { - return QDir::fromNativeSeparators(m_Settings.getModDirectory()); + return QDir::fromNativeSeparators(m_Settings.paths().mods()); } MOBase::VersionInfo OrganizerCore::appVersion() const @@ -821,10 +823,10 @@ MOBase::IModInterface *OrganizerCore::createMod(GuessedValue &name) return nullptr; } - m_InstallationManager.setModsDirectory(m_Settings.getModDirectory()); + m_InstallationManager.setModsDirectory(m_Settings.paths().mods()); QString targetDirectory - = QDir::fromNativeSeparators(m_Settings.getModDirectory()) + = QDir::fromNativeSeparators(m_Settings.paths().mods()) .append("/") .append(name); @@ -912,7 +914,7 @@ MOBase::IModInterface *OrganizerCore::installMod(const QString &fileName, modName.update(initModName, GUESS_USER); } m_CurrentProfile->writeModlistNow(); - m_InstallationManager.setModsDirectory(m_Settings.getModDirectory()); + m_InstallationManager.setModsDirectory(m_Settings.paths().mods()); if (m_InstallationManager.install(fileName, modName, hasIniTweaks)) { MessageDialog::showMessage(tr("Installation successful"), qApp->activeWindow()); @@ -977,7 +979,7 @@ void OrganizerCore::installDownload(int index) m_CurrentProfile->writeModlistNow(); bool hasIniTweaks = false; - m_InstallationManager.setModsDirectory(m_Settings.getModDirectory()); + m_InstallationManager.setModsDirectory(m_Settings.paths().mods()); if (m_InstallationManager.install(fileName, modName, hasIniTweaks)) { MessageDialog::showMessage(tr("Installation successful"), qApp->activeWindow()); @@ -1270,7 +1272,7 @@ bool OrganizerCore::previewFileWithAlternatives( 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().getModDirectory().size() + 1; + int offset = settings().paths().mods().size() + 1; offset = fileName.indexOf("/", offset); fileName = fileName.mid(offset + 1); } @@ -1412,7 +1414,7 @@ HANDLE OrganizerCore::spawnBinaryDirect(const QFileInfo &binary, LPDWORD exitCode) { HANDLE processHandle = spawnBinaryProcess(binary, arguments, profileName, currentDirectory, steamAppID, customOverwrite, forcedLibraries); - if (Settings::instance().lockGUI() && processHandle != INVALID_HANDLE_VALUE) { + if (Settings::instance().interface().lockGUI() && processHandle != INVALID_HANDLE_VALUE) { std::unique_ptr dlg; ILockedWaitingForProcess* uilock = nullptr; @@ -1461,7 +1463,7 @@ HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary, ::SetEnvironmentVariableW(L"SteamAPPId", ToWString(steamAppID).c_str()); } else { ::SetEnvironmentVariableW(L"SteamAPPId", - ToWString(m_Settings.getSteamAppID()).c_str()); + ToWString(m_Settings.steam().appID()).c_str()); } QWidget *window = qApp->activeWindow(); @@ -1477,7 +1479,7 @@ HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary, || QFileInfo(managedGame()->gameDirectory().absoluteFilePath( "steam_api64.dll")) .exists()) - && (m_Settings.getLoadMechanism() == LoadMechanism::LOAD_MODORGANIZER)) { + && (m_Settings.game().loadMechanismType() == LoadMechanism::LOAD_MODORGANIZER)) { bool steamFound = true; bool steamAccess = true; @@ -1592,7 +1594,7 @@ HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary, } } - QString modsPath = settings().getModDirectory(); + QString modsPath = settings().paths().mods(); // Check if this a request with either an executable or a working directory under our mods folder // then will start the process in a virtualized "environment" with the appropriate paths fixed: @@ -1749,7 +1751,7 @@ HANDLE OrganizerCore::startApplication(const QString &executable, bool OrganizerCore::waitForApplication(HANDLE handle, LPDWORD exitCode) { - if (!Settings::instance().lockGUI()) + if (!Settings::instance().interface().lockGUI()) return true; ILockedWaitingForProcess* uilock = nullptr; @@ -1960,8 +1962,10 @@ void OrganizerCore::refreshModList(bool saveChanges) if (saveChanges) { m_CurrentProfile->writeModlistNow(true); } - ModInfo::updateFromDisc(m_Settings.getModDirectory(), &m_DirectoryStructure, - m_PluginContainer, m_Settings.displayForeign(), managedGame()); + + ModInfo::updateFromDisc( + m_Settings.paths().mods(), &m_DirectoryStructure, + m_PluginContainer, m_Settings.interface().displayForeign(), managedGame()); m_CurrentProfile->refreshModStatus(); @@ -2130,7 +2134,7 @@ void OrganizerCore::updateModsInDirectoryStructure(QMaparchivesWriter().writeImmediately(false); @@ -2156,7 +2160,7 @@ void OrganizerCore::loggedInAction(QWidget* parent, std::function f) f(); } else { QString apiKey; - if (settings().getNexusApiKey(apiKey)) { + if (settings().nexus().apiKey(apiKey)) { doAfterLogin([f]{ f(); }); NexusInterface::instance(m_PluginContainer)->getAccessManager()->apiCheck(apiKey); } else { @@ -2295,8 +2299,10 @@ void OrganizerCore::profileRefresh() { // have to refresh mods twice (again in refreshModList), otherwise the refresh // isn't complete. Not sure why - ModInfo::updateFromDisc(m_Settings.getModDirectory(), &m_DirectoryStructure, - m_PluginContainer, m_Settings.displayForeign(), managedGame()); + ModInfo::updateFromDisc( + m_Settings.paths().mods(), &m_DirectoryStructure, + m_PluginContainer, m_Settings.interface().displayForeign(), managedGame()); + m_CurrentProfile->refreshModStatus(); refreshModList(); @@ -2463,7 +2469,7 @@ void OrganizerCore::syncOverwrite() SyncOverwriteDialog syncDialog(modInfo->absolutePath(), m_DirectoryStructure, qApp->activeWindow()); if (syncDialog.exec() == QDialog::Accepted) { - syncDialog.apply(QDir::fromNativeSeparators(m_Settings.getModDirectory())); + syncDialog.apply(QDir::fromNativeSeparators(m_Settings.paths().mods())); modInfo->testValid(); refreshDirectoryStructure(); } @@ -2486,7 +2492,7 @@ std::vector OrganizerCore::activeProblems() const 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 sevre error which will most likely make the + // 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); @@ -2562,7 +2568,7 @@ void OrganizerCore::savePluginList() } m_PluginList.saveTo(m_CurrentProfile->getLockedOrderFileName(), m_CurrentProfile->getDeleterFileName(), - m_Settings.hideUncheckedPlugins()); + m_Settings.game().hideUncheckedPlugins()); m_PluginList.saveLoadOrder(*m_DirectoryStructure); } @@ -2574,7 +2580,7 @@ void OrganizerCore::prepareStart() m_CurrentProfile->writeModlist(); m_CurrentProfile->createTweakedIniFile(); saveCurrentLists(); - m_Settings.setupLoadMechanism(); + m_Settings.game().setupLoadMechanism(); storeSettings(); } @@ -2588,7 +2594,7 @@ std::vector OrganizerCore::fileMapping(const QString &profileName, } IPluginGame *game = qApp->property("managed_game").value(); - Profile profile(QDir(m_Settings.getProfileDirectory() + "/" + profileName), + Profile profile(QDir(m_Settings.paths().profiles() + "/" + profileName), game); MappingType result; @@ -2634,7 +2640,7 @@ std::vector OrganizerCore::fileMapping(const QString &profileName, } result.insert(result.end(), { - QDir::toNativeSeparators(m_Settings.getOverwriteDirectory()), + QDir::toNativeSeparators(m_Settings.paths().overwrite()), dataPath, true, customOverwrite.isEmpty() diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index ddfe492e..33423225 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -191,7 +191,7 @@ void PluginList::refresh(const QString &profileName continue; } - bool forceEnabled = Settings::instance().forceEnableCoreFiles() && + bool forceEnabled = Settings::instance().game().forceEnableCoreFiles() && primaryPlugins.contains(filename, Qt::CaseInsensitive); //(std::find(primaryPlugins.begin(), primaryPlugins.end(), filename.toLower()) != primaryPlugins.end()); diff --git a/src/profile.cpp b/src/profile.cpp index 7f4ebcaa..e76060b9 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -73,7 +73,7 @@ Profile::Profile(const QString &name, IPluginGame const *gamePlugin, bool useDef : m_ModListWriter(std::bind(&Profile::doWriteModlist, this)) , m_GamePlugin(gamePlugin) { - QString profilesDir = Settings::instance().getProfileDirectory(); + QString profilesDir = Settings::instance().paths().profiles(); QDir profileBase(profilesDir); QString fixedName = name; if (!fixDirectoryName(fixedName)) { @@ -299,7 +299,7 @@ void Profile::createTweakedIniFile() // static void Profile::renameModInAllProfiles(const QString& oldName, const QString& newName) { - QDir profilesDir(Settings::instance().getProfileDirectory()); + QDir profilesDir(Settings::instance().paths().profiles()); profilesDir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot); QDirIterator profileIter(profilesDir); while (profileIter.hasNext()) { @@ -655,7 +655,7 @@ void Profile::setModPriority(unsigned int index, int &newPriority) Profile *Profile::createPtrFrom(const QString &name, const Profile &reference, MOBase::IPluginGame const *gamePlugin) { - QString profileDirectory = Settings::instance().getProfileDirectory() + "/" + name; + QString profileDirectory = Settings::instance().paths().profiles() + "/" + name; reference.copyFilesTo(profileDirectory); return new Profile(QDir(profileDirectory), gamePlugin); } @@ -906,7 +906,7 @@ QString Profile::savePath() const void Profile::rename(const QString &newName) { - QDir profileDir(Settings::instance().getProfileDirectory()); + QDir profileDir(Settings::instance().paths().profiles()); profileDir.rename(name(), newName); m_Directory.setPath(profileDir.absoluteFilePath(newName)); } diff --git a/src/profilesdialog.cpp b/src/profilesdialog.cpp index 2f1bd059..c91f48f4 100644 --- a/src/profilesdialog.cpp +++ b/src/profilesdialog.cpp @@ -57,7 +57,7 @@ ProfilesDialog::ProfilesDialog(const QString &profileName, MOBase::IPluginGame c { ui->setupUi(this); - QDir profilesDir(Settings::instance().getProfileDirectory()); + QDir profilesDir(Settings::instance().paths().profiles()); profilesDir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot); QDirIterator profileIter(profilesDir); @@ -203,7 +203,7 @@ void ProfilesDialog::on_removeProfileButton_clicked() if (confirmBox.exec() == QMessageBox::Yes) { QString profilePath; if (profileToDelete.get() == nullptr) { - profilePath = Settings::instance().getProfileDirectory() + 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. " diff --git a/src/settings.cpp b/src/settings.cpp index 71288950..8b063efb 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -150,7 +150,7 @@ std::optional getOptional( template T get( const QSettings& settings, - const QString& section, const QString& key, T def={}) + const QString& section, const QString& key, T def) { if (auto v=getOptional(settings, section, key)) { return *v; @@ -453,22 +453,74 @@ void warnIfNotCheckable(const QAbstractButton* b) } +bool setWindowsCredential(const QString key, const QString data) +{ + QString finalKey("ModOrganizer2_" + key); + wchar_t* keyData = new wchar_t[finalKey.size()+1]; + finalKey.toWCharArray(keyData); + keyData[finalKey.size()] = L'\0'; + bool result = false; + if (data.isEmpty()) { + result = CredDeleteW(keyData, CRED_TYPE_GENERIC, 0); + if (!result) + if (GetLastError() == ERROR_NOT_FOUND) + result = true; + } else { + wchar_t* charData = new wchar_t[data.size()]; + data.toWCharArray(charData); + + CREDENTIALW cred = {}; + cred.Flags = 0; + cred.Type = CRED_TYPE_GENERIC; + cred.TargetName = keyData; + cred.CredentialBlob = (LPBYTE)charData; + cred.CredentialBlobSize = sizeof(wchar_t) * data.size(); + cred.Persist = CRED_PERSIST_LOCAL_MACHINE; + + result = CredWriteW(&cred, 0); + delete[] charData; + } + delete[] keyData; + return result; +} + +QString getWindowsCredential(const QString key) +{ + QString result; + QString finalKey("ModOrganizer2_" + key); + wchar_t* keyData = new wchar_t[finalKey.size()+1]; + finalKey.toWCharArray(keyData); + keyData[finalKey.size()] = L'\0'; + PCREDENTIALW creds; + if (CredReadW(keyData, 1, 0, &creds)) { + wchar_t *charData = (wchar_t *)creds->CredentialBlob; + result = QString::fromWCharArray(charData, creds->CredentialBlobSize / sizeof(wchar_t)); + CredFree(creds); + } else { + const auto e = GetLastError(); + if (e != ERROR_NOT_FOUND) { + log::error("Retrieving encrypted data failed: {}", formatSystemMessage(e)); + } + } + delete[] keyData; + return result; +} + + Settings *Settings::s_Instance = nullptr; Settings::Settings(const QString& path) : m_Settings(path, QSettings::IniFormat), - m_Geometry(m_Settings), m_Colors(m_Settings), m_Plugins(m_Settings) + m_Game(m_Settings), m_Geometry(m_Settings), m_Widgets(m_Settings), + m_Colors(m_Settings), m_Plugins(m_Settings), m_Paths(m_Settings), + m_Network(m_Settings), m_Nexus(*this, m_Settings), m_Steam(*this, m_Settings), + m_Interface(m_Settings), m_Diagnostics(m_Settings) { if (s_Instance != nullptr) { throw std::runtime_error("second instance of \"Settings\" created"); } else { s_Instance = this; } - - MOBase::QuestionBoxMemory::setCallbacks( - [this](auto&& w, auto&& f){ return getQuestionButton(w, f); }, - [this](auto&& w, auto&& b){ setQuestionWindowButton(w, b); }, - [this](auto&& w, auto&& f, auto&& b){ setQuestionFileButton(w, f, b); }); } Settings::~Settings() @@ -488,7 +540,7 @@ Settings &Settings::instance() void Settings::processUpdates( const QVersionNumber& currentVersion, const QVersionNumber& lastVersion) { - if (getFirstStart()) { + if (firstStart()) { return; } @@ -523,1569 +575,1670 @@ void Settings::processUpdates( set(m_Settings, "General", "version", currentVersion.toString()); } -QString Settings::getFilename() const +QString Settings::filename() const { return m_Settings.fileName(); } -void Settings::registerAsNXMHandler(bool force) +bool Settings::usePrereleases() const { - const auto nxmPath = QCoreApplication::applicationDirPath() + "/nxmhandler.exe"; - const auto executable = QCoreApplication::applicationFilePath(); - - QString mode = force ? "forcereg" : "reg"; - QString parameters = mode + " " + m_GamePlugin->gameShortName(); - for (const QString& altGame : m_GamePlugin->validShortNames()) { - parameters += "," + altGame; - } - parameters += " \"" + executable + "\""; - - if (!shell::Execute(nxmPath, parameters)) { - QMessageBox::critical( - nullptr, tr("Failed"), tr("Failed to start the helper application")); - } + return get(m_Settings, "Settings", "use_prereleases", false); } -bool Settings::colorSeparatorScrollbar() const +void Settings::setUsePrereleases(bool b) { - return get(m_Settings, "Settings", "colorSeparatorScrollbars", true); + set(m_Settings, "Settings", "use_prereleases", b); } -void Settings::setColorSeparatorScrollbar(bool b) +std::optional Settings::version() const { - set(m_Settings, "Settings", "colorSeparatorScrollbars", b); + if (auto v=getOptional(m_Settings, "General", "version")) { + return QVersionNumber::fromString(*v).normalized(); + } + + return {}; } -void Settings::managedGameChanged(IPluginGame const *gamePlugin) +bool Settings::firstStart() const { - m_GamePlugin = gamePlugin; + return get(m_Settings, "General", "first_start", true); } -bool Settings::obfuscate(const QString key, const QString data) +void Settings::setFirstStart(bool b) { - QString finalKey("ModOrganizer2_" + key); - wchar_t* keyData = new wchar_t[finalKey.size()+1]; - finalKey.toWCharArray(keyData); - keyData[finalKey.size()] = L'\0'; - bool result = false; - if (data.isEmpty()) { - result = CredDeleteW(keyData, CRED_TYPE_GENERIC, 0); - if (!result) - if (GetLastError() == ERROR_NOT_FOUND) - result = true; - } else { - wchar_t* charData = new wchar_t[data.size()]; - data.toWCharArray(charData); + set(m_Settings, "General", "first_start", b); +} - CREDENTIALW cred = {}; - cred.Flags = 0; - cred.Type = CRED_TYPE_GENERIC; - cred.TargetName = keyData; - cred.CredentialBlob = (LPBYTE)charData; - cred.CredentialBlobSize = sizeof(wchar_t) * data.size(); - cred.Persist = CRED_PERSIST_LOCAL_MACHINE; +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" + ).join(";"); - result = CredWriteW(&cred, 0); - delete[] charData; - } - delete[] keyData; - return result; + return get(m_Settings, "Settings", "executable_blacklist", def); } -QString Settings::deObfuscate(const QString key) +void Settings::setExecutablesBlacklist(const QString& s) { - QString result; - QString finalKey("ModOrganizer2_" + key); - wchar_t* keyData = new wchar_t[finalKey.size()+1]; - finalKey.toWCharArray(keyData); - keyData[finalKey.size()] = L'\0'; - PCREDENTIALW creds; - if (CredReadW(keyData, 1, 0, &creds)) { - wchar_t *charData = (wchar_t *)creds->CredentialBlob; - result = QString::fromWCharArray(charData, creds->CredentialBlobSize / sizeof(wchar_t)); - CredFree(creds); - } else { - const auto e = GetLastError(); - if (e != ERROR_NOT_FOUND) { - log::error("Retrieving encrypted data failed: {}", formatSystemMessage(e)); - } - } - delete[] keyData; - return result; + set(m_Settings, "Settings", "executable_blacklist", s); } -QColor Settings::getIdealTextColor(const QColor& rBackgroundColor) +void Settings::setMotdHash(uint hash) { - if (rBackgroundColor.alpha() == 0) - return QColor(Qt::black); - - const int THRESHOLD = 106 * 255.0f / rBackgroundColor.alpha(); - int BackgroundDelta = (rBackgroundColor.red() * 0.299) + (rBackgroundColor.green() * 0.587) + (rBackgroundColor.blue() * 0.114); - return QColor((255 - BackgroundDelta <= THRESHOLD) ? Qt::black : Qt::white); + set(m_Settings, "General", "motd_hash", hash); } - -bool Settings::hideUncheckedPlugins() const +unsigned int Settings::motdHash() const { - return get(m_Settings, "Settings", "hide_unchecked_plugins", false); + return get(m_Settings, "General", "motd_hash", 0); } -void Settings::setHideUncheckedPlugins(bool b) +bool Settings::archiveParsing() const { - set(m_Settings, "Settings", "hide_unchecked_plugins", b); + return get(m_Settings, "Settings", "archive_parsing_experimental", false); } -bool Settings::forceEnableCoreFiles() const +void Settings::setArchiveParsing(bool b) { - return get(m_Settings, "Settings", "force_enable_core_files", true); + set(m_Settings, "Settings", "archive_parsing_experimental", b); } -void Settings::setForceEnableCoreFiles(bool b) +std::vector> Settings::executables() const { - set(m_Settings, "Settings", "force_enable_core_files", b); + ScopedReadArray sra(m_Settings, "customExecutables"); + std::vector> v; + + sra.for_each([&]{ + std::map map; + + for (auto&& key : sra.keys()) { + map[key] = m_Settings.value(key); + } + + v.push_back(map); + }); + + return v; } -bool Settings::lockGUI() const +void Settings::setExecutables(const std::vector>& v) { - return get(m_Settings, "Settings", "lock_gui", true); + removeSection(m_Settings, "customExecutables"); + + ScopedWriteArray swa(m_Settings, "customExecutables"); + + for (const auto& map : v) { + swa.next(); + + for (auto&& p : map) { + swa.set(p.first, p.second); + } + } } -void Settings::setLockGUI(bool b) +bool Settings::keepBackupOnInstall() const { - set(m_Settings, "Settings", "lock_gui", b); + return get(m_Settings, "General", "backup_install", false); } -bool Settings::automaticLoginEnabled() const +void Settings::setKeepBackupOnInstall(bool b) { - return get(m_Settings, "Settings", "nexus_login", false); + set(m_Settings, "General", "backup_install", b); } -QString Settings::getSteamAppID() const +GameSettings& Settings::game() { - return get(m_Settings, "Settings", "app_id", m_GamePlugin->steamAPPId()); + return m_Game; } -void Settings::setSteamAppID(const QString& id) +const GameSettings& Settings::game() const { - if (id.isEmpty()) { - remove(m_Settings, "Settings", "app_id"); - } else { - set(m_Settings, "Settings", "app_id", id); - } + return m_Game; } -bool Settings::usePrereleases() const +GeometrySettings& Settings::geometry() { - return get(m_Settings, "Settings", "use_prereleases", false); + return m_Geometry; } -void Settings::setUsePrereleases(bool b) +const GeometrySettings& Settings::geometry() const { - set(m_Settings, "Settings", "use_prereleases", b); + return m_Geometry; } -QString Settings::getConfigurablePath(const QString &key, - const QString &def, - bool resolve) const +WidgetSettings& Settings::widgets() { - QString result = QDir::fromNativeSeparators( - get(m_Settings, "Settings", key, QString("%BASE_DIR%/") + def)); - - if (resolve) { - result.replace("%BASE_DIR%", getBaseDirectory()); - } - - return result; + return m_Widgets; } -void Settings::setConfigurablePath(const QString &key, const QString& path) +const WidgetSettings& Settings::widgets() const { - if (path.isEmpty()) { - remove(m_Settings, "Settings", key); - } else { - set(m_Settings, "Settings", key, path); - } + return m_Widgets; } -QString Settings::getBaseDirectory() const +ColorSettings& Settings::colors() { - return QDir::fromNativeSeparators(get(m_Settings, - "Settings", "base_directory", qApp->property("dataPath").toString())); + return m_Colors; } -QString Settings::getDownloadDirectory(bool resolve) const +const ColorSettings& Settings::colors() const { - return getConfigurablePath( - "download_directory", - ToQString(AppConfig::downloadPath()), - resolve); + return m_Colors; } -QString Settings::getCacheDirectory(bool resolve) const +PluginSettings& Settings::plugins() { - return getConfigurablePath( - "cache_directory", - ToQString(AppConfig::cachePath()), - resolve); + return m_Plugins; } -QString Settings::getModDirectory(bool resolve) const +const PluginSettings& Settings::plugins() const { - return getConfigurablePath( - "mod_directory", - ToQString(AppConfig::modsPath()), - resolve); + return m_Plugins; } -QString Settings::getProfileDirectory(bool resolve) const +PathSettings& Settings::paths() { - return getConfigurablePath( - "profiles_directory", - ToQString(AppConfig::profilesPath()), - resolve); + return m_Paths; } -QString Settings::getOverwriteDirectory(bool resolve) const +const PathSettings& Settings::paths() const { - return getConfigurablePath( - "overwrite_directory", - ToQString(AppConfig::overwritePath()), - resolve); + return m_Paths; } -void Settings::setBaseDirectory(const QString& path) +NetworkSettings& Settings::network() { - if (path.isEmpty()) { - remove(m_Settings, "Settings", "base_directory"); - } else { - set(m_Settings, "Settings", "base_directory", path); - } + return m_Network; } -void Settings::setDownloadDirectory(const QString& path) +const NetworkSettings& Settings::network() const { - setConfigurablePath("download_directory", path); + return m_Network; } -void Settings::setModDirectory(const QString& path) +NexusSettings& Settings::nexus() { - setConfigurablePath("mod_directory", path); + return m_Nexus; } -void Settings::setCacheDirectory(const QString& path) +const NexusSettings& Settings::nexus() const { - setConfigurablePath("cache_directory", path); + return m_Nexus; } -void Settings::setProfileDirectory(const QString& path) +SteamSettings& Settings::steam() { - setConfigurablePath("profiles_directory", path); + return m_Steam; } -void Settings::setOverwriteDirectory(const QString& path) +const SteamSettings& Settings::steam() const { - setConfigurablePath("overwrite_directory", path); + return m_Steam; } -std::optional Settings::getManagedGameDirectory() const +InterfaceSettings& Settings::interface() { - if (auto v=getOptional(m_Settings, "General", "gamePath")) { - return QString::fromUtf8(*v); - } - - return {}; + return m_Interface; } -void Settings::setManagedGameDirectory(const QString& path) +const InterfaceSettings& Settings::interface() const { - set(m_Settings, "General", "gamePath", QDir::toNativeSeparators(path).toUtf8()); + return m_Interface; } -std::optional Settings::getManagedGameName() const +DiagnosticsSettings& Settings::diagnostics() { - return getOptional(m_Settings, "General", "gameName"); + return m_Diagnostics; } -void Settings::setManagedGameName(const QString& name) +const DiagnosticsSettings& Settings::diagnostics() const { - set(m_Settings, "General", "gameName", name); + return m_Diagnostics; } -std::optional Settings::getManagedGameEdition() const +QSettings::Status Settings::sync() const { - return getOptional(m_Settings, "General", "game_edition"); + m_Settings.sync(); + return m_Settings.status(); } -void Settings::setManagedGameEdition(const QString& name) +void Settings::dump() const { - set(m_Settings, "General", "game_edition", name); -} + static const QStringList ignore({ + "username", "password", "nexus_api_key" + }); -std::optional Settings::getSelectedProfileName() const -{ - if (auto v=getOptional(m_Settings, "General", "selected_profile")) { - return QString::fromUtf8(*v); + log::debug("settings:"); + + { + ScopedGroup sg(m_Settings, "Settings"); + + for (auto k : m_Settings.allKeys()) { + if (ignore.contains(k, Qt::CaseInsensitive)) { + continue; + } + + log::debug(" . {}={}", k, m_Settings.value(k).toString()); + } } - return {}; + m_Network.dump(); } -void Settings::setSelectedProfileName(const QString& name) +void Settings::managedGameChanged(IPluginGame const *gamePlugin) { - set(m_Settings, "General", "selected_profile", name.toUtf8()); + m_Game.setPlugin(gamePlugin); } -std::optional Settings::getStyleName() const + +GameSettings::GameSettings(QSettings& settings) + : m_Settings(settings), m_GamePlugin(nullptr) { - return getOptional(m_Settings, "Settings", "style"); } -void Settings::setStyleName(const QString& name) +const MOBase::IPluginGame* GameSettings::plugin() { - set(m_Settings, "Settings", "style", name); + return m_GamePlugin; } -bool Settings::getUseProxy() const +void GameSettings::setPlugin(const MOBase::IPluginGame* gamePlugin) { - return get(m_Settings, "Settings", "use_proxy", false); + m_GamePlugin = gamePlugin; } -void Settings::setUseProxy(bool b) +bool GameSettings::forceEnableCoreFiles() const { - set(m_Settings, "Settings", "use_proxy", b); + return get(m_Settings, "Settings", "force_enable_core_files", true); } -std::optional Settings::getVersion() const +void GameSettings::setForceEnableCoreFiles(bool b) { - if (auto v=getOptional(m_Settings, "General", "version")) { - return QVersionNumber::fromString(*v).normalized(); - } - - return {}; + set(m_Settings, "Settings", "force_enable_core_files", b); } -bool Settings::getFirstStart() const +std::optional GameSettings::directory() const { - return get(m_Settings, "General", "first_start", true); + if (auto v=getOptional(m_Settings, "General", "gamePath")) { + return QString::fromUtf8(*v); + } + + return {}; } -void Settings::setFirstStart(bool b) +void GameSettings::setDirectory(const QString& path) { - set(m_Settings, "General", "first_start", b); + set(m_Settings, "General", "gamePath", QDir::toNativeSeparators(path).toUtf8()); } -std::optional Settings::getPreviousSeparatorColor() const +std::optional GameSettings::name() const { - const auto c = getOptional(m_Settings, "General", "previousSeparatorColor"); - if (c && c->isValid()) { - return c; - } - - return {}; + return getOptional(m_Settings, "General", "gameName"); } -void Settings::setPreviousSeparatorColor(const QColor& c) const +void GameSettings::setName(const QString& name) { - set(m_Settings, "General", "previousSeparatorColor", c); + set(m_Settings, "General", "gameName", name); } -void Settings::removePreviousSeparatorColor() +std::optional GameSettings::edition() const { - remove(m_Settings, "General", "previousSeparatorColor"); + return getOptional(m_Settings, "General", "game_edition"); } -bool Settings::getNexusApiKey(QString &apiKey) const +void GameSettings::setEdition(const QString& name) { - QString tempKey = deObfuscate("APIKEY"); - if (tempKey.isEmpty()) - return false; - - apiKey = tempKey; - return true; + set(m_Settings, "General", "game_edition", name); } -bool Settings::setNexusApiKey(const QString& apiKey) +std::optional GameSettings::selectedProfileName() const { - if (!obfuscate("APIKEY", apiKey)) { - const auto e = GetLastError(); - log::error("Storing API key failed: {}", formatSystemMessage(e)); - return false; + if (auto v=getOptional(m_Settings, "General", "selected_profile")) { + return QString::fromUtf8(*v); } - return true; + return {}; } -bool Settings::clearNexusApiKey() +void GameSettings::setSelectedProfileName(const QString& name) { - return setNexusApiKey(""); + set(m_Settings, "General", "selected_profile", name.toUtf8()); } -bool Settings::hasNexusApiKey() const +LoadMechanism::EMechanism GameSettings::loadMechanismType() const { - return !deObfuscate("APIKEY").isEmpty(); -} + const auto def = LoadMechanism::LOAD_MODORGANIZER; -bool Settings::getSteamLogin(QString &username, QString &password) const -{ - username = get(m_Settings, "Settings", "steam_username", ""); - password = deObfuscate("steam_password"); + const auto i = get(m_Settings, + "Settings", "load_mechanism", def); - return !username.isEmpty() && !password.isEmpty(); -} + switch (i) + { + // ok + case LoadMechanism::LOAD_MODORGANIZER: // fall-through + { + break; + } -bool Settings::compactDownloads() const -{ - return get(m_Settings, "Settings", "compact_downloads", false); -} + default: + { + log::error( + "invalid load mechanism {}, reverting to {}", + static_cast(i), toString(def)); -void Settings::setCompactDownloads(bool b) -{ - set(m_Settings, "Settings", "compact_downloads", b); -} + set(m_Settings, "Settings", "load_mechanism", def); -bool Settings::metaDownloads() const -{ - return get(m_Settings, "Settings", "meta_downloads", false); -} + return def; + } + } -void Settings::setMetaDownloads(bool b) -{ - set(m_Settings, "Settings", "meta_downloads", b); + return i; } -bool Settings::offlineMode() const +void GameSettings::setLoadMechanism(LoadMechanism::EMechanism m) { - return get(m_Settings, "Settings/offline_mode", false); + set(m_Settings, "Settings", "load_mechanism", m); } -void Settings::setOfflineMode(bool b) +const LoadMechanism& GameSettings::loadMechanism() const { - set(m_Settings, "Settings", "offline_mode", b); + return m_LoadMechanism; } -log::Levels Settings::logLevel() const +void GameSettings::setupLoadMechanism() { - return get(m_Settings, "Settings", "log_level", log::Levels::Info); + m_LoadMechanism.activate(loadMechanismType()); } -void Settings::setLogLevel(log::Levels level) +bool GameSettings::hideUncheckedPlugins() const { - set(m_Settings, "Settings", "log_level", level); + return get(m_Settings, "Settings", "hide_unchecked_plugins", false); } -CrashDumpsType Settings::crashDumpsType() const +void GameSettings::setHideUncheckedPlugins(bool b) { - return get(m_Settings, - "Settings", "crash_dumps_type", CrashDumpsType::Mini); + set(m_Settings, "Settings", "hide_unchecked_plugins", b); } -void Settings::setCrashDumpsType(CrashDumpsType type) -{ - set(m_Settings, "Settings", "crash_dumps_type", type); -} -int Settings::crashDumpsMax() const +GeometrySettings::GeometrySettings(QSettings& s) + : m_Settings(s), m_Reset(false) { - return get(m_Settings, "Settings", "crash_dumps_max", 5); } -void Settings::setCrashDumpsMax(int n) +void GeometrySettings::requestReset() { - set(m_Settings, "Settings", "crash_dumps_max", n); + m_Reset = true; } -QString Settings::executablesBlacklist() const +void GeometrySettings::resetIfNeeded() { - static const QString def = (QStringList() - << "Chrome.exe" - << "Firefox.exe" - << "TSVNCache.exe" - << "TGitCache.exe" - << "Steam.exe" - << "GameOverlayUI.exe" - << "Discord.exe" - << "GalaxyClient.exe" - << "Spotify.exe" - ).join(";"); + if (!m_Reset) { + return; + } - return get(m_Settings, "Settings", "executable_blacklist", def); + removeSection(m_Settings, "Geometry"); } -void Settings::setExecutablesBlacklist(const QString& s) +void GeometrySettings::saveGeometry(const QWidget* w) { - set(m_Settings, "Settings", "executable_blacklist", s); + set(m_Settings, "Geometry", geoSettingName(w), w->saveGeometry()); } -void Settings::setSteamLogin(QString username, QString password) +bool GeometrySettings::restoreGeometry(QWidget* w) const { - if (username == "") { - remove(m_Settings, "Settings", "steam_username"); - password = ""; - } else { - set(m_Settings, "Settings", "steam_username", username); + if (auto v=getOptional(m_Settings, "Geometry", geoSettingName(w))) { + w->restoreGeometry(*v); + return true; } - if (!obfuscate("steam_password", password)) { - const auto e = GetLastError(); - log::error("Storing or deleting password failed: {}", formatSystemMessage(e)); - } + return false; } -LoadMechanism::EMechanism Settings::getLoadMechanism() const +void GeometrySettings::saveState(const QMainWindow* w) { - const auto def = LoadMechanism::LOAD_MODORGANIZER; - - const auto i = get(m_Settings, - "Settings", "load_mechanism", def); - - switch (i) - { - // ok - case LoadMechanism::LOAD_MODORGANIZER: // fall-through - { - break; - } - - default: - { - log::error( - "invalid load mechanism {}, reverting to {}", - static_cast(i), toString(def)); - - set(m_Settings, "Settings", "load_mechanism", def); - - return def; - } - } - - return i; + set(m_Settings, "Geometry", stateSettingName(w), w->saveState()); } -void Settings::setLoadMechanism(LoadMechanism::EMechanism m) +bool GeometrySettings::restoreState(QMainWindow* w) const { - set(m_Settings, "Settings", "load_mechanism", m); -} + if (auto v=getOptional(m_Settings, "Geometry", stateSettingName(w))) { + w->restoreState(*v); + return true; + } -void Settings::setupLoadMechanism() -{ - m_LoadMechanism.activate(getLoadMechanism()); + return false; } -bool Settings::endorsementIntegration() const +void GeometrySettings::saveState(const QHeaderView* w) { - return get(m_Settings, "Settings", "endorsement_integration", true); + set(m_Settings, "Geometry", stateSettingName(w), w->saveState()); } -void Settings::setEndorsementIntegration(bool b) const +bool GeometrySettings::restoreState(QHeaderView* w) const { - set(m_Settings, "Settings", "endorsement_integration", b); + if (auto v=getOptional(m_Settings, "Geometry", stateSettingName(w))) { + w->restoreState(*v); + return true; + } + + return false; } -EndorsementState Settings::endorsementState() const +void GeometrySettings::saveState(const QSplitter* w) { - return endorsementStateFromString( - get(m_Settings, "General", "endorse_state", "")); + set(m_Settings, "Geometry", stateSettingName(w), w->saveState()); } -void Settings::setEndorsementState(EndorsementState s) +bool GeometrySettings::restoreState(QSplitter* w) const { - const auto v = toString(s); - - if (v.isEmpty()) { - remove(m_Settings, "General", "endorse_state"); - } else { - set(m_Settings, "General", "endorse_state", v); + if (auto v=getOptional(m_Settings, "Geometry", stateSettingName(w))) { + w->restoreState(*v); + return true; } -} -bool Settings::hideAPICounter() const -{ - return get(m_Settings, "Settings", "hide_api_counter", false); + return false; } -void Settings::setHideAPICounter(bool b) +void GeometrySettings::saveState(const ExpanderWidget* expander) { - set(m_Settings, "Settings", "hide_api_counter", b); + set(m_Settings, "Geometry", stateSettingName(expander), expander->saveState()); } -bool Settings::displayForeign() const +bool GeometrySettings::restoreState(ExpanderWidget* expander) const { - return get(m_Settings, "Settings", "display_foreign", true); -} + if (auto v=getOptional(m_Settings, "Geometry", stateSettingName(expander))) { + expander->restoreState(*v); + return true; + } -void Settings::setDisplayForeign(bool b) -{ - set(m_Settings, "Settings", "display_foreign", b); + return false; } -void Settings::setMotDHash(uint hash) +void GeometrySettings::saveVisibility(const QWidget* w) { - set(m_Settings, "General", "motd_hash", hash); + set(m_Settings, "Geometry", visibilitySettingName(w), w->isVisible()); } -unsigned int Settings::getMotDHash() const +bool GeometrySettings::restoreVisibility(QWidget* w, std::optional def) const { - return get(m_Settings, "motd_hash", 0); -} + if (auto v=getOptional(m_Settings, "Geometry", visibilitySettingName(w), def)) { + w->setVisible(*v); + return true; + } -bool Settings::archiveParsing() const -{ - return get(m_Settings, "Settings", "archive_parsing_experimental", false); + return false; } -void Settings::setArchiveParsing(bool b) +void GeometrySettings::restoreToolbars(QMainWindow* w) const { - set(m_Settings, "Settings", "archive_parsing_experimental", b); -} + // all toolbars have the same size and button style settings + const auto size = getOptional(m_Settings, "Geometry", "toolbar_size"); + const auto style = getOptional(m_Settings, "Geometry", "toolbar_button_style"); -QString Settings::language() + for (auto* tb : w->findChildren()) { + if (size) { + tb->setIconSize(*size); + } + + if (style) { + tb->setToolButtonStyle(static_cast(*style)); + } + + restoreVisibility(tb); + } +} + +void GeometrySettings::saveToolbars(const QMainWindow* w) { - QString result = get(m_Settings, "Settings", "language", ""); + const auto tbs = w->findChildren(); - if (result.isEmpty()) { - QStringList languagePreferences = QLocale::system().uiLanguages(); + // save visibility for all + for (auto* tb : tbs) { + saveVisibility(tb); + } - if (languagePreferences.length() > 0) { - // the users most favoritest language - result = languagePreferences.at(0); - } else { - // fallback system locale - result = QLocale::system().name(); + // all toolbars have the same size and button style settings, just save the + // first one + if (!tbs.isEmpty()) { + const auto* tb = tbs[0]; + + set(m_Settings, "Geometry", "toolbar_size", tb->iconSize()); + set(m_Settings, "Geometry", "toolbar_button_style", static_cast(tb->toolButtonStyle())); + } +} + +QStringList GeometrySettings::modInfoTabOrder() const +{ + QStringList v; + + if (m_Settings.contains("mod_info_tabs")) { + // old byte array from 2.2.0 + QDataStream stream(m_Settings.value("mod_info_tabs").toByteArray()); + + int count = 0; + stream >> count; + + for (int i=0; i> s; + v.push_back(s); + } + } else { + // string list since 2.2.1 + QString string = m_Settings.value("mod_info_tab_order").toString(); + QTextStream stream(&string); + + while (!stream.atEnd()) { + QString s; + stream >> s; + v.push_back(s); } } - return result; + return v; } -void Settings::setLanguage(const QString& name) +void GeometrySettings::setModInfoTabOrder(const QString& names) { - set(m_Settings, "Settings", "language", name); + set(m_Settings, "Geometry", "mod_info_tab_order", names); } -void Settings::setDownloadSpeed(const QString& name, int bytesPerSecond) +void GeometrySettings::centerOnMainWindowMonitor(QWidget* w) { - auto servers = getServers(); + const auto monitor = getOptional( + m_Settings, "Geometry", "MainWindow_monitor"); - for (auto& server : servers) { - if (server.name() == name) { - server.addDownload(bytesPerSecond); - updateServers(servers); - return; + QPoint center; + + if (monitor && QGuiApplication::screens().size() > *monitor) { + center = QGuiApplication::screens().at(*monitor)->geometry().center(); + } else { + center = QGuiApplication::primaryScreen()->geometry().center(); + } + + w->move(center - w->rect().center()); +} + +void GeometrySettings::saveMainWindowMonitor(const QMainWindow* w) +{ + if (auto* handle=w->windowHandle()) { + if (auto* screen = handle->screen()) { + const int screenId = QGuiApplication::screens().indexOf(screen); + set(m_Settings, "Geometry", "MainWindow_monitor", screenId); } } +} - log::error( - "server '{}' not found while trying to add a download with bps {}", - name, bytesPerSecond); +Qt::Orientation dockOrientation(const QMainWindow* mw, const QDockWidget* d) +{ + // docks in these areas are horizontal + const auto horizontalAreas = + Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea; + + if (mw->dockWidgetArea(const_cast(d)) & horizontalAreas) { + return Qt::Horizontal; + } else { + return Qt::Vertical; + } } -ServerList Settings::getServers() const +void GeometrySettings::saveDocks(const QMainWindow* mw) { - // servers used to be a map of byte arrays until 2.2.1, it's now an array of - // individual values instead + // this attempts to fix https://bugreports.qt.io/browse/QTBUG-46620 where dock + // sizes are not restored when the main window is maximized; it is used in + // MainWindow::readSettings() and MainWindow::storeSettings() + // + // there's also https://stackoverflow.com/questions/44005852, which has what + // seems to be a popular fix, but it breaks the restored size of the window + // by setting it to the desktop's resolution, so that doesn't work + // + // the only fix I could find is to remember the sizes of the docks and manually + // setting them back; saving is straightforward, but restoring is messy + // + // this also depends on the window being visible before the timer in restore() + // is fired and the timer must be processed by application.exec(); therefore, + // the splash screen _must_ be closed before readSettings() is called, because + // it has its own event loop, which seems to interfere with this + // + // all of this should become unnecessary when QTBUG-46620 is fixed // - // so post 2.2.1, only one key is returned: "size", the size of the arrays; - // in 2.2.1, one key per server is returned - { - const QStringList keys = ScopedGroup(m_Settings, "Servers").keys(); - if (!keys.empty() && keys[0] != "size") { - // old format - return getServersFromOldMap(); + // saves the size of each dock + for (const auto* dock : mw->findChildren()) { + int size = 0; + + // save the width for horizontal docks, or the height for vertical + if (dockOrientation(mw, dock) == Qt::Horizontal) { + size = dock->size().width(); + } else { + size = dock->size().height(); } + + set(m_Settings, "Geometry", dockSettingName(dock), size); } +} +void GeometrySettings::restoreDocks(QMainWindow* mw) const +{ + struct DockInfo + { + QDockWidget* d; + int size = 0; + Qt::Orientation ori; + }; - // post 2.2.1 format, array of values + std::vector dockInfos; - ServerList list; + // for each dock + for (auto* dock : mw->findChildren()) { + if (auto size=getOptional(m_Settings, "Geometry", dockSettingName(dock))) { + // remember this dock, its size and orientation + dockInfos.push_back({dock, *size, dockOrientation(mw, dock)}); + } + } - { - ScopedReadArray sra(m_Settings, "Servers"); + // the main window must have had time to process the settings from + // readSettings() or it seems to override whatever is set here + // + // some people said a single processEvents() call is enough, but it doesn't + // look like it + QTimer::singleShot(5, [=] { + for (const auto& info : dockInfos) { + mw->resizeDocks({info.d}, {info.size}, info.ori); + } + }); +} - sra.for_each([&] { - ServerInfo::SpeedList lastDownloads; - const auto lastDownloadsString = sra.get("lastDownloads", ""); +WidgetSettings::WidgetSettings(QSettings& s) + : m_Settings(s) +{ + 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); }); +} - for (const auto& s : lastDownloadsString.split(" ")) { - const auto bytesPerSecond = s.toInt(); - if (bytesPerSecond > 0) { - lastDownloads.push_back(bytesPerSecond); - } - } +std::optional WidgetSettings::index(const QComboBox* cb) const +{ + return getOptional(m_Settings, "Widgets", indexSettingName(cb)); +} - ServerInfo server( - sra.get("name", ""), - sra.get("premium", false), - QDate::fromString(sra.get("lastSeen", ""), Qt::ISODate), - sra.get("preferred", 0), - lastDownloads); +void WidgetSettings::saveIndex(const QComboBox* cb) +{ + set(m_Settings, "Widgets", indexSettingName(cb), cb->currentIndex()); +} - list.add(std::move(server)); - }); +void WidgetSettings::restoreIndex(QComboBox* cb, std::optional def) const +{ + if (auto v=getOptional(m_Settings, "Widgets", indexSettingName(cb), def)) { + cb->setCurrentIndex(*v); } - - return list; } -ServerList Settings::getServersFromOldMap() const +std::optional WidgetSettings::index(const QTabWidget* w) const { - // for 2.2.1 and before + return getOptional(m_Settings, "Widgets", indexSettingName(w)); +} - ServerList list; - const ScopedGroup sg(m_Settings, "Servers"); +void WidgetSettings::saveIndex(const QTabWidget* w) +{ + set(m_Settings, "Widgets", indexSettingName(w), w->currentIndex()); +} - sg.for_each([&](auto&& serverKey) { - QVariantMap data = sg.get(serverKey); +void WidgetSettings::restoreIndex(QTabWidget* w, std::optional def) const +{ + if (auto v=getOptional(m_Settings, "Widgets", indexSettingName(w), def)) { + w->setCurrentIndex(*v); + } +} - ServerInfo server( - serverKey, - data["premium"].toBool(), - data["lastSeen"].toDate(), - data["preferred"].toInt(), - {}); +std::optional WidgetSettings::checked(const QAbstractButton* w) const +{ + warnIfNotCheckable(w); + return getOptional(m_Settings, "Widgets", checkedSettingName(w)); +} - // ignoring download count and speed, it's now a list of values instead of - // a total +void WidgetSettings::saveChecked(const QAbstractButton* w) +{ + warnIfNotCheckable(w); + set(m_Settings, "Widgets", checkedSettingName(w), w->isChecked()); +} - list.add(std::move(server)); - }); +void WidgetSettings::restoreChecked(QAbstractButton* w, std::optional def) const +{ + warnIfNotCheckable(w); - return list; + if (auto v=getOptional(m_Settings, "Widgets", checkedSettingName(w), def)) { + w->setChecked(*v); + } } -void Settings::updateServers(ServerList servers) +QuestionBoxMemory::Button WidgetSettings::questionButton( + const QString& windowName, const QString& filename) const { - // clean up unavailable servers - servers.cleanup(); - - removeSection(m_Settings, "Servers"); + const QString sectionName("DialogChoices"); - { - ScopedWriteArray swa(m_Settings, "Servers"); + if (!filename.isEmpty()) { + const auto fileSetting = windowName + "/" + filename; + if (auto v=getOptional(m_Settings, sectionName, filename)) { + return static_cast(*v); + } + } - for (const auto& server : servers) { - swa.next(); + if (auto v=getOptional(m_Settings, sectionName, windowName)) { + return static_cast(*v); + } - swa.set("name", server.name()); - swa.set("premium", server.isPremium()); - swa.set("lastSeen", server.lastSeen().toString(Qt::ISODate)); - swa.set("preferred", server.preferred()); + return QuestionBoxMemory::NoButton; +} - QString lastDownloads; - for (const auto& speed : server.lastDownloads()) { - if (speed > 0) { - lastDownloads += QString("%1 ").arg(speed); - } - } +void WidgetSettings::setQuestionWindowButton( + const QString& windowName, QuestionBoxMemory::Button button) +{ + const QString sectionName("DialogChoices"); - swa.set("lastDownloads", lastDownloads.trimmed()); - } + if (button == QuestionBoxMemory::NoButton) { + remove(m_Settings, sectionName, windowName); + } else { + set(m_Settings, sectionName, windowName, button); } } -std::map Settings::getRecentDirectories() const +void WidgetSettings::setQuestionFileButton( + const QString& windowName, const QString& filename, + QuestionBoxMemory::Button button) { - std::map map; + const QString sectionName("DialogChoices"); + const QString settingName(windowName + "/" + filename); - ScopedReadArray sra(m_Settings, "RecentDirectories"); + if (button == QuestionBoxMemory::NoButton) { + remove(m_Settings, sectionName, settingName); + } else { + set(m_Settings, sectionName, settingName, button); + } +} - sra.for_each([&] { - const QVariant name = sra.get("name"); - const QVariant dir = sra.get("directory"); +void WidgetSettings::resetQuestionButtons() +{ + removeSection(m_Settings, "DialogChoices"); +} - if (name.isValid() && dir.isValid()) { - map.emplace(name.toString(), dir.toString()); - } - }); - return map; +ColorSettings::ColorSettings(QSettings& s) + : m_Settings(s) +{ } -void Settings::setRecentDirectories(const std::map& map) +QColor ColorSettings::modlistOverwrittenLoose() const { - removeSection(m_Settings, "RecentDirectories"); + return get( + m_Settings, "Settings", "overwrittenLooseFilesColor", + QColor(0, 255, 0, 64)); +} - ScopedWriteArray swa(m_Settings, "recentDirectories"); +void ColorSettings::setModlistOverwrittenLoose(const QColor& c) +{ + set(m_Settings, "Settings", "overwrittenLooseFilesColor", c); +} - for (auto&& p : map) { - swa.next(); +QColor ColorSettings::modlistOverwritingLoose() const +{ + return get( + m_Settings, "Settings", "overwritingLooseFilesColor", + QColor(255, 0, 0, 64)); +} - swa.set("name", p.first); - swa.set("directory", p.second); - } +void ColorSettings::setModlistOverwritingLoose(const QColor& c) +{ + set(m_Settings, "Settings", "overwritingLooseFilesColor", c); } -std::vector> Settings::getExecutables() const +QColor ColorSettings::modlistOverwrittenArchive() const { - ScopedReadArray sra(m_Settings, "customExecutables"); - std::vector> v; + return get( + m_Settings, "Settings", "overwrittenArchiveFilesColor", + QColor(0, 255, 255, 64)); +} - sra.for_each([&]{ - std::map map; +void ColorSettings::setModlistOverwrittenArchive(const QColor& c) +{ + set(m_Settings, "Settings", "overwrittenArchiveFilesColor", c); +} - for (auto&& key : sra.keys()) { - map[key] = m_Settings.value(key); - } +QColor ColorSettings::modlistOverwritingArchive() const +{ + return get( + m_Settings, "Settings", "overwritingArchiveFilesColor", + QColor(255, 0, 255, 64)); +} - v.push_back(map); - }); +void ColorSettings::setModlistOverwritingArchive(const QColor& c) +{ + set(m_Settings, "Settings", "overwritingArchiveFilesColor", c); +} - return v; +QColor ColorSettings::modlistContainsPlugin() const +{ + return get( + m_Settings, "Settings", "containsPluginColor", + QColor(0, 0, 255, 64)); } -void Settings::setExecutables(const std::vector>& v) +void ColorSettings::setModlistContainsPlugin(const QColor& c) { - removeSection(m_Settings, "customExecutables"); + set(m_Settings, "Settings", "containsPluginColor", c); +} - ScopedWriteArray swa(m_Settings, "customExecutables"); +QColor ColorSettings::pluginListContained() const +{ + return get( + m_Settings, "Settings", "containedColor", + QColor(0, 0, 255, 64)); +} - for (const auto& map : v) { - swa.next(); +void ColorSettings::setPluginListContained(const QColor& c) +{ + set(m_Settings, "Settings", "containedColor", c); +} - for (auto&& p : map) { - swa.set(p.first, p.second); - } +std::optional ColorSettings::previousSeparatorColor() const +{ + const auto c = getOptional(m_Settings, "General", "previousSeparatorColor"); + if (c && c->isValid()) { + return c; } + + return {}; } -bool Settings::isTutorialCompleted(const QString& windowName) const +void ColorSettings::setPreviousSeparatorColor(const QColor& c) const { - return get(m_Settings, "CompletedWindowTutorials", windowName, false); + set(m_Settings, "General", "previousSeparatorColor", c); } -void Settings::setTutorialCompleted(const QString& windowName, bool b) +void ColorSettings::removePreviousSeparatorColor() { - set(m_Settings, "CompletedWindowTutorials", windowName, b); + remove(m_Settings, "General", "previousSeparatorColor"); } -bool Settings::keepBackupOnInstall() const +bool ColorSettings::colorSeparatorScrollbar() const { - return get(m_Settings, "backup_install", false); + return get(m_Settings, "Settings", "colorSeparatorScrollbars", true); } -void Settings::setKeepBackupOnInstall(bool b) +void ColorSettings::setColorSeparatorScrollbar(bool b) { - set(m_Settings, "General", "backup_install", b); + set(m_Settings, "Settings", "colorSeparatorScrollbars", b); } -QuestionBoxMemory::Button Settings::getQuestionButton( - const QString& windowName, const QString& filename) const +QColor ColorSettings::idealTextColor(const QColor& rBackgroundColor) { - const QString sectionName("DialogChoices"); + if (rBackgroundColor.alpha() == 0) + return QColor(Qt::black); - if (!filename.isEmpty()) { - const auto fileSetting = windowName + "/" + filename; - if (auto v=getOptional(m_Settings, sectionName, filename)) { - return static_cast(*v); + const int THRESHOLD = 106 * 255.0f / rBackgroundColor.alpha(); + int BackgroundDelta = (rBackgroundColor.red() * 0.299) + (rBackgroundColor.green() * 0.587) + (rBackgroundColor.blue() * 0.114); + return QColor((255 - BackgroundDelta <= THRESHOLD) ? Qt::black : Qt::white); +} + + + +PluginSettings::PluginSettings(QSettings& settings) + : m_Settings(settings) +{ +} + +void PluginSettings::clearPlugins() +{ + m_Plugins.clear(); + m_PluginSettings.clear(); + + m_PluginBlacklist.clear(); + + ScopedReadArray sra(m_Settings, "pluginBlacklist"); + sra.for_each([&]{ + m_PluginBlacklist.insert(sra.get("name")); + }); +} + +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()) { + const QString settingName = plugin->name() + "/" + setting.key; + + QVariant temp = get( + m_Settings, "Plugins", settingName, setting.defaultValue); + + 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; } - } - if (auto v=getOptional(m_Settings, sectionName, windowName)) { - return static_cast(*v); + m_PluginSettings[plugin->name()][setting.key] = temp; + + m_PluginDescriptions[plugin->name()][setting.key] = QString("%1 (default: %2)") + .arg(setting.description) + .arg(setting.defaultValue.toString()); } +} - return QuestionBoxMemory::NoButton; +bool PluginSettings::pluginBlacklisted(const QString &fileName) const +{ + return m_PluginBlacklist.contains(fileName); } -void Settings::setQuestionWindowButton( - const QString& windowName, QuestionBoxMemory::Button button) +QVariant PluginSettings::pluginSetting(const QString &pluginName, const QString &key) const { - const QString sectionName("DialogChoices/"); + auto iterPlugin = m_PluginSettings.find(pluginName); + if (iterPlugin == m_PluginSettings.end()) { + return QVariant(); + } - if (button == QuestionBoxMemory::NoButton) { - remove(m_Settings, sectionName, windowName); - } else { - set(m_Settings, sectionName, windowName, button); + auto iterSetting = iterPlugin->find(key); + if (iterSetting == iterPlugin->end()) { + return QVariant(); } + + return *iterSetting; } -void Settings::setQuestionFileButton( - const QString& windowName, const QString& filename, - QuestionBoxMemory::Button button) +void PluginSettings::setPluginSetting(const QString &pluginName, const QString &key, const QVariant &value) { - const QString sectionName("DialogChoices"); - const QString settingName(windowName + "/" + filename); + auto iterPlugin = m_PluginSettings.find(pluginName); - if (button == QuestionBoxMemory::NoButton) { - remove(m_Settings, sectionName, settingName); - } else { - set(m_Settings, sectionName, settingName, button); + if (iterPlugin == m_PluginSettings.end()) { + throw MyException( + QObject::tr("attempt to store setting for unknown plugin \"%1\"") + .arg(pluginName)); } + + // store the new setting both in memory and in the ini + m_PluginSettings[pluginName][key] = value; + set(m_Settings, "Plugins", pluginName + "/" + key, value); } -void Settings::resetQuestionButtons() +QVariant PluginSettings::pluginPersistent(const QString &pluginName, const QString &key, const QVariant &def) const { - removeSection(m_Settings, "DialogChoices"); + if (!m_PluginSettings.contains(pluginName)) { + return def; + } + + return get(m_Settings, "PluginPersistance", pluginName + "/" + key, def); } -std::optional Settings::getIndex(const QComboBox* cb) const +void PluginSettings::setPluginPersistent( + const QString &pluginName, const QString &key, const QVariant &value, bool sync) { - return getOptional(m_Settings, "Widgets", indexSettingName(cb)); + if (!m_PluginSettings.contains(pluginName)) { + throw MyException( + QObject::tr("attempt to store setting for unknown plugin \"%1\"") + .arg(pluginName)); + } + + set(m_Settings, "PluginPersistance", pluginName + "/" + key, value); + + if (sync) { + m_Settings.sync(); + } } -void Settings::saveIndex(const QComboBox* cb) +void PluginSettings::addBlacklistPlugin(const QString &fileName) { - set(m_Settings, "Widgets", indexSettingName(cb), cb->currentIndex()); + m_PluginBlacklist.insert(fileName); + writePluginBlacklist(); } -void Settings::restoreIndex(QComboBox* cb, std::optional def) const +void PluginSettings::writePluginBlacklist() { - if (auto v=getOptional(m_Settings, "Widgets", indexSettingName(cb), def)) { - cb->setCurrentIndex(*v); + removeSection(m_Settings, "PluginBlacklist"); + + ScopedWriteArray swa(m_Settings, "PluginBlacklist"); + + for (const QString &plugin : m_PluginBlacklist) { + swa.next(); + swa.set("name", plugin); } } -std::optional Settings::getIndex(const QTabWidget* w) const +QVariantMap PluginSettings::pluginSettings(const QString &pluginName) const { - return getOptional(m_Settings, "Widgets", indexSettingName(w)); + return m_PluginSettings[pluginName]; } -void Settings::saveIndex(const QTabWidget* w) +void PluginSettings::setPluginSettings(const QString &pluginName, const QVariantMap& map) { - set(m_Settings, "Widgets", indexSettingName(w), w->currentIndex()); + m_PluginSettings[pluginName] = map; } -void Settings::restoreIndex(QTabWidget* w, std::optional def) const +QVariantMap PluginSettings::pluginDescriptions(const QString &pluginName) const { - if (auto v=getOptional(m_Settings, "Widgets", indexSettingName(w), def)) { - w->setCurrentIndex(*v); - } + return m_PluginDescriptions[pluginName]; } -std::optional Settings::getChecked(const QAbstractButton* w) const +void PluginSettings::pluginDescriptions(const QString &pluginName, const QVariantMap& map) { - warnIfNotCheckable(w); - return getOptional(m_Settings, "Widgets", checkedSettingName(w)); + m_PluginDescriptions[pluginName] = map; } -void Settings::saveChecked(const QAbstractButton* w) +const QSet& PluginSettings::pluginBlacklist() const { - warnIfNotCheckable(w); - set(m_Settings, "Widgets", checkedSettingName(w), w->isChecked()); + return m_PluginBlacklist; } -void Settings::restoreChecked(QAbstractButton* w, std::optional def) const +void PluginSettings::setPluginBlacklist(const QStringList& pluginNames) { - warnIfNotCheckable(w); + m_PluginBlacklist.clear(); - if (auto v=getOptional(m_Settings, "Widgets", checkedSettingName(w), def)) { - w->setChecked(*v); + for (const auto& name : pluginNames) { + m_PluginBlacklist.insert(name); } } -GeometrySettings& Settings::geometry() +void PluginSettings::save() { - return m_Geometry; -} + 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()); + } + } -const GeometrySettings& Settings::geometry() const -{ - return m_Geometry; + writePluginBlacklist(); } -ColorSettings& Settings::colors() -{ - return m_Colors; -} -const ColorSettings& Settings::colors() const +PathSettings::PathSettings(QSettings& settings) + : m_Settings(settings) { - return m_Colors; } -PluginSettings& Settings::plugins() +std::map PathSettings::recent() const { - return m_Plugins; -} + std::map map; -const PluginSettings& Settings::plugins() const -{ - return m_Plugins; -} + ScopedReadArray sra(m_Settings, "RecentDirectories"); -QSettings::Status Settings::sync() const -{ - m_Settings.sync(); - return m_Settings.status(); -} + sra.for_each([&] { + const QVariant name = sra.get("name"); + const QVariant dir = sra.get("directory"); -void Settings::dump() const -{ - static const QStringList ignore({ - "username", "password", "nexus_api_key" + if (name.isValid() && dir.isValid()) { + map.emplace(name.toString(), dir.toString()); + } }); - log::debug("settings:"); + return map; +} - { - ScopedGroup sg(m_Settings, "Settings"); +void PathSettings::setRecent(const std::map& map) +{ + removeSection(m_Settings, "RecentDirectories"); - for (auto k : m_Settings.allKeys()) { - if (ignore.contains(k, Qt::CaseInsensitive)) { - continue; - } + ScopedWriteArray swa(m_Settings, "recentDirectories"); - log::debug(" . {}={}", k, m_Settings.value(k).toString()); - } - } + for (auto&& p : map) { + swa.next(); - log::debug("servers:"); + swa.set("name", p.first); + swa.set("directory", p.second); + } +} - for (const auto& server : getServers()) { - QString lastDownloads; - for (auto speed : server.lastDownloads()) { - lastDownloads += QString("%1 ").arg(speed); - } +QString PathSettings::getConfigurablePath(const QString &key, + const QString &def, + bool resolve) const +{ + QString result = QDir::fromNativeSeparators( + get(m_Settings, "Settings", key, QString("%BASE_DIR%/") + def)); - log::debug( - " . {} premium={} lastSeen={} preferred={} lastDownloads={}", - server.name(), - server.isPremium() ? "yes" : "no", - server.lastSeen().toString(Qt::ISODate), - server.preferred(), - lastDownloads.trimmed()); + if (resolve) { + result.replace("%BASE_DIR%", base()); } -} + return result; +} -GeometrySettings::GeometrySettings(QSettings& s) - : m_Settings(s), m_Reset(false) +void PathSettings::setConfigurablePath(const QString &key, const QString& path) { + if (path.isEmpty()) { + remove(m_Settings, "Settings", key); + } else { + set(m_Settings, "Settings", key, path); + } } -void GeometrySettings::requestReset() +QString PathSettings::base() const { - m_Reset = true; + return QDir::fromNativeSeparators(get(m_Settings, + "Settings", "base_directory", qApp->property("dataPath").toString())); } -void GeometrySettings::resetIfNeeded() +QString PathSettings::downloads(bool resolve) const { - if (!m_Reset) { - return; - } - - removeSection(m_Settings, "Geometry"); + return getConfigurablePath( + "download_directory", + ToQString(AppConfig::downloadPath()), + resolve); } -void GeometrySettings::saveGeometry(const QWidget* w) +QString PathSettings::cache(bool resolve) const { - set(m_Settings, "Geometry", geoSettingName(w), w->saveGeometry()); + return getConfigurablePath( + "cache_directory", + ToQString(AppConfig::cachePath()), + resolve); } -bool GeometrySettings::restoreGeometry(QWidget* w) const +QString PathSettings::mods(bool resolve) const { - if (auto v=getOptional(m_Settings, "Geometry", geoSettingName(w))) { - w->restoreGeometry(*v); - return true; - } + return getConfigurablePath( + "mod_directory", + ToQString(AppConfig::modsPath()), + resolve); +} - return false; +QString PathSettings::profiles(bool resolve) const +{ + return getConfigurablePath( + "profiles_directory", + ToQString(AppConfig::profilesPath()), + resolve); } -void GeometrySettings::saveState(const QMainWindow* w) +QString PathSettings::overwrite(bool resolve) const { - set(m_Settings, "Geometry", stateSettingName(w), w->saveState()); + return getConfigurablePath( + "overwrite_directory", + ToQString(AppConfig::overwritePath()), + resolve); } -bool GeometrySettings::restoreState(QMainWindow* w) const +void PathSettings::setBase(const QString& path) { - if (auto v=getOptional(m_Settings, "Geometry", stateSettingName(w))) { - w->restoreState(*v); - return true; + if (path.isEmpty()) { + remove(m_Settings, "Settings", "base_directory"); + } else { + set(m_Settings, "Settings", "base_directory", path); } - - return false; } -void GeometrySettings::saveState(const QHeaderView* w) +void PathSettings::setDownloads(const QString& path) { - set(m_Settings, "Geometry", stateSettingName(w), w->saveState()); + setConfigurablePath("download_directory", path); } -bool GeometrySettings::restoreState(QHeaderView* w) const +void PathSettings::setMods(const QString& path) { - if (auto v=getOptional(m_Settings, "Geometry", stateSettingName(w))) { - w->restoreState(*v); - return true; - } - - return false; + setConfigurablePath("mod_directory", path); } -void GeometrySettings::saveState(const QSplitter* w) +void PathSettings::setCache(const QString& path) { - set(m_Settings, "Geometry", stateSettingName(w), w->saveState()); + setConfigurablePath("cache_directory", path); } -bool GeometrySettings::restoreState(QSplitter* w) const +void PathSettings::setProfiles(const QString& path) { - if (auto v=getOptional(m_Settings, "Geometry", stateSettingName(w))) { - w->restoreState(*v); - return true; - } - - return false; + setConfigurablePath("profiles_directory", path); } -void GeometrySettings::saveState(const ExpanderWidget* expander) +void PathSettings::setOverwrite(const QString& path) { - set(m_Settings, "Geometry", stateSettingName(expander), expander->saveState()); + setConfigurablePath("overwrite_directory", path); } -bool GeometrySettings::restoreState(ExpanderWidget* expander) const -{ - if (auto v=getOptional(m_Settings, "Geometry", stateSettingName(expander))) { - expander->restoreState(*v); - return true; - } - return false; +NetworkSettings::NetworkSettings(QSettings& settings) + : m_Settings(settings) +{ } -void GeometrySettings::saveVisibility(const QWidget* w) +bool NetworkSettings::offlineMode() const { - set(m_Settings, "Geometry", visibilitySettingName(w), w->isVisible()); + return get(m_Settings, "Settings", "offline_mode", false); } -bool GeometrySettings::restoreVisibility(QWidget* w, std::optional def) const +void NetworkSettings::setOfflineMode(bool b) { - if (auto v=getOptional(m_Settings, "Geometry", visibilitySettingName(w), def)) { - w->setVisible(*v); - return true; - } + set(m_Settings, "Settings", "offline_mode", b); +} - return false; +bool NetworkSettings::useProxy() const +{ + return get(m_Settings, "Settings", "use_proxy", false); } -void GeometrySettings::restoreToolbars(QMainWindow* w) const +void NetworkSettings::setUseProxy(bool b) { - // all toolbars have the same size and button style settings - const auto size = getOptional(m_Settings, "Geometry", "toolbar_size"); - const auto style = getOptional(m_Settings, "Geometry", "toolbar_button_style"); + set(m_Settings, "Settings", "use_proxy", b); +} - for (auto* tb : w->findChildren()) { - if (size) { - tb->setIconSize(*size); - } +void NetworkSettings::setDownloadSpeed(const QString& name, int bytesPerSecond) +{ + auto current = servers(); - if (style) { - tb->setToolButtonStyle(static_cast(*style)); + for (auto& server : current) { + if (server.name() == name) { + server.addDownload(bytesPerSecond); + updateServers(current); + return; } - - restoreVisibility(tb); } + + log::error( + "server '{}' not found while trying to add a download with bps {}", + name, bytesPerSecond); } -void GeometrySettings::saveToolbars(const QMainWindow* w) +ServerList NetworkSettings::servers() const { - const auto tbs = w->findChildren(); + // servers used to be a map of byte arrays until 2.2.1, it's now an array of + // individual values instead + // + // so post 2.2.1, only one key is returned: "size", the size of the arrays; + // in 2.2.1, one key per server is returned + { + const QStringList keys = ScopedGroup(m_Settings, "Servers").keys(); - // save visibility for all - for (auto* tb : tbs) { - saveVisibility(tb); + if (!keys.empty() && keys[0] != "size") { + // old format + return serversFromOldMap(); + } } - // all toolbars have the same size and button style settings, just save the - // first one - if (!tbs.isEmpty()) { - const auto* tb = tbs[0]; - set(m_Settings, "Geometry", "toolbar_size", tb->iconSize()); - set(m_Settings, "Geometry", "toolbar_button_style", static_cast(tb->toolButtonStyle())); - } -} + // post 2.2.1 format, array of values -QStringList GeometrySettings::getModInfoTabOrder() const -{ - QStringList v; + ServerList list; - if (m_Settings.contains("mod_info_tabs")) { - // old byte array from 2.2.0 - QDataStream stream(m_Settings.value("mod_info_tabs").toByteArray()); + { + ScopedReadArray sra(m_Settings, "Servers"); - int count = 0; - stream >> count; + sra.for_each([&] { + ServerInfo::SpeedList lastDownloads; - for (int i=0; i> s; - v.push_back(s); - } - } else { - // string list since 2.2.1 - QString string = m_Settings.value("mod_info_tab_order").toString(); - QTextStream stream(&string); + const auto lastDownloadsString = sra.get("lastDownloads", ""); - while (!stream.atEnd()) { - QString s; - stream >> s; - v.push_back(s); - } + for (const auto& s : lastDownloadsString.split(" ")) { + const auto bytesPerSecond = s.toInt(); + if (bytesPerSecond > 0) { + lastDownloads.push_back(bytesPerSecond); + } + } + + ServerInfo server( + sra.get("name", ""), + sra.get("premium", false), + QDate::fromString(sra.get("lastSeen", ""), Qt::ISODate), + sra.get("preferred", 0), + lastDownloads); + + list.add(std::move(server)); + }); } - return v; + return list; } -void GeometrySettings::setModInfoTabOrder(const QString& names) +ServerList NetworkSettings::serversFromOldMap() const { - set(m_Settings, "Geometry", "mod_info_tab_order", names); -} + // for 2.2.1 and before -void GeometrySettings::centerOnMainWindowMonitor(QWidget* w) -{ - const auto monitor = getOptional( - m_Settings, "Geometry", "MainWindow_monitor"); + ServerList list; + const ScopedGroup sg(m_Settings, "Servers"); - QPoint center; + sg.for_each([&](auto&& serverKey) { + QVariantMap data = sg.get(serverKey); - if (monitor && QGuiApplication::screens().size() > *monitor) { - center = QGuiApplication::screens().at(*monitor)->geometry().center(); - } else { - center = QGuiApplication::primaryScreen()->geometry().center(); - } + ServerInfo server( + serverKey, + data["premium"].toBool(), + data["lastSeen"].toDate(), + data["preferred"].toInt(), + {}); - w->move(center - w->rect().center()); -} + // ignoring download count and speed, it's now a list of values instead of + // a total -void GeometrySettings::saveMainWindowMonitor(const QMainWindow* w) -{ - if (auto* handle=w->windowHandle()) { - if (auto* screen = handle->screen()) { - const int screenId = QGuiApplication::screens().indexOf(screen); - set(m_Settings, "Geometry", "MainWindow_monitor", screenId); - } - } + list.add(std::move(server)); + }); + + return list; } -Qt::Orientation dockOrientation(const QMainWindow* mw, const QDockWidget* d) +void NetworkSettings::updateServers(ServerList servers) { - // docks in these areas are horizontal - const auto horizontalAreas = - Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea; + // clean up unavailable servers + servers.cleanup(); - if (mw->dockWidgetArea(const_cast(d)) & horizontalAreas) { - return Qt::Horizontal; - } else { - return Qt::Vertical; - } -} + removeSection(m_Settings, "Servers"); -void GeometrySettings::saveDocks(const QMainWindow* mw) -{ - // this attempts to fix https://bugreports.qt.io/browse/QTBUG-46620 where dock - // sizes are not restored when the main window is maximized; it is used in - // MainWindow::readSettings() and MainWindow::storeSettings() - // - // there's also https://stackoverflow.com/questions/44005852, which has what - // seems to be a popular fix, but it breaks the restored size of the window - // by setting it to the desktop's resolution, so that doesn't work - // - // the only fix I could find is to remember the sizes of the docks and manually - // setting them back; saving is straightforward, but restoring is messy - // - // this also depends on the window being visible before the timer in restore() - // is fired and the timer must be processed by application.exec(); therefore, - // the splash screen _must_ be closed before readSettings() is called, because - // it has its own event loop, which seems to interfere with this - // - // all of this should become unnecessary when QTBUG-46620 is fixed - // + { + ScopedWriteArray swa(m_Settings, "Servers"); - // saves the size of each dock - for (const auto* dock : mw->findChildren()) { - int size = 0; + for (const auto& server : servers) { + swa.next(); - // save the width for horizontal docks, or the height for vertical - if (dockOrientation(mw, dock) == Qt::Horizontal) { - size = dock->size().width(); - } else { - size = dock->size().height(); - } + swa.set("name", server.name()); + swa.set("premium", server.isPremium()); + swa.set("lastSeen", server.lastSeen().toString(Qt::ISODate)); + swa.set("preferred", server.preferred()); - set(m_Settings, "Geometry", dockSettingName(dock), size); + QString lastDownloads; + for (const auto& speed : server.lastDownloads()) { + if (speed > 0) { + lastDownloads += QString("%1 ").arg(speed); + } + } + + swa.set("lastDownloads", lastDownloads.trimmed()); + } } } -void GeometrySettings::restoreDocks(QMainWindow* mw) const +void NetworkSettings::dump() const { - struct DockInfo - { - QDockWidget* d; - int size = 0; - Qt::Orientation ori; - }; - - std::vector dockInfos; + log::debug("servers:"); - // for each dock - for (auto* dock : mw->findChildren()) { - if (auto size=getOptional(m_Settings, "Geometry", dockSettingName(dock))) { - // remember this dock, its size and orientation - dockInfos.push_back({dock, *size, dockOrientation(mw, dock)}); + for (const auto& server : servers()) { + QString lastDownloads; + for (auto speed : server.lastDownloads()) { + lastDownloads += QString("%1 ").arg(speed); } - } - // the main window must have had time to process the settings from - // readSettings() or it seems to override whatever is set here - // - // some people said a single processEvents() call is enough, but it doesn't - // look like it - QTimer::singleShot(5, [=] { - for (const auto& info : dockInfos) { - mw->resizeDocks({info.d}, {info.size}, info.ori); - } - }); + log::debug( + " . {} premium={} lastSeen={} preferred={} lastDownloads={}", + server.name(), + server.isPremium() ? "yes" : "no", + server.lastSeen().toString(Qt::ISODate), + server.preferred(), + lastDownloads.trimmed()); + } } -ColorSettings::ColorSettings(QSettings& s) - : m_Settings(s) +NexusSettings::NexusSettings(Settings& parent, QSettings& settings) + : m_Parent(parent), m_Settings(settings) { } -QColor ColorSettings::modlistOverwrittenLoose() const +bool NexusSettings::automaticLoginEnabled() const { - return get( - m_Settings, "Settings", "overwrittenLooseFilesColor", - QColor(0, 255, 0, 64)); + return get(m_Settings, "Settings", "nexus_login", false); } -void ColorSettings::setModlistOverwrittenLoose(const QColor& c) +bool NexusSettings::apiKey(QString &apiKey) const { - set(m_Settings, "Settings", "overwrittenLooseFilesColor", c); + QString tempKey = getWindowsCredential("APIKEY"); + if (tempKey.isEmpty()) + return false; + + apiKey = tempKey; + return true; } -QColor ColorSettings::modlistOverwritingLoose() const +bool NexusSettings::setApiKey(const QString& apiKey) { - return get( - m_Settings, "Settings", "overwritingLooseFilesColor", - QColor(255, 0, 0, 64)); + if (!setWindowsCredential("APIKEY", apiKey)) { + const auto e = GetLastError(); + log::error("Storing API key failed: {}", formatSystemMessage(e)); + return false; + } + + return true; } -void ColorSettings::setModlistOverwritingLoose(const QColor& c) +bool NexusSettings::clearApiKey() { - set(m_Settings, "Settings", "overwritingLooseFilesColor", c); + return setApiKey(""); } -QColor ColorSettings::modlistOverwrittenArchive() const +bool NexusSettings::hasApiKey() const { - return get( - m_Settings, "Settings", "overwrittenArchiveFilesColor", - QColor(0, 255, 255, 64)); + return !getWindowsCredential("APIKEY").isEmpty(); } -void ColorSettings::setModlistOverwrittenArchive(const QColor& c) +bool NexusSettings::endorsementIntegration() const { - set(m_Settings, "Settings", "overwrittenArchiveFilesColor", c); + return get(m_Settings, "Settings", "endorsement_integration", true); } -QColor ColorSettings::modlistOverwritingArchive() const +void NexusSettings::setEndorsementIntegration(bool b) const { - return get( - m_Settings, "Settings", "overwritingArchiveFilesColor", - QColor(255, 0, 255, 64)); + set(m_Settings, "Settings", "endorsement_integration", b); } -void ColorSettings::setModlistOverwritingArchive(const QColor& c) +EndorsementState NexusSettings::endorsementState() const { - set(m_Settings, "Settings", "overwritingArchiveFilesColor", c); + return endorsementStateFromString( + get(m_Settings, "General", "endorse_state", "")); } -QColor ColorSettings::modlistContainsPlugin() const +void NexusSettings::setEndorsementState(EndorsementState s) { - return get( - m_Settings, "Settings", "containsPluginColor", - QColor(0, 0, 255, 64)); + const auto v = toString(s); + + if (v.isEmpty()) { + remove(m_Settings, "General", "endorse_state"); + } else { + set(m_Settings, "General", "endorse_state", v); + } } -void ColorSettings::setModlistContainsPlugin(const QColor& c) +void NexusSettings::registerAsNXMHandler(bool force) { - set(m_Settings, "Settings", "containsPluginColor", c); + const auto nxmPath = QCoreApplication::applicationDirPath() + "/nxmhandler.exe"; + const auto executable = QCoreApplication::applicationFilePath(); + + QString mode = force ? "forcereg" : "reg"; + QString parameters = mode + " " + m_Parent.game().plugin()->gameShortName(); + for (const QString& altGame : m_Parent.game().plugin()->validShortNames()) { + parameters += "," + altGame; + } + parameters += " \"" + executable + "\""; + + if (!shell::Execute(nxmPath, parameters)) { + QMessageBox::critical( + nullptr, QObject::tr("Failed"), + QObject::tr("Failed to start the helper application")); + } } -QColor ColorSettings::pluginListContained() const + +SteamSettings::SteamSettings(Settings& parent, QSettings& settings) + : m_Parent(parent), m_Settings(settings) { - return get( - m_Settings, "Settings", "containedColor", - QColor(0, 0, 255, 64)); } -void ColorSettings::setPluginListContained(const QColor& c) +QString SteamSettings::appID() const { - set(m_Settings, "Settings", "containedColor", c); + return get( + m_Settings, "Settings", "app_id", m_Parent.game().plugin()->steamAPPId()); } - -PluginSettings::PluginSettings(QSettings& settings) - : m_Settings(settings) +void SteamSettings::setAppID(const QString& id) { + if (id.isEmpty()) { + remove(m_Settings, "Settings", "app_id"); + } else { + set(m_Settings, "Settings", "app_id", id); + } } -void PluginSettings::clearPlugins() +bool SteamSettings::login(QString &username, QString &password) const { - m_Plugins.clear(); - m_PluginSettings.clear(); - - m_PluginBlacklist.clear(); + username = get(m_Settings, "Settings", "steam_username", ""); + password = getWindowsCredential("steam_password"); - ScopedReadArray sra(m_Settings, "pluginBlacklist"); - sra.for_each([&]{ - m_PluginBlacklist.insert(sra.get("name")); - }); + return !username.isEmpty() && !password.isEmpty(); } -void PluginSettings::registerPlugin(IPlugin *plugin) +void SteamSettings::setLogin(QString username, QString password) { - m_Plugins.push_back(plugin); - m_PluginSettings.insert(plugin->name(), QVariantMap()); - m_PluginDescriptions.insert(plugin->name(), QVariantMap()); + if (username == "") { + remove(m_Settings, "Settings", "steam_username"); + password = ""; + } else { + set(m_Settings, "Settings", "steam_username", username); + } - for (const PluginSetting &setting : plugin->settings()) { - const QString settingName = plugin->name() + "/" + setting.key; + if (!setWindowsCredential("steam_password", password)) { + const auto e = GetLastError(); + log::error("Storing or deleting password failed: {}", formatSystemMessage(e)); + } +} - QVariant temp = get( - m_Settings, "Plugins", settingName, setting.defaultValue); - 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()); +InterfaceSettings::InterfaceSettings(QSettings& settings) + : m_Settings(settings) +{ +} - temp = setting.defaultValue; - } +bool InterfaceSettings::lockGUI() const +{ + return get(m_Settings, "Settings", "lock_gui", true); +} - m_PluginSettings[plugin->name()][setting.key] = temp; +void InterfaceSettings::setLockGUI(bool b) +{ + set(m_Settings, "Settings", "lock_gui", b); +} - m_PluginDescriptions[plugin->name()][setting.key] = QString("%1 (default: %2)") - .arg(setting.description) - .arg(setting.defaultValue.toString()); - } +std::optional InterfaceSettings::styleName() const +{ + return getOptional(m_Settings, "Settings", "style"); } -bool PluginSettings::pluginBlacklisted(const QString &fileName) const +void InterfaceSettings::setStyleName(const QString& name) { - return m_PluginBlacklist.contains(fileName); + set(m_Settings, "Settings", "style", name); } -QVariant PluginSettings::pluginSetting(const QString &pluginName, const QString &key) const +bool InterfaceSettings::compactDownloads() const { - auto iterPlugin = m_PluginSettings.find(pluginName); - if (iterPlugin == m_PluginSettings.end()) { - return QVariant(); - } + return get(m_Settings, "Settings", "compact_downloads", false); +} - auto iterSetting = iterPlugin->find(key); - if (iterSetting == iterPlugin->end()) { - return QVariant(); - } +void InterfaceSettings::setCompactDownloads(bool b) +{ + set(m_Settings, "Settings", "compact_downloads", b); +} - return *iterSetting; +bool InterfaceSettings::metaDownloads() const +{ + return get(m_Settings, "Settings", "meta_downloads", false); } -void PluginSettings::setPluginSetting(const QString &pluginName, const QString &key, const QVariant &value) +void InterfaceSettings::setMetaDownloads(bool b) { - auto iterPlugin = m_PluginSettings.find(pluginName); + set(m_Settings, "Settings", "meta_downloads", b); +} - if (iterPlugin == m_PluginSettings.end()) { - throw MyException( - QObject::tr("attempt to store setting for unknown plugin \"%1\"") - .arg(pluginName)); - } +bool InterfaceSettings::hideAPICounter() const +{ + return get(m_Settings, "Settings", "hide_api_counter", false); +} - // store the new setting both in memory and in the ini - m_PluginSettings[pluginName][key] = value; - set(m_Settings, "Plugins", pluginName + "/" + key, value); +void InterfaceSettings::setHideAPICounter(bool b) +{ + set(m_Settings, "Settings", "hide_api_counter", b); } -QVariant PluginSettings::pluginPersistent(const QString &pluginName, const QString &key, const QVariant &def) const +bool InterfaceSettings::displayForeign() const { - if (!m_PluginSettings.contains(pluginName)) { - return def; - } + return get(m_Settings, "Settings", "display_foreign", true); +} - return get(m_Settings, "PluginPersistance", pluginName + "/" + key, def); +void InterfaceSettings::setDisplayForeign(bool b) +{ + set(m_Settings, "Settings", "display_foreign", b); } -void PluginSettings::setPluginPersistent( - const QString &pluginName, const QString &key, const QVariant &value, bool sync) +QString InterfaceSettings::language() { - if (!m_PluginSettings.contains(pluginName)) { - throw MyException( - QObject::tr("attempt to store setting for unknown plugin \"%1\"") - .arg(pluginName)); - } + QString result = get(m_Settings, "Settings", "language", ""); - set(m_Settings, "PluginPersistance", pluginName + "/" + key, value); + if (result.isEmpty()) { + QStringList languagePreferences = QLocale::system().uiLanguages(); - if (sync) { - m_Settings.sync(); + if (languagePreferences.length() > 0) { + // the users most favoritest language + result = languagePreferences.at(0); + } else { + // fallback system locale + result = QLocale::system().name(); + } } + + return result; } -void PluginSettings::addBlacklistPlugin(const QString &fileName) +void InterfaceSettings::setLanguage(const QString& name) { - m_PluginBlacklist.insert(fileName); - writePluginBlacklist(); + set(m_Settings, "Settings", "language", name); } -void PluginSettings::writePluginBlacklist() +bool InterfaceSettings::isTutorialCompleted(const QString& windowName) const { - removeSection(m_Settings, "PluginBlacklist"); - - ScopedWriteArray swa(m_Settings, "PluginBlacklist"); - - for (const QString &plugin : m_PluginBlacklist) { - swa.next(); - swa.set("name", plugin); - } + return get(m_Settings, "CompletedWindowTutorials", windowName, false); } -QVariantMap PluginSettings::pluginSettings(const QString &pluginName) const +void InterfaceSettings::setTutorialCompleted(const QString& windowName, bool b) { - return m_PluginSettings[pluginName]; + set(m_Settings, "CompletedWindowTutorials", windowName, b); } -void PluginSettings::setPluginSettings(const QString &pluginName, const QVariantMap& map) + +DiagnosticsSettings::DiagnosticsSettings(QSettings& settings) + : m_Settings(settings) { - m_PluginSettings[pluginName] = map; } -QVariantMap PluginSettings::pluginDescriptions(const QString &pluginName) const +log::Levels DiagnosticsSettings::logLevel() const { - return m_PluginDescriptions[pluginName]; + return get(m_Settings, "Settings", "log_level", log::Levels::Info); } -void PluginSettings::pluginDescriptions(const QString &pluginName, const QVariantMap& map) +void DiagnosticsSettings::setLogLevel(log::Levels level) { - m_PluginDescriptions[pluginName] = map; + set(m_Settings, "Settings", "log_level", level); } -const QSet& PluginSettings::pluginBlacklist() const +CrashDumpsType DiagnosticsSettings::crashDumpsType() const { - return m_PluginBlacklist; + return get(m_Settings, + "Settings", "crash_dumps_type", CrashDumpsType::Mini); } -void PluginSettings::setPluginBlacklist(const QStringList& pluginNames) +void DiagnosticsSettings::setCrashDumpsType(CrashDumpsType type) { - m_PluginBlacklist.clear(); - - for (const auto& name : pluginNames) { - m_PluginBlacklist.insert(name); - } + set(m_Settings, "Settings", "crash_dumps_type", type); } -void PluginSettings::save() +int DiagnosticsSettings::crashDumpsMax() const { - 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()); - } - } + return get(m_Settings, "Settings", "crash_dumps_max", 5); +} - writePluginBlacklist(); +void DiagnosticsSettings::setCrashDumpsMax(int n) +{ + set(m_Settings, "Settings", "crash_dumps_max", n); } diff --git a/src/settings.h b/src/settings.h index 403c2d71..5c0a2542 100644 --- a/src/settings.h +++ b/src/settings.h @@ -25,6 +25,10 @@ along with Mod Organizer. If not, see . #include #include +#ifdef interface + #undef interface +#endif + namespace MOBase { class IPlugin; class IPluginGame; @@ -50,6 +54,58 @@ private: }; +class GameSettings +{ +public: + GameSettings(QSettings& setting); + + const MOBase::IPluginGame* plugin(); + void setPlugin(const MOBase::IPluginGame* gamePlugin); + + /** + * whether files of the core game are forced-enabled so the user can't + * accidentally disable them + */ + bool forceEnableCoreFiles() const; + void setForceEnableCoreFiles(bool b); + + /** + * the directory where the managed game is stored (with native separators) + **/ + std::optional directory() const; + void setDirectory(const QString& path); + + std::optional name() const; + void setName(const QString& name); + + std::optional edition() const; + void setEdition(const QString& name); + + std::optional selectedProfileName() const; + void setSelectedProfileName(const QString& name); + + /** + * @return the load mechanism to be used + **/ + LoadMechanism::EMechanism loadMechanismType() const; + void setLoadMechanism(LoadMechanism::EMechanism m); + const LoadMechanism& loadMechanism() const; + void setupLoadMechanism(); + + /** + * @return true if the user wants unchecked plugins (esp, esm) should be hidden from + * the virtual data directory + **/ + bool hideUncheckedPlugins() const; + void setHideUncheckedPlugins(bool b); + +private: + QSettings& m_Settings; + const MOBase::IPluginGame* m_GamePlugin; + LoadMechanism m_LoadMechanism; +}; + + class GeometrySettings { public: @@ -83,7 +139,7 @@ public: void saveDocks(const QMainWindow* w); void restoreDocks(QMainWindow* w) const; - QStringList getModInfoTabOrder() const; + QStringList modInfoTabOrder() const; void setModInfoTabOrder(const QString& names); void centerOnMainWindowMonitor(QWidget* w); @@ -95,6 +151,40 @@ private: }; +class WidgetSettings +{ +public: + WidgetSettings(QSettings& s); + + std::optional index(const QComboBox* cb) const; + void saveIndex(const QComboBox* cb); + void restoreIndex(QComboBox* cb, std::optional def={}) const; + + std::optional index(const QTabWidget* w) const; + void saveIndex(const QTabWidget* w); + void restoreIndex(QTabWidget* w, std::optional def={}) const; + + std::optional checked(const QAbstractButton* w) const; + void saveChecked(const QAbstractButton* w); + void restoreChecked(QAbstractButton* w, std::optional def={}) const; + + MOBase::QuestionBoxMemory::Button questionButton( + const QString& windowName, const QString& filename) const; + + void setQuestionWindowButton( + const QString& windowName, MOBase::QuestionBoxMemory::Button button); + + void setQuestionFileButton( + const QString& windowName, const QString& filename, + MOBase::QuestionBoxMemory::Button choice); + + void resetQuestionButtons(); + +private: + QSettings& m_Settings; +}; + + class ColorSettings { public: @@ -120,6 +210,19 @@ public: QColor pluginListContained() const; void setPluginListContained(const QColor& c) ; + std::optional previousSeparatorColor() const; + void setPreviousSeparatorColor(const QColor& c) const; + void removePreviousSeparatorColor(); + + /** + * @brief color the scrollbar of the mod list for custom separator colors? + * @return the state of the setting + */ + bool colorSeparatorScrollbar() const; + void setColorSeparatorScrollbar(bool b); + + static QColor idealTextColor(const QColor& rBackgroundColor); + private: QSettings& m_Settings; }; @@ -165,210 +268,229 @@ private: }; -enum class EndorsementState -{ - Accepted = 1, - Refused, - NoDecision -}; - -EndorsementState endorsementStateFromString(const QString& s); -QString toString(EndorsementState s); - - -/** - * manages the settings for Mod Organizer. The settings are not cached - * inside the class but read/written directly from/to disc - **/ -class Settings : public QObject +class PathSettings { - Q_OBJECT; - public: - Settings(const QString& path); - ~Settings(); + PathSettings(QSettings& settings); - static Settings &instance(); + QString base() const; + QString downloads(bool resolve = true) const; + QString mods(bool resolve = true) const; + QString cache(bool resolve = true) const; + QString profiles(bool resolve = true) const; + QString overwrite(bool resolve = true) const; - void processUpdates( - const QVersionNumber& currentVersion, const QVersionNumber& lastVersion); + void setBase(const QString& path); + void setDownloads(const QString& path); + void setMods(const QString& path); + void setCache(const QString& path); + void setProfiles(const QString& path); + void setOverwrite(const QString& path); - QString getFilename() const; + std::map recent() const; + void setRecent(const std::map& map); - /** - * @return true if the user wants unchecked plugins (esp, esm) should be hidden from - * the virtual dat adirectory - **/ - bool hideUncheckedPlugins() const; - void setHideUncheckedPlugins(bool b); +private: + QSettings& m_Settings; - /** - * @return true if files of the core game are forced-enabled so the user can't accidentally disable them - */ - bool forceEnableCoreFiles() const; - void setForceEnableCoreFiles(bool b); + QString getConfigurablePath(const QString &key, const QString &def, bool resolve) const; + void setConfigurablePath(const QString &key, const QString& path); +}; - /** - * @return true if the GUI should be locked when running executables - */ - bool lockGUI() const; - void setLockGUI(bool b); - /** - * the steam appid is assigned by the steam platform to each product sold there. - * The appid may differ between different versions of a game so it may be impossible - * for Mod Organizer to automatically recognize it, though usually it does - * @return the steam appid for the game - **/ - QString getSteamAppID() const; - void setSteamAppID(const QString& id); - - QString getBaseDirectory() const; - QString getDownloadDirectory(bool resolve = true) const; - QString getModDirectory(bool resolve = true) const; - QString getCacheDirectory(bool resolve = true) const; - QString getProfileDirectory(bool resolve = true) const; - QString getOverwriteDirectory(bool resolve = true) const; - - void setBaseDirectory(const QString& path); - void setDownloadDirectory(const QString& path); - void setModDirectory(const QString& path); - void setCacheDirectory(const QString& path); - void setProfileDirectory(const QString& path); - void setOverwriteDirectory(const QString& path); +class NetworkSettings +{ +public: + NetworkSettings(QSettings& settings); /** - * retrieve the directory where the managed game is stored (with native separators) - **/ - std::optional getManagedGameDirectory() const; - void setManagedGameDirectory(const QString& path); - - std::optional getManagedGameName() const; - void setManagedGameName(const QString& name); - - std::optional getManagedGameEdition() const; - void setManagedGameEdition(const QString& name); + * @return true if the user disabled internet features + */ + bool offlineMode() const; + void setOfflineMode(bool b); - std::optional getSelectedProfileName() const; - void setSelectedProfileName(const QString& name); + /** + * @return true if the user configured the use of a network proxy + */ + bool useProxy() const; + void setUseProxy(bool b); - std::optional getStyleName() const; - void setStyleName(const QString& name); + void setDownloadSpeed(const QString &serverName, int bytesPerSecond); + ServerList servers() const; + void updateServers(ServerList servers); - std::optional getVersion() const; + void dump() const; - bool getFirstStart() const; - void setFirstStart(bool b); +private: + QSettings& m_Settings; - std::optional getPreviousSeparatorColor() const; - void setPreviousSeparatorColor(const QColor& c) const; - void removePreviousSeparatorColor(); + ServerList serversFromOldMap() const; +}; - std::map getRecentDirectories() const; - void setRecentDirectories(const std::map& map); - std::vector> getExecutables() const; - void setExecutables(const std::vector>& v); +enum class EndorsementState +{ + Accepted = 1, + Refused, + NoDecision +}; - bool isTutorialCompleted(const QString& windowName) const; - void setTutorialCompleted(const QString& windowName, bool b=true); +EndorsementState endorsementStateFromString(const QString& s); +QString toString(EndorsementState s); - bool keepBackupOnInstall() const; - void setKeepBackupOnInstall(bool b); +class NexusSettings +{ +public: + NexusSettings(Settings& parent, QSettings& settings); - MOBase::QuestionBoxMemory::Button getQuestionButton( - const QString& windowName, const QString& filename) const; + /** + * @return true if the user has set up automatic login to nexus + **/ + bool automaticLoginEnabled() const; - void setQuestionWindowButton( - const QString& windowName, MOBase::QuestionBoxMemory::Button button); + /** + * @brief retrieve the login information for nexus + * + * @param username (out) receives the user name for nexus + * @param password (out) received the password for nexus + * @return true if automatic login is active, false otherwise + **/ + bool apiKey(QString &apiKey) const; - void setQuestionFileButton( - const QString& windowName, const QString& filename, - MOBase::QuestionBoxMemory::Button choice); + /** + * @brief set the nexus login information + * + * @param username username + * @param password password + */ + bool setApiKey(const QString& apiKey); - void resetQuestionButtons(); + /** + * @brief clears the nexus login information + */ + bool clearApiKey(); - std::optional getIndex(const QComboBox* cb) const; - void saveIndex(const QComboBox* cb); - void restoreIndex(QComboBox* cb, std::optional def={}) const; + /** + * @brief returns whether an API key is currently stored + */ + bool hasApiKey() const; - std::optional getIndex(const QTabWidget* w) const; - void saveIndex(const QTabWidget* w); - void restoreIndex(QTabWidget* w, std::optional def={}) const; + /** + * @return true if endorsement integration is enabled + */ + bool endorsementIntegration() const; + void setEndorsementIntegration(bool b) const; - std::optional getChecked(const QAbstractButton* w) const; - void saveChecked(const QAbstractButton* w); - void restoreChecked(QAbstractButton* w, std::optional def={}) const; + EndorsementState endorsementState() const; + void setEndorsementState(EndorsementState s); - GeometrySettings& geometry(); - const GeometrySettings& geometry() const; + /** + * @brief register MO as the handler for nxm links + * @param force set to true to enforce the registration dialog to show up, + * even if the user said earlier not to + */ + void registerAsNXMHandler(bool force); - ColorSettings& colors(); - const ColorSettings& colors() const; +private: + Settings& m_Parent; + QSettings& m_Settings; +}; - PluginSettings& plugins(); - const PluginSettings& plugins() const; +class SteamSettings +{ +public: + SteamSettings(Settings& parent, QSettings& settings); /** - * @return true if the user has set up automatic login to nexus - **/ - bool automaticLoginEnabled() const; + * the steam appid is assigned by the steam platform to each product sold there. + * The appid may differ between different versions of a game so it may be impossible + * for Mod Organizer to automatically recognize it, though usually it does + * @return the steam appid for the game + **/ + QString appID() const; + void setAppID(const QString& id); /** - * @brief retrieve the login information for nexus - * - * @param username (out) receives the user name for nexus - * @param password (out) received the password for nexus - * @return true if automatic login is active, false otherwise - **/ - bool getNexusApiKey(QString &apiKey) const; + * @brief retrieve the login information for steam + * + * @param username (out) receives the user name for nexus + * @param password (out) received the password for nexus + * @return true if a username has been specified, false otherwise + **/ + bool login(QString &username, QString &password) const; /** - * @brief set the nexus login information + * @brief set the steam login information * * @param username username * @param password password */ - bool setNexusApiKey(const QString& apiKey); + void setLogin(QString username, QString password); - /** - * @brief clears the nexus login information - */ - bool clearNexusApiKey(); +private: + Settings& m_Parent; + QSettings& m_Settings; +}; - /** - * @brief returns whether an API key is currently stored - */ - bool hasNexusApiKey() const; - /** - * @brief retrieve the login information for steam - * - * @param username (out) receives the user name for nexus - * @param password (out) received the password for nexus - * @return true if a username has been specified, false otherwise - **/ - bool getSteamLogin(QString &username, QString &password) const; +class InterfaceSettings +{ +public: + InterfaceSettings(QSettings& settings); /** - * @return true if the user disabled internet features - */ - bool offlineMode() const; - void setOfflineMode(bool b); + * @return true if the GUI should be locked when running executables + */ + bool lockGUI() const; + void setLockGUI(bool b); + + std::optional styleName() const; + void setStyleName(const QString& name); /** - * @return true if the user chose compact downloads - */ + * @return true if the user chose compact downloads + */ bool compactDownloads() const; void setCompactDownloads(bool b); /** - * @return true if the user chose meta downloads - */ + * @return true if the user chose meta downloads + */ bool metaDownloads() const; void setMetaDownloads(bool b); + /** + * @return true if the API counter should be hidden + */ + bool hideAPICounter() const; + void setHideAPICounter(bool b); + + /** + * @return true if the user wants to see non-official plugins installed outside MO in his mod list + */ + bool displayForeign() const; + void setDisplayForeign(bool b); + + /** + * @return short code of the configured language (corresponding to the translation files) + */ + QString language(); + void setLanguage(const QString& name); + + bool isTutorialCompleted(const QString& windowName) const; + void setTutorialCompleted(const QString& windowName, bool b=true); + +private: + QSettings& m_Settings; +}; + + +class DiagnosticsSettings +{ +public: + DiagnosticsSettings(QSettings& settings); + MOBase::log::Levels logLevel() const; void setLogLevel(MOBase::log::Levels level); @@ -378,60 +500,48 @@ public: int crashDumpsMax() const; void setCrashDumpsMax(int n); - QString executablesBlacklist() const; - void setExecutablesBlacklist(const QString& s); +private: + QSettings& m_Settings; +}; - /** - * @brief set the steam login information - * - * @param username username - * @param password password - */ - void setSteamLogin(QString username, QString password); - /** - * @return the load mechanism to be used - **/ - LoadMechanism::EMechanism getLoadMechanism() const; - void setLoadMechanism(LoadMechanism::EMechanism m); - /** - * @brief activate the load mechanism selected by the user - **/ - void setupLoadMechanism(); +/** + * manages the settings for Mod Organizer. The settings are not cached + * inside the class but read/written directly from/to disc + **/ +class Settings : public QObject +{ + Q_OBJECT; - /** - * @return true if the user configured the use of a network proxy - */ - bool getUseProxy() const; - void setUseProxy(bool b); +public: + Settings(const QString& path); + ~Settings(); - /** - * @return true if endorsement integration is enabled - */ - bool endorsementIntegration() const; - void setEndorsementIntegration(bool b) const; + static Settings &instance(); - EndorsementState endorsementState() const; - void setEndorsementState(EndorsementState s); + QString filename() const; - /** - * @return true if the API counter should be hidden - */ - bool hideAPICounter() const; - void setHideAPICounter(bool b); + std::optional version() const; + void processUpdates(const QVersionNumber& current, const QVersionNumber& last); - /** - * @return true if the user wants to see non-official plugins installed outside MO in his mod list - */ - bool displayForeign() const; - void setDisplayForeign(bool b); + bool firstStart() const; + void setFirstStart(bool b); + + std::vector> executables() const; + void setExecutables(const std::vector>& v); + + bool keepBackupOnInstall() const; + void setKeepBackupOnInstall(bool b); + + QString executablesBlacklist() const; + void setExecutablesBlacklist(const QString& s); /** * @brief sets the new motd hash **/ - unsigned int getMotDHash() const; - void setMotDHash(unsigned int hash); + unsigned int motdHash() const; + void setMotdHash(unsigned int hash); /** * @return true if the user wants to have archives being parsed to show conflicts and contents @@ -439,41 +549,45 @@ public: bool archiveParsing() const; void setArchiveParsing(bool b); - /** - * @return short code of the configured language (corresponding to the translation files) - */ - QString language(); - void setLanguage(const QString& name); - - void setDownloadSpeed(const QString &serverName, int bytesPerSecond); - ServerList getServers() const; - ServerList getServersFromOldMap() const; - void updateServers(ServerList servers); - bool usePrereleases() const; void setUsePrereleases(bool b); - /** - * @brief register MO as the handler for nxm links - * @param force set to true to enforce the registration dialog to show up, - * even if the user said earlier not to - */ - void registerAsNXMHandler(bool force); - /** - * @brief color the scrollbar of the mod list for custom separator colors? - * @return the state of the setting - */ - bool colorSeparatorScrollbar() const; - void setColorSeparatorScrollbar(bool b); + GameSettings& game(); + const GameSettings& game() const; + + GeometrySettings& geometry(); + const GeometrySettings& geometry() const; - static QColor getIdealTextColor(const QColor& rBackgroundColor); + WidgetSettings& widgets(); + const WidgetSettings& widgets() const; - MOBase::IPluginGame const *gamePlugin() { return m_GamePlugin; } - const LoadMechanism& loadMechanism() const { return m_LoadMechanism; } + ColorSettings& colors(); + const ColorSettings& colors() const; - QSettings::Status sync() const; + PluginSettings& plugins(); + const PluginSettings& plugins() const; + + PathSettings& paths(); + const PathSettings& paths() const; + + NetworkSettings& network(); + const NetworkSettings& network() const; + + NexusSettings& nexus(); + const NexusSettings& nexus() const; + + SteamSettings& steam(); + const SteamSettings& steam() const; + InterfaceSettings& interface(); + const InterfaceSettings& interface() const; + + DiagnosticsSettings& diagnostics(); + const DiagnosticsSettings& diagnostics() const; + + + QSettings::Status sync() const; void dump() const; public slots: @@ -485,18 +599,19 @@ signals: private: static Settings *s_Instance; - MOBase::IPluginGame const *m_GamePlugin; mutable QSettings m_Settings; + + GameSettings m_Game; GeometrySettings m_Geometry; + WidgetSettings m_Widgets; ColorSettings m_Colors; PluginSettings m_Plugins; - LoadMechanism m_LoadMechanism; - - static bool obfuscate(const QString key, const QString data); - static QString deObfuscate(const QString key); - - QString getConfigurablePath(const QString &key, const QString &def, bool resolve) const; - void setConfigurablePath(const QString &key, const QString& path); + PathSettings m_Paths; + NetworkSettings m_Network; + NexusSettings m_Nexus; + SteamSettings m_Steam; + InterfaceSettings m_Interface; + DiagnosticsSettings m_Diagnostics; }; #endif // SETTINGS_H diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index 35d14644..1d3d4a39 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -51,11 +51,11 @@ int SettingsDialog::exec() { GeometrySaver gs(m_settings, this); - m_settings.restoreIndex(ui->tabWidget); + m_settings.widgets().restoreIndex(ui->tabWidget); auto ret = TutorableDialog::exec(); - m_settings.saveIndex(ui->tabWidget); + m_settings.widgets().saveIndex(ui->tabWidget); if (ret == QDialog::Accepted) { for (auto&& tab : m_tabs) { @@ -109,7 +109,7 @@ void SettingsDialog::accept() if ((QDir::fromNativeSeparators(newModPath) != QDir::fromNativeSeparators( - Settings::instance().getModDirectory(true))) && + Settings::instance().paths().mods(true))) && (QMessageBox::question( nullptr, tr("Confirm"), tr("Changing the mod directory affects all your profiles! " diff --git a/src/settingsdialogdiagnostics.cpp b/src/settingsdialogdiagnostics.cpp index 278da0bf..386c7425 100644 --- a/src/settingsdialogdiagnostics.cpp +++ b/src/settingsdialogdiagnostics.cpp @@ -12,7 +12,7 @@ DiagnosticsSettingsTab::DiagnosticsSettingsTab(Settings& s, SettingsDialog& d) setLevelsBox(); setCrashDumpTypesBox(); - ui->dumpsMaxEdit->setValue(settings().crashDumpsMax()); + ui->dumpsMaxEdit->setValue(settings().diagnostics().crashDumpsMax()); QString logsPath = qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath()); @@ -36,7 +36,7 @@ void DiagnosticsSettingsTab::setLevelsBox() ui->logLevelBox->addItem(QObject::tr("Error"), log::Error); for (int i=0; ilogLevelBox->count(); ++i) { - if (ui->logLevelBox->itemData(i) == settings().logLevel()) { + if (ui->logLevelBox->itemData(i) == settings().diagnostics().logLevel()) { ui->logLevelBox->setCurrentIndex(i); break; } @@ -56,7 +56,8 @@ void DiagnosticsSettingsTab::setCrashDumpTypesBox() add(QObject::tr("Data"), CrashDumpsType::Data); add(QObject::tr("Full"), CrashDumpsType::Full); - const auto current = static_cast(settings().crashDumpsType()); + const auto current = static_cast( + settings().diagnostics().crashDumpsType()); for (int i=0; idumpsTypeBox->count(); ++i) { if (ui->dumpsTypeBox->itemData(i) == current) { @@ -68,11 +69,11 @@ void DiagnosticsSettingsTab::setCrashDumpTypesBox() void DiagnosticsSettingsTab::update() { - settings().setLogLevel( + settings().diagnostics().setLogLevel( static_cast(ui->logLevelBox->currentData().toInt())); - settings().setCrashDumpsType( + settings().diagnostics().setCrashDumpsType( static_cast(ui->dumpsTypeBox->currentData().toInt())); - settings().setCrashDumpsMax(ui->dumpsMaxEdit->value()); + settings().diagnostics().setCrashDumpsMax(ui->dumpsMaxEdit->value()); } diff --git a/src/settingsdialoggeneral.cpp b/src/settingsdialoggeneral.cpp index e3d73037..3f7ece38 100644 --- a/src/settingsdialoggeneral.cpp +++ b/src/settingsdialoggeneral.cpp @@ -11,7 +11,7 @@ GeneralSettingsTab::GeneralSettingsTab(Settings& s, SettingsDialog& d) { addLanguages(); { - QString languageCode = settings().language(); + QString languageCode = settings().interface().language(); int currentID = ui->languageBox->findData(languageCode); // I made a mess. :( Most languages are stored with only the iso country // code (2 characters like "de") but chinese @@ -29,7 +29,7 @@ GeneralSettingsTab::GeneralSettingsTab(Settings& s, SettingsDialog& d) { const int currentID = ui->styleBox->findData( - settings().getStyleName().value_or("")); + settings().interface().styleName().value_or("")); if (currentID != -1) { ui->styleBox->setCurrentIndex(currentID); @@ -51,10 +51,10 @@ GeneralSettingsTab::GeneralSettingsTab(Settings& s, SettingsDialog& d) setContainsColor(settings().colors().modlistContainsPlugin()); setContainedColor(settings().colors().pluginListContained()); - ui->compactBox->setChecked(settings().compactDownloads()); - ui->showMetaBox->setChecked(settings().metaDownloads()); + ui->compactBox->setChecked(settings().interface().compactDownloads()); + ui->showMetaBox->setChecked(settings().interface().metaDownloads()); ui->usePrereleaseBox->setChecked(settings().usePrereleases()); - ui->colorSeparatorsBox->setChecked(settings().colorSeparatorScrollbar()); + ui->colorSeparatorsBox->setChecked(settings().colors().colorSeparatorScrollbar()); QObject::connect(ui->overwritingArchiveBtn, &QPushButton::clicked, [&]{ on_overwritingArchiveBtn_clicked(); }); QObject::connect(ui->overwritingBtn, &QPushButton::clicked, [&]{ on_overwritingBtn_clicked(); }); @@ -69,18 +69,18 @@ GeneralSettingsTab::GeneralSettingsTab(Settings& s, SettingsDialog& d) void GeneralSettingsTab::update() { - const QString oldLanguage = settings().language(); + const QString oldLanguage = settings().interface().language(); const QString newLanguage = ui->languageBox->itemData(ui->languageBox->currentIndex()).toString(); if (newLanguage != oldLanguage) { - settings().setLanguage(newLanguage); + settings().interface().setLanguage(newLanguage); emit settings().languageChanged(newLanguage); } - const QString oldStyle = settings().getStyleName().value_or(""); + const QString oldStyle = settings().interface().styleName().value_or(""); const QString newStyle = ui->styleBox->itemData(ui->styleBox->currentIndex()).toString(); if (oldStyle != newStyle) { - settings().setStyleName(newStyle); + settings().interface().setStyleName(newStyle); emit settings().styleChanged(newStyle); } @@ -91,10 +91,10 @@ void GeneralSettingsTab::update() settings().colors().setModlistContainsPlugin(getContainsColor()); settings().colors().setPluginListContained(getContainedColor()); - settings().setCompactDownloads(ui->compactBox->isChecked()); - settings().setMetaDownloads(ui->showMetaBox->isChecked()); + settings().interface().setCompactDownloads(ui->compactBox->isChecked()); + settings().interface().setMetaDownloads(ui->showMetaBox->isChecked()); settings().setUsePrereleases(ui->usePrereleaseBox->isChecked()); - settings().setColorSeparatorScrollbar(ui->colorSeparatorsBox->isChecked()); + settings().colors().setColorSeparatorScrollbar(ui->colorSeparatorsBox->isChecked()); } void GeneralSettingsTab::addLanguages() @@ -145,7 +145,7 @@ void GeneralSettingsTab::addStyles() void GeneralSettingsTab::resetDialogs() { - settings().resetQuestionButtons(); + settings().widgets().resetQuestionButtons(); } void GeneralSettingsTab::setButtonColor(QPushButton *button, const QColor &color) @@ -161,7 +161,7 @@ void GeneralSettingsTab::setButtonColor(QPushButton *button, const QColor &color .arg(color.green()) .arg(color.blue()) .arg(color.alpha()) - .arg(Settings::getIdealTextColor(color).name()) + .arg(ColorSettings::idealTextColor(color).name()) ); }; diff --git a/src/settingsdialognexus.cpp b/src/settingsdialognexus.cpp index 8822200e..0b08f13f 100644 --- a/src/settingsdialognexus.cpp +++ b/src/settingsdialognexus.cpp @@ -74,13 +74,13 @@ private: NexusSettingsTab::NexusSettingsTab(Settings& s, SettingsDialog& d) : SettingsTab(s, d) { - ui->offlineBox->setChecked(settings().offlineMode()); - ui->proxyBox->setChecked(settings().getUseProxy()); - ui->endorsementBox->setChecked(settings().endorsementIntegration()); - ui->hideAPICounterBox->setChecked(settings().hideAPICounter()); + ui->offlineBox->setChecked(settings().network().offlineMode()); + ui->proxyBox->setChecked(settings().network().useProxy()); + ui->endorsementBox->setChecked(settings().nexus().endorsementIntegration()); + ui->hideAPICounterBox->setChecked(settings().interface().hideAPICounter()); // display server preferences - for (const auto& server : s.getServers()) { + for (const auto& server : s.network().servers()) { QString descriptor = server.name(); if (!descriptor.compare("CDN", Qt::CaseInsensitive)) { @@ -117,12 +117,12 @@ NexusSettingsTab::NexusSettingsTab(Settings& s, SettingsDialog& d) void NexusSettingsTab::update() { - settings().setOfflineMode(ui->offlineBox->isChecked()); - settings().setUseProxy(ui->proxyBox->isChecked()); - settings().setEndorsementIntegration(ui->endorsementBox->isChecked()); - settings().setHideAPICounter(ui->hideAPICounterBox->isChecked()); + settings().network().setOfflineMode(ui->offlineBox->isChecked()); + settings().network().setUseProxy(ui->proxyBox->isChecked()); + settings().nexus().setEndorsementIntegration(ui->endorsementBox->isChecked()); + settings().interface().setHideAPICounter(ui->hideAPICounterBox->isChecked()); - auto servers = settings().getServers(); + auto servers = settings().network().servers(); // store server preference for (int i = 0; i < ui->knownServersList->count(); ++i) { @@ -167,7 +167,7 @@ void NexusSettingsTab::update() } } - settings().updateServers(servers); + settings().network().updateServers(servers); } void NexusSettingsTab::on_nexusConnect_clicked() @@ -225,13 +225,13 @@ void NexusSettingsTab::on_nexusDisconnect_clicked() void NexusSettingsTab::on_clearCacheButton_clicked() { - QDir(Settings::instance().getCacheDirectory()).removeRecursively(); + QDir(Settings::instance().paths().cache()).removeRecursively(); NexusInterface::instance(dialog().m_PluginContainer)->clearCache(); } void NexusSettingsTab::on_associateButton_clicked() { - Settings::instance().registerAsNXMHandler(true); + Settings::instance().nexus().registerAsNXMHandler(true); } void NexusSettingsTab::validateKey(const QString& key) @@ -312,7 +312,7 @@ void NexusSettingsTab::addNexusLog(const QString& s) bool NexusSettingsTab::setKey(const QString& key) { dialog().m_keyChanged = true; - const bool ret = settings().setNexusApiKey(key); + const bool ret = settings().nexus().setApiKey(key); updateNexusState(); return ret; } @@ -320,7 +320,7 @@ bool NexusSettingsTab::setKey(const QString& key) bool NexusSettingsTab::clearKey() { dialog().m_keyChanged = true; - const auto ret = settings().clearNexusApiKey(); + const auto ret = settings().nexus().clearApiKey(); NexusInterface::instance(dialog().m_PluginContainer)->getAccessManager()->clearApiKey(); updateNexusState(); @@ -352,7 +352,7 @@ void NexusSettingsTab::updateNexusButtons() ui->nexusManualKey->setText(QObject::tr("Cancel")); ui->nexusManualKey->setEnabled(true); } - else if (settings().hasNexusApiKey()) { + else if (settings().nexus().hasApiKey()) { // api key is present ui->nexusConnect->setText(QObject::tr("Connect to Nexus")); ui->nexusConnect->setEnabled(false); diff --git a/src/settingsdialogpaths.cpp b/src/settingsdialogpaths.cpp index 32aaf4bf..aeb4dd5d 100644 --- a/src/settingsdialogpaths.cpp +++ b/src/settingsdialogpaths.cpp @@ -6,17 +6,23 @@ PathsSettingsTab::PathsSettingsTab(Settings& s, SettingsDialog& d) : SettingsTab(s, d) { - ui->baseDirEdit->setText(settings().getBaseDirectory()); - ui->managedGameDirEdit->setText(settings().gamePlugin()->gameDirectory().absoluteFilePath(settings().gamePlugin()->binaryName())); - QString basePath = settings().getBaseDirectory(); + ui->baseDirEdit->setText(settings().paths().base()); + + ui->managedGameDirEdit->setText( + settings().game().plugin()->gameDirectory().absoluteFilePath( + settings().game().plugin()->binaryName())); + + QString basePath = settings().paths().base(); QDir baseDir(basePath); + for (const auto &dir : { - std::make_pair(ui->downloadDirEdit, settings().getDownloadDirectory(false)), - std::make_pair(ui->modDirEdit, settings().getModDirectory(false)), - std::make_pair(ui->cacheDirEdit, settings().getCacheDirectory(false)), - std::make_pair(ui->profilesDirEdit, settings().getProfileDirectory(false)), - std::make_pair(ui->overwriteDirEdit, settings().getOverwriteDirectory(false)) + 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; dir.first->setText(storePath); @@ -40,17 +46,17 @@ PathsSettingsTab::PathsSettingsTab(Settings& s, SettingsDialog& d) void PathsSettingsTab::update() { - using Setter = void (Settings::*)(const QString&); + using Setter = void (PathSettings::*)(const QString&); using Directory = std::tuple; - QString basePath = settings().getBaseDirectory(); + QString basePath = settings().paths().base(); for (const Directory &dir :{ - Directory{ui->downloadDirEdit->text(), &Settings::setDownloadDirectory, AppConfig::downloadPath()}, - Directory{ui->cacheDirEdit->text(), &Settings::setCacheDirectory, AppConfig::cachePath()}, - Directory{ui->modDirEdit->text(), &Settings::setModDirectory, AppConfig::modsPath()}, - Directory{ui->overwriteDirEdit->text(), &Settings::setOverwriteDirectory, AppConfig::overwritePath()}, - Directory{ui->profilesDirEdit->text(), &Settings::setProfileDirectory, AppConfig::profilesPath()} + 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; @@ -70,22 +76,26 @@ void PathsSettingsTab::update() } if (QFileInfo(realPath) != QFileInfo(basePath + "/" + QString::fromStdWString(defaultName))) { - (settings().*setter)(path); + (settings().paths().*setter)(path); } else { - (settings().*setter)(""); + (settings().paths().*setter)(""); } } if (QFileInfo(ui->baseDirEdit->text()) != QFileInfo(qApp->property("dataPath").toString())) { - settings().setBaseDirectory(ui->baseDirEdit->text()); + settings().paths().setBase(ui->baseDirEdit->text()); } else { - settings().setBaseDirectory(""); + settings().paths().setBase(""); } - QFileInfo oldGameExe(settings().gamePlugin()->gameDirectory().absoluteFilePath(settings().gamePlugin()->binaryName())); + QFileInfo oldGameExe( + settings().game().plugin()->gameDirectory().absoluteFilePath( + settings().game().plugin()->binaryName())); + QFileInfo newGameExe(ui->managedGameDirEdit->text()); + if (oldGameExe != newGameExe) { - settings().setManagedGameDirectory(newGameExe.absolutePath()); + settings().game().setDirectory(newGameExe.absolutePath()); } } diff --git a/src/settingsdialogsteam.cpp b/src/settingsdialogsteam.cpp index 9ed93e47..3c4c5de6 100644 --- a/src/settingsdialogsteam.cpp +++ b/src/settingsdialogsteam.cpp @@ -5,7 +5,7 @@ SteamSettingsTab::SteamSettingsTab(Settings& s, SettingsDialog& d) : SettingsTab(s, d) { QString username, password; - settings().getSteamLogin(username, password); + settings().steam().login(username, password); ui->steamUserEdit->setText(username); ui->steamPassEdit->setText(password); @@ -13,5 +13,5 @@ SteamSettingsTab::SteamSettingsTab(Settings& s, SettingsDialog& d) void SteamSettingsTab::update() { - settings().setSteamLogin(ui->steamUserEdit->text(), ui->steamPassEdit->text()); + settings().steam().setLogin(ui->steamUserEdit->text(), ui->steamPassEdit->text()); } diff --git a/src/settingsdialogworkarounds.cpp b/src/settingsdialogworkarounds.cpp index b06bd77c..4d811e40 100644 --- a/src/settingsdialogworkarounds.cpp +++ b/src/settingsdialogworkarounds.cpp @@ -6,12 +6,12 @@ WorkaroundsSettingsTab::WorkaroundsSettingsTab(Settings& s, SettingsDialog& d) : SettingsTab(s, d) { - ui->appIDEdit->setText(settings().getSteamAppID()); + ui->appIDEdit->setText(settings().steam().appID()); - LoadMechanism::EMechanism mechanismID = settings().getLoadMechanism(); + LoadMechanism::EMechanism mechanismID = settings().game().loadMechanismType(); int index = 0; - if (settings().loadMechanism().isDirectLoadingSupported()) { + if (settings().game().loadMechanism().isDirectLoadingSupported()) { ui->mechanismBox->addItem(QObject::tr("Mod Organizer"), LoadMechanism::LOAD_MODORGANIZER); if (mechanismID == LoadMechanism::LOAD_MODORGANIZER) { index = ui->mechanismBox->count() - 1; @@ -20,10 +20,10 @@ WorkaroundsSettingsTab::WorkaroundsSettingsTab(Settings& s, SettingsDialog& d) ui->mechanismBox->setCurrentIndex(index); - ui->hideUncheckedBox->setChecked(settings().hideUncheckedPlugins()); - ui->forceEnableBox->setChecked(settings().forceEnableCoreFiles()); - ui->displayForeignBox->setChecked(settings().displayForeign()); - ui->lockGUIBox->setChecked(settings().lockGUI()); + ui->hideUncheckedBox->setChecked(settings().game().hideUncheckedPlugins()); + ui->forceEnableBox->setChecked(settings().game().forceEnableCoreFiles()); + ui->displayForeignBox->setChecked(settings().interface().displayForeign()); + ui->lockGUIBox->setChecked(settings().interface().lockGUI()); ui->enableArchiveParsingBox->setChecked(settings().archiveParsing()); setExecutableBlacklist(settings().executablesBlacklist()); @@ -35,19 +35,19 @@ WorkaroundsSettingsTab::WorkaroundsSettingsTab(Settings& s, SettingsDialog& d) void WorkaroundsSettingsTab::update() { - if (ui->appIDEdit->text() != settings().gamePlugin()->steamAPPId()) { - settings().setSteamAppID(ui->appIDEdit->text()); + if (ui->appIDEdit->text() != settings().game().plugin()->steamAPPId()) { + settings().steam().setAppID(ui->appIDEdit->text()); } else { - settings().setSteamAppID(""); + settings().steam().setAppID(""); } - settings().setLoadMechanism(static_cast( + settings().game().setLoadMechanism(static_cast( ui->mechanismBox->itemData(ui->mechanismBox->currentIndex()).toInt())); - settings().setHideUncheckedPlugins(ui->hideUncheckedBox->isChecked()); - settings().setForceEnableCoreFiles(ui->forceEnableBox->isChecked()); - settings().setDisplayForeign(ui->displayForeignBox->isChecked()); - settings().setLockGUI(ui->lockGUIBox->isChecked()); + settings().game().setHideUncheckedPlugins(ui->hideUncheckedBox->isChecked()); + settings().game().setForceEnableCoreFiles(ui->forceEnableBox->isChecked()); + settings().interface().setDisplayForeign(ui->displayForeignBox->isChecked()); + settings().interface().setLockGUI(ui->lockGUIBox->isChecked()); settings().setArchiveParsing(ui->enableArchiveParsingBox->isChecked()); settings().setExecutablesBlacklist(getExecutableBlacklist()); } diff --git a/src/statusbar.cpp b/src/statusbar.cpp index d22010a5..3734aa87 100644 --- a/src/statusbar.cpp +++ b/src/statusbar.cpp @@ -129,7 +129,7 @@ void StatusBar::setUpdateAvailable(bool b) void StatusBar::checkSettings(const Settings& settings) { - m_api->setVisible(!settings.hideAPICounter()); + m_api->setVisible(!settings.interface().hideAPICounter()); } void StatusBar::showEvent(QShowEvent*) diff --git a/src/usvfsconnector.cpp b/src/usvfsconnector.cpp index 41f58308..4315ed92 100644 --- a/src/usvfsconnector.cpp +++ b/src/usvfsconnector.cpp @@ -163,8 +163,8 @@ QString toString(CrashDumpsType t) UsvfsConnector::UsvfsConnector() { USVFSParameters params; - LogLevel level = toUsvfsLogLevel(Settings::instance().logLevel()); - CrashDumpsType dumpType = Settings::instance().crashDumpsType(); + LogLevel level = toUsvfsLogLevel(Settings::instance().diagnostics().logLevel()); + CrashDumpsType dumpType = Settings::instance().diagnostics().crashDumpsType(); std::string dumpPath = MOShared::ToString(OrganizerCore::crashDumpsPath(), true); USVFSInitParameters(¶ms, SHMID, false, level, dumpType, dumpPath.c_str()); -- cgit v1.3.1 From c17b0829dc23b488523a12e0748b18aab1f427c9 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 4 Oct 2019 07:14:30 -0400 Subject: emblemes -> emblems --- src/modlist.cpp | 2 +- src/pluginlist.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/modlist.cpp') diff --git a/src/modlist.cpp b/src/modlist.cpp index 6018d3d4..c5bc37e9 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -1272,7 +1272,7 @@ QString ModList::getColumnToolTip(int column) case COL_CATEGORY: return tr("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_FLAGS: return tr("Emblemes to highlight things that might require attention."); + case COL_FLAGS: return tr("Emblems to highlight things that might require attention."); case COL_CONTENT: return tr("Depicts the content of the mod:
" "" "" diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index 31e88f7e..5f1ae347 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -114,7 +114,7 @@ QString PluginList::getColumnToolTip(int column) { switch (column) { case COL_NAME: return tr("Name of the plugin"); - case COL_FLAGS: return tr("Emblemes to highlight things that might require attention."); + 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."); -- cgit v1.3.1 From 7f2d0e672205b85425cff488aa41ba0117abd191 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Wed, 27 Nov 2019 15:15:27 -0500 Subject: fix crash when changing categories on mods when the "no categories" filter is selected --- src/modlist.cpp | 27 +++++++++++++++++++++++++++ src/modlist.h | 1 + 2 files changed, 28 insertions(+) (limited to 'src/modlist.cpp') diff --git a/src/modlist.cpp b/src/modlist.cpp index c5bc37e9..b7a9b0a1 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -61,6 +61,7 @@ ModList::ModList(PluginContainer *pluginContainer, QObject *parent) , m_Profile(nullptr) , m_NexusInterface(nullptr) , m_Modified(false) + , m_InNotifyChange(false) , m_FontMetrics(QFont()) , m_DropOnItems(false) , m_PluginContainer(pluginContainer) @@ -1195,6 +1196,32 @@ bool ModList::removeRows(int row, int count, const QModelIndex &parent) void ModList::notifyChange(int rowStart, int rowEnd) { + // this function can emit dataChanged(), which can eventually recurse back + // here; for example: + // + // - a filter is active in the mod list, such as "no categories" + // - mods are selected and a category is set on them + // - these mods get updated here and disappear from the list because they're + // not in "no categories" anymore + // - dataChanged() is emitted + // - it's picked up in MainWindow::modlistSelectionsChanged() because the + // selected mods are gone + // - it calls setOverwriteMarkers(), which calls notifyChange() again and + // ends up here + // - dataChanged() is emitted again + // + // at this point, MO crashes because dataChanged() is not reentrant: it's in + // the middle of modifying internal data and crashes when trying to change an + // internal vector + // + // long story short, this prevents reentrancy + if (m_InNotifyChange) { + return; + } + + m_InNotifyChange = true; + Guard g([&]{ m_InNotifyChange = false; }); + if (rowStart < 0) { m_Overwrite.clear(); m_Overwritten.clear(); diff --git a/src/modlist.h b/src/modlist.h index 5ce32f6e..631401c0 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -341,6 +341,7 @@ private: std::set m_RequestIDs; mutable bool m_Modified; + bool m_InNotifyChange; QFontMetrics m_FontMetrics; -- cgit v1.3.1 From b3331ef2c0b50ab2cea4c328e78f6ab58bca099d Mon Sep 17 00:00:00 2001 From: Silarn Date: Fri, 6 Dec 2019 23:12:18 -0600 Subject: Separate conflict flags and render them in separate columns --- src/CMakeLists.txt | 3 + src/colortable.cpp | 61 +- src/mainwindow.cpp | 22 +- src/modconflicticondelegate.cpp | 160 ++ src/modconflicticondelegate.h | 36 + src/modflagicondelegate.cpp | 74 +- src/modflagicondelegate.h | 4 - src/modinfo.h | 25 +- src/modinfobackup.cpp | 1 + src/modinfodialogfwd.h | 1 + src/modinfooverwrite.cpp | 9 + src/modinfooverwrite.h | 1 + src/modinfowithconflictinfo.cpp | 4 +- src/modinfowithconflictinfo.h | 3 +- src/modlist.cpp | 40 +- src/modlist.h | 3 + src/modlistsortproxy.cpp | 21 + src/modlistsortproxy.h | 1 + src/organizer_en.ts | 3671 ++++++++++++++++++++++----------------- 19 files changed, 2390 insertions(+), 1750 deletions(-) create mode 100644 src/modconflicticondelegate.cpp create mode 100644 src/modconflicticondelegate.h (limited to 'src/modlist.cpp') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a46908ef..d0215930 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -114,6 +114,7 @@ SET(organizer_SRCS previewdialog.cpp aboutdialog.cpp modflagicondelegate.cpp + modconflicticondelegate.cpp genericicondelegate.cpp organizerproxy.cpp viewmarkingscrollbar.cpp @@ -238,6 +239,7 @@ SET(organizer_HDRS previewdialog.h aboutdialog.h modflagicondelegate.h + modconflicticondelegate.h genericicondelegate.h organizerproxy.h viewmarkingscrollbar.h @@ -491,6 +493,7 @@ set(widgets loglist loghighlighter modflagicondelegate + modconflicticondelegate modidlineedit noeditdelegate qtgroupingproxy diff --git a/src/colortable.cpp b/src/colortable.cpp index 61c5ee5f..b1e4ef6c 100644 --- a/src/colortable.cpp +++ b/src/colortable.cpp @@ -1,5 +1,6 @@ #include "colortable.h" #include "modflagicondelegate.h" +#include "modconflicticondelegate.h" #include "settings.h" class ColorItem; @@ -52,21 +53,17 @@ public: } void paint( - QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index) const override + QPainter* painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const override { paintBackground(m_table, painter, option, index); ModFlagIconDelegate::paintIcons(painter, option, index, getIcons(index)); } protected: - QList getIcons(const QModelIndex &index) const override + QList 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, ModInfo::FLAG_BACKUP, ModInfo::FLAG_NOTENDORSED, ModInfo::FLAG_NOTES, @@ -76,7 +73,48 @@ protected: return getIconsForFlags(flags, false); } - size_t getNumIcons(const QModelIndex &index) const override + size_t getNumIcons(const QModelIndex& index) const override + { + return getIcons(index).size(); + } + +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) + { + } + + 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)); + } + +protected: + QList 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 + }; + + return getIconsForFlags(flags, false); + } + + size_t getNumIcons(const QModelIndex& index) const override { return getIcons(index).size(); } @@ -183,11 +221,12 @@ void paintBackground( ColorTable::ColorTable(QWidget* parent) : QTableWidget(parent), m_settings(nullptr) { - setColumnCount(3); - setHorizontalHeaderLabels({"", "", ""}); + setColumnCount(4); + setHorizontalHeaderLabels({"", "", "", ""}); setItemDelegateForColumn(1, new ColoredBackgroundDelegate(this)); - setItemDelegateForColumn(2, new FakeModFlagIconDelegate(this)); + setItemDelegateForColumn(2, new FakeModConflictIconDelegate(this)); + setItemDelegateForColumn(3, new FakeModFlagIconDelegate(this)); connect( this, &QTableWidget::cellActivated, diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index cb242b88..68627c90 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -61,6 +61,7 @@ along with Mod Organizer. If not, see . #include "filedialogmemory.h" #include "tutorialmanager.h" #include "modflagicondelegate.h" +#include "modconflicticondelegate.h" #include "genericicondelegate.h" #include "selectiondialog.h" #include "csvbuilder.h" @@ -552,7 +553,16 @@ void MainWindow::setupModList() flagDelegate, SLOT(columnResized(int,int,int))); + ModConflictIconDelegate* conflictFlagDelegate = new ModConflictIconDelegate( + ui->modList, ModList::COL_CONFLICTFLAGS, 120); + + connect( + ui->modList->header(), SIGNAL(sectionResized(int, int, int)), + conflictFlagDelegate, SLOT(columnResized(int, int, int))); + + ui->modList->setItemDelegateForColumn(ModList::COL_FLAGS, flagDelegate); + ui->modList->setItemDelegateForColumn(ModList::COL_CONFLICTFLAGS, conflictFlagDelegate); ui->modList->setItemDelegateForColumn(ModList::COL_CONTENT, contentDelegate); ui->modList->header()->installEventFilter(m_OrganizerCore.modList()); @@ -2317,6 +2327,15 @@ void MainWindow::processUpdates(Settings& settings) { ui->downloadView->header()->hideSection(i); } } + + if (lastVersion < QVersionNumber(2, 2, 2)) { + bool lastHidden = true; + for (int i = ModList::COL_CONFLICTFLAGS; i < ui->modList->model()->columnCount(); ++i) { + bool hidden = ui->modList->header()->isSectionHidden(i); + ui->modList->header()->setSectionHidden(i, lastHidden); + lastHidden = hidden; + } + } } if (currentVersion < lastVersion) { @@ -3877,7 +3896,8 @@ void MainWindow::on_modList_doubleClicked(const QModelIndex &index) 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_FLAGS: tab = ModInfoTabIDs::Conflicts; break; + case ModList::COL_CONFLICTFLAGS: tab = ModInfoTabIDs::Conflicts; break; + case ModList::COL_FLAGS: tab = ModInfoTabIDs::Flags; break; } displayModInformation(sourceIdx.row(), tab); diff --git a/src/modconflicticondelegate.cpp b/src/modconflicticondelegate.cpp new file mode 100644 index 00000000..2ccf3363 --- /dev/null +++ b/src/modconflicticondelegate.cpp @@ -0,0 +1,160 @@ +#include "modconflicticondelegate.h" +#include +#include + +using namespace MOBase; + +ModInfo::EConflictFlag ModConflictIconDelegate::m_ConflictFlags[4] = { ModInfo::FLAG_CONFLICT_MIXED + , ModInfo::FLAG_CONFLICT_OVERWRITE + , ModInfo::FLAG_CONFLICT_OVERWRITTEN + , ModInfo::FLAG_CONFLICT_REDUNDANT }; + +ModInfo::EConflictFlag ModConflictIconDelegate::m_ArchiveLooseConflictFlags[2] = { ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITE + , ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITTEN }; + +ModInfo::EConflictFlag ModConflictIconDelegate::m_ArchiveConflictFlags[3] = { ModInfo::FLAG_ARCHIVE_CONFLICT_MIXED + , ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITE + , ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITTEN }; + +ModConflictIconDelegate::ModConflictIconDelegate(QObject *parent, int logicalIndex, int compactSize) + : IconDelegate(parent) + , m_LogicalIndex(logicalIndex) + , m_CompactSize(compactSize) + , m_Compact(false) +{ +} + +void ModConflictIconDelegate::columnResized(int logicalIndex, int, int newSize) +{ + if (logicalIndex == m_LogicalIndex) { + m_Compact = newSize < m_CompactSize; + } +} + +QList ModConflictIconDelegate::getIconsForFlags( + std::vector flags, bool compact) +{ + QList result; + + // Don't do flags for overwrite + 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(), + m_ConflictFlags, m_ConflictFlags + 4); + if (iter != flags.end()) { + result.append(getFlagIcon(*iter)); + flags.erase(iter); + } else if (!compact) { + result.append(QString()); + } + } + + { // insert loose vs archive overwrite second + auto iter = std::find(flags.begin(), flags.end(), + ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITE); + if (iter != flags.end()) { + result.append(getFlagIcon(*iter)); + flags.erase(iter); + } else if (!compact) { + result.append(QString()); + } + } + + { // insert loose vs archive overwritten third + auto iter = std::find_first_of(flags.begin(), flags.end(), + m_ArchiveLooseConflictFlags + 1, m_ArchiveLooseConflictFlags + 2); + if (iter != flags.end()) { + result.append(getFlagIcon(*iter)); + flags.erase(iter); + } else if (!compact) { + result.append(QString()); + } + } + + { // insert archive conflicts last + auto iter = std::find_first_of(flags.begin(), flags.end(), + m_ArchiveConflictFlags, m_ArchiveConflictFlags + 3); + if (iter != flags.end()) { + result.append(getFlagIcon(*iter)); + flags.erase(iter); + } else if (!compact) { + result.append(QString()); + } + } + + for (auto iter = flags.begin(); iter != flags.end(); ++iter) { + auto iconPath = getFlagIcon(*iter); + if (!iconPath.isEmpty()) + result.append(iconPath); + } + + return result; +} + +QList ModConflictIconDelegate::getIcons(const QModelIndex &index) const +{ + QVariant modid = index.data(Qt::UserRole + 1); + + if (modid.isValid()) { + ModInfo::Ptr info = ModInfo::getByIndex(modid.toInt()); + return getIconsForFlags(info->getConflictFlags(), m_Compact); + } + + return {}; +} + +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(); + } +} + +size_t ModConflictIconDelegate::getNumIcons(const QModelIndex &index) const +{ + unsigned int modIdx = index.data(Qt::UserRole + 1).toInt(); + if (modIdx < ModInfo::getNumMods()) { + ModInfo::Ptr info = ModInfo::getByIndex(modIdx); + std::vector flags = info->getConflictFlags(); + size_t count = flags.size(); + if (std::find_first_of(flags.begin(), flags.end(), m_ConflictFlags, m_ConflictFlags + 4) == flags.end()) { + ++count; + } + return count; + } else { + return 0; + } +} + + +QSize ModConflictIconDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &modelIndex) const +{ + size_t count = getNumIcons(modelIndex); + unsigned int index = modelIndex.data(Qt::UserRole + 1).toInt(); + QSize result; + if (index < ModInfo::getNumMods()) { + result = QSize(static_cast(count) * 40, 20); + } else { + result = QSize(1, 20); + } + if (option.rect.width() > 0) { + result.setWidth(std::min(option.rect.width(), result.width())); + } + return result; +} + diff --git a/src/modconflicticondelegate.h b/src/modconflicticondelegate.h new file mode 100644 index 00000000..d36477c6 --- /dev/null +++ b/src/modconflicticondelegate.h @@ -0,0 +1,36 @@ +#ifndef MODCONFLICTICONDELEGATE_H +#define MODCONFLICTICONDELEGATE_H + +#include "icondelegate.h" + +class ModConflictIconDelegate : public IconDelegate +{ + Q_OBJECT; + +public: + explicit ModConflictIconDelegate(QObject *parent = 0, int logicalIndex = -1, int compactSize = 120); + virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; + + static QList getIconsForFlags( + std::vector flags, bool compact); + + static QString getFlagIcon(ModInfo::EConflictFlag flag); + +public slots: + void columnResized(int logicalIndex, int oldSize, int newSize); + +protected: + virtual QList getIcons(const QModelIndex &index) const; + virtual size_t getNumIcons(const QModelIndex &index) const; + +private: + static ModInfo::EConflictFlag m_ConflictFlags[4]; + static ModInfo::EConflictFlag m_ArchiveLooseConflictFlags[2]; + static ModInfo::EConflictFlag m_ArchiveConflictFlags[3]; + + int m_LogicalIndex; + int m_CompactSize; + bool m_Compact; +}; + +#endif // MODCONFLICTICONDELEGATE_H diff --git a/src/modflagicondelegate.cpp b/src/modflagicondelegate.cpp index a5e9aa22..6e1df147 100644 --- a/src/modflagicondelegate.cpp +++ b/src/modflagicondelegate.cpp @@ -4,18 +4,6 @@ using namespace MOBase; -ModInfo::EFlag ModFlagIconDelegate::m_ConflictFlags[4] = { ModInfo::FLAG_CONFLICT_MIXED - , ModInfo::FLAG_CONFLICT_OVERWRITE - , ModInfo::FLAG_CONFLICT_OVERWRITTEN - , ModInfo::FLAG_CONFLICT_REDUNDANT }; - -ModInfo::EFlag ModFlagIconDelegate::m_ArchiveLooseConflictFlags[2] = { ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITE - , ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITTEN }; - -ModInfo::EFlag ModFlagIconDelegate::m_ArchiveConflictFlags[3] = { ModInfo::FLAG_ARCHIVE_CONFLICT_MIXED - , ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITE - , ModInfo::FLAG_ARCHIVE_CONFLICT_OVERWRITTEN }; - ModFlagIconDelegate::ModFlagIconDelegate(QObject *parent, int logicalIndex, int compactSize) : IconDelegate(parent) , m_LogicalIndex(logicalIndex) @@ -37,54 +25,9 @@ QList ModFlagIconDelegate::getIconsForFlags( QList result; // Don't do flags for overwrite - if (std::find(flags.begin(), flags.end(),ModInfo::FLAG_OVERWRITE) != flags.end()) + if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != 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(), - m_ConflictFlags, m_ConflictFlags + 4); - if (iter != flags.end()) { - result.append(getFlagIcon(*iter)); - flags.erase(iter); - } else if (!compact) { - result.append(QString()); - } - } - - { // insert loose vs archive overwrite second - auto iter = std::find(flags.begin(), flags.end(), - ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITE); - if (iter != flags.end()) { - result.append(getFlagIcon(*iter)); - flags.erase(iter); - } else if (!compact) { - result.append(QString()); - } - } - - { // insert loose vs archive overwritten third - auto iter = std::find_first_of(flags.begin(), flags.end(), - m_ArchiveLooseConflictFlags + 1, m_ArchiveLooseConflictFlags + 2); - if (iter != flags.end()) { - result.append(getFlagIcon(*iter)); - flags.erase(iter); - } else if (!compact) { - result.append(QString()); - } - } - - { // insert archive conflicts last - auto iter = std::find_first_of(flags.begin(), flags.end(), - m_ArchiveConflictFlags, m_ArchiveConflictFlags + 3); - if (iter != flags.end()) { - result.append(getFlagIcon(*iter)); - flags.erase(iter); - } else if (!compact) { - result.append(QString()); - } - } - for (auto iter = flags.begin(); iter != flags.end(); ++iter) { auto iconPath = getFlagIcon(*iter); if (!iconPath.isEmpty()) @@ -113,15 +56,6 @@ QString ModFlagIconDelegate::getFlagIcon(ModInfo::EFlag flag) 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_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_ALTERNATE_GAME: return QStringLiteral(":/MO/gui/alternate_game"); case ModInfo::FLAG_FOREIGN: return QString(); case ModInfo::FLAG_SEPARATOR: return QString(); @@ -140,11 +74,7 @@ size_t ModFlagIconDelegate::getNumIcons(const QModelIndex &index) const if (modIdx < ModInfo::getNumMods()) { ModInfo::Ptr info = ModInfo::getByIndex(modIdx); std::vector flags = info->getFlags(); - size_t count = flags.size(); - if (std::find_first_of(flags.begin(), flags.end(), m_ConflictFlags, m_ConflictFlags + 4) == flags.end()) { - ++count; - } - return count; + return flags.size(); } else { return 0; } diff --git a/src/modflagicondelegate.h b/src/modflagicondelegate.h index 4f22dd90..ecab7e95 100644 --- a/src/modflagicondelegate.h +++ b/src/modflagicondelegate.h @@ -24,10 +24,6 @@ protected: virtual size_t getNumIcons(const QModelIndex &index) const; private: - static ModInfo::EFlag m_ConflictFlags[4]; - static ModInfo::EFlag m_ArchiveLooseConflictFlags[2]; - static ModInfo::EFlag m_ArchiveConflictFlags[3]; - int m_LogicalIndex; int m_CompactSize; bool m_Compact; diff --git a/src/modinfo.h b/src/modinfo.h index 30a115c7..7c41e0a1 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -60,14 +60,7 @@ public: static QString s_HiddenExt; - enum EFlag { - FLAG_INVALID, - FLAG_BACKUP, - FLAG_SEPARATOR, - FLAG_OVERWRITE, - FLAG_FOREIGN, - FLAG_NOTENDORSED, - FLAG_NOTES, + enum EConflictFlag { FLAG_CONFLICT_OVERWRITE, FLAG_CONFLICT_OVERWRITTEN, FLAG_CONFLICT_MIXED, @@ -77,6 +70,17 @@ public: FLAG_ARCHIVE_CONFLICT_OVERWRITE, FLAG_ARCHIVE_CONFLICT_OVERWRITTEN, FLAG_ARCHIVE_CONFLICT_MIXED, + FLAG_OVERWRITE_CONFLICT, + }; + + enum EFlag { + FLAG_INVALID, + FLAG_BACKUP, + FLAG_SEPARATOR, + FLAG_OVERWRITE, + FLAG_FOREIGN, + FLAG_NOTENDORSED, + FLAG_NOTES, FLAG_PLUGIN_SELECTED, FLAG_ALTERNATE_GAME, FLAG_TRACKED, @@ -519,6 +523,11 @@ public: */ virtual std::vector getFlags() const = 0; + /** + * @return a list of conflict flags for this mod + */ + virtual std::vector getConflictFlags() const = 0; + /** * @return a list of content types contained in a mod */ diff --git a/src/modinfobackup.cpp b/src/modinfobackup.cpp index 6e307103..6a34b86a 100644 --- a/src/modinfobackup.cpp +++ b/src/modinfobackup.cpp @@ -1,5 +1,6 @@ #include "modinfobackup.h" + std::vector ModInfoBackup::getFlags() const { std::vector result = ModInfoRegular::getFlags(); diff --git a/src/modinfodialogfwd.h b/src/modinfodialogfwd.h index 2147fc04..e4a61208 100644 --- a/src/modinfodialogfwd.h +++ b/src/modinfodialogfwd.h @@ -14,6 +14,7 @@ enum class ModInfoTabIDs Images, Esps, Conflicts, + Flags, Categories, Nexus, Notes, diff --git a/src/modinfooverwrite.cpp b/src/modinfooverwrite.cpp index fb110abb..9a6a22c1 100644 --- a/src/modinfooverwrite.cpp +++ b/src/modinfooverwrite.cpp @@ -37,6 +37,15 @@ std::vector ModInfoOverwrite::getFlags() const return result; } +std::vector ModInfoOverwrite::getConflictFlags() const +{ + std::vector result; + result.push_back(FLAG_OVERWRITE_CONFLICT); + for (auto flag : ModInfoWithConflictInfo::getConflictFlags()) + result.push_back(flag); + return result; +} + int ModInfoOverwrite::getHighlight() const { int highlight = (isValid() ? HIGHLIGHT_IMPORTANT : HIGHLIGHT_INVALID) | HIGHLIGHT_CENTER; diff --git a/src/modinfooverwrite.h b/src/modinfooverwrite.h index c5f58c2e..ecbdbe3d 100644 --- a/src/modinfooverwrite.h +++ b/src/modinfooverwrite.h @@ -51,6 +51,7 @@ public: virtual QDateTime getExpires() const { return QDateTime(); } virtual std::vector getIniTweaks() const { return std::vector(); } virtual std::vector getFlags() const; + virtual std::vector getConflictFlags() const; virtual int getHighlight() const; virtual QString getDescription() const; virtual int getNexusFileStatus() const { return 0; } diff --git a/src/modinfowithconflictinfo.cpp b/src/modinfowithconflictinfo.cpp index 7a2b0071..f5a243ae 100644 --- a/src/modinfowithconflictinfo.cpp +++ b/src/modinfowithconflictinfo.cpp @@ -14,9 +14,9 @@ void ModInfoWithConflictInfo::clearCaches() m_LastConflictCheck = QTime(); } -std::vector ModInfoWithConflictInfo::getFlags() const +std::vector ModInfoWithConflictInfo::getConflictFlags() const { - std::vector result; + std::vector result; switch (isConflicted()) { case CONFLICT_MIXED: { result.push_back(ModInfo::FLAG_CONFLICT_MIXED); diff --git a/src/modinfowithconflictinfo.h b/src/modinfowithconflictinfo.h index 13d87d25..9869bc5a 100644 --- a/src/modinfowithconflictinfo.h +++ b/src/modinfowithconflictinfo.h @@ -12,7 +12,8 @@ public: ModInfoWithConflictInfo(PluginContainer *pluginContainer, MOShared::DirectoryEntry **directoryStructure); - std::vector getFlags() const; + std::vector getConflictFlags() const; + virtual std::vector getFlags() const { return std::vector(); }; /** * @brief clear all caches held for this mod diff --git a/src/modlist.cpp b/src/modlist.cpp index b7a9b0a1..c5b8c856 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -159,15 +159,6 @@ QString ModList::getFlagText(ModInfo::EFlag flag, ModInfo::Ptr modInfo) const output << QString("%1").arg(modInfo->notes()); return output.join(""); } - 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"); case ModInfo::FLAG_ALTERNATE_GAME: return tr("
This mod is for a different game, " "make sure it's compatible or it could cause crashes."); case ModInfo::FLAG_TRACKED: return tr("Mod is being tracked on the website"); @@ -176,6 +167,23 @@ QString ModList::getFlagText(ModInfo::EFlag 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 ""; + } +} + + QVariantList ModList::contentsToIcons(const std::vector &contents) const { QVariantList result; @@ -218,7 +226,8 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) { if ((column == COL_FLAGS) - || (column == COL_CONTENT)) { + || (column == COL_CONTENT) + || (column == COL_CONFLICTFLAGS)) { return QVariant(); } else if (column == COL_NAME) { auto flags = modInfo->getFlags(); @@ -443,6 +452,15 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const result += getFlagText(flag, modInfo); } + return result; + } else if (column == COL_CONFLICTFLAGS) { + QString result; + + for (ModInfo::EConflictFlag flag : modInfo->getConflictFlags()) { + if (result.length() != 0) result += "
"; + result += getConflictFlagText(flag, modInfo); + } + return result; } else if (column == COL_CONTENT) { return contentsToToolTip(modInfo->getContents()); @@ -1274,6 +1292,7 @@ void ModList::dropModeUpdate(bool dropOnItems) 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"); @@ -1299,6 +1318,7 @@ QString ModList::getColumnToolTip(int column) case COL_CATEGORY: return tr("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: return tr("Depicts the content of the mod:
" "
Game plugins (esp/esm/esl)
" diff --git a/src/modlist.h b/src/modlist.h index 631401c0..8841ec29 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -57,6 +57,7 @@ public: enum EColumn { COL_NAME, + COL_CONFLICTFLAGS, COL_FLAGS, COL_CONTENT, COL_CATEGORY, @@ -289,6 +290,8 @@ private: QString getFlagText(ModInfo::EFlag flag, ModInfo::Ptr modInfo) const; + QString getConflictFlagText(ModInfo::EConflictFlag flag, ModInfo::Ptr modInfo) const; + static QString getColumnToolTip(int column); QVariantList contentsToIcons(const std::vector &content) const; diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp index 64d5de42..440786c5 100644 --- a/src/modlistsortproxy.cpp +++ b/src/modlistsortproxy.cpp @@ -115,6 +115,17 @@ unsigned long ModListSortProxy::flagsId(const std::vector &flags return result; } +unsigned long ModListSortProxy::conflictFlagsId(const std::vector& flags) const +{ + unsigned long result = 0; + for (ModInfo::EConflictFlag flag : flags) { + if ((flag != ModInfo::FLAG_OVERWRITE_CONFLICT)) { + result += 1 << (int)flag; + } + } + return result; +} + bool ModListSortProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const { @@ -155,6 +166,16 @@ bool ModListSortProxy::lessThan(const QModelIndex &left, lt = flagsId(leftFlags) < flagsId(rightFlags); } } break; + case ModList::COL_CONFLICTFLAGS: { + std::vector leftFlags = leftMod->getConflictFlags(); + std::vector rightFlags = rightMod->getConflictFlags(); + if (leftFlags.size() != rightFlags.size()) { + lt = leftFlags.size() < rightFlags.size(); + } + else { + lt = conflictFlagsId(leftFlags) < conflictFlagsId(rightFlags); + } + } break; case ModList::COL_CONTENT: { std::vector lContent = leftMod->getContents(); std::vector rContent = rightMod->getContents(); diff --git a/src/modlistsortproxy.h b/src/modlistsortproxy.h index 46356fe9..d733b783 100644 --- a/src/modlistsortproxy.h +++ b/src/modlistsortproxy.h @@ -142,6 +142,7 @@ protected: private: unsigned long flagsId(const std::vector &flags) const; + unsigned long conflictFlagsId(const std::vector& flags) const; bool hasConflictFlag(const std::vector &flags) const; void updateFilterActive(); bool filterMatchesModAnd(ModInfo::Ptr info, bool enabled) const; diff --git a/src/organizer_en.ts b/src/organizer_en.ts index e3531cb2..72972e4f 100644 --- a/src/organizer_en.ts +++ b/src/organizer_en.ts @@ -15,117 +15,122 @@ - - <html><head/><body><p>Source code can be found at <a href="https://github.com/ModOrganizer2/modorganizer"><span style=" text-decoration: underline; color:#007af4;">GitHub</span></a>.</p></body></html> + + usvfs: - + + <html><head/><body><p>Source code can be found at <a href="https://github.com/ModOrganizer2/modorganizer">GitHub</a>.</p></body></html> + + + + Used Software - + Thanks - + Lead Developers && Maintainers - + LePresidente (Project Lead) - + MO2 Developers && Contributors - + Translators - + Cyb3r (Dutch) - + fruttyx (French) - + Yoplala (French) - + Faron (German) - + yohru (Japanese) - + Mordan (Greek) - + Yoosk (Polish) - + Brgodfx (Portuguese) - + zDas (Portuguese) - + Jax (Swedish) - + Nubbie (Swedish) - + ...and all other contributors! - + Other Supporters && Contributors - + Tannin (Original Creator) - + Close - + No license @@ -173,17 +178,17 @@ p, li { white-space: pre-wrap; } AdvancedConflictListModel - + Overwrites - + File - + Overwritten By @@ -289,33 +294,43 @@ p, li { white-space: pre-wrap; } ConflictsTab - - &Hide + + &Execute - - &Unhide + + &Open - - &Open/Execute + + Open with &VFS - + &Preview - + + &Go to... + + + + Open in &Explorer - - &Go to... + + &Hide + + + + + &Unhide @@ -403,79 +418,84 @@ p, li { white-space: pre-wrap; } - - < game %1 mod %2 file %3 > + + Source Game - Unknown + < game %1 mod %2 file %3 > + Unknown + + + + Pending - + Started - + Canceling - + Pausing - + Canceled - + Paused - + Error - - - + + + Fetching Info - + Downloaded - + Installed - + Uninstalled - + Pending download - + Information missing, please select "Query Info" from the context menu to re-retrieve. @@ -483,156 +503,153 @@ p, li { white-space: pre-wrap; } DownloadListWidget - + Install - + Query Info - + Visit on Nexus - + Open File - - - + + + Show in Folder - - + + Delete - + Un-Hide - + Hide - + Cancel - + Pause - + Resume - + Delete Installed Downloads... - Delete Installed... - + Delete Uninstalled Downloads... - Delete Uninstalled... - + Delete All Downloads... - Delete All... - + Hide Installed... - + Hide Uninstalled... - + Hide All... - + Un-Hide All... - - - - + + + + Delete Files? - + This will permanently delete the selected download. Are you absolutely sure you want to proceed? - + This will remove all finished downloads from this list and from disk. Are you absolutely sure you want to proceed? - + This will remove all installed downloads from this list and from disk. Are you absolutely sure you want to proceed? - + This will remove all uninstalled downloads from this list and from disk. Are you absolutely sure you want to proceed? - - - + + + Hide Files? - + This will remove all finished downloads from this list (but NOT from disk). - + This will remove all installed downloads from this list (but NOT from disk). - + This will remove all uninstalled downloads from this list (but NOT from disk). @@ -645,37 +662,37 @@ Are you absolutely sure you want to proceed? - + Memory allocation error (in refreshing directory). - + failed to download %1: could not open output file: %2 - + Download again? - + 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. - + Wrong Game - + The download link is for a mod for "%1" but this instance of MO has been set up for "%2". - + There is already a download queued for this file. Mod %1 @@ -683,12 +700,12 @@ File %2 - + Already Queued - + There is already a download started for this file. Mod %1: %2 @@ -696,276 +713,277 @@ File %3: %4 - + Already Started - - + + remove: invalid download index %1 - + failed to delete %1 - + failed to delete meta file for %1 - + restore: invalid download index: %1 - + cancel: invalid download index %1 - + pause: invalid download index %1 - + resume: invalid download index %1 - + resume (int): invalid download index %1 - + No known download urls. Sorry, this download can't be resumed. - - + + query: invalid download index %1 - + Please enter the nexus mod id - + Mod ID: - + Please select the source game code for %1 - + Hashing download file '%1' - + Cancel - + VisitNexus: invalid download index %1 - + Nexus ID for this Mod is unknown - + OpenFile: invalid download index %1 - + OpenFileInDownloadsFolder: invalid download index %1 - + get pending: invalid download index %1 - + get path: invalid download index %1 - + Main - + Update - + Optional - + Old - + Miscellaneous - + Deleted - + Unknown - + display name: invalid download index %1 - + file name: invalid download index %1 - + file time: invalid download index %1 - + file size: invalid download index %1 - + progress: invalid download index %1 - + state: invalid download index %1 - + infocomplete: invalid download index %1 - - + + + mod id: invalid download index %1 - + ishidden: invalid download index %1 - + file info: invalid download index %1 - + mark installed: invalid download index %1 - + mark uninstalled: invalid download index %1 - + Memory allocation error (in processing progress event). - + Memory allocation error (in processing downloaded data). - + Information updated - - + + No matching file found on Nexus! Maybe this file is no longer available or it was renamed? - + No file on Nexus matches the selected file by name. Please manually choose the correct one. - + No download server available. Please try again later. - + Failed to request file info from nexus: %1 - + Warning: Content type is: %1 - + Download header content length: %1 downloaded file size: %2 - + Download failed: %1 (%2) - + We were unable to download the file due to errors after four retries. There may be an issue with the Nexus servers. - + failed to re-open %1 - + Unable to write download to drive (return %1). Check the drive's available storage. @@ -998,19 +1016,18 @@ Canceling download "%2"... - + Remove the selected executable - + Remove - @@ -1018,7 +1035,11 @@ Canceling download "%2"... - + + Up + + + @@ -1026,261 +1047,339 @@ Canceling download "%2"... - + + Down + + + + Adds the executables provided by the game plugin and moves any existing executables out of the way - + Reset - + List of configured executables - + This is a list of your configured executables. Executables in grey are automatically recognised and can not be modified. - + Title - + Name of the executable. This is only for display purposes. - + Binary - + Binary to run - + Browse filesystem - + Browse filesystem for the executable to run. - - + + ... - + Start in - + Arguments - + Arguments to pass to the application - + Allow the Steam AppID to be used for this executable to be changed. - + Allow the Steam AppID to be used for this executable to be changed. Every game/tool distributed through Steam has a unique ID. MO needs to know this ID to start those programs directly, otherwise the program is started by steam and then MO will not work. By default, MO will use the AppID for the game. Right now the only case I know of where this needs to be overwritten is for the Skyrim Creation Kit which has its own AppID. This overwrite is already preconfigured. - + Overwrite Steam AppID - + Steam AppID to use for this executable that differs from the games AppID. - + Steam AppID to use for this executable that differs from the games AppID. Every game/tool distributed through Steam has a unique ID. MO needs to know this ID to start those programs directly, otherwise the program is started by steam and then MO will not work. By default, MO will use the AppID for the game (usually 72850). Right now the only case I know of where this needs to be overwritten is for the Skyrim Creation Kit which has its own AppID (usually 202480). This overwrite is already preconfigured. - + If this is enabled, new files are created in the specified mod instead of the "Overwrite" mod. - - Create Files in Mod instead of Overwrite (*) + + Create files in mod instead of overwrite (*) - + If this is enabled, the configured libraries will be automatically loaded when this executable is launched. - - Force Load Libraries (*) + + Force load libraries (*) - + Configure Libraries - - Use Application's Icon for desktop shortcuts - Use Application's Icon for shortcuts + + Use application's icon for desktop shortcuts + + + + + + This executable will not appear in the list, on the toolbar or in the menu. It will still be visible in this dialog. + + + + + Hide in user interface + + + + + (*) Profile specific + + + + + Add from file... + + + + + Add empty - - (*) Profile Specific + + Clone selected - + Reset plugin executables - + 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. - - + + New Executable - - Select a binary + + Select a directory - - Executable (%1) + + Executables (*.exe *.bat *.jar) - - Select a directory + + All Files (*.*) - - Java (32-bit) required + + Select an executable - - MO requires 32-bit java to run this application. If you already have it installed, select javaw.exe from that installation as the binary. + + Java required + + + + + MO requires Java to run this application. If you already have it installed, select javaw.exe from that installation as the binary. FileTreeTab - + &New Folder - + &Open/Execute - + + Open with &VFS + + + + &Preview - + Open in &Explorer - + &Rename - + &Delete - + &Hide - + &Unhide - - + + New Folder - + Failed to create "%1" - + Are you sure you want to delete "%1"? - + Are you sure you want to delete the selected files? - + Confirm - + Failed to delete %1 + + + &Execute + + + + + &Open + + + + + FilterList + + + Not + + + + + Filter separators + + + + + Show separators + + + + + Hide separators + + + + + <Contains %1> + + FindDialog @@ -1416,9 +1515,16 @@ Right now the only case I know of where this needs to be overwritten is for the Extracting files + + + + + Extraction failed: %1 + + - failed to create backup + Failed to create backup @@ -1511,29 +1617,6 @@ This is likely due to a corrupted or incompatible download or unrecognized archi - - LockedDialog - - - Running virtualized processes - - - - - This dialog should disappear automatically if the application/game is done. Click unlock if it didn't. - - - - - MO is locked while the executable is running. - - - - - Unlock - - - LogList @@ -1572,6 +1655,57 @@ This is likely due to a corrupted or incompatible download or unrecognized archi + + Loot + + + failed to start loot + + + + + Loot failed. Exit code was: %1 + + + + + LootDialog + + + LOOT + + + + + Progress + + + + + about:blank + + + + + Details + + + + + Open JSON report + + + + + Stopping LOOT... + + + + + Loot failed to run + + + MOApplication @@ -1598,17 +1732,17 @@ This is likely due to a corrupted or incompatible download or unrecognized archi - + failed to write to %1 - + file not found: %1 - + Save @@ -1632,48 +1766,59 @@ This is likely due to a corrupted or incompatible download or unrecognized archi MainWindow - - - Categories + + Filters - + Clear - - If checked, only mods that match all selected categories are displayed. + + Edit... + + + + + Display mods that match all selected categories. - + And - - If checked, all mods that match at least one of the selected categories are displayed. + + Display mods that match at least one of the selected categories - + Or - + + Filter: only show the separators that match the current filters +Show: always show separators +Hide: never show separators + + + + Profile - + Pick a module collection - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -1683,84 +1828,84 @@ p, li { white-space: pre-wrap; } - + Open list options... - + Refresh list. This is usually not necessary unless you modified data outside the program. - + Show Open Folders menu... - - + + Restore Backup... - - - + + + Create Backup - - + + Active: - + This provides statistics about the mod list. The total number of active mod is normally displayed. Other statistics may be accessed with the tooltip of this counter. - - List of available mods. - - - - + This is a list of installed mods. Use the checkboxes to activate/deactivate mods and drag & drop mods to change their "installation" orders. - - - - + + + + Filter - + Clear all Filters - + No groups - + + Categories + + + + Nexus IDs - + Pick a program to run. - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -1770,12 +1915,12 @@ p, li { white-space: pre-wrap; } - + Run program - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -1784,17 +1929,17 @@ p, li { white-space: pre-wrap; } - + Run - + Create a shortcut in your start menu or on the desktop to the specified program - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -1803,32 +1948,32 @@ p, li { white-space: pre-wrap; } - + Shortcut - + Plugins - + Sort - + This provides statistics about the plugin list. The total number of active plugins is normally displayed. Other statistics may be accessed with the tooltip of this counter. - + List of available esp/esm files - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -1837,27 +1982,27 @@ p, li { white-space: pre-wrap; } - + Archives - + <html><head/><body><p>BSAs / BA2s are bundles of game assets (textures, scripts, etc.). By default, the engine loads these bundles in a separate step from loose files. <p>Their load order is specified by the priority of the corresponding plugin (right pane, plugins tab).</p><p>If there is a matching plugin, the game will load them no matter what.</p></body></html> - - <html><head/><body><p>Currently detected archives. (<a href="#"><span style=" text-decoration: underline; color:#0000ff;">What is an archive?</span></a>)</p></body></html> + + <html><head/><body><p>Currently detected archives. (<a href="#">What is an archive?</a>)</p></body></html> - + List of available BS Archives. Archives not checked here are not managed by MO and ignore installation order. - + BSA files are archives (comparable to .zip files) that contain data assets (meshes, textures, ...) to be used by the game. As such they "compete" with loose files in your data directory over which is loaded. By default, BSAs that share their base name with an enabled ESP (i.e. plugin.esp and plugin.bsa) are automatically loaded and will have precedence over all loose files, the installation order you set up to the left is then ignored! @@ -1865,72 +2010,72 @@ p, li { white-space: pre-wrap; } - + Data - + refresh data-directory overview - + Refresh the overview. This may take a moment. - - - - + + + + Refresh - + This is an overview of your data directory as visible to the game (and tools). - + File - + Mod - - + + Filters the above list so that only conflicts are displayed. - + Show only conflicts - - + + Filters the above list so that files from archives are not shown - + Show files from Archives - + Saves - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -1941,1170 +2086,1119 @@ p, li { white-space: pre-wrap; } - + Downloads - + Refresh downloads view - + This is a list of mods you downloaded from Nexus. Double click one to install it. You can also drag an archive into here. - + Show Hidden - + Main ToolBar - + &File - - + + &Tools - - - + + + &Help - + &View - + &Toolbars - + &Run - - + + Log - + Install &Mod... - + Install &Mod - - + + Install a new mod from an archive - + Ctrl+M - + &Profiles... - + &Profiles - - + + Configure profiles - + Ctrl+P - + &Executables... - + &Executables - - + + Configure the executables that can be started through Mod Organizer - + Ctrl+E - + &Tool Plugins - + Tools - + Ctrl+I - + &Settings... - + &Settings - - + + Configure settings and workarounds - + Ctrl+S - - + + Visit &Nexus - - + + Visit the Nexus website in your browser for more mods - + Ctrl+N - - + + &Update Mod Organizer - - + + Mod Organizer is up-to-date - + &Notifications... - - + + Open the notifications dialog - + This button will be highlighted on the toolbar if MO discovered potential problems in your setup and provide tips on how to fix them. - - + + Show help options - + Ctrl+H - - + + &Endorse ModOrganizer - - - + + + Endorse Mod Organizer - + &Change Game... - + &Change Game - - + + Open the Instance selection dialog to manage a different Game - - + + E&xit - - + + Exits Mod Organizer - + M&ain Toolbar - + &Small Icons - + Lar&ge Icons - + &Icons Only - + &Text Only - + I&cons and Text - + M&edium Icons - + &Menu - + Status &bar - St&atus bar - + Toolbar and Menu - + Desktop - + Start Menu - + There is no supported sort mechanism for this game. You will probably have to use a third-party tool. - + Crash on exit - + MO crashed while exiting. Some settings may not be saved. Error: %1 - + There are notifications to read - + There are no notifications - - - + + + Endorse - + Won't Endorse - + Help on UI - + Documentation - + Chat on Discord - + Report Issue - + Tutorials - + About - + About Qt - + Name - + Please enter a name for the new profile - + failed to create profile: %1 - + Show tutorial? - + 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. - + Downloads in progress - + There are still downloads in progress, do you really want to quit? - + Plugin "%1" failed: %2 - + Plugin "%1" failed - + Browse Mod Page - + Also in: <br> - + No conflict - + <Edit...> - + + (no executables) + + + + This bsa is enabled in the ini file so it may be required! - + Activating Network Proxy - + 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. - + Choose Mod - + Mod Archive - + Start Tutorial? - + You're about to start a tutorial. For technical reasons it's not possible to end the tutorial early. Continue? - + failed to change origin name: %1 - + failed to move "%1" from mod "%2" to "%3": %4 - - <Contains %1> + + failed to rename mod: %1 - - <Checked> + + Overwrite? - - <Unchecked> + + This will replace the existing mod "%1". Continue? - - <Update> + + failed to remove mod "%1" - - <Mod Backup> + + + + failed to rename "%1" to "%2" - - <Managed by MO> + + + + + Confirm - - <Managed outside MO> + + Remove the following mods?<br><ul>%1</ul> - - <No category> + + failed to remove mod: %1 - - <Conflicted> + + + + Failed - - <Not Endorsed> + + Installation file no longer exists - - failed to rename mod: %1 - - - - - Overwrite? - - - - - This will replace the existing mod "%1". Continue? - - - - - failed to remove mod "%1" - - - - - - - failed to rename "%1" to "%2" - - - - - - - - Confirm - - - - - Remove the following mods?<br><ul>%1</ul> - - - - - failed to remove mod: %1 - - - - - - - Failed - - - - - Installation file no longer exists - - - - + Mods installed with old versions of MO can't be reinstalled in this way. - + Failed to create backup. - + Endorsing multiple mods will take a while. Please wait... - + Unendorsing multiple mods will take a while. Please wait... - + Failed to display overwrite dialog: %1 - + Opening Nexus Links - + You are trying to open %1 links to Nexus Mods. Are you sure you want to do this? - + Nexus ID for this mod is unknown - + Opening Web Pages - + You are trying to open %1 Web Pages. Are you sure you want to do this? - + <table cellspacing="5"><tr><th>Type</th><th>All</th><th>Visible</th><tr><td>Enabled mods:&emsp;</td><td align=right>%1 / %2</td><td align=right>%3 / %4</td></tr><tr><td>Unmanaged/DLCs:&emsp;</td><td align=right>%5</td><td align=right>%6</td></tr><tr><td>Mod backups:&emsp;</td><td align=right>%7</td><td align=right>%8</td></tr><tr><td>Separators:&emsp;</td><td align=right>%9</td><td align=right>%10</td></tr></table> - + <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> - - - + + + Create Mod... - + This will create an empty mod. Please enter a name: - - + + A mod with this name already exists - + Create Separator... - + This will create a new separator. Please enter a name: - + A separator with this name already exists - + This will move all files from overwrite into a new, regular mod. Please enter a name: - + Move successful. - - + + Are you sure? - + About to recursively delete: - + Continue? - + The versioning scheme decides which version is considered newer than another. This function will guess the versioning scheme under the assumption that the installed version is outdated. - + Sorry - + I don't know a versioning scheme where %1 is newer than %2. - + Really enable all visible mods? - + Really disable all visible mods? - + Export to csv - + CSV (Comma Separated Values) is a format that can be imported in programs like Excel to create a spreadsheet. You can also use online editors and converters instead. - + Select what mods you want export: - + All installed mods - + Only active (checked) mods from your current profile - + All currently visible mods in the mod list - + Choose what Columns to export: - + Mod_Priority - + Mod_Name - + Notes_column - + Mod_Status - + Primary_Category - + Nexus_ID - + Mod_Nexus_URL - + Mod_Version - + Install_Date - + Download_File_Name - + export failed: %1 - + Open Game folder - + Open MyGames folder - + Open INIs folder - + Open Instance folder - + Open Mods folder - + Open Profile folder - + Open Downloads folder - + Open MO2 Install folder - + Open MO2 Plugins folder - + + Open MO2 Stylesheets folder + + + + Open MO2 Logs folder - + Install Mod... - + Create empty mod - + Create Separator - + Enable all visible - + Disable all visible - + Check for updates - + Export to csv... - - + + Send to - - + + Top - - + + Bottom - - + + Priority... - + Separator... - + All Mods - + Sync to Mods... - + Move content to Mod... - + Clear Overwrite... - - + + Open in Explorer - + Restore Backup - + Remove Backup... - - + + Change Categories - - + + Primary Category - + Rename Separator... - + Remove Separator... - + Select Color... - + Reset Color - + Change versioning scheme - + Force-check updates - + Un-ignore update - + Ignore update - - + + Enable selected - - + + Disable selected - + Rename Mod... - + Reinstall Mod - + Remove Mod... - + Un-Endorse - + Won't endorse - + Endorsement state unknown - + Start tracking - + Stop tracking - + Tracked state unknown - + Ignore missing data - + Mark as converted/working - + Visit on Nexus - + Visit on %1 - + Information... - - + + Exception: - - + + Unknown exception - - <All> - - - - - <Multiple> - - - - + %1 more - + 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. @@ -3112,12 +3206,12 @@ You can also use online editors and converters instead. - + Enable Mods... - + Delete %n save(s) @@ -3125,349 +3219,330 @@ You can also use online editors and converters instead. - - Restarting MO + + Restart Mod Organizer - - Changing the managed game directory requires restarting MO. -Any pending downloads will be paused. - -Click OK to restart MO now. + + Mod Organizer must restart to finish configuration changes + + + + + Restart + + + + + Continue - + + Some things might be weird. + + + + Can't change download directory while downloads are in progress! - + failed to write to file %1 - + %1 written - + Enter Name - - Please enter a name for the executable + + Enter a name for the executable - + Not an executable - + This is not a recognized executable. - + Replace file? - + There already is a hidden version of this file. Replace it? - + File operation failed - + Failed to remove "%1". Maybe you lack the required file permissions? - + There already is a visible version of this file. Replace it? - - + + Set Priority - + Set the priority of the selected plugins - + Update available - - Open/Execute + + &Execute - - Add as Executable + + &Open + + + + + Open with &VFS - + + &Add as Executable + + + + Preview - + Un-Hide - + Hide - + Write To File... - + Do you want to endorse Mod Organizer on %1 now? - + Abstain from Endorsing Mod Organizer - + Are you sure you want to abstain from endorsing Mod Organizer 2? You will have to visit the mod page on the %1 Nexus site to change your mind. - + Thank you for endorsing MO2! :) - + Please reconsider endorsing MO2 on Nexus! - + Thank you! - + Thank you for your endorsement! - + Mod ID %1 no longer seems to be available on Nexus. - + Request to Nexus failed: %1 - - + + failed to read %1: %2 - - + Error - + failed to extract %1 (errorcode %2) - + Extract BSA - + This archive contains invalid hashes. Some files may be broken. - + Extract... - + This will restart MO, continue? - - Edit Categories... - - - - - Deselect filter + + <Multiple> - + Remove '%1' from the toolbar - + Enable all - + Disable all - + Unlock load order - + Lock load order - + Open Origin in Explorer - + Open Origin Info... - - depends on missing "%1" - - - - - incompatible with "%1" - - - - - Please wait while LOOT is running - - - - - loot failed. Exit code was: %1 - - - - - failed to start loot - - - - - failed to run loot: %1 - - - - - Errors occurred - - - - + Backup of load order created - + Choose backup to restore - + No Backups - + There are no backups to restore - - + + Restore failed - - + + Failed to restore the backup. Errorcode: %1 - + Backup of mod list created - + A file with the same name has already been downloaded. What would you like to do? - + Overwrite - + Rename new file - + Ignore file - + Set the priority of the selected mods @@ -3484,101 +3559,100 @@ You will have to visit the mod page on the %1 Nexus site to change your mind. ModInfo - + Plugins - + Textures - + Meshes - + Bethesda Archive - + UI Changes - + Sound Effects - + Scripts - + Script Extender - + Script Extender Files - + SkyProc Tools - + MCM Data - + INI files - + ModGroup files - + invalid content type: %1 - + invalid mod index: %1 - + remove: invalid mod index %1 - + All of your mods have been checked recently. We restrict update checks to help preserve your available API requests. - + 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. - You have mods that haven't been checked within 30 days 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. ModInfoBackup - + This is the backup of a mod @@ -3638,27 +3712,32 @@ You will have to visit the mod page on the %1 Nexus site to change your mind. + Open with Preview Plugin + + + + Open in Explorer - + 0x0 - - + + Optional ESPs - + List of esps, esms, and esls that can not be loaded by the game. - + List of esps, esms, and esls contained in this plugin that currently can not be loaded by the game. They will not even appear in the esp-list in the main MO-window. They usually contain optional functionality, see the readme. @@ -3666,135 +3745,132 @@ Most mods do not have optional esps, so chances are good you are looking at an e - + Move a file to the data directory. - + This moves a esp to the esp directory so it can be enabled in the main window. Please note that the ESP merely becomes "available", it will not necessarily be loaded! That is configured in the main window of MO. - This moves a esp to the esp directory so it can be enabled in the main window. Please note that the ESP merely becomes "available", it will not necessarily be loaded! That is configured in the main window of omo. - + Make the selected mod in the right list unavailable. - Make the selected mod in the lower list unavailable. - + The selected esp (in the right list) will be pushed into a subdirectory of the mod and will thus become "invisible" to the game. It can then no longer be activated. - The selected esp (in the lower list) will be pushed into a subdirectory of the mod and will thus become "invisible" to the game. It can then no longer be activated. - + Available ESPs - + ESPs in the data directory and thus visible to the game. - + <html><head/><body><p>These are the mod files that are in the (virtual) data directory of your game and will thus be selectable in the esp list in the main window.</p></body></html> - + Conflicts - + General - + The following conflicted files are provided by this mod - + The following conflicted files are provided by other mods - + The following files have no conflicts - + Advanced - + Whether files that have no conflicts should be visible in the list - + Show files that have no conflicts - + Shows all mods overwriting or being overwritten by this mod - + Show all conflicting mods - + Shows only the nearest conflicting mods, in order of priority - + Show nearest conflicting mod - + Filter - + Categories - + Primary Category - + Nexus Info - + Mod ID - + Mod ID for this mod on Nexus. - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -3803,22 +3879,22 @@ p, li { white-space: pre-wrap; } - + Source Game - + Source game for this mod. - + <html><head/><body><p>Source game for this mod. This determines where the mod was downloaded from and decides where to fetch info, version updates, and send endorsements. Changing this will likely require you to enter a new Mod ID.</p></body></html> - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -3827,83 +3903,83 @@ p, li { white-space: pre-wrap; } - + Version - - + + Refresh - + Refresh all information from Nexus. - - + + Open in Browser - + Endorse - + Track - + about:blank - + Use Custom URL - + Notes - - - + + + Enter comments about the mod here. These are displayed in the notes column of the mod list. - - - + + + Enter notes about the mod here. These can be viewed in the mod list by hovering over the notes column or the flags column. - + Filetree - + Open Mod in Explorer - + A directory view of this mod - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -3913,17 +3989,17 @@ p, li { white-space: pre-wrap; } - + Previous - + Next - + Close @@ -3954,7 +4030,7 @@ p, li { white-space: pre-wrap; } ModInfoOverwrite - + This pseudo mod contains files from the virtual data tree that got modified (i.e. by the construction kit) @@ -3983,318 +4059,328 @@ p, li { white-space: pre-wrap; } ModList - + Game Plugins (ESP/ESM/ESL) - + Interface - + Meshes - + Bethesda Archive - + Scripts (Papyrus) - + Script Extender Plugin - + SkyProc Patcher - + Sound or Music - + Textures - + MCM Configuration - + INI files - + ModGroup files - + This entry contains files that have been created inside the virtual data tree (i.e. by the construction kit) - + Backup - + Separator - + No valid game data - + Not endorsed yet - + + <br>This mod is for a different game, make sure it's compatible or it could cause crashes. + + + + + Mod is being tracked on the website + + + + Overwrites loose files - + Overwritten loose files - + Loose files Overwrites & Overwritten - + Redundant - + Overwrites an archive with loose files - + Archive is overwritten by loose files - + Overwrites another archive file - + Overwritten by another archive file - + Archive files overwrites & overwritten - - <br>This mod is for a different game, make sure it's compatible or it could cause crashes. - - - - - Mod is being tracked on the website - - - - + Non-MO - + invalid - + installed version: "%1", newest version: "%2" - + 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". - + This file has been marked as "Old". There is most likely an updated version of this file available. - + This file has been marked as "Deleted"! You may want to check for an update or remove the nexus ID from this mod! - + %1 minute(s) and %2 second(s) - + This mod will be available to check in %2. - + Categories: <br> - + Invalid name - + Name is already in use by another mod - + drag&drop failed: %1 - + Confirm - + Are you sure you want to remove "%1"? - + + Conflicts + + + + Flags - + Content - + Mod Name - + Version - + Priority - + Category - + Source Game - + Nexus ID - + Installation - + Notes - - + + unknown - + Name of your mods - + Version of the mod (if available) - + Installation priority of your mod. The higher, the more "important" it is and thus overwrites files from mods with lower priority. - + Category of the mod. - + The source game which was the origin of this mod. - + Id of the mod as used on Nexus. - - Emblemes to highlight things that might require attention. + + Indicators of file conflicts between mods. + + + + + Emblems to highlight things that might require attention. - + Depicts the content of the mod:<br><table cellspacing=7><tr><td><img src=":/MO/gui/content/plugin" width=32/></td><td>Game plugins (esp/esm/esl)</td></tr><tr><td><img src=":/MO/gui/content/interface" width=32/></td><td>Interface</td></tr><tr><td><img src=":/MO/gui/content/mesh" width=32/></td><td>Meshes</td></tr><tr><td><img src=":/MO/gui/content/bsa" width=32/></td><td>BSA</td></tr><tr><td><img src=":/MO/gui/content/texture" width=32/></td><td>Textures</td></tr><tr><td><img src=":/MO/gui/content/sound" width=32/></td><td>Sounds</td></tr><tr><td><img src=":/MO/gui/content/music" width=32/></td><td>Music</td></tr><tr><td><img src=":/MO/gui/content/string" width=32/></td><td>Strings</td></tr><tr><td><img src=":/MO/gui/content/script" width=32/></td><td>Scripts (Papyrus)</td></tr><tr><td><img src=":/MO/gui/content/skse" width=32/></td><td>Script Extender plugins</td></tr><tr><td><img src=":/MO/gui/content/skyproc" width=32/></td><td>SkyProc Patcher</td></tr><tr><td><img src=":/MO/gui/content/menu" width=32/></td><td>Mod Configuration Menu</td></tr><tr><td><img src=":/MO/gui/content/inifile" width=32/></td><td>INI files</td></tr><tr><td><img src=":/MO/gui/content/modgroup" width=32/></td><td>ModGroup files</td></tr></table> - + Time this mod was installed - + User notes about the mod @@ -4302,7 +4388,7 @@ p, li { white-space: pre-wrap; } ModListSortProxy - + Drag&Drop is only supported when sorting by priority @@ -4345,31 +4431,31 @@ p, li { white-space: pre-wrap; } NexusInterface - Failed to guess mod id for "%1", please pick the correct one + Please pick the mod ID for "%1" - + You must authorize MO2 in Settings -> Nexus to use the Nexus API. - + 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. - + 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. - + empty response - + invalid response @@ -4452,7 +4538,7 @@ p, li { white-space: pre-wrap; } NoConflictListModel - + File @@ -4460,212 +4546,207 @@ p, li { white-space: pre-wrap; } OrganizerCore - - Failed to write settings - - - - + File is write protected - + Invalid file format (probably a bug) - + Unknown error %1 - + + Failed to write settings + + + + An error occurred trying to write back MO settings to %1: %2 - - + + Download started - + Download failed - - - - + + + + Installation cancelled - - + + Another installation is currently in progress. - - + + Installation successful - - + + Configure Mod - - + + This mod contains ini tweaks. Do you want to configure them now? - - + + mod not found: %1 - - + + The mod was not installed completely. - + file not found: %1 - + failed to generate preview for %1 - + Sorry - + Sorry, can't preview anything. This function currently does not support extracting from bsas. - + File '%1' not found. - + Failed to generate preview for %1 - - Error - - - - - No profile set - - - - + Failed to refresh list of esps: %1 - + Multiple esps/esls activated, please check that they don't conflict. - + You need to be logged in with Nexus - + Download? - + A download has been started but no installed page plugin recognizes it. If you download anyway no information (i.e. version) will be associated with the download. Continue? - - + + failed to update mod list: %1 - - + + login successful - + Login failed - + Login failed, try again? - + login failed: %1. Download will not be associated with an account - + login failed: %1 - + login failed: %1. You need to log-in with Nexus to update MO. - + MO1 "Script Extender" load mechanism has left hook.dll in your game folder - - + + Description missing - + <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. - + failed to save load order: %1 - + + Error + + + + The designated write target "%1" is not enabled. @@ -4673,12 +4754,12 @@ Continue? OverwriteConflictListModel - + File - + Overwritten Mods @@ -4721,43 +4802,43 @@ Continue? - + mod not found: %1 - + Failed to delete "%1" - - - - + + + + Confirm - - + + Are you sure you want to delete "%1"? - - + + Are you sure you want to delete the selected files? - - + + New Folder - + Failed to create "%1" @@ -4765,12 +4846,12 @@ Continue? OverwrittenConflictListModel - + File - + Providing Mod @@ -4778,18 +4859,18 @@ Continue? PluginContainer - + Some plugins could not be loaded - - + + Description missing - + The following plugins could not be loaded. The reason may be missing dependencies (i.e. python) or an outdated version: @@ -4797,152 +4878,176 @@ Continue? PluginList - + Name - + Priority - + Mod Index - + Flags - - + + unknown - - Name of your mods + + Name of the plugin + + + + + Emblems to highlight things that might require attention. - - Load priority of your mod. The higher, the more "important" it is and thus overwrites data from plugins with lower priority. + + Load priority of plugins. The higher, the more "important" it is and thus overwrites data from plugins with lower priority. - - The modindex determines the formids of objects originating from this mods. + + Determines the formids of objects originating from this mods. - + failed to update esp info for file %1 (source id: %2), error: %3 - + Plugin not found: %1 - - + + Confirm - + Really enable all plugins? - + Really disable all plugins? - + The file containing locked plugin indices is broken - - - <b>Origin</b>: %1 + + Origin - - <br><b><i>This plugin can't be disabled (enforced by the game).</i></b> + + This plugin can't be disabled (enforced by the game). - + Author - + Description - + Missing Masters - + Enabled Masters - + Loads Archives - + 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) - + Loads INI settings - + There is an ini file connected to this plugin. Its settings will be added to your game settings, overwriting in case of conflicts. - + This ESP is flagged as an ESL. It will adhere to the ESP load order but the records will be loaded in ESL space. - - failed to restore load order for %1 + + Incompatible with %1 - - - PluginListSortProxy - - Drag&Drop is only supported when sorting by priority or mod index + + Depends on missing %1 - - - PreviewDialog - - Preview + + Warning + + + + + Error + + + + + failed to restore load order for %1 + + + + + PluginListSortProxy + + + Drag&Drop is only supported when sorting by priority or mod index + + + + + PreviewDialog + + + Preview @@ -4965,11 +5070,6 @@ Continue? p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click a notification above to get more details...</p></body></html> - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:7.8pt;"><br /></p></body></html> @@ -5326,33 +5426,53 @@ p, li { white-space: pre-wrap; } - QApplication + QObject - + + + + INI file is read-only - - - Mod Organizer is attempting to write to "%1" which is currently set to read-only. Clear the read-only flag to allow the write? + + + Mod Organizer is attempting to write to "%1" which is currently set to read-only. - - File is read-only + + + Clear the read-only flag + + + + + + Allow the write once + + + + + + The file will be set to read-only again. + + + + + + Skip this file - - - QObject - - - - + + + + + Error @@ -5379,8 +5499,8 @@ p, li { white-space: pre-wrap; } - - failed to open temporary file + + Failed to save '{}', could not create a temporary file: {} (error {}) @@ -5399,52 +5519,73 @@ p, li { white-space: pre-wrap; } - - + + Error %1 + + + + + failed to create directory "%1" - - + + failed to copy "%1" to "%2" - + %1 MB - + %1 GB - + %1 TB - + %1 KB - + %1 B/s - + %1 KB/s - + %1 MB/s + + + Regular + + + + + Premium + + + + + + None + + Failed to save custom categories @@ -5454,15 +5595,95 @@ p, li { white-space: pre-wrap; } - + invalid category index: %1 - + + <Active> + + + + + <Update available> + + + + + <Has category> + + + + + <Conflicted> + + + + + <Endorsed> + + + + + <Has backup> + + + + + <Managed> + + + + + <Has valid game data> + + + + + <Has Nexus ID> + + + + + <Tracked on Nexus> + + + + invalid category id: %1 + + + Is overwritten (loose files) + + + + + Is overwriting (loose files) + + + + + Is overwritten (archives) + + + + + Is overwriting (archives) + + + + + Mod contains selected plugin + + + + + Plugin is contained in selected mod + + invalid field name "%1" @@ -5504,34 +5725,40 @@ p, li { white-space: pre-wrap; } - + The hidden file "%1" already exists. Replace it? - + The visible file "%1" already exists. Replace it? - + Replace file? - - + + File operation failed - - Failed to remove "%1". Maybe you lack the required file permissions? + + Failed to remove "%1": %2 - - failed to rename %1 to %2 + + Failed to rename file: %1. + +Source: +"%2" + +Destination: +"%3" @@ -5670,122 +5897,214 @@ If the folder was still in use, restart MO and try again. - + failed to create %1 - + Data directory created - + New data directory created at %1. If you don't want to store a lot of data there, reconfigure the storage directories via settings. - - + + General messages + + + + + Plugins + + + + + No messages. + + + + + Incompatibilities + + + + + Missing masters + + + + + Verified clean by %1 + + + + + %1 found %2 ITM record(s), %3 deleted reference(s) and %4 deleted navmesh(es). + + + + + + + Warning + + + + + failed to run loot: %1 + + + + + Checking masterlist existence + + + + + Updating masterlist + + + + + Loading lists + + + + + Reading plugins + + + + + Sorting plugins + + + + + Writing loadorder.txt + + + + + Parsing loot messages + + + + + Done + + + + + Failed to create "%1". Your user account probably lacks permission. - + Plugin to handle %1 no longer installed - - - + + + The configured path to the game directory (%1) appears to be a symbolic (or other) link. This setup is incompatible with MO2's VFS and will not run correctly. - + Could not use configuration settings for game "%1", path "%2". - - - + + + Please select the installation of %1 to manage - - - + + + Please select the game to manage - + Canceled finding %1 in "%2". - + Canceled finding game in "%1". - + %1 not identified in "%2". The directory is required to contain the game binary. - + No game identified in "%1". The directory is required to contain the game binary.<br><br><b>These are the games supported by Mod Organizer:</b><ul>%2</ul> - + Please select the game edition you have (MO can't start the game correctly if this is set incorrectly!) - + failed to start shortcut: %1 - + failed to start application: %1 - - + + Mod Organizer - + An instance of Mod Organizer is already running - + Failed to set up instance - + + <Unmanaged> + + + + Please use "Help" from the toolbar to get usage instructions to all elements - - + + <Manage...> - + failed to parse profile %1: %2 @@ -5821,512 +6140,586 @@ If the folder was still in use, restart MO 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. + + Connecting to Nexus... - - 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. + + Waiting for Nexus... - - The file '%1' does not exist. + + Opened Nexus in browser. - - - - - Cannot start Steam + + Switch to your browser and accept the request. - - The path to the Steam executable cannot be found. You might try reinstalling Steam. + + Finished. - - - - Continue without starting Steam + + No answer from Nexus. - - - The program may fail to launch. + + + A firewall might be blocking Mod Organizer. - - Cannot launch program + + Nexus closed the connection. - - - - Cannot start %1 + + Cancelled. - - Cannot launch helper + + Failed to request %1 - - 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". - -You can restart Mod Organizer as administrator and try launching the program again. + + + Cancelled - - - Restart Mod Organizer as administrator + + Internal error - - - You must allow "helper.exe" to make changes to the system. + + HTTP code %1 - - Launch Steam + + Invalid JSON - - This program requires Steam + + Bad response - - Mod Organizer has detected that this program likely requires Steam to be running to function properly. + + API key is empty - - Start Steam + + SSL error - - - The program might fail to run. + + Timed out - - Steam is running as administrator + + 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. - - Running Steam as administrator is typically unnecessary and can cause problems when Mod Organizer itself is not running as administrator. - -You can restart Mod Organizer as administrator and try launching the program again. + + failed to initialize plugin %1: %2 - - - - Continue + + Plugin error - - Event Log not running + + It appears the plugin "%1" failed to load last startup and caused MO to crash. Do you want to disable it? +(Please note: If this is the first time you see this message for this plugin you may want to give it another try. The plugin may be able to recover from the problem) - - The Event Log service is not running + + failed to access %1 - - 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. + + failed to set file time %1 - - - Your mods might not work. + + + + No profile set - - Blacklisted program + + Before you can use ModOrganizer, you need to create at least one profile. ATTENTION: Run the game at least once before creating a profile! - - The program %1 is blacklisted + + + attempt to store setting for unknown plugin "%1" - - 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. + + Failed - - Change the blacklist + + Failed to start the helper application: %1 - - Waiting + + + Debug - - Please press OK once you're logged into steam. + + + Info (recommended) - - One of the configured MO2 directories (profiles, mods, or overwrite) is on a path containing a symbolic (or other) link. This is incompatible with MO2's VFS system. + + Trace - - Select binary + + Mini (recommended) - - Binary + + Data - - failed to initialize plugin %1: %2 + + Full - - Plugin error + + Confirm? - - It appears the plugin "%1" failed to load last startup and caused MO to crash. Do you want to disable it? -(Please note: If this is the first time you see this message for this plugin you may want to give it another try. The plugin may be able to recover from the problem) + + This will reset all the choices you made to dialogs and make them all visible again. Continue? - - failed to access %1 + + Connected. - - failed to set file time %1 + + Not connected. - - Before you can use ModOrganizer, you need to create at least one profile. ATTENTION: Run the game at least once before creating a profile! + + Disconnected. - - - Elevation required + + Checking API key... - - 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. + + Received API key. - - Loading... + + Received user acount information - - &Save + + Linked with Nexus successfully. - - &Word wrap + + Failed to set API key - - &Open in Explorer + + + + + + + + + + + + Cancel - - Regular + + + + Enter API Key Manually - - Premium + + + + Connect to Nexus - - - None + + + + + + N/A - - - Connecting to Nexus... + + Failed to create "%1", you may not have the necessary permissions. Path remains unchanged. - - Waiting for Nexus... + + Select base directory - - Opened Nexus in browser. -Switch to your browser and accept the request. + + Select download directory - - - Finished. + + Select mod directory - - No answer from Nexus. -A firewall might be blocking Mod Organizer. + + Select cache directory - - Nexus closed the connection. + + Select profiles directory - - Cancelled. + + Select overwrite directory - - Invalid JSON + + Select game executable - - Bad response + + Executables Blacklist - - There was a timeout during the request + + Enter one executable per line to be blacklisted from the virtual file system. +Mods and other virtualized files will not be visible to these executables and +any executables launched by them. + +Example: + Chrome.exe + Firefox.exe - - Cancelled + + + + Restart Mod Organizer - - Failed to request %1 + + Geometries will be reset to their default values. - - - attempt to store setting for unknown plugin "%1" + + 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. - - Failed + + 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. - - Failed to start the helper application + + The file '%1' does not exist. - - Debug + + + + + Cannot start Steam - - Info (recommended) + + The path to the Steam executable cannot be found. You might try reinstalling Steam. - - Warning + + + + Continue without starting Steam - - Mini (recommended) + + + The program may fail to launch. - - Data + + Cannot launch program - - Full + + + + Cannot start %1 - - Confirm? + + Cannot launch helper + + + + + + Elevation required + + + + + 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". + +You can restart Mod Organizer as administrator and try launching the program again. + + + + + + Restart Mod Organizer as administrator + + + + + + You must allow "helper.exe" to make changes to the system. + + + + + Launch Steam + + + + + This program requires Steam + + + + + Mod Organizer has detected that this program likely requires Steam to be running to function properly. + + + + + Start Steam + + + + + + The program might fail to run. + + + + + Steam is running as administrator + + + + + Running Steam as administrator is typically unnecessary and can cause problems when Mod Organizer itself is not running as administrator. + +You can restart Mod Organizer as administrator and try launching the program again. + + + + + + + Continue + + + + + Event Log not running + + + + + The Event Log service is not running - - This will reset all the choices you made to dialogs and make them all visible again. Continue? + + 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. - - Disconnected. + + + Your mods might not work. - - Checking API key... + + Blacklisted program - - Received API key. + + The program %1 is blacklisted - - Linked with Nexus successfully. + + 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. - - - - - - - - - - Cancel + + Change the blacklist - - - - Enter API Key Manually + + Waiting - - - - Connect to Nexus + + Please press OK once you're logged into steam. - - - - - - N/A + + Select binary - - Failed to create "%1", you may not have the necessary permissions. Path remains unchanged. + + Binary - - Select base directory + + 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. - - Select download directory + + Loading... - - Select mod directory + + &Save - - Select cache directory + + &Word wrap - - Select profiles directory + + &Open in Explorer - - Select overwrite directory + + Mod Organizer is locked while the application is running. - - Select game executable + + Mod Organizer is currently running an application. - - Executables Blacklist + + The application must run to completion because its output is required. - - Enter one executable per line to be blacklisted from the virtual file system. -Mods and other virtualized files will not be visible to these executables and -any executables launched by them. - -Example: - Chrome.exe - Firefox.exe + + Mod Organizer is waiting on application to close before exiting. - - Restart Mod Organizer? + + Unlock - - In order to reset the geometry, Mod Organizer must be restarted. -Restart now? + + Exit Now @@ -6445,58 +6838,58 @@ Restart now? - + New update available (%1) - + Do you want to install update? All your mods and setup will be left untouched. Select Show Details option to see the full change-log. - + Install - + Download failed - + Failed to find correct download, please try again later. - + Update - + Download in progress - + Download failed: %1 - + Failed to install update: %1 - - Failed to start %1 + + Failed to start %1: %2 - + Error @@ -6514,473 +6907,488 @@ Select Show Details option to see the full change-log. - + + User Interface + + + + Language - - The display language + + Style - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The display language. This will only displaye languages for which you have a translation installed.</span></p></body></html> + + + Visual theme of the user interface. - - Style + + Explore... - - graphical style + + + The language of the user interface. - - graphical style of the MO user interface + + https://www.transifex.com/tannin/mod-organizer/ - - Update to non-stable releases. + + <a href="https://www.transifex.com/tannin/mod-organizer/">Help translate Mod Organizer</a> - - If this is enabled, the integrated update mechanism will notify of all releases, including pre-releases (alphas, betas). Please use this only if you're sufficiently tech-savvy to investigate issues, look for known problems in the issue tracker and create meaningful reports. - If this is enabled, the integrated update mechanism will notify of all releases, including pre-releases (alphas, betas). - -Please use this only if you're sufficiently tech-savvy to investigate issues, look for known problems in the issue tracker and create meaningful reports. - -If you use pre-releases, never contact me directly by e-mail or via private messages! + + + Dialogs will always be centered on the main window, but will remember their size. - - Install Pre-releases (Betas) + + Always center dialogs - - User interface + + Show confirmation when changing instance - - Colors + + Whether double-clicking on a file opens the preview window or launches the program associated with it. This applies to the Data tab as well as the Conflicts and Filetree tabs in the mod info window. - - - When this is enabled, the color defined for a separator will be shown on the mod list scrollbar at the location of the separator. This can be useful for quick navigation between separator sections or to a specific separator section. + + Open previews on double-click - - Show mod list separator colors on the scrollbar + + + Reset all choices made in dialogs. - - Plugin is Contained in selected Mod + + Reset Dialog Choices - - Is overwritten (loose files) + + + Modify the categories available to arrange your mods. - - Is overwriting (loose files) + + Configure Mod Categories - - Reset Colors + + Download List - - Mod Contains selected Plugin + + + Show meta information instead of file names in the download list. - - Is overwritten (archive files) + + Show Meta Information - - Is overwriting (archive files) + + + Make the download list more compact. - - - Modify the categories available to arrange your mods. + + Compact List - - Configure Mod Categories + + Colors - - Reset stored information from dialogs. + + + Colors set on separators will also be shown in the mod list scrollbar at the location of the separator. This can be useful for quickly navigating to a specific separator. - - This will make all dialogs show up again where you checked the "Remember selection"-box. + + Show mod list separator colors on the scrollbar - - If checked, the download interface will be more compact. + + + Reset all colors to their default value. - - Compact Download Interface + + Reset Colors - - If checked, the download list will display meta information instead of file names. + + Updates + + + + + + Check for Mod Organizer updates on Github on startup. - - Download Meta Information + + Check for updates + + + + + + Update to non-stable releases. + + + + + Install Pre-releases (Betas) - + Paths - - - - + + + + ... - + Caches - + Overwrite - - + + Directory where downloads are stored. - + Downloads - + Profiles - + Directory where mods are stored. - + Directory where mods are stored. Please note that changing this will break all associations of profiles with mods that don't exist in the new location (with the same name). - + Mods - + Managed Game - + Base Directory - + Use %BASE_DIR% to refer to the Base Directory. - + Important: All directories have to be writable! - + Nexus - - Connect to Nexus - - - - - Manually enter the API key and try to login + + Nexus Account - - Enter API Key Manually + + User ID: - - Clear the stored Nexus API key and force reauthorization. + + id - - Disconnect from Nexus + + Name: - - - <html><head/><body><p>By default, a counter is displayed in the bottom right corner. This informs the user of their remaining API requests. The Nexus API becomes unusable once these API requests run out. Checking this option will hide that counter.</p></body></html> + + name - - Remove cache and cookies. + + Account: - - Clear Cache + + account - - Disable automatic internet features + + Statistics - - Reset Dialog Choices + + Daily requests: - - Nexus Account + + daily requests - - User ID: + + Hourly requests: - - id + + hourly requests - - Name: + + Nexus Connection - - name + + Connect to Nexus - - Account: + + Manually enter the API key and try to login - - account + + Enter API Key Manually - - Statistics + + Clear the stored Nexus API key and force reauthorization. - - Daily requests: + + Disconnect from Nexus - - daily requests + + Disable automatic internet features - - Hourly requests: + + Disable automatic internet features. This does not affect features that are explicitly invoked by the user (like checking mods for updates, endorsing, opening the web browser) - - hourly requests + + Offline Mode - - Nexus Connection + + Use a proxy for network connections. - - Disable automatic internet features. This does not affect features that are explicitly invoked by the user (like checking mods for updates, endorsing, opening the web browser) + + Use a proxy for network connections. This uses the system-wide settings which can be configured in Internet Explorer. Please note that MO will start up a few seconds slower on some systems when using a proxy. - - Offline Mode + + Use HTTP Proxy (Uses System Settings) - - Use a proxy for network connections. + + Endorsement Integration - - Use a proxy for network connections. This uses the system-wide settings which can be configured in Internet Explorer. Please note that MO will start up a few seconds slower on some systems when using a proxy. + + + <html><head/><body><p>By default, a counter is displayed in the bottom right corner. This informs the user of their remaining API requests. The Nexus API becomes unusable once these API requests run out. Checking this option will hide that counter.</p></body></html> - - Use HTTP Proxy (Uses System Settings) + + Hide API Request Counter - - Endorsement Integration + + Associate with "Download with manager" links - - Hide API Request Counter + + Remove cache and cookies. - - Associate with "Download with manager" links + + Clear Cache - + Known Servers (updated on download) - + Preferred Servers (Drag & Drop) - + Steam - + Username - + <html><head/><body><p>If you save your steam user ID and password here, they will be used when logging into steam.</p></body></html> - + Password - + Plugins - + Author: - + Version: - + Description: - + Key - + Value - + Blacklisted Plugins (use <del> to remove): - + Workarounds - + Steam App ID - + The Steam AppID for your game - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -6996,17 +7404,17 @@ p, li { white-space: pre-wrap; } - + Load Mechanism - + Select loading mechanism. See help for details. - + Mod Organizer needs a dll to be injected into the game so all mods are visible to it. There are several means to do this: *Mod Organizer* (default) In this mode the Mod Organizer itself injects the dll. The disadvantage is that you always have to start the game through MO or a link created by it. @@ -7017,28 +7425,28 @@ If you use the Steam version of Oblivion the default will NOT work. In this case - + Enforces that inactive ESPs and ESMs are never loaded. - + It seems that the Games occasionally load ESP or ESM files even if they haven't been activated as plugins. I don't yet know what the circumstances are, but user reports imply it is in some cases unwanted. If this is checked, ESPs and ESMs not checked in the List are invisible to the game and can not be loaded. - + Hide inactive ESPs/ESMs - + Disable this to no longer display mods installed outside MO in the mod list (left pane). Assets from those mods will then be treated as having lowest mod priority together with the original game content. - + By default Mod Organizer will display esp+bsa bundles installed with foreign tools as mods (left pane). This allows you to control their priority in relation to other mods. This is particularly useful if you also use Steam Workshop to install mods. However, if you installed loose file mods outside MO which conflict with BSAs also installed outside MO those conflicts can't be resolved correctly. @@ -7046,66 +7454,66 @@ If you disable this feature, MO will only display official DLCs this way. Please - + Display mods installed outside MO - + If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on) - + If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on) Uncheck this if you want to use Mod Organizer with total conversions (like Nehrim) but be aware that the game will crash if required files are not enabled. - + Force-enable game files - - + + Disable this to prevent the GUI from being locked when running an executable. This may result in abnormal behavior. - + Lock GUI when running executable - + Enable parsing of Archives. This is an Experimental Feature. Has negative effects on performance and known incorrectness. - + <html><head/><body><p>By default, MO will parse archive files (BSA, BA2) to calculate conflicts between the contents of the archive files and other loose files. This process has a noticeable cost in performance.</p><p>This feature should not be confused with the archive management feature offered by MO1. MO2 will only show conflicts with archives and will NOT load them into the game or program.</p><p>If you disable this feature, MO will only display conflicts between loose files.</p></body></html> - + Enable parsing of Archives (Experimental Feature) - - + + For Skyrim, this can be used instead of Archive Invalidation. It should make AI redundant for all Profiles. For the other games this is not a sufficient replacement for AI! - + Back-date BSAs - + Add executables to the blacklist to prevent them from accessing the virtual file system. This is useful to prevent unintended programs from being hooked. Hooking unintended @@ -7114,81 +7522,81 @@ programs you are intentionally running. - + Add executables to the blacklist to prevent them from accessing the virtual file system. This is useful to prevent unintended programs from being hooked. Hooking unintended programs may affect the execution of these programs or the programs you are intentionally running. - + Configure Executables Blacklist - - + + Resets the window geometries for all windows. This can be useful if a window becomes too small or too large, if a column becomes too thin or too wide, and in similar situations. - + Reset Window Geometries - + These are workarounds for problems with Mod Organizer. Please make sure you read the help text before changing anything here. - + Diagnostics - - Max Dumps To Keep + + Hint: right click link and copy link location - - Maximum number of crash dumps to keep on disk. Use 0 for unlimited. + + + Logs and crash dumps are stored under your current instance in the <a href="LOGS_FULL_PATH">LOGS_DIR</a> + and <a href="DUMPS_FULL_PATH">DUMPS_DIR</a> folders. + Sending logs and/or crash dumps to the developers can help investigate issues. + It is recommended to compress large log and dmp files before sending. + - - - Maximum number of crash dumps to keep on disk. Use 0 for unlimited. - Set "Crash Dumps" above to None to disable crash dump collection. - + + Log Level - - Hint: right click link and copy link location + + Decides the amount of data printed to "ModOrganizer.log" - + - Logs and crash dumps are stored under your current instance in the <a href="LOGS_FULL_PATH">LOGS_DIR</a> - and <a href="DUMPS_FULL_PATH">DUMPS_DIR</a> folders. - Sending logs and/or crash dumps to the developers can help investigate issues. - It is recommended to compress large log and dmp files before sending. - + Decides the amount of data printed to "ModOrganizer.log". + "Debug" produces very useful information for finding problems. There is usually no noteworthy performance impact but the file may become rather large. If this is a problem you may prefer the "Info" level for regular use. On the "Error" level the log file usually remains empty. + - + Crash Dumps - + Decides which type of crash dumps are collected when injected processes crash. - + Decides which type of crash dumps are collected when injected processes crash. "None" Disables the generation of crash dumps by MO. @@ -7199,41 +7607,35 @@ programs you are intentionally running. - - Log Level + + Max Dumps To Keep - - Decides the amount of data printed to "ModOrganizer.log" + + Maximum number of crash dumps to keep on disk. Use 0 for unlimited. - + - Decides the amount of data printed to "ModOrganizer.log". - "Debug" produces very useful information for finding problems. There is usually no noteworthy performance impact but the file may become rather large. If this is a problem you may prefer the "Info" level for regular use. On the "Error" level the log file usually remains empty. + Maximum number of crash dumps to keep on disk. Use 0 for unlimited. + Set "Crash Dumps" above to None to disable crash dump collection. - - Restart Mod Organizer? + + LOOT Log Level - - In order to finish configuration changes, MO must be restarted. -Restart it now? - - - - + Confirm - + Changing the mod directory affects all your profiles! Mods not present (or named differently) in the new location will be disabled in all profiles. There is no way to undo this unless you backed up your profiles manually. Proceed? @@ -7241,22 +7643,22 @@ Restart it now? SingleInstance - + SHM error: %1 - + failed to connect to running instance: %1 - + failed to communicate with running instance: %1 - + failed to receive data from secondary instance: %1 @@ -7441,7 +7843,7 @@ On Windows XP: UsvfsConnector - + Preparing vfs @@ -7449,41 +7851,29 @@ On Windows XP: ValidationProgressDialog - + Validating Nexus Connection - - Hide - - - - - WaitingOnCloseDialog - - - Waiting for virtualized processes - - - - - This dialog should disappear automatically if the application/game is done. + + + Connecting to Nexus... - - Virtualized processes are still running, it is prefered to keep MO running until they are finished. + + Cancel - - Close Now + + Hide - - Cancel + + Trying again... @@ -7801,7 +8191,6 @@ Please open the "Nexus"-tab Use this interface to obtain an API key from NexusMods. This is used for all API connections - downloads, updates etc. MO2 uses the Windows Credential Manager to store this data securely. If the SSO page on Nexus is failing, use the manual entry and copy the API key from your profile. - Use this interface to obtain an API key from NexusMods.This is used for all API connections - downloads, updatesetc. MO2 uses the Windows Credential Manager to storethis data securely. If the SSO page on Nexus is failing,use the manual entry and copy the API key from your profile. -- cgit v1.3.1 From c9d33dad4667e6087ced5155805e88984cc6b3fd Mon Sep 17 00:00:00 2001 From: Silarn Date: Sat, 14 Dec 2019 19:05:11 -0600 Subject: Allow content tooltip to translate --- src/modlist.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'src/modlist.cpp') diff --git a/src/modlist.cpp b/src/modlist.cpp index c5b8c856..5cfa7022 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -66,18 +66,18 @@ ModList::ModList(PluginContainer *pluginContainer, QObject *parent) , m_DropOnItems(false) , m_PluginContainer(pluginContainer) { - m_ContentIcons[ModInfo::CONTENT_PLUGIN] = std::make_tuple(":/MO/gui/content/plugin", tr("Game Plugins (ESP/ESM/ESL)")); - m_ContentIcons[ModInfo::CONTENT_INTERFACE] = std::make_tuple(":/MO/gui/content/interface", tr("Interface")); - m_ContentIcons[ModInfo::CONTENT_MESH] = std::make_tuple(":/MO/gui/content/mesh", tr("Meshes")); - m_ContentIcons[ModInfo::CONTENT_BSA] = std::make_tuple(":/MO/gui/content/bsa", tr("Bethesda Archive")); - m_ContentIcons[ModInfo::CONTENT_SCRIPT] = std::make_tuple(":/MO/gui/content/script", tr("Scripts (Papyrus)")); - m_ContentIcons[ModInfo::CONTENT_SKSE] = std::make_tuple(":/MO/gui/content/skse", tr("Script Extender Plugin")); - m_ContentIcons[ModInfo::CONTENT_SKYPROC] = std::make_tuple(":/MO/gui/content/skyproc", tr("SkyProc Patcher")); - m_ContentIcons[ModInfo::CONTENT_SOUND] = std::make_tuple(":/MO/gui/content/sound", tr("Sound or Music")); - m_ContentIcons[ModInfo::CONTENT_TEXTURE] = std::make_tuple(":/MO/gui/content/texture", tr("Textures")); - m_ContentIcons[ModInfo::CONTENT_MCM] = std::make_tuple(":/MO/gui/content/menu", tr("MCM Configuration")); - m_ContentIcons[ModInfo::CONTENT_INI] = std::make_tuple(":/MO/gui/content/inifile", tr("INI files")); - m_ContentIcons[ModInfo::CONTENT_MODGROUP] = std::make_tuple(":/MO/gui/content/modgroup", tr("ModGroup files")); + m_ContentIcons[ModInfo::CONTENT_PLUGIN] = std::make_tuple(":/MO/gui/content/plugin", QT_TR_NOOP("Game Plugins (ESP/ESM/ESL)")); + m_ContentIcons[ModInfo::CONTENT_INTERFACE] = std::make_tuple(":/MO/gui/content/interface", QT_TR_NOOP("Interface")); + m_ContentIcons[ModInfo::CONTENT_MESH] = std::make_tuple(":/MO/gui/content/mesh", QT_TR_NOOP("Meshes")); + m_ContentIcons[ModInfo::CONTENT_BSA] = std::make_tuple(":/MO/gui/content/bsa", QT_TR_NOOP("Bethesda Archive")); + m_ContentIcons[ModInfo::CONTENT_SCRIPT] = std::make_tuple(":/MO/gui/content/script", QT_TR_NOOP("Scripts (Papyrus)")); + m_ContentIcons[ModInfo::CONTENT_SKSE] = std::make_tuple(":/MO/gui/content/skse", QT_TR_NOOP("Script Extender Plugin")); + m_ContentIcons[ModInfo::CONTENT_SKYPROC] = std::make_tuple(":/MO/gui/content/skyproc", QT_TR_NOOP("SkyProc Patcher")); + m_ContentIcons[ModInfo::CONTENT_SOUND] = std::make_tuple(":/MO/gui/content/sound", QT_TR_NOOP("Sound or Music")); + m_ContentIcons[ModInfo::CONTENT_TEXTURE] = std::make_tuple(":/MO/gui/content/texture", QT_TR_NOOP("Textures")); + m_ContentIcons[ModInfo::CONTENT_MCM] = std::make_tuple(":/MO/gui/content/menu", QT_TR_NOOP("MCM Configuration")); + m_ContentIcons[ModInfo::CONTENT_INI] = std::make_tuple(":/MO/gui/content/inifile", QT_TR_NOOP("INI files")); + m_ContentIcons[ModInfo::CONTENT_MODGROUP] = std::make_tuple(":/MO/gui/content/modgroup", QT_TR_NOOP("ModGroup files")); m_LastCheck.start(); } @@ -207,7 +207,7 @@ QString ModList::contentsToToolTip(const std::vector &content if (contentsSet.find(iter->first) != contentsSet.end()) { result.append(QString("" "") - .arg(std::get<0>(iter->second)).arg(std::get<1>(iter->second))); + .arg(std::get<0>(iter->second)).arg(tr(std::get<1>(iter->second).toStdString().c_str()))); } } result.append("
%2
"); -- cgit v1.3.1