]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/connection/RouteGraphNode.java
Grant access to diagram APIs to enable web based diagram editing
[simantics/platform.git] / bundles / org.simantics.scenegraph / src / org / simantics / scenegraph / g2d / nodes / connection / RouteGraphNode.java
index 084c0d6582874a7f7cb64439a58e2495e4da12f8..b0e9147f63134e5c2af5dee0c2436efbdbc016e3 100644 (file)
@@ -24,6 +24,7 @@ import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
 import java.lang.reflect.Constructor;
 import java.util.Collection;
+import java.util.List;
 import java.util.Map;
 
 import org.simantics.diagram.connection.RouteGraph;
@@ -45,6 +46,7 @@ import org.simantics.scenegraph.INode;
 import org.simantics.scenegraph.ISelectionPainterNode;
 import org.simantics.scenegraph.g2d.G2DNode;
 import org.simantics.scenegraph.g2d.G2DParentNode;
+import org.simantics.scenegraph.g2d.G2DSceneGraph;
 import org.simantics.scenegraph.g2d.IG2DNode;
 import org.simantics.scenegraph.g2d.events.EventTypes;
 import org.simantics.scenegraph.g2d.events.KeyEvent.KeyPressedEvent;
@@ -59,12 +61,17 @@ import org.simantics.scenegraph.g2d.events.command.CommandEvent;
 import org.simantics.scenegraph.g2d.events.command.Commands;
 import org.simantics.scenegraph.g2d.nodes.GridNode;
 import org.simantics.scenegraph.g2d.nodes.LinkNode;
+import org.simantics.scenegraph.g2d.nodes.NavigationNode;
+import org.simantics.scenegraph.g2d.nodes.SVGNodeAssignment;
 import org.simantics.scenegraph.g2d.nodes.connection.HighlightActionPointsAction.Action;
 import org.simantics.scenegraph.g2d.nodes.connection.HighlightActionPointsAction.Pick;
 import org.simantics.scenegraph.g2d.snap.ISnapAdvisor;
+import org.simantics.scenegraph.utils.ColorUtil;
 import org.simantics.scenegraph.utils.GeometryUtils;
 import org.simantics.scenegraph.utils.InitValueSupport;
 import org.simantics.scenegraph.utils.NodeUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import gnu.trove.map.hash.THashMap;
 
@@ -73,7 +80,9 @@ import gnu.trove.map.hash.THashMap;
  */
 public class RouteGraphNode extends G2DNode implements ISelectionPainterNode, InitValueSupport  {
 
-    private static final long       serialVersionUID = -917194130412280965L;
+    private static final Logger LOGGER = LoggerFactory.getLogger(RouteGraphNode.class);
+
+       private static final long       serialVersionUID = -917194130412280965L;
 
     private static final double     TOLERANCE        = IAction.TOLERANCE;
     private static final Stroke     SELECTION_STROKE = new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);
@@ -123,6 +132,8 @@ public class RouteGraphNode extends G2DNode implements ISelectionPainterNode, In
 
 
     protected transient Map<Object,ILineEndStyle> dynamicStyles = null;
+
+    private transient boolean ignoreSelection = false;
     
     @Override
     public void initValues() {
@@ -130,6 +141,82 @@ public class RouteGraphNode extends G2DNode implements ISelectionPainterNode, In
         wrapRenderer();
     }
 
+    private static float tryParseFloat(String s, float def) {
+       try {
+               return Float.parseFloat(s);
+       } catch (NumberFormatException e) {
+               LOGGER.error("Could not parse '" + s + "' into float.");
+               return def;
+       }
+    }
+    
+    /*
+     * 1.0 BUTT MITER 1.0 0.0
+     */
+    private static Stroke parseStroke(String definition) {
+       
+       float width = 1.0f;
+       int cap = BasicStroke.CAP_BUTT;
+       int join = BasicStroke.JOIN_MITER;
+       float miterLimit = 1.0f;
+       float[] dash = { 1, 0};
+       float dash_phase = 0;
+
+       String[] parts = definition.split(" ");
+       
+       if(parts.length > 0) {
+               width = tryParseFloat(parts[0], width);
+       }
+       if(parts.length > 1) { 
+               if("BUTT".equals(parts[1])) cap = BasicStroke.CAP_BUTT;
+               else if("ROUND".equals(parts[1])) cap = BasicStroke.CAP_ROUND;
+               else if("SQUARE".equals(parts[1])) cap = BasicStroke.CAP_SQUARE;
+       }
+       if(parts.length > 2) { 
+               if("BEVEL".equals(parts[2])) cap = BasicStroke.JOIN_BEVEL;
+               else if("MITER".equals(parts[2])) cap = BasicStroke.JOIN_MITER;
+               else if("ROUND".equals(parts[2])) cap = BasicStroke.JOIN_ROUND;
+       }
+       if(parts.length > 3) {
+               miterLimit = tryParseFloat(parts[3], miterLimit);
+       } 
+       if(parts.length > 4) {
+               dash_phase = tryParseFloat(parts[4], dash_phase);
+       }
+       if(parts.length > 6) {
+               dash = new float[parts.length - 5];
+               for(int i=5;i<parts.length;i++) {
+                       dash[i-5] = tryParseFloat(parts[i], 1.0f);
+               }
+       }
+                       
+       
+       try {
+               return new BasicStroke(width, cap, join, miterLimit, dash, dash_phase);
+       } catch (IllegalArgumentException e) {
+               return new BasicStroke();
+       }
+       
+    }
+    
+    public void setAssignments(List<SVGNodeAssignment> assignments) {
+       for(SVGNodeAssignment ass : assignments) {
+               if("dynamicColor".equals(ass.elementId)) {
+                       setDynamicColor(ColorUtil.hexColor(ass.value));
+               } else if("dynamicStroke".equals(ass.elementId)) {
+                       setDynamicStroke(parseStroke(ass.value));
+               }
+       }
+    }
+
+    public void setIgnoreSelection(boolean value) {
+        ignoreSelection = value;
+    }
+    
+    public boolean getIgnoreSelection() {
+        return ignoreSelection;
+    }  
+  
     @PropertySetter("color")
     @SyncField(value = {"dynamicColor"})
     public void setDynamicColor(Color color) {
@@ -292,7 +379,7 @@ public class RouteGraphNode extends G2DNode implements ISelectionPainterNode, In
      * @param after
      * @return <code>true</code> if changes were fired
      */
-    private boolean setRouteGraphAndFireChanges(RouteGraph before, RouteGraph after) {
+    public boolean setRouteGraphAndFireChanges(RouteGraph before, RouteGraph after) {
         RouteGraphDelta delta = new RouteGraphDelta(before, after);
         if (!delta.isEmpty()) {
             setRouteGraph(after);
@@ -347,7 +434,9 @@ public class RouteGraphNode extends G2DNode implements ISelectionPainterNode, In
         Object aaHint = g.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
         g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
 
-        boolean selected = NodeUtil.isSelected(this, 1);
+        boolean selected = ignoreSelection ? false : NodeUtil.isSelected(this, 1);
+
+        rg.updateTerminals();
 
         if (currentAction != null) {
             currentAction.render(g, renderer, mouseX, mouseY);
@@ -398,7 +487,7 @@ public class RouteGraphNode extends G2DNode implements ISelectionPainterNode, In
         return null;
     }
 
-    private double getSelectionStrokeWidth() {
+    public double getSelectionStrokeWidth() {
         if (selectionStroke instanceof BasicStroke) {
             BasicStroke bs = (BasicStroke) selectionStroke;
             return bs.getLineWidth();
@@ -442,6 +531,12 @@ public class RouteGraphNode extends G2DNode implements ISelectionPainterNode, In
 
     @Override
     protected boolean mouseDragged(MouseDragBegin e) {
+        // Consume event if drag is possible. 
+        // PointerInteractor will call handleDrag with the MouseDragBegin event for the route line that is closest to the cursor.
+        return currentAction != null;
+    }
+
+    public boolean handleDrag(MouseDragBegin e) {
         if (dragAction != null && !e.hasAnyModifier(MouseEvent.ALL_MODIFIERS_MASK) && e.button == MouseEvent.LEFT_BUTTON) {
             currentAction = dragAction;
             dragAction = null;
@@ -461,7 +556,7 @@ public class RouteGraphNode extends G2DNode implements ISelectionPainterNode, In
             }
         }
         if (newBranchPointPosition != null) {
-            RouteLine line = rg.pickLine(mouseX, mouseY, pickTolerance);
+            RouteLine line = rg.pickLine(mouseX, mouseY, scaledPickTolerance());
             if (line != null) {
                 newBranchPointPosition.setLocation(mouseX, mouseY);
                 SplittedRouteGraph.snapToLine(newBranchPointPosition, line);
@@ -572,7 +667,7 @@ public class RouteGraphNode extends G2DNode implements ISelectionPainterNode, In
                     return false;
                 }
                 //System.out.println("move action");
-                dragAction = SnappingMoveAction.create(rg, mouseX, mouseY, pickTolerance, moveFilter, getSnapAdvisor());
+                dragAction = SnappingMoveAction.create(rg, mouseX, mouseY, scaledPickTolerance(), moveFilter, getSnapAdvisor());
                 //System.out.println("DRAG ACTION: " + dragAction);
             }
 
@@ -583,6 +678,20 @@ public class RouteGraphNode extends G2DNode implements ISelectionPainterNode, In
         return false;
     }
 
+    private double scaledPickTolerance() {
+        NavigationNode nn = NodeUtil.findNearestParentNode(this, NavigationNode.class);
+        double scale = 1.0;
+        if (nn != null) {
+            scale = GeometryUtils.getScale(nn.getTransform());
+        }
+        double pickDistance = 0;
+        G2DSceneGraph sg = NodeUtil.getRootNode(nn != null ? nn : this);
+        if (sg != null) {
+            pickDistance = sg.getGlobalProperty(G2DSceneGraph.PICK_DISTANCE, pickDistance);
+        }
+        return Math.max(getSelectionStrokeWidth() / 2.0, pickDistance / scale);
+    }
+    
     /**
      * Checks the selections data node in the scene graph for any links 
      * @return
@@ -667,11 +776,11 @@ public class RouteGraphNode extends G2DNode implements ISelectionPainterNode, In
             return false;
 
         if (!e.hasAnyModifier(MouseEvent.ALL_MODIFIERS_MASK) && e.keyCode == KeyEvent.VK_S) {
-            Object target = rg.pick(mouseX, mouseY, pickTolerance, RouteGraph.PICK_PERSISTENT_LINES | RouteGraph.PICK_TRANSIENT_LINES);
+            Object target = rg.pick(mouseX, mouseY, scaledPickTolerance(), RouteGraph.PICK_PERSISTENT_LINES | RouteGraph.PICK_TRANSIENT_LINES);
             return splitTarget(target);
         }
         else if (!e.hasAnyModifier(MouseEvent.ALT_MASK | MouseEvent.ALT_GRAPH_MASK | MouseEvent.CTRL_MASK) && (e.keyCode == KeyEvent.VK_R || e.keyCode == KeyEvent.VK_D)) {
-            Object target = rg.pick(mouseX, mouseY, pickTolerance, RouteGraph.PICK_PERSISTENT_LINES);
+            Object target = rg.pick(mouseX, mouseY, scaledPickTolerance(), RouteGraph.PICK_PERSISTENT_LINES);
             return deleteTarget(target);
         }
         else if (e.keyCode == KeyEvent.VK_ESCAPE) {
@@ -695,7 +804,7 @@ public class RouteGraphNode extends G2DNode implements ISelectionPainterNode, In
         }
         else if (e.keyCode == KeyEvent.VK_ALT) {
             // Begin connection branching visualization.
-            RouteLine line = rg.pickLine(mouseX, mouseY, pickTolerance);
+            RouteLine line = rg.pickLine(mouseX, mouseY, scaledPickTolerance());
             if (branchable && line != null) {
                 newBranchPointPosition = new Point2D.Double(mouseX, mouseY);
                 SplittedRouteGraph.snapToLine(newBranchPointPosition, line);