1
14 package demo.view.layout.tree;
15
16 import y.algo.Trees;
17 import y.base.DataProvider;
18 import y.base.Edge;
19 import y.base.Graph;
20 import y.base.Node;
21 import y.base.NodeMap;
22 import y.layout.LayoutGraph;
23 import y.layout.Layouter;
24 import y.layout.tree.AbstractRotatableNodePlacer;
25 import y.layout.tree.AbstractRotatableNodePlacer.Matrix;
26 import y.layout.tree.AbstractRotatableNodePlacer.RootAlignment;
27 import y.layout.tree.BusPlacer;
28 import y.layout.tree.DefaultNodePlacer;
29 import y.layout.tree.DelegatingNodePlacer;
30 import y.layout.tree.DoubleLinePlacer;
31 import y.layout.tree.GenericTreeLayouter;
32 import y.layout.tree.LayeredNodePlacer;
33 import y.layout.tree.NodePlacer;
34 import y.layout.tree.SimpleNodePlacer;
35 import y.util.DataProviderAdapter;
36
37
48 public abstract class TreeLayoutConfiguration implements Layouter {
49
50
54 public static final TreeLayoutConfiguration LAYERED_TREE = new TreeLayoutConfiguration() {
55 protected void prepare() {
56 super.prepare();
57 LayeredNodePlacer layeredNodePlacer = new LayeredNodePlacer();
58 layeredNodePlacer.setRootAlignment( RootAlignment.CENTER );
59 layeredNodePlacer.setRoutingStyle( LayeredNodePlacer.ORTHOGONAL_STYLE );
60 setNodePlacers( Trees.getRoot( graph ), layeredNodePlacer );
61 }
62 };
63
64
67 public static final TreeLayoutConfiguration LAYERED_TREE_90 = new TreeLayoutConfiguration() {
68 protected void prepare() {
69 super.prepare();
70 LayeredNodePlacer layeredNodePlacer = new LayeredNodePlacer( Matrix.ROT90, Matrix.ROT90 );
71 layeredNodePlacer.setRootAlignment( RootAlignment.CENTER );
72 layeredNodePlacer.setRoutingStyle( LayeredNodePlacer.ORTHOGONAL_STYLE );
73 setNodePlacers( Trees.getRoot( graph ), layeredNodePlacer );
74 }
75 };
76
77
80 public static final TreeLayoutConfiguration DOUBLE_LINE = new TreeLayoutConfiguration() {
81 protected void prepare() {
82 super.prepare();
83 DoubleLinePlacer nodePlacer = new DoubleLinePlacer();
84 nodePlacer.setSpacing( 20 );
85 layouter.setDefaultNodePlacer( nodePlacer );
86 }
87 };
88
89
92 public static final TreeLayoutConfiguration DEFAULT_DELEGATING = new TreeLayoutConfiguration() {
93 protected void prepare() {
94 super.prepare();
95
96 Node root = Trees.getRoot( graph );
97
98 SimpleNodePlacer placerNorth = new SimpleNodePlacer( Matrix.ROT180 );
100 placerNorth.setRootAlignment( RootAlignment.CENTER );
101
102 SimpleNodePlacer placerSouth = new SimpleNodePlacer();
103 placerSouth.setRootAlignment( RootAlignment.CENTER );
104
105 setNodePlacer( root, new DelegatingNodePlacer( Matrix.DEFAULT, placerNorth, placerSouth ) );
106
107 int upperCount = root.outDegree() / 2;
109
110 graph = ( LayoutGraph ) root.getGraph();
111 int counter = 0;
112 for ( Edge edge = root.firstOutEdge(); edge != null; edge = edge.nextOutEdge() ) {
113 Node child = edge.target();
114
115 if ( counter < upperCount ) {
116 setNodePlacers( child, placerNorth );
117 } else {
118 setNodePlacers( child, placerSouth );
119 }
120 counter++;
121 }
122 }
123 };
124
125
129 public static final TreeLayoutConfiguration PLAYOFFS_DOUBLE = new TreeLayoutConfiguration() {
130 protected void prepare() {
131 super.prepare();
132
133 Node root = Trees.getRoot( graph );
135
136 SimpleNodePlacer placerNorth = new SimpleNodePlacer( Matrix.MIR_HOR );
137 placerNorth.setRootAlignment( RootAlignment.MEDIAN );
138
139 SimpleNodePlacer placerSouth = new SimpleNodePlacer();
140 placerSouth.setRootAlignment( RootAlignment.MEDIAN );
141
142 DelegatingNodePlacer rootPlacer = new DelegatingNodePlacer( Matrix.DEFAULT, placerNorth, placerSouth );
143 rootPlacer.setOrientation( DelegatingNodePlacer.VERTICAL );
144 setNodePlacer( root, rootPlacer );
145
146 if ( root.outDegree() != 2 ) {
147 throw new IllegalStateException( "May only be used with a binary tree." );
148 }
149
150 Node upperChild = root.firstOutEdge().target();
152 Node lowerChild = root.firstOutEdge().nextOutEdge().target();
153
154 SimpleNodePlacer placerLeft = new SimpleNodePlacer( Matrix.ROT90 );
155 placerLeft.setRootAlignment( RootAlignment.MEDIAN );
156
157 SimpleNodePlacer placerRight = new SimpleNodePlacer( Matrix.ROT270 );
158 placerRight.setRootAlignment( RootAlignment.MEDIAN );
159
160 DelegatingNodePlacer placer2ndLayer = new DelegatingNodePlacer( Matrix.ROT180, placerLeft, placerRight );
161 setNodePlacer( upperChild, placer2ndLayer );
162 setNodePlacer( lowerChild, placer2ndLayer );
163
164 LayeredNodePlacer leftPlacer = new LayeredNodePlacer( Matrix.ROT90, Matrix.ROT90 );
166 leftPlacer.setRootAlignment( RootAlignment.MEDIAN );
167 leftPlacer.setRoutingStyle( LayeredNodePlacer.ORTHOGONAL_STYLE );
168
169 LayeredNodePlacer rightPlacer = new LayeredNodePlacer( Matrix.ROT270, Matrix.ROT270 );
170 rightPlacer.setRootAlignment( RootAlignment.MEDIAN );
171 rightPlacer.setRoutingStyle( LayeredNodePlacer.ORTHOGONAL_STYLE );
172
173 if ( upperChild.outDegree() != 2 ) {
174 throw new IllegalStateException( "May only be used with a binary tree." );
175 }
176 if ( lowerChild.outDegree() != 2 ) {
177 throw new IllegalStateException( "May only be used with a binary tree." );
178 }
179
180 Node upperLeft = upperChild.firstOutEdge().target();
181 Node upperRight = upperChild.firstOutEdge().nextOutEdge().target();
182 setNodePlacers( upperLeft, leftPlacer );
183 setNodePlacers( upperRight, rightPlacer );
184
185 Node lowerLeft = lowerChild.firstOutEdge().target();
186 Node lowerRight = lowerChild.firstOutEdge().nextOutEdge().target();
187 setNodePlacers( lowerLeft, leftPlacer );
188 setNodePlacers( lowerRight, rightPlacer );
189 }
190 };
191
192
195 public static final TreeLayoutConfiguration PLAYOFFS = new TreeLayoutConfiguration() {
196 protected void prepare() {
197 super.prepare();
198
199 Node root = Trees.getRoot( graph );
201
202 LayeredNodePlacer placerLeft = new LayeredNodePlacer( Matrix.ROT270, Matrix.ROT270 );
203 placerLeft.setRootAlignment( RootAlignment.MEDIAN );
204 placerLeft.setRoutingStyle( LayeredNodePlacer.ORTHOGONAL_STYLE );
205
206 LayeredNodePlacer placerRight = new LayeredNodePlacer( Matrix.ROT90, Matrix.ROT90 );
207 placerRight.setRootAlignment( RootAlignment.MEDIAN );
208 placerRight.setRoutingStyle( LayeredNodePlacer.ORTHOGONAL_STYLE );
209
210 DelegatingNodePlacer rootPlacer = new DelegatingNodePlacer( Matrix.DEFAULT, placerLeft, placerRight );
211 setNodePlacer( root, rootPlacer );
212
213 if ( root.outDegree() != 2 ) {
214 throw new IllegalStateException( "May only be used with a binary tree." );
215 }
216
217 Node firstChild = root.firstOutEdge().target();
219 Node secondChild = root.firstOutEdge().nextOutEdge().target();
220
221 setNodePlacers( firstChild, placerLeft );
222 setNodePlacers( secondChild, placerRight );
223 }
224 };
225
226
229 public static final TreeLayoutConfiguration BUS = new TreeLayoutConfiguration() {
230 protected void prepare() {
231 super.prepare();
232
233 Node root = Trees.getRoot( graph );
234 setNodePlacer( root, new BusPlacer() );
235
236 DoubleLinePlacer northDouble = new DoubleLinePlacer( Matrix.ROT180 );
237 DoubleLinePlacer southDouble = new DoubleLinePlacer();
238
239 SimpleNodePlacer north = new SimpleNodePlacer( Matrix.ROT180 );
240 north.setRootAlignment( RootAlignment.CENTER );
241 SimpleNodePlacer south = new SimpleNodePlacer();
242 south.setRootAlignment( RootAlignment.CENTER );
243
244 int upperCount = root.outDegree() / 2;
245
246 graph = ( LayoutGraph ) root.getGraph();
247 int counter = 0;
248 for ( Edge edge = root.firstOutEdge(); edge != null; edge = edge.nextOutEdge() ) {
249 Node child = edge.target();
250
251 if ( counter < upperCount ) {
252 setNodePlacer( child, north );
253 setNodePlacerForChildren( child, northDouble );
254 } else {
255 setNodePlacer( child, south );
256 setNodePlacerForChildren( child, southDouble );
257 }
258 counter++;
259 }
260 }
261 };
262
263
264 protected LayoutGraph graph;
265 protected GenericTreeLayouter layouter;
266
267 protected NodeMap nodePlacerMap;
268
269 protected TreeLayoutConfiguration() {
270 }
271
272 protected void setNodePlacer( Node node, NodePlacer nodePlacer ) {
273 nodePlacerMap.set( node, nodePlacer );
274 }
275
276 protected void setNodePlacers( Node root, NodePlacer nodePlacer ) {
277 setNodePlacer( root, nodePlacer );
278 setNodePlacerForChildren( root, nodePlacer );
279 }
280
281 protected void setNodePlacerForChildren( Node root, NodePlacer nodePlacer ) {
282 for ( Edge edge = root.firstOutEdge(); edge != null; edge = edge.nextOutEdge() ) {
283 Node child = edge.target();
284 setNodePlacers( child, nodePlacer );
285 }
286 }
287
288 public final void layout( GenericTreeLayouter layouter, LayoutGraph graph ) {
289 configure( layouter, graph );
290 try {
291 layouter.doLayout( this.graph );
292 } finally {
293 cleanUp( this.graph );
294 }
295
296 this.layouter = null;
297 this.graph = null;
298 }
299
300 protected void prepare() {
301 nodePlacerMap = graph.createNodeMap();
302
303 graph.addDataProvider( GenericTreeLayouter.NODE_PLACER_DPKEY, nodePlacerMap );
304 graph.addDataProvider( GenericTreeLayouter.CHILD_COMPARATOR_DPKEY, new ChildEdgeComparatorProvider() );
305 }
306
307
311 public void configure( GenericTreeLayouter layouter, LayoutGraph graph ) {
312 this.graph = graph;
313 this.layouter = layouter;
314 prepare();
315 }
316
317 public static void cleanUp( Graph graph ) {
318 DataProvider nodePlacerMap = graph.getDataProvider( GenericTreeLayouter.NODE_PLACER_DPKEY );
319 if ( nodePlacerMap != null && nodePlacerMap instanceof NodeMap ) {
320 graph.disposeNodeMap( ( NodeMap ) nodePlacerMap );
321 }
322 graph.removeDataProvider( GenericTreeLayouter.NODE_PLACER_DPKEY );
323 graph.removeDataProvider( GenericTreeLayouter.CHILD_COMPARATOR_DPKEY );
324 }
325
326 public boolean canLayout( LayoutGraph graph ) {
327 return true;
328 }
329
330 public void doLayout( LayoutGraph graph ) {
331 layout( new GenericTreeLayouter(), graph );
332 }
333
334 class ChildEdgeComparatorProvider extends DataProviderAdapter {
335 public Object get( Object dataHolder ) {
336 NodePlacer placer = ( NodePlacer ) nodePlacerMap.get( dataHolder );
337 if ( placer instanceof AbstractRotatableNodePlacer ) {
338 return ( ( AbstractRotatableNodePlacer ) placer ).createComparator();
339 }
340 if ( placer instanceof DefaultNodePlacer ) {
341 return ( ( DefaultNodePlacer ) placer ).createComparator();
342 }
343 return null;
344 }
345 }
346 }
347