1
28 package demo.layout.router;
29
30 import demo.view.DemoBase;
31 import y.base.Edge;
32 import y.base.EdgeCursor;
33 import y.base.GraphEvent;
34 import y.base.GraphListener;
35 import y.base.Node;
36 import y.base.NodeList;
37 import y.geom.YPoint;
38 import y.util.DataProviderAdapter;
39 import y.util.DataProviders;
40 import y.view.Arrow;
41 import y.view.BridgeCalculator;
42 import y.view.DefaultGraph2DRenderer;
43 import y.view.EdgeRealizer;
44 import y.view.EditMode;
45 import y.view.GenericNodeRealizer;
46 import y.view.Graph2D;
47 import y.view.Graph2DView;
48 import y.view.Graph2DViewActions;
49 import y.view.HotSpotMode;
50 import y.view.MovePortMode;
51 import y.view.MoveSelectionMode;
52 import y.view.NodePort;
53 import y.view.NodeRealizer;
54 import y.view.SelectionBoxMode;
55 import y.view.ShapeNodePainter;
56 import y.view.ViewMode;
57
58 import javax.swing.AbstractAction;
59 import javax.swing.Action;
60 import javax.swing.ActionMap;
61 import javax.swing.JComponent;
62 import javax.swing.JMenu;
63 import javax.swing.JMenuBar;
64 import javax.swing.JPanel;
65 import javax.swing.JRootPane;
66 import javax.swing.JSplitPane;
67 import javax.swing.JToolBar;
68 import java.awt.BorderLayout;
69 import java.awt.Color;
70 import java.awt.EventQueue;
71 import java.awt.event.ActionEvent;
72 import java.net.URL;
73 import java.util.Locale;
74 import java.util.Map;
75
76
100 public class BusRouterDemo extends DemoBase {
101 static final String HUB_CONFIGURATION = "BusHub";
102 static final Object HUB_MARKER_DPKEY = "demo.layout.router.BusRouterDemo.HUB_MARKER_DPKEY";
103
104 static final int MODE_ALL = 0;
105 static final int MODE_SELECTED = 1;
106 static final int MODE_PARTIAL = 2;
107
108 private final BusDyer busDyer;
109 private JComponent glassPane;
110 private NodeRealizer hubRealizer;
111 private HubRoutingSupport hubRoutingSupport;
112
113
116 public BusRouterDemo() {
117 this(null);
118 }
119
120
123 public BusRouterDemo(final String helpFilePath) {
124 busDyer = createBusDyer();
126 view.getGraph2D().addGraphListener(busDyer);
127
128 hubRoutingSupport = createHubRoutingSupport();
129
130 BusRouterDemoTools demoTools = new BusRouterDemoTools();
132 demoTools.setViewAndRouter(view, hubRoutingSupport.getModule());
133 demoTools.updateGrid();
134 demoTools.updateSnapping();
135
136 JSplitPane mainSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, demoTools.createOptionComponent(), view);
137 mainSplitPane.setBorder(null);
138 contentPane.add(mainSplitPane, BorderLayout.CENTER);
139
140 addHelpPane(helpFilePath);
141
142 EventQueue.invokeLater(new Runnable() {
143 public void run() {
144 loadInitialGraph();
145 }
146 });
147 }
148
149 protected void loadInitialGraph() {
150 loadGraph("resource/threeBuses.graphml");
151 }
152
153 protected boolean isClipboardEnabled() {
154 return false;
155 }
156
157
160 public void doLayout(final int mode) {
161 final Graph2D graph = view.getGraph2D();
162 final NodeRealizer oldNodeRealizer = graph.getDefaultNodeRealizer();
163
164 if (glassPane == null) {
165 glassPane = new JPanel();
167 final JRootPane rootPane = view.getRootPane();
168 rootPane.setGlassPane(glassPane);
169 }
170 glassPane.setEnabled(true);
171
172 graph.firePreEvent();
173 try {
174 graph.backupRealizers();
176
177 setBridgeCalculatorEnabled(false);
179 graph.setDefaultNodeRealizer(getHubRealizer());
180
181 hubRoutingSupport.doLayout(graph, mode);
182 busDyer.colorize(null);
183 } finally {
184 graph.setDefaultNodeRealizer(oldNodeRealizer);
185 setBridgeCalculatorEnabled(true);
186
187 glassPane.setEnabled(false);
188 graph.updateViews();
189 graph.firePostEvent();
190 }
191 }
192
193
196 protected void initialize() {
197 super.initialize();
198 hubRealizer = createHubRealizer();
199
200 setBridgeCalculatorEnabled(true);
201
202 view.getGraph2D().addDataProvider(HUB_MARKER_DPKEY, new DataProviderAdapter() {
204 public boolean getBool(Object dataHolder) {
205 return dataHolder instanceof Node && isHub((Node) dataHolder);
206 }
207 });
208
209 view.getGraph2D().addDataProvider(EditMode.ORTHOGONAL_ROUTING_DPKEY,
211 DataProviders.createConstantDataProvider(Boolean.TRUE));
212 }
213
214
218 protected void registerViewActions() {
219 super.registerViewActions();
220 ActionMap amap = view.getCanvasComponent().getActionMap();
222 if (amap != null) {
223 if (isDeletionEnabled()) {
224 amap.put(Graph2DViewActions.DELETE_SELECTION, createDeleteSelectionAction());
225 }
226
227 amap.put(Graph2DViewActions.SELECT_ALL, new Graph2DViewActions.SelectAllAction(view) {
229 protected void setSelected(Graph2D graph, Node node, boolean flag) {
230 if (!isHub(node)) {
231 super.setSelected(graph, node, flag);
232 }
233 }
234 });
235 }
236 }
237
238
241 protected Action createDeleteSelectionAction() {
242 final Action oldAction = super.createDeleteSelectionAction();
243 final Action newAction = new HubDeleteSelectionAction();
244 newAction.putValue(Action.SHORT_DESCRIPTION, oldAction.getValue(Action.SHORT_DESCRIPTION));
245 newAction.putValue(Action.SMALL_ICON, oldAction.getValue(Action.SMALL_ICON));
246 return newAction;
247 }
248
249
252 protected JToolBar createToolBar() {
253 JToolBar toolBar = super.createToolBar();
254 toolBar.setFloatable(false);
255
256 toolBar.addSeparator();
257
258 Action routeAllAction = new AbstractAction("Route All") {
260 public void actionPerformed(ActionEvent e) {
261 doLayout(MODE_ALL);
262 }
263 };
264 routeAllAction.putValue(Action.SHORT_DESCRIPTION, "Route all buses");
265 routeAllAction.putValue(Action.SMALL_ICON, SHARED_LAYOUT_ICON);
266 toolBar.add(createActionControl(routeAllAction));
267
268 Action routeSelectedAction = new AbstractAction("Route Selected") {
270 public void actionPerformed(ActionEvent e) {
271 doLayout(MODE_SELECTED);
272 }
273 };
274 routeSelectedAction.putValue(Action.SHORT_DESCRIPTION, "Route selected buses");
275 routeSelectedAction.putValue(Action.SMALL_ICON, SHARED_LAYOUT_ICON);
276 toolBar.add(createActionControl(routeSelectedAction, true));
277
278 Action propertiesAction = new AbstractAction("Settings...") {
280 public void actionPerformed(ActionEvent e) {
281 OptionSupport.showDialog(hubRoutingSupport.getModule(), view.getGraph2D(), false, view.getFrame());
282 }
283 };
284 propertiesAction.putValue(Action.SHORT_DESCRIPTION, "Configure the bus router");
285 propertiesAction.putValue(Action.SMALL_ICON, getIconResource("resource/properties.png"));
286 toolBar.add(createActionControl(propertiesAction));
287
288 return toolBar;
289 }
290
291
294 protected JMenuBar createMenuBar() {
295 final JMenuBar menuBar = super.createMenuBar();
296 JMenu menu = new JMenu("Sample Graphs");
297 menuBar.add(menu);
298
299 menu.add(new EmptyGraphAction("Empty Graph"));
300
301 menu.add(new AbstractAction("One Bus") {
302 public void actionPerformed(ActionEvent e) {
303 loadGraph("resource/oneBus.graphml");
304 }
305 });
306
307 menu.add(new AbstractAction("Three Buses") {
308 public void actionPerformed(ActionEvent e) {
309 loadGraph("resource/threeBuses.graphml");
310 }
311 });
312
313 return menuBar;
314 }
315
316
319 protected EditMode createEditMode() {
320 EditMode editMode = new HubEditMode();
321
322 if (editMode.getMovePortMode() instanceof MovePortMode) {
324 ((MovePortMode) editMode.getMovePortMode()).setIndicatingTargetNode(true);
325 }
326
327 editMode.allowMovingWithPopup(true);
329 return editMode;
330 }
331
332
335 protected BusDyer createBusDyer() {
336 return new BusDyer(view.getGraph2D());
337 }
338
339
342 protected HubRoutingSupport createHubRoutingSupport() {
343 return new HubRoutingSupport();
344 }
345
346
349 protected void configureDefaultRealizers() {
350 super.configureDefaultRealizers();
351
352 EdgeRealizer er = view.getGraph2D().getDefaultEdgeRealizer();
353 er.setTargetArrow(Arrow.NONE);
354 view.getGraph2D().setDefaultEdgeRealizer(er);
355 }
356
357
360 protected void loadGraph(URL resource) {
361 super.loadGraph(resource);
362
363 EventQueue.invokeLater(new Runnable() {
364 public void run() {
365 doLayout(MODE_ALL);
366 }
367 });
368 }
369
370
373 private void setBridgeCalculatorEnabled(boolean enable) {
374 if (enable) {
375 BridgeCalculator bridgeCalculator = new BridgeCalculator();
377 ((DefaultGraph2DRenderer) view.getGraph2DRenderer()).setBridgeCalculator(bridgeCalculator);
378 bridgeCalculator.setCrossingMode(BridgeCalculator.CROSSING_MODE_ORDER_INDUCED);
379 bridgeCalculator.setCrossingStyle(BridgeCalculator.CROSSING_STYLE_ARC);
380 bridgeCalculator.setOrientationStyle(BridgeCalculator.ORIENTATION_STYLE_UP);
381 } else {
382 ((DefaultGraph2DRenderer) view.getGraph2DRenderer()).setBridgeCalculator(null);
383 }
384 }
385
386 NodeRealizer getHubRealizer() {
387 return hubRealizer;
388 }
389
390
393 static boolean isHub(final Node node) {
394 final NodeRealizer realizer = ((Graph2D) node.getGraph()).getRealizer(node);
395 return realizer instanceof GenericNodeRealizer
396 && HUB_CONFIGURATION.equals(((GenericNodeRealizer) realizer).getConfiguration());
397 }
398
399
402 static NodeRealizer createHubRealizer() {
403 final GenericNodeRealizer.Factory factory = GenericNodeRealizer.getFactory();
404 final Map map = GenericNodeRealizer.getFactory().createDefaultConfigurationMap();
405
406 map.put(GenericNodeRealizer.Painter.class, new ShapeNodePainter(ShapeNodePainter.RECT));
407 factory.addConfiguration(HUB_CONFIGURATION, map);
408
409 NodeRealizer nr = new GenericNodeRealizer(HUB_CONFIGURATION);
410 nr.setFillColor(Color.BLACK);
411 nr.setLineColor(null);
412 nr.setSize(5.0, 5.0);
413 nr.removeLabel(nr.getLabel(0));
414 return nr;
415 }
416
417
423 protected class HubEditMode extends EditMode {
424 protected HubEditMode() {
425 setCreateEdgeMode(new AutoRoutingCreateEdgeMode(getHubRealizer()));
426 }
427
428
432 protected ViewMode createMoveSelectionMode() {
433 return new MoveSelectionMode() {
434 protected void selectionMovedAction(double dx, double dy, double x, double y) {
435 super.selectionMovedAction(dx, dy, x, y);
436 doLayout(MODE_PARTIAL);
437 }
438 };
439 }
440
441 protected ViewMode createCreateEdgeMode() {
442 return null;
443 }
444
445 protected ViewMode createMovePortMode() {
446 return null;
447 }
448
449
452 protected ViewMode createHotSpotMode() {
453 return new HotSpotMode() {
454 private boolean dirty;
455
456 public void mousePressedLeft(double x, double y) {
457 dirty = false;
458 super.mousePressedLeft(x, y);
459 }
460
461 public void mouseReleasedLeft(double x, double y) {
462 super.mouseReleasedLeft(x, y);
463 if (dirty) {
464 doLayout(MODE_PARTIAL);
465 }
466 dirty = false;
467 }
468
469 protected void updateNodeRealizerBounds(NodeRealizer vr, double x, double y, double w, double h) {
470 super.updateNodeRealizerBounds(vr, x, y, w, h);
471 dirty = true;
472 }
473 };
474 }
475
476
479 protected ViewMode createSelectionBoxMode() {
480 return new SelectionBoxMode() {
481 protected void setSelected(Graph2D graph, Node n, boolean state) {
482 if (!isHub(n)) {
483 super.setSelected(graph, n, state);
484 }
485 }
486 };
487 }
488
489
492 protected void setSelected(Graph2D graph, Node node, boolean state) {
493 if (!isHub(node)) {
494 super.setSelected(graph, node, state);
495 }
496 }
497
498
501 protected void nodeClicked(Graph2D graph, Node node, boolean wasSelected, double x, double y,
502 boolean modifierSet) {
503 if (isHub(node)) {
504 if (!modifierSet) {
505 graph.unselectAll();
506 }
507
508 if (!modifierSet || graph.isSelectionEmpty() || graph.selectedEdges().ok()) {
509 for (EdgeCursor edgeCursor = node.edges(); edgeCursor.ok(); edgeCursor.next()) {
510 final Edge edge = edgeCursor.edge();
511 setSelected(graph, edge, true);
512 }
513 }
514 graph.updateViews();
515 } else {
516 super.nodeClicked(graph, node, wasSelected, x, y, modifierSet);
517 }
518 }
519
520
523 public void mouseDraggedLeft(double x, double y) {
524 if (isModifierPressed(lastPressEvent)) {
525 double px = translateX(lastPressEvent.getX());
526 double py = translateY(lastPressEvent.getY());
527 Edge edge = getHitInfo(px, py).getHitEdge();
528 if (edge != null) {
529 setChild(getCreateEdgeMode(), lastPressEvent, lastDragEvent);
530 return;
531 }
532 }
533 super.mouseDraggedLeft(x, y);
534 }
535
536 }
537
538
547 protected class AutoRoutingCreateEdgeMode extends HubCreateEdgeMode {
548
549 protected AutoRoutingCreateEdgeMode(NodeRealizer hubRealizer) {
550 super(hubRealizer);
551 }
552
553 protected Edge createEdge(Graph2D graph, Node startNode, Node targetNode, EdgeRealizer realizer) {
554 graph.firePreEvent();
556 return super.createEdge(graph, startNode, targetNode, realizer);
557 }
558
559 protected void edgeCreated(final Edge edge) {
560 super.edgeCreated(edge);
561 if (!isHub(edge.source()) && !isHub(edge.target())) {
563 final Edge edge2 = splitSingleBusEdge(edge);
565 EventQueue.invokeLater(new Runnable() {
566 public void run() {
567 getGraph2D().unselectAll();
568 getGraph2D().setSelected(edge, true);
569 getGraph2D().setSelected(edge2, true);
570 doLayout(MODE_SELECTED);
571
572 getGraph2D().firePostEvent();
574 }
575 });
576 } else if (isHub(edge.source()) && isHub(edge.target())) {
577 EventQueue.invokeLater(new Runnable() {
579 public void run() {
580 getGraph2D().unselectAll();
581 getGraph2D().setSelected(edge, true);
582 doLayout(MODE_SELECTED);
583
584 getGraph2D().firePostEvent();
586 }
587 });
588 } else {
589 EventQueue.invokeLater(new Runnable() {
591 public void run() {
592 getGraph2D().unselectAll();
593 getGraph2D().setSelected(edge, true);
594 doLayout(MODE_PARTIAL);
595
596 getGraph2D().firePostEvent();
598 }
599 });
600 }
601 }
602
603
610 protected Edge splitSingleBusEdge(Edge edge) {
611 final Graph2D graph = getGraph2D();
612 final Node oldSource = edge.source();
613 final Node oldTarget = edge.target();
614
615 graph.firePreEvent();
616 try {
617
620 final Node hub = graph.createNode(getHubRealizer().createCopy());
621 graph.setCenter(hub, YPoint.midPoint(graph.getSourcePointAbs(edge), graph.getTargetPointAbs(edge)));
622
623 graph.changeEdge(edge, oldSource, hub);
624 graph.setTargetPointRel(edge, YPoint.ORIGIN);
625
626 final EdgeRealizer edgeRealizer = graph.getRealizer(edge);
627 final EdgeRealizer edgeRealizer2 = edgeRealizer.createCopy();
628 final Edge edge2 = graph.createEdge(hub, oldTarget, edgeRealizer2);
629 graph.setSourcePointRel(edge2, YPoint.ORIGIN);
630
631 final NodePort targetPort = NodePort.getTargetPort(edgeRealizer);
632 if (isNodePortAware() && targetPort != null) {
633 NodePort.bindTargetPort(targetPort, edgeRealizer2);
634 }
635
636 return edge2;
637 } finally {
638 graph.firePostEvent();
639 }
640 }
641 }
642
643
647 protected class HubDeleteSelectionAction extends Graph2DViewActions.DeleteSelectionAction {
648
649 protected HubDeleteSelectionAction() {
650 super(BusRouterDemo.this.view);
651 }
652
653 public void delete(Graph2DView view) {
654 final Graph2D graph = view.getGraph2D();
655 try {
656 graph.firePreEvent();
657 deleteImpl(view);
658 } finally {
659 graph.firePostEvent();
660 }
661 }
662
663
667 private void deleteImpl(Graph2DView view) {
668 final NodeList hubsToDelete = new NodeList();
669
670 GraphListener listener = new GraphListener() {
671 public void onGraphEvent(GraphEvent e) {
672 if (e.getType() == GraphEvent.PRE_EDGE_REMOVAL) {
673 final Edge edge = (Edge) e.getData();
674 if (isHubToDelete(edge.source())) {
675 hubsToDelete.add(edge.source());
676 }
677 if (isHubToDelete(edge.target())) {
678 hubsToDelete.add(edge.target());
679 }
680 }
681 }
682
683 private boolean isHubToDelete(Node node) {
684 return isHub(node) && node.degree() < 3;
686 }
687 };
688
689 final Graph2D graph = view.getGraph2D();
690 try {
691 graph.addGraphListener(listener);
692 super.delete(view);
693
694 while (!hubsToDelete.isEmpty()) {
695 final Node node = hubsToDelete.popNode();
696 if (node.getGraph() != null) {
697 graph.removeNode(node);
698 }
699 }
700 } finally {
701 graph.removeGraphListener(listener);
702 }
703 }
704 }
705
706
709 protected class EmptyGraphAction extends AbstractAction {
710
711 protected EmptyGraphAction(String name) {
712 super(name);
713 }
714
715 public void actionPerformed(ActionEvent e) {
716 view.getGraph2D().clear();
717 view.getGraph2D().setURL(null);
718 view.fitContent();
719 view.updateView();
720 getUndoManager().resetQueue();
721 }
722 }
723
724
729 public static void main(String[] args) {
730 EventQueue.invokeLater(new Runnable() {
731 public void run() {
732 Locale.setDefault(Locale.ENGLISH);
733 initLnF();
734 new BusRouterDemo("resource/busrouterhelp.html").start("Bus Router Demo");
735 }
736 });
737 }
738 }
739