summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Merry2016-12-16 15:08:04 +0000
committerGravatar GitHub2016-12-16 15:08:04 +0000
commitacc83a1c32ef43c6ff84926ff21dc5ef872decc0 (patch)
tree95c20b3525c9e3a92444d45d3b5e071cea4e7dd7 /src
parentMerge pull request #2338 from wwylele/fix-dead (diff)
parentmain: Open folder when open save folder location context menu is clicked (diff)
downloadyuzu-acc83a1c32ef43c6ff84926ff21dc5ef872decc0.tar.gz
yuzu-acc83a1c32ef43c6ff84926ff21dc5ef872decc0.tar.xz
yuzu-acc83a1c32ef43c6ff84926ff21dc5ef872decc0.zip
Merge pull request #2322 from MerryMage/ctx-mnu
game_list: Add a context menu with "Open Save Location" option
Diffstat (limited to 'src')
-rw-r--r--src/citra_qt/game_list.cpp28
-rw-r--r--src/citra_qt/game_list.h3
-rw-r--r--src/citra_qt/game_list_p.h5
-rw-r--r--src/citra_qt/main.cpp19
-rw-r--r--src/citra_qt/main.h1
-rw-r--r--src/core/file_sys/archive_source_sd_savedata.cpp5
-rw-r--r--src/core/file_sys/archive_source_sd_savedata.h2
-rw-r--r--src/core/loader/loader.h9
-rw-r--r--src/core/loader/ncch.cpp12
-rw-r--r--src/core/loader/ncch.h7
10 files changed, 87 insertions, 4 deletions
diff --git a/src/citra_qt/game_list.cpp b/src/citra_qt/game_list.cpp
index e536628dd..09469f3c5 100644
--- a/src/citra_qt/game_list.cpp
+++ b/src/citra_qt/game_list.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <QHeaderView> 5#include <QHeaderView>
6#include <QMenu>
6#include <QThreadPool> 7#include <QThreadPool>
7#include <QVBoxLayout> 8#include <QVBoxLayout>
8#include "common/common_paths.h" 9#include "common/common_paths.h"
@@ -28,6 +29,7 @@ GameList::GameList(QWidget* parent) : QWidget{parent} {
28 tree_view->setSortingEnabled(true); 29 tree_view->setSortingEnabled(true);
29 tree_view->setEditTriggers(QHeaderView::NoEditTriggers); 30 tree_view->setEditTriggers(QHeaderView::NoEditTriggers);
30 tree_view->setUniformRowHeights(true); 31 tree_view->setUniformRowHeights(true);
32 tree_view->setContextMenuPolicy(Qt::CustomContextMenu);
31 33
32 item_model->insertColumns(0, COLUMN_COUNT); 34 item_model->insertColumns(0, COLUMN_COUNT);
33 item_model->setHeaderData(COLUMN_NAME, Qt::Horizontal, "Name"); 35 item_model->setHeaderData(COLUMN_NAME, Qt::Horizontal, "Name");
@@ -35,10 +37,10 @@ GameList::GameList(QWidget* parent) : QWidget{parent} {
35 item_model->setHeaderData(COLUMN_SIZE, Qt::Horizontal, "Size"); 37 item_model->setHeaderData(COLUMN_SIZE, Qt::Horizontal, "Size");
36 38
37 connect(tree_view, &QTreeView::activated, this, &GameList::ValidateEntry); 39 connect(tree_view, &QTreeView::activated, this, &GameList::ValidateEntry);
40 connect(tree_view, &QTreeView::customContextMenuRequested, this, &GameList::PopupContextMenu);
38 41
39 // We must register all custom types with the Qt Automoc system so that we are able to use it 42 // We must register all custom types with the Qt Automoc system so that we are able to use it
40 // with 43 // with signals/slots. In this case, QList falls under the umbrells of custom types.
41 // signals/slots. In this case, QList falls under the umbrells of custom types.
42 qRegisterMetaType<QList<QStandardItem*>>("QList<QStandardItem*>"); 44 qRegisterMetaType<QList<QStandardItem*>>("QList<QStandardItem*>");
43 45
44 layout->addWidget(tree_view); 46 layout->addWidget(tree_view);
@@ -71,6 +73,23 @@ void GameList::DonePopulating() {
71 tree_view->setEnabled(true); 73 tree_view->setEnabled(true);
72} 74}
73 75
76void GameList::PopupContextMenu(const QPoint& menu_location) {
77 QModelIndex item = tree_view->indexAt(menu_location);
78 if (!item.isValid())
79 return;
80
81 int row = item_model->itemFromIndex(item)->row();
82 QStandardItem* child_file = item_model->invisibleRootItem()->child(row, COLUMN_NAME);
83 u64 program_id = child_file->data(GameListItemPath::ProgramIdRole).toULongLong();
84
85 QMenu context_menu;
86 QAction* open_save_location = context_menu.addAction(tr("Open Save Data Location"));
87 open_save_location->setEnabled(program_id != 0);
88 connect(open_save_location, &QAction::triggered,
89 [&]() { emit OpenSaveFolderRequested(program_id); });
90 context_menu.exec(tree_view->viewport()->mapToGlobal(menu_location));
91}
92
74void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) { 93void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) {
75 if (!FileUtil::Exists(dir_path.toStdString()) || 94 if (!FileUtil::Exists(dir_path.toStdString()) ||
76 !FileUtil::IsDirectory(dir_path.toStdString())) { 95 !FileUtil::IsDirectory(dir_path.toStdString())) {
@@ -128,8 +147,11 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
128 std::vector<u8> smdh; 147 std::vector<u8> smdh;
129 loader->ReadIcon(smdh); 148 loader->ReadIcon(smdh);
130 149
150 u64 program_id = 0;
151 loader->ReadProgramId(program_id);
152
131 emit EntryReady({ 153 emit EntryReady({
132 new GameListItemPath(QString::fromStdString(physical_name), smdh), 154 new GameListItemPath(QString::fromStdString(physical_name), smdh, program_id),
133 new GameListItem( 155 new GameListItem(
134 QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))), 156 QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))),
135 new GameListItemSize(FileUtil::GetSize(physical_name)), 157 new GameListItemSize(FileUtil::GetSize(physical_name)),
diff --git a/src/citra_qt/game_list.h b/src/citra_qt/game_list.h
index 30b2c79a8..1abf10051 100644
--- a/src/citra_qt/game_list.h
+++ b/src/citra_qt/game_list.h
@@ -36,12 +36,15 @@ public:
36signals: 36signals:
37 void GameChosen(QString game_path); 37 void GameChosen(QString game_path);
38 void ShouldCancelWorker(); 38 void ShouldCancelWorker();
39 void OpenSaveFolderRequested(u64 program_id);
39 40
40private: 41private:
41 void AddEntry(const QList<QStandardItem*>& entry_items); 42 void AddEntry(const QList<QStandardItem*>& entry_items);
42 void ValidateEntry(const QModelIndex& item); 43 void ValidateEntry(const QModelIndex& item);
43 void DonePopulating(); 44 void DonePopulating();
44 45
46 void PopupContextMenu(const QPoint& menu_location);
47
45 QTreeView* tree_view = nullptr; 48 QTreeView* tree_view = nullptr;
46 QStandardItemModel* item_model = nullptr; 49 QStandardItemModel* item_model = nullptr;
47 GameListWorker* current_worker = nullptr; 50 GameListWorker* current_worker = nullptr;
diff --git a/src/citra_qt/game_list_p.h b/src/citra_qt/game_list_p.h
index 5ca3fe991..a15f06c5f 100644
--- a/src/citra_qt/game_list_p.h
+++ b/src/citra_qt/game_list_p.h
@@ -71,10 +71,13 @@ class GameListItemPath : public GameListItem {
71public: 71public:
72 static const int FullPathRole = Qt::UserRole + 1; 72 static const int FullPathRole = Qt::UserRole + 1;
73 static const int TitleRole = Qt::UserRole + 2; 73 static const int TitleRole = Qt::UserRole + 2;
74 static const int ProgramIdRole = Qt::UserRole + 3;
74 75
75 GameListItemPath() : GameListItem() {} 76 GameListItemPath() : GameListItem() {}
76 GameListItemPath(const QString& game_path, const std::vector<u8>& smdh_data) : GameListItem() { 77 GameListItemPath(const QString& game_path, const std::vector<u8>& smdh_data, u64 program_id)
78 : GameListItem() {
77 setData(game_path, FullPathRole); 79 setData(game_path, FullPathRole);
80 setData(qulonglong(program_id), ProgramIdRole);
78 81
79 if (!Loader::IsValidSMDH(smdh_data)) { 82 if (!Loader::IsValidSMDH(smdh_data)) {
80 // SMDH is not valid, set a default icon 83 // SMDH is not valid, set a default icon
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index a3887f9ab..ad6221739 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cinttypes>
5#include <clocale> 6#include <clocale>
6#include <memory> 7#include <memory>
7#include <thread> 8#include <thread>
@@ -41,6 +42,7 @@
41#include "common/string_util.h" 42#include "common/string_util.h"
42#include "core/arm/disassembler/load_symbol_map.h" 43#include "core/arm/disassembler/load_symbol_map.h"
43#include "core/core.h" 44#include "core/core.h"
45#include "core/file_sys/archive_source_sd_savedata.h"
44#include "core/gdbstub/gdbstub.h" 46#include "core/gdbstub/gdbstub.h"
45#include "core/loader/loader.h" 47#include "core/loader/loader.h"
46#include "core/settings.h" 48#include "core/settings.h"
@@ -171,6 +173,8 @@ GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) {
171 // Setup connections 173 // Setup connections
172 connect(game_list, SIGNAL(GameChosen(QString)), this, SLOT(OnGameListLoadFile(QString)), 174 connect(game_list, SIGNAL(GameChosen(QString)), this, SLOT(OnGameListLoadFile(QString)),
173 Qt::DirectConnection); 175 Qt::DirectConnection);
176 connect(game_list, SIGNAL(OpenSaveFolderRequested(u64)), this,
177 SLOT(OnGameListOpenSaveFolder(u64)), Qt::DirectConnection);
174 connect(ui.action_Configure, SIGNAL(triggered()), this, SLOT(OnConfigure())); 178 connect(ui.action_Configure, SIGNAL(triggered()), this, SLOT(OnConfigure()));
175 connect(ui.action_Load_File, SIGNAL(triggered()), this, SLOT(OnMenuLoadFile()), 179 connect(ui.action_Load_File, SIGNAL(triggered()), this, SLOT(OnMenuLoadFile()),
176 Qt::DirectConnection); 180 Qt::DirectConnection);
@@ -460,6 +464,21 @@ void GMainWindow::OnGameListLoadFile(QString game_path) {
460 BootGame(game_path.toStdString()); 464 BootGame(game_path.toStdString());
461} 465}
462 466
467void GMainWindow::OnGameListOpenSaveFolder(u64 program_id) {
468 std::string sdmc_dir = FileUtil::GetUserPath(D_SDMC_IDX);
469 std::string path = FileSys::ArchiveSource_SDSaveData::GetSaveDataPathFor(sdmc_dir, program_id);
470 QString qpath = QString::fromStdString(path);
471
472 QDir dir(qpath);
473 if (!dir.exists()) {
474 QMessageBox::critical(this, tr("Error Opening Save Folder"), tr("Folder does not exist!"));
475 return;
476 }
477
478 LOG_INFO(Frontend, "Opening save data path for program_id=%" PRIu64, program_id);
479 QDesktopServices::openUrl(QUrl::fromLocalFile(qpath));
480}
481
463void GMainWindow::OnMenuLoadFile() { 482void GMainWindow::OnMenuLoadFile() {
464 QString filename = 483 QString filename =
465 QFileDialog::getOpenFileName(this, tr("Load File"), UISettings::values.roms_path, 484 QFileDialog::getOpenFileName(this, tr("Load File"), UISettings::values.roms_path,
diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h
index f87178227..035b68a35 100644
--- a/src/citra_qt/main.h
+++ b/src/citra_qt/main.h
@@ -105,6 +105,7 @@ private slots:
105 void OnStopGame(); 105 void OnStopGame();
106 /// Called whenever a user selects a game in the game list widget. 106 /// Called whenever a user selects a game in the game list widget.
107 void OnGameListLoadFile(QString game_path); 107 void OnGameListLoadFile(QString game_path);
108 void OnGameListOpenSaveFolder(u64 program_id);
108 void OnMenuLoadFile(); 109 void OnMenuLoadFile();
109 void OnMenuLoadSymbolMap(); 110 void OnMenuLoadSymbolMap();
110 /// Called whenever a user selects the "File->Select Game List Root" menu item 111 /// Called whenever a user selects the "File->Select Game List Root" menu item
diff --git a/src/core/file_sys/archive_source_sd_savedata.cpp b/src/core/file_sys/archive_source_sd_savedata.cpp
index 2d8a950a3..287322d3e 100644
--- a/src/core/file_sys/archive_source_sd_savedata.cpp
+++ b/src/core/file_sys/archive_source_sd_savedata.cpp
@@ -90,4 +90,9 @@ ResultVal<ArchiveFormatInfo> ArchiveSource_SDSaveData::GetFormatInfo(u64 program
90 return MakeResult<ArchiveFormatInfo>(info); 90 return MakeResult<ArchiveFormatInfo>(info);
91} 91}
92 92
93std::string ArchiveSource_SDSaveData::GetSaveDataPathFor(const std::string& mount_point,
94 u64 program_id) {
95 return GetSaveDataPath(GetSaveDataContainerPath(mount_point), program_id);
96}
97
93} // namespace FileSys 98} // namespace FileSys
diff --git a/src/core/file_sys/archive_source_sd_savedata.h b/src/core/file_sys/archive_source_sd_savedata.h
index b33126c31..b5fe43cc1 100644
--- a/src/core/file_sys/archive_source_sd_savedata.h
+++ b/src/core/file_sys/archive_source_sd_savedata.h
@@ -23,6 +23,8 @@ public:
23 ResultCode Format(u64 program_id, const FileSys::ArchiveFormatInfo& format_info); 23 ResultCode Format(u64 program_id, const FileSys::ArchiveFormatInfo& format_info);
24 ResultVal<ArchiveFormatInfo> GetFormatInfo(u64 program_id) const; 24 ResultVal<ArchiveFormatInfo> GetFormatInfo(u64 program_id) const;
25 25
26 static std::string GetSaveDataPathFor(const std::string& mount_point, u64 program_id);
27
26private: 28private:
27 std::string mount_point; 29 std::string mount_point;
28}; 30};
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 5e3d46638..a6c2a745f 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -144,6 +144,15 @@ public:
144 } 144 }
145 145
146 /** 146 /**
147 * Get the program id of the application
148 * @param out_program_id Reference to store program id into
149 * @return ResultStatus result of function
150 */
151 virtual ResultStatus ReadProgramId(u64& out_program_id) {
152 return ResultStatus::ErrorNotImplemented;
153 }
154
155 /**
147 * Get the RomFS of the application 156 * Get the RomFS of the application
148 * Since the RomFS can be huge, we return a file reference instead of copying to a buffer 157 * Since the RomFS can be huge, we return a file reference instead of copying to a buffer
149 * @param romfs_file The file containing the RomFS 158 * @param romfs_file The file containing the RomFS
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index d4be61e0e..6f2164428 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -344,6 +344,18 @@ ResultStatus AppLoader_NCCH::ReadLogo(std::vector<u8>& buffer) {
344 return LoadSectionExeFS("logo", buffer); 344 return LoadSectionExeFS("logo", buffer);
345} 345}
346 346
347ResultStatus AppLoader_NCCH::ReadProgramId(u64& out_program_id) {
348 if (!file.IsOpen())
349 return ResultStatus::Error;
350
351 ResultStatus result = LoadExeFS();
352 if (result != ResultStatus::Success)
353 return result;
354
355 out_program_id = ncch_header.program_id;
356 return ResultStatus::Success;
357}
358
347ResultStatus AppLoader_NCCH::ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, 359ResultStatus AppLoader_NCCH::ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset,
348 u64& size) { 360 u64& size) {
349 if (!file.IsOpen()) 361 if (!file.IsOpen())
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h
index bcf3ae6e3..6c93d46d8 100644
--- a/src/core/loader/ncch.h
+++ b/src/core/loader/ncch.h
@@ -220,6 +220,13 @@ public:
220 ResultStatus ReadLogo(std::vector<u8>& buffer) override; 220 ResultStatus ReadLogo(std::vector<u8>& buffer) override;
221 221
222 /** 222 /**
223 * Get the program id of the application
224 * @param out_program_id Reference to store program id into
225 * @return ResultStatus result of function
226 */
227 ResultStatus ReadProgramId(u64& out_program_id) override;
228
229 /**
223 * Get the RomFS of the application 230 * Get the RomFS of the application
224 * @param romfs_file Reference to buffer to store data 231 * @param romfs_file Reference to buffer to store data
225 * @param offset Offset in the file to the RomFS 232 * @param offset Offset in the file to the RomFS