diff --git a/app/core.cpp b/app/core.cpp index 6f47c7d17..4594978e2 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -187,7 +187,7 @@ void Core::CreateNewFolder() Folder* folder = active_project_panel->GetSelectedFolder(); // Create new folder - Folder* new_folder = new Folder(); + ItemPtr new_folder = std::make_shared(); // Set a default name new_folder->set_name(tr("New Folder")); @@ -200,7 +200,7 @@ void Core::CreateNewFolder() olive::undo_stack.push(aic); // Trigger an automatic rename so users can enter the folder name - active_project_panel->Edit(new_folder); + active_project_panel->Edit(new_folder.get()); } void Core::AddOpenProject(ProjectPtr p) diff --git a/app/project/item/footage/footage.h b/app/project/item/footage/footage.h index b7ac67a6b..0ef52e43e 100644 --- a/app/project/item/footage/footage.h +++ b/app/project/item/footage/footage.h @@ -231,4 +231,6 @@ private: }; +using FootagePtr = std::shared_ptr; + #endif // FOOTAGE_H diff --git a/app/project/item/item.cpp b/app/project/item/item.cpp index 11f87a683..2389440f6 100644 --- a/app/project/item/item.cpp +++ b/app/project/item/item.cpp @@ -27,20 +27,16 @@ Item::Item() : Item::~Item() { - // Delete all children - for (int i=0;iparent_ == this) { return; } if (c->parent_ != nullptr) { - c->parent_->remove_child(c); + c->parent_->remove_child(c.get()); } children_.append(c); @@ -53,7 +49,14 @@ void Item::remove_child(Item *c) return; } - children_.removeAll(c); + // Remove all instances of this child in the list + for (int i=0;iparent_ = nullptr; } @@ -64,7 +67,18 @@ int Item::child_count() Item *Item::child(int i) { - return children_.at(i); + return children_.at(i).get(); +} + +ItemPtr Item::shared_ptr_from_raw(Item *item) +{ + for (int i=0;iremove_child(this); - } - - p->add_child(this); -} diff --git a/app/project/item/item.h b/app/project/item/item.h index fff65e557..b8e02666a 100644 --- a/app/project/item/item.h +++ b/app/project/item/item.h @@ -21,10 +21,14 @@ #ifndef ITEM_H #define ITEM_H +#include #include #include #include +class Item; +using ItemPtr = std::shared_ptr; + class Item { public: @@ -40,7 +44,7 @@ public: Item(); /** - * @brief Item destructor, deletes all children + * @brief Required virtual Item destructor */ virtual ~Item(); @@ -66,11 +70,13 @@ public: virtual Type type() const = 0; - void add_child(Item *c); + void add_child(ItemPtr c); void remove_child(Item* c); int child_count(); Item* child(int i); + ItemPtr shared_ptr_from_raw(Item* item); + const QString& name() const; void set_name(const QString& n); @@ -81,10 +87,9 @@ public: void set_icon(const QIcon& icon); Item *parent() const; - void set_parent(Item *p); private: - QList children_; + QList children_; Item* parent_; diff --git a/app/project/projectviewmodel.cpp b/app/project/projectviewmodel.cpp index 55bfed70e..3b339914e 100644 --- a/app/project/projectviewmodel.cpp +++ b/app/project/projectviewmodel.cpp @@ -376,7 +376,7 @@ bool ProjectViewModel::dropMimeData(const QMimeData *data, Qt::DropAction action return false; } -void ProjectViewModel::AddChild(Item *parent, Item *child) +void ProjectViewModel::AddChild(Item *parent, ItemPtr child) { QModelIndex parent_index; @@ -477,7 +477,9 @@ void ProjectViewModel::MoveItemInternal(Item *item, Item *destination) beginMoveRows(item_index.parent(), item_index.row(), item_index.row(), destination_index, destination->child_count()); - item->set_parent(destination); + ItemPtr item_ptr = item->parent()->shared_ptr_from_raw(item); + + destination->add_child(item_ptr); endMoveRows(); } @@ -532,7 +534,7 @@ void ProjectViewModel::RenameItemCommand::undo() model_->RenameChild(item_, old_name_); } -ProjectViewModel::AddItemCommand::AddItemCommand(ProjectViewModel* model, Item* folder, Item* child, QUndoCommand* parent) : +ProjectViewModel::AddItemCommand::AddItemCommand(ProjectViewModel* model, Item* folder, ItemPtr child, QUndoCommand* parent) : QUndoCommand(parent), model_(model), parent_(folder), @@ -543,10 +545,6 @@ ProjectViewModel::AddItemCommand::AddItemCommand(ProjectViewModel* model, Item* ProjectViewModel::AddItemCommand::~AddItemCommand() { - // FIXME Use smart pointers. I hate having to do this. - if (!done_) { - delete child_; - } } void ProjectViewModel::AddItemCommand::redo() @@ -558,7 +556,7 @@ void ProjectViewModel::AddItemCommand::redo() void ProjectViewModel::AddItemCommand::undo() { - model_->RemoveChild(parent_, child_); + model_->RemoveChild(parent_, child_.get()); done_ = false; } diff --git a/app/project/projectviewmodel.h b/app/project/projectviewmodel.h index 2900d070b..dec60c6e2 100644 --- a/app/project/projectviewmodel.h +++ b/app/project/projectviewmodel.h @@ -93,7 +93,7 @@ public: virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; /** Other model functions */ - void AddChild(Item* parent, Item* child); + void AddChild(Item* parent, ItemPtr child); void RemoveChild(Item* parent, Item* child); void RenameChild(Item* item, const QString& name); @@ -144,7 +144,7 @@ public: */ class AddItemCommand : public QUndoCommand { public: - AddItemCommand(ProjectViewModel* model, Item* folder, Item* child, QUndoCommand* parent = nullptr); + AddItemCommand(ProjectViewModel* model, Item* folder, ItemPtr child, QUndoCommand* parent = nullptr); virtual ~AddItemCommand() override; @@ -155,7 +155,7 @@ public: private: ProjectViewModel* model_; Item* parent_; - Item* child_; + ItemPtr child_; bool done_; }; private: diff --git a/app/task/import/import.cpp b/app/task/import/import.cpp index f579c5a89..ccb0f694e 100644 --- a/app/task/import/import.cpp +++ b/app/task/import/import.cpp @@ -59,6 +59,11 @@ void ImportTask::Import(const QStringList &files, Folder *folder, QUndoCommand * { for (int i=0;i(); f->set_name(file_info.fileName()); @@ -95,12 +101,12 @@ void ImportTask::Import(const QStringList &files, Folder *folder, QUndoCommand * } // Recursively follow this path - Import(full_urls, f, parent_command); + Import(full_urls, static_cast(f.get()), parent_command); } } else { - Footage* f = new Footage(); + FootagePtr f = std::make_shared(); // FIXME: Is it possible for a file to go missing between the Import dialog and here? // And what is the behavior/result of that? diff --git a/app/task/probe/probe.cpp b/app/task/probe/probe.cpp index 06e644e8f..744bd8c12 100644 --- a/app/task/probe/probe.cpp +++ b/app/task/probe/probe.cpp @@ -24,7 +24,7 @@ #include "decoder/probeserver.h" -ProbeTask::ProbeTask(Footage *footage) : +ProbeTask::ProbeTask(FootagePtr footage) : footage_(footage) { QString base_filename = QFileInfo(footage_->filename()).fileName(); @@ -34,7 +34,7 @@ ProbeTask::ProbeTask(Footage *footage) : bool ProbeTask::Action() { - olive::ProbeMedia(footage_); + olive::ProbeMedia(footage_.get()); return true; } diff --git a/app/task/probe/probe.h b/app/task/probe/probe.h index 0841f0dd0..4346cfef9 100644 --- a/app/task/probe/probe.h +++ b/app/task/probe/probe.h @@ -38,12 +38,12 @@ class ProbeTask : public Task { Q_OBJECT public: - ProbeTask(Footage* footage); + ProbeTask(FootagePtr footage); virtual bool Action() override; private: - Footage* footage_; + FootagePtr footage_; }; #endif // PROBE_H diff --git a/app/task/task.cpp b/app/task/task.cpp index c0cde65a6..586abc42a 100644 --- a/app/task/task.cpp +++ b/app/task/task.cpp @@ -23,7 +23,8 @@ Task::Task() : status_(kWaiting), thread_(this), - text_(tr("Task")) + text_(tr("Task")), + cancelled_(false) { connect(&thread_, SIGNAL(finished()), this, SLOT(ThreadComplete())); } @@ -55,6 +56,8 @@ bool Task::Start() } } + cancelled_ = false; + set_status(kWorking); thread_.start(); @@ -90,6 +93,18 @@ void Task::AddDependency(Task *dependency) dependencies_.append(dependency); } +void Task::Cancel() +{ + if (status_ != kWorking) { + return; + } + + cancelled_ = true; + + // FIXME: Should we limit the wait time? + thread_.wait(); +} + void Task::set_error(const QString &s) { error_ = s; @@ -100,6 +115,11 @@ void Task::set_text(const QString &s) text_ = s; } +bool Task::cancelled() +{ + return cancelled_; +} + void Task::set_status(const Task::Status &status) { status_ = status; diff --git a/app/task/task.h b/app/task/task.h index 501a9c37d..4ffde285e 100644 --- a/app/task/task.h +++ b/app/task/task.h @@ -141,6 +141,18 @@ public: */ void AddDependency(Task* dependency); +public slots: + /** + * @brief Cancel the Task + * + * Sends a signal to the Task to stop and waits for the Task to finish before returning. Tasks must be responsive to + * cancelling so that the main thread doesn't halt for too long. + * + * Cancel()'s function is fairly simple, it sets cancelled_ to TRUE and waits for the thread to return. It's the + * responsibility of the code in Action() to be able to respond quickly to cancelled_ changing. + */ + void Cancel(); + protected: /** * @brief Set the error message @@ -159,6 +171,11 @@ protected: */ void set_text(const QString& s); + /** + * @brief Returns whether the thread has been explicitly cancelled or not + */ + bool cancelled(); + signals: /** * @brief Signal emitted whenever the Task status changes @@ -197,6 +214,8 @@ private: QList dependencies_; + bool cancelled_; + private slots: /** * @brief A slot when the inner thread completes either successfully or unsuccessfully diff --git a/app/widget/taskview/taskviewitem.cpp b/app/widget/taskview/taskviewitem.cpp index 07e7cf635..476ca93fe 100644 --- a/app/widget/taskview/taskviewitem.cpp +++ b/app/widget/taskview/taskviewitem.cpp @@ -76,6 +76,7 @@ void TaskViewItem::SetTask(Task *t) 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(cancel_btn_, SIGNAL(clicked(bool)), task_, SLOT(Cancel())); } void TaskViewItem::TaskStatusChange(Task::Status status)