From 3ad8b211e656d1d4ea193a3680c61c16d4cd300a Mon Sep 17 00:00:00 2001 From: Jesse Qu Date: Thu, 9 Jul 2026 11:40:14 +0800 Subject: [PATCH] refactor: distribute serialization/deserialization from Document into item classes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move per-type serialization logic out of Document's monolithic serializeItem()/deserializeItem() into each item class: - Add virtual serialize() to AbstractShapeType template, overridden by GraphicsRectItem, GraphicPolygonItem, and GraphicsItemGroup - Add static createFromJson() factory + self-registration to each item - Extract shared pen/brush/common helpers into serializationUtils - Add type registry (serializationRegistry) for factory-based deserialization - Document::saveAs()/load() now delegate to item->serialize() and createItemFromJson() — no longer owns per-type dispatch - Adding a new shape type no longer requires touching Document --- CMakeLists.txt | 5 + include/document.h | 4 - include/graphicsItem/graphicsBaseItem.h | 3 + include/graphicsItem/graphicsItemGroup.h | 2 + include/graphicsItem/graphicsPolygonItem.h | 2 + include/graphicsItem/graphicsRectItem.h | 2 + include/util/serializationRegistry.h | 13 ++ include/util/serializationUtils.h | 19 ++ source/document.cpp | 229 +------------------- source/graphicsItem/graphicsItemGroup.cpp | 61 ++++++ source/graphicsItem/graphicsPolygonItem.cpp | 41 ++++ source/graphicsItem/graphicsRectItem.cpp | 45 ++++ source/util/serializationRegistry.cpp | 25 +++ source/util/serializationUtils.cpp | 73 +++++++ 14 files changed, 298 insertions(+), 226 deletions(-) create mode 100644 include/util/serializationRegistry.h create mode 100644 include/util/serializationUtils.h create mode 100644 source/util/serializationRegistry.cpp create mode 100644 source/util/serializationUtils.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ffd4e0d..079344c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,9 @@ set(H_HEADER_FILES include/util/editingSelector.h include/util/selectorManager.h + include/util/serializationUtils.h + include/util/serializationRegistry.h + include/graphicsItem/itemControlHandle.h include/graphicsItem/graphicsBaseItem.h include/graphicsItem/graphicsRectItem.h @@ -83,6 +86,8 @@ set(CPP_SOURCE_FILES source/util/scalingSelector.cpp source/util/editingSelector.cpp source/util/selectorManager.cpp + source/util/serializationUtils.cpp + source/util/serializationRegistry.cpp source/graphicsItem/itemControlHandle.cpp source/graphicsItem/graphicsBaseItem.cpp diff --git a/include/document.h b/include/document.h index e633ad8..a320fc1 100644 --- a/include/document.h +++ b/include/document.h @@ -51,10 +51,6 @@ private: void setModified(bool modified); void setupNewScene(); - // Serialization helpers - QJsonObject serializeItem(QGraphicsItem *item) const; - QGraphicsItem *deserializeItem(const QJsonObject &obj); - DesignerScene *m_pScene; QUndoStack *m_pUndoStack; bool m_bModified; diff --git a/include/graphicsItem/graphicsBaseItem.h b/include/graphicsItem/graphicsBaseItem.h index 04550c5..178d63e 100644 --- a/include/graphicsItem/graphicsBaseItem.h +++ b/include/graphicsItem/graphicsBaseItem.h @@ -8,6 +8,7 @@ #include #include #include +#include enum ShapeType { @@ -95,6 +96,8 @@ public: virtual void updateCoordinate() {} + virtual QJsonObject serialize() const = 0; + //handle相关 virtual int handleCount() { return m_vecHanle.count(); } virtual ItemControlHandle* getHandle(int nHandle) diff --git a/include/graphicsItem/graphicsItemGroup.h b/include/graphicsItem/graphicsItemGroup.h index 1a39cf8..ae503f2 100644 --- a/include/graphicsItem/graphicsItemGroup.h +++ b/include/graphicsItem/graphicsItemGroup.h @@ -18,6 +18,8 @@ public: void removeOperationCopy(); void moveOperationCopy(const QPointF&); void rotateOperationCopy(const double&); + QJsonObject serialize() const override; + static QGraphicsItem *createFromJson(const QJsonObject &obj); void addItems(const QList&); //QList getItems() {return m_listItem;} diff --git a/include/graphicsItem/graphicsPolygonItem.h b/include/graphicsItem/graphicsPolygonItem.h index 2a0bee9..121caa8 100644 --- a/include/graphicsItem/graphicsPolygonItem.h +++ b/include/graphicsItem/graphicsPolygonItem.h @@ -14,6 +14,8 @@ public: void resize(int,double, double, const QPointF&); void updateCoordinate(); void move(const QPointF&); + QJsonObject serialize() const override; + static QGraphicsItem *createFromJson(const QJsonObject &obj); void editShape(int, const QPointF&); void addPoint(const QPointF&); diff --git a/include/graphicsItem/graphicsRectItem.h b/include/graphicsItem/graphicsRectItem.h index bae9663..8b256fe 100644 --- a/include/graphicsItem/graphicsRectItem.h +++ b/include/graphicsItem/graphicsRectItem.h @@ -19,6 +19,8 @@ public: void setRatioX(double rx) { m_dRatioX = rx; } void setRatioY(double ry) { m_dRatioY = ry; } void move(const QPointF&); + QJsonObject serialize() const override; + static QGraphicsItem *createFromJson(const QJsonObject &obj); void editShape(int, const QPointF&); protected: diff --git a/include/util/serializationRegistry.h b/include/util/serializationRegistry.h new file mode 100644 index 0000000..2162477 --- /dev/null +++ b/include/util/serializationRegistry.h @@ -0,0 +1,13 @@ +#ifndef SERIALIZATIONREGISTRY_H +#define SERIALIZATIONREGISTRY_H + +#include +#include +#include + +using ItemFactory = std::function; + +void registerItemFactory(const QString &type, ItemFactory factory); +QGraphicsItem *createItemFromJson(const QJsonObject &obj); + +#endif // SERIALIZATIONREGISTRY_H diff --git a/include/util/serializationUtils.h b/include/util/serializationUtils.h new file mode 100644 index 0000000..dfec896 --- /dev/null +++ b/include/util/serializationUtils.h @@ -0,0 +1,19 @@ +#ifndef SERIALIZATIONUTILS_H +#define SERIALIZATIONUTILS_H + +#include +#include +#include +#include + +QString penStyleToString(Qt::PenStyle style); +Qt::PenStyle penStyleFromString(const QString &str); + +QJsonObject serializePen(const QPen &pen); +QPen deserializePen(const QJsonObject &obj); +QJsonObject serializeBrush(const QBrush &brush); + +QJsonObject serializeCommon(const QGraphicsItem *item, const QString &type); +void applyCommon(QGraphicsItem *item, const QJsonObject &obj); + +#endif // SERIALIZATIONUTILS_H diff --git a/source/document.cpp b/source/document.cpp index 4f21dec..14054b7 100644 --- a/source/document.cpp +++ b/source/document.cpp @@ -2,10 +2,8 @@ #include "designerScene.h" #include "graphicsItem/graphicsBaseItem.h" -#include "graphicsItem/graphicsRectItem.h" -#include "graphicsItem/graphicsPolygonItem.h" #include "graphicsItem/graphicsItemGroup.h" -#include "graphicsItem/itemControlHandle.h" +#include "util/serializationRegistry.h" #include "global.h" #include @@ -38,8 +36,6 @@ Document::~Document() void Document::setupNewScene() { if (m_pScene) { - // Clear items only — do NOT delete the scene. The view in DrawingPanel - // still references it, and deleting would leave a dangling pointer. m_pScene->clear(); } else { m_pScene = new DesignerScene(this); @@ -94,219 +90,6 @@ void Document::clear() emit filePathChanged(m_sFilePath); } -// -- Pen style string conversion ------------------------------------------ - -static QString penStyleToString(Qt::PenStyle style) -{ - switch (style) { - case Qt::NoPen: return "none"; - case Qt::SolidLine: return "solid"; - case Qt::DashLine: return "dash"; - case Qt::DotLine: return "dot"; - case Qt::DashDotLine: return "dashDot"; - case Qt::DashDotDotLine: return "dashDotDot"; - default: return "solid"; - } -} - -static Qt::PenStyle penStyleFromString(const QString &str) -{ - static const QHash map = { - {"none", Qt::NoPen}, - {"solid", Qt::SolidLine}, - {"dash", Qt::DashLine}, - {"dot", Qt::DotLine}, - {"dashDot", Qt::DashDotLine}, - {"dashDotDot", Qt::DashDotDotLine} - }; - return map.value(str, Qt::SolidLine); -} - -// -- Write helpers --------------------------------------------------------- - -static QJsonObject serializePen(const QPen &pen) -{ - QJsonObject obj; - obj["color"] = pen.color().name(QColor::HexArgb); - obj["width"] = pen.widthF(); - obj["style"] = penStyleToString(pen.style()); - return obj; -} - -static QJsonObject serializeBrush(const QBrush &brush) -{ - QJsonObject obj; - obj["color"] = brush.color().name(QColor::HexArgb); - return obj; -} - -static QJsonObject serializeCommon(QGraphicsItem *item, const QString &type) -{ - QJsonObject obj; - obj["type"] = type; - obj["pos"] = QJsonObject{{"x", item->pos().x()}, {"y", item->pos().y()}}; - obj["rotation"] = item->rotation(); - obj["zValue"] = item->zValue(); - return obj; -} - -// -- Item serialization ---------------------------------------------------- - -QJsonObject Document::serializeItem(QGraphicsItem *item) const -{ - // Groups use a different template instantiation (AbstractShapeType), - // so qgraphicsitem_cast will not match them. - // Check for groups first. - GraphicsItemGroup *group = dynamic_cast(item); - if (group) { - QJsonObject obj = serializeCommon(item, "group"); - obj["pen"] = serializePen(group->pen()); - obj["brush"] = serializeBrush(group->brush()); - - QJsonArray children; - const auto kids = group->childItems(); - for (QGraphicsItem *child : kids) { - if (qgraphicsitem_cast(child)) - continue; - QJsonObject childObj = serializeItem(child); - if (!childObj.isEmpty()) - children.append(childObj); - } - obj["children"] = children; - return obj; - } - - AbstractShape *shape = qgraphicsitem_cast(item); - if (!shape) - return {}; - - // Use dynamic_cast for type dispatch — GraphicsBaseItem subclasses do not - // override QGraphicsItem::type(), so the GIT_* enum values are never returned. - if (GraphicsRectItem *rectItem = dynamic_cast(item)) { - bool isRound = rectItem->isRound(); - QJsonObject obj = serializeCommon(item, isRound ? "roundRect" : "rect"); - obj["width"] = shape->width(); - obj["height"] = shape->height(); - if (isRound) { - obj["ratioX"] = rectItem->ratioX(); - obj["ratioY"] = rectItem->ratioY(); - } - obj["pen"] = serializePen(shape->pen()); - obj["brush"] = serializeBrush(shape->brush()); - return obj; - } - - if (GraphicPolygonItem *poly = dynamic_cast(item)) { - QJsonObject obj = serializeCommon(item, "polygon"); - QJsonArray pts; - for (const QPointF &pt : poly->getPoints()) { - pts.append(QJsonObject{{"x", pt.x()}, {"y", pt.y()}}); - } - obj["points"] = pts; - obj["pen"] = serializePen(shape->pen()); - obj["brush"] = serializeBrush(shape->brush()); - return obj; - } - - qWarning("Document::serializeItem: unrecognized item"); - return {}; -} - -// -- Item deserialization -------------------------------------------------- - -static void applyCommon(QGraphicsItem *item, const QJsonObject &obj) -{ - QJsonObject pos = obj["pos"].toObject(); - item->setPos(pos["x"].toDouble(), pos["y"].toDouble()); - item->setRotation(obj["rotation"].toDouble()); - item->setZValue(obj["zValue"].toDouble()); -} - -template -static void applyPen(AbstractShapeType *shape, const QJsonObject &penObj) -{ - QPen pen; - pen.setColor(QColor(penObj["color"].toString())); - pen.setWidthF(penObj["width"].toDouble()); - pen.setStyle(penStyleFromString(penObj["style"].toString())); - shape->setPen(pen); -} - -template -static void applyBrush(AbstractShapeType *shape, const QJsonObject &brushObj) -{ - shape->setBrushColor(QColor(brushObj["color"].toString())); -} - -QGraphicsItem *Document::deserializeItem(const QJsonObject &obj) -{ - // Note: deserializeItem creates the item but does NOT add it to the scene. - // The caller (load() or a parent group) is responsible for scene addition. - QString type = obj["type"].toString(); - - if (type == "group") { - GraphicsItemGroup *group = new GraphicsItemGroup(); - applyCommon(group, obj); - - QJsonArray children = obj["children"].toArray(); - QList childItems; - for (const QJsonValue &val : children) { - QGraphicsItem *child = deserializeItem(val.toObject()); - if (child) - childItems.append(child); - } - - // Child positions in JSON are group-relative, but addToGroup() - // treats child pos() as scene-absolute. Convert before grouping. - for (QGraphicsItem *child : childItems) - child->setPos(group->mapToScene(child->pos())); - - group->addItems(childItems); - applyPen(group, obj["pen"].toObject()); - applyBrush(group, obj["brush"].toObject()); - group->setHandleVisible(false); - return group; - } - - if (type == "rect" || type == "roundRect") { - double w = obj["width"].toDouble(); - double h = obj["height"].toDouble(); - bool isRound = (type == "roundRect"); - GraphicsRectItem *item = new GraphicsRectItem( - QRectF(-w / 2, -h / 2, w, h).toRect(), isRound); - applyCommon(item, obj); - applyPen(item, obj["pen"].toObject()); - applyBrush(item, obj["brush"].toObject()); - if (isRound) { - item->setRatioX(obj["ratioX"].toDouble(0.1)); - item->setRatioY(obj["ratioY"].toDouble(0.1)); - } - item->updateCoordinate(); - item->setHandleVisible(false); - return item; - } - - if (type == "polygon") { - GraphicPolygonItem *item = new GraphicPolygonItem(); - QJsonArray pts = obj["points"].toArray(); - for (const QJsonValue &val : pts) { - QJsonObject pt = val.toObject(); - item->addPoint(QPointF(pt["x"].toDouble(), pt["y"].toDouble())); - } - item->endDrawing(); - applyCommon(item, obj); - applyPen(item, obj["pen"].toObject()); - applyBrush(item, obj["brush"].toObject()); - item->updateCoordinate(); - item->setHandleVisible(false); - return item; - } - - return nullptr; -} - -// -- Save / Load ----------------------------------------------------------- - bool Document::save() { if (m_sFilePath.isEmpty()) @@ -319,10 +102,13 @@ bool Document::saveAs(const QString &filePath) QJsonArray items; const auto sceneItems = m_pScene->items(); for (QGraphicsItem *item : sceneItems) { - // Only serialize top-level items (children of groups are serialized recursively) if (item->parentItem()) continue; - QJsonObject obj = serializeItem(item); + QJsonObject obj; + if (auto *group = dynamic_cast(item)) + obj = group->serialize(); + else if (auto *shape = qgraphicsitem_cast(item)) + obj = shape->serialize(); if (!obj.isEmpty()) items.append(obj); } @@ -362,14 +148,13 @@ bool Document::load(const QString &filePath) QJsonObject root = doc.object(); - // Clear current state without triggering undo m_nSavedIndex = 0; m_pUndoStack->clear(); setupNewScene(); QJsonArray items = root["items"].toArray(); for (const QJsonValue &val : items) { - QGraphicsItem *item = deserializeItem(val.toObject()); + QGraphicsItem *item = createItemFromJson(val.toObject()); if (item) m_pScene->addItem(item); } diff --git a/source/graphicsItem/graphicsItemGroup.cpp b/source/graphicsItem/graphicsItemGroup.cpp index 4aa4184..4ee8582 100644 --- a/source/graphicsItem/graphicsItemGroup.cpp +++ b/source/graphicsItem/graphicsItemGroup.cpp @@ -3,6 +3,7 @@ #include #include #include +#include GraphicsItemGroup::GraphicsItemGroup(QGraphicsItem *parent) : AbstractShapeType(parent) @@ -286,3 +287,63 @@ void GraphicsItemGroup::addItems(const QList& items) updateCoordinate(); } + +#include "util/serializationUtils.h" +#include "graphicsItem/graphicsBaseItem.h" +#include "graphicsItem/itemControlHandle.h" + +QJsonObject GraphicsItemGroup::serialize() const +{ + QJsonObject obj = serializeCommon(this, "group"); + obj["pen"] = serializePen(m_pen); + obj["brush"] = serializeBrush(m_brush); + + QJsonArray children; + const auto kids = childItems(); + for (QGraphicsItem *child : kids) { + if (qgraphicsitem_cast(child)) + continue; + QJsonObject childObj; + if (auto *group = dynamic_cast(child)) + childObj = group->serialize(); + else if (auto *shape = qgraphicsitem_cast(child)) + childObj = shape->serialize(); + if (!childObj.isEmpty()) + children.append(childObj); + } + obj["children"] = children; + return obj; +} + +#include "util/serializationRegistry.h" + +QGraphicsItem *GraphicsItemGroup::createFromJson(const QJsonObject &obj) +{ + GraphicsItemGroup *group = new GraphicsItemGroup(); + applyCommon(group, obj); + + QJsonArray children = obj["children"].toArray(); + QList childItems; + for (const QJsonValue &val : children) { + QGraphicsItem *child = createItemFromJson(val.toObject()); + if (child) + childItems.append(child); + } + + // Child positions in JSON are group-relative, but addToGroup() + // treats child pos() as scene-absolute. Convert before grouping. + for (QGraphicsItem *child : childItems) + child->setPos(group->mapToScene(child->pos())); + + group->addItems(childItems); + group->setPen(deserializePen(obj["pen"].toObject())); + group->setBrushColor(QColor(obj["brush"].toObject()["color"].toString())); + group->setHandleVisible(false); + return group; +} + +static struct GroupItemRegistrar { + GroupItemRegistrar() { + registerItemFactory("group", &GraphicsItemGroup::createFromJson); + } +} _groupItemRegistrar; diff --git a/source/graphicsItem/graphicsPolygonItem.cpp b/source/graphicsItem/graphicsPolygonItem.cpp index 787b4bf..2456507 100644 --- a/source/graphicsItem/graphicsPolygonItem.cpp +++ b/source/graphicsItem/graphicsPolygonItem.cpp @@ -3,6 +3,7 @@ #include #include +#include GraphicPolygonItem::GraphicPolygonItem(QGraphicsItem *parent) : GraphicsBaseItem(parent) @@ -150,3 +151,43 @@ bool GraphicPolygonItem::endDrawing() return bSuccess; } + +#include "util/serializationUtils.h" + +QJsonObject GraphicPolygonItem::serialize() const +{ + QJsonObject obj = serializeCommon(this, "polygon"); + QJsonArray pts; + for (const QPointF &pt : m_points) { + pts.append(QJsonObject{{"x", pt.x()}, {"y", pt.y()}}); + } + obj["points"] = pts; + obj["pen"] = serializePen(m_pen); + obj["brush"] = serializeBrush(m_brush); + return obj; +} + +#include "util/serializationRegistry.h" + +QGraphicsItem *GraphicPolygonItem::createFromJson(const QJsonObject &obj) +{ + GraphicPolygonItem *item = new GraphicPolygonItem(); + QJsonArray pts = obj["points"].toArray(); + for (const QJsonValue &val : pts) { + QJsonObject pt = val.toObject(); + item->addPoint(QPointF(pt["x"].toDouble(), pt["y"].toDouble())); + } + item->endDrawing(); + applyCommon(item, obj); + item->setPen(deserializePen(obj["pen"].toObject())); + item->setBrushColor(QColor(obj["brush"].toObject()["color"].toString())); + item->updateCoordinate(); + item->setHandleVisible(false); + return item; +} + +static struct PolygonItemRegistrar { + PolygonItemRegistrar() { + registerItemFactory("polygon", &GraphicPolygonItem::createFromJson); + } +} _polygonItemRegistrar; diff --git a/source/graphicsItem/graphicsRectItem.cpp b/source/graphicsItem/graphicsRectItem.cpp index dc39043..060081c 100644 --- a/source/graphicsItem/graphicsRectItem.cpp +++ b/source/graphicsItem/graphicsRectItem.cpp @@ -196,3 +196,48 @@ void GraphicsRectItem::editShape(int nHandle,const QPointF& ptMouse) prepareGeometryChange(); updateHandles(); } + +#include "util/serializationUtils.h" + +QJsonObject GraphicsRectItem::serialize() const +{ + QJsonObject obj = serializeCommon(this, m_bIsRound ? "roundRect" : "rect"); + obj["width"] = m_dWidth; + obj["height"] = m_dHeight; + if (m_bIsRound) { + obj["ratioX"] = m_dRatioX; + obj["ratioY"] = m_dRatioY; + } + obj["pen"] = serializePen(m_pen); + obj["brush"] = serializeBrush(m_brush); + return obj; +} + +#include "util/serializationRegistry.h" + +QGraphicsItem *GraphicsRectItem::createFromJson(const QJsonObject &obj) +{ + QString type = obj["type"].toString(); + bool isRound = (type == "roundRect"); + double w = obj["width"].toDouble(); + double h = obj["height"].toDouble(); + GraphicsRectItem *item = new GraphicsRectItem( + QRectF(-w / 2, -h / 2, w, h).toRect(), isRound); + applyCommon(item, obj); + item->setPen(deserializePen(obj["pen"].toObject())); + item->setBrushColor(QColor(obj["brush"].toObject()["color"].toString())); + if (isRound) { + item->setRatioX(obj["ratioX"].toDouble(0.1)); + item->setRatioY(obj["ratioY"].toDouble(0.1)); + } + item->updateCoordinate(); + item->setHandleVisible(false); + return item; +} + +static struct RectItemRegistrar { + RectItemRegistrar() { + registerItemFactory("rect", &GraphicsRectItem::createFromJson); + registerItemFactory("roundRect", &GraphicsRectItem::createFromJson); + } +} _rectItemRegistrar; diff --git a/source/util/serializationRegistry.cpp b/source/util/serializationRegistry.cpp new file mode 100644 index 0000000..b81c68d --- /dev/null +++ b/source/util/serializationRegistry.cpp @@ -0,0 +1,25 @@ +#include "util/serializationRegistry.h" + +#include +#include + +static QHash ®istry() +{ + static QHash map; + return map; +} + +void registerItemFactory(const QString &type, ItemFactory factory) +{ + registry().insert(type, factory); +} + +QGraphicsItem *createItemFromJson(const QJsonObject &obj) +{ + QString type = obj["type"].toString(); + ItemFactory factory = registry().value(type); + if (factory) + return factory(obj); + qWarning("createItemFromJson: unknown type '%s'", qPrintable(type)); + return nullptr; +} diff --git a/source/util/serializationUtils.cpp b/source/util/serializationUtils.cpp new file mode 100644 index 0000000..2d7abd8 --- /dev/null +++ b/source/util/serializationUtils.cpp @@ -0,0 +1,73 @@ +#include "util/serializationUtils.h" + +#include +#include + +QString penStyleToString(Qt::PenStyle style) +{ + switch (style) { + case Qt::NoPen: return "none"; + case Qt::SolidLine: return "solid"; + case Qt::DashLine: return "dash"; + case Qt::DotLine: return "dot"; + case Qt::DashDotLine: return "dashDot"; + case Qt::DashDotDotLine: return "dashDotDot"; + default: return "solid"; + } +} + +Qt::PenStyle penStyleFromString(const QString &str) +{ + static const QHash map = { + {"none", Qt::NoPen}, + {"solid", Qt::SolidLine}, + {"dash", Qt::DashLine}, + {"dot", Qt::DotLine}, + {"dashDot", Qt::DashDotLine}, + {"dashDotDot", Qt::DashDotDotLine} + }; + return map.value(str, Qt::SolidLine); +} + +QJsonObject serializePen(const QPen &pen) +{ + QJsonObject obj; + obj["color"] = pen.color().name(QColor::HexArgb); + obj["width"] = pen.widthF(); + obj["style"] = penStyleToString(pen.style()); + return obj; +} + +QPen deserializePen(const QJsonObject &obj) +{ + QPen pen; + pen.setColor(QColor(obj["color"].toString())); + pen.setWidthF(obj["width"].toDouble()); + pen.setStyle(penStyleFromString(obj["style"].toString())); + return pen; +} + +QJsonObject serializeBrush(const QBrush &brush) +{ + QJsonObject obj; + obj["color"] = brush.color().name(QColor::HexArgb); + return obj; +} + +QJsonObject serializeCommon(const QGraphicsItem *item, const QString &type) +{ + QJsonObject obj; + obj["type"] = type; + obj["pos"] = QJsonObject{{"x", item->pos().x()}, {"y", item->pos().y()}}; + obj["rotation"] = item->rotation(); + obj["zValue"] = item->zValue(); + return obj; +} + +void applyCommon(QGraphicsItem *item, const QJsonObject &obj) +{ + QJsonObject pos = obj["pos"].toObject(); + item->setPos(pos["x"].toDouble(), pos["y"].toDouble()); + item->setRotation(obj["rotation"].toDouble()); + item->setZValue(obj["zValue"].toDouble()); +}