1   /****************************************************************************
2    **
3    ** This file is part of yFiles-2.6. 
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-2008 by yWorks GmbH, Vor dem Kreuzberg 28, 
11   ** 72070 Tuebingen, Germany. All rights reserved.
12   **
13   ***************************************************************************/
14  package demo.view.layout;
15  
16  import demo.view.DemoBase;
17  import y.base.Edge;
18  import y.base.Node;
19  import y.layout.BufferedLayouter;
20  import y.layout.CanonicMultiStageLayouter;
21  import y.layout.EdgeLabelLayout;
22  import y.layout.GraphLayout;
23  import y.layout.Layouter;
24  import y.layout.OrientationLayouter;
25  import y.layout.circular.CircularLayouter;
26  import y.layout.hierarchic.HierarchicLayouter;
27  import y.layout.organic.SmartOrganicLayouter;
28  import y.layout.orthogonal.OrthogonalLayouter;
29  import y.option.OptionHandler;
30  import y.util.D;
31  import y.view.Arrow;
32  import y.view.EdgeLabel;
33  import y.view.Graph2D;
34  import y.view.LayoutMorpher;
35  import y.anim.AnimationFactory;
36  import y.anim.AnimationPlayer;
37  
38  import javax.swing.AbstractAction;
39  import javax.swing.JToolBar;
40  import javax.swing.SwingUtilities;
41  import javax.swing.JRootPane;
42  import java.awt.event.ActionEvent;
43  import java.util.Arrays;
44  import java.util.List;
45  import java.util.Random;
46  
47  /**
48   * Demonstrates how layout and labeling algorithms can be applied to a
49   * graph being displayed within a viewer component.
50   * <br>
51   * The view actions provided with ViewActionDemo are accessible as well.
52   * <br>
53   * The layout options can be either given as command line arguments or
54   * within a settings dialog that will automatically pop up if no
55   * command line arguments are provided.
56   * <br>
57   * Command line usage:
58   * <pre>
59   * java demo.view.layout.LayoutDemo {hierarchic,orthogonal,organic,circular} [anim] [label]
60   * </pre>
61   * <br>
62   * The first command line argument is the name of the layout algorithm
63   * to be applied. 
64   * If the optional argument "label" is given, node and edge labels will
65   * be created and a generic labeling algorithm will be used to place them.
66   * If the optional argument "anim" is given, then the
67   * layout will be applied to the graph in an animated fashion.
68   */
69  public class LayoutDemo extends DemoBase
70  {
71    private AnimationPlayer animationPlayer = new AnimationPlayer();
72    OptionHandler layoutOptions;
73  
74    public LayoutDemo()
75    {
76      this(new String[]{"hierarchic", "anim", "label"});
77    }
78  
79    public LayoutDemo(String[] args) {
80      animationPlayer.addAnimationListener( view );
81      initLayoutOptions( args );
82  
83      //use an arrow to make edge directions clear
84      view.getGraph2D().getDefaultEdgeRealizer().setArrow( Arrow.STANDARD );
85  
86      //build sample graph
87      buildGraph( view.getGraph2D() );
88    }
89  
90    /**
91     * Initializes layout options from command line arguments.
92     * If no command line arguments are given, a settings dialog will
93     * automatically be displayed.
94     */
95    void initLayoutOptions(String[] args) {
96      //create layout options
97      boolean anim = true;
98      boolean label = true;
99      String layout = "hierarchic";
100     if (args.length > 0) {
101       layout = args[0];
102       List list = Arrays.asList(args);
103       anim = list.contains("anim");
104       label = list.contains("label");
105     }
106 
107     layoutOptions = new OptionHandler("Settings");
108     final String[] algoEnum = {"hierarchic", "orthogonal", "organic", "circular" };
109     layoutOptions.addEnum("Layout Style", algoEnum, layout, null);
110     layoutOptions.addBool("Activate Generic Labeling", label);
111     layoutOptions.addBool("Activate Layout Morphing", anim);
112 
113     if(args.length == 0) {
114       layoutOptions.showEditor();
115     }
116   }
117 
118 
119 
120   /** Creates a small random graph with labelled edges */
121   void buildGraph(Graph2D graph)
122   {
123     graph.clear();
124     Node nodes[] = new Node[10];
125     for(int i = 0; i < nodes.length; i++)
126     {
127       nodes[i] = graph.createNode();
128       graph.getRealizer(nodes[i]).setLabelText(""+i);
129     }
130 
131     Random random = new Random(0);
132     for ( int i = 0; i < nodes.length; i++ ) {
133       for ( int j = i + 1; j < nodes.length; j++ ) {
134         if ( random.nextDouble() > 0.75 ) {
135           Edge edge = graph.createEdge( nodes[ i ], nodes[ j ] );
136           EdgeLabel edgeLabel = new EdgeLabel( i + " -> " + j );
137           edgeLabel.setModel( EdgeLabel.SIDE_SLIDER );
138           edgeLabel.setPreferredPlacement( EdgeLabelLayout.PLACE_AT_CENTER );
139           graph.getRealizer( edge ).addLabel( edgeLabel );
140         }
141       }
142     }
143   }
144 
145   /**
146    * Adds an extra layout action to the toolbar
147    */
148   protected JToolBar createToolBar() {
149     JToolBar bar = super.createToolBar();
150     bar.addSeparator();
151     bar.add(new LayoutAction());
152     return bar;
153   }
154 
155   /**
156    * Layout action that configures and launches a layout algorithm.
157    */
158   class LayoutAction extends AbstractAction {
159     LayoutAction() {
160       super("Auto-Layout Graph");
161     }
162 
163     public void actionPerformed(ActionEvent e) {
164       if(layoutOptions.showEditor()) {
165         applyLayout();
166       }
167     }
168   }
169 
170   /**
171    * Configures and invokes a layout algorthm
172    */
173   void applyLayout() {
174     Layouter layouter = createLayouter(layoutOptions);
175     applyLayout(layouter, layoutOptions.getBool("Activate Layout Morphing"));
176   }
177 
178   /**
179    * Creates and returns a Layouter instance according to the given layout options.
180    */
181   Layouter createLayouter(OptionHandler layoutOptions) {
182 
183     String layout = layoutOptions.getString("Layout Style");
184     boolean label = layoutOptions.getBool("Activate Generic Labeling");
185 
186     CanonicMultiStageLayouter layouter = null;
187 
188     if (layout.equals("circular")) {
189       CircularLayouter cl = new CircularLayouter();
190       cl.getSingleCycleLayouter().setMinimalNodeDistance(100);
191       layouter = cl;
192     } else if (layout.equals("hierarchic")) {
193       HierarchicLayouter hl = new HierarchicLayouter();
194       //set some options
195       hl.setMinimalLayerDistance(60);
196       hl.setMinimalNodeDistance(20);
197 
198       //use left-to-right layout orientation
199       OrientationLayouter ol = new OrientationLayouter();
200       ol.setOrientation(OrientationLayouter.LEFT_TO_RIGHT);
201       hl.setOrientationLayouter(ol);
202 
203       layouter = hl;
204     } else if (layout.equals("organic")) {
205       SmartOrganicLayouter ol = new SmartOrganicLayouter();
206       //set some options
207       ol.setPreferredEdgeLength(80);
208       ol.setQualityTimeRatio(1.0);
209       ol.setNodeOverlapsAllowed(false);
210       layouter = ol;
211     } else if (layout.equals("orthogonal")) {
212       OrthogonalLayouter ol = new OrthogonalLayouter();
213       //set some options
214       layouter = ol;
215     }
216 
217     if (layouter == null) usage();
218 
219     if (label) {
220       // enable the generic labeling feature
221       layouter.setLabelLayouterEnabled(true);
222     }
223 
224     return layouter;
225   }
226 
227   /**
228    * Applies the given layout algorithm to the graph
229    * residing in the view. depending on the parameter
230    * the layout will be applied in an animated fashion
231    * to the graph or not.
232    */
233   void applyLayout(Layouter layouter, boolean animated) {
234     if (animated) {
235       GraphLayout gl = new BufferedLayouter(layouter).calcLayout(view.getGraph2D());
236 
237       LayoutMorpher morpher = new LayoutMorpher( view, gl );
238       morpher.setPreferredDuration( 800 );
239       animationPlayer.animate( AnimationFactory.createEasedAnimation( morpher ) );
240     } else {
241       layouter.doLayout(view.getGraph2D());
242 
243       //adjusts the zoom and origin of the view to make the
244       //whole graph visible
245       view.fitContent();
246 
247       //an ALTERNATIVE to fitContent is updateWorldRect
248       //adjusts view scrollbars, so that the whole graph is visible
249       //does not change zoom on the view
250 
251       //view.updateWorldRect();
252 
253       view.updateView();
254     }
255   }
256 
257 
258   void usage() {
259     D.bug("USAGE: java demo.view.layout.LayoutDemoTmp " +
260         "{organic,circular,random,hierarchic,orthogonal} [label] [anim]");
261     System.exit(0);
262   }
263 
264   public void addContentTo( final JRootPane rootPane ) {
265     super.addContentTo( rootPane );
266     SwingUtilities.invokeLater(new Runnable() {
267       public void run() {
268         applyLayout();
269       }
270     });
271   }
272 
273   public static void main(String[] args)
274   {
275     initLnF();
276     final LayoutDemo demo = new LayoutDemo(args);
277 
278     demo.start(demo.getClass().getName());
279 
280     ////////////////// IMPORTANT ////////////////////
281     // Graph2DView must be visible before
282     // animated layout morphing can be performed
283     /////////////////////////////////////////////////
284 
285     SwingUtilities.invokeLater(new Runnable() {
286       public void run() {
287         demo.applyLayout();
288       }
289     });
290   }
291 }
292