refactored copy/paste code for new serializers

Vastly improves code quality and reusability
This commit is contained in:
itsmattkc
2022-01-12 16:34:40 -08:00
parent 4ecce20c35
commit 576ea8e81f
18 changed files with 346 additions and 269 deletions
+14
View File
@@ -83,6 +83,20 @@ void NodeGraph::childEvent(QChildEvent *event)
emit NodeAdded(node);
emit node->AddedToGraph(this);
// Emit input connections
for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) {
if (nodes().contains(it->second)) {
emit InputConnected(it->second, it->first);
}
}
// Emit output connections
for (auto it=node->output_connections().cbegin(); it!=node->output_connections().cend(); it++) {
if (nodes().contains(it->second.node())) {
emit InputConnected(it->first, it->second);
}
}
} else if (event->type() == QEvent::ChildRemoved) {
node_children_.removeOne(node);
+17 -20
View File
@@ -24,7 +24,6 @@
#include "core.h"
#include "node/factory.h"
#include "node/project/serializer/serializer.h"
#include "widget/nodeview/nodeviewundo.h"
#include "window/mainwindow/mainwindow.h"
@@ -48,47 +47,45 @@ void NodeCopyPasteService::CopyNodesToClipboard(QVector<Node *> nodes, void *use
}
}
ProjectSerializer::Save(nodes.first()->project(), &writer, nodes);
ProjectSerializer::SaveData data(nodes.first()->project(), QString(), nodes);
/*writer.writeStartElement(QStringLiteral("custom"));
CopyNodesToClipboardInternal(&writer, nodes, userdata);
writer.writeEndElement(); // custom*/
CopyNodesToClipboardCallback(nodes, &data, userdata);
ProjectSerializer::Save(&writer, data);
Core::CopyStringToClipboard(copy_str);
}
QVector<Node *> NodeCopyPasteService::PasteNodesFromClipboard(Project *project, MultiUndoCommand* command, void *userdata)
void NodeCopyPasteService::PasteNodesFromClipboard(void *userdata)
{
QVector<Node*> pasted_nodes;
QString clipboard = Core::PasteStringFromClipboard();
if (clipboard.isEmpty()) {
return pasted_nodes;
return;
}
QXmlStreamReader reader(clipboard);
Project temp;
ProjectSerializer::Load(&temp, &reader);
ProjectSerializer::Result res = ProjectSerializer::Load(&temp, &reader);
if (res.code() != ProjectSerializer::kSuccess) {
return;
}
QVector<Node*> pasted_nodes;
foreach (Node *n, temp.nodes()) {
if (!temp.default_nodes().contains(n)) {
// Move nodes out of Project
n->setParent(nullptr);
pasted_nodes.append(n);
}
}
return pasted_nodes;
}
if (pasted_nodes.isEmpty()) {
return;
}
void NodeCopyPasteService::CopyNodesToClipboardInternal(QXmlStreamWriter*, const QVector<Node *> &, void*)
{
}
void NodeCopyPasteService::PasteNodesFromClipboardInternal(QXmlStreamReader* reader, XMLNodeData &xml_node_data, void*)
{
Q_UNUSED(xml_node_data)
reader->skipCurrentElement();
PasteNodesToClipboardCallback(pasted_nodes, res.GetLoadData(), userdata);
}
}
+5 -3
View File
@@ -25,7 +25,9 @@
#include <QUndoCommand>
#include "node/node.h"
#include "node/project/project.h"
#include "node/project/sequence/sequence.h"
#include "node/project/serializer/serializer.h"
namespace olive {
@@ -37,11 +39,11 @@ public:
protected:
void CopyNodesToClipboard(QVector<Node *> nodes, void* userdata = nullptr);
QVector<Node*> PasteNodesFromClipboard(Project *project, MultiUndoCommand *command, void* userdata = nullptr);
void PasteNodesFromClipboard(void* userdata = nullptr);
virtual void CopyNodesToClipboardInternal(QXmlStreamWriter *writer, const QVector<Node*> &nodes, void* userdata);
virtual void CopyNodesToClipboardCallback(const QVector<Node*> &nodes, ProjectSerializer::SaveData *data, void *userdata){}
virtual void PasteNodesFromClipboardInternal(QXmlStreamReader *reader, XMLNodeData &xml_node_data, void* userdata);
virtual void PasteNodesToClipboardCallback(const QVector<Node*> &nodes, const ProjectSerializer::LoadData &load_data, void *userdata){}
};
+16 -10
View File
@@ -119,24 +119,30 @@ ProjectSerializer::Result ProjectSerializer::Load(Project *project, QXmlStreamRe
}
if (serializer) {
serializer->Load(project, reader, nullptr);
return kSuccess;
LoadData ld = serializer->Load(project, reader, nullptr);
Result r(kSuccess);
if (reader->hasError()) {
r = Result(kXmlError);
r.SetDetails(reader->errorString());
}
r.SetLoadData(ld);
return r;
} else {
// Reached the end of the list with no serializer, assume too new
return kProjectTooNew;
}
}
ProjectSerializer::Result ProjectSerializer::Save(Project *project, const QString &filename, const QVector<Node *> &only)
ProjectSerializer::Result ProjectSerializer::Save(const SaveData &data)
{
QString temp_save = FileFunctions::GetSafeTemporaryFilename(filename);
QString temp_save = FileFunctions::GetSafeTemporaryFilename(data.GetFilename());
QFile project_file(temp_save);
if (project_file.open(QFile::WriteOnly | QFile::Text)) {
QXmlStreamWriter writer(&project_file);
Result inner_result = Save(project, &writer, filename, only);
Result inner_result = Save(&writer, data);
project_file.close();
@@ -145,7 +151,7 @@ ProjectSerializer::Result ProjectSerializer::Save(Project *project, const QStrin
}
// Save was successful, we can now rewrite the original file
if (FileFunctions::RenameFileAllowOverwrite(temp_save, filename)) {
if (FileFunctions::RenameFileAllowOverwrite(temp_save, data.GetFilename())) {
return kSuccess;
} else {
Result r(kOverwriteError);
@@ -159,7 +165,7 @@ ProjectSerializer::Result ProjectSerializer::Save(Project *project, const QStrin
}
}
ProjectSerializer::Result ProjectSerializer::Save(Project *project, QXmlStreamWriter *writer, const QString &filename, const QVector<Node *> &only)
ProjectSerializer::Result ProjectSerializer::Save(QXmlStreamWriter *writer, const SaveData &data)
{
writer->setAutoFormatting(true);
@@ -175,13 +181,13 @@ ProjectSerializer::Result ProjectSerializer::Save(Project *project, QXmlStreamWr
// Allows easy integer math for checking project versions.
writer->writeTextElement(QStringLiteral("version"), QString::number(serializer->Version()));
if (!filename.isEmpty()) {
writer->writeTextElement("url", filename);
if (!data.GetFilename().isEmpty()) {
writer->writeTextElement("url", data.GetFilename());
}
writer->writeStartElement(QStringLiteral("project"));
serializer->Save(project, writer, only, nullptr);
serializer->Save(writer, data, nullptr);
writer->writeEndElement(); // project
+66 -22
View File
@@ -39,7 +39,7 @@ class ProjectSerializer
public:
ProjectSerializer() = default;
virtual ~ProjectSerializer(){};
virtual ~ProjectSerializer(){}
DISABLE_COPY_MOVE(ProjectSerializer)
@@ -50,7 +50,18 @@ public:
kUnknownVersion,
kFileError,
kXmlError,
kOverwriteError,
kOverwriteError
};
using SerializedProperties = QHash<Node*, QMap<QString, QString> >;
class LoadData
{
public:
LoadData() = default;
SerializedProperties properties;
};
class Result
@@ -63,26 +74,63 @@ public:
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_; }
void SetLoadData(const LoadData &p) { load_data_ = p; }
private:
ResultCode code_;
QString details_;
LoadData load_data_;
};
class SaveData
{
public:
SaveData(Project *project, const QString &filename, const QVector<Node*> &only = QVector<Node*>(), const SerializedProperties &p = SerializedProperties())
{
project_ = project;
filename_ = filename;
only_serialize_nodes_ = only;
properties_ = p;
}
Project *GetProject() const
{
return project_;
}
const QString &GetFilename() const
{
return filename_;
}
const QVector<Node*> &GetOnlySerializeNodes() const { return only_serialize_nodes_; }
void SetOnlySerializeNodes(const QVector<Node*> &only) { only_serialize_nodes_ = only; }
const SerializedProperties &GetProperties() const { return properties_; }
void SetProperties(const SerializedProperties &p) { properties_ = p; }
private:
Project *project_;
QString filename_;
QVector<Node*> only_serialize_nodes_;
SerializedProperties properties_;
};
static void Initialize();
@@ -92,17 +140,13 @@ public:
static Result Load(Project *project, const QString &filename);
static Result Load(Project *project, QXmlStreamReader *read_device);
static Result Save(Project *project, const QString &filename, const QVector<Node*> &only = QVector<Node*>());
static Result Save(Project *project, QXmlStreamWriter *write_device, const QString &filename, const QVector<Node*> &only = QVector<Node*>());
static Result Save(Project *project, QXmlStreamWriter *write_device, const QVector<Node*> &only = QVector<Node*>())
{
return Save(project, write_device, QString(), only);
}
static Result Save(const SaveData &data);
static Result Save(QXmlStreamWriter *write_device, const SaveData &data);
protected:
virtual void Load(Project *project, QXmlStreamReader *reader, void *reserved) const = 0;
virtual LoadData Load(Project *project, QXmlStreamReader *reader, void *reserved) const = 0;
virtual void Save(Project *project, QXmlStreamWriter *writer, const QVector<Node*> &only, void *reserved) const {}
virtual void Save(QXmlStreamWriter *writer, const SaveData &data, void *reserved) const {}
virtual uint Version() const = 0;
@@ -22,8 +22,9 @@
namespace olive {
void ProjectSerializer190219::Load(Project *project, QXmlStreamReader *reader, void *reserved) const
ProjectSerializer::LoadData ProjectSerializer190219::Load(Project *project, QXmlStreamReader *reader, void *reserved) const
{
return LoadData();
}
}
@@ -31,7 +31,7 @@ public:
ProjectSerializer190219() = default;
protected:
virtual void Load(Project *project, QXmlStreamReader *reader, void *reserved) const override;
virtual LoadData Load(Project *project, QXmlStreamReader *reader, void *reserved) const override;
virtual uint Version() const override
{
@@ -24,7 +24,7 @@
namespace olive {
void ProjectSerializer210528::Load(Project *project, QXmlStreamReader *reader, void *reserved) const
ProjectSerializer210528::LoadData ProjectSerializer210528::Load(Project *project, QXmlStreamReader *reader, void *reserved) const
{
XMLNodeData xml_node_data;
@@ -161,6 +161,8 @@ void ProjectSerializer210528::Load(Project *project, QXmlStreamReader *reader, v
// Make connections
PostConnect(xml_node_data);
return LoadData();
}
void ProjectSerializer210528::LoadNode(Node *node, XMLNodeData &xml_node_data, QXmlStreamReader *reader) const
@@ -31,7 +31,7 @@ public:
ProjectSerializer210528() = default;
protected:
virtual void Load(Project *project, QXmlStreamReader *reader, void *reserved) const override;
virtual LoadData Load(Project *project, QXmlStreamReader *reader, void *reserved) const override;
virtual uint Version() const override
{
@@ -24,7 +24,7 @@
namespace olive {
void ProjectSerializer210907::Load(Project *project, QXmlStreamReader *reader, void *reserved) const
ProjectSerializer210907::LoadData ProjectSerializer210907::Load(Project *project, QXmlStreamReader *reader, void *reserved) const
{
XMLNodeData xml_node_data;
@@ -161,6 +161,8 @@ void ProjectSerializer210907::Load(Project *project, QXmlStreamReader *reader, v
// Make connections
PostConnect(xml_node_data);
return LoadData();
}
void ProjectSerializer210907::LoadNode(Node *node, XMLNodeData &xml_node_data, QXmlStreamReader *reader) const
@@ -31,7 +31,7 @@ public:
ProjectSerializer210907() = default;
protected:
virtual void Load(Project *project, QXmlStreamReader *reader, void *reserved) const override;
virtual LoadData Load(Project *project, QXmlStreamReader *reader, void *reserved) const override;
virtual uint Version() const override
{
@@ -24,8 +24,10 @@
namespace olive {
void ProjectSerializer211228::Load(Project *project, QXmlStreamReader *reader, void *reserved) const
ProjectSerializer211228::LoadData ProjectSerializer211228::Load(Project *project, QXmlStreamReader *reader, void *reserved) const
{
QMap<quintptr, QMap<QString, QString> > properties;
QMap<quintptr, QMap<quintptr, Node::Position> > positions;
XMLNodeData xml_node_data;
while (XMLReadNextStartElement(reader)) {
@@ -112,22 +114,15 @@ void ProjectSerializer211228::Load(Project *project, QXmlStreamReader *reader, v
}
}
Node *context = xml_node_data.node_ptrs.value(context_ptr);
if (!context) {
qWarning() << "Failed to find pointer for context";
reader->skipCurrentElement();
} else {
if (context_ptr) {
while (XMLReadNextStartElement(reader)) {
if (reader->name() == QStringLiteral("node")) {
quintptr node_ptr;
Node::Position node_pos;
if (LoadPosition(reader, &node_ptr, &node_pos)) {
Node *node = xml_node_data.node_ptrs.value(node_ptr);
if (node) {
context->SetNodePositionInContext(node, node_pos);
if (node_ptr) {
positions[context_ptr].insert(node_ptr, node_pos);
} else {
qWarning() << "Failed to find pointer for node position";
reader->skipCurrentElement();
@@ -137,6 +132,9 @@ void ProjectSerializer211228::Load(Project *project, QXmlStreamReader *reader, v
reader->skipCurrentElement();
}
}
} else {
qWarning() << "Attempted to load context with no pointer";
reader->skipCurrentElement();
}
} else {
@@ -147,6 +145,34 @@ void ProjectSerializer211228::Load(Project *project, QXmlStreamReader *reader, v
}
} 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 {
// Skip this
@@ -159,17 +185,44 @@ void ProjectSerializer211228::Load(Project *project, QXmlStreamReader *reader, v
}
}
// Resolve positions
for (auto it=positions.cbegin(); it!=positions.cend(); it++) {
Node *ctx = xml_node_data.node_ptrs.value(it.key());
if (ctx) {
for (auto jt=it.value().cbegin(); jt!=it.value().cend(); jt++) {
Node *n = xml_node_data.node_ptrs.value(jt.key());
if (n) {
ctx->SetNodePositionInContext(n, jt.value());
}
}
}
}
// Make connections
PostConnect(xml_node_data);
LoadData load_data;
// Resolve serialized properties (if any)
for (auto it=properties.cbegin(); it!=properties.cend(); it++) {
Node *node = xml_node_data.node_ptrs.value(it.key());
if (node) {
load_data.properties.insert(node, it.value());
}
}
return load_data;
}
void ProjectSerializer211228::Save(Project *project, QXmlStreamWriter *writer, const QVector<Node *> &only, void *reserved) const
void ProjectSerializer211228::Save(QXmlStreamWriter *writer, const SaveData &data, void *reserved) const
{
writer->writeTextElement(QStringLiteral("uuid"), project->GetUuid().toString());
Project *project = data.GetProject();
writer->writeTextElement(QStringLiteral("uuid"), data.GetProject()->GetUuid().toString());
writer->writeStartElement(QStringLiteral("nodes"));
const QVector<Node*> &using_node_list = (only.isEmpty()) ? project->nodes() : only;
const QVector<Node*> &using_node_list = (data.GetOnlySerializeNodes().isEmpty()) ? project->nodes() : data.GetOnlySerializeNodes();
foreach (Node* node, using_node_list) {
writer->writeStartElement(QStringLiteral("node"));
@@ -202,7 +255,7 @@ void ProjectSerializer211228::Save(Project *project, QXmlStreamWriter *writer, c
writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast<quintptr>(context)));
for (auto jt=map.cbegin(); jt!=map.cend(); jt++) {
if (only.isEmpty() || only.contains(jt.key())) {
if (data.GetOnlySerializeNodes().isEmpty() || data.GetOnlySerializeNodes().contains(jt.key())) {
writer->writeStartElement(QStringLiteral("node"));
SavePosition(writer, jt.key(), jt.value());
writer->writeEndElement(); // node
@@ -215,6 +268,22 @@ void ProjectSerializer211228::Save(Project *project, QXmlStreamWriter *writer, c
writer->writeEndElement(); // positions
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
// Save main window project layout
project->GetLayoutInfo().toXml(writer);
}
@@ -229,7 +298,9 @@ void ProjectSerializer211228::LoadNode(Node *node, XMLNodeData &xml_node_data, Q
if (reader->name() == QStringLiteral("input")) {
LoadInput(node, reader, xml_node_data);
} else if (reader->name() == QStringLiteral("ptr")) {
xml_node_data.node_ptrs.insert(reader->readElementText().toULongLong(), node);
quintptr ptr = reader->readElementText().toULongLong();
xml_node_data.node_ptrs.insert(ptr, node);
qDebug() << "Inserting" << ptr << "as" << node;
} else if (reader->name() == QStringLiteral("label")) {
node->SetLabel(reader->readElementText());
} else if (reader->name() == QStringLiteral("uuid")) {
@@ -245,9 +316,7 @@ void ProjectSerializer211228::LoadNode(Node *node, XMLNodeData &xml_node_data, Q
}
}
} else if (reader->name() == QStringLiteral("custom")) {
LoadNodeCustom(reader, node, xml_node_data);
} else if (reader->name() == QStringLiteral("connections")) {
// Load connections
while (XMLReadNextStartElement(reader)) {
@@ -307,7 +376,7 @@ void ProjectSerializer211228::LoadNode(Node *node, XMLNodeData &xml_node_data, Q
void ProjectSerializer211228::SaveNode(Node *node, QXmlStreamWriter *writer) const
{
writer->writeTextElement(QStringLiteral("ptr"), QString::number(reinterpret_cast<quintptr>(this)));
writer->writeTextElement(QStringLiteral("ptr"), QString::number(reinterpret_cast<quintptr>(node)));
writer->writeTextElement(QStringLiteral("uuid"), node->GetUUID().toString());
writer->writeTextElement(QStringLiteral("label"), node->GetLabel());
@@ -31,9 +31,9 @@ public:
ProjectSerializer211228() = default;
protected:
virtual void Load(Project *project, QXmlStreamReader *reader, void *reserved) const override;
virtual LoadData Load(Project *project, QXmlStreamReader *reader, void *reserved) const override;
virtual void Save(Project *project, QXmlStreamWriter *writer, const QVector<Node*> &only, void *reserved) const override;
virtual void Save(QXmlStreamWriter *writer, const SaveData &data, void *reserved) const override;
virtual uint Version() const override
{