mirror of
https://github.com/Dark98/threeSD.git
synced 2026-07-02 16:49:04 +00:00
Add a rate limiter to Qt's progress dialog
To work around a macOS specific issue where theh progress bar is not updated. With this the previous workaround for other OSes also isn't needed.
This commit is contained in:
@@ -15,6 +15,8 @@ add_executable(threeSD
|
|||||||
helpers/frontend_common.h
|
helpers/frontend_common.h
|
||||||
helpers/multi_job.cpp
|
helpers/multi_job.cpp
|
||||||
helpers/multi_job.h
|
helpers/multi_job.h
|
||||||
|
helpers/rate_limited_progress_dialog.cpp
|
||||||
|
helpers/rate_limited_progress_dialog.h
|
||||||
helpers/simple_job.cpp
|
helpers/simple_job.cpp
|
||||||
helpers/simple_job.h
|
helpers/simple_job.h
|
||||||
cia_build_dialog.cpp
|
cia_build_dialog.cpp
|
||||||
|
|||||||
@@ -1,66 +1,67 @@
|
|||||||
// Copyright 2019 threeSD Project
|
// Copyright 2019 threeSD Project
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include "frontend/helpers/multi_job.h"
|
#include "frontend/helpers/multi_job.h"
|
||||||
|
|
||||||
MultiJob::MultiJob(QObject* parent, Core::SDMCImporter& importer_,
|
MultiJob::MultiJob(QObject* parent, Core::SDMCImporter& importer_,
|
||||||
std::vector<Core::ContentSpecifier> contents_, ExecuteFunc execute_func_,
|
std::vector<Core::ContentSpecifier> contents_, ExecuteFunc execute_func_,
|
||||||
AbortFunc abort_func_)
|
AbortFunc abort_func_)
|
||||||
: QThread(parent), importer(importer_), contents(std::move(contents_)),
|
: QThread(parent), importer(importer_), contents(std::move(contents_)),
|
||||||
execute_func(std::move(execute_func_)), abort_func(abort_func_) {}
|
execute_func(std::move(execute_func_)), abort_func(abort_func_) {}
|
||||||
|
|
||||||
MultiJob::~MultiJob() = default;
|
MultiJob::~MultiJob() = default;
|
||||||
|
|
||||||
void MultiJob::run() {
|
void MultiJob::run() {
|
||||||
u64 total_size = 0;
|
u64 total_size = 0;
|
||||||
for (const auto& content : contents) {
|
for (const auto& content : contents) {
|
||||||
total_size += content.maximum_size;
|
total_size += content.maximum_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t count = 0;
|
std::size_t count = 0;
|
||||||
int eta = -1;
|
int eta = -1;
|
||||||
|
|
||||||
const auto initial_time = std::chrono::steady_clock::now();
|
const auto initial_time = std::chrono::steady_clock::now();
|
||||||
const auto UpdateETA = [total_size, &eta, initial_time](u64 size_imported) {
|
const auto UpdateETA = [total_size, &eta, initial_time](u64 size_imported) {
|
||||||
if (size_imported < 10 * 1024 * 1024) { // 10M Threshold
|
if (size_imported < 10 * 1024 * 1024) { // 10M Threshold
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
const u64 time_elapsed =
|
const u64 time_elapsed =
|
||||||
duration_cast<milliseconds>(steady_clock::now() - initial_time).count();
|
duration_cast<milliseconds>(steady_clock::now() - initial_time).count();
|
||||||
eta =
|
eta =
|
||||||
static_cast<int>(time_elapsed * (total_size - size_imported) / (size_imported) / 1000);
|
static_cast<int>(time_elapsed * (total_size - size_imported) / (size_imported) / 1000);
|
||||||
};
|
};
|
||||||
const auto Callback = [this, &eta, &UpdateETA](u64 current_imported_size,
|
const auto Callback = [this, &eta, &UpdateETA](u64 current_imported_size,
|
||||||
u64 total_imported_size, u64 /*total_size*/) {
|
u64 total_imported_size, u64 /*total_size*/) {
|
||||||
UpdateETA(total_imported_size);
|
UpdateETA(total_imported_size);
|
||||||
emit ProgressUpdated(current_imported_size, total_imported_size, eta);
|
emit ProgressUpdated(current_imported_size, total_imported_size, eta);
|
||||||
};
|
};
|
||||||
|
|
||||||
Common::ProgressCallbackWrapper wrapper{total_size};
|
Common::ProgressCallbackWrapper wrapper{total_size};
|
||||||
for (const auto& content : contents) {
|
for (const auto& content : contents) {
|
||||||
emit NextContent(count + 1, content, eta);
|
emit NextContent(count + 1, wrapper.current_done_size + wrapper.current_pending_size,
|
||||||
if (!execute_func(importer, content, wrapper.Wrap(Callback))) {
|
content, eta);
|
||||||
if (!cancelled) {
|
if (!execute_func(importer, content, wrapper.Wrap(Callback))) {
|
||||||
failed_contents.emplace_back(content);
|
if (!cancelled) {
|
||||||
}
|
failed_contents.emplace_back(content);
|
||||||
}
|
}
|
||||||
count++;
|
}
|
||||||
|
count++;
|
||||||
if (cancelled) {
|
|
||||||
break;
|
if (cancelled) {
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
emit Completed();
|
}
|
||||||
}
|
emit Completed();
|
||||||
|
}
|
||||||
void MultiJob::Cancel() {
|
|
||||||
cancelled.store(true);
|
void MultiJob::Cancel() {
|
||||||
abort_func(importer);
|
cancelled.store(true);
|
||||||
}
|
abort_func(importer);
|
||||||
|
}
|
||||||
std::vector<Core::ContentSpecifier> MultiJob::GetFailedContents() const {
|
|
||||||
return failed_contents;
|
std::vector<Core::ContentSpecifier> MultiJob::GetFailedContents() const {
|
||||||
}
|
return failed_contents;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,55 +1,56 @@
|
|||||||
// Copyright 2019 threeSD Project
|
// Copyright 2019 threeSD Project
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include "common/progress_callback.h"
|
#include "common/progress_callback.h"
|
||||||
#include "core/importer.h"
|
#include "core/importer.h"
|
||||||
|
|
||||||
class MultiJob : public QThread {
|
class MultiJob : public QThread {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using ExecuteFunc = std::function<bool(Core::SDMCImporter&, const Core::ContentSpecifier&,
|
using ExecuteFunc = std::function<bool(Core::SDMCImporter&, const Core::ContentSpecifier&,
|
||||||
const Common::ProgressCallback&)>;
|
const Common::ProgressCallback&)>;
|
||||||
using AbortFunc = std::function<void(Core::SDMCImporter&)>;
|
using AbortFunc = std::function<void(Core::SDMCImporter&)>;
|
||||||
|
|
||||||
explicit MultiJob(QObject* parent, Core::SDMCImporter& importer,
|
explicit MultiJob(QObject* parent, Core::SDMCImporter& importer,
|
||||||
std::vector<Core::ContentSpecifier> contents, ExecuteFunc execute_func,
|
std::vector<Core::ContentSpecifier> contents, ExecuteFunc execute_func,
|
||||||
AbortFunc abort_func);
|
AbortFunc abort_func);
|
||||||
~MultiJob() override;
|
~MultiJob() override;
|
||||||
|
|
||||||
void run() override;
|
void run() override;
|
||||||
void Cancel();
|
void Cancel();
|
||||||
|
|
||||||
std::vector<Core::ContentSpecifier> GetFailedContents() const;
|
std::vector<Core::ContentSpecifier> GetFailedContents() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/**
|
/**
|
||||||
* Called when progress is updated on the current content.
|
* Called when progress is updated on the current content.
|
||||||
* @param current_imported_size Imported size of the current content.
|
* @param current_imported_size Imported size of the current content.
|
||||||
* @param total_imported_size Total imported size taking all previous contents into
|
* @param total_imported_size Total imported size taking all previous contents into
|
||||||
* consideration.
|
* consideration.
|
||||||
* @param eta ETA in seconds, 0 when not determined.
|
* @param eta ETA in seconds, 0 when not determined.
|
||||||
*/
|
*/
|
||||||
void ProgressUpdated(u64 current_imported_size, u64 total_imported_size, int eta);
|
void ProgressUpdated(u64 current_imported_size, u64 total_imported_size, int eta);
|
||||||
|
|
||||||
/// Dumping of a content has been finished, go on to the next. Called at start as well.
|
/// Dumping of a content has been finished, go on to the next. Called at start as well.
|
||||||
void NextContent(std::size_t count, const Core::ContentSpecifier& next_content, int eta);
|
void NextContent(std::size_t count, u64 total_imported_size,
|
||||||
|
const Core::ContentSpecifier& next_content, int eta);
|
||||||
void Completed();
|
|
||||||
|
void Completed();
|
||||||
private:
|
|
||||||
std::atomic_bool cancelled{false};
|
private:
|
||||||
Core::SDMCImporter& importer;
|
std::atomic_bool cancelled{false};
|
||||||
std::vector<Core::ContentSpecifier> contents;
|
Core::SDMCImporter& importer;
|
||||||
std::vector<Core::ContentSpecifier> failed_contents;
|
std::vector<Core::ContentSpecifier> contents;
|
||||||
ExecuteFunc execute_func;
|
std::vector<Core::ContentSpecifier> failed_contents;
|
||||||
AbortFunc abort_func;
|
ExecuteFunc execute_func;
|
||||||
};
|
AbortFunc abort_func;
|
||||||
|
};
|
||||||
Q_DECLARE_METATYPE(Core::ContentSpecifier)
|
|
||||||
|
Q_DECLARE_METATYPE(Core::ContentSpecifier)
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
// Copyright 2021 Pengfei Zhu
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "frontend/helpers/rate_limited_progress_dialog.h"
|
||||||
|
|
||||||
|
RateLimitedProgressDialog::RateLimitedProgressDialog(const QString& label_text,
|
||||||
|
const QString& cancel_button_text, int minimum,
|
||||||
|
int maximum, QWidget* parent)
|
||||||
|
: QProgressDialog(label_text, cancel_button_text, minimum, maximum, parent) {
|
||||||
|
|
||||||
|
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||||
|
setWindowModality(Qt::WindowModal);
|
||||||
|
setMinimumDuration(0);
|
||||||
|
setValue(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
RateLimitedProgressDialog::~RateLimitedProgressDialog() = default;
|
||||||
|
|
||||||
|
void RateLimitedProgressDialog::Update(int progress, const QString& label_text) {
|
||||||
|
if (progress == maximum()) { // always set the maximum
|
||||||
|
setValue(progress);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto current_time = std::chrono::steady_clock::now();
|
||||||
|
if (current_time - last_update_time < MinimumInterval) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue(progress);
|
||||||
|
setLabelText(label_text);
|
||||||
|
last_update_time = current_time;
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// Copyright 2021 Pengfei Zhu
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <QProgressDialog>
|
||||||
|
|
||||||
|
class RateLimitedProgressDialog : public QProgressDialog {
|
||||||
|
public:
|
||||||
|
explicit RateLimitedProgressDialog(const QString& label_text, const QString& cancel_button_text,
|
||||||
|
int minimum, int maximum, QWidget* parent = nullptr);
|
||||||
|
~RateLimitedProgressDialog() override;
|
||||||
|
|
||||||
|
void Update(int progress, const QString& label_text);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::chrono::steady_clock::time_point last_update_time = std::chrono::steady_clock::now();
|
||||||
|
static constexpr auto MinimumInterval = std::chrono::milliseconds{100};
|
||||||
|
};
|
||||||
@@ -3,9 +3,8 @@
|
|||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QProgressBar>
|
|
||||||
#include <QProgressDialog>
|
|
||||||
#include "frontend/helpers/frontend_common.h"
|
#include "frontend/helpers/frontend_common.h"
|
||||||
|
#include "frontend/helpers/rate_limited_progress_dialog.h"
|
||||||
#include "frontend/helpers/simple_job.h"
|
#include "frontend/helpers/simple_job.h"
|
||||||
|
|
||||||
SimpleJob::SimpleJob(QObject* parent, ExecuteFunc execute_, AbortFunc abort_)
|
SimpleJob::SimpleJob(QObject* parent, ExecuteFunc execute_, AbortFunc abort_)
|
||||||
@@ -30,34 +29,25 @@ void SimpleJob::Cancel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SimpleJob::StartWithProgressDialog(QWidget* widget) {
|
void SimpleJob::StartWithProgressDialog(QWidget* widget) {
|
||||||
// We need to create the bar ourselves to circumvent an issue caused by modal ProgressDialog's
|
auto* dialog = new RateLimitedProgressDialog(tr("Initializing..."), tr("Cancel"), 0, 0, widget);
|
||||||
// event handling.
|
connect(this, &SimpleJob::ProgressUpdated, this, [dialog](u64 current, u64 total) {
|
||||||
auto* bar = new QProgressBar(widget);
|
if (dialog->wasCanceled()) {
|
||||||
bar->setRange(0, 100);
|
return;
|
||||||
bar->setValue(0);
|
}
|
||||||
|
|
||||||
auto* dialog = new QProgressDialog(tr("Initializing..."), tr("Cancel"), 0, 0, widget);
|
|
||||||
dialog->setWindowFlags(dialog->windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
|
||||||
dialog->setWindowModality(Qt::WindowModal);
|
|
||||||
dialog->setBar(bar);
|
|
||||||
dialog->setMinimumDuration(0);
|
|
||||||
|
|
||||||
connect(this, &SimpleJob::ProgressUpdated, this, [bar, dialog](u64 current, u64 total) {
|
|
||||||
// Try to map total to int range
|
// Try to map total to int range
|
||||||
// This is equal to ceil(total / INT_MAX)
|
// This is equal to ceil(total / INT_MAX)
|
||||||
const u64 multiplier =
|
const u64 multiplier =
|
||||||
(total + std::numeric_limits<int>::max() - 1) / std::numeric_limits<int>::max();
|
(total + std::numeric_limits<int>::max() - 1) / std::numeric_limits<int>::max();
|
||||||
bar->setMaximum(static_cast<int>(total / multiplier));
|
dialog->setMaximum(static_cast<int>(total / multiplier));
|
||||||
bar->setValue(static_cast<int>(current / multiplier));
|
dialog->Update(static_cast<int>(current / multiplier),
|
||||||
dialog->setLabelText(
|
tr("%1 / %2").arg(ReadableByteSize(current), ReadableByteSize(total)));
|
||||||
tr("%1 / %2").arg(ReadableByteSize(current)).arg(ReadableByteSize(total)));
|
|
||||||
});
|
});
|
||||||
connect(this, &SimpleJob::ErrorOccured, this, [widget, dialog] {
|
connect(this, &SimpleJob::ErrorOccured, this, [widget, dialog] {
|
||||||
QMessageBox::critical(widget, tr("threeSD"),
|
QMessageBox::critical(widget, tr("threeSD"),
|
||||||
tr("Operation failed. Please refer to the log."));
|
tr("Operation failed. Please refer to the log."));
|
||||||
dialog->hide();
|
dialog->hide();
|
||||||
});
|
});
|
||||||
connect(this, &SimpleJob::Completed, this, [dialog] { dialog->setValue(dialog->maximum()); });
|
connect(this, &SimpleJob::Completed, dialog, &QProgressDialog::hide);
|
||||||
connect(dialog, &QProgressDialog::canceled, this, &SimpleJob::Cancel);
|
connect(dialog, &QProgressDialog::canceled, this, &SimpleJob::Cancel);
|
||||||
|
|
||||||
start();
|
start();
|
||||||
|
|||||||
@@ -12,8 +12,6 @@
|
|||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QProgressBar>
|
|
||||||
#include <QProgressDialog>
|
|
||||||
#include <QStorageInfo>
|
#include <QStorageInfo>
|
||||||
#include <QtConcurrent/QtConcurrentRun>
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
@@ -23,6 +21,7 @@
|
|||||||
#include "frontend/cia_build_dialog.h"
|
#include "frontend/cia_build_dialog.h"
|
||||||
#include "frontend/helpers/frontend_common.h"
|
#include "frontend/helpers/frontend_common.h"
|
||||||
#include "frontend/helpers/multi_job.h"
|
#include "frontend/helpers/multi_job.h"
|
||||||
|
#include "frontend/helpers/rate_limited_progress_dialog.h"
|
||||||
#include "frontend/helpers/simple_job.h"
|
#include "frontend/helpers/simple_job.h"
|
||||||
#include "frontend/import_dialog.h"
|
#include "frontend/import_dialog.h"
|
||||||
#include "frontend/title_info_dialog.h"
|
#include "frontend/title_info_dialog.h"
|
||||||
@@ -128,12 +127,9 @@ void ImportDialog::SetContentSizes(int previous_width, int previous_height) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ImportDialog::RelistContent() {
|
void ImportDialog::RelistContent() {
|
||||||
auto* dialog = new QProgressDialog(tr("Loading Contents..."), tr("Cancel"), 0, 0, this);
|
auto* dialog =
|
||||||
dialog->setWindowFlags(dialog->windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
new RateLimitedProgressDialog(tr("Loading Contents..."), tr("Cancel"), 0, 0, this);
|
||||||
dialog->setWindowModality(Qt::WindowModal);
|
|
||||||
dialog->setCancelButton(nullptr);
|
dialog->setCancelButton(nullptr);
|
||||||
dialog->setMinimumDuration(0);
|
|
||||||
dialog->setValue(0);
|
|
||||||
|
|
||||||
using FutureWatcher = QFutureWatcher<void>;
|
using FutureWatcher = QFutureWatcher<void>;
|
||||||
auto* future_watcher = new FutureWatcher(this);
|
auto* future_watcher = new FutureWatcher(this);
|
||||||
@@ -601,48 +597,47 @@ void ImportDialog::RunMultiJob(MultiJob* job, std::size_t total_count, u64 total
|
|||||||
label->setWordWrap(true);
|
label->setWordWrap(true);
|
||||||
label->setFixedWidth(600);
|
label->setFixedWidth(600);
|
||||||
|
|
||||||
// We need to create the bar ourselves to circumvent an issue caused by modal ProgressDialog's
|
auto* dialog = new RateLimitedProgressDialog(tr("Initializing..."), tr("Cancel"), 0,
|
||||||
// event handling.
|
static_cast<int>(total_size / multiplier), this);
|
||||||
auto* bar = new QProgressBar(this);
|
|
||||||
bar->setRange(0, static_cast<int>(total_size / multiplier));
|
|
||||||
bar->setValue(0);
|
|
||||||
|
|
||||||
auto* dialog = new QProgressDialog(tr("Initializing..."), tr("Cancel"), 0, 0, this);
|
|
||||||
dialog->setWindowFlags(dialog->windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
|
||||||
dialog->setWindowModality(Qt::WindowModal);
|
|
||||||
dialog->setBar(bar);
|
|
||||||
dialog->setLabel(label);
|
dialog->setLabel(label);
|
||||||
dialog->setMinimumDuration(0);
|
|
||||||
|
|
||||||
connect(job, &MultiJob::NextContent, this,
|
connect(job, &MultiJob::NextContent, this,
|
||||||
[this, dialog, total_count](std::size_t count,
|
[this, dialog, multiplier, total_count](std::size_t count, u64 total_imported_size,
|
||||||
const Core::ContentSpecifier& next_content, int eta) {
|
const Core::ContentSpecifier& next_content,
|
||||||
dialog->setLabelText(
|
int eta) {
|
||||||
tr("<p>(%1/%2) %3 (%4)</p><p> </p><p align=\"right\">%5</p>")
|
if (dialog->wasCanceled()) {
|
||||||
.arg(count)
|
return;
|
||||||
.arg(total_count)
|
}
|
||||||
.arg(GetContentName(next_content))
|
dialog->Update(static_cast<int>(total_imported_size / multiplier),
|
||||||
.arg(GetContentTypeName<false>(next_content.type))
|
tr("<p>(%1/%2) %3 (%4)</p><p> </p><p align=\"right\">%5</p>")
|
||||||
.arg(FormatETA(eta)));
|
.arg(count)
|
||||||
|
.arg(total_count)
|
||||||
|
.arg(GetContentName(next_content))
|
||||||
|
.arg(GetContentTypeName<false>(next_content.type))
|
||||||
|
.arg(FormatETA(eta)));
|
||||||
current_content = next_content;
|
current_content = next_content;
|
||||||
current_count = count;
|
current_count = count;
|
||||||
});
|
});
|
||||||
connect(job, &MultiJob::ProgressUpdated, this,
|
connect(
|
||||||
[this, bar, dialog, multiplier, total_count](u64 current_imported_size,
|
job, &MultiJob::ProgressUpdated, this,
|
||||||
u64 total_imported_size, int eta) {
|
[this, dialog, multiplier, total_count](u64 current_imported_size, u64 total_imported_size,
|
||||||
bar->setValue(static_cast<int>(total_imported_size / multiplier));
|
int eta) {
|
||||||
dialog->setLabelText(tr("<p>(%1/%2) %3 (%4)</p><p align=\"center\">%5 "
|
if (dialog->wasCanceled()) {
|
||||||
"/ %6</p><p align=\"right\">%7</p>")
|
return;
|
||||||
.arg(current_count)
|
}
|
||||||
.arg(total_count)
|
dialog->Update(
|
||||||
.arg(GetContentName(current_content))
|
static_cast<int>(total_imported_size / multiplier),
|
||||||
.arg(GetContentTypeName<false>(current_content.type))
|
tr("<p>(%1/%2) %3 (%4)</p><p align=\"center\">%5 / %6</p><p align=\"right\">%7</p>")
|
||||||
.arg(ReadableByteSize(current_imported_size))
|
.arg(current_count)
|
||||||
.arg(ReadableByteSize(current_content.maximum_size))
|
.arg(total_count)
|
||||||
.arg(FormatETA(eta)));
|
.arg(GetContentName(current_content))
|
||||||
});
|
.arg(GetContentTypeName<false>(current_content.type))
|
||||||
|
.arg(ReadableByteSize(current_imported_size))
|
||||||
|
.arg(ReadableByteSize(current_content.maximum_size))
|
||||||
|
.arg(FormatETA(eta)));
|
||||||
|
});
|
||||||
connect(job, &MultiJob::Completed, this, [this, dialog, job] {
|
connect(job, &MultiJob::Completed, this, [this, dialog, job] {
|
||||||
dialog->setValue(dialog->maximum());
|
dialog->hide();
|
||||||
|
|
||||||
const auto failed_contents = job->GetFailedContents();
|
const auto failed_contents = job->GetFailedContents();
|
||||||
if (failed_contents.empty()) {
|
if (failed_contents.empty()) {
|
||||||
@@ -662,13 +657,9 @@ void ImportDialog::RunMultiJob(MultiJob* job, std::size_t total_count, u64 total
|
|||||||
});
|
});
|
||||||
connect(dialog, &QProgressDialog::canceled, this, [this, job] {
|
connect(dialog, &QProgressDialog::canceled, this, [this, job] {
|
||||||
// Add yet-another-ProgressDialog to indicate cancel progress
|
// Add yet-another-ProgressDialog to indicate cancel progress
|
||||||
auto* cancel_dialog = new QProgressDialog(tr("Canceling..."), tr("Cancel"), 0, 0, this);
|
auto* cancel_dialog =
|
||||||
cancel_dialog->setWindowFlags(cancel_dialog->windowFlags() &
|
new RateLimitedProgressDialog(tr("Canceling..."), tr("Cancel"), 0, 0, this);
|
||||||
(~Qt::WindowContextHelpButtonHint));
|
|
||||||
cancel_dialog->setWindowModality(Qt::WindowModal);
|
|
||||||
cancel_dialog->setCancelButton(nullptr);
|
cancel_dialog->setCancelButton(nullptr);
|
||||||
cancel_dialog->setMinimumDuration(0);
|
|
||||||
cancel_dialog->setValue(0);
|
|
||||||
connect(job, &MultiJob::Completed, cancel_dialog, &QProgressDialog::hide);
|
connect(job, &MultiJob::Completed, cancel_dialog, &QProgressDialog::hide);
|
||||||
job->Cancel();
|
job->Cancel();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user