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/modinfodialog.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/modinfodialog.cpp') 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); } } } -- 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/modinfodialog.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 cc3a16c6e9d58ed68a31be52f9fe2ef1d514ff5f Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sat, 3 Aug 2019 03:28:33 -0400 Subject: moved geometry handling to mod info and overwrite dialogs --- src/mainwindow.cpp | 18 +----------- src/modinfodialog.cpp | 72 +++++++++++++-------------------------------- src/modinfodialog.h | 26 ++++++++-------- src/overwriteinfodialog.cpp | 19 ++++++++++++ src/overwriteinfodialog.h | 11 ++++++- src/settings.cpp | 66 +++++++++++++++++++++++++++++++++++++++++ src/settings.h | 9 ++++++ 7 files changed, 137 insertions(+), 84 deletions(-) (limited to 'src/modinfodialog.cpp') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index ac86d9d8..32f728d8 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -3165,9 +3165,6 @@ void MainWindow::overwriteClosed(int) OverwriteInfoDialog *dialog = this->findChild("__overwriteDialog"); if (dialog != nullptr) { m_OrganizerCore.modList()->modInfoChanged(dialog->modInfo()); - QSettings &settings = m_OrganizerCore.settings().directInterface(); - QString key = QString("geometry/%1").arg(dialog->objectName()); - settings.setValue(key, dialog->saveGeometry()); dialog->deleteLater(); } m_OrganizerCore.refreshDirectoryStructure(); @@ -3191,11 +3188,7 @@ void MainWindow::displayModInformation( } else { qobject_cast(dialog)->setModInfo(modInfo); } - QSettings &settings = m_OrganizerCore.settings().directInterface(); - QString key = QString("geometry/%1").arg(dialog->objectName()); - if (settings.contains(key)) { - dialog->restoreGeometry(settings.value(key).toByteArray()); - } + dialog->show(); dialog->raise(); dialog->activateWindow(); @@ -3214,16 +3207,7 @@ void MainWindow::displayModInformation( dialog.selectTab(tabID); } - dialog.restoreState(m_OrganizerCore.settings()); - QSettings &settings = m_OrganizerCore.settings().directInterface(); - QString key = QString("geometry/%1").arg(dialog.objectName()); - if (settings.contains(key)) { - dialog.restoreGeometry(settings.value(key).toByteArray()); - } - dialog.exec(); - dialog.saveState(m_OrganizerCore.settings()); - settings.setValue(key, dialog.saveGeometry()); modInfo->saveMeta(); emit modInfoDisplayed(); diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 4b1e2f76..5e614358 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -210,6 +210,11 @@ void ModInfoDialog::createTabs() int ModInfoDialog::exec() { + restoreState(); + if (auto v=m_core->settings().geometry().getModInfoDialog()) { + restoreGeometry(*v); + } + // whether to select the first tab; if the main window requested a specific // tab, it is selected when encountered in update() const auto selectFirst = (m_initialTab == ModInfoTabIDs::None); @@ -220,7 +225,12 @@ int ModInfoDialog::exec() ui->tabWidget->setCurrentIndex(0); } - return TutorableDialog::exec(); + const int r = TutorableDialog::exec(); + + saveState(); + m_core->settings().geometry().setModInfoDialog(saveGeometry()); + + return r; } void ModInfoDialog::setMod(ModInfo::Ptr mod) @@ -356,7 +366,7 @@ void ModInfoDialog::setTabsVisibility(bool firstTime) if (!firstTime) { // but don't do it the first time visibility is set because the tabs are // in the default order, which will clobber the current settings - saveTabOrder(Settings::instance()); + saveTabOrder(); } // remember selection, if any @@ -375,7 +385,7 @@ void ModInfoDialog::reAddTabs( Q_ASSERT(visibility.size() == m_tabs.size()); // ordered tab names from settings - const auto orderedNames = getOrderedTabNames(); + const auto orderedNames = m_core->settings().geometry().getModInfoTabOrder(); // 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 @@ -575,37 +585,28 @@ MOShared::FilesOrigin* ModInfoDialog::getOrigin() return origin; } -void ModInfoDialog::saveState(Settings& s) const +void ModInfoDialog::saveState() const { - saveTabOrder(s); - - // remove 2.2.0 settings - s.directInterface().remove("mod_info_tabs"); - s.directInterface().remove("mod_info_conflict_expanders"); - s.directInterface().remove("mod_info_conflicts"); - s.directInterface().remove("mod_info_advanced_conflicts"); - s.directInterface().remove("mod_info_conflicts_overwrite"); - s.directInterface().remove("mod_info_conflicts_noconflict"); - s.directInterface().remove("mod_info_conflicts_overwritten"); + saveTabOrder(); // save state for each tab for (const auto& tabInfo : m_tabs) { - tabInfo.tab->saveState(s); + tabInfo.tab->saveState(m_core->settings()); } } -void ModInfoDialog::restoreState(const Settings& s) +void ModInfoDialog::restoreState() { // tab order is not restored here, it will be picked up if tabs have to be // removed and re-added // restore state for each tab for (const auto& tabInfo : m_tabs) { - tabInfo.tab->restoreState(s); + tabInfo.tab->restoreState(m_core->settings()); } } -void ModInfoDialog::saveTabOrder(Settings& s) const +void ModInfoDialog::saveTabOrder() const { if (static_cast(m_tabs.size()) != ui->tabWidget->count()) { // only save tab state when all tabs are visible @@ -629,40 +630,7 @@ void ModInfoDialog::saveTabOrder(Settings& s) const names += ui->tabWidget->widget(i)->objectName(); } - s.directInterface().setValue("mod_info_tab_order", names); -} - -std::vector ModInfoDialog::getOrderedTabNames() const -{ - const auto& settings = Settings::instance().directInterface(); - - std::vector v; - - if (settings.contains("mod_info_tabs")) { - // old byte array from 2.2.0 - QDataStream stream(settings.value("mod_info_tabs").toByteArray()); - - int count = 0; - stream >> count; - - for (int i=0; i> s; - v.emplace_back(std::move(s)); - } - } else { - // string list - QString string = settings.value("mod_info_tab_order").toString(); - QTextStream stream(&string); - - while (!stream.atEnd()) { - QString s; - stream >> s; - v.emplace_back(std::move(s)); - } - } - - return v; + m_core->settings().geometry().setModInfoTabOrder(names); } void ModInfoDialog::onOriginModified(int originID) diff --git a/src/modinfodialog.h b/src/modinfodialog.h index 34555b0c..48680ca4 100644 --- a/src/modinfodialog.h +++ b/src/modinfodialog.h @@ -61,18 +61,11 @@ public: // void selectTab(ModInfoTabIDs id); - // updates all tabs, selects the initial tab and opens the dialog + // updates all tabs, selects the initial tab, opens the dialog and + // saves/restores geometry // int exec() override; - // saves the dialog state and calls saveState() on all tabs - // - void saveState(Settings& s) const; - - // restores the dialog state and calls restoreState() on all tabs - // - void restoreState(const Settings& s); - signals: // emitted when a tab changes the origin // @@ -146,6 +139,15 @@ private: void createTabs(); + // saves the dialog state and calls saveState() on all tabs + // + void saveState() const; + + // restores the dialog state and calls restoreState() on all tabs + // + void restoreState(); + + // sets the currently selected mod; resets first activation, but doesn't // update anything // @@ -213,11 +215,7 @@ private: // setTabsVisibility() to make sure any changes to order are saved before // re-adding tabs // - void saveTabOrder(Settings& s) const; - - // returns a list of tab names in the order they should appear on the widget - // - std::vector getOrderedTabNames() const; + void saveTabOrder() const; // asks all the tabs if they accept closing the dialog, returns false if one // objected diff --git a/src/overwriteinfodialog.cpp b/src/overwriteinfodialog.cpp index 715e11e3..f3ae0ff5 100644 --- a/src/overwriteinfodialog.cpp +++ b/src/overwriteinfodialog.cpp @@ -104,6 +104,25 @@ OverwriteInfoDialog::~OverwriteInfoDialog() delete ui; } +void OverwriteInfoDialog::showEvent(QShowEvent* e) +{ + const auto& settings = Settings::instance(); + + if (auto v=settings.geometry().getOverwriteDialog()) { + restoreGeometry(*v); + } + + QDialog::showEvent(e); +} + +void OverwriteInfoDialog::done(int r) +{ + auto& settings = Settings::instance(); + settings.geometry().setOverwriteDialog(saveGeometry()); + + QDialog::done(r); +} + void OverwriteInfoDialog::setModInfo(ModInfo::Ptr modInfo) { m_ModInfo = modInfo; diff --git a/src/overwriteinfodialog.h b/src/overwriteinfodialog.h index 4b731736..bedb779a 100644 --- a/src/overwriteinfodialog.h +++ b/src/overwriteinfodialog.h @@ -31,7 +31,7 @@ class OverwriteInfoDialog; class OverwriteInfoDialog : public QDialog { Q_OBJECT - + public: explicit OverwriteInfoDialog(ModInfo::Ptr modInfo, QWidget *parent = 0); @@ -39,8 +39,17 @@ public: ModInfo::Ptr modInfo() const { return m_ModInfo; } + // saves geometry + // + void done(int r) override; + void setModInfo(ModInfo::Ptr modInfo); +protected: + // restores geometry + // + void showEvent(QShowEvent* e) override; + private: void openFile(const QModelIndex &index); diff --git a/src/settings.cpp b/src/settings.cpp index 1f5abb2a..73595ac9 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -120,6 +120,16 @@ void Settings::processUpdates( m_Settings.endGroup(); } + if (lastVersion < QVersionNumber(2, 2, 1)) { + m_Settings.remove("mod_info_tabs"); + m_Settings.remove("mod_info_conflict_expanders"); + m_Settings.remove("mod_info_conflicts"); + m_Settings.remove("mod_info_advanced_conflicts"); + m_Settings.remove("mod_info_conflicts_overwrite"); + m_Settings.remove("mod_info_conflicts_noconflict"); + m_Settings.remove("mod_info_conflicts_overwritten"); + } + if (lastVersion < QVersionNumber(2, 2, 2)) { // log splitter is gone, it's a dock now m_Settings.remove("log_split"); @@ -876,6 +886,62 @@ void GeometrySettings::setProfilesDialog(const QByteArray& v) m_Settings.setValue("geometry/ProfilesDialog", v); } +std::optional GeometrySettings::getOverwriteDialog() const +{ + return getOptional(m_Settings, "geometry/__overwriteDialog"); +} + +void GeometrySettings::setOverwriteDialog(const QByteArray& v) +{ + m_Settings.setValue("geometry/__overwriteDialog", v); +} + +std::optional GeometrySettings::getModInfoDialog() const +{ + return getOptional(m_Settings, "geometry/ModInfoDialog"); +} + +void GeometrySettings::setModInfoDialog(const QByteArray& v) const +{ + m_Settings.setValue("geometry/ModInfoDialog", v); +} + +QStringList GeometrySettings::getModInfoTabOrder() 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 v; +} + +void GeometrySettings::setModInfoTabOrder(const QString& names) +{ + m_Settings.setValue("mod_info_tab_order", names); +} + std::optional GeometrySettings::getMainWindowMonitor() const { return getOptional(m_Settings, "window_monitor"); diff --git a/src/settings.h b/src/settings.h index 6d51c610..f4e36b2a 100644 --- a/src/settings.h +++ b/src/settings.h @@ -52,6 +52,15 @@ public: std::optional getProfilesDialog() const; void setProfilesDialog(const QByteArray& v); + std::optional getOverwriteDialog() const; + void setOverwriteDialog(const QByteArray& v); + + std::optional getModInfoDialog() const; + void setModInfoDialog(const QByteArray& v) const; + + QStringList getModInfoTabOrder() const; + void setModInfoTabOrder(const QString& names); + std::optional getMainWindowMonitor() const; void setDockSize(const QString& name, int size); -- cgit v1.3.1 From 799ddb1b2477434252d06975fd4c68106dc3826f Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 16 Aug 2019 06:03:05 -0400 Subject: added GeometrySaver removed widget-specific functions in GeometrySettings, now using generic functions in Settings removed some unused member variables in MainWindow --- src/categoriesdialog.cpp | 13 +-- src/editexecutablesdialog.cpp | 13 +-- src/listdialog.cpp | 13 +-- src/mainwindow.cpp | 49 ++++------ src/mainwindow.h | 4 - src/modinfodialog.cpp | 6 +- src/overwriteinfodialog.cpp | 11 +-- src/previewdialog.cpp | 13 +-- src/problemsdialog.cpp | 13 +-- src/profilesdialog.cpp | 13 +-- src/settings.cpp | 218 +++++++++++++++++++----------------------- src/settings.h | 64 +++++-------- 12 files changed, 158 insertions(+), 272 deletions(-) (limited to 'src/modinfodialog.cpp') diff --git a/src/categoriesdialog.cpp b/src/categoriesdialog.cpp index 91df5cae..b5194bf0 100644 --- a/src/categoriesdialog.cpp +++ b/src/categoriesdialog.cpp @@ -112,17 +112,8 @@ CategoriesDialog::~CategoriesDialog() int CategoriesDialog::exec() { - auto& settings = Settings::instance(); - - if (auto v=settings.geometry().getCategoriesDialog()) { - restoreGeometry(*v); - } - - const int r = QDialog::exec(); - - settings.geometry().setCategoriesDialog(saveGeometry()); - - return r; + GeometrySaver gs(Settings::instance(), this); + return QDialog::exec(); } diff --git a/src/editexecutablesdialog.cpp b/src/editexecutablesdialog.cpp index 9c5ae44a..7823fadc 100644 --- a/src/editexecutablesdialog.cpp +++ b/src/editexecutablesdialog.cpp @@ -67,17 +67,8 @@ EditExecutablesDialog::~EditExecutablesDialog() = default; int EditExecutablesDialog::exec() { - auto& settings = m_organizerCore.settings(); - - if (auto v=settings.geometry().getExecutablesDialog()) { - restoreGeometry(*v); - } - - const int r = QDialog::exec(); - - settings.geometry().setExecutablesDialog(saveGeometry()); - - return r; + GeometrySaver gs(Settings::instance(), this); + return QDialog::exec(); } void EditExecutablesDialog::loadCustomOverwrites() diff --git a/src/listdialog.cpp b/src/listdialog.cpp index 0fdcdb5f..2ad88408 100644 --- a/src/listdialog.cpp +++ b/src/listdialog.cpp @@ -35,17 +35,8 @@ ListDialog::~ListDialog() int ListDialog::exec() { - auto& settings = Settings::instance(); - - if (auto v=settings.geometry().getListDialog()) { - restoreGeometry(*v); - } - - const int r = QDialog::exec(); - - settings.geometry().setListDialog(saveGeometry()); - - return r; + GeometrySaver gs(Settings::instance(), this); + return QDialog::exec(); } void ListDialog::setChoices(QStringList choices) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 532914a5..85be8563 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -290,7 +290,6 @@ MainWindow::MainWindow(Settings &settings , m_linksSeparator(nullptr) , m_Tutorial(this, "MainWindow") , m_OldProfileIndex(-1) - , m_ModListGroupingProxy(nullptr) , m_ModListSortProxy(nullptr) , m_OldExecutableIndex(-1) , m_CategoryFactory(CategoryFactory::instance()) @@ -309,8 +308,8 @@ MainWindow::MainWindow(Settings &settings { QWebEngineProfile::defaultProfile()->setPersistentCookiesPolicy(QWebEngineProfile::NoPersistentCookies); QWebEngineProfile::defaultProfile()->setHttpCacheMaximumSize(52428800); - QWebEngineProfile::defaultProfile()->setCachePath(m_OrganizerCore.settings().getCacheDirectory()); - QWebEngineProfile::defaultProfile()->setPersistentStoragePath(m_OrganizerCore.settings().getCacheDirectory()); + QWebEngineProfile::defaultProfile()->setCachePath(settings.getCacheDirectory()); + QWebEngineProfile::defaultProfile()->setPersistentStoragePath(settings.getCacheDirectory()); ui->setupUi(this); m_statusBar.reset(new StatusBar(statusBar(), ui)); @@ -340,7 +339,7 @@ MainWindow::MainWindow(Settings &settings m_statusBar->setAPI(ni->getAPIStats(), ni->getAPIUserAccount()); } - languageChange(m_OrganizerCore.settings().language()); + languageChange(settings.language()); m_CategoryFactory.loadCategories(); @@ -367,19 +366,9 @@ MainWindow::MainWindow(Settings &settings initDownloadView(); - bool pluginListAdjusted = false; - if (auto v=m_OrganizerCore.settings().geometry().getPluginListHeader()) { - ui->espList->header()->restoreState(*v); - pluginListAdjusted = true; - } - - if (auto v=m_OrganizerCore.settings().geometry().getDataTreeHeader()) { - ui->dataTree->header()->restoreState(*v); - } - - if (auto v=m_OrganizerCore.settings().geometry().getDownloadViewHeader()) { - ui->downloadView->header()->restoreState(*v); - } + const bool pluginListAdjusted = settings.restoreState(ui->espList->header()); + settings.restoreState(ui->dataTree->header()); + settings.restoreState(ui->downloadView->header()); ui->splitter->setStretchFactor(0, 3); ui->splitter->setStretchFactor(1, 2); @@ -586,9 +575,7 @@ void MainWindow::setupModList() ui->modList->header()->installEventFilter(m_OrganizerCore.modList()); - if (auto v=m_OrganizerCore.settings().geometry().getModListHeader()) { - ui->modList->header()->restoreState(*v); - + if (m_OrganizerCore.settings().restoreState(ui->modList->header())) { // hack: force the resize-signal to be triggered because restoreState doesn't seem to do that for (int column = 0; column <= ModList::COL_LASTCOLUMN; ++column) { int sectionSize = ui->modList->header()->sectionSize(column); @@ -2272,13 +2259,8 @@ void MainWindow::activateProxy(bool activate) void MainWindow::readSettings(const Settings& settings) { - if (auto v=settings.geometry().getMainWindow()) { - restoreGeometry(*v); - } - - if (auto v=settings.geometry().getMainWindowState()) { - restoreState(*v); - } + settings.restoreGeometry(this); + settings.restoreState(this); if (auto v=settings.geometry().getToolbarSize()) { setToolbarSize(*v); @@ -2381,8 +2363,9 @@ void MainWindow::storeSettings(Settings& s) { settings.remove("geometry"); settings.remove("reset_geometry"); } else { - settings.setValue("window_geometry", saveGeometry()); - settings.setValue("window_state", saveState()); + s.saveState(this); + s.saveGeometry(this); + settings.setValue("toolbar_size", ui->toolBar->iconSize()); settings.setValue("toolbar_button_style", static_cast(ui->toolBar->toolButtonStyle())); settings.setValue("menubar_visible", m_menuBarVisible); @@ -2394,10 +2377,10 @@ void MainWindow::storeSettings(Settings& s) { settings.setValue("browser_geometry", m_IntegratedBrowser.saveGeometry()); settings.setValue("filters_visible", ui->displayCategoriesBtn->isChecked()); - s.geometry().setPluginListHeader(ui->espList->header()->saveState()); - s.geometry().setDataTreeHeader(ui->dataTree->header()->saveState()); - s.geometry().setDownloadViewHeader(ui->downloadView->header()->saveState()); - s.geometry().setModListHeader(ui->modList->header()->saveState()); + s.saveState(ui->espList->header()); + s.saveState(ui->dataTree->header()); + s.saveState(ui->downloadView->header()); + s.saveState(ui->modList->header()); DockFixer::save(this, s); } diff --git a/src/mainwindow.h b/src/mainwindow.h index 7460019d..946a341b 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -347,11 +347,9 @@ private: int m_OldProfileIndex; std::vector m_ModNameList; // the mod-list to go with the directory structure - bool m_Refreshing; QStringList m_DefaultArchives; - QAbstractItemModel *m_ModListGroupingProxy; ModListSortProxy *m_ModListSortProxy; PluginListSortProxy *m_PluginListSortProxy; @@ -367,8 +365,6 @@ private: CategoryFactory &m_CategoryFactory; - bool m_LoginAttempted; - QTimer m_CheckBSATimer; QTimer m_SaveMetaTimer; QTimer m_UpdateProblemsTimer; diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 5e614358..f3840230 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -210,10 +210,8 @@ void ModInfoDialog::createTabs() int ModInfoDialog::exec() { + GeometrySaver gs(Settings::instance(), this); restoreState(); - if (auto v=m_core->settings().geometry().getModInfoDialog()) { - restoreGeometry(*v); - } // whether to select the first tab; if the main window requested a specific // tab, it is selected when encountered in update() @@ -226,9 +224,7 @@ int ModInfoDialog::exec() } const int r = TutorableDialog::exec(); - saveState(); - m_core->settings().geometry().setModInfoDialog(saveGeometry()); return r; } diff --git a/src/overwriteinfodialog.cpp b/src/overwriteinfodialog.cpp index f3ae0ff5..47416311 100644 --- a/src/overwriteinfodialog.cpp +++ b/src/overwriteinfodialog.cpp @@ -106,20 +106,13 @@ OverwriteInfoDialog::~OverwriteInfoDialog() void OverwriteInfoDialog::showEvent(QShowEvent* e) { - const auto& settings = Settings::instance(); - - if (auto v=settings.geometry().getOverwriteDialog()) { - restoreGeometry(*v); - } - + Settings::instance().restoreGeometry(this); QDialog::showEvent(e); } void OverwriteInfoDialog::done(int r) { - auto& settings = Settings::instance(); - settings.geometry().setOverwriteDialog(saveGeometry()); - + Settings::instance().saveGeometry(this); QDialog::done(r); } diff --git a/src/previewdialog.cpp b/src/previewdialog.cpp index 06dcd674..91a5f13e 100644 --- a/src/previewdialog.cpp +++ b/src/previewdialog.cpp @@ -20,17 +20,8 @@ PreviewDialog::~PreviewDialog() int PreviewDialog::exec() { - auto& settings = Settings::instance(); - - if (auto v=settings.geometry().getPreviewDialog()) { - restoreGeometry(*v); - } - - const int r = QDialog::exec(); - - settings.geometry().setPreviewDialog(saveGeometry()); - - return r; + GeometrySaver gs(Settings::instance(), this); + return QDialog::exec(); } void PreviewDialog::addVariant(const QString &modName, QWidget *widget) diff --git a/src/problemsdialog.cpp b/src/problemsdialog.cpp index 99cc9833..63d58295 100644 --- a/src/problemsdialog.cpp +++ b/src/problemsdialog.cpp @@ -31,17 +31,8 @@ ProblemsDialog::~ProblemsDialog() int ProblemsDialog::exec() { - auto& settings = Settings::instance(); - - if (auto v=settings.geometry().getProblemsDialog()) { - restoreGeometry(*v); - } - - const int r = QDialog::exec(); - - settings.geometry().setProblemsDialog(saveGeometry()); - - return r; + GeometrySaver gs(Settings::instance(), this); + return QDialog::exec(); } void ProblemsDialog::runDiagnosis() diff --git a/src/profilesdialog.cpp b/src/profilesdialog.cpp index 25fff2b2..2f1bd059 100644 --- a/src/profilesdialog.cpp +++ b/src/profilesdialog.cpp @@ -86,17 +86,8 @@ ProfilesDialog::~ProfilesDialog() int ProfilesDialog::exec() { - auto& settings = Settings::instance(); - - if (auto v=settings.geometry().getProfilesDialog()) { - restoreGeometry(*v); - } - - const int r = QDialog::exec(); - - settings.geometry().setProfilesDialog(saveGeometry()); - - return r; + GeometrySaver gs(Settings::instance(), this); + return QDialog::exec(); } void ProfilesDialog::showEvent(QShowEvent *event) diff --git a/src/settings.cpp b/src/settings.cpp index a8dcfa39..91e667d5 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -884,94 +884,146 @@ void Settings::dump() const m_Settings.endGroup(); } +QString widgetNameWithTopLevel(const QWidget* widget) +{ + QStringList components; -GeometrySettings::GeometrySettings(QSettings& s) - : m_Settings(s) + auto* tl = widget->window(); + + if (tl == widget) { + // this is a top level widget, such as a dialog + components.push_back(widget->objectName()); + } else { + // this is a widget + const auto toplevelName = tl->objectName(); + if (!toplevelName.isEmpty()) { + components.push_back(toplevelName); + } + + const auto widgetName = widget->objectName(); + if (!widgetName.isEmpty()) { + components.push_back(widgetName); + } + } + + if (components.isEmpty()) { + // can't do much + return "unknown_widget"; + } + + return components.join("_"); +} + +QString widgetName(const QMainWindow* w) { + return w->objectName(); } -std::optional GeometrySettings::getMainWindow() const +QString widgetName(const QHeaderView* w) { - return getOptional(m_Settings, "window_geometry"); + return widgetNameWithTopLevel(w->parentWidget()); } -std::optional GeometrySettings::getMainWindowState() const +QString widgetName(const QWidget* w) { - return getOptional(m_Settings, "window_state"); + return widgetNameWithTopLevel(w); } -std::optional GeometrySettings::getToolbarSize() const +template +QString geoSettingName(const Widget* widget) { - return getOptional(m_Settings, "toolbar_size"); + return "geometry/" + widgetName(widget) + "_geometry"; } -std::optional GeometrySettings::getToolbarButtonStyle() const +template +QString stateSettingName(const Widget* widget) { - if (auto v=getOptional(m_Settings, "toolbar_button_style")) { - return static_cast(*v); - } + return "geometry/" + widgetName(widget) + "_state"; +} - return {}; +void Settings::saveGeometry(const QWidget* w) +{ + m_Settings.setValue(geoSettingName(w), w->saveGeometry()); } -std::optional GeometrySettings::getMenubarVisible() const +bool Settings::restoreGeometry(QWidget* w) const { - return getOptional(m_Settings, "menubar_visible"); + if (auto v=getOptional(m_Settings, geoSettingName(w))) { + w->restoreGeometry(*v); + return true; + } + + return false; } -std::optional GeometrySettings::getStatusbarVisible() const +void Settings::saveState(const QMainWindow* w) { - return getOptional(m_Settings, "statusbar_visible"); + m_Settings.setValue(stateSettingName(w), w->saveGeometry()); } -std::optional GeometrySettings::getMainSplitterState() const +bool Settings::restoreState(QMainWindow* w) const { - return getOptional(m_Settings, "window_split"); + if (auto v=getOptional(m_Settings, stateSettingName(w))) { + w->restoreState(*v); + return true; + } + + return false; } -std::optional GeometrySettings::getFiltersVisible() const +void Settings::saveState(const QHeaderView* w) { - return getOptional(m_Settings, "filters_visible"); + m_Settings.setValue(stateSettingName(w), w->saveState()); } -std::optional GeometrySettings::getExecutablesDialog() const +bool Settings::restoreState(QHeaderView* w) const { - return getOptional(m_Settings, "geometry/EditExecutablesDialog"); + if (auto v=getOptional(m_Settings, stateSettingName(w))) { + w->restoreState(*v); + return true; + } + + return false; } -void GeometrySettings::setExecutablesDialog(const QByteArray& v) + +GeometrySettings::GeometrySettings(QSettings& s) + : m_Settings(s) { - m_Settings.setValue("geometry/EditExecutablesDialog", v); } -std::optional GeometrySettings::getProfilesDialog() const +std::optional GeometrySettings::getToolbarSize() const { - return getOptional(m_Settings, "geometry/ProfilesDialog"); + return getOptional(m_Settings, "toolbar_size"); } -void GeometrySettings::setProfilesDialog(const QByteArray& v) +std::optional GeometrySettings::getToolbarButtonStyle() const { - m_Settings.setValue("geometry/ProfilesDialog", v); + if (auto v=getOptional(m_Settings, "toolbar_button_style")) { + return static_cast(*v); + } + + return {}; } -std::optional GeometrySettings::getOverwriteDialog() const +std::optional GeometrySettings::getMenubarVisible() const { - return getOptional(m_Settings, "geometry/__overwriteDialog"); + return getOptional(m_Settings, "menubar_visible"); } -void GeometrySettings::setOverwriteDialog(const QByteArray& v) +std::optional GeometrySettings::getStatusbarVisible() const { - m_Settings.setValue("geometry/__overwriteDialog", v); + return getOptional(m_Settings, "statusbar_visible"); } -std::optional GeometrySettings::getModInfoDialog() const +std::optional GeometrySettings::getMainSplitterState() const { - return getOptional(m_Settings, "geometry/ModInfoDialog"); + return getOptional(m_Settings, "window_split"); } -void GeometrySettings::setModInfoDialog(const QByteArray& v) const +std::optional GeometrySettings::getFiltersVisible() const { - m_Settings.setValue("geometry/ModInfoDialog", v); + return getOptional(m_Settings, "filters_visible"); } QStringList GeometrySettings::getModInfoTabOrder() const @@ -1010,86 +1062,6 @@ void GeometrySettings::setModInfoTabOrder(const QString& names) m_Settings.setValue("mod_info_tab_order", names); } -std::optional GeometrySettings::getListDialog() const -{ - return getOptional(m_Settings, "geometry/ListDialog"); -} - -void GeometrySettings::setListDialog(const QByteArray& v) -{ - m_Settings.setValue("geometry/ListDialog", v); -} - -std::optional GeometrySettings::getProblemsDialog() const -{ - return getOptional(m_Settings, "geometry/ProblemsDialog"); -} - -void GeometrySettings::setProblemsDialog(const QByteArray& v) -{ - m_Settings.setValue("geometry/ProblemsDialog", v); -} - -std::optional GeometrySettings::getCategoriesDialog() const -{ - return getOptional(m_Settings, "geometry/CategoriesDialog"); -} - -void GeometrySettings::setCategoriesDialog(const QByteArray& v) -{ - m_Settings.setValue("geometry/CategoriesDialog", v); -} - -std::optional GeometrySettings::getPreviewDialog() const -{ - return getOptional(m_Settings, "geometry/PreviewDialog"); -} - -void GeometrySettings::setPreviewDialog(const QByteArray& v) -{ - m_Settings.setValue("geometry/PreviewDialog", v); -} - -std::optional GeometrySettings::getPluginListHeader() const -{ - return getOptional(m_Settings, "geometry/espList"); -} - -void GeometrySettings::setPluginListHeader(const QByteArray& v) const -{ - m_Settings.setValue("geometry/espList", v); -} - -std::optional GeometrySettings::getDataTreeHeader() const -{ - return getOptional(m_Settings, "geometry/dataTree"); -} - -void GeometrySettings::setDataTreeHeader(const QByteArray& v) const -{ - m_Settings.setValue("geometry/dataTree", v); -} - -std::optional GeometrySettings::getDownloadViewHeader() const -{ - return getOptional(m_Settings, "geometry/downloadView"); -} - -void GeometrySettings::setDownloadViewHeader(const QByteArray& v) const -{ - m_Settings.setValue("geometry/downloadView", v); -} - -std::optional GeometrySettings::getModListHeader() const -{ - return getOptional(m_Settings, "geometry/modList"); -} - -void GeometrySettings::setModListHeader(const QByteArray& v) const -{ - m_Settings.setValue("geometry/modList", v); -} - std::optional GeometrySettings::getMainWindowMonitor() const { return getOptional(m_Settings, "window_monitor"); @@ -1109,3 +1081,15 @@ std::optional GeometrySettings::isCategoryListVisible() const { return getOptional(m_Settings, "categorylist_visible"); } + + +GeometrySaver::GeometrySaver(Settings& s, QDialog* dialog) + : m_settings(s), m_dialog(dialog) +{ + m_settings.restoreGeometry(m_dialog); +} + +GeometrySaver::~GeometrySaver() +{ + m_settings.saveGeometry(m_dialog); +} diff --git a/src/settings.h b/src/settings.h index 2c4c7ca6..1575b3cd 100644 --- a/src/settings.h +++ b/src/settings.h @@ -30,6 +30,18 @@ namespace MOBase { class PluginContainer; struct ServerInfo; +class Settings; + +class GeometrySaver +{ +public: + GeometrySaver(Settings& s, QDialog* dialog); + ~GeometrySaver(); + +private: + Settings& m_settings; + QDialog* m_dialog; +}; class GeometrySettings @@ -37,54 +49,17 @@ class GeometrySettings public: GeometrySettings(QSettings& s); - std::optional getMainWindow() const; - std::optional getMainWindowState() const; std::optional getToolbarSize() const; std::optional getToolbarButtonStyle() const; + std::optional getMenubarVisible() const; std::optional getStatusbarVisible() const; std::optional getMainSplitterState() const; std::optional getFiltersVisible() const; - std::optional getExecutablesDialog() const; - void setExecutablesDialog(const QByteArray& v); - - std::optional getProfilesDialog() const; - void setProfilesDialog(const QByteArray& v); - - std::optional getOverwriteDialog() const; - void setOverwriteDialog(const QByteArray& v); - - std::optional getModInfoDialog() const; - void setModInfoDialog(const QByteArray& v) const; - QStringList getModInfoTabOrder() const; void setModInfoTabOrder(const QString& names); - std::optional getListDialog() const; - void setListDialog(const QByteArray& v); - - std::optional getProblemsDialog() const; - void setProblemsDialog(const QByteArray& v); - - std::optional getCategoriesDialog() const; - void setCategoriesDialog(const QByteArray& v); - - std::optional getPreviewDialog() const; - void setPreviewDialog(const QByteArray& v); - - std::optional getPluginListHeader() const; - void setPluginListHeader(const QByteArray& v) const; - - std::optional getDataTreeHeader() const; - void setDataTreeHeader(const QByteArray& v) const; - - std::optional getDownloadViewHeader() const; - void setDownloadViewHeader(const QByteArray& v) const; - - std::optional getModListHeader() const; - void setModListHeader(const QByteArray& v) const; - std::optional getMainWindowMonitor() const; void setDockSize(const QString& name, int size); @@ -228,6 +203,19 @@ public: const GeometrySettings& geometry() const; + void saveGeometry(const QWidget* w); + bool restoreGeometry(QWidget* w) const; + + void saveState(const QMainWindow* window); + bool restoreState(QMainWindow* window) const; + + void saveState(const QHeaderView* header); + bool restoreState(QHeaderView* header) const; + + void saveState(const QToolBar* toolbar); + bool restoreState(QToolBar* toolbar) const; + + /** * retrieve the directory where profiles stored (with native separators) **/ -- 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/modinfodialog.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 7f0fa1069f07d90a92be7073b11bab86bac7b2d2 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Mon, 2 Sep 2019 16:09:31 -0400 Subject: don't log widget and geometry setting changes fixed mod info dialog tab order using different settings for read and write mod info dialog now doesn't complain when no tab order exists in the settings only remove section when the array is larger, prevents logging changes when nothing actually changed --- src/modinfodialog.cpp | 9 ++++++--- src/settings.cpp | 27 ++++++++++++++++++++------- src/settings.h | 2 +- src/settingsutilities.cpp | 18 ++++++++++++++++++ src/settingsutilities.h | 6 ++++++ 5 files changed, 51 insertions(+), 11 deletions(-) (limited to 'src/modinfodialog.cpp') diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 2178ef34..c7e071ad 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -383,9 +383,12 @@ void ModInfoDialog::reAddTabs( // ordered tab names from settings 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 - bool canSort = true; + // 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; if the list is empty, it's probably a first run + // and there's nothing to sort + bool canSort = !orderedNames.empty(); // gathering visible tabs std::vector visibleTabs; diff --git a/src/settings.cpp b/src/settings.cpp index 8ae7c343..a33005b6 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -210,7 +210,7 @@ std::vector> Settings::executables() const std::map map; for (auto&& key : sra.keys()) { - map[key] = m_Settings.value(key); + map[key] = sra.get(key); } v.push_back(map); @@ -693,7 +693,7 @@ QStringList GeometrySettings::modInfoTabOrder() const } } else { // string list since 2.2.1 - QString string = m_Settings.value("mod_info_tab_order").toString(); + QString string = get(m_Settings, "Widgets", "ModInfoTabOrder", ""); QTextStream stream(&string); while (!stream.atEnd()) { @@ -708,7 +708,7 @@ QStringList GeometrySettings::modInfoTabOrder() const void GeometrySettings::setModInfoTabOrder(const QString& names) { - set(m_Settings, "Geometry", "mod_info_tab_order", names); + set(m_Settings, "Widgets", "ModInfoTabOrder", names); } void GeometrySettings::centerOnMainWindowMonitor(QWidget* w) @@ -1061,13 +1061,21 @@ void PluginSettings::clearPlugins() { m_Plugins.clear(); m_PluginSettings.clear(); - m_PluginBlacklist.clear(); + m_PluginBlacklist = readPluginBlacklist(); +} + +QSet PluginSettings::readPluginBlacklist() const +{ + QSet set; + ScopedReadArray sra(m_Settings, "pluginBlacklist"); sra.for_each([&]{ - m_PluginBlacklist.insert(sra.get("name")); + set.insert(sra.get("name")); }); + + return set; } void PluginSettings::registerPlugin(IPlugin *plugin) @@ -1166,9 +1174,14 @@ void PluginSettings::addBlacklistPlugin(const QString &fileName) void PluginSettings::writePluginBlacklist() { - removeSection(m_Settings, "pluginBlacklist"); + const auto current = readPluginBlacklist(); + + if (current.size() > m_PluginBlacklist.size()) { + // Qt can't remove array elements, the section must be cleared + removeSection(m_Settings, "pluginBlacklist"); + } - ScopedWriteArray swa(m_Settings, "pluginBlacklist"); + ScopedWriteArray swa(m_Settings, "pluginBlacklist", m_PluginBlacklist.size()); for (const QString &plugin : m_PluginBlacklist) { swa.next(); diff --git a/src/settings.h b/src/settings.h index 68cfb9b7..2ff8da1c 100644 --- a/src/settings.h +++ b/src/settings.h @@ -261,8 +261,8 @@ private: QMap m_PluginDescriptions; QSet m_PluginBlacklist; - void readPluginBlacklist(); void writePluginBlacklist(); + QSet readPluginBlacklist() const; }; diff --git a/src/settingsutilities.cpp b/src/settingsutilities.cpp index d5e2dd9a..7a9dcc35 100644 --- a/src/settingsutilities.cpp +++ b/src/settingsutilities.cpp @@ -4,8 +4,26 @@ using namespace MOBase; +bool shouldLogSetting(const QString& displayName) +{ + // don't log Geometry/ and Widgets/, too noisy and not very useful + static const QStringList ignorePrefixes = {"Geometry/", "Widgets/"}; + + for (auto&& prefix : ignorePrefixes) { + if (displayName.startsWith(prefix, Qt::CaseInsensitive)) { + return false; + } + } + + return true; +} + void logRemoval(const QString& name) { + if (!shouldLogSetting(name)) { + return; + } + log::debug("setting '{}' removed", name); } diff --git a/src/settingsutilities.h b/src/settingsutilities.h index ca754759..d99abb06 100644 --- a/src/settingsutilities.h +++ b/src/settingsutilities.h @@ -24,10 +24,16 @@ struct ValueConverter>> }; +bool shouldLogSetting(const QString& displayName); + template void logChange( const QString& displayName, std::optional oldValue, const T& newValue) { + if (!shouldLogSetting(displayName)) { + return; + } + using VC = ValueConverter; if (oldValue) { -- cgit v1.3.1 From d4172dc5f8c642dbbe235a86a28992af310e703a Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Mon, 2 Dec 2019 13:51:46 -0500 Subject: added "open with vfs" option to conflicts tab --- src/env.cpp | 157 +++++++++++++++++++++++++++++++++++++++++ src/env.h | 20 ++++++ src/modinfodialog.cpp | 23 +++++- src/modinfodialogconflicts.cpp | 39 +++++++++- src/modinfodialogconflicts.h | 2 + src/modinfodialogfwd.h | 1 + src/processrunner.cpp | 20 +++++- src/processrunner.h | 12 ++-- 8 files changed, 263 insertions(+), 11 deletions(-) (limited to 'src/modinfodialog.cpp') diff --git a/src/env.cpp b/src/env.cpp index f9507dc1..0098456e 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -675,6 +675,163 @@ Service getService(const QString& name) } +std::optional getAssocString(const QFileInfo& file, ASSOCSTR astr) +{ + const auto ext = L"." + file.suffix().toStdWString(); + + // getting buffer size + DWORD bufferSize = 0; + auto r = AssocQueryStringW( + ASSOCF_INIT_IGNOREUNKNOWN, astr, ext.c_str(), L"open", nullptr, &bufferSize); + + // returns S_FALSE when giving back the buffer size, so that's actually the + // expected return value + + if (r != S_FALSE || bufferSize == 0) { + if (r == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION)) { + log::error("file '{}' has no associated executable", file.absoluteFilePath()); + } else { + log::error( + "can't get buffer size for AssocQueryStringW(), {}", + formatSystemMessage(r)); + } + return {}; + } + + // getting string + auto buffer = std::make_unique(bufferSize + 1); + std::fill(buffer.get(), buffer.get() + bufferSize + 1, 0); + + r = AssocQueryStringW( + ASSOCF_INIT_IGNOREUNKNOWN, astr, ext.c_str(), L"open", buffer.get(), &bufferSize); + + if (FAILED(r)) { + log::error( + "failed to get exe associated with '{}', {}", + file.suffix(), formatSystemMessage(r)); + + return {}; + } + + // buffer size includes the null terminator + return QString::fromWCharArray(buffer.get(), bufferSize - 1); +} + +QString formatCommandLine(const QFileInfo& targetInfo, const QString& cmd) +{ + // yeah, FormatMessage() expects at least as many arguments as there are + // placeholders and while the command for associations should typically only + // have %1, the user can actually enter anything in the registry + // + // since the maximum number of arguments is 99, this creates an array of 99 + // wchar_* where the first one (%1) points to the filename and the remaining + // 98 to "" + // + // FormatMessage() actually takes a va_list* for the arguments, but by passing + // FORMAT_MESSAGE_ARGUMENT_ARRAY, an array of DWORD_PTR can be given instead + + // 99 arguments + std::array args; + + // first one is the filename + const auto wpath = targetInfo.absoluteFilePath().toStdWString(); + args[0] = reinterpret_cast(wpath.c_str()); + + // remaining are "" + std::fill(args.begin() + 1, args.end(), reinterpret_cast(L"")); + + // must be freed with LocalFree() + wchar_t* buffer = nullptr; + + const auto wcmd = cmd.toStdWString(); + + const auto n = ::FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_ARGUMENT_ARRAY | + FORMAT_MESSAGE_FROM_STRING, + wcmd.c_str(), 0, 0, + reinterpret_cast(&buffer), + 0, reinterpret_cast(&args[0])); + + if (n == 0 || !buffer){ + const auto e = GetLastError(); + + log::error( + "failed to format command line '{}' with path '{}', {}", + cmd, targetInfo.absoluteFilePath(), formatSystemMessage(e)); + + return {}; + } + + auto s = QString::fromWCharArray(buffer, n); + ::LocalFree(buffer); + + return s.trimmed(); +} + +std::pair splitExeAndArguments(const QString& cmd) +{ + int exeBegin = 0; + int exeEnd = -1; + + if (cmd[0] == '"'){ + // surrounded by double-quotes, so find the next one + exeBegin = 1; + exeEnd = cmd.indexOf('"', exeBegin); + + if (exeEnd == -1) { + log::error("missing terminating double-quote in command line '{}'", cmd); + return {}; + } + } else { + // no double-quotes, find the first whitespace + exeEnd = cmd.indexOf(QRegExp("\\s")); + if (exeEnd == -1) { + exeEnd = cmd.size(); + } + } + + QString exe = cmd.mid(exeBegin, exeEnd - exeBegin).trimmed(); + QString args = cmd.mid(exeEnd + 1).trimmed(); + + return {std::move(exe), std::move(args)}; +} + +Association getAssociation(const QFileInfo& targetInfo) +{ + log::debug( + "getting association for '{}', extension is '.{}'", + targetInfo.absoluteFilePath(), targetInfo.suffix()); + + const auto cmd = getAssocString(targetInfo, ASSOCSTR_COMMAND); + if (!cmd) { + return {}; + } + + log::debug("raw cmd is '{}'", *cmd); + + QString formattedCmd = formatCommandLine(targetInfo, *cmd); + if (formattedCmd.isEmpty()) { + log::error( + "command line associated with '{}' is empty", + targetInfo.absoluteFilePath()); + + return {}; + } + + log::debug("formatted cmd is '{}'", formattedCmd); + + const auto p = splitExeAndArguments(formattedCmd); + if (p.first.isEmpty()) { + return {}; + } + + log::debug("split into exe='{}' and cmd='{}'", p.first, p.second); + + return {p.first, *cmd, p.second}; +} + + // returns the filename of the given process or the current one // std::wstring processFilename(HANDLE process=INVALID_HANDLE_VALUE) diff --git a/src/env.h b/src/env.h index dc0fd864..16f8039e 100644 --- a/src/env.h +++ b/src/env.h @@ -246,6 +246,26 @@ Service getService(const QString& name); QString toString(Service::StartType st); QString toString(Service::Status st); + +struct Association +{ + // path to the executable associated with the file + QFileInfo executable; + + // full command line associated with the file, no replacements + QString commandLine; + + // command line _without_ the executable and with placeholders such as %1 + // replaced by the given file + QString formattedCommandLine; +}; + +// returns the associated executable and command line, executable is empty on +// error +// +Association getAssociation(const QFileInfo& file); + + enum class CoreDumpTypes { Mini = 1, diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index c7e071ad..f5ca1de7 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -61,10 +61,27 @@ bool canPreviewFile( return pluginContainer.previewGenerator().previewSupported(ext); } -bool canOpenFile(bool isArchive, const QString&) +bool isExecutableFilename(const QString& filename) { - // can open anything as long as it's not in an archive - return !isArchive; + static const std::set exeExtensions = { + "exe", "cmd", "bat" + }; + + const auto ext = QFileInfo(filename).suffix().toLower(); + + return exeExtensions.contains(ext); +} + +bool canRunFile(bool isArchive, const QString& filename) +{ + // can run executables that are not archives + return !isArchive && isExecutableFilename(filename); +} + +bool canOpenFile(bool isArchive, const QString& filename) +{ + // can open non-executables that are not archives + return !isArchive && !isExecutableFilename(filename); } bool canExploreFile(bool isArchive, const QString&) diff --git a/src/modinfodialogconflicts.cpp b/src/modinfodialogconflicts.cpp index d37f068c..58e935f2 100644 --- a/src/modinfodialogconflicts.cpp +++ b/src/modinfodialogconflicts.cpp @@ -81,6 +81,11 @@ public: return canUnhideFile(isArchive(), fileName()); } + bool canRun() const + { + return canRunFile(isArchive(), fileName()); + } + bool canOpen() const { return canOpenFile(isArchive(), fileName()); @@ -536,6 +541,20 @@ void ConflictsTab::openItems(QTreeView* tree) }); } +void ConflictsTab::runItemsHooked(QTreeView* tree) +{ + // the menu item is only shown for a single selection, but handle all of them + // in case this changes + for_each_in_selection(tree, [&](const ConflictItem* item) { + core().processRunner() + .setFromFile(parentWidget(), item->fileName(), true) + .setWaitForCompletion() + .run(); + + return true; + }); +} + void ConflictsTab::previewItems(QTreeView* tree) { // the menu item is only shown for a single selection, but handle all of them @@ -571,6 +590,15 @@ void ConflictsTab::showContextMenu(const QPoint &pos, QTreeView* tree) menu.addAction(actions.open); } + // run hooked + if (actions.runHooked) { + connect(actions.runHooked, &QAction::triggered, [&]{ + runItemsHooked(tree); + }); + + menu.addAction(actions.runHooked); + } + // preview if (actions.preview) { connect(actions.preview, &QAction::triggered, [&]{ @@ -633,6 +661,7 @@ ConflictsTab::Actions ConflictsTab::createMenuActions(QTreeView* tree) bool enableHide = true; bool enableUnhide = true; + bool enableRun = true; bool enableOpen = true; bool enablePreview = true; bool enableExplore = true; @@ -657,6 +686,7 @@ ConflictsTab::Actions ConflictsTab::createMenuActions(QTreeView* tree) enableHide = item->canHide(); enableUnhide = item->canUnhide(); + enableRun = item->canRun(); enableOpen = item->canOpen(); enablePreview = item->canPreview(plugin()); enableExplore = item->canExplore(); @@ -665,6 +695,7 @@ ConflictsTab::Actions ConflictsTab::createMenuActions(QTreeView* tree) else { // this is a multiple selection, don't show open/preview so users don't open // a thousand files + enableRun = false; enableOpen = false; enablePreview = false; @@ -709,8 +740,12 @@ ConflictsTab::Actions ConflictsTab::createMenuActions(QTreeView* tree) actions.unhide = new QAction(tr("&Unhide"), parentWidget()); actions.unhide->setEnabled(enableUnhide); - actions.open = new QAction(tr("&Open/Execute"), parentWidget()); - actions.open->setEnabled(enableOpen); + if (enableRun) { + actions.open = new QAction(tr("&Execute"), parentWidget()); + } else if (enableOpen) { + actions.open = new QAction(tr("&Open"), parentWidget()); + actions.runHooked = new QAction(tr("Open with &VFS"), parentWidget()); + } actions.preview = new QAction(tr("&Preview"), parentWidget()); actions.preview->setEnabled(enablePreview); diff --git a/src/modinfodialogconflicts.h b/src/modinfodialogconflicts.h index ad305dfc..ebf82033 100644 --- a/src/modinfodialogconflicts.h +++ b/src/modinfodialogconflicts.h @@ -112,6 +112,7 @@ public: bool canHandleUnmanaged() const override; void openItems(QTreeView* tree); + void runItemsHooked(QTreeView* tree); void previewItems(QTreeView* tree); void exploreItems(QTreeView* tree); @@ -125,6 +126,7 @@ private: QAction* hide = nullptr; QAction* unhide = nullptr; QAction* open = nullptr; + QAction* runHooked = nullptr; QAction* preview = nullptr; QAction* explore = nullptr; QMenu* gotoMenu = nullptr; diff --git a/src/modinfodialogfwd.h b/src/modinfodialogfwd.h index 9ede766f..2147fc04 100644 --- a/src/modinfodialogfwd.h +++ b/src/modinfodialogfwd.h @@ -23,6 +23,7 @@ enum class ModInfoTabIDs class PluginContainer; bool canPreviewFile(PluginContainer& pluginContainer, bool isArchive, const QString& filename); +bool canRunFile(bool isArchive, const QString& filename); bool canOpenFile(bool isArchive, const QString& filename); bool canExploreFile(bool isArchive, const QString& filename); bool canHideFile(bool isArchive, const QString& filename); diff --git a/src/processrunner.cpp b/src/processrunner.cpp index b6167706..46065d69 100644 --- a/src/processrunner.cpp +++ b/src/processrunner.cpp @@ -3,6 +3,8 @@ #include "instancemanager.h" #include "iuserinterface.h" #include "envmodule.h" +#include "env.h" +#include #include using namespace MOBase; @@ -473,13 +475,14 @@ ProcessRunner& ProcessRunner::setWaitForCompletion( return *this; } -ProcessRunner& ProcessRunner::setFromFile(QWidget* parent, const QFileInfo& targetInfo) +ProcessRunner& ProcessRunner::setFromFile( + QWidget* parent, const QFileInfo& targetInfo, bool forceHook) { if (!parent && m_ui) { parent = m_ui->qtWidget(); } - // if the file is a .exe, start it directory; if it's anything else, ask the + // if the file is a .exe, start it directly; if it's anything else, ask the // shell to start it const auto fec = spawn::getFileExecutionContext(parent, targetInfo); @@ -497,6 +500,19 @@ ProcessRunner& ProcessRunner::setFromFile(QWidget* parent, const QFileInfo& targ case spawn::FileExecutionTypes::Other: // fall-through default: { + if (forceHook) { + auto assoc = env::getAssociation(targetInfo); + if (!assoc.executable.filePath().isEmpty()) { + setBinary(assoc.executable); + setArguments(assoc.formattedCommandLine); + setCurrentDirectory(assoc.executable.absoluteDir()); + + return *this; + } + + // if it fails, just use the regular shell open + } + m_shellOpen = targetInfo.absoluteFilePath(); // picked up by postRun() diff --git a/src/processrunner.h b/src/processrunner.h index a5099136..d576216a 100644 --- a/src/processrunner.h +++ b/src/processrunner.h @@ -68,10 +68,14 @@ public: ProcessRunner& setWaitForCompletion( WaitFlags flags=NoFlags, UILocker::Reasons reason=UILocker::LockUI); - // if the target is an executable file, runs that; for anything else, calls - // ShellExecute() on it - // - ProcessRunner& setFromFile(QWidget* parent, const QFileInfo& targetInfo); + // - if the target is an executable file, runs it hooked + // - if the target is a file: + // - if forceHook is false, calls ShellExecute() on it + // - if forceHook is true, gets the executable associated with the file + // and runs that hooked by passing the file as an argument + // + ProcessRunner& setFromFile( + QWidget* parent, const QFileInfo& targetInfo, bool forceHook = false); ProcessRunner& setFromExecutable(const Executable& exe); ProcessRunner& setFromShortcut(const MOShortcut& shortcut); -- cgit v1.3.1