ca.odell.glazedlists.AbstractEventList Maven / Gradle / Ivy
Show all versions of glazedlists_java15 Show documentation
/* 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.ListEventAssembler;
import ca.odell.glazedlists.event.ListEventListener;
import ca.odell.glazedlists.event.ListEventPublisher;
import ca.odell.glazedlists.impl.EventListIterator;
import ca.odell.glazedlists.impl.GlazedListsImpl;
import ca.odell.glazedlists.impl.SimpleIterator;
import ca.odell.glazedlists.impl.SubEventList;
import ca.odell.glazedlists.util.concurrent.ReadWriteLock;
import java.lang.reflect.Array;
import java.util.*;
/**
* A convenience class that implements common functionality for all {@link EventList}s.
*
* If you are creating a custom {@link EventList}, consider extending the more
* feature-rich {@link TransformedList}.
*
*
Documentation Note: Javadoc tags have been copied from the {@link List} API
* because the javadoc
tool does not inherit external descriptions.
*
* @author Jesse Wilson
*/
public abstract class AbstractEventList implements EventList {
/** the change event and notification system */
protected ListEventAssembler updates = null;
/** the read/write lock provides mutual exclusion to access */
protected ReadWriteLock readWriteLock = null;
/** the publisher manages the distribution of changes */
protected ListEventPublisher publisher = null;
/**
* Creates an {@link AbstractEventList} that sends events using the specified
* {@link ListEventPublisher}.
*
* @param publisher the channel for event distribution. If this is null,
* then a new {@link ListEventPublisher} will be created.
*/
protected AbstractEventList(ListEventPublisher publisher) {
if(publisher == null) publisher = ListEventAssembler.createListEventPublisher();
this.publisher = publisher;
updates = new ListEventAssembler(this, publisher);
}
/**
* Create an {@link AbstractEventList} that sends events with the default
* {@link ListEventPublisher}.
*/
protected AbstractEventList() {
this(null);
}
/** {@inheritDoc} */
public ListEventPublisher getPublisher() {
return publisher;
}
/** {@inheritDoc} */
public ReadWriteLock getReadWriteLock() {
return readWriteLock;
}
/** {@inheritDoc} */
public void addListEventListener(ListEventListener super E> listChangeListener) {
updates.addListEventListener(listChangeListener);
}
/** {@inheritDoc} */
public void removeListEventListener(ListEventListener super E> listChangeListener) {
updates.removeListEventListener(listChangeListener);
}
/**
* Returns the number of elements in this list. If this list contains
* more than Integer.MAX_VALUE elements, returns
* Integer.MAX_VALUE.
*
* @return the number of elements in this list.
*/
public abstract int size();
/**
* Returns true if this list contains no elements.
*
* @return true if this list contains no elements.
*/
public boolean isEmpty() {
return (size() == 0);
}
/**
* Returns true if this list contains the specified element.
* More formally, returns true if and only if this list contains
* at least one element e such that
* (o==null ? e==null : o.equals(e)).
*
* @param object element whose presence in this list is to be tested.
* @return true if this list contains the specified element.
* @throws ClassCastException if the type of the specified element
* is incompatible with this list (optional).
* @throws NullPointerException if the specified element is null and this
* list does not support null elements (optional).
*/
public boolean contains(Object object) {
// for through this, looking for the lucky object
for(Iterator i = iterator(); i.hasNext(); ) {
if(GlazedListsImpl.equal(object, i.next())) return true;
}
// not found
return false;
}
/**
* Returns an iterator over the elements in this list in proper sequence.
*
* The returned {@link Iterator} will become inconsistent if the
* {@link EventList} that it views is modified. To overcome this problem,
* use {@link #listIterator()}. When used concurrently, the returned
* {@link Iterator} requires locking via this list's
* {@link #getReadWriteLock() ReadWriteLock}.
*
* @return an iterator over the elements in this list in proper sequence.
*/
public Iterator iterator() {
return new SimpleIterator(this);
}
/**
* Returns an array containing all of the elements in this list in proper
* sequence. Obeys the general contract of the
* Collection.toArray method.
*
* @return an array containing all of the elements in this list in proper
* sequence.
* @see Arrays#asList
*/
public Object[] toArray() {
// copy values into the array
Object[] array = new Object[size()];
int index = 0;
for(Iterator i = iterator(); i.hasNext(); ) {
array[index] = i.next();
index++;
}
return array;
}
/**
* Returns an array containing all of the elements in this list in proper
* sequence; the runtime type of the returned array is that of the
* specified array. Obeys the general contract of the
* Collection.toArray(Object[]) method.
*
* @param array the array into which the elements of this list are to
* be stored, if it is big enough; otherwise, a new array of the
* same runtime type is allocated for this purpose.
* @return an array containing the elements of this list.
*
* @throws ArrayStoreException if the runtime type of the specified array
* is not a supertype of the runtime type of every element in
* this list.
* @throws NullPointerException if the specified array is null.
*/
public T[] toArray(T[] array) {
// create an array of the same type as the array passed
if (array.length < size()) {
array = (T[]) Array.newInstance(array.getClass().getComponentType(), size());
} else if(array.length > size()) {
array[size()] = null;
}
// copy values into the array
int index = 0;
for(Iterator i = iterator(); i.hasNext(); ) {
array[index] = (T) i.next();
index++;
}
return array;
}
/**
* Appends the specified element to the end of this list (optional
* operation).
*
* Lists that support this operation may place limitations on what
* elements may be added to this list. In particular, some
* lists will refuse to add null elements, and others will impose
* restrictions on the type of elements that may be added. List
* classes should clearly specify in their documentation any restrictions
* on what elements may be added.
*
* @param value element to be appended to this list.
* @return true (as per the general contract of the
* Collection.add method).
*
* @throws UnsupportedOperationException if the add method is not
* supported by this list.
* @throws ClassCastException if the class of the specified element
* prevents it from being added to this list.
* @throws NullPointerException if the specified element is null and this
* list does not support null elements.
* @throws IllegalArgumentException if some aspect of this element
* prevents it from being added to this list.
*/
public boolean add(E value) {
final int initialSize = this.size();
this.add(this.size(), value);
return this.size() != initialSize;
}
/**
* Removes the first occurrence in this list of the specified element
* (optional operation). If this list does not contain the element, it is
* unchanged. More formally, removes the element with the lowest index i
* such that (o==null ? get(i)==null : o.equals(get(i))) (if
* such an element exists).
*
* @param toRemove element to be removed from this list, if present.
* @return true if this list contained the specified element.
* @throws ClassCastException if the type of the specified element
* is incompatible with this list (optional).
* @throws NullPointerException if the specified element is null and this
* list does not support null elements (optional).
* @throws UnsupportedOperationException if the remove method is
* not supported by this list.
*/
public boolean remove(Object toRemove) {
int index = indexOf(toRemove);
if(index == -1) return false;
this.remove(index);
return true;
}
/**
* Returns true if this list contains all of the elements of the
* specified collection.
*
* @param values collection to be checked for containment in this list.
* @return true if this list contains all of the elements of the
* specified collection.
* @throws ClassCastException if the types of one or more elements
* in the specified collection are incompatible with this
* list (optional).
* @throws NullPointerException if the specified collection contains one
* or more null elements and this list does not support null
* elements (optional).
* @throws NullPointerException if the specified collection is
* null.
* @see #contains(Object)
*/
public boolean containsAll(Collection> values) {
// look for something that is missing
for(Iterator i = values.iterator(); i.hasNext(); ) {
Object a = i.next();
if(!contains(a)) return false;
}
// contained everything we looked for
return true;
}
/**
* Appends all of the elements in the specified collection to the end of
* this list, in the order that they are returned by the specified
* collection's iterator (optional operation). The behavior of this
* operation is unspecified if the specified collection is modified while
* the operation is in progress. (Note that this will occur if the
* specified collection is this list, and it's nonempty.)
*
* @param values collection whose elements are to be added to this list.
* @return true if this list changed as a result of the call.
*
* @throws UnsupportedOperationException if the addAll method is
* not supported by this list.
* @throws ClassCastException if the class of an element in the specified
* collection prevents it from being added to this list.
* @throws NullPointerException if the specified collection contains one
* or more null elements and this list does not support null
* elements, or if the specified collection is null.
* @throws IllegalArgumentException if some aspect of an element in the
* specified collection prevents it from being added to this
* list.
* @see #add(Object)
*/
public boolean addAll(Collection extends E> values) {
return addAll(size(), values);
}
/**
* Inserts all of the elements in the specified collection into this
* list at the specified position (optional operation). Shifts the
* element currently at that position (if any) and any subsequent
* elements to the right (increases their indices). The new elements
* will appear in this list in the order that they are returned by the
* specified collection's iterator. The behavior of this operation is
* unspecified if the specified collection is modified while the
* operation is in progress. (Note that this will occur if the specified
* collection is this list, and it's nonempty.)
*
* @param index index at which to insert first element from the specified
* collection.
* @param values elements to be inserted into this list.
* @return true if this list changed as a result of the call.
*
* @throws UnsupportedOperationException if the addAll method is
* not supported by this list.
* @throws ClassCastException if the class of one of elements of the
* specified collection prevents it from being added to this
* list.
* @throws NullPointerException if the specified collection contains one
* or more null elements and this list does not support null
* elements, or if the specified collection is null.
* @throws IllegalArgumentException if some aspect of one of elements of
* the specified collection prevents it from being added to
* this list.
* @throws IndexOutOfBoundsException if the index is out of range (index
* < 0 || index > size()).
*/
public boolean addAll(int index, Collection extends E> values) {
// don't do an add of an empty set
if(index < 0 || index > size()) throw new IndexOutOfBoundsException("Cannot add at " + index + " on list of size " + size());
if(values.size() == 0) return false;
final int initializeSize = this.size();
for (Iterator extends E> iter = values.iterator(); iter.hasNext();) {
this.add(index, iter.next());
// advance the insertion location if its within the size of the list
if (index < this.size())
index++;
}
return this.size() != initializeSize;
}
/**
* Removes from this list all the elements that are contained in the
* specified collection (optional operation).
*
* @param values collection that defines which elements will be removed from
* this list.
* @return true if this list changed as a result of the call.
*
* @throws UnsupportedOperationException if the removeAll method
* is not supported by this list.
* @throws ClassCastException if the types of one or more elements
* in this list are incompatible with the specified
* collection (optional).
* @throws NullPointerException if this list contains one or more
* null elements and the specified collection does not support
* null elements (optional).
* @throws NullPointerException if the specified collection is
* null.
* @see #remove(Object)
* @see #contains(Object)
*/
public boolean removeAll(Collection> values) {
boolean changed = false;
for(Iterator i = iterator(); i.hasNext(); ) {
if(values.contains(i.next())) {
i.remove();
changed = true;
}
}
return changed;
}
/**
* Retains only the elements in this list that are contained in the
* specified collection (optional operation). In other words, removes
* from this list all the elements that are not contained in the specified
* collection.
*
* @param values collection that defines which elements this set will retain.
*
* @return true if this list changed as a result of the call.
*
* @throws UnsupportedOperationException if the retainAll method
* is not supported by this list.
* @throws ClassCastException if the types of one or more elements
* in this list are incompatible with the specified
* collection (optional).
* @throws NullPointerException if this list contains one or more
* null elements and the specified collection does not support
* null elements (optional).
* @throws NullPointerException if the specified collection is
* null.
* @see #remove(Object)
* @see #contains(Object)
*/
public boolean retainAll(Collection> values) {
boolean changed = false;
for(Iterator i = iterator(); i.hasNext();) {
if(!values.contains(i.next())) {
i.remove();
changed = true;
}
}
return changed;
}
/**
* Removes all of the elements from this list (optional operation). This
* list will be empty after this call returns (unless it throws an
* exception).
*
* @throws UnsupportedOperationException if the clear method is
* not supported by this list.
*/
public void clear() {
for(Iterator i = iterator(); i.hasNext();) {
i.next();
i.remove();
}
}
/**
* Compares the specified object with this list for equality. Returns
* true if and only if the specified object is also a list, both
* lists have the same size, and all corresponding pairs of elements in
* the two lists are equal. (Two elements e1 and
* e2 are equal if (e1==null ? e2==null :
* e1.equals(e2)).) In other words, two lists are defined to be
* equal if they contain the same elements in the same order. This
* definition ensures that the equals method works properly across
* different implementations of the List interface.
*
* @param object the object to be compared for equality with this list.
* @return true if the specified object is equal to this list.
*/
@Override
public boolean equals(Object object) {
if(object == this) return true;
if(object == null) return false;
if(!(object instanceof List)) return false;
// ensure the lists are the same size
List otherList = (List)object;
if(otherList.size() != size()) return false;
// compare element wise, via iterators
Iterator iterA = iterator();
Iterator iterB = otherList.iterator();
while(iterA.hasNext() && iterB.hasNext()) {
if(!GlazedListsImpl.equal(iterA.next(), iterB.next())) return false;
}
// if we haven't failed yet, they match
return true;
}
/**
* Returns the hash code value for this list. The hash code of a list
* is defined to be the result of the following calculation:
*
* hashCode = 1;
* Iterator i = list.iterator();
* while (i.hasNext()) {
* Object obj = i.next();
* hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
* }
*
* This ensures that list1.equals(list2) implies that
* list1.hashCode()==list2.hashCode() for any two lists,
* list1 and list2, as required by the general
* contract of Object.hashCode.
*
* @return the hash code value for this list.
* @see Object#hashCode()
* @see Object#equals(Object)
* @see #equals(Object)
*/
@Override
public int hashCode() {
int hashCode = 1;
for(Iterator i = iterator(); i.hasNext(); ) {
E a = i.next();
hashCode = 31 * hashCode + (a == null ? 0 : a.hashCode());
}
return hashCode;
}
/**
* Returns the element at the specified position in this list.
*
* @param index index of element to return.
* @return the element at the specified position in this list.
*
* @throws IndexOutOfBoundsException if the index is out of range (index
* < 0 || index >= size()).
*/
public abstract E get(int index);
/**
* Replaces the element at the specified position in this list with the
* specified element (optional operation).
*
* @param index index of element to replace.
* @param value element to be stored at the specified position.
* @return the element previously at the specified position.
*
* @throws UnsupportedOperationException if the set method is not
* supported by this list.
* @throws ClassCastException if the class of the specified element
* prevents it from being added to this list.
* @throws NullPointerException if the specified element is null and
* this list does not support null elements.
* @throws IllegalArgumentException if some aspect of the specified
* element prevents it from being added to this list.
* @throws IndexOutOfBoundsException if the index is out of range
* (index < 0 || index >= size()).
*/
public E set(int index, E value) {
throw new UnsupportedOperationException("this list does not support set()");
}
/**
* Inserts the specified element at the specified position in this list
* (optional operation). Shifts the element currently at that position
* (if any) and any subsequent elements to the right (adds one to their
* indices).
*
* @param index index at which the specified element is to be inserted.
* @param value element to be inserted.
*
* @throws UnsupportedOperationException if the add method is not
* supported by this list.
* @throws ClassCastException if the class of the specified element
* prevents it from being added to this list.
* @throws NullPointerException if the specified element is null and
* this list does not support null elements.
* @throws IllegalArgumentException if some aspect of the specified
* element prevents it from being added to this list.
* @throws IndexOutOfBoundsException if the index is out of range
* (index < 0 || index > size()).
*/
public void add(int index, E value) {
throw new UnsupportedOperationException("this list does not support add()");
}
/**
* Removes the element at the specified position in this list (optional
* operation). Shifts any subsequent elements to the left (subtracts one
* from their indices). Returns the element that was removed from the
* list.
*
* @param index the index of the element to removed.
* @return the element previously at the specified position.
*
* @throws UnsupportedOperationException if the remove method is
* not supported by this list.
* @throws IndexOutOfBoundsException if the index is out of range (index
* < 0 || index >= size()).
*/
public E remove(int index) {
throw new UnsupportedOperationException("this list does not support remove()");
}
/**
* Returns the index in this list of the first occurrence of the specified
* element, or -1 if this list does not contain this element.
* More formally, returns the lowest index i such that
* (o==null ? get(i)==null : o.equals(get(i))),
* or -1 if there is no such index.
*
* @param object element to search for.
* @return the index in this list of the first occurrence of the specified
* element, or -1 if this list does not contain this element.
* @throws ClassCastException if the type of the specified element
* is incompatible with this list (optional).
* @throws NullPointerException if the specified element is null and this
* list does not support null elements (optional).
*/
public int indexOf(Object object) {
// for through this, looking for the lucky object
int index = 0;
for(Iterator i = iterator(); i.hasNext(); ) {
if(GlazedListsImpl.equal(object, i.next())) return index;
else index++;
}
// not found
return -1;
}
/**
* Returns the index in this list of the last occurrence of the specified
* element, or -1 if this list does not contain this element.
* More formally, returns the highest index i such that
* (o==null ? get(i)==null : o.equals(get(i))),
* or -1 if there is no such index.
*
* @param object element to search for.
* @return the index in this list of the last occurrence of the specified
* element, or -1 if this list does not contain this element.
* @throws ClassCastException if the type of the specified element
* is incompatible with this list (optional).
* @throws NullPointerException if the specified element is null and this
* list does not support null elements (optional).
*/
public int lastIndexOf(Object object) {
// for through this, looking for the lucky object
for(int i = size() - 1; i >= 0; i--) {
if(GlazedListsImpl.equal(object, get(i))) return i;
}
// not found
return -1;
}
/**
* Returns a list iterator of the elements in this list (in proper
* sequence).
*
* Unlike the {@link ListIterator} from a regular {@link List}, the
* {@link EventList}'s {@link ListIterator} will remain consistent even if the
* {@link EventList} is changed externally. Note that when used concurrently,
* the returned {@link ListIterator} requires locking via this list's
* {@link #getReadWriteLock() ReadWriteLock}.
*
* @return a list iterator of the elements in this list (in proper
* sequence).
*/
public ListIterator listIterator() {
return listIterator(0);
}
/**
* Returns a list iterator of the elements in this list (in proper
* sequence), starting at the specified position in this list. The
* specified index indicates the first element that would be returned by
* an initial call to the next method. An initial call to
* the previous method would return the element with the
* specified index minus one.
*
* Unlike the {@link ListIterator} from a regular {@link List}, the
* {@link EventList}'s {@link ListIterator} will remain consistent even if the
* {@link EventList} is changed externally. Note that when used concurrently,
* the returned {@link ListIterator} requires locking via this list's
* {@link #getReadWriteLock() ReadWriteLock}.
*
* @param index index of first element to be returned from the
* list iterator (by a call to the next method).
* @return a list iterator of the elements in this list (in proper
* sequence), starting at the specified position in this list.
* @throws IndexOutOfBoundsException if the index is out of range (index
* < 0 || index > size()).
*/
public ListIterator listIterator(int index) {
return new EventListIterator(this, index);
}
/**
* Returns a view of the portion of this list between the specified
* fromIndex, inclusive, and toIndex, exclusive. (If
* fromIndex and toIndex are equal, the returned list is
* empty.)
* Unlike the standard {@link List#subList(int,int) List.subList()}
* method, the {@link List} returned by this method will continue to be
* consistent even if the {@link EventList} it views is modified,
* structurally or otherwise. The returned {@link List} can always be safely
* cast to {@link EventList}. Note that when used concurrently, the returned
* {@link List} requires locking via this list's
* {@link #getReadWriteLock() ReadWriteLock}.
*
*
This method eliminates the need for explicit range operations (of
* the sort that commonly exist for arrays). Any operation that expects
* a list can be used as a range operation by passing a subList view
* instead of a whole list. For example, the following idiom
* removes a range of elements from a list:
*
* list.subList(from, to).clear();
*
* Similar idioms may be constructed for indexOf and
* lastIndexOf, and all of the algorithms in the
* Collections class can be applied to a subList.
*
* @param fromIndex low endpoint (inclusive) of the subList.
* @param toIndex high endpoint (exclusive) of the subList.
* @return a view of the specified range within this list.
*
* @throws IndexOutOfBoundsException for an illegal endpoint index value
* (fromIndex < 0 || toIndex > size || fromIndex > toIndex).
*/
public List subList(int fromIndex, int toIndex) {
return new SubEventList(this, fromIndex, toIndex, true);
}
/**
* Returns a string representation of this collection. The string
* representation consists of a list of the collection's elements in the
* order they are returned by its iterator, enclosed in square brackets
* ("[]"). Adjacent elements are separated by the characters
* ", " (comma and space). Elements are converted to strings as
* by String.valueOf(Object).
*
* This implementation creates an empty string buffer, appends a left
* square bracket, and iterates over the collection appending the string
* representation of each element in turn. After appending each element
* except the last, the string ", " is appended. Finally a right
* bracket is appended. A string is obtained from the string buffer, and
* returned.
*
* @return a string representation of this collection.
*/
@Override
public String toString() {
StringBuffer result = new StringBuffer();
result.append("[");
for(Iterator i = iterator(); i.hasNext(); ) {
result.append(String.valueOf(i.next()));
if(i.hasNext()) result.append(", ");
}
result.append("]");
return result.toString();
}
}