]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.g2d/src/org/simantics/g2d/utils/TopologicalSelectionExpander.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.g2d / src / org / simantics / g2d / utils / TopologicalSelectionExpander.java
index 55f2ce1fb09bf9d55b18539ef8b6f42af15c5afe..f9b121ad4ed187346432e2c0177534830eb3127d 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in 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.g2d.utils;\r
-\r
-import java.util.ArrayDeque;\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.Collections;\r
-import java.util.Deque;\r
-import java.util.HashSet;\r
-import java.util.Queue;\r
-import java.util.Set;\r
-\r
-import org.simantics.g2d.connection.ConnectionEntity;\r
-import org.simantics.g2d.diagram.IDiagram;\r
-import org.simantics.g2d.diagram.handler.DataElementMap;\r
-import org.simantics.g2d.diagram.handler.RelationshipHandler;\r
-import org.simantics.g2d.diagram.handler.RelationshipHandler.Relation;\r
-import org.simantics.g2d.diagram.handler.Topology;\r
-import org.simantics.g2d.diagram.handler.Topology.Connection;\r
-import org.simantics.g2d.diagram.handler.Topology.Terminal;\r
-import org.simantics.g2d.element.ElementHints;\r
-import org.simantics.g2d.element.IElement;\r
-import org.simantics.g2d.element.handler.TerminalTopology;\r
-import org.simantics.g2d.elementclass.FlagHandler;\r
-\r
-/**\r
- * This class tries to expand the selection provided by the specified elements\r
- * by a single expansion step. Its purpose is to provide a way for the user to\r
- * easily select a larger range of elements based on the diagram connectivity.\r
- * This can be useful e.g. when preparing for a copy-paste operation or simply\r
- * for visualizing the connectivity of a diagram.</p>\r
- * \r
- * <p>\r
- * The expansion logic is as follows:\r
- * </p>\r
- * <ol>\r
- * <li>If connections are included in the current selection, make sure that no\r
- * connection entity is only partly selected. If only partly selected connection\r
- * entities are found, complete those and stop there. Otherwise continue to the\r
- * next step.</li>\r
- * <li>Expand the current selection by one step. For connections this means\r
- * selecting all nodes that are attached by the connection but not yet in the\r
- * current selection. For nodes this means expanding the selection to all the\r
- * connections reachable from that particular node.</li>\r
- * </ol>\r
- * \r
- * @author Tuukka Lehtonen\r
- */\r
-public class TopologicalSelectionExpander {\r
-\r
-    public static final boolean DEBUG = false;\r
-\r
-    IDiagram              diagram;\r
-    Set<IElement>         startSelection;\r
-    Set<IElement>         resultSelection;\r
-    Set<ConnectionEntity> processedConnections = new HashSet<ConnectionEntity>();\r
-\r
-    Topology              topology;\r
-    DataElementMap        dem;\r
-\r
-    public static Set<IElement> expandSelection(IDiagram diagram, Set<IElement> elements) {\r
-        return new TopologicalSelectionExpander(diagram, elements).expanded();\r
-    }\r
-\r
-    public TopologicalSelectionExpander(IDiagram diagram, Set<IElement> startSelection) {\r
-        assert diagram != null;\r
-\r
-        this.diagram = diagram;\r
-        this.startSelection = startSelection;\r
-        this.resultSelection = new HashSet<IElement>(startSelection);\r
-\r
-        this.topology = diagram.getDiagramClass().getAtMostOneItemOfClass(Topology.class);\r
-        this.dem = diagram.getDiagramClass().getAtMostOneItemOfClass(DataElementMap.class);\r
-    }\r
-\r
-    /**\r
-     * @return <code>null</code> if the selection did not change in the\r
-     *         expansion, another set of elements otherwise\r
-     */\r
-    public Set<IElement> expandedIfChanged() {\r
-        Set<IElement> result = expanded();\r
-        if (DEBUG)\r
-            System.out.println("result selection: " + result);\r
-        if (result.equals(startSelection))\r
-            return null;\r
-        if (DEBUG)\r
-            System.out.println("setting new selection");\r
-        return result;\r
-    }\r
-\r
-    /**\r
-     * @return\r
-     */\r
-    public Set<IElement> expanded() {\r
-        if (topology == null || dem == null || startSelection.isEmpty())\r
-            return startSelection;\r
-\r
-        if (DEBUG)\r
-            System.out.println("expand start selection: " + startSelection);\r
-\r
-        Deque<IElement> work = new ArrayDeque<IElement>(startSelection.size() + 4);\r
-        work.addAll(startSelection);\r
-\r
-        // 1. Iterate the start selection to see if there are any partly\r
-        // selected connection entities. If so, then only complete the\r
-        // selection of those entities before expanding the selection in\r
-        // any other way.\r
-        boolean connectionPartsSelected = false;\r
-        for (IElement e : work) {\r
-            IElement connection = getConnectionOfConnectionPart(e);\r
-            if (connection != null) {\r
-                // There was a mere connection part selection among the selection.\r
-                Set<IElement> connectionParts = getAllConnectionEntityParts(e);\r
-                if (!connectionParts.isEmpty()) {\r
-                    if (DEBUG)\r
-                        System.out.println("\tconnection part selected: " + e + ", replacing with connection " + connection);\r
-                    resultSelection.add(connection);\r
-                    resultSelection.removeAll(connectionParts);\r
-                    connectionPartsSelected = true;\r
-                }\r
-            }\r
-        }\r
-\r
-        if (!connectionPartsSelected) {\r
-            // No connection entities were partly selected. Go ahead with\r
-            // the normal selection expansion procedure.\r
-            while (!work.isEmpty()) {\r
-                IElement e = work.poll();\r
-                if (DEBUG)\r
-                    System.out.println("\texpanding at element: " + e);\r
-                @SuppressWarnings("unused")\r
-                boolean expanded = expandConnection(e, work) || expandNode(e, work);\r
-            }\r
-        }\r
-\r
-        if (DEBUG)\r
-            System.out.println("expanded selection: " + resultSelection);\r
-        return resultSelection;\r
-    }\r
-\r
-    boolean expandConnection(IElement connection, Queue<IElement> workQueue) {\r
-        ConnectionEntity ce = connection.getHint(ElementHints.KEY_CONNECTION_ENTITY);\r
-        if (ce == null)\r
-            return false;\r
-\r
-        if (!processedConnections.add(ce))\r
-            return true;\r
-\r
-        // Expand the selection to all the nodes attached to this connection.\r
-        if (DEBUG)\r
-            System.out.println("\texpanding at connection " + ce);\r
-        Collection<Connection> terminals = new ArrayList<Connection>();\r
-        ce.getTerminalConnections(terminals);\r
-        if (DEBUG)\r
-            System.out.println("\t\tfound " + terminals.size() + " terminal connections: " + terminals);\r
-        for (Connection terminal : terminals) {\r
-            if (resultSelection.add(terminal.node)) {\r
-                if (DEBUG)\r
-                    System.out.println("\t\t\tadding node '" + terminal.node + "' at terminal '" + terminal.terminal + "'");\r
-            }\r
-        }\r
-        return true;\r
-    }\r
-\r
-    boolean expandNode(IElement e, Queue<IElement> workQueue) {\r
-        // This is a node.\r
-        TerminalTopology tt = e.getElementClass().getAtMostOneItemOfClass(TerminalTopology.class);\r
-        if (tt == null)\r
-            return false;\r
-        if (DEBUG)\r
-            System.out.println("\texpanding selection to node terminal connections: " + e);\r
-\r
-        Collection<Terminal> terminals = new ArrayList<Terminal>();\r
-        tt.getTerminals(e, terminals);\r
-        Collection<Connection> connections = new ArrayList<Connection>();\r
-        for (Terminal terminal : terminals) {\r
-            topology.getConnections(e, terminal, connections);\r
-        }\r
-        if (DEBUG)\r
-            System.out.println("\t\tfound " + connections.size() + " connected terminals: " + connections);\r
-        for (Connection connection : connections) {\r
-            IElement conn = getConnectionEntityConnection(connection.edge);\r
-            if (conn != null) {\r
-                if (DEBUG)\r
-                    System.out.println("\t\t\tadding connection: " + conn);\r
-                resultSelection.add(conn);\r
-            }\r
-        }\r
-        \r
-        boolean expanded = !connections.isEmpty(); \r
-\r
-        // We want to:\r
-        // * expand selection to monitors and other related "sub-elements" of the selection\r
-        // We don't want to:\r
-        // * expand selection through flags\r
-        FlagHandler fh = e.getElementClass().getAtMostOneItemOfClass(FlagHandler.class);\r
-        if (fh == null) {\r
-            RelationshipHandler rh = diagram.getDiagramClass().getAtMostOneItemOfClass(RelationshipHandler.class);\r
-            if (rh != null) {\r
-                for(Relation rel : rh.getRelations(diagram, e, new ArrayList<Relation>())) {\r
-                    if(rel.getSubject() instanceof IElement) {\r
-                        expanded |= resultSelection.add((IElement)rel.getSubject());\r
-                    }\r
-                    if(rel.getObject() instanceof IElement) {\r
-                        expanded |= resultSelection.add((IElement)rel.getObject());\r
-                    }\r
-                }\r
-            }\r
-        }\r
-\r
-        return expanded;\r
-    }\r
-\r
-    static IElement getConnectionOfConnectionPart(IElement e) {\r
-        ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY);\r
-        if (ce == null)\r
-            return null;\r
-        IElement c = ce.getConnection();\r
-        if (c == e)\r
-            return null;\r
-        return c;\r
-    }\r
-\r
-    static IElement getConnectionEntityConnection(IElement e) {\r
-        ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY);\r
-        if (ce == null)\r
-            return null;\r
-        return ce.getConnection();\r
-    }\r
-\r
-    static Set<IElement> getAllConnectionEntityParts(IElement e) {\r
-        ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY);\r
-        if (ce == null)\r
-            return Collections.emptySet();\r
-        Set<IElement> result = new HashSet<IElement>();\r
-        result.add(e);\r
-        ce.getBranchPoints(result);\r
-        ce.getSegments(result);\r
-        return result;\r
-    }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.g2d.utils;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashSet;
+import java.util.Queue;
+import java.util.Set;
+
+import org.simantics.g2d.connection.ConnectionEntity;
+import org.simantics.g2d.diagram.IDiagram;
+import org.simantics.g2d.diagram.handler.DataElementMap;
+import org.simantics.g2d.diagram.handler.RelationshipHandler;
+import org.simantics.g2d.diagram.handler.RelationshipHandler.Relation;
+import org.simantics.g2d.diagram.handler.Topology;
+import org.simantics.g2d.diagram.handler.Topology.Connection;
+import org.simantics.g2d.diagram.handler.Topology.Terminal;
+import org.simantics.g2d.element.ElementHints;
+import org.simantics.g2d.element.IElement;
+import org.simantics.g2d.element.handler.TerminalTopology;
+import org.simantics.g2d.elementclass.FlagHandler;
+
+/**
+ * This class tries to expand the selection provided by the specified elements
+ * by a single expansion step. Its purpose is to provide a way for the user to
+ * easily select a larger range of elements based on the diagram connectivity.
+ * This can be useful e.g. when preparing for a copy-paste operation or simply
+ * for visualizing the connectivity of a diagram.</p>
+ * 
+ * <p>
+ * The expansion logic is as follows:
+ * </p>
+ * <ol>
+ * <li>If connections are included in the current selection, make sure that no
+ * connection entity is only partly selected. If only partly selected connection
+ * entities are found, complete those and stop there. Otherwise continue to the
+ * next step.</li>
+ * <li>Expand the current selection by one step. For connections this means
+ * selecting all nodes that are attached by the connection but not yet in the
+ * current selection. For nodes this means expanding the selection to all the
+ * connections reachable from that particular node.</li>
+ * </ol>
+ * 
+ * @author Tuukka Lehtonen
+ */
+public class TopologicalSelectionExpander {
+
+    public static final boolean DEBUG = false;
+
+    IDiagram              diagram;
+    Set<IElement>         startSelection;
+    Set<IElement>         resultSelection;
+    Set<ConnectionEntity> processedConnections = new HashSet<ConnectionEntity>();
+
+    Topology              topology;
+    DataElementMap        dem;
+
+    public static Set<IElement> expandSelection(IDiagram diagram, Set<IElement> elements) {
+        return new TopologicalSelectionExpander(diagram, elements).expanded();
+    }
+
+    public TopologicalSelectionExpander(IDiagram diagram, Set<IElement> startSelection) {
+        assert diagram != null;
+
+        this.diagram = diagram;
+        this.startSelection = startSelection;
+        this.resultSelection = new HashSet<IElement>(startSelection);
+
+        this.topology = diagram.getDiagramClass().getAtMostOneItemOfClass(Topology.class);
+        this.dem = diagram.getDiagramClass().getAtMostOneItemOfClass(DataElementMap.class);
+    }
+
+    /**
+     * @return <code>null</code> if the selection did not change in the
+     *         expansion, another set of elements otherwise
+     */
+    public Set<IElement> expandedIfChanged() {
+        Set<IElement> result = expanded();
+        if (DEBUG)
+            System.out.println("result selection: " + result);
+        if (result.equals(startSelection))
+            return null;
+        if (DEBUG)
+            System.out.println("setting new selection");
+        return result;
+    }
+
+    /**
+     * @return
+     */
+    public Set<IElement> expanded() {
+        if (topology == null || dem == null || startSelection.isEmpty())
+            return startSelection;
+
+        if (DEBUG)
+            System.out.println("expand start selection: " + startSelection);
+
+        Deque<IElement> work = new ArrayDeque<IElement>(startSelection.size() + 4);
+        work.addAll(startSelection);
+
+        // 1. Iterate the start selection to see if there are any partly
+        // selected connection entities. If so, then only complete the
+        // selection of those entities before expanding the selection in
+        // any other way.
+        boolean connectionPartsSelected = false;
+        for (IElement e : work) {
+            IElement connection = getConnectionOfConnectionPart(e);
+            if (connection != null) {
+                // There was a mere connection part selection among the selection.
+                Set<IElement> connectionParts = getAllConnectionEntityParts(e);
+                if (!connectionParts.isEmpty()) {
+                    if (DEBUG)
+                        System.out.println("\tconnection part selected: " + e + ", replacing with connection " + connection);
+                    resultSelection.add(connection);
+                    resultSelection.removeAll(connectionParts);
+                    connectionPartsSelected = true;
+                }
+            }
+        }
+
+        if (!connectionPartsSelected) {
+            // No connection entities were partly selected. Go ahead with
+            // the normal selection expansion procedure.
+            while (!work.isEmpty()) {
+                IElement e = work.poll();
+                if (DEBUG)
+                    System.out.println("\texpanding at element: " + e);
+                @SuppressWarnings("unused")
+                boolean expanded = expandConnection(e, work) || expandNode(e, work);
+            }
+        }
+
+        if (DEBUG)
+            System.out.println("expanded selection: " + resultSelection);
+        return resultSelection;
+    }
+
+    boolean expandConnection(IElement connection, Queue<IElement> workQueue) {
+        ConnectionEntity ce = connection.getHint(ElementHints.KEY_CONNECTION_ENTITY);
+        if (ce == null)
+            return false;
+
+        if (!processedConnections.add(ce))
+            return true;
+
+        // Expand the selection to all the nodes attached to this connection.
+        if (DEBUG)
+            System.out.println("\texpanding at connection " + ce);
+        Collection<Connection> terminals = new ArrayList<Connection>();
+        ce.getTerminalConnections(terminals);
+        if (DEBUG)
+            System.out.println("\t\tfound " + terminals.size() + " terminal connections: " + terminals);
+        for (Connection terminal : terminals) {
+            if (resultSelection.add(terminal.node)) {
+                if (DEBUG)
+                    System.out.println("\t\t\tadding node '" + terminal.node + "' at terminal '" + terminal.terminal + "'");
+            }
+        }
+        return true;
+    }
+
+    boolean expandNode(IElement e, Queue<IElement> workQueue) {
+        // This is a node.
+        TerminalTopology tt = e.getElementClass().getAtMostOneItemOfClass(TerminalTopology.class);
+        if (tt == null)
+            return false;
+        if (DEBUG)
+            System.out.println("\texpanding selection to node terminal connections: " + e);
+
+        Collection<Terminal> terminals = new ArrayList<Terminal>();
+        tt.getTerminals(e, terminals);
+        Collection<Connection> connections = new ArrayList<Connection>();
+        for (Terminal terminal : terminals) {
+            topology.getConnections(e, terminal, connections);
+        }
+        if (DEBUG)
+            System.out.println("\t\tfound " + connections.size() + " connected terminals: " + connections);
+        for (Connection connection : connections) {
+            IElement conn = getConnectionEntityConnection(connection.edge);
+            if (conn != null) {
+                if (DEBUG)
+                    System.out.println("\t\t\tadding connection: " + conn);
+                resultSelection.add(conn);
+            }
+        }
+        
+        boolean expanded = !connections.isEmpty(); 
+
+        // We want to:
+        // * expand selection to monitors and other related "sub-elements" of the selection
+        // We don't want to:
+        // * expand selection through flags
+        FlagHandler fh = e.getElementClass().getAtMostOneItemOfClass(FlagHandler.class);
+        if (fh == null) {
+            RelationshipHandler rh = diagram.getDiagramClass().getAtMostOneItemOfClass(RelationshipHandler.class);
+            if (rh != null) {
+                for(Relation rel : rh.getRelations(diagram, e, new ArrayList<Relation>())) {
+                    if(rel.getSubject() instanceof IElement) {
+                        expanded |= resultSelection.add((IElement)rel.getSubject());
+                    }
+                    if(rel.getObject() instanceof IElement) {
+                        expanded |= resultSelection.add((IElement)rel.getObject());
+                    }
+                }
+            }
+        }
+
+        return expanded;
+    }
+
+    static IElement getConnectionOfConnectionPart(IElement e) {
+        ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY);
+        if (ce == null)
+            return null;
+        IElement c = ce.getConnection();
+        if (c == e)
+            return null;
+        return c;
+    }
+
+    static IElement getConnectionEntityConnection(IElement e) {
+        ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY);
+        if (ce == null)
+            return null;
+        return ce.getConnection();
+    }
+
+    static Set<IElement> getAllConnectionEntityParts(IElement e) {
+        ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY);
+        if (ce == null)
+            return Collections.emptySet();
+        Set<IElement> result = new HashSet<IElement>();
+        result.add(e);
+        ce.getBranchPoints(result);
+        ce.getSegments(result);
+        return result;
+    }
+
+}