File: TransformedList.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 (172 lines) | stat: -rw-r--r-- 6,321 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
/* Glazed Lists                                                 (c) 2003-2006 */
/* http://publicobject.com/glazedlists/                      publicobject.com,*/
/*                                                     O'Dell Engineering Ltd.*/
package ca.odell.glazedlists;

// the Glazed Lists' change objects
import ca.odell.glazedlists.event.ListEvent;
import ca.odell.glazedlists.event.ListEventListener;

import java.util.Collection;

/**
 * A convenience class for {@link EventList}s that decorate another {@link EventList}.
 * Extending classes transform their source {@link EventList} by modifying the
 * order, visibility and value of its elements.
 *
 * <p>Extending classes may implement the method {@link #getSourceIndex(int)} to
 * translate between indices of this and indices of the source.
 *
 * <p>Extending classes may implement the method {@link #isWritable()} to make the
 * source writable via this API.
 *
 * <p>Extending classes must explicitly call {@link #addListEventListener(ListEventListener)}
 * to receive change notifications from the source {@link EventList}.
 *
 * <p><strong><font color="#FF0000">Warning:</font></strong> This class is
 * thread ready but not thread safe. See {@link EventList} for an example
 * of thread safe code.
 *
 * @author <a href="mailto:jesse@swank.ca">Jesse Wilson</a>
 */
public abstract class TransformedList<S, E> extends AbstractEventList<E> implements ListEventListener<S> {

    /** the event list to transform */
    protected EventList<S> source;

    /**
     * Creates a {@link TransformedList} to transform the specified {@link EventList}.
     *
     * @param source the {@link EventList} to transform
     */
    protected TransformedList(EventList<S> source) {
        super(source.getPublisher());
        this.source = source;
        readWriteLock = source.getReadWriteLock();
    }

    /**
     * Gets the index in the source {@link EventList} that corresponds to the
     * specified index. More formally, returns the index such that
     * <br><code>this.get(i) == source.get(getSourceIndex(i))</code> for all
     * legal values of <code>i</code>.
     */
    protected int getSourceIndex(int mutationIndex) {
        return mutationIndex;
    }

    /**
     * Gets whether the source {@link EventList} is writable via this API.
     *
     * <p>Extending classes must override this method in order to make themselves
     * writable.
     */
    protected abstract boolean isWritable();

    /** {@inheritDoc} */
    public abstract void listChanged(ListEvent<S> listChanges);

    /** {@inheritDoc} */
    @Override
    public void add(int index, E value) {
        if(!isWritable()) throw new IllegalStateException("Non-writable List cannot be modified");
        if(index < 0 || index > size()) throw new IndexOutOfBoundsException("Cannot add at " + index + " on list of size " + size());
        final int sourceIndex = index < size() ? getSourceIndex(index) : source.size();
        source.add(sourceIndex, (S) value);
    }

    /** {@inheritDoc} */
    @Override
    public boolean addAll(int index, Collection<? extends E> values) {
        // nest changes and let the other methods compose the event
        updates.beginEvent(true);
        try {
            return super.addAll(index, values);
        } finally {
            updates.commitEvent();
        }
    }

    /** {@inheritDoc} */
    @Override
    public void clear() {
        // nest changes and let the other methods compose the event
        updates.beginEvent(true);
        try {
            super.clear();
        } finally {
            updates.commitEvent();
        }
    }

    /** {@inheritDoc} */
    @Override
    public E get(int index) {
        if(index < 0 || index >= size()) throw new IndexOutOfBoundsException("Cannot get at " + index + " on list of size " + size());
        return (E) source.get(getSourceIndex(index));
    }

    /** {@inheritDoc} */
    @Override
    public E remove(int index) {
        if(!isWritable()) throw new IllegalStateException("Non-writable List cannot be modified");
        if(index < 0 || index >= size()) throw new IndexOutOfBoundsException("Cannot remove at " + index + " on list of size " + size());
        return (E) source.remove(getSourceIndex(index));
    }

    /** {@inheritDoc} */
    @Override
    public boolean removeAll(Collection<?> collection) {
        // nest changes and let the other methods compose the event
        updates.beginEvent(true);
        try {
            return super.removeAll(collection);
        } finally {
            updates.commitEvent();
        }
    }

    /** {@inheritDoc} */
    @Override
    public boolean retainAll(Collection<?> values) {
        // nest changes and let the other methods compose the event
        updates.beginEvent(true);
        try {
            return super.retainAll(values);
        } finally {
            updates.commitEvent();
        }
    }

    /** {@inheritDoc} */
    @Override
    public E set(int index, E value) {
        if(!isWritable()) throw new IllegalStateException("List " + this.getClass().getName() + " cannot be modified in the current state");
        if(index < 0 || index >= size()) throw new IndexOutOfBoundsException("Cannot set at " + index + " on list of size " + size());
        return (E) source.set(getSourceIndex(index), (S) value);
    }

    /** {@inheritDoc} */
    @Override
    public int size() {
        return source.size();
    }

    /**
     * Releases the resources consumed by this {@link TransformedList} so that it
     * may eventually be garbage collected.
     *
     * <p>A {@link TransformedList} will be garbage collected without a call to
     * {@link #dispose()}, but not before its source {@link EventList} is garbage
     * collected. By calling {@link #dispose()}, you allow the {@link TransformedList}
     * to be garbage collected before its source {@link EventList}. This is
     * necessary for situations where a {@link TransformedList} is short-lived but
     * its source {@link EventList} is long-lived.
     *
     * <p><strong><font color="#FF0000">Warning:</font></strong> It is an error
     * to call any method on a {@link TransformedList} after it has been disposed.
     */
    public void dispose() {
        source.removeListEventListener(this);
    }
}