try to fix some minor dropdown bugs
[potlatch2.git] / org / idmedia / as3commons / util / AbstractList.as
1 /*
2  * Copyright the original author or authors.
3  * 
4  * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the 'License');
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * 
8  *      http://www.mozilla.org/MPL/MPL-1.1.html
9  * 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an 'AS IS' BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.idmedia.as3commons.util {
17   import org.idmedia.as3commons.lang.UnsupportedOperationException;
18   import org.idmedia.as3commons.lang.IndexOutOfBoundsException;
19   
20   /**
21    * This class provides a skeletal implementation of the <tt>List</tt>
22    * interface to minimize the effort required to implement this interface
23    * backed by a "random access" data store (such as an array).  For sequential
24    * access data (such as a linked list), <tt>AbstractSequentialList</tt> should
25    * be used in preference to this class.<p>
26    *
27    * To implement an unmodifiable list, the programmer needs only to extend this
28    * class and provide implementations for the <tt>get(int index)</tt> and
29    * <tt>size()</tt> methods.<p>
30    *
31    * To implement a modifiable list, the programmer must additionally override
32    * the <tt>set(int index, Object element)</tt> method (which otherwise throws
33    * an <tt>UnsupportedOperationException</tt>.  If the list is variable-size
34    * the programmer must additionally override the <tt>add(int index, Object
35    * element)</tt> and <tt>remove(int index)</tt> methods.<p>
36    *
37    * Unlike the other abstract collection implementations, the programmer does
38    * <i>not</i> have to provide an iterator implementation; the iterator and
39    * list iterator are implemented by this class, on top the "random access"
40    * methods: <tt>get(index:int)</tt>, <tt>setAt(index:int, value:*)</tt>,
41    * <tt>set(int index, Object element)</tt>, <tt>add(int index, Object
42    * element)</tt> and <tt>remove(int index)</tt>.<p>
43    *
44    * The documentation for each non-abstract methods in this class describes its
45    * implementation in detail.  Each of these methods may be overridden if the
46    * collection being implemented admits a more efficient implementation.<p>
47    *
48    * @author  sleistner
49    * @see Collection
50    * @see List
51    * @see AbstractCollection
52    */
53   public class AbstractList extends AbstractCollection implements List {
54     
55     private var modCount:int = 0;
56     
57     /**
58      * Sole constructor.  (For invocation by subclass constructors, typically
59      * implicit.)
60      */
61     function AbstractList() {
62     }
63     
64     /**
65      * Appends the specified element to the end of this List (optional
66      * operation). <p>
67      *
68      * This implementation calls <tt>addAt(size(), value)</tt>.<p>
69      *
70      * Note that this implementation throws an
71      * <tt>UnsupportedOperationException</tt> unless <tt>add(int, Object)</tt>
72      * is overridden.
73      *
74      * @param value element to be appended to this list.
75      * 
76      * @return <tt>true</tt> (as per the general contract of
77      * <tt>Collection.add</tt>).
78      * 
79      * @throws UnsupportedOperationException if the <tt>add</tt> method is not
80      *            supported by this Set.
81      * 
82      * @throws IllegalArgumentException some aspect of this element prevents
83      *            it from being added to this collection.
84      */
85     override public function add(value:*):Boolean {
86       return addAt(size(), value);
87     }
88     
89     /**
90      * Returns the element at the specified position in this list.
91      *
92      * @param index index of element to return.
93      * 
94      * @return the element at the specified position in this list.
95      * @throws IndexOutOfBoundsException if the given index is out of range
96      *            (<tt>index &lt; 0 || index &gt;= size()</tt>).
97      */
98     public function get(index:int):* {
99       return null;      
100     }
101     
102     /**
103      * Inserts the specified element at the specified position in this list
104      * (optional operation).  Shifts the element currently at that position
105      * (if any) and any subsequent elements to the right (adds one to their
106      * indices).<p>
107      *
108      * This implementation always throws an UnsupportedOperationException.
109      *
110      * @param index index at which the specified element is to be inserted.
111      * @param value element to be inserted.
112      * 
113      * @throws UnsupportedOperationException if the <tt>add</tt> method is not
114      *            supported by this list.
115      * @throws IllegalArgumentException if some aspect of the specified
116      *            element prevents it from being added to this list.
117      * @throws IndexOutOfBoundsException index is out of range (<tt>index &lt;
118      *            0 || index &gt; size()</tt>).
119      */
120     public function addAt(index:int, value:*):Boolean {
121       throw new UnsupportedOperationException();
122     }
123     
124     /**
125      * Replaces the element at the specified position in this list with the
126      * specified element (optional operation). <p>
127      *
128      * This implementation always throws an
129      * <tt>UnsupportedOperationException</tt>.
130      *
131      * @param index index of element to replace.
132      * @param value element to be stored at the specified position.
133      * @return the element previously at the specified position.
134      * 
135      * @throws UnsupportedOperationException if the <tt>set</tt> method is not
136      *            supported by this List.
137      * @throws IllegalArgumentException if some aspect of the specified
138      *            element prevents it from being added to this list.
139      * 
140      * @throws IndexOutOfBoundsException if the specified index is out of
141      *            range (<tt>index &lt; 0 || index &gt;= size()</tt>).
142      */
143     public function setAt(index:int, value:*):Boolean {
144       throw new UnsupportedOperationException();
145     }
146     
147     /**
148      * Adds all of the elements in the specified collection to this collection
149      * (optional operation).  The behavior of this operation is undefined if
150      * the specified collection is modified while the operation is in
151      * progress.  (This implies that the behavior of this call is undefined if
152      * the specified collection is this collection, and this collection is
153      * nonempty.) <p>
154      *
155      * This implementation iterates over the specified collection, and adds
156      * each object returned by the iterator to this collection, in turn.<p>
157      *
158      * Note that this implementation will throw an
159      * <tt>UnsupportedOperationException</tt> unless <tt>add</tt> is
160      * overridden (assuming the specified collection is non-empty).
161      *
162      * @param c collection whose elements are to be added to this collection.
163      * @return <tt>true</tt> if this collection changed as a result of the
164      *         call.
165      * @throws UnsupportedOperationException if this collection does not
166      *         support the <tt>addAll</tt> method.
167      * @throws NullPointerException if the specified collection is null.
168      * 
169      * @see #add(Object)
170      */
171     override public function addAll(collection:Collection):Boolean {
172       throw new UnsupportedOperationException();
173     }
174     
175     /**
176      * Removes all of the elements from this collection (optional operation).
177      * The collection will be empty after this call returns (unless it throws
178      * an exception).<p>
179      *
180      * This implementation iterates over this collection, removing each
181      * element using the <tt>Iterator.remove</tt> operation.  Most
182      * implementations will probably choose to override this method for
183      * efficiency.<p>
184      *
185      * Note that this implementation will throw an
186      * <tt>UnsupportedOperationException</tt> if the iterator returned by this
187      * collection's <tt>iterator</tt> method does not implement the
188      * <tt>remove</tt> method and this collection is non-empty.
189      *
190      * @throws UnsupportedOperationException if the <tt>clear</tt> method is
191      *            not supported by this collection.
192      */
193     override public function clear():void {
194       removeRange(0, size());
195     }
196     
197     /**
198      * Returns an iterator over the elements in this list in proper
199      * sequence. <p>
200      *
201      * This implementation returns a straightforward implementation of the
202      * iterator interface, relying on the backing list's <tt>size()</tt>,
203      * <tt>get(int)</tt>, and <tt>remove(int)</tt> methods.<p>
204      *
205      * Note that the iterator returned by this method will throw an
206      * <tt>UnsupportedOperationException</tt> in response to its
207      * <tt>remove</tt> method unless the list's <tt>remove(int)</tt> method is
208      * overridden.<p>
209      *
210      * @return an iterator over the elements in this list in proper sequence.
211      */
212     override public function iterator():Iterator {
213       return new ListIteratorImpl(this);
214     }
215     
216     /**
217      * Returns an iterator of the elements in this list (in proper sequence).
218      * This implementation returns <tt>listIterator(0)</tt>.
219      * 
220      * @return an iterator of the elements in this list (in proper sequence).
221      * 
222      * @see #indexedListIterator(int)
223      */
224     public function listIterator():ListIterator {
225       return new ListIteratorImpl(this);
226     }
227     
228     /**
229      * Returns a list iterator of the elements in this list (in proper
230      * sequence), starting at the specified position in the list.  The
231      * specified index indicates the first element that would be returned by
232      * an initial call to the <tt>next</tt> method.  An initial call to
233      * the <tt>previous</tt> method would return the element with the
234      * specified index minus one.<p>
235      *
236      * This implementation returns a straightforward implementation of the
237      * <tt>ListIterator</tt> interface that extends the implementation of the
238      * <tt>Iterator</tt> interface returned by the <tt>iterator()</tt> method.
239      * The <tt>ListIterator</tt> implementation relies on the backing list's
240      * <tt>getAt(int)</tt>, <tt>setAt(int, *)</tt>, <tt>addAt(int, *)</tt>
241      * and <tt>remove(int)</tt> methods.<p>
242      *
243      * Note that the list iterator returned by this implementation will throw
244      * an <tt>UnsupportedOperationException</tt> in response to its
245      * <tt>remove</tt>, <tt>set</tt> and <tt>add</tt> methods unless the
246      * list's <tt>removeAt(int)</tt>, <tt>setAt(int, *)</tt>, and
247      * <tt>addAt(int, *)</tt> methods are overridden.<p>
248      *
249      * This implementation can be made to throw runtime exceptions in the
250      * face of concurrent modification, as described in the specification for
251      * the (protected) <tt>modCount</tt> field.
252      *
253      * @param index index of the first element to be returned from the list
254      *              iterator (by a call to the <tt>next</tt> method).
255      * 
256      * @return a list iterator of the elements in this list (in proper
257      *         sequence), starting at the specified position in the list.
258      * 
259      * @throws IndexOutOfBoundsException if the specified index is out of
260      *            range (<tt>index &lt; 0 || index &gt; size()</tt>).
261      * 
262      */
263     public function indexedListIterator(index:uint):ListIterator {
264       if(index < 0 || index > size()) {
265         throw new IndexOutOfBoundsException('Index: ' + index);
266       }
267       var iter:ListIterator = listIterator();
268       iter.setIndex(index);
269       return iter;
270     }
271     
272     /**
273      * Removes the element at the specified position in this list (optional
274      * operation).  Shifts any subsequent elements to the left (subtracts one
275      * from their indices).  Returns the element that was removed from the
276      * list.<p>
277      *
278      * This implementation always throws an
279      * <tt>UnsupportedOperationException</tt>.
280      *
281      * @param index the index of the element to remove.
282      * @return the element previously at the specified position.
283      * 
284      * @throws UnsupportedOperationException if the <tt>remove</tt> method is
285      *            not supported by this list.
286      * @throws IndexOutOfBoundsException if the specified index is out of
287      *            range (<tt>index &lt; 0 || index &gt;= size()</tt>).
288      */
289     public function removeAt(index:int):Boolean {
290       throw new UnsupportedOperationException();
291     }
292     
293     public function removeAtAndReturn(index:int):* {
294       throw new UnsupportedOperationException();
295     }
296     
297     public function removeAtTo(index:int, toPos:int):Boolean {
298       throw new UnsupportedOperationException();
299     }
300     
301     private function removeRange(fromIndex:int, toIndex:int):void {
302       var listIter:ListIterator = indexedListIterator(fromIndex);
303       for(var i:int = 0, n:int = toIndex - fromIndex;i < n; i++) {
304         listIter.next();
305         listIter.remove();
306       }
307     }
308     
309     /**
310      * Returns the index in this list of the first occurence of the specified
311      * element, or -1 if the list does not contain this element.  More
312      * formally, returns the lowest index <tt>i</tt> such that <tt>(o==null ?
313      * get(i)==null : o.equals(get(i)))</tt>, or -1 if there is no such
314      * index.<p>
315      *
316      * This implementation first gets a list iterator (with
317      * <tt>listIterator()</tt>).  Then, it iterates over the list until the
318      * specified element is found or the end of the list is reached.
319      *
320      * @param value element to search for.
321      * 
322      * @return the index in this List of the first occurence of the specified
323      *         element, or -1 if the List does not contain this element.
324      */
325     public function indexOf(elem:* = null):int {
326       return toArray().indexOf(elem);
327     }
328   }
329 }
330
331 import org.idmedia.as3commons.util.List;
332 import org.idmedia.as3commons.util.ListIterator;
333 import org.idmedia.as3commons.util.Iterator;
334 import org.idmedia.as3commons.lang.IndexOutOfBoundsException;
335 import org.idmedia.as3commons.lang.IllegalStateException;
336 import org.idmedia.as3commons.lang.NoSuchElementException;
337 import org.idmedia.as3commons.lang.ConcurrentModificationException;
338
339 internal class IteratorImpl implements Iterator {
340   
341   protected var cursor:int = 0;
342   protected var lastRet:int = -1;
343   protected var list:List;
344   
345   function IteratorImpl(list:List) {
346     this.list = list;
347   }
348   
349   public function hasNext():Boolean {
350     return cursor < list.size();
351   }
352   
353   public function next():* {
354     try {
355       var nextValue:* = list.get(cursor);
356       lastRet = cursor;
357       cursor++;
358       return nextValue;
359     } catch(e:IndexOutOfBoundsException) {
360       throw new NoSuchElementException();
361     }
362   }
363   
364   public function remove():void {
365     if (lastRet == -1) {
366       throw new IllegalStateException();
367     }
368                                                 
369     try {
370       list.removeAt(lastRet);
371       if (lastRet < cursor) {
372         cursor--;
373       }
374       lastRet = -1;
375     } catch(e:IndexOutOfBoundsException) {
376       throw new ConcurrentModificationException(e.getMessage());
377     }
378   }
379 }       
380
381 internal class ListIteratorImpl extends IteratorImpl implements ListIterator {
382   
383   function ListIteratorImpl(list:List) {
384     super(list);
385   }
386   
387   public function hasPrevious():Boolean {
388     return cursor != 0;
389   }
390   
391   public function previous():* {
392     try {
393       var i:int = cursor - 1;
394       var previousValue:* = list.get(i);
395       lastRet = cursor = i;
396       return previousValue;
397     } catch(e:IndexOutOfBoundsException) {
398       throw new NoSuchElementException();
399     }
400   }
401   
402   public function nextIndex():int {
403     return cursor;
404   }
405   
406   public function previousIndex():int {
407     return cursor - 1;
408   }
409   
410   public function setValue(object:*):void {
411     if(lastRet == -1) {
412       throw new IllegalStateException();
413     }
414                 
415     try {
416       list.setAt(lastRet, object);
417     } catch(e:IndexOutOfBoundsException) {
418       throw new ConcurrentModificationException();
419     }
420   }
421   
422   public function add(object:*):void {
423     try {
424       list.addAt(cursor++, object);
425       lastRet = -1;
426     } catch(e:IndexOutOfBoundsException) {
427       throw new ConcurrentModificationException();
428     }
429   }
430   
431   public function setIndex(index:int):void {
432     if(index < 0 || index >= list.size()) {
433       throw new IndexOutOfBoundsException('Index: ' + index);
434     }
435     cursor = index;
436   }
437 }