From 6410929e17d642618f284d5c97d457f1ac653e6e Mon Sep 17 00:00:00 2001 From: SulfurNitride Date: Sat, 14 Feb 2026 15:40:33 -0600 Subject: Migrate data paths to ~/.local/share/fluorine/, add native build, fix %command% and system Proton scanning - All data paths migrated from ~/.var/app/com.fluorine.manager/ to ~/.local/share/fluorine/ so native and Flatpak builds share the same instances, plugins, and configs - New fluorinepaths.h/.cpp with fluorineDataDir() helper and one-time migration from old path (writes MOVED.txt breadcrumb) - New libs/nak/src/paths.rs as Rust equivalent (data_dir()) - Strip %command% tokens from launch wrapper in protonlauncher.cpp - Always scan /usr/share/steam/compatibilitytools.d/ for system Proton packages (Arch installs Proton there); add Flatpak filesystem permission - Native build (build-native.sh) installs to ~/.local/share/fluorine/ with desktop entry and ~/.local/bin symlink instead of portable zip - build-flatpak.sh wrapper for Flatpak builds - Fix container locale (LANG=C.UTF-8) for AutoUic warnings - Fix prefixExists() to handle both compatdata and pfx directory layouts - Fix globalInstancesRootPath() to use fluorineDataDir() on Linux - Fix umu-run Flatpak lookup to use fluorineDataDir() - Update README with build instructions and Arch dependency list Co-Authored-By: Claude Opus 4.6 --- src/src/CMakeLists.txt | 2 + src/src/bbcode.cpp | 2 +- src/src/categoriesdialog.cpp | 56 ++++++++-------- src/src/commandline.cpp | 17 +++-- src/src/copyeventfilter.cpp | 2 +- src/src/createinstancedialog.cpp | 54 +++++++++++++++- src/src/createinstancedialog.h | 39 +----------- src/src/datatab.cpp | 2 +- src/src/downloadlistview.cpp | 46 +++++++------- src/src/downloadmanager.cpp | 117 +++++++++++++++++++++------------- src/src/envmodule.cpp | 2 +- src/src/fluorineconfig.cpp | 5 +- src/src/fluorinepaths.cpp | 91 ++++++++++++++++++++++++++ src/src/fluorinepaths.h | 15 +++++ src/src/icondelegate.cpp | 2 +- src/src/instancemanager.cpp | 7 ++ src/src/instancemanagerdialog.cpp | 52 +++++++++------ src/src/loglist.cpp | 16 ++--- src/src/main.cpp | 3 + src/src/mainwindow.cpp | 23 +++---- src/src/modinfo.cpp | 3 +- src/src/modinforegular.cpp | 87 ++++++++++++------------- src/src/modlist.cpp | 120 +++++++++++++++++------------------ src/src/modlistcontextmenu.cpp | 130 +++++++++++++++++++------------------- src/src/modlistsortproxy.cpp | 74 ++++++++++++---------- src/src/modlistsortproxy.h | 5 +- src/src/modlistview.cpp | 60 +++++++++--------- src/src/modlistviewactions.cpp | 16 ++--- src/src/nxmaccessmanager.cpp | 8 +-- src/src/organizercore.cpp | 4 +- src/src/plugincontainer.cpp | 19 ++++-- src/src/pluginlist.cpp | 7 +- src/src/pluginlistcontextmenu.cpp | 22 +++---- src/src/pluginlistsortproxy.cpp | 36 +++++++---- src/src/pluginlistsortproxy.h | 5 +- src/src/pluginlistview.cpp | 16 ++--- src/src/profile.cpp | 8 +-- src/src/protonlauncher.cpp | 8 ++- src/src/qtgroupingproxy.cpp | 6 +- src/src/selfupdater.cpp | 11 ++-- src/src/settings.cpp | 2 +- src/src/settingsdialog.ui | 4 +- src/src/settingsdialogmodlist.cpp | 4 +- src/src/settingsdialogproton.cpp | 7 +- src/src/spawn.cpp | 4 +- src/src/texteditor.cpp | 18 +++--- src/src/uilocker.cpp | 4 +- 47 files changed, 728 insertions(+), 513 deletions(-) create mode 100644 src/src/fluorinepaths.cpp create mode 100644 src/src/fluorinepaths.h (limited to 'src') diff --git a/src/src/CMakeLists.txt b/src/src/CMakeLists.txt index 2b3d9cc..664b236 100644 --- a/src/src/CMakeLists.txt +++ b/src/src/CMakeLists.txt @@ -31,11 +31,13 @@ file(GLOB ORGANIZER_QRC # Keep explicitly listed sources tracked by CMake even when using GLOB. list(APPEND ORGANIZER_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/fluorineconfig.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/fluorinepaths.cpp ${CMAKE_CURRENT_SOURCE_DIR}/protonlauncher.cpp ${CMAKE_CURRENT_SOURCE_DIR}/settingsdialogproton.cpp ${CMAKE_CURRENT_SOURCE_DIR}/wineprefix.cpp) list(APPEND ORGANIZER_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/fluorineconfig.h + ${CMAKE_CURRENT_SOURCE_DIR}/fluorinepaths.h ${CMAKE_CURRENT_SOURCE_DIR}/protonlauncher.h ${CMAKE_CURRENT_SOURCE_DIR}/settingsdialogproton.h ${CMAKE_CURRENT_SOURCE_DIR}/wineprefix.h) diff --git a/src/src/bbcode.cpp b/src/src/bbcode.cpp index 4d8148e..5567fb0 100644 --- a/src/src/bbcode.cpp +++ b/src/src/bbcode.cpp @@ -43,7 +43,7 @@ public: { // extract the tag name auto match = m_TagNameExp.match(input, 1, QRegularExpression::NormalMatch, - QRegularExpression::AnchoredMatchOption); + QRegularExpression::AnchorAtOffsetMatchOption); QString tagName = match.captured(0).toLower(); TagMap::iterator tagIter = m_TagMap.find(tagName); if (tagIter != m_TagMap.end()) { diff --git a/src/src/categoriesdialog.cpp b/src/src/categoriesdialog.cpp index 09b89ba..d575e17 100644 --- a/src/src/categoriesdialog.cpp +++ b/src/src/categoriesdialog.cpp @@ -29,6 +29,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include class NewIDValidator : public QIntValidator { @@ -223,25 +224,25 @@ void CategoriesDialog::fillTable() ++row; table->insertRow(row); - QScopedPointer idItem(new QTableWidgetItem()); + auto idItem = std::make_unique(); idItem->setData(Qt::DisplayRole, category.ID()); - QScopedPointer nameItem(new QTableWidgetItem(category.name())); - QScopedPointer parentIDItem(new QTableWidgetItem()); + auto nameItem = std::make_unique(category.name()); + auto parentIDItem = std::make_unique(); parentIDItem->setData(Qt::DisplayRole, category.parentID()); - QScopedPointer nexusCatItem(new QTableWidgetItem()); + auto nexusCatItem = std::make_unique(); - table->setItem(row, 0, idItem.take()); - table->setItem(row, 1, nameItem.take()); - table->setItem(row, 2, parentIDItem.take()); - table->setItem(row, 3, nexusCatItem.take()); + table->setItem(row, 0, idItem.release()); + table->setItem(row, 1, nameItem.release()); + table->setItem(row, 2, parentIDItem.release()); + table->setItem(row, 3, nexusCatItem.release()); } for (const auto& nexusCat : categories.m_NexusMap) { - QScopedPointer nexusItem(new QListWidgetItem()); + auto nexusItem = std::make_unique(); nexusItem->setData(Qt::DisplayRole, nexusCat.second.name()); nexusItem->setData(Qt::UserRole, nexusCat.second.ID()); - list->addItem(nexusItem.take()); + list->addItem(nexusItem.release()); auto item = table->item(categories.resolveNexusID(nexusCat.first) - 1, 3); if (item != nullptr) { auto itemData = item->data(Qt::UserRole).toList(); @@ -268,14 +269,14 @@ void CategoriesDialog::addCategory_clicked() ui->categoriesTable->setSortingEnabled(false); ui->categoriesTable->insertRow(row); - QScopedPointer idItem(new QTableWidgetItem()); + auto idItem = std::make_unique(); idItem->setData(Qt::DisplayRole, ++m_HighestID); - QScopedPointer parentIDItem(new QTableWidgetItem()); + auto parentIDItem = std::make_unique(); parentIDItem->setData(Qt::DisplayRole, 0); - ui->categoriesTable->setItem(row, 0, idItem.take()); + ui->categoriesTable->setItem(row, 0, idItem.release()); ui->categoriesTable->setItem(row, 1, new QTableWidgetItem("new")); - ui->categoriesTable->setItem(row, 2, parentIDItem.take()); + ui->categoriesTable->setItem(row, 2, parentIDItem.release()); ui->categoriesTable->setItem(row, 3, new QTableWidgetItem("")); ui->categoriesTable->setSortingEnabled(true); } @@ -322,35 +323,34 @@ void CategoriesDialog::nexusImport_clicked() data.append(QVariant(name)); data.append(QVariant(nexusID)); nexusData.insert(nexusData.size(), data); - QScopedPointer nexusCatItem( - new QTableWidgetItem(nexusLabel.join(", "))); + auto nexusCatItem = std::make_unique(nexusLabel.join(", ")); nexusCatItem->setData(Qt::UserRole, nexusData); if (!table->findItems(name, Qt::MatchExactly).size()) { row = table->rowCount(); table->insertRow(table->rowCount()); - QScopedPointer idItem(new QTableWidgetItem()); + auto idItem = std::make_unique(); idItem->setData(Qt::DisplayRole, ++m_HighestID); - QScopedPointer nameItem(new QTableWidgetItem(name)); - QScopedPointer parentIDItem(new QTableWidgetItem()); + auto nameItem = std::make_unique(name); + auto parentIDItem = std::make_unique(); parentIDItem->setData(Qt::DisplayRole, 0); // No parent - table->setItem(row, 0, idItem.take()); - table->setItem(row, 1, nameItem.take()); - table->setItem(row, 2, parentIDItem.take()); + table->setItem(row, 0, idItem.release()); + table->setItem(row, 1, nameItem.release()); + table->setItem(row, 2, parentIDItem.release()); if (importDialog.assign()) { - table->setItem(row, 3, nexusCatItem.take()); + table->setItem(row, 3, nexusCatItem.release()); } } else { for (auto item : table->findItems(name, Qt::MatchContains | Qt::MatchWrap)) { if (item->column() == 1 && item->text() == name && importDialog.remap()) { - table->setItem(item->row(), 3, nexusCatItem.take()); + table->setItem(item->row(), 3, nexusCatItem.release()); } else if (importDialog.remap()) { - QScopedPointer blankItem(new QTableWidgetItem()); + auto blankItem = std::make_unique(); blankItem->setData(Qt::UserRole, QVariantList()); - table->setItem(item->row(), 3, blankItem.get()); + table->setItem(item->row(), 3, blankItem.release()); } } } @@ -370,10 +370,10 @@ void CategoriesDialog::nxmGameInfoAvailable(QString gameName, QVariant, list->clear(); for (const auto& category : categories) { auto catMap = category.toMap(); - QScopedPointer nexusItem(new QListWidgetItem()); + auto nexusItem = std::make_unique(); nexusItem->setData(Qt::DisplayRole, catMap["name"].toString()); nexusItem->setData(Qt::UserRole, catMap["category_id"].toInt()); - list->addItem(nexusItem.take()); + list->addItem(nexusItem.release()); } } diff --git a/src/src/commandline.cpp b/src/src/commandline.cpp index 1582923..9c1fa85 100644 --- a/src/src/commandline.cpp +++ b/src/src/commandline.cpp @@ -984,13 +984,16 @@ std::optional CreatePortableCommand::runEarly() } } - // Create empty profile files - const QStringList profileFiles = {"modlist.txt", "plugins.txt", "loadorder.txt", "initweaks.ini"}; - for (const auto& f : profileFiles) { - QFile file(QDir(instanceDir).filePath("profiles/Default/" + f)); - file.open(QIODevice::WriteOnly); - file.close(); - } + // Create empty profile files + const QStringList profileFiles = {"modlist.txt", "plugins.txt", "loadorder.txt", "initweaks.ini"}; + for (const auto& f : profileFiles) { + QFile file(QDir(instanceDir).filePath("profiles/Default/" + f)); + if (!file.open(QIODevice::WriteOnly)) { + std::cerr << "Error: failed to create file: " << f.toStdString() << "\n"; + return 1; + } + file.close(); + } // Generate ModOrganizer.ini { diff --git a/src/src/copyeventfilter.cpp b/src/src/copyeventfilter.cpp index 901e797..a5fc5f9 100644 --- a/src/src/copyeventfilter.cpp +++ b/src/src/copyeventfilter.cpp @@ -24,7 +24,7 @@ void CopyEventFilter::copySelection() const // sort to reflect the visual order QModelIndexList selectedRows = m_view->selectionModel()->selectedRows(); std::sort(selectedRows.begin(), selectedRows.end(), - [=](const auto& lidx, const auto& ridx) { + [=, this](const auto& lidx, const auto& ridx) { return m_view->visualRect(lidx).top() < m_view->visualRect(ridx).top(); }); diff --git a/src/src/createinstancedialog.cpp b/src/src/createinstancedialog.cpp index 10bcce5..89506e6 100644 --- a/src/src/createinstancedialog.cpp +++ b/src/src/createinstancedialog.cpp @@ -7,6 +7,7 @@ #include "ui_createinstancedialog.h" #include #include +#include using namespace MOBase; @@ -133,13 +134,13 @@ CreateInstanceDialog::CreateInstanceDialog(const PluginContainer& pc, Settings* addShortcutAction(QKeySequence::Find, Actions::Find); - addShortcut(Qt::ALT + Qt::Key_Left, [&] { + addShortcut(Qt::ALT | Qt::Key_Left, [&] { back(); }); - addShortcut(Qt::ALT + Qt::Key_Right, [&] { + addShortcut(Qt::ALT | Qt::Key_Right, [&] { next(false); }); - addShortcut(Qt::CTRL + Qt::Key_Return, [&] { + addShortcut(Qt::CTRL | Qt::Key_Return, [&] { next(); }); @@ -494,6 +495,22 @@ bool CreateInstanceDialog::switching() const return m_switching; } +template +auto CreateInstanceDialog::getSelected(MF mf, Args&&... args) const +{ + // return type + using T = decltype((std::declval().*mf)(std::forward(args)...)); + + for (auto&& p : m_pages) { + const auto t = (p.get()->*mf)(std::forward(args)...); + if (t != T()) { + return t; + } + } + + return T(); +} + CreateInstanceDialog::CreationInfo CreateInstanceDialog::rawCreationInfo() const { const auto iniFilename = QString::fromStdWString(AppConfig::iniFileName()); @@ -562,3 +579,34 @@ CreateInstanceDialog::CreationInfo CreateInstanceDialog::creationInfo() const return ci; } + +template +void CreateInstanceDialog::setSinglePage(const QString& instanceName) +{ + for (auto&& p : m_pages) { + if (auto* tp = dynamic_cast(p.get())) { + tp->setSkip(false); + } else { + p->setSkip(true); + } + } + + setSinglePageImpl(instanceName); +} + +template +Page* CreateInstanceDialog::getPage() +{ + for (auto&& p : m_pages) { + if (auto* tp = dynamic_cast(p.get())) { + return tp; + } + } + + return nullptr; +} + +// explicit instantiations for types used by instancemanager.cpp +template void CreateInstanceDialog::setSinglePage(const QString&); +template void CreateInstanceDialog::setSinglePage(const QString&); +template cid::GamePage* CreateInstanceDialog::getPage(); diff --git a/src/src/createinstancedialog.h b/src/src/createinstancedialog.h index d1f5656..bacdcf9 100644 --- a/src/src/createinstancedialog.h +++ b/src/src/createinstancedialog.h @@ -102,32 +102,12 @@ public: // disables all the pages except for the given one, used on startup when some // specific info is missing template - void setSinglePage(const QString& instanceName) - { - for (auto&& p : m_pages) { - if (auto* tp = dynamic_cast(p.get())) { - tp->setSkip(false); - } else { - p->setSkip(true); - } - } - - setSinglePageImpl(instanceName); - } + void setSinglePage(const QString& instanceName); // returns the page having the give path, or null // template - Page* getPage() - { - for (auto&& p : m_pages) { - if (auto* tp = dynamic_cast(p.get())) { - return tp; - } - } - - return nullptr; - } + Page* getPage(); // moves to the next page; if `allowFinish` is true, calls finish() if // currently on the last page @@ -218,20 +198,7 @@ private: // that's not empty; used by gatherInfo() // template - auto getSelected(MF mf, Args&&... args) const - { - // return type - using T = decltype((std::declval().*mf)(std::forward(args)...)); - - for (auto&& p : m_pages) { - const auto t = (p.get()->*mf)(std::forward(args)...); - if (t != T()) { - return t; - } - } - - return T(); - } + auto getSelected(MF mf, Args&&... args) const; }; #endif // MODORGANIZER_CREATEINSTANCEDIALOG_INCLUDED diff --git a/src/src/datatab.cpp b/src/src/datatab.cpp index c36c7c1..ea1430b 100644 --- a/src/src/datatab.cpp +++ b/src/src/datatab.cpp @@ -58,7 +58,7 @@ DataTab::DataTab(OrganizerCore& core, PluginContainer& pc, QWidget* parent, onHiddenFiles(); }); - connect(ui.tree->selectionModel(), &QItemSelectionModel::selectionChanged, [=] { + connect(ui.tree->selectionModel(), &QItemSelectionModel::selectionChanged, [=, this] { const auto* fileTreeModel = m_filetree->model(); const auto& selectedIndexList = MOShared::indexViewToModel( ui.tree->selectionModel()->selectedRows(), fileTreeModel); diff --git a/src/src/downloadlistview.cpp b/src/src/downloadlistview.cpp index 5b9b9e4..8928e6c 100644 --- a/src/src/downloadlistview.cpp +++ b/src/src/downloadlistview.cpp @@ -228,64 +228,64 @@ void DownloadListView::onCustomContextMenu(const QPoint& point) hidden = m_Manager->isHidden(row); if (state >= DownloadManager::STATE_READY) { - menu.addAction(tr("Install"), [=] { + menu.addAction(tr("Install"), [=, this] { issueInstall(row); }); if (m_Manager->isInfoIncomplete(row)) { - menu.addAction(tr("Query Info"), [=] { + menu.addAction(tr("Query Info"), [=, this] { issueQueryInfoMd5(row); }); } else { - menu.addAction(tr("Visit on Nexus"), [=] { + menu.addAction(tr("Visit on Nexus"), [=, this] { issueVisitOnNexus(row); }); - menu.addAction(tr("Visit the uploader's profile"), [=] { + menu.addAction(tr("Visit the uploader's profile"), [=, this] { issueVisitUploaderProfile(row); }); } - menu.addAction(tr("Open File"), [=] { + menu.addAction(tr("Open File"), [=, this] { issueOpenFile(row); }); - menu.addAction(tr("Open Meta File"), [=] { + menu.addAction(tr("Open Meta File"), [=, this] { issueOpenMetaFile(row); }); - menu.addAction(tr("Reveal in Explorer"), [=] { + menu.addAction(tr("Reveal in Explorer"), [=, this] { issueOpenInDownloadsFolder(row); }); menu.addSeparator(); - menu.addAction(tr("Delete..."), [=] { + menu.addAction(tr("Delete..."), [=, this] { issueDelete(row); }); if (hidden) - menu.addAction(tr("Un-Hide"), [=] { + menu.addAction(tr("Un-Hide"), [=, this] { issueRestoreToView(row); }); else - menu.addAction(tr("Hide"), [=] { + menu.addAction(tr("Hide"), [=, this] { issueRemoveFromView(row); }); } else if (state == DownloadManager::STATE_DOWNLOADING) { - menu.addAction(tr("Cancel"), [=] { + menu.addAction(tr("Cancel"), [=, this] { issueCancel(row); }); - menu.addAction(tr("Pause"), [=] { + menu.addAction(tr("Pause"), [=, this] { issuePause(row); }); - menu.addAction(tr("Reveal in Explorer"), [=] { + menu.addAction(tr("Reveal in Explorer"), [=, this] { issueOpenInDownloadsFolder(row); }); } else if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR) || (state == DownloadManager::STATE_PAUSING)) { - menu.addAction(tr("Delete..."), [=] { + menu.addAction(tr("Delete..."), [=, this] { issueDelete(row); }); - menu.addAction(tr("Resume"), [=] { + menu.addAction(tr("Resume"), [=, this] { issueResume(row); }); - menu.addAction(tr("Reveal in Explorer"), [=] { + menu.addAction(tr("Reveal in Explorer"), [=, this] { issueOpenInDownloadsFolder(row); }); } @@ -297,29 +297,29 @@ void DownloadListView::onCustomContextMenu(const QPoint& point) // display download-specific actions } - menu.addAction(tr("Delete Installed Downloads..."), [=] { + menu.addAction(tr("Delete Installed Downloads..."), [=, this] { issueDeleteCompleted(); }); - menu.addAction(tr("Delete Uninstalled Downloads..."), [=] { + menu.addAction(tr("Delete Uninstalled Downloads..."), [=, this] { issueDeleteUninstalled(); }); - menu.addAction(tr("Delete All Downloads..."), [=] { + menu.addAction(tr("Delete All Downloads..."), [=, this] { issueDeleteAll(); }); menu.addSeparator(); if (!hidden) { - menu.addAction(tr("Hide Installed..."), [=] { + menu.addAction(tr("Hide Installed..."), [=, this] { issueRemoveFromViewCompleted(); }); - menu.addAction(tr("Hide Uninstalled..."), [=] { + menu.addAction(tr("Hide Uninstalled..."), [=, this] { issueRemoveFromViewUninstalled(); }); - menu.addAction(tr("Hide All..."), [=] { + menu.addAction(tr("Hide All..."), [=, this] { issueRemoveFromViewAll(); }); } else { - menu.addAction(tr("Un-Hide All..."), [=] { + menu.addAction(tr("Un-Hide All..."), [=, this] { issueRestoreToViewAll(); }); } diff --git a/src/src/downloadmanager.cpp b/src/src/downloadmanager.cpp index 875bcd9..ae3b94e 100644 --- a/src/src/downloadmanager.cpp +++ b/src/src/downloadmanager.cpp @@ -229,12 +229,13 @@ DownloadManager::DownloadManager(NexusInterface* nexusInterface, QObject* parent m_ParentWidget(nullptr) { m_OrganizerCore = dynamic_cast(parent); - connect(&m_DirWatcher, SIGNAL(directoryChanged(QString)), this, - SLOT(directoryChanged(QString))); - m_TimeoutTimer.setSingleShot(false); - // connect(&m_TimeoutTimer, SIGNAL(timeout()), this, SLOT(checkDownloadTimeout())); - m_TimeoutTimer.start(5 * 1000); -} + connect(&m_DirWatcher, SIGNAL(directoryChanged(QString)), this, + SLOT(directoryChanged(QString))); + m_TimeoutTimer.setSingleShot(false); + connect(&m_TimeoutTimer, &QTimer::timeout, this, + &DownloadManager::checkDownloadTimeout); + m_TimeoutTimer.start(5 * 1000); +} DownloadManager::~DownloadManager() { @@ -952,17 +953,19 @@ void DownloadManager::removeDownload(int index, bool deleteFile) refreshList(); } -void DownloadManager::cancelDownload(int index) -{ - if ((index < 0) || (index >= m_ActiveDownloads.size())) { - reportError(tr("cancel: invalid download index %1").arg(index)); - return; - } - - if (m_ActiveDownloads.at(index)->m_State == STATE_DOWNLOADING) { - setState(m_ActiveDownloads.at(index), STATE_CANCELING); - } -} +void DownloadManager::cancelDownload(int index) +{ + if ((index < 0) || (index >= m_ActiveDownloads.size())) { + reportError(tr("cancel: invalid download index %1").arg(index)); + return; + } + + DownloadInfo* info = m_ActiveDownloads.at(index); + if (info->m_State == STATE_DOWNLOADING || info->m_State == STATE_STARTED || + info->m_State == STATE_PAUSING) { + setState(info, STATE_CANCELING); + } +} void DownloadManager::pauseDownload(int index) { @@ -1610,14 +1613,20 @@ void DownloadManager::setState(DownloadManager::DownloadInfo* info, row = i; break; } - } - info->m_State = state; - switch (state) { - case STATE_PAUSED: { - info->m_Reply->abort(); - info->m_Output.close(); - m_DownloadPaused(row); - } break; + } + info->m_State = state; + switch (state) { + case STATE_CANCELING: { + // Force termination so the download transitions through finished(). + if (info->m_Reply != nullptr && info->m_Reply->isRunning()) { + info->m_Reply->abort(); + } + } break; + case STATE_PAUSED: { + info->m_Reply->abort(); + info->m_Output.close(); + m_DownloadPaused(row); + } break; case STATE_ERROR: { info->m_Reply->abort(); info->m_Output.close(); @@ -2411,24 +2420,46 @@ void DownloadManager::managedGameChanged(MOBase::IPluginGame const* managedGame) m_ManagedGame = managedGame; } -void DownloadManager::checkDownloadTimeout() -{ - for (int i = 0; i < m_ActiveDownloads.size(); ++i) { - if (m_ActiveDownloads[i]->m_StartTime.elapsed() - - m_ActiveDownloads[i]->m_DownloadTimeLast > - 5 * 1000 && - m_ActiveDownloads[i]->m_State == STATE_DOWNLOADING && - m_ActiveDownloads[i]->m_Reply != nullptr && - m_ActiveDownloads[i]->m_Reply->isOpen()) { - pauseDownload(i); - downloadFinished(i); - resumeDownload(i); - } - } -} - -void DownloadManager::writeData(DownloadInfo* info) -{ +void DownloadManager::checkDownloadTimeout() +{ + for (int i = 0; i < m_ActiveDownloads.size(); ++i) { + DownloadInfo* info = m_ActiveDownloads[i]; + if (info->m_State != STATE_DOWNLOADING || info->m_Reply == nullptr || + !info->m_Reply->isOpen()) { + continue; + } + + const bool stalled = + (info->m_StartTime.elapsed() - info->m_DownloadTimeLast) > (5 * 1000); + if (!stalled) { + continue; + } + + pauseDownload(i); + downloadFinished(i); + + // downloadFinished() can remove the download entry, so find it again. + const int index = indexByInfo(info); + if (index < 0) { + continue; + } + + if (info->m_Tries <= 0) { + emit showMessage(tr("Download stalled repeatedly and was paused. " + "Please retry manually.")); + continue; + } + + --info->m_Tries; + log::warn("download '{}' stalled, retrying ({} retries left)", info->m_FileName, + info->m_Tries); + resumeDownloadInt(index); + emit update(index); + } +} + +void DownloadManager::writeData(DownloadInfo* info) +{ if (info != nullptr) { qint64 ret = info->m_Output.write(info->m_Reply->readAll()); if (ret < info->m_Reply->size()) { diff --git a/src/src/envmodule.cpp b/src/src/envmodule.cpp index 2c8d5be..fd5651a 100644 --- a/src/src/envmodule.cpp +++ b/src/src/envmodule.cpp @@ -529,7 +529,7 @@ HandlePtr Process::openHandleForWait() const // On Linux, just wrap the pid. The caller can use waitpid() or // kill(pid, 0) to check on the process. if (kill(m_pid, 0) == 0) { - return HandlePtr(HandleCloser::pointer(m_pid)); + return HandlePtr(HandleCloser::pointer(static_cast(m_pid))); } return {}; } diff --git a/src/src/fluorineconfig.cpp b/src/src/fluorineconfig.cpp index 34cc5cd..7ca320e 100644 --- a/src/src/fluorineconfig.cpp +++ b/src/src/fluorineconfig.cpp @@ -98,7 +98,10 @@ bool FluorineConfig::prefixExists() const return false; } - return QDir(QDir(prefix_path).filePath("drive_c")).exists(); + // prefix_path may point to the compatdata dir (containing pfx/) or + // directly to the pfx dir (containing drive_c). + const QDir dir(prefix_path); + return dir.exists("drive_c") || dir.exists("pfx/drive_c"); } QString FluorineConfig::compatDataPath() const diff --git a/src/src/fluorinepaths.cpp b/src/src/fluorinepaths.cpp new file mode 100644 index 0000000..815f5aa --- /dev/null +++ b/src/src/fluorinepaths.cpp @@ -0,0 +1,91 @@ +#include "fluorinepaths.h" +#include "fluorineconfig.h" + +#include +#include +#include + +#include + +static const QString OldRoot = + QDir::homePath() + "/.var/app/com.fluorine.manager"; + +QString fluorineDataDir() +{ + // Use $HOME directly so this resolves the same path in both native + // and Flatpak builds (the Flatpak has --filesystem=home). + return QDir::homePath() + "/.local/share/fluorine"; +} + +void fluorineMigrateDataDir() +{ +#ifdef _WIN32 + return; +#endif + + const QString oldRoot = OldRoot; + const QString newRoot = fluorineDataDir(); + + // Already migrated or old path never existed + if (QFile::exists(oldRoot + "/MOVED.txt")) { + return; + } + if (!QDir(oldRoot).exists()) { + return; + } + + // Check if there is actually data to migrate + const QStringList subdirs = {"logs", "bin", "config", "Prefix"}; + bool hasData = false; + for (const QString& sub : subdirs) { + if (QDir(oldRoot + "/" + sub).exists()) { + hasData = true; + break; + } + } + if (!hasData) { + return; + } + + fprintf(stderr, "[fluorine] Migrating data from %s to %s\n", + qUtf8Printable(oldRoot), qUtf8Printable(newRoot)); + + QDir().mkpath(newRoot); + + for (const QString& sub : subdirs) { + const QString src = oldRoot + "/" + sub; + const QString dst = newRoot + "/" + sub; + if (!QDir(src).exists()) { + continue; + } + if (QDir(dst).exists()) { + fprintf(stderr, "[fluorine] skip %s (destination already exists)\n", + qUtf8Printable(sub)); + continue; + } + if (QDir().rename(src, dst)) { + fprintf(stderr, "[fluorine] moved %s\n", qUtf8Printable(sub)); + } else { + fprintf(stderr, "[fluorine] FAILED to move %s\n", qUtf8Printable(sub)); + } + } + + // Update FluorineConfig's prefix_path if it references the old root + if (auto cfg = FluorineConfig::load()) { + if (cfg->prefix_path.startsWith(oldRoot)) { + cfg->prefix_path.replace(oldRoot, newRoot); + cfg->save(); + fprintf(stderr, "[fluorine] updated config prefix_path\n"); + } + } + + // Write breadcrumb so we don't attempt migration again + QFile marker(oldRoot + "/MOVED.txt"); + if (marker.open(QIODevice::WriteOnly)) { + QTextStream ts(&marker); + ts << "Data migrated to " << newRoot << "\n"; + marker.close(); + } + + fprintf(stderr, "[fluorine] Migration complete.\n"); +} diff --git a/src/src/fluorinepaths.h b/src/src/fluorinepaths.h new file mode 100644 index 0000000..a32f6ec --- /dev/null +++ b/src/src/fluorinepaths.h @@ -0,0 +1,15 @@ +#ifndef FLUORINEPATHS_H +#define FLUORINEPATHS_H + +#include + +/// Returns the shared Fluorine data directory: ~/.local/share/fluorine +/// Uses $HOME directly to bypass Flatpak's XDG_DATA_HOME remapping +/// (the Flatpak has --filesystem=home). +QString fluorineDataDir(); + +/// One-time migration from the old ~/.var/app/com.fluorine.manager/ path +/// to ~/.local/share/fluorine/. Call before initLogging(). +void fluorineMigrateDataDir(); + +#endif // FLUORINEPATHS_H diff --git a/src/src/icondelegate.cpp b/src/src/icondelegate.cpp index b3c23b0..5a26730 100644 --- a/src/src/icondelegate.cpp +++ b/src/src/icondelegate.cpp @@ -33,7 +33,7 @@ IconDelegate::IconDelegate(QTreeView* view, int column, int compactSize) { if (view) { connect(view->header(), &QHeaderView::sectionResized, - [=](int column, int, int size) { + [=, this](int column, int, int size) { if (column == m_column) { m_compact = size < m_compactSize; } diff --git a/src/src/instancemanager.cpp b/src/src/instancemanager.cpp index 1b9eff1..3aa4db5 100644 --- a/src/src/instancemanager.cpp +++ b/src/src/instancemanager.cpp @@ -21,6 +21,7 @@ along with Mod Organizer. If not, see . #include "createinstancedialog.h" #include "createinstancedialogpages.h" #include "filesystemutilities.h" +#include "fluorinepaths.h" #include "instancemanagerdialog.h" #include "nexusinterface.h" #include "plugincontainer.h" @@ -625,8 +626,14 @@ QString InstanceManager::instancePath(const QString& instanceName) const QString InstanceManager::globalInstancesRootPath() const { +#ifndef _WIN32 + // Use the shared Fluorine data dir so the path is the same in native and + // Flatpak builds (QStandardPaths is remapped inside a Flatpak sandbox). + return QDir::fromNativeSeparators(fluorineDataDir()); +#else return QDir::fromNativeSeparators( QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)); +#endif } QString InstanceManager::iniPath(const QString& instanceDir) const diff --git a/src/src/instancemanagerdialog.cpp b/src/src/instancemanagerdialog.cpp index 24ce3bd..d9a4a74 100644 --- a/src/src/instancemanagerdialog.cpp +++ b/src/src/instancemanagerdialog.cpp @@ -690,27 +690,37 @@ void InstanceManagerDialog::createNew() select(dlg.creationInfo().instanceName); } -std::size_t InstanceManagerDialog::singleSelectionIndex() const -{ - const auto sel = - m_filter.mapSelectionToSource(ui->list->selectionModel()->selection()); - - if (sel.size() != 1) { - return NoSelection; - } - - return static_cast(sel.indexes()[0].row()); -} - -const Instance* InstanceManagerDialog::singleSelection() const -{ - const auto i = singleSelectionIndex(); - if (i == NoSelection) { - return nullptr; - } - - return m_instances[i].get(); -} +std::size_t InstanceManagerDialog::singleSelectionIndex() const +{ + const auto sel = + m_filter.mapSelectionToSource(ui->list->selectionModel()->selection()); + + if (sel.size() != 1) { + return NoSelection; + } + + const auto indexes = sel.indexes(); + if (indexes.size() != 1 || !indexes[0].isValid()) { + return NoSelection; + } + + const int row = indexes[0].row(); + if (row < 0 || static_cast(row) >= m_instances.size()) { + return NoSelection; + } + + return static_cast(row); +} + +const Instance* InstanceManagerDialog::singleSelection() const +{ + const auto i = singleSelectionIndex(); + if (i == NoSelection || i >= m_instances.size()) { + return nullptr; + } + + return m_instances[i].get(); +} void InstanceManagerDialog::fillData(const Instance& ii) { diff --git a/src/src/loglist.cpp b/src/src/loglist.cpp index 55ace68..15299f5 100644 --- a/src/src/loglist.cpp +++ b/src/src/loglist.cpp @@ -20,6 +20,7 @@ along with Mod Organizer. If not, see . #include "loglist.h" #include "copyeventfilter.h" #include "env.h" +#include "fluorinepaths.h" #include "organizercore.h" #include @@ -28,15 +29,6 @@ using namespace MOBase; static LogModel* g_instance = nullptr; const std::size_t MaxLines = 1000; -static QString fluorineLogDir() -{ -#ifndef _WIN32 - return QDir::homePath() + "/.var/app/com.fluorine.manager/logs"; -#else - return {}; -#endif -} - static std::unique_ptr m_console; static bool m_stdout = false; static std::mutex m_stdoutMutex; @@ -249,7 +241,7 @@ void LogList::clear() void LogList::openLogsFolder() { #ifndef _WIN32 - const QString logsPath = fluorineLogDir(); + const QString logsPath = fluorineDataDir() + "/logs"; #else const QString logsPath = qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath()); @@ -414,8 +406,8 @@ bool createAndMakeWritable(const std::wstring& subPath) bool setLogDirectory(const QString& dir) { #ifndef _WIN32 - // On Linux, all logs go to ~/.var/app/com.fluorine.manager/logs/ - const QString logDir = fluorineLogDir(); + // On Linux, all logs go to ~/.local/share/fluorine/logs/ + const QString logDir = fluorineDataDir() + "/logs"; QDir().mkpath(logDir); const auto logFile = logDir + "/" + QString::fromStdWString(AppConfig::logFileName()); diff --git a/src/src/main.cpp b/src/src/main.cpp index b82b1b8..b12ac7e 100644 --- a/src/src/main.cpp +++ b/src/src/main.cpp @@ -1,5 +1,6 @@ #include "commandline.h" #include "env.h" +#include "fluorinepaths.h" #include "instancemanager.h" #include "loglist.h" #include "moapplication.h" @@ -82,6 +83,8 @@ int run(int argc, char* argv[]) } #endif + fluorineMigrateDataDir(); + initLogging(); // Route NaK (Rust) log messages through MOBase::log diff --git a/src/src/mainwindow.cpp b/src/src/mainwindow.cpp index 8a219a7..008d3b6 100644 --- a/src/src/mainwindow.cpp +++ b/src/src/mainwindow.cpp @@ -145,6 +145,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include #include #include @@ -492,31 +493,31 @@ MainWindow::MainWindow(Settings& settings, OrganizerCore& organizerCore, m_Tutorial.expose("espList", m_OrganizerCore.pluginList()); m_OrganizerCore.setUserInterface(this); - m_OrganizerCore.onFinishedRun([=](const QString, unsigned int) { + m_OrganizerCore.onFinishedRun([=, this](const QString, unsigned int) { if (isHidden()) { m_SystemTrayManager->restoreFromSystemTray(); } }); - connect(m_OrganizerCore.modList(), &ModList::showMessage, [=](auto&& message) { + connect(m_OrganizerCore.modList(), &ModList::showMessage, [=, this](auto&& message) { showMessage(message); }); connect(m_OrganizerCore.modList(), &ModList::modRenamed, - [=](auto&& oldName, auto&& newName) { + [=, this](auto&& oldName, auto&& newName) { modRenamed(oldName, newName); }); - connect(m_OrganizerCore.modList(), &ModList::modUninstalled, [=](auto&& name) { + connect(m_OrganizerCore.modList(), &ModList::modUninstalled, [=, this](auto&& name) { modRemoved(name); }); - connect(m_OrganizerCore.modList(), &ModList::fileMoved, [=](auto&&... args) { + connect(m_OrganizerCore.modList(), &ModList::fileMoved, [=, this](auto&&... args) { fileMoved(args...); }); connect(m_OrganizerCore.installationManager(), &InstallationManager::modReplaced, - [=](auto&& name) { + [=, this](auto&& name) { modRemoved(name); }); connect(m_OrganizerCore.downloadManager(), &DownloadManager::showMessage, - [=](auto&& message) { + [=, this](auto&& message) { showMessage(message); }); for (const QString& fileName : m_PluginContainer.pluginFileNames()) { @@ -555,7 +556,7 @@ void MainWindow::setupModList() { ui->modList->setup(m_OrganizerCore, m_CategoryFactory, this, ui); - connect(&ui->modList->actions(), &ModListViewActions::overwriteCleared, [=]() { + connect(&ui->modList->actions(), &ModListViewActions::overwriteCleared, [=, this]() { scheduleCheckForProblems(); }); connect(&ui->modList->actions(), &ModListViewActions::originModified, this, @@ -2711,7 +2712,7 @@ QMenu* MainWindow::openFolderMenu() FolderMenu->addAction(tr("Open MO2 Plugins folder"), this, SLOT(openPluginsFolder())); FolderMenu->addAction(tr("Open MO2 Stylesheets folder"), this, SLOT(openStylesheetsFolder())); - FolderMenu->addAction(tr("Open MO2 Logs folder"), [=] { + FolderMenu->addAction(tr("Open MO2 Logs folder"), [=, this] { ui->logList->openLogsFolder(); }); @@ -3431,7 +3432,7 @@ void MainWindow::nxmModInfoAvailable(QString gameName, int modID, QVariant userD mod->setLastNexusQuery(QDateTime::currentDateTimeUtc()); mod->setNexusLastModified( - QDateTime::fromSecsSinceEpoch(result["updated_timestamp"].toInt(), Qt::UTC)); + QDateTime::fromSecsSinceEpoch(result["updated_timestamp"].toInt(), QTimeZone::UTC)); m_OrganizerCore.modList()->notifyChange(ModInfo::getIndex(mod->name())); } @@ -3703,7 +3704,7 @@ void MainWindow::extractBSATriggered(QTreeWidgetItem* item) void MainWindow::on_bsaList_customContextMenuRequested(const QPoint& pos) { QMenu menu; - menu.addAction(tr("Extract..."), [=, item = ui->bsaList->itemAt(pos)]() { + menu.addAction(tr("Extract..."), [=, this, item = ui->bsaList->itemAt(pos)]() { extractBSATriggered(item); }); diff --git a/src/src/modinfo.cpp b/src/src/modinfo.cpp index f12ceda..d10abfd 100644 --- a/src/src/modinfo.cpp +++ b/src/src/modinfo.cpp @@ -44,6 +44,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include using namespace MOBase; using namespace MOShared; @@ -412,7 +413,7 @@ std::set> ModInfo::filteredMods(QString gameName, info->gameName().compare(gameName, Qt::CaseInsensitive) == 0) if (info->getLastNexusUpdate().addSecs(-3600) < QDateTime::fromSecsSinceEpoch( - update["latest_file_update"].toInt(), Qt::UTC)) + update["latest_file_update"].toInt(), QTimeZone::UTC)) return true; return false; }); diff --git a/src/src/modinforegular.cpp b/src/src/modinforegular.cpp index 808b572..562f3e5 100644 --- a/src/src/modinforegular.cpp +++ b/src/src/modinforegular.cpp @@ -5,55 +5,56 @@ #include "moddatacontent.h" #include "organizercore.h" #include "plugincontainer.h" -#include "report.h" -#include "settings.h" -#include -#include +#include "report.h" +#include "settings.h" +#include +#include #include #include #include +#include #include using namespace MOBase; using namespace MOShared; -namespace -{ -// Arguably this should be a class static or we should be using FileString rather -// than QString for the names. Or both. -static bool ByName(const ModInfo::Ptr& LHS, const ModInfo::Ptr& RHS) -{ - return QString::compare(LHS->name(), RHS->name(), Qt::CaseInsensitive) < 0; -} - -QString loadMetaPath(const QString& value) -{ - if (value.isEmpty()) { - return value; - } - - if (MOBase::isWindowsDrivePath(value) || QDir::isAbsolutePath(value)) { - return MOBase::normalizePathForHost(value); - } - - return QDir::fromNativeSeparators(value); -} - -QString storeMetaPath(const QString& value) -{ - if (value.isEmpty()) { - return value; - } - - if (MOBase::isWindowsDrivePath(value) || QDir::isAbsolutePath(value)) { - return MOBase::normalizePathForWine(value); - } - - return QDir::fromNativeSeparators(value); -} -} // namespace +namespace +{ +// Arguably this should be a class static or we should be using FileString rather +// than QString for the names. Or both. +static bool ByName(const ModInfo::Ptr& LHS, const ModInfo::Ptr& RHS) +{ + return QString::compare(LHS->name(), RHS->name(), Qt::CaseInsensitive) < 0; +} + +QString loadMetaPath(const QString& value) +{ + if (value.isEmpty()) { + return value; + } + + if (MOBase::isWindowsDrivePath(value) || QDir::isAbsolutePath(value)) { + return MOBase::normalizePathForHost(value); + } + + return QDir::fromNativeSeparators(value); +} + +QString storeMetaPath(const QString& value) +{ + if (value.isEmpty()) { + return value; + } + + if (MOBase::isWindowsDrivePath(value) || QDir::isAbsolutePath(value)) { + return MOBase::normalizePathForWine(value); + } + + return QDir::fromNativeSeparators(value); +} +} // namespace ModInfoRegular::ModInfoRegular(const QDir& path, OrganizerCore& core) : ModInfoWithConflictInfo(core), m_Name(path.dirName()), @@ -121,8 +122,8 @@ void ModInfoRegular::readMeta() m_Version.parse(metaFile.value("version", "").toString()); m_NewestVersion = metaFile.value("newestVersion", "").toString(); m_IgnoredVersion = metaFile.value("ignoredVersion", "").toString(); - m_InstallationFile = - loadMetaPath(metaFile.value("installationFile", "").toString()); + m_InstallationFile = + loadMetaPath(metaFile.value("installationFile", "").toString()); m_NexusDescription = metaFile.value("nexusDescription", "").toString(); m_NexusFileStatus = metaFile.value("nexusFileStatus", "1").toInt(); m_NexusCategory = metaFile.value("nexusCategory", 0).toInt(); @@ -287,7 +288,7 @@ void ModInfoRegular::saveMeta() metaFile.setValue("newestVersion", m_NewestVersion.canonicalString()); metaFile.setValue("ignoredVersion", m_IgnoredVersion.canonicalString()); metaFile.setValue("version", m_Version.canonicalString()); - metaFile.setValue("installationFile", storeMetaPath(m_InstallationFile)); + metaFile.setValue("installationFile", storeMetaPath(m_InstallationFile)); metaFile.setValue("repository", m_Repository); metaFile.setValue("gameName", m_GameName); metaFile.setValue("modid", m_NexusID); @@ -393,7 +394,7 @@ void ModInfoRegular::nxmDescriptionAvailable(QString, int, QVariant, } m_LastNexusQuery = QDateTime::currentDateTimeUtc(); m_NexusLastModified = - QDateTime::fromSecsSinceEpoch(result["updated_timestamp"].toInt(), Qt::UTC); + QDateTime::fromSecsSinceEpoch(result["updated_timestamp"].toInt(), QTimeZone::UTC); m_MetaInfoChanged = true; saveMeta(); disconnect(sender(), SIGNAL(descriptionAvailable(QString, int, QVariant, QVariant))); diff --git a/src/src/modlist.cpp b/src/src/modlist.cpp index 9f695bd..35f4a94 100644 --- a/src/src/modlist.cpp +++ b/src/src/modlist.cpp @@ -659,33 +659,33 @@ QMimeData* ModList::mimeData(const QModelIndexList& indexes) const return result; } -void ModList::changeModPriority(std::vector sourceIndices, int newPriority) -{ - if (m_Profile == nullptr) - return; - - sourceIndices.erase( - std::remove_if(sourceIndices.begin(), sourceIndices.end(), [](int index) { - return index < 0 || static_cast(index) >= ModInfo::getNumMods(); - }), - sourceIndices.end()); - - if (sourceIndices.empty()) { - return; - } - - const bool anyNeedsMove = std::any_of( - sourceIndices.begin(), sourceIndices.end(), - [this, newPriority](int index) { return m_Profile->getModPriority(index) != newPriority; }); - if (!anyNeedsMove) { - return; - } - - emit layoutAboutToBeChanged(); +void ModList::changeModPriority(std::vector sourceIndices, int newPriority) +{ + if (m_Profile == nullptr) + return; + + sourceIndices.erase( + std::remove_if(sourceIndices.begin(), sourceIndices.end(), [](int index) { + return index < 0 || static_cast(index) >= ModInfo::getNumMods(); + }), + sourceIndices.end()); + + if (sourceIndices.empty()) { + return; + } + + const bool anyNeedsMove = std::any_of( + sourceIndices.begin(), sourceIndices.end(), + [this, newPriority](int index) { return m_Profile->getModPriority(index) != newPriority; }); + if (!anyNeedsMove) { + return; + } + + emit layoutAboutToBeChanged(); // sort the moving mods by ascending priorities std::sort(sourceIndices.begin(), sourceIndices.end(), - [=](const int& LHS, const int& RHS) { + [=, this](const int& LHS, const int& RHS) { return m_Profile->getModPriority(LHS) > m_Profile->getModPriority(RHS); }); @@ -701,7 +701,7 @@ void ModList::changeModPriority(std::vector sourceIndices, int newPriority) // sort the moving mods by descending priorities std::sort(sourceIndices.begin(), sourceIndices.end(), - [=](const int& LHS, const int& RHS) { + [=, this](const int& LHS, const int& RHS) { return m_Profile->getModPriority(LHS) < m_Profile->getModPriority(RHS); }); @@ -1147,8 +1147,8 @@ bool ModList::canDropMimeData(const QMimeData* mimeData, Qt::DropAction action, return false; } -bool ModList::dropMimeData(const QMimeData* mimeData, Qt::DropAction action, int row, - int, const QModelIndex& parent) +bool ModList::dropMimeData(const QMimeData* mimeData, Qt::DropAction action, int row, + int, const QModelIndex& parent) { if (action == Qt::IgnoreAction) { return true; @@ -1165,38 +1165,38 @@ bool ModList::dropMimeData(const QMimeData* mimeData, Qt::DropAction action, int return false; } - if (dropInfo.isLocalFileDrop()) { - return dropLocalFiles(dropInfo, row, parent); - } else { - if (dropInfo.isModDrop()) { - std::vector sourceRows = dropInfo.rows(); - sourceRows.erase( - std::remove_if(sourceRows.begin(), sourceRows.end(), [](int index) { - return index < 0 || static_cast(index) >= ModInfo::getNumMods(); - }), - sourceRows.end()); - - if (sourceRows.empty()) { - return true; - } - - changeModPriority(sourceRows, dropPriority); - return true; - } else if (dropInfo.isDownloadDrop()) { - emit downloadArchiveDropped(dropInfo.download(), dropPriority); - return true; - } else if (dropInfo.isExternalArchiveDrop()) { - emit externalArchiveDropped(dropInfo.externalUrl(), dropPriority); - return true; - } else if (dropInfo.isExternalFolderDrop()) { - emit externalFolderDropped(dropInfo.externalUrl(), dropPriority); - return true; - } else { - return false; - } - } - return true; -} + if (dropInfo.isLocalFileDrop()) { + return dropLocalFiles(dropInfo, row, parent); + } else { + if (dropInfo.isModDrop()) { + std::vector sourceRows = dropInfo.rows(); + sourceRows.erase( + std::remove_if(sourceRows.begin(), sourceRows.end(), [](int index) { + return index < 0 || static_cast(index) >= ModInfo::getNumMods(); + }), + sourceRows.end()); + + if (sourceRows.empty()) { + return true; + } + + changeModPriority(sourceRows, dropPriority); + return true; + } else if (dropInfo.isDownloadDrop()) { + emit downloadArchiveDropped(dropInfo.download(), dropPriority); + return true; + } else if (dropInfo.isExternalArchiveDrop()) { + emit externalArchiveDropped(dropInfo.externalUrl(), dropPriority); + return true; + } else if (dropInfo.isExternalFolderDrop()) { + emit externalFolderDropped(dropInfo.externalUrl(), dropPriority); + return true; + } else { + return false; + } + } + return true; +} void ModList::removeRowForce(int row, const QModelIndex& parent) { @@ -1427,7 +1427,7 @@ void ModList::shiftModsPriority(const QModelIndexList& indices, int offset) auto index = idx.data(IndexRole).toInt(); allIndex.push_back(index); } - std::sort(allIndex.begin(), allIndex.end(), [=](int lhs, int rhs) { + std::sort(allIndex.begin(), allIndex.end(), [=, this](int lhs, int rhs) { bool cmp = m_Profile->getModPriority(lhs) < m_Profile->getModPriority(rhs); return offset > 0 ? !cmp : cmp; }); diff --git a/src/src/modlistcontextmenu.cpp b/src/src/modlistcontextmenu.cpp index d32d6cd..7c78b1f 100644 --- a/src/src/modlistcontextmenu.cpp +++ b/src/src/modlistcontextmenu.cpp @@ -7,6 +7,8 @@ #include "modlistviewactions.h" #include "organizercore.h" +#include + using namespace MOBase; ModListGlobalContextMenu::ModListGlobalContextMenu(OrganizerCore& core, @@ -20,7 +22,7 @@ ModListGlobalContextMenu::ModListGlobalContextMenu(OrganizerCore& core, QWidget* parent) : QMenu(parent) { - connect(this, &QMenu::aboutToShow, [=, &core] { + connect(this, &QMenu::aboutToShow, [=, this, &core] { populate(core, view, index); }); } @@ -47,24 +49,24 @@ void ModListGlobalContextMenu::populate(OrganizerCore& core, ModListView* view, createText = tr("Create empty mod below"); } - addAction(installText, [=]() { + addAction(installText, [=, this]() { view->actions().installMod("", index); }); - addAction(createText, [=]() { + addAction(createText, [=, this]() { view->actions().createEmptyMod(index); }); - addAction(tr("Create separator above"), [=]() { + addAction(tr("Create separator above"), [=, this]() { view->actions().createSeparator(index); }); } } else { - addAction(tr("Install mod..."), [=]() { + addAction(tr("Install mod..."), [=, this]() { view->actions().installMod(); }); - addAction(tr("Create empty mod"), [=]() { + addAction(tr("Create empty mod"), [=, this]() { view->actions().createEmptyMod(); }); - addAction(tr("Create separator"), [=]() { + addAction(tr("Create separator"), [=, this]() { view->actions().createSeparator(); }); } @@ -84,21 +86,21 @@ void ModListGlobalContextMenu::populate(OrganizerCore& core, ModListView* view, disableTxt = tr("Disable all matching mods"); } - addAction(enableTxt, [=] { + addAction(enableTxt, [=, this] { view->actions().setAllMatchingModsEnabled(true); }); - addAction(disableTxt, [=] { + addAction(disableTxt, [=, this] { view->actions().setAllMatchingModsEnabled(false); }); - addAction(tr("Check for updates"), [=]() { + addAction(tr("Check for updates"), [=, this]() { view->actions().checkModsForUpdates(); }); - addAction(tr("Auto assign categories"), [=]() { + addAction(tr("Auto assign categories"), [=, this]() { view->actions().assignCategories(); }); addAction(tr("Refresh"), &core, &OrganizerCore::refresh); - addAction(tr("Export to csv..."), [=]() { + addAction(tr("Export to csv..."), [=, this]() { view->actions().exportModListCSV(); }); } @@ -149,7 +151,7 @@ bool ModListChangeCategoryMenu::populate(QMenu* menu, CategoryFactory* factory, } int id = factory->getCategoryID(i); - QScopedPointer checkBox(new QCheckBox(targetMenu)); + auto checkBox = std::make_unique(targetMenu); bool enabled = categories.find(id) != categories.end(); checkBox->setText(factory->getCategoryName(i).replace('&', "&&")); if (enabled) { @@ -157,10 +159,10 @@ bool ModListChangeCategoryMenu::populate(QMenu* menu, CategoryFactory* factory, } checkBox->setChecked(enabled ? Qt::Checked : Qt::Unchecked); - QScopedPointer checkableAction(new QWidgetAction(targetMenu)); - checkableAction->setDefaultWidget(checkBox.take()); + auto checkableAction = std::make_unique(targetMenu); + checkableAction->setDefaultWidget(checkBox.release()); checkableAction->setData(id); - targetMenu->addAction(checkableAction.take()); + targetMenu->addAction(checkableAction.release()); if (factory->hasChildren(i)) { if (populate(targetMenu, factory, mod, factory->getCategoryID(i)) || enabled) { @@ -176,7 +178,7 @@ ModListPrimaryCategoryMenu::ModListPrimaryCategoryMenu(CategoryFactory* categori ModInfo::Ptr mod, QMenu* parent) : QMenu(tr("Primary Category"), parent) { - connect(this, &QMenu::aboutToShow, [=]() { + connect(this, &QMenu::aboutToShow, [=, this]() { populate(categories, mod); }); } @@ -242,7 +244,7 @@ ModListContextMenu::ModListContextMenu(const QModelIndex& index, OrganizerCore& bool expanded = view->isExpanded(viewIndex); addSeparator(); addAction(tr("Collapse all"), view, &QTreeView::collapseAll); - addAction(tr("Collapse others"), [=]() { + addAction(tr("Collapse others"), [=, this]() { m_view->collapseAll(); m_view->setExpanded(viewIndex, expanded); }); @@ -266,7 +268,7 @@ ModListContextMenu::ModListContextMenu(const QModelIndex& index, OrganizerCore& // add information for all except foreign if (!info->isForeign()) { - QAction* infoAction = addAction(tr("Information..."), [=]() { + QAction* infoAction = addAction(tr("Information..."), [=, this]() { view->actions().displayModInformation(m_index.data(ModList::IndexRole).toInt()); }); setDefaultAction(infoAction); @@ -341,14 +343,14 @@ void ModListContextMenu::addCategoryContextMenus(ModInfo::Ptr mod) { ModListChangeCategoryMenu* categoriesMenu = new ModListChangeCategoryMenu(m_categories, mod, this); - connect(categoriesMenu, &QMenu::aboutToHide, [=]() { + connect(categoriesMenu, &QMenu::aboutToHide, [=, this]() { m_actions.setCategories(m_selected, m_index, categoriesMenu->categories()); }); addMenuAsPushButton(categoriesMenu); ModListPrimaryCategoryMenu* primaryCategoryMenu = new ModListPrimaryCategoryMenu(m_categories, mod, this); - connect(primaryCategoryMenu, &QMenu::aboutToHide, [=]() { + connect(primaryCategoryMenu, &QMenu::aboutToHide, [=, this]() { int category = primaryCategoryMenu->primaryCategory(); if (category != -1) { m_actions.setPrimaryCategory(m_selected, category); @@ -360,20 +362,20 @@ void ModListContextMenu::addCategoryContextMenus(ModInfo::Ptr mod) void ModListContextMenu::addOverwriteActions(ModInfo::Ptr mod) { if (QDir(mod->absolutePath()).count() > 2) { - addAction(tr("Sync to Mods..."), [=]() { + addAction(tr("Sync to Mods..."), [=, this]() { m_core.syncOverwrite(); }); - addAction(tr("Create Mod..."), [=]() { + addAction(tr("Create Mod..."), [=, this]() { m_actions.createModFromOverwrite(); }); - addAction(tr("Move content to Mod..."), [=]() { + addAction(tr("Move content to Mod..."), [=, this]() { m_actions.moveOverwriteContentToExistingMod(); }); - addAction(tr("Clear Overwrite..."), [=]() { + addAction(tr("Clear Overwrite..."), [=, this]() { m_actions.clearOverwrite(); }); } - addAction(tr("Open in Explorer"), [=]() { + addAction(tr("Open in Explorer"), [=, this]() { m_actions.openExplorer(m_selected); }); } @@ -383,10 +385,10 @@ void ModListContextMenu::addSeparatorActions(ModInfo::Ptr mod) addCategoryContextMenus(mod); addSeparator(); - addAction(tr("Rename Separator..."), [=]() { + addAction(tr("Rename Separator..."), [=, this]() { m_actions.renameMod(m_index); }); - addAction(tr("Remove Separator..."), [=]() { + addAction(tr("Remove Separator..."), [=, this]() { m_actions.removeMods(m_selected); }); addSeparator(); @@ -395,12 +397,12 @@ void ModListContextMenu::addSeparatorActions(ModInfo::Ptr mod) addSendToContextMenu(); addSeparator(); } - addAction(tr("Select Color..."), [=]() { + addAction(tr("Select Color..."), [=, this]() { m_actions.setColor(m_selected, m_index); }); if (mod->color().isValid()) { - addAction(tr("Reset Color"), [=]() { + addAction(tr("Reset Color"), [=, this]() { m_actions.resetColor(m_selected); }); } @@ -418,45 +420,45 @@ void ModListContextMenu::addForeignActions(ModInfo::Ptr mod) void ModListContextMenu::addBackupActions(ModInfo::Ptr mod) { auto flags = mod->getFlags(); - addAction(tr("Restore Backup"), [=]() { + addAction(tr("Restore Backup"), [=, this]() { m_actions.restoreBackup(m_index); }); - addAction(tr("Remove Backup..."), [=]() { + addAction(tr("Remove Backup..."), [=, this]() { m_actions.removeMods(m_selected); }); addSeparator(); if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_INVALID) != flags.end()) { - addAction(tr("Ignore missing data"), [=]() { + addAction(tr("Ignore missing data"), [=, this]() { m_actions.ignoreMissingData(m_selected); }); } if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_ALTERNATE_GAME) != flags.end()) { - addAction(tr("Mark as converted/working"), [=]() { + addAction(tr("Mark as converted/working"), [=, this]() { m_actions.markConverted(m_selected); }); } addSeparator(); if (mod->nexusId() > 0) { - addAction(tr("Visit on Nexus"), [=]() { + addAction(tr("Visit on Nexus"), [=, this]() { m_actions.visitOnNexus(m_selected); }); } if (!mod->uploaderUrl().isEmpty()) { - addAction(tr("Visit the uploader's profile"), [=]() { + addAction(tr("Visit the uploader's profile"), [=, this]() { m_actions.visitUploaderProfile(m_selected); }); } const auto url = mod->parseCustomURL(); if (url.isValid()) { - addAction(tr("Visit on %1").arg(url.host()), [=]() { + addAction(tr("Visit on %1").arg(url.host()), [=, this]() { m_actions.visitWebPage(m_selected); }); } - addAction(tr("Open in Explorer"), [=]() { + addAction(tr("Open in Explorer"), [=, this]() { m_actions.openExplorer(m_selected); }); } @@ -469,32 +471,32 @@ void ModListContextMenu::addRegularActions(ModInfo::Ptr mod) addSeparator(); if (mod->downgradeAvailable()) { - addAction(tr("Change versioning scheme"), [=]() { + addAction(tr("Change versioning scheme"), [=, this]() { m_actions.changeVersioningScheme(m_index); }); } if (mod->nexusId() > 0) - addAction(tr("Force-check updates"), [=]() { + addAction(tr("Force-check updates"), [=, this]() { m_actions.checkModsForUpdates(m_selected); }); if (mod->updateIgnored()) { - addAction(tr("Un-ignore update"), [=]() { + addAction(tr("Un-ignore update"), [=, this]() { m_actions.setIgnoreUpdate(m_selected, false); }); } else { if (mod->updateAvailable() || mod->downgradeAvailable()) { - addAction(tr("Ignore update"), [=]() { + addAction(tr("Ignore update"), [=, this]() { m_actions.setIgnoreUpdate(m_selected, true); }); } } addSeparator(); - addAction(tr("Enable selected"), [=]() { + addAction(tr("Enable selected"), [=, this]() { m_core.modList()->setActive(m_selected, true); }); - addAction(tr("Disable selected"), [=]() { + addAction(tr("Disable selected"), [=, this]() { m_core.modList()->setActive(m_selected, false); }); @@ -505,22 +507,22 @@ void ModListContextMenu::addRegularActions(ModInfo::Ptr mod) addSeparator(); } - addAction(tr("Rename Mod..."), [=]() { + addAction(tr("Rename Mod..."), [=, this]() { m_actions.renameMod(m_index); }); - addAction(tr("Reinstall Mod"), [=]() { + addAction(tr("Reinstall Mod"), [=, this]() { m_actions.reinstallMod(m_index); }); - addAction(tr("Remove Mod..."), [=]() { + addAction(tr("Remove Mod..."), [=, this]() { m_actions.removeMods(m_selected); }); - addAction(tr("Create Backup"), [=]() { + addAction(tr("Create Backup"), [=, this]() { m_actions.createBackup(m_index); }); if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_HIDDEN_FILES) != flags.end()) { - addAction(tr("Restore hidden files"), [=]() { + addAction(tr("Restore hidden files"), [=, this]() { m_actions.restoreHiddenFiles(m_selected); }); } @@ -528,11 +530,11 @@ void ModListContextMenu::addRegularActions(ModInfo::Ptr mod) addSeparator(); if (m_index.column() == ModList::COL_NOTES) { - addAction(tr("Select Color..."), [=]() { + addAction(tr("Select Color..."), [=, this]() { m_actions.setColor(m_selected, m_index); }); if (mod->color().isValid()) { - addAction(tr("Reset Color"), [=]() { + addAction(tr("Reset Color"), [=, this]() { m_actions.resetColor(m_selected); }); } @@ -542,20 +544,20 @@ void ModListContextMenu::addRegularActions(ModInfo::Ptr mod) if (mod->nexusId() > 0 && Settings::instance().nexus().endorsementIntegration()) { switch (mod->endorsedState()) { case EndorsedState::ENDORSED_TRUE: { - addAction(tr("Un-Endorse"), [=]() { + addAction(tr("Un-Endorse"), [=, this]() { m_actions.setEndorsed(m_selected, false); }); } break; case EndorsedState::ENDORSED_FALSE: { - addAction(tr("Endorse"), [=]() { + addAction(tr("Endorse"), [=, this]() { m_actions.setEndorsed(m_selected, true); }); - addAction(tr("Won't endorse"), [=]() { + addAction(tr("Won't endorse"), [=, this]() { m_actions.willNotEndorsed(m_selected); }); } break; case EndorsedState::ENDORSED_NEVER: { - addAction(tr("Endorse"), [=]() { + addAction(tr("Endorse"), [=, this]() { m_actions.setEndorsed(m_selected, true); }); } break; @@ -570,7 +572,7 @@ void ModListContextMenu::addRegularActions(ModInfo::Ptr mod) if (mod->nexusId() > 0 && (mod->getNexusCategory() > 0 || !mod->installationFile().isEmpty()) && !mod->isSeparator()) { - addAction(tr("Remap Category (From Nexus)"), [=]() { + addAction(tr("Remap Category (From Nexus)"), [=, this]() { m_actions.remapCategory(m_selected); }); } @@ -578,12 +580,12 @@ void ModListContextMenu::addRegularActions(ModInfo::Ptr mod) if (mod->nexusId() > 0 && Settings::instance().nexus().trackedIntegration()) { switch (mod->trackedState()) { case TrackedState::TRACKED_FALSE: { - addAction(tr("Start tracking"), [=]() { + addAction(tr("Start tracking"), [=, this]() { m_actions.setTracked(m_selected, true); }); } break; case TrackedState::TRACKED_TRUE: { - addAction(tr("Stop tracking"), [=]() { + addAction(tr("Stop tracking"), [=, this]() { m_actions.setTracked(m_selected, false); }); } break; @@ -598,14 +600,14 @@ void ModListContextMenu::addRegularActions(ModInfo::Ptr mod) addSeparator(); if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_INVALID) != flags.end()) { - addAction(tr("Ignore missing data"), [=]() { + addAction(tr("Ignore missing data"), [=, this]() { m_actions.ignoreMissingData(m_selected); }); } if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_ALTERNATE_GAME) != flags.end()) { - addAction(tr("Mark as converted/working"), [=]() { + addAction(tr("Mark as converted/working"), [=, this]() { m_actions.markConverted(m_selected); }); } @@ -613,25 +615,25 @@ void ModListContextMenu::addRegularActions(ModInfo::Ptr mod) addSeparator(); if (mod->nexusId() > 0) { - addAction(tr("Visit on Nexus"), [=]() { + addAction(tr("Visit on Nexus"), [=, this]() { m_actions.visitOnNexus(m_selected); }); } if (!mod->uploaderUrl().isEmpty()) { - addAction(tr("Visit the uploader's profile"), [=]() { + addAction(tr("Visit the uploader's profile"), [=, this]() { m_actions.visitUploaderProfile(m_selected); }); } const auto url = mod->parseCustomURL(); if (url.isValid()) { - addAction(tr("Visit on %1").arg(url.host()), [=]() { + addAction(tr("Visit on %1").arg(url.host()), [=, this]() { m_actions.visitWebPage(m_selected); }); } - addAction(tr("Open in Explorer"), [=]() { + addAction(tr("Open in Explorer"), [=, this]() { m_actions.openExplorer(m_selected); }); } diff --git a/src/src/modlistsortproxy.cpp b/src/src/modlistsortproxy.cpp index 4ffeec9..81b9a17 100644 --- a/src/src/modlistsortproxy.cpp +++ b/src/src/modlistsortproxy.cpp @@ -51,26 +51,36 @@ void ModListSortProxy::setProfile(Profile* profile) m_Profile = profile; } -void ModListSortProxy::updateFilterActive() -{ - m_FilterActive = (!m_Criteria.empty() || !m_Filter.isEmpty()); - emit filterActive(m_FilterActive); -} - -void ModListSortProxy::setCriteria(const std::vector& criteria) -{ +void ModListSortProxy::updateFilterActive() +{ + m_FilterActive = (!m_Criteria.empty() || !m_Filter.isEmpty()); + emit filterActive(m_FilterActive); +} + +void ModListSortProxy::refreshFilter() +{ +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + beginFilterChange(); + endFilterChange(QSortFilterProxyModel::Direction::Rows); +#else + invalidateFilter(); +#endif +} + +void ModListSortProxy::setCriteria(const std::vector& criteria) +{ // avoid refreshing the filter unless we are checking all mods for update. const bool changed = (criteria != m_Criteria); const bool isForUpdates = (!criteria.empty() && criteria[0].id == CategoryFactory::UpdateAvailable); - if (changed || isForUpdates) { - m_Criteria = criteria; - updateFilterActive(); - invalidateFilter(); - emit filterInvalidated(); - } -} + if (changed || isForUpdates) { + m_Criteria = criteria; + updateFilterActive(); + refreshFilter(); + emit filterInvalidated(); + } +} unsigned long ModListSortProxy::flagsId(const std::vector& flags) const { @@ -254,13 +264,13 @@ bool ModListSortProxy::lessThan(const QModelIndex& left, const QModelIndex& righ return lt; } -void ModListSortProxy::updateFilter(const QString& filter) -{ - m_Filter = filter; - updateFilterActive(); - invalidateFilter(); - emit filterInvalidated(); -} +void ModListSortProxy::updateFilter(const QString& filter) +{ + m_Filter = filter; + updateFilterActive(); + refreshFilter(); + emit filterInvalidated(); +} bool ModListSortProxy::hasConflictFlag( const std::vector& flags) const @@ -560,14 +570,14 @@ void ModListSortProxy::setColumnVisible(int column, bool visible) void ModListSortProxy::setOptions(ModListSortProxy::FilterMode mode, SeparatorsMode separators) -{ - if (m_FilterMode != mode || separators != m_FilterSeparators) { - m_FilterMode = mode; - m_FilterSeparators = separators; - invalidateFilter(); - emit filterInvalidated(); - } -} +{ + if (m_FilterMode != mode || separators != m_FilterSeparators) { + m_FilterMode = mode; + m_FilterSeparators = separators; + refreshFilter(); + emit filterInvalidated(); + } +} bool ModListSortProxy::filterAcceptsRow(int source_row, const QModelIndex& parent) const { @@ -586,12 +596,12 @@ bool ModListSortProxy::filterAcceptsRow(int source_row, const QModelIndex& paren return false; } - unsigned int index = ULONG_MAX; + unsigned int index = UINT_MAX; { bool ok = false; index = idx.data(ModList::IndexRole).toInt(&ok); if (!ok) { - index = ULONG_MAX; + index = UINT_MAX; } } diff --git a/src/src/modlistsortproxy.h b/src/src/modlistsortproxy.h index 030dc76..b15606d 100644 --- a/src/src/modlistsortproxy.h +++ b/src/src/modlistsortproxy.h @@ -127,8 +127,9 @@ protected: virtual bool lessThan(const QModelIndex& left, const QModelIndex& right) const; virtual bool filterAcceptsRow(int row, const QModelIndex& parent) const; -private: - unsigned long flagsId(const std::vector& flags) const; +private: + void refreshFilter(); + unsigned long flagsId(const std::vector& flags) const; unsigned long conflictFlagsId(const std::vector& flags) const; bool hasConflictFlag(const std::vector& flags) const; void updateFilterActive(); diff --git a/src/src/modlistview.cpp b/src/src/modlistview.cpp index ae69ac4..108baf3 100644 --- a/src/src/modlistview.cpp +++ b/src/src/modlistview.cpp @@ -154,11 +154,11 @@ ModListView::ModListView(QWidget* parent) // time window m_refreshMarkersTimer.setInterval(50); m_refreshMarkersTimer.setSingleShot(true); - connect(&m_refreshMarkersTimer, &QTimer::timeout, [=] { + connect(&m_refreshMarkersTimer, &QTimer::timeout, [=, this] { refreshMarkersAndPlugins(); }); - installEventFilter(new CopyEventFilter(this, [=](auto& index) { + installEventFilter(new CopyEventFilter(this, [=, this](auto& index) { QVariant mIndex = index.data(ModList::IndexRole); QString name = index.data(Qt::DisplayRole).toString(); if (mIndex.isValid() && hasCollapsibleSeparators()) { @@ -430,7 +430,7 @@ void ModListView::scrollToAndSelect(const QModelIndexList& indexes, } selectionModel()->select(selection, QItemSelectionModel::Select | QItemSelectionModel::Rows); - QTimer::singleShot(50, [=] { + QTimer::singleShot(50, [=, this] { setFocus(); }); } @@ -716,21 +716,21 @@ void ModListView::setup(OrganizerCore& core, CategoryFactory& factory, MainWindo mwui->filtersSeparators, mwui->espList}; - connect(m_core, &OrganizerCore::modInstalled, [=](auto&& name) { + connect(m_core, &OrganizerCore::modInstalled, [=, this](auto&& name) { onModInstalled(name); }); connect(m_core, &OrganizerCore::profileChanged, this, &ModListView::onProfileChanged); - connect(core.modList(), &ModList::modPrioritiesChanged, [=](auto&& indices) { + connect(core.modList(), &ModList::modPrioritiesChanged, [=, this](auto&& indices) { onModPrioritiesChanged(indices); }); - connect(core.modList(), &ModList::clearOverwrite, [=] { + connect(core.modList(), &ModList::clearOverwrite, [=, this] { m_actions->clearOverwrite(); }); - connect(core.modList(), &ModList::modStatesChanged, [=] { + connect(core.modList(), &ModList::modStatesChanged, [=, this] { updateModCount(); setOverwriteMarkers(selectionModel()->selectedRows()); }); - connect(core.modList(), &ModList::modelReset, [=] { + connect(core.modList(), &ModList::modelReset, [=, this] { clearOverwriteMarkers(); }); @@ -746,14 +746,14 @@ void ModListView::setup(OrganizerCore& core, CategoryFactory& factory, MainWindo // we need to store the expanded/collapsed state of all items and restore them 1) when // switching proxies, 2) when filtering and 3) when reseting the mod list. - connect(this, &QTreeView::expanded, [=](const QModelIndex& index) { + connect(this, &QTreeView::expanded, [=, this](const QModelIndex& index) { auto it = m_collapsed[m_sortProxy->sourceModel()].find( index.data(Qt::DisplayRole).toString()); if (it != m_collapsed[m_sortProxy->sourceModel()].end()) { m_collapsed[m_sortProxy->sourceModel()].erase(it); } }); - connect(this, &QTreeView::collapsed, [=](const QModelIndex& index) { + connect(this, &QTreeView::collapsed, [=, this](const QModelIndex& index) { m_collapsed[m_sortProxy->sourceModel()].insert( index.data(Qt::DisplayRole).toString()); }); @@ -761,7 +761,7 @@ void ModListView::setup(OrganizerCore& core, CategoryFactory& factory, MainWindo // the top-level proxy m_sortProxy = new ModListSortProxy(core.currentProfile().get(), &core); setModel(m_sortProxy); - connect(m_sortProxy, &ModList::modelReset, [=] { + connect(m_sortProxy, &ModList::modelReset, [=, this] { refreshExpandedItems(); }); @@ -773,7 +773,7 @@ void ModListView::setup(OrganizerCore& core, CategoryFactory& factory, MainWindo } }); connect(ui.groupBy, QOverload::of(&QComboBox::currentIndexChanged), - [=](int index) { + [=, this](int index) { updateGroupByProxy(); onModFilterActive(m_sortProxy->isFilterActive()); }); @@ -788,11 +788,11 @@ void ModListView::setup(OrganizerCore& core, CategoryFactory& factory, MainWindo connect(m_sortProxy, &ModListSortProxy::filterInvalidated, this, &ModListView::updateModCount); - connect(header(), &QHeaderView::sortIndicatorChanged, [=](int, Qt::SortOrder) { + connect(header(), &QHeaderView::sortIndicatorChanged, [=, this](int, Qt::SortOrder) { verticalScrollBar()->repaint(); }); connect(header(), &QHeaderView::sectionResized, - [=](int logicalIndex, int oldSize, int newSize) { + [=, this](int logicalIndex, int oldSize, int newSize) { m_sortProxy->setColumnVisible(logicalIndex, newSize != 0); }); @@ -839,13 +839,13 @@ void ModListView::setup(OrganizerCore& core, CategoryFactory& factory, MainWindo // in the manual installer connect( m_core->modList(), &ModList::downloadArchiveDropped, this, - [=](int row, int priority) { + [=, this](int row, int priority) { m_core->installDownload(row, priority); }, Qt::QueuedConnection); connect( m_core->modList(), &ModList::externalArchiveDropped, this, - [=](const QUrl& url, int priority) { + [=, this](const QUrl& url, int priority) { setWindowState(Qt::WindowActive); m_core->installArchive(url.toLocalFile(), priority, false, nullptr); }, @@ -853,32 +853,32 @@ void ModListView::setup(OrganizerCore& core, CategoryFactory& factory, MainWindo connect(m_core->modList(), &ModList::externalFolderDropped, this, &ModListView::onExternalFolderDropped); - connect(selectionModel(), &QItemSelectionModel::selectionChanged, [=] { + connect(selectionModel(), &QItemSelectionModel::selectionChanged, [=, this] { m_refreshMarkersTimer.start(); }); - connect(this, &QTreeView::collapsed, [=] { + connect(this, &QTreeView::collapsed, [=, this] { m_refreshMarkersTimer.start(); }); - connect(this, &QTreeView::expanded, [=] { + connect(this, &QTreeView::expanded, [=, this] { m_refreshMarkersTimer.start(); }); // filters connect(m_sortProxy, &ModListSortProxy::filterActive, this, &ModListView::onModFilterActive); - connect(m_filters.get(), &FilterList::criteriaChanged, [=](auto&& v) { + connect(m_filters.get(), &FilterList::criteriaChanged, [=, this](auto&& v) { onFiltersCriteria(v); }); - connect(m_filters.get(), &FilterList::optionsChanged, [=](auto&& mode, auto&& sep) { + connect(m_filters.get(), &FilterList::optionsChanged, [=, this](auto&& mode, auto&& sep) { setFilterOptions(mode, sep); }); connect(ui.filter, &QLineEdit::textChanged, m_sortProxy, &ModListSortProxy::updateFilter); - connect(ui.clearFilters, &QPushButton::clicked, [=]() { + connect(ui.clearFilters, &QPushButton::clicked, [=, this]() { ui.filter->clear(); m_filters->clearSelection(); }); - connect(m_sortProxy, &ModListSortProxy::filterInvalidated, [=]() { + connect(m_sortProxy, &ModListSortProxy::filterInvalidated, [=, this]() { if (hasCollapsibleSeparators()) { refreshExpandedItems(); } @@ -1383,9 +1383,9 @@ void ModListView::dropEvent(QDropEvent* event) { // from Qt source QModelIndex index; - if (viewport()->rect().contains(event->pos())) { - index = indexAt(event->pos()); - if (!index.isValid() || !visualRect(index).contains(event->pos())) + if (viewport()->rect().contains(event->position().toPoint())) { + index = indexAt(event->position().toPoint()); + if (!index.isValid() || !visualRect(index).contains(event->position().toPoint())) index = QModelIndex(); } @@ -1439,10 +1439,10 @@ void ModListView::mousePressEvent(QMouseEvent* event) // restore triggers setEditTriggers(triggers); - const auto index = indexAt(event->pos()); + const auto index = indexAt(event->position().toPoint()); if (event->isAccepted() && hasCollapsibleSeparators() && index.isValid() && - model()->hasChildren(indexAt(event->pos())) && + model()->hasChildren(indexAt(event->position().toPoint())) && (event->modifiers() & Qt::AltModifier)) { const auto flag = selectionModel()->isSelected(index) @@ -1472,13 +1472,13 @@ void ModListView::mouseReleaseEvent(QMouseEvent* event) // selection state of the item after QTreeView::mouseReleaseEvent(event); - const auto index = indexAt(event->pos()); + const auto index = indexAt(event->position().toPoint()); // restore triggers setEditTriggers(triggers); if (event->isAccepted() && hasCollapsibleSeparators() && index.isValid() && - model()->hasChildren(indexAt(event->pos())) && + model()->hasChildren(indexAt(event->position().toPoint())) && (event->modifiers() & Qt::AltModifier)) { const auto flag = selectionModel()->isSelected(index) diff --git a/src/src/modlistviewactions.cpp b/src/src/modlistviewactions.cpp index 6b2daad..ace0045 100644 --- a/src/src/modlistviewactions.cpp +++ b/src/src/modlistviewactions.cpp @@ -232,7 +232,7 @@ void ModListViewActions::checkModsForUpdates() const } else { QString apiKey; if (GlobalSettings::nexusApiKey(apiKey)) { - m_core.doAfterLogin([=]() { + m_core.doAfterLogin([=, this]() { checkModsForUpdates(); }); NexusInterface::instance().getAccessManager()->apiCheck(apiKey); @@ -312,7 +312,7 @@ void ModListViewActions::checkModsForUpdates( } else { QString apiKey; if (GlobalSettings::nexusApiKey(apiKey)) { - m_core.doAfterLogin([=]() { + m_core.doAfterLogin([=, this]() { checkModsForUpdates(IDs); }); NexusInterface::instance().getAccessManager()->apiCheck(apiKey); @@ -578,7 +578,7 @@ void ModListViewActions::displayModInformation(ModInfo::Ptr modInfo, dialog->show(); dialog->raise(); dialog->activateWindow(); - connect(dialog, &QDialog::finished, [=]() { + connect(dialog, &QDialog::finished, [=, this]() { m_core.modList()->modInfoChanged(modInfo); dialog->deleteLater(); m_core.refreshDirectoryStructure(); @@ -592,7 +592,7 @@ void ModListViewActions::displayModInformation(ModInfo::Ptr modInfo, ModInfoDialog dialog(m_core, m_core.pluginContainer(), modInfo, m_view, m_parent); connect(&dialog, &ModInfoDialog::originModified, this, &ModListViewActions::originModified); - connect(&dialog, &ModInfoDialog::modChanged, [=](unsigned int index) { + connect(&dialog, &ModInfoDialog::modChanged, [=, this](unsigned int index) { auto idx = m_view->indexModelToView(m_core.modList()->index(index, 0)); m_view->selectionModel()->select(idx, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); @@ -740,7 +740,7 @@ void ModListViewActions::sendModsToFirstConflict(const QModelIndexList& indexes) std::set priorities; std::transform(conflicts.begin(), conflicts.end(), - std::inserter(priorities, priorities.end()), [=](auto index) { + std::inserter(priorities, priorities.end()), [=, this](auto index) { return m_core.currentProfile()->getModPriority(index); }); @@ -764,7 +764,7 @@ void ModListViewActions::sendModsToLastConflict(const QModelIndexList& indexes) std::set priorities; std::transform(conflicts.begin(), conflicts.end(), - std::inserter(priorities, priorities.end()), [=](auto index) { + std::inserter(priorities, priorities.end()), [=, this](auto index) { return m_core.currentProfile()->getModPriority(index); }); @@ -1136,7 +1136,7 @@ void ModListViewActions::restoreHiddenFiles(const QModelIndexList& indices) cons void ModListViewActions::setTracked(const QModelIndexList& indices, bool tracked) const { - m_core.loggedInAction(m_parent, [=] { + m_core.loggedInAction(m_parent, [=, this] { for (auto& idx : indices) { ModInfo::getByIndex(idx.data(ModList::IndexRole).toInt())->track(tracked); } @@ -1146,7 +1146,7 @@ void ModListViewActions::setTracked(const QModelIndexList& indices, bool tracked void ModListViewActions::setEndorsed(const QModelIndexList& indices, bool endorsed) const { - m_core.loggedInAction(m_parent, [=] { + m_core.loggedInAction(m_parent, [=, this] { if (indices.size() > 1) { MessageDialog::showMessage( tr("Endorsing multiple mods will take a while. Please wait..."), m_parent); diff --git a/src/src/nxmaccessmanager.cpp b/src/src/nxmaccessmanager.cpp index 3a68b62..ad9b0bd 100644 --- a/src/src/nxmaccessmanager.cpp +++ b/src/src/nxmaccessmanager.cpp @@ -162,11 +162,9 @@ NexusSSOLogin::NexusSSOLogin() : m_keyReceived(false), m_active(false) onConnected(); }); - QObject::connect(&m_socket, - qOverload(&QWebSocket::error), - [&](auto&& e) { - onError(e); - }); + QObject::connect(&m_socket, &QWebSocket::errorOccurred, [&](auto&& e) { + onError(e); + }); QObject::connect(&m_socket, &QWebSocket::sslErrors, [&](auto&& errors) { onSslErrors(errors); diff --git a/src/src/organizercore.cpp b/src/src/organizercore.cpp index 5a3d21d..e0e32cb 100644 --- a/src/src/organizercore.cpp +++ b/src/src/organizercore.cpp @@ -213,7 +213,7 @@ OrganizerCore::OrganizerCore(Settings& settings) &OrganizerCore::onDirectoryRefreshed); connect(&m_ModList, SIGNAL(removeOrigin(QString)), this, SLOT(removeOrigin(QString))); - connect(&m_ModList, &ModList::modStatesChanged, [=] { + connect(&m_ModList, &ModList::modStatesChanged, [=, this] { currentProfile()->writeModlist(); }); connect(&m_ModList, &ModList::modPrioritiesChanged, [this](auto&& indexes) { @@ -908,7 +908,7 @@ OrganizerCore::doInstall(const QString& archivePath, GuessedValue modNa // connect( this, &OrganizerCore::directoryStructureReady, this, - [=] { + [=, this] { const int modIndex = ModInfo::getIndex(modName); if (modIndex != UINT_MAX) { const auto modInfo = ModInfo::getByIndex(modIndex); diff --git a/src/src/plugincontainer.cpp b/src/src/plugincontainer.cpp index 1397aad..98665fb 100644 --- a/src/src/plugincontainer.cpp +++ b/src/src/plugincontainer.cpp @@ -1175,7 +1175,10 @@ void PluginContainer::loadPlugins() loadCheck.close(); } - loadCheck.open(QIODevice::WriteOnly); + if (!loadCheck.open(QIODevice::WriteOnly)) { + log::warn("failed to open loadcheck file for writing '{}'", + QDir::toNativeSeparators(loadCheck.fileName())); + } } QString pluginPath = @@ -1259,11 +1262,15 @@ void PluginContainer::loadPlugins() } log::warn("user skipped plugin '{}', remembering in loadcheck", skipPlugin); - loadCheck.open(QIODevice::WriteOnly); - loadCheck.write(skipPlugin.toUtf8()); - loadCheck.write("\n"); - loadCheck.flush(); - } + if (loadCheck.open(QIODevice::WriteOnly)) { + loadCheck.write(skipPlugin.toUtf8()); + loadCheck.write("\n"); + loadCheck.flush(); + } else { + log::warn("failed to persist skipped plugin to '{}'", + QDir::toNativeSeparators(loadCheck.fileName())); + } + } bf::at_key(m_Plugins).push_back(this); diff --git a/src/src/pluginlist.cpp b/src/src/pluginlist.cpp index aa44e0a..8fac338 100644 --- a/src/src/pluginlist.cpp +++ b/src/src/pluginlist.cpp @@ -567,7 +567,7 @@ void PluginList::shiftPluginsPriority(const QModelIndexList& indices, int offset for (auto& idx : indices) { allIndex.push_back(idx.row()); } - std::sort(allIndex.begin(), allIndex.end(), [=](int lhs, int rhs) { + std::sort(allIndex.begin(), allIndex.end(), [=, this](int lhs, int rhs) { bool cmp = m_ESPs[lhs].priority < m_ESPs[rhs].priority; return offset > 0 ? !cmp : cmp; }); @@ -662,7 +662,10 @@ void PluginList::readLockedOrderFrom(const QString& fileName) return; } - file.open(QIODevice::ReadOnly); + if (!file.open(QIODevice::ReadOnly)) { + log::error("failed to open locked order file '{}': {}", fileName, file.errorString()); + return; + } int lineNumber = 0; while (!file.atEnd()) { QByteArray line = file.readLine(); diff --git a/src/src/pluginlistcontextmenu.cpp b/src/src/pluginlistcontextmenu.cpp index 39f2065..d989c0f 100644 --- a/src/src/pluginlistcontextmenu.cpp +++ b/src/src/pluginlistcontextmenu.cpp @@ -21,24 +21,24 @@ PluginListContextMenu::PluginListContextMenu(const QModelIndex& index, } if (!m_selected.isEmpty()) { - addAction(tr("Enable selected"), [=]() { + addAction(tr("Enable selected"), [=, this]() { m_core.pluginList()->setEnabled(m_selected, true); }); - addAction(tr("Disable selected"), [=]() { + addAction(tr("Disable selected"), [=, this]() { m_core.pluginList()->setEnabled(m_selected, false); }); addSeparator(); } - addAction(tr("Enable all"), [=]() { + addAction(tr("Enable all"), [=, this]() { if (QMessageBox::question(m_view->topLevelWidget(), tr("Confirm"), tr("Really enable all plugins?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { m_core.pluginList()->setEnabledAll(true); } }); - addAction(tr("Disable all"), [=]() { + addAction(tr("Disable all"), [=, this]() { if (QMessageBox::question(m_view->topLevelWidget(), tr("Confirm"), tr("Really disable all plugins?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { @@ -65,12 +65,12 @@ PluginListContextMenu::PluginListContextMenu(const QModelIndex& index, } if (hasLocked) { - addAction(tr("Unlock load order"), [=]() { + addAction(tr("Unlock load order"), [=, this]() { setESPLock(m_selected, false); }); } if (hasUnlocked) { - addAction(tr("Lock load order"), [=]() { + addAction(tr("Lock load order"), [=, this]() { setESPLock(m_selected, true); }); } @@ -83,14 +83,14 @@ PluginListContextMenu::PluginListContextMenu(const QModelIndex& index, ModInfo::getIndex(m_core.pluginList()->origin(m_index.data().toString())); // this is to avoid showing the option on game files like skyrim.esm if (modInfoIndex != UINT_MAX) { - addAction(tr("Open Origin in Explorer"), [=]() { + addAction(tr("Open Origin in Explorer"), [=, this]() { openOriginExplorer(m_selected); }); ModInfo::Ptr modInfo = ModInfo::getByIndex(modInfoIndex); std::vector flags = modInfo->getFlags(); if (!modInfo->isForeign() && m_selected.size() == 1) { - QAction* infoAction = addAction(tr("Open Origin Info..."), [=]() { + QAction* infoAction = addAction(tr("Open Origin Info..."), [=, this]() { openOriginInformation(index); }); setDefaultAction(infoAction); @@ -103,13 +103,13 @@ QMenu* PluginListContextMenu::createSendToContextMenu() { QMenu* menu = new QMenu(m_view); menu->setTitle(tr("Send to... ")); - menu->addAction(tr("Top"), [=]() { + menu->addAction(tr("Top"), [=, this]() { m_core.pluginList()->sendToPriority(m_selected, 0); }); - menu->addAction(tr("Bottom"), [=]() { + menu->addAction(tr("Bottom"), [=, this]() { m_core.pluginList()->sendToPriority(m_selected, INT_MAX); }); - menu->addAction(tr("Priority..."), [=]() { + menu->addAction(tr("Priority..."), [=, this]() { sendPluginsToPriority(m_selected); }); return menu; diff --git a/src/src/pluginlistsortproxy.cpp b/src/src/pluginlistsortproxy.cpp index 0d42ce9..b7fb797 100644 --- a/src/src/pluginlistsortproxy.cpp +++ b/src/src/pluginlistsortproxy.cpp @@ -25,17 +25,27 @@ along with Mod Organizer. If not, see . #include #include -PluginListSortProxy::PluginListSortProxy(QObject* parent) - : QSortFilterProxyModel(parent), m_SortIndex(0), m_SortOrder(Qt::AscendingOrder) -{ +PluginListSortProxy::PluginListSortProxy(QObject* parent) + : QSortFilterProxyModel(parent), m_SortIndex(0), m_SortOrder(Qt::AscendingOrder) +{ m_EnabledColumns.set(PluginList::COL_NAME); m_EnabledColumns.set(PluginList::COL_PRIORITY); m_EnabledColumns.set(PluginList::COL_MODINDEX); - this->setDynamicSortFilter(true); -} - -void PluginListSortProxy::setEnabledColumns(unsigned int columns) -{ + this->setDynamicSortFilter(true); +} + +void PluginListSortProxy::refreshFilter() +{ +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + beginFilterChange(); + endFilterChange(QSortFilterProxyModel::Direction::Rows); +#else + invalidateFilter(); +#endif +} + +void PluginListSortProxy::setEnabledColumns(unsigned int columns) +{ emit layoutAboutToBeChanged(); for (int i = 0; i <= PluginList::COL_LASTCOLUMN; ++i) { m_EnabledColumns.set(i, (columns & (1 << i)) != 0); @@ -43,11 +53,11 @@ void PluginListSortProxy::setEnabledColumns(unsigned int columns) emit layoutChanged(); } -void PluginListSortProxy::updateFilter(const QString& filter) -{ - m_CurrentFilter = filter; - invalidateFilter(); -} +void PluginListSortProxy::updateFilter(const QString& filter) +{ + m_CurrentFilter = filter; + refreshFilter(); +} bool PluginListSortProxy::filterAcceptsRow(int row, const QModelIndex&) const { diff --git a/src/src/pluginlistsortproxy.h b/src/src/pluginlistsortproxy.h index 370dd87..73d439d 100644 --- a/src/src/pluginlistsortproxy.h +++ b/src/src/pluginlistsortproxy.h @@ -52,8 +52,9 @@ protected: virtual bool filterAcceptsRow(int row, const QModelIndex& parent) const; virtual bool lessThan(const QModelIndex& left, const QModelIndex& right) const; -private: - int m_SortIndex; +private: + void refreshFilter(); + int m_SortIndex; Qt::SortOrder m_SortOrder; std::bitset m_EnabledColumns; diff --git a/src/src/pluginlistview.cpp b/src/src/pluginlistview.cpp index e90b8b8..58b0548 100644 --- a/src/src/pluginlistview.cpp +++ b/src/src/pluginlistview.cpp @@ -203,7 +203,7 @@ void PluginListView::onSortButtonClicked() m_core->savePluginList(); topLevelWidget()->setEnabled(false); - Guard g([=]() { + Guard g([=, this]() { topLevelWidget()->setEnabled(true); }); @@ -251,15 +251,15 @@ void PluginListView::setup(OrganizerCore& core, MainWindow* mw, Ui::MainWindow* setItemDelegateForColumn(PluginList::COL_FLAGS, new GenericIconDelegate(this)); // counter - connect(core.pluginList(), &PluginList::writePluginsList, [=] { + connect(core.pluginList(), &PluginList::writePluginsList, [=, this] { updatePluginCount(); }); - connect(core.pluginList(), &PluginList::esplist_changed, [=] { + connect(core.pluginList(), &PluginList::esplist_changed, [=, this] { updatePluginCount(); }); // sort - connect(mwui->sortButton, &QPushButton::clicked, [=] { + connect(mwui->sortButton, &QPushButton::clicked, [=, this] { onSortButtonClicked(); }); @@ -269,7 +269,7 @@ void PluginListView::setup(OrganizerCore& core, MainWindow* mw, Ui::MainWindow* connect(ui.filter, &QLineEdit::textChanged, this, &PluginListView::onFilterChanged); // highlight mod list when selected - connect(selectionModel(), &QItemSelectionModel::selectionChanged, [=] { + connect(selectionModel(), &QItemSelectionModel::selectionChanged, [=, this] { std::set mods; auto& directoryEntry = *m_core->directoryStructure(); auto pluginIndices = indexViewToModel(selectionModel()->selectedRows()); @@ -291,10 +291,10 @@ void PluginListView::setup(OrganizerCore& core, MainWindow* mw, Ui::MainWindow* }); // using a lambda here to avoid storing the mod list actions - connect(this, &QTreeView::customContextMenuRequested, [=](auto&& pos) { + connect(this, &QTreeView::customContextMenuRequested, [=, this](auto&& pos) { onCustomContextMenuRequested(pos); }); - connect(this, &QTreeView::doubleClicked, [=](auto&& index) { + connect(this, &QTreeView::doubleClicked, [=, this](auto&& index) { onDoubleClicked(index); }); } @@ -303,7 +303,7 @@ void PluginListView::onCustomContextMenuRequested(const QPoint& pos) { try { PluginListContextMenu menu(indexViewToModel(indexAt(pos)), *m_core, this); - connect(&menu, &PluginListContextMenu::openModInformation, [=](auto&& modIndex) { + connect(&menu, &PluginListContextMenu::openModInformation, [=, this](auto&& modIndex) { m_modActions->displayModInformation(modIndex); }); menu.exec(viewport()->mapToGlobal(pos)); diff --git a/src/src/profile.cpp b/src/src/profile.cpp index 405ba4e..0060fa1 100644 --- a/src/src/profile.cpp +++ b/src/src/profile.cpp @@ -910,9 +910,9 @@ bool Profile::enableLocalSaves(bool enable) "games)"), QDialogButtonBox::No | QDialogButtonBox::Yes | QDialogButtonBox::Cancel, QDialogButtonBox::No); - if (res == QMessageBox::Yes) { + if (res == QDialogButtonBox::Yes) { shellDelete(QStringList(m_Directory.absoluteFilePath("saves"))); - } else if (res == QMessageBox::No) { + } else if (res == QDialogButtonBox::No) { // No action } else { return false; @@ -971,7 +971,7 @@ bool Profile::enableLocalSettings(bool enable) QDialogButtonBox::No | QDialogButtonBox::Yes | QDialogButtonBox::Cancel, QDialogButtonBox::No); - if (res == QMessageBox::Yes) { + if (res == QDialogButtonBox::Yes) { QStringList filesToDelete; for (QString file : m_GamePlugin->iniFiles()) { QString resolved = MOBase::resolveFileCaseInsensitive( @@ -979,7 +979,7 @@ bool Profile::enableLocalSettings(bool enable) filesToDelete << resolved; } shellDelete(filesToDelete, true); - } else if (res == QMessageBox::No) { + } else if (res == QDialogButtonBox::No) { // No action } else { return false; diff --git a/src/src/protonlauncher.cpp b/src/src/protonlauncher.cpp index 5c3ef54..233732f 100644 --- a/src/src/protonlauncher.cpp +++ b/src/src/protonlauncher.cpp @@ -1,4 +1,5 @@ #include "protonlauncher.h" +#include "fluorinepaths.h" #include #include @@ -224,6 +225,9 @@ ProtonLauncher& ProtonLauncher::setWrapper(const QString& wrapperCmd) const QStringList parts = QProcess::splitCommand(wrapperCmd.trimmed()); for (const QString& part : parts) { + if (part.compare("%command%", Qt::CaseInsensitive) == 0) { + continue; + } QString key; QString value; if (parseEnvAssignment(part, key, value)) { @@ -366,9 +370,7 @@ bool ProtonLauncher::launchWithUmu(qint64& pid) const // Use the full path to our copied umu-run since the host PATH won't include it. QString umuRun; if (isFlatpak()) { - const QString dataDir = - QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation); - const QString flatpakUmu = QDir(dataDir).filePath("fluorine/umu-run"); + const QString flatpakUmu = fluorineDataDir() + QStringLiteral("/umu-run"); if (QFileInfo::exists(flatpakUmu)) { umuRun = flatpakUmu; } else { diff --git a/src/src/qtgroupingproxy.cpp b/src/src/qtgroupingproxy.cpp index 1e866ca..0983e15 100644 --- a/src/src/qtgroupingproxy.cpp +++ b/src/src/qtgroupingproxy.cpp @@ -108,7 +108,7 @@ QList QtGroupingProxy::belongsTo(const QModelIndex& idx) int role = i.key(); QVariant variant = i.value(); - if (variant.type() == QVariant::List) { + if (variant.typeId() == QMetaType::QVariantList) { // a list of variants get's expanded to multiple rows QVariantList list = variant.toList(); for (int i = 0; i < list.length(); i++) { @@ -358,8 +358,8 @@ int QtGroupingProxy::columnCount(const QModelIndex& index) const static bool variantLess(const QVariant& LHS, const QVariant& RHS) { - if ((LHS.type() == RHS.type()) && - ((LHS.type() == QVariant::Int) || (LHS.type() == QVariant::UInt))) { + if ((LHS.typeId() == RHS.typeId()) && + ((LHS.typeId() == QMetaType::Int) || (LHS.typeId() == QMetaType::UInt))) { return LHS.toInt() < RHS.toInt(); } diff --git a/src/src/selfupdater.cpp b/src/src/selfupdater.cpp index 9d20421..4438f60 100644 --- a/src/src/selfupdater.cpp +++ b/src/src/selfupdater.cpp @@ -235,10 +235,13 @@ void SelfUpdater::openOutputFile(const QString& fileName) QString outputPath = QDir::fromNativeSeparators(qApp->property("dataPath").toString()) + "/" + fileName; - log::debug("downloading to {}", outputPath); - m_UpdateFile.setFileName(outputPath); - m_UpdateFile.open(QIODevice::WriteOnly); -} + log::debug("downloading to {}", outputPath); + m_UpdateFile.setFileName(outputPath); + if (!m_UpdateFile.open(QIODevice::WriteOnly)) { + log::error("failed to open update output file '{}': {}", outputPath, + m_UpdateFile.errorString()); + } +} void SelfUpdater::download(const QString& downloadLink) { diff --git a/src/src/settings.cpp b/src/src/settings.cpp index 5578daf..fc6316e 100644 --- a/src/src/settings.cpp +++ b/src/src/settings.cpp @@ -1409,7 +1409,7 @@ void PluginSettings::registerPlugin(IPlugin* plugin) if (!temp.isValid()) { temp = setting.defaultValue; - } else if (!temp.convert(setting.defaultValue.type())) { + } else if (!temp.convert(setting.defaultValue.metaType())) { log::warn("failed to interpret \"{}\" as correct type for \"{}\" in plugin " "\"{}\", using default", temp.toString(), setting.key, plugin->name()); diff --git a/src/src/settingsdialog.ui b/src/src/settingsdialog.ui index cd869a5..7755f6f 100644 --- a/src/src/settingsdialog.ui +++ b/src/src/settingsdialog.ui @@ -2171,7 +2171,7 @@ p, li { white-space: pre-wrap; } - + 0 @@ -2221,7 +2221,7 @@ p, li { white-space: pre-wrap; } - + Qt::Orientation::Horizontal diff --git a/src/src/settingsdialogmodlist.cpp b/src/src/settingsdialogmodlist.cpp index 8e93767..b46f1c4 100644 --- a/src/src/settingsdialogmodlist.cpp +++ b/src/src/settingsdialogmodlist.cpp @@ -18,10 +18,10 @@ ModListSettingsTab::ModListSettingsTab(Settings& s, SettingsDialog& d) {ModList::COL_VERSION, ui->collapsibleSeparatorsIconsVersionBox}} { // connect before setting to trigger - QObject::connect(ui->collapsibleSeparatorsAscBox, &QCheckBox::toggled, [=] { + QObject::connect(ui->collapsibleSeparatorsAscBox, &QCheckBox::toggled, [=, this] { updateCollapsibleSeparatorsGroup(); }); - QObject::connect(ui->collapsibleSeparatorsDscBox, &QCheckBox::toggled, [=] { + QObject::connect(ui->collapsibleSeparatorsDscBox, &QCheckBox::toggled, [=, this] { updateCollapsibleSeparatorsGroup(); }); diff --git a/src/src/settingsdialogproton.cpp b/src/src/settingsdialogproton.cpp index af1b344..f12b9c0 100644 --- a/src/src/settingsdialogproton.cpp +++ b/src/src/settingsdialogproton.cpp @@ -1,6 +1,7 @@ #include "settingsdialogproton.h" #include "fluorineconfig.h" +#include "fluorinepaths.h" #include "ui_settingsdialog.h" #include @@ -150,7 +151,7 @@ void ProtonSettingsTab::refreshState() ui->prefixLocationEdit->setReadOnly(false); if (ui->prefixLocationEdit->text().isEmpty()) { ui->prefixLocationEdit->setText( - QDir::homePath() + "/.var/app/com.fluorine.manager/Prefix"); + fluorineDataDir() + "/Prefix"); } } @@ -288,7 +289,7 @@ void ProtonSettingsTab::onBrowsePrefixLocation() QString ProtonSettingsTab::ensureWinetricks() { - const QString nakWinetricks = QDir::homePath() + "/.var/app/com.fluorine.manager/bin/winetricks"; + const QString nakWinetricks = fluorineDataDir() + "/bin/winetricks"; if (QFileInfo::exists(nakWinetricks)) { return nakWinetricks; } @@ -298,7 +299,7 @@ QString ProtonSettingsTab::ensureWinetricks() return systemWinetricks; } - const QString nakBinDir = QDir::homePath() + "/.var/app/com.fluorine.manager/bin"; + const QString nakBinDir = fluorineDataDir() + "/bin"; QDir().mkpath(nakBinDir); QString downloadTool; diff --git a/src/src/spawn.cpp b/src/src/spawn.cpp index b18282d..f68389e 100644 --- a/src/src/spawn.cpp +++ b/src/src/spawn.cpp @@ -914,7 +914,7 @@ bool checkSteam(QWidget* parent, const SpawnParameters& sp, const QDir& gameDire const auto c = dialogs::confirmStartSteam(parent, sp, details); - if (c == QDialogButtonBox::Yes) { + if (c == QMessageBox::Yes) { log::debug("user wants to start steam"); if (!startSteam(parent)) { @@ -928,7 +928,7 @@ bool checkSteam(QWidget* parent, const SpawnParameters& sp, const QDir& gameDire log::error("steam is still not running, hoping for the best"); return true; } - } else if (c == QDialogButtonBox::No) { + } else if (c == QMessageBox::No) { log::debug("user declined to start steam"); return true; } else { diff --git a/src/src/texteditor.cpp b/src/src/texteditor.cpp index 2ac9a7b..36d8103 100644 --- a/src/src/texteditor.cpp +++ b/src/src/texteditor.cpp @@ -99,13 +99,15 @@ bool TextEditor::load(const QString& filename) bool TextEditor::save() { - if (m_filename.isEmpty() || m_encoding.isEmpty()) { - return false; - } - - QFile file(m_filename); - file.open(QIODevice::WriteOnly); - file.resize(0); + if (m_filename.isEmpty() || m_encoding.isEmpty()) { + return false; + } + + QFile file(m_filename); + if (!file.open(QIODevice::WriteOnly)) { + return false; + } + file.resize(0); auto codec = QStringConverter::encodingForName(m_encoding.toUtf8()); if (!codec.has_value()) @@ -468,7 +470,7 @@ TextEditorToolbar::TextEditorToolbar(TextEditor& editor) m_save = new QAction(QIcon(":/MO/gui/save"), QObject::tr("&Save"), &editor); m_save->setShortcutContext(Qt::WidgetWithChildrenShortcut); - m_save->setShortcut(Qt::CTRL + Qt::Key_S); + m_save->setShortcut(Qt::CTRL | Qt::Key_S); m_editor.addAction(m_save); m_wordWrap = diff --git a/src/src/uilocker.cpp b/src/src/uilocker.cpp index e6189f6..9cdbf31 100644 --- a/src/src/uilocker.cpp +++ b/src/src/uilocker.cpp @@ -205,10 +205,10 @@ private: m_topLevel->setGeometry(mainUI->rect()); m_filter.reset(new Filter); - m_filter->resized = [=] { + m_filter->resized = [=, this] { m_topLevel->setGeometry(mainUI->rect()); }; - m_filter->closed = [=] { + m_filter->closed = [=, this] { checkTarget(); }; -- cgit v1.3.1