Fixed diagram copy/paste implementations to re-identify diagram elements 78/678/2
authorTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Tue, 4 Jul 2017 10:57:34 +0000 (13:57 +0300)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Tue, 4 Jul 2017 13:13:30 +0000 (16:13 +0300)
Previously copying elements within or between diagram editors and also
copying diagrams in the model browser would preserve GUID identifiers
for the diagram ordered set structure itself and all its elements. The
correct behavior is now implemented which is to force the system to
generate new GUID identifiers for all copied structures that have
identifiers.

refs #7348

Change-Id: I811bb4a118ffb9321577ef46f6651459379cdd08

bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/util/Layer0Utils.java
bundles/org.simantics.diagram/src/org/simantics/diagram/handler/Paster.java
bundles/org.simantics.modeling/src/org/simantics/modeling/adapters/CompositeCopyHandler.java
bundles/org.simantics.modeling/src/org/simantics/modeling/mapping/ElementCopyAdvisor.java

index 3da57809ae0f381debf8e6520c017855b2ad7144..c04ca3cd1e0b758d1d66a8a8628887dab576f5cc 100644 (file)
@@ -1407,4 +1407,27 @@ public class Layer0Utils {
         else
             graph.claimLiteral(component, L0.identifier, L0.identifier_Inverse, L0.GUID, guid, GUID.BINDING);
     }
+
+    /**
+     * Sets a new random unique identifier for the specified entity if it already
+     * has an identifier. If the entity does not have a previous identifier, nothing
+     * is done.
+     * 
+     * @param graph
+     * @param entity
+     *            for which the identifier is added
+     * @return <code>true</code> if the identifier was renewed, <code>false</code>
+     *         otherwise
+     * @throws DatabaseException
+     * @see {@link #claimNewIdentifier(WriteGraph, Resource, boolean)}
+     */
+    public static boolean renewIdentifier(WriteGraph graph, Resource entity) throws DatabaseException {
+        Layer0 L0 = Layer0.getInstance(graph);
+        Statement stm = graph.getPossibleStatement(entity, L0.identifier);
+        if (stm != null) {
+            graph.claimValue(stm.getObject(), GUID.random(), GUID.BINDING);
+            return true;
+        }
+        return false;
+    }
 }
index 6672599073b1b18e717bd1f79c36f6e3ac0bdb78..75b0473a1bc4991be688799f7a23799a5136457e 100644 (file)
@@ -28,6 +28,7 @@ import org.simantics.db.common.utils.CommonDBUtils;
 import org.simantics.db.common.utils.NameUtils;
 import org.simantics.db.common.utils.OrderedSetUtils;
 import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.util.Layer0Utils;
 import org.simantics.db.layer0.util.RemoverUtil;
 import org.simantics.db.request.Write;
 import org.simantics.diagram.content.ConnectionUtil;
@@ -863,6 +864,11 @@ public class Paster {
                 graph.claim(copy, L0.ConsistsOf, L0.PartOf, relationCopy);
                 graph.claim(copy, MOD.HasReferenceRelation, MOD.HasReferenceRelation_Inverse, relationCopy);
 
+                // #7348: renew reference relation GUID identifiers properly
+                Layer0Utils.renewIdentifier(graph, relationCopy);
+                for (Resource invRel : graph.getObjects(relationCopy, L0.ConsistsOf))
+                    Layer0Utils.renewIdentifier(graph, invRel);
+
                 return copy;
             }
 
index ae65e87f88476bf6b2059e8899d5a63266816fee..6167334fdd79815ad98a60cb1db1762d611a116f 100644 (file)
@@ -22,6 +22,7 @@ import org.simantics.db.Resource;
 import org.simantics.db.common.request.ObjectsWithType;
 import org.simantics.db.common.request.PossibleIndexRoot;
 import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.function.DbConsumer;
 import org.simantics.db.layer0.adapter.SubgraphExtent.ExtentStatus;
 import org.simantics.db.layer0.adapter.impl.DefaultCopyHandler;
 import org.simantics.db.layer0.util.TransferableGraphConfiguration2;
@@ -64,39 +65,63 @@ public class CompositeCopyHandler extends DefaultCopyHandler {
         if(indexRoot == null) throw new DatabaseException("Composite is not part of any index root");
         String indexRootUri = graph.getURI(indexRoot);
 
+        DbConsumer<Resource> identifierExcluder = r -> {
+            if (r != null)
+                exclusions.addAll(graph.getObjects(r, L0.identifier));
+        };
+
         for(Resource resource : resources) {
             // Process all connection joins.
             // This is the only way to access all of them.
             for (Resource diagram : graph.getObjects(resource, MOD.CompositeToDiagram)) {
-                for (Resource flag : graph.syncRequest(new ObjectsWithType(diagram, L0.ConsistsOf, DIA.Flag))) {
-                    for (Resource join : graph.getObjects(flag, DIA.FlagIsJoinedBy)) {
-                        // Joins with external references are omitted
-                        for (Resource comp : graph.getObjects(join, SR.JoinsComposite)) {
-                            if (!resourceSet.contains(comp))
-                                exclusions.add(join);
-                        }
-                        // This code excludes joins with flags to external
-                        // diagrams that are not connected (have no
-                        // configuration for the flag)
-                        for (Resource flag2 : graph.getObjects(join, DIA.JoinsFlag)) {
-                            Resource diagram2 = graph.getPossibleObject(flag2, L0.PartOf);
-                            if (diagram2 != null) {
-                                Resource comp = graph.getPossibleObject(diagram2, MOD.DiagramToComposite);
+                identifierExcluder.accept(diagram);
+
+                for (Resource element : graph.getObjects(diagram, L0.ConsistsOf)) {
+                    identifierExcluder.accept(element);
+
+                    Set<Resource> types = graph.getTypes(element);
+
+                    // Check all diagram flag elements for necessary exclusions.
+                    if (types.contains(DIA.Flag)) {
+                        for (Resource join : graph.getObjects(element, DIA.FlagIsJoinedBy)) {
+                            // Joins with external references are omitted
+                            for (Resource comp : graph.getObjects(join, SR.JoinsComposite)) {
                                 if (!resourceSet.contains(comp))
-                                    exclusions.add(join); 
+                                    exclusions.add(join);
+                            }
+                            // This code excludes joins with flags to external
+                            // diagrams that are not connected (have no
+                            // configuration for the flag)
+                            for (Resource flag2 : graph.getObjects(join, DIA.JoinsFlag)) {
+                                Resource diagram2 = graph.getPossibleObject(flag2, L0.PartOf);
+                                if (diagram2 != null) {
+                                    Resource comp = graph.getPossibleObject(diagram2, MOD.DiagramToComposite);
+                                    if (!resourceSet.contains(comp))
+                                        exclusions.add(join); 
+                                }
+                            }
+                        }
+                    }
+
+                    // Check all diagram monitor elements.
+                    // Any components referenced that are external to the exported diagrams must be excluded from the export.
+                    // This will leave the monitors without a monitored component but export and import will work anyway.
+                    if (types.contains(DIA.Monitor)) {
+                        for (Resource monitoredComponent : graph.getObjects(element, DIA.HasMonitorComponent)) {
+                            Resource monitoredComponentComposite = graph.getPossibleObject(monitoredComponent, L0.PartOf);
+                            if (monitoredComponentComposite != null && !resourceSet.contains(monitoredComponentComposite)) {
+                                exclusions.add(monitoredComponent);
                             }
                         }
                     }
-                }
 
-                // Check all diagram monitor elements.
-                // Any components referenced that are external to the exported diagrams must be excluded from the export.
-                // This will leave the monitors without a monitored component but export and import will work anyway.
-                for (Resource ref : graph.syncRequest(new ObjectsWithType(diagram, L0.ConsistsOf, DIA.Monitor))) {
-                    for (Resource monitoredComponent : graph.getObjects(ref, DIA.HasMonitorComponent)) {
-                        Resource monitoredComponentComposite = graph.getPossibleObject(monitoredComponent, L0.PartOf);
-                        if (monitoredComponentComposite != null && !resourceSet.contains(monitoredComponentComposite)) {
-                            exclusions.add(monitoredComponent);
+                    // Check all diagram reference elements for necessary exclusions.
+                    if (types.contains(MOD.ReferenceElement)) {
+                        for (Resource rel : graph.getObjects(element, L0.ConsistsOf)) {
+                            identifierExcluder.accept(rel);
+                            for (Resource invRel : graph.getObjects(rel, L0.ConsistsOf)) {
+                                identifierExcluder.accept(invRel);
+                            }
                         }
                     }
                 }
@@ -119,13 +144,11 @@ public class CompositeCopyHandler extends DefaultCopyHandler {
             // Include resource as root
             CompositeInfo info = CompositeInfo.fromResource(graph, resource);
             roots.add(new RootSpec(resource, info.getTGName(), true, typeId(graph, L0, indexRootUri, resource)));
-               Resource id = graph.getPossibleObject(resource, L0.identifier);
-               if(id != null) exclusions.add(id);
+            identifierExcluder.accept(resource);
             // Include components as roots
-            for(Resource child : graph.sync(new ObjectsWithType(resource, L0.ConsistsOf, SR.Component))) {
-               DiagramComponentInfo cinfo = DiagramComponentInfo.fromResource(graph, info, child);
-               id = graph.getPossibleObject(child, L0.identifier);
-               if(id != null) exclusions.add(id);
+            for (Resource child : graph.sync(new ObjectsWithType(resource, L0.ConsistsOf, SR.Component))) {
+                DiagramComponentInfo cinfo = DiagramComponentInfo.fromResource(graph, info, child);
+                identifierExcluder.accept(child);
                 roots.add(new RootSpec(child, cinfo.getTGName(info), true, typeId(graph, L0, indexRootUri, child)));
             }
         }
index 994aa1ab13feb132f6a9ce5ebaa5270c01bf6582..d666d63d5f24b9ba33b47a0fef6d363831dcecc3 100644 (file)
@@ -23,6 +23,7 @@ import org.simantics.db.common.utils.OrderedSetUtils;
 import org.simantics.db.exception.CancelTransactionException;
 import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.layer0.request.PossibleModel;
+import org.simantics.db.layer0.util.Layer0Utils;
 import org.simantics.diagram.stubs.DiagramResource;
 import org.simantics.diagram.stubs.G2DResource;
 import org.simantics.diagram.synchronization.ISynchronizationContext;
@@ -89,6 +90,8 @@ public class ElementCopyAdvisor extends GraphCopyAdvisor {
         if (graph.hasStatement(sourceContainer, L0.ConsistsOf, source))
             graph.claim(targetContainer, L0.ConsistsOf, copy);
 
+        Layer0Utils.claimNewIdentifier(graph, copy, false);
+
         return copy;
     }