From d416ecb32462bdeed99ebc9bdd221c47fe882bf0 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 3 Nov 2024 17:57:58 +1000 Subject: [PATCH] Qt: Add 'Clear Cheats' option to cheats page --- .../gamecheatsettingswidget.cpp | 47 +++++++++++++++++++ src/duckstation-qt/gamecheatsettingswidget.h | 1 + src/duckstation-qt/gamecheatsettingswidget.ui | 16 +++++++ src/duckstation-qt/gamesummarywidget.cpp | 3 +- src/duckstation-qt/settingswindow.cpp | 26 +++++++--- src/duckstation-qt/settingswindow.h | 7 ++- 6 files changed, 89 insertions(+), 11 deletions(-) diff --git a/src/duckstation-qt/gamecheatsettingswidget.cpp b/src/duckstation-qt/gamecheatsettingswidget.cpp index 0e8ed7010..136ca1f85 100644 --- a/src/duckstation-qt/gamecheatsettingswidget.cpp +++ b/src/duckstation-qt/gamecheatsettingswidget.cpp @@ -11,6 +11,7 @@ #include "core/cheats.h" #include "common/error.h" +#include "common/log.h" #include "common/string_util.h" #include "fmt/format.h" @@ -20,6 +21,8 @@ #include #include +LOG_CHANNEL(Cheats); + namespace { class CheatListOptionDelegate : public QStyledItemDelegate { @@ -195,6 +198,7 @@ GameCheatSettingsWidget::GameCheatSettingsWidget(SettingsWindow* dialog, QWidget connect(m_ui.reloadCheats, &QToolButton::clicked, this, &GameCheatSettingsWidget::onReloadClicked); connect(m_ui.importCheats, &QPushButton::clicked, this, &GameCheatSettingsWidget::onImportClicked); connect(m_ui.exportCheats, &QPushButton::clicked, this, &GameCheatSettingsWidget::onExportClicked); + connect(m_ui.clearCheats, &QPushButton::clicked, this, &GameCheatSettingsWidget::onClearClicked); } GameCheatSettingsWidget::~GameCheatSettingsWidget() = default; @@ -578,6 +582,49 @@ void GameCheatSettingsWidget::onExportClicked() } } +void GameCheatSettingsWidget::onClearClicked() +{ + if (QMessageBox::question(this, tr("Confirm Removal"), + tr("You are removing all cheats manually added for this game. This action cannot be " + "reversed.\n\nAny database cheats will still be loaded and present unless you uncheck " + "the \"Load Database Cheats\" option.\n\nAre you sure you want to continue?")) != + QMessageBox::Yes) + { + return; + } + + disableAllCheats(); + + Error error; + std::string path = Cheats::GetChtFilename(m_dialog->getGameSerial(), std::nullopt, true); + if (FileSystem::FileExists(path.c_str())) + { + if (!FileSystem::DeleteFile(path.c_str(), &error)) + ERROR_LOG("Failed to remove cht file '{}': {}", Path::GetFileName(path), error.GetDescription()); + } + + // check for a non-hashed path and remove that too + path = Cheats::GetChtFilename(m_dialog->getGameSerial(), m_dialog->getGameHash(), true); + if (FileSystem::FileExists(path.c_str())) + { + if (!FileSystem::DeleteFile(path.c_str(), &error)) + ERROR_LOG("Failed to remove cht file '{}': {}", Path::GetFileName(path), error.GetDescription()); + } + + // and a legacy cht file with the game title + if (const std::string& title = m_dialog->getGameTitle(); !title.empty()) + { + path = Path::Combine(EmuFolders::Cheats, Path::SanitizeFileName(title)); + if (FileSystem::FileExists(path.c_str())) + { + if (!FileSystem::DeleteFile(path.c_str(), &error)) + ERROR_LOG("Failed to remove cht file '{}': {}", Path::GetFileName(path), error.GetDescription()); + } + } + + reloadList(); +} + QTreeWidgetItem* GameCheatSettingsWidget::getTreeWidgetParent(const std::string_view parent) { if (parent.empty()) diff --git a/src/duckstation-qt/gamecheatsettingswidget.h b/src/duckstation-qt/gamecheatsettingswidget.h index 83834fdd8..81964e7df 100644 --- a/src/duckstation-qt/gamecheatsettingswidget.h +++ b/src/duckstation-qt/gamecheatsettingswidget.h @@ -55,6 +55,7 @@ private Q_SLOTS: void onImportFromFileTriggered(); void onImportFromTextTriggered(); void onExportClicked(); + void onClearClicked(); void reloadList(); private: diff --git a/src/duckstation-qt/gamecheatsettingswidget.ui b/src/duckstation-qt/gamecheatsettingswidget.ui index 33fed1365..cef9c3f83 100644 --- a/src/duckstation-qt/gamecheatsettingswidget.ui +++ b/src/duckstation-qt/gamecheatsettingswidget.ui @@ -146,6 +146,22 @@ + + + + + 0 + 0 + + + + Clear List + + + + + + diff --git a/src/duckstation-qt/gamesummarywidget.cpp b/src/duckstation-qt/gamesummarywidget.cpp index 0f55ffdab..e4c216dbf 100644 --- a/src/duckstation-qt/gamesummarywidget.cpp +++ b/src/duckstation-qt/gamesummarywidget.cpp @@ -218,8 +218,7 @@ void GameSummaryWidget::populateCustomAttributes() void GameSummaryWidget::updateWindowTitle() { - const QString window_title = tr("%1 [%2]").arg(m_ui.title->text()).arg(m_ui.serial->text()); - m_dialog->setWindowTitle(window_title); + m_dialog->setGameTitle(m_ui.title->text().toStdString()); } void GameSummaryWidget::setCustomTitle(const std::string& text) diff --git a/src/duckstation-qt/settingswindow.cpp b/src/duckstation-qt/settingswindow.cpp index 86962ba38..4d9726950 100644 --- a/src/duckstation-qt/settingswindow.cpp +++ b/src/duckstation-qt/settingswindow.cpp @@ -48,14 +48,17 @@ SettingsWindow::SettingsWindow() : QWidget() connectUi(); } -SettingsWindow::SettingsWindow(const std::string& path, std::string serial, GameHash hash, DiscRegion region, - const GameDatabase::Entry* entry, std::unique_ptr sif) - : QWidget(), m_sif(std::move(sif)), m_database_entry(entry), m_serial(serial), m_hash(hash) +SettingsWindow::SettingsWindow(const std::string& path, std::string title, std::string serial, GameHash hash, + DiscRegion region, const GameDatabase::Entry* entry, + std::unique_ptr sif) + : QWidget(), m_sif(std::move(sif)), m_database_entry(entry), m_title(std::move(title)), m_serial(std::move(serial)), + m_hash(hash) { m_ui.setupUi(this); + setGameTitle(std::move(title)); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - addWidget(m_game_summary = new GameSummaryWidget(path, serial, region, entry, this, m_ui.settingsContainer), + addWidget(m_game_summary = new GameSummaryWidget(path, m_serial, region, entry, this, m_ui.settingsContainer), tr("Summary"), QStringLiteral("file-list-line"), tr("Summary
This page shows information about the selected game, and allows you to " "validate your disc was dumped correctly.")); @@ -655,14 +658,22 @@ void SettingsWindow::saveAndReloadGameSettings() g_emu_thread->reloadGameSettings(false); } +void SettingsWindow::setGameTitle(std::string title) +{ + m_title = std::move(title); + + const QString window_title = tr("%1 [%2]").arg(QString::fromStdString(m_title)).arg(QString::fromStdString(m_serial)); + setWindowTitle(window_title); +} + bool SettingsWindow::hasGameTrait(GameDatabase::Trait trait) { return (m_database_entry && m_database_entry->HasTrait(trait) && m_sif->GetBoolValue("Main", "ApplyCompatibilitySettings", true)); } -SettingsWindow* SettingsWindow::openGamePropertiesDialog(const std::string& path, const std::string& title, - std::string serial, GameHash hash, DiscRegion region, +SettingsWindow* SettingsWindow::openGamePropertiesDialog(const std::string& path, std::string title, std::string serial, + GameHash hash, DiscRegion region, const char* category /* = nullptr */) { const GameDatabase::Entry* dentry = nullptr; @@ -706,7 +717,8 @@ SettingsWindow* SettingsWindow::openGamePropertiesDialog(const std::string& path if (FileSystem::FileExists(sif->GetFileName().c_str())) sif->Load(); - SettingsWindow* dialog = new SettingsWindow(path, std::move(real_serial), hash, region, dentry, std::move(sif)); + SettingsWindow* dialog = + new SettingsWindow(path, std::move(title), std::move(real_serial), hash, region, dentry, std::move(sif)); dialog->show(); if (category) dialog->setCategory(category); diff --git a/src/duckstation-qt/settingswindow.h b/src/duckstation-qt/settingswindow.h index 5cbeb3f71..ae0d90982 100644 --- a/src/duckstation-qt/settingswindow.h +++ b/src/duckstation-qt/settingswindow.h @@ -45,11 +45,11 @@ class SettingsWindow final : public QWidget public: SettingsWindow(); - SettingsWindow(const std::string& path, std::string serial, GameHash hash, DiscRegion region, + SettingsWindow(const std::string& path, std::string title, std::string serial, GameHash hash, DiscRegion region, const GameDatabase::Entry* entry, std::unique_ptr sif); ~SettingsWindow(); - static SettingsWindow* openGamePropertiesDialog(const std::string& path, const std::string& title, std::string serial, + static SettingsWindow* openGamePropertiesDialog(const std::string& path, std::string title, std::string serial, GameHash hash, DiscRegion region, const char* category = nullptr); static void closeGamePropertiesDialogs(); @@ -60,6 +60,7 @@ public: ALWAYS_INLINE bool isPerGameSettings() const { return static_cast(m_sif); } ALWAYS_INLINE INISettingsInterface* getSettingsInterface() const { return m_sif.get(); } + ALWAYS_INLINE const std::string& getGameTitle() const { return m_title; } ALWAYS_INLINE const std::string& getGameSerial() const { return m_serial; } ALWAYS_INLINE const std::optional& getGameHash() const { return m_hash; } @@ -100,6 +101,7 @@ public: void removeSettingValue(const char* section, const char* key); void saveAndReloadGameSettings(); + void setGameTitle(std::string title); bool hasGameTrait(GameDatabase::Trait trait); Q_SIGNALS: @@ -158,6 +160,7 @@ private: QObject* m_current_help_widget = nullptr; QMap m_widget_help_text_map; + std::string m_title; std::string m_serial; std::optional m_hash; };