diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp
index d4e52b8025..3ba64487e6 100644
--- a/rpcs3/rpcs3qt/main_window.cpp
+++ b/rpcs3/rpcs3qt/main_window.cpp
@@ -801,7 +801,7 @@ bool main_window::InstallPackages(QStringList file_paths, bool from_boot)
if (file_paths.count() == 1)
{
- const QString file_path = file_paths.front();
+ const QString& file_path = file_paths.front();
const QFileInfo file_info(file_path);
if (file_info.isDir())
@@ -819,92 +819,6 @@ bool main_window::InstallPackages(QStringList file_paths, bool from_boot)
return InstallPackages(dir_file_paths, from_boot);
}
-
- if (file_info.suffix().compare("pkg", Qt::CaseInsensitive) == 0)
- {
- compat::package_info info = game_compatibility::GetPkgInfo(file_path, m_game_list_frame ? m_game_list_frame->GetGameCompatibility() : nullptr);
-
- if (!info.is_valid)
- {
- QMessageBox::warning(this, tr("Invalid package!"), tr("The selected package is invalid!\n\nPath:\n%0").arg(file_path));
- return false;
- }
-
- if (info.type != compat::package_type::other)
- {
- if (info.type == compat::package_type::dlc)
- {
- info.local_cat = tr("\nDLC", "Block for package type (DLC)");
- }
- else
- {
- info.local_cat = tr("\nUpdate", "Block for package type (Update)");
- }
- }
- else if (!info.local_cat.isEmpty())
- {
- info.local_cat = tr("\n%0", "Block for package type").arg(info.local_cat);
- }
-
- if (!info.title_id.isEmpty())
- {
- info.title_id = tr("\n%0", "Block for Title ID").arg(info.title_id);
- }
-
- if (!info.version.isEmpty())
- {
- info.version = tr("\nVersion %0", "Block for Version").arg(info.version);
- }
-
- if (!info.changelog.isEmpty())
- {
- info.changelog = tr("Changelog:\n%0", "Block for Changelog").arg(info.changelog);
- }
-
- u64 free_space = 0;
-
- // Retrieve disk space info on data path's drive
- if (fs::device_stat stat{}; fs::statfs(rpcs3::utils::get_hdd0_dir(), stat))
- {
- free_space = stat.avail_free;
- }
-
- const QString installation_info =
- tr("Installation path: %0\nAvailable disk space: %1%2\nRequired disk space: %3")
- .arg(QString::fromStdString(rpcs3::utils::get_hdd0_game_dir()))
- .arg(gui::utils::format_byte_size(free_space))
- .arg(info.data_size <= free_space ? QString() : tr(" - NOT ENOUGH SPACE"))
- .arg(gui::utils::format_byte_size(info.data_size));
-
- const QString info_string = QStringLiteral("%0\n\n%1%2%3%4").arg(file_info.fileName()).arg(info.title).arg(info.local_cat).arg(info.title_id).arg(info.version);
- QString message = tr("Do you want to install this package?\n\n%0\n\n%1").arg(info_string).arg(installation_info);
-
- QMessageBox mb(QMessageBox::Icon::Question, tr("PKG Decrypter / Installer"), gui::utils::make_paragraph(message), QMessageBox::Yes | QMessageBox::No, this);
- mb.setDefaultButton(QMessageBox::No);
- mb.setTextFormat(Qt::RichText); // Support HTML tags
- mb.button(QMessageBox::Yes)->setEnabled(info.data_size <= free_space);
-
- if (!info.changelog.isEmpty())
- {
- mb.setInformativeText(tr("To see the changelog, please click \"Show Details\"."));
- mb.setDetailedText(info.changelog);
-
- // Smartass hack to make the unresizeable message box wide enough for the changelog
- const int log_width = QLabel(info.changelog).sizeHint().width();
- while (QLabel(message).sizeHint().width() < log_width)
- {
- message += " ";
- }
-
- mb.setText(message);
- }
-
- if (mb.exec() != QMessageBox::Yes)
- {
- gui_log.notice("PKG: Cancelled installation from drop.\n%s\n%s", info_string, info.changelog);
- return true;
- }
- }
}
// Install rap files if available
@@ -983,28 +897,22 @@ bool main_window::HandlePackageInstallation(QStringList file_paths, bool from_bo
}
std::vector packages;
+ bool precompile_caches = false;
+ bool create_desktop_shortcuts = false;
+ bool create_app_shortcut = false;
game_compatibility* compat = m_game_list_frame ? m_game_list_frame->GetGameCompatibility() : nullptr;
- if (file_paths.size() > 1)
+ // Let the user choose the packages to install and select the order in which they shall be installed.
+ pkg_install_dialog dlg(file_paths, compat, this);
+ connect(&dlg, &QDialog::accepted, this, [&]()
{
- // Let the user choose the packages to install and select the order in which they shall be installed.
- pkg_install_dialog dlg(file_paths, compat, this);
- connect(&dlg, &QDialog::accepted, this, [&packages, &dlg]()
- {
- packages = dlg.GetPathsToInstall();
- });
- dlg.exec();
- }
- else
- {
- packages.push_back(game_compatibility::GetPkgInfo(file_paths.front(), compat));
- }
-
- if (packages.empty())
- {
- return true;
- }
+ packages = dlg.get_paths_to_install();
+ precompile_caches = dlg.precompile_caches();
+ create_desktop_shortcuts = dlg.create_desktop_shortcuts();
+ create_app_shortcut = dlg.create_app_shortcut();
+ });
+ dlg.exec();
if (!from_boot)
{
@@ -1178,7 +1086,7 @@ bool main_window::HandlePackageInstallation(QStringList file_paths, bool from_bo
if (!bootable_paths_installed.empty())
{
- m_game_list_frame->AddRefreshedSlot([this, paths = std::move(bootable_paths_installed)](std::set& claimed_paths) mutable
+ m_game_list_frame->AddRefreshedSlot([this, create_desktop_shortcuts, precompile_caches, create_app_shortcut, paths = std::move(bootable_paths_installed)](std::set& claimed_paths) mutable
{
// Try to claim operations on ID
for (auto it = paths.begin(); it != paths.end();)
@@ -1196,7 +1104,12 @@ bool main_window::HandlePackageInstallation(QStringList file_paths, bool from_bo
}
}
- ShowOptionalGamePreparations(tr("Success!"), tr("Successfully installed software from package(s)!"), std::move(paths));
+ CreateShortCuts(paths, create_desktop_shortcuts, create_app_shortcut);
+
+ if (precompile_caches)
+ {
+ PrecompileCachesFromInstalledPackages(paths);
+ }
});
}
@@ -2431,49 +2344,7 @@ void main_window::ShowOptionalGamePreparations(const QString& title, const QStri
dlg->hide();
dlg->accept();
- std::set locations;
-
-#ifdef _WIN32
- locations.insert(gui::utils::shortcut_location::rpcs3_shortcuts);
-#endif
- if (create_desktop_shortcuts)
- {
- locations.insert(gui::utils::shortcut_location::desktop);
- }
-
- if (create_app_shortcut)
- {
- locations.insert(gui::utils::shortcut_location::applications);
- }
-
- if (!locations.empty())
- {
- std::vector game_data_shortcuts;
-
- for (const auto& [boot_path, title_id] : paths)
- {
- for (const game_info& gameinfo : m_game_list_frame->GetGameInfo())
- {
- if (gameinfo && gameinfo->info.serial == title_id.toStdString())
- {
- if (Emu.IsPathInsideDir(boot_path, gameinfo->info.path))
- {
- if (!locations.empty())
- {
- game_data_shortcuts.push_back(gameinfo);
- }
- }
-
- break;
- }
- }
- }
-
- if (!game_data_shortcuts.empty() && !locations.empty())
- {
- m_game_list_frame->CreateShortcuts(game_data_shortcuts, locations);
- }
- }
+ CreateShortCuts(paths, create_desktop_shortcuts, create_app_shortcut);
if (precompile_caches)
{
@@ -2485,6 +2356,55 @@ void main_window::ShowOptionalGamePreparations(const QString& title, const QStri
dlg->open();
}
+void main_window::CreateShortCuts(const std::map& paths, bool create_desktop_shortcuts, bool create_app_shortcut)
+{
+ if (paths.empty()) return;
+
+ std::set locations;
+
+#ifdef _WIN32
+ locations.insert(gui::utils::shortcut_location::rpcs3_shortcuts);
+#endif
+ if (create_desktop_shortcuts)
+ {
+ locations.insert(gui::utils::shortcut_location::desktop);
+ }
+
+ if (create_app_shortcut)
+ {
+ locations.insert(gui::utils::shortcut_location::applications);
+ }
+
+ if (!locations.empty())
+ {
+ std::vector game_data_shortcuts;
+
+ for (const auto& [boot_path, title_id] : paths)
+ {
+ for (const game_info& gameinfo : m_game_list_frame->GetGameInfo())
+ {
+ if (gameinfo && gameinfo->info.serial == title_id.toStdString())
+ {
+ if (Emu.IsPathInsideDir(boot_path, gameinfo->info.path))
+ {
+ if (!locations.empty())
+ {
+ game_data_shortcuts.push_back(gameinfo);
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ if (!game_data_shortcuts.empty() && !locations.empty())
+ {
+ m_game_list_frame->CreateShortcuts(game_data_shortcuts, locations);
+ }
+ }
+}
+
void main_window::PrecompileCachesFromInstalledPackages(const std::map& bootable_paths)
{
std::vector game_data;
diff --git a/rpcs3/rpcs3qt/main_window.h b/rpcs3/rpcs3qt/main_window.h
index 960a70c722..40d874e11c 100644
--- a/rpcs3/rpcs3qt/main_window.h
+++ b/rpcs3/rpcs3qt/main_window.h
@@ -149,6 +149,7 @@ private:
static bool InstallFileInExData(const std::string& extension, const QString& path, const std::string& filename);
bool HandlePackageInstallation(QStringList file_paths, bool from_boot);
+ void CreateShortCuts(const std::map& paths, bool create_desktop_shortcuts, bool create_app_shortcut);
void HandlePupInstallation(const QString& file_path, const QString& dir_path = "");
void ExtractPup();
diff --git a/rpcs3/rpcs3qt/pkg_install_dialog.cpp b/rpcs3/rpcs3qt/pkg_install_dialog.cpp
index 370f4d053c..9b0f926484 100644
--- a/rpcs3/rpcs3qt/pkg_install_dialog.cpp
+++ b/rpcs3/rpcs3qt/pkg_install_dialog.cpp
@@ -7,12 +7,11 @@
#include "Emu/system_utils.hpp"
#include "Utilities/File.h"
-#include
#include
#include
#include
-#include
#include
+#include
enum Roles
{
@@ -105,8 +104,6 @@ pkg_install_dialog::pkg_install_dialog(const QStringList& paths, game_compatibil
item->setData(Roles::VersionRole, info.version);
item->setData(Roles::DataSizeRole, static_cast(info.data_size));
item->setToolTip(tooltip);
- item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
- item->setCheckState(Qt::Checked);
}
m_dir_list->sortItems();
@@ -134,42 +131,79 @@ pkg_install_dialog::pkg_install_dialog(const QStringList& paths, game_compatibil
}
});
- connect(m_dir_list, &QListWidget::itemChanged, this, [this, installation_info, buttons](QListWidgetItem*)
+ QHBoxLayout* hbox = nullptr;
+ if (m_dir_list->count() > 1)
{
- UpdateInfo(installation_info, buttons);
- });
+ for (int i = 0; i < m_dir_list->count(); i++)
+ {
+ if (QListWidgetItem* item = m_dir_list->item(i))
+ {
+ item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
+ item->setCheckState(Qt::Checked);
+ }
+ }
+
+ connect(m_dir_list, &QListWidget::itemChanged, this, [this, installation_info, buttons](QListWidgetItem*)
+ {
+ update_info(installation_info, buttons);
+ });
- QToolButton* move_up = new QToolButton;
- move_up->setArrowType(Qt::UpArrow);
- move_up->setToolTip(tr("Move selected item up"));
- connect(move_up, &QToolButton::clicked, this, [this]() { MoveItem(-1); });
+ QToolButton* move_up = new QToolButton;
+ move_up->setArrowType(Qt::UpArrow);
+ move_up->setToolTip(tr("Move selected item up"));
+ connect(move_up, &QToolButton::clicked, this, [this]() { move_item(-1); });
- QToolButton* move_down = new QToolButton;
- move_down->setArrowType(Qt::DownArrow);
- move_down->setToolTip(tr("Move selected item down"));
- connect(move_down, &QToolButton::clicked, this, [this]() { MoveItem(1); });
+ QToolButton* move_down = new QToolButton;
+ move_down->setArrowType(Qt::DownArrow);
+ move_down->setToolTip(tr("Move selected item down"));
+ connect(move_down, &QToolButton::clicked, this, [this]() { move_item(1); });
- QHBoxLayout* hbox = new QHBoxLayout;
- hbox->addStretch();
- hbox->addWidget(move_up);
- hbox->addWidget(move_down);
+ hbox = new QHBoxLayout;
+ hbox->addStretch();
+ hbox->addWidget(move_up);
+ hbox->addWidget(move_down);
+ }
- QLabel* description = new QLabel(tr("You are about to install multiple packages.\nReorder and/or exclude them if needed, then click \"Install\" to proceed."));
+ QLabel* description = new QLabel(m_dir_list->count() == 1
+ ? tr("Do you want to install this package?")
+ : tr("You are about to install multiple packages.\nReorder and/or exclude them if needed, then click \"Install\" to proceed.")
+ );
+ QLabel* label = new QLabel(tr("Would you like to precompile caches and install shortcuts to the installed software?"));
+
+ QCheckBox* precompile_check = new QCheckBox(tr("Precompile caches"));
+ connect(precompile_check, &QCheckBox::checkStateChanged, this, [this](Qt::CheckState state){ m_precompile_caches = state != Qt::CheckState::Unchecked; });
+ precompile_check->setChecked(true);
+
+ QCheckBox* desk_check = new QCheckBox(tr("Add desktop shortcut(s)"));
+ connect(desk_check, &QCheckBox::checkStateChanged, this, [this](Qt::CheckState state){ m_create_desktop_shortcuts = state != Qt::CheckState::Unchecked; });
+
+#ifdef _WIN32
+ QCheckBox* quick_check = new QCheckBox(tr("Add Start menu shortcut(s)"));
+#elif defined(__APPLE__)
+ QCheckBox* quick_check = new QCheckBox(tr("Add dock shortcut(s)"));
+#else
+ QCheckBox* quick_check = new QCheckBox(tr("Add launcher shortcut(s)"));
+#endif
+ connect(quick_check, &QCheckBox::checkStateChanged, this, [this](Qt::CheckState state){ m_create_app_shortcut = state != Qt::CheckState::Unchecked; });
QVBoxLayout* vbox = new QVBoxLayout;
vbox->addWidget(description);
- vbox->addLayout(hbox);
+ if (hbox) vbox->addLayout(hbox);
vbox->addWidget(m_dir_list);
+ vbox->addWidget(label);
+ vbox->addWidget(precompile_check);
+ vbox->addWidget(desk_check);
+ vbox->addWidget(quick_check);
vbox->addWidget(installation_info);
vbox->addWidget(buttons);
setLayout(vbox);
- setWindowTitle(tr("Batch PKG Installation"));
+ setWindowTitle(tr("PKG Installation"));
setObjectName("pkg_install_dialog");
- UpdateInfo(installation_info, buttons); // Just to show and check available and required size
+ update_info(installation_info, buttons); // Just to show and check available and required size
}
-void pkg_install_dialog::UpdateInfo(QLabel* installation_info, QDialogButtonBox* buttons) const
+void pkg_install_dialog::update_info(QLabel* installation_info, QDialogButtonBox* buttons) const
{
u64 data_size = 0;
u64 free_space = 0;
@@ -182,7 +216,7 @@ void pkg_install_dialog::UpdateInfo(QLabel* installation_info, QDialogButtonBox*
for (int i = 0; i < m_dir_list->count(); i++)
{
- if (m_dir_list->item(i)->checkState() == Qt::Checked)
+ if (m_dir_list->count() == 1 || m_dir_list->item(i)->checkState() == Qt::Checked)
{
data_size += m_dir_list->item(i)->data(Roles::DataSizeRole).toULongLong();
}
@@ -197,7 +231,7 @@ void pkg_install_dialog::UpdateInfo(QLabel* installation_info, QDialogButtonBox*
buttons->button(QDialogButtonBox::Ok)->setEnabled(data_size && (data_size <= free_space));
}
-void pkg_install_dialog::MoveItem(int offset) const
+void pkg_install_dialog::move_item(int offset) const
{
const int src_index = m_dir_list->currentRow();
const int dest_index = src_index + offset;
@@ -211,14 +245,14 @@ void pkg_install_dialog::MoveItem(int offset) const
}
}
-std::vector pkg_install_dialog::GetPathsToInstall() const
+std::vector pkg_install_dialog::get_paths_to_install() const
{
std::vector result;
for (int i = 0; i < m_dir_list->count(); i++)
{
const QListWidgetItem* item = m_dir_list->item(i);
- if (item && item->checkState() == Qt::Checked)
+ if (item && (m_dir_list->count() == 1 || item->checkState() == Qt::Checked))
{
compat::package_info info;
info.path = item->data(Roles::FullPathRole).toString();
diff --git a/rpcs3/rpcs3qt/pkg_install_dialog.h b/rpcs3/rpcs3qt/pkg_install_dialog.h
index 2122259a1d..82593ab6b5 100644
--- a/rpcs3/rpcs3qt/pkg_install_dialog.h
+++ b/rpcs3/rpcs3qt/pkg_install_dialog.h
@@ -18,11 +18,17 @@ class pkg_install_dialog : public QDialog
public:
explicit pkg_install_dialog(const QStringList& paths, game_compatibility* compat, QWidget* parent = nullptr);
- std::vector GetPathsToInstall() const;
+ std::vector get_paths_to_install() const;
+ bool precompile_caches() const { return m_precompile_caches; }
+ bool create_desktop_shortcuts() const { return m_create_desktop_shortcuts; }
+ bool create_app_shortcut() const { return m_create_app_shortcut; }
private:
- void UpdateInfo(QLabel* installation_info, QDialogButtonBox* buttons) const;
- void MoveItem(int offset) const;
+ void update_info(QLabel* installation_info, QDialogButtonBox* buttons) const;
+ void move_item(int offset) const;
QListWidget* m_dir_list;
+ bool m_precompile_caches = false;
+ bool m_create_desktop_shortcuts = false;
+ bool m_create_app_shortcut = false;
};