diff --git a/app/core.cpp b/app/core.cpp index 4594978e2..c49c063b7 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -110,7 +110,7 @@ void Core::ImportFiles(const QStringList &urls, ProjectViewModel* model, Folder* return; } - olive::task_manager.AddTask(new ImportTask(model, parent, urls)); + olive::task_manager.AddTask(std::make_shared(model, parent, urls)); } const olive::tool::Tool &Core::tool() diff --git a/app/task/import/import.cpp b/app/task/import/import.cpp index ccb0f694e..f24ea0049 100644 --- a/app/task/import/import.cpp +++ b/app/task/import/import.cpp @@ -50,6 +50,14 @@ bool ImportTask::Action() Import(urls_, parent_, command); + // If this task was cancelled, we won't bother pushing an undo command (we don't end up with anything undoable since + // the undo command executes the final import anyway) + if (cancelled()) { + delete command; + + return true; + } + olive::undo_stack.push(command); return true; @@ -122,14 +130,15 @@ void ImportTask::Import(const QStringList &files, Folder *folder, QUndoCommand * parent_command); // Create ProbeTask to analyze this media - ProbeTask* pt = new ProbeTask(f); + TaskPtr pt = std::make_shared(f); // The task won't work unless it's in the main thread and we're definitely not // FIXME: Should Tasks check what thread they're in and move themselves to the main thread? pt->moveToThread(qApp->thread()); // Queue task in task manager - olive::task_manager.AddTask(pt); + new TaskManager::AddTaskCommand(pt, parent_command); + //olive::task_manager.AddTask(pt); } diff --git a/app/task/task.cpp b/app/task/task.cpp index 586abc42a..77b53e108 100644 --- a/app/task/task.cpp +++ b/app/task/task.cpp @@ -93,8 +93,34 @@ void Task::AddDependency(Task *dependency) dependencies_.append(dependency); } +void Task::EmitRemovedSignal() +{ + emit Removed(); +} + +void Task::ResetState() +{ + if (status_ == kWaiting) { + return; + } + + if (status_ == kWorking) { + Cancel(); + } + + cancelled_ = false; + + set_error(QString()); + + set_status(kWaiting); +} + void Task::Cancel() { + if (status_ == kWaiting) { + set_status(kFinished); + } + if (status_ != kWorking) { return; } diff --git a/app/task/task.h b/app/task/task.h index 4ffde285e..3ff9d7315 100644 --- a/app/task/task.h +++ b/app/task/task.h @@ -21,6 +21,7 @@ #ifndef TASK_H #define TASK_H +#include #include #include "task/taskthread.h" @@ -141,6 +142,16 @@ public: */ void AddDependency(Task* dependency); + /** + * @brief Emit the Removed() signal when this Task is about to get removed + */ + void EmitRemovedSignal(); + + /** + * @brief Reset this Task back to the waiting state + */ + void ResetState(); + public slots: /** * @brief Cancel the Task @@ -198,6 +209,11 @@ signals: */ void Finished(); + /** + * @brief Signal emitted when this Task is removed from TaskManager + */ + void Removed(); + private: /** * @brief Set the status of this Task (also emits StatusChanged()) @@ -223,4 +239,6 @@ private slots: void ThreadComplete(); }; +using TaskPtr = std::shared_ptr; + #endif // TASK_H diff --git a/app/task/taskmanager.cpp b/app/task/taskmanager.cpp index 896bf3027..563567f85 100644 --- a/app/task/taskmanager.cpp +++ b/app/task/taskmanager.cpp @@ -35,16 +35,16 @@ TaskManager::~TaskManager() Clear(); } -void TaskManager::AddTask(Task* t) -{ +void TaskManager::AddTask(TaskPtr t) +{ // Connect Task's status signal to the Callback - connect(t, SIGNAL(StatusChanged(Task::Status)), this, SLOT(TaskCallback(Task::Status))); + connect(t.get(), SIGNAL(StatusChanged(Task::Status)), this, SLOT(TaskCallback(Task::Status))); // Add the Task to the queue tasks_.append(t); // Emit signal that a Task was added - emit TaskAdded(t); + emit TaskAdded(t.get()); // Scan through queue and start any Tasks that can (including this one) StartNextWaiting(); @@ -52,11 +52,9 @@ void TaskManager::AddTask(Task* t) void TaskManager::Clear() { - // TODO Cancelling tasks - // Delete Tasks from memory for (int i=0;iCancel(); } tasks_.clear(); } @@ -67,7 +65,7 @@ void TaskManager::StartNextWaiting() int working_count = 0; for (int i=0;istatus() == Task::kWorking) { @@ -93,13 +91,17 @@ void TaskManager::StartNextWaiting() void TaskManager::DeleteTask(Task *t) { - // TODO Cancelling tasks? + // Cancel the task + t->Cancel(); // Remove instances of Task from queue - tasks_.removeAll(t); - - // Destroy Task object - t->deleteLater(); + for (int i=0;iEmitRemovedSignal(); + tasks_.removeAt(i); + break; + } + } } void TaskManager::TaskCallback(Task::Status status) @@ -127,3 +129,21 @@ void TaskManager::TaskCallback(Task::Status status) break; } } + +TaskManager::AddTaskCommand::AddTaskCommand(TaskPtr t, QUndoCommand *parent) : + QUndoCommand(parent), + task_(t) +{ +} + +void TaskManager::AddTaskCommand::redo() +{ + olive::task_manager.AddTask(task_); +} + +void TaskManager::AddTaskCommand::undo() +{ + olive::task_manager.DeleteTask(task_.get()); + + task_->ResetState(); +} diff --git a/app/task/taskmanager.h b/app/task/taskmanager.h index 67b22fdb5..3504a13d8 100644 --- a/app/task/taskmanager.h +++ b/app/task/taskmanager.h @@ -22,6 +22,7 @@ #define TASKMANAGER_H #include +#include #include "task/task.h" @@ -84,13 +85,25 @@ public: * * The task to add and run. TaskManager takes ownership of this Task and will be responsible for freeing it. */ - void AddTask(Task *t); + void AddTask(TaskPtr t); /** - * @brief Forcibly + * @brief Forcibly cancel all commands and clear them */ void Clear(); + class AddTaskCommand : public QUndoCommand { + public: + AddTaskCommand(TaskPtr t, QUndoCommand* parent = nullptr); + + virtual void redo() override; + + virtual void undo() override; + + private: + TaskPtr task_; + }; + signals: /** * @brief Signal emitted when a Task is added by AddTask() @@ -129,7 +142,7 @@ private: /** * @brief Internal task array */ - QVector tasks_; + QVector tasks_; /** * @brief Constant set at run-time of how many Tasks can run concurrently diff --git a/app/widget/taskview/taskviewitem.cpp b/app/widget/taskview/taskviewitem.cpp index 476ca93fe..dd525302f 100644 --- a/app/widget/taskview/taskviewitem.cpp +++ b/app/widget/taskview/taskviewitem.cpp @@ -75,7 +75,7 @@ void TaskViewItem::SetTask(Task *t) // Connect to the task connect(task_, SIGNAL(StatusChanged(Task::Status)), this, SLOT(TaskStatusChange(Task::Status))); connect(task_, SIGNAL(ProgressChanged(int)), progress_bar_, SLOT(setValue(int))); - connect(task_, SIGNAL(destroyed()), this, SLOT(deleteLater())); + connect(task_, SIGNAL(Removed()), this, SLOT(deleteLater())); connect(cancel_btn_, SIGNAL(clicked(bool)), task_, SLOT(Cancel())); }