1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
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.
14  *
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).
20  *
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.
25  *
26  ************************************************************************/
27 
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;
36 
37 /**
38  * This class is a container for interfaces.
39  *
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.
46  *
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();
58  *
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
64  *
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>
72  *
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.
83  *
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).
96  */
97 public class InterfaceContainer implements Cloneable
98 {
99     final boolean DEBUG= false;
100     /**
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.
103      */
104     Object elementData[];
105 
106     /**
107      * The size of the ArrayList (the number of elements it contains).
108      *
109      * @serial
110      */
111     private int size;
112 
113 
114     //private ArrayList data= new ArrayList();
115     /** Creates a new instance of InterfaceContainer */
116     public InterfaceContainer()
117     {
118         this(10);
119     }
120     /**
121      * Constructs an empty list with the specified initial capacity.
122      *
123      * @param   initialCapacity   the initial capacity of the list.
124      * @exception IllegalArgumentException if the specified initial capacity
125      *            is negative
126      */
127     public InterfaceContainer(int initialCapacity)
128     {
129         if (initialCapacity < 0)
130             throw new java.lang.IllegalArgumentException("Illegal Capacity: "+
131             initialCapacity);
132         this.elementData = new Object[initialCapacity];
133     }
134 
135     /**
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.
139      */
140     synchronized public void trimToSize()
141     {
142         int oldCapacity = elementData.length;
143         if (size < oldCapacity)
144         {
145             Object oldData[] = elementData;
146             elementData = new Object[size];
147             System.arraycopy(oldData, 0, elementData, 0, size);
148         }
149     }
150 
151     /**
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.
155      *
156      * @param   minCapacity   the desired minimum capacity.
157      */
158     synchronized public void ensureCapacity(int minCapacity)
159     {
160         int oldCapacity = elementData.length;
161         if (minCapacity > oldCapacity)
162         {
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);
169         }
170     }
171 
172     /**
173      * Appends the specified element to the end of this list.
174      *
175      * @param o element to be appended to this list.
176      * @return <tt>true</tt> (as per the general contract of Collection.add).
177      */
178     synchronized public boolean add(Object o)
179     {
180         boolean ret= false;
181         if (elementData != null && o != null)
182         {
183             ensureCapacity(size + 1);  // Increments modCount!!
184             elementData[size++] = o;
185             ret= true;
186         }
187         return ret;
188     }
189 
190     /**
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).
194      *
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>.
199      */
200     synchronized public void add(int index, Object element)
201     {
202         if (elementData != null && element != null)
203         {
204             if (index > size || index < 0)
205                 throw new IndexOutOfBoundsException(
206                 "Index: "+index+", Size: "+size);
207 
208             ensureCapacity(size+1);
209             System.arraycopy(elementData, index, elementData, index + 1,
210             size - index);
211             elementData[index] = element;
212             size++;
213         }
214     }
215 
216 
217     /**
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.)
225      *
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>.
229      */
230     synchronized public boolean addAll(Collection c)
231     {
232         int numNew = c.size();
233         ensureCapacity(size + numNew);
234 
235         Iterator e = c.iterator();
236         for (int i=0; i<numNew; i++)
237         {
238             Object o= e.next();
239             if (o != null)
240                 elementData[size++] = o;
241         }
242         return numNew != 0;
243     }
244     /**
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.
251      *
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>.
257      */
258     synchronized public boolean addAll(int index, Collection c)
259     {
260         boolean ret= false;
261         if (elementData != null)
262         {
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++)
272             {
273                 Object o= icol.next();
274                 if (o != null)
275                     arColl[curIndex++]= o;
276             }
277             int numNew = curIndex;
278             ensureCapacity(size + numNew);  // Increments modCount!!
279 
280             int numMoved = size - index;
281             if (numMoved > 0)
282                 System.arraycopy(elementData, index, elementData, index + numNew,
283                 numMoved);
284 
285             for (int i=0; i<numNew; i++)
286             {
287                 elementData[index++]= arColl[i];
288             }
289             size += numNew;
290             ret= numNew != 0;
291         }
292         return ret;
293     }
294 
295     /**
296      * Removes all of the elements from this list.  The list will
297      * be empty after this call returns.
298      */
299     synchronized public void clear()
300     {
301         if (elementData != null)
302         {
303             // Let gc do its work
304             for (int i = 0; i < size; i++)
305                 elementData[i] = null;
306 
307             size = 0;
308         }
309     }
310     /**
311      * Returns <tt>true</tt> if this list contains the specified element.
312      *
313      * @param elem element whose presence in this List is to be tested.
314      */
315     synchronized public boolean contains(Object elem)
316     {
317         return indexOf(elem) >= 0;
318     }
319 
320     synchronized public boolean containsAll(Collection collection)
321     {
322         boolean retVal= true;
323         if (elementData != null && collection != null)
324         {
325             Iterator it= collection.iterator();
326             while (it.hasNext())
327             {
328                 Object obj= it.next();
329                 if (false == contains(obj))
330                 {
331                     retVal= false;
332                     break;
333                 }
334             }
335         }
336         return retVal;
337     }
338     /**
339      * Returns the element at the specified position in this list.
340      *
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>.
345      */
346     synchronized public Object get(int index)
347     {
348         if (elementData != null)
349         {
350             RangeCheck(index);
351             return elementData[index];
352         }
353         return null;
354     }
355 
356     /**
357      * Searches for the first occurence of the given argument, testing
358      * for equality using the <tt>equals</tt> method.
359      *
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)
364      */
365     synchronized public int indexOf(Object elem)
366     {
367         int index= -1;
368         if (elementData != null && elem != null)
369         {
370             for (int i = 0; i < size; i++)
371             {
372                 if (elem == elementData[i])
373                 {
374                     index= i;
375                     break;
376                 }
377             }
378 
379             if (index == -1)
380             {
381                 for (int i = 0; i < size; i++)
382                 {
383                     if (UnoRuntime.areSame(elem, elementData[i]))
384                     {
385                         index= i;
386                         break;
387                     }
388                 }
389             }
390         }
391         return index;
392     }
393     /**
394      * Tests if this list has no elements.
395      *
396      * @return  <tt>true</tt> if this list has no elements;
397      *          <tt>false</tt> otherwise.
398      */
399     synchronized public boolean isEmpty()
400     {
401         return size == 0;
402     }
403 
404     synchronized public Iterator iterator()
405     {
406         if (elementData != null)
407         {
408             InterfaceContainer aCopy= (InterfaceContainer) clone();
409             return new Itr(aCopy);
410         }
411         return null;
412     }
413     /**
414      * Returns the index of the last occurrence of the specified object in
415      * this list.
416      *
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.
420      */
421     synchronized public int lastIndexOf(Object elem)
422     {
423         int index= -1;
424         if (elementData != null && elem != null)
425         {
426             for (int i = size-1; i >= 0; i--)
427             {
428                 if (elem == elementData[i])
429                 {
430                     index= i;
431                     break;
432                 }
433             }
434             if (index == -1)
435             {
436                 for (int i = size-1; i >= 0; i--)
437                 {
438                     if (UnoRuntime.areSame(elem, elementData[i]))
439                     {
440                         index= i;
441                         break;
442                     }
443                 }
444             }
445         }
446         return index;
447     }
448 
449     /**
450      * Returns a shallow copy of this <tt>ArrayList</tt> instance. The contained
451      * references are copied but the objects not.
452      *
453      * @return  a clone of this <tt>List</tt> instance.
454      */
455     synchronized public Object clone()
456     {
457         Object ret= null;
458         if (elementData != null)
459         {
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;
465         }
466         return ret;
467     }
468     synchronized public ListIterator listIterator()
469     {
470         return listIterator(0);
471     }
472 
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.
476      */
477     synchronized public ListIterator listIterator(int index)
478     {
479         if (elementData != null)
480         {
481             InterfaceContainer aCopy= (InterfaceContainer) clone();
482             return new LstItr(aCopy, index);
483         }
484         return null;
485     }
486     /**
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).
490      *
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>.
495      */
496     synchronized public Object remove(int index)
497     {
498         Object ret= null;
499         if (elementData != null)
500         {
501             RangeCheck(index);
502             ret= elementData[index];
503 
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
509         }
510         return ret;
511     }
512 
513 
514     /** Parameter obj may  */
515     synchronized public boolean remove(Object obj)
516     {
517         boolean ret= false;
518         if (elementData != null && obj != null)
519         {
520             int index= indexOf(obj);
521             if (index != -1)
522             {
523                 ret= true;
524                 remove(index);
525             }
526         }
527         return ret;
528     }
529 
530     synchronized public boolean removeAll(Collection collection)
531     {
532         boolean retVal= false;
533         if (elementData != null && collection != null)
534         {
535             Iterator it= collection.iterator();
536             while (it.hasNext())
537             {
538                 Object obj= it.next();
539                 boolean bMod= remove( obj);
540                 if (bMod)
541                     retVal= true;
542             }
543         }
544         return retVal;
545     }
546 
547     synchronized public boolean retainAll(Collection collection)
548     {
549         boolean retVal= false;
550         if (elementData != null && collection != null)
551         {
552             // iterate over data
553             Object[] arRetained= new Object[size];
554             int indexRetained= 0;
555             for(int i= 0; i < size; i++)
556             {
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())
562                 {
563                     if (curElem == itColl.next())
564                     {
565                         // current element is in collection
566                         bExists= true;
567                         break;
568                     }
569                 }
570                 if (bExists == false)
571                 {
572                     itColl= collection.iterator();
573                     while (itColl.hasNext())
574                     {
575                         Object o= itColl.next();
576                         if (o != null)
577                         {
578                             if (UnoRuntime.areSame(o, curElem))
579                             {
580                                 bExists= true;
581                                 break;
582                             }
583                         }
584                     }
585                 }
586                 if (bExists == true)
587                     arRetained[indexRetained++]= curElem;
588             }
589             retVal= size != indexRetained;
590             if (indexRetained > 0)
591             {
592                 elementData= arRetained;
593                 size= indexRetained;
594             }
595         }
596         return retVal;
597     }
598 
599 
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>.
606      */
607     synchronized public Object set(int index, Object element)
608     {
609           Object ret= null;
610           if (elementData != null && element != null)
611           {
612               RangeCheck(index);
613               ret = elementData[index];
614               elementData[index] = element;
615           }
616           return ret;
617     }
618 
619     /**
620      * Returns the number of elements in this list.
621      *
622      * @return  the number of elements in this list.
623      */
624     synchronized public int size()
625     {
626         if (elementData != null)
627             return size;
628         return 0;
629     }
630 
631 
632     /**
633      * Returns an array containing all of the elements in this list
634      * in the correct order.
635      *
636      * @return an array containing all of the elements in this list
637      * 	       in the correct order.
638      */
639     synchronized public Object[] toArray()
640     {
641         if (elementData != null)
642         {
643             Object[] result = new Object[size];
644             System.arraycopy(elementData, 0, result, 0, size);
645             return result;
646         }
647         return null;
648     }
649 
650     /**
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>
656      *
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.
663      *
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.
670      */
671     synchronized public Object[] toArray(Object a[])
672     {
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);
678 
679         if (a.length > size)
680             a[size] = null;
681 
682         return a;
683     }
684 
685     /**
686      * Check if the given index is in range.  If not, throw an appropriate
687      * runtime exception.
688      */
689     private void RangeCheck(int index)
690     {
691         if (index >= size || index < 0)
692             throw new IndexOutOfBoundsException(
693             "Index: "+index+", Size: "+size);
694     }
695 
696     public void disposeAndClear(EventObject evt)
697     {
698         Iterator aIt;
699         synchronized (this)
700         {
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;
707         }
708         if (aIt != null)
709         {
710             while( aIt.hasNext() )
711             {
712                 try
713                 {
714                     Object o= aIt.next();
715                     XEventListener evtListener= UnoRuntime.queryInterface(
716                     XEventListener.class, o);
717                     if( evtListener != null )
718                         evtListener.disposing( evt );
719                 }
720                 catch ( RuntimeException e)
721                 {
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(.
724                 }
725             }
726         }
727     }
728 
729 
730     private class Itr implements Iterator
731     {
732         InterfaceContainer dataIt;
733         /**
734          * Index of element to be returned by subsequent call to next.
735          */
736         int cursor= 0;
737         /**
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.
741          */
742         int lastRet = -1;
743 
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.
747          */
748         Object lastRetObj= null;
749 
750         Itr(InterfaceContainer _data)
751         {
752             dataIt= _data;
753         }
754 
755         synchronized public boolean hasNext()
756         {
757             return cursor !=dataIt.size();
758         }
759 
760         public synchronized Object next()
761         {
762             try
763             {
764                 Object next = dataIt.get(cursor);
765                 lastRet = cursor++;
766                 lastRetObj= next;
767                 return next;
768             }
769             catch(java.lang.IndexOutOfBoundsException e)
770             {
771                 throw new java.util.NoSuchElementException();
772             }
773         }
774 
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.
780          */
781         public synchronized void remove()
782         {
783             if (lastRet == -1)
784                 throw new IllegalStateException();
785             // Remove the entry from InterfaceContainer.
786             InterfaceContainer.this.remove(lastRetObj);
787             dataIt.remove(lastRet);
788 
789             if (lastRet < cursor)
790                 cursor--;
791             lastRet = -1;
792             lastRetObj= null;
793         }
794     }
795 
796     private class LstItr extends Itr implements ListIterator
797     {
798 
799         LstItr(InterfaceContainer _data, int _index)
800         {
801             super(_data);
802             cursor= _index;
803         }
804 
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.
808          */
809         public synchronized void add(Object o)
810         {
811             InterfaceContainer.this.add(o);
812             dataIt.add(cursor++, o);
813             lastRet = -1;
814             lastRetObj= null;
815         }
816 
817         synchronized public boolean hasPrevious()
818         {
819             return cursor != 0;
820         }
821 
822         synchronized public int nextIndex()
823         {
824             return cursor;
825         }
826 
827         public synchronized Object previous()
828         {
829             try
830             {
831                 Object previous = dataIt.get(--cursor);
832                 lastRet = cursor;
833                 lastRetObj= previous;
834                 return previous;
835             } catch(IndexOutOfBoundsException e)
836             {
837                 throw new NoSuchElementException();
838             }
839         }
840 
841         synchronized public int previousIndex()
842         {
843             return cursor-1;
844         }
845 
846         /** This is not possible since several iterators can modify InterfaceContainer
847          */
848         public synchronized void set(Object o)
849         {
850             throw new UnsupportedOperationException();
851         }
852 
853 
854     } // class LstItr
855 }
856 
857