aboutsummaryrefslogtreecommitdiff
path: root/src/qt_common/qt_content_util.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qt_common/qt_content_util.cpp')
-rw-r--r--src/qt_common/qt_content_util.cpp246
1 files changed, 218 insertions, 28 deletions
diff --git a/src/qt_common/qt_content_util.cpp b/src/qt_common/qt_content_util.cpp
index 2f659cf1b2..f0a6a3ad80 100644
--- a/src/qt_common/qt_content_util.cpp
+++ b/src/qt_common/qt_content_util.cpp
@@ -1,17 +1,22 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
-#include "qt_common/qt_game_util.h"
#include "qt_content_util.h"
#include "common/fs/fs.h"
#include "core/hle/service/acc/profile_manager.h"
#include "frontend_common/content_manager.h"
+#include "frontend_common/data_manager.h"
#include "frontend_common/firmware_manager.h"
#include "qt_common/qt_common.h"
+#include "qt_common/qt_compress.h"
+#include "qt_common/qt_game_util.h"
#include "qt_common/qt_progress_dialog.h"
#include "qt_frontend_util.h"
+#include <QFuture>
+#include <QtConcurrentRun>
#include <JlCompress.h>
+#include <qfuturewatcher.h>
namespace QtCommon::Content {
@@ -21,10 +26,10 @@ bool CheckGameFirmware(u64 program_id, QObject* parent)
&& !FirmwareManager::CheckFirmwarePresence(*system)) {
auto result = QtCommon::Frontend::ShowMessage(
QMessageBox::Warning,
- "Game Requires Firmware",
- "The game you are trying to launch requires firmware to boot or to get past the "
- "opening menu. Please <a href='https://yuzu-mirror.github.io/help/quickstart'>"
- "dump and install firmware</a>, or press \"OK\" to launch anyways.",
+ tr("Game Requires Firmware"),
+ tr("The game you are trying to launch requires firmware to boot or to get past the "
+ "opening menu. Please <a href='https://yuzu-mirror.github.io/help/quickstart'>"
+ "dump and install firmware</a>, or press \"OK\" to launch anyways."),
QMessageBox::Ok | QMessageBox::Cancel,
parent);
@@ -60,8 +65,8 @@ void InstallFirmware(const QString& location, bool recursive)
const auto ShowMessage = [&]() {
QtCommon::Frontend::ShowMessage(icon,
- failedTitle,
- GetFirmwareInstallResultString(result));
+ tr(failedTitle),
+ tr(GetFirmwareInstallResultString(result)));
};
LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString());
@@ -125,8 +130,8 @@ void InstallFirmware(const QString& location, bool recursive)
i++;
auto firmware_src_vfile = vfs->OpenFile(firmware_src_path.generic_string(),
FileSys::OpenMode::Read);
- auto firmware_dst_vfile = firmware_vdir
- ->CreateFileRelative(firmware_src_path.filename().string());
+ auto firmware_dst_vfile = firmware_vdir->CreateFileRelative(
+ firmware_src_path.filename().string());
if (!VfsRawCopy(firmware_src_vfile, firmware_dst_vfile)) {
LOG_ERROR(Frontend,
@@ -168,9 +173,9 @@ void InstallFirmware(const QString& location, bool recursive)
const auto failed_names = QString::fromStdString(
fmt::format("{}", fmt::join(results, "\n")));
progress.close();
- QtCommon::Frontend::Critical(tr("Firmware integrity verification failed!"),
- tr("Verification failed for the following files:\n\n%1")
- .arg(failed_names));
+ QtCommon::Frontend::Critical(
+ tr("Firmware integrity verification failed!"),
+ tr("Verification failed for the following files:\n\n%1").arg(failed_names));
return;
}
@@ -181,10 +186,10 @@ void InstallFirmware(const QString& location, bool recursive)
const std::string display_version(firmware_data.display_version.data());
result = FirmwareInstallResult::Success;
- QtCommon::Frontend::Information(rootObject,
- tr(successTitle),
- tr(GetFirmwareInstallResultString(result))
- .arg(QString::fromStdString(display_version)));
+ QtCommon::Frontend::Information(
+ rootObject,
+ tr(successTitle),
+ tr(GetFirmwareInstallResultString(result)).arg(QString::fromStdString(display_version)));
}
QString UnzipFirmwareToTmp(const QString& location)
@@ -193,7 +198,7 @@ QString UnzipFirmwareToTmp(const QString& location)
fs::path tmp{fs::temp_directory_path()};
if (!fs::create_directories(tmp / "eden" / "firmware")) {
- return "";
+ return QString();
}
tmp /= "eden";
@@ -205,7 +210,7 @@ QString UnzipFirmwareToTmp(const QString& location)
QStringList result = JlCompress::extractDir(&zip, qCacheDir);
if (result.isEmpty()) {
- return "";
+ return QString();
}
return qCacheDir;
@@ -264,9 +269,8 @@ void InstallKeys()
return;
}
- FirmwareManager::KeyInstallResult result = FirmwareManager::InstallKeys(key_source_location
- .toStdString(),
- "keys");
+ FirmwareManager::KeyInstallResult result
+ = FirmwareManager::InstallKeys(key_source_location.toStdString(), "keys");
system->GetFileSystemController().CreateFactories(*QtCommon::vfs);
@@ -282,9 +286,14 @@ void InstallKeys()
}
}
-void VerifyInstalledContents() {
+void VerifyInstalledContents()
+{
// Initialize a progress dialog.
- QtCommon::Frontend::QtProgressDialog progress(tr("Verifying integrity..."), tr("Cancel"), 0, 100, QtCommon::rootObject);
+ QtCommon::Frontend::QtProgressDialog progress(tr("Verifying integrity..."),
+ tr("Cancel"),
+ 0,
+ 100,
+ QtCommon::rootObject);
progress.setWindowModality(Qt::WindowModal);
progress.setMinimumDuration(100);
progress.setAutoClose(false);
@@ -296,16 +305,17 @@ void VerifyInstalledContents() {
return progress.wasCanceled();
};
- const std::vector<std::string> result =
- ContentManager::VerifyInstalledContents(*QtCommon::system, *QtCommon::provider, QtProgressCallback);
+ const std::vector<std::string> result
+ = ContentManager::VerifyInstalledContents(*QtCommon::system,
+ *QtCommon::provider,
+ QtProgressCallback);
progress.close();
if (result.empty()) {
QtCommon::Frontend::Information(tr("Integrity verification succeeded!"),
tr("The operation completed successfully."));
} else {
- const auto failed_names =
- QString::fromStdString(fmt::format("{}", fmt::join(result, "\n")));
+ const auto failed_names = QString::fromStdString(fmt::format("{}", fmt::join(result, "\n")));
QtCommon::Frontend::Critical(
tr("Integrity verification failed!"),
tr("Verification failed for the following files:\n\n%1").arg(failed_names));
@@ -332,7 +342,7 @@ void FixProfiles()
qorphaned.reserve(8 * 33);
for (const std::string& s : orphaned) {
- qorphaned += "\n" + QString::fromStdString(s);
+ qorphaned = qorphaned % QStringLiteral("\n") % QString::fromStdString(s);
}
QtCommon::Frontend::Critical(
@@ -348,4 +358,184 @@ void FixProfiles()
QtCommon::Game::OpenSaveFolder();
}
+void ClearDataDir(FrontendCommon::DataManager::DataDir dir, const std::string& user_id)
+{
+ auto result = QtCommon::Frontend::Warning(tr("Really clear data?"),
+ tr("Important data may be lost!"),
+ QMessageBox::Yes | QMessageBox::No);
+
+ if (result != QMessageBox::Yes)
+ return;
+
+ result = QtCommon::Frontend::Warning(
+ tr("Are you REALLY sure?"),
+ tr("Once deleted, your data will NOT come back!\n"
+ "Only do this if you're 100% sure you want to delete this data."),
+ QMessageBox::Yes | QMessageBox::No);
+
+ if (result != QMessageBox::Yes)
+ return;
+
+ QtCommon::Frontend::QtProgressDialog dialog(tr("Clearing..."), QString(), 0, 0);
+ dialog.show();
+
+ FrontendCommon::DataManager::ClearDir(dir, user_id);
+
+ dialog.close();
+}
+
+void ExportDataDir(FrontendCommon::DataManager::DataDir data_dir,
+ const std::string& user_id,
+ const QString& name,
+ std::function<void()> callback)
+{
+ using namespace QtCommon::Frontend;
+ const std::string dir = FrontendCommon::DataManager::GetDataDir(data_dir, user_id);
+
+ const QString zip_dump_location = GetSaveFileName(tr("Select Export Location"),
+ tr("%1.zip").arg(name),
+ tr("Zipped Archives (*.zip)"));
+
+ if (zip_dump_location.isEmpty())
+ return;
+
+ QtProgressDialog* progress = new QtProgressDialog(
+ tr("Exporting data. This may take a while..."), tr("Cancel"), 0, 100, rootObject);
+
+ progress->setWindowTitle(tr("Exporting"));
+ progress->setWindowModality(Qt::WindowModal);
+ progress->setMinimumDuration(100);
+ progress->setAutoClose(false);
+ progress->setAutoReset(false);
+ progress->show();
+
+ QGuiApplication::processEvents();
+
+ auto progress_callback = [=](size_t total_size, size_t processed_size) {
+ QMetaObject::invokeMethod(progress,
+ &QtProgressDialog::setValue,
+ static_cast<int>((processed_size * 100) / total_size));
+
+ return !progress->wasCanceled();
+ };
+
+ QFuture<bool> future = QtConcurrent::run([=]() {
+ return QtCommon::Compress::compressDir(zip_dump_location,
+ QString::fromStdString(dir),
+ JlCompress::Options(),
+ progress_callback);
+ });
+
+ QFutureWatcher<bool>* watcher = new QFutureWatcher<bool>(rootObject);
+
+ QObject::connect(watcher, &QFutureWatcher<bool>::finished, rootObject, [=]() {
+ progress->close();
+
+ if (watcher->result()) {
+ Information(tr("Exported Successfully"), tr("Data was exported successfully."));
+ } else if (progress->wasCanceled()) {
+ Information(tr("Export Cancelled"), tr("Export was cancelled by the user."));
+ } else {
+ Critical(
+ tr("Export Failed"),
+ tr("Ensure you have write permissions on the targeted directory and try again."));
+ }
+
+ progress->deleteLater();
+ watcher->deleteLater();
+ if (callback)
+ callback();
+ });
+
+ watcher->setFuture(future);
+}
+
+void ImportDataDir(FrontendCommon::DataManager::DataDir data_dir,
+ const std::string& user_id,
+ std::function<void()> callback)
+{
+ const std::string dir = FrontendCommon::DataManager::GetDataDir(data_dir, user_id);
+
+ using namespace QtCommon::Frontend;
+
+ const QString zip_dump_location = GetOpenFileName(tr("Select Import Location"),
+ {},
+ tr("Zipped Archives (*.zip)"));
+
+ if (zip_dump_location.isEmpty())
+ return;
+
+ StandardButton button = Warning(
+ tr("Import Warning"),
+ tr("All previous data in this directory will be deleted. Are you sure you wish to "
+ "proceed?"),
+ StandardButton::Yes | StandardButton::No);
+
+ if (button != QMessageBox::Yes)
+ return;
+
+ QtProgressDialog* progress = new QtProgressDialog(
+ tr("Importing data. This may take a while..."), tr("Cancel"), 0, 100, rootObject);
+
+ progress->setWindowTitle(tr("Importing"));
+ progress->setWindowModality(Qt::WindowModal);
+ progress->setMinimumDuration(100);
+ progress->setAutoClose(false);
+ progress->setAutoReset(false);
+ progress->show();
+ progress->setValue(0);
+
+ QGuiApplication::processEvents();
+
+ // to prevent GUI mangling we have to run this in a thread as well
+ QFuture<bool> delete_future = QtConcurrent::run([=]() {
+ FrontendCommon::DataManager::ClearDir(data_dir, user_id);
+ return !progress->wasCanceled();
+ });
+
+ QFutureWatcher<bool>* delete_watcher = new QFutureWatcher<bool>(rootObject);
+ delete_watcher->setFuture(delete_future);
+
+ QObject::connect(delete_watcher, &QFutureWatcher<bool>::finished, rootObject, [=]() {
+ auto progress_callback = [=](size_t total_size, size_t processed_size) {
+ QMetaObject::invokeMethod(progress,
+ &QtProgressDialog::setValue,
+ static_cast<int>((processed_size * 100) / total_size));
+
+ return !progress->wasCanceled();
+ };
+
+ QFuture<bool> future = QtConcurrent::run([=]() {
+ return !QtCommon::Compress::extractDir(zip_dump_location,
+ QString::fromStdString(dir),
+ progress_callback)
+ .empty();
+ });
+
+ QFutureWatcher<bool>* watcher = new QFutureWatcher<bool>(rootObject);
+
+ QObject::connect(watcher, &QFutureWatcher<bool>::finished, rootObject, [=]() {
+ progress->close();
+
+ // this sucks
+ if (watcher->result()) {
+ Information(tr("Imported Successfully"), tr("Data was imported successfully."));
+ } else if (progress->wasCanceled()) {
+ Information(tr("Import Cancelled"), tr("Import was cancelled by the user."));
+ } else {
+ Critical(tr("Import Failed"),
+ tr("Ensure you have read permissions on the targeted directory and try "
+ "again."));
+ }
+
+ progress->deleteLater();
+ watcher->deleteLater();
+ if (callback)
+ callback();
+ });
+
+ watcher->setFuture(future);
+ });
+}
+
} // namespace QtCommon::Content