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