]> gerrit.simantics Code Review - simantics/sysdyn.git/commitdiff
Fixes several inconsistencies with creating flows in different input modes. The Sysdy...
authorjkauttio <jkauttio@ac1ea38d-2e2b-0410-8846-a27921b304fc>
Fri, 22 Nov 2013 16:04:04 +0000 (16:04 +0000)
committerjkauttio <jkauttio@ac1ea38d-2e2b-0410-8846-a27921b304fc>
Fri, 22 Nov 2013 16:04:04 +0000 (16:04 +0000)
fixes #4511

git-svn-id: https://www.simantics.org/svn/simantics/sysdyn/trunk@28363 ac1ea38d-2e2b-0410-8846-a27921b304fc

org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/editor/participant/SysdynConnectTool.java
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/editor/participant/SysdynPointerInteractor.java

index 8c2f81908e76643bb488759ab18b19b7f1e8a79c..284f09fea638b29a83ef1ed674c0954214d987fe 100644 (file)
@@ -42,6 +42,9 @@ import org.simantics.g2d.routing.IConnection;
 import org.simantics.g2d.routing.IRouter2;\r
 import org.simantics.g2d.routing.TrivialRouter2;\r
 import org.simantics.scenegraph.g2d.G2DParentNode;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonPressedEvent;\r
 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent;\r
 import org.simantics.scenegraph.g2d.nodes.ShapeNode;\r
 import org.simantics.scenegraph.g2d.snap.ISnapAdvisor;\r
@@ -49,198 +52,187 @@ import org.simantics.structural2.modelingRules.ConnectionJudgement;
 import org.simantics.sysdyn.SysdynResource;\r
 import org.simantics.sysdyn.ui.editor.routing.FlowRouter;\r
 import org.simantics.sysdyn.ui.elements.CloudFactory;\r
+import org.simantics.sysdyn.ui.elements.SysdynElementHints;\r
 import org.simantics.sysdyn.ui.elements.ValveFactory.ValveSceneGraph;\r
 import org.simantics.sysdyn.ui.elements.connections.ConnectionClasses;\r
 import org.simantics.ui.SimanticsUI;\r
 import org.simantics.utils.datastructures.Callback;\r
 import org.simantics.utils.datastructures.Pair;\r
+import org.simantics.utils.ui.ErrorLogger;\r
 import org.simantics.utils.ui.ExceptionUtils;\r
 \r
 public class SysdynConnectTool extends ConnectTool2 {\r
-       \r
-    public SysdynConnectTool(TerminalInfo startTerminal, int mouseId,\r
+\r
+       public SysdynConnectTool(TerminalInfo startTerminal, int mouseId,\r
                        Point2D startCanvasPos) {\r
                super(startTerminal, mouseId, startCanvasPos);\r
        }\r
 \r
-\r
+       @Override\r
        @SGInit\r
-    public void initSG(G2DParentNode parent) {\r
-        ghostNode = parent.addNode(G2DParentNode.class);\r
-        ghostNode.setZIndex(PAINT_PRIORITY);\r
-\r
-        ShapeNode pathNode = ghostNode.getOrCreateNode("path", ShapeNode.class);\r
-        pathNode.setColor(Color.BLACK);\r
-        pathNode.setStroke(new BasicStroke(1f));\r
-        pathNode.setScaleStroke(true);\r
-        pathNode.setZIndex(0);\r
-\r
-        G2DParentNode points = ghostNode.getOrCreateNode("points", G2DParentNode.class);\r
-        points.setZIndex(1);\r
-\r
-        updateSG();\r
-    }\r
-\r
-    \r
-    protected TerminalInfo createFlag(EdgeEnd connectionEnd) {\r
-        ElementClass flagClass = elementClassProvider.get(ElementClasses.FLAG);\r
-        IElement e = Element.spawnNew(flagClass);\r
-\r
-        e.setHint(FlagClass.KEY_FLAG_TYPE, endToFlagType(connectionEnd));\r
-        e.setHint(FlagClass.KEY_FLAG_MODE, FlagClass.Mode.Internal);\r
-\r
-        TerminalInfo ti = new TerminalInfo();\r
-        ti.e = e;\r
-        \r
-        // start: this part changed to support overlapping terminals\r
+       public void initSG(G2DParentNode parent) {\r
+               ghostNode = parent.addNode(G2DParentNode.class);\r
+               ghostNode.setZIndex(PAINT_PRIORITY);\r
+\r
+               ShapeNode pathNode = ghostNode.getOrCreateNode("path", ShapeNode.class);\r
+               pathNode.setColor(Color.BLACK);\r
+               pathNode.setStroke(new BasicStroke(1f));\r
+               pathNode.setScaleStroke(true);\r
+               pathNode.setZIndex(0);\r
+\r
+               G2DParentNode points = ghostNode.getOrCreateNode("points", G2DParentNode.class);\r
+               points.setZIndex(1);\r
+\r
+               updateSG();\r
+       }\r
+\r
+       @Override\r
+       protected TerminalInfo createFlag(EdgeEnd connectionEnd) {\r
+               ElementClass flagClass = elementClassProvider.get(ElementClasses.FLAG);\r
+               IElement e = Element.spawnNew(flagClass);\r
+\r
+               e.setHint(FlagClass.KEY_FLAG_TYPE, endToFlagType(connectionEnd));\r
+               e.setHint(FlagClass.KEY_FLAG_MODE, FlagClass.Mode.Internal);\r
+\r
+               TerminalInfo ti = new TerminalInfo();\r
+               ti.e = e;\r
+\r
+               // start: this part changed to support overlapping terminals\r
                ArrayList<Terminal> terminals = new ArrayList<Terminal>();\r
                ElementUtils.getTerminals(e, terminals, false);\r
                ti.t = terminals.get(0);\r
                // end\r
-               \r
-        ti.posElem = TerminalUtil.getTerminalPosOnElement(e, ti.t);\r
-        ti.posDia = TerminalUtil.getTerminalPosOnDiagram(e, ti.t);\r
-\r
-        return ti;\r
-    }\r
-    \r
-    static class Segment {\r
-        public final ControlPoint begin;\r
-        public final ControlPoint end;\r
-        public Path2D             path;\r
-\r
-        public Segment(ControlPoint begin, ControlPoint end) {\r
-            this.begin = begin;\r
-            this.end = end;\r
-        }\r
-\r
-        @Override\r
-        public String toString() {\r
-            return "Segment[begin=" + begin + ", end=" + end + ", path=" + path + "]";\r
-        }\r
-    }\r
-    \r
-    private List<Segment> toSegments(Deque<ControlPoint> points) {\r
-        if (points.isEmpty())\r
-            return Collections.emptyList();\r
-\r
-        List<Segment> segments = new ArrayList<Segment>();\r
-\r
-        Iterator<ControlPoint> it = points.iterator();\r
-        ControlPoint prev = it.next();\r
-        while (it.hasNext()) {\r
-            ControlPoint next = it.next();\r
-            segments.add(new Segment(prev, next));\r
-            prev = next;\r
-        }\r
-\r
-        return segments;\r
-    }\r
-    \r
-    public interface SysdynConnection extends IConnection { }\r
-    \r
-    protected void updateSG() {\r
-        if (controlPoints.isEmpty())\r
-            return;\r
-\r
-        // Route connection segments separately\r
-        IRouter2 router = ElementUtils.getHintOrDefault(diagram, DiagramHints.ROUTE_ALGORITHM, TrivialRouter2.INSTANCE);\r
-        final List<Segment> segments = toSegments(controlPoints);\r
-        //System.out.println("controlpoints: " + controlPoints);\r
-        //System.out.println("segments: " + segments);\r
-        router.route(new SysdynConnection() {\r
-            @Override\r
-            public Collection<? extends Object> getSegments() {\r
-                return segments;\r
-            }\r
-\r
-            @Override\r
-            public Connector getBegin(Object seg) {\r
-                return getConnector(((Segment) seg).begin);\r
-            }\r
-\r
-            @Override\r
-            public Connector getEnd(Object seg) {\r
-                return getConnector(((Segment) seg).end);\r
-            }\r
-\r
-            private Connector getConnector(ControlPoint cp) {\r
-               Connector c = new Connector();\r
-                c.x = cp.getPosition().getX();\r
-                c.y = cp.getPosition().getY();\r
-                \r
+\r
+               ti.posElem = TerminalUtil.getTerminalPosOnElement(e, ti.t);\r
+               ti.posDia = TerminalUtil.getTerminalPosOnDiagram(e, ti.t);\r
+\r
+               return ti;\r
+       }\r
+\r
+       static class Segment {\r
+               public final ControlPoint begin;\r
+               public final ControlPoint end;\r
+               public Path2D             path;\r
+\r
+               public Segment(ControlPoint begin, ControlPoint end) {\r
+                       this.begin = begin;\r
+                       this.end = end;\r
+               }\r
+\r
+               @Override\r
+               public String toString() {\r
+                       return "Segment[begin=" + begin + ", end=" + end + ", path=" + path + "]";\r
+               }\r
+       }\r
+\r
+       private List<Segment> toSegments(Deque<ControlPoint> points) {\r
+               if (points.isEmpty())\r
+                       return Collections.emptyList();\r
+\r
+               List<Segment> segments = new ArrayList<Segment>();\r
+\r
+               Iterator<ControlPoint> it = points.iterator();\r
+               ControlPoint prev = it.next();\r
+               while (it.hasNext()) {\r
+                       ControlPoint next = it.next();\r
+                       segments.add(new Segment(prev, next));\r
+                       prev = next;\r
+               }\r
+\r
+               return segments;\r
+       }\r
+\r
+       public interface SysdynConnection extends IConnection { }\r
+\r
+       @Override\r
+       protected void updateSG() {\r
+               if (controlPoints.isEmpty())\r
+                       return;\r
+\r
+               // Route connection segments separately\r
+               IRouter2 router = ElementUtils.getHintOrDefault(diagram, DiagramHints.ROUTE_ALGORITHM, TrivialRouter2.INSTANCE);\r
+               final List<Segment> segments = toSegments(controlPoints);\r
+               //System.out.println("controlpoints: " + controlPoints);\r
+               //System.out.println("segments: " + segments);\r
+               router.route(new SysdynConnection() {\r
+                       @Override\r
+                       public Collection<? extends Object> getSegments() {\r
+                               return segments;\r
+                       }\r
+\r
+                       @Override\r
+                       public Connector getBegin(Object seg) {\r
+                               return getConnector(((Segment) seg).begin);\r
+                       }\r
+\r
+                       @Override\r
+                       public Connector getEnd(Object seg) {\r
+                               return getConnector(((Segment) seg).end);\r
+                       }\r
+\r
+                       private Connector getConnector(ControlPoint cp) {\r
+                               Connector c = new Connector();\r
+                               c.x = cp.getPosition().getX();\r
+                               c.y = cp.getPosition().getY();\r
+\r
                                c.allowedDirections = Constants.EAST_FLAG | Constants.WEST_FLAG\r
-                               | Constants.NORTH_FLAG | Constants.SOUTH_FLAG;\r
-\r
-                TerminalInfo ti = cp.getAttachedTerminal();\r
-                if (ti != null && (ti != startFlag && ti != endFlag)) {\r
-                       if(ti.e.getElementClass().containsClass(ValveSceneGraph.class)) {\r
-                               Rectangle2D bounds = ElementUtils.getElementBoundsOnDiagram(ti.e).getBounds2D();\r
-                               c.parentObstacle = new Rectangle2D.Double(\r
-                                               bounds.getCenterX() - FlowRouter.OFFSET,\r
-                                               bounds.getCenterY() - FlowRouter.OFFSET, \r
-                                               FlowRouter.OFFSET * 2,\r
-                                               FlowRouter.OFFSET * 2);\r
-                       } else {\r
-                               c.parentObstacle =  ElementUtils.getElementBoundsOnDiagram(ti.e).getBounds2D();\r
-                       }\r
-                } else if (ti != null && ti == startFlag) {\r
-                    c.parentObstacle = org.simantics.scenegraph.utils.GeometryUtils.transformRectangle(AffineTransform.getTranslateInstance(c.x, c.y),\r
-                            ElementUtils.getElementBoundsOnDiagram(ti.e).getBounds2D());\r
-                } else if (isEndingInFlag() && ti.e != null) {\r
-                    c.parentObstacle = org.simantics.scenegraph.utils.GeometryUtils.transformRectangle(AffineTransform.getTranslateInstance(c.x, c.y),\r
-                            CloudFactory.CLOUD_IMAGE.getBounds());\r
-                } else {\r
-                    c.parentObstacle = org.simantics.scenegraph.utils.GeometryUtils.transformRectangle(AffineTransform.getTranslateInstance(c.x, c.y),\r
-                            BranchPointClass.DEFAULT_IMAGE2.getBounds());\r
-                }\r
-\r
-                return c;\r
-            }\r
-\r
-            @Override\r
-            public void setPath(Object seg, Path2D path) {\r
-                ((Segment) seg).path = (Path2D) path.clone();\r
-            }\r
-\r
-//            private int toAllowedDirections(BranchPoint.Direction direction) {\r
-//                switch (direction) {\r
-//                    case Any:\r
-//                        return 0xf;\r
-//                    case Horizontal:\r
-//                        return Constants.EAST_FLAG | Constants.WEST_FLAG;\r
-//                    case Vertical:\r
-//                        return Constants.NORTH_FLAG | Constants.SOUTH_FLAG;\r
-//                    default:\r
-//                        throw new IllegalArgumentException("unrecognized direction: " + direction);\r
-//                }\r
-//            }\r
-        });\r
-\r
-        // Combine the routed paths\r
-        Path2D path = new Path2D.Double();\r
-        for (Segment seg : segments) {\r
-            //System.out.println("SEG: " + seg);\r
-            if (seg.path != null)\r
-                path.append(seg.path.getPathIterator(null), true);\r
-        }\r
-        \r
-        // Create scene graph to visualize the connection.\r
-        ShapeNode pathNode = ghostNode.getOrCreateNode("path", ShapeNode.class);\r
-        pathNode.setShape(path);\r
-        \r
-        /*\r
-         * Removed Points\r
-         */\r
-        \r
-        setDirty();\r
-    }\r
-    \r
-    \r
-    @Override\r
+                                               | Constants.NORTH_FLAG | Constants.SOUTH_FLAG;\r
+\r
+                               TerminalInfo ti = cp.getAttachedTerminal();\r
+                               if (ti != null && (ti != startFlag && ti != endFlag)) {\r
+                                       if(ti.e.getElementClass().containsClass(ValveSceneGraph.class)) {\r
+                                               Rectangle2D bounds = ElementUtils.getElementBoundsOnDiagram(ti.e).getBounds2D();\r
+                                               c.parentObstacle = new Rectangle2D.Double(\r
+                                                               bounds.getCenterX() - FlowRouter.OFFSET,\r
+                                                               bounds.getCenterY() - FlowRouter.OFFSET, \r
+                                                               FlowRouter.OFFSET * 2,\r
+                                                               FlowRouter.OFFSET * 2);\r
+                                       } else {\r
+                                               c.parentObstacle =  ElementUtils.getElementBoundsOnDiagram(ti.e).getBounds2D();\r
+                                       }\r
+                               } else if (ti != null && ti == startFlag) {\r
+                                       c.parentObstacle = org.simantics.scenegraph.utils.GeometryUtils.transformRectangle(AffineTransform.getTranslateInstance(c.x, c.y),\r
+                                                       ElementUtils.getElementBoundsOnDiagram(ti.e).getBounds2D());\r
+                               } else if (isEndingInFlag() && ti.e != null) {\r
+                                       c.parentObstacle = org.simantics.scenegraph.utils.GeometryUtils.transformRectangle(AffineTransform.getTranslateInstance(c.x, c.y),\r
+                                                       CloudFactory.CLOUD_IMAGE.getBounds());\r
+                               } else {\r
+                                       c.parentObstacle = org.simantics.scenegraph.utils.GeometryUtils.transformRectangle(AffineTransform.getTranslateInstance(c.x, c.y),\r
+                                                       BranchPointClass.DEFAULT_IMAGE2.getBounds());\r
+                               }\r
+\r
+                               return c;\r
+                       }\r
+\r
+                       @Override\r
+                       public void setPath(Object seg, Path2D path) {\r
+                               ((Segment) seg).path = (Path2D) path.clone();\r
+                       }\r
+               });\r
+\r
+               // Combine the routed paths\r
+               Path2D path = new Path2D.Double();\r
+               for (Segment seg : segments) {\r
+                       //System.out.println("SEG: " + seg);\r
+                       if (seg.path != null)\r
+                               path.append(seg.path.getPathIterator(null), true);\r
+               }\r
+\r
+               // Create scene graph to visualize the connection.\r
+               ShapeNode pathNode = ghostNode.getOrCreateNode("path", ShapeNode.class);\r
+               pathNode.setShape(path);\r
+\r
+               /*\r
+                * Removed Points\r
+                */\r
+\r
+               setDirty();\r
+       }\r
+\r
+       @Override\r
        protected Object canConnect(final IConnectionAdvisor advisor, final IElement endElement, final Terminal endTerminal) {\r
-        final IElement se = startTerminal != null ? startTerminal.e : startFlag.e;\r
-        final Terminal st = startTerminal != null ? startTerminal.t : null;\r
+               final IElement se = startTerminal != null ? startTerminal.e : startFlag.e;\r
+               final Terminal st = startTerminal != null ? startTerminal.t : null;\r
 \r
                if(se.equals(endElement)) return null;\r
                if(Boolean.FALSE.equals(diagram.getHint(DiagramHints.KEY_USE_CONNECTION_FLAGS)) && endElement == null) {\r
@@ -269,7 +261,7 @@ public class SysdynConnectTool extends ConnectTool2 {
                                                Resource start = soa.adapt(Resource.class);\r
                                                if(g.isInheritedFrom(start, sr.ModuleSymbol) && !end.equals(sr.InputSymbol)) return null;\r
                                                if(end.equals(sr.StockSymbol)) return null;\r
-                        if(end.equals(sr.ShadowSymbol)) return null;\r
+                                               if(end.equals(sr.ShadowSymbol)) return null;\r
                                        } else if (currentConnection.equals(flow)) {\r
                                                if(!(end.equals(sr.StockSymbol) || end.equals(sr.ValveSymbol) || end.equals(sr.CloudSymbol))) return null;\r
                                        } else {\r
@@ -289,25 +281,26 @@ public class SysdynConnectTool extends ConnectTool2 {
                }\r
 \r
        }\r
-    \r
-    protected boolean processMouseMove(MouseMovedEvent me) {\r
-        mouseHasMoved = true;\r
 \r
-        Point2D mouseControlPos = me.controlPosition;\r
-        Point2D mouseCanvasPos = util.controlToCanvas(mouseControlPos, new Point2D.Double());\r
+       @Override\r
+       protected boolean processMouseMove(MouseMovedEvent me) {\r
+               mouseHasMoved = true;\r
 \r
-        ISnapAdvisor snapAdvisor = getHint(DiagramHints.SNAP_ADVISOR);\r
-        if (snapAdvisor != null)\r
-            snapAdvisor.snap(mouseCanvasPos);\r
+               Point2D mouseControlPos = me.controlPosition;\r
+               Point2D mouseCanvasPos = util.controlToCanvas(mouseControlPos, new Point2D.Double());\r
 \r
-        // Record last snapped canvas position of mouse.\r
-        this.lastMouseCanvasPos.setLocation(mouseCanvasPos);\r
+               ISnapAdvisor snapAdvisor = getHint(DiagramHints.SNAP_ADVISOR);\r
+               if (snapAdvisor != null)\r
+                       snapAdvisor.snap(mouseCanvasPos);\r
 \r
-        if (isEndingInFlag()) {\r
-            endFlagNode.setTransform(AffineTransform.getTranslateInstance(mouseCanvasPos.getX(), mouseCanvasPos.getY()));\r
-        }\r
+               // Record last snapped canvas position of mouse.\r
+               this.lastMouseCanvasPos.setLocation(mouseCanvasPos);\r
 \r
-               List<TerminalInfo> tiList = ((org.simantics.sysdyn.ui.editor.participant.SysdynPointerInteractor)pi).pickTerminals(me.controlPosition);\r
+               if (isEndingInFlag()) {\r
+                       endFlagNode.setTransform(AffineTransform.getTranslateInstance(mouseCanvasPos.getX(), mouseCanvasPos.getY()));\r
+               }\r
+\r
+               List<TerminalInfo> tiList = ((SysdynPointerInteractor)pi).pickTerminals(me.controlPosition);\r
                TerminalInfo ti = null;\r
 \r
                IConnectionAdvisor advisor = diagram.getHint(DiagramHints.CONNECTION_ADVISOR);\r
@@ -320,88 +313,161 @@ public class SysdynConnectTool extends ConnectTool2 {
                                break;\r
                        }\r
                }\r
-        \r
-        if (ti != null && !isStartTerminal(ti.e, ti.t)) {\r
-            Pair<ConnectionJudgement, TerminalInfo> canConnect = canConnect(ti.e, ti.t);\r
-            if (canConnect != null) {\r
-                connectionJudgment = canConnect.first;\r
-\r
-                if (!isEndingInFlag() || !TerminalUtil.isSameTerminal(ti, endTerminal)) {\r
-                    controlPoints.getLast()\r
-                    .setPosition(ti.posDia)\r
-                    .setAttachedToTerminal(ti);\r
-\r
-                    endTerminal = ti;\r
-                }\r
-\r
-                // Make sure that we are ending with a flag if ALT is pressed\r
-                // and no end terminal is defined.\r
-                endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me));\r
-\r
-                updateSG();\r
-                return false;\r
-            }\r
-        }\r
-\r
-        connectionJudgment = null;\r
-        if (isEndTerminalDefined()) {\r
-            // CASE: Mouse was previously on top of a valid terminal to end\r
-            // the connection. Now the mouse has been moved where there is\r
-            // no longer a terminal to connect to.\r
-            //\r
-            // => Disconnect the last edge segment from the previous\r
-            // terminal, mark endElement/endTerminal non-existent\r
-            // and connect the disconnected edge to a new branch point.\r
-\r
-            controlPoints.getLast()\r
-            .setPosition(mouseCanvasPos)\r
-            .setDirection(calculateCurrentBranchPointDirection())\r
-            .setAttachedToTerminal(null);\r
-\r
-            endTerminal = null;\r
-        } else {\r
-            // CASE: Mouse was not previously on top of a valid ending\r
-            // element terminal.\r
-            //\r
-            // => Move and re-orient last branch point.\r
-\r
-            controlPoints.getLast()\r
-            .setPosition(mouseCanvasPos)\r
-            .setDirection(calculateCurrentBranchPointDirection());\r
-        }\r
-\r
-        // Make sure that we are ending with a flag if ALT is pressed and no end\r
-        // terminal is defined.\r
-        endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me));\r
-\r
-        updateSG();\r
-\r
-        return false;\r
-    }\r
-\r
-    @Override\r
+\r
+               if (ti != null && !isStartTerminal(ti.e, ti.t)) {\r
+                       Pair<ConnectionJudgement, TerminalInfo> canConnect = canConnect(ti.e, ti.t);\r
+                       if (canConnect != null) {\r
+                               connectionJudgment = canConnect.first;\r
+\r
+                               if (!isEndingInFlag() || !TerminalUtil.isSameTerminal(ti, endTerminal)) {\r
+                                       controlPoints.getLast()\r
+                                       .setPosition(ti.posDia)\r
+                                       .setAttachedToTerminal(ti);\r
+\r
+                                       endTerminal = ti;\r
+                               }\r
+\r
+                               // Make sure that we are ending with a flag if ALT is pressed\r
+                               // and no end terminal is defined. If we are in flow creation\r
+                               // mode, we want to show the terminal cloud (or flag) even when\r
+                               // alt is not pressed.\r
+                               if (inFlowMode() && flowInProgress() && !startTerminals.isEmpty())\r
+                                       endWithoutTerminal(lastMouseCanvasPos, true);\r
+                               else\r
+                                       endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me));\r
+                               updateSG();\r
+                               return false;\r
+                       }\r
+               }\r
+\r
+               connectionJudgment = null;\r
+               if (isEndTerminalDefined()) {\r
+                       // CASE: Mouse was previously on top of a valid terminal to end\r
+                       // the connection. Now the mouse has been moved where there is\r
+                       // no longer a terminal to connect to.\r
+                       //\r
+                       // => Disconnect the last edge segment from the previous\r
+                       // terminal, mark endElement/endTerminal non-existent\r
+                       // and connect the disconnected edge to a new branch point.\r
+\r
+                       controlPoints.getLast()\r
+                       .setPosition(mouseCanvasPos)\r
+                       .setDirection(calculateCurrentBranchPointDirection())\r
+                       .setAttachedToTerminal(null);\r
+\r
+                       endTerminal = null;\r
+               } else {\r
+                       // CASE: Mouse was not previously on top of a valid ending\r
+                       // element terminal.\r
+                       //\r
+                       // => Move and re-orient last branch point.\r
+\r
+                       controlPoints.getLast()\r
+                       .setPosition(mouseCanvasPos)\r
+                       .setDirection(calculateCurrentBranchPointDirection());\r
+               }\r
+\r
+               // Make sure that we are ending with a flag if ALT is pressed and no end\r
+               // terminal is defined. If we are in flow creation mode, we want to show \r
+               // the terminal cloud (or flag) even when alt is not pressed.\r
+               if (inFlowMode() && flowInProgress() && !startTerminals.isEmpty())\r
+                       endWithoutTerminal(lastMouseCanvasPos, true);\r
+               else\r
+                       endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me));\r
+               updateSG();\r
+               return false;\r
+       }\r
+\r
+       @Override\r
+       protected boolean processMouseButtonPress(MouseButtonPressedEvent e) {\r
+               MouseButtonEvent me = e;\r
+\r
+               // Do nothing before the mouse has moved at least a little.\r
+        // This prevents the user from ending the connection right where\r
+        // it started.\r
+               if (!mouseHasMoved)\r
+                       return true;\r
+\r
+               if (me.button == MouseEvent.LEFT_BUTTON || \r
+                               (me.button == MouseEvent.RIGHT_BUTTON && flowInProgress() && !inFlowMode())) {\r
+                       Point2D mouseControlPos = me.controlPosition;\r
+                       Point2D mouseCanvasPos = util.getInverseTransform().transform(mouseControlPos, new Point2D.Double());\r
+\r
+                       ISnapAdvisor snapAdvisor = getHint(DiagramHints.SNAP_ADVISOR);\r
+                       if (snapAdvisor != null)\r
+                               snapAdvisor.snap(mouseCanvasPos);\r
+\r
+                       // Clicked on an allowed end terminal. End connection & end mode.\r
+                       if (isEndTerminalDefined()) {\r
+                               createConnection();\r
+                               remove();\r
+                               return true;\r
+                       } else {\r
+                               // Finish connection in thin air only if the\r
+                               // connection was started from a valid terminal.\r
+                               \r
+                               // If we are in flow creation mode, we want to be able to\r
+                               // create the terminal cloud (or flag) without having to \r
+                               // press alt.\r
+                               \r
+                               if (!startTerminals.isEmpty() && ((me.stateMask & MouseEvent.ALT_MASK) != 0 || \r
+                                               (inFlowMode() && flowInProgress()))) {\r
+                                       Pair<ConnectionJudgement, TerminalInfo> pair = canConnect(null, null);\r
+                                       if (pair != null) {\r
+                                               connectionJudgment = (ConnectionJudgement) pair.first;\r
+                                               selectedStartTerminal = pair.second;\r
+                                               createConnection();\r
+                                               setDirty();\r
+                                               remove();\r
+                                       } else {\r
+                                               // Inform the user why connection couldn't be created.\r
+                                               ErrorLogger.defaultLogWarning("Can't resolve connection type for new connection.", null);\r
+                                       }\r
+                                       return true;\r
+                               } else if (routePointsAllowed()\r
+                                               && (me.stateMask & (MouseEvent.ALT_MASK | MouseEvent.SHIFT_MASK | MouseEvent.CTRL_MASK)) == 0) {\r
+                                       // Add new connection control point.\r
+                                       controlPoints.add(newControlPointWithCalculatedDirection(mouseCanvasPos));\r
+                                       resetForcedBranchPointDirection();\r
+                                       updateSG();\r
+                               }\r
+                       }\r
+               }\r
+\r
+               return true;\r
+       }\r
+       \r
+       private boolean inFlowMode() {\r
+               return SysdynElementHints.FLOW_TOOL.equals(getHint(SysdynElementHints.SYSDYN_KEY_TOOL));\r
+       }\r
+       \r
+       private boolean flowInProgress() {\r
+               return elementClassProvider.get(ElementClasses.CONNECTION).equals(elementClassProvider.get(ConnectionClasses.FLOW));\r
+       }\r
+\r
+       @Override\r
        protected void createConnection() {\r
-       \r
-       if(this.connectionJudgment == null) return;\r
-       \r
-        final ConnectionJudgement judgment = this.connectionJudgment;\r
-        // ConnectionBuilder changed to SysdynconnectionBuilder to support overlapping terminals and valve creation\r
-        final ConnectionBuilder builder = new SysdynConnectionBuilder(this.diagram);\r
-        final Deque<ControlPoint> controlPoints = this.controlPoints;\r
-        final TerminalInfo startTerminal = this.startTerminal;\r
-        final TerminalInfo endTerminal = this.endTerminal;\r
-\r
-        SimanticsUI.getSession().asyncRequest(new WriteRequest() {\r
-            @Override\r
-            public void perform(WriteGraph graph) throws DatabaseException {\r
-                builder.create(graph, judgment, controlPoints, startTerminal, endTerminal);\r
-            }\r
-        }, new Callback<DatabaseException>() {\r
-            @Override\r
-            public void run(DatabaseException parameter) {\r
-                if (parameter != null)\r
-                    ExceptionUtils.logAndShowError(parameter);\r
-            }\r
-        });\r
-    }    \r
+\r
+               if(this.connectionJudgment == null) return;\r
+\r
+               final ConnectionJudgement judgment = this.connectionJudgment;\r
+               // ConnectionBuilder changed to SysdynconnectionBuilder to support overlapping terminals and valve creation\r
+               final ConnectionBuilder builder = new SysdynConnectionBuilder(this.diagram);\r
+               final Deque<ControlPoint> controlPoints = this.controlPoints;\r
+               final TerminalInfo startTerminal = this.startTerminal;\r
+               final TerminalInfo endTerminal = this.endTerminal;\r
+\r
+               SimanticsUI.getSession().asyncRequest(new WriteRequest() {\r
+                       @Override\r
+                       public void perform(WriteGraph graph) throws DatabaseException {\r
+                               builder.create(graph, judgment, controlPoints, startTerminal, endTerminal);\r
+                       }\r
+               }, new Callback<DatabaseException>() {\r
+                       @Override\r
+                       public void run(DatabaseException parameter) {\r
+                               if (parameter != null)\r
+                                       ExceptionUtils.logAndShowError(parameter);\r
+                       }\r
+               });\r
+       }    \r
 }\r
index f5ba77d807055d66d2a279d509d53b34f1984c67..7b3487071e02924e0e8caefcf62a41755392ba8b 100644 (file)
@@ -156,7 +156,7 @@ public class SysdynPointerInteractor extends PointerInteractor {
        }\r
        \r
        private ICanvasParticipant getFlowConnectTool(TerminalInfo ti, int mouseId, Point2D curCanvasPos) {\r
-               // flows must start from thin air or clouds\r
+               // flows must not start from auxiliaries, inputs or modules\r
                if (ti != null && (ti.e.getElementClass().getId().equals(AuxiliaryFactory.class.getSimpleName()) || \r
                                ti.e.getElementClass().getId().equals(InputFactory.class.getSimpleName()) || \r
                                ti.e.getElementClass().getId().equals(ModuleFactory.class.getSimpleName()))) \r
@@ -176,6 +176,7 @@ public class SysdynPointerInteractor extends PointerInteractor {
                return null;\r
        }\r
 \r
+       @Override\r
        public List<TerminalInfo> pickTerminals(Point2D controlPos) {\r
                Rectangle2D controlPickRect = new Rectangle2D.Double(controlPos.getX()-SysdynPointerInteractor.PICK_DIST, controlPos.getY()-SysdynPointerInteractor.PICK_DIST, SysdynPointerInteractor.PICK_DIST*2+1, SysdynPointerInteractor.PICK_DIST*2+1);\r
                Shape       canvasPickRect  = GeometryUtils.transformShape(controlPickRect, util.getInverseTransform());\r