127 lines
4.3 KiB
C++
127 lines
4.3 KiB
C++
// Copyright 2020 Dolphin Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#pragma once
|
|
|
|
#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 SetCancelButtonTextSignal(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); }
|
|
void SetValue(int progress) { 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(); }
|
|
|
|
void SetValueSlot(int progress)
|
|
{
|
|
// Normally we would've been able to just call setValue instead of having this wrapper
|
|
// around it, but due to the https://bugreports.qt.io/browse/QTBUG-10561 stack overflow,
|
|
// we can't. Short summary of the stack overflow: setValue calls processEvents,
|
|
// which calls SetValueSlot if there is another SetValueSlot event in the queue,
|
|
// which would call setValue if it wasn't for the check below, and so on.
|
|
|
|
m_last_received_progress = progress;
|
|
|
|
if (m_is_setting_value)
|
|
return;
|
|
|
|
m_is_setting_value = true;
|
|
|
|
int last_set_progress;
|
|
do
|
|
{
|
|
last_set_progress = m_last_received_progress;
|
|
m_dialog.setValue(m_last_received_progress);
|
|
} while (m_last_received_progress != last_set_progress);
|
|
|
|
m_is_setting_value = false;
|
|
}
|
|
|
|
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);
|
|
|
|
QObject::connect(this, &ParallelProgressDialog::SetValueSignal, this,
|
|
&ParallelProgressDialog::SetValueSlot);
|
|
|
|
ConnectSlot(&QProgressDialog::canceled, &ParallelProgressDialog::OnCancelled);
|
|
|
|
ConnectSlot(&QProgressDialog::canceled, &ParallelProgressDialog::Canceled);
|
|
ConnectSlot(&QProgressDialog::finished, &ParallelProgressDialog::Finished);
|
|
}
|
|
|
|
QProgressDialog m_dialog;
|
|
Common::Flag m_was_cancelled;
|
|
int m_last_received_progress;
|
|
bool m_is_setting_value = false;
|
|
};
|