1   /****************************************************************************
2    **
3    ** This file is part of yFiles-2.9. 
4    ** 
5    ** yWorks proprietary/confidential. Use is subject to license terms.
6    **
7    ** Redistribution of this file or of an unauthorized byte-code version
8    ** of this file is strictly forbidden.
9    **
10   ** Copyright (c) 2000-2011 by yWorks GmbH, Vor dem Kreuzberg 28, 
11   ** 72070 Tuebingen, Germany. All rights reserved.
12   **
13   ***************************************************************************/
14  package demo.layout.router;
15  
16  import demo.view.DemoBase;
17  import y.base.DataProvider;
18  import y.base.Edge;
19  import y.base.EdgeCursor;
20  import y.base.EdgeMap;
21  import y.base.Node;
22  import y.base.NodeCursor;
23  import y.layout.LayoutGraph;
24  import y.layout.Layouter;
25  import y.layout.PortConstraintConfigurator;
26  import y.layout.PortConstraintKeys;
27  import y.layout.router.ChannelEdgeRouter;
28  import y.layout.router.OrthogonalEdgeRouter;
29  import y.module.ChannelEdgeRouterModule;
30  import y.module.OrthogonalEdgeRouterModule;
31  import y.module.PortConstraintModule;
32  import y.module.YModule;
33  import y.util.DataProviderAdapter;
34  import y.view.Bend;
35  import y.view.BendCursor;
36  import y.view.BendList;
37  import y.view.CreateEdgeMode;
38  import y.view.EditMode;
39  import y.view.Graph2D;
40  import y.view.HotSpotMode;
41  import y.view.PolyLineEdgeRealizer;
42  import y.view.PortAssignmentMoveSelectionMode;
43  import y.view.Selections;
44  
45  import javax.swing.AbstractAction;
46  import javax.swing.JComboBox;
47  import javax.swing.JToolBar;
48  import java.awt.EventQueue;
49  import java.awt.event.ActionEvent;
50  import java.awt.event.ActionListener;
51  import java.util.Locale;
52  
53  
54  /**
55   * A demo that shows some of the capabilities of the yFiles Orthogonal Edge Router implementations.
56   * <br> The following aspects of using
57   * the edge routers are demonstrated. <ol> <li>How to use OrthogonalEdgeRouterModule or
58   * ChannelEdgeRouterModule as a convenient means to launch and
59   * configure the edge routers.</li> <li>How to modify the yFiles EditMode in order to trigger the orthogonal edge router
60   * whenever <ul> <li>new edges get created</li> <li>nodes get resized</li> <li>selected nodes will be moved</li>
61   * </ul></li> <li>How to specify port constraints for the edge router. With the help of port constraints it is possible
62   * to tell the orthogonal edge router on which side of a node or on which exact coordinate a start or endpoint of an
63   * edge should connect to a node.</li> </ol>
64   * <br/>
65   * Usage: Create nodes. Create edges crossing other nodes. The edges will be routed immediately.
66   * To reroute all edges use the toolbar button "Route Edges".
67   *
68   * @see <a href="http://docs.yworks.com/yfiles/doc/developers-guide/orthogonal_edge_router.html">Section Orthogonal Edge Routing</a> in the yFiles for Java Developer's Guide
69   * @see <a href="http://docs.yworks.com/yfiles/doc/developers-guide/channel_edge_router.html">Section Channel Edge Routing</a> in the yFiles for Java Developer's Guide
70   */
71  public class EdgeRouterDemo extends DemoBase {
72    RouterStrategy strategy;
73    PortAssignmentMoveSelectionMode paMode;
74  
75    // two available strategies
76    private OrthogonalEdgeRouterStrategy orthogonalEdgeRouterStrategy;
77    private ChannelEdgeRouterStrategy channelEdgeRouterStrategy;
78  
79    public EdgeRouterDemo() {
80      PolyLineEdgeRealizer er = (PolyLineEdgeRealizer) view.getGraph2D().getDefaultEdgeRealizer();
81      er.setSmoothedBends(true);
82      Graph2D graph = view.getGraph2D();
83      EdgeMap sourcePortMap = graph.createEdgeMap();
84      EdgeMap targetPortMap = graph.createEdgeMap();
85      graph.addDataProvider(PortConstraintKeys.SOURCE_PORT_CONSTRAINT_KEY, sourcePortMap);
86      graph.addDataProvider(PortConstraintKeys.TARGET_PORT_CONSTRAINT_KEY, targetPortMap);
87      paMode.setSpc(sourcePortMap);
88      paMode.setTpc(targetPortMap);
89      
90      createInitialGraph();
91    }
92  
93    protected void initialize() {
94      channelEdgeRouterStrategy = new ChannelEdgeRouterStrategy();
95      orthogonalEdgeRouterStrategy = new OrthogonalEdgeRouterStrategy();
96    }
97  
98    protected void createInitialGraph() {
99      Graph2D graph = view.getGraph2D();
100     graph.createEdge(graph.createNode(100,100,"1"), graph.createEdge(graph.createNode(200,200,"2"), graph.createNode(300,100,"3")).source());
101   }
102 
103   /**
104    * Returns ViewActionDemo toolbar plus actions to trigger some layout algorithms
105    */
106   protected JToolBar createToolBar() {
107     final JComboBox comboBox = new JComboBox(new Object[]{"Orthogonal Edge Router", "Channel Edge Router"});
108     comboBox.setMaximumSize(comboBox.getPreferredSize());
109     comboBox.addActionListener(new ActionListener() {
110       public void actionPerformed(ActionEvent e) {
111         strategy = comboBox.getSelectedIndex() == 0 ?
112             (RouterStrategy) orthogonalEdgeRouterStrategy :
113             channelEdgeRouterStrategy;
114         strategy.getModule().start(view.getGraph2D());
115       }
116     });
117     strategy = orthogonalEdgeRouterStrategy;
118 
119     JToolBar toolBar = super.createToolBar();
120     toolBar.addSeparator();
121     toolBar.add(createActionControl(new LayoutAction()));
122     toolBar.addSeparator(TOOLBAR_SMALL_SEPARATOR);
123     toolBar.add(comboBox);
124     toolBar.addSeparator(TOOLBAR_SMALL_SEPARATOR);
125     toolBar.add(createActionControl(new OptionAction()));
126     toolBar.add(createActionControl(new ConfigurePortConstraints()));
127 
128     return toolBar;
129   }
130 
131 
132   /**
133    * Provides configuration options for the edge router.
134    */
135   class OptionAction extends AbstractAction {
136     OptionAction() {
137       super("Settings...", getIconResource("resource/properties.png"));
138     }
139 
140     public void actionPerformed(ActionEvent e) {
141       OptionSupport.showDialog(strategy.getModule(), view.getGraph2D(), false, view.getFrame());
142     }
143   }
144 
145   /**
146    * Launches the Orthogonal Edge Router.
147    */
148   class LayoutAction extends AbstractAction {
149     LayoutAction() {
150       super("Route Edges", SHARED_LAYOUT_ICON);
151     }
152 
153     public void actionPerformed(ActionEvent e) {
154       strategy.getModule().start(view.getGraph2D());
155     }
156   }
157 
158   /**
159    * Configuration Utility for Port Constraints.  With the help of port constraints it is possible to tell the
160    * orthogonal edge router on which side of a node or on which exact coordinate a start or endpoint of an edge should
161    * connect to a node.
162    */
163   class ConfigurePortConstraints extends AbstractAction {
164     YModule module;
165 
166     ConfigurePortConstraints() {
167       super("Port Constraints...", getIconResource("resource/properties.png"));
168       module = new PortConstraintModule();
169     }
170 
171     public void actionPerformed(ActionEvent e) {
172       OptionSupport.showDialog(module, view.getGraph2D(), true, view.getFrame());
173     }
174   }
175 
176   /**
177    * Adds a specially configured EditMode that will automatically route all newly created edges orthogonally. The
178    * orthogonal edge router will also be activated on some edges, when nodes get resized or a node selection gets
179    * moved.
180    */
181   protected void registerViewModes() {
182     EditMode mode = new EditMode();
183     mode.setMoveSelectionMode(paMode = new MyMoveSelectionMode());
184     mode.setCreateEdgeMode(new MyCreateEdgeMode());
185     mode.setHotSpotMode(new MyHotSpotMode());
186     view.addViewMode(mode);
187   }
188 
189   /** A special mode for creating edges. */
190   class MyCreateEdgeMode extends CreateEdgeMode {
191     MyCreateEdgeMode() {
192       super();
193       allowSelfloopCreation(false);
194     }
195 
196     protected void edgeCreated(final Edge e) {
197       final Graph2D graph = view.getGraph2D();
198 
199       strategy.routeNewEdge(e);
200 
201 
202       graph.updateViews();
203     }
204   }
205 
206 
207   /** A special mode for resizing nodes. */
208   class MyHotSpotMode extends HotSpotMode {
209     public void mouseReleasedLeft(double x, double y) {
210       super.mouseReleasedLeft(x, y);
211 
212       final Graph2D graph = view.getGraph2D();
213 
214       DataProvider selectedNodes = Selections.createSelectionDataProvider(graph);
215       strategy.rerouteAdjacentEdges(selectedNodes, graph);
216       graph.updateViews();
217     }
218   }
219 
220   /** A special mode for moving a selection of the graph. */
221   class MyMoveSelectionMode extends PortAssignmentMoveSelectionMode {
222 
223     MyMoveSelectionMode() {
224       super(null, null);
225     }
226 
227     private boolean routeEdgesOnMove = true;
228 
229     protected BendList getBendsToBeMoved() {
230       BendList bends = super.getBendsToBeMoved();
231 
232       //add all bends from edges, whose source and target nodes are selected, since they will not be routed. 
233       for (NodeCursor nodeCursor = getGraph2D().selectedNodes(); nodeCursor.ok(); nodeCursor.next()) {
234         Node node = nodeCursor.node();
235         for(EdgeCursor edgeCursor = node.outEdges(); edgeCursor.ok(); edgeCursor.next()) {
236           Edge edge = edgeCursor.edge();
237           if(getGraph2D().isSelected(edge.target())){
238             for(BendCursor bendCursor = getGraph2D().getRealizer(edge).bends(); bendCursor.ok(); bendCursor.next()){
239               Bend bend = bendCursor.bend();
240               bends.add(bend);
241             }
242           }
243         }
244       }
245       return bends;
246     }
247 
248     protected void selectionOnMove(double dx, double dy, double x, double y) {
249       super.selectionOnMove(dx, dy, x, y);
250       if (routeEdgesOnMove) {
251         routeEdgesToSelection();
252       }
253     }
254 
255     protected void selectionMovedAction(double dx, double dy, double x, double y) {
256       super.selectionMovedAction(dx, dy, x, y);
257       routeEdgesToSelection();
258     }
259 
260     void routeEdgesToSelection() {
261       final Graph2D graph = view.getGraph2D();
262       if (graph.selectedNodes().ok()) {
263         strategy.routeEdgesToSelection(graph);
264         graph.updateViews();
265       }
266     }
267   }
268 
269   /** Launches this demo. */
270   public static void main(String[] args) {
271     EventQueue.invokeLater(new Runnable() {
272       public void run() {
273         Locale.setDefault(Locale.ENGLISH);
274         initLnF();
275         (new EdgeRouterDemo()).start("Orthogonal Edge Router Demo");
276       }
277     });
278   }
279 
280   abstract static class RouterStrategy {
281     abstract YModule getModule();
282 
283     abstract void routeNewEdge(Edge e);
284 
285     abstract void rerouteAdjacentEdges(DataProvider selectedNodes, LayoutGraph graph);
286 
287     abstract void routeEdgesToSelection(Graph2D graph);
288 
289     abstract void route(Layouter router, LayoutGraph graph);
290 
291     protected void routeNewEdge(Layouter router, final Edge e, Graph2D graph) {
292       EdgeMap spc = (EdgeMap) graph.getDataProvider(PortConstraintKeys.SOURCE_PORT_CONSTRAINT_KEY);
293       EdgeMap tpc = (EdgeMap) graph.getDataProvider(PortConstraintKeys.TARGET_PORT_CONSTRAINT_KEY);
294 
295       PortConstraintConfigurator pcc = new PortConstraintConfigurator();
296       if (spc != null && tpc != null) {
297         spc.set(e, pcc.createPortConstraintFromSketch(graph, e, true, false));
298         tpc.set(e, pcc.createPortConstraintFromSketch(graph, e, false, false));
299         route(router, graph);
300         spc.set(e, null);
301         tpc.set(e, null);
302       } else {
303         route(router, graph);
304       }
305     }
306 
307     protected void routeEdgesToSelection(final Graph2D graph, Layouter router, Object affectedEdgesKey) {
308       graph.addDataProvider(affectedEdgesKey, new DataProviderAdapter() {
309         public boolean getBool(Object dataHolder) {
310           return graph.isSelected(((Edge) dataHolder).source()) ^ graph.isSelected(((Edge) dataHolder).target());
311         }
312       });
313       route(router, graph);
314       graph.removeDataProvider(affectedEdgesKey);
315     }
316 
317     protected void routeNewEdge(final Edge e, Graph2D graph, Layouter router, Object selectedEdgesKey) {
318       DataProvider activeEdges = new DataProviderAdapter() {
319         public boolean getBool(Object o) {
320           return e == o;
321         }
322       };
323       graph.addDataProvider(selectedEdgesKey, activeEdges);
324       routeNewEdge(router, e, graph);
325       graph.removeDataProvider(selectedEdgesKey);
326     }
327   }
328 
329   static class OrthogonalEdgeRouterStrategy extends RouterStrategy {
330     private OrthogonalEdgeRouterModule module = new OrthogonalEdgeRouterModule();
331 
332     public YModule getModule() {
333       return module;
334     }
335 
336     public void routeNewEdge(final Edge e) {
337       Graph2D graph = (Graph2D) e.getGraph();
338       OrthogonalEdgeRouter router = new OrthogonalEdgeRouter();
339       module.configure(router);
340       router.setSphereOfAction(OrthogonalEdgeRouter.ROUTE_SELECTED_EDGES);
341       routeNewEdge(e, graph, router, Layouter.SELECTED_EDGES);
342     }
343 
344     public void rerouteAdjacentEdges(DataProvider selectedNodes, LayoutGraph graph) {
345       OrthogonalEdgeRouter router = new OrthogonalEdgeRouter();
346       module.configure(router);
347       router.setSphereOfAction(OrthogonalEdgeRouter.ROUTE_EDGES_AT_SELECTED_NODES);
348       graph.addDataProvider(Layouter.SELECTED_NODES, selectedNodes);
349       this.route(router, graph);
350       graph.removeDataProvider(Layouter.SELECTED_NODES);
351     }
352 
353     public void routeEdgesToSelection(final Graph2D graph) {
354       OrthogonalEdgeRouter router = new OrthogonalEdgeRouter();
355       module.configure(router);
356       router.setSphereOfAction(OrthogonalEdgeRouter.ROUTE_SELECTED_EDGES);
357       routeEdgesToSelection(graph, router, Layouter.SELECTED_EDGES);
358     }
359 
360     void route(Layouter router, LayoutGraph graph) {
361       router.doLayout(graph);
362     }
363   }
364 
365   static class ChannelEdgeRouterStrategy extends RouterStrategy {
366     private ChannelEdgeRouterModule module = new ChannelEdgeRouterModule();
367 
368     public YModule getModule() {
369       return module;
370     }
371 
372     public void routeNewEdge(final Edge e) {
373       final Graph2D graph = (Graph2D) e.getGraph();
374       ChannelEdgeRouter router = new ChannelEdgeRouter();
375       module.configure(router);
376       routeNewEdge(e, graph, router, ChannelEdgeRouter.AFFECTED_EDGES);
377     }
378 
379     public void rerouteAdjacentEdges(final DataProvider selectedNodes, LayoutGraph graph) {
380       ChannelEdgeRouter router = new ChannelEdgeRouter();
381       module.configure(router);
382       graph.addDataProvider(ChannelEdgeRouter.AFFECTED_EDGES, new DataProviderAdapter() {
383         public boolean getBool(Object dataHolder) {
384           return selectedNodes.getBool((((Edge) dataHolder).source())) || selectedNodes.getBool(((Edge) dataHolder).target());
385         }
386       });
387       this.route(router, graph);
388       graph.removeDataProvider(ChannelEdgeRouter.AFFECTED_EDGES);
389     }
390 
391     public void routeEdgesToSelection(final Graph2D graph) {
392       ChannelEdgeRouter router = new ChannelEdgeRouter();
393       module.configure(router);
394       routeEdgesToSelection(graph, router, ChannelEdgeRouter.AFFECTED_EDGES);
395     }
396 
397     void route(Layouter router, LayoutGraph graph) {
398       router.doLayout(graph);
399     }
400   }
401 }
402 
403 
404       
405