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.hierarchic;
15  
16  import demo.view.DemoBase;
17  import demo.view.DemoDefaults;
18  
19  import y.base.Edge;
20  import y.base.EdgeCursor;
21  import y.base.EdgeMap;
22  import y.base.Node;
23  import y.base.NodeCursor;
24  import y.base.NodeMap;
25  import y.io.GraphMLIOHandler;
26  import y.io.graphml.KeyScope;
27  import y.io.graphml.KeyType;
28  import y.layout.hierarchic.IncrementalHierarchicLayouter;
29  import y.layout.hierarchic.TopologicalLayerer;
30  import y.layout.hierarchic.incremental.LayerConstraintFactory;
31  import y.layout.hierarchic.incremental.ConstraintIncrementalLayerer;
32  import y.view.Arrow;
33  import y.view.EdgeRealizer;
34  import y.view.Graph2D;
35  
36  import javax.swing.AbstractAction;
37  import javax.swing.BorderFactory;
38  import javax.swing.JButton;
39  import javax.swing.JPanel;
40  import javax.swing.JScrollPane;
41  import javax.swing.JToolBar;
42  import java.awt.BorderLayout;
43  import java.awt.Color;
44  import java.awt.GridBagConstraints;
45  import java.awt.GridBagLayout;
46  import java.awt.Insets;
47  import java.awt.EventQueue;
48  import java.awt.event.ActionEvent;
49  import java.awt.event.ActionListener;
50  import java.util.Locale;
51  
52  /**
53   * Demo that shows how to apply layer constraints when calculating hierarchical layouts.
54   * <p> With the buttons on the left side of the GUI,
55   * various constraints can be set on the currently selected nodes (either absolute top/bottom level or relative layering
56   * constraints). The "Top-most"/"Bottom-most" buttons set absolute layering constraints, whereas the other buttons assign
57   * relative layering constraints. The top button ("Remove constraints") clears all constraints from the currently
58   * selected nodes.
59   * </p>
60   * <p>
61   * Additionally, a DataProvider is registered under the key <code>ConstraintIncrementalLayerer.EDGE_WEIGHTS_DPKEY</code>, and if a numeric edge label is set, that label gets set as
62   * value for that DataProvider.
63   * </p>
64   *
65   * @see <a href="http://docs.yworks.com/yfiles/doc/developers-guide/incremental_hierarchical_layouter.html#incremental_hierarchical_layer_assignment_constraints">Section Constrained Layer Assignment</a> in the yFiles for Java Developer's Guide
66   */
67  public class LayerConstraintsDemo extends DemoBase {
68  
69    public static final int TOP_LEVEL = 1;
70    public static final int BOTTOM_LEVEL = 5;
71  
72    private NodeMap levels;
73    private EdgeMap weights;
74  
75    public LayerConstraintsDemo() {
76      super();    
77      final Graph2D graph = view.getGraph2D();
78      EdgeRealizer defaultER = graph.getDefaultEdgeRealizer();
79      defaultER.setArrow(Arrow.STANDARD);
80  
81      levels = graph.createNodeMap();
82  
83      //additionally, register an edge weight map
84      weights = graph.createEdgeMap();
85      graph.addDataProvider(ConstraintIncrementalLayerer.EDGE_WEIGHTS_DPKEY, weights);
86  
87      JPanel left = new JPanel(new GridBagLayout());
88  
89      GridBagConstraints gbc = new GridBagConstraints();
90      gbc.fill = GridBagConstraints.BOTH;
91      gbc.anchor = GridBagConstraints.NORTHWEST;
92  
93      gbc.gridx = 0;
94      gbc.gridy = GridBagConstraints.RELATIVE;
95  
96      JPanel groupSpec;
97      groupSpec = new JPanel(new GridBagLayout());
98      groupSpec.setBorder(BorderFactory.createTitledBorder("Layering constraints"));
99  
100     // build the grouping mechanism
101 
102     Color[] groupColors = new Color[]{DemoDefaults.DEFAULT_CONTRAST_COLOR, Color.RED, Color.ORANGE, Color.yellow, new Color(204, 255, 0), Color.GREEN};
103     String[] groupLabels = new String[]{"Remove constraint", "Top-most level", "Above medium level", "Medium level",
104         "Below medium level",
105         "Bottom-most level"};
106     gbc.insets = new Insets(5, 0, 5, 0);
107     for (int i = 0; i < groupColors.length; i++) {
108       if (i > 1 && i < 5) {
109         gbc.insets = new Insets(0, 0, 0, 0);
110       } else {
111         gbc.insets = new Insets(5, 0, 5, 0);
112       }
113       GroupButton groupButton = new GroupButton(groupColors[i], groupLabels[i], i);
114       groupSpec.add(groupButton, gbc);
115     }
116     gbc.weightx = gbc.weighty = 1;
117     groupSpec.add(new JPanel(), gbc);
118     gbc.weightx = gbc.weighty = 0;
119     gbc.gridwidth = 2;
120     left.add(groupSpec, gbc);
121     gbc.gridwidth = 1;
122 
123     gbc.weighty = 1.0d;
124     left.add(new JPanel(), gbc);
125 
126     contentPane.add(new JScrollPane(left), BorderLayout.WEST);
127     
128     loadGraph("resource/LayerConstraintsDemo.graphml");
129   }
130     
131   protected GraphMLIOHandler createGraphMLIOHandler() {
132     GraphMLIOHandler ioh = super.createGraphMLIOHandler();
133     ioh.getGraphMLHandler().addOutputDataProvider("level", levels, KeyScope.NODE, KeyType.INT);
134     ioh.getGraphMLHandler().addInputDataAcceptor("level", levels, KeyScope.NODE, KeyType.INT);
135     return ioh;
136   }
137   
138   protected void configureDefaultRealizers() {
139     super.configureDefaultRealizers();
140     view.getGraph2D().getDefaultNodeRealizer().setFillColor(DemoDefaults.DEFAULT_CONTRAST_COLOR);
141   }
142 
143   protected JToolBar createToolBar() {
144     JToolBar toolBar = super.createToolBar();
145     toolBar.addSeparator();
146     toolBar.add(createActionControl(new LayoutAction()));
147     return toolBar;
148   }
149 
150   /** this method assigns the level id and the corresponding color hint to the currently selected nodes */
151   protected void assignLevel(Color color, int index) {
152     Graph2D graph = view.getGraph2D();
153 
154     for (NodeCursor nc = graph.selectedNodes(); nc.ok(); nc.next()) {
155       Node n = nc.node();
156       // set the color hint
157       if (color != null) {
158         graph.getRealizer(n).setFillColor(color);
159       } else {
160         graph.getRealizer(n).setFillColor(graph.getDefaultNodeRealizer().getFillColor());
161       }
162       levels.setInt(n, index);
163     }
164     graph.updateViews();
165   }
166 
167   
168   // helper class
169   class GroupButton extends JButton implements ActionListener {
170     Color color;
171     int index;
172 
173     GroupButton(Color color, String groupLabel, int index) {
174       super("");
175       setText(groupLabel);
176       this.color = color;
177       this.index = index;
178       setBackground(color);
179       this.addActionListener(this);
180     }
181 
182     public void actionPerformed(ActionEvent e) {
183       LayerConstraintsDemo.this.assignLevel(color, index);
184     }
185   }
186 
187   class LayoutAction extends AbstractAction {
188     LayoutAction() {
189       super("Layout", SHARED_LAYOUT_ICON);
190     }
191 
192     public void actionPerformed(ActionEvent ev) {
193       Graph2D graph = view.getGraph2D();
194 
195 
196       doLayout(graph);
197       graph.updateViews();
198       view.fitContent();
199     }
200   }
201 
202   private void doLayout(Graph2D graph) {
203     IncrementalHierarchicLayouter hl = new IncrementalHierarchicLayouter();
204     hl.setFromScratchLayeringStrategy(IncrementalHierarchicLayouter.LAYERING_STRATEGY_HIERARCHICAL_TOPMOST);
205     hl.setOrthogonallyRouted(true);
206     LayerConstraintFactory lcf = hl.createLayerConstraintFactory(graph);
207     createConstraints(graph, lcf);
208 
209     TopologicalLayerer topologicalLayerer = new TopologicalLayerer();
210     topologicalLayerer.setRankingPolicy(TopologicalLayerer.NO_RERANKING);
211     hl.setFromScratchLayerer(topologicalLayerer);
212 
213     view.applyLayoutAnimated(hl);
214   }
215 
216   /**
217    * Assign constraints to nodes and edges
218    *
219    * @param graph
220    * @param cf
221    */
222   private void createConstraints(Graph2D graph, LayerConstraintFactory cf) {
223     Node flr, slr, thrdlr;
224     flr = slr = thrdlr = null;
225     for (NodeCursor nodeCursor = graph.nodes(); nodeCursor.ok(); nodeCursor.next()) {
226       Node node = nodeCursor.node();
227       int index = levels.getInt(node);
228       switch (index) {
229         case TOP_LEVEL:
230           cf.addPlaceNodeAtTopConstraint(node);
231           break;
232         case BOTTOM_LEVEL:
233           cf.addPlaceNodeAtBottomConstraint(node);
234           break;
235         case TOP_LEVEL + 1:
236           if (flr == null) {
237             flr = node;
238           } else {
239             cf.addPlaceNodeInSameLayerConstraint(flr, node);
240           }
241           break;
242         case TOP_LEVEL + 2:
243           if (slr == null) {
244             slr = node;
245           } else {
246             cf.addPlaceNodeInSameLayerConstraint(slr, node);
247           }
248           break;
249         case TOP_LEVEL + 3:
250           if (thrdlr == null) {
251             thrdlr = node;
252           } else {
253             cf.addPlaceNodeInSameLayerConstraint(thrdlr, node);
254           }
255           break;
256         default:
257           break;
258       }
259       if (flr != null && slr != null) {
260         //place second layer below first layer
261         cf.addPlaceNodeBelowConstraint(flr, slr);
262       }
263       if (slr != null && thrdlr != null) {
264         //place thrd layer below second layer
265         cf.addPlaceNodeBelowConstraint(slr, thrdlr);
266       }
267       if (flr != null && thrdlr != null) {
268         //place first layer above 3rd layer
269         cf.addPlaceNodeAboveConstraint(thrdlr, flr);
270       }
271     }
272 
273     //assign weights from edge labels
274     for (EdgeCursor edgeCursor = graph.edges(); edgeCursor.ok(); edgeCursor.next()) {
275       Edge edge = edgeCursor.edge();
276       if (graph.getRealizer(edge).labelCount() > 0) {
277         String str = graph.getLabelText(edge);
278         try {
279           weights.setInt(edge, Integer.parseInt(str));
280         }
281         catch (NumberFormatException e) {
282           weights.setInt(edge, 1);
283         }
284       }
285       else {
286         weights.setInt(edge, 1);
287       }
288     }
289   }
290 
291 
292   /** Launches this demo. */
293   public static void main(String[] args) {
294     EventQueue.invokeLater(new Runnable() {
295       public void run() {
296         Locale.setDefault(Locale.ENGLISH);
297         initLnF();
298         (new LayerConstraintsDemo()).start("Layer Constraints Demo");
299       }
300     });
301   }
302 
303 
304 }