arranged items so they are inputs of folder rather than outputs

This commit is contained in:
itsmattkc
2021-03-12 12:22:19 +11:00
parent c885fbac5c
commit 500fb58d49
26 changed files with 281 additions and 309 deletions
-2
View File
@@ -29,7 +29,6 @@
namespace olive {
class Block;
class Item;
class Node;
class NodeInput;
@@ -51,7 +50,6 @@ struct XMLNodeData {
QHash<quintptr, Node*> node_ptrs;
QList<SerializedConnection> desired_connections;
QList<BlockLink> block_links;
QHash<quintptr, Item*> item_ptrs;
};
+3 -2
View File
@@ -65,6 +65,7 @@
#include "widget/menu/menushared.h"
#include "widget/taskview/taskviewitem.h"
#include "widget/viewer/viewer.h"
#include "widget/nodeparamview/nodeparamviewundo.h"
#include "window/mainwindow/mainstatusbar.h"
#include "window/mainwindow/mainwindow.h"
@@ -370,7 +371,7 @@ void Core::CreateNewFolder()
MultiUndoCommand* command = new MultiUndoCommand();
command->add_child(new NodeAddCommand(active_project, new_folder));
command->add_child(new NodeEdgeAddCommand(folder, NodeInput(new_folder, Item::kParentInput)));
command->add_child(new FolderAddChild(folder, new_folder));
Core::instance()->undo_stack()->push(command);
@@ -405,7 +406,7 @@ void Core::CreateNewSequence()
MultiUndoCommand* command = new MultiUndoCommand();
command->add_child(new NodeAddCommand(active_project, new_sequence));
command->add_child(new NodeEdgeAddCommand(GetSelectedFolderInActiveProject(), NodeInput(new_sequence, Item::kParentInput)));
command->add_child(new FolderAddChild(GetSelectedFolderInActiveProject(), new_sequence));
// Create and connect default nodes to new sequence
new_sequence->add_default_nodes(command);
-1
View File
@@ -22,7 +22,6 @@
#define NODEGRAPH_H
#include "node/node.h"
#include "project/item/item.h"
namespace olive {
+4 -3
View File
@@ -46,7 +46,8 @@ const QString Node::kDefaultOutput = QStringLiteral("output");
Node::Node(bool create_default_output) :
can_be_deleted_(true),
override_color_(-1),
last_change_time_(0)
last_change_time_(0),
folder_(nullptr)
{
if (create_default_output) {
AddOutput();
@@ -1126,7 +1127,7 @@ Node *Node::CopyNodeAndDependencyGraphMinusItemsInternal(QMap<const Node*, Node*
Node* connected = output.node();
Node* connected_copy;
if (dynamic_cast<Item*>(connected)) {
if (connected->IsItem()) {
// This is an item and we avoid copying those and just connect to them directly
connected_copy = connected;
} else {
@@ -1529,7 +1530,7 @@ void GetDependenciesRecursively(QVector<Node*>& list, const Node* node, bool tra
Node* connected_node = it->second.node();
if (!exclusive_only
|| (connected_node->outputs().size() == 1 && !dynamic_cast<Item*>(connected_node))) {
|| (connected_node->outputs().size() == 1 && !connected_node->IsItem())) {
if (!list.contains(connected_node)) {
list.append(connected_node);
+34
View File
@@ -46,6 +46,7 @@
namespace olive {
class NodeGraph;
class Folder;
/**
* @brief A single processing unit that can be connected with others to create intricate processing systems
@@ -155,6 +156,21 @@ public:
*/
virtual QString Description() const;
const QString& ToolTip() const
{
return tooltip_;
}
Folder* folder() const
{
return folder_;
}
virtual bool IsItem() const
{
return false;
}
/**
* @brief Function called to retranslate parameter names (should be overridden in derivatives)
*/
@@ -162,6 +178,10 @@ public:
virtual QIcon icon() const;
virtual QString duration() const {return QString();}
virtual QString rate() const {return QString();}
const QVector<QString>& inputs() const
{
return input_ids_;
@@ -718,6 +738,11 @@ public:
static bool Unlink(Node* a, Node* b);
static bool AreLinked(Node* a, Node* b);
void SetFolder(Folder* folder)
{
folder_ = folder;
}
static const QString kDefaultOutput;
protected:
@@ -819,6 +844,11 @@ protected:
virtual void childEvent(QChildEvent *event) override;
void SetToolTip(const QString& s)
{
tooltip_ = s;
}
signals:
/**
* @brief Signal emitted whenever the position is set through SetPosition()
@@ -1137,6 +1167,10 @@ private:
qint64 last_change_time_;
QString tooltip_;
Folder* folder_;
private slots:
/**
* @brief Slot when a keyframe's time changes to keep the keyframes correctly sorted by time
+6 -6
View File
@@ -115,7 +115,7 @@ void ProjectPanel::set_root(Folder *item)
Retranslate();
}
QVector<Item *> ProjectPanel::SelectedItems() const
QVector<Node *> ProjectPanel::SelectedItems() const
{
return explorer_->SelectedItems();
}
@@ -163,7 +163,7 @@ void ProjectPanel::DeleteSelected()
explorer_->DeleteSelected();
}
void ProjectPanel::Edit(Item* item)
void ProjectPanel::Edit(Node* item)
{
explorer_->Edit(item);
}
@@ -179,7 +179,7 @@ void ProjectPanel::Retranslate()
UpdateSubtitle();
}
void ProjectPanel::ItemDoubleClickSlot(Item *item)
void ProjectPanel::ItemDoubleClickSlot(Node *item)
{
if (item == nullptr) {
// If the user double clicks on empty space, show the import dialog
@@ -215,7 +215,7 @@ void ProjectPanel::UpdateSubtitle()
do {
folder_path.prepend(QStringLiteral("/%1").arg(item->GetLabel()));
item = item->item_parent();
item = item->folder();
} while (item != project()->root());
project_title.append(folder_path);
@@ -234,10 +234,10 @@ void ProjectPanel::SaveConnectedProject()
QVector<Footage *> ProjectPanel::GetSelectedFootage() const
{
QVector<Item*> items = SelectedItems();
QVector<Node*> items = SelectedItems();
QVector<Footage*> footage;
foreach (Item* i, items) {
foreach (Node* i, items) {
if (dynamic_cast<Footage*>(i)) {
footage.append(static_cast<Footage*>(i));
}
+3 -3
View File
@@ -44,7 +44,7 @@ public:
void set_root(Folder* item);
QVector<Item *> SelectedItems() const;
QVector<Node *> SelectedItems() const;
Folder* GetSelectedFolder() const;
@@ -61,7 +61,7 @@ public:
virtual void DeleteSelected() override;
public slots:
void Edit(Item *item);
void Edit(Node *item);
signals:
void ProjectNameChanged();
@@ -72,7 +72,7 @@ private:
ProjectExplorer* explorer_;
private slots:
void ItemDoubleClickSlot(Item* item);
void ItemDoubleClickSlot(Node *item);
void ShowNewMenu();
-2
View File
@@ -20,7 +20,5 @@ add_subdirectory(sequence)
set(OLIVE_SOURCES
${OLIVE_SOURCES}
project/item/item.h
project/item/item.cpp
PARENT_SCOPE
)
+57 -9
View File
@@ -27,8 +27,13 @@
namespace olive {
#define super Node
const QString Folder::kChildInput = QStringLiteral("child_in");
Folder::Folder()
{
AddInput(kChildInput, NodeValue::kNone, InputFlags(kInputFlagArray | kInputFlagNotKeyframable));
}
QIcon Folder::icon() const
@@ -36,6 +41,13 @@ QIcon Folder::icon() const
return icon::Folder;
}
void Folder::Retranslate()
{
super::Retranslate();
SetInputName(kChildInput, tr("Children"));
}
bool ChildExistsWithNameInternal(const Folder* n, const QString& s)
{
foreach (const Node::OutputConnection& c, n->output_connections()) {
@@ -60,33 +72,69 @@ bool Folder::ChildExistsWithName(const QString &s) const
return ChildExistsWithNameInternal(this, s);
}
void Folder::OutputConnectedEvent(const QString &output, const NodeInput &input)
int Folder::index_of_child_in_array(Node *item) const
{
Q_UNUSED(output)
int index_of_item = item_children_.indexOf(item);
Item* item = dynamic_cast<Item*>(input.node());
if (index_of_item == -1) {
return -1;
}
return item_element_index_.at(index_of_item);
}
void Folder::InputConnectedEvent(const QString &input, int element, const NodeOutput &output)
{
if (input == kChildInput && element != -1) {
Node* item = output.node();
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);
item_element_index_.append(element);
item->SetFolder(this);
emit EndInsertItem();
}
}
void Folder::OutputDisconnectedEvent(const QString &output, const NodeInput &input)
void Folder::InputDisconnectedEvent(const QString &input, int element, const NodeOutput &output)
{
Q_UNUSED(output)
if (input == kChildInput && element != -1) {
Node* item = output.node();
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);
item_element_index_.removeAt(child_index);
item->SetFolder(nullptr);
emit EndRemoveItem();
}
}
FolderAddChild::FolderAddChild(Folder *folder, Node *child, bool autoposition) :
folder_(folder),
child_(child),
autoposition_(autoposition)
{
}
Project *FolderAddChild::GetRelevantProject() const
{
return folder_->project();
}
void FolderAddChild::redo()
{
int array_index = folder_->InputArraySize(Folder::kChildInput);
folder_->InputArrayAppend(Folder::kChildInput, false);
Node::ConnectEdge(child_, NodeInput(folder_, Folder::kChildInput, array_index));
}
void FolderAddChild::undo()
{
Node::DisconnectEdge(child_, NodeInput(folder_, Folder::kChildInput, folder_->InputArraySize(Folder::kChildInput)-1));
folder_->InputArrayRemoveLast(Folder::kChildInput);
}
}
+43 -10
View File
@@ -22,7 +22,6 @@
#define FOLDER_H
#include "node/node.h"
#include "project/item/item.h"
namespace olive {
@@ -32,7 +31,7 @@ namespace olive {
* The Item base class already has support for children, but this functionality is disabled by default
* (see CanHaveChildren() override). The Folder is a specific type that enables this functionality.
*/
class Folder : public Item
class Folder : public Node
{
Q_OBJECT
public:
@@ -65,6 +64,8 @@ public:
virtual QIcon icon() const override;
virtual void Retranslate() override;
bool ChildExistsWithName(const QString& s) const;
int item_child_count() const
@@ -72,16 +73,21 @@ public:
return item_children_.size();
}
Item* item_child(int i) const
Node* item_child(int i) const
{
return item_children_.at(i);
}
const QVector<Item*>& children() const
const QVector<Node*>& children() const
{
return item_children_;
}
virtual bool IsItem() const override
{
return true;
}
/**
* @brief Returns a list of nodes that are of a certain type that this node outputs to
*/
@@ -95,24 +101,28 @@ public:
return list;
}
int index_of_child(Item* item) const
int index_of_child(Node* item) const
{
return item_children_.indexOf(item);
}
int index_of_child_in_array(Node* item) const;
static const QString kChildInput;
signals:
void BeginInsertItem(Item* n, int index);
void BeginInsertItem(Node* n, int index);
void EndInsertItem();
void BeginRemoveItem(Item* n, int index);
void BeginRemoveItem(Node* n, int index);
void EndRemoveItem();
protected:
virtual void OutputConnectedEvent(const QString& output, const NodeInput& input) override;
virtual void InputConnectedEvent(const QString& input, int element, const NodeOutput& output) override;
virtual void OutputDisconnectedEvent(const QString& output, const NodeInput& input) override;
virtual void InputDisconnectedEvent(const QString& input, int element, const NodeOutput& output) override;
private:
template<typename T>
@@ -140,7 +150,30 @@ private:
}
}
QVector<Item*> item_children_;
QVector<Node*> item_children_;
QVector<int> item_element_index_;
};
class FolderAddChild : public UndoCommand
{
public:
FolderAddChild(Folder* folder, Node* child, bool autoposition = true);
virtual Project * GetRelevantProject() const override;
virtual void redo() override;
virtual void undo() override;
private:
Folder* folder_;
Node* child_;
bool autoposition_;
QPointF old_position_;
};
+8 -9
View File
@@ -38,10 +38,9 @@ namespace olive {
const QString Footage::kFilenameInput = QStringLiteral("file_in");
const QString Footage::kStreamPropertiesFormat = QStringLiteral("stream_properties:%1");
#define super Item
#define super Node
Footage::Footage(const QString &filename) :
super(true, false),
cancelled_(nullptr)
{
AddInput(kFilenameInput, NodeValue::kFile, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable));
@@ -381,7 +380,7 @@ QIcon Footage::icon() const
return icon::Error;
}
QString Footage::duration()
QString Footage::duration() const
{
// Try video first
VideoParams video = GetFirstEnabledVideoStream();
@@ -420,7 +419,7 @@ QString Footage::duration()
return QString();
}
QString Footage::rate()
QString Footage::rate() const
{
if (inputs_for_stream_properties_.isEmpty()) {
return QString();
@@ -431,12 +430,12 @@ QString Footage::rate()
VideoParams video_stream = GetFirstEnabledVideoStream();
if (video_stream.video_type() != VideoParams::kVideoTypeStill) {
return QCoreApplication::translate("Footage", "%1 FPS").arg(video_stream.frame_rate().toDouble());
return tr("%1 FPS").arg(video_stream.frame_rate().toDouble());
}
} else if (HasEnabledAudioStreams()) {
// No video streams, return audio
AudioParams audio_stream = GetFirstEnabledAudioStream();
return QCoreApplication::translate("Footage", "%1 Hz").arg(audio_stream.sample_rate());
return tr("%1 Hz").arg(audio_stream.sample_rate());
}
return QString();
@@ -620,7 +619,7 @@ QString Footage::GetStreamTypeName(Stream::Type type)
void Footage::UpdateTooltip()
{
if (valid_) {
QString tip = QCoreApplication::translate("Footage", "Filename: %1").arg(filename());
QString tip = tr("Filename: %1").arg(filename());
for (auto it=inputs_for_stream_properties_.cbegin(); it!=inputs_for_stream_properties_.cend(); it++) {
if (it.key().type() == Stream::kVideo) {
@@ -640,9 +639,9 @@ void Footage::UpdateTooltip()
}
}
set_tooltip(tip);
SetToolTip(tip);
} else {
set_tooltip(QCoreApplication::translate("Footage", "This footage is not valid for use"));
SetToolTip(tr("This footage is not valid for use"));
}
}
+8 -4
View File
@@ -27,7 +27,6 @@
#include "common/rational.h"
#include "footagedescription.h"
#include "node/node.h"
#include "project/item/item.h"
#include "render/audioparams.h"
#include "render/videoparams.h"
#include "stream.h"
@@ -42,7 +41,7 @@ namespace olive {
* Footage objects store a list of Stream objects which store the majority of video/audio metadata. These streams
* are identical to the stream data in the files.
*/
class Footage : public Item, public TimelinePoints
class Footage : public Node, public TimelinePoints
{
Q_OBJECT
public:
@@ -263,9 +262,14 @@ public:
virtual QIcon icon() const override;
virtual QString duration() override;
virtual QString duration() const override;
virtual QString rate() override;
virtual QString rate() const override;
virtual bool IsItem() const override
{
return true;
}
bool HasEnabledVideoStreams() const;
bool HasEnabledAudioStreams() const;
-72
View File
@@ -1,72 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "item.h"
#include "folder/folder.h"
namespace olive {
#define super QObject
const QString Item::kParentInput = QStringLiteral("parent_in");
Item::Item(bool create_folder_input, bool create_default_output) :
Node(create_default_output)
{
if (create_folder_input) {
// Hierarchy input for items
AddInput(kParentInput, NodeValue::kNone);
IgnoreHashingFrom(kParentInput);
IgnoreInvalidationsFrom(kParentInput);
}
}
const QString &Item::tooltip() const
{
return tooltip_;
}
void Item::set_tooltip(const QString &t)
{
tooltip_ = t;
}
QString Item::duration()
{
return QString();
}
QString Item::rate()
{
return QString();
}
Folder *Item::item_parent() const
{
return dynamic_cast<Folder*>(GetConnectedNode(kParentInput));
}
void Item::Retranslate()
{
SetInputName(kParentInput, tr("Folder"));
}
}
-75
View File
@@ -1,75 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef ITEM_H
#define ITEM_H
#include <memory>
#include <QIcon>
#include <QList>
#include <QMutex>
#include <QString>
#include <QXmlStreamWriter>
#include "common/threadedobject.h"
#include "common/xmlutils.h"
#include "node/node.h"
namespace olive {
class Folder;
class Project;
/**
* @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 : public Node
{
Q_OBJECT
public:
/**
* @brief Item constructor
*/
Item(bool create_folder_input = true, bool create_default_output = true);
const QString& tooltip() const;
void set_tooltip(const QString& t);
virtual QString duration();
virtual QString rate();
Folder *item_parent() const;
static const QString kParentInput;
virtual void Retranslate() override;
private:
QString tooltip_;
};
}
#endif // ITEM_H
+4 -5
View File
@@ -46,10 +46,9 @@ const QString Sequence::kTrackInputFormat = QStringLiteral("track_in_%1");
const uint64_t Sequence::kVideoParamEditMask = VideoParamEdit::kWidthHeight | VideoParamEdit::kInterlacing | VideoParamEdit::kFrameRate | VideoParamEdit::kPixelAspect;
#define super Item
#define super Node
Sequence::Sequence(bool viewer_only_mode) :
Item(!viewer_only_mode, true),
video_frame_cache_(this),
audio_playback_cache_(this),
operation_stack_(0)
@@ -104,7 +103,7 @@ QIcon Sequence::icon() const
return icon::Sequence;
}
QString Sequence::duration()
QString Sequence::duration() const
{
rational timeline_length = GetLength();
@@ -113,7 +112,7 @@ QString Sequence::duration()
return Timecode::timestamp_to_timecode(timestamp, video_params().time_base(), Core::instance()->GetTimecodeDisplay());
}
QString Sequence::rate()
QString Sequence::rate() const
{
return tr("%1 FPS").arg(video_params().time_base().flipped().toDouble());
}
@@ -341,7 +340,7 @@ void Sequence::InvalidateCache(const TimeRange& range, const QString& from, int
super::InvalidateCache(range, from, element, job_time);
}
rational Sequence::GetLength()
const rational& Sequence::GetLength() const
{
return last_length_;
}
+9 -5
View File
@@ -31,7 +31,6 @@
#include "node/output/track/tracklist.h"
#include "node/traverser.h"
#include "project/item/footage/footage.h"
#include "project/item/item.h"
#include "render/audioparams.h"
#include "render/audioplaybackcache.h"
#include "render/framehashcache.h"
@@ -46,7 +45,7 @@ namespace olive {
/**
* @brief The main timeline object, an graph of edited clips that forms a complete edit
*/
class Sequence : public Item, public TimelinePoints
class Sequence : public Node, public TimelinePoints
{
Q_OBJECT
public:
@@ -83,8 +82,8 @@ public:
virtual QIcon icon() const override;
virtual QString duration() override;
virtual QString rate() override;
virtual QString duration() const override;
virtual QString rate() const override;
void set_default_parameters();
@@ -136,7 +135,7 @@ public:
SetStandardValue(kAudioParamsInput, QVariant::fromValue(audio));
}
rational GetLength();
const rational &GetLength() const;
virtual void Retranslate() override;
@@ -173,6 +172,11 @@ public:
return uuid_;
}
virtual bool IsItem() const override
{
return true;
}
signals:
void TimebaseChanged(const rational&);
+43 -44
View File
@@ -26,6 +26,7 @@
#include "core.h"
#include "widget/nodeview/nodeviewundo.h"
#include "widget/nodeparamview/nodeparamviewundo.h"
namespace olive {
@@ -78,10 +79,10 @@ QModelIndex ProjectViewModel::index(int row, int column, const QModelIndex &pare
QModelIndex ProjectViewModel::parent(const QModelIndex &child) const
{
// Get the Item object from the index
Item* item = GetItemObjectFromIndex(child);
Node* item = GetItemObjectFromIndex(child);
// Get Item's parent object
Item* par = item->item_parent();
Folder* par = item->folder();
// If the parent is the root, return an empty index
if (par == project_->root()) {
@@ -128,7 +129,7 @@ int ProjectViewModel::columnCount(const QModelIndex &parent) const
QVariant ProjectViewModel::data(const QModelIndex &index, int role) const
{
Item* internal_item = GetItemObjectFromIndex(index);
Node* internal_item = GetItemObjectFromIndex(index);
ColumnType column_type = columns_.at(index.column());
@@ -154,7 +155,7 @@ QVariant ProjectViewModel::data(const QModelIndex &index, int role) const
}
break;
case Qt::ToolTipRole:
return internal_item->tooltip();
return internal_item->ToolTip();
}
return QVariant();
@@ -185,7 +186,7 @@ bool ProjectViewModel::hasChildren(const QModelIndex &parent) const
{
// If it's a folder, we always return TRUE in order to always show the "expand triangle" icon,
// even when there are no "physical" children
Item* item = GetItemObjectFromIndex(parent);
Node* item = GetItemObjectFromIndex(parent);
return dynamic_cast<Folder*>(item);
}
@@ -194,7 +195,7 @@ bool ProjectViewModel::setData(const QModelIndex &index, const QVariant &value,
{
// The name is editable
if (index.isValid() && columns_.at(index.column()) == kName && role == Qt::EditRole) {
Item* item = GetItemObjectFromIndex(index);
Node* item = GetItemObjectFromIndex(index);
QString new_name = value.toString();
@@ -268,7 +269,7 @@ QMimeData *ProjectViewModel::mimeData(const QModelIndexList &indexes) const
// Check if we've dragged this item before
if (!dragged_items.contains(index.internalPointer())) {
// If not, add it to the stream (and also keep track of it in the vector)
Footage* footage = dynamic_cast<Footage*>(static_cast<Item*>(index.internalPointer()));
Footage* footage = dynamic_cast<Footage*>(static_cast<Node*>(index.internalPointer()));
if (footage) {
QVector<Footage::StreamReference> streams = footage->GetEnabledStreamsAsReferences();
@@ -309,10 +310,10 @@ bool ProjectViewModel::dropMimeData(const QMimeData *data, Qt::DropAction action
QDataStream stream(&model_data, QIODevice::ReadOnly);
// Get the Item object that the items were dropped on
Item* drop_location = GetItemObjectFromIndex(drop);
Folder* drop_location = dynamic_cast<Folder*>(GetItemObjectFromIndex(drop));
// If this is not a folder, we cannot drop these items here
if (!dynamic_cast<Folder*>(drop_location)) {
if (!drop_location) {
return false;
}
@@ -328,16 +329,15 @@ bool ProjectViewModel::dropMimeData(const QMimeData *data, Qt::DropAction action
while (!stream.atEnd()) {
stream >> streams >> item_ptr;
Item* item = reinterpret_cast<Item*>(item_ptr);
Node* item = reinterpret_cast<Node*>(item_ptr);
// Check if Item is already the drop location or if its parent is the drop location, in which case this is a
// no-op
if (item != drop_location && item->item_parent() != drop_location && !ItemIsParentOfChild(item, drop_location)) {
NodeInput child_input(item, Item::kParentInput);
move_command->add_child(new NodeEdgeRemoveCommand(item->item_parent(), child_input));
move_command->add_child(new NodeEdgeAddCommand(static_cast<Folder*>(drop_location), child_input));
if (item != drop_location && item->folder() != drop_location
&& (!dynamic_cast<Folder*>(item) || !ItemIsParentOfChild(static_cast<Folder*>(item), drop_location))) {
move_command->add_child(new NodeEdgeRemoveCommand(item, NodeInput(item->folder(), Folder::kChildInput, item->folder()->index_of_child_in_array(item))));
move_command->add_child(new FolderAddChild(drop_location, item));
}
}
@@ -363,24 +363,31 @@ bool ProjectViewModel::dropMimeData(const QMimeData *data, Qt::DropAction action
}
// Get folder dropped onto
Item* drop_item = GetItemObjectFromIndex(drop);
Node* drop_item = GetItemObjectFromIndex(drop);
// If we didn't drop onto an item, find the nearest parent folder (should eventually terminate at root either way)
while (!dynamic_cast<Folder*>(drop_item)) {
drop_item = drop_item->item_parent();
if (!dynamic_cast<Folder*>(drop_item)) {
drop_item = drop_item->folder();
if (!drop_item) {
// Failed to find folder to place this in
return false;
}
}
// Trigger an import
Core::instance()->ImportFiles(urls, this, static_cast<Folder*>(drop_item));
return true;
}
return false;
}
int ProjectViewModel::IndexOfChild(Item *item) const
int ProjectViewModel::IndexOfChild(Node *item) const
{
// Find parent's index within its own parent
Folder* parent = item->item_parent();
Folder* parent = item->folder();
if (parent) {
return parent->index_of_child(item);
@@ -389,20 +396,20 @@ int ProjectViewModel::IndexOfChild(Item *item) const
return -1;
}
Item *ProjectViewModel::GetItemObjectFromIndex(const QModelIndex &index) const
Node *ProjectViewModel::GetItemObjectFromIndex(const QModelIndex &index) const
{
if (index.isValid()) {
return static_cast<Item*>(index.internalPointer());
return static_cast<Node*>(index.internalPointer());
}
return project_ ? project_->root() : nullptr;
}
bool ProjectViewModel::ItemIsParentOfChild(Item *parent, Item *child) const
bool ProjectViewModel::ItemIsParentOfChild(Folder *parent, Node *child) const
{
// Loop through parent hierarchy checking if `parent` is one of its parents
do {
child = child->item_parent();
child = child->folder();
if (parent == child) {
return true;
@@ -412,9 +419,9 @@ bool ProjectViewModel::ItemIsParentOfChild(Item *parent, Item *child) const
return false;
}
void ProjectViewModel::ConnectItem(Item *n)
void ProjectViewModel::ConnectItem(Node *n)
{
connect(n, &Item::LabelChanged, this, &ProjectViewModel::ItemRenamed);
connect(n, &Node::LabelChanged, this, &ProjectViewModel::ItemRenamed);
Folder* f = dynamic_cast<Folder*>(n);
if (f) {
@@ -423,19 +430,15 @@ void ProjectViewModel::ConnectItem(Item *n)
connect(f, &Folder::BeginRemoveItem, this, &ProjectViewModel::FolderBeginRemoveItem);
connect(f, &Folder::EndRemoveItem, this, &ProjectViewModel::FolderEndRemoveItem);
foreach (const Node::OutputConnection& c, f->output_connections()) {
Item* item = dynamic_cast<Item*>(c.second.node());
if (item) {
ConnectItem(item);
}
foreach (Node* c, f->children()) {
ConnectItem(c);
}
}
}
void ProjectViewModel::DisconnectItem(Item *n)
void ProjectViewModel::DisconnectItem(Node *n)
{
disconnect(n, &Item::LabelChanged, this, &ProjectViewModel::ItemRenamed);
disconnect(n, &Node::LabelChanged, this, &ProjectViewModel::ItemRenamed);
Folder* f = dynamic_cast<Folder*>(n);
if (f) {
@@ -444,17 +447,13 @@ void ProjectViewModel::DisconnectItem(Item *n)
disconnect(f, &Folder::BeginRemoveItem, this, &ProjectViewModel::FolderBeginRemoveItem);
disconnect(f, &Folder::EndRemoveItem, this, &ProjectViewModel::FolderEndRemoveItem);
foreach (const Node::OutputConnection& c, f->output_connections()) {
Item* item = dynamic_cast<Item*>(c.second.node());
if (item) {
DisconnectItem(item);
}
foreach (Node* c, f->children()) {
ConnectItem(c);
}
}
}
void ProjectViewModel::FolderBeginInsertItem(Item *n, int insert_index)
void ProjectViewModel::FolderBeginInsertItem(Node *n, int insert_index)
{
Folder* folder = static_cast<Folder*>(sender());
@@ -474,7 +473,7 @@ void ProjectViewModel::FolderEndInsertItem()
endInsertRows();
}
void ProjectViewModel::FolderBeginRemoveItem(Item *n, int child_index)
void ProjectViewModel::FolderBeginRemoveItem(Node *n, int child_index)
{
Folder* folder = static_cast<Folder*>(sender());
@@ -496,14 +495,14 @@ void ProjectViewModel::FolderEndRemoveItem()
void ProjectViewModel::ItemRenamed()
{
Item* item = static_cast<Item*>(sender());
Node* item = static_cast<Node*>(sender());
QModelIndex index = CreateIndexFromItem(item);
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
}
QModelIndex ProjectViewModel::CreateIndexFromItem(Item *item, int column)
QModelIndex ProjectViewModel::CreateIndexFromItem(Node *item, int column)
{
return createIndex(IndexOfChild(item), column, item);
}
+8 -8
View File
@@ -102,7 +102,7 @@ public:
/**
* @brief Convenience function for creating QModelIndexes from an Item object
*/
QModelIndex CreateIndexFromItem(Item* item, int column = 0);
QModelIndex CreateIndexFromItem(Node *item, int column = 0);
private:
/**
@@ -115,36 +115,36 @@ private:
*
* Index of the specified item, or -1 if the item is root (in which case it has no parent).
*/
int IndexOfChild(Item* item) const;
int IndexOfChild(Node* item) const;
/**
* @brief Retrieves the Item object from a given index
*
* A convenience function for retrieving Item objects. If the index is not valid, this returns the root Item.
*/
Item* GetItemObjectFromIndex(const QModelIndex& index) const;
Node* GetItemObjectFromIndex(const QModelIndex& index) const;
/**
* @brief Check if an Item is a parent of a Child
*
* Checks entire "parent hierarchy" of `child` to see if `parent` is one of its parents.
*/
bool ItemIsParentOfChild(Item* parent, Item* child) const;
bool ItemIsParentOfChild(Folder *parent, Node* child) const;
void ConnectItem(Item* n);
void ConnectItem(Node* n);
void DisconnectItem(Item* n);
void DisconnectItem(Node *n);
Project* project_;
QVector<ColumnType> columns_;
private slots:
void FolderBeginInsertItem(Item* n, int insert_index);
void FolderBeginInsertItem(Node *n, int insert_index);
void FolderEndInsertItem();
void FolderBeginRemoveItem(Item* n, int child_index);
void FolderBeginRemoveItem(Node* n, int child_index);
void FolderEndRemoveItem();
+2 -2
View File
@@ -102,7 +102,7 @@ void ProjectImportTask::Import(Folder *folder, QFileInfoList import, int &counte
// Create undoable command that adds the items to the model
parent_command->add_child(new NodeAddCommand(folder->parent(), f));
parent_command->add_child(new NodeEdgeAddCommand(folder, NodeInput(f, Item::kParentInput)));
parent_command->add_child(new FolderAddChild(folder, f));
// Recursively follow this path
Import(f, entry_list, counter, parent_command);
@@ -123,7 +123,7 @@ void ProjectImportTask::Import(Folder *folder, QFileInfoList import, int &counte
// Create undoable command that adds the items to the model
parent_command->add_child(new NodeAddCommand(folder->parent(), footage));
parent_command->add_child(new NodeEdgeAddCommand(folder, NodeInput(footage, Item::kParentInput)));
parent_command->add_child(new FolderAddChild(folder, footage));
} else {
// Add to list so we can tell the user about it later
invalid_files_.append(file_info.absoluteFilePath());
+1 -3
View File
@@ -47,9 +47,7 @@ bool SaveOTIOTask::Run()
std::vector<opentimelineio::v1_0::SerializableObject*> serialized;
foreach (Item* item, sequences) {
Sequence* seq = static_cast<Sequence*>(item);
foreach (Sequence* seq, sequences) {
auto otio_timeline = SerializeTimeline(seq);
if (otio_timeline) {
+18 -2
View File
@@ -180,9 +180,25 @@ void NodeParamSetStandardValueCommand::undo()
ref_.input().node()->SetSplitStandardValueOnTrack(ref_, old_value_);
}
Project *NodeParamArrayInsertCommand::GetRelevantProject() const
NodeParamArrayAppendCommand::NodeParamArrayAppendCommand(Node *node, const QString &input) :
node_(node),
input_(input)
{
return input_.node()->project();
}
Project *NodeParamArrayAppendCommand::GetRelevantProject() const
{
return node_->project();
}
void NodeParamArrayAppendCommand::redo()
{
node_->InputArrayAppend(input_, false);
}
void NodeParamArrayAppendCommand::undo()
{
node_->InputArrayRemoveLast(input_, false);
}
}
+7 -16
View File
@@ -139,30 +139,21 @@ private:
};
class NodeParamArrayInsertCommand : public UndoCommand
class NodeParamArrayAppendCommand : public UndoCommand
{
public:
NodeParamArrayInsertCommand(const NodeInput& input, int index) :
input_(input),
index_(index)
{
}
NodeParamArrayAppendCommand(Node* node, const QString& input);
virtual Project* GetRelevantProject() const override;
virtual void redo() override
{
input_.node()->InputArrayInsert(input_.input(), index_);
}
virtual void redo() override;
virtual void undo() override
{
input_.node()->InputArrayRemove(input_.input(), index_);
}
virtual void undo() override;
private:
NodeInput input_;
int index_;
Node* node_;
QString input_;
};
+14 -14
View File
@@ -122,7 +122,7 @@ void ProjectExplorer::set_view_type(ProjectToolbar::ViewType type)
}
}
void ProjectExplorer::Edit(Item *item)
void ProjectExplorer::Edit(Node *item)
{
CurrentView()->edit(sort_model_.mapFromSource(model_.CreateIndexFromItem(item)));
}
@@ -199,7 +199,7 @@ void ProjectExplorer::ItemDoubleClickedSlot(const QModelIndex &index)
rename_timer_.stop();
// Retrieve source item from index
Item* i = static_cast<Item*>(sort_model_.mapToSource(index).internalPointer());
Node* i = static_cast<Node*>(sort_model_.mapToSource(index).internalPointer());
// If the item is a folder, browse to it
if (dynamic_cast<Folder*>(i) && (view_type() == ProjectToolbar::ListView || view_type() == ProjectToolbar::IconView)) {
@@ -264,7 +264,7 @@ void ProjectExplorer::ShowContextMenu()
// Actions to add when only one item is selected
if (context_menu_items_.size() == 1) {
Item* context_menu_item = context_menu_items_.first();
Node* context_menu_item = context_menu_items_.first();
if (dynamic_cast<Folder*>(context_menu_item)) {
@@ -298,7 +298,7 @@ void ProjectExplorer::ShowContextMenu()
bool all_items_have_video_streams = true;
bool all_items_are_footage_or_sequence = true;
foreach (Item* i, context_menu_items_) {
foreach (Node* i, context_menu_items_) {
Footage* footage_cast_test = dynamic_cast<Footage*>(i);
Sequence* sequence_cast_test = dynamic_cast<Sequence*>(i);
@@ -349,7 +349,7 @@ void ProjectExplorer::ShowContextMenu()
void ProjectExplorer::ShowItemPropertiesDialog()
{
Item* sel = context_menu_items_.first();
Node* sel = context_menu_items_.first();
// FIXME: Support for multiple items
if (dynamic_cast<Footage*>(sel)) {
@@ -408,7 +408,7 @@ void ProjectExplorer::ContextMenuStartProxy(QAction *a)
Sequence* sequence = Node::ValueToPtr<Sequence>(a->data());
// To get here, the `context_menu_items_` must be all kFootage
foreach (Item* i, context_menu_items_) {
foreach (Node* i, context_menu_items_) {
Footage* f = static_cast<Footage*>(i);
QVector<VideoParams> enabled_streams = f->GetEnabledVideoStreams();
@@ -444,18 +444,18 @@ void ProjectExplorer::set_root(Folder *item)
tree_view_->setRootIndex(index);
}
QVector<Item *> ProjectExplorer::SelectedItems() const
QVector<Node *> ProjectExplorer::SelectedItems() const
{
// Determine which view is active and get its selected indexes
QModelIndexList index_list = CurrentView()->selectionModel()->selectedRows();
// Convert indexes to item objects
QVector<Item*> selected_items;
QVector<Node*> selected_items;
for (int i=0;i<index_list.size();i++) {
QModelIndex index = sort_model_.mapToSource(index_list.at(i));
Item* item = static_cast<Item*>(index.internalPointer());
Node* item = static_cast<Node*>(index.internalPointer());
selected_items.append(item);
}
@@ -472,7 +472,7 @@ Folder *ProjectExplorer::GetSelectedFolder() const
Folder* folder = nullptr;
// Get the selected items from the panel
QVector<Item*> selected_items = SelectedItems();
QVector<Node*> selected_items = SelectedItems();
// Heuristic for finding the selected folder:
//
@@ -482,11 +482,11 @@ Folder *ProjectExplorer::GetSelectedFolder() const
// - If more than one folder is found, we play it safe and import into the root folder
for (int i=0;i<selected_items.size();i++) {
Item* sel_item = selected_items.at(i);
Node* sel_item = selected_items.at(i);
// If this item is not a folder, presumably it's parent is
if (!dynamic_cast<Folder*>(sel_item)) {
sel_item = sel_item->item_parent();
sel_item = sel_item->folder();
}
if (folder == nullptr) {
@@ -525,7 +525,7 @@ void ProjectExplorer::DeselectAll()
void ProjectExplorer::DeleteSelected()
{
QVector<Item*> selected = SelectedItems();
QVector<Node*> selected = SelectedItems();
if (selected.isEmpty()) {
return;
@@ -535,7 +535,7 @@ void ProjectExplorer::DeleteSelected()
bool dont_confirm_footage_in_use = false;
foreach (Item* item, selected) {
foreach (Node* item, selected) {
// Verify whether this item is in use anywhere
Footage* footage_cast_test = dynamic_cast<Footage*>(item);
Sequence* sequence_cast_test = dynamic_cast<Sequence*>(item);
+4 -4
View File
@@ -59,7 +59,7 @@ public:
void set_root(Folder *item);
QVector<Item *> SelectedItems() const;
QVector<Node *> SelectedItems() const;
/**
* @brief Use a heuristic to determine which (if any) folder is selected
@@ -89,7 +89,7 @@ public:
public slots:
void set_view_type(ProjectToolbar::ViewType type);
void Edit(Item* item);
void Edit(Node* item);
signals:
/**
@@ -99,7 +99,7 @@ signals:
*
* The Item that was double clicked, or nullptr if empty area was double clicked
*/
void DoubleClickedItem(Item* item);
void DoubleClickedItem(Node* item);
private:
/**
@@ -153,7 +153,7 @@ private:
QTimer rename_timer_;
QVector<Item*> context_menu_items_;
QVector<Node*> context_menu_items_;
private slots:
void ItemClickedSlot(const QModelIndex& index);
+2 -2
View File
@@ -92,7 +92,7 @@ void ImportTool::DragEnter(TimelineViewMouseEvent *event)
stream >> enabled_streams >> item_ptr;
// Get Item object
Item* item = reinterpret_cast<Item*>(item_ptr);
Node* item = reinterpret_cast<Node*>(item_ptr);
// Check if Item is Footage
if (dynamic_cast<Footage*>(item)) {
@@ -390,7 +390,7 @@ void ImportTool::DropGhosts(bool insert)
dst_graph = Core::instance()->GetActiveProject();
command->add_child(new NodeAddCommand(dst_graph, new_sequence));
command->add_child(new NodeEdgeAddCommand(Core::instance()->GetSelectedFolderInActiveProject(), NodeInput(new_sequence, Item::kParentInput)));
command->add_child(new FolderAddChild(Core::instance()->GetSelectedFolderInActiveProject(), new_sequence));
new_sequence->add_default_nodes(command);
FootageToGhosts(0, dragged_footage_, new_sequence->video_params().time_base(), 0);
@@ -43,11 +43,8 @@ MainWindowLayoutInfo MainWindowLayoutInfo::fromXml(QXmlStreamReader *reader, XML
if (reader->name() == QStringLiteral("folder")) {
quintptr item_id = reader->readElementText().toULongLong();
Item* open_item = xml_data.item_ptrs.value(item_id);
if (open_item) {
info.open_folders_.append(static_cast<Folder*>(open_item));
}
Folder* open_item = static_cast<Folder*>(xml_data.node_ptrs.value(item_id));
info.open_folders_.append(open_item);
} else {
reader->skipCurrentElement();
}
@@ -62,7 +59,7 @@ MainWindowLayoutInfo MainWindowLayoutInfo::fromXml(QXmlStreamReader *reader, XML
if (reader->name() == QStringLiteral("sequence")) {
quintptr item_id = reader->readElementText().toULongLong();
open_seq = dynamic_cast<Sequence*>(xml_data.item_ptrs.value(item_id));
open_seq = static_cast<Sequence*>(xml_data.node_ptrs.value(item_id));
} else if (reader->name() == QStringLiteral("state")) {
tl_state = QByteArray::fromBase64(reader->readElementText().toUtf8());
} else {