DolphinQt: Run tasks that use progress dialogs on separate threads
This commit is contained in:
parent
4ff855921e
commit
c6ee767851
|
@ -224,6 +224,7 @@ add_executable(dolphin-emu
|
||||||
QtUtils/FlowLayout.h
|
QtUtils/FlowLayout.h
|
||||||
QtUtils/ModalMessageBox.cpp
|
QtUtils/ModalMessageBox.cpp
|
||||||
QtUtils/ModalMessageBox.h
|
QtUtils/ModalMessageBox.h
|
||||||
|
QtUtils/ParallelProgressDialog.h
|
||||||
QtUtils/ImageConverter.cpp
|
QtUtils/ImageConverter.cpp
|
||||||
QtUtils/ImageConverter.h
|
QtUtils/ImageConverter.h
|
||||||
QtUtils/WindowActivationEventFilter.cpp
|
QtUtils/WindowActivationEventFilter.cpp
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QProgressDialog>
|
|
||||||
#include <QStandardItemModel>
|
#include <QStandardItemModel>
|
||||||
#include <QStyleFactory>
|
#include <QStyleFactory>
|
||||||
#include <QTreeView>
|
#include <QTreeView>
|
||||||
|
@ -23,6 +22,7 @@
|
||||||
#include "DiscIO/Volume.h"
|
#include "DiscIO/Volume.h"
|
||||||
|
|
||||||
#include "DolphinQt/QtUtils/ModalMessageBox.h"
|
#include "DolphinQt/QtUtils/ModalMessageBox.h"
|
||||||
|
#include "DolphinQt/QtUtils/ParallelProgressDialog.h"
|
||||||
#include "DolphinQt/Resources.h"
|
#include "DolphinQt/Resources.h"
|
||||||
|
|
||||||
#include "UICommon/UICommon.h"
|
#include "UICommon/UICommon.h"
|
||||||
|
@ -282,28 +282,34 @@ void FilesystemWidget::ExtractDirectory(const DiscIO::Partition& partition, cons
|
||||||
std::unique_ptr<DiscIO::FileInfo> info = filesystem->FindFileInfo(path.toStdString());
|
std::unique_ptr<DiscIO::FileInfo> info = filesystem->FindFileInfo(path.toStdString());
|
||||||
u32 size = info->GetTotalChildren();
|
u32 size = info->GetTotalChildren();
|
||||||
|
|
||||||
QProgressDialog* dialog = new QProgressDialog(this);
|
ParallelProgressDialog dialog(this);
|
||||||
dialog->setWindowFlags(dialog->windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
dialog.GetRaw()->setMinimum(0);
|
||||||
dialog->setMinimum(0);
|
dialog.GetRaw()->setMaximum(size);
|
||||||
dialog->setMaximum(size);
|
dialog.GetRaw()->setWindowTitle(tr("Progress"));
|
||||||
dialog->show();
|
|
||||||
dialog->setWindowTitle(tr("Progress"));
|
|
||||||
|
|
||||||
bool all = path.isEmpty();
|
const bool all = path.isEmpty();
|
||||||
|
|
||||||
DiscIO::ExportDirectory(
|
std::future<void> future = std::async(std::launch::async, [&] {
|
||||||
*m_volume, partition, *info, true, path.toStdString(), out.toStdString(),
|
int progress = 0;
|
||||||
[all, dialog](const std::string& current) {
|
|
||||||
dialog->setLabelText(
|
|
||||||
(all ? QObject::tr("Extracting All Files...") : QObject::tr("Extracting Directory..."))
|
|
||||||
.append(QStringLiteral(" %1").arg(QString::fromStdString(current))));
|
|
||||||
dialog->setValue(dialog->value() + 1);
|
|
||||||
|
|
||||||
QCoreApplication::processEvents();
|
DiscIO::ExportDirectory(
|
||||||
return dialog->wasCanceled();
|
*m_volume, partition, *info, true, path.toStdString(), out.toStdString(),
|
||||||
});
|
[all, &dialog, &progress](const std::string& current) {
|
||||||
|
dialog.SetLabelText(
|
||||||
|
(all ? QObject::tr("Extracting All Files...") :
|
||||||
|
QObject::tr("Extracting Directory..."))
|
||||||
|
.append(QStringLiteral(" %1").arg(QString::fromStdString(current))));
|
||||||
|
dialog.SetValue(++progress);
|
||||||
|
|
||||||
dialog->close();
|
QCoreApplication::processEvents();
|
||||||
|
return dialog.WasCanceled();
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog.Reset();
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog.GetRaw()->exec();
|
||||||
|
future.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilesystemWidget::ExtractFile(const DiscIO::Partition& partition, const QString& path,
|
void FilesystemWidget::ExtractFile(const DiscIO::Partition& partition, const QString& path,
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#include <QGroupBox>
|
#include <QGroupBox>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QProgressDialog>
|
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QTextEdit>
|
#include <QTextEdit>
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,9 @@
|
||||||
|
|
||||||
#include "DolphinQt/Config/VerifyWidget.h"
|
#include "DolphinQt/Config/VerifyWidget.h"
|
||||||
|
|
||||||
|
#include <future>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -12,12 +14,12 @@
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QProgressDialog>
|
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "DiscIO/Volume.h"
|
#include "DiscIO/Volume.h"
|
||||||
#include "DiscIO/VolumeVerifier.h"
|
#include "DiscIO/VolumeVerifier.h"
|
||||||
|
#include "DolphinQt/QtUtils/ParallelProgressDialog.h"
|
||||||
|
|
||||||
VerifyWidget::VerifyWidget(std::shared_ptr<DiscIO::Volume> volume) : m_volume(std::move(volume))
|
VerifyWidget::VerifyWidget(std::shared_ptr<DiscIO::Volume> volume) : m_volume(std::move(volume))
|
||||||
{
|
{
|
||||||
|
@ -131,33 +133,44 @@ void VerifyWidget::Verify()
|
||||||
// We have to divide the number of processed bytes with something so it won't make ints overflow
|
// We have to divide the number of processed bytes with something so it won't make ints overflow
|
||||||
constexpr int DIVISOR = 0x100;
|
constexpr int DIVISOR = 0x100;
|
||||||
|
|
||||||
QProgressDialog progress(tr("Verifying"), tr("Cancel"), 0, verifier.GetTotalBytes() / DIVISOR,
|
ParallelProgressDialog progress(tr("Verifying"), tr("Cancel"), 0,
|
||||||
this);
|
static_cast<int>(verifier.GetTotalBytes() / DIVISOR), this);
|
||||||
progress.setWindowTitle(tr("Verifying"));
|
progress.GetRaw()->setWindowTitle(tr("Verifying"));
|
||||||
progress.setWindowFlags(progress.windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
progress.GetRaw()->setMinimumDuration(500);
|
||||||
progress.setMinimumDuration(500);
|
progress.GetRaw()->setWindowModality(Qt::WindowModal);
|
||||||
progress.setWindowModality(Qt::WindowModal);
|
|
||||||
|
|
||||||
verifier.Start();
|
auto future =
|
||||||
while (verifier.GetBytesProcessed() != verifier.GetTotalBytes())
|
std::async(std::launch::async,
|
||||||
{
|
[&verifier, &progress]() -> std::optional<DiscIO::VolumeVerifier::Result> {
|
||||||
progress.setValue(verifier.GetBytesProcessed() / DIVISOR);
|
progress.SetValue(0);
|
||||||
if (progress.wasCanceled())
|
verifier.Start();
|
||||||
return;
|
while (verifier.GetBytesProcessed() != verifier.GetTotalBytes())
|
||||||
|
{
|
||||||
|
progress.SetValue(static_cast<int>(verifier.GetBytesProcessed() / DIVISOR));
|
||||||
|
if (progress.WasCanceled())
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
verifier.Process();
|
verifier.Process();
|
||||||
}
|
}
|
||||||
verifier.Finish();
|
verifier.Finish();
|
||||||
|
|
||||||
DiscIO::VolumeVerifier::Result result = verifier.GetResult();
|
const DiscIO::VolumeVerifier::Result result = verifier.GetResult();
|
||||||
progress.setValue(verifier.GetBytesProcessed() / DIVISOR);
|
progress.Reset();
|
||||||
|
|
||||||
m_summary_text->setText(QString::fromStdString(result.summary_text));
|
return result;
|
||||||
|
});
|
||||||
|
progress.GetRaw()->exec();
|
||||||
|
|
||||||
m_problems->setRowCount(static_cast<int>(result.problems.size()));
|
std::optional<DiscIO::VolumeVerifier::Result> result = future.get();
|
||||||
|
if (!result)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_summary_text->setText(QString::fromStdString(result->summary_text));
|
||||||
|
|
||||||
|
m_problems->setRowCount(static_cast<int>(result->problems.size()));
|
||||||
for (int i = 0; i < m_problems->rowCount(); ++i)
|
for (int i = 0; i < m_problems->rowCount(); ++i)
|
||||||
{
|
{
|
||||||
const DiscIO::VolumeVerifier::Problem problem = result.problems[i];
|
const DiscIO::VolumeVerifier::Problem problem = result->problems[i];
|
||||||
|
|
||||||
QString severity;
|
QString severity;
|
||||||
switch (problem.severity)
|
switch (problem.severity)
|
||||||
|
@ -179,12 +192,12 @@ void VerifyWidget::Verify()
|
||||||
SetProblemCellText(i, 1, severity);
|
SetProblemCellText(i, 1, severity);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetHash(m_crc32_line_edit, result.hashes.crc32);
|
SetHash(m_crc32_line_edit, result->hashes.crc32);
|
||||||
SetHash(m_md5_line_edit, result.hashes.md5);
|
SetHash(m_md5_line_edit, result->hashes.md5);
|
||||||
SetHash(m_sha1_line_edit, result.hashes.sha1);
|
SetHash(m_sha1_line_edit, result->hashes.sha1);
|
||||||
|
|
||||||
if (m_redump_line_edit)
|
if (m_redump_line_edit)
|
||||||
m_redump_line_edit->setText(QString::fromStdString(result.redump.message));
|
m_redump_line_edit->setText(QString::fromStdString(result->redump.message));
|
||||||
}
|
}
|
||||||
|
|
||||||
void VerifyWidget::SetProblemCellText(int row, int column, QString text)
|
void VerifyWidget::SetProblemCellText(int row, int column, QString text)
|
||||||
|
|
|
@ -181,6 +181,7 @@
|
||||||
<QtMoc Include="QtUtils\FileOpenEventFilter.h" />
|
<QtMoc Include="QtUtils\FileOpenEventFilter.h" />
|
||||||
<QtMoc Include="QtUtils\FlowLayout.h" />
|
<QtMoc Include="QtUtils\FlowLayout.h" />
|
||||||
<QtMoc Include="QtUtils\ModalMessageBox.h" />
|
<QtMoc Include="QtUtils\ModalMessageBox.h" />
|
||||||
|
<QtMoc Include="QtUtils\ParallelProgressDialog.h" />
|
||||||
<QtMoc Include="QtUtils\WindowActivationEventFilter.h" />
|
<QtMoc Include="QtUtils\WindowActivationEventFilter.h" />
|
||||||
<QtMoc Include="QtUtils\WrapInScrollArea.h" />
|
<QtMoc Include="QtUtils\WrapInScrollArea.h" />
|
||||||
<QtMoc Include="RenderWidget.h" />
|
<QtMoc Include="RenderWidget.h" />
|
||||||
|
@ -282,6 +283,7 @@
|
||||||
<ClCompile Include="$(QtMocOutPrefix)NewBreakpointDialog.cpp" />
|
<ClCompile Include="$(QtMocOutPrefix)NewBreakpointDialog.cpp" />
|
||||||
<ClCompile Include="$(QtMocOutPrefix)NewPatchDialog.cpp" />
|
<ClCompile Include="$(QtMocOutPrefix)NewPatchDialog.cpp" />
|
||||||
<ClCompile Include="$(QtMocOutPrefix)PadMappingDialog.cpp" />
|
<ClCompile Include="$(QtMocOutPrefix)PadMappingDialog.cpp" />
|
||||||
|
<ClCompile Include="$(QtMocOutPrefix)ParallelProgressDialog.cpp" />
|
||||||
<ClCompile Include="$(QtMocOutPrefix)PatchesWidget.cpp" />
|
<ClCompile Include="$(QtMocOutPrefix)PatchesWidget.cpp" />
|
||||||
<ClCompile Include="$(QtMocOutPrefix)PatchInstructionDialog.cpp" />
|
<ClCompile Include="$(QtMocOutPrefix)PatchInstructionDialog.cpp" />
|
||||||
<ClCompile Include="$(QtMocOutPrefix)PathPane.cpp" />
|
<ClCompile Include="$(QtMocOutPrefix)PathPane.cpp" />
|
||||||
|
@ -541,4 +543,4 @@
|
||||||
<Message Text="Copy: @(BinaryFiles) -> $(BinaryOutputDir)" Importance="High" />
|
<Message Text="Copy: @(BinaryFiles) -> $(BinaryOutputDir)" Importance="High" />
|
||||||
<Copy SourceFiles="@(BinaryFiles)" DestinationFolder="$(BinaryOutputDir)" />
|
<Copy SourceFiles="@(BinaryFiles)" DestinationFolder="$(BinaryOutputDir)" />
|
||||||
</Target>
|
</Target>
|
||||||
</Project>
|
</Project>
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <future>
|
||||||
|
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
@ -20,7 +21,6 @@
|
||||||
#include <QListView>
|
#include <QListView>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QProgressDialog>
|
|
||||||
#include <QShortcut>
|
#include <QShortcut>
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
#include <QTableView>
|
#include <QTableView>
|
||||||
|
@ -46,6 +46,7 @@
|
||||||
#include "DolphinQt/MenuBar.h"
|
#include "DolphinQt/MenuBar.h"
|
||||||
#include "DolphinQt/QtUtils/DoubleClickEventFilter.h"
|
#include "DolphinQt/QtUtils/DoubleClickEventFilter.h"
|
||||||
#include "DolphinQt/QtUtils/ModalMessageBox.h"
|
#include "DolphinQt/QtUtils/ModalMessageBox.h"
|
||||||
|
#include "DolphinQt/QtUtils/ParallelProgressDialog.h"
|
||||||
#include "DolphinQt/Resources.h"
|
#include "DolphinQt/Resources.h"
|
||||||
#include "DolphinQt/Settings.h"
|
#include "DolphinQt/Settings.h"
|
||||||
#include "DolphinQt/WiiUpdate.h"
|
#include "DolphinQt/WiiUpdate.h"
|
||||||
|
@ -574,34 +575,50 @@ void GameList::CompressISO(bool decompress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QProgressDialog progress_dialog(decompress ? tr("Decompressing...") : tr("Compressing..."),
|
ParallelProgressDialog progress_dialog(
|
||||||
tr("Abort"), 0, 100, this);
|
decompress ? tr("Decompressing...") : tr("Compressing..."), tr("Abort"), 0, 100, this);
|
||||||
progress_dialog.setWindowModality(Qt::WindowModal);
|
progress_dialog.GetRaw()->setWindowModality(Qt::WindowModal);
|
||||||
progress_dialog.setWindowFlags(progress_dialog.windowFlags() &
|
progress_dialog.GetRaw()->setWindowTitle(tr("Progress"));
|
||||||
~Qt::WindowContextHelpButtonHint);
|
|
||||||
progress_dialog.setWindowTitle(tr("Progress"));
|
|
||||||
|
|
||||||
bool good;
|
std::future<bool> good;
|
||||||
|
|
||||||
if (decompress)
|
if (decompress)
|
||||||
{
|
{
|
||||||
if (files.size() > 1)
|
if (files.size() > 1)
|
||||||
progress_dialog.setLabelText(tr("Decompressing...") + QLatin1Char{'\n'} +
|
{
|
||||||
QFileInfo(QString::fromStdString(original_path)).fileName());
|
progress_dialog.GetRaw()->setLabelText(
|
||||||
good = DiscIO::DecompressBlobToFile(original_path, dst_path.toStdString(), &CompressCB,
|
tr("Decompressing...") + QLatin1Char{'\n'} +
|
||||||
&progress_dialog);
|
QFileInfo(QString::fromStdString(original_path)).fileName());
|
||||||
|
}
|
||||||
|
|
||||||
|
good = std::async(std::launch::async, [&] {
|
||||||
|
const bool good = DiscIO::DecompressBlobToFile(original_path, dst_path.toStdString(),
|
||||||
|
&CompressCB, &progress_dialog);
|
||||||
|
progress_dialog.Reset();
|
||||||
|
return good;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (files.size() > 1)
|
if (files.size() > 1)
|
||||||
progress_dialog.setLabelText(tr("Compressing...") + QLatin1Char{'\n'} +
|
{
|
||||||
QFileInfo(QString::fromStdString(original_path)).fileName());
|
progress_dialog.GetRaw()->setLabelText(
|
||||||
good = DiscIO::CompressFileToBlob(original_path, dst_path.toStdString(),
|
tr("Compressing...") + QLatin1Char{'\n'} +
|
||||||
file->GetPlatform() == DiscIO::Platform::WiiDisc ? 1 : 0,
|
QFileInfo(QString::fromStdString(original_path)).fileName());
|
||||||
16384, &CompressCB, &progress_dialog);
|
}
|
||||||
|
|
||||||
|
good = std::async(std::launch::async, [&] {
|
||||||
|
const bool good =
|
||||||
|
DiscIO::CompressFileToBlob(original_path, dst_path.toStdString(),
|
||||||
|
file->GetPlatform() == DiscIO::Platform::WiiDisc ? 1 : 0,
|
||||||
|
16384, &CompressCB, &progress_dialog);
|
||||||
|
progress_dialog.Reset();
|
||||||
|
return good;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!good)
|
progress_dialog.GetRaw()->exec();
|
||||||
|
if (!good.get())
|
||||||
{
|
{
|
||||||
QErrorMessage(this).showMessage(tr("Dolphin failed to complete the requested action."));
|
QErrorMessage(this).showMessage(tr("Dolphin failed to complete the requested action."));
|
||||||
return;
|
return;
|
||||||
|
@ -934,10 +951,10 @@ static bool CompressCB(const std::string& text, float percent, void* ptr)
|
||||||
if (ptr == nullptr)
|
if (ptr == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto* progress_dialog = static_cast<QProgressDialog*>(ptr);
|
auto* progress_dialog = static_cast<ParallelProgressDialog*>(ptr);
|
||||||
|
|
||||||
progress_dialog->setValue(percent * 100);
|
progress_dialog->SetValue(percent * 100);
|
||||||
return !progress_dialog->wasCanceled();
|
return !progress_dialog->WasCanceled();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameList::OnSectionResized(int index, int, int)
|
void GameList::OnSectionResized(int index, int, int)
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
#include <QAbstractEventDispatcher>
|
#include <QAbstractEventDispatcher>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QProgressDialog>
|
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
|
||||||
|
|
|
@ -87,6 +87,7 @@
|
||||||
#include "DolphinQt/NetPlay/NetPlaySetupDialog.h"
|
#include "DolphinQt/NetPlay/NetPlaySetupDialog.h"
|
||||||
#include "DolphinQt/QtUtils/FileOpenEventFilter.h"
|
#include "DolphinQt/QtUtils/FileOpenEventFilter.h"
|
||||||
#include "DolphinQt/QtUtils/ModalMessageBox.h"
|
#include "DolphinQt/QtUtils/ModalMessageBox.h"
|
||||||
|
#include "DolphinQt/QtUtils/ParallelProgressDialog.h"
|
||||||
#include "DolphinQt/QtUtils/QueueOnObject.h"
|
#include "DolphinQt/QtUtils/QueueOnObject.h"
|
||||||
#include "DolphinQt/QtUtils/RunOnObject.h"
|
#include "DolphinQt/QtUtils/RunOnObject.h"
|
||||||
#include "DolphinQt/QtUtils/WindowActivationEventFilter.h"
|
#include "DolphinQt/QtUtils/WindowActivationEventFilter.h"
|
||||||
|
@ -1510,23 +1511,21 @@ void MainWindow::OnImportNANDBackup()
|
||||||
if (file.isEmpty())
|
if (file.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QProgressDialog* dialog = new QProgressDialog(this);
|
ParallelProgressDialog dialog(this);
|
||||||
dialog->setMinimum(0);
|
dialog.GetRaw()->setMinimum(0);
|
||||||
dialog->setMaximum(0);
|
dialog.GetRaw()->setMaximum(0);
|
||||||
dialog->setLabelText(tr("Importing NAND backup"));
|
dialog.GetRaw()->setLabelText(tr("Importing NAND backup"));
|
||||||
dialog->setCancelButton(nullptr);
|
dialog.GetRaw()->setCancelButton(nullptr);
|
||||||
|
|
||||||
auto beginning = QDateTime::currentDateTime().toMSecsSinceEpoch();
|
auto beginning = QDateTime::currentDateTime().toMSecsSinceEpoch();
|
||||||
|
|
||||||
auto result = std::async(std::launch::async, [&] {
|
std::future<void> result = std::async(std::launch::async, [&] {
|
||||||
DiscIO::NANDImporter().ImportNANDBin(
|
DiscIO::NANDImporter().ImportNANDBin(
|
||||||
file.toStdString(),
|
file.toStdString(),
|
||||||
[&dialog, beginning] {
|
[&dialog, beginning] {
|
||||||
QueueOnObject(dialog, [&dialog, beginning] {
|
dialog.SetLabelText(
|
||||||
dialog->setLabelText(
|
tr("Importing NAND backup\n Time elapsed: %1s")
|
||||||
tr("Importing NAND backup\n Time elapsed: %1s")
|
.arg((QDateTime::currentDateTime().toMSecsSinceEpoch() - beginning) / 1000));
|
||||||
.arg((QDateTime::currentDateTime().toMSecsSinceEpoch() - beginning) / 1000));
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
[this] {
|
[this] {
|
||||||
std::optional<std::string> keys_file = RunOnObject(this, [this] {
|
std::optional<std::string> keys_file = RunOnObject(this, [this] {
|
||||||
|
@ -1540,10 +1539,10 @@ void MainWindow::OnImportNANDBackup()
|
||||||
return *keys_file;
|
return *keys_file;
|
||||||
return std::string("");
|
return std::string("");
|
||||||
});
|
});
|
||||||
QueueOnObject(dialog, &QProgressDialog::close);
|
dialog.Reset();
|
||||||
});
|
});
|
||||||
|
|
||||||
dialog->exec();
|
dialog.GetRaw()->exec();
|
||||||
|
|
||||||
result.wait();
|
result.wait();
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QProgressDialog>
|
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QSignalBlocker>
|
#include <QSignalBlocker>
|
||||||
#include <QSpinBox>
|
#include <QSpinBox>
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QProgressDialog>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include "Common/Flag.h"
|
||||||
|
|
||||||
|
class ParallelProgressDialog final : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Only use this from the main thread
|
||||||
|
template <typename... Args>
|
||||||
|
ParallelProgressDialog(Args&&... args) : m_dialog{std::forward<Args>(args)...}
|
||||||
|
{
|
||||||
|
setParent(m_dialog.parent());
|
||||||
|
m_dialog.setWindowFlags(m_dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||||
|
ConnectSignalsAndSlots();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only use this from the main thread
|
||||||
|
QProgressDialog* GetRaw() { return &m_dialog; }
|
||||||
|
|
||||||
|
// All of the following can be called from any thread
|
||||||
|
void Cancel() { emit CancelSignal(); }
|
||||||
|
void Reset() { emit ResetSignal(); }
|
||||||
|
void SetCancelButtonText(const QString& text) { emit SetCancelButtonText(text); }
|
||||||
|
void SetLabelText(const QString& text) { emit SetLabelTextSignal(text); }
|
||||||
|
void SetMaximum(int maximum) { emit SetMaximumSignal(maximum); }
|
||||||
|
void SetMinimum(int minimum) { emit SetMinimumSignal(minimum); }
|
||||||
|
void SetMinimumDuration(int ms) { emit SetMinimumDurationSignal(ms); }
|
||||||
|
void SetRange(int minimum, int maximum) { emit SetRangeSignal(minimum, maximum); }
|
||||||
|
|
||||||
|
// Can be called from any thread, but only from one thread at a time
|
||||||
|
void SetValue(int progress)
|
||||||
|
{
|
||||||
|
// HACK: To avoid the https://bugreports.qt.io/browse/QTBUG-10561 stack overflow,
|
||||||
|
// limit how often QProgressDialog::setValue can run
|
||||||
|
const auto current_time = std::chrono::steady_clock::now();
|
||||||
|
if (current_time - m_last_setvalue_time >= std::chrono::milliseconds(50))
|
||||||
|
{
|
||||||
|
m_last_setvalue_time = current_time;
|
||||||
|
emit SetValueSignal(progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can be called from any thread
|
||||||
|
bool WasCanceled() { return m_was_cancelled.IsSet(); }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void CancelSignal();
|
||||||
|
void ResetSignal();
|
||||||
|
void SetCancelButtonTextSignal(const QString& cancel_button_text);
|
||||||
|
void SetLabelTextSignal(const QString& text);
|
||||||
|
void SetMaximumSignal(int maximum);
|
||||||
|
void SetMinimumSignal(int minimum);
|
||||||
|
void SetMinimumDurationSignal(int ms);
|
||||||
|
void SetRangeSignal(int minimum, int maximum);
|
||||||
|
void SetValueSignal(int progress);
|
||||||
|
|
||||||
|
void Canceled();
|
||||||
|
void Finished(int result);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void OnCancelled() { m_was_cancelled.Set(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename Func1, typename Func2>
|
||||||
|
void ConnectSignal(Func1 signal, Func2 slot)
|
||||||
|
{
|
||||||
|
QObject::connect(this, signal, &m_dialog, slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Func1, typename Func2>
|
||||||
|
void ConnectSlot(Func1 signal, Func2 slot)
|
||||||
|
{
|
||||||
|
QObject::connect(&m_dialog, signal, this, slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectSignalsAndSlots()
|
||||||
|
{
|
||||||
|
ConnectSignal(&ParallelProgressDialog::CancelSignal, &QProgressDialog::cancel);
|
||||||
|
ConnectSignal(&ParallelProgressDialog::ResetSignal, &QProgressDialog::reset);
|
||||||
|
ConnectSignal(&ParallelProgressDialog::SetCancelButtonTextSignal,
|
||||||
|
&QProgressDialog::setCancelButtonText);
|
||||||
|
ConnectSignal(&ParallelProgressDialog::SetLabelTextSignal, &QProgressDialog::setLabelText);
|
||||||
|
ConnectSignal(&ParallelProgressDialog::SetMaximumSignal, &QProgressDialog::setMaximum);
|
||||||
|
ConnectSignal(&ParallelProgressDialog::SetMinimumSignal, &QProgressDialog::setMinimum);
|
||||||
|
ConnectSignal(&ParallelProgressDialog::SetMinimumDurationSignal,
|
||||||
|
&QProgressDialog::setMinimumDuration);
|
||||||
|
ConnectSignal(&ParallelProgressDialog::SetRangeSignal, &QProgressDialog::setRange);
|
||||||
|
ConnectSignal(&ParallelProgressDialog::SetValueSignal, &QProgressDialog::setValue);
|
||||||
|
|
||||||
|
ConnectSlot(&QProgressDialog::canceled, &ParallelProgressDialog::OnCancelled);
|
||||||
|
|
||||||
|
ConnectSlot(&QProgressDialog::canceled, &ParallelProgressDialog::Canceled);
|
||||||
|
ConnectSlot(&QProgressDialog::finished, &ParallelProgressDialog::Finished);
|
||||||
|
}
|
||||||
|
|
||||||
|
QProgressDialog m_dialog;
|
||||||
|
Common::Flag m_was_cancelled;
|
||||||
|
std::chrono::time_point<std::chrono::steady_clock> m_last_setvalue_time;
|
||||||
|
};
|
Loading…
Reference in New Issue