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