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.module;
15  
16  import y.layout.ComponentLayouter;
17  import y.layout.Layouter;
18  import y.layout.PartitionLayouter;
19  import y.layout.grouping.GroupNodeHider;
20  import y.layout.orthogonal.CompactOrthogonalLayouter;
21  import y.layout.orthogonal.OrthogonalLayouter;
22  import y.layout.router.ChannelEdgeRouter;
23  import y.layout.router.OrthogonalPatternEdgeRouter;
24  import y.module.LayoutModule;
25  import y.option.ConstraintManager;
26  import y.option.OptionGroup;
27  import y.option.OptionHandler;
28  import y.view.hierarchy.GroupLayoutConfigurator;
29  
30  import java.awt.Dimension;
31  
32  /**
33   * This module represents an interactive configurator and launcher for
34   * {@link y.layout.orthogonal.CompactOrthogonalLayouter}.
35   *
36   */
37  public class CompactOrthogonalLayoutModule extends LayoutModule {
38    private static final String NAME = "COMPACT_ORTHOGONAL";
39  
40    private static final String ORTHOGONAL_LAYOUT_STYLE = "ORTHOGONAL_LAYOUT_STYLE";
41    private static final String GRID = "GRID";
42  
43    private static final String NORMAL = "NORMAL";
44    private static final String NORMAL_TREE = "NORMAL_TREE";
45    private static final String FIXED_MIXED = "FIXED_MIXED";
46    private static final String FIXED_BOX_NODES = "FIXED_BOX_NODES";
47  
48    private static final String ASPECT_RATIO = "ASPECT_RATIO";
49    private static final String USE_VIEW_ASPECT_RATIO = "USE_VIEW_ASPECT_RATIO";
50  
51    private static final String PLACEMENT_STRATEGY = "PLACEMENT_STRATEGY";
52    private static final String STYLE_ROWS = "STYLE_ROWS";
53    private static final String STYLE_PACKED_COMPACT_RECTANGLE = "STYLE_PACKED_COMPACT_RECTANGLE";
54  
55    // ChannelInterEdgeRouter stuff
56    private static final String PATH_FINDER = "PATH_FINDER";
57    private static final String ORTHOGONAL_PATTERN_PATH_FINDER = "ORTHOGONAL_PATTERN_PATH_FINDER";
58    private static final String ORTHOGONAL_SHORTESTPATH_PATH_FINDER = "ORTHOGONAL_SHORTESTPATH_PATH_FINDER";
59    private static final String INTER_EDGE_ROUTER = "INTER_EDGE_ROUTER";
60    private static final String ROUTE_ALL_EDGES = "ROUTE_ALL_EDGES";
61  
62    // ChannelEdgeRouter stuff
63    private static final String MINIMUM_DISTANCE = "MINIMUM_DISTANCE";
64    private static final String CENTER_TO_SPACE_RATIO = "SPACE_DRIVEN_VS_CENTER_DRIVEN_SEARCH";
65    private static final String EDGE_CROSSING_COST = "EDGE_CROSSING_COST";
66    private static final String NODE_CROSSING_COST = "NODE_CROSSING_COST";
67    private static final String BEND_COST = "BEND_COST";
68  
69    // for the option handler
70    private static final String[] COMPONENT_STYLE_ENUM = {
71      STYLE_ROWS,
72      STYLE_PACKED_COMPACT_RECTANGLE
73    };
74    private static final String[] STYLE_ENUM = {
75      NORMAL, NORMAL_TREE, FIXED_MIXED, FIXED_BOX_NODES
76    };
77    private static final String[] PATH_FINDER_ENUM = {
78      ORTHOGONAL_PATTERN_PATH_FINDER,
79      ORTHOGONAL_SHORTESTPATH_PATH_FINDER
80    };
81  
82  
83    public CompactOrthogonalLayoutModule() {
84      super (NAME,"yFiles Layout Team",
85             "Compact Orthogonal Layouter");
86      setPortIntersectionCalculatorEnabled(true);
87    }
88  
89    public OptionHandler createOptionHandler() {
90      OptionHandler op = new OptionHandler(getModuleName());
91      ConstraintManager cm =  new ConstraintManager(op);
92      OptionGroup og;
93  
94  
95      // use an instance of the layouter as a defaults provider
96      CompactOrthogonalLayouter layouter = new CompactOrthogonalLayouter();
97      prepare(layouter);
98  
99      OrthogonalLayouter cl = (OrthogonalLayouter) layouter.getCoreLayouter();
100 
101     int styleIndex = 0;
102     switch (cl.getLayoutStyle()) {
103       case OrthogonalLayouter.NORMAL_STYLE:
104         styleIndex = 0;
105         break;
106       case OrthogonalLayouter.NORMAL_TREE_STYLE:
107         styleIndex = 1;
108         break;
109       case OrthogonalLayouter.FIXED_MIXED_STYLE:
110         styleIndex = 2;
111         break;
112       case OrthogonalLayouter.FIXED_BOX_STYLE:
113         styleIndex = 3;
114         break;
115     }
116     op.addEnum(ORTHOGONAL_LAYOUT_STYLE, STYLE_ENUM, styleIndex);
117 
118 
119     PartitionLayouter.ComponentPartitionPlacer cpp = (PartitionLayouter.ComponentPartitionPlacer) layouter.getPartitionPlacer();
120 
121     int compStyleIndex = 0;
122     switch (cpp.getComponentLayouter().getStyle()) {
123       case ComponentLayouter.STYLE_ROWS:
124         compStyleIndex = 0;
125         break;
126       case ComponentLayouter.STYLE_PACKED_COMPACT_RECTANGLE:
127         compStyleIndex = 1;
128         break;
129     }
130     op.addEnum(PLACEMENT_STRATEGY, COMPONENT_STYLE_ENUM, compStyleIndex);
131 
132     op.addBool(USE_VIEW_ASPECT_RATIO, true);
133     op.addDouble(ASPECT_RATIO, layouter.getAspectRatio());
134     cm.setEnabledOnValueEquals(USE_VIEW_ASPECT_RATIO, Boolean.FALSE, ASPECT_RATIO);
135 
136     op.addInt(GRID, layouter.getGridSpacing());
137 
138 
139     // ChannelInterEdgeRouter stuff
140     og = new OptionGroup();
141     og.setAttribute(OptionGroup.ATTRIBUTE_TITLE, INTER_EDGE_ROUTER);
142 
143     og.addItem(op.addEnum(PATH_FINDER, PATH_FINDER_ENUM, 1));
144 
145     PartitionLayouter.ChannelInterEdgeRouter cier = (PartitionLayouter.ChannelInterEdgeRouter)layouter.getInterEdgeRouter();
146     og.addItem(op.addBool(ROUTE_ALL_EDGES, !cier.isRouteInterEdgesOnly()));
147 
148     // ChannelEdgeRouter stuff
149     OrthogonalPatternEdgeRouter oper = new OrthogonalPatternEdgeRouter();
150     ChannelEdgeRouter.OrthogonalShortestPathPathFinder osppf = new ChannelEdgeRouter.OrthogonalShortestPathPathFinder();
151 
152     // path finding strategy properties
153     og.addItem(op.addDouble(BEND_COST, oper.getBendCost()));
154     og.addItem(op.addDouble(NODE_CROSSING_COST, oper.getNodeCrossingCost()));
155     og.addItem(op.addInt(MINIMUM_DISTANCE, osppf.getMinimumDistance()));
156     og.addItem(op.addDouble(EDGE_CROSSING_COST, osppf.getCrossingCost()));
157     og.addItem(op.addDouble(CENTER_TO_SPACE_RATIO, osppf.getCenterToSpaceRatio(), 0, 1));
158 
159     cm.setEnabledOnValueEquals(PATH_FINDER, ORTHOGONAL_PATTERN_PATH_FINDER, BEND_COST);
160     cm.setEnabledOnValueEquals(PATH_FINDER, ORTHOGONAL_PATTERN_PATH_FINDER, NODE_CROSSING_COST);
161     cm.setEnabledOnValueEquals(PATH_FINDER, ORTHOGONAL_SHORTESTPATH_PATH_FINDER, CENTER_TO_SPACE_RATIO);
162     return op;
163   }
164 
165 
166   private void prepare( CompactOrthogonalLayouter layouter ) {
167     PartitionLayouter.InterEdgeRouter ier = layouter.getInterEdgeRouter();
168     if (!(ier instanceof PartitionLayouter.ChannelInterEdgeRouter)) {
169       ier = new PartitionLayouter.ChannelInterEdgeRouter();
170       layouter.setInterEdgeRouter(ier);
171     }
172 
173     PartitionLayouter.PartitionPlacer pp = layouter.getPartitionPlacer();
174     if (!(pp instanceof PartitionLayouter.ComponentPartitionPlacer)) {
175       pp = new PartitionLayouter.ComponentPartitionPlacer();
176       layouter.setPartitionPlacer(pp);
177     }
178     Layouter cl = layouter.getCoreLayouter();
179     if (!(cl instanceof OrthogonalLayouter)) {
180       cl = new OrthogonalLayouter();
181       layouter.setCoreLayouter(cl);
182     }
183   }
184 
185   private void applyOptions( OptionHandler oh, PartitionLayouter.ChannelInterEdgeRouter router ) {
186     router.setRouteInterEdgesOnly(!oh.getBool(ROUTE_ALL_EDGES));
187     if (oh.getEnum(PATH_FINDER) == 0) {
188       OrthogonalPatternEdgeRouter oper = new OrthogonalPatternEdgeRouter();
189       oper.setMinimumDistance(oh.getInt(MINIMUM_DISTANCE));
190       oper.setEdgeCrossingCost(oh.getDouble(EDGE_CROSSING_COST));
191       oper.setNodeCrossingCost(oh.getDouble(NODE_CROSSING_COST));
192       oper.setBendCost(oh.getDouble(BEND_COST));
193       router.getChannelEdgeRouter().setPathFinderStrategy(oper);
194     } else {
195       ChannelEdgeRouter.OrthogonalShortestPathPathFinder osppf = new ChannelEdgeRouter.OrthogonalShortestPathPathFinder();
196       osppf.setMinimumDistance(oh.getInt(MINIMUM_DISTANCE));
197       osppf.setCrossingCost(oh.getDouble(EDGE_CROSSING_COST));
198       osppf.setCenterToSpaceRatio(oh.getDouble(CENTER_TO_SPACE_RATIO));
199       router.getChannelEdgeRouter().setPathFinderStrategy(osppf);
200     }
201   }
202 
203   private void applyOptions( OptionHandler oh, PartitionLayouter.ComponentPartitionPlacer placer ) {
204     if (STYLE_PACKED_COMPACT_RECTANGLE.equals(oh.get(PLACEMENT_STRATEGY))) {
205       placer.getComponentLayouter().setStyle(ComponentLayouter.STYLE_PACKED_COMPACT_RECTANGLE);
206     }
207     else if (STYLE_ROWS.equals(oh.get(PLACEMENT_STRATEGY))) {
208       placer.getComponentLayouter().setStyle(ComponentLayouter.STYLE_ROWS);
209     }
210   }
211 
212   private void applyOptions( OptionHandler oh, OrthogonalLayouter layouter ) {
213     switch (OptionHandler.getIndex(STYLE_ENUM, oh.getString(ORTHOGONAL_LAYOUT_STYLE))) {
214       default:
215       case 0:
216         layouter.setLayoutStyle(OrthogonalLayouter.NORMAL_STYLE);
217         break;
218       case 1:
219         layouter.setLayoutStyle(OrthogonalLayouter.NORMAL_TREE_STYLE);
220         break;
221       case 2:
222         layouter.setLayoutStyle(OrthogonalLayouter.FIXED_MIXED_STYLE);
223         break;
224       case 3:
225         layouter.setLayoutStyle(OrthogonalLayouter.FIXED_BOX_STYLE);
226         break;
227     }
228   }
229 
230   private void applyOptions( OptionHandler oh, CompactOrthogonalLayouter layouter ) {
231     layouter.setGridSpacing(oh.getInt(GRID));
232 
233     final double ar;
234     if (oh.getBool(USE_VIEW_ASPECT_RATIO) && getGraph2DView() != null) {
235       final Dimension dim = getGraph2DView().getSize();
236       ar = dim.getWidth()/dim.getHeight();
237     } else {
238       ar = oh.getDouble(ASPECT_RATIO);
239     }
240 
241     // this needs to be done as a final step since it will reconfigure
242     // layout stages which support aspect ratio accordingly
243     layouter.setAspectRatio(ar);
244   }
245 
246   public void mainrun() {
247     final OptionHandler op = getOptionHandler();
248 
249     CompactOrthogonalLayouter compactOrthogonal = new CompactOrthogonalLayouter();
250     prepare(compactOrthogonal);
251 
252     PartitionLayouter.ChannelInterEdgeRouter router = (PartitionLayouter.ChannelInterEdgeRouter) compactOrthogonal.getInterEdgeRouter();
253     applyOptions(op, router);
254 
255     PartitionLayouter.ComponentPartitionPlacer placer = (PartitionLayouter.ComponentPartitionPlacer) compactOrthogonal.getPartitionPlacer();
256     applyOptions(op, placer);
257 
258     OrthogonalLayouter orthogonalCore = (OrthogonalLayouter) compactOrthogonal.getCoreLayouter();
259     applyOptions(op, orthogonalCore);
260 
261     applyOptions(op, compactOrthogonal);
262 
263 
264     // initialize potential grouping information
265     GroupLayoutConfigurator glc = new GroupLayoutConfigurator(getGraph2D());
266     try {
267       // register grouping relevant DataProviders
268       glc.prepareAll();
269       // launch layouter in buffered mode
270       launchLayouter(new GroupNodeHider(compactOrthogonal));
271     } finally {
272       // make sure the DataProviders will always be unregistered
273       glc.restoreAll();
274     }
275   }
276 }
277