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.module;
15  
16  import y.module.LayoutModule;
17  import y.module.YModule;
18  
19  import y.option.OptionHandler;
20  import y.layout.partial.PartialLayouter;
21  import y.layout.organic.SmartOrganicLayouter;
22  import y.layout.Layouter;
23  import y.layout.orthogonal.OrthogonalLayouter;
24  import y.layout.circular.CircularLayouter;
25  import y.layout.hierarchic.IncrementalHierarchicLayouter;
26  import y.view.Graph2D;
27  import y.view.Selections;
28  
29  /**
30   * This module represents an interactive configurator and launcher for
31   * {@link y.layout.partial.PartialLayouter}.
32   *
33   *
34   * @see <a href="http://docs.yworks.com/yfiles/doc/developers-guide/partial_layout.html#partial_layout">Section Partial Layout </a> in the yFiles for Java Developer's Guide
35   */
36  public class PartialLayoutModule extends LayoutModule {
37    private static final String PARTIAL = "PARTIAL";
38    private static final String GENERAL = "GENERAL";
39    public static final String SUBGRAPH_LAYOUTER = "SUBGRAPH_LAYOUTER";
40    public static final String SUBGRAPH_LAYOUTER_IHL = "SUBGRAPH_LAYOUTER_IHL";
41    public static final String SUBGRAPH_LAYOUTER_ORGANIC = "SUBGRAPH_LAYOUTER_ORGANIC";
42    public static final String SUBGRAPH_LAYOUTER_CIRCULAR = "SUBGRAPH_LAYOUTER_CIRCULAR";
43    public static final String SUBGRAPH_LAYOUTER_ORTHOGONAL = "SUBGRAPH_LAYOUTER_ORTHOGONAL";
44    private static final String SUBGRAPH_LAYOUTER_NO_LAYOUT = "SUBGRAPH_LAYOUTER_NO_LAYOUT";
45    private static final String MIN_NODE_DIST = "MIN_NODE_DIST";
46  
47    public static final String SUBGRAPH_POSITION_STRATEGY = "SUBGRAPH_POSITION_STRATEGY";
48    public static final String SUBGRAPH_POSITIONING_STRATEGY_BARYCENTER = "SUBGRAPH_POSITION_STRATEGY_BARYCENTER";
49    public static final String SUBGRAPH_POSITIONING_STRATEGY_FROM_SKETCH = "SUBGRAPH_POSITION_STRATEGY_FROM_SKETCH";
50  
51    public static final String ROUTING_TO_SUBGRAPH = "ROUTING_TO_SUBGRAPH";
52    public static final String ROUTING_TO_SUBGRAPH_STRAIGHT_LINE = "ROUTING_TO_SUBGRAPH_STRAIGHT_LINE";
53    public static final String ROUTING_TO_SUBGRAPH_POLYLINE = "ROUTING_TO_SUBGRAPH_POLYLINE";
54    public static final String ROUTING_TO_SUBGRAPH_ORTHOGONALLY = "ROUTING_TO_SUBGRAPH_ORTHOGONALLY";
55    public static final String ROUTING_TO_SUBGRAPH_ORGANIC = "ROUTING_TO_SUBGRAPH_ORGANIC";
56    public static final String ROUTING_TO_SUBGRAPH_AUTO = "ROUTING_TO_SUBGRAPH_AUTO";
57  
58    public static final String MODE_COMPONENT_ASSIGNMENT = "MODE_COMPONENT_ASSIGNMENT";
59    public static final String MODE_COMPONENT_CLUSTERING = "MODE_COMPONENT_CLUSTERING";
60    public static final String MODE_COMPONENT_CONNECTED = "MODE_COMPONENT_CONNECTED";
61    public static final String MODE_COMPONENT_CUSTOMIZED = "MODE_COMPONENT_CUSTOMIZED";
62    public static final String MODE_COMPONENT_SINGLE = "MODE_COMPONENT_SINGLE";
63  
64    public static final String HIERARCHY_REORGANIZATION = "HIERARCHY_REORGANIZATION";
65  
66    public static final String ORIENTATION_MAIN_GRAPH = "ORIENTATION_MAIN_GRAPH";
67    public static final String ORIENTATION_MAIN_GRAPH_NONE = "ORIENTATION_MAIN_GRAPH_NONE";
68    public static final String ORIENTATION_MAIN_GRAPH_AUTO_DETECT = "ORIENTATION_MAIN_GRAPH_AUTO_DETECT";
69    public static final String ORIENTATION_MAIN_GRAPH_TOP_TO_DOWN = "ORIENTATION_MAIN_GRAPH_TOP_TO_DOWN";
70    public static final String ORIENTATION_MAIN_GRAPH_DOWN_TO_TOP = "ORIENTATION_MAIN_GRAPH_DOWN_TO_TOP";
71    public static final String ORIENTATION_MAIN_GRAPH_LEFT_TO_RIGHT = "ORIENTATION_MAIN_GRAPH_LEFT_TO_RIGHT";
72    public static final String ORIENTATION_MAIN_GRAPH_RIGHT_TO_LEFT = "ORIENTATION_MAIN_GRAPH_RIGHT_TO_LEFT";
73  
74    public static final String CONSIDER_SNAPLINES = "CONSIDER_SNAPLINES";
75  
76    private static final String[] subgraphLayouterEnum = {SUBGRAPH_LAYOUTER_IHL, SUBGRAPH_LAYOUTER_ORGANIC,
77        SUBGRAPH_LAYOUTER_CIRCULAR, SUBGRAPH_LAYOUTER_ORTHOGONAL,
78        SUBGRAPH_LAYOUTER_NO_LAYOUT};
79    private static final String[] subgraphPositionStrategyEnum = {SUBGRAPH_POSITIONING_STRATEGY_BARYCENTER,
80        SUBGRAPH_POSITIONING_STRATEGY_FROM_SKETCH};
81    private static final String[] routerToSubgraphEnum = {ROUTING_TO_SUBGRAPH_AUTO, ROUTING_TO_SUBGRAPH_STRAIGHT_LINE,
82        ROUTING_TO_SUBGRAPH_POLYLINE, ROUTING_TO_SUBGRAPH_ORTHOGONALLY
83        , ROUTING_TO_SUBGRAPH_ORGANIC};
84    private static final String[] modeComponentAsignmentEnum = {MODE_COMPONENT_CONNECTED,
85        MODE_COMPONENT_SINGLE, MODE_COMPONENT_CUSTOMIZED};
86    private static final String[] orientationMainGraphEnum = {ORIENTATION_MAIN_GRAPH_AUTO_DETECT,
87        ORIENTATION_MAIN_GRAPH_TOP_TO_DOWN, ORIENTATION_MAIN_GRAPH_DOWN_TO_TOP, ORIENTATION_MAIN_GRAPH_LEFT_TO_RIGHT,
88        ORIENTATION_MAIN_GRAPH_RIGHT_TO_LEFT, ORIENTATION_MAIN_GRAPH_NONE};
89  
90  
91    private static final byte EDGE_ROUTING_ORTHOGONAL = 0;
92    private static final byte EDGE_ROUTING_STRAIGHTLINE = 1;
93    private static final byte EDGE_ROUTING_AUTOMATIC = 2;
94    private static final byte EDGE_ROUTING_ORGANIC = 3;
95    private static final byte EDGE_ROUTING_POLYLINE = 4;
96  
97    public PartialLayoutModule() {
98      super(PARTIAL, "yFiles Layout Team", "An algorithm that lays out only a subset of a graph.");
99    }
100 
101   public OptionHandler createOptionHandler() {
102     OptionHandler op = new OptionHandler(getModuleName());
103     op.useSection(GENERAL);
104     op.addEnum(ROUTING_TO_SUBGRAPH, routerToSubgraphEnum, 0);
105     op.addEnum(MODE_COMPONENT_ASSIGNMENT, modeComponentAsignmentEnum, 0);
106     op.addEnum(SUBGRAPH_LAYOUTER, subgraphLayouterEnum, 0);
107     op.addEnum(SUBGRAPH_POSITION_STRATEGY, subgraphPositionStrategyEnum, 0);
108     op.addInt(MIN_NODE_DIST, 30, 1, 100);
109     op.addEnum(ORIENTATION_MAIN_GRAPH, orientationMainGraphEnum, 0);
110     op.addBool(CONSIDER_SNAPLINES, true);
111     return op;
112   }
113 
114   protected void mainrun() {
115     final Graph2D graph = getGraph2D();
116     if (graph.selectedNodes().size() + graph.selectedEdges().size() == 0) {
117       return; //nothing to do
118     }
119 
120     OptionHandler op = getOptionHandler();
121 
122     //register dp for selected nodes/edges
123     graph.addDataProvider(PartialLayouter.PARTIAL_NODES_DPKEY, Selections.createSelectionDataProvider(graph));
124     graph.addDataProvider(PartialLayouter.PARTIAL_EDGES_DPKEY, Selections.createSelectionDataProvider(graph));
125 
126     //create layouter
127     final PartialLayouter partialLayouter = new PartialLayouter();
128     partialLayouter.setMinimalNodeDistance(op.getInt(MIN_NODE_DIST));
129     partialLayouter.setConsiderNodeAlignment(op.getBool(CONSIDER_SNAPLINES));
130 
131     final byte subgraphPositioningStrategy = subgraphPositioningStrategyAsByte(
132         subgraphPositionStrategyEnum[op.getEnum(SUBGRAPH_POSITION_STRATEGY)]);
133     partialLayouter.setPositioningStrategy(subgraphPositioningStrategy);
134 
135     final byte componentAssignment = componentAssignmentAsByte(
136         modeComponentAsignmentEnum[op.getEnum(MODE_COMPONENT_ASSIGNMENT)]);
137     partialLayouter.setComponentAssignmentStrategy(componentAssignment);
138 
139     final byte mainGraphOrientation = graphOrientationAsByte(
140         orientationMainGraphEnum[op.getEnum(ORIENTATION_MAIN_GRAPH)]);
141     partialLayouter.setLayoutOrientation(mainGraphOrientation);
142 
143     final byte routingToSubGraph = routingToSubGraphAsByte(routerToSubgraphEnum[op.getEnum(ROUTING_TO_SUBGRAPH)]);
144     partialLayouter.setEdgeRoutingStrategy((routingToSubGraph == EDGE_ROUTING_POLYLINE) ?
145         EDGE_ROUTING_STRAIGHTLINE : routingToSubGraph);
146 
147     //determine the subgraph layouter
148     final String subgraphLayouterString = subgraphLayouterEnum[op.getEnum(SUBGRAPH_LAYOUTER)];
149     Layouter subgraphLayouter = null;
150     if (PartialLayouter.COMPONENT_ASSIGNMENT_STRATEGY_SINGLE == componentAssignment) {
151       //trivial case: for single nodes components it should be no subgraph layouter
152       subgraphLayouter = null;
153     } else if (SUBGRAPH_LAYOUTER_IHL.equals(subgraphLayouterString)) {
154       subgraphLayouter = new IncrementalHierarchicLayouter();
155       ((IncrementalHierarchicLayouter) subgraphLayouter).setIntegratedEdgeLabelingEnabled(true);
156       if (PartialLayouter.EDGE_ROUTING_STRATEGY_ORTHOGONAL == routingToSubGraph) {
157         ((IncrementalHierarchicLayouter) subgraphLayouter).setOrthogonallyRouted(true);
158       } else {
159         ((IncrementalHierarchicLayouter) subgraphLayouter).setOrthogonallyRouted(false);
160       }
161     } else if (SUBGRAPH_LAYOUTER_ORGANIC.equals(subgraphLayouterString)) {
162       subgraphLayouter = new SmartOrganicLayouter();
163       ((SmartOrganicLayouter) subgraphLayouter).setDeterministic(true);
164     } else if (SUBGRAPH_LAYOUTER_CIRCULAR.equals(subgraphLayouterString)) {
165       subgraphLayouter = new CircularLayouter();
166     } else if (SUBGRAPH_LAYOUTER_ORTHOGONAL.equals(subgraphLayouterString)) {
167       subgraphLayouter = new OrthogonalLayouter();
168     } else if (SUBGRAPH_LAYOUTER_NO_LAYOUT.equals(subgraphLayouterString)) {
169       subgraphLayouter = null;
170     }
171     partialLayouter.setCoreLayouter(subgraphLayouter);
172 
173     getLayoutExecutor().setConfiguringTableNodeRealizers(true);
174     final boolean horizontalLayout = (mainGraphOrientation == PartialLayouter.ORIENTATION_LEFT_TO_RIGHT)
175         || (mainGraphOrientation == PartialLayouter.ORIENTATION_RIGHT_TO_LEFT);
176     getLayoutExecutor().getTableLayoutConfigurator().setHorizontalLayoutConfiguration(horizontalLayout);
177 
178     launchLayouter(partialLayouter);
179   }
180 
181   /** Determines the routing of inter edges (main graph to subgraph). */
182   private static byte routingToSubGraphAsByte(final String routingToSubGraphString) {
183     if (ROUTING_TO_SUBGRAPH_ORTHOGONALLY.equals(routingToSubGraphString)) {
184       return EDGE_ROUTING_ORTHOGONAL;
185     } else if (ROUTING_TO_SUBGRAPH_STRAIGHT_LINE.equals(routingToSubGraphString)) {
186       return EDGE_ROUTING_STRAIGHTLINE;
187     } else if (ROUTING_TO_SUBGRAPH_AUTO.equals(routingToSubGraphString)) {
188       return EDGE_ROUTING_AUTOMATIC;
189     } else if (ROUTING_TO_SUBGRAPH_ORGANIC.equals(routingToSubGraphString)) {
190       return EDGE_ROUTING_ORGANIC;
191     } else if (ROUTING_TO_SUBGRAPH_POLYLINE.equals(routingToSubGraphString)) {
192       return EDGE_ROUTING_POLYLINE;
193     } else {
194       return PartialLayouter.EDGE_ROUTING_STRATEGY_STRAIGHTLINE;
195     }
196   }
197 
198   /** Determines the subgraph position strategy. */
199   private static byte subgraphPositioningStrategyAsByte(final String subgraphPositioningStrategyString) {
200     if (SUBGRAPH_POSITIONING_STRATEGY_FROM_SKETCH.equals(subgraphPositioningStrategyString)) {
201       return PartialLayouter.SUBGRAPH_POSITIONING_STRATEGY_FROM_SKETCH;
202     } else {
203       return PartialLayouter.SUBGRAPH_POSITIONING_STRATEGY_BARYCENTER;
204     }
205   }
206 
207   /** Determines component by: {Clustering, Connected graph, Particular}. */
208   private static byte componentAssignmentAsByte(final String componentAssignmentString) {
209     if (MODE_COMPONENT_SINGLE.equals(componentAssignmentString)) {
210       return PartialLayouter.COMPONENT_ASSIGNMENT_STRATEGY_SINGLE;
211     } else if (MODE_COMPONENT_CONNECTED.equals(componentAssignmentString)) {
212       return PartialLayouter.COMPONENT_ASSIGNMENT_STRATEGY_CONNECTED;
213     } else if (MODE_COMPONENT_CLUSTERING.equals(componentAssignmentString)) {
214       return PartialLayouter.COMPONENT_ASSIGNMENT_STRATEGY_CLUSTERING;
215     } else {
216       return PartialLayouter.COMPONENT_ASSIGNMENT_STRATEGY_CUSTOMIZED;
217     }
218   }
219 
220   /** Determines the main graph Orientation. */
221   private static byte graphOrientationAsByte(final String graphOrientationString) {
222     if (ORIENTATION_MAIN_GRAPH_AUTO_DETECT.equals(graphOrientationString)) {
223       return PartialLayouter.ORIENTATION_AUTO_DETECTION;
224     } else if (ORIENTATION_MAIN_GRAPH_TOP_TO_DOWN.equals(graphOrientationString)) {
225       return PartialLayouter.ORIENTATION_TOP_TO_BOTTOM;
226     } else if (ORIENTATION_MAIN_GRAPH_DOWN_TO_TOP.equals(graphOrientationString)) {
227       return PartialLayouter.ORIENTATION_BOTTOM_TO_TOP;
228     } else if (ORIENTATION_MAIN_GRAPH_LEFT_TO_RIGHT.equals(graphOrientationString)) {
229       return PartialLayouter.ORIENTATION_LEFT_TO_RIGHT;
230     } else if (ORIENTATION_MAIN_GRAPH_RIGHT_TO_LEFT.equals(graphOrientationString)) {
231       return PartialLayouter.ORIENTATION_RIGHT_TO_LEFT;
232     } else if (ORIENTATION_MAIN_GRAPH_NONE.equals(graphOrientationString)) {
233       return PartialLayouter.ORIENTATION_NONE;
234     } else {
235       return PartialLayouter.ORIENTATION_AUTO_DETECTION;
236     }
237   }
238 }
239