|
@@ -847,6 +847,9 @@ void GMainWindow::ConnectWidgetEvents() {
|
|
|
connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder);
|
|
connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder);
|
|
|
connect(game_list, &GameList::OpenTransferableShaderCacheRequested, this,
|
|
connect(game_list, &GameList::OpenTransferableShaderCacheRequested, this,
|
|
|
&GMainWindow::OnTransferableShaderCacheOpenFile);
|
|
&GMainWindow::OnTransferableShaderCacheOpenFile);
|
|
|
|
|
+ connect(game_list, &GameList::RemoveInstalledEntryRequested, this,
|
|
|
|
|
+ &GMainWindow::OnGameListRemoveInstalledEntry);
|
|
|
|
|
+ connect(game_list, &GameList::RemoveFileRequested, this, &GMainWindow::OnGameListRemoveFile);
|
|
|
connect(game_list, &GameList::DumpRomFSRequested, this, &GMainWindow::OnGameListDumpRomFS);
|
|
connect(game_list, &GameList::DumpRomFSRequested, this, &GMainWindow::OnGameListDumpRomFS);
|
|
|
connect(game_list, &GameList::CopyTIDRequested, this, &GMainWindow::OnGameListCopyTID);
|
|
connect(game_list, &GameList::CopyTIDRequested, this, &GMainWindow::OnGameListCopyTID);
|
|
|
connect(game_list, &GameList::NavigateToGamedbEntryRequested, this,
|
|
connect(game_list, &GameList::NavigateToGamedbEntryRequested, this,
|
|
@@ -1257,7 +1260,6 @@ void GMainWindow::OnGameListOpenFolder(GameListOpenTarget target, const std::str
|
|
|
case GameListOpenTarget::SaveData: {
|
|
case GameListOpenTarget::SaveData: {
|
|
|
open_target = tr("Save Data");
|
|
open_target = tr("Save Data");
|
|
|
const std::string nand_dir = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir);
|
|
const std::string nand_dir = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir);
|
|
|
- ASSERT(program_id != 0);
|
|
|
|
|
|
|
|
|
|
if (has_user_save) {
|
|
if (has_user_save) {
|
|
|
// User save data
|
|
// User save data
|
|
@@ -1322,14 +1324,12 @@ void GMainWindow::OnGameListOpenFolder(GameListOpenTarget target, const std::str
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) {
|
|
void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) {
|
|
|
- ASSERT(program_id != 0);
|
|
|
|
|
-
|
|
|
|
|
const QString shader_dir =
|
|
const QString shader_dir =
|
|
|
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir));
|
|
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir));
|
|
|
- const QString tranferable_shader_cache_folder_path =
|
|
|
|
|
|
|
+ const QString transferable_shader_cache_folder_path =
|
|
|
shader_dir + QStringLiteral("opengl") + QDir::separator() + QStringLiteral("transferable");
|
|
shader_dir + QStringLiteral("opengl") + QDir::separator() + QStringLiteral("transferable");
|
|
|
const QString transferable_shader_cache_file_path =
|
|
const QString transferable_shader_cache_file_path =
|
|
|
- tranferable_shader_cache_folder_path + QDir::separator() +
|
|
|
|
|
|
|
+ transferable_shader_cache_folder_path + QDir::separator() +
|
|
|
QString::fromStdString(fmt::format("{:016X}.bin", program_id));
|
|
QString::fromStdString(fmt::format("{:016X}.bin", program_id));
|
|
|
|
|
|
|
|
if (!QFile::exists(transferable_shader_cache_file_path)) {
|
|
if (!QFile::exists(transferable_shader_cache_file_path)) {
|
|
@@ -1350,7 +1350,7 @@ void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) {
|
|
|
param << QDir::toNativeSeparators(transferable_shader_cache_file_path);
|
|
param << QDir::toNativeSeparators(transferable_shader_cache_file_path);
|
|
|
QProcess::startDetached(explorer, param);
|
|
QProcess::startDetached(explorer, param);
|
|
|
#else
|
|
#else
|
|
|
- QDesktopServices::openUrl(QUrl::fromLocalFile(tranferable_shader_cache_folder_path));
|
|
|
|
|
|
|
+ QDesktopServices::openUrl(QUrl::fromLocalFile(transferable_shader_cache_folder_path));
|
|
|
#endif
|
|
#endif
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -1394,6 +1394,174 @@ static bool RomFSRawCopy(QProgressDialog& dialog, const FileSys::VirtualDir& src
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryType type) {
|
|
|
|
|
+ const QString entry_type = [this, type] {
|
|
|
|
|
+ switch (type) {
|
|
|
|
|
+ case InstalledEntryType::Game:
|
|
|
|
|
+ return tr("Contents");
|
|
|
|
|
+ case InstalledEntryType::Update:
|
|
|
|
|
+ return tr("Update");
|
|
|
|
|
+ case InstalledEntryType::AddOnContent:
|
|
|
|
|
+ return tr("DLC");
|
|
|
|
|
+ default:
|
|
|
|
|
+ return QString{};
|
|
|
|
|
+ }
|
|
|
|
|
+ }();
|
|
|
|
|
+
|
|
|
|
|
+ if (QMessageBox::question(
|
|
|
|
|
+ this, tr("Remove Entry"), tr("Remove Installed Game %1?").arg(entry_type),
|
|
|
|
|
+ QMessageBox::Yes | QMessageBox::No, QMessageBox::No) != QMessageBox::Yes) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ switch (type) {
|
|
|
|
|
+ case InstalledEntryType::Game:
|
|
|
|
|
+ RemoveBaseContent(program_id, entry_type);
|
|
|
|
|
+ [[fallthrough]];
|
|
|
|
|
+ case InstalledEntryType::Update:
|
|
|
|
|
+ RemoveUpdateContent(program_id, entry_type);
|
|
|
|
|
+ if (type != InstalledEntryType::Game) {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ [[fallthrough]];
|
|
|
|
|
+ case InstalledEntryType::AddOnContent:
|
|
|
|
|
+ RemoveAddOnContent(program_id, entry_type);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + DIR_SEP +
|
|
|
|
|
+ "game_list");
|
|
|
|
|
+ game_list->PopulateAsync(UISettings::values.game_dirs);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void GMainWindow::RemoveBaseContent(u64 program_id, const QString& entry_type) {
|
|
|
|
|
+ const auto& fs_controller = Core::System::GetInstance().GetFileSystemController();
|
|
|
|
|
+ const auto res = fs_controller.GetUserNANDContents()->RemoveExistingEntry(program_id) ||
|
|
|
|
|
+ fs_controller.GetSDMCContents()->RemoveExistingEntry(program_id);
|
|
|
|
|
+
|
|
|
|
|
+ if (res) {
|
|
|
|
|
+ QMessageBox::information(this, tr("Successfully Removed"),
|
|
|
|
|
+ tr("Successfully removed the installed base game."));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ QMessageBox::warning(
|
|
|
|
|
+ this, tr("Error Removing %1").arg(entry_type),
|
|
|
|
|
+ tr("The base game is not installed in the NAND and cannot be removed."));
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void GMainWindow::RemoveUpdateContent(u64 program_id, const QString& entry_type) {
|
|
|
|
|
+ const auto update_id = program_id | 0x800;
|
|
|
|
|
+ const auto& fs_controller = Core::System::GetInstance().GetFileSystemController();
|
|
|
|
|
+ const auto res = fs_controller.GetUserNANDContents()->RemoveExistingEntry(update_id) ||
|
|
|
|
|
+ fs_controller.GetSDMCContents()->RemoveExistingEntry(update_id);
|
|
|
|
|
+
|
|
|
|
|
+ if (res) {
|
|
|
|
|
+ QMessageBox::information(this, tr("Successfully Removed"),
|
|
|
|
|
+ tr("Successfully removed the installed update."));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ QMessageBox::warning(this, tr("Error Removing %1").arg(entry_type),
|
|
|
|
|
+ tr("There is no update installed for this title."));
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void GMainWindow::RemoveAddOnContent(u64 program_id, const QString& entry_type) {
|
|
|
|
|
+ u32 count{};
|
|
|
|
|
+ const auto& fs_controller = Core::System::GetInstance().GetFileSystemController();
|
|
|
|
|
+ const auto dlc_entries = Core::System::GetInstance().GetContentProvider().ListEntriesFilter(
|
|
|
|
|
+ FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
|
|
|
|
|
+
|
|
|
|
|
+ for (const auto& entry : dlc_entries) {
|
|
|
|
|
+ if ((entry.title_id & DLC_BASE_TITLE_ID_MASK) == program_id) {
|
|
|
|
|
+ const auto res =
|
|
|
|
|
+ fs_controller.GetUserNANDContents()->RemoveExistingEntry(entry.title_id) ||
|
|
|
|
|
+ fs_controller.GetSDMCContents()->RemoveExistingEntry(entry.title_id);
|
|
|
|
|
+ if (res) {
|
|
|
|
|
+ ++count;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (count == 0) {
|
|
|
|
|
+ QMessageBox::warning(this, tr("Error Removing %1").arg(entry_type),
|
|
|
|
|
+ tr("There are no DLC installed for this title."));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ QMessageBox::information(this, tr("Successfully Removed"),
|
|
|
|
|
+ tr("Successfully removed %1 installed DLC.").arg(count));
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target) {
|
|
|
|
|
+ const QString question = [this, target] {
|
|
|
|
|
+ switch (target) {
|
|
|
|
|
+ case GameListRemoveTarget::ShaderCache:
|
|
|
|
|
+ return tr("Delete Transferable Shader Cache?");
|
|
|
|
|
+ case GameListRemoveTarget::CustomConfiguration:
|
|
|
|
|
+ return tr("Remove Custom Game Configuration?");
|
|
|
|
|
+ default:
|
|
|
|
|
+ return QString{};
|
|
|
|
|
+ }
|
|
|
|
|
+ }();
|
|
|
|
|
+
|
|
|
|
|
+ if (QMessageBox::question(this, tr("Remove File"), question, QMessageBox::Yes | QMessageBox::No,
|
|
|
|
|
+ QMessageBox::No) != QMessageBox::Yes) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ switch (target) {
|
|
|
|
|
+ case GameListRemoveTarget::ShaderCache:
|
|
|
|
|
+ RemoveTransferableShaderCache(program_id);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case GameListRemoveTarget::CustomConfiguration:
|
|
|
|
|
+ RemoveCustomConfiguration(program_id);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void GMainWindow::RemoveTransferableShaderCache(u64 program_id) {
|
|
|
|
|
+ const QString shader_dir =
|
|
|
|
|
+ QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir));
|
|
|
|
|
+ const QString transferable_shader_cache_folder_path =
|
|
|
|
|
+ shader_dir + QStringLiteral("opengl") + QDir::separator() + QStringLiteral("transferable");
|
|
|
|
|
+ const QString transferable_shader_cache_file_path =
|
|
|
|
|
+ transferable_shader_cache_folder_path + QDir::separator() +
|
|
|
|
|
+ QString::fromStdString(fmt::format("{:016X}.bin", program_id));
|
|
|
|
|
+
|
|
|
|
|
+ if (!QFile::exists(transferable_shader_cache_file_path)) {
|
|
|
|
|
+ QMessageBox::warning(this, tr("Error Removing Transferable Shader Cache"),
|
|
|
|
|
+ tr("A shader cache for this title does not exist."));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (QFile::remove(transferable_shader_cache_file_path)) {
|
|
|
|
|
+ QMessageBox::information(this, tr("Successfully Removed"),
|
|
|
|
|
+ tr("Successfully removed the transferable shader cache."));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ QMessageBox::warning(this, tr("Error Removing Transferable Shader Cache"),
|
|
|
|
|
+ tr("Failed to remove the transferable shader cache."));
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void GMainWindow::RemoveCustomConfiguration(u64 program_id) {
|
|
|
|
|
+ const QString config_dir =
|
|
|
|
|
+ QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir));
|
|
|
|
|
+ const QString custom_config_file_path =
|
|
|
|
|
+ config_dir + QString::fromStdString(fmt::format("{:016X}.ini", program_id));
|
|
|
|
|
+
|
|
|
|
|
+ if (!QFile::exists(custom_config_file_path)) {
|
|
|
|
|
+ QMessageBox::warning(this, tr("Error Removing Custom Configuration"),
|
|
|
|
|
+ tr("A custom configuration for this title does not exist."));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (QFile::remove(custom_config_file_path)) {
|
|
|
|
|
+ QMessageBox::information(this, tr("Successfully Removed"),
|
|
|
|
|
+ tr("Successfully removed the custom game configuration."));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ QMessageBox::warning(this, tr("Error Removing Custom Configuration"),
|
|
|
|
|
+ tr("Failed to remove the custom game configuration."));
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path) {
|
|
void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path) {
|
|
|
const auto failed = [this] {
|
|
const auto failed = [this] {
|
|
|
QMessageBox::warning(this, tr("RomFS Extraction Failed!"),
|
|
QMessageBox::warning(this, tr("RomFS Extraction Failed!"),
|
|
@@ -1714,9 +1882,9 @@ void GMainWindow::OnMenuInstallToNAND() {
|
|
|
: tr("%n file(s) failed to install\n", "", failed_files.size()));
|
|
: tr("%n file(s) failed to install\n", "", failed_files.size()));
|
|
|
|
|
|
|
|
QMessageBox::information(this, tr("Install Results"), install_results);
|
|
QMessageBox::information(this, tr("Install Results"), install_results);
|
|
|
- game_list->PopulateAsync(UISettings::values.game_dirs);
|
|
|
|
|
FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + DIR_SEP +
|
|
FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + DIR_SEP +
|
|
|
"game_list");
|
|
"game_list");
|
|
|
|
|
+ game_list->PopulateAsync(UISettings::values.game_dirs);
|
|
|
ui.action_Install_File_NAND->setEnabled(true);
|
|
ui.action_Install_File_NAND->setEnabled(true);
|
|
|
}
|
|
}
|
|
|
|
|
|