comparison NGSrich_0.5.5/src/org/jdom/ContentList.java @ 0:89ad0a9cca52 default tip

Uploaded
author pfrommolt
date Mon, 21 Nov 2011 08:12:19 -0500
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:89ad0a9cca52
1 /*--
2
3 $Id: ContentList.java,v 1.42 2007/11/10 05:28:58 jhunter Exp $
4
5 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
6 All rights reserved.
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions
10 are met:
11
12 1. Redistributions of source code must retain the above copyright
13 notice, this list of conditions, and the following disclaimer.
14
15 2. Redistributions in binary form must reproduce the above copyright
16 notice, this list of conditions, and the disclaimer that follows
17 these conditions in the documentation and/or other materials
18 provided with the distribution.
19
20 3. The name "JDOM" must not be used to endorse or promote products
21 derived from this software without prior written permission. For
22 written permission, please contact <request_AT_jdom_DOT_org>.
23
24 4. Products derived from this software may not be called "JDOM", nor
25 may "JDOM" appear in their name, without prior written permission
26 from the JDOM Project Management <request_AT_jdom_DOT_org).
27
28 In addition, we request (but do not require) that you include in the
29 end-user documentation provided with the redistribution and/or in the
30 software itself an acknowledgement equivalent to the following:
31 "This product includes software developed by the
32 JDOM Project (http://www.jdom.org/)."
33 Alternatively, the acknowledgment may be graphical using the logos
34 available at http://www.jdom.org/images/logos.
35
36 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
40 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 SUCH DAMAGE.
48
49 This software consists of voluntary contributions made by many
50 individuals on behalf of the JDOM Project and was originally
51 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
52 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
53 on the JDOM Project, please see <http://www.jdom.org/>.
54
55 */
56
57 package org.jdom;
58
59 import java.util.*;
60
61 import org.jdom.filter.*;
62
63 /**
64 * A non-public list implementation holding only legal JDOM content, including
65 * content for Document or Element nodes. Users see this class as a simple List
66 * implementation.
67 *
68 * @see CDATA
69 * @see Comment
70 * @see Element
71 * @see EntityRef
72 * @see ProcessingInstruction
73 * @see Text
74 *
75 * @version $Revision: 1.42 $, $Date: 2007/11/10 05:28:58 $
76 * @author Alex Rosen
77 * @author Philippe Riand
78 * @author Bradley S. Huffman
79 */
80 final class ContentList extends AbstractList implements java.io.Serializable {
81
82 private static final String CVS_ID =
83 "@(#) $RCSfile: ContentList.java,v $ $Revision: 1.42 $ $Date: 2007/11/10 05:28:58 $ $Name: jdom_1_1_1 $";
84
85 private static final long serialVersionUID = 1L;
86
87 private static final int INITIAL_ARRAY_SIZE = 5;
88
89 /** Our backing list */
90 private Content elementData[];
91 private int size;
92
93 /** Document or Element this list belongs to */
94 private Parent parent;
95
96 /** Force either a Document or Element parent */
97 ContentList(Parent parent) {
98 this.parent = parent;
99 }
100
101 /**
102 * Package internal method to support building from sources that are
103 * 100% trusted.
104 *
105 * @param c content to add without any checks
106 */
107 final void uncheckedAddContent(Content c) {
108 c.parent = parent;
109 ensureCapacity(size + 1);
110 elementData[size++] = c;
111 modCount++;
112 }
113
114 /**
115 * Inserts the specified object at the specified position in this list.
116 * Shifts the object currently at that position (if any) and any
117 * subsequent objects to the right (adds one to their indices).
118 *
119 * @param index The location to set the value to.
120 * @param obj The object to insert into the list.
121 * throws IndexOutOfBoundsException if index < 0 || index > size()
122 */
123 public void add(int index, Object obj) {
124 if (obj == null) {
125 throw new IllegalAddException("Cannot add null object");
126 }
127 if (obj instanceof String) { // String is OK to add as special case
128 obj = new Text(obj.toString()); // wrap it as a Content
129 }
130 if ((obj instanceof Content)) {
131 add(index, (Content) obj);
132 } else {
133 throw new IllegalAddException("Class " +
134 obj.getClass().getName() +
135 " is of unrecognized type and cannot be added");
136 }
137 }
138
139 /**
140 * @see org.jdom.ContentList#add(int, org.jdom.Content)
141 */
142 private void documentCanContain(int index, Content child) throws IllegalAddException {
143 if (child instanceof Element) {
144 if (indexOfFirstElement() >= 0) {
145 throw new IllegalAddException(
146 "Cannot add a second root element, only one is allowed");
147 }
148 if (indexOfDocType() > index) {
149 throw new IllegalAddException(
150 "A root element cannot be added before the DocType");
151 }
152 }
153 if (child instanceof DocType) {
154 if (indexOfDocType() >= 0) {
155 throw new IllegalAddException(
156 "Cannot add a second doctype, only one is allowed");
157 }
158 int firstElt = indexOfFirstElement();
159 if (firstElt != -1 && firstElt < index) {
160 throw new IllegalAddException(
161 "A DocType cannot be added after the root element");
162 }
163 }
164 if (child instanceof CDATA) {
165 throw new IllegalAddException("A CDATA is not allowed at the document root");
166 }
167
168 if (child instanceof Text) {
169 throw new IllegalAddException("A Text is not allowed at the document root");
170 }
171
172 if (child instanceof EntityRef) {
173 throw new IllegalAddException("An EntityRef is not allowed at the document root");
174 }
175 }
176
177 private static void elementCanContain(int index, Content child) throws IllegalAddException {
178 if (child instanceof DocType) {
179 throw new IllegalAddException(
180 "A DocType is not allowed except at the document level");
181 }
182 }
183
184 /**
185 * Check and add the <code>Element</code> to this list at
186 * the given index.
187 *
188 * @param index index where to add <code>Element</code>
189 * @param child <code>Element</code> to add
190 */
191 void add(int index, Content child) {
192 if (child == null) {
193 throw new IllegalAddException("Cannot add null object");
194 }
195 if (parent instanceof Document) {
196 documentCanContain(index, child);
197 }
198 else {
199 elementCanContain(index, child);
200 }
201
202 if (child.getParent() != null) {
203 Parent p = child.getParent();
204 if (p instanceof Document) {
205 throw new IllegalAddException((Element)child,
206 "The Content already has an existing parent document");
207 }
208 else {
209 throw new IllegalAddException(
210 "The Content already has an existing parent \"" +
211 ((Element)p).getQualifiedName() + "\"");
212 }
213 }
214
215 if (child == parent) {
216 throw new IllegalAddException(
217 "The Element cannot be added to itself");
218 }
219
220 // Detect if we have <a><b><c/></b></a> and c.add(a)
221 if ((parent instanceof Element && child instanceof Element) &&
222 ((Element) child).isAncestor((Element)parent)) {
223 throw new IllegalAddException(
224 "The Element cannot be added as a descendent of itself");
225 }
226
227 if (index<0 || index>size) {
228 throw new IndexOutOfBoundsException("Index: " + index +
229 " Size: " + size());
230 }
231
232 child.setParent(parent);
233
234 ensureCapacity(size+1);
235 if( index==size ) {
236 elementData[size++] = child;
237 } else {
238 System.arraycopy(elementData, index, elementData, index + 1, size - index);
239 elementData[index] = child;
240 size++;
241 }
242 modCount++;
243 }
244
245 /**
246 * Add the specified collecton to the end of this list.
247 *
248 * @param collection The collection to add to the list.
249 * @return <code>true</code> if the list was modified as a result of
250 * the add.
251 */
252 public boolean addAll(Collection collection) {
253 return addAll(size(), collection);
254 }
255
256 /**
257 * Inserts the specified collecton at the specified position in this list.
258 * Shifts the object currently at that position (if any) and any
259 * subsequent objects to the right (adds one to their indices).
260 *
261 * @param index The offset to start adding the data in the collection
262 * @param collection The collection to insert into the list.
263 * @return <code>true</code> if the list was modified as a result of
264 * the add.
265 * throws IndexOutOfBoundsException if index < 0 || index > size()
266 */
267 public boolean addAll(int index, Collection collection) {
268 if (index<0 || index>size) {
269 throw new IndexOutOfBoundsException("Index: " + index +
270 " Size: " + size());
271 }
272
273 if ((collection == null) || (collection.size() == 0)) {
274 return false;
275 }
276 ensureCapacity(size() + collection.size());
277
278 int count = 0;
279 try {
280 Iterator i = collection.iterator();
281 while (i.hasNext()) {
282 Object obj = i.next();
283 add(index + count, obj);
284 count++;
285 }
286 }
287 catch (RuntimeException exception) {
288 for (int i = 0; i < count; i++) {
289 remove(index);
290 }
291 throw exception;
292 }
293
294 return true;
295 }
296
297 /**
298 * Clear the current list.
299 */
300 public void clear() {
301 if (elementData != null) {
302 for (int i = 0; i < size; i++) {
303 Content obj = elementData[i];
304 removeParent(obj);
305 }
306 elementData = null;
307 size = 0;
308 }
309 modCount++;
310 }
311
312 /**
313 * Clear the current list and set it to the contents
314 * of the <code>Collection</code>.
315 * object.
316 *
317 * @param collection The collection to use.
318 */
319 void clearAndSet(Collection collection) {
320 Content[] old = elementData;
321 int oldSize = size;
322
323 elementData = null;
324 size = 0;
325
326 if ((collection != null) && (collection.size() != 0)) {
327 ensureCapacity(collection.size());
328 try {
329 addAll(0, collection);
330 }
331 catch (RuntimeException exception) {
332 elementData = old;
333 size = oldSize;
334 throw exception;
335 }
336 }
337
338 if (old != null) {
339 for (int i = 0; i < oldSize; i++) {
340 removeParent(old[i]);
341 }
342 }
343 modCount++;
344 }
345
346 /**
347 * Increases the capacity of this <code>ContentList</code> instance,
348 * if necessary, to ensure that it can hold at least the number of
349 * items specified by the minimum capacity argument.
350 *
351 * @param minCapacity the desired minimum capacity.
352 */
353 void ensureCapacity(int minCapacity) {
354 if( elementData==null ) {
355 elementData = new Content[Math.max(minCapacity, INITIAL_ARRAY_SIZE)];
356 } else {
357 int oldCapacity = elementData.length;
358 if (minCapacity > oldCapacity) {
359 Object oldData[] = elementData;
360 int newCapacity = (oldCapacity * 3)/2 + 1;
361 if (newCapacity < minCapacity)
362 newCapacity = minCapacity;
363 elementData = new Content[newCapacity];
364 System.arraycopy(oldData, 0, elementData, 0, size);
365 }
366 }
367 }
368
369 /**
370 * Return the object at the specified offset.
371 *
372 * @param index The offset of the object.
373 * @return The Object which was returned.
374 */
375 public Object get(int index) {
376 if (index<0 || index>=size) {
377 throw new IndexOutOfBoundsException("Index: " + index +
378 " Size: " + size());
379 }
380 return elementData[index];
381 }
382
383 /**
384 * Return a view of this list based on the given filter.
385 *
386 * @param filter <code>Filter</code> for this view.
387 * @return a list representing the rules of the <code>Filter</code>.
388 */
389 List getView(Filter filter) {
390 return new FilterList(filter);
391 }
392
393 /**
394 * Return the index of the first Element in the list. If the parent
395 * is a <code>Document</code> then the element is the root element.
396 * If the list contains no Elements, it returns -1.
397 *
398 * @return index of first element, or -1 if one doesn't exist
399 */
400 int indexOfFirstElement() {
401 if( elementData!=null ) {
402 for (int i = 0; i < size; i++) {
403 if (elementData[i] instanceof Element) {
404 return i;
405 }
406 }
407 }
408 return -1;
409 }
410
411 /**
412 * Return the index of the DocType element in the list. If the list contains
413 * no DocType, it returns -1.
414 *
415 * @return index of the DocType, or -1 if it doesn't
416 * exist
417 */
418 int indexOfDocType() {
419 if (elementData != null) {
420 for (int i = 0; i < size; i++) {
421 if (elementData[i] instanceof DocType) {
422 return i;
423 }
424 }
425 }
426 return -1;
427 }
428
429 /**
430 * Remove the object at the specified offset.
431 *
432 * @param index The offset of the object.
433 * @return The Object which was removed.
434 */
435 public Object remove(int index) {
436 if (index<0 || index>=size)
437 throw new IndexOutOfBoundsException("Index: " + index +
438 " Size: " + size());
439
440 Content old = elementData[index];
441 removeParent(old);
442 int numMoved = size - index - 1;
443 if (numMoved > 0)
444 System.arraycopy(elementData, index+1, elementData, index,numMoved);
445 elementData[--size] = null; // Let gc do its work
446 modCount++;
447 return old;
448 }
449
450
451 /** Remove the parent of a Object */
452 private static void removeParent(Content c) {
453 c.setParent(null);
454 }
455
456 /**
457 * Set the object at the specified location to the supplied
458 * object.
459 *
460 * @param index The location to set the value to.
461 * @param obj The location to set the value to.
462 * @return The object which was replaced.
463 * throws IndexOutOfBoundsException if index < 0 || index >= size()
464 */
465 public Object set(int index, Object obj) {
466 if (index<0 || index>=size)
467 throw new IndexOutOfBoundsException("Index: " + index +
468 " Size: " + size());
469
470 if ((obj instanceof Element) && (parent instanceof Document)) {
471 int root = indexOfFirstElement();
472 if ((root >= 0) && (root != index)) {
473 throw new IllegalAddException(
474 "Cannot add a second root element, only one is allowed");
475 }
476 }
477
478 if ((obj instanceof DocType) && (parent instanceof Document)) {
479 int docTypeIndex = indexOfDocType();
480 if ((docTypeIndex >= 0) && (docTypeIndex != index)) {
481 throw new IllegalAddException(
482 "Cannot add a second doctype, only one is allowed");
483 }
484 }
485
486 Object old = remove(index);
487 try {
488 add(index, obj);
489 }
490 catch (RuntimeException exception) {
491 add(index, old);
492 throw exception;
493 }
494 return old;
495 }
496
497 /**
498 * Return the number of items in this list
499 *
500 * @return The number of items in this list.
501 */
502 public int size() {
503 return size;
504 }
505
506 /**
507 * Return this list as a <code>String</code>
508 *
509 * @return The number of items in this list.
510 */
511 public String toString() {
512 return super.toString();
513 }
514
515 /** Give access of ContentList.modCount to FilterList */
516 private int getModCount() {
517 return modCount;
518 }
519
520 /* * * * * * * * * * * * * FilterList * * * * * * * * * * * * * * * */
521 /* * * * * * * * * * * * * FilterList * * * * * * * * * * * * * * * */
522
523 /**
524 * <code>FilterList</code> represents legal JDOM content, including content
525 * for <code>Document</code>s or <code>Element</code>s.
526 */
527
528 class FilterList extends AbstractList implements java.io.Serializable {
529
530 /** The Filter */
531 Filter filter;
532
533 /** Current number of items in this view */
534 int count = 0;
535
536 /** Expected modCount in our backing list */
537 int expected = -1;
538
539 // Implementation Note: Directly after size() is called, expected
540 // is sync'd with ContentList.modCount and count provides
541 // the true size of this view. Before the first call to
542 // size() or if the backing list is modified outside this
543 // FilterList, both might contain bogus values and should
544 // not be used without first calling size();
545
546 /**
547 * Create a new instance of the FilterList with the specified Filter.
548 */
549 FilterList(Filter filter) {
550 this.filter = filter;
551 }
552
553 /**
554 * Inserts the specified object at the specified position in this list.
555 * Shifts the object currently at that position (if any) and any
556 * subsequent objects to the right (adds one to their indices).
557 *
558 * @param index The location to set the value to.
559 * @param obj The object to insert into the list.
560 * throws IndexOutOfBoundsException if index < 0 || index > size()
561 */
562 public void add(int index, Object obj) {
563 if (filter.matches(obj)) {
564 int adjusted = getAdjustedIndex(index);
565 ContentList.this.add(adjusted, obj);
566 expected++;
567 count++;
568 }
569 else throw new IllegalAddException("Filter won't allow the " +
570 obj.getClass().getName() +
571 " '" + obj + "' to be added to the list");
572 }
573
574 /**
575 * Return the object at the specified offset.
576 *
577 * @param index The offset of the object.
578 * @return The Object which was returned.
579 */
580 public Object get(int index) {
581 int adjusted = getAdjustedIndex(index);
582 return ContentList.this.get(adjusted);
583 }
584
585 public Iterator iterator() {
586 return new FilterListIterator(filter, 0);
587 }
588
589 public ListIterator listIterator() {
590 return new FilterListIterator(filter, 0);
591 }
592
593 public ListIterator listIterator(int index) {
594 return new FilterListIterator(filter, index);
595 }
596
597 /**
598 * Remove the object at the specified offset.
599 *
600 * @param index The offset of the object.
601 * @return The Object which was removed.
602 */
603 public Object remove(int index) {
604 int adjusted = getAdjustedIndex(index);
605 Object old = ContentList.this.get(adjusted);
606 if (filter.matches(old)) {
607 old = ContentList.this.remove(adjusted);
608 expected++;
609 count--;
610 }
611 else {
612 throw new IllegalAddException("Filter won't allow the " +
613 (old.getClass()).getName() +
614 " '" + old + "' (index " + index +
615 ") to be removed");
616 }
617 return old;
618 }
619
620 /**
621 * Set the object at the specified location to the supplied
622 * object.
623 *
624 * @param index The location to set the value to.
625 * @param obj The location to set the value to.
626 * @return The object which was replaced.
627 * throws IndexOutOfBoundsException if index < 0 || index >= size()
628 */
629 public Object set(int index, Object obj) {
630 Object old = null;
631 if (filter.matches(obj)) {
632 int adjusted = getAdjustedIndex(index);
633 old = ContentList.this.get(adjusted);
634 if (!filter.matches(old)) {
635 throw new IllegalAddException("Filter won't allow the " +
636 (old.getClass()).getName() +
637 " '" + old + "' (index " + index +
638 ") to be removed");
639 }
640 old = ContentList.this.set(adjusted, obj);
641 expected += 2;
642 }
643 else {
644 throw new IllegalAddException("Filter won't allow index " +
645 index + " to be set to " +
646 (obj.getClass()).getName());
647 }
648 return old;
649 }
650
651 /**
652 * Return the number of items in this list
653 *
654 * @return The number of items in this list.
655 */
656 public int size() {
657 // Implementation Note: Directly after size() is called, expected
658 // is sync'd with ContentList.modCount and count provides
659 // the true size of this view. Before the first call to
660 // size() or if the backing list is modified outside this
661 // FilterList, both might contain bogus values and should
662 // not be used without first calling size();
663
664 if (expected == ContentList.this.getModCount()) {
665 return count;
666 }
667
668 count = 0;
669 for (int i = 0; i < ContentList.this.size(); i++) {
670 Object obj = ContentList.this.elementData[i];
671 if (filter.matches(obj)) {
672 count++;
673 }
674 }
675 expected = ContentList.this.getModCount();
676 return count;
677 }
678
679 /**
680 * Return the adjusted index
681 *
682 * @param index Index of in this view.
683 * @return True index in backing list
684 */
685 final private int getAdjustedIndex(int index) {
686 int adjusted = 0;
687 for (int i = 0; i < ContentList.this.size; i++) {
688 Object obj = ContentList.this.elementData[i];
689 if (filter.matches(obj)) {
690 if (index == adjusted) {
691 return i;
692 }
693 adjusted++;
694 }
695 }
696
697 if (index == adjusted) {
698 return ContentList.this.size;
699 }
700
701 return ContentList.this.size + 1;
702 }
703 }
704
705 /* * * * * * * * * * * * * FilterListIterator * * * * * * * * * * * */
706 /* * * * * * * * * * * * * FilterListIterator * * * * * * * * * * * */
707
708 class FilterListIterator implements ListIterator {
709
710 /** The Filter that applies */
711 Filter filter;
712
713 /** Whether this iterator is in forward or reverse. */
714 private boolean forward = false;
715 /** Whether a call to remove() is valid */
716 private boolean canremove = false;
717 /** Whether a call to set() is valid */
718 private boolean canset = false;
719
720 /** Index in backing list of next object */
721 private int cursor = -1;
722 /** the backing index to use if we actually DO move */
723 private int tmpcursor = -1;
724 /** Index in ListIterator */
725 private int index = -1;
726
727 /** Expected modCount in our backing list */
728 private int expected = -1;
729
730 /** Number of elements matching the filter. */
731 private int fsize = 0;
732
733 /**
734 * Default constructor
735 */
736 FilterListIterator(Filter filter, int start) {
737 this.filter = filter;
738 expected = ContentList.this.getModCount();
739 // always start list iterators in backward mode ....
740 // it makes sense... really.
741 forward = false;
742
743 if (start < 0) {
744 throw new IndexOutOfBoundsException("Index: " + start);
745 }
746
747 // the number of matching elements....
748 fsize = 0;
749
750 // go through the list, count the matching elements...
751 for (int i = 0; i < ContentList.this.size(); i++) {
752 if (filter.matches(ContentList.this.get(i))) {
753 if (start == fsize) {
754 // set the back-end cursor to the matching element....
755 cursor = i;
756 // set the front-end cursor too.
757 index = fsize;
758 }
759 fsize++;
760 }
761 }
762
763 if (start > fsize) {
764 throw new IndexOutOfBoundsException("Index: " + start + " Size: " + fsize);
765 }
766 if (cursor == -1) {
767 // implies that start == fsize (i.e. after the last element
768 // put the insertion point at the end of the Underlying
769 // content list ....
770 // i.e. an add() at this point may potentially end up with
771 // filtered content between previous() and next()
772 // the alternative is to put the cursor on the Content after
773 // the last Content that the filter passed
774 // The implications are ambiguous.
775 cursor = ContentList.this.size();
776 index = fsize;
777 }
778
779 }
780
781 /**
782 * Returns <code>true</code> if this list iterator has a next element.
783 */
784 public boolean hasNext() {
785 return nextIndex() < fsize;
786 }
787
788 /**
789 * Returns the next element in the list.
790 */
791 public Object next() {
792 if (!hasNext())
793 throw new NoSuchElementException("next() is beyond the end of the Iterator");
794 index = nextIndex();
795 cursor = tmpcursor;
796 forward = true;
797 canremove = true;
798 canset = true;
799 return ContentList.this.get(cursor);
800 }
801
802 /**
803 * Returns <code>true</code> if this list iterator has more elements
804 * when traversing the list in the reverse direction.
805 */
806 public boolean hasPrevious() {
807 return previousIndex() >= 0;
808 }
809
810 /**
811 * Returns the previous element in the list.
812 */
813 public Object previous() {
814 if (!hasPrevious())
815 throw new NoSuchElementException("previous() is before the start of the Iterator");
816 index = previousIndex();
817 cursor = tmpcursor;
818 forward = false;
819 canremove = true;
820 canset = true;
821 return ContentList.this.get(cursor);
822 }
823
824 /**
825 * Returns the index of the element that would be returned by a
826 * subsequent call to <code>next</code>.
827 */
828 public int nextIndex() {
829 checkConcurrentModification();
830 if (forward) {
831 // Starting with next possibility ....
832 for (int i = cursor + 1; i < ContentList.this.size(); i++) {
833 if (filter.matches(ContentList.this.get(i))) {
834 tmpcursor = i;
835 return index + 1;
836 }
837 }
838 // Never found another match.... put the insertion point at
839 // the end of the list....
840 tmpcursor = ContentList.this.size();
841 return index + 1;
842 }
843
844 // We've been going back... so nextIndex() returns the same
845 // element.
846 tmpcursor = cursor;
847 return index;
848 }
849
850 /**
851 * Returns the index of the element that would be returned by a
852 * subsequent call to <code>previous</code>. (Returns -1 if the
853 * list iterator is at the beginning of the list.)
854 */
855 public int previousIndex() {
856 checkConcurrentModification();
857 if (!forward) {
858 // starting with next possibility ....
859 for (int i = cursor - 1; i >= 0; i--) {
860 if (filter.matches(ContentList.this.get(i))) {
861 tmpcursor = i;
862 return index - 1;
863 }
864 }
865 // Never found another match.... put the insertion point at
866 // the start of the list....
867 tmpcursor = -1;
868 return index - 1;
869 }
870
871 // We've been going forwards... so previousIndex() returns same
872 // element.
873 tmpcursor = cursor;
874 return index;
875 }
876
877 /**
878 * Inserts the specified element into the list.
879 */
880 public void add(Object obj) {
881 // Call to nextIndex() will check concurrent.
882 nextIndex();
883 // tmpcursor is the backing cursor of the next element
884 // Remember that List.add(index,obj) is really an insert....
885 ContentList.this.add(tmpcursor, obj);
886 forward = true;
887 expected = ContentList.this.getModCount();
888 canremove = canset = false;
889 index = nextIndex();
890 cursor = tmpcursor;
891 fsize++;
892 }
893
894 /**
895 * Removes from the list the last element that was returned by
896 * the last call to <code>next</code> or <code>previous</code>.
897 */
898 public void remove() {
899 if (!canremove)
900 throw new IllegalStateException("Can not remove an "
901 + "element unless either next() or previous() has been called "
902 + "since the last remove()");
903 nextIndex(); // to get out cursor ...
904 ContentList.this.remove(cursor);
905 cursor = tmpcursor - 1;
906 expected = ContentList.this.getModCount();
907
908 forward = false;
909 canremove = false;
910 canset = false;
911 fsize--;
912 }
913
914 /**
915 * Replaces the last element returned by <code>next</code> or
916 * <code>previous</code> with the specified element.
917 */
918 public void set(Object obj) {
919 if (!canset)
920 throw new IllegalStateException("Can not set an element "
921 + "unless either next() or previous() has been called since the "
922 + "last remove() or set()");
923 checkConcurrentModification();
924
925 if (!filter.matches(obj)) {
926 throw new IllegalAddException("Filter won't allow index " + index + " to be set to "
927 + (obj.getClass()).getName());
928 }
929
930 ContentList.this.set(cursor, obj);
931 expected = ContentList.this.getModCount();
932
933 }
934
935 /**
936 * Check if are backing list is being modified by someone else.
937 */
938 private void checkConcurrentModification() {
939 if (expected != ContentList.this.getModCount()) {
940 throw new ConcurrentModificationException();
941 }
942 }
943 }
944 }