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.Layouter;
17  import y.layout.router.EdgeGroupRouterStage;
18  import y.layout.router.GroupNodeRouterStage;
19  import y.layout.router.OrthogonalEdgeRouter;
20  import y.layout.router.PatchRouterStage;
21  import y.layout.router.ReducedSphereOfActionStage;
22  import y.option.ConstraintManager;
23  import y.option.OptionGroup;
24  import y.option.OptionHandler;
25  import y.view.hierarchy.GroupLayoutConfigurator;
26  import y.module.LayoutModule;
27  
28  /**
29   * This module represents an interactive configurator and launcher for
30   * {@link y.layout.router.OrthogonalEdgeRouter}.
31   * It is similar to OrthogonalEdgeRouterModule found in the yFiles package
32   * y.module.
33   *
34   */
35  public class OrthogonalEdgeRouterModule extends LayoutModule
36  {
37    private static final String NAME  = "ORTHOGONAL_EDGE_ROUTER";
38    private static final String SCOPE = "SCOPE";
39    private static final String SCOPE_ALL_EDGES = "ALL_EDGES";
40    private static final String SCOPE_SELECTED_EDGES = "SELECTED_EDGES";
41    private static final String SCOPE_AT_SELECTED_NODES = "AT_SELECTED_NODES";
42    private static final String MINIMUM_DISTANCE_TO_EDGE = "MINIMUM_DISTANCE_TO_EDGE";
43    private static final String USE_CUSTOM_MINIMUM_DISTANCE_TO_NODE = "USE_CUSTOM_MINIMUM_DISTANCE_TO_NODE";
44    private static final String CUSTOM_MINIMUM_DISTANCE_TO_NODE = "CUSTOM_MINIMUM_DISTANCE_TO_NODE";
45    private static final String SPACE_DRIVEN_VS_CENTER_DRIVEN_SEARCH = "SPACE_DRIVEN_VS_CENTER_DRIVEN_SEARCH";
46    private static final String LOCAL_CROSSING_MINIMIZATION = "LOCAL_CROSSING_MINIMIZATION";
47    private static final String GRID_SPACING = "GRID_SPACING";
48    private static final String ROUTE_ON_GRID = "ROUTE_ON_GRID";
49    private static final String CROSSING_COST     = "CROSSING_COST";
50    private static final String REROUTING_ENABLED = "REROUTING_ENABLED";
51  
52    private static final String LAYOUT_OPTIONS = "LAYOUT_OPTIONS";
53    private static final String CROSSING_MINIMIZATION = "CROSSING_MINIMIZATION";
54  
55  
56    //////////////////////////////////////////////////////////////////////////////
57    //// Own stuff
58    //////////////////////////////////////////////////////////////////////////////
59    private OrthogonalEdgeRouter router;
60  
61    //////////////////////////////////////////////////////////////////////////////
62    //// Construction
63    //////////////////////////////////////////////////////////////////////////////
64    public OrthogonalEdgeRouterModule()
65    {
66      super(NAME, "yFiles Layout Team", "Routes edges orthogonally.");
67      setPortIntersectionCalculatorEnabled(true);
68    }
69    
70    //////////////////////////////////////////////////////////////////////////////
71    //// Implementation for abstract class y.module.YModule
72    //////////////////////////////////////////////////////////////////////////////
73    protected void init(){ instantiateRouter(); }
74    
75    protected void mainrun()
76    {  
77      // initialize potential grouping information
78      GroupLayoutConfigurator glc = new GroupLayoutConfigurator(getGraph2D());
79      try {
80        // register grouping relevant DataProviders
81        glc.prepareAll();
82        // launch layouter in buffered mode
83        launchLayouter(
84            new EdgeGroupRouterStage(
85                new GroupNodeRouterStage(
86                    new ReducedSphereOfActionStage(
87                        new PatchRouterStage(router)))));
88      } finally {
89        // make sure the DataProviders will always be unregistered
90        glc.restoreAll();
91      }
92    }
93    
94    protected void dispose(){ router = null; }
95    
96    /**
97     * Creates and initializes the Option Handler so that a convenient way for
98     * manipulating the parameters is at the user's hand.
99     */
100   protected OptionHandler createOptionHandler()
101   {
102     OptionHandler oh = new OptionHandler(getModuleName());  
103     initOptionHandler(oh, null);
104     return oh;
105   }
106   
107   void initOptionHandler(OptionHandler oh, Layouter layouter)
108   {
109     oh.clear();
110     if(layouter == null) layouter = new OrthogonalEdgeRouter();
111     OrthogonalEdgeRouter router = (OrthogonalEdgeRouter)layouter;
112 
113     OptionGroup og = new OptionGroup();
114     og.setAttribute(OptionGroup.ATTRIBUTE_TITLE, LAYOUT_OPTIONS);
115     String enums[] = { SCOPE_ALL_EDGES, SCOPE_SELECTED_EDGES, SCOPE_AT_SELECTED_NODES };
116     if(router.getSphereOfAction() == OrthogonalEdgeRouter.ROUTE_ALL_EDGES)
117       og.addItem(oh.addEnum(SCOPE, enums, 0));
118     else if(router.getSphereOfAction() == OrthogonalEdgeRouter.ROUTE_EDGES_AT_SELECTED_NODES)
119       og.addItem(oh.addEnum(SCOPE, enums, 1));
120     else
121       og.addItem(oh.addEnum(SCOPE, enums, 2));
122     
123     // The value given for 'minimum distance' denotes a halo to the left and
124     // right of an edge segment.
125     og.addItem(oh.addInt(MINIMUM_DISTANCE_TO_EDGE, router.getMinimumDistance()));
126     og.addItem(oh.addBool(USE_CUSTOM_MINIMUM_DISTANCE_TO_NODE, !router.getCoupledDistances()));
127     og.addItem(oh.addInt(CUSTOM_MINIMUM_DISTANCE_TO_NODE, router.getMinimumDistanceToNode()));
128     og.addItem(oh.addBool(ROUTE_ON_GRID, router.isGridRoutingEnabled()));
129     og.addItem(oh.addInt(GRID_SPACING, router.getGridSpacing()));
130     og.addItem(oh.addDouble(SPACE_DRIVEN_VS_CENTER_DRIVEN_SEARCH,
131                             router.getCenterToSpaceRatio(), 0.0, 1.0));
132     
133     og = new OptionGroup();
134     og.setAttribute(OptionGroup.ATTRIBUTE_TITLE, CROSSING_MINIMIZATION);
135     og.addItem(oh.addBool(LOCAL_CROSSING_MINIMIZATION,
136                           router.isLocalCrossingMinimizationEnabled()));
137     
138     og.addItem(oh.addDouble(CROSSING_COST, router.getCrossingCost()));
139     og.addItem(oh.addBool(REROUTING_ENABLED, router.isReroutingEnabled()));
140   
141     ConstraintManager cm = new ConstraintManager(oh);
142     cm.setEnabledOnValueEquals(ROUTE_ON_GRID, Boolean.TRUE, GRID_SPACING);
143     cm.setEnabledOnValueEquals(USE_CUSTOM_MINIMUM_DISTANCE_TO_NODE,
144                                Boolean.TRUE,
145                                CUSTOM_MINIMUM_DISTANCE_TO_NODE);
146     
147   }
148   
149   /**
150    * Initializes the option hander of this module with the 
151    * properties of the given router. 
152    * @param layouter an instance of {@link y.layout.router.OrthogonalEdgeRouter}.
153    */
154   public void initOptionHandler(Layouter layouter)
155   {
156     OptionHandler oh = getOptionHandler();
157     initOptionHandler(oh, layouter);
158   }
159   
160   /**
161    * Configures an instance of OrthogonalEdgeRouter. The values provided by
162    * this module's option handler are being used for this purpose.
163    */
164   public void configure(Layouter layouter)
165   {
166     if (layouter instanceof OrthogonalEdgeRouter)
167     {
168       OrthogonalEdgeRouter router = (OrthogonalEdgeRouter)layouter;
169       OptionHandler oh = getOptionHandler();
170       
171       String choice = oh.getString(SCOPE);
172       if (choice.equals(SCOPE_AT_SELECTED_NODES))
173         router.setSphereOfAction(OrthogonalEdgeRouter.ROUTE_EDGES_AT_SELECTED_NODES);
174       else if (choice.equals(SCOPE_SELECTED_EDGES))
175         router.setSphereOfAction(OrthogonalEdgeRouter.ROUTE_SELECTED_EDGES);
176       else
177         router.setSphereOfAction(OrthogonalEdgeRouter.ROUTE_ALL_EDGES);
178       
179       router.setMinimumDistance(oh.getInt(MINIMUM_DISTANCE_TO_EDGE));
180       router.setCoupledDistances(!oh.getBool(USE_CUSTOM_MINIMUM_DISTANCE_TO_NODE));
181       router.setMinimumDistanceToNode(oh.getInt(CUSTOM_MINIMUM_DISTANCE_TO_NODE));
182       
183       router.setGridRoutingEnabled(oh.getBool(ROUTE_ON_GRID));
184       router.setGridSpacing(oh.getInt(GRID_SPACING));
185       
186       router.setCenterToSpaceRatio(oh.getDouble(SPACE_DRIVEN_VS_CENTER_DRIVEN_SEARCH));
187       
188       router.setLocalCrossingMinimizationEnabled(oh.getBool(LOCAL_CROSSING_MINIMIZATION));
189 
190       router.setCrossingCost(oh.getDouble(CROSSING_COST));
191       router.setReroutingEnabled(oh.getBool(REROUTING_ENABLED));
192       
193       // Further, non-public options.
194       //router.setInnerPortsEnabled(true);
195     }
196     else
197     {
198       throw new IllegalArgumentException("argument must be of type y.layout.router.OrthogonalEdgeRouter");
199     }
200   }
201   
202   //////////////////////////////////////////////////////////////////////////////
203   //// Own stuff
204   //////////////////////////////////////////////////////////////////////////////
205   private void instantiateRouter()
206   {
207     if (router != null)
208       return;
209     router = new OrthogonalEdgeRouter();
210     configure(router);
211   }
212 }
213