task: massively simplified task system

Made various changes and fixes to the task system:

- Tasks are built around QtConcurrent rather than QThread. Reduces
  code complexity significantly.
- Task error reporting is now streamlined in both TaskManager and
  TaskDialog.
- Moved ProjectImport/Save/LoadManager to the app/task folder
This commit is contained in:
itsmattkc
2020-05-19 02:44:32 +10:00
parent c4b0a53174
commit b9cd83eff1
49 changed files with 864 additions and 1332 deletions
+32 -39
View File
@@ -20,76 +20,69 @@
#include "task.h"
#include <QMessageBox>
#include <QThread>
#include <QtConcurrent/QtConcurrent>
OLIVE_NAMESPACE_ENTER
TaskDialog::TaskDialog(Task* task, const QString& title, QWidget *parent) :
ProgressDialog(task->GetTitle(), title, parent),
task_(task),
task_failed_(false)
destroy_on_close_(true)
{
thread_ = new QThread();
// Clear task when this dialog is destroyed
task_->setParent(this);
// Connect the save manager progress signal to the progress bar update on the dialog
connect(task_, &Task::ProgressChanged, this, &TaskDialog::SetProgress, Qt::QueuedConnection);
// Connect error reporting
connect(task_, &Task::Failed, this, &TaskDialog::TaskFailed, Qt::QueuedConnection);
// Connect cancel signal (must be a direct connection or it'll be queued after the task has already finished)
// Connect cancel signal (must be a direct connection or it'll be queued after the task has
// already finished)
connect(this, &TaskDialog::Cancelled, task_, &Task::Cancel, Qt::DirectConnection);
// Connect cleanup functions (ensure everything new'd in this function is deleteLater'd)
connect(task_, &Task::Finished, this, &TaskDialog::close, Qt::QueuedConnection);
// When task is finished, signal thread to quit
connect(task_, &Task::Finished, thread_, &QThread::quit, Qt::QueuedConnection);
// When thread has quit, delete both task and thread
connect(thread_, &QThread::finished, task_, &Task::deleteLater, Qt::QueuedConnection);
connect(thread_, &QThread::finished, thread_, &QThread::deleteLater, Qt::QueuedConnection);
}
void TaskDialog::showEvent(QShowEvent *e)
{
QDialog::showEvent(e);
ProgressDialog::showEvent(e);
// Create a separate thread to run this task in
thread_->start();
// Create watcher for when the task finishes
QFutureWatcher<bool>* task_watcher = new QFutureWatcher<bool>();
// Move the task to this thread
task_->moveToThread(thread_);
// Listen for when the task finishes
connect(task_watcher, &QFutureWatcher<bool>::finished,
this, &TaskDialog::TaskFinished, Qt::QueuedConnection);
// Start the task
QMetaObject::invokeMethod(task_, "Start", Qt::QueuedConnection);
// Run task in another thread with QtConcurrent
task_watcher->setFuture(QtConcurrent::run(task_, &Task::Run));
}
void TaskDialog::closeEvent(QCloseEvent *e)
{
// Show error if the task failed
if (!task_->IsCancelled() && task_failed_) {
QMessageBox::critical(this,
tr("Error"),
task_error_,
QMessageBox::Ok);
}
// Cancel task if it is running
task_->Cancel();
// Standard close function
QDialog::closeEvent(e);
ProgressDialog::closeEvent(e);
// Clean up this dialog (FIXME: Is this necessary?)
deleteLater();
// Clean up this task and dialog
if (destroy_on_close_) {
deleteLater();
}
}
void TaskDialog::TaskFailed(const QString &s)
void TaskDialog::TaskFinished()
{
task_failed_ = true;
task_error_ = s;
QFutureWatcher<bool>* task_watcher = static_cast<QFutureWatcher<bool>*>(sender());
if (task_watcher->result()) {
emit TaskSucceeded(task_);
} else {
ShowErrorMessage(tr("Task Failed"), task_->GetError());
emit TaskFailed(task_);
}
task_watcher->deleteLater();
close();
}
OLIVE_NAMESPACE_EXIT
+32 -5
View File
@@ -30,23 +30,50 @@ class TaskDialog : public ProgressDialog
{
Q_OBJECT
public:
/**
* @brief TaskDialog Constructor
*
* Creates a TaskDialog. The TaskDialog takes ownership of the Task and will destroy it on close.
* Connect to the Task::Succeeded() if you want to retrieve information from the task before it
* gets destroyed.
*/
TaskDialog(Task *task, const QString &title, QWidget* parent = nullptr);
/**
* @brief Set whether TaskDialog should destroy itself (and the task) when it's closed
*
* This is TRUE by default.
*/
void SetDestroyOnClose(bool e)
{
destroy_on_close_ = e;
}
/**
* @brief Returns this dialog's task
*/
Task* GetTask() const
{
return task_;
}
protected:
virtual void showEvent(QShowEvent* e) override;
virtual void closeEvent(QCloseEvent* e) override;
signals:
void TaskSucceeded(Task* task);
void TaskFailed(Task* task);
private:
Task* task_;
QThread* thread_;
bool task_failed_;
QString task_error_;
bool destroy_on_close_;
private slots:
void TaskFailed(const QString& s);
void TaskFinished();
};