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
;
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
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.
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
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;
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.
99 * The size of the ArrayList (the number of elements it contains).
104 /** Creates a new instance of InterfaceContainer */
105 public InterfaceContainer()
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
116 public InterfaceContainer(int initialCapacity
)
118 if (initialCapacity
< 0)
119 throw new java
.lang
.IllegalArgumentException("Illegal Capacity: "+
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
)
170 if (elementData
!= null && o
!= null)
172 ensureCapacity(size
+ 1); // Increments modCount!!
173 elementData
[size
++] = o
;
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 < 0 || index > 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,
200 elementData
[index
] = element
;
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
215 * @param c the elements to be inserted into this list.
216 * @throws IndexOutOfBoundsException if index out of range <tt>(index
217 * < 0 || index > 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
++)
229 elementData
[size
++] = o
;
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 * < 0 || index > size())</tt>.
247 synchronized public boolean addAll(int index
, Collection c
)
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();
260 for (int i
=0; i
< sizeCol
; i
++)
262 Object o
= icol
.next();
264 arColl
[curIndex
++]= o
;
266 int numNew
= curIndex
;
267 ensureCapacity(size
+ numNew
); // Increments modCount!!
269 int numMoved
= size
- index
;
271 System
.arraycopy(elementData
, index
, elementData
, index
+ numNew
,
274 for (int i
=0; i
<numNew
; i
++)
276 elementData
[index
++]= arColl
[i
];
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;
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();
317 Object obj
= it
.next();
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 * < 0 || index >= size())</tt>.
335 synchronized public Object
get(int index
)
337 if (elementData
!= null)
340 return elementData
[index
];
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) {
362 for (int i
= 0; i
< size
; i
++)
364 if (elem
== elementData
[i
])
373 for (int i
= 0; i
< size
; i
++)
375 if (UnoRuntime
.areSame(elem
, elementData
[i
]))
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()
395 synchronized public Iterator
iterator()
397 if (elementData
!= null)
399 InterfaceContainer aCopy
= (InterfaceContainer
) clone();
400 return new Itr(aCopy
);
405 * Returns the index of the last occurrence of the specified object in
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) {
420 for (int i
= size
-1; i
>= 0; i
--)
422 if (elem
== elementData
[i
])
430 for (int i
= size
-1; i
>= 0; i
--)
432 if (UnoRuntime
.areSame(elem
, elementData
[i
]))
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.
449 synchronized public Object
clone()
452 if (elementData
!= null)
454 InterfaceContainer cont
= new InterfaceContainer();
455 cont
.elementData
= new Object
[size
];
457 System
.arraycopy(elementData
, 0, cont
.elementData
, 0, size
);
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
);
481 * Removes the element at the specified position in this list.
482 * Shifts any subsequent elements to the left (subtracts one from their
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 * < 0 || index >= size())</tt>.
490 synchronized public Object
remove(int index
)
493 if (elementData
!= null)
496 ret
= elementData
[index
];
498 int numMoved
= size
- index
- 1;
500 System
.arraycopy(elementData
, index
+1, elementData
, index
,
502 elementData
[--size
] = null; // Let gc do its work
508 /** Parameter obj may */
509 synchronized public boolean remove(Object obj
)
512 if (elementData
!= null && obj
!= null)
514 int index
= indexOf(obj
);
524 synchronized public boolean removeAll(Collection collection
)
526 boolean retVal
= false;
527 if (elementData
!= null && collection
!= null)
529 Iterator it
= collection
.iterator();
532 Object obj
= it
.next();
533 boolean bMod
= remove( obj
);
541 synchronized public boolean retainAll(Collection collection
)
543 if (elementData
== null || collection
== null) {
547 boolean retVal
= false;
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
568 itColl
= collection
.iterator();
569 while (itColl
.hasNext())
571 Object o
= itColl
.next();
574 if (UnoRuntime
.areSame(o
, curElem
))
583 arRetained
[indexRetained
++]= curElem
;
585 retVal
= size
!= indexRetained
;
586 if (indexRetained
> 0)
588 elementData
= arRetained
;
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 < 0 || index >= size())</tt>.
602 synchronized public Object
set(int index
, Object element
)
605 if (elementData
!= null && element
!= null)
608 ret
= elementData
[index
];
609 elementData
[index
] = element
;
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)
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
);
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
[])
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
);
681 * Check if the given index is in range. If not, throw an appropriate
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
)
697 // Container freigeben, falls im disposing neue Eintraege kommen
698 // set the member to null, the iterator delete the values
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.
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
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
743 Object lastRetObj
= null;
745 Itr(InterfaceContainer _data
)
750 synchronized public boolean hasNext()
752 return cursor
!=dataIt
.size();
755 public synchronized Object
next()
759 Object next
= dataIt
.get(cursor
);
764 catch(java
.lang
.IndexOutOfBoundsException e
)
766 java
.util
.NoSuchElementException ex2
= new java
.util
.NoSuchElementException();
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()
781 throw new IllegalStateException();
782 // Remove the entry from InterfaceContainer.
783 InterfaceContainer
.this.remove(lastRetObj
);
784 dataIt
.remove(lastRet
);
786 if (lastRet
< cursor
)
793 private class LstItr
extends Itr
implements ListIterator
796 LstItr(InterfaceContainer _data
, int _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
);
814 synchronized public boolean hasPrevious()
819 synchronized public int nextIndex()
824 public synchronized Object
previous()
828 Object previous
= dataIt
.get(--cursor
);
830 lastRetObj
= previous
;
832 } catch(IndexOutOfBoundsException e
)
834 java
.util
.NoSuchElementException ex2
= new java
.util
.NoSuchElementException();
840 synchronized public int previousIndex()
845 /** This is not possible since several iterators can modify InterfaceContainer
847 public synchronized void set(Object o
)
849 throw new UnsupportedOperationException();