diff options
| author | Glenn Smith <glenn@vector35.com> | 2021-12-28 15:59:31 -0500 |
|---|---|---|
| committer | Glenn Smith <glenn@vector35.com> | 2022-01-17 20:42:22 -0500 |
| commit | e88ed98d60b046cbeb5f4c96fc374c7576d7b57a (patch) | |
| tree | e937ffccba9868cb259e4ec817157b255dc74652 /ui/progresstask.h | |
| parent | dc2a99e1159c3951b91935490ec8d2da5fc8e1e7 (diff) | |
OptionsDialog/SettingsView + ProgressTask fixes
Diffstat (limited to 'ui/progresstask.h')
| -rw-r--r-- | ui/progresstask.h | 197 |
1 files changed, 58 insertions, 139 deletions
diff --git a/ui/progresstask.h b/ui/progresstask.h index e8ba1ba2..a291c439 100644 --- a/ui/progresstask.h +++ b/ui/progresstask.h @@ -4,8 +4,13 @@ #include <QtCore/QThread> #include <QtCore/QVariant> #include <QtCore/QCoreApplication> +#include <QtGui/QKeyEvent> #include <QtConcurrent/QtConcurrent> -#include <QtWidgets/QProgressDialog> +#include <QtWidgets/QBoxLayout> +#include <QtWidgets/QDialog> +#include <QtWidgets/QLabel> +#include <QtWidgets/QProgressBar> +#include <QtWidgets/QPushButton> #include <atomic> #include <functional> #include <chrono> @@ -16,91 +21,40 @@ /*! Dialog displaying a progress bar and cancel button */ -class BINARYNINJAUIAPI ProgressDialog: public QObject +class BINARYNINJAUIAPI ProgressDialog: public QDialog { Q_OBJECT - QProgressDialog* m_progress; + QProgressBar* m_progress; + QLabel* m_text; + QPushButton* m_cancel; + bool m_cancellable; bool m_maxSet; + std::atomic<bool> m_processing; + std::atomic<bool> m_wasCancelled; std::chrono::steady_clock::time_point m_lastUpdate; public: - ProgressDialog(QWidget* parent, const QString& title, const QString& text, const QString& cancel=QString()) - { - m_progress = new QProgressDialog(parent); - m_progress->setWindowTitle(title); - m_progress->setLabelText(text); - m_progress->setMinimumDuration(200); - m_progress->setWindowModality(Qt::WindowModal); - m_progress->setCancelButtonText(cancel); - m_progress->setValue(m_progress->minimum()); - connect(m_progress, &QProgressDialog::canceled, this, &ProgressDialog::cancelButton); - m_maxSet = false; - m_lastUpdate = std::chrono::steady_clock::now(); - } - - bool wasCancelled() const - { - return m_progress->wasCanceled(); - } + ProgressDialog(QWidget* parent, const QString& title, const QString& text, const QString& cancel=QString()); - void hideForModal(std::function<void()> modal) - { - m_progress->blockSignals(true); - int value = m_progress->value(); - m_progress->reset(); + bool wasCancelled() const; - modal(); + void hideForModal(std::function<void()> modal); - m_progress->setValue(value); - m_progress->blockSignals(false); - } + QString text() const; - QString text() const - { - return m_progress->labelText(); - } + void setText(const QString& text); - void setText(const QString& text) - { - m_progress->setLabelText(text); - } +protected: + virtual void keyPressEvent(QKeyEvent* event) override; private Q_SLOTS: - void cancelButton() - { - Q_EMIT canceled(); - } + void cancelButton(); public Q_SLOTS: - void update(int cur, int total) - { - if (m_progress->wasCanceled()) - return; + void update(int cur, int total); - bool maxUpdated = false; - if (!m_maxSet || (total != m_progress->maximum())) - { - m_progress->setMaximum((int)total); - m_maxSet = true; - maxUpdated = true; - } - - std::chrono::steady_clock::time_point curTime = std::chrono::steady_clock::now(); - if (cur == total || std::chrono::duration_cast<std::chrono::milliseconds>(curTime - m_lastUpdate).count() >= 100 || maxUpdated) - { - m_progress->blockSignals(true); - m_progress->setValue((int)cur); - m_progress->blockSignals(false); - m_lastUpdate = std::chrono::steady_clock::now(); - } - } - - void cancel() - { - m_progress->cancel(); - Q_EMIT canceled(); - } + void cancel(); Q_SIGNALS: void canceled(); }; @@ -121,6 +75,10 @@ Q_SIGNALS: ProgressTask* task = new ProgressTask("Long Operation", "Long Operation", "Cancel", [](std::function<bool(size_t, size_t)> progress) { doLongOperationWithProgress(progress); + + // Report progress by calling the progress function + if (!progress(current, maximum)) + return; // If the progress function returns false, then the user has cancelled the operation }); // Throws if doLongOperationWithProgress threw task->wait(); @@ -138,106 +96,67 @@ class BINARYNINJAUIAPI ProgressTask: public QObject std::exception_ptr m_exception; public: + /*! + Construct a new progress task, which automatically starts running a given function + \param parent Parent QWidget to display progress dialog on top of + \param name Title for progress dialog + \param text Text for progress dialog + \param cancel Cancel button title. If empty, the cancel button will not be shown + \param func Function to run in the background, which takes a progress reporting function for its argument. + The function should call the progress function periodically to signal updates and check for cancellation. + */ ProgressTask(QWidget* parent, const QString& name, const QString& text, const QString& cancel, - std::function<void(std::function<bool(size_t, size_t)>)> func): - QObject(), m_canceled(false), m_func(func), m_exception() - { - m_thread = new QThread(parent); - m_dialog = new ProgressDialog(parent, name, text, cancel); - connect(this, &ProgressTask::progress, m_dialog, &ProgressDialog::update); - connect(m_thread, &QThread::finished, this, &ProgressTask::finish); - connect(m_thread, &QThread::started, this, &ProgressTask::start); - connect(m_dialog, &ProgressDialog::canceled, [this]() { - m_canceled = true; - }); - - m_thread->start(); - - moveToThread(m_thread); - } - virtual ~ProgressTask() {} + std::function<void(std::function<bool(size_t, size_t)>)> func); + virtual ~ProgressTask(); /*! - Wait for the task to finish - \throws exception Any exception that the provided func throws + Wait for the task to finish + \throws exception Any exception that the provided func throws + \returns False if canceled, true otherwise */ - void wait() - { - while (!m_thread->isFinished()) - { - m_thread->wait(50); - QCoreApplication::processEvents(); - } - m_dialog->cancel(); - m_dialog->deleteLater(); - deleteLater(); - if (m_exception) - { - std::rethrow_exception(m_exception); - } - } + bool wait(); /*! Hide the task to present a modal (in a function) since the progress dialog will block other parts of the ui from responding while it is present. \param modal Function to present a modal ui on top */ - void hideForModal(std::function<void()> modal) - { - m_dialog->hideForModal(modal); - } + void hideForModal(std::function<void()> modal); /*! Get the text label of the progress dialog \return Text label contents */ - QString text() const - { - return m_dialog->text(); - } + QString text() const; /*! Set the text label on the progress dialog \param text New text label contents */ - void setText(const QString& text) - { - m_dialog->setText(text); - } + void setText(const QString& text); private Q_SLOTS: - void start() - { - try - { - m_func([this](size_t cur, size_t total) { - Q_EMIT progress(cur, total); - return !m_canceled.load(); - }); - } - catch (...) - { - m_exception = std::current_exception(); - } - m_thread->quit(); - } + void start(); - void finish() - { - Q_EMIT finished(); - } + void finish(); public Q_SLOTS: /*! Cancel the progress dialog */ - void cancel() - { - m_canceled = true; - } + void cancel(); Q_SIGNALS: - void progress(int, int); + /*! + Signal reported every time there is a progress update (probably often) + \param cur Current progress value + \param max Maximum progress value + */ + void progress(int cur, int max); + + /*! + Signal reported when the task has finished + */ void finished(); }; |
