/**
*
*/
package cz.cuni.mff.peckam.java.origamist.utils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/**
* A list that notifies its observers whenever an item is added/removed.
*
* @param T The type of elements in the list.
*
* @author Martin Pecka
*/
public class ObservableList<T> extends ArrayList<T>
{
/** */
private static final long serialVersionUID = 3207567353639585374L;
/**
* Observers of the change notifications.
*/
protected List<Observer<? super T>> observers = new LinkedList<Observer<? super T>>();
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ObservableList()
{
super();
}
/**
* Constructs a list containing the elements of the specified collection, in the order they are returned by the
* collection's iterator.
*
* @param c the collection whose elements are to be placed into this list.
* @throws NullPointerException if the specified collection is null.
*/
public ObservableList(Collection<? extends T> c)
{
super();
if (c.size() == 0)
return;
addAll(c);
}
/**
* Constructs an empty list with the specified initial capacity.
*
* @param initialCapacity the initial capacity of the list
*
* @throws IllegalArgumentException if the specified initial capacity is negative
*/
public ObservableList(int initialCapacity)
{
super(initialCapacity);
}
/**
* Add a new observer.
*
* @param observer The observer to add.
*/
public void addObserver(Observer<? super T> observer)
{
observers.add(observer);
}
/**
* Remove the specified observer.
*
* @param observer The observer to remove.
*/
public void removeObserver(Observer<? super T> observer)
{
observers.remove(observer);
}
/**
* @return the observers
*/
public List<Observer<? super T>> getObservers()
{
return observers;
}
/**
* Notify all observers about the given change.
*
* @param change The change that has happened.
*/
protected void fireChangeNotification(ChangeNotification<T> change)
{
for (Observer<? super T> l : observers)
l.changePerformed(change);
}
/**
* Notify all observers about the given change.
*
* @param item The item that has changed.
* @param type The type of the change.
*/
protected void fireChangeNotification(T item, ChangeTypes type)
{
fireChangeNotification(new ChangeNotification<T>(this, item, type));
}
/**
* Notify all observers about the given change.
*
* @param item The item that has changed.
* @param oldItem The previous item (if type is CHANGE).
* @param type The type of the change.
*/
protected void fireChangeNotification(T item, T oldItem, ChangeTypes type)
{
fireChangeNotification(new ChangeNotification<T>(this, item, oldItem, type));
}
@Override
public void add(int index, T element)
{
super.add(index, element);
fireChangeNotification(element, ChangeTypes.ADD);
}
@Override
public boolean add(T e)
{
super.add(e);
fireChangeNotification(e, ChangeTypes.ADD);
return true;
}
@Override
public boolean addAll(Collection<? extends T> c)
{
if (c.size() == 0)
return false;
if (c.size() == 1) {
add(c.iterator().next());
} else {
Iterator<? extends T> it = c.iterator();
while (it.hasNext()) {
T item = it.next();
add(item);
}
}
return true;
}
@Override
public boolean addAll(int index, Collection<? extends T> c)
{
if (c.size() == 0)
return false;
int i = index;
if (c.size() == 1) {
add(i, c.iterator().next());
} else {
Iterator<? extends T> it = c.iterator();
while (it.hasNext()) {
T item = it.next();
add(i++, item);
}
}
return true;
}
@Override
public void clear()
{
for (int i = size() - 1; i >= 0; i--) {
remove(i);
}
}
@Override
public T remove(int index)
{
T i = null;
if ((i = super.remove(index)) != null) {
fireChangeNotification(i, ChangeTypes.REMOVE);
}
return null;
}
@SuppressWarnings("unchecked")
@Override
public boolean remove(Object o)
{
if (super.remove(o)) {
fireChangeNotification((T) o, ChangeTypes.REMOVE);
return true;
}
return false;
}
@Override
protected void removeRange(int fromIndex, int toIndex)
{
List<T> removed = new LinkedList<T>();
for (int i = fromIndex; i < toIndex; i++)
removed.add(get(i));
super.removeRange(fromIndex, toIndex);
for (T item : removed)
fireChangeNotification(item, ChangeTypes.REMOVE);
}
@Override
public T set(int index, T element)
{
T item = super.set(index, element);
fireChangeNotification(element, item, ChangeTypes.CHANGE);
return item;
}
/**
* Type of the change that can happen in the list
*
* @author Martin Pecka
*/
public enum ChangeTypes
{
/**
* Item was removed
*/
REMOVE,
/**
* Item was added
*/
ADD,
/**
* Item was changed
*/
CHANGE
}
}