arranged items so they are inputs of folder rather than outputs
This commit is contained in:
@@ -20,7 +20,5 @@ add_subdirectory(sequence)
|
||||
|
||||
set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
project/item/item.h
|
||||
project/item/item.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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_;
|
||||
}
|
||||
|
||||
@@ -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&);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user