uno grid a11y: Use ImplInheritanceHelper
[LibreOffice.git] / ridljar / com / sun / star / lib / uno / helper / InterfaceContainer.java
blobe858ced81fd807d35de907d5b8ea8e1614ba902c
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 a 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];
124 private InterfaceContainer(Object[] data) {
125 elementData = data;
126 size = elementData == null ? 0 : elementData.length;
130 * Trims the capacity of this <code>ArrayList</code> instance to be the
131 * list's current size. An application can use this operation to minimize
132 * the storage of an <code>ArrayList</code> instance.
134 synchronized public void trimToSize()
136 int oldCapacity = elementData.length;
137 if (size < oldCapacity)
139 Object oldData[] = elementData;
140 elementData = new Object[size];
141 System.arraycopy(oldData, 0, elementData, 0, size);
146 * Increases the capacity of this <code>ArrayList</code> instance, if
147 * necessary, to ensure that it can hold at least the number of elements
148 * specified by the minimum capacity argument.
150 * @param minCapacity the desired minimum capacity.
152 synchronized public void ensureCapacity(int minCapacity)
154 int oldCapacity = elementData.length;
155 if (minCapacity > oldCapacity)
157 Object oldData[] = elementData;
158 int newCapacity = (oldCapacity * 3)/2 + 1;
159 if (newCapacity < minCapacity)
160 newCapacity = minCapacity;
161 elementData = new Object[newCapacity];
162 System.arraycopy(oldData, 0, elementData, 0, size);
167 * Appends the specified element to the end of this list.
169 * @param o element to be appended to this list.
170 * @return <code>true</code> (as per the general contract of Collection.add).
172 synchronized public boolean add(Object o)
174 boolean ret= false;
175 if (elementData != null && o != null)
177 ensureCapacity(size + 1); // Increments modCount!!
178 elementData[size++] = o;
179 ret= true;
181 return ret;
185 * Inserts the specified element at the specified position in this
186 * list. Shifts the element currently at that position (if any) and
187 * any subsequent elements to the right (adds one to their indices).
189 * @param index index at which the specified element is to be inserted.
190 * @param element element to be inserted.
191 * @throws IndexOutOfBoundsException if index is out of range
192 * <code>(index &lt; 0 || index &gt; size())</code>.
194 synchronized public void add(int index, Object element)
196 if (elementData != null && element != null)
198 if (index > size || index < 0)
199 throw new IndexOutOfBoundsException(
200 "Index: "+index+", Size: "+size);
202 ensureCapacity(size+1);
203 System.arraycopy(elementData, index, elementData, index + 1,
204 size - index);
205 elementData[index] = element;
206 size++;
212 * Appends all of the elements in the specified Collection to the end of
213 * this list, in the order that they are returned by the
214 * specified Collection's Iterator. The behavior of this operation is
215 * undefined if the specified Collection is modified while the operation
216 * is in progress. (This implies that the behavior of this call is
217 * undefined if the specified Collection is this list, and this
218 * list is nonempty.)
220 * @param c the elements to be inserted into this list.
221 * @throws IndexOutOfBoundsException if index out of range <code>(index
222 * &lt; 0 || index &gt; size())</code>.
223 * @return true if an element was inserted.
225 synchronized public boolean addAll(Collection c)
227 int numNew = c.size();
228 ensureCapacity(size + numNew);
230 Iterator e = c.iterator();
231 for (int i=0; i<numNew; i++)
233 Object o= e.next();
234 if (o != null)
235 elementData[size++] = o;
237 return numNew != 0;
240 * Inserts all of the elements in the specified Collection into this
241 * list, starting at the specified position. Shifts the element
242 * currently at that position (if any) and any subsequent elements to
243 * the right (increases their indices). The new elements will appear
244 * in the list in the order that they are returned by the
245 * specified Collection's iterator.
247 * @param index index at which to insert first element
248 * from the specified collection.
249 * @param c elements to be inserted into this list.
250 * @throws IndexOutOfBoundsException if index out of range <code>(index
251 * &lt; 0 || index &gt; size())</code>.
252 * @return true if an element was inserted.
254 synchronized public boolean addAll(int index, Collection c)
256 boolean ret= false;
257 if (elementData != null)
259 if (index > size || index < 0)
260 throw new IndexOutOfBoundsException(
261 "Index: "+index+", Size: "+size);
262 // only add the non-null elements
263 int sizeCol= c.size();
264 Object[] arColl= new Object[sizeCol];
265 Iterator icol= c.iterator();
266 int curIndex= 0;
267 for (int i=0; i < sizeCol; i++)
269 Object o= icol.next();
270 if (o != null)
271 arColl[curIndex++]= o;
273 int numNew = curIndex;
274 ensureCapacity(size + numNew); // Increments modCount!!
276 int numMoved = size - index;
277 if (numMoved > 0)
278 System.arraycopy(elementData, index, elementData, index + numNew,
279 numMoved);
281 for (int i=0; i<numNew; i++)
283 elementData[index++]= arColl[i];
285 size += numNew;
286 ret= numNew != 0;
288 return ret;
292 * Removes all of the elements from this list. The list will
293 * be empty after this call returns.
295 synchronized public void clear()
297 if (elementData != null)
299 // Let gc do its work
300 for (int i = 0; i < size; i++)
301 elementData[i] = null;
303 size = 0;
307 * Returns <code>true</code> if this list contains the specified element.
309 * @param elem element whose presence in this List is to be tested.
310 * @return <code>true</code> if this list contains the specified element.
312 synchronized public boolean contains(Object elem)
314 return indexOf(elem) >= 0;
317 synchronized public boolean containsAll(Collection collection)
319 boolean retVal= true;
320 if (elementData != null && collection != null)
322 Iterator it= collection.iterator();
323 while (it.hasNext())
325 Object obj= it.next();
326 if (!contains(obj))
328 retVal= false;
329 break;
333 return retVal;
336 * Returns the element at the specified position in this list.
338 * @param index index of element to return.
339 * @return the element at the specified position in this list.
340 * @throws IndexOutOfBoundsException if index is out of range <code>(index
341 * &lt; 0 || index &gt;= size())</code>.
343 synchronized public Object get(int index)
345 if (elementData != null)
347 RangeCheck(index);
348 return elementData[index];
350 return null;
354 * Searches for the first occurrence of the given argument, testing
355 * for equality using the <code>equals</code> method.
357 * @param elem an object.
358 * @return the index of the first occurrence of the argument in this
359 * list; returns <code>-1</code> if the object is not found.
360 * @see Object#equals(Object)
362 synchronized public int indexOf(Object elem)
364 if (elementData == null || elem == null) {
365 return -1;
368 int index= -1;
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;
390 return index;
393 * Tests if this list has no elements.
395 * @return <code>true</code> if this list has no elements;
396 * <code>false</code> otherwise.
398 synchronized public boolean isEmpty()
400 return size == 0;
403 synchronized public Iterator iterator()
405 if (elementData != null)
407 InterfaceContainer aCopy= (InterfaceContainer) clone();
408 return new Itr(aCopy);
410 return null;
413 * Returns the index of the last occurrence of the specified object in
414 * this list.
416 * @param elem the desired element.
417 * @return the index of the last occurrence of the specified object in
418 * this list; returns -1 if the object is not found.
420 synchronized public int lastIndexOf(Object elem)
422 if (elementData == null || elem == null) {
423 return -1;
426 int index= -1;
428 for (int i = size-1; i >= 0; i--)
430 if (elem == elementData[i])
432 index= i;
433 break;
436 if (index == -1)
438 for (int i = size-1; i >= 0; i--)
440 if (UnoRuntime.areSame(elem, elementData[i]))
442 index= i;
443 break;
447 return index;
451 * Returns a shallow copy of this <code>ArrayList</code> instance. The contained
452 * references are copied but the objects not.
454 * @return a clone of this <code>List</code> instance.
456 @Override
457 synchronized public Object clone()
459 Object[] data;
460 if (elementData == null) {
461 data = null;
462 } else {
463 data = new Object[size];
464 System.arraycopy(elementData, 0, data, 0, size);
466 return new InterfaceContainer(data);
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. Conversely, changes to the iterator are effect
475 * InterfaceContainer.
476 * @param index the starting offset into the list.
477 * @return a new iterator.
479 synchronized public ListIterator listIterator(int index)
481 if (elementData != null)
483 InterfaceContainer aCopy= (InterfaceContainer) clone();
484 return new LstItr(aCopy, index);
486 return null;
489 * Removes the element at the specified position in this list.
490 * Shifts any subsequent elements to the left (subtracts one from their
491 * indices).
493 * @param index the index of the element to removed.
494 * @return the element that was removed from the list.
495 * @throws IndexOutOfBoundsException if index out of range <code>(index
496 * &lt; 0 || index &gt;= size())</code>.
498 synchronized public Object remove(int index)
500 Object ret= null;
501 if (elementData != null)
503 RangeCheck(index);
504 ret= elementData[index];
506 int numMoved = size - index - 1;
507 if (numMoved > 0)
508 System.arraycopy(elementData, index+1, elementData, index,
509 numMoved);
510 elementData[--size] = null; // Let gc do its work
512 return ret;
516 /** Parameter obj may... or may not. What did the original author want
517 * to tell us here?
518 * @param obj the object to be removed.
519 * @return true if obj was successfully removed from the list.
521 synchronized public boolean remove(Object obj)
523 boolean ret= false;
524 if (elementData != null && obj != null)
526 int index= indexOf(obj);
527 if (index != -1)
529 ret= true;
530 remove(index);
533 return ret;
536 synchronized public boolean removeAll(Collection collection)
538 boolean retVal= false;
539 if (elementData != null && collection != null)
541 Iterator it= collection.iterator();
542 while (it.hasNext())
544 Object obj= it.next();
545 boolean bMod= remove( obj);
546 if (bMod)
547 retVal= true;
550 return retVal;
553 synchronized public boolean retainAll(Collection collection)
555 if (elementData == null || collection == null) {
556 return false;
559 boolean retVal= false;
560 // iterate over data
561 Object[] arRetained= new Object[size];
562 int indexRetained= 0;
563 for(int i= 0; i < size; i++)
565 Object curElem= elementData[i];
566 // try to find the element in collection
567 Iterator itColl= collection.iterator();
568 boolean bExists= false;
569 while (itColl.hasNext())
571 if (curElem == itColl.next())
573 // current element is in collection
574 bExists= true;
575 break;
578 if (!bExists)
580 itColl= collection.iterator();
581 while (itColl.hasNext())
583 Object o= itColl.next();
584 if (o != null && UnoRuntime.areSame(o, curElem))
586 bExists= true;
587 break;
591 if (bExists)
592 arRetained[indexRetained++]= curElem;
594 retVal= size != indexRetained;
595 if (indexRetained > 0)
597 elementData= arRetained;
598 size= indexRetained;
600 return retVal;
604 /** Not supported.
605 * @param index index of element to replace.
606 * @param element element to be stored at the specified position.
607 * @return the element previously at the specified position.
608 * @throws IndexOutOfBoundsException if index out of range
609 * <code>(index &lt; 0 || index &gt;= size())</code>.
611 synchronized public Object set(int index, Object element)
613 Object ret= null;
614 if (elementData != null && element != null)
616 RangeCheck(index);
617 ret = elementData[index];
618 elementData[index] = element;
620 return ret;
624 * Returns the number of elements in this list.
626 * @return the number of elements in this list.
628 synchronized public int size()
630 if (elementData != null)
631 return size;
632 return 0;
637 * Returns an array containing all of the elements in this list
638 * in the correct order.
640 * @return an array containing all of the elements in this list
641 * in the correct order.
643 synchronized public Object[] toArray()
645 if (elementData != null)
647 Object[] result = new Object[size];
648 System.arraycopy(elementData, 0, result, 0, size);
649 return result;
651 return null;
655 * Returns an array containing all of the elements in this list in the
656 * correct order. The runtime type of the returned array is that of the
657 * specified array. If the list fits in the specified array, it is
658 * returned therein. Otherwise, a new array is allocated with the runtime
659 * type of the specified array and the size of this list.<p>
661 * If the list fits in the specified array with room to spare (i.e., the
662 * array has more elements than the list), the element in the array
663 * immediately following the end of the collection is set to
664 * <code>null</code>. This is useful in determining the length of the list
665 * <i>only</i> if the caller knows that the list does not contain any
666 * <code>null</code> elements.
668 * @param a the array into which the elements of the list are to
669 * be stored, if it is big enough; otherwise, a new array of the
670 * same runtime type is allocated for this purpose.
671 * @return an array containing the elements of the list.
672 * @throws ArrayStoreException if the runtime type of a is not a supertype
673 * of the runtime type of every element in this list.
675 synchronized public Object[] toArray(Object a[])
677 if (a.length < size)
678 a = (Object[])java.lang.reflect.Array.newInstance(
679 a.getClass().getComponentType(), size);
680 if (elementData != null)
681 System.arraycopy(elementData, 0, a, 0, size);
683 if (a.length > size)
684 a[size] = null;
686 return a;
690 * Check if the given index is in range. If not, throw an appropriate
691 * runtime exception.
693 private void RangeCheck(int index)
695 if (index >= size || index < 0)
696 throw new IndexOutOfBoundsException(
697 "Index: "+index+", Size: "+size);
700 public void disposeAndClear(EventObject evt)
702 Iterator aIt;
703 synchronized (this)
705 aIt= iterator();
706 // Release containers if new entries occur in disposing;
707 // set the member to null, the iterator delete the values
708 clear();
709 elementData= null;
710 size= 0;
712 if (aIt != null)
714 while( aIt.hasNext() )
718 Object o= aIt.next();
719 XEventListener evtListener= UnoRuntime.queryInterface(
720 XEventListener.class, o);
721 if( evtListener != null )
722 evtListener.disposing( evt );
724 catch ( RuntimeException e)
726 // be robust, if e.g. a remote bridge has disposed already.
727 // there is no way, to delegate the error to the caller :o(.
734 private class Itr implements Iterator
736 InterfaceContainer dataIt;
738 * Index of element to be returned by subsequent call to next.
740 int cursor= 0;
742 * Index of element returned by most recent call to next or
743 * previous. Reset to -1 if this element is deleted by a call
744 * to remove.
746 int lastRet = -1;
748 /** The object that has been returned by most recent call to next
749 * or previous. Reset to null if this element is deleted by a call
750 * to remove.
752 Object lastRetObj= null;
754 Itr(InterfaceContainer _data)
756 dataIt= _data;
759 synchronized public boolean hasNext()
761 return cursor !=dataIt.size();
764 public synchronized Object next()
768 Object next = dataIt.get(cursor);
769 lastRet = cursor++;
770 lastRetObj= next;
771 return next;
773 catch(java.lang.IndexOutOfBoundsException e)
775 java.util.NoSuchElementException ex2 = new java.util.NoSuchElementException();
776 ex2.initCause(e);
777 throw ex2;
781 /** Removes the interface from the list, that has been last returned by a
782 * call to next(). This is done according to the specification of the interface
783 * method. The element is also removed from InterfaceContainer but independent
784 * of the location. If the element is multiple times in InterfaceContainer then
785 * it is up to the java.util.ArrayList implementation what element is removed.
787 public synchronized void remove()
789 if (lastRet == -1)
790 throw new IllegalStateException();
791 // Remove the entry from InterfaceContainer.
792 InterfaceContainer.this.remove(lastRetObj);
793 dataIt.remove(lastRet);
795 if (lastRet < cursor)
796 cursor--;
797 lastRet = -1;
798 lastRetObj= null;
802 private class LstItr extends Itr implements ListIterator
805 LstItr(InterfaceContainer _data, int _index)
807 super(_data);
808 cursor= _index;
811 /** Inserts an element to the iterators list according to the specification
812 * of this interface method. The element is also added to InterfaceContainer
813 * but its location within the list cannot be guaranteed.
815 public synchronized void add(Object o)
817 InterfaceContainer.this.add(o);
818 dataIt.add(cursor++, o);
819 lastRet = -1;
820 lastRetObj= null;
823 synchronized public boolean hasPrevious()
825 return cursor != 0;
828 synchronized public int nextIndex()
830 return cursor;
833 public synchronized Object previous()
837 Object previous = dataIt.get(--cursor);
838 lastRet = cursor;
839 lastRetObj= previous;
840 return previous;
841 } catch(IndexOutOfBoundsException e)
843 java.util.NoSuchElementException ex2 = new java.util.NoSuchElementException();
844 ex2.initCause(e);
845 throw ex2;
849 synchronized public int previousIndex()
851 return cursor-1;
854 /** This is not possible since several iterators can modify InterfaceContainer
856 public synchronized void set(Object o)
858 throw new UnsupportedOperationException();
862 } // class LstItr