Version 3.6.0.2, tag libreoffice-3.6.0.2
[LibreOffice.git] / javaunohelper / com / sun / star / lib / uno / helper / InterfaceContainer.java
bloba0a72b5cf6162000da579c6da3980ec9878abc15
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 package com.sun.star.lib.uno.helper;
29 import java.util.Iterator;
30 import java.util.ListIterator;
31 import java.util.NoSuchElementException;
32 import java.util.Collection;
33 import com.sun.star.lang.EventObject;
34 import com.sun.star.lang.XEventListener;
35 import com.sun.star.uno.UnoRuntime;
37 /**
38 * This class is a container for interfaces.
40 * It is intended to be used as storage for UNO interface of a specific type.
41 * The client has to ensure that the container contains only elements of the same
42 * type. If one needs to store different types, then one uses OMultiTypeInterfaceContainer.
43 * When the client calls disposeAndClear, the contained objects are queried for
44 * com.sun.star.lang.XEventListener and disposing is called. Afterwards
45 * the list cannot be used anymore.
47 * This list does not allow null values.
48 * All methods are thread-safe. The same holds true for
49 * iterators, issued by this class. Several iterators can exist at the same time and can also
50 * be modified (java.util.ListIterator.add, java.util.ListIterator.remove etc.). To make this work,
51 * the InterfaceContainer provides the iterators with copys of the list's data.
52 * The add and remove calls on the iterator modify the data in the iterator's list as well as
53 * in InterfaceContainer. Modification on InterfaceContainer, however, are not
54 * synchronized with existing iterators. For example
55 * <pre>
56 * InterfaceContainer cont= new InterfaceContainer();
57 * ListIterator it= cont.listIterator();
59 * cont.add( someInterface);
60 * // one cannot obtain someInterface through iterator it,
61 * // instead get a new iterator
62 * it= cont.listIterator();
63 * // it now keeps a fresh copy of cont and hence contains someInterface
65 * // Adding an interface on the iterator will cause the interface also to be added
66 * // to InterfaceContainer
67 * it.add( someOtherInterface);
68 * // someOtherInterface is now in it and cont
69 * ListIterator it2= cont.listIterator();
70 * //someOtherInterface can also be obtained by all newly created iterators, e.g. it2.
71 * </pre>
73 * The add and remove methods of an iterator work on a particular location within a list,
74 * dependent on what the value of the iterator's cursor is. After the call the value at the
75 * appropriate position has been modified. Since the iterator received a copy of InterfaceContainer's
76 * data, InterfaceContainer may have been modified (by List methods or through other iterators).
77 * Therefore both data sets may not contain the same elements anymore. Consequently, a List method
78 * that modifies data, does not modify InterfaceContainer's data at a certain index
79 * (according to the iterators cursor). Instead, new elements are added at the end of list. When
80 * Iterator.remove is called, then the first occurrence of that element in InterfaceContainer
81 * is removed.
82 * ListIterator.set is not supported.
84 * A lot of methods resemble those of the to java.util.List interface, allthough
85 * this class does not implement it. However, the list iterators returned, for example by
86 * the listIterator method implement the java.util.ListIterator interface.
87 * Implementing the List interface would mean to support all none - optional methods as
88 * prescribed by the interface declaration. Among those is the subList method which returns
89 * a range of values of the list's data wrapped in a List implementation. Changes to the sub
90 * list have to cause changes in the main list. This is a problem, since this class is to be
91 * used in a multi-threaded environment. The sub list could work on a copy as the iterators
92 * do, but all the functions which work on an given index could not be properly supported.
93 * Unfortunatly, the List interface documentation states that all optional methods implemented
94 * by the list have to be implemented in the sub list. That would mean to do without all those
95 * critical methods, allthough they might work well in the "main list" (as opposed to sub list).
97 public class InterfaceContainer implements Cloneable
99 final boolean DEBUG= false;
101 * The array buffer into which the elements of the ArrayList are stored.
102 * The capacity of the ArrayList is the length of this array buffer.
104 Object elementData[];
107 * The size of the ArrayList (the number of elements it contains).
109 * @serial
111 private int size;
114 //private ArrayList data= new ArrayList();
115 /** Creates a new instance of InterfaceContainer */
116 public InterfaceContainer()
118 this(10);
121 * Constructs an empty list with the specified initial capacity.
123 * @param initialCapacity the initial capacity of the list.
124 * @exception IllegalArgumentException if the specified initial capacity
125 * is negative
127 public InterfaceContainer(int initialCapacity)
129 if (initialCapacity < 0)
130 throw new java.lang.IllegalArgumentException("Illegal Capacity: "+
131 initialCapacity);
132 this.elementData = new Object[initialCapacity];
136 * Trims the capacity of this <tt>ArrayList</tt> instance to be the
137 * list's current size. An application can use this operation to minimize
138 * the storage of an <tt>ArrayList</tt> instance.
140 synchronized public void trimToSize()
142 int oldCapacity = elementData.length;
143 if (size < oldCapacity)
145 Object oldData[] = elementData;
146 elementData = new Object[size];
147 System.arraycopy(oldData, 0, elementData, 0, size);
152 * Increases the capacity of this <tt>ArrayList</tt> instance, if
153 * necessary, to ensure that it can hold at least the number of elements
154 * specified by the minimum capacity argument.
156 * @param minCapacity the desired minimum capacity.
158 synchronized public void ensureCapacity(int minCapacity)
160 int oldCapacity = elementData.length;
161 if (minCapacity > oldCapacity)
163 Object oldData[] = elementData;
164 int newCapacity = (oldCapacity * 3)/2 + 1;
165 if (newCapacity < minCapacity)
166 newCapacity = minCapacity;
167 elementData = new Object[newCapacity];
168 System.arraycopy(oldData, 0, elementData, 0, size);
173 * Appends the specified element to the end of this list.
175 * @param o element to be appended to this list.
176 * @return <tt>true</tt> (as per the general contract of Collection.add).
178 synchronized public boolean add(Object o)
180 boolean ret= false;
181 if (elementData != null && o != null)
183 ensureCapacity(size + 1); // Increments modCount!!
184 elementData[size++] = o;
185 ret= true;
187 return ret;
191 * Inserts the specified element at the specified position in this
192 * list. Shifts the element currently at that position (if any) and
193 * any subsequent elements to the right (adds one to their indices).
195 * @param index index at which the specified element is to be inserted.
196 * @param element element to be inserted.
197 * @throws IndexOutOfBoundsException if index is out of range
198 * <tt>(index &lt; 0 || index &gt; size())</tt>.
200 synchronized public void add(int index, Object element)
202 if (elementData != null && element != null)
204 if (index > size || index < 0)
205 throw new IndexOutOfBoundsException(
206 "Index: "+index+", Size: "+size);
208 ensureCapacity(size+1);
209 System.arraycopy(elementData, index, elementData, index + 1,
210 size - index);
211 elementData[index] = element;
212 size++;
218 * Appends all of the elements in the specified Collection to the end of
219 * this list, in the order that they are returned by the
220 * specified Collection's Iterator. The behavior of this operation is
221 * undefined if the specified Collection is modified while the operation
222 * is in progress. (This implies that the behavior of this call is
223 * undefined if the specified Collection is this list, and this
224 * list is nonempty.)
226 * @param c the elements to be inserted into this list.
227 * @throws IndexOutOfBoundsException if index out of range <tt>(index
228 * &lt; 0 || index &gt; size())</tt>.
230 synchronized public boolean addAll(Collection c)
232 int numNew = c.size();
233 ensureCapacity(size + numNew);
235 Iterator e = c.iterator();
236 for (int i=0; i<numNew; i++)
238 Object o= e.next();
239 if (o != null)
240 elementData[size++] = o;
242 return numNew != 0;
245 * Inserts all of the elements in the specified Collection into this
246 * list, starting at the specified position. Shifts the element
247 * currently at that position (if any) and any subsequent elements to
248 * the right (increases their indices). The new elements will appear
249 * in the list in the order that they are returned by the
250 * specified Collection's iterator.
252 * @param index index at which to insert first element
253 * from the specified collection.
254 * @param c elements to be inserted into this list.
255 * @throws IndexOutOfBoundsException if index out of range <tt>(index
256 * &lt; 0 || index &gt; size())</tt>.
258 synchronized public boolean addAll(int index, Collection c)
260 boolean ret= false;
261 if (elementData != null)
263 if (index > size || index < 0)
264 throw new IndexOutOfBoundsException(
265 "Index: "+index+", Size: "+size);
266 // only add the non-null elements
267 int sizeCol= c.size();
268 Object[] arColl= new Object[sizeCol];
269 Iterator icol= c.iterator();
270 int curIndex= 0;
271 for (int i=0; i < sizeCol; i++)
273 Object o= icol.next();
274 if (o != null)
275 arColl[curIndex++]= o;
277 int numNew = curIndex;
278 ensureCapacity(size + numNew); // Increments modCount!!
280 int numMoved = size - index;
281 if (numMoved > 0)
282 System.arraycopy(elementData, index, elementData, index + numNew,
283 numMoved);
285 for (int i=0; i<numNew; i++)
287 elementData[index++]= arColl[i];
289 size += numNew;
290 ret= numNew != 0;
292 return ret;
296 * Removes all of the elements from this list. The list will
297 * be empty after this call returns.
299 synchronized public void clear()
301 if (elementData != null)
303 // Let gc do its work
304 for (int i = 0; i < size; i++)
305 elementData[i] = null;
307 size = 0;
311 * Returns <tt>true</tt> if this list contains the specified element.
313 * @param elem element whose presence in this List is to be tested.
315 synchronized public boolean contains(Object elem)
317 return indexOf(elem) >= 0;
320 synchronized public boolean containsAll(Collection collection)
322 boolean retVal= true;
323 if (elementData != null && collection != null)
325 Iterator it= collection.iterator();
326 while (it.hasNext())
328 Object obj= it.next();
329 if (false == contains(obj))
331 retVal= false;
332 break;
336 return retVal;
339 * Returns the element at the specified position in this list.
341 * @param index index of element to return.
342 * @return the element at the specified position in this list.
343 * @throws IndexOutOfBoundsException if index is out of range <tt>(index
344 * &lt; 0 || index &gt;= size())</tt>.
346 synchronized public Object get(int index)
348 if (elementData != null)
350 RangeCheck(index);
351 return elementData[index];
353 return null;
357 * Searches for the first occurrence of the given argument, testing
358 * for equality using the <tt>equals</tt> method.
360 * @param elem an object.
361 * @return the index of the first occurrence of the argument in this
362 * list; returns <tt>-1</tt> if the object is not found.
363 * @see Object#equals(Object)
365 synchronized public int indexOf(Object elem)
367 int index= -1;
368 if (elementData != null && elem != null)
370 for (int i = 0; i < size; i++)
372 if (elem == elementData[i])
374 index= i;
375 break;
379 if (index == -1)
381 for (int i = 0; i < size; i++)
383 if (UnoRuntime.areSame(elem, elementData[i]))
385 index= i;
386 break;
391 return index;
394 * Tests if this list has no elements.
396 * @return <tt>true</tt> if this list has no elements;
397 * <tt>false</tt> otherwise.
399 synchronized public boolean isEmpty()
401 return size == 0;
404 synchronized public Iterator iterator()
406 if (elementData != null)
408 InterfaceContainer aCopy= (InterfaceContainer) clone();
409 return new Itr(aCopy);
411 return null;
414 * Returns the index of the last occurrence of the specified object in
415 * this list.
417 * @param elem the desired element.
418 * @return the index of the last occurrence of the specified object in
419 * this list; returns -1 if the object is not found.
421 synchronized public int lastIndexOf(Object elem)
423 int index= -1;
424 if (elementData != null && elem != null)
426 for (int i = size-1; i >= 0; i--)
428 if (elem == elementData[i])
430 index= i;
431 break;
434 if (index == -1)
436 for (int i = size-1; i >= 0; i--)
438 if (UnoRuntime.areSame(elem, elementData[i]))
440 index= i;
441 break;
446 return index;
450 * Returns a shallow copy of this <tt>ArrayList</tt> instance. The contained
451 * references are copied but the objects not.
453 * @return a clone of this <tt>List</tt> instance.
455 synchronized public Object clone()
457 Object ret= null;
458 if (elementData != null)
460 InterfaceContainer cont= new InterfaceContainer();
461 cont.elementData = new Object[size];
462 cont.size= size;
463 System.arraycopy(elementData, 0, cont.elementData, 0, size);
464 ret= cont;
466 return ret;
468 synchronized public ListIterator listIterator()
470 return listIterator(0);
473 /** The iterator keeps a copy of the list. Changes to InterfaceContainer do not
474 * affect the data of the iterator. Conversly, changes to the iterator are effect
475 * InterfaceContainer.
477 synchronized public ListIterator listIterator(int index)
479 if (elementData != null)
481 InterfaceContainer aCopy= (InterfaceContainer) clone();
482 return new LstItr(aCopy, index);
484 return null;
487 * Removes the element at the specified position in this list.
488 * Shifts any subsequent elements to the left (subtracts one from their
489 * indices).
491 * @param index the index of the element to removed.
492 * @return the element that was removed from the list.
493 * @throws IndexOutOfBoundsException if index out of range <tt>(index
494 * &lt; 0 || index &gt;= size())</tt>.
496 synchronized public Object remove(int index)
498 Object ret= null;
499 if (elementData != null)
501 RangeCheck(index);
502 ret= elementData[index];
504 int numMoved = size - index - 1;
505 if (numMoved > 0)
506 System.arraycopy(elementData, index+1, elementData, index,
507 numMoved);
508 elementData[--size] = null; // Let gc do its work
510 return ret;
514 /** Parameter obj may */
515 synchronized public boolean remove(Object obj)
517 boolean ret= false;
518 if (elementData != null && obj != null)
520 int index= indexOf(obj);
521 if (index != -1)
523 ret= true;
524 remove(index);
527 return ret;
530 synchronized public boolean removeAll(Collection collection)
532 boolean retVal= false;
533 if (elementData != null && collection != null)
535 Iterator it= collection.iterator();
536 while (it.hasNext())
538 Object obj= it.next();
539 boolean bMod= remove( obj);
540 if (bMod)
541 retVal= true;
544 return retVal;
547 synchronized public boolean retainAll(Collection collection)
549 boolean retVal= false;
550 if (elementData != null && collection != null)
552 // iterate over data
553 Object[] arRetained= new Object[size];
554 int indexRetained= 0;
555 for(int i= 0; i < size; i++)
557 Object curElem= elementData[i];
558 // try to find the element in collection
559 Iterator itColl= collection.iterator();
560 boolean bExists= false;
561 while (itColl.hasNext())
563 if (curElem == itColl.next())
565 // current element is in collection
566 bExists= true;
567 break;
570 if (bExists == false)
572 itColl= collection.iterator();
573 while (itColl.hasNext())
575 Object o= itColl.next();
576 if (o != null)
578 if (UnoRuntime.areSame(o, curElem))
580 bExists= true;
581 break;
586 if (bExists == true)
587 arRetained[indexRetained++]= curElem;
589 retVal= size != indexRetained;
590 if (indexRetained > 0)
592 elementData= arRetained;
593 size= indexRetained;
596 return retVal;
600 /** Not supported.
601 * @param index index of element to replace.
602 * @param element element to be stored at the specified position.
603 * @return the element previously at the specified position.
604 * @throws IndexOutOfBoundsException if index out of range
605 * <tt>(index &lt; 0 || index &gt;= size())</tt>.
607 synchronized public Object set(int index, Object element)
609 Object ret= null;
610 if (elementData != null && element != null)
612 RangeCheck(index);
613 ret = elementData[index];
614 elementData[index] = element;
616 return ret;
620 * Returns the number of elements in this list.
622 * @return the number of elements in this list.
624 synchronized public int size()
626 if (elementData != null)
627 return size;
628 return 0;
633 * Returns an array containing all of the elements in this list
634 * in the correct order.
636 * @return an array containing all of the elements in this list
637 * in the correct order.
639 synchronized public Object[] toArray()
641 if (elementData != null)
643 Object[] result = new Object[size];
644 System.arraycopy(elementData, 0, result, 0, size);
645 return result;
647 return null;
651 * Returns an array containing all of the elements in this list in the
652 * correct order. The runtime type of the returned array is that of the
653 * specified array. If the list fits in the specified array, it is
654 * returned therein. Otherwise, a new array is allocated with the runtime
655 * type of the specified array and the size of this list.<p>
657 * If the list fits in the specified array with room to spare (i.e., the
658 * array has more elements than the list), the element in the array
659 * immediately following the end of the collection is set to
660 * <tt>null</tt>. This is useful in determining the length of the list
661 * <i>only</i> if the caller knows that the list does not contain any
662 * <tt>null</tt> elements.
664 * @param a the array into which the elements of the list are to
665 * be stored, if it is big enough; otherwise, a new array of the
666 * same runtime type is allocated for this purpose.
667 * @return an array containing the elements of the list.
668 * @throws ArrayStoreException if the runtime type of a is not a supertype
669 * of the runtime type of every element in this list.
671 synchronized public Object[] toArray(Object a[])
673 if (a.length < size)
674 a = (Object[])java.lang.reflect.Array.newInstance(
675 a.getClass().getComponentType(), size);
676 if (elementData != null)
677 System.arraycopy(elementData, 0, a, 0, size);
679 if (a.length > size)
680 a[size] = null;
682 return a;
686 * Check if the given index is in range. If not, throw an appropriate
687 * runtime exception.
689 private void RangeCheck(int index)
691 if (index >= size || index < 0)
692 throw new IndexOutOfBoundsException(
693 "Index: "+index+", Size: "+size);
696 public void disposeAndClear(EventObject evt)
698 Iterator aIt;
699 synchronized (this)
701 aIt= iterator();
702 // Container freigeben, falls im disposing neue Eintraege kommen
703 // set the member to null, the iterator delete the values
704 clear();
705 elementData= null;
706 size= 0;
708 if (aIt != null)
710 while( aIt.hasNext() )
714 Object o= aIt.next();
715 XEventListener evtListener= UnoRuntime.queryInterface(
716 XEventListener.class, o);
717 if( evtListener != null )
718 evtListener.disposing( evt );
720 catch ( RuntimeException e)
722 // be robust, if e.g. a remote bridge has disposed already.
723 // there is no way, to delegate the error to the caller :o(.
730 private class Itr implements Iterator
732 InterfaceContainer dataIt;
734 * Index of element to be returned by subsequent call to next.
736 int cursor= 0;
738 * Index of element returned by most recent call to next or
739 * previous. Reset to -1 if this element is deleted by a call
740 * to remove.
742 int lastRet = -1;
744 /** The object that has been returned by most recent call to next
745 * or previous. Reset to null if this element is deleted by a call
746 * to remove.
748 Object lastRetObj= null;
750 Itr(InterfaceContainer _data)
752 dataIt= _data;
755 synchronized public boolean hasNext()
757 return cursor !=dataIt.size();
760 public synchronized Object next()
764 Object next = dataIt.get(cursor);
765 lastRet = cursor++;
766 lastRetObj= next;
767 return next;
769 catch(java.lang.IndexOutOfBoundsException e)
771 throw new java.util.NoSuchElementException();
775 /** Removes the interface from the list, that has been last returned by a
776 * call to next(). This is done according to the specification of the interface
777 * method. The element is also removed from InterfaceContainer but independent
778 * of the location. If the element is multiple times in InterfaceContainer then
779 * it is up to the java.util.ArrayList implementation what element is removed.
781 public synchronized void remove()
783 if (lastRet == -1)
784 throw new IllegalStateException();
785 // Remove the entry from InterfaceContainer.
786 InterfaceContainer.this.remove(lastRetObj);
787 dataIt.remove(lastRet);
789 if (lastRet < cursor)
790 cursor--;
791 lastRet = -1;
792 lastRetObj= null;
796 private class LstItr extends Itr implements ListIterator
799 LstItr(InterfaceContainer _data, int _index)
801 super(_data);
802 cursor= _index;
805 /** Inserts an element to the iterators list according to the specification
806 * of this interface method. The element is also added to InterfaceContainer
807 * but its location within the list cannot be guaranteed.
809 public synchronized void add(Object o)
811 InterfaceContainer.this.add(o);
812 dataIt.add(cursor++, o);
813 lastRet = -1;
814 lastRetObj= null;
817 synchronized public boolean hasPrevious()
819 return cursor != 0;
822 synchronized public int nextIndex()
824 return cursor;
827 public synchronized Object previous()
831 Object previous = dataIt.get(--cursor);
832 lastRet = cursor;
833 lastRetObj= previous;
834 return previous;
835 } catch(IndexOutOfBoundsException e)
837 throw new NoSuchElementException();
841 synchronized public int previousIndex()
843 return cursor-1;
846 /** This is not possible since several iterators can modify InterfaceContainer
848 public synchronized void set(Object o)
850 throw new UnsupportedOperationException();
854 } // class LstItr