]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.diagram/src/org/simantics/diagram/handler/ConnectionCommandHandler.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.diagram / src / org / simantics / diagram / handler / ConnectionCommandHandler.java
index 129cdf16d431055d1189eea6d907b2063c7300e4..ec2bc6a6f185e660107544f57cd439160d434e80 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.diagram.handler;\r
-\r
-import java.awt.geom.AffineTransform;\r
-import java.awt.geom.Line2D;\r
-import java.awt.geom.Point2D;\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.Collections;\r
-import java.util.HashSet;\r
-import java.util.Set;\r
-\r
-import org.simantics.Simantics;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.WriteGraph;\r
-import org.simantics.db.common.request.WriteRequest;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.diagram.content.ConnectionUtil;\r
-import org.simantics.diagram.content.EdgeResource;\r
-import org.simantics.diagram.stubs.DiagramResource;\r
-import org.simantics.diagram.synchronization.graph.RemoveBranchpoint;\r
-import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;\r
-import org.simantics.g2d.connection.ConnectionEntity;\r
-import org.simantics.g2d.diagram.DiagramHints;\r
-import org.simantics.g2d.diagram.IDiagram;\r
-import org.simantics.g2d.diagram.handler.PickRequest;\r
-import org.simantics.g2d.diagram.handler.Topology;\r
-import org.simantics.g2d.diagram.handler.Topology.Connection;\r
-import org.simantics.g2d.diagram.participant.AbstractDiagramParticipant;\r
-import org.simantics.g2d.diagram.participant.Selection;\r
-import org.simantics.g2d.element.ElementHints;\r
-import org.simantics.g2d.element.ElementUtils;\r
-import org.simantics.g2d.element.IElement;\r
-import org.simantics.g2d.elementclass.BranchPoint;\r
-import org.simantics.g2d.elementclass.BranchPoint.Direction;\r
-import org.simantics.g2d.participant.MouseUtil;\r
-import org.simantics.g2d.participant.MouseUtil.MouseInfo;\r
-import org.simantics.g2d.participant.WorkbenchStatusLine;\r
-import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler;\r
-import org.simantics.scenegraph.g2d.events.command.CommandEvent;\r
-import org.simantics.scenegraph.g2d.events.command.Commands;\r
-import org.simantics.scenegraph.g2d.snap.ISnapAdvisor;\r
-import org.simantics.ui.SimanticsUI;\r
-import org.simantics.utils.ui.ErrorLogger;\r
-\r
-/**\r
- * A participant for handling:\r
- * <ul>\r
- * <li>DELETE for deleting route points from DIA.Connection type connections\r
- * <li>SPLIT_CONNECTION for creating new route points into DIA.Connection type connections\r
- * <li>ROTATE_ELEMENT_CW & ROTATE_ELEMENT_CCW for rotating route points orientations.\r
- * </ul>\r
- * \r
- *  NOTE: this participant does nothing useful with DIA.RouteGraphConnection type connections.\r
- * \r
- * @author Tuukka Lehtonen\r
- * \r
- * TODO: start using {@link WorkbenchStatusLine}\r
- */\r
-public class ConnectionCommandHandler extends AbstractDiagramParticipant {\r
-\r
-    @Dependency MouseUtil mouseUtil;\r
-    @Dependency Selection selection;\r
-    //@Dependency WorkbenchStatusLine statusLine;\r
-\r
-    @EventHandler(priority = 100)\r
-    public boolean handleCommand(CommandEvent event) {\r
-        if (Commands.DELETE.equals(event.command)) {\r
-            try {\r
-                return joinConnection();\r
-            } catch (DatabaseException e) {\r
-                ErrorLogger.defaultLogError(e);\r
-                return false;\r
-            }\r
-        } else if (Commands.SPLIT_CONNECTION.equals(event.command) && routePointsEnabled()) {\r
-            return splitConnection();\r
-        } else if (Commands.ROTATE_ELEMENT_CW.equals(event.command) || Commands.ROTATE_ELEMENT_CCW.equals(event.command)) {\r
-            boolean clockWise = Commands.ROTATE_ELEMENT_CW.equals(event.command);\r
-            try {\r
-                return rotateBranchPoint(clockWise);\r
-            } catch (DatabaseException e) {\r
-                ErrorLogger.defaultLogError(e);\r
-                return false;\r
-            }\r
-        }\r
-        return false;\r
-    }\r
-\r
-    private boolean routePointsEnabled() {\r
-        return Boolean.TRUE.equals(diagram.getHint(DiagramHints.KEY_ALLOW_ROUTE_POINTS));\r
-    }\r
-\r
-    boolean joinConnection() throws DatabaseException {\r
-\r
-        final Set<IElement> routePoints = getBranchPoints(2);\r
-\r
-        if (routePoints.isEmpty())\r
-            return false;\r
-\r
-        selection.clear(0);\r
-\r
-        Simantics.getSession().sync(new WriteRequest() {\r
-            @Override\r
-            public void perform(WriteGraph graph) throws DatabaseException {\r
-                for (IElement routePoint : routePoints) {\r
-                    Object node = ElementUtils.getObject(routePoint);\r
-                    if (node instanceof Resource) {\r
-                        new RemoveBranchpoint(routePoint).perform(graph);\r
-                    }\r
-                }\r
-            }\r
-        });\r
-        setDirty();\r
-\r
-        //statusLine.message("Deleted " + routePoints.size() + " route points");\r
-        return true;\r
-    }\r
-\r
-    private boolean rotateBranchPoint(final boolean clockWise) throws DatabaseException {\r
-        final Set<IElement> routePoints = getBranchPoints(Integer.MAX_VALUE);\r
-        if (routePoints.isEmpty())\r
-            return false;\r
-\r
-        // Rotate branch points.\r
-        try {\r
-            SimanticsUI.getSession().syncRequest(new WriteRequest() {\r
-                @Override\r
-                public void perform(WriteGraph graph) throws DatabaseException {\r
-                    DiagramResource DIA = DiagramResource.getInstance(graph);\r
-                    for (IElement bp : routePoints) {\r
-                        Resource bpr = (Resource) ElementUtils.getObject(bp);\r
-                        boolean vertical = graph.hasStatement(bpr, DIA.Vertical, bpr);\r
-                        boolean horizontal = graph.hasStatement(bpr, DIA.Horizontal, bpr);\r
-                        Direction dir = Direction.toDirection(horizontal, vertical);\r
-                        Direction newDir = clockWise ? dir.cycleNext() : dir.cyclePrevious();\r
-                        switch (newDir) {\r
-                            case Any:\r
-                                graph.deny(bpr, DIA.Vertical);\r
-                                graph.deny(bpr, DIA.Horizontal);\r
-                                break;\r
-                            case Horizontal:\r
-                                graph.deny(bpr, DIA.Vertical);\r
-                                graph.claim(bpr, DIA.Horizontal, bpr);\r
-                                break;\r
-                            case Vertical:\r
-                                graph.deny(bpr, DIA.Horizontal);\r
-                                graph.claim(bpr, DIA.Vertical, bpr);\r
-                                break;\r
-                        }\r
-                    }\r
-                }\r
-            });\r
-        } catch (DatabaseException e) {\r
-            ErrorLogger.defaultLogError(e);\r
-        }\r
-\r
-        return true;\r
-    }\r
-\r
-    boolean splitConnection() {\r
-\r
-        final IElement edge = getSingleConnectionSegment();\r
-        if (edge == null)\r
-            return false;\r
-        final IDiagram diagram = ElementUtils.peekDiagram(edge);\r
-        if (diagram == null)\r
-            return false;\r
-\r
-        MouseInfo mi = mouseUtil.getMouseInfo(0);\r
-        final Point2D mousePos = mi.canvasPosition;\r
-\r
-        ISnapAdvisor snap = getHint(DiagramHints.SNAP_ADVISOR);\r
-        if (snap != null)\r
-            snap.snap(mousePos);\r
-\r
-        final AffineTransform splitPos = AffineTransform.getTranslateInstance(mousePos.getX(), mousePos.getY());\r
-\r
-        try {\r
-            SimanticsUI.getSession().syncRequest(new WriteRequest() {\r
-                @Override\r
-                public void perform(WriteGraph graph) throws DatabaseException {\r
-                    DiagramResource DIA = DiagramResource.getInstance(graph);\r
-\r
-                    // Split the edge with a new branch point\r
-                    ConnectionUtil cu = new ConnectionUtil(graph);\r
-                    EdgeResource segment = (EdgeResource) ElementUtils.getObject(edge);\r
-                    Resource bp = cu.split(segment, splitPos);\r
-\r
-                    Line2D nearestLine = ConnectionUtil.resolveNearestEdgeLineSegment(mousePos, edge);\r
-                    if (nearestLine != null) {\r
-                        double angle = Math.atan2(\r
-                                Math.abs(nearestLine.getY2() - nearestLine.getY1()),\r
-                                Math.abs(nearestLine.getX2() - nearestLine.getX1())\r
-                        );\r
-\r
-                        if (angle >= 0 && angle < Math.PI / 4) {\r
-                            graph.claim(bp, DIA.Horizontal, bp);\r
-                        } else if (angle > Math.PI / 4 && angle <= Math.PI / 2) {\r
-                            graph.claim(bp, DIA.Vertical, bp);\r
-                        }\r
-                    }\r
-                }\r
-            });\r
-\r
-            selection.clear(0);\r
-\r
-        } catch (DatabaseException e) {\r
-            ErrorLogger.defaultLogError(e);\r
-        }\r
-\r
-        return false;\r
-    }\r
-\r
-    /**\r
-     * @return all route points in the current diagram selection if and only if\r
-     *         only route points are selected. If anything else is selected,\r
-     *         even branch points, an empty set will be returned.\r
-     */\r
-    Set<IElement> getBranchPoints(int maxDegree) throws DatabaseException {\r
-\r
-        Set<IElement> ss = selection.getSelection(0);\r
-        if (ss.isEmpty())\r
-            return Collections.emptySet();\r
-\r
-        final Set<IElement> result = new HashSet<IElement>();\r
-        Collection<Connection> connections = new ArrayList<Connection>();\r
-        for (IElement e : ss) {\r
-            if (!e.getElementClass().containsClass(BranchPoint.class))\r
-                return Collections.emptySet();\r
-            ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY);\r
-            if (ce == null)\r
-                return Collections.emptySet();\r
-            IDiagram diagram = ElementUtils.peekDiagram(e);\r
-            if (diagram == null)\r
-                return Collections.emptySet();\r
-            for (Topology topology : diagram.getDiagramClass().getItemsByClass(Topology.class)) {\r
-                connections.clear();\r
-                topology.getConnections(e, ElementUtils.getSingleTerminal(e), connections);\r
-                int degree = connections.size();\r
-                if (degree < 2 || degree > maxDegree)\r
-                    return Collections.emptySet();\r
-                result.add(e);\r
-            }\r
-        }\r
-\r
-        return result;\r
-    }\r
-\r
-    /**\r
-     * @return if a single edge is selected, return the edge. If a single\r
-     *         connection is selected and it contains only one edge segment,\r
-     *         return it. Otherwise return <code>null</code>.\r
-     */\r
-    IElement getSingleConnectionSegment() {\r
-        Set<IElement> s = selection.getSelection(0);\r
-        if (s.size() != 1)\r
-            return null;\r
-        IElement e = s.iterator().next();\r
-        if (PickRequest.PickFilter.FILTER_CONNECTIONS.accept(e)) {\r
-            // Does this connection have only one edge and no branch points?\r
-            ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY);\r
-            Collection<IElement> coll = ce.getBranchPoints(null);\r
-            if (!coll.isEmpty())\r
-                return null;\r
-            ce.getSegments(coll);\r
-            if (coll.size() != 1)\r
-                return null;\r
-            // Return the only edge element of the whole connection.\r
-            return coll.iterator().next();\r
-        }\r
-        if (PickRequest.PickFilter.FILTER_CONNECTION_EDGES.accept(e))\r
-            return e;\r
-        return null;\r
-    }\r
-\r
-    /**\r
-     * @return the selected top-level connection element if and only if the\r
-     *         selection contains the connection or parts of the same connection\r
-     *         (edge segments or branch/route points) and nothing else.\r
-     */\r
-    IElement getSingleConnection() {\r
-\r
-        Set<IElement> ss = selection.getSelection(0);\r
-        if (ss.isEmpty())\r
-            return null;\r
-\r
-        IElement result = null;\r
-\r
-        for (IElement e : ss) {\r
-            ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY);\r
-            if (ce == null)\r
-                continue;\r
-            if (result != null && !ce.getConnection().equals(result))\r
-                return null;\r
-            result = ce.getConnection();\r
-        }\r
-\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.diagram.handler;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Line2D;
+import java.awt.geom.Point2D;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.simantics.Simantics;
+import org.simantics.db.Resource;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.request.WriteRequest;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.diagram.content.ConnectionUtil;
+import org.simantics.diagram.content.EdgeResource;
+import org.simantics.diagram.stubs.DiagramResource;
+import org.simantics.diagram.synchronization.graph.RemoveBranchpoint;
+import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;
+import org.simantics.g2d.connection.ConnectionEntity;
+import org.simantics.g2d.diagram.DiagramHints;
+import org.simantics.g2d.diagram.IDiagram;
+import org.simantics.g2d.diagram.handler.PickRequest;
+import org.simantics.g2d.diagram.handler.Topology;
+import org.simantics.g2d.diagram.handler.Topology.Connection;
+import org.simantics.g2d.diagram.participant.AbstractDiagramParticipant;
+import org.simantics.g2d.diagram.participant.Selection;
+import org.simantics.g2d.element.ElementHints;
+import org.simantics.g2d.element.ElementUtils;
+import org.simantics.g2d.element.IElement;
+import org.simantics.g2d.elementclass.BranchPoint;
+import org.simantics.g2d.elementclass.BranchPoint.Direction;
+import org.simantics.g2d.participant.MouseUtil;
+import org.simantics.g2d.participant.MouseUtil.MouseInfo;
+import org.simantics.g2d.participant.WorkbenchStatusLine;
+import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler;
+import org.simantics.scenegraph.g2d.events.command.CommandEvent;
+import org.simantics.scenegraph.g2d.events.command.Commands;
+import org.simantics.scenegraph.g2d.snap.ISnapAdvisor;
+import org.simantics.ui.SimanticsUI;
+import org.simantics.utils.ui.ErrorLogger;
+
+/**
+ * A participant for handling:
+ * <ul>
+ * <li>DELETE for deleting route points from DIA.Connection type connections
+ * <li>SPLIT_CONNECTION for creating new route points into DIA.Connection type connections
+ * <li>ROTATE_ELEMENT_CW & ROTATE_ELEMENT_CCW for rotating route points orientations.
+ * </ul>
+ * 
+ *  NOTE: this participant does nothing useful with DIA.RouteGraphConnection type connections.
+ * 
+ * @author Tuukka Lehtonen
+ * 
+ * TODO: start using {@link WorkbenchStatusLine}
+ */
+public class ConnectionCommandHandler extends AbstractDiagramParticipant {
+
+    @Dependency MouseUtil mouseUtil;
+    @Dependency Selection selection;
+    //@Dependency WorkbenchStatusLine statusLine;
+
+    @EventHandler(priority = 100)
+    public boolean handleCommand(CommandEvent event) {
+        if (Commands.DELETE.equals(event.command)) {
+            try {
+                return joinConnection();
+            } catch (DatabaseException e) {
+                ErrorLogger.defaultLogError(e);
+                return false;
+            }
+        } else if (Commands.SPLIT_CONNECTION.equals(event.command) && routePointsEnabled()) {
+            return splitConnection();
+        } else if (Commands.ROTATE_ELEMENT_CW.equals(event.command) || Commands.ROTATE_ELEMENT_CCW.equals(event.command)) {
+            boolean clockWise = Commands.ROTATE_ELEMENT_CW.equals(event.command);
+            try {
+                return rotateBranchPoint(clockWise);
+            } catch (DatabaseException e) {
+                ErrorLogger.defaultLogError(e);
+                return false;
+            }
+        }
+        return false;
+    }
+
+    private boolean routePointsEnabled() {
+        return Boolean.TRUE.equals(diagram.getHint(DiagramHints.KEY_ALLOW_ROUTE_POINTS));
+    }
+
+    boolean joinConnection() throws DatabaseException {
+
+        final Set<IElement> routePoints = getBranchPoints(2);
+
+        if (routePoints.isEmpty())
+            return false;
+
+        selection.clear(0);
+
+        Simantics.getSession().sync(new WriteRequest() {
+            @Override
+            public void perform(WriteGraph graph) throws DatabaseException {
+                for (IElement routePoint : routePoints) {
+                    Object node = ElementUtils.getObject(routePoint);
+                    if (node instanceof Resource) {
+                        new RemoveBranchpoint(routePoint).perform(graph);
+                    }
+                }
+            }
+        });
+        setDirty();
+
+        //statusLine.message("Deleted " + routePoints.size() + " route points");
+        return true;
+    }
+
+    private boolean rotateBranchPoint(final boolean clockWise) throws DatabaseException {
+        final Set<IElement> routePoints = getBranchPoints(Integer.MAX_VALUE);
+        if (routePoints.isEmpty())
+            return false;
+
+        // Rotate branch points.
+        try {
+            SimanticsUI.getSession().syncRequest(new WriteRequest() {
+                @Override
+                public void perform(WriteGraph graph) throws DatabaseException {
+                    DiagramResource DIA = DiagramResource.getInstance(graph);
+                    for (IElement bp : routePoints) {
+                        Resource bpr = (Resource) ElementUtils.getObject(bp);
+                        boolean vertical = graph.hasStatement(bpr, DIA.Vertical, bpr);
+                        boolean horizontal = graph.hasStatement(bpr, DIA.Horizontal, bpr);
+                        Direction dir = Direction.toDirection(horizontal, vertical);
+                        Direction newDir = clockWise ? dir.cycleNext() : dir.cyclePrevious();
+                        switch (newDir) {
+                            case Any:
+                                graph.deny(bpr, DIA.Vertical);
+                                graph.deny(bpr, DIA.Horizontal);
+                                break;
+                            case Horizontal:
+                                graph.deny(bpr, DIA.Vertical);
+                                graph.claim(bpr, DIA.Horizontal, bpr);
+                                break;
+                            case Vertical:
+                                graph.deny(bpr, DIA.Horizontal);
+                                graph.claim(bpr, DIA.Vertical, bpr);
+                                break;
+                        }
+                    }
+                }
+            });
+        } catch (DatabaseException e) {
+            ErrorLogger.defaultLogError(e);
+        }
+
+        return true;
+    }
+
+    boolean splitConnection() {
+
+        final IElement edge = getSingleConnectionSegment();
+        if (edge == null)
+            return false;
+        final IDiagram diagram = ElementUtils.peekDiagram(edge);
+        if (diagram == null)
+            return false;
+
+        MouseInfo mi = mouseUtil.getMouseInfo(0);
+        final Point2D mousePos = mi.canvasPosition;
+
+        ISnapAdvisor snap = getHint(DiagramHints.SNAP_ADVISOR);
+        if (snap != null)
+            snap.snap(mousePos);
+
+        final AffineTransform splitPos = AffineTransform.getTranslateInstance(mousePos.getX(), mousePos.getY());
+
+        try {
+            SimanticsUI.getSession().syncRequest(new WriteRequest() {
+                @Override
+                public void perform(WriteGraph graph) throws DatabaseException {
+                    DiagramResource DIA = DiagramResource.getInstance(graph);
+
+                    // Split the edge with a new branch point
+                    ConnectionUtil cu = new ConnectionUtil(graph);
+                    EdgeResource segment = (EdgeResource) ElementUtils.getObject(edge);
+                    Resource bp = cu.split(segment, splitPos);
+
+                    Line2D nearestLine = ConnectionUtil.resolveNearestEdgeLineSegment(mousePos, edge);
+                    if (nearestLine != null) {
+                        double angle = Math.atan2(
+                                Math.abs(nearestLine.getY2() - nearestLine.getY1()),
+                                Math.abs(nearestLine.getX2() - nearestLine.getX1())
+                        );
+
+                        if (angle >= 0 && angle < Math.PI / 4) {
+                            graph.claim(bp, DIA.Horizontal, bp);
+                        } else if (angle > Math.PI / 4 && angle <= Math.PI / 2) {
+                            graph.claim(bp, DIA.Vertical, bp);
+                        }
+                    }
+                }
+            });
+
+            selection.clear(0);
+
+        } catch (DatabaseException e) {
+            ErrorLogger.defaultLogError(e);
+        }
+
+        return false;
+    }
+
+    /**
+     * @return all route points in the current diagram selection if and only if
+     *         only route points are selected. If anything else is selected,
+     *         even branch points, an empty set will be returned.
+     */
+    Set<IElement> getBranchPoints(int maxDegree) throws DatabaseException {
+
+        Set<IElement> ss = selection.getSelection(0);
+        if (ss.isEmpty())
+            return Collections.emptySet();
+
+        final Set<IElement> result = new HashSet<IElement>();
+        Collection<Connection> connections = new ArrayList<Connection>();
+        for (IElement e : ss) {
+            if (!e.getElementClass().containsClass(BranchPoint.class))
+                return Collections.emptySet();
+            ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY);
+            if (ce == null)
+                return Collections.emptySet();
+            IDiagram diagram = ElementUtils.peekDiagram(e);
+            if (diagram == null)
+                return Collections.emptySet();
+            for (Topology topology : diagram.getDiagramClass().getItemsByClass(Topology.class)) {
+                connections.clear();
+                topology.getConnections(e, ElementUtils.getSingleTerminal(e), connections);
+                int degree = connections.size();
+                if (degree < 2 || degree > maxDegree)
+                    return Collections.emptySet();
+                result.add(e);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * @return if a single edge is selected, return the edge. If a single
+     *         connection is selected and it contains only one edge segment,
+     *         return it. Otherwise return <code>null</code>.
+     */
+    IElement getSingleConnectionSegment() {
+        Set<IElement> s = selection.getSelection(0);
+        if (s.size() != 1)
+            return null;
+        IElement e = s.iterator().next();
+        if (PickRequest.PickFilter.FILTER_CONNECTIONS.accept(e)) {
+            // Does this connection have only one edge and no branch points?
+            ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY);
+            Collection<IElement> coll = ce.getBranchPoints(null);
+            if (!coll.isEmpty())
+                return null;
+            ce.getSegments(coll);
+            if (coll.size() != 1)
+                return null;
+            // Return the only edge element of the whole connection.
+            return coll.iterator().next();
+        }
+        if (PickRequest.PickFilter.FILTER_CONNECTION_EDGES.accept(e))
+            return e;
+        return null;
+    }
+
+    /**
+     * @return the selected top-level connection element if and only if the
+     *         selection contains the connection or parts of the same connection
+     *         (edge segments or branch/route points) and nothing else.
+     */
+    IElement getSingleConnection() {
+
+        Set<IElement> ss = selection.getSelection(0);
+        if (ss.isEmpty())
+            return null;
+
+        IElement result = null;
+
+        for (IElement e : ss) {
+            ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY);
+            if (ce == null)
+                continue;
+            if (result != null && !ce.getConnection().equals(result))
+                return null;
+            result = ce.getConnection();
+        }
+
+        return result;
+    }
+
+}