Qt/Loader: Let users choose which packages to install

This commit is contained in:
Megamouse 2023-06-01 02:08:09 +02:00
parent c3b7229fbb
commit 66e1cf96e2
6 changed files with 111 additions and 44 deletions

View File

@ -1645,17 +1645,19 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch,
}
}
std::vector<std::string> pkgs;
if (!lock_file && !ins_dir.empty())
{
sys_log.notice("Found INSDIR: %s", ins_dir);
for (auto&& entry : fs::dir{ins_dir})
{
const std::string pkg = ins_dir + entry.name;
if (!entry.is_directory && entry.name.ends_with(".PKG") && !rpcs3::utils::install_pkg(pkg))
const std::string pkg_file = ins_dir + entry.name;
if (!entry.is_directory && entry.name.ends_with(".PKG"))
{
sys_log.error("Failed to install %s", pkg);
return game_boot_result::install_failed;
pkgs.push_back(pkg_file);
}
}
}
@ -1670,10 +1672,9 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch,
{
const std::string pkg_file = pkg_dir + entry.name + "/INSTALL.PKG";
if (fs::is_file(pkg_file) && !rpcs3::utils::install_pkg(pkg_file))
if (fs::is_file(pkg_file))
{
sys_log.error("Failed to install %s", pkg_file);
return game_boot_result::install_failed;
pkgs.push_back(pkg_file);
}
}
}
@ -1689,15 +1690,31 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch,
{
const std::string pkg_file = extra_dir + entry.name + "/DATA000.PKG";
if (fs::is_file(pkg_file) && !rpcs3::utils::install_pkg(pkg_file))
if (fs::is_file(pkg_file))
{
sys_log.error("Failed to install %s", pkg_file);
return game_boot_result::install_failed;
pkgs.push_back(pkg_file);
}
}
}
}
if (!pkgs.empty())
{
bool install_success = true;
BlockingCallFromMainThread([this, &pkgs, &install_success]()
{
if (!GetCallbacks().on_install_pkgs(pkgs))
{
install_success = false;
}
});
if (!install_success)
{
sys_log.error("Failed to install packages");
return game_boot_result::install_failed;
}
}
if (!lock_file)
{
// Create lock file to prevent double installation

View File

@ -95,6 +95,7 @@ struct EmuCallbacks
std::function<bool(const std::string&, s32, s32, s32&, s32&, u8*, bool)> get_scaled_image; // (filename, target_width, target_height, width, height, dst, force_fit)
std::string(*resolve_path)(std::string_view) = [](std::string_view arg){ return std::string{arg}; }; // Resolve path using Qt
std::function<std::vector<std::string>()> get_font_dirs;
std::function<bool(const std::vector<std::string>&)> on_install_pkgs;
};
namespace utils

View File

@ -348,5 +348,18 @@ EmuCallbacks main_application::CreateCallbacks()
return font_dirs;
};
callbacks.on_install_pkgs = [](const std::vector<std::string>& pkgs)
{
for (const std::string& pkg : pkgs)
{
if (!rpcs3::utils::install_pkg(pkg))
{
sys_log.error("Failed to install %s", pkg);
return false;
}
}
return true;
};
return callbacks;
}

View File

@ -554,6 +554,21 @@ void gui_application::InitializeCallbacks()
});
};
if (m_show_gui) // If this is false, we already have a fallback in the main_application.
{
callbacks.on_install_pkgs = [this](const std::vector<std::string>& pkgs)
{
ensure(m_main_window);
ensure(!pkgs.empty());
QStringList pkg_list;
for (const std::string& pkg : pkgs)
{
pkg_list << QString::fromStdString(pkg);
}
return m_main_window->InstallPackages(pkg_list, true);
};
}
Emu.SetCallbacks(std::move(callbacks));
}

View File

@ -710,10 +710,12 @@ bool main_window::InstallFileInExData(const std::string& extension, const QStrin
return to.commit();
}
void main_window::InstallPackages(QStringList file_paths)
bool main_window::InstallPackages(QStringList file_paths, bool from_boot)
{
if (file_paths.isEmpty())
{
ensure(!from_boot);
// If this function was called without a path, ask the user for files to install.
const QString path_last_pkg = m_gui_settings->GetValue(gui::fd_install_pkg).toString();
const QStringList paths = QFileDialog::getOpenFileNames(this, tr("Select packages and/or rap files to install"),
@ -721,7 +723,7 @@ void main_window::InstallPackages(QStringList file_paths)
if (paths.isEmpty())
{
return;
return true;
}
file_paths.append(paths);
@ -739,7 +741,7 @@ void main_window::InstallPackages(QStringList file_paths)
if (!info.is_valid)
{
QMessageBox::warning(this, tr("Invalid package!"), tr("The selected package is invalid!\n\nPath:\n%0").arg(file_path));
return;
return false;
}
if (info.type != compat::package_type::other)
@ -780,21 +782,10 @@ void main_window::InstallPackages(QStringList file_paths)
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) != QMessageBox::Yes)
{
gui_log.notice("PKG: Cancelled installation from drop.\n%s", sstr(info_string));
return;
return true;
}
}
if (!m_gui_settings->GetBootConfirmation(this))
{
// Last chance to cancel the operation
return;
}
if (!Emu.IsStopped())
{
Emu.GracefulShutdown(false);
}
// Install rap files if available
int installed_rap_and_edat_count = 0;
@ -818,8 +809,22 @@ void main_window::InstallPackages(QStringList file_paths)
}
};
install_filetype("rap");
install_filetype("edat");
if (!from_boot)
{
if (!m_gui_settings->GetBootConfirmation(this))
{
// Last chance to cancel the operation
return true;
}
if (!Emu.IsStopped())
{
Emu.GracefulShutdown(false);
}
install_filetype("rap");
install_filetype("edat");
}
if (installed_rap_and_edat_count > 0)
{
@ -830,21 +835,30 @@ void main_window::InstallPackages(QStringList file_paths)
// Find remaining package files
file_paths = file_paths.filter(QRegularExpression(".*\\.pkg", QRegularExpression::PatternOption::CaseInsensitiveOption));
if (!file_paths.isEmpty())
if (file_paths.isEmpty())
{
// Handle further installations with a timeout. Otherwise the source explorer instance is not usable during the following file processing.
QTimer::singleShot(0, [this, paths = std::move(file_paths)]()
{
HandlePackageInstallation(paths);
});
return true;
}
if (from_boot)
{
return HandlePackageInstallation(file_paths, true);
}
// Handle further installations with a timeout. Otherwise the source explorer instance is not usable during the following file processing.
QTimer::singleShot(0, [this, paths = std::move(file_paths)]()
{
HandlePackageInstallation(paths, false);
});
return true;
}
void main_window::HandlePackageInstallation(QStringList file_paths)
bool main_window::HandlePackageInstallation(QStringList file_paths, bool from_boot)
{
if (file_paths.empty())
{
return;
return false;
}
std::vector<compat::package_info> packages;
@ -868,15 +882,18 @@ void main_window::HandlePackageInstallation(QStringList file_paths)
if (packages.empty())
{
return;
return true;
}
if (!m_gui_settings->GetBootConfirmation(this))
if (!from_boot)
{
return;
}
if (!m_gui_settings->GetBootConfirmation(this))
{
return true;
}
Emu.GracefulShutdown(false);
Emu.GracefulShutdown(false);
}
std::vector<std::string> path_vec;
for (const compat::package_info& pkg : packages)
@ -973,7 +990,9 @@ void main_window::HandlePackageInstallation(QStringList file_paths)
}
}
if (worker())
const bool success = worker();
if (success)
{
pdlg.SetValue(pdlg.maximum());
std::this_thread::sleep_for(100ms);
@ -1032,7 +1051,7 @@ void main_window::HandlePackageInstallation(QStringList file_paths)
if (bootable_paths_installed.empty())
{
m_gui_settings->ShowInfoBox(tr("Success!"), tr("Successfully installed software from package(s)!"), gui::ib_pkg_success, this);
return;
return true;
}
auto dlg = new QDialog(this);
@ -1144,6 +1163,8 @@ void main_window::HandlePackageInstallation(QStringList file_paths)
}
}
}
return success;
}
void main_window::ExtractMSELF()

View File

@ -86,7 +86,7 @@ public:
bool Init(bool with_cli_boot);
QIcon GetAppIcon() const;
bool OnMissingFw();
void InstallPackages(QStringList file_paths = QStringList());
bool InstallPackages(QStringList file_paths = {}, bool from_boot = false);
void InstallPup(QString file_path = "");
Q_SIGNALS:
@ -149,7 +149,7 @@ private:
static bool InstallFileInExData(const std::string& extension, const QString& path, const std::string& filename);
void HandlePackageInstallation(QStringList file_paths);
bool HandlePackageInstallation(QStringList file_paths, bool from_boot);
void HandlePupInstallation(const QString& file_path, const QString& dir_path = "");
void ExtractPup();