update credits
[LibreOffice.git] / javaunohelper / com / sun / star / lib / uno / helper / InterfaceContainer.java
bloba61edc06acc89998a30e89b2c4f1d37d69be67bd
1 /*
2 * This file is part of the LibreOffice project.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 * This file incorporates work covered by the following license notice:
10 * Licensed to the Apache Software Foundation (ASF) under one or more
11 * contributor license agreements. See the NOTICE file distributed
12 * with this work for additional information regarding copyright
13 * ownership. The ASF licenses this file to you under the Apache
14 * License, Version 2.0 (the "License"); you may not use this file
15 * except in compliance with the License. You may obtain a copy of
16 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
19 package com.sun.star.lib.uno.helper;
21 import java.util.Iterator;
22 import java.util.ListIterator;
23 import java.util.Collection;
25 import com.sun.star.lang.EventObject;
26 import com.sun.star.lang.XEventListener;
27 import com.sun.star.uno.UnoRuntime;
29 /**
30 * This class is a container for interfaces.
32 * It is intended to be used as storage for UNO interface of a specific type.
33 * The client has to ensure that the container contains only elements of the same
34 * type. If one needs to store different types, then one uses OMultiTypeInterfaceContainer.
35 * When the client calls disposeAndClear, the contained objects are queried for
36 * com.sun.star.lang.XEventListener and disposing is called. Afterwards
37 * the list cannot be used anymore.
39 * This list does not allow null values.
40 * All methods are thread-safe. The same holds true for
41 * iterators, issued by this class. Several iterators can exist at the same time and can also
42 * be modified (java.util.ListIterator.add, java.util.ListIterator.remove etc.). To make this work,
43 * the InterfaceContainer provides the iterators with copies of the list's data.
44 * The add and remove calls on the iterator modify the data in the iterator's list as well as
45 * in InterfaceContainer. Modification on InterfaceContainer, however, are not
46 * synchronized with existing iterators. For example
47 * <pre>
48 * InterfaceContainer cont= new InterfaceContainer();
49 * ListIterator it= cont.listIterator();
51 * cont.add( someInterface);
52 * // one cannot obtain someInterface through iterator it,
53 * // instead get a new iterator
54 * it= cont.listIterator();
55 * // it now keeps a fresh copy of cont and hence contains someInterface
57 * // Adding an interface on the iterator will cause the interface also to be added
58 * // to InterfaceContainer
59 * it.add( someOtherInterface);
60 * // someOtherInterface is now in it and cont
61 * ListIterator it2= cont.listIterator();
62 * //someOtherInterface can also be obtained by all newly created iterators, e.g. it2.
63 * </pre>
65 * The add and remove methods of an iterator work on a particular location within a list,
66 * dependent on what the value of the iterator's cursor is. After the call the value at the
67 * appropriate position has been modified. Since the iterator received a copy of InterfaceContainer's
68 * data, InterfaceContainer may have been modified (by List methods or through other iterators).
69 * Therefore both data sets may not contain the same elements anymore. Consequently, a List method
70 * that modifies data, does not modify InterfaceContainer's data at a certain index
71 * (according to the iterators cursor). Instead, new elements are added at the end of list. When
72 * Iterator.remove is called, then the first occurrence of that element in InterfaceContainer
73 * is removed.
74 * ListIterator.set is not supported.
76 * A lot of methods resemble those of the to java.util.List interface, although
77 * this class does not implement it. However, the list iterators returned, for example by
78 * the listIterator method implement the java.util.ListIterator interface.
79 * Implementing the List interface would mean to support all none - optional methods as
80 * prescribed by the interface declaration. Among those is the subList method which returns
81 * a range of values of the list's data wrapped in a List implementation. Changes to the sub
82 * list have to cause changes in the main list. This is a problem, since this class is to be
83 * used in a multi-threaded environment. The sub list could work on a copy as the iterators
84 * do, but all the functions which work on an given index could not be properly supported.
85 * Unfortunately, the List interface documentation states that all optional methods implemented
86 * by the list have to be implemented in the sub list. That would mean to do without all those
87 * critical methods, although they might work well in the "main list" (as opposed to sub list).
89 public class InterfaceContainer implements Cloneable
91 static final boolean DEBUG= false;
92 /**
93 * The array buffer into which the elements of the ArrayList are stored.
94 * The capacity of the ArrayList is the length of this array buffer.
96 Object elementData[];
98 /**
99 * The size of the ArrayList (the number of elements it contains).
101 private int size;
104 /** Creates a new instance of InterfaceContainer */
105 public InterfaceContainer()
107 this(10);
110 * Constructs an empty list with the specified initial capacity.
112 * @param initialCapacity the initial capacity of the list.
113 * @exception IllegalArgumentException if the specified initial capacity
114 * is negative
116 public InterfaceContainer(int initialCapacity)
118 if (initialCapacity < 0)
119 throw new java.lang.IllegalArgumentException("Illegal Capacity: "+
120 initialCapacity);
121 this.elementData = new Object[initialCapacity];
125 * Trims the capacity of this <tt>ArrayList</tt> instance to be the
126 * list's current size. An application can use this operation to minimize
127 * the storage of an <tt>ArrayList</tt> instance.
129 synchronized public void trimToSize()
131 int oldCapacity = elementData.length;
132 if (size < oldCapacity)
134 Object oldData[] = elementData;
135 elementData = new Object[size];
136 System.arraycopy(oldData, 0, elementData, 0, size);
141 * Increases the capacity of this <tt>ArrayList</tt> instance, if
142 * necessary, to ensure that it can hold at least the number of elements
143 * specified by the minimum capacity argument.
145 * @param minCapacity the desired minimum capacity.
147 synchronized public void ensureCapacity(int minCapacity)
149 int oldCapacity = elementData.length;
150 if (minCapacity > oldCapacity)
152 Object oldData[] = elementData;
153 int newCapacity = (oldCapacity * 3)/2 + 1;
154 if (newCapacity < minCapacity)
155 newCapacity = minCapacity;
156 elementData = new Object[newCapacity];
157 System.arraycopy(oldData, 0, elementData, 0, size);
162 * Appends the specified element to the end of this list.
164 * @param o element to be appended to this list.
165 * @return <tt>true</tt> (as per the general contract of Collection.add).
167 synchronized public boolean add(Object o)
169 boolean ret= false;
170 if (elementData != null && o != null)
172 ensureCapacity(size + 1); // Increments modCount!!
173 elementData[size++] = o;
174 ret= true;
176 return ret;
180 * Inserts the specified element at the specified position in this
181 * list. Shifts the element currently at that position (if any) and
182 * any subsequent elements to the right (adds one to their indices).
184 * @param index index at which the specified element is to be inserted.
185 * @param element element to be inserted.
186 * @throws IndexOutOfBoundsException if index is out of range
187 * <tt>(index &lt; 0 || index &gt; size())</tt>.
189 synchronized public void add(int index, Object element)
191 if (elementData != null && element != null)
193 if (index > size || index < 0)
194 throw new IndexOutOfBoundsException(
195 "Index: "+index+", Size: "+size);
197 ensureCapacity(size+1);
198 System.arraycopy(elementData, index, elementData, index + 1,
199 size - index);
200 elementData[index] = element;
201 size++;
207 * Appends all of the elements in the specified Collection to the end of
208 * this list, in the order that they are returned by the
209 * specified Collection's Iterator. The behavior of this operation is
210 * undefined if the specified Collection is modified while the operation
211 * is in progress. (This implies that the behavior of this call is
212 * undefined if the specified Collection is this list, and this
213 * list is nonempty.)
215 * @param c the elements to be inserted into this list.
216 * @throws IndexOutOfBoundsException if index out of range <tt>(index
217 * &lt; 0 || index &gt; size())</tt>.
219 synchronized public boolean addAll(Collection c)
221 int numNew = c.size();
222 ensureCapacity(size + numNew);
224 Iterator e = c.iterator();
225 for (int i=0; i<numNew; i++)
227 Object o= e.next();
228 if (o != null)
229 elementData[size++] = o;
231 return numNew != 0;
234 * Inserts all of the elements in the specified Collection into this
235 * list, starting at the specified position. Shifts the element
236 * currently at that position (if any) and any subsequent elements to
237 * the right (increases their indices). The new elements will appear
238 * in the list in the order that they are returned by the
239 * specified Collection's iterator.
241 * @param index index at which to insert first element
242 * from the specified collection.
243 * @param c elements to be inserted into this list.
244 * @throws IndexOutOfBoundsException if index out of range <tt>(index
245 * &lt; 0 || index &gt; size())</tt>.
247 synchronized public boolean addAll(int index, Collection c)
249 boolean ret= false;
250 if (elementData != null)
252 if (index > size || index < 0)
253 throw new IndexOutOfBoundsException(
254 "Index: "+index+", Size: "+size);
255 // only add the non-null elements
256 int sizeCol= c.size();
257 Object[] arColl= new Object[sizeCol];
258 Iterator icol= c.iterator();
259 int curIndex= 0;
260 for (int i=0; i < sizeCol; i++)
262 Object o= icol.next();
263 if (o != null)
264 arColl[curIndex++]= o;
266 int numNew = curIndex;
267 ensureCapacity(size + numNew); // Increments modCount!!
269 int numMoved = size - index;
270 if (numMoved > 0)
271 System.arraycopy(elementData, index, elementData, index + numNew,
272 numMoved);
274 for (int i=0; i<numNew; i++)
276 elementData[index++]= arColl[i];
278 size += numNew;
279 ret= numNew != 0;
281 return ret;
285 * Removes all of the elements from this list. The list will
286 * be empty after this call returns.
288 synchronized public void clear()
290 if (elementData != null)
292 // Let gc do its work
293 for (int i = 0; i < size; i++)
294 elementData[i] = null;
296 size = 0;
300 * Returns <tt>true</tt> if this list contains the specified element.
302 * @param elem element whose presence in this List is to be tested.
304 synchronized public boolean contains(Object elem)
306 return indexOf(elem) >= 0;
309 synchronized public boolean containsAll(Collection collection)
311 boolean retVal= true;
312 if (elementData != null && collection != null)
314 Iterator it= collection.iterator();
315 while (it.hasNext())
317 Object obj= it.next();
318 if (!contains(obj))
320 retVal= false;
321 break;
325 return retVal;
328 * Returns the element at the specified position in this list.
330 * @param index index of element to return.
331 * @return the element at the specified position in this list.
332 * @throws IndexOutOfBoundsException if index is out of range <tt>(index
333 * &lt; 0 || index &gt;= size())</tt>.
335 synchronized public Object get(int index)
337 if (elementData != null)
339 RangeCheck(index);
340 return elementData[index];
342 return null;
346 * Searches for the first occurrence of the given argument, testing
347 * for equality using the <tt>equals</tt> method.
349 * @param elem an object.
350 * @return the index of the first occurrence of the argument in this
351 * list; returns <tt>-1</tt> if the object is not found.
352 * @see Object#equals(Object)
354 synchronized public int indexOf(Object elem)
356 if (elementData == null || elem == null) {
357 return -1;
360 int index= -1;
362 for (int i = 0; i < size; i++)
364 if (elem == elementData[i])
366 index= i;
367 break;
371 if (index == -1)
373 for (int i = 0; i < size; i++)
375 if (UnoRuntime.areSame(elem, elementData[i]))
377 index= i;
378 break;
382 return index;
385 * Tests if this list has no elements.
387 * @return <tt>true</tt> if this list has no elements;
388 * <tt>false</tt> otherwise.
390 synchronized public boolean isEmpty()
392 return size == 0;
395 synchronized public Iterator iterator()
397 if (elementData != null)
399 InterfaceContainer aCopy= (InterfaceContainer) clone();
400 return new Itr(aCopy);
402 return null;
405 * Returns the index of the last occurrence of the specified object in
406 * this list.
408 * @param elem the desired element.
409 * @return the index of the last occurrence of the specified object in
410 * this list; returns -1 if the object is not found.
412 synchronized public int lastIndexOf(Object elem)
414 if (elementData == null || elem == null) {
415 return -1;
418 int index= -1;
420 for (int i = size-1; i >= 0; i--)
422 if (elem == elementData[i])
424 index= i;
425 break;
428 if (index == -1)
430 for (int i = size-1; i >= 0; i--)
432 if (UnoRuntime.areSame(elem, elementData[i]))
434 index= i;
435 break;
439 return index;
443 * Returns a shallow copy of this <tt>ArrayList</tt> instance. The contained
444 * references are copied but the objects not.
446 * @return a clone of this <tt>List</tt> instance.
448 @Override
449 synchronized public Object clone()
451 Object ret= null;
452 if (elementData != null)
454 InterfaceContainer cont= new InterfaceContainer();
455 cont.elementData = new Object[size];
456 cont.size= size;
457 System.arraycopy(elementData, 0, cont.elementData, 0, size);
458 ret= cont;
460 return ret;
462 synchronized public ListIterator listIterator()
464 return listIterator(0);
467 /** The iterator keeps a copy of the list. Changes to InterfaceContainer do not
468 * affect the data of the iterator. Conversely, changes to the iterator are effect
469 * InterfaceContainer.
471 synchronized public ListIterator listIterator(int index)
473 if (elementData != null)
475 InterfaceContainer aCopy= (InterfaceContainer) clone();
476 return new LstItr(aCopy, index);
478 return null;
481 * Removes the element at the specified position in this list.
482 * Shifts any subsequent elements to the left (subtracts one from their
483 * indices).
485 * @param index the index of the element to removed.
486 * @return the element that was removed from the list.
487 * @throws IndexOutOfBoundsException if index out of range <tt>(index
488 * &lt; 0 || index &gt;= size())</tt>.
490 synchronized public Object remove(int index)
492 Object ret= null;
493 if (elementData != null)
495 RangeCheck(index);
496 ret= elementData[index];
498 int numMoved = size - index - 1;
499 if (numMoved > 0)
500 System.arraycopy(elementData, index+1, elementData, index,
501 numMoved);
502 elementData[--size] = null; // Let gc do its work
504 return ret;
508 /** Parameter obj may */
509 synchronized public boolean remove(Object obj)
511 boolean ret= false;
512 if (elementData != null && obj != null)
514 int index= indexOf(obj);
515 if (index != -1)
517 ret= true;
518 remove(index);
521 return ret;
524 synchronized public boolean removeAll(Collection collection)
526 boolean retVal= false;
527 if (elementData != null && collection != null)
529 Iterator it= collection.iterator();
530 while (it.hasNext())
532 Object obj= it.next();
533 boolean bMod= remove( obj);
534 if (bMod)
535 retVal= true;
538 return retVal;
541 synchronized public boolean retainAll(Collection collection)
543 if (elementData == null || collection == null) {
544 return false;
547 boolean retVal= false;
548 // iterate over data
549 Object[] arRetained= new Object[size];
550 int indexRetained= 0;
551 for(int i= 0; i < size; i++)
553 Object curElem= elementData[i];
554 // try to find the element in collection
555 Iterator itColl= collection.iterator();
556 boolean bExists= false;
557 while (itColl.hasNext())
559 if (curElem == itColl.next())
561 // current element is in collection
562 bExists= true;
563 break;
566 if (!bExists)
568 itColl= collection.iterator();
569 while (itColl.hasNext())
571 Object o= itColl.next();
572 if (o != null)
574 if (UnoRuntime.areSame(o, curElem))
576 bExists= true;
577 break;
582 if (bExists)
583 arRetained[indexRetained++]= curElem;
585 retVal= size != indexRetained;
586 if (indexRetained > 0)
588 elementData= arRetained;
589 size= indexRetained;
591 return retVal;
595 /** Not supported.
596 * @param index index of element to replace.
597 * @param element element to be stored at the specified position.
598 * @return the element previously at the specified position.
599 * @throws IndexOutOfBoundsException if index out of range
600 * <tt>(index &lt; 0 || index &gt;= size())</tt>.
602 synchronized public Object set(int index, Object element)
604 Object ret= null;
605 if (elementData != null && element != null)
607 RangeCheck(index);
608 ret = elementData[index];
609 elementData[index] = element;
611 return ret;
615 * Returns the number of elements in this list.
617 * @return the number of elements in this list.
619 synchronized public int size()
621 if (elementData != null)
622 return size;
623 return 0;
628 * Returns an array containing all of the elements in this list
629 * in the correct order.
631 * @return an array containing all of the elements in this list
632 * in the correct order.
634 synchronized public Object[] toArray()
636 if (elementData != null)
638 Object[] result = new Object[size];
639 System.arraycopy(elementData, 0, result, 0, size);
640 return result;
642 return null;
646 * Returns an array containing all of the elements in this list in the
647 * correct order. The runtime type of the returned array is that of the
648 * specified array. If the list fits in the specified array, it is
649 * returned therein. Otherwise, a new array is allocated with the runtime
650 * type of the specified array and the size of this list.<p>
652 * If the list fits in the specified array with room to spare (i.e., the
653 * array has more elements than the list), the element in the array
654 * immediately following the end of the collection is set to
655 * <tt>null</tt>. This is useful in determining the length of the list
656 * <i>only</i> if the caller knows that the list does not contain any
657 * <tt>null</tt> elements.
659 * @param a the array into which the elements of the list are to
660 * be stored, if it is big enough; otherwise, a new array of the
661 * same runtime type is allocated for this purpose.
662 * @return an array containing the elements of the list.
663 * @throws ArrayStoreException if the runtime type of a is not a supertype
664 * of the runtime type of every element in this list.
666 synchronized public Object[] toArray(Object a[])
668 if (a.length < size)
669 a = (Object[])java.lang.reflect.Array.newInstance(
670 a.getClass().getComponentType(), size);
671 if (elementData != null)
672 System.arraycopy(elementData, 0, a, 0, size);
674 if (a.length > size)
675 a[size] = null;
677 return a;
681 * Check if the given index is in range. If not, throw an appropriate
682 * runtime exception.
684 private void RangeCheck(int index)
686 if (index >= size || index < 0)
687 throw new IndexOutOfBoundsException(
688 "Index: "+index+", Size: "+size);
691 public void disposeAndClear(EventObject evt)
693 Iterator aIt;
694 synchronized (this)
696 aIt= iterator();
697 // Container freigeben, falls im disposing neue Eintraege kommen
698 // set the member to null, the iterator delete the values
699 clear();
700 elementData= null;
701 size= 0;
703 if (aIt != null)
705 while( aIt.hasNext() )
709 Object o= aIt.next();
710 XEventListener evtListener= UnoRuntime.queryInterface(
711 XEventListener.class, o);
712 if( evtListener != null )
713 evtListener.disposing( evt );
715 catch ( RuntimeException e)
717 // be robust, if e.g. a remote bridge has disposed already.
718 // there is no way, to delegate the error to the caller :o(.
725 private class Itr implements Iterator
727 InterfaceContainer dataIt;
729 * Index of element to be returned by subsequent call to next.
731 int cursor= 0;
733 * Index of element returned by most recent call to next or
734 * previous. Reset to -1 if this element is deleted by a call
735 * to remove.
737 int lastRet = -1;
739 /** The object that has been returned by most recent call to next
740 * or previous. Reset to null if this element is deleted by a call
741 * to remove.
743 Object lastRetObj= null;
745 Itr(InterfaceContainer _data)
747 dataIt= _data;
750 synchronized public boolean hasNext()
752 return cursor !=dataIt.size();
755 public synchronized Object next()
759 Object next = dataIt.get(cursor);
760 lastRet = cursor++;
761 lastRetObj= next;
762 return next;
764 catch(java.lang.IndexOutOfBoundsException e)
766 java.util.NoSuchElementException ex2 = new java.util.NoSuchElementException();
767 ex2.initCause(e);
768 throw ex2;
772 /** Removes the interface from the list, that has been last returned by a
773 * call to next(). This is done according to the specification of the interface
774 * method. The element is also removed from InterfaceContainer but independent
775 * of the location. If the element is multiple times in InterfaceContainer then
776 * it is up to the java.util.ArrayList implementation what element is removed.
778 public synchronized void remove()
780 if (lastRet == -1)
781 throw new IllegalStateException();
782 // Remove the entry from InterfaceContainer.
783 InterfaceContainer.this.remove(lastRetObj);
784 dataIt.remove(lastRet);
786 if (lastRet < cursor)
787 cursor--;
788 lastRet = -1;
789 lastRetObj= null;
793 private class LstItr extends Itr implements ListIterator
796 LstItr(InterfaceContainer _data, int _index)
798 super(_data);
799 cursor= _index;
802 /** Inserts an element to the iterators list according to the specification
803 * of this interface method. The element is also added to InterfaceContainer
804 * but its location within the list cannot be guaranteed.
806 public synchronized void add(Object o)
808 InterfaceContainer.this.add(o);
809 dataIt.add(cursor++, o);
810 lastRet = -1;
811 lastRetObj= null;
814 synchronized public boolean hasPrevious()
816 return cursor != 0;
819 synchronized public int nextIndex()
821 return cursor;
824 public synchronized Object previous()
828 Object previous = dataIt.get(--cursor);
829 lastRet = cursor;
830 lastRetObj= previous;
831 return previous;
832 } catch(IndexOutOfBoundsException e)
834 java.util.NoSuchElementException ex2 = new java.util.NoSuchElementException();
835 ex2.initCause(e);
836 throw ex2;
840 synchronized public int previousIndex()
842 return cursor-1;
845 /** This is not possible since several iterators can modify InterfaceContainer
847 public synchronized void set(Object o)
849 throw new UnsupportedOperationException();
853 } // class LstItr