Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: javax/ide/menu/spi/PositionMap.java


1   package javax.ide.menu.spi;
2   
3   import java.util.ArrayList;
4   import java.util.HashMap;
5   import java.util.Iterator;
6   import java.util.LinkedHashMap;
7   import java.util.List;
8   import java.util.ListIterator;
9   import java.util.Map;
10  
11  
12  
13  /**
14   * A map that tracks Positionable items. Provides utilities for getting the
15   * items in their "resolved" order.
16   */
17  final class PositionMap 
18  {
19    // Ordering of items is essentially a graph problem. We build a graph of items
20    // where the (directed) edges are their required positions in relation to each
21    // other. The correct order of the items is a topological sort of this graph.
22    
23    private Map _idsToVertices = new LinkedHashMap();
24    private Vertex _currentAncestor;
25    
26    private List _sortedList;
27    
28    /**
29     * Adds a positionable to the map.
30     * 
31     * @param p the positionable to add.
32     */
33    public void add( Positionable p )
34    {
35      // Invalidate the sorted list if required.
36      _sortedList = null;
37      
38      Vertex thisVertex = (Vertex) _idsToVertices.get( p.getID() );
39      if ( thisVertex == null )
40      {
41        thisVertex = new Vertex( p );
42        _idsToVertices.put( p.getID(), thisVertex );
43      }
44    }
45    
46    private void addToGraph( Vertex thisVertex )
47    {
48      Positionable p = thisVertex.getPositionable();
49      
50      String before = p.getBefore();
51      String after = p.getAfter();
52      
53      if ( after == null && before == null && _currentAncestor != null )
54      {
55        after = _currentAncestor.getName();
56      }
57      
58      if ( after != null )
59      {
60        Vertex afterVertex = (Vertex) _idsToVertices.get( after );
61        if ( afterVertex == null )
62        {
63          afterVertex = new Vertex( after );    
64          _idsToVertices.put( after, afterVertex );
65        }
66              
67        // Anything after the afterVertex must also be after this vertex.
68        thisVertex.attachAfter( afterVertex.getToEdges() );
69  
70        afterVertex.attachAfter( thisVertex );
71  
72        if ( thisVertex.isUndefinedReference() )
73        {
74          // Anything before thisVertex (except afterVertex itself) 
75          // must also be after afterVertex.
76          for ( Iterator i = thisVertex.getFromEdges(); i.hasNext();  )
77          {
78            Vertex v = (Vertex) i.next();
79            if ( afterVertex != v )
80            {
81              afterVertex.attachAfter( v );
82            }
83          }
84          thisVertex.setPositionable( p );
85        }
86  
87      }
88      
89      if ( before != null )
90      {
91        Vertex beforeVertex = (Vertex) _idsToVertices.get( before );
92        if ( beforeVertex == null )
93        {
94          beforeVertex = new Vertex( before );
95          _idsToVertices.put( before, beforeVertex );
96        }
97        
98        // Anything before the beforeVertex must be before this vertex.
99        thisVertex.attachBefore( beforeVertex.getFromEdges() );
100       
101       beforeVertex.attachBefore( thisVertex );
102 
103       if ( thisVertex.isUndefinedReference() )
104       {
105         // Anything after thisVertex (except beforeVertex itself) 
106         // must also be before beforeVertex.
107         for ( Iterator i = thisVertex.getToEdges(); i.hasNext();  )
108         {
109           Vertex v = (Vertex) i.next();
110           if ( beforeVertex != v )
111           {
112             beforeVertex.attachBefore( v );
113           }
114         }      
115         thisVertex.setPositionable( p );
116       }
117     }
118     _currentAncestor = thisVertex;
119   }
120   
121   /**
122    * Gets items in the correct, sorted order.
123    * 
124    * @return the items in the correct, sorted order.
125    */
126   public List getSortedItems()
127   {
128     if ( _sortedList == null )
129     {
130       _sortedList = sort();
131     }
132     return _sortedList;
133   }
134   
135   /**
136    * Get a positionable by its id.
137    * 
138    * @param id the id of a positionable
139    * @return the Positionable with the specified id, or null if no such 
140    *    Positionable has been added.
141    */
142   public Positionable get( String id )
143   {
144     Vertex vertex = (Vertex) _idsToVertices.get( id );
145     if ( vertex == null || vertex.isUndefinedReference() )
146     {
147       return null;
148     }
149     return vertex.getPositionable();
150   }
151   
152   /**
153    * Build a sorted list of all items.
154    * 
155    * @return a sorted list of all items.
156    */
157   private List sort()
158   {
159     // Build the graph.
160     for ( Iterator i = _idsToVertices.values().iterator(); i.hasNext(); )
161     {
162       Vertex vertex = (Vertex) i.next();
163       addToGraph( vertex );
164     }
165   
166     Map colorings = new HashMap();
167     List topo = new ArrayList();
168     
169     // Now visit remaining items.
170     for ( Iterator i = _idsToVertices.values().iterator(); i.hasNext(); )
171     {
172       Vertex vertex = (Vertex) i.next();
173       Object color = colorings.get( vertex );
174       if ( color == null )
175       {
176         visit( colorings, vertex, topo );
177       }
178     }
179 
180     
181     // Reverse the list, removing any unresolved items.
182     ArrayList sorted = new ArrayList( topo.size() );
183     for ( ListIterator li = topo.listIterator( topo.size() ); li.hasPrevious(); )
184     {
185       Vertex v = (Vertex) li.previous();
186       if ( !v.isUndefinedReference() )
187       {
188         sorted.add( v.getPositionable() );
189       }
190     }
191     return sorted;
192   }
193   
194   private void visit( Map colorings, Vertex vertex, List topo )
195   {
196     colorings.put( vertex, COLOR_VISITING );
197     
198     for ( Iterator children = vertex.getToEdges(); children.hasNext(); )
199     {
200       Vertex child = (Vertex) children.next();
201       Object color = colorings.get( child );
202       if ( color == COLOR_VISITING )
203       {
204         // Cycle detected. Skip this child.
205         continue;
206       }
207       else if ( color != COLOR_VISITED )
208       {
209         visit( colorings, child, topo );
210       }
211     }
212     
213     // Have visited all children, now add to the topo list.
214     topo.add( vertex );
215     colorings.put( vertex, COLOR_VISITED ); 
216   }
217   
218   
219   private final static Object COLOR_VISITING = "visiting";
220   private final static Object COLOR_VISITED = "visited";
221   
222   
223   
224   /**
225    * A vertex in the graph. Each vertex represents a Positionable and its back
226    * and forward references to other vertices. An undefined reference is a 
227    * vertex for which the positionable has not yet been encountered (such cases
228    * occur when an item defines itself to be before or after another item which
229    * has not yet been defined)
230    */
231   private class Vertex
232   {
233     private List _toEdges = new ArrayList();
234     private List _fromEdges = new ArrayList();
235     private final String _name;
236     private Positionable _positionable;
237   
238     public Vertex( String name )
239     {
240       _name = name;
241     }
242     
243     public Vertex( Positionable positionable )
244     {
245       _name = positionable.getID();
246       _positionable = positionable;
247     }
248     
249     
250     public void setPositionable( Positionable p )
251     {
252       _positionable = p;
253     }
254     
255     public Positionable getPositionable()
256     {
257       return _positionable;
258     }
259     
260     public boolean isUndefinedReference()
261     {
262       return _positionable == null;
263     }
264     
265     public String getName()
266     {
267       return _name;
268     }
269     
270     public Iterator getFromEdges()
271     {
272       return _fromEdges.iterator();
273     }
274     
275     public Iterator getToEdges()
276     {
277       return _toEdges.iterator();
278     }
279     
280     public void attachBefore( Vertex otherVertex )
281     {
282       if ( otherVertex == this )
283       {
284         throw new IllegalArgumentException( "Cannot connect a vertex to itself" );
285       }
286       _fromEdges.add( otherVertex );
287       otherVertex._toEdges.add( this );
288     }
289     
290     public void attachAfter( Vertex otherVertex )
291     {
292       if ( otherVertex == this )
293       {
294         throw new IllegalArgumentException( "Cannot connect a vertex to itself" );
295       }
296       _toEdges.add( otherVertex );
297       otherVertex._fromEdges.add( this );
298     }
299     
300     public void attachAfter( Iterator vertices )
301     {
302       while ( vertices.hasNext() )
303       {
304         Vertex v = (Vertex) vertices.next();
305         attachAfter( v );
306       }
307     }
308 
309     public void attachBefore( Iterator vertices )
310     {
311       while ( vertices.hasNext() )
312       {
313         Vertex v = (Vertex) vertices.next();
314         attachBefore( v );
315       }
316     }
317   }  
318 }