change: change code style to Linux style except indent.
This commit is contained in:
@@ -26,7 +26,8 @@
|
||||
#include "node/project/sequence/sequence.h"
|
||||
#include "ui/icons/icons.h"
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
#define super Node
|
||||
|
||||
@@ -34,143 +35,152 @@ const QString Folder::kChildInput = QStringLiteral("child_in");
|
||||
|
||||
Folder::Folder()
|
||||
{
|
||||
SetFlag(kIsItem);
|
||||
SetFlag(kIsItem);
|
||||
|
||||
AddInput(kChildInput, NodeValue::kNone, InputFlags(kInputFlagArray | kInputFlagNotKeyframable));
|
||||
AddInput(kChildInput, NodeValue::kNone,
|
||||
InputFlags(kInputFlagArray | kInputFlagNotKeyframable));
|
||||
}
|
||||
|
||||
QVariant Folder::data(const DataType &d) const
|
||||
{
|
||||
if (d == ICON) {
|
||||
return icon::Folder;
|
||||
}
|
||||
if (d == ICON) {
|
||||
return icon::Folder;
|
||||
}
|
||||
|
||||
return super::data(d);
|
||||
return super::data(d);
|
||||
}
|
||||
|
||||
void Folder::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kChildInput, tr("Children"));
|
||||
SetInputName(kChildInput, tr("Children"));
|
||||
}
|
||||
|
||||
Node *GetChildWithNameInternal(const Folder* n, const QString& s)
|
||||
Node *GetChildWithNameInternal(const Folder *n, const QString &s)
|
||||
{
|
||||
for (int i=0; i<n->item_child_count(); i++) {
|
||||
Node* child = n->item_child(i);
|
||||
for (int i = 0; i < n->item_child_count(); i++) {
|
||||
Node *child = n->item_child(i);
|
||||
|
||||
if (child->GetLabel() == s) {
|
||||
return child;
|
||||
} else if (Folder* subfolder = dynamic_cast<Folder*>(child)) {
|
||||
if (Node *n2 = GetChildWithNameInternal(subfolder, s)) {
|
||||
return n2;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (child->GetLabel() == s) {
|
||||
return child;
|
||||
} else if (Folder *subfolder = dynamic_cast<Folder *>(child)) {
|
||||
if (Node *n2 = GetChildWithNameInternal(subfolder, s)) {
|
||||
return n2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Node *Folder::GetChildWithName(const QString &s) const
|
||||
{
|
||||
return GetChildWithNameInternal(this, s);
|
||||
return GetChildWithNameInternal(this, s);
|
||||
}
|
||||
|
||||
bool Folder::HasChildRecursive(Node *child) const
|
||||
{
|
||||
for (Node *i : item_children_) {
|
||||
if (i == child) {
|
||||
return true;
|
||||
} else if (Folder *f = dynamic_cast<Folder*>(i)) {
|
||||
if (f->HasChildRecursive(child)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Node *i : item_children_) {
|
||||
if (i == child) {
|
||||
return true;
|
||||
} else if (Folder *f = dynamic_cast<Folder *>(i)) {
|
||||
if (f->HasChildRecursive(child)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
int Folder::index_of_child_in_array(Node *item) const
|
||||
{
|
||||
int index_of_item = item_children_.indexOf(item);
|
||||
int index_of_item = item_children_.indexOf(item);
|
||||
|
||||
if (index_of_item == -1) {
|
||||
return -1;
|
||||
}
|
||||
if (index_of_item == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return item_element_index_.at(index_of_item);
|
||||
return item_element_index_.at(index_of_item);
|
||||
}
|
||||
|
||||
void Folder::InputConnectedEvent(const QString &input, int element, Node *output)
|
||||
void Folder::InputConnectedEvent(const QString &input, int element,
|
||||
Node *output)
|
||||
{
|
||||
if (input == kChildInput && element != -1) {
|
||||
Node* item = output;
|
||||
if (input == kChildInput && element != -1) {
|
||||
Node *item = output;
|
||||
|
||||
// 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();
|
||||
}
|
||||
// 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::InputDisconnectedEvent(const QString &input, int element, Node *output)
|
||||
void Folder::InputDisconnectedEvent(const QString &input, int element,
|
||||
Node *output)
|
||||
{
|
||||
if (input == kChildInput && element != -1) {
|
||||
Node* item = output;
|
||||
if (input == kChildInput && element != -1) {
|
||||
Node *item = output;
|
||||
|
||||
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();
|
||||
}
|
||||
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) :
|
||||
folder_(folder),
|
||||
child_(child)
|
||||
FolderAddChild::FolderAddChild(Folder *folder, Node *child)
|
||||
: folder_(folder)
|
||||
, child_(child)
|
||||
{
|
||||
}
|
||||
|
||||
Project *FolderAddChild::GetRelevantProject() const
|
||||
{
|
||||
return folder_->project();
|
||||
return folder_->project();
|
||||
}
|
||||
|
||||
void FolderAddChild::redo()
|
||||
{
|
||||
int array_index = folder_->InputArraySize(Folder::kChildInput);
|
||||
folder_->InputArrayAppend(Folder::kChildInput);
|
||||
Node::ConnectEdge(child_, NodeInput(folder_, Folder::kChildInput, array_index));
|
||||
int array_index = folder_->InputArraySize(Folder::kChildInput);
|
||||
folder_->InputArrayAppend(Folder::kChildInput);
|
||||
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);
|
||||
Node::DisconnectEdge(
|
||||
child_, NodeInput(folder_, Folder::kChildInput,
|
||||
folder_->InputArraySize(Folder::kChildInput) - 1));
|
||||
folder_->InputArrayRemoveLast(Folder::kChildInput);
|
||||
}
|
||||
|
||||
void Folder::RemoveElementCommand::redo()
|
||||
{
|
||||
if (!subcommand_) {
|
||||
remove_index_ = folder_->index_of_child_in_array(child_);
|
||||
if (remove_index_ != -1) {
|
||||
NodeInput connected_input(folder_, Folder::kChildInput, remove_index_);
|
||||
subcommand_ = new MultiUndoCommand();
|
||||
subcommand_->add_child(new NodeEdgeRemoveCommand(folder_->GetConnectedOutput(connected_input), connected_input));
|
||||
subcommand_->add_child(new NodeArrayRemoveCommand(folder_, Folder::kChildInput, remove_index_));
|
||||
}
|
||||
}
|
||||
if (!subcommand_) {
|
||||
remove_index_ = folder_->index_of_child_in_array(child_);
|
||||
if (remove_index_ != -1) {
|
||||
NodeInput connected_input(folder_, Folder::kChildInput,
|
||||
remove_index_);
|
||||
subcommand_ = new MultiUndoCommand();
|
||||
subcommand_->add_child(new NodeEdgeRemoveCommand(
|
||||
folder_->GetConnectedOutput(connected_input), connected_input));
|
||||
subcommand_->add_child(new NodeArrayRemoveCommand(
|
||||
folder_, Folder::kChildInput, remove_index_));
|
||||
}
|
||||
}
|
||||
|
||||
if (subcommand_) {
|
||||
subcommand_->redo_now();
|
||||
}
|
||||
if (subcommand_) {
|
||||
subcommand_->redo_now();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+131
-134
@@ -23,7 +23,8 @@
|
||||
|
||||
#include "node/node.h"
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief The Folder class representing a directory in a project structure
|
||||
@@ -31,193 +32,189 @@ 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 Node
|
||||
{
|
||||
Q_OBJECT
|
||||
class Folder : public Node {
|
||||
Q_OBJECT
|
||||
public:
|
||||
Folder();
|
||||
Folder();
|
||||
|
||||
NODE_DEFAULT_FUNCTIONS(Folder)
|
||||
NODE_DEFAULT_FUNCTIONS(Folder)
|
||||
|
||||
virtual QString Name() const override
|
||||
{
|
||||
return tr("Folder");
|
||||
}
|
||||
virtual QString Name() const override
|
||||
{
|
||||
return tr("Folder");
|
||||
}
|
||||
|
||||
virtual QString id() const override
|
||||
{
|
||||
return QStringLiteral("org.olivevideoeditor.Olive.folder");
|
||||
}
|
||||
virtual QString id() const override
|
||||
{
|
||||
return QStringLiteral("org.olivevideoeditor.Olive.folder");
|
||||
}
|
||||
|
||||
virtual QVector<CategoryID> Category() const override
|
||||
{
|
||||
return {kCategoryProject};
|
||||
}
|
||||
virtual QVector<CategoryID> Category() const override
|
||||
{
|
||||
return { kCategoryProject };
|
||||
}
|
||||
|
||||
virtual QString Description() const override
|
||||
{
|
||||
return tr("Organize several items into a single collection.");
|
||||
}
|
||||
virtual QString Description() const override
|
||||
{
|
||||
return tr("Organize several items into a single collection.");
|
||||
}
|
||||
|
||||
virtual QVariant data(const DataType &d) const override;
|
||||
virtual QVariant data(const DataType &d) const override;
|
||||
|
||||
virtual void Retranslate() override;
|
||||
virtual void Retranslate() override;
|
||||
|
||||
Node *GetChildWithName(const QString& s) const;
|
||||
bool ChildExistsWithName(const QString& s) const
|
||||
{
|
||||
return GetChildWithName(s);
|
||||
}
|
||||
Node *GetChildWithName(const QString &s) const;
|
||||
bool ChildExistsWithName(const QString &s) const
|
||||
{
|
||||
return GetChildWithName(s);
|
||||
}
|
||||
|
||||
bool HasChildRecursive(Node *child) const;
|
||||
bool HasChildRecursive(Node *child) const;
|
||||
|
||||
int item_child_count() const
|
||||
{
|
||||
return item_children_.size();
|
||||
}
|
||||
int item_child_count() const
|
||||
{
|
||||
return item_children_.size();
|
||||
}
|
||||
|
||||
Node* item_child(int i) const
|
||||
{
|
||||
return item_children_.at(i);
|
||||
}
|
||||
Node *item_child(int i) const
|
||||
{
|
||||
return item_children_.at(i);
|
||||
}
|
||||
|
||||
const QVector<Node*>& children() const
|
||||
{
|
||||
return item_children_;
|
||||
}
|
||||
const QVector<Node *> &children() const
|
||||
{
|
||||
return item_children_;
|
||||
}
|
||||
|
||||
int index_of_child(Node* item) const
|
||||
{
|
||||
return item_children_.indexOf(item);
|
||||
}
|
||||
int index_of_child(Node *item) const
|
||||
{
|
||||
return item_children_.indexOf(item);
|
||||
}
|
||||
|
||||
int index_of_child_in_array(Node* item) const;
|
||||
int index_of_child_in_array(Node *item) const;
|
||||
|
||||
template <typename T>
|
||||
QVector<T*> ListChildrenOfType() const
|
||||
{
|
||||
QVector<T*> list;
|
||||
template <typename T> QVector<T *> ListChildrenOfType() const
|
||||
{
|
||||
QVector<T *> list;
|
||||
|
||||
foreach (Node* node, item_children_) {
|
||||
T* cast_test = dynamic_cast<T*>(node);
|
||||
if (cast_test) {
|
||||
list.append(cast_test);
|
||||
}
|
||||
foreach (Node *node, item_children_) {
|
||||
T *cast_test = dynamic_cast<T *>(node);
|
||||
if (cast_test) {
|
||||
list.append(cast_test);
|
||||
}
|
||||
|
||||
Folder *folder_test = dynamic_cast<Folder*>(node);
|
||||
if (folder_test) {
|
||||
list.append(folder_test->ListChildrenOfType<T>());
|
||||
}
|
||||
}
|
||||
Folder *folder_test = dynamic_cast<Folder *>(node);
|
||||
if (folder_test) {
|
||||
list.append(folder_test->ListChildrenOfType<T>());
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
static const QString kChildInput;
|
||||
static const QString kChildInput;
|
||||
|
||||
class RemoveElementCommand : public UndoCommand
|
||||
{
|
||||
public:
|
||||
RemoveElementCommand(Folder *folder, Node *child) :
|
||||
folder_(folder),
|
||||
child_(child),
|
||||
subcommand_(nullptr)
|
||||
{
|
||||
}
|
||||
class RemoveElementCommand : public UndoCommand {
|
||||
public:
|
||||
RemoveElementCommand(Folder *folder, Node *child)
|
||||
: folder_(folder)
|
||||
, child_(child)
|
||||
, subcommand_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~RemoveElementCommand() override
|
||||
{
|
||||
delete subcommand_;
|
||||
}
|
||||
virtual ~RemoveElementCommand() override
|
||||
{
|
||||
delete subcommand_;
|
||||
}
|
||||
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return folder_->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return folder_->project();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void redo() override;
|
||||
protected:
|
||||
virtual void redo() override;
|
||||
|
||||
virtual void undo() override
|
||||
{
|
||||
if (subcommand_) {
|
||||
subcommand_->undo_now();
|
||||
}
|
||||
}
|
||||
virtual void undo() override
|
||||
{
|
||||
if (subcommand_) {
|
||||
subcommand_->undo_now();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Folder *folder_;
|
||||
private:
|
||||
Folder *folder_;
|
||||
|
||||
Node *child_;
|
||||
Node *child_;
|
||||
|
||||
int remove_index_;
|
||||
int remove_index_;
|
||||
|
||||
MultiUndoCommand *subcommand_;
|
||||
|
||||
};
|
||||
MultiUndoCommand *subcommand_;
|
||||
};
|
||||
|
||||
signals:
|
||||
void BeginInsertItem(Node* n, int index);
|
||||
void BeginInsertItem(Node *n, int index);
|
||||
|
||||
void EndInsertItem();
|
||||
void EndInsertItem();
|
||||
|
||||
void BeginRemoveItem(Node* n, int index);
|
||||
void BeginRemoveItem(Node *n, int index);
|
||||
|
||||
void EndRemoveItem();
|
||||
void EndRemoveItem();
|
||||
|
||||
protected:
|
||||
virtual void InputConnectedEvent(const QString& input, int element, Node *output) override;
|
||||
virtual void InputConnectedEvent(const QString &input, int element,
|
||||
Node *output) override;
|
||||
|
||||
virtual void InputDisconnectedEvent(const QString& input, int element, Node *output) override;
|
||||
virtual void InputDisconnectedEvent(const QString &input, int element,
|
||||
Node *output) 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();
|
||||
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);
|
||||
T *cast_test = dynamic_cast<T *>(connected);
|
||||
|
||||
if (cast_test) {
|
||||
// Avoid duplicates
|
||||
if (!list.contains(cast_test)) {
|
||||
list.append(cast_test);
|
||||
}
|
||||
}
|
||||
if (cast_test) {
|
||||
// Avoid duplicates
|
||||
if (!list.contains(cast_test)) {
|
||||
list.append(cast_test);
|
||||
}
|
||||
}
|
||||
|
||||
if (recursive) {
|
||||
Folder* subfolder = dynamic_cast<Folder*>(connected);
|
||||
if (recursive) {
|
||||
Folder *subfolder = dynamic_cast<Folder *>(connected);
|
||||
|
||||
if (subfolder) {
|
||||
ListOutputsOfTypeInternal(subfolder, list, recursive);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QVector<Node*> item_children_;
|
||||
QVector<int> item_element_index_;
|
||||
if (subfolder) {
|
||||
ListOutputsOfTypeInternal(subfolder, list, recursive);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QVector<Node *> item_children_;
|
||||
QVector<int> item_element_index_;
|
||||
};
|
||||
|
||||
class FolderAddChild : public UndoCommand
|
||||
{
|
||||
class FolderAddChild : public UndoCommand {
|
||||
public:
|
||||
FolderAddChild(Folder* folder, Node* child);
|
||||
FolderAddChild(Folder *folder, Node *child);
|
||||
|
||||
virtual Project * GetRelevantProject() const override;
|
||||
virtual Project *GetRelevantProject() const override;
|
||||
|
||||
protected:
|
||||
virtual void redo() override;
|
||||
virtual void redo() override;
|
||||
|
||||
virtual void undo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
Folder* folder_;
|
||||
|
||||
Node* child_;
|
||||
Folder *folder_;
|
||||
|
||||
Node *child_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -31,7 +31,8 @@
|
||||
#include "render/cancelatom.h"
|
||||
#include "render/videoparams.h"
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A reference to an external media file with metadata in a project structure
|
||||
@@ -40,40 +41,40 @@ 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 ViewerOutput
|
||||
{
|
||||
Q_OBJECT
|
||||
class Footage : public ViewerOutput {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
/**
|
||||
* @brief Footage Constructor
|
||||
*/
|
||||
Footage(const QString& filename = QString());
|
||||
Footage(const QString &filename = QString());
|
||||
|
||||
NODE_DEFAULT_FUNCTIONS(Footage)
|
||||
NODE_DEFAULT_FUNCTIONS(Footage)
|
||||
|
||||
virtual QString Name() const override
|
||||
{
|
||||
return tr("Media");
|
||||
}
|
||||
virtual QString Name() const override
|
||||
{
|
||||
return tr("Media");
|
||||
}
|
||||
|
||||
virtual QString id() const override
|
||||
{
|
||||
return QStringLiteral("org.olivevideoeditor.Olive.footage");
|
||||
}
|
||||
virtual QString id() const override
|
||||
{
|
||||
return QStringLiteral("org.olivevideoeditor.Olive.footage");
|
||||
}
|
||||
|
||||
virtual QVector<CategoryID> Category() const override
|
||||
{
|
||||
return {kCategoryProject};
|
||||
}
|
||||
virtual QVector<CategoryID> Category() const override
|
||||
{
|
||||
return { kCategoryProject };
|
||||
}
|
||||
|
||||
virtual QString Description() const override
|
||||
{
|
||||
return tr("Import video, audio, or still image files into the composition.");
|
||||
}
|
||||
virtual QString Description() const override
|
||||
{
|
||||
return tr(
|
||||
"Import video, audio, or still image files into the composition.");
|
||||
}
|
||||
|
||||
virtual void Retranslate() override;
|
||||
virtual void Retranslate() override;
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Reset Footage state ready for running through Probe() again
|
||||
*
|
||||
* If a Footage object needs to be re-probed (e.g. source file changes or Footage is linked to a new file), its
|
||||
@@ -83,24 +84,24 @@ public:
|
||||
* In most cases, you'll be using olive::ProbeMedia() for re-probing which already runs Clear(), so you won't need
|
||||
* to worry about this.
|
||||
*/
|
||||
void Clear();
|
||||
void Clear();
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return valid_;
|
||||
}
|
||||
bool IsValid() const
|
||||
{
|
||||
return valid_;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Sets this footage to valid and ready to use
|
||||
*/
|
||||
void SetValid();
|
||||
void SetValid();
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Return the current filename of this Footage object
|
||||
*/
|
||||
QString filename() const;
|
||||
QString filename() const;
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Set the filename
|
||||
*
|
||||
* NOTE: This does not automtaically clear the old streams and re-probe for new ones. If the file link has been
|
||||
@@ -110,17 +111,17 @@ public:
|
||||
*
|
||||
* New filename
|
||||
*/
|
||||
void set_filename(const QString& s);
|
||||
void set_filename(const QString &s);
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Retrieve the last modified time/date
|
||||
*
|
||||
* The file's last modified timestamp is stored for potential organization in the ProjectExplorer. It can be
|
||||
* retrieved here.
|
||||
*/
|
||||
const qint64 ×tamp() const;
|
||||
const qint64 ×tamp() const;
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Set the last modified time/date
|
||||
*
|
||||
* This should probably only be done on import or replace.
|
||||
@@ -129,89 +130,98 @@ public:
|
||||
*
|
||||
* New last modified time/date
|
||||
*/
|
||||
void set_timestamp(const qint64 &t);
|
||||
void set_timestamp(const qint64 &t);
|
||||
|
||||
void SetCancelPointer(CancelAtom *c)
|
||||
{
|
||||
cancelled_ = c;
|
||||
}
|
||||
void SetCancelPointer(CancelAtom *c)
|
||||
{
|
||||
cancelled_ = c;
|
||||
}
|
||||
|
||||
int GetStreamIndex(Track::Type type, int index) const;
|
||||
int GetStreamIndex(const Track::Reference& ref) const
|
||||
{
|
||||
return GetStreamIndex(ref.type(), ref.index());
|
||||
}
|
||||
int GetStreamIndex(Track::Type type, int index) const;
|
||||
int GetStreamIndex(const Track::Reference &ref) const
|
||||
{
|
||||
return GetStreamIndex(ref.type(), ref.index());
|
||||
}
|
||||
|
||||
Track::Reference GetReferenceFromRealIndex(int real_index) const;
|
||||
Track::Reference GetReferenceFromRealIndex(int real_index) const;
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Get the Decoder ID set when this Footage was probed
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* A decoder ID
|
||||
*/
|
||||
const QString& decoder() const;
|
||||
const QString &decoder() const;
|
||||
|
||||
static QString DescribeVideoStream(const VideoParams& params);
|
||||
static QString DescribeAudioStream(const AudioParams& params);
|
||||
static QString DescribeSubtitleStream(const SubtitleParams& params);
|
||||
static QString DescribeVideoStream(const VideoParams ¶ms);
|
||||
static QString DescribeAudioStream(const AudioParams ¶ms);
|
||||
static QString DescribeSubtitleStream(const SubtitleParams ¶ms);
|
||||
|
||||
virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override;
|
||||
virtual void Value(const NodeValueRow &value, const NodeGlobals &globals,
|
||||
NodeValueTable *table) const override;
|
||||
|
||||
static QString GetStreamTypeName(Track::Type type);
|
||||
static QString GetStreamTypeName(Track::Type type);
|
||||
|
||||
virtual Node *GetConnectedTextureOutput() override;
|
||||
virtual Node *GetConnectedTextureOutput() override;
|
||||
|
||||
virtual Node *GetConnectedSampleOutput() override;
|
||||
virtual Node *GetConnectedSampleOutput() override;
|
||||
|
||||
static rational AdjustTimeByLoopMode(rational time, LoopMode loop_mode, const rational& length, VideoParams::Type type, const rational &timebase);
|
||||
static rational AdjustTimeByLoopMode(rational time, LoopMode loop_mode,
|
||||
const rational &length,
|
||||
VideoParams::Type type,
|
||||
const rational &timebase);
|
||||
|
||||
virtual QVariant data(const DataType &d) const override;
|
||||
virtual QVariant data(const DataType &d) const override;
|
||||
|
||||
virtual int GetTotalStreamCount() const override { return total_stream_count_; }
|
||||
virtual int GetTotalStreamCount() const override
|
||||
{
|
||||
return total_stream_count_;
|
||||
}
|
||||
|
||||
virtual bool LoadCustom(QXmlStreamReader *reader, SerializedData *data) override;
|
||||
virtual void SaveCustom(QXmlStreamWriter *writer) const override;
|
||||
virtual bool LoadCustom(QXmlStreamReader *reader,
|
||||
SerializedData *data) override;
|
||||
virtual void SaveCustom(QXmlStreamWriter *writer) const override;
|
||||
|
||||
static const QString kFilenameInput;
|
||||
static const QString kFilenameInput;
|
||||
|
||||
virtual void AddedToGraphEvent(Project *p) override;
|
||||
virtual void RemovedFromGraphEvent(Project *p) override;
|
||||
virtual void AddedToGraphEvent(Project *p) override;
|
||||
virtual void RemovedFromGraphEvent(Project *p) override;
|
||||
|
||||
protected:
|
||||
virtual void InputValueChangedEvent(const QString &input, int element) override;
|
||||
virtual void InputValueChangedEvent(const QString &input,
|
||||
int element) override;
|
||||
|
||||
virtual rational VerifyLengthInternal(Track::Type type) const override;
|
||||
virtual rational VerifyLengthInternal(Track::Type type) const override;
|
||||
|
||||
private:
|
||||
QString GetColorspaceToUse(const VideoParams& params) const;
|
||||
QString GetColorspaceToUse(const VideoParams ¶ms) const;
|
||||
|
||||
void Reprobe();
|
||||
void Reprobe();
|
||||
|
||||
VideoParams MergeVideoStream(const VideoParams &base, const VideoParams &over);
|
||||
VideoParams MergeVideoStream(const VideoParams &base,
|
||||
const VideoParams &over);
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Internal timestamp object
|
||||
*/
|
||||
qint64 timestamp_;
|
||||
qint64 timestamp_;
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Internal attached decoder ID
|
||||
*/
|
||||
QString decoder_;
|
||||
QString decoder_;
|
||||
|
||||
bool valid_;
|
||||
bool valid_;
|
||||
|
||||
CancelAtom *cancelled_;
|
||||
CancelAtom *cancelled_;
|
||||
|
||||
int total_stream_count_;
|
||||
int total_stream_count_;
|
||||
|
||||
private slots:
|
||||
void CheckFootage();
|
||||
|
||||
void DefaultColorSpaceChanged();
|
||||
void CheckFootage();
|
||||
|
||||
void DefaultColorSpaceChanged();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -27,134 +27,143 @@
|
||||
#include "common/xmlutils.h"
|
||||
#include "node/project/serializer/typeserializer.h"
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
bool FootageDescription::Load(const QString &filename)
|
||||
{
|
||||
// Reset self
|
||||
*this = FootageDescription();
|
||||
// Reset self
|
||||
*this = FootageDescription();
|
||||
|
||||
QFile file(filename);
|
||||
QFile file(filename);
|
||||
|
||||
if (file.open(QFile::ReadOnly)) {
|
||||
QXmlStreamReader reader(&file);
|
||||
if (file.open(QFile::ReadOnly)) {
|
||||
QXmlStreamReader reader(&file);
|
||||
|
||||
while (XMLReadNextStartElement(&reader)) {
|
||||
if (reader.name() == QStringLiteral("streamcache")) {
|
||||
// Default to first version of metadata (which wasn't versioned at all)
|
||||
unsigned version = 1;
|
||||
while (XMLReadNextStartElement(&reader)) {
|
||||
if (reader.name() == QStringLiteral("streamcache")) {
|
||||
// Default to first version of metadata (which wasn't versioned at all)
|
||||
unsigned version = 1;
|
||||
|
||||
{
|
||||
XMLAttributeLoop((&reader), attr) {
|
||||
if (attr.name() == QStringLiteral("version")) {
|
||||
version = attr.value().toUInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
XMLAttributeLoop((&reader), attr)
|
||||
{
|
||||
if (attr.name() == QStringLiteral("version")) {
|
||||
version = attr.value().toUInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (version != kFootageMetaVersion) {
|
||||
// If this is a different version, discard so we can probe new data
|
||||
return false;
|
||||
}
|
||||
if (version != kFootageMetaVersion) {
|
||||
// If this is a different version, discard so we can probe new data
|
||||
return false;
|
||||
}
|
||||
|
||||
while (XMLReadNextStartElement(&reader)) {
|
||||
if (reader.name() == QStringLiteral("decoder")) {
|
||||
decoder_ = reader.readElementText();
|
||||
} else if (reader.name() == QStringLiteral("streams")) {
|
||||
{
|
||||
XMLAttributeLoop((&reader), attr) {
|
||||
if (attr.name() == QStringLiteral("count")) {
|
||||
total_stream_count_ = attr.value().toInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
while (XMLReadNextStartElement(&reader)) {
|
||||
if (reader.name() == QStringLiteral("decoder")) {
|
||||
decoder_ = reader.readElementText();
|
||||
} else if (reader.name() == QStringLiteral("streams")) {
|
||||
{
|
||||
XMLAttributeLoop((&reader), attr)
|
||||
{
|
||||
if (attr.name() == QStringLiteral("count")) {
|
||||
total_stream_count_ = attr.value().toInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (XMLReadNextStartElement(&reader)) {
|
||||
if (reader.name() == QStringLiteral("video")) {
|
||||
VideoParams vp;
|
||||
vp.Load(&reader);
|
||||
AddVideoStream(vp);
|
||||
} else if (reader.name() == QStringLiteral("audio")) {
|
||||
AudioParams ap = TypeSerializer::LoadAudioParams(&reader);
|
||||
AddAudioStream(ap);
|
||||
} else if (reader.name() == QStringLiteral("subtitle")) {
|
||||
SubtitleParams sp;
|
||||
sp.Load(&reader);
|
||||
AddSubtitleStream(sp);
|
||||
} else {
|
||||
reader.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
while (XMLReadNextStartElement(&reader)) {
|
||||
if (reader.name() == QStringLiteral("video")) {
|
||||
VideoParams vp;
|
||||
vp.Load(&reader);
|
||||
AddVideoStream(vp);
|
||||
} else if (reader.name() ==
|
||||
QStringLiteral("audio")) {
|
||||
AudioParams ap =
|
||||
TypeSerializer::LoadAudioParams(&reader);
|
||||
AddAudioStream(ap);
|
||||
} else if (reader.name() ==
|
||||
QStringLiteral("subtitle")) {
|
||||
SubtitleParams sp;
|
||||
sp.Load(&reader);
|
||||
AddSubtitleStream(sp);
|
||||
} else {
|
||||
reader.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
file.close();
|
||||
|
||||
if (reader.hasError()) {
|
||||
qWarning() << "Failed to load footage description for" << filename << reader.errorString();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (reader.hasError()) {
|
||||
qWarning() << "Failed to load footage description for" << filename
|
||||
<< reader.errorString();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FootageDescription::Save(const QString &filename) const
|
||||
{
|
||||
QFile file(filename);
|
||||
QFile file(filename);
|
||||
|
||||
if (!file.open(QFile::WriteOnly)) {
|
||||
return false;
|
||||
}
|
||||
if (!file.open(QFile::WriteOnly)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QXmlStreamWriter writer(&file);
|
||||
QXmlStreamWriter writer(&file);
|
||||
|
||||
writer.writeStartDocument();
|
||||
writer.writeStartDocument();
|
||||
|
||||
writer.writeStartElement(QStringLiteral("streamcache"));
|
||||
writer.writeStartElement(QStringLiteral("streamcache"));
|
||||
|
||||
writer.writeAttribute(QStringLiteral("version"), QString::number(kFootageMetaVersion));
|
||||
writer.writeAttribute(QStringLiteral("version"),
|
||||
QString::number(kFootageMetaVersion));
|
||||
|
||||
writer.writeTextElement(QStringLiteral("decoder"), decoder_);
|
||||
writer.writeTextElement(QStringLiteral("decoder"), decoder_);
|
||||
|
||||
writer.writeStartElement(QStringLiteral("streams"));
|
||||
writer.writeStartElement(QStringLiteral("streams"));
|
||||
|
||||
writer.writeAttribute(QStringLiteral("count"), QString::number(total_stream_count_));
|
||||
writer.writeAttribute(QStringLiteral("count"),
|
||||
QString::number(total_stream_count_));
|
||||
|
||||
foreach (const VideoParams& vp, video_streams_) {
|
||||
writer.writeStartElement(QStringLiteral("video"));
|
||||
vp.Save(&writer);
|
||||
writer.writeEndElement(); // video
|
||||
}
|
||||
foreach (const VideoParams &vp, video_streams_) {
|
||||
writer.writeStartElement(QStringLiteral("video"));
|
||||
vp.Save(&writer);
|
||||
writer.writeEndElement(); // video
|
||||
}
|
||||
|
||||
foreach (const AudioParams& ap, audio_streams_) {
|
||||
writer.writeStartElement(QStringLiteral("audio"));
|
||||
TypeSerializer::SaveAudioParams(&writer, ap);
|
||||
writer.writeEndElement(); // audio
|
||||
}
|
||||
foreach (const AudioParams &ap, audio_streams_) {
|
||||
writer.writeStartElement(QStringLiteral("audio"));
|
||||
TypeSerializer::SaveAudioParams(&writer, ap);
|
||||
writer.writeEndElement(); // audio
|
||||
}
|
||||
|
||||
foreach (const SubtitleParams& sp, subtitle_streams_) {
|
||||
writer.writeStartElement(QStringLiteral("subtitle"));
|
||||
sp.Save(&writer);
|
||||
writer.writeEndElement(); // audio
|
||||
}
|
||||
foreach (const SubtitleParams &sp, subtitle_streams_) {
|
||||
writer.writeStartElement(QStringLiteral("subtitle"));
|
||||
sp.Save(&writer);
|
||||
writer.writeEndElement(); // audio
|
||||
}
|
||||
|
||||
writer.writeEndElement(); // streams
|
||||
writer.writeEndElement(); // streams
|
||||
|
||||
writer.writeEndElement(); // streamcache
|
||||
writer.writeEndElement(); // streamcache
|
||||
|
||||
writer.writeEndDocument();
|
||||
writer.writeEndDocument();
|
||||
|
||||
file.close();
|
||||
file.close();
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,128 +25,154 @@
|
||||
#include "render/subtitleparams.h"
|
||||
#include "render/videoparams.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class FootageDescription
|
||||
namespace olive
|
||||
{
|
||||
|
||||
class FootageDescription {
|
||||
public:
|
||||
FootageDescription(const QString& decoder = QString()) :
|
||||
decoder_(decoder),
|
||||
total_stream_count_(0)
|
||||
{
|
||||
}
|
||||
FootageDescription(const QString &decoder = QString())
|
||||
: decoder_(decoder)
|
||||
, total_stream_count_(0)
|
||||
{
|
||||
}
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return !decoder_.isEmpty() && (!video_streams_.isEmpty() || !audio_streams_.isEmpty() || !subtitle_streams_.isEmpty());
|
||||
}
|
||||
bool IsValid() const
|
||||
{
|
||||
return !decoder_.isEmpty() &&
|
||||
(!video_streams_.isEmpty() || !audio_streams_.isEmpty() ||
|
||||
!subtitle_streams_.isEmpty());
|
||||
}
|
||||
|
||||
const QString& decoder() const
|
||||
{
|
||||
return decoder_;
|
||||
}
|
||||
const QString &decoder() const
|
||||
{
|
||||
return decoder_;
|
||||
}
|
||||
|
||||
void AddVideoStream(const VideoParams& video_params)
|
||||
{
|
||||
Q_ASSERT(!HasStreamIndex(video_params.stream_index()));
|
||||
void AddVideoStream(const VideoParams &video_params)
|
||||
{
|
||||
Q_ASSERT(!HasStreamIndex(video_params.stream_index()));
|
||||
|
||||
video_streams_.append(video_params);
|
||||
}
|
||||
video_streams_.append(video_params);
|
||||
}
|
||||
|
||||
void AddAudioStream(const AudioParams& audio_params)
|
||||
{
|
||||
Q_ASSERT(!HasStreamIndex(audio_params.stream_index()));
|
||||
void AddAudioStream(const AudioParams &audio_params)
|
||||
{
|
||||
Q_ASSERT(!HasStreamIndex(audio_params.stream_index()));
|
||||
|
||||
audio_streams_.append(audio_params);
|
||||
}
|
||||
audio_streams_.append(audio_params);
|
||||
}
|
||||
|
||||
void AddSubtitleStream(const SubtitleParams& sub_params)
|
||||
{
|
||||
Q_ASSERT(!HasStreamIndex(sub_params.stream_index()));
|
||||
void AddSubtitleStream(const SubtitleParams &sub_params)
|
||||
{
|
||||
Q_ASSERT(!HasStreamIndex(sub_params.stream_index()));
|
||||
|
||||
subtitle_streams_.append(sub_params);
|
||||
}
|
||||
subtitle_streams_.append(sub_params);
|
||||
}
|
||||
|
||||
Track::Type GetTypeOfStream(int index)
|
||||
{
|
||||
if (StreamIsVideo(index)) {
|
||||
return Track::kVideo;
|
||||
} else if (StreamIsAudio(index)) {
|
||||
return Track::kAudio;
|
||||
} else if (StreamIsSubtitle(index)) {
|
||||
return Track::kSubtitle;
|
||||
} else {
|
||||
return Track::kNone;
|
||||
}
|
||||
}
|
||||
Track::Type GetTypeOfStream(int index)
|
||||
{
|
||||
if (StreamIsVideo(index)) {
|
||||
return Track::kVideo;
|
||||
} else if (StreamIsAudio(index)) {
|
||||
return Track::kAudio;
|
||||
} else if (StreamIsSubtitle(index)) {
|
||||
return Track::kSubtitle;
|
||||
} else {
|
||||
return Track::kNone;
|
||||
}
|
||||
}
|
||||
|
||||
bool StreamIsVideo(int index) const
|
||||
{
|
||||
foreach (const VideoParams& vp, video_streams_) {
|
||||
if (vp.stream_index() == index) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool StreamIsVideo(int index) const
|
||||
{
|
||||
foreach (const VideoParams &vp, video_streams_) {
|
||||
if (vp.stream_index() == index) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StreamIsAudio(int index) const
|
||||
{
|
||||
foreach (const AudioParams& ap, audio_streams_) {
|
||||
if (ap.stream_index() == index) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool StreamIsAudio(int index) const
|
||||
{
|
||||
foreach (const AudioParams &ap, audio_streams_) {
|
||||
if (ap.stream_index() == index) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StreamIsSubtitle(int index) const
|
||||
{
|
||||
foreach (const SubtitleParams& sp, subtitle_streams_) {
|
||||
if (sp.stream_index() == index) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool StreamIsSubtitle(int index) const
|
||||
{
|
||||
foreach (const SubtitleParams &sp, subtitle_streams_) {
|
||||
if (sp.stream_index() == index) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HasStreamIndex(int index) const
|
||||
{
|
||||
return StreamIsVideo(index) || StreamIsAudio(index) || StreamIsSubtitle(index);
|
||||
}
|
||||
bool HasStreamIndex(int index) const
|
||||
{
|
||||
return StreamIsVideo(index) || StreamIsAudio(index) ||
|
||||
StreamIsSubtitle(index);
|
||||
}
|
||||
|
||||
int GetStreamCount() const { return total_stream_count_; }
|
||||
void SetStreamCount(int s) { total_stream_count_ = s; }
|
||||
int GetStreamCount() const
|
||||
{
|
||||
return total_stream_count_;
|
||||
}
|
||||
void SetStreamCount(int s)
|
||||
{
|
||||
total_stream_count_ = s;
|
||||
}
|
||||
|
||||
bool Load(const QString& filename);
|
||||
bool Load(const QString &filename);
|
||||
|
||||
bool Save(const QString& filename) const;
|
||||
bool Save(const QString &filename) const;
|
||||
|
||||
const QVector<VideoParams>& GetVideoStreams() const { return video_streams_; }
|
||||
QVector<VideoParams>& GetVideoStreams() { return video_streams_; }
|
||||
const QVector<VideoParams> &GetVideoStreams() const
|
||||
{
|
||||
return video_streams_;
|
||||
}
|
||||
QVector<VideoParams> &GetVideoStreams()
|
||||
{
|
||||
return video_streams_;
|
||||
}
|
||||
|
||||
const QVector<AudioParams>& GetAudioStreams() const { return audio_streams_; }
|
||||
QVector<AudioParams>& GetAudioStreams() { return audio_streams_; }
|
||||
const QVector<AudioParams> &GetAudioStreams() const
|
||||
{
|
||||
return audio_streams_;
|
||||
}
|
||||
QVector<AudioParams> &GetAudioStreams()
|
||||
{
|
||||
return audio_streams_;
|
||||
}
|
||||
|
||||
const QVector<SubtitleParams>& GetSubtitleStreams() const { return subtitle_streams_; }
|
||||
QVector<SubtitleParams>& GetSubtitleStreams() { return subtitle_streams_; }
|
||||
const QVector<SubtitleParams> &GetSubtitleStreams() const
|
||||
{
|
||||
return subtitle_streams_;
|
||||
}
|
||||
QVector<SubtitleParams> &GetSubtitleStreams()
|
||||
{
|
||||
return subtitle_streams_;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr unsigned kFootageMetaVersion = 6;
|
||||
static constexpr unsigned kFootageMetaVersion = 6;
|
||||
|
||||
QString decoder_;
|
||||
QString decoder_;
|
||||
|
||||
QVector<VideoParams> video_streams_;
|
||||
QVector<VideoParams> video_streams_;
|
||||
|
||||
QVector<AudioParams> audio_streams_;
|
||||
QVector<AudioParams> audio_streams_;
|
||||
|
||||
QVector<SubtitleParams> subtitle_streams_;
|
||||
|
||||
int total_stream_count_;
|
||||
QVector<SubtitleParams> subtitle_streams_;
|
||||
|
||||
int total_stream_count_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
#include "ui/icons/icons.h"
|
||||
#include "timeline/timelineundogeneral.h"
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
const QString Sequence::kTrackInputFormat = QStringLiteral("track_in_%1");
|
||||
|
||||
@@ -34,157 +35,166 @@ const QString Sequence::kTrackInputFormat = QStringLiteral("track_in_%1");
|
||||
|
||||
Sequence::Sequence()
|
||||
{
|
||||
SetFlag(kIsItem);
|
||||
SetFlag(kIsItem);
|
||||
|
||||
// Create TrackList instances
|
||||
track_lists_.resize(Track::kCount);
|
||||
// Create TrackList instances
|
||||
track_lists_.resize(Track::kCount);
|
||||
|
||||
for (int i=0;i<Track::kCount;i++) {
|
||||
// Create track input
|
||||
QString track_input_id = kTrackInputFormat.arg(i);
|
||||
for (int i = 0; i < Track::kCount; i++) {
|
||||
// Create track input
|
||||
QString track_input_id = kTrackInputFormat.arg(i);
|
||||
|
||||
AddInput(track_input_id, NodeValue::kNone, InputFlags(kInputFlagNotKeyframable | kInputFlagArray | kInputFlagHidden | kInputFlagIgnoreInvalidations));
|
||||
AddInput(track_input_id, NodeValue::kNone,
|
||||
InputFlags(kInputFlagNotKeyframable | kInputFlagArray |
|
||||
kInputFlagHidden | kInputFlagIgnoreInvalidations));
|
||||
|
||||
TrackList* list = new TrackList(this, static_cast<Track::Type>(i), track_input_id);
|
||||
track_lists_.replace(i, list);
|
||||
connect(list, &TrackList::TrackListChanged, this, &Sequence::UpdateTrackCache);
|
||||
connect(list, &TrackList::LengthChanged, this, &Sequence::VerifyLength);
|
||||
connect(list, &TrackList::TrackAdded, this, &Sequence::TrackAdded);
|
||||
connect(list, &TrackList::TrackRemoved, this, &Sequence::TrackRemoved);
|
||||
}
|
||||
TrackList *list =
|
||||
new TrackList(this, static_cast<Track::Type>(i), track_input_id);
|
||||
track_lists_.replace(i, list);
|
||||
connect(list, &TrackList::TrackListChanged, this,
|
||||
&Sequence::UpdateTrackCache);
|
||||
connect(list, &TrackList::LengthChanged, this, &Sequence::VerifyLength);
|
||||
connect(list, &TrackList::TrackAdded, this, &Sequence::TrackAdded);
|
||||
connect(list, &TrackList::TrackRemoved, this, &Sequence::TrackRemoved);
|
||||
}
|
||||
}
|
||||
|
||||
void Sequence::add_default_nodes(MultiUndoCommand* command)
|
||||
void Sequence::add_default_nodes(MultiUndoCommand *command)
|
||||
{
|
||||
// Create tracks and connect them to the viewer
|
||||
UndoCommand* video_track_command = new TimelineAddTrackCommand(track_list(Track::kVideo));
|
||||
UndoCommand* audio_track_command = new TimelineAddTrackCommand(track_list(Track::kAudio));
|
||||
// Create tracks and connect them to the viewer
|
||||
UndoCommand *video_track_command =
|
||||
new TimelineAddTrackCommand(track_list(Track::kVideo));
|
||||
UndoCommand *audio_track_command =
|
||||
new TimelineAddTrackCommand(track_list(Track::kAudio));
|
||||
|
||||
if (command) {
|
||||
command->add_child(video_track_command);
|
||||
command->add_child(audio_track_command);
|
||||
} else {
|
||||
video_track_command->redo_now();
|
||||
audio_track_command->redo_now();
|
||||
delete video_track_command;
|
||||
delete audio_track_command;
|
||||
}
|
||||
if (command) {
|
||||
command->add_child(video_track_command);
|
||||
command->add_child(audio_track_command);
|
||||
} else {
|
||||
video_track_command->redo_now();
|
||||
audio_track_command->redo_now();
|
||||
delete video_track_command;
|
||||
delete audio_track_command;
|
||||
}
|
||||
}
|
||||
|
||||
QVariant Sequence::data(const DataType &d) const
|
||||
{
|
||||
if (d == ICON) {
|
||||
return icon::Sequence;
|
||||
}
|
||||
if (d == ICON) {
|
||||
return icon::Sequence;
|
||||
}
|
||||
|
||||
return super::data(d);
|
||||
return super::data(d);
|
||||
}
|
||||
|
||||
QVector<Track *> Sequence::GetUnlockedTracks() const
|
||||
{
|
||||
QVector<Track*> tracks = GetTracks();
|
||||
QVector<Track *> tracks = GetTracks();
|
||||
|
||||
for (int i=0;i<tracks.size();i++) {
|
||||
if (tracks.at(i)->IsLocked()) {
|
||||
tracks.removeAt(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < tracks.size(); i++) {
|
||||
if (tracks.at(i)->IsLocked()) {
|
||||
tracks.removeAt(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
return tracks;
|
||||
return tracks;
|
||||
}
|
||||
|
||||
void Sequence::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
super::Retranslate();
|
||||
|
||||
for (int i=0;i<Track::kCount;i++) {
|
||||
QString input_name;
|
||||
for (int i = 0; i < Track::kCount; i++) {
|
||||
QString input_name;
|
||||
|
||||
switch (static_cast<Track::Type>(i)) {
|
||||
case Track::kVideo:
|
||||
input_name = tr("Video Tracks");
|
||||
break;
|
||||
case Track::kAudio:
|
||||
input_name = tr("Audio Tracks");
|
||||
break;
|
||||
case Track::kSubtitle:
|
||||
input_name = tr("Subtitle Tracks");
|
||||
break;
|
||||
case Track::kNone:
|
||||
case Track::kCount:
|
||||
break;
|
||||
}
|
||||
switch (static_cast<Track::Type>(i)) {
|
||||
case Track::kVideo:
|
||||
input_name = tr("Video Tracks");
|
||||
break;
|
||||
case Track::kAudio:
|
||||
input_name = tr("Audio Tracks");
|
||||
break;
|
||||
case Track::kSubtitle:
|
||||
input_name = tr("Subtitle Tracks");
|
||||
break;
|
||||
case Track::kNone:
|
||||
case Track::kCount:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!input_name.isEmpty()) {
|
||||
SetInputName(kTrackInputFormat.arg(i), input_name);
|
||||
}
|
||||
}
|
||||
if (!input_name.isEmpty()) {
|
||||
SetInputName(kTrackInputFormat.arg(i), input_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Sequence::InvalidateCache(const TimeRange &range, const QString &from, int element, InvalidateCacheOptions options)
|
||||
void Sequence::InvalidateCache(const TimeRange &range, const QString &from,
|
||||
int element, InvalidateCacheOptions options)
|
||||
{
|
||||
if (from == kTrackInputFormat.arg(Track::kSubtitle)) {
|
||||
emit SubtitlesChanged(range);
|
||||
}
|
||||
if (from == kTrackInputFormat.arg(Track::kSubtitle)) {
|
||||
emit SubtitlesChanged(range);
|
||||
}
|
||||
|
||||
super::InvalidateCache(range, from, element, options);
|
||||
super::InvalidateCache(range, from, element, options);
|
||||
}
|
||||
|
||||
rational Sequence::VerifyLengthInternal(Track::Type type) const
|
||||
{
|
||||
if (!track_lists_.isEmpty()) {
|
||||
switch (type) {
|
||||
case Track::kVideo:
|
||||
return track_lists_.at(Track::kVideo)->GetTotalLength();
|
||||
case Track::kAudio:
|
||||
return track_lists_.at(Track::kAudio)->GetTotalLength();
|
||||
case Track::kSubtitle:
|
||||
return track_lists_.at(Track::kSubtitle)->GetTotalLength();
|
||||
case Track::kNone:
|
||||
case Track::kCount:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!track_lists_.isEmpty()) {
|
||||
switch (type) {
|
||||
case Track::kVideo:
|
||||
return track_lists_.at(Track::kVideo)->GetTotalLength();
|
||||
case Track::kAudio:
|
||||
return track_lists_.at(Track::kAudio)->GetTotalLength();
|
||||
case Track::kSubtitle:
|
||||
return track_lists_.at(Track::kSubtitle)->GetTotalLength();
|
||||
case Track::kNone:
|
||||
case Track::kCount:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Sequence::InputConnectedEvent(const QString &input, int element, Node *output)
|
||||
void Sequence::InputConnectedEvent(const QString &input, int element,
|
||||
Node *output)
|
||||
{
|
||||
foreach (TrackList* list, track_lists_) {
|
||||
if (list->track_input() == input) {
|
||||
// Return because we found our input
|
||||
list->TrackConnected(output, element);
|
||||
return;
|
||||
}
|
||||
}
|
||||
foreach (TrackList *list, track_lists_) {
|
||||
if (list->track_input() == input) {
|
||||
// Return because we found our input
|
||||
list->TrackConnected(output, element);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
super::InputConnectedEvent(input, element, output);
|
||||
super::InputConnectedEvent(input, element, output);
|
||||
}
|
||||
|
||||
void Sequence::InputDisconnectedEvent(const QString &input, int element, Node *output)
|
||||
void Sequence::InputDisconnectedEvent(const QString &input, int element,
|
||||
Node *output)
|
||||
{
|
||||
foreach (TrackList* list, track_lists_) {
|
||||
if (list->track_input() == input) {
|
||||
// Return because we found our input
|
||||
list->TrackDisconnected(output, element);
|
||||
return;
|
||||
}
|
||||
}
|
||||
foreach (TrackList *list, track_lists_) {
|
||||
if (list->track_input() == input) {
|
||||
// Return because we found our input
|
||||
list->TrackDisconnected(output, element);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
super::InputDisconnectedEvent(input, element, output);
|
||||
super::InputDisconnectedEvent(input, element, output);
|
||||
}
|
||||
|
||||
void Sequence::UpdateTrackCache()
|
||||
{
|
||||
track_cache_.clear();
|
||||
track_cache_.clear();
|
||||
|
||||
foreach (TrackList* list, track_lists_) {
|
||||
foreach (Track* track, list->GetTracks()) {
|
||||
track_cache_.append(track);
|
||||
}
|
||||
}
|
||||
foreach (TrackList *list, track_lists_) {
|
||||
foreach (Track *track, list->GetTracks()) {
|
||||
track_cache_.append(track);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,90 +24,94 @@
|
||||
#include "node/output/track/tracklist.h"
|
||||
#include "node/output/viewer/viewer.h"
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief The main timeline object, an graph of edited clips that forms a complete edit
|
||||
*/
|
||||
class Sequence : public ViewerOutput
|
||||
{
|
||||
Q_OBJECT
|
||||
class Sequence : public ViewerOutput {
|
||||
Q_OBJECT
|
||||
public:
|
||||
Sequence();
|
||||
Sequence();
|
||||
|
||||
NODE_DEFAULT_FUNCTIONS(Sequence)
|
||||
NODE_DEFAULT_FUNCTIONS(Sequence)
|
||||
|
||||
virtual QString Name() const override
|
||||
{
|
||||
return tr("Sequence");
|
||||
}
|
||||
virtual QString Name() const override
|
||||
{
|
||||
return tr("Sequence");
|
||||
}
|
||||
|
||||
virtual QString id() const override
|
||||
{
|
||||
return QStringLiteral("org.olivevideoeditor.Olive.sequence");
|
||||
}
|
||||
virtual QString id() const override
|
||||
{
|
||||
return QStringLiteral("org.olivevideoeditor.Olive.sequence");
|
||||
}
|
||||
|
||||
virtual QVector<CategoryID> Category() const override
|
||||
{
|
||||
return {kCategoryProject};
|
||||
}
|
||||
virtual QVector<CategoryID> Category() const override
|
||||
{
|
||||
return { kCategoryProject };
|
||||
}
|
||||
|
||||
virtual QString Description() const override
|
||||
{
|
||||
return tr("A series of cuts that result in an edited video. Also called a timeline.");
|
||||
}
|
||||
virtual QString Description() const override
|
||||
{
|
||||
return tr(
|
||||
"A series of cuts that result in an edited video. Also called a timeline.");
|
||||
}
|
||||
|
||||
void add_default_nodes(MultiUndoCommand *command = nullptr);
|
||||
void add_default_nodes(MultiUndoCommand *command = nullptr);
|
||||
|
||||
virtual QVariant data(const DataType &d) const override;
|
||||
virtual QVariant data(const DataType &d) const override;
|
||||
|
||||
const QVector<Track *> &GetTracks() const
|
||||
{
|
||||
return track_cache_;
|
||||
}
|
||||
const QVector<Track *> &GetTracks() const
|
||||
{
|
||||
return track_cache_;
|
||||
}
|
||||
|
||||
Track* GetTrackFromReference(const Track::Reference& track_ref) const
|
||||
{
|
||||
return track_lists_.at(track_ref.type())->GetTrackAt(track_ref.index());
|
||||
}
|
||||
Track *GetTrackFromReference(const Track::Reference &track_ref) const
|
||||
{
|
||||
return track_lists_.at(track_ref.type())->GetTrackAt(track_ref.index());
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Same as GetTracks() but omits tracks that are locked.
|
||||
*/
|
||||
QVector<Track *> GetUnlockedTracks() const;
|
||||
QVector<Track *> GetUnlockedTracks() const;
|
||||
|
||||
TrackList* track_list(Track::Type type) const
|
||||
{
|
||||
return track_lists_.at(type);
|
||||
}
|
||||
TrackList *track_list(Track::Type type) const
|
||||
{
|
||||
return track_lists_.at(type);
|
||||
}
|
||||
|
||||
virtual void Retranslate() override;
|
||||
virtual void Retranslate() override;
|
||||
|
||||
virtual void InvalidateCache(const TimeRange& range, const QString& from, int element, InvalidateCacheOptions options) override;
|
||||
virtual void InvalidateCache(const TimeRange &range, const QString &from,
|
||||
int element,
|
||||
InvalidateCacheOptions options) override;
|
||||
|
||||
static const QString kTrackInputFormat;
|
||||
static const QString kTrackInputFormat;
|
||||
|
||||
protected:
|
||||
virtual void InputConnectedEvent(const QString &input, int element, Node *output) override;
|
||||
virtual void InputConnectedEvent(const QString &input, int element,
|
||||
Node *output) override;
|
||||
|
||||
virtual void InputDisconnectedEvent(const QString &input, int element, Node *output) override;
|
||||
virtual void InputDisconnectedEvent(const QString &input, int element,
|
||||
Node *output) override;
|
||||
|
||||
virtual rational VerifyLengthInternal(Track::Type type) const override;
|
||||
virtual rational VerifyLengthInternal(Track::Type type) const override;
|
||||
|
||||
signals:
|
||||
void TrackAdded(Track* track);
|
||||
void TrackRemoved(Track* track);
|
||||
void TrackAdded(Track *track);
|
||||
void TrackRemoved(Track *track);
|
||||
|
||||
void SubtitlesChanged(const TimeRange &range);
|
||||
void SubtitlesChanged(const TimeRange &range);
|
||||
|
||||
private:
|
||||
QVector<TrackList*> track_lists_;
|
||||
QVector<TrackList *> track_lists_;
|
||||
|
||||
QVector<Track*> track_cache_;
|
||||
QVector<Track *> track_cache_;
|
||||
|
||||
private slots:
|
||||
void UpdateTrackCache();
|
||||
|
||||
void UpdateTrackCache();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -34,274 +34,299 @@
|
||||
#include "serializer220403.h"
|
||||
#include "serializer230220.h"
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
QVector<ProjectSerializer*> ProjectSerializer::instances_;
|
||||
QVector<ProjectSerializer *> ProjectSerializer::instances_;
|
||||
|
||||
void ProjectSerializer::Initialize()
|
||||
{
|
||||
// Make sure to order these from oldest to newest
|
||||
// Make sure to order these from oldest to newest
|
||||
|
||||
// FIXME: Implement this - yes it's a 0.1 project loader
|
||||
//instances_.append(new ProjectSerializer190219);
|
||||
// FIXME: Implement this - yes it's a 0.1 project loader
|
||||
//instances_.append(new ProjectSerializer190219);
|
||||
|
||||
instances_.append(new ProjectSerializer210528);
|
||||
instances_.append(new ProjectSerializer210907);
|
||||
instances_.append(new ProjectSerializer211228);
|
||||
instances_.append(new ProjectSerializer220403);
|
||||
instances_.append(new ProjectSerializer230220);
|
||||
instances_.append(new ProjectSerializer210528);
|
||||
instances_.append(new ProjectSerializer210907);
|
||||
instances_.append(new ProjectSerializer211228);
|
||||
instances_.append(new ProjectSerializer220403);
|
||||
instances_.append(new ProjectSerializer230220);
|
||||
}
|
||||
|
||||
void ProjectSerializer::Destroy()
|
||||
{
|
||||
qDeleteAll(instances_);
|
||||
instances_.clear();
|
||||
qDeleteAll(instances_);
|
||||
instances_.clear();
|
||||
}
|
||||
|
||||
ProjectSerializer::Result ProjectSerializer::Load(Project *project, const QString &filename, LoadType load_type)
|
||||
ProjectSerializer::Result ProjectSerializer::Load(Project *project,
|
||||
const QString &filename,
|
||||
LoadType load_type)
|
||||
{
|
||||
QFile project_file(filename);
|
||||
QFile project_file(filename);
|
||||
|
||||
if (project_file.open(QFile::ReadOnly)) {
|
||||
// Some project files are compressed, marked with "OVEC" at the beginning of the file. Check for
|
||||
// that signature now.
|
||||
std::unique_ptr<QXmlStreamReader> reader;
|
||||
if (CheckCompressedID(&project_file)) {
|
||||
// File is compressed, decompress into memory
|
||||
QByteArray b;
|
||||
b = qUncompress(project_file.readAll());
|
||||
reader.reset(new QXmlStreamReader(b));
|
||||
} else {
|
||||
project_file.seek(0);
|
||||
reader.reset(new QXmlStreamReader(&project_file));
|
||||
}
|
||||
if (project_file.open(QFile::ReadOnly)) {
|
||||
// Some project files are compressed, marked with "OVEC" at the beginning of the file. Check for
|
||||
// that signature now.
|
||||
std::unique_ptr<QXmlStreamReader> reader;
|
||||
if (CheckCompressedID(&project_file)) {
|
||||
// File is compressed, decompress into memory
|
||||
QByteArray b;
|
||||
b = qUncompress(project_file.readAll());
|
||||
reader.reset(new QXmlStreamReader(b));
|
||||
} else {
|
||||
project_file.seek(0);
|
||||
reader.reset(new QXmlStreamReader(&project_file));
|
||||
}
|
||||
|
||||
Result inner_result = Load(project, reader.get(), load_type);
|
||||
Result inner_result = Load(project, reader.get(), load_type);
|
||||
|
||||
project_file.close();
|
||||
project_file.close();
|
||||
|
||||
if (inner_result.code() != kSuccess) {
|
||||
return inner_result;
|
||||
}
|
||||
if (inner_result.code() != kSuccess) {
|
||||
return inner_result;
|
||||
}
|
||||
|
||||
if (reader->hasError()) {
|
||||
Result r(kXmlError);
|
||||
r.SetDetails(reader->errorString());
|
||||
return r;
|
||||
} else {
|
||||
return inner_result;
|
||||
}
|
||||
} else {
|
||||
return kFileError;
|
||||
}
|
||||
if (reader->hasError()) {
|
||||
Result r(kXmlError);
|
||||
r.SetDetails(reader->errorString());
|
||||
return r;
|
||||
} else {
|
||||
return inner_result;
|
||||
}
|
||||
} else {
|
||||
return kFileError;
|
||||
}
|
||||
}
|
||||
|
||||
ProjectSerializer::Result ProjectSerializer::Load(Project *project, QXmlStreamReader *reader, LoadType load_type)
|
||||
ProjectSerializer::Result ProjectSerializer::Load(Project *project,
|
||||
QXmlStreamReader *reader,
|
||||
LoadType load_type)
|
||||
{
|
||||
// Determine project version
|
||||
uint version = 0;
|
||||
Result res = kUnknownVersion;
|
||||
// Determine project version
|
||||
uint version = 0;
|
||||
Result res = kUnknownVersion;
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("olive")
|
||||
|| reader->name() == QStringLiteral("project")) { // 0.1 projects only
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("olive") ||
|
||||
reader->name() == QStringLiteral("project")) { // 0.1 projects only
|
||||
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("version")) { // 230220+ projects
|
||||
version = attr.value().toUInt();
|
||||
} else if (reader->name() == QStringLiteral("url")) { // 230220+ projects
|
||||
project->SetSavedURL(attr.value().toString());
|
||||
}
|
||||
}
|
||||
XMLAttributeLoop(reader, attr)
|
||||
{
|
||||
if (attr.name() ==
|
||||
QStringLiteral("version")) { // 230220+ projects
|
||||
version = attr.value().toUInt();
|
||||
} else if (reader->name() ==
|
||||
QStringLiteral("url")) { // 230220+ projects
|
||||
project->SetSavedURL(attr.value().toString());
|
||||
}
|
||||
}
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("version")) { // projects <= 220403
|
||||
version = reader->readElementText().toUInt();
|
||||
} else if (reader->name() == QStringLiteral("url")) { // projects <= 220403
|
||||
if (project) {
|
||||
project->SetSavedURL(reader->readElementText());
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
} else {
|
||||
// Handle any other value with the serializer
|
||||
res = LoadWithSerializerVersion(version, project, reader, load_type);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() ==
|
||||
QStringLiteral("version")) { // projects <= 220403
|
||||
version = reader->readElementText().toUInt();
|
||||
} else if (reader->name() ==
|
||||
QStringLiteral("url")) { // projects <= 220403
|
||||
if (project) {
|
||||
project->SetSavedURL(reader->readElementText());
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
} else {
|
||||
// Handle any other value with the serializer
|
||||
res = LoadWithSerializerVersion(version, project, reader,
|
||||
load_type);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
return res;
|
||||
}
|
||||
|
||||
ProjectSerializer::Result ProjectSerializer::Paste(LoadType load_type, Project *project)
|
||||
ProjectSerializer::Result ProjectSerializer::Paste(LoadType load_type,
|
||||
Project *project)
|
||||
{
|
||||
QString clipboard = Core::PasteStringFromClipboard();
|
||||
if (clipboard.isEmpty()) {
|
||||
return kNoData;
|
||||
}
|
||||
QString clipboard = Core::PasteStringFromClipboard();
|
||||
if (clipboard.isEmpty()) {
|
||||
return kNoData;
|
||||
}
|
||||
|
||||
QXmlStreamReader reader(clipboard);
|
||||
QXmlStreamReader reader(clipboard);
|
||||
|
||||
return ProjectSerializer::Load(project, &reader, load_type);
|
||||
return ProjectSerializer::Load(project, &reader, load_type);
|
||||
}
|
||||
|
||||
ProjectSerializer::Result ProjectSerializer::Save(const SaveData &data, bool compress)
|
||||
ProjectSerializer::Result ProjectSerializer::Save(const SaveData &data,
|
||||
bool compress)
|
||||
{
|
||||
QString temp_save = FileFunctions::GetSafeTemporaryFilename(data.GetFilename());
|
||||
QString temp_save =
|
||||
FileFunctions::GetSafeTemporaryFilename(data.GetFilename());
|
||||
|
||||
QFile project_file(temp_save);
|
||||
QFile project_file(temp_save);
|
||||
|
||||
if (project_file.open(QFile::WriteOnly)) {
|
||||
QByteArray b;
|
||||
QXmlStreamWriter writer(&b);
|
||||
if (project_file.open(QFile::WriteOnly)) {
|
||||
QByteArray b;
|
||||
QXmlStreamWriter writer(&b);
|
||||
|
||||
Result inner_result = Save(&writer, data);
|
||||
Result inner_result = Save(&writer, data);
|
||||
|
||||
if (writer.hasError()) {
|
||||
Result r(kXmlError);
|
||||
return r;
|
||||
}
|
||||
if (writer.hasError()) {
|
||||
Result r(kXmlError);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (compress) {
|
||||
project_file.write("OVEC");
|
||||
project_file.write(qCompress(b));
|
||||
} else {
|
||||
project_file.write(b);
|
||||
}
|
||||
if (compress) {
|
||||
project_file.write("OVEC");
|
||||
project_file.write(qCompress(b));
|
||||
} else {
|
||||
project_file.write(b);
|
||||
}
|
||||
|
||||
project_file.close();
|
||||
project_file.close();
|
||||
|
||||
if (inner_result != kSuccess) {
|
||||
return inner_result;
|
||||
}
|
||||
if (inner_result != kSuccess) {
|
||||
return inner_result;
|
||||
}
|
||||
|
||||
// Save was successful, we can now rewrite the original file
|
||||
if (FileFunctions::RenameFileAllowOverwrite(temp_save, data.GetFilename())) {
|
||||
return kSuccess;
|
||||
} else {
|
||||
Result r(kOverwriteError);
|
||||
r.SetDetails(temp_save);
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
Result r(kFileError);
|
||||
r.SetDetails(temp_save);
|
||||
return r;
|
||||
}
|
||||
// Save was successful, we can now rewrite the original file
|
||||
if (FileFunctions::RenameFileAllowOverwrite(temp_save,
|
||||
data.GetFilename())) {
|
||||
return kSuccess;
|
||||
} else {
|
||||
Result r(kOverwriteError);
|
||||
r.SetDetails(temp_save);
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
Result r(kFileError);
|
||||
r.SetDetails(temp_save);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
ProjectSerializer::Result ProjectSerializer::Save(QXmlStreamWriter *writer, const SaveData &data)
|
||||
ProjectSerializer::Result ProjectSerializer::Save(QXmlStreamWriter *writer,
|
||||
const SaveData &data)
|
||||
{
|
||||
writer->setAutoFormatting(true);
|
||||
writer->setAutoFormatting(true);
|
||||
|
||||
writer->writeStartDocument();
|
||||
writer->writeStartDocument();
|
||||
|
||||
writer->writeStartElement("olive");
|
||||
writer->writeStartElement("olive");
|
||||
|
||||
// By default, save as last serializer which, assuming the instances are ordered correctly,
|
||||
// will be the newest file format. But we may allow saving as older versions later on.
|
||||
ProjectSerializer *serializer = instances_.last();
|
||||
// By default, save as last serializer which, assuming the instances are ordered correctly,
|
||||
// will be the newest file format. But we may allow saving as older versions later on.
|
||||
ProjectSerializer *serializer = instances_.last();
|
||||
|
||||
// Version is stored in YYMMDD from whenever the project format was last changed
|
||||
// Allows easy integer math for checking project versions.
|
||||
writer->writeAttribute(QStringLiteral("version"), QString::number(serializer->Version()));
|
||||
// Version is stored in YYMMDD from whenever the project format was last changed
|
||||
// Allows easy integer math for checking project versions.
|
||||
writer->writeAttribute(QStringLiteral("version"),
|
||||
QString::number(serializer->Version()));
|
||||
|
||||
if (!data.GetFilename().isEmpty()) {
|
||||
writer->writeAttribute("url", data.GetFilename());
|
||||
}
|
||||
if (!data.GetFilename().isEmpty()) {
|
||||
writer->writeAttribute("url", data.GetFilename());
|
||||
}
|
||||
|
||||
serializer->Save(writer, data, nullptr);
|
||||
serializer->Save(writer, data, nullptr);
|
||||
|
||||
writer->writeEndElement(); // olive
|
||||
writer->writeEndElement(); // olive
|
||||
|
||||
writer->writeEndDocument();
|
||||
writer->writeEndDocument();
|
||||
|
||||
if (writer->hasError()) {
|
||||
return kXmlError;
|
||||
}
|
||||
if (writer->hasError()) {
|
||||
return kXmlError;
|
||||
}
|
||||
|
||||
return kSuccess;
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
ProjectSerializer::Result ProjectSerializer::Copy(const SaveData &data)
|
||||
{
|
||||
QString copy_str;
|
||||
QXmlStreamWriter writer(©_str);
|
||||
QString copy_str;
|
||||
QXmlStreamWriter writer(©_str);
|
||||
|
||||
ProjectSerializer::Result res = ProjectSerializer::Save(&writer, data);
|
||||
ProjectSerializer::Result res = ProjectSerializer::Save(&writer, data);
|
||||
|
||||
if (res == kSuccess) {
|
||||
Core::CopyStringToClipboard(copy_str);
|
||||
}
|
||||
if (res == kSuccess) {
|
||||
Core::CopyStringToClipboard(copy_str);
|
||||
}
|
||||
|
||||
return res;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool ProjectSerializer::CheckCompressedID(QFile *file)
|
||||
{
|
||||
QByteArray b = file->read(4);
|
||||
return !memcmp(b.data(), "OVEC", 4);
|
||||
QByteArray b = file->read(4);
|
||||
return !memcmp(b.data(), "OVEC", 4);
|
||||
}
|
||||
|
||||
bool ProjectSerializer::IsCancelled() const
|
||||
{
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
ProjectSerializer::Result ProjectSerializer::LoadWithSerializerVersion(uint version, Project *project, QXmlStreamReader *reader, LoadType load_type)
|
||||
ProjectSerializer::Result
|
||||
ProjectSerializer::LoadWithSerializerVersion(uint version, Project *project,
|
||||
QXmlStreamReader *reader,
|
||||
LoadType load_type)
|
||||
{
|
||||
// Failed to find version in file
|
||||
if (version == 0) {
|
||||
return kUnknownVersion;
|
||||
}
|
||||
// Failed to find version in file
|
||||
if (version == 0) {
|
||||
return kUnknownVersion;
|
||||
}
|
||||
|
||||
// We should now have the version, if we have a serializer for it, use it to load the project
|
||||
ProjectSerializer *serializer = nullptr;
|
||||
// We should now have the version, if we have a serializer for it, use it to load the project
|
||||
ProjectSerializer *serializer = nullptr;
|
||||
|
||||
foreach (ProjectSerializer *s, instances_) {
|
||||
if (version == s->Version()) {
|
||||
serializer = s;
|
||||
break;
|
||||
} else if (version < s->Version()) {
|
||||
// Assuming the instance list is in order, if the project version is less than any version
|
||||
// we find, we must not support it anymore
|
||||
return kProjectTooOld;
|
||||
}
|
||||
}
|
||||
foreach (ProjectSerializer *s, instances_) {
|
||||
if (version == s->Version()) {
|
||||
serializer = s;
|
||||
break;
|
||||
} else if (version < s->Version()) {
|
||||
// Assuming the instance list is in order, if the project version is less than any version
|
||||
// we find, we must not support it anymore
|
||||
return kProjectTooOld;
|
||||
}
|
||||
}
|
||||
|
||||
if (serializer) {
|
||||
LoadData ld = serializer->Load(project, reader, load_type, nullptr);
|
||||
Result r(kSuccess);
|
||||
if (reader->hasError()) {
|
||||
r = Result(kXmlError);
|
||||
r.SetDetails(QCoreApplication::translate("Serializer", "%1 on line %2").arg(reader->errorString(), QString::number(reader->lineNumber())));
|
||||
}
|
||||
r.SetLoadData(ld);
|
||||
return r;
|
||||
} else {
|
||||
// Reached the end of the list with no serializer, assume too new
|
||||
return kProjectTooNew;
|
||||
}
|
||||
if (serializer) {
|
||||
LoadData ld = serializer->Load(project, reader, load_type, nullptr);
|
||||
Result r(kSuccess);
|
||||
if (reader->hasError()) {
|
||||
r = Result(kXmlError);
|
||||
r.SetDetails(
|
||||
QCoreApplication::translate("Serializer", "%1 on line %2")
|
||||
.arg(reader->errorString(),
|
||||
QString::number(reader->lineNumber())));
|
||||
}
|
||||
r.SetLoadData(ld);
|
||||
return r;
|
||||
} else {
|
||||
// Reached the end of the list with no serializer, assume too new
|
||||
return kProjectTooNew;
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectSerializer::SaveData::SetOnlySerializeNodesAndResolveGroups(QVector<Node *> nodes)
|
||||
void ProjectSerializer::SaveData::SetOnlySerializeNodesAndResolveGroups(
|
||||
QVector<Node *> nodes)
|
||||
{
|
||||
// For any groups, add children
|
||||
for (int i=0; i<nodes.size(); i++) {
|
||||
// If this is a group, add the child nodes too
|
||||
if (NodeGroup *g = dynamic_cast<NodeGroup*>(nodes.at(i))) {
|
||||
for (auto it=g->GetContextPositions().cbegin(); it!=g->GetContextPositions().cend(); it++) {
|
||||
if (!nodes.contains(it.key())) {
|
||||
nodes.append(it.key());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// For any groups, add children
|
||||
for (int i = 0; i < nodes.size(); i++) {
|
||||
// If this is a group, add the child nodes too
|
||||
if (NodeGroup *g = dynamic_cast<NodeGroup *>(nodes.at(i))) {
|
||||
for (auto it = g->GetContextPositions().cbegin();
|
||||
it != g->GetContextPositions().cend(); it++) {
|
||||
if (!nodes.contains(it.key())) {
|
||||
nodes.append(it.key());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetOnlySerializeNodes(nodes);
|
||||
SetOnlySerializeNodes(nodes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
#include "node/project.h"
|
||||
#include "typeserializer.h"
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief An abstract base class for serializing/deserializing project data
|
||||
@@ -35,167 +36,236 @@ namespace olive {
|
||||
* The goal of this is to further abstract serialized project data from their
|
||||
* in-memory representations.
|
||||
*/
|
||||
class ProjectSerializer
|
||||
{
|
||||
class ProjectSerializer {
|
||||
public:
|
||||
enum LoadType
|
||||
{
|
||||
kProject,
|
||||
kOnlyNodes,
|
||||
kOnlyClips,
|
||||
kOnlyMarkers,
|
||||
kOnlyKeyframes
|
||||
};
|
||||
enum LoadType {
|
||||
kProject,
|
||||
kOnlyNodes,
|
||||
kOnlyClips,
|
||||
kOnlyMarkers,
|
||||
kOnlyKeyframes
|
||||
};
|
||||
|
||||
ProjectSerializer() = default;
|
||||
ProjectSerializer() = default;
|
||||
|
||||
virtual ~ProjectSerializer(){}
|
||||
virtual ~ProjectSerializer()
|
||||
{
|
||||
}
|
||||
|
||||
DISABLE_COPY_MOVE(ProjectSerializer)
|
||||
DISABLE_COPY_MOVE(ProjectSerializer)
|
||||
|
||||
enum ResultCode {
|
||||
kSuccess,
|
||||
kProjectTooOld,
|
||||
kProjectTooNew,
|
||||
kUnknownVersion,
|
||||
kFileError,
|
||||
kXmlError,
|
||||
kOverwriteError,
|
||||
kNoData
|
||||
};
|
||||
enum ResultCode {
|
||||
kSuccess,
|
||||
kProjectTooOld,
|
||||
kProjectTooNew,
|
||||
kUnknownVersion,
|
||||
kFileError,
|
||||
kXmlError,
|
||||
kOverwriteError,
|
||||
kNoData
|
||||
};
|
||||
|
||||
using SerializedProperties = QHash<Node*, QMap<QString, QString> >;
|
||||
using SerializedKeyframes = QHash<QString, QVector<NodeKeyframe*> >;
|
||||
using SerializedProperties = QHash<Node *, QMap<QString, QString>>;
|
||||
using SerializedKeyframes = QHash<QString, QVector<NodeKeyframe *>>;
|
||||
|
||||
class LoadData
|
||||
{
|
||||
public:
|
||||
LoadData() = default;
|
||||
class LoadData {
|
||||
public:
|
||||
LoadData() = default;
|
||||
|
||||
SerializedProperties properties;
|
||||
SerializedProperties properties;
|
||||
|
||||
std::vector<TimelineMarker*> markers;
|
||||
std::vector<TimelineMarker *> markers;
|
||||
|
||||
SerializedKeyframes keyframes;
|
||||
SerializedKeyframes keyframes;
|
||||
|
||||
MainWindowLayoutInfo layout;
|
||||
MainWindowLayoutInfo layout;
|
||||
|
||||
QVector<Node*> nodes;
|
||||
QVector<Node *> nodes;
|
||||
|
||||
Node::OutputConnections promised_connections;
|
||||
Node::OutputConnections promised_connections;
|
||||
};
|
||||
|
||||
};
|
||||
class Result {
|
||||
public:
|
||||
Result(const ResultCode &code)
|
||||
: code_(code)
|
||||
{
|
||||
}
|
||||
|
||||
class Result
|
||||
{
|
||||
public:
|
||||
Result(const ResultCode &code) :
|
||||
code_(code)
|
||||
{}
|
||||
bool operator==(const ResultCode &code)
|
||||
{
|
||||
return code_ == code;
|
||||
}
|
||||
bool operator!=(const ResultCode &code)
|
||||
{
|
||||
return code_ != code;
|
||||
}
|
||||
|
||||
bool operator==(const ResultCode &code) { return code_ == code; }
|
||||
bool operator!=(const ResultCode &code) { return code_ != code; }
|
||||
const ResultCode &code() const
|
||||
{
|
||||
return code_;
|
||||
}
|
||||
|
||||
const ResultCode &code() const { return code_; }
|
||||
const QString &GetDetails() const
|
||||
{
|
||||
return details_;
|
||||
}
|
||||
|
||||
const QString &GetDetails() const { return details_; }
|
||||
void SetDetails(const QString &s)
|
||||
{
|
||||
details_ = s;
|
||||
}
|
||||
|
||||
void SetDetails(const QString &s) { details_ = s; }
|
||||
const LoadData &GetLoadData() const
|
||||
{
|
||||
return load_data_;
|
||||
}
|
||||
|
||||
const LoadData &GetLoadData() const { return load_data_; }
|
||||
void SetLoadData(const LoadData &p)
|
||||
{
|
||||
load_data_ = p;
|
||||
}
|
||||
|
||||
void SetLoadData(const LoadData &p) { load_data_ = p; }
|
||||
private:
|
||||
ResultCode code_;
|
||||
|
||||
private:
|
||||
ResultCode code_;
|
||||
QString details_;
|
||||
|
||||
QString details_;
|
||||
LoadData load_data_;
|
||||
};
|
||||
|
||||
LoadData load_data_;
|
||||
class SaveData {
|
||||
public:
|
||||
SaveData(LoadType type, Project *project = nullptr,
|
||||
const QString &filename = QString())
|
||||
{
|
||||
type_ = type;
|
||||
project_ = project;
|
||||
filename_ = filename;
|
||||
}
|
||||
|
||||
};
|
||||
Project *GetProject() const
|
||||
{
|
||||
return project_;
|
||||
}
|
||||
void SetProject(Project *p)
|
||||
{
|
||||
project_ = p;
|
||||
}
|
||||
|
||||
class SaveData
|
||||
{
|
||||
public:
|
||||
SaveData(LoadType type, Project *project = nullptr, const QString &filename = QString())
|
||||
{
|
||||
type_ = type;
|
||||
project_ = project;
|
||||
filename_ = filename;
|
||||
}
|
||||
const QString &GetFilename() const
|
||||
{
|
||||
return filename_;
|
||||
}
|
||||
void SetFilename(const QString &s)
|
||||
{
|
||||
filename_ = s;
|
||||
}
|
||||
|
||||
Project *GetProject() const { return project_; }
|
||||
void SetProject(Project *p) { project_ = p; }
|
||||
LoadType type() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
const QString &GetFilename() const { return filename_; }
|
||||
void SetFilename(const QString &s) { filename_ = s; }
|
||||
const MainWindowLayoutInfo &GetLayout() const
|
||||
{
|
||||
return layout_;
|
||||
}
|
||||
void SetLayout(const MainWindowLayoutInfo &layout)
|
||||
{
|
||||
layout_ = layout;
|
||||
}
|
||||
|
||||
LoadType type() const { return type_; }
|
||||
const QVector<Node *> &GetOnlySerializeNodes() const
|
||||
{
|
||||
return only_serialize_nodes_;
|
||||
}
|
||||
void SetOnlySerializeNodes(const QVector<Node *> &only)
|
||||
{
|
||||
only_serialize_nodes_ = only;
|
||||
}
|
||||
void SetOnlySerializeNodesAndResolveGroups(QVector<Node *> only);
|
||||
|
||||
const MainWindowLayoutInfo &GetLayout() const { return layout_; }
|
||||
void SetLayout(const MainWindowLayoutInfo &layout) { layout_ = layout; }
|
||||
const std::vector<TimelineMarker *> &GetOnlySerializeMarkers() const
|
||||
{
|
||||
return only_serialize_markers_;
|
||||
}
|
||||
void SetOnlySerializeMarkers(const std::vector<TimelineMarker *> &only)
|
||||
{
|
||||
only_serialize_markers_ = only;
|
||||
}
|
||||
|
||||
const QVector<Node*> &GetOnlySerializeNodes() const { return only_serialize_nodes_; }
|
||||
void SetOnlySerializeNodes(const QVector<Node*> &only) { only_serialize_nodes_ = only; }
|
||||
void SetOnlySerializeNodesAndResolveGroups(QVector<Node*> only);
|
||||
const std::vector<NodeKeyframe *> &GetOnlySerializeKeyframes() const
|
||||
{
|
||||
return only_serialize_keyframes_;
|
||||
}
|
||||
void SetOnlySerializeKeyframes(const std::vector<NodeKeyframe *> &only)
|
||||
{
|
||||
only_serialize_keyframes_ = only;
|
||||
}
|
||||
|
||||
const std::vector<TimelineMarker*> &GetOnlySerializeMarkers() const { return only_serialize_markers_; }
|
||||
void SetOnlySerializeMarkers(const std::vector<TimelineMarker*> &only) { only_serialize_markers_ = only; }
|
||||
const SerializedProperties &GetProperties() const
|
||||
{
|
||||
return properties_;
|
||||
}
|
||||
void SetProperties(const SerializedProperties &p)
|
||||
{
|
||||
properties_ = p;
|
||||
}
|
||||
|
||||
const std::vector<NodeKeyframe*> &GetOnlySerializeKeyframes() const { return only_serialize_keyframes_; }
|
||||
void SetOnlySerializeKeyframes(const std::vector<NodeKeyframe*> &only) { only_serialize_keyframes_ = only; }
|
||||
private:
|
||||
LoadType type_;
|
||||
|
||||
const SerializedProperties &GetProperties() const { return properties_; }
|
||||
void SetProperties(const SerializedProperties &p) { properties_ = p; }
|
||||
Project *project_;
|
||||
|
||||
private:
|
||||
LoadType type_;
|
||||
QString filename_;
|
||||
|
||||
Project *project_;
|
||||
MainWindowLayoutInfo layout_;
|
||||
|
||||
QString filename_;
|
||||
QVector<Node *> only_serialize_nodes_;
|
||||
|
||||
MainWindowLayoutInfo layout_;
|
||||
SerializedProperties properties_;
|
||||
|
||||
QVector<Node*> only_serialize_nodes_;
|
||||
std::vector<TimelineMarker *> only_serialize_markers_;
|
||||
|
||||
SerializedProperties properties_;
|
||||
std::vector<NodeKeyframe *> only_serialize_keyframes_;
|
||||
};
|
||||
|
||||
std::vector<TimelineMarker*> only_serialize_markers_;
|
||||
static void Initialize();
|
||||
|
||||
std::vector<NodeKeyframe*> only_serialize_keyframes_;
|
||||
static void Destroy();
|
||||
|
||||
};
|
||||
static Result Load(Project *project, const QString &filename,
|
||||
LoadType load_type);
|
||||
static Result Load(Project *project, QXmlStreamReader *read_device,
|
||||
LoadType load_type);
|
||||
static Result Paste(LoadType load_type, Project *project = nullptr);
|
||||
|
||||
static void Initialize();
|
||||
static Result Save(const SaveData &data, bool compress);
|
||||
static Result Save(QXmlStreamWriter *write_device, const SaveData &data);
|
||||
static Result Copy(const SaveData &data);
|
||||
|
||||
static void Destroy();
|
||||
|
||||
static Result Load(Project *project, const QString &filename, LoadType load_type);
|
||||
static Result Load(Project *project, QXmlStreamReader *read_device, LoadType load_type);
|
||||
static Result Paste(LoadType load_type, Project *project = nullptr);
|
||||
|
||||
static Result Save(const SaveData &data, bool compress);
|
||||
static Result Save(QXmlStreamWriter *write_device, const SaveData &data);
|
||||
static Result Copy(const SaveData &data);
|
||||
|
||||
static bool CheckCompressedID(QFile *file);
|
||||
static bool CheckCompressedID(QFile *file);
|
||||
|
||||
protected:
|
||||
virtual LoadData Load(Project *project, QXmlStreamReader *reader, LoadType load_type, void *reserved) const = 0;
|
||||
virtual LoadData Load(Project *project, QXmlStreamReader *reader,
|
||||
LoadType load_type, void *reserved) const = 0;
|
||||
|
||||
virtual void Save(QXmlStreamWriter *writer, const SaveData &data, void *reserved) const {}
|
||||
virtual void Save(QXmlStreamWriter *writer, const SaveData &data,
|
||||
void *reserved) const
|
||||
{
|
||||
}
|
||||
|
||||
virtual uint Version() const = 0;
|
||||
virtual uint Version() const = 0;
|
||||
|
||||
bool IsCancelled() const;
|
||||
bool IsCancelled() const;
|
||||
|
||||
private:
|
||||
static Result LoadWithSerializerVersion(uint version, Project *project, QXmlStreamReader *reader, LoadType load_type);
|
||||
|
||||
static QVector<ProjectSerializer*> instances_;
|
||||
static Result LoadWithSerializerVersion(uint version, Project *project,
|
||||
QXmlStreamReader *reader,
|
||||
LoadType load_type);
|
||||
|
||||
static QVector<ProjectSerializer *> instances_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -20,11 +20,14 @@
|
||||
|
||||
#include "serializer190219.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
ProjectSerializer::LoadData ProjectSerializer190219::Load(Project *project, QXmlStreamReader *reader, LoadType load_type, void *reserved) const
|
||||
namespace olive
|
||||
{
|
||||
return LoadData();
|
||||
|
||||
ProjectSerializer::LoadData
|
||||
ProjectSerializer190219::Load(Project *project, QXmlStreamReader *reader,
|
||||
LoadType load_type, void *reserved) const
|
||||
{
|
||||
return LoadData();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,21 +23,21 @@
|
||||
|
||||
#include "serializer.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class ProjectSerializer190219 : public ProjectSerializer
|
||||
namespace olive
|
||||
{
|
||||
|
||||
class ProjectSerializer190219 : public ProjectSerializer {
|
||||
public:
|
||||
ProjectSerializer190219() = default;
|
||||
ProjectSerializer190219() = default;
|
||||
|
||||
protected:
|
||||
virtual LoadData Load(Project *project, QXmlStreamReader *reader, LoadType load_type, void *reserved) const override;
|
||||
|
||||
virtual uint Version() const override
|
||||
{
|
||||
return 190219;
|
||||
}
|
||||
virtual LoadData Load(Project *project, QXmlStreamReader *reader,
|
||||
LoadType load_type, void *reserved) const override;
|
||||
|
||||
virtual uint Version() const override
|
||||
{
|
||||
return 190219;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,73 +23,81 @@
|
||||
|
||||
#include "serializer.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class ProjectSerializer210528 : public ProjectSerializer
|
||||
namespace olive
|
||||
{
|
||||
|
||||
class ProjectSerializer210528 : public ProjectSerializer {
|
||||
public:
|
||||
ProjectSerializer210528() = default;
|
||||
ProjectSerializer210528() = default;
|
||||
|
||||
protected:
|
||||
virtual LoadData Load(Project *project, QXmlStreamReader *reader, LoadType load_type, void *reserved) const override;
|
||||
virtual LoadData Load(Project *project, QXmlStreamReader *reader,
|
||||
LoadType load_type, void *reserved) const override;
|
||||
|
||||
virtual uint Version() const override
|
||||
{
|
||||
return 210528;
|
||||
}
|
||||
virtual uint Version() const override
|
||||
{
|
||||
return 210528;
|
||||
}
|
||||
|
||||
private:
|
||||
struct XMLNodeData {
|
||||
struct SerializedConnection {
|
||||
NodeInput input;
|
||||
quintptr output_node;
|
||||
QString output_param;
|
||||
};
|
||||
struct XMLNodeData {
|
||||
struct SerializedConnection {
|
||||
NodeInput input;
|
||||
quintptr output_node;
|
||||
QString output_param;
|
||||
};
|
||||
|
||||
struct BlockLink {
|
||||
Node* block;
|
||||
quintptr link;
|
||||
};
|
||||
struct BlockLink {
|
||||
Node *block;
|
||||
quintptr link;
|
||||
};
|
||||
|
||||
struct GroupLink {
|
||||
NodeGroup *group;
|
||||
quintptr input_node;
|
||||
QString input_id;
|
||||
int input_element;
|
||||
};
|
||||
struct GroupLink {
|
||||
NodeGroup *group;
|
||||
quintptr input_node;
|
||||
QString input_id;
|
||||
int input_element;
|
||||
};
|
||||
|
||||
QHash<quintptr, Node*> node_ptrs;
|
||||
QList<SerializedConnection> desired_connections;
|
||||
QList<BlockLink> block_links;
|
||||
QVector<GroupLink> group_input_links;
|
||||
QHash<NodeGroup*, quintptr> group_output_links;
|
||||
QHash<quintptr, Node *> node_ptrs;
|
||||
QList<SerializedConnection> desired_connections;
|
||||
QList<BlockLink> block_links;
|
||||
QVector<GroupLink> group_input_links;
|
||||
QHash<NodeGroup *, quintptr> group_output_links;
|
||||
};
|
||||
|
||||
};
|
||||
void LoadNode(Node *node, XMLNodeData &xml_node_data,
|
||||
QXmlStreamReader *reader) const;
|
||||
|
||||
void LoadNode(Node *node, XMLNodeData &xml_node_data, QXmlStreamReader *reader) const;
|
||||
void LoadColorManager(QXmlStreamReader *reader, Project *project) const;
|
||||
|
||||
void LoadColorManager(QXmlStreamReader* reader, Project *project) const;
|
||||
void LoadProjectSettings(QXmlStreamReader *reader, Project *project) const;
|
||||
|
||||
void LoadProjectSettings(QXmlStreamReader* reader, Project *project) const;
|
||||
void LoadInput(Node *node, QXmlStreamReader *reader,
|
||||
XMLNodeData &xml_node_data) const;
|
||||
|
||||
void LoadInput(Node *node, QXmlStreamReader* reader, XMLNodeData &xml_node_data) const;
|
||||
void LoadImmediate(QXmlStreamReader *reader, Node *node,
|
||||
const QString &input, int element,
|
||||
XMLNodeData &xml_node_data) const;
|
||||
|
||||
void LoadImmediate(QXmlStreamReader *reader, Node *node, const QString& input, int element, XMLNodeData& xml_node_data) const;
|
||||
bool LoadPosition(QXmlStreamReader *reader, quintptr *node_ptr,
|
||||
Node::Position *pos) const;
|
||||
|
||||
bool LoadPosition(QXmlStreamReader *reader, quintptr *node_ptr, Node::Position *pos) const;
|
||||
void PostConnect(const XMLNodeData &xml_node_data) const;
|
||||
|
||||
void PostConnect(const XMLNodeData &xml_node_data) const;
|
||||
void LoadNodeCustom(QXmlStreamReader *reader, Node *node,
|
||||
XMLNodeData &xml_node_data) const;
|
||||
|
||||
void LoadNodeCustom(QXmlStreamReader *reader, Node *node, XMLNodeData &xml_node_data) const;
|
||||
void LoadTimelinePoints(QXmlStreamReader *reader,
|
||||
ViewerOutput *points) const;
|
||||
|
||||
void LoadTimelinePoints(QXmlStreamReader *reader, ViewerOutput *points) const;
|
||||
void LoadWorkArea(QXmlStreamReader *reader,
|
||||
TimelineWorkArea *workarea) const;
|
||||
|
||||
void LoadWorkArea(QXmlStreamReader *reader, TimelineWorkArea *workarea) const;
|
||||
|
||||
void LoadMarkerList(QXmlStreamReader *reader, TimelineMarkerList *markers) const;
|
||||
|
||||
void LoadValueHint(Node::ValueHint *hint, QXmlStreamReader *reader) const;
|
||||
void LoadMarkerList(QXmlStreamReader *reader,
|
||||
TimelineMarkerList *markers) const;
|
||||
|
||||
void LoadValueHint(Node::ValueHint *hint, QXmlStreamReader *reader) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,72 +23,80 @@
|
||||
|
||||
#include "serializer.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class ProjectSerializer210907 : public ProjectSerializer
|
||||
namespace olive
|
||||
{
|
||||
|
||||
class ProjectSerializer210907 : public ProjectSerializer {
|
||||
public:
|
||||
ProjectSerializer210907() = default;
|
||||
ProjectSerializer210907() = default;
|
||||
|
||||
protected:
|
||||
virtual LoadData Load(Project *project, QXmlStreamReader *reader, LoadType load_type, void *reserved) const override;
|
||||
virtual LoadData Load(Project *project, QXmlStreamReader *reader,
|
||||
LoadType load_type, void *reserved) const override;
|
||||
|
||||
virtual uint Version() const override
|
||||
{
|
||||
return 210907;
|
||||
}
|
||||
virtual uint Version() const override
|
||||
{
|
||||
return 210907;
|
||||
}
|
||||
|
||||
private:
|
||||
struct XMLNodeData {
|
||||
struct SerializedConnection {
|
||||
NodeInput input;
|
||||
quintptr output_node;
|
||||
};
|
||||
struct XMLNodeData {
|
||||
struct SerializedConnection {
|
||||
NodeInput input;
|
||||
quintptr output_node;
|
||||
};
|
||||
|
||||
struct BlockLink {
|
||||
Node* block;
|
||||
quintptr link;
|
||||
};
|
||||
struct BlockLink {
|
||||
Node *block;
|
||||
quintptr link;
|
||||
};
|
||||
|
||||
struct GroupLink {
|
||||
NodeGroup *group;
|
||||
quintptr input_node;
|
||||
QString input_id;
|
||||
int input_element;
|
||||
};
|
||||
struct GroupLink {
|
||||
NodeGroup *group;
|
||||
quintptr input_node;
|
||||
QString input_id;
|
||||
int input_element;
|
||||
};
|
||||
|
||||
QHash<quintptr, Node*> node_ptrs;
|
||||
QList<SerializedConnection> desired_connections;
|
||||
QList<BlockLink> block_links;
|
||||
QVector<GroupLink> group_input_links;
|
||||
QHash<NodeGroup*, quintptr> group_output_links;
|
||||
QHash<quintptr, Node *> node_ptrs;
|
||||
QList<SerializedConnection> desired_connections;
|
||||
QList<BlockLink> block_links;
|
||||
QVector<GroupLink> group_input_links;
|
||||
QHash<NodeGroup *, quintptr> group_output_links;
|
||||
};
|
||||
|
||||
};
|
||||
void LoadNode(Node *node, XMLNodeData &xml_node_data,
|
||||
QXmlStreamReader *reader) const;
|
||||
|
||||
void LoadNode(Node *node, XMLNodeData &xml_node_data, QXmlStreamReader *reader) const;
|
||||
void LoadColorManager(QXmlStreamReader *reader, Project *project) const;
|
||||
|
||||
void LoadColorManager(QXmlStreamReader* reader, Project *project) const;
|
||||
void LoadProjectSettings(QXmlStreamReader *reader, Project *project) const;
|
||||
|
||||
void LoadProjectSettings(QXmlStreamReader* reader, Project *project) const;
|
||||
void LoadInput(Node *node, QXmlStreamReader *reader,
|
||||
XMLNodeData &xml_node_data) const;
|
||||
|
||||
void LoadInput(Node *node, QXmlStreamReader* reader, XMLNodeData &xml_node_data) const;
|
||||
void LoadImmediate(QXmlStreamReader *reader, Node *node,
|
||||
const QString &input, int element,
|
||||
XMLNodeData &xml_node_data) const;
|
||||
|
||||
void LoadImmediate(QXmlStreamReader *reader, Node *node, const QString& input, int element, XMLNodeData& xml_node_data) const;
|
||||
bool LoadPosition(QXmlStreamReader *reader, quintptr *node_ptr,
|
||||
Node::Position *pos) const;
|
||||
|
||||
bool LoadPosition(QXmlStreamReader *reader, quintptr *node_ptr, Node::Position *pos) const;
|
||||
void PostConnect(const XMLNodeData &xml_node_data) const;
|
||||
|
||||
void PostConnect(const XMLNodeData &xml_node_data) const;
|
||||
void LoadNodeCustom(QXmlStreamReader *reader, Node *node,
|
||||
XMLNodeData &xml_node_data) const;
|
||||
|
||||
void LoadNodeCustom(QXmlStreamReader *reader, Node *node, XMLNodeData &xml_node_data) const;
|
||||
void LoadTimelinePoints(QXmlStreamReader *reader,
|
||||
ViewerOutput *points) const;
|
||||
|
||||
void LoadTimelinePoints(QXmlStreamReader *reader, ViewerOutput *points) const;
|
||||
void LoadWorkArea(QXmlStreamReader *reader,
|
||||
TimelineWorkArea *workarea) const;
|
||||
|
||||
void LoadWorkArea(QXmlStreamReader *reader, TimelineWorkArea *workarea) const;
|
||||
|
||||
void LoadMarkerList(QXmlStreamReader *reader, TimelineMarkerList *markers) const;
|
||||
|
||||
void LoadValueHint(Node::ValueHint *hint, QXmlStreamReader *reader) const;
|
||||
void LoadMarkerList(QXmlStreamReader *reader,
|
||||
TimelineMarkerList *markers) const;
|
||||
|
||||
void LoadValueHint(Node::ValueHint *hint, QXmlStreamReader *reader) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,73 +23,81 @@
|
||||
|
||||
#include "serializer.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class ProjectSerializer211228 : public ProjectSerializer
|
||||
namespace olive
|
||||
{
|
||||
|
||||
class ProjectSerializer211228 : public ProjectSerializer {
|
||||
public:
|
||||
ProjectSerializer211228() = default;
|
||||
ProjectSerializer211228() = default;
|
||||
|
||||
protected:
|
||||
virtual LoadData Load(Project *project, QXmlStreamReader *reader, LoadType load_type, void *reserved) const override;
|
||||
virtual LoadData Load(Project *project, QXmlStreamReader *reader,
|
||||
LoadType load_type, void *reserved) const override;
|
||||
|
||||
virtual uint Version() const override
|
||||
{
|
||||
return 211228;
|
||||
}
|
||||
virtual uint Version() const override
|
||||
{
|
||||
return 211228;
|
||||
}
|
||||
|
||||
private:
|
||||
struct XMLNodeData {
|
||||
struct SerializedConnection {
|
||||
NodeInput input;
|
||||
quintptr output_node;
|
||||
};
|
||||
struct XMLNodeData {
|
||||
struct SerializedConnection {
|
||||
NodeInput input;
|
||||
quintptr output_node;
|
||||
};
|
||||
|
||||
struct BlockLink {
|
||||
Node* block;
|
||||
quintptr link;
|
||||
};
|
||||
struct BlockLink {
|
||||
Node *block;
|
||||
quintptr link;
|
||||
};
|
||||
|
||||
struct GroupLink {
|
||||
NodeGroup *group;
|
||||
quintptr input_node;
|
||||
QString input_id;
|
||||
int input_element;
|
||||
};
|
||||
struct GroupLink {
|
||||
NodeGroup *group;
|
||||
quintptr input_node;
|
||||
QString input_id;
|
||||
int input_element;
|
||||
};
|
||||
|
||||
QHash<quintptr, Node*> node_ptrs;
|
||||
QList<SerializedConnection> desired_connections;
|
||||
QList<BlockLink> block_links;
|
||||
QVector<GroupLink> group_input_links;
|
||||
QHash<NodeGroup*, quintptr> group_output_links;
|
||||
QHash<Node*, QUuid> node_uuids;
|
||||
QHash<quintptr, Node *> node_ptrs;
|
||||
QList<SerializedConnection> desired_connections;
|
||||
QList<BlockLink> block_links;
|
||||
QVector<GroupLink> group_input_links;
|
||||
QHash<NodeGroup *, quintptr> group_output_links;
|
||||
QHash<Node *, QUuid> node_uuids;
|
||||
};
|
||||
|
||||
};
|
||||
void LoadNode(Node *node, XMLNodeData &xml_node_data,
|
||||
QXmlStreamReader *reader) const;
|
||||
|
||||
void LoadNode(Node *node, XMLNodeData &xml_node_data, QXmlStreamReader *reader) const;
|
||||
void LoadColorManager(QXmlStreamReader *reader, Project *project) const;
|
||||
|
||||
void LoadColorManager(QXmlStreamReader* reader, Project *project) const;
|
||||
void LoadProjectSettings(QXmlStreamReader *reader, Project *project) const;
|
||||
|
||||
void LoadProjectSettings(QXmlStreamReader* reader, Project *project) const;
|
||||
void LoadInput(Node *node, QXmlStreamReader *reader,
|
||||
XMLNodeData &xml_node_data) const;
|
||||
|
||||
void LoadInput(Node *node, QXmlStreamReader* reader, XMLNodeData &xml_node_data) const;
|
||||
void LoadImmediate(QXmlStreamReader *reader, Node *node,
|
||||
const QString &input, int element,
|
||||
XMLNodeData &xml_node_data) const;
|
||||
|
||||
void LoadImmediate(QXmlStreamReader *reader, Node *node, const QString& input, int element, XMLNodeData& xml_node_data) const;
|
||||
bool LoadPosition(QXmlStreamReader *reader, quintptr *node_ptr,
|
||||
Node::Position *pos) const;
|
||||
|
||||
bool LoadPosition(QXmlStreamReader *reader, quintptr *node_ptr, Node::Position *pos) const;
|
||||
void PostConnect(const XMLNodeData &xml_node_data) const;
|
||||
|
||||
void PostConnect(const XMLNodeData &xml_node_data) const;
|
||||
void LoadNodeCustom(QXmlStreamReader *reader, Node *node,
|
||||
XMLNodeData &xml_node_data) const;
|
||||
|
||||
void LoadNodeCustom(QXmlStreamReader *reader, Node *node, XMLNodeData &xml_node_data) const;
|
||||
void LoadTimelinePoints(QXmlStreamReader *reader,
|
||||
ViewerOutput *points) const;
|
||||
|
||||
void LoadTimelinePoints(QXmlStreamReader *reader, ViewerOutput *points) const;
|
||||
void LoadWorkArea(QXmlStreamReader *reader,
|
||||
TimelineWorkArea *workarea) const;
|
||||
|
||||
void LoadWorkArea(QXmlStreamReader *reader, TimelineWorkArea *workarea) const;
|
||||
|
||||
void LoadMarkerList(QXmlStreamReader *reader, TimelineMarkerList *markers) const;
|
||||
|
||||
void LoadValueHint(Node::ValueHint *hint, QXmlStreamReader *reader) const;
|
||||
void LoadMarkerList(QXmlStreamReader *reader,
|
||||
TimelineMarkerList *markers) const;
|
||||
|
||||
void LoadValueHint(Node::ValueHint *hint, QXmlStreamReader *reader) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,83 +23,92 @@
|
||||
|
||||
#include "serializer.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class ProjectSerializer220403 : public ProjectSerializer
|
||||
namespace olive
|
||||
{
|
||||
|
||||
class ProjectSerializer220403 : public ProjectSerializer {
|
||||
public:
|
||||
ProjectSerializer220403() = default;
|
||||
ProjectSerializer220403() = default;
|
||||
|
||||
protected:
|
||||
virtual LoadData Load(Project *project, QXmlStreamReader *reader, LoadType load_type, void *reserved) const override;
|
||||
virtual LoadData Load(Project *project, QXmlStreamReader *reader,
|
||||
LoadType load_type, void *reserved) const override;
|
||||
|
||||
virtual uint Version() const override
|
||||
{
|
||||
return 220403;
|
||||
}
|
||||
virtual uint Version() const override
|
||||
{
|
||||
return 220403;
|
||||
}
|
||||
|
||||
private:
|
||||
struct XMLNodeData {
|
||||
struct SerializedConnection {
|
||||
NodeInput input;
|
||||
quintptr output_node;
|
||||
};
|
||||
struct XMLNodeData {
|
||||
struct SerializedConnection {
|
||||
NodeInput input;
|
||||
quintptr output_node;
|
||||
};
|
||||
|
||||
struct BlockLink {
|
||||
Node* block;
|
||||
quintptr link;
|
||||
};
|
||||
struct BlockLink {
|
||||
Node *block;
|
||||
quintptr link;
|
||||
};
|
||||
|
||||
struct GroupLink {
|
||||
NodeGroup *group;
|
||||
QString passthrough_id;
|
||||
quintptr input_node;
|
||||
QString input_id;
|
||||
int input_element;
|
||||
QString custom_name;
|
||||
InputFlags custom_flags;
|
||||
NodeValue::Type data_type;
|
||||
QVariant default_val;
|
||||
QHash<QString, QVariant> custom_properties;
|
||||
};
|
||||
struct GroupLink {
|
||||
NodeGroup *group;
|
||||
QString passthrough_id;
|
||||
quintptr input_node;
|
||||
QString input_id;
|
||||
int input_element;
|
||||
QString custom_name;
|
||||
InputFlags custom_flags;
|
||||
NodeValue::Type data_type;
|
||||
QVariant default_val;
|
||||
QHash<QString, QVariant> custom_properties;
|
||||
};
|
||||
|
||||
QHash<quintptr, Node*> node_ptrs;
|
||||
QList<SerializedConnection> desired_connections;
|
||||
QList<BlockLink> block_links;
|
||||
QVector<GroupLink> group_input_links;
|
||||
QHash<NodeGroup*, quintptr> group_output_links;
|
||||
QHash<Node*, QUuid> node_uuids;
|
||||
QHash<quintptr, Node *> node_ptrs;
|
||||
QList<SerializedConnection> desired_connections;
|
||||
QList<BlockLink> block_links;
|
||||
QVector<GroupLink> group_input_links;
|
||||
QHash<NodeGroup *, quintptr> group_output_links;
|
||||
QHash<Node *, QUuid> node_uuids;
|
||||
};
|
||||
|
||||
};
|
||||
void LoadNode(Node *node, XMLNodeData &xml_node_data,
|
||||
QXmlStreamReader *reader) const;
|
||||
|
||||
void LoadNode(Node *node, XMLNodeData &xml_node_data, QXmlStreamReader *reader) const;
|
||||
void LoadColorManager(QXmlStreamReader *reader, Project *project) const;
|
||||
|
||||
void LoadColorManager(QXmlStreamReader* reader, Project *project) const;
|
||||
void LoadProjectSettings(QXmlStreamReader *reader, Project *project) const;
|
||||
|
||||
void LoadProjectSettings(QXmlStreamReader* reader, Project *project) const;
|
||||
void LoadInput(Node *node, QXmlStreamReader *reader,
|
||||
XMLNodeData &xml_node_data) const;
|
||||
|
||||
void LoadInput(Node *node, QXmlStreamReader* reader, XMLNodeData &xml_node_data) const;
|
||||
void LoadImmediate(QXmlStreamReader *reader, Node *node,
|
||||
const QString &input, int element,
|
||||
XMLNodeData &xml_node_data) const;
|
||||
|
||||
void LoadImmediate(QXmlStreamReader *reader, Node *node, const QString& input, int element, XMLNodeData& xml_node_data) const;
|
||||
void LoadKeyframe(QXmlStreamReader *reader, NodeKeyframe *key,
|
||||
NodeValue::Type data_type) const;
|
||||
|
||||
void LoadKeyframe(QXmlStreamReader *reader, NodeKeyframe *key, NodeValue::Type data_type) const;
|
||||
bool LoadPosition(QXmlStreamReader *reader, quintptr *node_ptr,
|
||||
Node::Position *pos) const;
|
||||
|
||||
bool LoadPosition(QXmlStreamReader *reader, quintptr *node_ptr, Node::Position *pos) const;
|
||||
void PostConnect(const XMLNodeData &xml_node_data) const;
|
||||
|
||||
void PostConnect(const XMLNodeData &xml_node_data) const;
|
||||
void LoadNodeCustom(QXmlStreamReader *reader, Node *node,
|
||||
XMLNodeData &xml_node_data) const;
|
||||
|
||||
void LoadNodeCustom(QXmlStreamReader *reader, Node *node, XMLNodeData &xml_node_data) const;
|
||||
void LoadTimelinePoints(QXmlStreamReader *reader,
|
||||
ViewerOutput *viewer) const;
|
||||
|
||||
void LoadTimelinePoints(QXmlStreamReader *reader, ViewerOutput *viewer) const;
|
||||
void LoadMarker(QXmlStreamReader *reader, TimelineMarker *marker) const;
|
||||
|
||||
void LoadMarker(QXmlStreamReader *reader, TimelineMarker *marker) const;
|
||||
void LoadWorkArea(QXmlStreamReader *reader,
|
||||
TimelineWorkArea *workarea) const;
|
||||
|
||||
void LoadWorkArea(QXmlStreamReader *reader, TimelineWorkArea *workarea) const;
|
||||
|
||||
void LoadMarkerList(QXmlStreamReader *reader, TimelineMarkerList *markers) const;
|
||||
|
||||
void LoadValueHint(Node::ValueHint *hint, QXmlStreamReader *reader) const;
|
||||
void LoadMarkerList(QXmlStreamReader *reader,
|
||||
TimelineMarkerList *markers) const;
|
||||
|
||||
void LoadValueHint(Node::ValueHint *hint, QXmlStreamReader *reader) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -26,459 +26,527 @@
|
||||
#include "node/group/group.h"
|
||||
#include "node/serializeddata.h"
|
||||
#include <QtCore>
|
||||
namespace olive {
|
||||
|
||||
ProjectSerializer230220::LoadData ProjectSerializer230220::Load(Project *project, QXmlStreamReader *reader, LoadType load_type, void *reserved) const
|
||||
namespace olive
|
||||
{
|
||||
QMap<quintptr, QMap<QString, QString> > properties;
|
||||
QMap<quintptr, QMap<quintptr, Node::Position> > positions;
|
||||
LoadData load_data;
|
||||
SerializedData project_data;
|
||||
|
||||
switch (load_type) {
|
||||
case kProject:
|
||||
{
|
||||
if (reader->name() == QStringLiteral("project")) {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("project")) {
|
||||
project_data = project->Load(reader);
|
||||
} else if (reader->name() == QStringLiteral("layout")) {
|
||||
load_data.layout = MainWindowLayoutInfo::fromXml(reader, project_data.node_ptrs);
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
PostConnect(project->nodes(), &project_data);
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kOnlyMarkers:
|
||||
{
|
||||
if (reader->name() == QStringLiteral("markers")) {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("marker")) {
|
||||
TimelineMarker *marker = new TimelineMarker();
|
||||
marker->load(reader);
|
||||
load_data.markers.push_back(marker);
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kOnlyKeyframes:
|
||||
{
|
||||
if (reader->name() == QStringLiteral("keyframes")) {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
QString node_id;
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("id")) {
|
||||
node_id = attr.value().toString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Node *n = nullptr;
|
||||
if (!node_id.isEmpty()) {
|
||||
n = NodeFactory::CreateFromID(node_id);
|
||||
}
|
||||
|
||||
if (!n) {
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("input")) {
|
||||
QString input_id;
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("id")) {
|
||||
input_id = attr.value().toString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (input_id.isEmpty()) {
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("element")) {
|
||||
QString element_id;
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("id")) {
|
||||
element_id = attr.value().toString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (element_id.isEmpty()) {
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("track")) {
|
||||
QString track_id;
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("id")) {
|
||||
track_id = attr.value().toString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (track_id.isEmpty()) {
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("key")) {
|
||||
NodeKeyframe *key = new NodeKeyframe();
|
||||
key->set_input(input_id);
|
||||
key->set_element(element_id.toInt());
|
||||
key->set_track(track_id.toInt());
|
||||
|
||||
key->load(reader, n->GetInputDataType(input_id));
|
||||
|
||||
load_data.keyframes[node_id].append(key);
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete n;
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kOnlyClips:
|
||||
case kOnlyNodes:
|
||||
{
|
||||
if ((load_type == kOnlyNodes && reader->name() == QStringLiteral("nodes")) || (load_type == kOnlyClips && reader->name() == QStringLiteral("timeline"))) {
|
||||
QMap<quintptr, Node*> skipped_items;
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
QString id;
|
||||
quintptr ptr = 0;
|
||||
QVector<quintptr> items;
|
||||
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("id")) {
|
||||
id = attr.value().toString();
|
||||
} else if (attr.name() == QStringLiteral("ptr")) {
|
||||
ptr = attr.value().toULongLong();
|
||||
} else if (attr.name() == QStringLiteral("items")) {
|
||||
QVector<QStringView> l = attr.value().split(',');
|
||||
items.reserve(l.size());
|
||||
for (const QStringView &s : l) {
|
||||
items.append(s.toULongLong());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (id.isEmpty()) {
|
||||
qWarning() << "Failed to load node with empty ID";
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
bool dependency_of_item = false;
|
||||
|
||||
if (project && !items.empty()) {
|
||||
for (quintptr p : items) {
|
||||
if (project->nodes().contains(reinterpret_cast<Node*>(p))) {
|
||||
dependency_of_item = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dependency_of_item) {
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
Node* node = NodeFactory::CreateFromID(id);
|
||||
if (!node) {
|
||||
qWarning() << "Failed to find node with ID" << id;
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
if (project && node->IsItem() && ptr) {
|
||||
// If we're pasting an object into the same project, we should re-use the item
|
||||
// rather than duplicate.
|
||||
Node *existing = reinterpret_cast<Node *>(ptr);
|
||||
if (project->nodes().contains(existing)) {
|
||||
// Connect this
|
||||
skipped_items.insert(ptr, existing);
|
||||
|
||||
// Don't continue loading this
|
||||
delete node;
|
||||
node = nullptr;
|
||||
|
||||
// Skip element
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
if (node) {
|
||||
// Disable cache while node is being loaded (we'll re-enable it later)
|
||||
node->SetCachesEnabled(false);
|
||||
node->Load(reader, &project_data);
|
||||
load_data.nodes.append(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (reader->name() == QStringLiteral("properties")) {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
quintptr ptr = 0;
|
||||
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("ptr")) {
|
||||
ptr = attr.value().toULongLong();
|
||||
|
||||
// Only attribute we're looking for right now
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr) {
|
||||
QMap<QString, QString> properties_for_node;
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
properties_for_node.insert(reader->name().toString(), reader->readElementText());
|
||||
}
|
||||
properties.insert(ptr, properties_for_node);
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
if (!skipped_items.empty()) {
|
||||
for (auto it = project_data.desired_connections.begin(); it != project_data.desired_connections.end(); ) {
|
||||
const SerializedData::SerializedConnection &sc = *it;
|
||||
|
||||
if (Node *si = skipped_items.value(sc.output_node)) {
|
||||
// Convert this to a promised connection
|
||||
Node::OutputConnection oc = {si, sc.input};
|
||||
load_data.promised_connections.push_back(oc);
|
||||
it = project_data.desired_connections.erase(it);
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve serialized properties (if any)
|
||||
for (auto it=properties.cbegin(); it!=properties.cend(); it++) {
|
||||
Node *node = project_data.node_ptrs.value(it.key());
|
||||
if (node) {
|
||||
load_data.properties.insert(node, it.value());
|
||||
}
|
||||
}
|
||||
|
||||
PostConnect(load_data.nodes, &project_data);
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return load_data;
|
||||
}
|
||||
|
||||
void WriteNodeMap(QXmlStreamWriter *writer, Node *node, const QVector<Node*> &nodes)
|
||||
ProjectSerializer230220::LoadData
|
||||
ProjectSerializer230220::Load(Project *project, QXmlStreamReader *reader,
|
||||
LoadType load_type, void *reserved) const
|
||||
{
|
||||
writer->writeStartElement(QStringLiteral("node"));
|
||||
QMap<quintptr, QMap<QString, QString>> properties;
|
||||
QMap<quintptr, QMap<quintptr, Node::Position>> positions;
|
||||
LoadData load_data;
|
||||
SerializedData project_data;
|
||||
|
||||
writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast<quintptr>(node)));
|
||||
switch (load_type) {
|
||||
case kProject: {
|
||||
if (reader->name() == QStringLiteral("project")) {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("project")) {
|
||||
project_data = project->Load(reader);
|
||||
} else if (reader->name() == QStringLiteral("layout")) {
|
||||
load_data.layout = MainWindowLayoutInfo::fromXml(
|
||||
reader, project_data.node_ptrs);
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
for (auto oc : node->output_connections()) {
|
||||
if (nodes.contains(oc.second.node())) {
|
||||
WriteNodeMap(writer, oc.second.node(), nodes);
|
||||
}
|
||||
}
|
||||
PostConnect(project->nodes(), &project_data);
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kOnlyMarkers: {
|
||||
if (reader->name() == QStringLiteral("markers")) {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("marker")) {
|
||||
TimelineMarker *marker = new TimelineMarker();
|
||||
marker->load(reader);
|
||||
load_data.markers.push_back(marker);
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kOnlyKeyframes: {
|
||||
if (reader->name() == QStringLiteral("keyframes")) {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
QString node_id;
|
||||
XMLAttributeLoop(reader, attr)
|
||||
{
|
||||
if (attr.name() == QStringLiteral("id")) {
|
||||
node_id = attr.value().toString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
writer->writeEndElement();
|
||||
Node *n = nullptr;
|
||||
if (!node_id.isEmpty()) {
|
||||
n = NodeFactory::CreateFromID(node_id);
|
||||
}
|
||||
|
||||
if (!n) {
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("input")) {
|
||||
QString input_id;
|
||||
XMLAttributeLoop(reader, attr)
|
||||
{
|
||||
if (attr.name() == QStringLiteral("id")) {
|
||||
input_id = attr.value().toString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (input_id.isEmpty()) {
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() ==
|
||||
QStringLiteral("element")) {
|
||||
QString element_id;
|
||||
XMLAttributeLoop(reader, attr)
|
||||
{
|
||||
if (attr.name() ==
|
||||
QStringLiteral("id")) {
|
||||
element_id =
|
||||
attr.value().toString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (element_id.isEmpty()) {
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
while (XMLReadNextStartElement(
|
||||
reader)) {
|
||||
if (reader->name() ==
|
||||
QStringLiteral(
|
||||
"track")) {
|
||||
QString track_id;
|
||||
XMLAttributeLoop(reader,
|
||||
attr)
|
||||
{
|
||||
if (attr.name() ==
|
||||
QStringLiteral(
|
||||
"id")) {
|
||||
track_id =
|
||||
attr.value()
|
||||
.toString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (track_id.isEmpty()) {
|
||||
reader
|
||||
->skipCurrentElement();
|
||||
} else {
|
||||
while (
|
||||
XMLReadNextStartElement(
|
||||
reader)) {
|
||||
if (reader
|
||||
->name() ==
|
||||
QStringLiteral(
|
||||
"key")) {
|
||||
NodeKeyframe *key =
|
||||
new NodeKeyframe();
|
||||
key->set_input(
|
||||
input_id);
|
||||
key->set_element(
|
||||
element_id
|
||||
.toInt());
|
||||
key->set_track(
|
||||
track_id
|
||||
.toInt());
|
||||
|
||||
key->load(
|
||||
reader,
|
||||
n->GetInputDataType(
|
||||
input_id));
|
||||
|
||||
load_data
|
||||
.keyframes
|
||||
[node_id]
|
||||
.append(
|
||||
key);
|
||||
} else {
|
||||
reader
|
||||
->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader
|
||||
->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete n;
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kOnlyClips:
|
||||
case kOnlyNodes: {
|
||||
if ((load_type == kOnlyNodes &&
|
||||
reader->name() == QStringLiteral("nodes")) ||
|
||||
(load_type == kOnlyClips &&
|
||||
reader->name() == QStringLiteral("timeline"))) {
|
||||
QMap<quintptr, Node *> skipped_items;
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
QString id;
|
||||
quintptr ptr = 0;
|
||||
QVector<quintptr> items;
|
||||
|
||||
XMLAttributeLoop(reader, attr)
|
||||
{
|
||||
if (attr.name() == QStringLiteral("id")) {
|
||||
id = attr.value().toString();
|
||||
} else if (attr.name() == QStringLiteral("ptr")) {
|
||||
ptr = attr.value().toULongLong();
|
||||
} else if (attr.name() == QStringLiteral("items")) {
|
||||
QVector<QStringView> l = attr.value().split(',');
|
||||
items.reserve(l.size());
|
||||
for (const QStringView &s : l) {
|
||||
items.append(s.toULongLong());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (id.isEmpty()) {
|
||||
qWarning() << "Failed to load node with empty ID";
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
bool dependency_of_item = false;
|
||||
|
||||
if (project && !items.empty()) {
|
||||
for (quintptr p : items) {
|
||||
if (project->nodes().contains(
|
||||
reinterpret_cast<Node *>(p))) {
|
||||
dependency_of_item = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dependency_of_item) {
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
Node *node = NodeFactory::CreateFromID(id);
|
||||
if (!node) {
|
||||
qWarning()
|
||||
<< "Failed to find node with ID" << id;
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
if (project && node->IsItem() && ptr) {
|
||||
// If we're pasting an object into the same project, we should re-use the item
|
||||
// rather than duplicate.
|
||||
Node *existing =
|
||||
reinterpret_cast<Node *>(ptr);
|
||||
if (project->nodes().contains(existing)) {
|
||||
// Connect this
|
||||
skipped_items.insert(ptr, existing);
|
||||
|
||||
// Don't continue loading this
|
||||
delete node;
|
||||
node = nullptr;
|
||||
|
||||
// Skip element
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
if (node) {
|
||||
// Disable cache while node is being loaded (we'll re-enable it later)
|
||||
node->SetCachesEnabled(false);
|
||||
node->Load(reader, &project_data);
|
||||
load_data.nodes.append(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (reader->name() == QStringLiteral("properties")) {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
quintptr ptr = 0;
|
||||
|
||||
XMLAttributeLoop(reader, attr)
|
||||
{
|
||||
if (attr.name() == QStringLiteral("ptr")) {
|
||||
ptr = attr.value().toULongLong();
|
||||
|
||||
// Only attribute we're looking for right now
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr) {
|
||||
QMap<QString, QString> properties_for_node;
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
properties_for_node.insert(
|
||||
reader->name().toString(),
|
||||
reader->readElementText());
|
||||
}
|
||||
properties.insert(ptr, properties_for_node);
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
if (!skipped_items.empty()) {
|
||||
for (auto it = project_data.desired_connections.begin();
|
||||
it != project_data.desired_connections.end();) {
|
||||
const SerializedData::SerializedConnection &sc = *it;
|
||||
|
||||
if (Node *si = skipped_items.value(sc.output_node)) {
|
||||
// Convert this to a promised connection
|
||||
Node::OutputConnection oc = { si, sc.input };
|
||||
load_data.promised_connections.push_back(oc);
|
||||
it = project_data.desired_connections.erase(it);
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve serialized properties (if any)
|
||||
for (auto it = properties.cbegin(); it != properties.cend(); it++) {
|
||||
Node *node = project_data.node_ptrs.value(it.key());
|
||||
if (node) {
|
||||
load_data.properties.insert(node, it.value());
|
||||
}
|
||||
}
|
||||
|
||||
PostConnect(load_data.nodes, &project_data);
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return load_data;
|
||||
}
|
||||
|
||||
void ProjectSerializer230220::Save(QXmlStreamWriter *writer, const SaveData &data, void *reserved) const
|
||||
void WriteNodeMap(QXmlStreamWriter *writer, Node *node,
|
||||
const QVector<Node *> &nodes)
|
||||
{
|
||||
if (!data.GetOnlySerializeMarkers().empty()) {
|
||||
writer->writeStartElement(QStringLiteral("markers"));
|
||||
writer->writeStartElement(QStringLiteral("node"));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("version"), QString::number(1));
|
||||
writer->writeAttribute(QStringLiteral("ptr"),
|
||||
QString::number(reinterpret_cast<quintptr>(node)));
|
||||
|
||||
for (auto it=data.GetOnlySerializeMarkers().cbegin(); it!=data.GetOnlySerializeMarkers().cend(); it++) {
|
||||
TimelineMarker *marker = *it;
|
||||
writer->writeStartElement(QStringLiteral("marker"));
|
||||
marker->save(writer);
|
||||
writer->writeEndElement(); // marker
|
||||
}
|
||||
for (auto oc : node->output_connections()) {
|
||||
if (nodes.contains(oc.second.node())) {
|
||||
WriteNodeMap(writer, oc.second.node(), nodes);
|
||||
}
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // markers
|
||||
} else if (!data.GetOnlySerializeKeyframes().empty()) {
|
||||
writer->writeStartElement(QStringLiteral("keyframes"));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("version"), QString::number(1));
|
||||
|
||||
// Organize keyframes into node+input
|
||||
QHash<QString, QHash<QString, QMap<int, QMap<int, QVector<NodeKeyframe*> > > > > organized;
|
||||
|
||||
for (auto it=data.GetOnlySerializeKeyframes().cbegin(); it!=data.GetOnlySerializeKeyframes().cend(); it++) {
|
||||
NodeKeyframe *key = *it;
|
||||
organized[key->parent()->id()][key->input()][key->element()][key->track()].append(key);
|
||||
}
|
||||
|
||||
for (auto it=organized.cbegin(); it!=organized.cend(); it++) {
|
||||
writer->writeStartElement(QStringLiteral("node"));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("id"), it.key());
|
||||
|
||||
for (auto jt=it.value().cbegin(); jt!=it.value().cend(); jt++) {
|
||||
writer->writeStartElement(QStringLiteral("input"));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("id"), jt.key());
|
||||
|
||||
for (auto kt=jt.value().cbegin(); kt!=jt.value().cend(); kt++) {
|
||||
writer->writeStartElement(QStringLiteral("element"));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("id"), QString::number(kt.key()));
|
||||
|
||||
for (auto lt=kt.value().cbegin(); lt!=kt.value().cend(); lt++) {
|
||||
const QVector<NodeKeyframe *> &keys = lt.value();
|
||||
|
||||
writer->writeStartElement(QStringLiteral("track"));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("id"), QString::number(lt.key()));
|
||||
|
||||
for (NodeKeyframe *key : keys) {
|
||||
writer->writeStartElement(QStringLiteral("key"));
|
||||
key->save(writer, key->parent()->GetInputDataType(key->input()));
|
||||
writer->writeEndElement(); // key
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // track
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // element
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // input
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // node;
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // keyframes
|
||||
} else if (!data.GetOnlySerializeNodes().empty()) {
|
||||
if (data.type() == kOnlyClips) {
|
||||
writer->writeStartElement(QStringLiteral("timeline"));
|
||||
} else {
|
||||
writer->writeStartElement(QStringLiteral("nodes"));
|
||||
}
|
||||
|
||||
writer->writeAttribute(QStringLiteral("version"), QString::number(1));
|
||||
|
||||
for (Node *n : data.GetOnlySerializeNodes()) {
|
||||
writer->writeStartElement(QStringLiteral("node"));
|
||||
|
||||
QStringList item_list;
|
||||
for (Node *i : data.GetOnlySerializeNodes()) {
|
||||
if (i->IsItem() && i->InputsFrom(n, true)) {
|
||||
item_list.append(QString::number(reinterpret_cast<quintptr>(i)));
|
||||
}
|
||||
}
|
||||
if (!item_list.empty()) {
|
||||
writer->writeAttribute(QStringLiteral("items"), item_list.join(','));
|
||||
}
|
||||
|
||||
n->Save(writer);
|
||||
writer->writeEndElement(); // node
|
||||
}
|
||||
|
||||
if (!data.GetProperties().empty()) {
|
||||
writer->writeStartElement(QStringLiteral("properties"));
|
||||
for (auto it=data.GetProperties().cbegin(); it!=data.GetProperties().cend(); it++) {
|
||||
writer->writeStartElement(QStringLiteral("node"));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast<quintptr>(it.key())));
|
||||
|
||||
for (auto jt=it.value().cbegin(); jt!=it.value().cend(); jt++) {
|
||||
writer->writeTextElement(jt.key(), jt.value());
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // node
|
||||
}
|
||||
writer->writeEndElement(); // properties
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // nodes
|
||||
} else if (Project *project = data.GetProject()) {
|
||||
writer->writeStartElement(QStringLiteral("project"));
|
||||
|
||||
writer->writeStartElement(QStringLiteral("project"));
|
||||
project->Save(writer);
|
||||
writer->writeEndElement(); // project
|
||||
|
||||
writer->writeStartElement(QStringLiteral("layout"));
|
||||
data.GetLayout().toXml(writer);
|
||||
writer->writeEndElement(); // layout
|
||||
|
||||
writer->writeEndElement(); // project
|
||||
} else {
|
||||
qCritical() << "ProjectSerializer provided nothing to save";
|
||||
}
|
||||
writer->writeEndElement();
|
||||
}
|
||||
|
||||
void ProjectSerializer230220::PostConnect(const QVector<Node *> &nodes, SerializedData *project_data) const
|
||||
void ProjectSerializer230220::Save(QXmlStreamWriter *writer,
|
||||
const SaveData &data, void *reserved) const
|
||||
{
|
||||
foreach (const SerializedData::SerializedConnection& con, project_data->desired_connections) {
|
||||
if (Node *out = project_data->node_ptrs.value(con.output_node)) {
|
||||
Node::ConnectEdge(out, con.input);
|
||||
}
|
||||
}
|
||||
if (!data.GetOnlySerializeMarkers().empty()) {
|
||||
writer->writeStartElement(QStringLiteral("markers"));
|
||||
|
||||
foreach (const SerializedData::BlockLink& l, project_data->block_links) {
|
||||
Node *a = l.block;
|
||||
Node *b = project_data->node_ptrs.value(l.link);
|
||||
writer->writeAttribute(QStringLiteral("version"), QString::number(1));
|
||||
|
||||
Node::Link(a, b);
|
||||
}
|
||||
for (auto it = data.GetOnlySerializeMarkers().cbegin();
|
||||
it != data.GetOnlySerializeMarkers().cend(); it++) {
|
||||
TimelineMarker *marker = *it;
|
||||
writer->writeStartElement(QStringLiteral("marker"));
|
||||
marker->save(writer);
|
||||
writer->writeEndElement(); // marker
|
||||
}
|
||||
|
||||
for (auto it = nodes.cbegin(); it != nodes.cend(); it++){
|
||||
Node *n = *it;
|
||||
writer->writeEndElement(); // markers
|
||||
} else if (!data.GetOnlySerializeKeyframes().empty()) {
|
||||
writer->writeStartElement(QStringLiteral("keyframes"));
|
||||
|
||||
n->PostLoadEvent(project_data);
|
||||
writer->writeAttribute(QStringLiteral("version"), QString::number(1));
|
||||
|
||||
n->SetCachesEnabled(true);
|
||||
}
|
||||
// Organize keyframes into node+input
|
||||
QHash<QString,
|
||||
QHash<QString, QMap<int, QMap<int, QVector<NodeKeyframe *>>>>>
|
||||
organized;
|
||||
|
||||
for (auto it = data.GetOnlySerializeKeyframes().cbegin();
|
||||
it != data.GetOnlySerializeKeyframes().cend(); it++) {
|
||||
NodeKeyframe *key = *it;
|
||||
organized[key->parent()->id()][key->input()][key->element()]
|
||||
[key->track()]
|
||||
.append(key);
|
||||
}
|
||||
|
||||
for (auto it = organized.cbegin(); it != organized.cend(); it++) {
|
||||
writer->writeStartElement(QStringLiteral("node"));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("id"), it.key());
|
||||
|
||||
for (auto jt = it.value().cbegin(); jt != it.value().cend(); jt++) {
|
||||
writer->writeStartElement(QStringLiteral("input"));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("id"), jt.key());
|
||||
|
||||
for (auto kt = jt.value().cbegin(); kt != jt.value().cend();
|
||||
kt++) {
|
||||
writer->writeStartElement(QStringLiteral("element"));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("id"),
|
||||
QString::number(kt.key()));
|
||||
|
||||
for (auto lt = kt.value().cbegin(); lt != kt.value().cend();
|
||||
lt++) {
|
||||
const QVector<NodeKeyframe *> &keys = lt.value();
|
||||
|
||||
writer->writeStartElement(QStringLiteral("track"));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("id"),
|
||||
QString::number(lt.key()));
|
||||
|
||||
for (NodeKeyframe *key : keys) {
|
||||
writer->writeStartElement(QStringLiteral("key"));
|
||||
key->save(writer, key->parent()->GetInputDataType(
|
||||
key->input()));
|
||||
writer->writeEndElement(); // key
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // track
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // element
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // input
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // node;
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // keyframes
|
||||
} else if (!data.GetOnlySerializeNodes().empty()) {
|
||||
if (data.type() == kOnlyClips) {
|
||||
writer->writeStartElement(QStringLiteral("timeline"));
|
||||
} else {
|
||||
writer->writeStartElement(QStringLiteral("nodes"));
|
||||
}
|
||||
|
||||
writer->writeAttribute(QStringLiteral("version"), QString::number(1));
|
||||
|
||||
for (Node *n : data.GetOnlySerializeNodes()) {
|
||||
writer->writeStartElement(QStringLiteral("node"));
|
||||
|
||||
QStringList item_list;
|
||||
for (Node *i : data.GetOnlySerializeNodes()) {
|
||||
if (i->IsItem() && i->InputsFrom(n, true)) {
|
||||
item_list.append(
|
||||
QString::number(reinterpret_cast<quintptr>(i)));
|
||||
}
|
||||
}
|
||||
if (!item_list.empty()) {
|
||||
writer->writeAttribute(QStringLiteral("items"),
|
||||
item_list.join(','));
|
||||
}
|
||||
|
||||
n->Save(writer);
|
||||
writer->writeEndElement(); // node
|
||||
}
|
||||
|
||||
if (!data.GetProperties().empty()) {
|
||||
writer->writeStartElement(QStringLiteral("properties"));
|
||||
for (auto it = data.GetProperties().cbegin();
|
||||
it != data.GetProperties().cend(); it++) {
|
||||
writer->writeStartElement(QStringLiteral("node"));
|
||||
|
||||
writer->writeAttribute(
|
||||
QStringLiteral("ptr"),
|
||||
QString::number(reinterpret_cast<quintptr>(it.key())));
|
||||
|
||||
for (auto jt = it.value().cbegin(); jt != it.value().cend();
|
||||
jt++) {
|
||||
writer->writeTextElement(jt.key(), jt.value());
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // node
|
||||
}
|
||||
writer->writeEndElement(); // properties
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // nodes
|
||||
} else if (Project *project = data.GetProject()) {
|
||||
writer->writeStartElement(QStringLiteral("project"));
|
||||
|
||||
writer->writeStartElement(QStringLiteral("project"));
|
||||
project->Save(writer);
|
||||
writer->writeEndElement(); // project
|
||||
|
||||
writer->writeStartElement(QStringLiteral("layout"));
|
||||
data.GetLayout().toXml(writer);
|
||||
writer->writeEndElement(); // layout
|
||||
|
||||
writer->writeEndElement(); // project
|
||||
} else {
|
||||
qCritical() << "ProjectSerializer provided nothing to save";
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectSerializer230220::PostConnect(const QVector<Node *> &nodes,
|
||||
SerializedData *project_data) const
|
||||
{
|
||||
foreach (const SerializedData::SerializedConnection &con,
|
||||
project_data->desired_connections) {
|
||||
if (Node *out = project_data->node_ptrs.value(con.output_node)) {
|
||||
Node::ConnectEdge(out, con.input);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (const SerializedData::BlockLink &l, project_data->block_links) {
|
||||
Node *a = l.block;
|
||||
Node *b = project_data->node_ptrs.value(l.link);
|
||||
|
||||
Node::Link(a, b);
|
||||
}
|
||||
|
||||
for (auto it = nodes.cbegin(); it != nodes.cend(); it++) {
|
||||
Node *n = *it;
|
||||
|
||||
n->PostLoadEvent(project_data);
|
||||
|
||||
n->SetCachesEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -23,26 +23,28 @@
|
||||
|
||||
#include "serializer.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class ProjectSerializer230220 : public ProjectSerializer
|
||||
namespace olive
|
||||
{
|
||||
|
||||
class ProjectSerializer230220 : public ProjectSerializer {
|
||||
public:
|
||||
ProjectSerializer230220() = default;
|
||||
ProjectSerializer230220() = default;
|
||||
|
||||
protected:
|
||||
virtual LoadData Load(Project *project, QXmlStreamReader *reader, LoadType load_type, void *reserved) const override;
|
||||
virtual LoadData Load(Project *project, QXmlStreamReader *reader,
|
||||
LoadType load_type, void *reserved) const override;
|
||||
|
||||
virtual void Save(QXmlStreamWriter *writer, const SaveData &data, void *reserved) const override;
|
||||
virtual void Save(QXmlStreamWriter *writer, const SaveData &data,
|
||||
void *reserved) const override;
|
||||
|
||||
virtual uint Version() const override
|
||||
{
|
||||
return 230220;
|
||||
}
|
||||
virtual uint Version() const override
|
||||
{
|
||||
return 230220;
|
||||
}
|
||||
|
||||
private:
|
||||
void PostConnect(const QVector<Node*> &nodes, SerializedData *project_data) const;
|
||||
|
||||
void PostConnect(const QVector<Node *> &nodes,
|
||||
SerializedData *project_data) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -20,44 +20,55 @@
|
||||
|
||||
#include "typeserializer.h"
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
AudioParams TypeSerializer::LoadAudioParams(QXmlStreamReader *reader)
|
||||
{
|
||||
AudioParams a;
|
||||
AudioParams a;
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("samplerate")) {
|
||||
a.set_sample_rate(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("channellayout")) {
|
||||
a.set_channel_layout(reader->readElementText().toULongLong());
|
||||
} else if (reader->name() == QStringLiteral("format")) {
|
||||
a.set_format(SampleFormat::from_string(reader->readElementText().toStdString()));
|
||||
} else if (reader->name() == QStringLiteral("enabled")) {
|
||||
a.set_enabled(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("streamindex")) {
|
||||
a.set_stream_index(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("duration")) {
|
||||
a.set_duration(reader->readElementText().toLongLong());
|
||||
} else if (reader->name() == QStringLiteral("timebase")) {
|
||||
a.set_time_base(rational::fromString(reader->readElementText().toStdString()));
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("samplerate")) {
|
||||
a.set_sample_rate(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("channellayout")) {
|
||||
a.set_channel_layout(reader->readElementText().toULongLong());
|
||||
} else if (reader->name() == QStringLiteral("format")) {
|
||||
a.set_format(SampleFormat::from_string(
|
||||
reader->readElementText().toStdString()));
|
||||
} else if (reader->name() == QStringLiteral("enabled")) {
|
||||
a.set_enabled(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("streamindex")) {
|
||||
a.set_stream_index(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("duration")) {
|
||||
a.set_duration(reader->readElementText().toLongLong());
|
||||
} else if (reader->name() == QStringLiteral("timebase")) {
|
||||
a.set_time_base(
|
||||
rational::fromString(reader->readElementText().toStdString()));
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
return a;
|
||||
return a;
|
||||
}
|
||||
|
||||
void TypeSerializer::SaveAudioParams(QXmlStreamWriter *writer, const AudioParams &a)
|
||||
void TypeSerializer::SaveAudioParams(QXmlStreamWriter *writer,
|
||||
const AudioParams &a)
|
||||
{
|
||||
writer->writeTextElement(QStringLiteral("samplerate"), QString::number(a.sample_rate()));
|
||||
writer->writeTextElement(QStringLiteral("channellayout"), QString::number(a.channel_layout().u.mask));
|
||||
writer->writeTextElement(QStringLiteral("format"), QString::fromStdString(a.format().to_string()));
|
||||
writer->writeTextElement(QStringLiteral("enabled"), QString::number(a.enabled()));
|
||||
writer->writeTextElement(QStringLiteral("streamindex"), QString::number(a.stream_index()));
|
||||
writer->writeTextElement(QStringLiteral("duration"), QString::number(a.duration()));
|
||||
writer->writeTextElement(QStringLiteral("timebase"), QString::fromStdString(a.time_base().toString()));
|
||||
writer->writeTextElement(QStringLiteral("samplerate"),
|
||||
QString::number(a.sample_rate()));
|
||||
writer->writeTextElement(QStringLiteral("channellayout"),
|
||||
QString::number(a.channel_layout().u.mask));
|
||||
writer->writeTextElement(QStringLiteral("format"),
|
||||
QString::fromStdString(a.format().to_string()));
|
||||
writer->writeTextElement(QStringLiteral("enabled"),
|
||||
QString::number(a.enabled()));
|
||||
writer->writeTextElement(QStringLiteral("streamindex"),
|
||||
QString::number(a.stream_index()));
|
||||
writer->writeTextElement(QStringLiteral("duration"),
|
||||
QString::number(a.duration()));
|
||||
writer->writeTextElement(QStringLiteral("timebase"),
|
||||
QString::fromStdString(a.time_base().toString()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,18 +27,17 @@
|
||||
|
||||
#include "common/xmlutils.h"
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
using namespace core;
|
||||
|
||||
class TypeSerializer
|
||||
{
|
||||
class TypeSerializer {
|
||||
public:
|
||||
TypeSerializer() = default;
|
||||
|
||||
static AudioParams LoadAudioParams(QXmlStreamReader *reader);
|
||||
static void SaveAudioParams(QXmlStreamWriter *writer, const AudioParams &a);
|
||||
TypeSerializer() = default;
|
||||
|
||||
static AudioParams LoadAudioParams(QXmlStreamReader *reader);
|
||||
static void SaveAudioParams(QXmlStreamWriter *writer, const AudioParams &a);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user