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 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;
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
];
124 private InterfaceContainer(Object
[] 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
)
175 if (elementData
!= null && o
!= null)
177 ensureCapacity(size
+ 1); // Increments modCount!!
178 elementData
[size
++] = o
;
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 < 0 || index > 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,
205 elementData
[index
] = element
;
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
220 * @param c the elements to be inserted into this list.
221 * @throws IndexOutOfBoundsException if index out of range <code>(index
222 * < 0 || index > 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
++)
235 elementData
[size
++] = o
;
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 * < 0 || index > size())</code>.
252 * @return true if an element was inserted.
254 synchronized public boolean addAll(int index
, Collection c
)
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();
267 for (int i
=0; i
< sizeCol
; i
++)
269 Object o
= icol
.next();
271 arColl
[curIndex
++]= o
;
273 int numNew
= curIndex
;
274 ensureCapacity(size
+ numNew
); // Increments modCount!!
276 int numMoved
= size
- index
;
278 System
.arraycopy(elementData
, index
, elementData
, index
+ numNew
,
281 for (int i
=0; i
<numNew
; i
++)
283 elementData
[index
++]= arColl
[i
];
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;
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();
325 Object obj
= it
.next();
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 * < 0 || index >= size())</code>.
343 synchronized public Object
get(int index
)
345 if (elementData
!= null)
348 return elementData
[index
];
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) {
370 for (int i
= 0; i
< size
; i
++)
372 if (elem
== elementData
[i
])
381 for (int i
= 0; i
< size
; i
++)
383 if (UnoRuntime
.areSame(elem
, elementData
[i
]))
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()
403 synchronized public Iterator
iterator()
405 if (elementData
!= null)
407 InterfaceContainer aCopy
= (InterfaceContainer
) clone();
408 return new Itr(aCopy
);
413 * Returns the index of the last occurrence of the specified object in
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) {
428 for (int i
= size
-1; i
>= 0; i
--)
430 if (elem
== elementData
[i
])
438 for (int i
= size
-1; i
>= 0; i
--)
440 if (UnoRuntime
.areSame(elem
, elementData
[i
]))
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.
457 synchronized public Object
clone()
460 if (elementData
== null) {
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
);
489 * Removes the element at the specified position in this list.
490 * Shifts any subsequent elements to the left (subtracts one from their
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 * < 0 || index >= size())</code>.
498 synchronized public Object
remove(int index
)
501 if (elementData
!= null)
504 ret
= elementData
[index
];
506 int numMoved
= size
- index
- 1;
508 System
.arraycopy(elementData
, index
+1, elementData
, index
,
510 elementData
[--size
] = null; // Let gc do its work
516 /** Parameter obj may... or may not. What did the original author want
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
)
524 if (elementData
!= null && obj
!= null)
526 int index
= indexOf(obj
);
536 synchronized public boolean removeAll(Collection collection
)
538 boolean retVal
= false;
539 if (elementData
!= null && collection
!= null)
541 Iterator it
= collection
.iterator();
544 Object obj
= it
.next();
545 boolean bMod
= remove( obj
);
553 synchronized public boolean retainAll(Collection collection
)
555 if (elementData
== null || collection
== null) {
559 boolean retVal
= false;
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
580 itColl
= collection
.iterator();
581 while (itColl
.hasNext())
583 Object o
= itColl
.next();
584 if (o
!= null && UnoRuntime
.areSame(o
, curElem
))
592 arRetained
[indexRetained
++]= curElem
;
594 retVal
= size
!= indexRetained
;
595 if (indexRetained
> 0)
597 elementData
= arRetained
;
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 < 0 || index >= size())</code>.
611 synchronized public Object
set(int index
, Object element
)
614 if (elementData
!= null && element
!= null)
617 ret
= elementData
[index
];
618 elementData
[index
] = element
;
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)
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
);
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
[])
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
);
690 * Check if the given index is in range. If not, throw an appropriate
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
)
706 // Release containers if new entries occur in disposing;
707 // set the member to null, the iterator delete the values
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.
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
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
752 Object lastRetObj
= null;
754 Itr(InterfaceContainer _data
)
759 synchronized public boolean hasNext()
761 return cursor
!=dataIt
.size();
764 public synchronized Object
next()
768 Object next
= dataIt
.get(cursor
);
773 catch(java
.lang
.IndexOutOfBoundsException e
)
775 java
.util
.NoSuchElementException ex2
= new java
.util
.NoSuchElementException();
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()
790 throw new IllegalStateException();
791 // Remove the entry from InterfaceContainer.
792 InterfaceContainer
.this.remove(lastRetObj
);
793 dataIt
.remove(lastRet
);
795 if (lastRet
< cursor
)
802 private class LstItr
extends Itr
implements ListIterator
805 LstItr(InterfaceContainer _data
, int _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
);
823 synchronized public boolean hasPrevious()
828 synchronized public int nextIndex()
833 public synchronized Object
previous()
837 Object previous
= dataIt
.get(--cursor
);
839 lastRetObj
= previous
;
841 } catch(IndexOutOfBoundsException e
)
843 java
.util
.NoSuchElementException ex2
= new java
.util
.NoSuchElementException();
849 synchronized public int previousIndex()
854 /** This is not possible since several iterators can modify InterfaceContainer
856 public synchronized void set(Object o
)
858 throw new UnsupportedOperationException();