#pragma once #include #include #include #include #include #include "Common/Flag.h" class ParallelProgressDialog final : public QObject { Q_OBJECT public: // Only use this from the main thread template ParallelProgressDialog(Args&&... args) : m_dialog{std::forward(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 void ConnectSignal(Func1 signal, Func2 slot) { QObject::connect(this, signal, &m_dialog, slot); } template 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 m_last_setvalue_time; };