Update the install and progress dialogs
- Remove the overwrite files checkbox, it will always overwrite - The progressbar now reflects the progress in terms of data transferred.
This commit is contained in:
parent
7f4d96d873
commit
6d8d7ebc66
|
@ -22,7 +22,7 @@ InstallDialog::InstallDialog(QWidget* parent, const QStringList& files) : QDialo
|
||||||
item->setCheckState(Qt::Checked);
|
item->setCheckState(Qt::Checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
file_list->setMinimumWidth((file_list->sizeHintForColumn(0) * 10) / 9);
|
file_list->setMinimumWidth((file_list->sizeHintForColumn(0) * 11) / 10);
|
||||||
|
|
||||||
vbox_layout = new QVBoxLayout;
|
vbox_layout = new QVBoxLayout;
|
||||||
|
|
||||||
|
@ -30,8 +30,8 @@ InstallDialog::InstallDialog(QWidget* parent, const QStringList& files) : QDialo
|
||||||
|
|
||||||
description = new QLabel(tr("Please confirm these are the files you wish to install."));
|
description = new QLabel(tr("Please confirm these are the files you wish to install."));
|
||||||
|
|
||||||
overwrite_files = new QCheckBox(tr("Overwrite Existing Files"));
|
update_description =
|
||||||
overwrite_files->setCheckState(Qt::Unchecked);
|
new QLabel(tr("Installing an Update or DLC will overwrite the previously installed one."));
|
||||||
|
|
||||||
buttons = new QDialogButtonBox;
|
buttons = new QDialogButtonBox;
|
||||||
buttons->addButton(QDialogButtonBox::Cancel);
|
buttons->addButton(QDialogButtonBox::Cancel);
|
||||||
|
@ -40,10 +40,10 @@ InstallDialog::InstallDialog(QWidget* parent, const QStringList& files) : QDialo
|
||||||
connect(buttons, &QDialogButtonBox::accepted, this, &InstallDialog::accept);
|
connect(buttons, &QDialogButtonBox::accepted, this, &InstallDialog::accept);
|
||||||
connect(buttons, &QDialogButtonBox::rejected, this, &InstallDialog::reject);
|
connect(buttons, &QDialogButtonBox::rejected, this, &InstallDialog::reject);
|
||||||
|
|
||||||
hbox_layout->addWidget(overwrite_files);
|
|
||||||
hbox_layout->addWidget(buttons);
|
hbox_layout->addWidget(buttons);
|
||||||
|
|
||||||
vbox_layout->addWidget(description);
|
vbox_layout->addWidget(description);
|
||||||
|
vbox_layout->addWidget(update_description);
|
||||||
vbox_layout->addWidget(file_list);
|
vbox_layout->addWidget(file_list);
|
||||||
vbox_layout->addLayout(hbox_layout);
|
vbox_layout->addLayout(hbox_layout);
|
||||||
|
|
||||||
|
@ -67,10 +67,6 @@ QStringList InstallDialog::GetFiles() const {
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InstallDialog::ShouldOverwriteFiles() const {
|
|
||||||
return overwrite_files->isChecked();
|
|
||||||
}
|
|
||||||
|
|
||||||
int InstallDialog::GetMinimumWidth() const {
|
int InstallDialog::GetMinimumWidth() const {
|
||||||
return file_list->width();
|
return file_list->width();
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,6 @@ private:
|
||||||
QHBoxLayout* hbox_layout;
|
QHBoxLayout* hbox_layout;
|
||||||
|
|
||||||
QLabel* description;
|
QLabel* description;
|
||||||
QCheckBox* overwrite_files;
|
QLabel* update_description;
|
||||||
QDialogButtonBox* buttons;
|
QDialogButtonBox* buttons;
|
||||||
};
|
};
|
||||||
|
|
|
@ -848,6 +848,9 @@ void GMainWindow::ConnectWidgetEvents() {
|
||||||
connect(game_list, &GameList::OpenPerGameGeneralRequested, this,
|
connect(game_list, &GameList::OpenPerGameGeneralRequested, this,
|
||||||
&GMainWindow::OnGameListOpenPerGameProperties);
|
&GMainWindow::OnGameListOpenPerGameProperties);
|
||||||
|
|
||||||
|
connect(this, &GMainWindow::UpdateInstallProgress, this,
|
||||||
|
&GMainWindow::IncrementInstallProgress);
|
||||||
|
|
||||||
connect(this, &GMainWindow::EmulationStarting, render_window,
|
connect(this, &GMainWindow::EmulationStarting, render_window,
|
||||||
&GRenderWindow::OnEmulationStarting);
|
&GRenderWindow::OnEmulationStarting);
|
||||||
connect(this, &GMainWindow::EmulationStopping, render_window,
|
connect(this, &GMainWindow::EmulationStopping, render_window,
|
||||||
|
@ -1594,6 +1597,10 @@ void GMainWindow::OnMenuLoadFolder() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GMainWindow::IncrementInstallProgress() {
|
||||||
|
install_progress->setValue(install_progress->value() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
void GMainWindow::OnMenuInstallToNAND() {
|
void GMainWindow::OnMenuInstallToNAND() {
|
||||||
const QString file_filter =
|
const QString file_filter =
|
||||||
tr("Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive "
|
tr("Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive "
|
||||||
|
@ -1613,28 +1620,35 @@ void GMainWindow::OnMenuInstallToNAND() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const QStringList files = installDialog.GetFiles();
|
const QStringList files = installDialog.GetFiles();
|
||||||
const bool overwrite_files = installDialog.ShouldOverwriteFiles();
|
|
||||||
|
|
||||||
int count = 0;
|
int remaining = filenames.size();
|
||||||
const int total_count = filenames.size();
|
|
||||||
|
// This would only overflow above 2^43 bytes (8.796 TB)
|
||||||
|
int total_size = 0;
|
||||||
|
for (const QString& file : files) {
|
||||||
|
total_size += static_cast<int>(QFile(file).size() / 0x1000);
|
||||||
|
}
|
||||||
|
if (total_size < 0) {
|
||||||
|
LOG_CRITICAL(Frontend, "Attempting to install too many files, aborting.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QStringList new_files{}; // Newly installed files that do not yet exist in the NAND
|
QStringList new_files{}; // Newly installed files that do not yet exist in the NAND
|
||||||
QStringList overwritten_files{}; // Files that overwrote those existing in the NAND
|
QStringList overwritten_files{}; // Files that overwrote those existing in the NAND
|
||||||
QStringList existing_files{}; // Files that were not installed as they already exist in the NAND
|
|
||||||
QStringList failed_files{}; // Files that failed to install due to errors
|
QStringList failed_files{}; // Files that failed to install due to errors
|
||||||
|
|
||||||
ui.action_Install_File_NAND->setEnabled(false);
|
ui.action_Install_File_NAND->setEnabled(false);
|
||||||
|
|
||||||
QProgressDialog install_progress(QStringLiteral(""), tr("Cancel"), 0, total_count, this);
|
install_progress = new QProgressDialog(QStringLiteral(""), tr("Cancel"), 0, total_size, this);
|
||||||
install_progress.setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint &
|
install_progress->setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint &
|
||||||
~Qt::WindowMaximizeButtonHint);
|
~Qt::WindowMaximizeButtonHint);
|
||||||
install_progress.setAutoClose(false);
|
install_progress->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||||
install_progress.setFixedWidth(installDialog.GetMinimumWidth());
|
install_progress->setFixedWidth(installDialog.GetMinimumWidth() + 40);
|
||||||
install_progress.show();
|
install_progress->show();
|
||||||
|
|
||||||
for (const QString& file : files) {
|
for (const QString& file : files) {
|
||||||
install_progress.setWindowTitle(tr("%n file(s) remaining", "", total_count - count));
|
install_progress->setWindowTitle(tr("%n file(s) remaining", "", remaining));
|
||||||
install_progress.setLabelText(
|
install_progress->setLabelText(
|
||||||
tr("Installing file \"%1\"...").arg(QFileInfo(file).fileName()));
|
tr("Installing file \"%1\"...").arg(QFileInfo(file).fileName()));
|
||||||
|
|
||||||
QFuture<InstallResult> future;
|
QFuture<InstallResult> future;
|
||||||
|
@ -1642,19 +1656,21 @@ void GMainWindow::OnMenuInstallToNAND() {
|
||||||
|
|
||||||
if (file.endsWith(QStringLiteral("xci"), Qt::CaseInsensitive) ||
|
if (file.endsWith(QStringLiteral("xci"), Qt::CaseInsensitive) ||
|
||||||
file.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) {
|
file.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) {
|
||||||
future = QtConcurrent::run([this, &file, &overwrite_files, &install_progress] {
|
|
||||||
return InstallNSPXCI(file, overwrite_files, install_progress);
|
future = QtConcurrent::run([this, &file] { return InstallNSPXCI(file); });
|
||||||
});
|
|
||||||
|
|
||||||
while (!future.isFinished()) {
|
while (!future.isFinished()) {
|
||||||
QCoreApplication::processEvents();
|
QCoreApplication::processEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
result = future.result();
|
result = future.result();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
result = InstallNCA(file, overwrite_files, install_progress);
|
result = InstallNCA(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case InstallResult::Success:
|
case InstallResult::Success:
|
||||||
new_files.append(QFileInfo(file).fileName());
|
new_files.append(QFileInfo(file).fileName());
|
||||||
|
@ -1662,19 +1678,15 @@ void GMainWindow::OnMenuInstallToNAND() {
|
||||||
case InstallResult::Overwrite:
|
case InstallResult::Overwrite:
|
||||||
overwritten_files.append(QFileInfo(file).fileName());
|
overwritten_files.append(QFileInfo(file).fileName());
|
||||||
break;
|
break;
|
||||||
case InstallResult::AlreadyExists:
|
|
||||||
existing_files.append(QFileInfo(file).fileName());
|
|
||||||
break;
|
|
||||||
case InstallResult::Failure:
|
case InstallResult::Failure:
|
||||||
failed_files.append(QFileInfo(file).fileName());
|
failed_files.append(QFileInfo(file).fileName());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
install_progress.setValue(++count);
|
--remaining;
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
install_progress.close();
|
install_progress->close();
|
||||||
|
|
||||||
const QString install_results =
|
const QString install_results =
|
||||||
(new_files.isEmpty() ? QStringLiteral("")
|
(new_files.isEmpty() ? QStringLiteral("")
|
||||||
|
@ -1682,9 +1694,6 @@ void GMainWindow::OnMenuInstallToNAND() {
|
||||||
(overwritten_files.isEmpty()
|
(overwritten_files.isEmpty()
|
||||||
? QStringLiteral("")
|
? QStringLiteral("")
|
||||||
: tr("%n file(s) were overwritten\n", "", overwritten_files.size())) +
|
: tr("%n file(s) were overwritten\n", "", overwritten_files.size())) +
|
||||||
(existing_files.isEmpty()
|
|
||||||
? QStringLiteral("")
|
|
||||||
: tr("%n file(s) already exist in NAND\n", "", existing_files.size())) +
|
|
||||||
(failed_files.isEmpty() ? QStringLiteral("")
|
(failed_files.isEmpty() ? QStringLiteral("")
|
||||||
: tr("%n file(s) failed to install\n", "", failed_files.size()));
|
: tr("%n file(s) failed to install\n", "", failed_files.size()));
|
||||||
|
|
||||||
|
@ -1695,11 +1704,9 @@ void GMainWindow::OnMenuInstallToNAND() {
|
||||||
ui.action_Install_File_NAND->setEnabled(true);
|
ui.action_Install_File_NAND->setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
InstallResult GMainWindow::InstallNSPXCI(const QString& filename, bool overwrite_files,
|
InstallResult GMainWindow::InstallNSPXCI(const QString& filename) {
|
||||||
QProgressDialog& install_progress) {
|
const auto qt_raw_copy = [this](const FileSys::VirtualFile& src,
|
||||||
const auto qt_raw_copy = [this, &install_progress](const FileSys::VirtualFile& src,
|
const FileSys::VirtualFile& dest, std::size_t block_size) {
|
||||||
const FileSys::VirtualFile& dest,
|
|
||||||
std::size_t block_size) {
|
|
||||||
if (src == nullptr || dest == nullptr) {
|
if (src == nullptr || dest == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1710,11 +1717,13 @@ InstallResult GMainWindow::InstallNSPXCI(const QString& filename, bool overwrite
|
||||||
std::array<u8, 0x1000> buffer{};
|
std::array<u8, 0x1000> buffer{};
|
||||||
|
|
||||||
for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
|
for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
|
||||||
if (install_progress.wasCanceled()) {
|
if (install_progress->wasCanceled()) {
|
||||||
dest->Resize(0);
|
dest->Resize(0);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit UpdateInstallProgress();
|
||||||
|
|
||||||
const auto read = src->Read(buffer.data(), buffer.size(), i);
|
const auto read = src->Read(buffer.data(), buffer.size(), i);
|
||||||
dest->Write(buffer.data(), read, i);
|
dest->Write(buffer.data(), read, i);
|
||||||
}
|
}
|
||||||
|
@ -1739,32 +1748,19 @@ InstallResult GMainWindow::InstallNSPXCI(const QString& filename, bool overwrite
|
||||||
}
|
}
|
||||||
const auto res =
|
const auto res =
|
||||||
Core::System::GetInstance().GetFileSystemController().GetUserNANDContents()->InstallEntry(
|
Core::System::GetInstance().GetFileSystemController().GetUserNANDContents()->InstallEntry(
|
||||||
*nsp, false, qt_raw_copy);
|
*nsp, true, qt_raw_copy);
|
||||||
if (res == FileSys::InstallResult::Success) {
|
if (res == FileSys::InstallResult::Success) {
|
||||||
return InstallResult::Success;
|
return InstallResult::Success;
|
||||||
} else if (res == FileSys::InstallResult::ErrorAlreadyExists) {
|
} else if (res == FileSys::InstallResult::ErrorAlreadyExists) {
|
||||||
if (overwrite_files) {
|
|
||||||
const auto res2 = Core::System::GetInstance()
|
|
||||||
.GetFileSystemController()
|
|
||||||
.GetUserNANDContents()
|
|
||||||
->InstallEntry(*nsp, true, qt_raw_copy);
|
|
||||||
if (res2 != FileSys::InstallResult::Success) {
|
|
||||||
return InstallResult::Failure;
|
|
||||||
}
|
|
||||||
return InstallResult::Overwrite;
|
return InstallResult::Overwrite;
|
||||||
} else {
|
|
||||||
return InstallResult::AlreadyExists;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return InstallResult::Failure;
|
return InstallResult::Failure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InstallResult GMainWindow::InstallNCA(const QString& filename, bool overwrite_files,
|
InstallResult GMainWindow::InstallNCA(const QString& filename) {
|
||||||
QProgressDialog& install_progress) {
|
const auto qt_raw_copy = [this](const FileSys::VirtualFile& src,
|
||||||
const auto qt_raw_copy = [this, &install_progress](const FileSys::VirtualFile& src,
|
const FileSys::VirtualFile& dest, std::size_t block_size) {
|
||||||
const FileSys::VirtualFile& dest,
|
|
||||||
std::size_t block_size) {
|
|
||||||
if (src == nullptr || dest == nullptr) {
|
if (src == nullptr || dest == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1775,11 +1771,13 @@ InstallResult GMainWindow::InstallNCA(const QString& filename, bool overwrite_fi
|
||||||
std::array<u8, 0x1000> buffer{};
|
std::array<u8, 0x1000> buffer{};
|
||||||
|
|
||||||
for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
|
for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
|
||||||
if (install_progress.wasCanceled()) {
|
if (install_progress->wasCanceled()) {
|
||||||
dest->Resize(0);
|
dest->Resize(0);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit UpdateInstallProgress();
|
||||||
|
|
||||||
const auto read = src->Read(buffer.data(), buffer.size(), i);
|
const auto read = src->Read(buffer.data(), buffer.size(), i);
|
||||||
dest->Write(buffer.data(), read, i);
|
dest->Write(buffer.data(), read, i);
|
||||||
}
|
}
|
||||||
|
@ -1830,30 +1828,18 @@ InstallResult GMainWindow::InstallNCA(const QString& filename, bool overwrite_fi
|
||||||
res = Core::System::GetInstance()
|
res = Core::System::GetInstance()
|
||||||
.GetFileSystemController()
|
.GetFileSystemController()
|
||||||
.GetUserNANDContents()
|
.GetUserNANDContents()
|
||||||
->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy);
|
->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy);
|
||||||
} else {
|
} else {
|
||||||
res = Core::System::GetInstance()
|
res = Core::System::GetInstance()
|
||||||
.GetFileSystemController()
|
.GetFileSystemController()
|
||||||
.GetSystemNANDContents()
|
.GetSystemNANDContents()
|
||||||
->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy);
|
->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res == FileSys::InstallResult::Success) {
|
if (res == FileSys::InstallResult::Success) {
|
||||||
return InstallResult::Success;
|
return InstallResult::Success;
|
||||||
} else if (res == FileSys::InstallResult::ErrorAlreadyExists) {
|
} else if (res == FileSys::InstallResult::ErrorAlreadyExists) {
|
||||||
if (overwrite_files) {
|
|
||||||
const auto res2 =
|
|
||||||
Core::System::GetInstance()
|
|
||||||
.GetFileSystemController()
|
|
||||||
.GetUserNANDContents()
|
|
||||||
->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy);
|
|
||||||
if (res2 != FileSys::InstallResult::Success) {
|
|
||||||
return InstallResult::Failure;
|
|
||||||
}
|
|
||||||
return InstallResult::Overwrite;
|
return InstallResult::Overwrite;
|
||||||
} else {
|
|
||||||
return InstallResult::AlreadyExists;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return InstallResult::Failure;
|
return InstallResult::Failure;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,6 @@ enum class EmulatedDirectoryTarget {
|
||||||
enum class InstallResult {
|
enum class InstallResult {
|
||||||
Success,
|
Success,
|
||||||
Overwrite,
|
Overwrite,
|
||||||
AlreadyExists,
|
|
||||||
Failure,
|
Failure,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -110,6 +109,8 @@ signals:
|
||||||
// Signal that tells widgets to update icons to use the current theme
|
// Signal that tells widgets to update icons to use the current theme
|
||||||
void UpdateThemedIcons();
|
void UpdateThemedIcons();
|
||||||
|
|
||||||
|
void UpdateInstallProgress();
|
||||||
|
|
||||||
void ErrorDisplayFinished();
|
void ErrorDisplayFinished();
|
||||||
|
|
||||||
void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid);
|
void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid);
|
||||||
|
@ -206,6 +207,7 @@ private slots:
|
||||||
void OnGameListOpenPerGameProperties(const std::string& file);
|
void OnGameListOpenPerGameProperties(const std::string& file);
|
||||||
void OnMenuLoadFile();
|
void OnMenuLoadFile();
|
||||||
void OnMenuLoadFolder();
|
void OnMenuLoadFolder();
|
||||||
|
void IncrementInstallProgress();
|
||||||
void OnMenuInstallToNAND();
|
void OnMenuInstallToNAND();
|
||||||
void OnMenuRecentFile();
|
void OnMenuRecentFile();
|
||||||
void OnConfigure();
|
void OnConfigure();
|
||||||
|
@ -226,10 +228,8 @@ private slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id);
|
std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id);
|
||||||
InstallResult InstallNSPXCI(const QString& filename, bool overwrite_files,
|
InstallResult InstallNSPXCI(const QString& filename);
|
||||||
QProgressDialog& install_progress);
|
InstallResult InstallNCA(const QString& filename);
|
||||||
InstallResult InstallNCA(const QString& filename, bool overwrite_files,
|
|
||||||
QProgressDialog& install_progress);
|
|
||||||
void UpdateWindowTitle(const std::string& title_name = {},
|
void UpdateWindowTitle(const std::string& title_name = {},
|
||||||
const std::string& title_version = {});
|
const std::string& title_version = {});
|
||||||
void UpdateStatusBar();
|
void UpdateStatusBar();
|
||||||
|
@ -284,6 +284,9 @@ private:
|
||||||
|
|
||||||
HotkeyRegistry hotkey_registry;
|
HotkeyRegistry hotkey_registry;
|
||||||
|
|
||||||
|
// Install progress dialog
|
||||||
|
QProgressDialog* install_progress;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void dropEvent(QDropEvent* event) override;
|
void dropEvent(QDropEvent* event) override;
|
||||||
void dragEnterEvent(QDragEnterEvent* event) override;
|
void dragEnterEvent(QDragEnterEvent* event) override;
|
||||||
|
|
Reference in New Issue