/*
* Copyright (C) 2011 Virginia Tech Department of Computer Science
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sofia.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
// -------------------------------------------------------------------------
/**
* <p>
* An implementation of the {@link List} interface that is {@link Observable}
* and notifies its observers whenever the collection is changed.
* </p><p>
* Users of this class can add themselves as observers to an instance of this
* class and they will be notified when the structure of the list changes; that
* is, when items are added, removed, or replaced.
* </p>
*
* @param <E> the type of element stored in the list
*
* @author Tony Allevato
*/
public class ObservableList<E>
extends Observable
implements List<E>
{
//~ Fields ................................................................
private List<E> contents;
//~ Constructors ..........................................................
// ----------------------------------------------------------
/**
* Creates a new {@code ObservableList} that is backed by an
* {@link ArrayList} with default capacity.
*/
public ObservableList()
{
contents = new ArrayList<E>();
}
// ----------------------------------------------------------
/**
* Creates a new {@code ObservableList} that is backed by an
* {@link ArrayList} with the specified capacity.
*
* @param capacity the capacity of the array list
*/
public ObservableList(int capacity)
{
contents = new ArrayList<E>(capacity);
}
// ----------------------------------------------------------
/**
* Creates a new {@code ObservableList} that provides an observable view of
* an existing list. The list passed to this constructor is <em>not</em>
* copied; changes made to the observable list will also be reflected in
* the list being wrapped, and vice versa.
*
* @param listToWrap the list to wrap with an observable front-end
*/
public ObservableList(List<E> listToWrap)
{
contents = listToWrap;
}
// ----------------------------------------------------------
/**
* Creates a new {@code ObservableList} that is initialized with a copy of
* the data in the specified collection. Since this constructor creates a
* copy, changes to the observable list will <em>not</em> be reflected in
* the source collection, and vice versa.
*
* @param collection the collection to be copied into the new list
*/
public ObservableList(Collection<? extends E> collection)
{
contents = new ArrayList<E>(collection);
}
//~ Methods ...............................................................
// ----------------------------------------------------------
public void add(int index, E item)
{
contents.add(index, item);
notifyObservers();
}
// ----------------------------------------------------------
public boolean add(E item)
{
boolean result = contents.add(item);
notifyObservers();
return result;
}
// ----------------------------------------------------------
public boolean addAll(int index, Collection<? extends E> collection)
{
boolean result = contents.addAll(index, collection);
notifyObservers();
return result;
}
// ----------------------------------------------------------
public boolean addAll(Collection<? extends E> collection)
{
boolean result = contents.addAll(collection);
notifyObservers();
return result;
}
// ----------------------------------------------------------
public void clear()
{
contents.clear();
notifyObservers();
}
// ----------------------------------------------------------
public boolean contains(Object object)
{
return contents.contains(object);
}
// ----------------------------------------------------------
public boolean containsAll(Collection<?> collection)
{
return contents.containsAll(collection);
}
// ----------------------------------------------------------
public E get(int index)
{
return contents.get(index);
}
// ----------------------------------------------------------
public int indexOf(Object object)
{
return contents.indexOf(object);
}
// ----------------------------------------------------------
public boolean isEmpty()
{
return contents.isEmpty();
}
// ----------------------------------------------------------
public Iterator<E> iterator()
{
return new NotifyingIterator(contents.iterator());
}
// ----------------------------------------------------------
public int lastIndexOf(Object object)
{
return contents.lastIndexOf(object);
}
// ----------------------------------------------------------
public ListIterator<E> listIterator()
{
return new NotifyingListIterator(contents.listIterator());
}
// ----------------------------------------------------------
public ListIterator<E> listIterator(int index)
{
return new NotifyingListIterator(contents.listIterator(index));
}
// ----------------------------------------------------------
public E remove(int index)
{
E result = contents.remove(index);
notifyObservers();
return result;
}
// ----------------------------------------------------------
public boolean remove(Object object)
{
boolean result = contents.remove(object);
notifyObservers();
return result;
}
// ----------------------------------------------------------
public boolean removeAll(Collection<?> collection)
{
boolean result = contents.removeAll(collection);
notifyObservers();
return result;
}
// ----------------------------------------------------------
public boolean retainAll(Collection<?> collection)
{
boolean result = contents.retainAll(collection);
notifyObservers();
return result;
}
// ----------------------------------------------------------
public E set(int index, E item)
{
E result = contents.set(index, item);
notifyObservers();
return result;
}
// ----------------------------------------------------------
public int size()
{
return contents.size();
}
// ----------------------------------------------------------
public List<E> subList(int start, int end)
{
return contents.subList(start, end);
}
// ----------------------------------------------------------
public Object[] toArray()
{
return contents.toArray();
}
// ----------------------------------------------------------
public <T> T[] toArray(T[] array)
{
return contents.toArray(array);
}
//~ Nested classes ........................................................
// ----------------------------------------------------------
private class NotifyingIterator implements Iterator<E>
{
private Iterator<E> iterator;
// ----------------------------------------------------------
public NotifyingIterator(Iterator<E> iterator)
{
this.iterator = iterator;
}
// ----------------------------------------------------------
public boolean hasNext()
{
return iterator.hasNext();
}
// ----------------------------------------------------------
public E next()
{
return iterator.next();
}
// ----------------------------------------------------------
public void remove()
{
iterator.remove();
notifyObservers();
}
}
// ----------------------------------------------------------
private class NotifyingListIterator implements ListIterator<E>
{
private ListIterator<E> iterator;
// ----------------------------------------------------------
public NotifyingListIterator(ListIterator<E> iterator)
{
this.iterator = iterator;
}
// ----------------------------------------------------------
public void add(E item)
{
iterator.add(item);
notifyObservers();
}
// ----------------------------------------------------------
public boolean hasNext()
{
return iterator.hasNext();
}
// ----------------------------------------------------------
public boolean hasPrevious()
{
return iterator.hasPrevious();
}
// ----------------------------------------------------------
public E next()
{
return iterator.next();
}
// ----------------------------------------------------------
public int nextIndex()
{
return iterator.nextIndex();
}
// ----------------------------------------------------------
public E previous()
{
return iterator.previous();
}
// ----------------------------------------------------------
public int previousIndex()
{
return iterator.previousIndex();
}
// ----------------------------------------------------------
public void remove()
{
iterator.remove();
notifyObservers();
}
// ----------------------------------------------------------
public void set(E item)
{
iterator.set(item);
notifyObservers();
}
}
}