]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.diagram/src/org/simantics/diagram/participant/ConnectTool2.java
Sync git svn branch with SVN repository r33324.
[simantics/platform.git] / bundles / org.simantics.diagram / src / org / simantics / diagram / participant / ConnectTool2.java
index 4aaa717d843109cb5d92e97e925fc3dd6dfab020..71a8d28290f9b7e020ef3bbb368ccc994287f8bc 100644 (file)
@@ -25,7 +25,6 @@ import java.util.Arrays;
 import java.util.Collection;\r
 import java.util.Collections;\r
 import java.util.Deque;\r
-import java.util.HashSet;\r
 import java.util.Iterator;\r
 import java.util.List;\r
 \r
@@ -39,12 +38,15 @@ import org.simantics.db.common.utils.NameUtils;
 import org.simantics.db.exception.DatabaseException;\r
 import org.simantics.diagram.connection.RouteGraph;\r
 import org.simantics.diagram.connection.RouteGraphConnectionClass;\r
+import org.simantics.diagram.connection.RouteLine;\r
 import org.simantics.diagram.connection.RouteTerminal;\r
+import org.simantics.diagram.connection.delta.RouteGraphDelta;\r
 import org.simantics.diagram.connection.rendering.arrows.PlainLineEndStyle;\r
 import org.simantics.diagram.content.ResourceTerminal;\r
 import org.simantics.diagram.stubs.DiagramResource;\r
 import org.simantics.diagram.synchronization.ISynchronizationContext;\r
 import org.simantics.diagram.synchronization.SynchronizationHints;\r
+import org.simantics.diagram.synchronization.graph.RouteGraphConnection;\r
 import org.simantics.g2d.canvas.ICanvasContext;\r
 import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;\r
 import org.simantics.g2d.canvas.impl.DependencyReflection.Reference;\r
@@ -54,6 +56,7 @@ import org.simantics.g2d.connection.IConnectionAdvisor;
 import org.simantics.g2d.diagram.DiagramHints;\r
 import org.simantics.g2d.diagram.DiagramUtils;\r
 import org.simantics.g2d.diagram.IDiagram;\r
+import org.simantics.g2d.diagram.handler.PickContext;\r
 import org.simantics.g2d.diagram.handler.Topology.Terminal;\r
 import org.simantics.g2d.diagram.participant.ElementPainter;\r
 import org.simantics.g2d.diagram.participant.TerminalPainter;\r
@@ -70,6 +73,7 @@ import org.simantics.g2d.element.IElementClassProvider;
 import org.simantics.g2d.element.handler.EdgeVisuals.EdgeEnd;\r
 import org.simantics.g2d.element.handler.SceneGraph;\r
 import org.simantics.g2d.element.handler.TerminalTopology;\r
+import org.simantics.g2d.element.handler.impl.BranchPointTerminal;\r
 import org.simantics.g2d.element.impl.Element;\r
 import org.simantics.g2d.elementclass.BranchPoint;\r
 import org.simantics.g2d.elementclass.BranchPoint.Direction;\r
@@ -77,8 +81,8 @@ import org.simantics.g2d.elementclass.FlagClass;
 import org.simantics.g2d.elementclass.FlagHandler;\r
 import org.simantics.g2d.participant.RenderingQualityInteractor;\r
 import org.simantics.g2d.participant.TransformUtil;\r
+import org.simantics.g2d.utils.geom.DirectionSet;\r
 import org.simantics.modeling.ModelingResources;\r
-import org.simantics.scenegraph.INode;\r
 import org.simantics.scenegraph.g2d.G2DParentNode;\r
 import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler;\r
 import org.simantics.scenegraph.g2d.events.KeyEvent;\r
@@ -101,6 +105,8 @@ import org.simantics.utils.logging.TimeLogger;
 import org.simantics.utils.ui.ErrorLogger;\r
 import org.simantics.utils.ui.ExceptionUtils;\r
 \r
+import gnu.trove.map.hash.THashMap;\r
+\r
 /**\r
  * A basic tool for making connection on diagrams.\r
  * \r
@@ -141,6 +147,9 @@ public class ConnectTool2 extends AbstractMode {
     @Dependency\r
     protected PointerInteractor      pi;\r
 \r
+    @Dependency\r
+    protected PickContext            pickContext;\r
+\r
     /**\r
      * Start element terminal of the connection. <code>null</code> if connection\r
      * was started from a flag or a branch point.\r
@@ -269,6 +278,8 @@ public class ConnectTool2 extends AbstractMode {
 \r
     protected G2DParentNode          endFlagNode;\r
 \r
+    private RouteGraphTarget         lastRouteGraphTarget;\r
+\r
     /**\r
      * @param startTerminal\r
      * @param mouseId\r
@@ -387,9 +398,9 @@ public class ConnectTool2 extends AbstractMode {
 \r
         ShapeNode pathNode = ghostNode.getOrCreateNode("path", ShapeNode.class);\r
         pathNode.setColor(new Color(160, 0, 0));\r
-        pathNode.setStroke(new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10,\r
-                new float[] { 5f, 2f }, 0));\r
-        pathNode.setScaleStroke(true);\r
+        pathNode.setStroke(new BasicStroke(0.1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10,\r
+                new float[] { 0.5f, 0.2f }, 0));\r
+        pathNode.setScaleStroke(false);\r
         pathNode.setZIndex(0);\r
 \r
         G2DParentNode points = ghostNode.getOrCreateNode("points", G2DParentNode.class);\r
@@ -443,105 +454,18 @@ public class ConnectTool2 extends AbstractMode {
 \r
         ControlPoint begin = controlPoints.getFirst();\r
         ControlPoint end = controlPoints.getLast();\r
-        \r
+\r
         RouteGraph routeGraph = new RouteGraph();\r
         RouteTerminal a = addControlPoint(routeGraph, begin);\r
         RouteTerminal b = addControlPoint(routeGraph, end);\r
         routeGraph.link(a, b);\r
-        \r
-        // Route connection segments separately\r
-        /*Router2 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 IConnection() {\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
-                TerminalInfo ti = cp.getAttachedTerminal();\r
-                if (ti != null && (ti == startFlag || ti != endFlag)) {\r
-                    //System.out.println("CP1: " + cp);\r
-                    c.parentObstacle = DiagramUtils.getObstacleShape(ti.e);\r
-                    ConnectionDirectionUtil.determineAllowedDirections(c);\r
-                } else {\r
-                    //System.out.println("CP2: " + cp);\r
-                    c.parentObstacle = GeometryUtils.transformRectangle(AffineTransform.getTranslateInstance(c.x, c.y),\r
-                            BranchPointClass.DEFAULT_IMAGE2.getBounds());\r
-                    c.allowedDirections = toAllowedDirections(cp.getDirection());\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
         Path2D path = routeGraph.getPath2D();\r
 \r
         // Create scene graph to visualize the connection.\r
         ShapeNode pathNode = ghostNode.getOrCreateNode("path", ShapeNode.class);\r
         pathNode.setShape(path);\r
 \r
-        G2DParentNode points = ghostNode.getOrCreateNode("points", G2DParentNode.class);\r
-        HashSet<INode> unusedChildren = new HashSet<INode>(points.getNodes());\r
-        int i = 0;\r
-        for (ControlPoint cp : controlPoints) {\r
-            if (cp.isAttachedToTerminal())\r
-                continue;\r
-\r
-            String id = String.valueOf(i);\r
-            BranchPointNode bpn = points.getOrCreateNode(id, BranchPointNode.class);\r
-            bpn.setDegree(2);\r
-            bpn.setDirection((byte) cp.getDirection().ordinal());\r
-            bpn.setTransform(AffineTransform.getTranslateInstance(cp.getPosition().getX(), cp.getPosition().getY()));\r
-\r
-            ++i;\r
-            unusedChildren.remove(bpn);\r
-        }\r
-        for (INode unusedChild : unusedChildren)\r
-            points.removeNode(unusedChild);\r
-\r
         setDirty();\r
     }\r
 \r
@@ -668,12 +592,48 @@ public class ConnectTool2 extends AbstractMode {
 \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
+                    if (!endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me)))\r
+                        updateSG();\r
                     return false;\r
                 }\r
             }\r
+        } else {\r
+            RouteGraphTarget cp = RouteGraphConnectTool.pickRouteGraphConnection(\r
+                    diagram,\r
+                    pi.getCanvasPickShape(me.controlPosition),\r
+                    pi.getPickDistance());\r
+            if (cp != null) {\r
+                // Remove branch point highlight from previously picked route graph.\r
+                if (lastRouteGraphTarget != null && cp.getNode() != lastRouteGraphTarget.getNode())\r
+                    cp.getNode().showBranchPoint(null);\r
+                lastRouteGraphTarget = cp;\r
+\r
+                // Validate connection before visualizing connectability\r
+                Point2D isectPos = cp.getIntersectionPosition();\r
+                TerminalInfo ti = TerminalInfo.create(\r
+                        isectPos,\r
+                        cp.getElement(),\r
+                        BranchPointTerminal.existingTerminal(\r
+                                isectPos,\r
+                                DirectionSet.ANY,\r
+                                BranchPointNode.SHAPE),\r
+                        BranchPointNode.SHAPE);\r
+                Pair<ConnectionJudgement, TerminalInfo> canConnect = canConnect(ti.e, ti.t);\r
+                if (canConnect != null) {\r
+                    connectionJudgment = canConnect.first;\r
+                    controlPoints.getLast().setPosition(ti.posDia).setAttachedToTerminal(ti);\r
+                    endTerminal = ti;\r
+                    cp.getNode().showBranchPoint(isectPos);\r
+                    if (!endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me)))\r
+                        updateSG();\r
+                    return false;\r
+                }\r
+            } else {\r
+                if (lastRouteGraphTarget != null) {\r
+                    lastRouteGraphTarget.getNode().showBranchPoint(null);\r
+                    lastRouteGraphTarget = null;\r
+                }\r
+            }\r
         }\r
 \r
         connectionJudgment = null;\r
@@ -705,9 +665,8 @@ public class ConnectTool2 extends AbstractMode {
 \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
+        if (!endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me)))\r
+            updateSG();\r
 \r
         return false;\r
     }\r
@@ -729,8 +688,13 @@ public class ConnectTool2 extends AbstractMode {
             if (snapAdvisor != null)\r
                 snapAdvisor.snap(mouseCanvasPos);\r
 \r
-            // Clicked on an allowed end terminal. End connection & end mode.\r
-            if (isEndTerminalDefined()) {\r
+            if (lastRouteGraphTarget != null) {\r
+                lastRouteGraphTarget.getNode().showBranchPoint(null);\r
+                attachToConnection();\r
+                remove();\r
+                return true;\r
+            } else if (isEndTerminalDefined()) {\r
+                // Clicked on an allowed end terminal. End connection & end mode.\r
                 createConnection();\r
                 remove();\r
                 return true;\r
@@ -772,6 +736,53 @@ public class ConnectTool2 extends AbstractMode {
         return false;\r
     }\r
 \r
+    private void attachToConnection() {\r
+        ConnectionJudgement judgment = this.connectionJudgment;\r
+        if (judgment == null) {\r
+            ErrorLogger.defaultLogError("Cannot attach to connection, no judgment available on connection validity", null);\r
+            return;\r
+        }\r
+\r
+        ConnectionBuilder builder = new ConnectionBuilder(this.diagram);\r
+        RouteGraph before = lastRouteGraphTarget.getNode().getRouteGraph();\r
+        THashMap<Object, Object> copyMap = new THashMap<>();\r
+        RouteGraph after = before.copy(copyMap);\r
+\r
+        RouteLine attachTo = (RouteLine) copyMap.get(lastRouteGraphTarget.getLine());\r
+        after.makePersistent(attachTo);\r
+        for (RouteLine line : after.getAllLines()) {\r
+            if (!line.isTransient() && line.isHorizontal() == attachTo.isHorizontal()\r
+                    && line.getPosition() == attachTo.getPosition()) {\r
+                attachTo = line;\r
+                break;\r
+            }\r
+        }\r
+        RouteLine attachToLine = attachTo;\r
+        RouteGraphDelta delta = new RouteGraphDelta(before, after);\r
+\r
+        Simantics.getSession().asyncRequest(new WriteRequest() {\r
+            @Override\r
+            public void perform(WriteGraph graph) throws DatabaseException {\r
+                graph.markUndoPoint();\r
+                Resource connection = ElementUtils.getObject(endTerminal.e);\r
+                if (!delta.isEmpty()) {\r
+                    new RouteGraphConnection(graph, connection).synchronize(graph, before, after, delta);\r
+                }\r
+                Resource line = RouteGraphConnection.deserialize(graph, attachToLine.getData());\r
+                Deque<ControlPoint> cps = new ArrayDeque<>();\r
+                for (Iterator<ControlPoint> iterator = controlPoints.descendingIterator(); iterator.hasNext();)\r
+                    cps.add(iterator.next());\r
+                builder.attachToRouteGraph(graph, judgment, connection, line, cps, startTerminal, FlagClass.Type.In);\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
     protected boolean cancelPreviousBend() {\r
         if (!routePointsAllowed())\r
             return false;\r
@@ -912,10 +923,16 @@ public class ConnectTool2 extends AbstractMode {
         return endFlag != null;\r
     }\r
 \r
-    protected void endWithoutTerminal(Point2D mousePos, boolean altDown) {\r
+    /**\r
+     * @param mousePos\r
+     * @param altDown\r
+     * @return <code>true</code> if updateSG was executed, <code>false</code>\r
+     *         otherwise\r
+     */\r
+    protected boolean endWithoutTerminal(Point2D mousePos, boolean altDown) {\r
         // Just go with branch points if flags are not allowed.\r
         if (!createFlags)\r
-            return;\r
+            return false;\r
 \r
         boolean endTerminalDefined = isEndTerminalDefined();\r
 \r
@@ -931,6 +948,7 @@ public class ConnectTool2 extends AbstractMode {
                 setHint(TerminalPainter.TERMINAL_HOVER_STRATEGY, terminalHoverStrategy);\r
 \r
                 updateSG();\r
+                return true;\r
             }\r
         } else {\r
             if (isEndingInFlag()) {\r
@@ -954,8 +972,10 @@ public class ConnectTool2 extends AbstractMode {
                 setHint(TerminalPainter.TERMINAL_HOVER_STRATEGY, terminalHoverStrategy);\r
 \r
                 updateSG();\r
+                return true;\r
             }\r
         }\r
+        return false;\r
     }\r
 \r
     protected void createConnection() {\r