implement entire project in nodes
Project items are now represented directly in nodes opening up more versatility and possibilities. This is the first iteration of this and will be buggy. Need to test thoroughly.
This commit is contained in:
@@ -27,80 +27,65 @@
|
||||
|
||||
namespace olive {
|
||||
|
||||
Item::Type Folder::type() const
|
||||
Folder::Folder()
|
||||
{
|
||||
return kFolder;
|
||||
}
|
||||
|
||||
bool Folder::CanHaveChildren() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
QIcon Folder::icon()
|
||||
QIcon Folder::icon() const
|
||||
{
|
||||
return icon::Folder;
|
||||
}
|
||||
|
||||
void Folder::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, uint version, const QAtomicInt *cancelled)
|
||||
bool ChildExistsWithNameInternal(const Folder* n, const QString& s)
|
||||
{
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (cancelled && *cancelled) {
|
||||
return;
|
||||
}
|
||||
foreach (const Node::OutputConnection& c, n->output_connections()) {
|
||||
Node* connected = c.second.node();
|
||||
|
||||
if (attr.name() == QStringLiteral("name")) {
|
||||
set_name(attr.value().toString());
|
||||
} else if (attr.name() == QStringLiteral("ptr")) {
|
||||
xml_node_data.item_ptrs.insert(attr.value().toULongLong(), this);
|
||||
}
|
||||
}
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (cancelled && *cancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
Item* child;
|
||||
|
||||
if (reader->name() == QStringLiteral("folder")) {
|
||||
child = new Folder();
|
||||
} else if (reader->name() == QStringLiteral("footage")) {
|
||||
child = new Footage();
|
||||
} else if (reader->name() == QStringLiteral("sequence")) {
|
||||
child = new Sequence();
|
||||
if (connected->GetLabel() == s) {
|
||||
return true;
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
continue;
|
||||
}
|
||||
Folder* subfolder = dynamic_cast<Folder*>(connected);
|
||||
|
||||
child->setParent(this);
|
||||
child->Load(reader, xml_node_data, version, cancelled);
|
||||
if (subfolder && ChildExistsWithNameInternal(subfolder, s)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Folder::Save(QXmlStreamWriter *writer) const
|
||||
bool Folder::ChildExistsWithName(const QString &s) const
|
||||
{
|
||||
writer->writeAttribute(QStringLiteral("name"), name());
|
||||
return ChildExistsWithNameInternal(this, s);
|
||||
}
|
||||
|
||||
writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast<quintptr>(this)));
|
||||
void Folder::OutputConnectedEvent(const QString &output, const NodeInput &input)
|
||||
{
|
||||
Q_UNUSED(output)
|
||||
|
||||
foreach (Item* child, children()) {
|
||||
switch (child->type()) {
|
||||
case Item::kFootage:
|
||||
writer->writeStartElement(QStringLiteral("footage"));
|
||||
break;
|
||||
case Item::kSequence:
|
||||
writer->writeStartElement(QStringLiteral("sequence"));
|
||||
break;
|
||||
case Item::kFolder:
|
||||
writer->writeStartElement(QStringLiteral("folder"));
|
||||
break;
|
||||
}
|
||||
Item* item = dynamic_cast<Item*>(input.node());
|
||||
|
||||
child->Save(writer);
|
||||
if (item) {
|
||||
// The insert index is always our "count" because we only support appending in our internal
|
||||
// model. For sorting/organizing, a QSortFilterProxyModel is used instead.
|
||||
emit BeginInsertItem(item, item_child_count());
|
||||
item_children_.append(item);
|
||||
emit EndInsertItem();
|
||||
}
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // footage/folder/sequence
|
||||
void Folder::OutputDisconnectedEvent(const QString &output, const NodeInput &input)
|
||||
{
|
||||
Q_UNUSED(output)
|
||||
|
||||
Item* item = dynamic_cast<Item*>(input.node());
|
||||
|
||||
if (item) {
|
||||
int child_index = item_children_.indexOf(item);
|
||||
emit BeginRemoveItem(item, child_index);
|
||||
item_children_.removeAt(child_index);
|
||||
emit EndRemoveItem();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#ifndef FOLDER_H
|
||||
#define FOLDER_H
|
||||
|
||||
#include "node/node.h"
|
||||
#include "project/item/item.h"
|
||||
|
||||
namespace olive {
|
||||
@@ -33,20 +34,113 @@ namespace olive {
|
||||
*/
|
||||
class Folder : public Item
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Folder() = default;
|
||||
Folder();
|
||||
|
||||
virtual Type type() const override;
|
||||
virtual Node* copy() const override
|
||||
{
|
||||
return new Folder();
|
||||
}
|
||||
|
||||
virtual bool CanHaveChildren() const override;
|
||||
virtual QString Name() const override
|
||||
{
|
||||
return tr("Folder");
|
||||
}
|
||||
|
||||
virtual QIcon icon() override;
|
||||
virtual QString id() const override
|
||||
{
|
||||
return QStringLiteral("org.olivevideoeditor.Olive.folder");
|
||||
}
|
||||
|
||||
virtual void Load(QXmlStreamReader* reader, XMLNodeData &xml_node_data, uint version, const QAtomicInt *cancelled) override;
|
||||
virtual QVector<CategoryID> Category() const override
|
||||
{
|
||||
return {kCategoryProject};
|
||||
}
|
||||
|
||||
virtual void Save(QXmlStreamWriter* writer) const override;
|
||||
virtual QString Description() const override
|
||||
{
|
||||
return tr("Organize several items into a single collection.");
|
||||
}
|
||||
|
||||
virtual QIcon icon() const override;
|
||||
|
||||
bool ChildExistsWithName(const QString& s) const;
|
||||
|
||||
int item_child_count() const
|
||||
{
|
||||
return item_children_.size();
|
||||
}
|
||||
|
||||
Item* item_child(int i) const
|
||||
{
|
||||
return item_children_.at(i);
|
||||
}
|
||||
|
||||
const QVector<Item*>& children() const
|
||||
{
|
||||
return item_children_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a list of nodes that are of a certain type that this node outputs to
|
||||
*/
|
||||
template <typename T>
|
||||
QVector<T*> ListOutputsOfType(bool recursive = true) const
|
||||
{
|
||||
QVector<T *> list;
|
||||
|
||||
ListOutputsOfTypeInternal(this, list, recursive);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
int index_of_child(Item* item) const
|
||||
{
|
||||
return item_children_.indexOf(item);
|
||||
}
|
||||
|
||||
signals:
|
||||
void BeginInsertItem(Item* n, int index);
|
||||
|
||||
void EndInsertItem();
|
||||
|
||||
void BeginRemoveItem(Item* n, int index);
|
||||
|
||||
void EndRemoveItem();
|
||||
|
||||
protected:
|
||||
virtual void OutputConnectedEvent(const QString& output, const NodeInput& input) override;
|
||||
|
||||
virtual void OutputDisconnectedEvent(const QString& output, const NodeInput& input) override;
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
static void ListOutputsOfTypeInternal(const Folder* n, QVector<T*>& list, bool recursive)
|
||||
{
|
||||
foreach (const Node::OutputConnection& c, n->output_connections()) {
|
||||
Node* connected = c.second.node();
|
||||
|
||||
T* cast_test = dynamic_cast<T*>(connected);
|
||||
|
||||
if (cast_test) {
|
||||
// Avoid duplicates
|
||||
if (!list.contains(cast_test)) {
|
||||
list.append(cast_test);
|
||||
}
|
||||
}
|
||||
|
||||
if (recursive) {
|
||||
Folder* subfolder = dynamic_cast<Folder*>(connected);
|
||||
|
||||
if (subfolder) {
|
||||
ListOutputsOfTypeInternal(subfolder, list, recursive);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QVector<Item*> item_children_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user