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