]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.modeling/src/org/simantics/modeling/flags/MergeFlags.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.modeling / src / org / simantics / modeling / flags / MergeFlags.java
diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/flags/MergeFlags.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/flags/MergeFlags.java
new file mode 100644 (file)
index 0000000..5f26760
--- /dev/null
@@ -0,0 +1,382 @@
+/*******************************************************************************\r
+ * Copyright (c) 2012 Association for Decentralized Information Management in\r
+ * Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.modeling.flags;\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+import gnu.trove.set.hash.THashSet;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+\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.request.IndexRoot;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.common.utils.OrderedSetUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.diagram.content.ConnectionUtil;\r
+import org.simantics.diagram.stubs.DiagramResource;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.modeling.ModelingResources;\r
+import org.simantics.scl.commands.Commands;\r
+import org.simantics.scl.runtime.tuple.Tuple2;\r
+import org.simantics.structural.stubs.StructuralResource2;\r
+\r
+public class MergeFlags {\r
+\r
+    private static class CP {\r
+        public final Resource component;\r
+        public final Resource connectionPoint;\r
+        \r
+        public CP(Resource component, Resource connectionPoint) {\r
+            super();\r
+            this.component = component;\r
+            this.connectionPoint = connectionPoint;\r
+        }\r
+\r
+        @Override\r
+        public int hashCode() {\r
+            return component.hashCode() + 31 * connectionPoint.hashCode();\r
+        }\r
+\r
+        @Override\r
+        public boolean equals(Object obj) {\r
+            if (this == obj)\r
+                return true;\r
+            if (obj == null)\r
+                return false;\r
+            if (getClass() != obj.getClass())\r
+                return false;\r
+            CP other = (CP) obj;\r
+            return component.equals(other.component) \r
+                    && connectionPoint.equals(other.connectionPoint);\r
+        }\r
+    }\r
+    \r
+    public static String validateForMerge(ReadGraph g,\r
+            List<Resource> flags) throws DatabaseException {\r
+        if(flags.size() <= 1)\r
+            return "At least two flags must be chosen.";\r
+        \r
+        DiagramResource DIA = DiagramResource.getInstance(g);\r
+        StructuralResource2 STR = StructuralResource2.getInstance(g);\r
+        \r
+        for(Resource flag : flags)\r
+            if(!g.hasStatement(flag, DIA.FlagIsJoinedBy))\r
+                return "All flags are not joined to other flags.";\r
+\r
+        List<Resource> connectors = getPossibleRelated(g, flags, DIA.Flag_ConnectionPoint);\r
+        for(Resource connector : connectors) {\r
+            if(connector == null)\r
+                return "All flags are not connected";\r
+        }\r
+        \r
+        List<Resource> connections = getConnection(g, flags, connectors);\r
+        for(Resource connection : connections) {\r
+            if(connection == null)\r
+                return "Invalid flag. Didn't find configuration connection.";\r
+        }\r
+        \r
+        THashSet<Resource> uniqueConnections = new THashSet<Resource>(connections.size());\r
+        for(Resource connection : connections) {\r
+            uniqueConnections.add(connection);\r
+        }\r
+        \r
+        if(uniqueConnections.size() == 1)\r
+            return null;\r
+                \r
+        Iterator<Resource> it = uniqueConnections.iterator();\r
+        THashSet<CP> cps = getConnectionPoints(g, STR, it.next());\r
+        while(it.hasNext()) {\r
+            cps.retainAll(getConnectionPoints(g, STR, it.next()));\r
+            if(cps.isEmpty())\r
+                return "Flags are not connected to a common terminal.";\r
+        }\r
+        \r
+        return null;\r
+    }\r
+    \r
+    private static THashSet<CP> getConnectionPoints(ReadGraph g, StructuralResource2 STR, Resource connection) throws DatabaseException {\r
+        THashSet<CP> result = new THashSet<CP>(); \r
+        for(Statement stat : g.getStatements(connection, STR.Connects))\r
+            result.add(new CP(stat.getObject(), g.getInverse(stat.getPredicate())));\r
+        return result;\r
+    }\r
+    \r
+    /**\r
+     * Merges all flags in the given list to one or two flags.\r
+     * @param g\r
+     * @param flags to join\r
+     * @return Error message or empty string if the operation succeeded.\r
+     */\r
+    public static String merge(WriteGraph g, List<Resource> flags) throws DatabaseException {\r
+        return (String)Commands.get(g, "Simantics/Flag/mergeFlags").execute(g, g.syncRequest(new IndexRoot(flags.get(0))), flags);\r
+    }\r
+    \r
+    public static String mergeWithoutMetadata(WriteGraph g, List<Resource> flags) throws DatabaseException {\r
+        THashMap<Tuple2, ArrayList<Resource>> groups = \r
+                new THashMap<Tuple2, ArrayList<Resource>>();\r
+        \r
+        DiagramResource DIA = DiagramResource.getInstance(g);\r
+        StructuralResource2 STR = StructuralResource2.getInstance(g);\r
+        for(Resource flag : flags) {\r
+            Resource connector = g.getSingleObject(flag, DIA.Flag_ConnectionPoint);\r
+            Resource connection = null;\r
+            for(Resource temp : g.getObjects(connector, STR.Connects))\r
+                if(!temp.equals(flag)) {\r
+                    connection = temp;\r
+                    break;\r
+                }\r
+            if(connection == null)\r
+                continue;\r
+            \r
+            Resource flagType = g.getSingleObject(flag, DIA.HasFlagType);\r
+            Resource connectionType = g.getPossibleObject(connection, STR.HasConnectionType);\r
+            \r
+            Tuple2 tuple = new Tuple2(flagType, connectionType);\r
+            ArrayList<Resource> group = groups.get(tuple);\r
+            if(group == null) {\r
+                group = new ArrayList<Resource>();\r
+                groups.put(tuple, group);\r
+            }\r
+            group.add(flag);\r
+        }\r
+    \r
+        String errorMessage = "";\r
+        for(ArrayList<Resource> group : groups.values()) {\r
+            if(group.size() > 1) {\r
+                String temp = mergeAux(g, group);\r
+                if(temp != null)\r
+                    errorMessage = temp;\r
+            }\r
+        }\r
+        return errorMessage;\r
+    }\r
+    \r
+    /**\r
+     * Merges all flags in the given list to the first flag of the list.\r
+     * @param g\r
+     * @param flags to join\r
+     * @return Error message or null if the operation succeeded.\r
+     */\r
+    private static String mergeAux(WriteGraph g, List<Resource> flags) throws DatabaseException {\r
+        if(flags.size() <= 1)\r
+            return null; // Nothing to do\r
+        \r
+        DiagramResource DIA = DiagramResource.getInstance(g);\r
+        StructuralResource2 STR = StructuralResource2.getInstance(g);\r
+        \r
+        // Find connectors\r
+        List<Resource> connectors = getPossibleRelated(g, flags, DIA.Flag_ConnectionPoint);\r
+        for(Resource connector : connectors) {\r
+            if(connector == null)\r
+                return "All flags are not connected";\r
+        }        \r
+        \r
+        // Find configuration connections\r
+        List<Resource> connections = getConnection(g, flags, connectors);\r
+        for(Resource connection : connections) {\r
+            if(connection == null)\r
+                return "Invalid flag. Didn't find configuration connection.";\r
+        }\r
+        \r
+        // Choose canonical flag and connection where other flags are merged to\r
+        Resource canonicalFlag = flags.get(0);\r
+        Resource canonicalConnection = connections.get(0);\r
+        \r
+        // Do the merging\r
+        for(int i=1;i<flags.size();++i) {\r
+            Resource flag = flags.get(i);\r
+            Resource connection = connections.get(i);\r
+            \r
+            // Replace references in joins to the canonical flag and connection\r
+            for(Resource join : g.getObjects(flag, DIA.FlagIsJoinedBy)) {\r
+                g.denyStatement(flag, DIA.FlagIsJoinedBy, join);\r
+                g.claim(canonicalFlag, DIA.FlagIsJoinedBy, join);\r
+                g.denyStatement(join, STR.Joins, connection);\r
+                g.claim(join, STR.Joins, canonicalConnection);\r
+            }\r
+            \r
+            // Remove flag and its connector\r
+            removeElement(g, flag);\r
+            g.deny(connectors.get(i));\r
+        }\r
+        \r
+        // Clean up connections (remove extra route lines and complete connections)\r
+        THashSet<Resource> uniqueConnections = new THashSet<Resource>(connections.size());\r
+        for(int i=1;i<connections.size();++i)\r
+            uniqueConnections.add(connections.get(i));\r
+        \r
+        for(Resource connection : uniqueConnections)\r
+            cleanUpConnection(g, connection);\r
+        \r
+        return null;\r
+    }\r
+\r
+    private static void cleanUpConnection(WriteGraph g, Resource connection) throws DatabaseException {\r
+        DiagramResource DIA = DiagramResource.getInstance(g);\r
+        StructuralResource2 STR = StructuralResource2.getInstance(g);\r
+        ModelingResources MOD = ModelingResources.getInstance(g);\r
+        \r
+        Resource diagramConnection = g.getSingleObject(connection, MOD.ConnectionToDiagramConnection);\r
+        \r
+        // If connection is degenerated, remove it\r
+        if(g.getObjects(connection, STR.IsJoinedBy).size() == 0 &&  \r
+                g.getObjects(connection, STR.Connects).size() <= 1) {\r
+            g.deny(connection);\r
+            // Garbage collection removes interior route nodes etc. stuff\r
+            //removeElement(g, diagramConnection);\r
+            // platform #4473: Remove connection completely to not leave behind stray connectors.\r
+            new ConnectionUtil(g).removeConnection(diagramConnection);\r
+        }\r
+        // Otherwise just remove degenerated route nodes\r
+        else {\r
+            boolean modifiedSomething = true;\r
+            while(modifiedSomething) { // loop until no modification are made (O(n^2) algorithm)\r
+                modifiedSomething = false;\r
+                for(Resource routeNode : g.getObjects(diagramConnection, DIA.HasInteriorRouteNode))\r
+                    if(g.getObjects(routeNode, DIA.AreConnected).size() <= 1) {\r
+                        g.deny(routeNode);\r
+                        modifiedSomething = true;\r
+                    }\r
+            }\r
+        }\r
+    }\r
+    \r
+    private static void removeElement(WriteGraph g, Resource element) throws DatabaseException {\r
+        OrderedSetUtils.remove(g, OrderedSetUtils.getSingleOwnerList(g, element), element);\r
+        g.deny(element);\r
+    }\r
+\r
+    private static List<Resource> getConnection(ReadGraph g, List<Resource> flags, List<Resource> connectors) throws DatabaseException {\r
+        ArrayList<Resource> result = new ArrayList<Resource>(flags.size());\r
+        for(int i=0;i<flags.size();++i)\r
+            result.add(getConnection(g, flags.get(i), connectors.get(i)));\r
+        return result;\r
+    }\r
+    \r
+    private static Resource getConnection(ReadGraph g, Resource flag, Resource connector) throws DatabaseException {\r
+        StructuralResource2 STR = StructuralResource2.getInstance(g);\r
+        ModelingResources MOD = ModelingResources.getInstance(g);\r
+        for(Resource diagramConnection : g.getObjects(connector, STR.Connects)) {\r
+            if(!flag.equals(diagramConnection)) {\r
+                return g.getPossibleObject(diagramConnection, MOD.DiagramConnectionToConnection);\r
+            }\r
+        }\r
+        return null;\r
+    }\r
+    \r
+    private static List<Resource> getPossibleRelated(ReadGraph g, List<Resource> subjects, Resource relation) throws DatabaseException {\r
+        ArrayList<Resource> result = new ArrayList<Resource>(subjects.size());\r
+        for(int i=0;i<subjects.size();++i)\r
+            result.add(g.getPossibleObject(subjects.get(i), relation));\r
+        return result;\r
+    }\r
+\r
+       public static void expandFlagSet(ReadGraph graph, List<Resource> flags) throws DatabaseException {\r
+               DiagramResource DIA = DiagramResource.getInstance(graph);\r
+               StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
+                               \r
+               THashSet<Resource> connectionSet = new THashSet<Resource>();\r
+               \r
+               for(Resource flag : flags) {\r
+                       for(Resource connector : graph.getObjects(flag, STR.IsConnectedTo))\r
+                               for(Resource connection : graph.getObjects(connector, STR.Connects))\r
+                                       if(!connection.equals(flag))\r
+                                               connectionSet.add(connection);\r
+               }\r
+               \r
+               for(Resource connection : connectionSet.toArray(new Resource[connectionSet.size()])) {\r
+                       for(Resource connector : graph.getObjects(connection, STR.IsConnectedTo))\r
+                               for(Statement stat : graph.getStatements(connector, STR.Connects))\r
+                                       if(!stat.getObject().equals(connection))\r
+                                               for(Resource connector2 : graph.getObjects(stat.getObject(), graph.getInverse(stat.getPredicate())))\r
+                                                       if(!connector2.equals(connector))\r
+                                                               for(Resource connection2 : graph.getObjects(connector2, STR.Connects))\r
+                                                                       if(graph.isInstanceOf(connection2, DIA.Connection))\r
+                                                                               connectionSet.add(connection2);\r
+               }\r
+               \r
+               THashSet<Resource> visited = new THashSet<Resource>(flags);\r
+                                               \r
+               for(Resource connection : connectionSet) {\r
+                       visited.add(connection);\r
+                       for(Resource connector : graph.getObjects(connection, STR.IsConnectedTo))\r
+                               for(Resource flag : graph.getObjects(connector, STR.Connects))\r
+                                       if(visited.add(flag) && graph.isInstanceOf(flag, DIA.Flag)\r
+                                               && graph.hasStatement(flag, DIA.FlagIsJoinedBy))\r
+                                               flags.add(flag);\r
+               }                                       \r
+       }   \r
+       \r
+       public static void collectFlagGroupsInComposite(ReadGraph g, Resource composite, ArrayList<ArrayList<Resource>> groups) throws DatabaseException {\r
+           DiagramResource DIA = DiagramResource.getInstance(g);\r
+        ModelingResources MOD = ModelingResources.getInstance(g);\r
+        Layer0 L0 = Layer0.getInstance(g);\r
+        \r
+        Resource diagram = g.getPossibleObject(composite, MOD.CompositeToDiagram);\r
+        if(diagram == null)\r
+            return;\r
+        \r
+        THashSet<Resource> flags = new THashSet<Resource>();\r
+        for(Resource element : g.getObjects(diagram, L0.ConsistsOf))\r
+            if(g.isInstanceOf(element, DIA.Flag) && g.hasStatement(element, DIA.FlagIsJoinedBy))\r
+                flags.add(element);\r
+        \r
+        for(Resource flag : flags.toArray(new Resource[flags.size()])) \r
+            if(flags.contains(flag)) {\r
+                ArrayList<Resource> group = new ArrayList<Resource>();\r
+                group.add(flag);\r
+                expandFlagSet(g, group);\r
+                flags.removeAll(group);\r
+                if(group.size() > 1)\r
+                    groups.add(group);\r
+            }\r
+       }\r
+       \r
+       public static void expandCompositeSet(ReadGraph g, THashSet<Resource> composites) throws DatabaseException {\r
+           for(Resource composite : composites.toArray(new Resource[composites.size()]))\r
+               expandCompositeSet(g, composite, composites);\r
+       }\r
+\r
+    private static void expandCompositeSet(ReadGraph g, Resource composite,\r
+            THashSet<Resource> composites) throws DatabaseException {\r
+        Layer0 L0 = Layer0.getInstance(g);\r
+        StructuralResource2 STR = StructuralResource2.getInstance(g);\r
+        for(Resource child : g.getObjects(composite, L0.ConsistsOf))\r
+            if(g.isInstanceOf(child, STR.Composite))\r
+                if(composites.add(child))\r
+                    expandCompositeSet(g, child, composites);\r
+    }\r
+    \r
+    public static String mergeFlags (WriteGraph graph, Resource diagram ) throws DatabaseException {\r
+       \r
+       ArrayList<ArrayList<Resource>> groups = new ArrayList<ArrayList<Resource>>();\r
+       MergeFlags.collectFlagGroupsInComposite(graph, diagram, groups);\r
+        for(ArrayList<Resource> group : groups) {\r
+               MergeFlags.merge(graph, group);\r
+        }\r
+\r
+               return "Merged flags in diagram resource: " + diagram.toString() + " and name: " + NameUtils.getSafeName(graph, diagram);\r
+    }\r
+    \r
+    public static void expandFlags(WriteGraph graph, Resource diagram) throws DatabaseException {\r
+       ArrayList<Resource> groups = new ArrayList<Resource>();\r
+       ExpandFlags.collectGroupedFlags(graph, diagram, groups);\r
+       for(Resource group : groups) {\r
+               ExpandFlags.expandFlag(graph, group);\r
+       }\r
+    }    \r
+}\r