diff --git a/src/citra_qt/game_list.cpp b/src/citra_qt/game_list.cpp index 1cb5ec2078..a979625df8 100644 --- a/src/citra_qt/game_list.cpp +++ b/src/citra_qt/game_list.cpp @@ -316,10 +316,24 @@ void GameList::PopupContextMenu(const QPoint& menu_location) { u64 program_id = child_file->data(GameListItemPath::ProgramIdRole).toULongLong(); QMenu context_menu; + QAction* open_save_location = context_menu.addAction(tr("Open Save Data Location")); + QAction* open_application_location = context_menu.addAction(tr("Open Application Location")); + QAction* open_update_location = context_menu.addAction(tr("Open Update Data Location")); + open_save_location->setEnabled(program_id != 0); + open_application_location->setVisible(FileUtil::Exists( + Service::AM::GetTitleContentPath(Service::FS::MediaType::SDMC, program_id))); + open_update_location->setEnabled(0x00040000'00000000 <= program_id && + program_id <= 0x00040000'FFFFFFFF); + connect(open_save_location, &QAction::triggered, - [&]() { emit OpenSaveFolderRequested(program_id); }); + [&]() { emit OpenFolderRequested(program_id, GameListOpenTarget::SAVE_DATA); }); + connect(open_application_location, &QAction::triggered, + [&]() { emit OpenFolderRequested(program_id, GameListOpenTarget::APPLICATION); }); + connect(open_update_location, &QAction::triggered, + [&]() { emit OpenFolderRequested(program_id, GameListOpenTarget::UPDATE_DATA); }); + context_menu.exec(tree_view->viewport()->mapToGlobal(menu_location)); } diff --git a/src/citra_qt/game_list.h b/src/citra_qt/game_list.h index 86ea869e95..2e671454b7 100644 --- a/src/citra_qt/game_list.h +++ b/src/citra_qt/game_list.h @@ -21,6 +21,8 @@ class QTreeView; class QToolButton; class QVBoxLayout; +enum class GameListOpenTarget { SAVE_DATA = 0, APPLICATION = 1, UPDATE_DATA = 2 }; + class GameList : public QWidget { Q_OBJECT @@ -76,7 +78,7 @@ public: signals: void GameChosen(QString game_path); void ShouldCancelWorker(); - void OpenSaveFolderRequested(u64 program_id); + void OpenFolderRequested(u64 program_id, GameListOpenTarget target); private slots: void onTextChanged(const QString& newText); @@ -99,3 +101,5 @@ private: GameListWorker* current_worker = nullptr; QFileSystemWatcher* watcher = nullptr; }; + +Q_DECLARE_METATYPE(GameListOpenTarget); diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index cb25502d7c..5d60e2f30e 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -46,6 +46,7 @@ #include "core/core.h" #include "core/file_sys/archive_source_sd_savedata.h" #include "core/gdbstub/gdbstub.h" +#include "core/hle/service/fs/archive.h" #include "core/loader/loader.h" #include "core/settings.h" @@ -359,8 +360,7 @@ void GMainWindow::RestoreUIState() { void GMainWindow::ConnectWidgetEvents() { connect(game_list, &GameList::GameChosen, this, &GMainWindow::OnGameListLoadFile); - connect(game_list, &GameList::OpenSaveFolderRequested, this, - &GMainWindow::OnGameListOpenSaveFolder); + connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder); connect(this, &GMainWindow::EmulationStarting, render_window, &GRenderWindow::OnEmulationStarting); @@ -699,18 +699,44 @@ void GMainWindow::OnGameListLoadFile(QString game_path) { BootGame(game_path); } -void GMainWindow::OnGameListOpenSaveFolder(u64 program_id) { - std::string sdmc_dir = FileUtil::GetUserPath(D_SDMC_IDX); - std::string path = FileSys::ArchiveSource_SDSaveData::GetSaveDataPathFor(sdmc_dir, program_id); +void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target) { + std::string path; + std::string open_target; + + switch (target) { + case GameListOpenTarget::SAVE_DATA: { + open_target = "Save Data"; + std::string sdmc_dir = FileUtil::GetUserPath(D_SDMC_IDX); + path = FileSys::ArchiveSource_SDSaveData::GetSaveDataPathFor(sdmc_dir, program_id); + break; + } + case GameListOpenTarget::APPLICATION: + open_target = "Application"; + path = Service::AM::GetTitlePath(Service::FS::MediaType::SDMC, program_id) + "content/"; + break; + case GameListOpenTarget::UPDATE_DATA: + open_target = "Update Data"; + path = Service::AM::GetTitlePath(Service::FS::MediaType::SDMC, program_id + 0xe00000000) + + "content/"; + break; + default: + LOG_ERROR(Frontend, "Unexpected target %d", target); + return; + } + QString qpath = QString::fromStdString(path); QDir dir(qpath); if (!dir.exists()) { - QMessageBox::critical(this, tr("Error Opening Save Folder"), tr("Folder does not exist!")); + QMessageBox::critical( + this, tr("Error Opening %1 Folder").arg(QString::fromStdString(open_target)), + tr("Folder does not exist!")); return; } - LOG_INFO(Frontend, "Opening save data path for program_id=%" PRIu64, program_id); + LOG_INFO(Frontend, "Opening %s path for program_id=%016" PRIx64, open_target.c_str(), + program_id); + QDesktopServices::openUrl(QUrl::fromLocalFile(qpath)); } diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h index fa36546d46..fc72cb1e1e 100644 --- a/src/citra_qt/main.h +++ b/src/citra_qt/main.h @@ -16,6 +16,7 @@ class AboutDialog; class Config; class EmuThread; class GameList; +enum class GameListOpenTarget; class GImageInfo; class GPUCommandListWidget; class GPUCommandStreamWidget; @@ -130,7 +131,7 @@ private slots: void OnMenuReportCompatibility(); /// Called whenever a user selects a game in the game list widget. void OnGameListLoadFile(QString game_path); - void OnGameListOpenSaveFolder(u64 program_id); + void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target); void OnMenuLoadFile(); void OnMenuInstallCIA(); void OnUpdateProgress(size_t written, size_t total);