Fixed route graph splitting and diagram mapping race condition problem 64/4364/1
authorTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Fri, 21 Aug 2020 13:06:50 +0000 (16:06 +0300)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Fri, 21 Aug 2020 13:24:15 +0000 (13:24 +0000)
RouteGraphConnectionSplitter.doSplit now always splits the connection so
that part #1 is always the part that stays with the existing diagram
connection and part #2 contains the entities that are moved to the newly
created route graph connection resource. Part #1 is the part where the
"output terminal" attached to the connection lies. This simplifies and
clarifies the implementation of doSplit and does not require moving
diagram mapping statements around.

Also, more importantly RouteGraphConnectionSplitter and FlagUtil changes
ensure that diagram mapping is *not* executed in FlagUtil.join, which
was the main cause of the previous corruption. Diagram mapping is only
activated once for the affected diagram(s) after everything else is
done.

gitlab #549
gitlab #586

Change-Id: Icf7479e8e111bf663f637d6909419267cfa4eec4
(cherry picked from commit cc78488e2230fea07726acb86db3c7dd245b39ce)

bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/RouteLine.java
bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/segments/Segment.java
bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/splitting/SplittedRouteGraph.java
bundles/org.simantics.diagram/src/org/simantics/diagram/flag/FlagUtil.java
bundles/org.simantics.diagram/src/org/simantics/diagram/flag/RouteGraphConnectionSplitter.java
bundles/org.simantics.diagram/src/org/simantics/diagram/synchronization/graph/RouteGraphModification.java

index 2011bfa28f153afec115d4c8b3aab2baf9a1dde9..225c4abfe890ecb5250e724777fb5f2dc4659c97 100644 (file)
@@ -113,10 +113,17 @@ public class RouteLine implements RouteNode, Serializable {
             out.print("    HOR");
         else
             out.print("    VER");
+        if (hidden)
+            out.print(" HIDDEN");
+        out.print(" @ " + position);
         for(RoutePoint point : points) {
             out.print(" ("+point.x+","+point.y+")");
         }
         out.print(" (data=" + data + ")");
+        if (nextTransient != null)
+            out.print(" (next transient line=" + nextTransient.getData() + ")");
+        if (terminal != null)
+            out.print(" (terminal=" + terminal.getData() + ")");
         out.println();
     }
 
index b283cb4ed283e3cacda7abbff892a72cf3585f8b..4e4280c0aab746d3d3ea9afdb82d0a2db6f1340c 100644 (file)
@@ -28,4 +28,9 @@ public class Segment {
     public boolean isDegenerated() {
         return p1.getX() == p2.getX() && p1.getY() == p2.getY();
     }
+
+    @Override
+    public String toString() {
+        return String.format("(%f, %f) (%f, %f)", p1.getX(), p1.getY(), p2.getX(), p2.getY());
+    }
 }
index ae79dc019b3cb320f883315599a20952e2fb420d..8f7f71a299f08f5b08a51cf1adc29db72b623c03 100644 (file)
@@ -1,13 +1,17 @@
 package org.simantics.diagram.connection.splitting;
 
-import gnu.trove.set.hash.THashSet;
-
+import java.awt.geom.Line2D;
 import java.awt.geom.Point2D;
+import java.util.ArrayList;
 
 import org.simantics.diagram.connection.RouteGraph;
 import org.simantics.diagram.connection.RouteLine;
 import org.simantics.diagram.connection.RouteNode;
+import org.simantics.diagram.connection.RoutePoint;
 import org.simantics.diagram.connection.RouteTerminal;
+import org.simantics.diagram.connection.segments.Segment;
+
+import gnu.trove.set.hash.THashSet;
 
 public class SplittedRouteGraph {
     public final RouteLine splitLine;
@@ -91,7 +95,75 @@ public class SplittedRouteGraph {
         }
     }
 
-    /**
+    public static final class PickResult {
+        /**
+         * The connection route line nearest to {@link #pickPoint}.
+         */
+        public final RouteLine nearestLine;
+        /**
+         * Original pick point in canvas coordinates.
+         */
+        public final Point2D pickPoint;
+        /**
+         * Intersection point in canvas coordinates of {@link #nearestLine} and
+         * perpendicular line from {@link #pickPoint} to {@link #nearestLine}.
+         */
+        public final Point2D intersectionPoint;
+
+        public PickResult(RouteLine nearestLine, Point2D pickPoint, Point2D intersectionPoint) {
+            this.nearestLine = nearestLine;
+            this.pickPoint = pickPoint;
+            this.intersectionPoint = intersectionPoint;
+        }
+    }
+
+    public static PickResult pickNearestLine(RouteGraph rg, double x, double y) {
+        Segment nearestSegment = null;
+        RouteLine nearestLine = null;
+
+        ArrayList<Segment> segments = new ArrayList<>();
+        double minDistanceSq = Double.MAX_VALUE;
+        for (RouteLine line : rg.getAllLines()) {
+            segments.clear();
+            line.collectSegments(segments);
+            for (Segment segment : segments) {
+                RoutePoint p1 = segment.p1;
+                RoutePoint p2 = segment.p2;
+                double distanceSq = Line2D.ptSegDistSq(p1.getX(), p1.getY(), p2.getX(), p2.getY(), x, y);
+                if (distanceSq < minDistanceSq) {
+                    minDistanceSq = distanceSq;
+                    nearestSegment = segment;
+                    nearestLine = line;
+                }
+            }
+        }
+
+        if (nearestSegment == null)
+            return null;
+
+        RoutePoint p1 = nearestSegment.p1;
+        RoutePoint p2 = nearestSegment.p2;
+        Point2D p = pointToLineIntersection(p1.getX(), p1.getY(), p2.getX(), p2.getY(), x, y);
+        return new PickResult(nearestLine, new Point2D.Double(x, y), p);
+    }
+
+    private static Point2D pointToLineIntersection(double x1, double y1, double x2, double y2, double px, double py) {
+        double d = Math.pow(x2 - x1, 2.0) + Math.pow(y2 - y1, 2.0);
+        if (d == 0) {
+            return new Point2D.Double(x1, y1);
+        } else {
+            double u = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / d;
+            if (u > 1.0) {
+                return new Point2D.Double(x2, y2);
+            } else if (u <= 0.0) {
+                return new Point2D.Double(x1, y1);
+            } else {
+                return new Point2D.Double(x2 * u + x1 * (1.0-u), (y2 * u + y1 * (1.0- u)));
+            }
+        }
+    }
+
+       /**
      * @param point
      * @param line
      * @return the specified point instance snapped to the specified line
index d38a301da3c4a9d93dc60c2de926eaa41af5aea7..e53f4b636baf8480888e72bf30b572a93e43364f 100644 (file)
@@ -176,6 +176,17 @@ public final class FlagUtil {
      * @throws DatabaseException
      */
     public static Resource join(WriteGraph g, Resource flag, Resource otherFlag) throws DatabaseException {
+        return join(g, flag, otherFlag, true);
+    }
+
+    /**
+     * @param g
+     * @param flag
+     * @param otherFlag
+     * @return the created DIA.ConnectionJoin instance
+     * @throws DatabaseException
+     */
+    public static Resource join(WriteGraph g, Resource flag, Resource otherFlag, boolean activateDiagramMapping) throws DatabaseException {
         DiagramResource DIA = DiagramResource.getInstance(g);
         StructuralResource2 STR = StructuralResource2.getInstance(g);
         Resource connectionJoin = g.newResource();
@@ -184,14 +195,24 @@ public final class FlagUtil {
         g.claim(connectionJoin, DIA.JoinsFlag, flag);
         g.claim(connectionJoin, DIA.JoinsFlag, otherFlag);
 
-        IActivationManager manager = g.getService(IActivationManager.class);
-        for(Resource diagram : OrderedSetUtils.getSubjects(g, flag))
-            manager.activateOnce(g, diagram);
-        for(Resource diagram : OrderedSetUtils.getSubjects(g, otherFlag))
-            manager.activateOnce(g, diagram);
+        if (activateDiagramMapping) {
+            activateMappingForParentDiagramsOf(g, flag, otherFlag);
+        }
+
         return connectionJoin;
     }
 
+    public static void activateMappingForParentDiagramsOf(WriteGraph graph, Resource... elements) throws DatabaseException {
+        IActivationManager manager = graph.getService(IActivationManager.class);
+        Set<Resource> diagrams = new HashSet<>(elements.length);
+        for (Resource e : elements) {
+            diagrams.addAll(OrderedSetUtils.getSubjects(graph, e));
+        }
+        for (Resource diagram : diagrams) {
+            manager.activateOnce(graph, diagram);
+        }
+    }
+
     public static void disconnectFlag(WriteGraph graph, Resource flag) throws DatabaseException {
         // Remove any :ConnectionJoin's this flag is joined by
         // if there's less than two flags joined by the join.
@@ -531,5 +552,4 @@ public final class FlagUtil {
        return flags;
     }
 
-
-}
+}
\ No newline at end of file
index 3f1076b5df48e70047cd4dae8d9531bd494c9d0d..5c85a99440a9d7efe09b2eaaff2338d56b78291f 100644 (file)
@@ -1,11 +1,10 @@
 package org.simantics.diagram.flag;
 
-import gnu.trove.map.hash.TObjectIntHashMap;
-
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Point2D;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
 
 import org.simantics.databoard.Bindings;
 import org.simantics.db.ReadGraph;
@@ -24,9 +23,11 @@ import org.simantics.diagram.connection.RouteNode;
 import org.simantics.diagram.connection.RoutePoint;
 import org.simantics.diagram.connection.RouteTerminal;
 import org.simantics.diagram.connection.splitting.SplittedRouteGraph;
+import org.simantics.diagram.connection.splitting.SplittedRouteGraph.PickResult;
 import org.simantics.diagram.content.ConnectionUtil;
 import org.simantics.diagram.stubs.DiagramResource;
 import org.simantics.diagram.synchronization.graph.AddElement;
+import org.simantics.diagram.synchronization.graph.BasicResources;
 import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;
 import org.simantics.diagram.synchronization.graph.RouteGraphModification;
 import org.simantics.g2d.elementclass.FlagClass;
@@ -34,6 +35,8 @@ import org.simantics.layer0.Layer0;
 import org.simantics.modeling.ModelingResources;
 import org.simantics.structural.stubs.StructuralResource2;
 
+import gnu.trove.map.hash.TObjectIntHashMap;
+
 /**
  * A class that handles splitting a route graph connection in two with diagram
  * local flags.
@@ -87,34 +90,33 @@ public class RouteGraphConnectionSplitter {
         RouteGraphModification modis = new RouteGraphModification(ss, rg);
         TObjectIntHashMap<RouteNode> idMap = modis.getIdMap();
 
+        if (DEBUG) {
+            System.out.println("Split canvas position: " + splitCanvasPos);
+            rg.print();
+        }
+
         // Find the edge to disconnect in the graph.
         // Bisect the nearest route line.
-        RouteLine line = SplittedRouteGraph.findNearestLine(rg, splitCanvasPos);
-        if (DEBUG)
-            rg.print();
-        if (line == null)
+        PickResult picked = SplittedRouteGraph.pickNearestLine(rg, splitCanvasPos.getX(), splitCanvasPos.getY());
+        if (picked == null)
             return;
+
+        RouteLine line = picked.nearestLine;
+
         if (DEBUG) {
+            System.out.println("picked nearest line:");
             line.print(System.out);
             for (RoutePoint rp : line.getPoints())
                 System.out.println("RP: " + rp.getX() + ", " + rp.getY());
         }
 
         // Get exact intersection point on the line
-        double isectX = splitCanvasPos.getX();
-        double isectY = splitCanvasPos.getY();
-        SplittedRouteGraph srg;
-        if (line.isHorizontal()) {
-            isectY = line.getPosition();
-            srg = rg.splitGraph(line, isectX);
-        }
-        else {
-            isectX = line.getPosition();
-            srg = rg.splitGraph(line, isectY);
-        }
+        double isectX = picked.intersectionPoint.getX();
+        double isectY = picked.intersectionPoint.getY();
+        SplittedRouteGraph srg = rg.splitGraph(line, line.isHorizontal() ? isectX : isectY);
         if (DEBUG)
             System.out.println(srg);
-        
+
         // Disconnect
         if(rg.isSimpleConnection()) {
             RouteNode na = srg.terminals1.iterator().next();
@@ -141,44 +143,106 @@ public class RouteGraphConnectionSplitter {
                     idMap.get(srg.splitLine)
                     ));
         }
-        
-        ArrayList<Resource> interfaceNodes1Resources = new ArrayList<Resource>(srg.interfaceNodes1.size());
-        for(RouteNode n : srg.interfaceNodes1)
-            interfaceNodes1Resources.add(ss.getResource((Long)n.getData()));
-        ArrayList<Resource> interfaceNodes2Resources = new ArrayList<Resource>(srg.interfaceNodes2.size());
-        for(RouteNode n : srg.interfaceNodes2)
-            interfaceNodes2Resources.add(ss.getResource((Long)n.getData()));
-        
-        ArrayList<Resource> lines2Resources = new ArrayList<Resource>(srg.lines2.size());
-        for(RouteLine n : srg.lines2)
-            lines2Resources.add(ss.getResource((Long)n.getData()));
-        
-        ArrayList<Resource> terminals1Resources = new ArrayList<Resource>(srg.terminals1.size());
-        for(RouteTerminal n : srg.terminals1)
-            terminals1Resources.add(ss.getResource((Long)n.getData()));
-        ArrayList<Resource> terminals2Resources = new ArrayList<Resource>(srg.terminals2.size());
-        for(RouteTerminal n : srg.terminals2)
-            terminals2Resources.add(ss.getResource((Long)n.getData()));
+        ArrayList<Resource> terminals1Resources = toResources(srg.terminals1);
+        ArrayList<Resource> terminals2Resources = toResources(srg.terminals2);
+
+        boolean mustFlip = analyzePartInputs(graph, terminals1Resources, terminals2Resources);
+
+        ArrayList<Resource> interfaceNodes1 = toResources(mustFlip ? srg.interfaceNodes2 : srg.interfaceNodes1);
+        ArrayList<Resource> interfaceNodes2 = toResources(mustFlip ? srg.interfaceNodes1 : srg.interfaceNodes2);
+
+        ArrayList<Resource> lines2 = toResources(mustFlip ? srg.lines1 : srg.lines2);
+        ArrayList<Resource> terminals1 = mustFlip ? terminals2Resources : terminals1Resources;
+        ArrayList<Resource> terminals2 = mustFlip ? terminals1Resources : terminals2Resources;
+
         doSplit(graph, connection,
-                interfaceNodes1Resources,
-                interfaceNodes2Resources,
-                lines2Resources,
-                terminals1Resources,
-                terminals2Resources,
+                interfaceNodes1,
+                interfaceNodes2,
+                lines2,
+                terminals1,
+                terminals2,
                 line.isHorizontal(),
+                mustFlip,
                 isectX, isectY);
         modis.addModi(new RouteGraphModification.Split(
-                modis.toIds(interfaceNodes1Resources),
-                modis.toIds(interfaceNodes2Resources),
-                modis.toIds(lines2Resources),
-                modis.toIds(terminals1Resources),
-                modis.toIds(terminals2Resources),
+                modis.toIds(interfaceNodes1),
+                modis.toIds(interfaceNodes2),
+                modis.toIds(lines2),
+                modis.toIds(terminals1),
+                modis.toIds(terminals2),
                 line.isHorizontal(),
+                mustFlip,
                 isectX, isectY
                 ));
-        
     }
-    
+
+    private ArrayList<Resource> toResources(Collection<? extends RouteNode> nodes) throws DatabaseException {
+        ArrayList<Resource> result = new ArrayList<>(nodes.size());
+        for (RouteNode n : nodes)
+            result.add(ss.getResource((Long)n.getData()));
+        return result;
+    }
+
+    /**
+     * @param graph
+     * @param terminals1
+     * @param terminals2
+     * @return <code>true</code> if inputs need to be flipped, i.e. if terminals2
+     *         contains the output terminals and terminals1 doesn't.
+     * @throws DatabaseException
+     */
+    private boolean analyzePartInputs(ReadGraph graph, List<Resource> terminals1, List<Resource> terminals2) throws DatabaseException {
+        @SuppressWarnings("unused")
+        int inputs1 = 0, outputs1 = 0;
+        for(Resource connector : terminals1) {
+            if(graph.hasStatement(connector, DIA.IsHeadConnectorOf))
+                ++inputs1;
+            else
+                ++outputs1;
+        }
+        @SuppressWarnings("unused")
+        int inputs2 = 0, outputs2 = 0;
+        for(Resource connector : terminals2) {
+            if(graph.hasStatement(connector, DIA.IsHeadConnectorOf))
+                ++inputs2;
+            else
+                ++outputs2;
+        }
+
+        boolean mustFlip = outputs1 == 0;
+
+        if (DEBUG) {
+            System.out.println("inputs1:  " + inputs1);
+            System.out.println("outputs1: " + outputs1);
+            System.out.println("inputs2:  " + inputs2);
+            System.out.println("outputs2: " + outputs2);
+            System.out.println("=> type1:  " + (mustFlip ? FlagClass.Type.In : FlagClass.Type.Out));
+            System.out.println("=> type2:  " + (mustFlip ? FlagClass.Type.Out : FlagClass.Type.In));
+            System.out.println("=> must flip route graph parts to split: " + mustFlip);
+        }
+
+        return mustFlip;
+    }
+
+    private static String routeNodeDebugInfo(ReadGraph graph, Resource c) throws DatabaseException {
+        BasicResources BR = BasicResources.getInstance(graph);
+        String ctr = NameUtils.getSafeName(graph, c, true);
+        for (Resource e : graph.getObjects(c, BR.STR.Connects)) {
+            ctr += " --> " + NameUtils.getSafeName(graph, e);
+        }
+        for (Resource e : graph.getObjects(c, BR.DIA.AreConnected)) {
+            ctr += " <-> " + NameUtils.getSafeName(graph, e);
+        }
+        return ctr;
+    }
+
+    /**
+     * Internal routine that is only public because
+     * {@link RouteGraphModification#runUpdates(WriteGraph)} needs to invoke it.
+     * 
+     * Assumes that #1 parameters will stay with the existing connection and #2
+     * parameters will go to the newly created connection.
+     */
     public void doSplit(WriteGraph graph, 
             Resource connection,
             ArrayList<Resource> interfaceNodes1Resources,
@@ -186,22 +250,28 @@ public class RouteGraphConnectionSplitter {
             ArrayList<Resource> lines2Resources,
             ArrayList<Resource> terminals1Resources,
             ArrayList<Resource> terminals2Resources,
-            boolean isHorizontal, 
+            boolean isHorizontal,
+            boolean invertFlagRotation,
             double isectX, double isectY) throws DatabaseException {
 
+        // 1 = output, 2 = input
+        FlagClass.Type
+                type1 = FlagClass.Type.Out,
+                type2 = FlagClass.Type.In;
+
         if (DEBUG) {
             System.out.println("doSplit:");
             System.out.println(NameUtils.getSafeName(graph, connection, true));
             for (Resource i : interfaceNodes1Resources)
-                System.out.println("i1: " + NameUtils.getSafeName(graph, i, true));
+                System.out.println("i1: " + routeNodeDebugInfo(graph, i));
             for (Resource i : interfaceNodes2Resources)
-                System.out.println("i2: " + NameUtils.getSafeName(graph, i, true));
+                System.out.println("i2: " + routeNodeDebugInfo(graph, i));
             for (Resource l : lines2Resources)
-                System.out.println("l2r: " + NameUtils.getSafeName(graph, l, true));
+                System.out.println("l2r: " + routeNodeDebugInfo(graph, l));
             for (Resource t : terminals1Resources)
-                System.out.println("t1: " + NameUtils.getSafeName(graph, t, true));
+                System.out.println("t1: " + routeNodeDebugInfo(graph, t));
             for (Resource t : terminals2Resources)
-                System.out.println("t2: " + NameUtils.getSafeName(graph, t, true));
+                System.out.println("t2: " + routeNodeDebugInfo(graph, t));
             System.out.println("is horizontal: " + isHorizontal);
             System.out.println("@(x,y): " + isectX + ", " + isectY);
         }
@@ -209,15 +279,39 @@ public class RouteGraphConnectionSplitter {
         ConnectionUtil cu = new ConnectionUtil(graph);
         Resource diagram = OrderedSetUtils.getSingleOwnerList(graph, connection, DIA.Diagram);
 
-        Resource connectionType = graph.getSingleType(connection, DIA.Connection);
+        Resource diagramConnectionType = graph.getSingleType(connection, DIA.Connection);
         Resource hasConnectionType = graph.getPossibleObject(connection, STR.HasConnectionType);
-        Resource newConnection = cu.newConnection(diagram, connectionType);
+        Resource newConnection = cu.newConnection(diagram, diagramConnectionType);
         if (hasConnectionType != null)
             graph.claim(newConnection, STR.HasConnectionType, null, hasConnectionType);
 
         // Give running name to connection increment the counter attached to the diagram.
         AddElement.claimFreshElementName(graph, diagram, newConnection);
 
+        String commonLabel = DiagramFlagPreferences
+                .getActiveFlagLabelingScheme(graph)
+                .generateLabel(graph, diagram);
+
+        Point2D pos1, pos2;
+        double theta;
+        double flagDist = 3.0;
+        if(isHorizontal) {
+            theta = 0.0;
+            pos1 = new Point2D.Double(isectX-flagDist, isectY);
+            pos2 = new Point2D.Double(isectX+flagDist, isectY);
+        } else {
+            theta = Math.PI*0.5;
+            pos1 = new Point2D.Double(isectX, isectY-flagDist);
+            pos2 = new Point2D.Double(isectX, isectY+flagDist);
+        }
+
+        if (invertFlagRotation) {
+            theta += Math.PI;
+            Point2D p = pos1;
+            pos1 = pos2;
+            pos2 = p;
+        }
+
         // WORKAROUND for mapping problems:
         // If any terminal of the split connection contains a flag, make sure their STR.Joins relations are all removed
         // to give mapping a chance to fix them properly.
@@ -237,97 +331,31 @@ public class RouteGraphConnectionSplitter {
             graph.claim(rn, predicate, newConnection);
         }
 
-        // 1 = output, 2 = input
-        FlagClass.Type type1, type2;
-
-        FlagLabelingScheme scheme = DiagramFlagPreferences.getActiveFlagLabelingScheme(graph);
-        String commonLabel = scheme.generateLabel(graph, diagram);
-
         // Create flags and connect both disconnected ends to them.
-        Point2D pos1, pos2;
-        double theta;
-        double flagDist = 3.0;
-        if(isHorizontal) {
-            theta = 0.0;
-            pos1 = new Point2D.Double(isectX-flagDist, isectY);
-            pos2 = new Point2D.Double(isectX+flagDist, isectY);
-        }
-        else {
-            theta = Math.PI*0.5;
-            pos1 = new Point2D.Double(isectX, isectY-flagDist);
-            pos2 = new Point2D.Double(isectX, isectY+flagDist);
-        }
-
-        // Chooses flag directions
-        {
-            @SuppressWarnings("unused")
-            int inputs1 = 0, outputs1 = 0;
-            for(Resource connector : terminals1Resources) {
-                if(graph.hasStatement(connector, DIA.IsHeadConnectorOf))
-                    ++inputs1;
-                else
-                    ++outputs1;
-            }
-            @SuppressWarnings("unused")
-            int inputs2 = 0, outputs2 = 0;
-            for(Resource connector : terminals2Resources) {
-                if(graph.hasStatement(connector, DIA.IsHeadConnectorOf))
-                    ++inputs2;
-                else
-                    ++outputs2;
-            }
-            
-            if(outputs1 == 0) {
-                type1 = FlagClass.Type.In;
-                type2 = FlagClass.Type.Out;
-                theta += Math.PI;
-            }
-            else {
-                type1 = FlagClass.Type.Out;
-                type2 = FlagClass.Type.In;
-            }
-            if (DEBUG) {
-                System.out.println("inputs1:  " + inputs1);
-                System.out.println("outputs1: " + outputs1);
-                System.out.println("=> type1:  " + type1);
-                System.out.println("inputs2:  " + inputs2);
-                System.out.println("outputs2: " + outputs2);
-                System.out.println("=> type2:  " + type2);
-            }
-        }
         Resource flag1 = createFlag(graph, diagram, getFlagTransform(pos1, theta), type1, commonLabel);
         Resource flag2 = createFlag(graph, diagram, getFlagTransform(pos2, theta), type2, commonLabel);
+
         if (DEBUG) {
+            System.out.println("LABEL FOR NEW FLAGS: " + commonLabel);
             System.out.println("FLAG1: " + NameUtils.getSafeName(graph, flag1, true));
             System.out.println("FLAG2: " + NameUtils.getSafeName(graph, flag2, true));
         }
 
-//        System.out.println("conn1: " + NameUtils.getSafeLabel(graph, type1 == FlagClass.Type.In ? DIA.HasPlainConnector : DIA.HasArrowConnector));
-//        System.out.println("conn2: " + NameUtils.getSafeLabel(graph, type2 == FlagClass.Type.In ? DIA.HasPlainConnector : DIA.HasArrowConnector));
-        Resource flagConnector1 = cu.newConnector(connection, 
-                type1 == FlagClass.Type.In ? DIA.HasPlainConnector : DIA.HasArrowConnector);
-        Resource flagConnector2 = cu.newConnector(newConnection, 
-                type2 == FlagClass.Type.In ? DIA.HasPlainConnector : DIA.HasArrowConnector);
+        Resource flagConnector1 = cu.newConnector(connection, DIA.HasArrowConnector); 
+        Resource flagConnector2 = cu.newConnector(newConnection, DIA.HasPlainConnector);
         graph.claim(flag1, DIA.Flag_ConnectionPoint, flagConnector1);
         graph.claim(flag2, DIA.Flag_ConnectionPoint, flagConnector2);
 
         double position = isHorizontal ? isectY : isectX;
-        connectFlag(graph, isHorizontal, position, connection, flagConnector1, 
-                interfaceNodes1Resources);
-        connectFlag(graph, isHorizontal, position, newConnection, flagConnector2, 
-                interfaceNodes2Resources);
-
-        FlagUtil.join(graph, flag1, flag2);
-
-        // Move mapping relations to new connection if necessary
-        if(type1 == FlagClass.Type.In) {
-            moveStatements(graph, connection, newConnection, MOD.ElementToComponent);
-            moveStatements(graph, connection, newConnection, MOD.DiagramConnectionToConnection);
-            moveStatements(graph, connection, newConnection, MOD.DiagramConnectionToConnectionSpecial);
-            FlagUtil.fixBindsStatements(graph, graph.getPossibleObject(newConnection, MOD.DiagramConnectionToConnection));
-        }
-        else
-            FlagUtil.fixBindsStatements(graph, graph.getPossibleObject(connection, MOD.DiagramConnectionToConnection));
+        connectFlag(graph, isHorizontal, position, connection, flagConnector1, interfaceNodes1Resources);
+        connectFlag(graph, isHorizontal, position, newConnection, flagConnector2, interfaceNodes2Resources);
+
+        // Join the flags without activatingn diagram mapping at this point
+        FlagUtil.join(graph, flag1, flag2, false);
+        FlagUtil.fixBindsStatements(graph, graph.getPossibleObject(connection, MOD.DiagramConnectionToConnection));
+
+        // Finally ensure that all the diagrams related to the operation are mapped properly in one go
+        FlagUtil.activateMappingForParentDiagramsOf(graph, flag1, flag2);
     }
 
     /**
@@ -370,15 +398,6 @@ public class RouteGraphConnectionSplitter {
         }
     }
 
-    private static void moveStatements(WriteGraph graph, Resource from, Resource to, Resource relation) throws DatabaseException {
-       if(from.equals(to))
-               return;
-       for(Statement stat : graph.getStatements(from, relation))
-               if(stat.getSubject().equals(from))
-                       graph.claim(to, stat.getPredicate(), stat.getObject());
-       graph.deny(from, relation);
-    }
-    
     private void connectFlag(WriteGraph graph, boolean isHorizontal, double position, Resource connection, Resource flagConnector, Collection<Resource> interfaceNodes) 
             throws DatabaseException {
         if(interfaceNodes.size() > 1) {
@@ -421,6 +440,7 @@ public class RouteGraphConnectionSplitter {
     }
 
     public static void splitConnection(WriteGraph graph, Resource connection, double x, double y) throws DatabaseException {
+        // TODO: provide a proper runtimeDiagram parameter to load to support also connections attached to flags attached to diagram template flag tables
         RouteGraph rg = RouteGraphUtils.load(graph, null, connection);
         new RouteGraphConnectionSplitter(graph).split(graph, connection, rg, new Point2D.Double(x, y));
     }
index a15b99bc45907eeb319cdc7bc5925c0bb1af95be..41f4c00e621641ce6b46f02f8c7266d08d3b20d4 100644 (file)
@@ -162,12 +162,14 @@ public class RouteGraphModification {
         int[] lines2; 
         int[] terminals1; 
         int[] terminals2;
-        boolean isHorizontal; 
+        boolean isHorizontal;
+        boolean invertFlagRotation;
         double isectX;
         double isectY;
         
         public Split(int[] interface1, int[] interface2, int[] lines2,
                 int[] terminals1, int[] terminals2, boolean isHorizontal,
+                boolean invertFlagRotation,
                 double isectX, double isectY) {
             this.interface1 = interface1;
             this.interface2 = interface2;
@@ -175,6 +177,7 @@ public class RouteGraphModification {
             this.terminals1 = terminals1;
             this.terminals2 = terminals2;
             this.isHorizontal = isHorizontal;
+            this.invertFlagRotation = invertFlagRotation;
             this.isectX = isectX;
             this.isectY = isectY;
         }
@@ -188,6 +191,7 @@ public class RouteGraphModification {
             this.terminals1 = readInts(it);
             this.terminals2 = readInts(it);
             this.isHorizontal = Boolean.parseBoolean(it.next());
+            this.invertFlagRotation = Boolean.parseBoolean(it.next());
             this.isectX = Double.parseDouble(it.next());
             this.isectY = Double.parseDouble(it.next());
         }
@@ -208,6 +212,8 @@ public class RouteGraphModification {
             b.append("$");
             b.append(isHorizontal);
             b.append("$");
+            b.append(invertFlagRotation);
+            b.append("$");
             b.append(isectX);
             b.append("$");
             b.append(isectY);
@@ -531,6 +537,7 @@ public class RouteGraphModification {
                         toResources(modi.terminals1),
                         toResources(modi.terminals2),
                         modi.isHorizontal,
+                        modi.invertFlagRotation,
                         modi.isectX,
                         modi.isectY
                         );