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);
}
}
|