merge the formfield patch from ooo-build
[ooovba.git] / javaunohelper / com / sun / star / lib / uno / helper / InterfaceContainer.java
blob2c23ebc0d41ec21dd039a2b0ab25de50c5ea5da9
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: InterfaceContainer.java,v $
10 * $Revision: 1.4 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 package com.sun.star.lib.uno.helper;
32 import java.util.Iterator;
33 import java.util.ListIterator;
34 import java.util.NoSuchElementException;
35 import java.util.Collection;
36 import com.sun.star.lang.EventObject;
37 import com.sun.star.lang.XEventListener;
38 import com.sun.star.uno.UnoRuntime;
40 /**
41 * This class is a container for interfaces.
43 * It is intended to be used as storage for UNO interface of a specific type.
44 * The client has to ensure that the container contains only elements of the same
45 * type. If one needs to store different types, then one uses OMultiTypeInterfaceContainer.
46 * When the client calls disposeAndClear, the contained objects are queried for
47 * com.sun.star.lang.XEventListener and disposing is called. Afterwards
48 * the list cannot be used anymore.
50 * This list does not allow null values.
51 * All methods are thread-safe. The same holds true for
52 * iterators, issued by this class. Several iterators can exist at the same time and can also
53 * be modified (java.util.ListIterator.add, java.util.ListIterator.remove etc.). To make this work,
54 * the InterfaceContainer provides the iterators with copys of the list's data.
55 * The add and remove calls on the iterator modify the data in the iterator's list as well as
56 * in InterfaceContainer. Modification on InterfaceContainer, however, are not
57 * synchronized with existing iterators. For example
58 * <pre>
59 * InterfaceContainer cont= new InterfaceContainer();
60 * ListIterator it= cont.listIterator();
62 * cont.add( someInterface);
63 * // one cannot obtain someInterface through iterator it,
64 * // instead get a new iterator
65 * it= cont.listIterator();
66 * // it now keeps a fresh copy of cont and hence contains someInterface
68 * // Adding an interface on the iterator will cause the interface also to be added
69 * // to InterfaceContainer
70 * it.add( someOtherInterface);
71 * // someOtherInterface is now in it and cont
72 * ListIterator it2= cont.listIterator();
73 * //someOtherInterface can also be obtained by all newly created iterators, e.g. it2.
74 * </pre>
76 * The add and remove methods of an iterator work on a particular location within a list,
77 * dependent on what the value of the iterator's cursor is. After the call the value at the
78 * appropriate position has been modified. Since the iterator received a copy of InterfaceContainer's
79 * data, InterfaceContainer may have been modified (by List methods or through other iterators).
80 * Therefore both data sets may not contain the same elements anymore. Consequently, a List method
81 * that modifies data, does not modify InterfaceContainer's data at a certain index
82 * (according to the iterators cursor). Instead, new elements are added at the end of list. When
83 * Iterator.remove is called, then the first occurrence of that element in InterfaceContainer
84 * is removed.
85 * ListIterator.set is not supported.
87 * A lot of methods resemble those of the to java.util.List interface, allthough
88 * this class does not implement it. However, the list iterators returned, for example by
89 * the listIterator method implement the java.util.ListIterator interface.
90 * Implementing the List interface would mean to support all none - optional methods as
91 * prescribed by the interface declaration. Among those is the subList method which returns
92 * a range of values of the list's data wrapped in a List implementation. Changes to the sub
93 * list have to cause changes in the main list. This is a problem, since this class is to be
94 * used in a multi-threaded environment. The sub list could work on a copy as the iterators
95 * do, but all the functions which work on an given index could not be properly supported.
96 * Unfortunatly, the List interface documentation states that all optional methods implemented
97 * by the list have to be implemented in the sub list. That would mean to do without all those
98 * critical methods, allthough they might work well in the "main list" (as opposed to sub list).
100 public class InterfaceContainer implements Cloneable
102 final boolean DEBUG= false;
104 * The array buffer into which the elements of the ArrayList are stored.
105 * The capacity of the ArrayList is the length of this array buffer.
107 Object elementData[];
110 * The size of the ArrayList (the number of elements it contains).
112 * @serial
114 private int size;
117 //private ArrayList data= new ArrayList();
118 /** Creates a new instance of InterfaceContainer */
119 public InterfaceContainer()
121 this(10);
124 * Constructs an empty list with the specified initial capacity.
126 * @param initialCapacity the initial capacity of the list.
127 * @exception IllegalArgumentException if the specified initial capacity
128 * is negative
130 public InterfaceContainer(int initialCapacity)
132 if (initialCapacity < 0)
133 throw new java.lang.IllegalArgumentException("Illegal Capacity: "+
134 initialCapacity);
135 this.elementData = new Object[initialCapacity];
139 * Trims the capacity of this <tt>ArrayList</tt> instance to be the
140 * list's current size. An application can use this operation to minimize
141 * the storage of an <tt>ArrayList</tt> instance.
143 synchronized public void trimToSize()
145 int oldCapacity = elementData.length;
146 if (size < oldCapacity)
148 Object oldData[] = elementData;
149 elementData = new Object[size];
150 System.arraycopy(oldData, 0, elementData, 0, size);
155 * Increases the capacity of this <tt>ArrayList</tt> instance, if
156 * necessary, to ensure that it can hold at least the number of elements
157 * specified by the minimum capacity argument.
159 * @param minCapacity the desired minimum capacity.
161 synchronized public void ensureCapacity(int minCapacity)
163 int oldCapacity = elementData.length;
164 if (minCapacity > oldCapacity)
166 Object oldData[] = elementData;
167 int newCapacity = (oldCapacity * 3)/2 + 1;
168 if (newCapacity < minCapacity)
169 newCapacity = minCapacity;
170 elementData = new Object[newCapacity];
171 System.arraycopy(oldData, 0, elementData, 0, size);
176 * Appends the specified element to the end of this list.
178 * @param o element to be appended to this list.
179 * @return <tt>true</tt> (as per the general contract of Collection.add).
181 synchronized public boolean add(Object o)
183 boolean ret= false;
184 if (elementData != null && o != null)
186 ensureCapacity(size + 1); // Increments modCount!!
187 elementData[size++] = o;
188 ret= true;
190 return ret;
194 * Inserts the specified element at the specified position in this
195 * list. Shifts the element currently at that position (if any) and
196 * any subsequent elements to the right (adds one to their indices).
198 * @param index index at which the specified element is to be inserted.
199 * @param element element to be inserted.
200 * @throws IndexOutOfBoundsException if index is out of range
201 * <tt>(index &lt; 0 || index &gt; size())</tt>.
203 synchronized public void add(int index, Object element)
205 if (elementData != null && element != null)
207 if (index > size || index < 0)
208 throw new IndexOutOfBoundsException(
209 "Index: "+index+", Size: "+size);
211 ensureCapacity(size+1);
212 System.arraycopy(elementData, index, elementData, index + 1,
213 size - index);
214 elementData[index] = element;
215 size++;
221 * Appends all of the elements in the specified Collection to the end of
222 * this list, in the order that they are returned by the
223 * specified Collection's Iterator. The behavior of this operation is
224 * undefined if the specified Collection is modified while the operation
225 * is in progress. (This implies that the behavior of this call is
226 * undefined if the specified Collection is this list, and this
227 * list is nonempty.)
229 * @param c the elements to be inserted into this list.
230 * @throws IndexOutOfBoundsException if index out of range <tt>(index
231 * &lt; 0 || index &gt; size())</tt>.
233 synchronized public boolean addAll(Collection c)
235 int numNew = c.size();
236 ensureCapacity(size + numNew);
238 Iterator e = c.iterator();
239 for (int i=0; i<numNew; i++)
241 Object o= e.next();
242 if (o != null)
243 elementData[size++] = o;
245 return numNew != 0;
248 * Inserts all of the elements in the specified Collection into this
249 * list, starting at the specified position. Shifts the element
250 * currently at that position (if any) and any subsequent elements to
251 * the right (increases their indices). The new elements will appear
252 * in the list in the order that they are returned by the
253 * specified Collection's iterator.
255 * @param index index at which to insert first element
256 * from the specified collection.
257 * @param c elements to be inserted into this list.
258 * @throws IndexOutOfBoundsException if index out of range <tt>(index
259 * &lt; 0 || index &gt; size())</tt>.
261 synchronized public boolean addAll(int index, Collection c)
263 boolean ret= false;
264 if (elementData != null)
266 if (index > size || index < 0)
267 throw new IndexOutOfBoundsException(
268 "Index: "+index+", Size: "+size);
269 // only add the non-null elements
270 int sizeCol= c.size();
271 Object[] arColl= new Object[sizeCol];
272 Iterator icol= c.iterator();
273 int curIndex= 0;
274 for (int i=0; i < sizeCol; i++)
276 Object o= icol.next();
277 if (o != null)
278 arColl[curIndex++]= o;
280 int numNew = curIndex;
281 ensureCapacity(size + numNew); // Increments modCount!!
283 int numMoved = size - index;
284 if (numMoved > 0)
285 System.arraycopy(elementData, index, elementData, index + numNew,
286 numMoved);
288 for (int i=0; i<numNew; i++)
290 elementData[index++]= arColl[i];
292 size += numNew;
293 ret= numNew != 0;
295 return ret;
299 * Removes all of the elements from this list. The list will
300 * be empty after this call returns.
302 synchronized public void clear()
304 if (elementData != null)
306 // Let gc do its work
307 for (int i = 0; i < size; i++)
308 elementData[i] = null;
310 size = 0;
314 * Returns <tt>true</tt> if this list contains the specified element.
316 * @param elem element whose presence in this List is to be tested.
318 synchronized public boolean contains(Object elem)
320 return indexOf(elem) >= 0;
323 synchronized public boolean containsAll(Collection collection)
325 boolean retVal= true;
326 if (elementData != null && collection != null)
328 Iterator it= collection.iterator();
329 while (it.hasNext())
331 Object obj= it.next();
332 if (false == contains(obj))
334 retVal= false;
335 break;
339 return retVal;
342 * Returns the element at the specified position in this list.
344 * @param index index of element to return.
345 * @return the element at the specified position in this list.
346 * @throws IndexOutOfBoundsException if index is out of range <tt>(index
347 * &lt; 0 || index &gt;= size())</tt>.
349 synchronized public Object get(int index)
351 if (elementData != null)
353 RangeCheck(index);
354 return elementData[index];
356 return null;
360 * Searches for the first occurence of the given argument, testing
361 * for equality using the <tt>equals</tt> method.
363 * @param elem an object.
364 * @return the index of the first occurrence of the argument in this
365 * list; returns <tt>-1</tt> if the object is not found.
366 * @see Object#equals(Object)
368 synchronized public int indexOf(Object elem)
370 int index= -1;
371 if (elementData != null && elem != null)
373 for (int i = 0; i < size; i++)
375 if (elem == elementData[i])
377 index= i;
378 break;
382 if (index == -1)
384 for (int i = 0; i < size; i++)
386 if (UnoRuntime.areSame(elem, elementData[i]))
388 index= i;
389 break;
394 return index;
397 * Tests if this list has no elements.
399 * @return <tt>true</tt> if this list has no elements;
400 * <tt>false</tt> otherwise.
402 synchronized public boolean isEmpty()
404 return size == 0;
407 synchronized public Iterator iterator()
409 if (elementData != null)
411 InterfaceContainer aCopy= (InterfaceContainer) clone();
412 return new Itr(aCopy);
414 return null;
417 * Returns the index of the last occurrence of the specified object in
418 * this list.
420 * @param elem the desired element.
421 * @return the index of the last occurrence of the specified object in
422 * this list; returns -1 if the object is not found.
424 synchronized public int lastIndexOf(Object elem)
426 int index= -1;
427 if (elementData != null && elem != null)
429 for (int i = size-1; i >= 0; i--)
431 if (elem == elementData[i])
433 index= i;
434 break;
437 if (index == -1)
439 for (int i = size-1; i >= 0; i--)
441 if (UnoRuntime.areSame(elem, elementData[i]))
443 index= i;
444 break;
449 return index;
453 * Returns a shallow copy of this <tt>ArrayList</tt> instance. The contained
454 * references are copied but the objects not.
456 * @return a clone of this <tt>List</tt> instance.
458 synchronized public Object clone()
460 Object ret= null;
461 if (elementData != null)
463 InterfaceContainer cont= new InterfaceContainer();
464 cont.elementData = new Object[size];
465 cont.size= size;
466 System.arraycopy(elementData, 0, cont.elementData, 0, size);
467 ret= cont;
469 return ret;
471 synchronized public ListIterator listIterator()
473 return listIterator(0);
476 /** The iterator keeps a copy of the list. Changes to InterfaceContainer do not
477 * affect the data of the iterator. Conversly, changes to the iterator are effect
478 * InterfaceContainer.
480 synchronized public ListIterator listIterator(int index)
482 if (elementData != null)
484 InterfaceContainer aCopy= (InterfaceContainer) clone();
485 return new LstItr(aCopy, index);
487 return null;
490 * Removes the element at the specified position in this list.
491 * Shifts any subsequent elements to the left (subtracts one from their
492 * indices).
494 * @param index the index of the element to removed.
495 * @return the element that was removed from the list.
496 * @throws IndexOutOfBoundsException if index out of range <tt>(index
497 * &lt; 0 || index &gt;= size())</tt>.
499 synchronized public Object remove(int index)
501 Object ret= null;
502 if (elementData != null)
504 RangeCheck(index);
505 ret= elementData[index];
507 int numMoved = size - index - 1;
508 if (numMoved > 0)
509 System.arraycopy(elementData, index+1, elementData, index,
510 numMoved);
511 elementData[--size] = null; // Let gc do its work
513 return ret;
517 /** Parameter obj may */
518 synchronized public boolean remove(Object obj)
520 boolean ret= false;
521 if (elementData != null && obj != null)
523 int index= indexOf(obj);
524 if (index != -1)
526 ret= true;
527 remove(index);
530 return ret;
533 synchronized public boolean removeAll(Collection collection)
535 boolean retVal= false;
536 if (elementData != null && collection != null)
538 Iterator it= collection.iterator();
539 while (it.hasNext())
541 Object obj= it.next();
542 boolean bMod= remove( obj);
543 if (bMod)
544 retVal= true;
547 return retVal;
550 synchronized public boolean retainAll(Collection collection)
552 boolean retVal= false;
553 if (elementData != null && collection != null)
555 // iterate over data
556 Object[] arRetained= new Object[size];
557 int indexRetained= 0;
558 for(int i= 0; i < size; i++)
560 Object curElem= elementData[i];
561 // try to find the element in collection
562 Iterator itColl= collection.iterator();
563 boolean bExists= false;
564 while (itColl.hasNext())
566 if (curElem == itColl.next())
568 // current element is in collection
569 bExists= true;
570 break;
573 if (bExists == false)
575 itColl= collection.iterator();
576 while (itColl.hasNext())
578 Object o= itColl.next();
579 if (o != null)
581 if (UnoRuntime.areSame(o, curElem))
583 bExists= true;
584 break;
589 if (bExists == true)
590 arRetained[indexRetained++]= curElem;
592 retVal= size != indexRetained;
593 if (indexRetained > 0)
595 elementData= arRetained;
596 size= indexRetained;
599 return retVal;
603 /** Not supported.
604 * @param index index of element to replace.
605 * @param element element to be stored at the specified position.
606 * @return the element previously at the specified position.
607 * @throws IndexOutOfBoundsException if index out of range
608 * <tt>(index &lt; 0 || index &gt;= size())</tt>.
610 synchronized public Object set(int index, Object element)
612 Object ret= null;
613 if (elementData != null && element != null)
615 RangeCheck(index);
616 ret = elementData[index];
617 elementData[index] = element;
619 return ret;
623 * Returns the number of elements in this list.
625 * @return the number of elements in this list.
627 synchronized public int size()
629 if (elementData != null)
630 return size;
631 return 0;
636 * Returns an array containing all of the elements in this list
637 * in the correct order.
639 * @return an array containing all of the elements in this list
640 * in the correct order.
642 synchronized public Object[] toArray()
644 if (elementData != null)
646 Object[] result = new Object[size];
647 System.arraycopy(elementData, 0, result, 0, size);
648 return result;
650 return null;
654 * Returns an array containing all of the elements in this list in the
655 * correct order. The runtime type of the returned array is that of the
656 * specified array. If the list fits in the specified array, it is
657 * returned therein. Otherwise, a new array is allocated with the runtime
658 * type of the specified array and the size of this list.<p>
660 * If the list fits in the specified array with room to spare (i.e., the
661 * array has more elements than the list), the element in the array
662 * immediately following the end of the collection is set to
663 * <tt>null</tt>. This is useful in determining the length of the list
664 * <i>only</i> if the caller knows that the list does not contain any
665 * <tt>null</tt> elements.
667 * @param a the array into which the elements of the list are to
668 * be stored, if it is big enough; otherwise, a new array of the
669 * same runtime type is allocated for this purpose.
670 * @return an array containing the elements of the list.
671 * @throws ArrayStoreException if the runtime type of a is not a supertype
672 * of the runtime type of every element in this list.
674 synchronized public Object[] toArray(Object a[])
676 if (a.length < size)
677 a = (Object[])java.lang.reflect.Array.newInstance(
678 a.getClass().getComponentType(), size);
679 if (elementData != null)
680 System.arraycopy(elementData, 0, a, 0, size);
682 if (a.length > size)
683 a[size] = null;
685 return a;
689 * Check if the given index is in range. If not, throw an appropriate
690 * runtime exception.
692 private void RangeCheck(int index)
694 if (index >= size || index < 0)
695 throw new IndexOutOfBoundsException(
696 "Index: "+index+", Size: "+size);
699 public void disposeAndClear(EventObject evt)
701 Iterator aIt;
702 synchronized (this)
704 aIt= iterator();
705 // Container freigeben, falls im disposing neue Eintraege kommen
706 // set the member to null, the iterator delete the values
707 clear();
708 elementData= null;
709 size= 0;
711 if (aIt != null)
713 while( aIt.hasNext() )
717 Object o= aIt.next();
718 XEventListener evtListener= UnoRuntime.queryInterface(
719 XEventListener.class, o);
720 if( evtListener != null )
721 evtListener.disposing( evt );
723 catch ( RuntimeException e)
725 // be robust, if e.g. a remote bridge has disposed already.
726 // there is no way, to delegate the error to the caller :o(.
733 private class Itr implements Iterator
735 InterfaceContainer dataIt;
737 * Index of element to be returned by subsequent call to next.
739 int cursor= 0;
741 * Index of element returned by most recent call to next or
742 * previous. Reset to -1 if this element is deleted by a call
743 * to remove.
745 int lastRet = -1;
747 /** The object that has been returned by most recent call to next
748 * or previous. Reset to null if this element is deleted by a call
749 * to remove.
751 Object lastRetObj= null;
753 Itr(InterfaceContainer _data)
755 dataIt= _data;
758 synchronized public boolean hasNext()
760 return cursor !=dataIt.size();
763 public synchronized Object next()
767 Object next = dataIt.get(cursor);
768 lastRet = cursor++;
769 lastRetObj= next;
770 return next;
772 catch(java.lang.IndexOutOfBoundsException e)
774 throw new java.util.NoSuchElementException();
778 /** Removes the interface from the list, that has been last returned by a
779 * call to next(). This is done according to the specification of the interface
780 * method. The element is also removed from InterfaceContainer but independent
781 * of the location. If the element is multiple times in InterfaceContainer then
782 * it is up to the java.util.ArrayList implementation what element is removed.
784 public synchronized void remove()
786 if (lastRet == -1)
787 throw new IllegalStateException();
788 // Remove the entry from InterfaceContainer.
789 InterfaceContainer.this.remove(lastRetObj);
790 dataIt.remove(lastRet);
792 if (lastRet < cursor)
793 cursor--;
794 lastRet = -1;
795 lastRetObj= null;
799 private class LstItr extends Itr implements ListIterator
802 LstItr(InterfaceContainer _data, int _index)
804 super(_data);
805 cursor= _index;
808 /** Inserts an element to the iterators list according to the specification
809 * of this interface method. The element is also added to InterfaceContainer
810 * but its location within the list cannot be guaranteed.
812 public synchronized void add(Object o)
814 InterfaceContainer.this.add(o);
815 dataIt.add(cursor++, o);
816 lastRet = -1;
817 lastRetObj= null;
820 synchronized public boolean hasPrevious()
822 return cursor != 0;
825 synchronized public int nextIndex()
827 return cursor;
830 public synchronized Object previous()
834 Object previous = dataIt.get(--cursor);
835 lastRet = cursor;
836 lastRetObj= previous;
837 return previous;
838 } catch(IndexOutOfBoundsException e)
840 throw new NoSuchElementException();
844 synchronized public int previousIndex()
846 return cursor-1;
849 /** This is not possible since several iterators can modify InterfaceContainer
851 public synchronized void set(Object o)
853 throw new UnsupportedOperationException();
857 } // class LstItr