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:
+32
-39
@@ -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
@@ -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();
|
||||
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user