From a5ad887771bbbe7b49cdad6ea0e79268bdc61279 Mon Sep 17 00:00:00 2001 From: PabloMK7 Date: Sun, 9 Mar 2025 17:40:22 +0100 Subject: [PATCH] Do data migration before QtConfig is constructed --- src/citra_qt/CMakeLists.txt | 2 + src/citra_qt/citra_qt.cpp | 118 +---------------------- src/citra_qt/citra_qt.h | 11 +-- src/citra_qt/user_data_migration.cpp | 138 +++++++++++++++++++++++++++ src/citra_qt/user_data_migration.h | 22 +++++ 5 files changed, 165 insertions(+), 126 deletions(-) create mode 100644 src/citra_qt/user_data_migration.cpp create mode 100644 src/citra_qt/user_data_migration.h diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 620b5c183..1f8c31360 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -176,6 +176,8 @@ add_library(citra_qt STATIC EXCLUDE_FROM_ALL precompiled_headers.h uisettings.cpp uisettings.h + user_data_migration.cpp + user_data_migration.h qt_image_interface.cpp qt_image_interface.h util/clickable_label.cpp diff --git a/src/citra_qt/citra_qt.cpp b/src/citra_qt/citra_qt.cpp index 0e8c791d4..487f38587 100644 --- a/src/citra_qt/citra_qt.cpp +++ b/src/citra_qt/citra_qt.cpp @@ -166,9 +166,7 @@ void GMainWindow::ShowCommandOutput(std::string title, std::string message) { GMainWindow::GMainWindow(Core::System& system_) : ui{std::make_unique()}, system{system_}, movie{system.Movie()}, - emu_user_dir_exists{ - std::filesystem::is_directory(FileUtil::GetUserPath(FileUtil::UserPath::UserDir))}, - config{std::make_unique()}, emu_thread{nullptr} { + user_data_migrator{this}, config{std::make_unique()}, emu_thread{nullptr} { Common::Log::Initialize(); Common::Log::Start(); @@ -308,11 +306,6 @@ GMainWindow::GMainWindow(Core::System& system_) } } - // Check if data migration from Citra/Lime3DS needs to be performed - if (!emu_user_dir_exists) { - ShowMigrationPrompt(); - } - #ifdef __unix__ SetGamemodeEnabled(Settings::values.enable_gamemode.GetValue()); #endif @@ -1119,115 +1112,6 @@ void GMainWindow::OnDisplayTitleBars(bool show) { } } -void GMainWindow::ShowMigrationCancelledMessage() { - QMessageBox::information( - this, tr("Migration"), - tr("You can manually re-trigger this prompt by deleting the " - "new user data directory:\n" - "%1") - .arg(QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::UserDir))), - QMessageBox::Ok); -} - -void GMainWindow::ShowMigrationPrompt() { - namespace fs = std::filesystem; - - const QString migration_prompt_message = - tr("Would you like to migrate your data for use in Azahar?\n" - "(This may take a while; The old data will not be deleted)"); - const bool citra_dir_found = - fs::is_directory(FileUtil::GetUserPath(FileUtil::UserPath::LegacyCitraUserDir)); - const bool lime3ds_dir_found = - fs::is_directory(FileUtil::GetUserPath(FileUtil::UserPath::LegacyLime3DSUserDir)); - - if (citra_dir_found && lime3ds_dir_found) { - QMessageBox migration_prompt; - migration_prompt.setWindowTitle(tr("Migration")); - migration_prompt.setText( - tr("Azahar has detected emulator data for Citra and Lime3DS.\n\n") + - migration_prompt_message); - migration_prompt.setIcon(QMessageBox::Information); - - const QAbstractButton* lime3dsButton = - migration_prompt.addButton(tr("Migrate from Lime3DS"), QMessageBox::YesRole); - const QAbstractButton* citraButton = - migration_prompt.addButton(tr("Migrate from Citra"), QMessageBox::YesRole); - migration_prompt.addButton(QMessageBox::No); - - migration_prompt.exec(); - - if (citraButton == migration_prompt.clickedButton()) { - MigrateUserData(LegacyEmu::Citra); - } - if (lime3dsButton == migration_prompt.clickedButton()) { - MigrateUserData(LegacyEmu::Lime3DS); - } - - return; - } - - else if (citra_dir_found) { - if (QMessageBox::information( - this, tr("Migration"), - tr("Azahar has detected emulator data for Citra.\n\n") + migration_prompt_message, - QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes) { - MigrateUserData(LegacyEmu::Citra); - return; - } - } - - else if (lime3ds_dir_found) { - if (QMessageBox::information( - this, tr("Migration"), - tr("Azahar has detected emulator data for Lime3DS.\n\n") + migration_prompt_message, - QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes) { - MigrateUserData(LegacyEmu::Lime3DS); - return; - } - } - - // If we're here, the user chose not to migrate - ShowMigrationCancelledMessage(); -} - -void GMainWindow::MigrateUserData(const LegacyEmu selected_legacy_emu) { - namespace fs = std::filesystem; - const auto copy_options = fs::copy_options::update_existing | fs::copy_options::recursive; - - std::string legacy_user_dir; - std::string legacy_config_dir; - std::string legacy_cache_dir; - if (LegacyEmu::Citra == selected_legacy_emu) { - legacy_user_dir = FileUtil::GetUserPath(FileUtil::UserPath::LegacyCitraUserDir); - legacy_config_dir = FileUtil::GetUserPath(FileUtil::UserPath::LegacyCitraConfigDir); - legacy_cache_dir = FileUtil::GetUserPath(FileUtil::UserPath::LegacyCitraCacheDir); - } else if (LegacyEmu::Lime3DS == selected_legacy_emu) { - legacy_user_dir = FileUtil::GetUserPath(FileUtil::UserPath::LegacyLime3DSUserDir); - legacy_config_dir = FileUtil::GetUserPath(FileUtil::UserPath::LegacyLime3DSConfigDir); - legacy_cache_dir = FileUtil::GetUserPath(FileUtil::UserPath::LegacyLime3DSCacheDir); - } - - fs::copy(legacy_user_dir, FileUtil::GetUserPath(FileUtil::UserPath::UserDir), copy_options); - - if (fs::is_directory(legacy_config_dir)) { - fs::copy(legacy_config_dir, FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir), - copy_options); - } - if (fs::is_directory(legacy_cache_dir)) { - fs::copy(legacy_cache_dir, FileUtil::GetUserPath(FileUtil::UserPath::CacheDir), - copy_options); - } - - QMessageBox::information( - this, tr("Migration"), - tr("Data was migrated successfully. Azahar will now restart.\n\n" - "If you wish to clean up the files which were left in the old " - "data location, you can do so by deleting the following directory:\n" - "%1") - .arg(QString::fromStdString(legacy_user_dir)), - QMessageBox::Ok); -} - #if defined(HAVE_SDL2) && defined(__unix__) && !defined(__APPLE__) static std::optional HoldWakeLockLinux(u32 window_id = 0) { if (!QDBusConnection::sessionBus().isConnected()) { diff --git a/src/citra_qt/citra_qt.h b/src/citra_qt/citra_qt.h index 325d75ccb..078d254b5 100644 --- a/src/citra_qt/citra_qt.h +++ b/src/citra_qt/citra_qt.h @@ -14,6 +14,7 @@ #include #include "citra_qt/compatibility_list.h" #include "citra_qt/hotkeys.h" +#include "citra_qt/user_data_migration.h" #include "core/core.h" #include "core/savestate.h" @@ -165,14 +166,6 @@ private: void SetDiscordEnabled(bool state); void LoadAmiibo(const QString& filename); - enum LegacyEmu { - Citra, - Lime3DS, - }; - void ShowMigrationCancelledMessage(); - void ShowMigrationPrompt(); - void MigrateUserData(const LegacyEmu selected_legacy_emu); - /** * Stores the filename in the recently loaded files list. * The new filename is stored at the beginning of the recently loaded files list. @@ -347,7 +340,7 @@ private: // Created before `config` to ensure that emu data directory // isn't created before the check is performed - bool emu_user_dir_exists; + UserDataMigrator user_data_migrator; std::unique_ptr config; // Whether emulation is currently running in Citra. diff --git a/src/citra_qt/user_data_migration.cpp b/src/citra_qt/user_data_migration.cpp new file mode 100644 index 000000000..c941162d1 --- /dev/null +++ b/src/citra_qt/user_data_migration.cpp @@ -0,0 +1,138 @@ +// Copyright Citra Emulator Project / Azahar Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include +#include +#include "common/file_util.h" +#include "user_data_migration.h" + +// Needs to be included at the end due to https://bugreports.qt.io/browse/QTBUG-73263 +#include + +namespace fs = std::filesystem; + +UserDataMigrator::UserDataMigrator(QMainWindow* main_window) { + // NOTE: Logging is not initialized yet, do not produce logs here. + + // Check migration if user directory does not exist + if (!fs::is_directory(FileUtil::GetUserPath(FileUtil::UserPath::UserDir))) { + ShowMigrationPrompt(main_window); + } +} + +void UserDataMigrator::ShowMigrationPrompt(QMainWindow* main_window) { + namespace fs = std::filesystem; + + const QString migration_prompt_message = + main_window->tr("Would you like to migrate your data for use in Azahar?\n" + "(This may take a while; The old data will not be deleted)"); + const bool citra_dir_found = + fs::is_directory(FileUtil::GetUserPath(FileUtil::UserPath::LegacyCitraUserDir)); + const bool lime3ds_dir_found = + fs::is_directory(FileUtil::GetUserPath(FileUtil::UserPath::LegacyLime3DSUserDir)); + + if (citra_dir_found && lime3ds_dir_found) { + QMessageBox migration_prompt; + migration_prompt.setWindowTitle(main_window->tr("Migration")); + migration_prompt.setText( + main_window->tr("Azahar has detected user data for Citra and Lime3DS.\n\n") + + migration_prompt_message); + migration_prompt.setIcon(QMessageBox::Information); + + const QAbstractButton* lime3dsButton = migration_prompt.addButton( + main_window->tr("Migrate from Lime3DS"), QMessageBox::YesRole); + const QAbstractButton* citraButton = + migration_prompt.addButton(main_window->tr("Migrate from Citra"), QMessageBox::YesRole); + migration_prompt.addButton(QMessageBox::No); + + migration_prompt.exec(); + + if (citraButton == migration_prompt.clickedButton()) { + MigrateUserData(main_window, LegacyEmu::Citra); + } + if (lime3dsButton == migration_prompt.clickedButton()) { + MigrateUserData(main_window, LegacyEmu::Lime3DS); + } + + return; + } + + else if (citra_dir_found) { + if (QMessageBox::information( + main_window, main_window->tr("Migration"), + main_window->tr("Azahar has detected user data for Citra.\n\n") + + migration_prompt_message, + QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes) { + MigrateUserData(main_window, LegacyEmu::Citra); + return; + } + } + + else if (lime3ds_dir_found) { + if (QMessageBox::information( + main_window, main_window->tr("Migration"), + main_window->tr("Azahar has detected user data for Lime3DS.\n\n") + + migration_prompt_message, + QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes) { + MigrateUserData(main_window, LegacyEmu::Lime3DS); + return; + } + } + + // If we're here, the user chose not to migrate + ShowMigrationCancelledMessage(main_window); +} + +void UserDataMigrator::ShowMigrationCancelledMessage(QMainWindow* main_window) { + QMessageBox::information( + main_window, main_window->tr("Migration"), + main_window + ->tr("You can manually re-trigger this prompt by deleting the " + "new user data directory:\n" + "%1") + .arg(QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::UserDir))), + QMessageBox::Ok); +} + +void UserDataMigrator::MigrateUserData(QMainWindow* main_window, + const LegacyEmu selected_legacy_emu) { + namespace fs = std::filesystem; + const auto copy_options = fs::copy_options::update_existing | fs::copy_options::recursive; + + std::string legacy_user_dir; + std::string legacy_config_dir; + std::string legacy_cache_dir; + if (LegacyEmu::Citra == selected_legacy_emu) { + legacy_user_dir = FileUtil::GetUserPath(FileUtil::UserPath::LegacyCitraUserDir); + legacy_config_dir = FileUtil::GetUserPath(FileUtil::UserPath::LegacyCitraConfigDir); + legacy_cache_dir = FileUtil::GetUserPath(FileUtil::UserPath::LegacyCitraCacheDir); + } else if (LegacyEmu::Lime3DS == selected_legacy_emu) { + legacy_user_dir = FileUtil::GetUserPath(FileUtil::UserPath::LegacyLime3DSUserDir); + legacy_config_dir = FileUtil::GetUserPath(FileUtil::UserPath::LegacyLime3DSConfigDir); + legacy_cache_dir = FileUtil::GetUserPath(FileUtil::UserPath::LegacyLime3DSCacheDir); + } + + fs::copy(legacy_user_dir, FileUtil::GetUserPath(FileUtil::UserPath::UserDir), copy_options); + + if (fs::is_directory(legacy_config_dir)) { + fs::copy(legacy_config_dir, FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir), + copy_options); + } + if (fs::is_directory(legacy_cache_dir)) { + fs::copy(legacy_cache_dir, FileUtil::GetUserPath(FileUtil::UserPath::CacheDir), + copy_options); + } + + QMessageBox::information( + main_window, main_window->tr("Migration"), + main_window + ->tr("Data was migrated successfully.\n\n" + "If you wish to clean up the files which were left in the old " + "data location, you can do so by deleting the following directory:\n" + "%1") + .arg(QString::fromStdString(legacy_user_dir)), + QMessageBox::Ok); +} \ No newline at end of file diff --git a/src/citra_qt/user_data_migration.h b/src/citra_qt/user_data_migration.h new file mode 100644 index 000000000..dde927038 --- /dev/null +++ b/src/citra_qt/user_data_migration.h @@ -0,0 +1,22 @@ +// Copyright Citra Emulator Project / Azahar Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +class UserDataMigrator { +public: + UserDataMigrator(QMainWindow* main_window); + +private: + enum class LegacyEmu { + Citra, + Lime3DS, + }; + + void ShowMigrationPrompt(QMainWindow* main_window); + void ShowMigrationCancelledMessage(QMainWindow* main_window); + void MigrateUserData(QMainWindow* main_window, const LegacyEmu selected_legacy_emu); +}; \ No newline at end of file