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.partial;
15  
16  import y.layout.Layouter;
17  import y.layout.orthogonal.OrthogonalGroupLayouter;
18  import y.layout.partial.PartialLayouter;
19  import y.option.OptionHandler;
20  import y.view.Graph2DLayoutExecutor;
21  
22  import javax.swing.AbstractAction;
23  import javax.swing.Action;
24  import javax.swing.JToolBar;
25  import java.awt.EventQueue;
26  import java.awt.event.ActionEvent;
27  import java.util.Locale;
28  
29  /**
30   * This demo shows how to apply the partial layouter to orthogonal layouts. The partial layouter changes the coordinates
31   * for a given set of graph elements (called partial elements). The location or size of the remaining elements (called
32   * fixed elements) is not allowed to be changed. The layout algorithm tries to place the partial elements such that the
33   * resulting drawing (including the fixed elements) has a good quality with respect to common graph drawing aesthetics.
34   * <p/>
35   * Partial node elements can be assigned to so called subgraph components. During the layout process each subgraph
36   * induced by the nodes of a component is first laid out using the specified subgraph layouter. Then, the different
37   * components are placed one-by-one onto the drawing area such that the number of overlaps among graph elements is
38   * small. The user can specify different objectives (placement strategies) for finding 'good' positions for subgraph
39   * components.
40   * <p/>
41   * The demo allows to specify fixed and partial elements. Fixed elements are drawn grey and partial elements orange. To
42   * change the fixed/partial state of elements, select the corresponding elements and click on the "Lock Selected
43   * Elements" or "Unlock Selected Elements" button. The current state of selected elements can be toggled with a
44   * mouse-double-click. To start the partial layouter click on the "Apply Partial Layout" button.
45   *
46   * @see <a href="http://docs.yworks.com/yfiles/doc/developers-guide/partial_layout.html">Section Partial Layout</a> in the yFiles for Java Developer's Guide
47   */
48  public class OrthogonalPartialLayoutDemo extends PartialLayoutBase {
49  
50    public OrthogonalPartialLayoutDemo() {
51      this(null);
52    }
53  
54    public OrthogonalPartialLayoutDemo(final String helpFilePath) {
55      super(helpFilePath);
56    }
57  
58    /**
59     * Loads a graph, which contains fix nodes and nodes, which should be integrated into this graph.
60     */
61    protected void loadInitialGraph() {
62      loadGraph("resource/orthogonal.graphml");
63    }
64  
65    /**
66     * Adds an action for orthogonal layout to the default toolbar.
67     */
68    protected JToolBar createToolBar() {
69      JToolBar toolBar = super.createToolBar();
70  
71      final OrthogonalLayoutAction orthogonalLayoutAction = new OrthogonalLayoutAction("Orthogonal Layout");
72      orthogonalLayoutAction.putValue(Action.SHORT_DESCRIPTION, "Orthogonal Layout");
73      toolBar.add(orthogonalLayoutAction);
74  
75      return toolBar;
76    }
77  
78    protected OptionHandler createOptionHandler() {
79      final OptionHandler layoutOptionHandler = new OptionHandler("Option Table");
80  
81      layoutOptionHandler.addEnum("Subgraph Layout",
82          new Object[]{"Orthogonal Layout", "Unchanged"}, 0);
83      layoutOptionHandler.addInt("Grid Size", 10, 1, 50);
84      layoutOptionHandler.addEnum("Component Assignment",
85          new Object[]{"Single Nodes", "Connected Graphs", "Same Component"}, 0);
86      layoutOptionHandler.addBool("Use Snapping", true);
87      layoutOptionHandler.addBool("Use Sketch", false);
88      layoutOptionHandler.addBool("Resize Fixed Groups", true);
89  
90      return layoutOptionHandler;
91    }
92  
93    protected Layouter createConfiguredPartialLayouter() {
94      final PartialLayouter partialLayouter = new PartialLayouter();
95  
96      if (optionHandler != null) {
97        switch (optionHandler.getEnum("Subgraph Layout")) {
98          default:
99          case 0:
100           partialLayouter.setCoreLayouter(getOrthogonalLayouter());
101           break;
102         case 1:
103           // is null per default
104       }
105       partialLayouter.setPositioningStrategy(
106           optionHandler.getBool(
107               "Use Sketch") ? PartialLayouter.SUBGRAPH_POSITIONING_STRATEGY_FROM_SKETCH : PartialLayouter.SUBGRAPH_POSITIONING_STRATEGY_BARYCENTER);
108 
109       switch (optionHandler.getEnum("Component Assignment")) {
110         default:
111         case 0:
112           partialLayouter.setComponentAssignmentStrategy(PartialLayouter.COMPONENT_ASSIGNMENT_STRATEGY_SINGLE);
113           break;
114         case 1:
115           partialLayouter.setComponentAssignmentStrategy(PartialLayouter.COMPONENT_ASSIGNMENT_STRATEGY_CONNECTED);
116           break;
117         case 2:
118           partialLayouter.setComponentAssignmentStrategy(PartialLayouter.COMPONENT_ASSIGNMENT_STRATEGY_CUSTOMIZED);
119           break;
120       }
121       partialLayouter.setConsiderNodeAlignment(optionHandler.getBool("Use Snapping"));
122       partialLayouter.setFixedGroupResizingEnabled(optionHandler.getBool("Resize Fixed Groups"));
123       partialLayouter.setMinimalNodeDistance(optionHandler.getInt("Grid Size"));
124     }
125     partialLayouter.setEdgeRoutingStrategy(PartialLayouter.EDGE_ROUTING_STRATEGY_ORTHOGONAL);
126     partialLayouter.setLayoutOrientation(PartialLayouter.ORIENTATION_NONE);
127     return partialLayouter;
128   }
129 
130   /**
131    * This method configures and returns the OrthogonalGroupLayouter
132    * @return an instance of OrthogonalGroupLayouter
133    */
134   private OrthogonalGroupLayouter getOrthogonalLayouter() {
135     OrthogonalGroupLayouter layouter = new OrthogonalGroupLayouter();
136     if (optionHandler != null) {
137       layouter.setGrid(optionHandler.getInt("Grid Size"));
138     }
139     return layouter;
140   }
141 
142   /**
143    * Launches the OrthogonalLayouter.
144    */
145   class OrthogonalLayoutAction extends AbstractAction {
146     OrthogonalLayoutAction(String name) {
147       super(name);
148     }
149 
150     public void actionPerformed(ActionEvent e) {
151       Graph2DLayoutExecutor executor = new Graph2DLayoutExecutor();
152       executor.getLayoutMorpher().setEasedExecution(true);
153       executor.getLayoutMorpher().setSmoothViewTransform(true);
154       executor.doLayout(view, getOrthogonalLayouter());
155       view.updateView();
156     }
157   }
158 
159   public static void main(String[] args) {
160     EventQueue.invokeLater(new Runnable() {
161       public void run() {
162         Locale.setDefault(Locale.ENGLISH);
163         initLnF();
164         (new OrthogonalPartialLayoutDemo("resource/orthogonallayouthelp.html"))
165             .start("Orthogonal Partial Layouter Demo");
166       }
167     });
168   }
169 }