/**
* <copyright>
*
* Copyright (c) 2009 BestSolution.at 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:
* Tom Schindl<tom.schindl@bestsolution.at> - Initial API and implementation in 262160
* </copyright>
*
* $Id: EWritableList.java,v 1.3 2010/02/04 20:56:28 emerks Exp $
*/
package org.eclipse.emf.databinding.internal;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import org.eclipse.core.databinding.observable.Diffs;
import org.eclipse.core.databinding.observable.ObservableTracker;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.list.AbstractObservableList;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.list.ListDiff;
import org.eclipse.core.databinding.observable.list.ListDiffEntry;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.notify.NotifyingList;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.ecore.resource.Resource;
/**
* Writable list which can be used to observe an {@link NotifyingList}
*
* <p><b>PROVISIONAL:</b> This API is subject to arbitrary change, including renaming or removal.</p>
*
* @param <Type> the type
* @since 2.5
*/
public class EWritableList<Type> extends AbstractObservableList implements IObservableList
{
private NotifyingList<Type> wrappedList;
private Object elementType;
private boolean stale = false;
private class Listener extends AdapterImpl
{
private Object feature;
public Listener(Object feature)
{
this.feature = feature;
}
@Override
public void notifyChanged(Notification msg)
{
if (feature == null && msg.getFeature() == null && msg.getFeatureID(Resource.class) != Resource.RESOURCE__CONTENTS)
{
return;
}
if (feature == msg.getFeature() && !msg.isTouch())
{
final ListDiff diff;
switch (msg.getEventType())
{
case Notification.ADD: {
diff = Diffs.createListDiff(Diffs.createListDiffEntry(msg.getPosition(), true, msg.getNewValue()));
// fireListChange(diff);
break;
}
case Notification.ADD_MANY: {
Collection< ? > newValues = (Collection< ? >)msg.getNewValue();
ListDiffEntry[] listDiffEntries = new ListDiffEntry [newValues.size()];
int position = msg.getPosition();
int index = 0;
for (Object newValue : newValues)
{
listDiffEntries[index++] = Diffs.createListDiffEntry(position++, true, newValue);
}
diff = Diffs.createListDiff(listDiffEntries);
// fireListChange(diff);
break;
}
case Notification.REMOVE: {
diff = Diffs.createListDiff(Diffs.createListDiffEntry(msg.getPosition(), false, msg.getOldValue()));
// fireListChange(diff);
break;
}
case Notification.REMOVE_MANY: {
Collection< ? > oldValues = (Collection< ? >)msg.getOldValue();
ListDiffEntry[] listDiffEntries = new ListDiffEntry [oldValues.size()];
int position = msg.getPosition();
int index = 0;
for (Object oldValue : oldValues)
{
listDiffEntries[index++] = Diffs.createListDiffEntry(position++, false, oldValue);
}
diff = Diffs.createListDiff(listDiffEntries);
// fireListChange(diff);
break;
}
case Notification.MOVE: {
Object movedValue = msg.getNewValue();
ListDiffEntry[] listDiffEntries = new ListDiffEntry [2];
listDiffEntries[0] = Diffs.createListDiffEntry((Integer)msg.getOldValue(), false, movedValue);
listDiffEntries[1] = Diffs.createListDiffEntry(msg.getPosition(), true, movedValue);
diff = Diffs.createListDiff(listDiffEntries);
// fireListChange(diff);
break;
}
case Notification.UNSET: {
// This just represents going back to the unset state, but
// that doesn't affect the contents of the list.
//
return;
}
default: {
throw new RuntimeException("unhandled case");
}
}
getRealm().exec(new Runnable()
{
public void run()
{
fireListChange(diff);
}
});
// System.err.println("CHANGE: " +
// diff.getDifferences()[0].getElement());
// fireListChange(diff);
// listener.handlePropertyChange(new SimplePropertyEvent(msg
// .getNotifier(), EMFListProperty.this, diff));
}
}
}
private Adapter listener;
/**
* New writable list wrapping the {@link NotifyingList}
*
* @param wrappedList
* the wrapped list
*/
public EWritableList(NotifyingList<Type> wrappedList)
{
this(Realm.getDefault(), wrappedList);
}
/**
* New writable list wrapping the {@link NotifyingList} and using the
* {@link Realm}
*
* @param realm
* the realm
* @param wrappedList
* the wrapped list
*/
public EWritableList(Realm realm, NotifyingList<Type> wrappedList)
{
this(realm, wrappedList, null);
}
/**
* New writable list wrapping the {@link NotifyingList}
*
* @param realm
* the realm
* @param wrappedList
* the wrapped list
* @param elementType
* the element type
*/
public EWritableList(Realm realm, NotifyingList<Type> wrappedList, Class<Type> elementType)
{
super(realm);
this.wrappedList = wrappedList;
this.elementType = elementType;
}
@Override
protected void firstListenerAdded()
{
if (wrappedList.getNotifier() instanceof Notifier)
{
Notifier notifier = (Notifier)wrappedList.getNotifier();
listener = new Listener(wrappedList.getFeature());
notifier.eAdapters().add(listener);
}
else
{
throw new IllegalArgumentException("Wrapped list must have a notifier attached!");
}
}
@Override
protected void lastListenerRemoved()
{
if (wrappedList.getNotifier() instanceof Notifier)
{
Notifier notifier = (Notifier)wrappedList.getNotifier();
listener = new Listener(wrappedList.getFeature());
notifier.eAdapters().remove(listener);
}
else
{
throw new IllegalArgumentException("Wrapped list must have a notifier attached!");
}
}
@Override
public synchronized void dispose()
{
super.dispose();
}
private void getterCalled()
{
ObservableTracker.getterCalled(this);
}
@Override
@SuppressWarnings("unchecked")
public boolean add(Object o)
{
checkRealm();
return wrappedList.add((Type)o);
}
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public boolean addAll(Collection c)
{
checkRealm();
return wrappedList.addAll(c);
}
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public boolean addAll(int index, Collection c)
{
checkRealm();
return wrappedList.addAll(index, c);
}
@Override
public boolean contains(Object o)
{
getterCalled();
return wrappedList.contains(o);
}
@Override
@SuppressWarnings("rawtypes")
public boolean containsAll(Collection c)
{
getterCalled();
return wrappedList.containsAll(c);
}
@Override
public Object get(int index)
{
getterCalled();
return wrappedList.get(index);
}
public Object getElementType()
{
checkRealm();
return elementType;
}
@Override
public int indexOf(Object o)
{
getterCalled();
return wrappedList.indexOf(o);
}
@Override
public boolean isEmpty()
{
getterCalled();
return wrappedList.isEmpty();
}
@Override
public Iterator<Type> iterator()
{
getterCalled();
return wrappedList.iterator();
}
@Override
public int lastIndexOf(Object o)
{
getterCalled();
return wrappedList.lastIndexOf(o);
}
@Override
public ListIterator<Type> listIterator()
{
getterCalled();
return wrappedList.listIterator();
}
@Override
public ListIterator<Type> listIterator(int index)
{
getterCalled();
return wrappedList.listIterator(index);
}
@Override
public Object move(int oldIndex, int newIndex)
{
checkRealm();
return wrappedList.move(oldIndex, newIndex);
}
@Override
public boolean remove(Object o)
{
checkRealm();
return wrappedList.remove(o);
}
@Override
public Object remove(int index)
{
checkRealm();
return wrappedList.remove(index);
}
@Override
@SuppressWarnings("rawtypes")
public boolean removeAll(Collection c)
{
checkRealm();
return wrappedList.removeAll(c);
}
@Override
@SuppressWarnings("rawtypes")
public boolean retainAll(Collection c)
{
checkRealm();
return wrappedList.retainAll(c);
}
@Override
@SuppressWarnings("unchecked")
public Object set(int index, Object element)
{
checkRealm();
return wrappedList.set(index, (Type)element);
}
@Override
public int doGetSize()
{
getterCalled();
return wrappedList.size();
}
@Override
public List<Type> subList(int fromIndex, int toIndex)
{
getterCalled();
return wrappedList.subList(fromIndex, toIndex);
}
@Override
public Object[] toArray()
{
getterCalled();
return wrappedList.toArray();
}
@Override
public Object[] toArray(Object[] a)
{
getterCalled();
return wrappedList.toArray();
}
@Override
@SuppressWarnings("unchecked")
public void add(int index, Object element)
{
checkRealm();
wrappedList.add(index, (Type)element);
}
@Override
public void clear()
{
checkRealm();
wrappedList.clear();
}
@Override
public boolean isStale()
{
getterCalled();
return stale;
}
// public void setStale(boolean stale) {
// checkRealm();
//
// boolean wasStale = this.stale;
// this.stale = stale;
// if (!wasStale && stale) {
// fireStale();
// }
// }
}