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.orthogonal;
15  
16  import demo.view.DemoBase;
17  import demo.view.DemoDefaults;
18  
19  import y.base.DataProvider;
20  import y.base.Edge;
21  import y.base.EdgeCursor;
22  import y.base.Node;
23  import y.layout.LayoutOrientation;
24  import y.layout.Layouter;
25  import y.layout.PortConstraintKeys;
26  import y.layout.orthogonal.DirectedOrthogonalLayouter;
27  import y.layout.router.EdgeGroupRouterStage;
28  import y.layout.router.OrthogonalEdgeRouter;
29  import y.util.DataProviderAdapter;
30  import y.view.Arrow;
31  import y.view.BridgeCalculator;
32  import y.view.DefaultGraph2DRenderer;
33  import y.view.EdgeRealizer;
34  import y.view.Graph2D;
35  import y.view.LineType;
36  import y.view.NodeRealizer;
37  import y.view.PolyLineEdgeRealizer;
38  
39  import javax.swing.AbstractAction;
40  import javax.swing.JComboBox;
41  import javax.swing.JComponent;
42  import javax.swing.JList;
43  import javax.swing.JToolBar;
44  import javax.swing.ListCellRenderer;
45  import java.awt.Color;
46  import java.awt.Component;
47  import java.awt.Cursor;
48  import java.awt.Dimension;
49  import java.awt.Graphics;
50  import java.awt.Graphics2D;
51  import java.awt.EventQueue;
52  import java.awt.event.ActionEvent;
53  import java.awt.event.ItemEvent;
54  import java.awt.event.ItemListener;
55  import java.util.Locale;
56  
57  /**
58   * <p>
59   * This demo shows how {@link DirectedOrthogonalLayouter} and {@link OrthogonalEdgeRouter} can be used to
60   * nicely layout UML Class Diagrams in an orthogonal layout style.
61   * <p>
62   * Usually, there are different kind of relationships between the classes of an UML diagram.
63   * Some of the relationships are undirected (e.g. associations) while others are directed
64   * (e.g. generalizations and realizations). This demo arranges a diagram in a way that
65   * directed relationships point in a main layout direction(here bottom-to-top), while the
66   * undirected relationships will be arranged without such a direction constraint.
67   * Furthermore, all directed relationships of the same type sharing a common target node
68   * will be routed in a bus-like style. For this special task
69   * OrthogonalEdgeRouter will be used in combination with {@link EdgeGroupRouterStage}.
70   * <p>
71   * The toolbar of this demo offers four additional items:
72   * <ol>
73   * <li>A combobox that selects the type of relationship to be used: association (no arrow),
74   * generalization (arrow and solid line), and realization (arrow and dashed line).
75   * </li>
76   * <li>Layout button - to layout the diagram</li>
77   * <li>Layout From Sketch button - to layout the diagram, while obeying the layout of the given diagram</li>
78   * <li>Route Edges button - to route all edges of the diagram, while preserving the coordinates of the nodes</li>
79   * </ol>
80   *
81   * @see <a href="http://docs.yworks.com/yfiles/doc/developers-guide/directed_orthogonal_layouter.html">Section Directed Orthogonal Layout</a> in the yFiles for Java Developer's Guide
82   * @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
83   */
84  public class UMLClassDiagramLayouterDemo extends DemoBase {
85  
86    DirectedOrthogonalLayouter doLayouter;
87    OrthogonalEdgeRouter oeRouter;
88    Layouter layouter, router;
89  
90    public UMLClassDiagramLayouterDemo() {
91      final Graph2D graph = view.getGraph2D();
92  
93      //configure default node realizer
94      NodeRealizer nr = graph.getDefaultNodeRealizer();
95      nr.setSize(80.0, 50.0);
96      nr.setLabelText("<html><b>Class</b><br><hr>doit():void");
97      nr.setFillColor(new Color(189, 185, 146));
98  
99      //activate grid mode
100     view.setGridMode(true);
101     view.setGridResolution(15.0);
102 
103     //activate bridge style painting of edge crossings
104     DefaultGraph2DRenderer r = (DefaultGraph2DRenderer) view.getGraph2DRenderer();
105     BridgeCalculator bc = new BridgeCalculator();
106     bc.setCrossingMode(BridgeCalculator.CROSSING_MODE_VERTICAL_CROSSES_HORIZONTAL);
107     r.setBridgeCalculator(bc);
108 
109     configureLayout();
110 
111     loadGraph(getClass(), "resource/classdiagram01.graphml");
112     DemoDefaults.applyRealizerDefaults(graph, false, false);
113   }
114 
115 
116   /**
117    * Configures layout algorithm and adds layout-specific data providers to the graph
118    */
119   private void configureLayout() {
120     final Graph2D graph = view.getGraph2D();
121 
122     doLayouter = new DirectedOrthogonalLayouter();
123     doLayouter.setLayoutOrientation(LayoutOrientation.BOTTOM_TO_TOP);
124     doLayouter.setGrid(30);
125     layouter = doLayouter;
126 
127     DataProvider directedDP = new DataProviderAdapter() {
128       public boolean getBool(Object obj) {
129         return graph.getRealizer((Edge) obj).getTargetArrow() != Arrow.NONE;
130       }
131     };
132     graph.addDataProvider(DirectedOrthogonalLayouter.DIRECTED_EDGE_DPKEY, directedDP);
133 
134     DataProvider targetGroupDP = new DataProviderAdapter() {
135       public Object get(Object obj) {
136         EdgeRealizer er = graph.getRealizer((Edge) obj);
137         if (er.getTargetArrow() == Arrow.NONE) {
138           return null;
139         } else {
140           return er.getLineType();
141         }
142       }
143     };
144     graph.addDataProvider(PortConstraintKeys.TARGET_GROUPID_KEY, targetGroupDP);
145 
146     oeRouter = new OrthogonalEdgeRouter();
147     oeRouter.setGridSpacing(10);
148     oeRouter.setGridRoutingEnabled(true);
149     oeRouter.setCrossingCost(2.0);
150     oeRouter.setReroutingEnabled(true);
151     router = new EdgeGroupRouterStage(oeRouter);
152   }
153 
154   /**
155    * Run a layout algorithm
156    */
157   private void runLayout(Layouter layouter) {
158     Cursor oldCursor = view.getCanvasComponent().getCursor();
159     try {
160       contentPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
161       view.applyLayoutAnimated(layouter);
162     } finally {
163       contentPane.setCursor(oldCursor);
164     }
165   }
166 
167   /**
168    * Add a layout button and a combobox for edge realizer selection to the ToolBar
169    */
170   protected JToolBar createToolBar() {
171     final JToolBar toolBar = super.createToolBar();
172 
173     toolBar.addSeparator();
174     toolBar.add(createEdgeRealizerComboBox());
175 
176     toolBar.addSeparator();
177     toolBar.add(createActionControl(new AbstractAction(
178             "Layout", SHARED_LAYOUT_ICON) {
179       public void actionPerformed(ActionEvent e) {
180         doLayouter.setUseSketchDrawing(false);
181         runLayout(doLayouter);
182       }
183     }));
184 
185     toolBar.add(createActionControl(new AbstractAction(
186             "Layout From Sketch", SHARED_LAYOUT_ICON) {
187       public void actionPerformed(ActionEvent e) {
188         doLayouter.setUseSketchDrawing(true);
189         runLayout(doLayouter);
190       }
191     }));
192 
193     toolBar.add(createActionControl(new AbstractAction(
194             "Route Edges", SHARED_LAYOUT_ICON) {
195       public void actionPerformed(ActionEvent e) {
196         runLayout(router);
197       }
198     }));
199 
200     return toolBar;
201   }
202 
203   JComboBox createEdgeRealizerComboBox() {
204     final EdgeRealizer association = new PolyLineEdgeRealizer();
205     final EdgeRealizer generalization = new PolyLineEdgeRealizer();
206     generalization.setTargetArrow(Arrow.WHITE_DELTA);
207     generalization.setLineType(LineType.LINE_2);
208     generalization.setLineColor(new Color(51, 51, 153));
209     final EdgeRealizer realization = new PolyLineEdgeRealizer();
210     realization.setReversedPathRenderingEnabled(true);
211     realization.setTargetArrow(Arrow.WHITE_DELTA);
212     realization.setLineType(LineType.DASHED_2);
213     realization.setLineColor(new Color(51, 51, 153));
214 
215     final Object[] items = {
216         association,
217         generalization,
218         realization
219     };
220 
221     final JComboBox box = new JComboBox(items);
222     box.setRenderer(new EdgeRealizerCellRenderer());
223     box.setMaximumSize(new Dimension(box.getMinimumSize().width, box.getMaximumSize().height));
224     box.addItemListener(new ItemListener() {
225       public void itemStateChanged(ItemEvent ev) {
226         if (ev.getStateChange() == ItemEvent.SELECTED) {
227           EdgeRealizer r = (EdgeRealizer) box.getSelectedItem();
228           if (r != null) {
229             for (EdgeCursor ec = view.getGraph2D().selectedEdges(); ec.ok(); ec.next()) {
230               EdgeRealizer ser = view.getGraph2D().getRealizer(ec.edge());
231               ser.setLineColor(r.getLineColor());
232               ser.setTargetArrow(r.getTargetArrow());
233               ser.setLineType(r.getLineType());
234             }
235             view.getGraph2D().setDefaultEdgeRealizer(r.createCopy());
236           }
237         }
238       }
239     });
240     box.setSelectedIndex(0);
241 
242     return box;
243   }
244 
245   static class EdgeRealizerCellRenderer extends JComponent implements ListCellRenderer {
246     private Graph2D graph;
247     private EdgeRealizer er;
248 
249     public EdgeRealizerCellRenderer() {
250       graph = new Graph2D();
251       Node s = graph.createNode(0.0, 12.0, 1.0, 1.0, "");
252       Node t = graph.createNode(60.0, 12.0, 1.0, 1.0, "");
253       graph.createEdge(s, t);
254     }
255 
256     public Component getListCellRendererComponent(
257         JList list,
258         Object value,
259         int index,
260         boolean isSelected,
261         boolean cellHasFocus) {
262 
263       setPreferredSize(new Dimension(60, 24));
264 
265       er = (EdgeRealizer) value;
266       graph.setRealizer(graph.firstEdge(), er);
267       return this;
268     }
269 
270     public void paint(Graphics g) {
271       Graphics2D gfx = (Graphics2D) g;
272       er.paint(gfx);
273     }
274   }
275 
276   public static void main(String[] args) {
277     EventQueue.invokeLater(new Runnable() {
278       public void run() {
279         Locale.setDefault(Locale.ENGLISH);
280         initLnF();
281         (new UMLClassDiagramLayouterDemo()).start();
282       }
283     });
284   }
285 }
286