File: EventListIterator.java

package info (click to toggle)
libglazedlists-java 1.9.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 3,024 kB
  • ctags: 4,252
  • sloc: java: 22,561; xml: 818; sh: 51; makefile: 5
file content (197 lines) | stat: -rw-r--r-- 6,598 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/* Glazed Lists                                                 (c) 2003-2006 */
/* http://publicobject.com/glazedlists/                      publicobject.com,*/
/*                                                     O'Dell Engineering Ltd.*/
package ca.odell.glazedlists.impl;

// the core Glazed Lists package
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.GlazedLists;
import ca.odell.glazedlists.event.ListEvent;
import ca.odell.glazedlists.event.ListEventListener;

import java.util.ListIterator;
import java.util.NoSuchElementException;

/**
 * The EventListIterator is an iterator that allows the user to iterate
 * on a list <i>that may be changed while it is iterated</i>. This is
 * possible because the iterator is a listener for change events to the
 * source list.
 *
 * <p>This iterator simply keeps an index of where it is and what it last
 * saw. It knows nothing about the underlying storage performance of the List
 * that it iterates, and therefore provides generic, possibly slow access
 * to its elements.
 *
 * @author <a href="mailto:jesse@swank.ca">Jesse Wilson</a>
 */
public class EventListIterator<E> implements ListIterator<E>, ListEventListener<E> {

    /** the list being iterated */
    private EventList<E> source;

    /** the index of the next element to view */
    private int nextIndex;

    /** the most recently accessed element */
    private int lastIndex = -1;

    /**
     * Create a new event list iterator that iterates over the specified
     * source list.
     *
     * @param source the list to iterate
     */
    public EventListIterator(EventList<E> source) {
        this(source, 0, true);
    }

    /**
     * Creates a new iterator that starts at the specified index.
     *
     * @param source the list to iterate
     * @param nextIndex the starting point within the list
     */
    public EventListIterator(EventList<E> source, int nextIndex) {
        this(source, nextIndex, true);
    }

    /**
     * Creates a new iterator that starts at the specified index.
     *
     * @param source the list to iterate
     * @param nextIndex the starting point within the list
     * @param automaticallyRemove true if this SubList should deregister itself
     *      from the ListEventListener list of the source list once it is
     *      otherwise out of scope.
     *
     * @see GlazedLists#weakReferenceProxy(EventList, ListEventListener)
     */
    public EventListIterator(EventList<E> source, int nextIndex, boolean automaticallyRemove) {
        this.source = source;
        this.nextIndex = nextIndex;

        // listen directly or via a proxy that will do garbage collection
        if(automaticallyRemove) {
            ListEventListener<E> gcProxy = new WeakReferenceProxy<E>(source, this);
            source.addListEventListener(gcProxy);
            // do not manage dependencies for iterators, they never have multiple sources
            source.getPublisher().removeDependency(source, gcProxy);

        } else {
            source.addListEventListener(this);
            // do not manage dependencies for iterators, they never have multiple sources
            source.getPublisher().removeDependency(source, this);
        }
    }

    /**
     * Returns true if this list iterator has more elements when traversing the
     * list in the forward direction.
     */
    public boolean hasNext() {
        return nextIndex < source.size();
    }

    /**
     * Returns the next element in the list.
     */
    public E next() {
        // next shouldn't have been called.
        if(nextIndex == source.size()) {
           throw new NoSuchElementException("Cannot retrieve element " + nextIndex + " on a list of size " + source.size());

        // when next has not been removed
        } else {
            lastIndex = nextIndex;
            nextIndex++;
            return source.get(lastIndex);
        }
    }

    /**
     * Returns the index of the element that would be returned by a subsequent call to next.
     */
    public int nextIndex() {
        return nextIndex;
    }

    /**
     * Returns true if this list iterator has more elements when traversing the
     * list in the reverse direction.
     */
    public boolean hasPrevious() {
        return nextIndex > 0;
    }

    /**
     * Returns the previous element in the list.
     */
    public E previous() {
        // previous shouldn't have been called
        if(nextIndex == 0) {
            throw new NoSuchElementException("Cannot retrieve element " + nextIndex + " on a list of size " + source.size());

        // when previous has not been removed
        } else {
            nextIndex--;
            lastIndex = nextIndex;
            return source.get(nextIndex);
        }
    }

    /**
     * Returns the index of the element that would be returned by a subsequent call to previous.
     */
    public int previousIndex() {
        return nextIndex - 1;
    }

    /**
     * Inserts the specified element into the list (optional operation).
     */
    public void add(E o) {
        source.add(nextIndex, o);
    }

    /**
     * Removes from the list the last element that was returned by next
     * or previous (optional operation).
     */
    public void remove() {
        if(lastIndex == -1) throw new IllegalStateException("Cannot remove() without a prior call to next() or previous()");
        source.remove(lastIndex);
    }

    /**
     * Replaces the last element returned by next or previous with the
     * specified element (optional operation).
     */
    public void set(E o) {
        if(lastIndex == -1) throw new IllegalStateException("Cannot set() without a prior call to next() or previous()");
        source.set(lastIndex, o);
    }

    /**
     * When the list is changed, the iterator adjusts its index.
     */
    public void listChanged(ListEvent<E> listChanges) {
        while(listChanges.next()) {
            int changeIndex = listChanges.getIndex();
            int changeType = listChanges.getType();

            // if it is an insert
            if(changeType == ListEvent.INSERT) {
                if(changeIndex <= nextIndex) nextIndex++;

                if(lastIndex != -1 && changeIndex <= lastIndex) lastIndex++;
            // if it is a delete
            } else if(changeType == ListEvent.DELETE) {
                if(changeIndex < nextIndex) nextIndex--;

                if(lastIndex != -1 && changeIndex < lastIndex) lastIndex--;
                else if(lastIndex != -1 && changeIndex == lastIndex) lastIndex = -1;
            }
        }
    }
}