From a8f6f0d7a0f1c8506e225dc5a817cadc0c0b3662 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Mon, 28 Dec 2020 05:28:37 -0500 Subject: split saves tab, no changes --- src/savestab.cpp | 278 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 src/savestab.cpp (limited to 'src/savestab.cpp') diff --git a/src/savestab.cpp b/src/savestab.cpp new file mode 100644 index 00000000..a14321d3 --- /dev/null +++ b/src/savestab.cpp @@ -0,0 +1,278 @@ +#include "savestab.h" +#include "ui_mainwindow.h" +#include "organizercore.h" +#include "activatemodsdialog.h" +#include +#include + +using namespace MOBase; + +SavesTab::SavesTab(QWidget* window, OrganizerCore& core, Ui::MainWindow* mwui) + : m_window(window), m_core(core), m_CurrentSaveView(nullptr), ui{ + mwui->tabWidget, mwui->savesTab, mwui->savegameList} +{ + m_SavesWatcherTimer.setSingleShot(true); + m_SavesWatcherTimer.setInterval(500); + + ui.list->installEventFilter(this); + ui.list->setMouseTracking(true); + + connect( + &m_SavesWatcher, &QFileSystemWatcher::directoryChanged, + [&]{ m_SavesWatcherTimer.start(); }); + + connect( + &m_SavesWatcherTimer, &QTimer::timeout, + [&]{ refreshSavesIfOpen(); }); + + connect( + ui.list, &QWidget::customContextMenuRequested, + [&](auto pos){ onContextMenu(pos); }); + + connect( + ui.list, &QListWidget::itemEntered, + [&](auto* item){ saveSelectionChanged(item); }); +} + +void SavesTab::displaySaveGameInfo(QListWidgetItem *newItem) +{ + // don't display the widget if the main window doesn't have focus + // + // this goes against the standard behaviour for tooltips, which are displayed + // on hover regardless of focus, but this widget is so large and busy that + // it's probably better this way + if (!m_window->isActiveWindow()){ + return; + } + + if (m_CurrentSaveView == nullptr) { + const IPluginGame* game = m_core.managedGame(); + const SaveGameInfo* info = game->feature(); + + if (info != nullptr) { + m_CurrentSaveView = info->getSaveGameWidget(m_window); + } + + if (m_CurrentSaveView == nullptr) { + return; + } + } + + m_CurrentSaveView->setSave(*m_SaveGames[ui.list->row(newItem)]); + + QWindow *window = m_CurrentSaveView->window()->windowHandle(); + QRect screenRect; + if (window == nullptr) + screenRect = QGuiApplication::primaryScreen()->geometry(); + else + screenRect = window->screen()->geometry(); + + QPoint pos = QCursor::pos(); + if (pos.x() + m_CurrentSaveView->width() > screenRect.right()) { + pos.rx() -= (m_CurrentSaveView->width() + 2); + } else { + pos.rx() += 5; + } + + if (pos.y() + m_CurrentSaveView->height() > screenRect.bottom()) { + pos.ry() -= (m_CurrentSaveView->height() + 10); + } else { + pos.ry() += 20; + } + m_CurrentSaveView->move(pos); + + m_CurrentSaveView->show(); + m_CurrentSaveView->setProperty("displayItem", QVariant::fromValue(static_cast(newItem))); +} + + +void SavesTab::saveSelectionChanged(QListWidgetItem *newItem) +{ + if (newItem == nullptr) { + hideSaveGameInfo(); + } else if (m_CurrentSaveView == nullptr || newItem != m_CurrentSaveView->property("displayItem").value()) { + displaySaveGameInfo(newItem); + } +} + + +void SavesTab::hideSaveGameInfo() +{ + if (m_CurrentSaveView != nullptr) { + m_CurrentSaveView->deleteLater(); + m_CurrentSaveView = nullptr; + } +} + +void SavesTab::refreshSavesIfOpen() +{ + if (ui.mainTabs->currentWidget() == ui.tab) { + refreshSaveList(); + } +} + +QDir SavesTab::currentSavesDir() const +{ + QDir savesDir; + if (m_core.currentProfile()->localSavesEnabled()) { + savesDir.setPath(m_core.currentProfile()->savePath()); + } else { + auto iniFiles = m_core.managedGame()->iniFiles(); + + if (iniFiles.isEmpty()) { + return m_core.managedGame()->savesDirectory(); + } + + QString iniPath = m_core.currentProfile()->absoluteIniFilePath(iniFiles[0]); + + wchar_t path[MAX_PATH]; + if (::GetPrivateProfileStringW( + L"General", L"SLocalSavePath", L"", + path, MAX_PATH, + iniPath.toStdWString().c_str() + )) { + savesDir.setPath(m_core.managedGame()->documentsDirectory().absoluteFilePath(QString::fromWCharArray(path))); + } + else { + savesDir = m_core.managedGame()->savesDirectory(); + } + } + + return savesDir; +} + +void SavesTab::startMonitorSaves() +{ + stopMonitorSaves(); + + QDir savesDir = currentSavesDir(); + + m_SavesWatcher.addPath(savesDir.absolutePath()); +} + +void SavesTab::stopMonitorSaves() +{ + if (m_SavesWatcher.directories().length() > 0) { + m_SavesWatcher.removePaths(m_SavesWatcher.directories()); + } +} + +void SavesTab::refreshSaveList() +{ + TimeThis tt("MainWindow::refreshSaveList()"); + + startMonitorSaves(); // re-starts monitoring + + try + { + QDir savesDir = currentSavesDir(); + MOBase::log::debug("reading save games from {}", savesDir.absolutePath()); + m_SaveGames = m_core.managedGame()->listSaves(savesDir); + std::sort(m_SaveGames.begin(), m_SaveGames.end(), [](auto const& lhs, auto const& rhs) { + return lhs->getCreationTime() > rhs->getCreationTime(); + }); + + ui.list->clear(); + for (auto& save: m_SaveGames) { + ui.list->addItem(savesDir.relativeFilePath(save->getFilepath())); + } + } + catch(std::exception& e) + { + // listSaves() can throw + log::error("{}", e.what()); + } +} + +void SavesTab::deleteSavegame() +{ + SaveGameInfo const *info = m_core.managedGame()->feature(); + + QString savesMsgLabel; + QStringList deleteFiles; + + int count = 0; + + for (const QModelIndex &idx : ui.list->selectionModel()->selectedIndexes()) { + + auto& saveGame = m_SaveGames[idx.row()]; + + if (count < 10) { + savesMsgLabel += "
  • " + QFileInfo(saveGame->getFilepath()).completeBaseName() + "
  • "; + } + ++count; + + deleteFiles += saveGame->allFiles(); + } + + if (count > 10) { + savesMsgLabel += "
  • ... " + tr("%1 more").arg(count - 10) + "
  • "; + } + + if (QMessageBox::question(m_window, tr("Confirm"), + tr("Are you sure you want to remove the following %n save(s)?
    " + "
      %1

    " + "Removed saves will be sent to the Recycle Bin.", "", count) + .arg(savesMsgLabel), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + shellDelete(deleteFiles, true); // recycle bin delete. + refreshSaveList(); + } +} + + +void SavesTab::onContextMenu(const QPoint& pos) +{ + QItemSelectionModel* selection = ui.list->selectionModel(); + + if (!selection->hasSelection()) { + return; + } + + QMenu menu; + + SaveGameInfo const* info = this->m_core.managedGame()->feature(); + if (info != nullptr) { + QAction* action = menu.addAction(tr("Fix enabled mods...")); + action->setEnabled(false); + if (selection->selectedIndexes().count() == 1) { + auto& save = m_SaveGames[selection->selectedIndexes()[0].row()]; + SaveGameInfo::MissingAssets missing = info->getMissingAssets(*save); + if (missing.size() != 0) { + connect(action, &QAction::triggered, this, [this, missing] { fixMods(missing); }); + action->setEnabled(true); + } + } + } + + QString deleteMenuLabel = tr("Delete %n save(s)", "", selection->selectedIndexes().count()); + + menu.addAction(deleteMenuLabel, [&]{ deleteSavegame(); }); + + menu.exec(ui.list->viewport()->mapToGlobal(pos)); +} + +void SavesTab::fixMods(SaveGameInfo::MissingAssets const &missingAssets) +{ + ActivateModsDialog dialog(missingAssets, m_window); + if (dialog.exec() == QDialog::Accepted) { + // activate the required mods, then enable all esps + std::set modsToActivate = dialog.getModsToActivate(); + for (std::set::iterator iter = modsToActivate.begin(); iter != modsToActivate.end(); ++iter) { + if ((*iter != "") && (*iter != "")) { + unsigned int modIndex = ModInfo::getIndex(*iter); + m_core.currentProfile()->setModEnabled(modIndex, true); + } + } + + m_core.currentProfile()->writeModlist(); + m_core.refreshLists(); + + std::set espsToActivate = dialog.getESPsToActivate(); + for (std::set::iterator iter = espsToActivate.begin(); iter != espsToActivate.end(); ++iter) { + m_core.pluginList()->enableESP(*iter); + } + + m_core.saveCurrentLists(); + } +} -- cgit v1.3.1 From f46a14f3bfa0bec9decad453d967de089e4833ad Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Mon, 28 Dec 2020 05:37:14 -0500 Subject: delete shortcut for save games --- src/mainwindow.cpp | 5 +---- src/savestab.cpp | 18 ++++++++++++++++++ src/savestab.h | 3 +++ 3 files changed, 22 insertions(+), 4 deletions(-) (limited to 'src/savestab.cpp') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index e7d99f23..0f5b15e3 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1503,10 +1503,7 @@ void MainWindow::cleanup() bool MainWindow::eventFilter(QObject *object, QEvent *event) { - if ((object == ui->savegameList) && - ((event->type() == QEvent::Leave) || (event->type() == QEvent::WindowDeactivate))) { - m_SavesTab->hideSaveGameInfo(); - } else if (event->type() == QEvent::StatusTip && object != this) { + if (event->type() == QEvent::StatusTip && object != this) { QMainWindow::event(event); return true; } diff --git a/src/savestab.cpp b/src/savestab.cpp index a14321d3..31471740 100644 --- a/src/savestab.cpp +++ b/src/savestab.cpp @@ -32,6 +32,24 @@ SavesTab::SavesTab(QWidget* window, OrganizerCore& core, Ui::MainWindow* mwui) connect( ui.list, &QListWidget::itemEntered, [&](auto* item){ saveSelectionChanged(item); }); + + ui.list->installEventFilter(this); +} + +bool SavesTab::eventFilter(QObject* object, QEvent* e) +{ + if (object == ui.list) { + if (e->type() == QEvent::Leave || e->type() == QEvent::WindowDeactivate) { + hideSaveGameInfo(); + } else if (e->type() == QEvent::KeyPress) { + QKeyEvent *keyEvent = static_cast(e); + if (keyEvent->key() == Qt::Key_Delete) { + deleteSavegame(); + } + } + } + + return false; } void SavesTab::displaySaveGameInfo(QListWidgetItem *newItem) diff --git a/src/savestab.h b/src/savestab.h index d3eb7e63..8d84e3c1 100644 --- a/src/savestab.h +++ b/src/savestab.h @@ -32,6 +32,9 @@ public: void stopMonitorSaves(); void hideSaveGameInfo(); +protected: + bool eventFilter(QObject* object, QEvent* e) override; + private: struct SavesTabUi { -- cgit v1.3.1 From c2c0f7c98d4b61314c679e0fed7fac914f4f1284 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Mon, 28 Dec 2020 05:44:51 -0500 Subject: added open in explorer in save game context menu --- src/savestab.cpp | 16 +++++++++++++++- src/savestab.h | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) (limited to 'src/savestab.cpp') diff --git a/src/savestab.cpp b/src/savestab.cpp index 31471740..e2c796b6 100644 --- a/src/savestab.cpp +++ b/src/savestab.cpp @@ -264,9 +264,10 @@ void SavesTab::onContextMenu(const QPoint& pos) } QString deleteMenuLabel = tr("Delete %n save(s)", "", selection->selectedIndexes().count()); - menu.addAction(deleteMenuLabel, [&]{ deleteSavegame(); }); + menu.addAction(tr("Open in Explorer..."), [&]{ openInExplorer(); }); + menu.exec(ui.list->viewport()->mapToGlobal(pos)); } @@ -294,3 +295,16 @@ void SavesTab::fixMods(SaveGameInfo::MissingAssets const &missingAssets) m_core.saveCurrentLists(); } } + +void SavesTab::openInExplorer() +{ + const SaveGameInfo* info = m_core.managedGame()->feature(); + + const auto sel = ui.list->selectionModel()->selectedIndexes(); + if (sel.empty()) { + return; + } + + auto& saveGame = m_SaveGames[sel[0].row()]; + shell::Explore(saveGame->getFilepath()); +} diff --git a/src/savestab.h b/src/savestab.h index 8d84e3c1..db82b816 100644 --- a/src/savestab.h +++ b/src/savestab.h @@ -58,6 +58,7 @@ private: void saveSelectionChanged(QListWidgetItem *newItem); void fixMods(SaveGameInfo::MissingAssets const &missingAssets); void refreshSavesIfOpen(); + void openInExplorer(); }; #endif // MODORGANIZER_SAVESTAB_INCLUDED -- cgit v1.3.1