blob: ca0c7503da4b956e28e781abb964acff3878c4cf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Brad Reynolds - bug 164653
* Brad Reynolds - bug 167204
* Gautam Saggar - bug 169529
* Brad Reynolds - bug 147515
* Matthew Hall - bug 208858, 213145
*******************************************************************************/
package org.eclipse.core.databinding.observable.list;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.databinding.observable.Diffs;
import org.eclipse.core.databinding.observable.Realm;
/**
* Mutable observable list backed by an ArrayList.
*
* <p>
* This class is thread safe. All state accessing methods must be invoked from
* the {@link Realm#isCurrent() current realm}. Methods for adding and removing
* listeners may be invoked from any thread.
* </p>
*
* @since 1.0
*/
public class WritableList extends ObservableList {
/**
* Creates an empty writable list in the default realm with a
* <code>null</code> element type.
*
*/
public WritableList() {
this(Realm.getDefault());
}
/**
* Creates an empty writable list with a <code>null</code> element type.
*
* @param realm
*/
public WritableList(Realm realm) {
this(realm, new ArrayList(), null);
}
/**
* Constructs a new instance with the default realm.
*
* @param toWrap
* @param elementType
* can be <code>null</code>
*/
public WritableList(List toWrap, Object elementType) {
this(Realm.getDefault(), toWrap, elementType);
}
/**
* Creates a writable list containing elements of the given type, wrapping
* an existing client-supplied list.
*
* @param realm
* @param toWrap
* The java.utilList to wrap
* @param elementType
* can be <code>null</code>
*/
public WritableList(Realm realm, List toWrap, Object elementType) {
super(realm, toWrap, elementType);
}
public Object set(int index, Object element) {
checkRealm();
Object oldElement = wrappedList.set(index, element);
fireListChange(Diffs.createListDiff(Diffs.createListDiffEntry(index,
false, oldElement), Diffs.createListDiffEntry(index, true,
element)));
return oldElement;
}
/**
* @since 1.1
*/
public Object move(int oldIndex, int newIndex) {
checkRealm();
int size = wrappedList.size();
if (oldIndex < 0 || oldIndex >= size)
throw new IndexOutOfBoundsException(
"oldIndex: " + oldIndex + ", size:" + size); //$NON-NLS-1$ //$NON-NLS-2$
if (newIndex < 0 || newIndex >= size)
throw new IndexOutOfBoundsException(
"newIndex: " + newIndex + ", size:" + size); //$NON-NLS-1$ //$NON-NLS-2$
if (oldIndex == newIndex)
return wrappedList.get(oldIndex);
Object element = wrappedList.remove(oldIndex);
wrappedList.add(newIndex, element);
fireListChange(Diffs.createListDiff(Diffs.createListDiffEntry(oldIndex,
false, element), Diffs.createListDiffEntry(newIndex, true,
element)));
return element;
}
public Object remove(int index) {
checkRealm();
Object oldElement = wrappedList.remove(index);
fireListChange(Diffs.createListDiff(Diffs.createListDiffEntry(index,
false, oldElement)));
return oldElement;
}
public boolean add(Object element) {
checkRealm();
boolean added = wrappedList.add(element);
if (added) {
fireListChange(Diffs.createListDiff(Diffs.createListDiffEntry(
wrappedList.size() - 1, true, element)));
}
return added;
}
public void add(int index, Object element) {
checkRealm();
wrappedList.add(index, element);
fireListChange(Diffs.createListDiff(Diffs.createListDiffEntry(index,
true, element)));
}
public boolean addAll(Collection c) {
checkRealm();
ListDiffEntry[] entries = new ListDiffEntry[c.size()];
int i = 0;
int addIndex = wrappedList.size();
for (Iterator it = c.iterator(); it.hasNext();) {
Object element = it.next();
entries[i++] = Diffs.createListDiffEntry(addIndex++, true, element);
}
boolean added = wrappedList.addAll(c);
fireListChange(Diffs.createListDiff(entries));
return added;
}
public boolean addAll(int index, Collection c) {
checkRealm();
ListDiffEntry[] entries = new ListDiffEntry[c.size()];
int i = 0;
int addIndex = index;
for (Iterator it = c.iterator(); it.hasNext();) {
Object element = it.next();
entries[i++] = Diffs.createListDiffEntry(addIndex++, true, element);
}
boolean added = wrappedList.addAll(index, c);
fireListChange(Diffs.createListDiff(entries));
return added;
}
public boolean remove(Object o) {
checkRealm();
int index = wrappedList.indexOf(o);
if (index == -1) {
return false;
}
wrappedList.remove(index);
fireListChange(Diffs.createListDiff(Diffs.createListDiffEntry(index,
false, o)));
return true;
}
public boolean removeAll(Collection c) {
checkRealm();
List entries = new ArrayList();
for (Iterator it = c.iterator(); it.hasNext();) {
Object element = it.next();
int removeIndex = wrappedList.indexOf(element);
if (removeIndex != -1) {
wrappedList.remove(removeIndex);
entries.add(Diffs.createListDiffEntry(removeIndex, false,
element));
}
}
if (entries.size() > 0)
fireListChange(Diffs.createListDiff((ListDiffEntry[]) entries
.toArray(new ListDiffEntry[entries.size()])));
return entries.size() > 0;
}
public boolean retainAll(Collection c) {
checkRealm();
List entries = new ArrayList();
int removeIndex = 0;
for (Iterator it = wrappedList.iterator(); it.hasNext();) {
Object element = it.next();
if (!c.contains(element)) {
entries.add(Diffs.createListDiffEntry(removeIndex, false,
element));
it.remove();
} else {
// only increment if we haven't removed the current element
removeIndex++;
}
}
if (entries.size() > 0)
fireListChange(Diffs.createListDiff((ListDiffEntry[]) entries
.toArray(new ListDiffEntry[entries.size()])));
return entries.size() > 0;
}
public void clear() {
checkRealm();
List entries = new ArrayList();
for (Iterator it = wrappedList.iterator(); it.hasNext();) {
Object element = it.next();
// always report 0 as the remove index
entries.add(Diffs.createListDiffEntry(0, false, element));
it.remove();
}
fireListChange(Diffs.createListDiff((ListDiffEntry[]) entries
.toArray(new ListDiffEntry[entries.size()])));
}
/**
* @param elementType
* can be <code>null</code>
* @return new list with the default realm.
*/
public static WritableList withElementType(Object elementType) {
return new WritableList(Realm.getDefault(), new ArrayList(),
elementType);
}
}