]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.diagram/src/org/simantics/diagram/flag/Joiner.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.diagram / src / org / simantics / diagram / flag / Joiner.java
index 490a770dfb631e4a24567aada7f24011747a7413..fdd1109ca3909bb5e6c47ae33ff7fa93d580b869 100644 (file)
-package org.simantics.diagram.flag;\r
-\r
-import java.util.Collection;\r
-import java.util.HashSet;\r
-import java.util.Set;\r
-\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.Statement;\r
-import org.simantics.db.WriteGraph;\r
-import org.simantics.db.common.utils.OrderedSetUtils;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.layer0.util.RemoverUtil;\r
-import org.simantics.diagram.content.ConnectionUtil;\r
-import org.simantics.diagram.stubs.DiagramResource;\r
-import org.simantics.g2d.elementclass.FlagClass.Type;\r
-import org.simantics.layer0.Layer0;\r
-import org.simantics.modeling.ModelingResources;\r
-import org.simantics.structural.stubs.StructuralResource2;\r
-\r
-/**\r
- * A class that handles joining of diagram-local flag pairs into a direct\r
- * connections.\r
- * \r
- * @author Tuukka Lehtonen\r
- */\r
-public class Joiner {\r
-\r
-    Layer0              L0;\r
-    DiagramResource     DIA;\r
-    StructuralResource2 STR;\r
-    ModelingResources   MOD;\r
-\r
-    ConnectionUtil cu;\r
-\r
-    public Joiner(ReadGraph graph) {\r
-        this.L0 = Layer0.getInstance(graph);\r
-        this.DIA = DiagramResource.getInstance(graph);\r
-        this.STR = StructuralResource2.getInstance(graph);\r
-        this.MOD = ModelingResources.getInstance(graph);\r
-        this.cu = new ConnectionUtil(graph);\r
-    }\r
-\r
-    public void joinLocal(WriteGraph graph, Collection<Resource> flags) throws DatabaseException {\r
-        // Only those flags that are known to be removed during the joining of\r
-        // two flags are added to this set to prevent processing them multiple times.\r
-        Set<Resource> removed = new HashSet<Resource>();\r
-        for (Resource flag1 : flags) {\r
-            Collection<Resource> flag1Counterparts = FlagUtil.getCounterparts(graph, flag1);\r
-            for (Resource flag2 : flag1Counterparts) {\r
-                boolean flag1Removed = FlagUtil.countCounterparts(graph, flag1) <= 1;\r
-                boolean flag2Removed = FlagUtil.countCounterparts(graph, flag2) <= 1;\r
-                if (flag1Removed && !removed.add(flag1))\r
-                    continue;\r
-                if (flag2Removed && !removed.add(flag2))\r
-                    continue;\r
-                boolean switchFlags = !flag1Removed && flag2Removed;\r
-                Resource f1 = switchFlags ? flag2 : flag1;\r
-                Resource f2 = switchFlags ? flag1 : flag2;\r
-                joinFlagPair(graph, f1, f2);\r
-            }\r
-        }\r
-    }\r
-\r
-    private boolean joinFlagPair(WriteGraph graph, Resource flag1, Resource flag2) throws DatabaseException {\r
-        Type type1 = FlagUtil.getFlagType(graph, flag1);\r
-        Type type2 = FlagUtil.getFlagType(graph, flag2);\r
-\r
-        Resource connector1 = null;\r
-        Resource connector2 = null;\r
-\r
-        Resource connection1 = null;\r
-        Resource connection2 = null;\r
-\r
-        // #7781: prevent joining of flags where one of them or both\r
-        // have no connections to them, i.e. are disconnected.\r
-        // First ensure that both flags are connected to something,\r
-        // even considering joining them.\r
-        for (Resource connector : graph.getObjects(flag1, STR.IsConnectedTo)) {\r
-            connector1 = graph.getPossibleObject(connector, DIA.AreConnected);\r
-            connection1 = ConnectionUtil.getConnection(graph, connector1);\r
-        }\r
-        for (Resource connector : graph.getObjects(flag2, STR.IsConnectedTo)) {\r
-            connector2 = graph.getPossibleObject(connector, DIA.AreConnected);\r
-            connection2 = ConnectionUtil.getConnection(graph, connector2);\r
-        }\r
-        if (connection1 == null || connector1 == null || connection2 == null || connector2 == null)\r
-            return false;\r
-\r
-        // If a flag has more than 1 counterpart it must not be\r
-        // removed because it is a merged flag that has multiple\r
-        // connection joins attached to it.\r
-        boolean removeFlag1 = FlagUtil.countCounterparts(graph, flag1) <= 1;\r
-        boolean removeFlag2 = FlagUtil.countCounterparts(graph, flag2) <= 1;\r
-\r
-        // Disconnect flags from their respective edges\r
-        // This code relies on the fact that flag terminals are\r
-        // functional and can only be connected once. This implies\r
-        // that their :DIA.Connectors cannot have more than one\r
-        // AreConnected relation.\r
-        if (removeFlag1) {\r
-            for (Resource connector : graph.getObjects(flag1, STR.IsConnectedTo)) {\r
-                connector1 = graph.getSingleObject(connector, DIA.AreConnected);\r
-                connection1 = ConnectionUtil.getConnection(graph, connector1);\r
-                cu.removeConnectionPart(connector);\r
-            }\r
-        }\r
-        if (removeFlag2) {\r
-            for (Resource connector : graph.getObjects(flag2, STR.IsConnectedTo)) {\r
-                connector2 = graph.getSingleObject(connector, DIA.AreConnected);\r
-                connection2 = ConnectionUtil.getConnection(graph, connector2);\r
-                cu.removeConnectionPart(connector);\r
-            }\r
-        }\r
-\r
-        // Decide which connection to remove. The strategy is:\r
-        // * always keep the connection that has an ElementToComponent relation.\r
-        // * if there are no ElementToComponent relations, keep the connection on the OutputFlag side.\r
-        // * if flag type information is not available, keep connection1.\r
-        Resource connectionToKeep = connection1;\r
-        Resource connectionToRemove = connection2;\r
-        Resource hasElementToComponent1 = graph.getPossibleObject(connection1, MOD.ElementToComponent);\r
-        Resource hasElementToComponent2 = graph.getPossibleObject(connection2, MOD.ElementToComponent);\r
-        if (hasElementToComponent1 != null && hasElementToComponent2 != null)\r
-            throw new UnsupportedOperationException("Both flag are connected with connections that have mapped components, can't decide which connection to remove in join operation");\r
-        if (hasElementToComponent2 != null\r
-                || (type1 != Type.Out && type2 == Type.Out)) {\r
-            connectionToKeep = connection2;\r
-            connectionToRemove = connection1;\r
-        }\r
-\r
-        // Remove connection join and flags when necessary\r
-        if (removeFlag1)\r
-            for (Resource diagram : OrderedSetUtils.getOwnerLists(graph, flag1, DIA.Diagram))\r
-                OrderedSetUtils.remove(graph, diagram, flag1);\r
-        if (removeFlag2)\r
-            for (Resource diagram : OrderedSetUtils.getOwnerLists(graph, flag2, DIA.Diagram))\r
-                OrderedSetUtils.remove(graph, diagram, flag2);\r
-        FlagUtil.disconnectFlag(graph, flag1);\r
-        double[] transform1 = graph.getRelatedValue(flag1, DIA.HasTransform, Bindings.DOUBLE_ARRAY);\r
-        double[] transform2 = graph.getRelatedValue(flag2, DIA.HasTransform, Bindings.DOUBLE_ARRAY);\r
-        if (removeFlag1)\r
-            RemoverUtil.remove(graph, flag1);\r
-        if (removeFlag2)\r
-            RemoverUtil.remove(graph, flag2);\r
-\r
-        // Move connector from connection to remove to other connection\r
-        for(Statement connectorStat : graph.getStatements(connectionToRemove, DIA.HasConnector)) {\r
-            graph.deny(connectorStat);\r
-            graph.claim(connectionToKeep, connectorStat.getPredicate(), connectorStat.getObject());\r
-        }\r
-        for(Resource node : graph.getObjects(connectionToRemove, DIA.HasInteriorRouteNode)) {\r
-            graph.deny(node, DIA.HasInteriorRouteNode_Inverse, connectionToRemove);\r
-            graph.claim(node, DIA.HasInteriorRouteNode_Inverse, connectionToKeep);\r
-        }\r
-\r
-        // Remove obsolete connection\r
-        cu.removeConnection(connectionToRemove);\r
-\r
-        // Reconnect respective edges\r
-        if(graph.isInstanceOf(connector1, DIA.RouteLine) && graph.isInstanceOf(connector2, DIA.RouteLine)\r
-                && graph.getRelatedValue(connector1, DIA.IsHorizontal) == graph.getRelatedValue(connector2, DIA.IsHorizontal)) {\r
-            boolean horizontal = graph.getRelatedValue(connector1, DIA.IsHorizontal);\r
-\r
-            double position;\r
-            if(horizontal)\r
-                position = 0.5 * (transform1[4] + transform2[4]);\r
-            else\r
-                position = 0.5 * (transform1[5] + transform2[5]);\r
-\r
-            Resource intermediateRouteLine = graph.newResource();\r
-            graph.claim(intermediateRouteLine, L0.InstanceOf, DIA.RouteLine);\r
-            graph.claimLiteral(intermediateRouteLine, DIA.IsHorizontal, !horizontal);\r
-            graph.claimLiteral(intermediateRouteLine, DIA.HasPosition, position);\r
-            graph.claim(connectionToKeep, DIA.HasInteriorRouteNode, intermediateRouteLine);\r
-            graph.claim(connector1, DIA.AreConnected, intermediateRouteLine);\r
-            graph.claim(connector2, DIA.AreConnected, intermediateRouteLine);\r
-        }\r
-        else\r
-            graph.claim(connector1, DIA.AreConnected, connector2);\r
-\r
-        return true;\r
-    }\r
-\r
-    public static void joinFlagsLocal(WriteGraph graph, Collection<Resource> flags) throws DatabaseException {\r
-        new Joiner(graph).joinLocal(graph, flags);\r
-    }\r
-\r
+package org.simantics.diagram.flag;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.Statement;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.utils.OrderedSetUtils;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.util.RemoverUtil;
+import org.simantics.diagram.content.ConnectionUtil;
+import org.simantics.diagram.stubs.DiagramResource;
+import org.simantics.g2d.elementclass.FlagClass.Type;
+import org.simantics.layer0.Layer0;
+import org.simantics.modeling.ModelingResources;
+import org.simantics.structural.stubs.StructuralResource2;
+
+/**
+ * A class that handles joining of diagram-local flag pairs into a direct
+ * connections.
+ * 
+ * @author Tuukka Lehtonen
+ */
+public class Joiner {
+
+    Layer0              L0;
+    DiagramResource     DIA;
+    StructuralResource2 STR;
+    ModelingResources   MOD;
+
+    ConnectionUtil cu;
+
+    public Joiner(ReadGraph graph) {
+        this.L0 = Layer0.getInstance(graph);
+        this.DIA = DiagramResource.getInstance(graph);
+        this.STR = StructuralResource2.getInstance(graph);
+        this.MOD = ModelingResources.getInstance(graph);
+        this.cu = new ConnectionUtil(graph);
+    }
+
+    public void joinLocal(WriteGraph graph, Collection<Resource> flags) throws DatabaseException {
+        // Only those flags that are known to be removed during the joining of
+        // two flags are added to this set to prevent processing them multiple times.
+        Set<Resource> removed = new HashSet<Resource>();
+        for (Resource flag1 : flags) {
+            Collection<Resource> flag1Counterparts = FlagUtil.getCounterparts(graph, flag1);
+            for (Resource flag2 : flag1Counterparts) {
+                boolean flag1Removed = FlagUtil.countCounterparts(graph, flag1) <= 1;
+                boolean flag2Removed = FlagUtil.countCounterparts(graph, flag2) <= 1;
+                if (flag1Removed && !removed.add(flag1))
+                    continue;
+                if (flag2Removed && !removed.add(flag2))
+                    continue;
+                boolean switchFlags = !flag1Removed && flag2Removed;
+                Resource f1 = switchFlags ? flag2 : flag1;
+                Resource f2 = switchFlags ? flag1 : flag2;
+                joinFlagPair(graph, f1, f2);
+            }
+        }
+    }
+
+    private boolean joinFlagPair(WriteGraph graph, Resource flag1, Resource flag2) throws DatabaseException {
+        Type type1 = FlagUtil.getFlagType(graph, flag1);
+        Type type2 = FlagUtil.getFlagType(graph, flag2);
+
+        Resource connector1 = null;
+        Resource connector2 = null;
+
+        Resource connection1 = null;
+        Resource connection2 = null;
+
+        // #7781: prevent joining of flags where one of them or both
+        // have no connections to them, i.e. are disconnected.
+        // First ensure that both flags are connected to something,
+        // even considering joining them.
+        for (Resource connector : graph.getObjects(flag1, STR.IsConnectedTo)) {
+            connector1 = graph.getPossibleObject(connector, DIA.AreConnected);
+            connection1 = ConnectionUtil.getConnection(graph, connector1);
+        }
+        for (Resource connector : graph.getObjects(flag2, STR.IsConnectedTo)) {
+            connector2 = graph.getPossibleObject(connector, DIA.AreConnected);
+            connection2 = ConnectionUtil.getConnection(graph, connector2);
+        }
+        if (connection1 == null || connector1 == null || connection2 == null || connector2 == null)
+            return false;
+
+        // If a flag has more than 1 counterpart it must not be
+        // removed because it is a merged flag that has multiple
+        // connection joins attached to it.
+        boolean removeFlag1 = FlagUtil.countCounterparts(graph, flag1) <= 1;
+        boolean removeFlag2 = FlagUtil.countCounterparts(graph, flag2) <= 1;
+
+        // Disconnect flags from their respective edges
+        // This code relies on the fact that flag terminals are
+        // functional and can only be connected once. This implies
+        // that their :DIA.Connectors cannot have more than one
+        // AreConnected relation.
+        if (removeFlag1) {
+            for (Resource connector : graph.getObjects(flag1, STR.IsConnectedTo)) {
+                connector1 = graph.getSingleObject(connector, DIA.AreConnected);
+                connection1 = ConnectionUtil.getConnection(graph, connector1);
+                cu.removeConnectionPart(connector);
+            }
+        }
+        if (removeFlag2) {
+            for (Resource connector : graph.getObjects(flag2, STR.IsConnectedTo)) {
+                connector2 = graph.getSingleObject(connector, DIA.AreConnected);
+                connection2 = ConnectionUtil.getConnection(graph, connector2);
+                cu.removeConnectionPart(connector);
+            }
+        }
+
+        // Decide which connection to remove. The strategy is:
+        // * always keep the connection that has an ElementToComponent relation.
+        // * if there are no ElementToComponent relations, keep the connection on the OutputFlag side.
+        // * if flag type information is not available, keep connection1.
+        Resource connectionToKeep = connection1;
+        Resource connectionToRemove = connection2;
+        Resource hasElementToComponent1 = graph.getPossibleObject(connection1, MOD.ElementToComponent);
+        Resource hasElementToComponent2 = graph.getPossibleObject(connection2, MOD.ElementToComponent);
+        if (hasElementToComponent1 != null && hasElementToComponent2 != null)
+            throw new UnsupportedOperationException("Both flag are connected with connections that have mapped components, can't decide which connection to remove in join operation");
+        if (hasElementToComponent2 != null
+                || (type1 != Type.Out && type2 == Type.Out)) {
+            connectionToKeep = connection2;
+            connectionToRemove = connection1;
+        }
+
+        // Remove connection join and flags when necessary
+        if (removeFlag1)
+            for (Resource diagram : OrderedSetUtils.getOwnerLists(graph, flag1, DIA.Diagram))
+                OrderedSetUtils.remove(graph, diagram, flag1);
+        if (removeFlag2)
+            for (Resource diagram : OrderedSetUtils.getOwnerLists(graph, flag2, DIA.Diagram))
+                OrderedSetUtils.remove(graph, diagram, flag2);
+        FlagUtil.disconnectFlag(graph, flag1);
+        double[] transform1 = graph.getRelatedValue(flag1, DIA.HasTransform, Bindings.DOUBLE_ARRAY);
+        double[] transform2 = graph.getRelatedValue(flag2, DIA.HasTransform, Bindings.DOUBLE_ARRAY);
+        if (removeFlag1)
+            RemoverUtil.remove(graph, flag1);
+        if (removeFlag2)
+            RemoverUtil.remove(graph, flag2);
+
+        // Move connector from connection to remove to other connection
+        for(Statement connectorStat : graph.getStatements(connectionToRemove, DIA.HasConnector)) {
+            graph.deny(connectorStat);
+            graph.claim(connectionToKeep, connectorStat.getPredicate(), connectorStat.getObject());
+        }
+        for(Resource node : graph.getObjects(connectionToRemove, DIA.HasInteriorRouteNode)) {
+            graph.deny(node, DIA.HasInteriorRouteNode_Inverse, connectionToRemove);
+            graph.claim(node, DIA.HasInteriorRouteNode_Inverse, connectionToKeep);
+        }
+
+        // Remove obsolete connection
+        cu.removeConnection(connectionToRemove);
+
+        // Reconnect respective edges
+        if(graph.isInstanceOf(connector1, DIA.RouteLine) && graph.isInstanceOf(connector2, DIA.RouteLine)
+                && graph.getRelatedValue(connector1, DIA.IsHorizontal) == graph.getRelatedValue(connector2, DIA.IsHorizontal)) {
+            boolean horizontal = graph.getRelatedValue(connector1, DIA.IsHorizontal);
+
+            double position;
+            if(horizontal)
+                position = 0.5 * (transform1[4] + transform2[4]);
+            else
+                position = 0.5 * (transform1[5] + transform2[5]);
+
+            Resource intermediateRouteLine = graph.newResource();
+            graph.claim(intermediateRouteLine, L0.InstanceOf, DIA.RouteLine);
+            graph.claimLiteral(intermediateRouteLine, DIA.IsHorizontal, !horizontal);
+            graph.claimLiteral(intermediateRouteLine, DIA.HasPosition, position);
+            graph.claim(connectionToKeep, DIA.HasInteriorRouteNode, intermediateRouteLine);
+            graph.claim(connector1, DIA.AreConnected, intermediateRouteLine);
+            graph.claim(connector2, DIA.AreConnected, intermediateRouteLine);
+        }
+        else
+            graph.claim(connector1, DIA.AreConnected, connector2);
+
+        return true;
+    }
+
+    public static void joinFlagsLocal(WriteGraph graph, Collection<Resource> flags) throws DatabaseException {
+        new Joiner(graph).joinLocal(graph, flags);
+    }
+
 }
\ No newline at end of file