mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-12-16 04:09:07 +00:00
Check available and required size when installing a package (#17829)
Show and check available and required size when installing a package. Installation is not allowed, by disabling `Yes` and/or `Install` button, if not enough disk space is detected. On multi installation dialog box, installation size for each package is reported in the list. fixes #14440 </br> </br> ### Single PKG installation - Not enough space available  </br> </br> ### Single PKG installation - Required space available  </br> </br> ### Multi PKG installation - Not enough space available  </br> </br> ### Multi PKG installation - Required space available  --------- Co-authored-by: Megamouse <studienricky89@googlemail.com>
This commit is contained in:
parent
3f6529fecb
commit
0f1d516d9a
@ -347,6 +347,7 @@ public:
|
||||
};
|
||||
|
||||
bool is_valid() const { return m_is_valid; }
|
||||
const PKGHeader& get_header() const { return m_header; }
|
||||
package_install_result check_target_app_version() const;
|
||||
static package_install_result extract_data(std::deque<package_reader>& readers, std::deque<std::string>& bootable_paths);
|
||||
const psf::registry& get_psf() const { return m_psf; }
|
||||
|
||||
@ -184,6 +184,11 @@ namespace rpcs3::utils
|
||||
return g_cfg_vfs.get(g_cfg_vfs.dev_bdvd, get_emu_dir());
|
||||
}
|
||||
|
||||
std::string get_hdd0_game_dir()
|
||||
{
|
||||
return get_hdd0_dir() + "game/";
|
||||
}
|
||||
|
||||
u64 get_cache_disk_usage()
|
||||
{
|
||||
if (const u64 data_size = fs::get_dir_size(rpcs3::utils::get_cache_dir(), 1); data_size != umax)
|
||||
|
||||
@ -34,6 +34,8 @@ namespace rpcs3::utils
|
||||
std::string get_flash3_dir();
|
||||
std::string get_bdvd_dir();
|
||||
|
||||
std::string get_hdd0_game_dir();
|
||||
|
||||
// Cache directories and disk usage
|
||||
u64 get_cache_disk_usage();
|
||||
std::string get_cache_dir();
|
||||
|
||||
@ -272,6 +272,10 @@ compat::package_info game_compatibility::GetPkgInfo(const QString& pkg_path, gam
|
||||
info.category = QString::fromStdString(std::string(psf::get_string(psf, "CATEGORY")));
|
||||
info.version = QString::fromStdString(std::string(psf::get_string(psf, "APP_VER")));
|
||||
|
||||
// Technically, there is no specific package's header info providing its installation size on disk.
|
||||
// We use "data_size" header as an approximation (a bit larger) for this purpose
|
||||
info.data_size = reader.get_header().data_size.value();
|
||||
|
||||
if (!info.category.isEmpty())
|
||||
{
|
||||
const Localized localized;
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/types.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QJsonObject>
|
||||
@ -108,6 +110,7 @@ namespace compat
|
||||
QString version; // May be empty
|
||||
QString category; // HG, DG, GD etc.
|
||||
QString local_cat; // Localized category
|
||||
u64 data_size = 0; // Installation size
|
||||
|
||||
package_type type = package_type::other; // The type of package (Update, DLC or other)
|
||||
};
|
||||
|
||||
@ -860,11 +860,28 @@ bool main_window::InstallPackages(QStringList file_paths, bool from_boot)
|
||||
info.changelog = tr("Changelog:\n%0", "Block for Changelog").arg(info.changelog);
|
||||
}
|
||||
|
||||
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").arg(info_string);
|
||||
u64 free_space = 0;
|
||||
|
||||
QMessageBox mb(QMessageBox::Icon::Question, tr("PKG Decrypter / Installer"), message, QMessageBox::Yes | QMessageBox::No, this);
|
||||
// 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(rpcs3::utils::get_hdd0_game_dir())
|
||||
.arg(gui::utils::format_byte_size(free_space))
|
||||
.arg(info.data_size <= free_space ? QString() : tr(" - <b>NOT ENOUGH SPACE</b>"))
|
||||
.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())
|
||||
{
|
||||
|
||||
@ -2,6 +2,10 @@
|
||||
#include "game_compatibility.h"
|
||||
#include "numbered_widget_item.h"
|
||||
#include "richtext_item_delegate.h"
|
||||
#include "qt_utils.h"
|
||||
|
||||
#include "Emu/system_utils.hpp"
|
||||
#include "Utilities/File.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QPushButton>
|
||||
@ -17,6 +21,7 @@ enum Roles
|
||||
TitleRole = Qt::UserRole + 2,
|
||||
TitleIdRole = Qt::UserRole + 3,
|
||||
VersionRole = Qt::UserRole + 4,
|
||||
DataSizeRole = Qt::UserRole + 5,
|
||||
};
|
||||
|
||||
pkg_install_dialog::pkg_install_dialog(const QStringList& paths, game_compatibility* compat, QWidget* parent)
|
||||
@ -89,7 +94,8 @@ pkg_install_dialog::pkg_install_dialog(const QStringList& paths, game_compatibil
|
||||
append_comma();
|
||||
accumulated_info += file_info.fileName();
|
||||
|
||||
const QString text = tr("<b>%0</b> (%2)", "Package text").arg(info.title.simplified()).arg(accumulated_info);
|
||||
const QString text = tr("<b>%0</b> (%1) - %2", "Package text").arg(info.title.simplified())
|
||||
.arg(accumulated_info).arg(gui::utils::format_byte_size(info.data_size));
|
||||
|
||||
QListWidgetItem* item = new numbered_widget_item(text, m_dir_list);
|
||||
item->setData(Roles::FullPathRole, info.path);
|
||||
@ -97,6 +103,7 @@ pkg_install_dialog::pkg_install_dialog(const QStringList& paths, game_compatibil
|
||||
item->setData(Roles::TitleRole, info.title);
|
||||
item->setData(Roles::TitleIdRole, info.title_id);
|
||||
item->setData(Roles::VersionRole, info.version);
|
||||
item->setData(Roles::DataSizeRole, static_cast<qulonglong>(info.data_size));
|
||||
item->setToolTip(tooltip);
|
||||
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||
item->setCheckState(Qt::Checked);
|
||||
@ -106,6 +113,10 @@ pkg_install_dialog::pkg_install_dialog(const QStringList& paths, game_compatibil
|
||||
m_dir_list->setCurrentRow(0);
|
||||
m_dir_list->setMinimumWidth((m_dir_list->sizeHintForColumn(0) * 125) / 100);
|
||||
|
||||
// Create contextual label (updated in connect(m_dir_list, &QListWidget::itemChanged ...))
|
||||
QLabel* installation_info = new QLabel();
|
||||
installation_info->setTextFormat(Qt::RichText); // Support HTML tags
|
||||
|
||||
// Create buttons
|
||||
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
|
||||
buttons->button(QDialogButtonBox::Ok)->setText(tr("Install"));
|
||||
@ -123,19 +134,9 @@ pkg_install_dialog::pkg_install_dialog(const QStringList& paths, game_compatibil
|
||||
}
|
||||
});
|
||||
|
||||
connect(m_dir_list, &QListWidget::itemChanged, this, [this, buttons](QListWidgetItem*)
|
||||
connect(m_dir_list, &QListWidget::itemChanged, this, [this, installation_info, buttons](QListWidgetItem*)
|
||||
{
|
||||
bool any_checked = false;
|
||||
for (int i = 0; i < m_dir_list->count(); i++)
|
||||
{
|
||||
if (m_dir_list->item(i)->checkState() == Qt::Checked)
|
||||
{
|
||||
any_checked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
buttons->button(QDialogButtonBox::Ok)->setEnabled(any_checked);
|
||||
UpdateInfo(installation_info, buttons);
|
||||
});
|
||||
|
||||
QToolButton* move_up = new QToolButton;
|
||||
@ -159,11 +160,41 @@ pkg_install_dialog::pkg_install_dialog(const QStringList& paths, game_compatibil
|
||||
vbox->addWidget(description);
|
||||
vbox->addLayout(hbox);
|
||||
vbox->addWidget(m_dir_list);
|
||||
vbox->addWidget(installation_info);
|
||||
vbox->addWidget(buttons);
|
||||
|
||||
setLayout(vbox);
|
||||
setWindowTitle(tr("Batch PKG Installation"));
|
||||
setObjectName("pkg_install_dialog");
|
||||
UpdateInfo(installation_info, buttons); // Just to show and check available and required size
|
||||
}
|
||||
|
||||
void pkg_install_dialog::UpdateInfo(QLabel* installation_info, QDialogButtonBox* buttons) const
|
||||
{
|
||||
u64 data_size = 0;
|
||||
u64 free_space = 0;
|
||||
|
||||
// Retrieve disk space info on data path's drive
|
||||
if (fs::device_stat stat{}; fs::statfs(rpcs3::utils::get_hdd0_game_dir(), stat))
|
||||
{
|
||||
free_space = stat.avail_free;
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_dir_list->count(); i++)
|
||||
{
|
||||
if (m_dir_list->item(i)->checkState() == Qt::Checked)
|
||||
{
|
||||
data_size += m_dir_list->item(i)->data(Roles::DataSizeRole).toULongLong();
|
||||
}
|
||||
}
|
||||
|
||||
installation_info->setText(gui::utils::make_paragraph(
|
||||
tr("Installation path: %0\nAvailable disk space: %1%2\nRequired disk space: %3")
|
||||
.arg(rpcs3::utils::get_hdd0_game_dir())
|
||||
.arg(gui::utils::format_byte_size(free_space))
|
||||
.arg(data_size <= free_space ? QString() : tr(" - <b>NOT ENOUGH SPACE</b>"))
|
||||
.arg(gui::utils::format_byte_size(data_size))));
|
||||
buttons->button(QDialogButtonBox::Ok)->setEnabled(data_size && (data_size <= free_space));
|
||||
}
|
||||
|
||||
void pkg_install_dialog::MoveItem(int offset) const
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
|
||||
#include <QDialog>
|
||||
#include <QListWidget>
|
||||
#include <QLabel>
|
||||
#include <QDialogButtonBox>
|
||||
|
||||
namespace compat
|
||||
{
|
||||
@ -19,6 +21,7 @@ public:
|
||||
std::vector<compat::package_info> GetPathsToInstall() const;
|
||||
|
||||
private:
|
||||
void UpdateInfo(QLabel* installation_info, QDialogButtonBox* buttons) const;
|
||||
void MoveItem(int offset) const;
|
||||
|
||||
QListWidget* m_dir_list;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user