diff --git a/app/codec/decoder.cpp b/app/codec/decoder.cpp index 26efa8ccc..53e728415 100644 --- a/app/codec/decoder.cpp +++ b/app/codec/decoder.cpp @@ -203,7 +203,7 @@ QVector ReceiveListOfAllDecoders() return decoders; } -FootagePtr Decoder::Probe(Project* project, const QString &filename, const QAtomicInt* cancelled) +Footage* Decoder::Probe(Project* project, const QString &filename, const QAtomicInt* cancelled) { // Check for a valid filename if (filename.isEmpty()) { @@ -229,7 +229,7 @@ FootagePtr Decoder::Probe(Project* project, const QString &filename, const QAtom DecoderPtr decoder = decoder_list.at(i); - FootagePtr footage = decoder->Probe(filename, cancelled); + Footage* footage = decoder->Probe(filename, cancelled); if (footage) { QFileInfo file_info(filename); diff --git a/app/codec/decoder.h b/app/codec/decoder.h index 74137e33b..e57226b16 100644 --- a/app/codec/decoder.h +++ b/app/codec/decoder.h @@ -129,7 +129,7 @@ public: * * TRUE if a Decoder was successfully able to parse and probe this file. FALSE if not. */ - static FootagePtr Probe(Project *project, const QString& filename, const QAtomicInt *cancelled); + static Footage *Probe(Project *project, const QString& filename, const QAtomicInt *cancelled); /** * @brief Generate a Footage object from a file @@ -142,7 +142,7 @@ public: * * This function is re-entrant. */ - virtual FootagePtr Probe(const QString& filename, const QAtomicInt* cancelled) const = 0; + virtual Footage *Probe(const QString& filename, const QAtomicInt* cancelled) const = 0; /** * @brief Closes media/deallocates memory diff --git a/app/codec/ffmpeg/ffmpegdecoder.cpp b/app/codec/ffmpeg/ffmpegdecoder.cpp index bfafa2b2f..10be95915 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.cpp +++ b/app/codec/ffmpeg/ffmpegdecoder.cpp @@ -218,13 +218,13 @@ QString FFmpegDecoder::id() return QStringLiteral("ffmpeg"); } -FootagePtr FFmpegDecoder::Probe(const QString& filename, const QAtomicInt* cancelled) const +Footage *FFmpegDecoder::Probe(const QString& filename, const QAtomicInt* cancelled) const { // Variable for receiving errors from FFmpeg int error_code; // Result to return - FootagePtr footage = nullptr; + Footage* footage = nullptr; // Convert QString to a C string QByteArray ba = filename.toUtf8(); @@ -444,7 +444,7 @@ FootagePtr FFmpegDecoder::Probe(const QString& filename, const QAtomicInt* cance if (found_valid_streams) { // We actually have footage we can return instead of nullptr - footage = std::make_shared(); + footage = new Footage(); // Copy streams over foreach (StreamPtr stream, streams) { diff --git a/app/codec/ffmpeg/ffmpegdecoder.h b/app/codec/ffmpeg/ffmpegdecoder.h index 6bbf80b1e..154e446e0 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.h +++ b/app/codec/ffmpeg/ffmpegdecoder.h @@ -57,7 +57,7 @@ public: virtual bool SupportsVideo() override{return true;} virtual bool SupportsAudio() override{return true;} - virtual FootagePtr Probe(const QString& filename, const QAtomicInt* cancelled) const override; + virtual Footage* Probe(const QString& filename, const QAtomicInt* cancelled) const override; protected: virtual bool OpenInternal() override; diff --git a/app/codec/oiio/oiiodecoder.cpp b/app/codec/oiio/oiiodecoder.cpp index f3fc5eb6c..49752415e 100644 --- a/app/codec/oiio/oiiodecoder.cpp +++ b/app/codec/oiio/oiiodecoder.cpp @@ -51,7 +51,7 @@ QString OIIODecoder::id() return QStringLiteral("oiio"); } -FootagePtr OIIODecoder::Probe(const QString& filename, const QAtomicInt* cancelled) const +Footage *OIIODecoder::Probe(const QString& filename, const QAtomicInt* cancelled) const { Q_UNUSED(cancelled) @@ -75,7 +75,7 @@ FootagePtr OIIODecoder::Probe(const QString& filename, const QAtomicInt* cancell return nullptr; } - FootagePtr footage = std::make_shared(); + Footage* footage = new Footage(); VideoStreamPtr image_stream = std::make_shared(); diff --git a/app/codec/oiio/oiiodecoder.h b/app/codec/oiio/oiiodecoder.h index 9b06df1d6..04a1397b1 100644 --- a/app/codec/oiio/oiiodecoder.h +++ b/app/codec/oiio/oiiodecoder.h @@ -40,7 +40,7 @@ public: virtual bool SupportsVideo() override{return true;} - virtual FootagePtr Probe(const QString& filename, const QAtomicInt* cancelled) const override; + virtual Footage* Probe(const QString& filename, const QAtomicInt* cancelled) const override; protected: virtual bool OpenInternal() override; diff --git a/app/core.cpp b/app/core.cpp index 937a48c72..f9846885c 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -378,7 +378,7 @@ void Core::CreateNewFolder() Folder* folder = active_project_panel->GetSelectedFolder(); // Create new folder - ItemPtr new_folder = std::make_shared(); + Folder* new_folder = new Folder(); // Set a default name new_folder->set_name(tr("New Folder")); @@ -391,7 +391,7 @@ void Core::CreateNewFolder() Core::instance()->undo_stack()->push(aic); // Trigger an automatic rename so users can enter the folder name - active_project_panel->Edit(new_folder.get()); + active_project_panel->Edit(new_folder); } void Core::CreateNewSequence() @@ -404,18 +404,19 @@ void Core::CreateNewSequence() } // Create new sequence - SequencePtr new_sequence = CreateNewSequenceForProject(active_project); + Sequence* new_sequence = CreateNewSequenceForProject(active_project); // Set all defaults for the sequence new_sequence->set_default_parameters(); - SequenceDialog sd(new_sequence.get(), SequenceDialog::kNew, main_window_); + SequenceDialog sd(new_sequence, SequenceDialog::kNew, main_window_); // Make sure SequenceDialog doesn't make an undo command for editing the sequence, since we make an undo command for // adding it later on sd.SetUndoable(false); if (sd.exec() == QDialog::Accepted) { + // Create an undoable command ProjectViewModel::AddItemCommand* aic = new ProjectViewModel::AddItemCommand(GetActiveProjectModel(), GetSelectedFolderInActiveProject(), @@ -425,7 +426,13 @@ void Core::CreateNewSequence() Core::instance()->undo_stack()->push(aic); - Core::instance()->main_window()->OpenSequence(new_sequence.get()); + Core::instance()->main_window()->OpenSequence(new_sequence); + + } else { + + // If the dialog was accepted, ownership goes to the AddItemCommand. But if we get here, just delete + delete new_sequence; + } } @@ -538,7 +545,7 @@ bool Core::StartHeadlessExport() if (task_dialog.Run()) { std::unique_ptr p = std::unique_ptr(plm.GetLoadedProject()); - QList items = p->get_items_of_type(Item::kSequence); + QVector items = p->get_items_of_type(Item::kSequence); // Check if this project contains sequences if (items.isEmpty()) { @@ -546,7 +553,7 @@ bool Core::StartHeadlessExport() return false; } - SequencePtr sequence = nullptr; + Sequence* sequence = nullptr; // Check if this project contains multiple sequences if (items.size() > 1) { @@ -579,9 +586,9 @@ bool Core::StartHeadlessExport() } } - sequence = std::static_pointer_cast(items.at(sequence_index)); + sequence = static_cast(items.at(sequence_index)); } else { - sequence = std::static_pointer_cast(items.first()); + sequence = static_cast(items.first()); } ExportParams params; @@ -1087,9 +1094,9 @@ void Core::LabelNodes(const QVector &nodes) const } } -SequencePtr Core::CreateNewSequenceForProject(Project* project) const +Sequence *Core::CreateNewSequenceForProject(Project* project) const { - SequencePtr new_sequence = std::make_shared(); + Sequence* new_sequence = new Sequence(); // Get default name for this sequence (in the format "Sequence N", the first that doesn't exist) int sequence_number = 1; @@ -1282,12 +1289,12 @@ void Core::CacheActiveSequence(bool in_out_only) bool Core::ValidateFootageInLoadedProject(Project* project, const QString& project_saved_url) { - QList footage_we_couldnt_validate; + QVector footage_we_couldnt_validate; - QList project_footage = project->get_items_of_type(Item::kFootage); + QVector project_footage = project->get_items_of_type(Item::kFootage); - foreach (ItemPtr item, project_footage) { - FootagePtr footage = std::static_pointer_cast(item); + foreach (Item* item, project_footage) { + Footage* footage = static_cast(item); if (!QFileInfo::exists(footage->filename()) && !project_saved_url.isEmpty()) { // If the footage doesn't exist, it might have moved with the project diff --git a/app/core.h b/app/core.h index da6c2d9d2..c05fb5a23 100644 --- a/app/core.h +++ b/app/core.h @@ -246,7 +246,7 @@ public: /** * @brief Create a new sequence named appropriately for the active project */ - SequencePtr CreateNewSequenceForProject(Project *project) const; + Sequence* CreateNewSequenceForProject(Project *project) const; /** * @brief Opens a project from the recently opened list diff --git a/app/dialog/footagerelink/footagerelinkdialog.cpp b/app/dialog/footagerelink/footagerelinkdialog.cpp index cc8b149fb..1a840b6aa 100644 --- a/app/dialog/footagerelink/footagerelinkdialog.cpp +++ b/app/dialog/footagerelink/footagerelinkdialog.cpp @@ -31,7 +31,7 @@ namespace olive { -FootageRelinkDialog::FootageRelinkDialog(const QList& footage, QWidget* parent) : +FootageRelinkDialog::FootageRelinkDialog(const QVector &footage, QWidget* parent) : QDialog(parent), footage_(footage) { @@ -54,7 +54,7 @@ FootageRelinkDialog::FootageRelinkDialog(const QList& footage, QWidg table_->header()->setStretchLastSection(false); for (int i=0; i& footage, QWidg void FootageRelinkDialog::UpdateFootageItem(int index) { - FootagePtr f = footage_.at(index); + Footage* f = footage_.at(index); QTreeWidgetItem* item = table_->topLevelItem(index); item->setIcon(0, f->icon()); item->setText(1, f->filename()); @@ -96,7 +96,7 @@ void FootageRelinkDialog::UpdateFootageItem(int index) void FootageRelinkDialog::BrowseForFootage() { int index = sender()->property("index").toInt(); - FootagePtr f = footage_.at(index); + Footage* f = footage_.at(index); QFileInfo info(f->filename()); @@ -124,7 +124,7 @@ void FootageRelinkDialog::BrowseForFootage() // Check all other footage files for matches for (int it=0; itIsValid()) { diff --git a/app/dialog/footagerelink/footagerelinkdialog.h b/app/dialog/footagerelink/footagerelinkdialog.h index 91999ffc2..d1c04cd56 100644 --- a/app/dialog/footagerelink/footagerelinkdialog.h +++ b/app/dialog/footagerelink/footagerelinkdialog.h @@ -32,14 +32,14 @@ class FootageRelinkDialog : public QDialog { Q_OBJECT public: - FootageRelinkDialog(const QList& footage, QWidget* parent = nullptr); + FootageRelinkDialog(const QVector& footage, QWidget* parent = nullptr); private: void UpdateFootageItem(int index); QTreeWidget* table_; - QList footage_; + QVector footage_; private slots: void BrowseForFootage(); diff --git a/app/node/graph.h b/app/node/graph.h index e722403d7..36d431a13 100644 --- a/app/node/graph.h +++ b/app/node/graph.h @@ -21,16 +21,18 @@ #ifndef NODEGRAPH_H #define NODEGRAPH_H -#include - #include "node/node.h" +#include "project/item/item.h" namespace olive { /** * @brief A collection of nodes + * + * This doesn't technically need to be a derivative of Item, but since both Item and NodeGraph need + * to be QObject derivatives, this simplifies Sequence. */ -class NodeGraph : public QObject +class NodeGraph : public Item { Q_OBJECT public: diff --git a/app/panel/project/project.cpp b/app/panel/project/project.cpp index 5a8318e93..5fbbd7a3c 100644 --- a/app/panel/project/project.cpp +++ b/app/panel/project/project.cpp @@ -215,7 +215,7 @@ void ProjectPanel::UpdateSubtitle() do { folder_path.prepend(QStringLiteral("/%1").arg(item->name())); - item = item->parent(); + item = item->item_parent(); } while (item != project()->root()); project_title.append(folder_path); diff --git a/app/project/item/folder/folder.cpp b/app/project/item/folder/folder.cpp index 69c0aaa82..0618e4f3b 100644 --- a/app/project/item/folder/folder.cpp +++ b/app/project/item/folder/folder.cpp @@ -61,20 +61,20 @@ void Folder::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, uint ver return; } - ItemPtr child; + Item* child; if (reader->name() == QStringLiteral("folder")) { - child = std::make_shared(); + child = new Folder(); } else if (reader->name() == QStringLiteral("footage")) { - child = std::make_shared(); + child = new Footage(); } else if (reader->name() == QStringLiteral("sequence")) { - child = std::make_shared(); + child = new Sequence(); } else { reader->skipCurrentElement(); continue; } - add_child(child); + child->setParent(this); child->Load(reader, xml_node_data, version, cancelled); } } @@ -85,7 +85,7 @@ void Folder::Save(QXmlStreamWriter *writer) const writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast(this))); - foreach (ItemPtr child, children()) { + foreach (Item* child, children()) { switch (child->type()) { case Item::kFootage: writer->writeStartElement(QStringLiteral("footage")); diff --git a/app/project/item/footage/footage.cpp b/app/project/item/footage/footage.cpp index 08c358208..5f59c67b6 100644 --- a/app/project/item/footage/footage.cpp +++ b/app/project/item/footage/footage.cpp @@ -299,7 +299,7 @@ StreamPtr Footage::get_first_stream_of_type(const Stream::Type &type) const return nullptr; } -bool Footage::CompareFootageToFile(FootagePtr footage, const QString &filename) +bool Footage::CompareFootageToFile(Footage *footage, const QString &filename) { // Heuristic to determine if file has changed QFileInfo info(filename); @@ -311,9 +311,9 @@ bool Footage::CompareFootageToFile(FootagePtr footage, const QString &filename) } else { // Footage may have changed and we'll have to re-probe it. It also may not have, in which // case nothing needs to change. - ItemPtr item = Decoder::Probe(footage->project(), filename, nullptr); + std::unique_ptr item(Decoder::Probe(footage->project(), filename, nullptr)); - if (item && item->type() == footage->type()) { + if (item) { // Item is the same type, that's a good sign. Let's look for any differences. // FIXME: Implement this return true; @@ -325,7 +325,7 @@ bool Footage::CompareFootageToFile(FootagePtr footage, const QString &filename) return false; } -bool Footage::CompareFootageToItsFilename(FootagePtr footage) +bool Footage::CompareFootageToItsFilename(Footage *footage) { return CompareFootageToFile(footage, footage->filename()); } diff --git a/app/project/item/footage/footage.h b/app/project/item/footage/footage.h index a01c35600..39850ef8a 100644 --- a/app/project/item/footage/footage.h +++ b/app/project/item/footage/footage.h @@ -32,9 +32,6 @@ namespace olive { -class Footage; -using FootagePtr = std::shared_ptr; - /** * @brief A reference to an external media file with metadata in a project structure * @@ -44,6 +41,7 @@ using FootagePtr = std::shared_ptr; */ class Footage : public Item, public TimelinePoints { + Q_OBJECT public: /** * @brief Footage Constructor @@ -202,8 +200,8 @@ public: StreamPtr get_first_stream_of_type(const Stream::Type& type) const; - static bool CompareFootageToFile(FootagePtr footage, const QString& filename); - static bool CompareFootageToItsFilename(FootagePtr footage); + static bool CompareFootageToFile(Footage* footage, const QString& filename); + static bool CompareFootageToItsFilename(Footage* footage); private: /** diff --git a/app/project/item/item.cpp b/app/project/item/item.cpp index 33657825e..0495c3729 100644 --- a/app/project/item/item.cpp +++ b/app/project/item/item.cpp @@ -23,7 +23,7 @@ namespace olive { Item::Item() : - parent_(nullptr), + item_parent_(nullptr), project_(nullptr) { } @@ -32,65 +32,6 @@ Item::~Item() { } -void Item::add_child(ItemPtr c) -{ - if (c->parent_ == this) { - return; - } - - if (c->parent_ != nullptr) { - c->parent_->remove_child(c.get()); - } - - children_.append(c); - c->parent_ = this; -} - -void Item::remove_child(Item *c) -{ - if (c->parent_ != this) { - return; - } - - // Remove all instances of this child in the list - for (int i=0;iparent_ = nullptr; -} - -int Item::child_count() const -{ - return children_.size(); -} - -Item *Item::child(int i) const -{ - return children_.at(i).get(); -} - -const QList &Item::children() const -{ - return children_; -} - -ItemPtr Item::get_shared_ptr() const -{ - QList siblings = parent()->children(); - - foreach (ItemPtr s, siblings) { - if (s.get() == this) { - return s; - } - } - - return nullptr; -} - const QString &Item::name() const { return name_; @@ -123,17 +64,12 @@ QString Item::rate() return QString(); } -Item *Item::parent() const -{ - return parent_; -} - const Item *Item::root() const { const Item* item = this; - while (item->parent()) { - item = item->parent(); + while (item->item_parent()) { + item = item->item_parent(); } return item; @@ -151,11 +87,11 @@ void Item::set_project(Project *project) project_ = project; } -QList Item::get_children_of_type(Type type, bool recursive) const +QVector Item::get_children_of_type(Type type, bool recursive) const { - QList list; + QVector list; - foreach (ItemPtr item, children_) { + foreach (Item* item, item_children_) { if (item->type() == type) { list.append(item); } @@ -182,12 +118,31 @@ void Item::NameChangedEvent(const QString &) { } +void Item::childEvent(QChildEvent *event) +{ + QObject::childEvent(event); + + Item* cast_test = dynamic_cast(event->child()); + + if (cast_test) { + if (event->type() == QEvent::ChildAdded) { + + item_children_.append(cast_test); + cast_test->item_parent_ = this; + + } else if (event->type() == QEvent::ChildRemoved) { + + item_children_.removeOne(cast_test); + cast_test->item_parent_ = nullptr; + + } + } +} + bool Item::ChildExistsWithNameInternal(const QString &name, Item *folder) { // Loop through all children - for (int i=0;ichild_count();i++) { - Item* child = folder->child(i); - + foreach (Item* child, folder->item_children_) { // If this child has the same name, return true if (child->name() == name) { return true; diff --git a/app/project/item/item.h b/app/project/item/item.h index efaaaf963..3d64daa32 100644 --- a/app/project/item/item.h +++ b/app/project/item/item.h @@ -37,17 +37,15 @@ namespace olive { class Project; -class Item; -using ItemPtr = std::shared_ptr; - /** * @brief A base-class representing any element in a Project * * Project objects implement a parent-child hierarchy of Items that can be used throughout the Project. The Item class * itself is abstract and will need to be subclassed to be used in a Project. */ -class Item +class Item : public QObject { + Q_OBJECT public: enum Type { kFolder, @@ -65,21 +63,26 @@ public: */ virtual ~Item(); - DISABLE_COPY_MOVE(Item) - virtual void Load(QXmlStreamReader* reader, XMLNodeData &xml_node_data, uint version, const QAtomicInt *cancelled) = 0; virtual void Save(QXmlStreamWriter* writer) const = 0; virtual Type type() const = 0; - void add_child(ItemPtr c); - void remove_child(Item* c); - int child_count() const; - Item* child(int i) const; - const QList& children() const; + int item_child_count() const + { + return item_children_.size(); + } - ItemPtr get_shared_ptr() const; + Item* item_child(int i) const + { + return item_children_.at(i); + } + + const QVector& children() const + { + return item_children_; + } const QString& name() const; void set_name(const QString& n); @@ -93,13 +96,17 @@ public: virtual QString rate(); - Item *parent() const; + Item *item_parent() const + { + return item_parent_; + } + const Item* root() const; Project* project() const; void set_project(Project* project); - QList get_children_of_type(Type type, bool recursive) const; + QVector get_children_of_type(Type type, bool recursive) const; virtual bool CanHaveChildren() const; @@ -108,12 +115,14 @@ public: protected: virtual void NameChangedEvent(const QString& name); + virtual void childEvent(QChildEvent *event) override; + private: - bool ChildExistsWithNameInternal(const QString& name, Item* folder); + static bool ChildExistsWithNameInternal(const QString& name, Item* folder); - QList children_; + QVector item_children_; - Item* parent_; + Item* item_parent_; Project* project_; diff --git a/app/project/item/sequence/sequence.cpp b/app/project/item/sequence/sequence.cpp index a24d93b85..cccc57c72 100644 --- a/app/project/item/sequence/sequence.cpp +++ b/app/project/item/sequence/sequence.cpp @@ -171,12 +171,6 @@ void Sequence::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, uint v // Link blocks XMLLinkBlocks(xml_node_data); - - // Ensure this and all children are in the main thread - // NOTE: It might be good to move the Item system to QObjects so they inherit their thread - if (QThread::currentThread() != qApp->thread()) { - moveToThread(qApp->thread()); - } } void Sequence::Save(QXmlStreamWriter *writer) const diff --git a/app/project/item/sequence/sequence.h b/app/project/item/sequence/sequence.h index aab7920df..023f9378f 100644 --- a/app/project/item/sequence/sequence.h +++ b/app/project/item/sequence/sequence.h @@ -31,14 +31,12 @@ namespace olive { -class Sequence; -using SequencePtr = std::shared_ptr; - /** * @brief The main timeline object, an graph of edited clips that forms a complete edit */ -class Sequence : public Item, public NodeGraph, public TimelinePoints +class Sequence : public NodeGraph, public TimelinePoints { + Q_OBJECT public: Sequence(); diff --git a/app/project/project.cpp b/app/project/project.cpp index 84f15dd8b..9aa04a90f 100644 --- a/app/project/project.cpp +++ b/app/project/project.cpp @@ -161,7 +161,7 @@ ColorManager *Project::color_manager() return &color_manager_; } -QList Project::get_items_of_type(Item::Type type) const +QVector Project::get_items_of_type(Item::Type type) const { return root_.get_children_of_type(type, true); } @@ -204,10 +204,10 @@ const QString &Project::cache_path(bool default_if_empty) const void Project::ColorConfigChanged() { - QList footage = this->get_items_of_type(Item::kFootage); + QVector footage = this->get_items_of_type(Item::kFootage); - foreach (ItemPtr item, footage) { - foreach (StreamPtr s, std::static_pointer_cast(item)->streams()) { + foreach (Item* item, footage) { + foreach (StreamPtr s, static_cast(item)->streams()) { if (s->type() == Stream::kVideo) { std::static_pointer_cast(s)->ColorConfigChanged(); } @@ -217,10 +217,10 @@ void Project::ColorConfigChanged() void Project::DefaultColorSpaceChanged() { - QList footage = this->get_items_of_type(Item::kFootage); + QVector footage = this->get_items_of_type(Item::kFootage); - foreach (ItemPtr item, footage) { - foreach (StreamPtr s, std::static_pointer_cast(item)->streams()) { + foreach (Item* item, footage) { + foreach (StreamPtr s, static_cast(item)->streams()) { if (s->type() == Stream::kVideo) { std::static_pointer_cast(s)->DefaultColorSpaceChanged(); } diff --git a/app/project/project.h b/app/project/project.h index d6d801ca5..59501cd97 100644 --- a/app/project/project.h +++ b/app/project/project.h @@ -61,7 +61,7 @@ public: ColorManager* color_manager(); - QList get_items_of_type(Item::Type type) const; + QVector get_items_of_type(Item::Type type) const; bool is_modified() const; void set_modified(bool e); diff --git a/app/project/projectviewmodel.cpp b/app/project/projectviewmodel.cpp index f11135e3e..b5a9acbb4 100644 --- a/app/project/projectviewmodel.cpp +++ b/app/project/projectviewmodel.cpp @@ -64,7 +64,7 @@ QModelIndex ProjectViewModel::index(int row, int column, const QModelIndex &pare Item* item_parent = GetItemObjectFromIndex(parent); // Return an index to this object - return createIndex(row, column, item_parent->child(row)); + return createIndex(row, column, item_parent->item_child(row)); } QModelIndex ProjectViewModel::parent(const QModelIndex &child) const @@ -73,7 +73,7 @@ QModelIndex ProjectViewModel::parent(const QModelIndex &child) const Item* item = GetItemObjectFromIndex(child); // Get Item's parent object - Item* par = item->parent(); + Item* par = item->item_parent(); // If the parent is the root, return an empty index if (par == project_->root()) { @@ -99,11 +99,11 @@ int ProjectViewModel::rowCount(const QModelIndex &parent) const // If the index is the root, return the root child count if (parent == QModelIndex()) { - return project_->root()->child_count(); + return project_->root()->item_child_count(); } // Otherwise, the index must contain a valid pointer, so we just return its child count - return GetItemObjectFromIndex(parent)->child_count(); + return GetItemObjectFromIndex(parent)->item_child_count(); } int ProjectViewModel::columnCount(const QModelIndex &parent) const @@ -375,7 +375,7 @@ bool ProjectViewModel::dropMimeData(const QMimeData *data, Qt::DropAction action // If we didn't drop onto an item, find the nearest parent folder (should eventually terminate at root either way) while (!drop_item->CanHaveChildren()) { - drop_item = drop_item->parent(); + drop_item = drop_item->item_parent(); } // Trigger an import @@ -385,7 +385,7 @@ bool ProjectViewModel::dropMimeData(const QMimeData *data, Qt::DropAction action return false; } -void ProjectViewModel::AddChild(Item *parent, ItemPtr child) +void ProjectViewModel::AddChild(Item *parent, Item *child) { QModelIndex parent_index; @@ -393,14 +393,14 @@ void ProjectViewModel::AddChild(Item *parent, ItemPtr child) parent_index = CreateIndexFromItem(parent); } - beginInsertRows(parent_index, parent->child_count(), parent->child_count()); + beginInsertRows(parent_index, parent->item_child_count(), parent->item_child_count()); - parent->add_child(child); + child->setParent(parent); endInsertRows(); } -void ProjectViewModel::RemoveChild(Item *parent, Item *child) +void ProjectViewModel::RemoveChild(Item *parent, Item *child, QObject *new_parent) { QModelIndex parent_index; @@ -412,7 +412,7 @@ void ProjectViewModel::RemoveChild(Item *parent, Item *child) beginRemoveRows(parent_index, child_row, child_row); - parent->remove_child(child); + child->setParent(new_parent); endRemoveRows(); } @@ -435,11 +435,11 @@ int ProjectViewModel::IndexOfChild(Item *item) const return -1; } - Item* parent = item->parent(); + Item* parent = item->item_parent(); if (parent != nullptr) { - for (int i=0;ichild_count();i++) { - if (parent->child(i) == item) { + for (int i=0;iitem_child_count();i++) { + if (parent->item_child(i) == item) { return i; } } @@ -452,7 +452,7 @@ int ProjectViewModel::ChildCount(const QModelIndex &index) { Item* item = GetItemObjectFromIndex(index); - return item->child_count(); + return item->item_child_count(); } Item *ProjectViewModel::GetItemObjectFromIndex(const QModelIndex &index) const @@ -468,7 +468,7 @@ bool ProjectViewModel::ItemIsParentOfChild(Item *parent, Item *child) const { // Loop through parent hierarchy checking if `parent` is one of its parents do { - child = child->parent(); + child = child->item_parent(); if (parent == child) { return true; @@ -484,11 +484,10 @@ void ProjectViewModel::MoveItemInternal(Item *item, Item *destination) QModelIndex destination_index = CreateIndexFromItem(destination); - beginMoveRows(item_index.parent(), item_index.row(), item_index.row(), destination_index, destination->child_count()); + beginMoveRows(item_index.parent(), item_index.row(), item_index.row(), + destination_index, destination->item_child_count()); - ItemPtr item_ptr = item->get_shared_ptr(); - - destination->add_child(item_ptr); + item->setParent(destination); endMoveRows(); } @@ -553,13 +552,13 @@ void ProjectViewModel::RenameItemCommand::undo_internal() model_->RenameChild(item_, old_name_); } -ProjectViewModel::AddItemCommand::AddItemCommand(ProjectViewModel* model, Item* folder, ItemPtr child, QUndoCommand* parent) : +ProjectViewModel::AddItemCommand::AddItemCommand(ProjectViewModel* model, Item* folder, Item* child, QUndoCommand* parent) : UndoCommand(parent), model_(model), parent_(folder), - child_(child), - done_(false) + child_(child) { + child_->setParent(&memory_manager_); } Project *ProjectViewModel::AddItemCommand::GetRelevantProject() const @@ -570,18 +569,14 @@ Project *ProjectViewModel::AddItemCommand::GetRelevantProject() const void ProjectViewModel::AddItemCommand::redo_internal() { model_->AddChild(parent_, child_); - - done_ = true; } void ProjectViewModel::AddItemCommand::undo_internal() { - model_->RemoveChild(parent_, child_.get()); - - done_ = false; + model_->RemoveChild(parent_, child_, &memory_manager_); } -ProjectViewModel::RemoveItemCommand::RemoveItemCommand(ProjectViewModel *model, ItemPtr item, QUndoCommand *parent) : +ProjectViewModel::RemoveItemCommand::RemoveItemCommand(ProjectViewModel *model, Item *item, QUndoCommand *parent) : UndoCommand(parent), model_(model), item_(item) @@ -595,8 +590,8 @@ Project *ProjectViewModel::RemoveItemCommand::GetRelevantProject() const void ProjectViewModel::RemoveItemCommand::redo_internal() { - parent_ = item_->parent(); - model_->RemoveChild(parent_, item_.get()); + parent_ = item_->item_parent(); + model_->RemoveChild(parent_, item_, &memory_manager_); } void ProjectViewModel::RemoveItemCommand::undo_internal() diff --git a/app/project/projectviewmodel.h b/app/project/projectviewmodel.h index e524684ba..9f790a96a 100644 --- a/app/project/projectviewmodel.h +++ b/app/project/projectviewmodel.h @@ -100,8 +100,8 @@ 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, ItemPtr child); - void RemoveChild(Item* parent, Item* child); + void AddChild(Item* parent, Item* child); + void RemoveChild(Item* parent, Item* child, QObject* new_parent); void RenameChild(Item* item, const QString& name); /** @@ -157,7 +157,7 @@ public: */ class AddItemCommand : public UndoCommand { public: - AddItemCommand(ProjectViewModel* model, Item* folder, ItemPtr child, QUndoCommand* parent = nullptr); + AddItemCommand(ProjectViewModel* model, Item* folder, Item *child, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; @@ -169,8 +169,9 @@ public: private: ProjectViewModel* model_; Item* parent_; - ItemPtr child_; - bool done_; + Item* child_; + QObject memory_manager_; + }; /** @@ -178,7 +179,7 @@ public: */ class RemoveItemCommand : public UndoCommand { public: - RemoveItemCommand(ProjectViewModel* model, ItemPtr item, QUndoCommand* parent = nullptr); + RemoveItemCommand(ProjectViewModel* model, Item* item, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; @@ -189,10 +190,9 @@ public: private: ProjectViewModel* model_; - - ItemPtr item_; - + Item* item_; Item* parent_; + QObject memory_manager_; }; diff --git a/app/task/project/import/import.cpp b/app/task/project/import/import.cpp index be423648f..267ddd8ca 100644 --- a/app/task/project/import/import.cpp +++ b/app/task/project/import/import.cpp @@ -93,8 +93,9 @@ void ProjectImportTask::Import(Folder *folder, QFileInfoList import, int &counte // Only proceed if the empty actually has files in it if (!entry_list.isEmpty()) { // Create a folder corresponding to the directory + Folder* f = new Folder(); - ItemPtr f = std::make_shared(); + f->moveToThread(folder->thread()); f->set_name(file_info.fileName()); @@ -105,22 +106,25 @@ void ProjectImportTask::Import(Folder *folder, QFileInfoList import, int &counte parent_command); // Recursively follow this path - Import(static_cast(f.get()), entry_list, counter, parent_command); + Import(f, entry_list, counter, parent_command); } } else { - FootagePtr item = Decoder::Probe(model_->project(), file_info.absoluteFilePath(), - &IsCancelled()); + Footage* footage = Decoder::Probe(model_->project(), file_info.absoluteFilePath(), + &IsCancelled()); + + if (footage) { + // Move footage to main thread + footage->moveToThread(folder->thread()); - if (item) { // See if this footage is an image sequence - ValidateImageSequence(item, import, i); + ValidateImageSequence(footage, import, i); // Create undoable command that adds the items to the model new ProjectViewModel::AddItemCommand(model_, folder, - item, + footage, parent_command); } else { // Add to list so we can tell the user about it later @@ -135,14 +139,9 @@ void ProjectImportTask::Import(Folder *folder, QFileInfoList import, int &counte } } -void ProjectImportTask::ValidateImageSequence(ItemPtr item, QFileInfoList& info_list, int index) +void ProjectImportTask::ValidateImageSequence(Footage *footage, QFileInfoList& info_list, int index) { // Heuristically determine whether this file is part of an image sequence or not - if (!ItemIsStillImageFootageOnly(item)) { - return; - } - - FootagePtr footage = std::static_pointer_cast(item); VideoStreamPtr video_stream = std::static_pointer_cast(footage->streams().first()); // By this point we've established that video contains a single still image stream. Now we'll @@ -159,8 +158,8 @@ void ProjectImportTask::ValidateImageSequence(ItemPtr item, QFileInfoList& info_ // See if the same decoder can retrieve surrounding files DecoderPtr decoder = Decoder::CreateFromID(footage->decoder()); - ItemPtr previous_file = decoder->Probe(previous_img_fn, nullptr); - ItemPtr next_file = decoder->Probe(next_img_fn, nullptr); + Footage* previous_file = decoder->Probe(previous_img_fn, nullptr); + Footage* next_file = decoder->Probe(next_img_fn, nullptr); // Finally see if these files have the same dimensions if ((previous_file && CompareStillImageSize(previous_file, dim)) @@ -218,15 +217,8 @@ void ProjectImportTask::ValidateImageSequence(ItemPtr item, QFileInfoList& info_ } } -bool ProjectImportTask::ItemIsStillImageFootageOnly(ItemPtr item) +bool ProjectImportTask::ItemIsStillImageFootageOnly(Footage* footage) { - if (item->type() != Item::kFootage) { - // Item isn't footage, definitely isn't an image sequence - return false; - } - - FootagePtr footage = std::static_pointer_cast(item); - if (footage->stream_count() != 1) { // Footage with more than one stream (usually video+audio) most likely isn't an image sequence return false; @@ -247,13 +239,12 @@ bool ProjectImportTask::ItemIsStillImageFootageOnly(ItemPtr item) return true; } -bool ProjectImportTask::CompareStillImageSize(ItemPtr item, const QSize &sz) +bool ProjectImportTask::CompareStillImageSize(Footage* footage, const QSize &sz) { - if (!ItemIsStillImageFootageOnly(item)) { + if (!ItemIsStillImageFootageOnly(footage)) { return false; } - FootagePtr footage = std::static_pointer_cast(item); VideoStreamPtr video_stream = std::static_pointer_cast(footage->streams().first()); return video_stream->width() == sz.width() && video_stream->height() == sz.height(); diff --git a/app/task/project/import/import.h b/app/task/project/import/import.h index 9dd44b65e..a8546ffcb 100644 --- a/app/task/project/import/import.h +++ b/app/task/project/import/import.h @@ -59,11 +59,11 @@ protected: private: void Import(Folder* folder, QFileInfoList import, int& counter, QUndoCommand *parent_command); - void ValidateImageSequence(ItemPtr item, QFileInfoList &info_list, int index); + void ValidateImageSequence(Footage *footage, QFileInfoList &info_list, int index); - static bool ItemIsStillImageFootageOnly(ItemPtr item); + static bool ItemIsStillImageFootageOnly(Footage *footage); - static bool CompareStillImageSize(ItemPtr item, const QSize& sz); + static bool CompareStillImageSize(Footage *footage, const QSize& sz); static int64_t GetImageSequenceLimit(const QString &start_fn, int64_t start, bool up); diff --git a/app/widget/footagecombobox/footagecombobox.cpp b/app/widget/footagecombobox/footagecombobox.cpp index 684eeeca2..2eced37a5 100644 --- a/app/widget/footagecombobox/footagecombobox.cpp +++ b/app/widget/footagecombobox/footagecombobox.cpp @@ -38,7 +38,7 @@ FootageComboBox::FootageComboBox(QWidget *parent) : void FootageComboBox::showPopup() { - if (root_ == nullptr || root_->child_count() == 0) { + if (root_ == nullptr || root_->item_child_count() == 0) { return; } @@ -82,10 +82,9 @@ void FootageComboBox::SetFootage(StreamPtr f) UpdateText(); } -void FootageComboBox::TraverseFolder(const Folder *f, QMenu *m) +void FootageComboBox::TraverseFolder(const Folder *f, QMenu *m) const { - for (int i=0;ichild_count();i++) { - Item* child = f->child(i); + foreach (Item* child, f->children()) { if (child->CanHaveChildren()) { @@ -108,7 +107,9 @@ void FootageComboBox::TraverseFolder(const Folder *f, QMenu *m) stream_action->setIcon(stream->icon()); } } + } + } } diff --git a/app/widget/footagecombobox/footagecombobox.h b/app/widget/footagecombobox/footagecombobox.h index 2d96f4a6f..fa1038eef 100644 --- a/app/widget/footagecombobox/footagecombobox.h +++ b/app/widget/footagecombobox/footagecombobox.h @@ -50,7 +50,7 @@ signals: void FootageChanged(StreamPtr f); private: - void TraverseFolder(const Folder *f, QMenu* m); + void TraverseFolder(const Folder *f, QMenu* m) const; void UpdateText(); diff --git a/app/widget/nodecopypaste/nodecopypaste.cpp b/app/widget/nodecopypaste/nodecopypaste.cpp index ccc6c235a..e6949a176 100644 --- a/app/widget/nodecopypaste/nodecopypaste.cpp +++ b/app/widget/nodecopypaste/nodecopypaste.cpp @@ -135,7 +135,7 @@ QVector NodeCopyPasteWidget::PasteNodesFromClipboard(Sequence *graph, QU // Connect footage to existing footage if it exists if (!xml_node_data.footage_connections.isEmpty()) { // Get list of all footage from project - QList footage = graph->project()->get_items_of_type(Item::kFootage); + QVector footage = graph->project()->get_items_of_type(Item::kFootage); if (!footage.isEmpty()) { foreach (const XMLNodeData::FootageConnection& con, xml_node_data.footage_connections) { @@ -145,8 +145,8 @@ QVector NodeCopyPasteWidget::PasteNodesFromClipboard(Sequence *graph, QU bool found = false; - foreach (ItemPtr item, footage) { - const QList& streams = std::static_pointer_cast(item)->streams(); + foreach (Item* item, footage) { + const QList& streams = static_cast(item)->streams(); foreach (StreamPtr s, streams) { if (s.get() == loaded_stream) { diff --git a/app/widget/projectexplorer/projectexplorer.cpp b/app/widget/projectexplorer/projectexplorer.cpp index a9c38820e..fb200fd27 100644 --- a/app/widget/projectexplorer/projectexplorer.cpp +++ b/app/widget/projectexplorer/projectexplorer.cpp @@ -324,15 +324,15 @@ void ProjectExplorer::ShowContextMenu() Menu* proxy_menu = new Menu(tr("Pre-Cache"), &menu); menu.addMenu(proxy_menu); - QList sequences = project()->get_items_of_type(Item::kSequence); + QVector sequences = project()->get_items_of_type(Item::kSequence); if (sequences.isEmpty()) { QAction* a = proxy_menu->addAction(tr("No sequences exist in project")); a->setEnabled(false); } else { - foreach (ItemPtr i, sequences) { + foreach (Item* i, sequences) { QAction* a = proxy_menu->addAction(tr("For \"%1\"").arg(i->name())); - a->setData(Node::PtrToValue(i.get())); + a->setData(Node::PtrToValue(i)); } connect(proxy_menu, &Menu::triggered, this, &ProjectExplorer::ContextMenuStartProxy); @@ -501,7 +501,7 @@ Folder *ProjectExplorer::GetSelectedFolder() const // If this item is not a folder, presumably it's parent is if (!sel_item->CanHaveChildren()) { - sel_item = sel_item->parent(); + sel_item = sel_item->item_parent(); Q_ASSERT(sel_item->CanHaveChildren()); } @@ -545,11 +545,11 @@ QList ProjectExplorer::GetMediaNodesUsingFootage(Footage *item) QList list; // Get all sequences. - QList sequences = model_.project()->get_items_of_type(Item::kSequence); + QVector sequences = model_.project()->get_items_of_type(Item::kSequence); // Footage can contain multiple streams, all of which need to be dealt with - foreach (ItemPtr s, sequences) { - const QList& nodes = static_cast(s.get())->nodes(); + foreach (Item* s, sequences) { + const QList& nodes = static_cast(s)->nodes(); foreach (Node* n, nodes) { if (n->IsMedia()) { MediaInput* media_node = static_cast(n); @@ -677,7 +677,7 @@ void ProjectExplorer::DeleteSelected() break; } - new ProjectViewModel::RemoveItemCommand(&model_, item->get_shared_ptr(), command); + new ProjectViewModel::RemoveItemCommand(&model_, item, command); } Core::instance()->undo_stack()->pushIfHasChildren(command); diff --git a/app/widget/timelinewidget/tool/import.cpp b/app/widget/timelinewidget/tool/import.cpp index ff9a6a2b3..288288aad 100644 --- a/app/widget/timelinewidget/tool/import.cpp +++ b/app/widget/timelinewidget/tool/import.cpp @@ -353,7 +353,7 @@ void ImportTool::DropGhosts(bool insert) Project* active_project = Core::instance()->GetActiveProject(); if (active_project) { - SequencePtr new_sequence = Core::instance()->CreateNewSequenceForProject(active_project); + Sequence* new_sequence = Core::instance()->CreateNewSequenceForProject(active_project); new_sequence->set_default_parameters(); @@ -371,7 +371,7 @@ void ImportTool::DropGhosts(bool insert) } else { - SequenceDialog sd(new_sequence.get(), SequenceDialog::kNew, parent()); + SequenceDialog sd(new_sequence, SequenceDialog::kNew, parent()); sd.SetUndoable(false); if (sd.exec() != QDialog::Accepted) { @@ -390,11 +390,15 @@ void ImportTool::DropGhosts(bool insert) FootageToGhosts(0, dragged_footage_, new_sequence->video_params().time_base(), 0); - dst_graph = new_sequence.get(); + dst_graph = new_sequence; viewer_node = new_sequence->viewer_output(); // Set this as the sequence to open - open_sequence = new_sequence.get(); + open_sequence = new_sequence; + } else { + // If the sequence is valid, ownership is passed to AddItemCommand. + // Otherwise, we're responsible for deleting it. + delete new_sequence; } } } diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index 662e31d75..c6244d299 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -329,10 +329,10 @@ void MainWindow::ProjectOpen(Project *p) void MainWindow::ProjectClose(Project *p) { // Close any open sequences from project - QList open_sequences = p->get_items_of_type(Item::kSequence); + QVector open_sequences = p->get_items_of_type(Item::kSequence); - foreach (ItemPtr item, open_sequences) { - Sequence* seq = static_cast(item.get()); + foreach (Item* item, open_sequences) { + Sequence* seq = static_cast(item); if (IsSequenceOpen(seq)) { CloseSequence(seq); @@ -340,15 +340,15 @@ void MainWindow::ProjectClose(Project *p) } // Close any open footage in footage viewer - QList footage = p->get_items_of_type(Item::kFootage); + QVector footage = p->get_items_of_type(Item::kFootage); QList footage_in_viewer = footage_viewer_panel_->GetSelectedFootage(); if (!footage_in_viewer.isEmpty()) { // FootageViewer only has the one footage item Footage* f = footage_in_viewer.first(); - foreach (ItemPtr i, footage) { - if (f == i.get()) { + foreach (Item* i, footage) { + if (f == i) { footage_viewer_panel_->SetFootage(nullptr); break; }