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.base.Edge;
17  import y.base.EdgeCursor;
18  
19  import y.layout.LabelLayoutConstants;
20  import y.layout.LabelLayoutTranslator;
21  import y.layout.LabelRanking;
22  import y.layout.LayoutStage;
23  import y.layout.Layouter;
24  import y.layout.grouping.FixedGroupLayoutStage;
25  import y.layout.labeling.GreedyMISLabeling;
26  import y.layout.orthogonal.OrthogonalGroupLayouter;
27  import y.layout.orthogonal.OrthogonalLayouter;
28  import y.option.ConstraintManager;
29  
30  import y.view.EdgeLabel;
31  import y.view.EdgeRealizer;
32  import y.view.Graph2D;
33  import y.view.hierarchy.GroupLayoutConfigurator;
34  import y.view.hierarchy.HierarchyManager;
35  
36  import y.option.OptionHandler;
37  import y.module.LayoutModule;
38  
39  
40  /**
41   * This module represents an interactive configurator and launcher for
42   * {@link y.layout.orthogonal.OrthogonalLayouter}
43   * and {@link y.layout.orthogonal.OrthogonalGroupLayouter} respectively.
44   * It is similar to OrthogonalLayoutModule found in the yFiles package y.module.
45   *
46   */
47  public class OrthogonalLayoutModule extends LayoutModule
48  {
49    private static final String ORTHOGONAL = "ORTHOGONAL_LAYOUTER";
50    private static final String GROUPING      = "GROUPING";
51    private static final String GROUP_POLICY  = "GROUP_LAYOUT_POLICY";
52    private static final String IGNORE_GROUPS = "IGNORE_GROUPS";
53    private static final String LAYOUT_GROUPS = "LAYOUT_GROUPS";
54    private static final String FIX_GROUPS    = "FIX_GROUPS";
55    private static final String GROUP_LAYOUT_QUALITY = "GROUP_LAYOUT_QUALITY";
56  
57    private static final String LENGTH_REDUCTION = "LENGTH_REDUCTION";
58    private static final String STYLE = "STYLE";
59    private static final String USE_RANDOMIZATION = "USE_RANDOMIZATION";
60    private static final String USE_FACE_MAXIMIZATION = "USE_FACE_MAXIMIZATION";
61    private static final String USE_EXISTING_DRAWING_AS_SKETCH = "USE_EXISTING_DRAWING_AS_SKETCH";
62    private static final String CROSSING_POSTPROCESSING = "CROSSING_POSTPROCESSING";
63    private static final String PERCEIVED_BENDS_POSTPROCESSING = "PERCEIVED_BENDS_POSTPROCESSING";
64    private static final String GRID = "GRID";
65    private static final String NORMAL = "NORMAL";
66    private static final String NORMAL_TREE = "NORMAL_TREE";
67    private static final String UNIFORM_NODES = "UNIFORM_NODES";
68    private static final String BOX_NODES = "BOX_NODES";
69    private static final String MIXED = "MIXED";
70    private static final String FIXED_MIXED = "FIXED_MIXED";
71    private static final String FIXED_BOX_NODES = "FIXED_BOX_NODES";
72  
73    private static final String LAYOUT = "LAYOUT";
74    private static final String EDGE_LABEL_MODEL = "EDGE_LABEL_MODEL";
75    private static final String EDGE_LABELING = "EDGE_LABELING";
76    private static final String LABELING = "LABELING";
77    private static final String GENERIC = "GENERIC";
78    private static final String NONE = "NONE";
79    private static final String INTEGRATED = "INTEGRATED";
80    private static final String FREE = "FREE";
81    private static final String SIDE_SLIDER = "SIDE_SLIDER";
82    private static final String CENTER_SLIDER = "CENTER_SLIDER";
83    private static final String AS_IS = "AS_IS";
84    private static final String BEST = "BEST";
85  
86    private final String styleEnum[] = {NORMAL, NORMAL_TREE, UNIFORM_NODES, BOX_NODES, MIXED, FIXED_MIXED, FIXED_BOX_NODES};
87  
88    private static final String[] edgeLabeling = {
89      NONE,
90      INTEGRATED,
91      GENERIC
92    };
93  
94    private static final String[] edgeLabelModel = {
95      BEST,
96      AS_IS,
97      CENTER_SLIDER,
98      SIDE_SLIDER,
99      FREE,
100   };
101 
102   public OrthogonalLayoutModule()
103   {
104     super (ORTHOGONAL,"yFiles Layout Team",
105            "Orthogonal Layouter");
106     setPortIntersectionCalculatorEnabled(true);
107   }
108 
109   public OptionHandler createOptionHandler()
110   {
111     OptionHandler op = new OptionHandler(getModuleName());
112     
113     ConstraintManager cm = new ConstraintManager( op );
114  
115     
116     op.useSection(LAYOUT);
117     op.addEnum(STYLE,styleEnum,0);
118     op.addInt(GRID,25);
119     op.addBool(LENGTH_REDUCTION, true);
120     op.addBool(USE_EXISTING_DRAWING_AS_SKETCH,false);
121     op.addBool(CROSSING_POSTPROCESSING,true);
122     op.addBool(PERCEIVED_BENDS_POSTPROCESSING, true);
123     op.addBool(USE_RANDOMIZATION,true);
124     op.addBool(USE_FACE_MAXIMIZATION,false);
125     op.useSection(LABELING);
126     op.addEnum(EDGE_LABELING, edgeLabeling, 0);
127     op.addEnum(EDGE_LABEL_MODEL, edgeLabelModel, 0);
128     
129     cm.setEnabledOnValueEquals( EDGE_LABELING, NONE, EDGE_LABEL_MODEL, true);
130     
131     cm.setEnabledOnValueEquals( USE_EXISTING_DRAWING_AS_SKETCH, Boolean.FALSE, CROSSING_POSTPROCESSING);
132     cm.setEnabledOnValueEquals( USE_EXISTING_DRAWING_AS_SKETCH, Boolean.FALSE, PERCEIVED_BENDS_POSTPROCESSING);
133     cm.setEnabledOnValueEquals( USE_EXISTING_DRAWING_AS_SKETCH, Boolean.FALSE, STYLE);
134     cm.setEnabledOnValueEquals( USE_EXISTING_DRAWING_AS_SKETCH, Boolean.FALSE, USE_RANDOMIZATION);
135 
136     
137     op.useSection(GROUPING);
138     String[] gEnum = { LAYOUT_GROUPS, FIX_GROUPS, IGNORE_GROUPS };
139     op.addEnum(GROUP_POLICY, gEnum, 0);
140     op.addDouble(GROUP_LAYOUT_QUALITY, 1.0, 0.0, 1.0);
141     
142     cm.setEnabledOnValueEquals( GROUP_POLICY, LAYOUT_GROUPS, GROUP_LAYOUT_QUALITY);
143     
144     return op;
145   }
146 
147   public void mainrun()
148   {
149     OptionHandler op = getOptionHandler();
150     
151     OrthogonalLayouter orthogonal = new OrthogonalLayouter();
152     
153     ////////////////////////////////////////////////////////////////////////////
154     // Layout
155     ////////////////////////////////////////////////////////////////////////////
156 
157     switch (OptionHandler.getIndex(styleEnum, op.getString(STYLE))){
158       default:
159       case 0:
160         orthogonal.setLayoutStyle(OrthogonalLayouter.NORMAL_STYLE);
161         break;
162       case 1:
163         orthogonal.setLayoutStyle(OrthogonalLayouter.NORMAL_TREE_STYLE);
164         break;
165       case 2:
166         orthogonal.setLayoutStyle(OrthogonalLayouter.UNIFORM_STYLE);
167         break;
168       case 3:
169         orthogonal.setLayoutStyle(OrthogonalLayouter.BOX_STYLE);
170         break;
171       case 4:
172         orthogonal.setLayoutStyle(OrthogonalLayouter.MIXED_STYLE);
173         break;
174       case 5:
175         orthogonal.setLayoutStyle(OrthogonalLayouter.FIXED_MIXED_STYLE);
176         break;
177       case 6:
178         orthogonal.setLayoutStyle(OrthogonalLayouter.FIXED_BOX_STYLE);
179         break;
180     }
181     orthogonal.setGrid(op.getInt(GRID));
182     orthogonal.setUseLengthReduction(
183       op.getBool(LENGTH_REDUCTION));
184     orthogonal.setUseCrossingPostprocessing(
185       op.getBool(CROSSING_POSTPROCESSING));
186     orthogonal.setPerceivedBendsOptimizationEnabled(
187       op.getBool(PERCEIVED_BENDS_POSTPROCESSING));
188     orthogonal.setUseRandomization(
189       op.getBool(USE_RANDOMIZATION));
190     orthogonal.setUseFaceMaximization(
191       op.getBool(USE_FACE_MAXIMIZATION));
192     orthogonal.setUseSketchDrawing(op.getBool(USE_EXISTING_DRAWING_AS_SKETCH));
193 
194 
195     ////////////////////////////////////////////////////////////////////////////
196     // Labels
197     ////////////////////////////////////////////////////////////////////////////
198 
199     String el = op.getString(EDGE_LABELING);
200     if(!el.equals(NONE))
201     {
202       setupEdgeLabelModel(el, op.getString(EDGE_LABEL_MODEL));
203       if(el.equals(GENERIC))
204       {
205         GreedyMISLabeling la = new GreedyMISLabeling();
206         la.setPlaceNodeLabels(false);
207         la.setPlaceEdgeLabels(true);
208         la.setProfitModel(new LabelRanking());
209         orthogonal.setLabelLayouter(la);
210         orthogonal.setLabelLayouterEnabled(true);
211       }
212       else if(el.equals(INTEGRATED))
213       {
214         orthogonal.setLabelLayouter(new LabelLayoutTranslator());
215         orthogonal.setLabelLayouterEnabled(true);
216       }
217     }
218     else
219     {
220       orthogonal.setLabelLayouterEnabled(false);
221     }
222     
223     Graph2D graph = getGraph2D();
224     Layouter layouter = orthogonal;
225     LayoutStage preStage = null;
226     
227     if(HierarchyManager.containsGroupNodes(graph) && !op.get(GROUP_POLICY).equals(IGNORE_GROUPS))
228     {
229       GroupLayoutConfigurator glc = new GroupLayoutConfigurator(graph);
230     
231       glc.prepareAutoBoundsFeatures();
232       glc.prepareGroupDataProviders();
233       glc.prepareGroupNodeInsets();
234       
235       FixedGroupLayoutStage fgl = null;
236       if(op.get(GROUP_POLICY).equals(FIX_GROUPS))
237       {
238         fgl = new FixedGroupLayoutStage();
239         fgl.setInterEdgeRoutingStyle(FixedGroupLayoutStage.ROUTING_STYLE_ORTHOGONAL);
240         orthogonal.prependStage(fgl);
241         preStage = fgl;
242       }  
243       else
244       {
245         OrthogonalGroupLayouter ogl = new OrthogonalGroupLayouter();
246         ogl.setLabelLayouterEnabled(orthogonal.isLabelLayouterEnabled());
247         ogl.setLabelLayouter(orthogonal.getLabelLayouter());
248             
249         ogl.setGrid(op.getInt(GRID));
250         ogl.setLayoutQuality(op.getDouble(GROUP_LAYOUT_QUALITY));
251         layouter = ogl;
252       } 
253     
254       try
255       {
256         launchLayouter(layouter);
257       }
258       finally
259       {
260         glc.restoreAutoBoundsFeatures();
261         glc.restoreGroupDataProviders();
262         glc.restoreGroupNodeInsets();
263         if(preStage != null) orthogonal.removeStage(preStage);
264       }
265     }
266     else
267     {
268       try {
269       launchLayouter(layouter);
270       }
271       finally {
272       }
273     }
274   }
275 
276   void setupEdgeLabelModel(String edgeLabeling, String edgeLabelModel)
277   {
278     if(edgeLabeling.equals(NONE) || edgeLabelModel.equals(AS_IS))
279     {
280       return; //nothing to do
281     }
282 
283     if(edgeLabelModel.equals(BEST))
284     {
285       if(edgeLabeling.equals(GENERIC))
286         edgeLabelModel = SIDE_SLIDER;
287       else if(edgeLabeling.equals(INTEGRATED))
288         edgeLabelModel = FREE;
289     }
290 
291     byte model = EdgeLabel.SIDE_SLIDER;
292     int preferredSide = LabelLayoutConstants.PLACE_RIGHT_OF_EDGE;
293     if(edgeLabelModel.equals(CENTER_SLIDER))
294     {
295       model = EdgeLabel.CENTER_SLIDER;
296       preferredSide = LabelLayoutConstants.PLACE_ON_EDGE;
297     }
298     else if(edgeLabelModel.equals(FREE))
299     {
300       model = EdgeLabel.FREE;
301       preferredSide = LabelLayoutConstants.PLACE_ON_EDGE;
302     }
303 
304     Graph2D graph = getGraph2D();
305     for(EdgeCursor ec = graph.edges(); ec.ok(); ec.next())
306     {
307       Edge e = ec.edge();
308       EdgeRealizer er = graph.getRealizer(e);
309       for(int i = 0; i < er.labelCount(); i++)
310       {
311         EdgeLabel el = er.getLabel(i);
312         el.setModel(model);
313         int prefAlongEdge = el.getPreferredPlacement() & LabelLayoutConstants.PLACEMENT_ALONG_EDGE_MASK;
314         el.setPreferredPlacement((byte)(preferredSide | prefAlongEdge));
315       }
316     }
317   }
318 }
319