@@ -578,6 +578,109 @@ void BasicGraphicsScene::removeNodeFromGroup(NodeId nodeId)
578578 nodeIt->second ->lock (false );
579579}
580580
581+ std::unordered_map<QUuid, QUuid> BasicGraphicsScene::loadItems (const QByteArray &data,
582+ QPointF pastePos,
583+ bool usePastePos)
584+ {
585+ QJsonObject const jsonDocument = QJsonDocument::fromJson (data).object ();
586+
587+ std::unordered_map<QUuid, QUuid> IDMap{};
588+
589+ QPointF offset;
590+ bool offsetInitialized{false };
591+ clearSelection ();
592+
593+ QJsonArray nodesJsonArray = jsonDocument.value (" nodes" ).toArray ();
594+ QHash<NodeId, QJsonObject> nodeById;
595+ nodeById.reserve (nodesJsonArray.size ());
596+ for (const QJsonValue &v : nodesJsonArray) {
597+ QJsonObject o = v.toObject ();
598+ NodeId id = static_cast <NodeId>(o.value (" id" ).toInt (InvalidNodeId));
599+ if (id != InvalidNodeId)
600+ nodeById.insert (id, o);
601+ }
602+
603+ QSet<NodeId> createdOldNodeIds;
604+
605+ QJsonArray groupsJsonArray = jsonDocument.value (" groups" ).toArray ();
606+ for (const QJsonValue &groupVal : groupsJsonArray) {
607+ auto [groupWeakPtr, groupIDsMap] = restoreGroup (groupVal.toObject (), nodeById);
608+
609+ for (const auto &[oldGroupId, newGroupId] : groupIDsMap) {
610+ NodeId oldNodeId = static_cast <NodeId>(oldGroupId);
611+ NodeId newNodeId = static_cast <NodeId>(newGroupId);
612+
613+ createdOldNodeIds.insert (oldNodeId);
614+
615+ QUuid oldUuid = encodeNodeId (oldNodeId);
616+ QUuid newUuid = encodeNodeId (newNodeId);
617+ IDMap[oldUuid] = newUuid;
618+ }
619+
620+ if (auto groupPtr = groupWeakPtr.lock (); groupPtr) {
621+ auto &ggoRef = groupPtr->groupGraphicsObject ();
622+
623+ if (usePastePos && !offsetInitialized) {
624+ offset = pastePos - ggoRef.pos ();
625+ offsetInitialized = true ;
626+ }
627+ if (usePastePos) {
628+ ggoRef.moveNodes (offset);
629+ }
630+ ggoRef.moveConnections ();
631+ ggoRef.setSelected (true );
632+ }
633+ }
634+
635+ for (QJsonValueRef node : nodesJsonArray) {
636+ QJsonObject nodeObj = node.toObject ();
637+ NodeId oldNodeId = static_cast <NodeId>(nodeObj.value (" id" ).toInt (InvalidNodeId));
638+
639+ if (createdOldNodeIds.contains (oldNodeId)) {
640+ continue ;
641+ }
642+
643+ auto &nodeRef = loadNodeToMap (nodeObj, false );
644+
645+ NodeId newNodeId = nodeRef.nodeId ();
646+ QUuid oldId = encodeNodeId (oldNodeId);
647+ QUuid newId = encodeNodeId (newNodeId);
648+ IDMap.insert (std::make_pair (oldId, newId));
649+
650+ if (usePastePos && !offsetInitialized) {
651+ offset = pastePos - nodeRef.pos ();
652+ offsetInitialized = true ;
653+ }
654+ if (usePastePos) {
655+ nodeRef.moveBy (offset.x (), offset.y ());
656+ }
657+ nodeRef.moveConnections ();
658+ nodeRef.setSelected (true );
659+ }
660+
661+ QJsonArray connectionJsonArray = jsonDocument.value (" connections" ).toArray ();
662+ for (QJsonValueRef connection : connectionJsonArray) {
663+ auto nodeIdMap = convertMap (IDMap);
664+ loadConnectionToMap (connection.toObject (), nodeIdMap);
665+
666+ ConnectionId connId = fromJson (connection.toObject ());
667+ auto it = _connectionGraphicsObjects.find (connId);
668+ if (it != _connectionGraphicsObjects.end ()) {
669+ UniqueConnectionGraphicsObject &obj = it->second ;
670+ obj->setSelected (true );
671+ }
672+ }
673+
674+ return IDMap;
675+ }
676+
677+ std::unordered_map<QUuid, QUuid> BasicGraphicsScene::loadFromMemory (const QByteArray &data)
678+ {
679+ std::unordered_map<QUuid, QUuid> map = loadItems (data, QPointF (), false );
680+ clearSelection ();
681+ return map;
682+ }
683+
581684std::weak_ptr<QtNodes::NodeGroup> BasicGraphicsScene::createGroupFromSelection (QString groupName)
582685{
583686 if (!_groupingEnabled)
@@ -636,25 +739,48 @@ void BasicGraphicsScene::loadConnectionToMap(QJsonObject const &connectionJson,
636739}
637740
638741std::pair<std::weak_ptr<NodeGroup>, std::unordered_map<GroupId, GroupId>>
639- BasicGraphicsScene::restoreGroup (QJsonObject const &groupJson)
742+ BasicGraphicsScene::restoreGroup (QJsonObject const &groupJson,
743+ QHash<NodeId, QJsonObject> const &nodeById)
744+
640745{
641746 if (!_groupingEnabled)
642747 return {std::weak_ptr<NodeGroup>(), {}};
643748
644- // since the new nodes will have the same IDs as in the file and the connections
645- // need these old IDs to be restored, we must create new IDs and map them to the
646- // old ones so the connections are properly restored
647749 std::unordered_map<GroupId, GroupId> IDsMap{};
648750 std::unordered_map<NodeId, NodeId> nodeIdMap{};
649-
650751 std::vector<NodeGraphicsObject *> group_children{};
651752
652- QJsonArray nodesJson = groupJson[" nodes" ].toArray ();
653- for (const QJsonValueRef nodeJson : nodesJson) {
654- QJsonObject nodeObject = nodeJson.toObject ();
655- NodeId const oldNodeId = jsonValueToNodeId (nodeObject[" id" ]);
753+ QJsonArray nodesJson = groupJson.value (" nodes" ).toArray ();
754+ for (QJsonValue const &nodeVal : nodesJson) {
755+ QJsonObject nodeObject;
756+
757+ if (nodeVal.isDouble ()) {
758+ NodeId const oldNodeId = static_cast <NodeId>(nodeVal.toInt (InvalidNodeId));
759+ if (oldNodeId == InvalidNodeId) {
760+ qWarning () << " restoreGroup(): invalid node id in group:" << nodeVal;
761+ continue ;
762+ }
763+
764+ auto it = nodeById.find (oldNodeId);
765+ if (it == nodeById.end ()) {
766+ qWarning () << " restoreGroup(): group references missing node id:" << oldNodeId;
767+ continue ;
768+ }
769+
770+ nodeObject = it.value ();
771+ }
772+
773+ else if (nodeVal.isObject ()) {
774+ nodeObject = nodeVal.toObject ();
775+ } else {
776+ qWarning () << " restoreGroup(): unexpected node entry type:" << nodeVal;
777+ continue ;
778+ }
779+
780+ NodeId const oldNodeId = jsonValueToNodeId (nodeObject.value (" id" ));
781+
782+ NodeGraphicsObject &nodeRef = loadNodeToMap (nodeObject, /* keepOriginalId=*/ false );
656783
657- NodeGraphicsObject &nodeRef = loadNodeToMap (nodeObject, false );
658784 NodeId const newNodeId = nodeRef.nodeId ();
659785
660786 if (oldNodeId != InvalidNodeId) {
@@ -665,12 +791,12 @@ BasicGraphicsScene::restoreGroup(QJsonObject const &groupJson)
665791 group_children.push_back (&nodeRef);
666792 }
667793
668- QJsonArray connectionJsonArray = groupJson[ " connections" ] .toArray ();
669- for (auto connection : connectionJsonArray) {
670- loadConnectionToMap (connection .toObject (), nodeIdMap);
794+ QJsonArray connectionJsonArray = groupJson. value ( " connections" ) .toArray ();
795+ for (QJsonValue const &connectionVal : connectionJsonArray) {
796+ loadConnectionToMap (connectionVal .toObject (), nodeIdMap);
671797 }
672798
673- return std::make_pair (createGroup (group_children, groupJson[ " name" ] .toString ()), IDsMap);
799+ return std::make_pair (createGroup (group_children, groupJson. value ( " name" ) .toString ()), IDsMap);
674800}
675801
676802std::unordered_map<GroupId, std::shared_ptr<NodeGroup>> const &BasicGraphicsScene::groups () const
@@ -802,17 +928,28 @@ std::weak_ptr<NodeGroup> BasicGraphicsScene::loadGroupFile()
802928
803929 if (!file.open (QIODevice::ReadOnly)) {
804930 qDebug () << " Error loading group file!" ;
931+ return std::weak_ptr<NodeGroup>();
805932 }
806933
807934 QDir d = QFileInfo (fileName).absoluteDir ();
808- QString absolute = d.absolutePath ();
809- QDir::setCurrent (absolute);
935+ QDir::setCurrent (d.absolutePath ());
810936
811937 QByteArray wholeFile = file.readAll ();
812-
813938 const QJsonObject fileJson = QJsonDocument::fromJson (wholeFile).object ();
814939
815- return restoreGroup (fileJson).first ;
940+ QHash<NodeId, QJsonObject> nodeById;
941+
942+ QJsonArray nodesArr = fileJson.value (" nodes" ).toArray ();
943+ nodeById.reserve (nodesArr.size ());
944+ for (QJsonValue const &v : nodesArr) {
945+ QJsonObject o = v.toObject ();
946+ NodeId id = jsonValueToNodeId (o.value (" id" ));
947+ if (id != InvalidNodeId) {
948+ nodeById.insert (id, o);
949+ }
950+ }
951+
952+ return restoreGroup (fileJson, nodeById).first ;
816953}
817954
818955GroupId BasicGraphicsScene::nextGroupId ()
0 commit comments