/*******************************************************************************
* Copyright (c) 2006-2013 The RCP Company 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:
* The RCP Company - initial API and implementation
*******************************************************************************/
package com.rcpcompany.uibindings.internal.observables;
import org.eclipse.core.databinding.observable.Diffs;
import org.eclipse.core.databinding.observable.list.IListChangeListener;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.list.ListChangeEvent;
import org.eclipse.core.databinding.observable.value.AbstractObservableValue;
import org.eclipse.core.databinding.observable.value.ValueDiff;
import org.eclipse.emf.ecore.EcorePackage;
/**
* Observable value that will return and monitor the index of an element in a list.
*
* @author Tonny Madsen, The RCP Company
*/
public class ListIndexObservableValue extends AbstractObservableValue {
private final int myOffset;
/**
* Constructs and returns a new observable value that will return and monitor the index of an
* element in a list.
*
* @param list the list
* @param element the element
*/
public ListIndexObservableValue(IObservableList list, Object element) {
this(list, element, 0);
}
/**
* Constructs and returns a new observable value that will return and monitor the index of an
* element in a list.
*
* @param list the list
* @param element the element
* @param offset an offset of add to the index
*/
public ListIndexObservableValue(IObservableList list, Object element, int offset) {
super(list.getRealm());
myList = list;
myElement = element;
myOffset = offset;
myIndex = calculateIndex();
}
private final IObservableList myList;
private final Object myElement;
/**
* The currently known index of the element
*/
protected int myIndex;
private final IListChangeListener myListListener = new IListChangeListener() {
@Override
public void handleListChange(ListChangeEvent event) {
/*
* Real ugly, but... the problem is that ChangeManager.fireEvent() holds on to the "old"
* list of listeners while firing events. So when changes are made to the list -
* especially some that invalidate the objects that are referenced - this leads to
* problem later...
*/
if (getRealm() == null) return;
/*
* Check if the old index still match
*/
final int i = myIndex - myOffset;
if (i != -1 && i < myList.size() && myList.get(i) == myElement) return;
final int newIndex = calculateIndex();
final ValueDiff diff = Diffs.createValueDiff(myIndex, newIndex);
myIndex = newIndex;
getRealm().exec(new Runnable() {
@Override
public void run() {
fireValueChange(diff);
}
});
}
};
@Override
public synchronized void dispose() {
if (hasListeners()) {
lastListenerRemoved();
}
super.dispose();
}
@Override
protected void firstListenerAdded() {
super.firstListenerAdded();
myList.addListChangeListener(myListListener);
}
@Override
protected void lastListenerRemoved() {
myList.removeListChangeListener(myListListener);
super.lastListenerRemoved();
}
protected int calculateIndex() {
return myList.indexOf(myElement) + myOffset;
}
@Override
protected Object doGetValue() {
return myIndex;
}
@Override
public Object getValueType() {
return EcorePackage.Literals.EINT;
}
}