package org.marketcetera.photon.strategy.engine.ui;
import java.text.MessageFormat;
import org.eclipse.core.databinding.observable.IObservable;
import org.eclipse.core.databinding.observable.Observables;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.masterdetail.IObservableFactory;
import org.eclipse.core.databinding.observable.set.IObservableSet;
import org.eclipse.core.runtime.Assert;
import org.eclipse.emf.databinding.EMFProperties;
import org.eclipse.emf.databinding.IEMFListProperty;
import org.eclipse.jface.databinding.viewers.ObservableListTreeContentProvider;
import org.eclipse.jface.databinding.viewers.TreeStructureAdvisor;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.marketcetera.photon.commons.ui.IdentityComparer;
import org.marketcetera.photon.strategy.engine.model.core.DeployedStrategy;
import org.marketcetera.photon.strategy.engine.model.core.StrategyEngine;
import org.marketcetera.photon.strategy.engine.model.core.StrategyEngineCorePackage;
import org.marketcetera.util.misc.ClassVersion;
import com.google.common.collect.ForwardingObject;
/* $License$ */
/**
* Tree content provider for strategy engines and their deployed strategies. It
* expects as input an {@link IObservableList} of {@link StrategyEngine}
* objects. The input list will not be modified.
* <p>
* Instances of this class are thread confined. They can only be instantiated
* and accessed on a single UI thread. Some additional caveats to note:
* <ul>
* <li>The input IObservableList must be on the realm of the current display.
* None of its elements should be modified in any way, except in that realm,
* i.e. the UI thread.</li>
* <li>The viewer must have an IElementComparer that declares the input list
* equal to itself despite changes to its contents. {@link IdentityComparer} can
* be used for this purpose.</li>
* </ul>
*
* @author <a href="mailto:will@marketcetera.com">Will Horn</a>
* @version $Id: StrategyEnginesContentProvider.java 16154 2012-07-14 16:34:05Z colin $
* @since 2.0.0
*/
@ClassVersion("$Id: StrategyEnginesContentProvider.java 16154 2012-07-14 16:34:05Z colin $")
public class StrategyEnginesContentProvider extends ForwardingObject implements
ITreeContentProvider {
private final ObservableListTreeContentProvider mDelegate;
/**
* Constructor. Must be called from the realm of the current display.
*/
public StrategyEnginesContentProvider() {
mDelegate = new ObservableListTreeContentProvider(new FactoryImpl(),
new TreeStructureAdvisorImpl());
}
@Override
public Object[] getChildren(Object parentElement) {
return delegate().getChildren(parentElement);
}
@Override
public Object getParent(Object element) {
return delegate().getParent(element);
}
@Override
public boolean hasChildren(Object element) {
return delegate().hasChildren(element);
}
@Override
public Object[] getElements(Object inputElement) {
return delegate().getElements(inputElement);
}
@Override
public void dispose() {
delegate().dispose();
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
// validate input up front
if (newInput != null) {
Assert
.isLegal(
newInput instanceof IObservableList,
MessageFormat
.format(
"input [{0}] is not an IObservableList", newInput.getClass())); //$NON-NLS-1$
Realm realm = ((IObservableList) newInput).getRealm();
Assert
.isLegal(
realm.isCurrent(),
MessageFormat
.format(
"input [{0} on realm {1}] must be on the current display realm", newInput.getClass(), realm)); //$NON-NLS-1$;
Object elementType = ((IObservableList) newInput).getElementType();
Assert
.isLegal(
elementType == StrategyEngine.class,
MessageFormat
.format(
"input [{0} with element type {1}] should have element type StrategyEngine.class", newInput, elementType)); //$NON-NLS-1$;
Assert.isLegal(viewer != null, "viewer cannot be null"); //$NON-NLS-1$;
Assert
.isLegal(
viewer instanceof AbstractTreeViewer,
MessageFormat
.format(
"viewer [{0}] is not an AbstractTreeViewer", viewer.getClass())); //$NON-NLS-1$;
Assert.isLegal(((AbstractTreeViewer) viewer).getComparer() != null,
"viewer must have an IElementComparer set"); //$NON-NLS-1$;
}
delegate().inputChanged(viewer, oldInput, newInput);
}
@Override
protected ObservableListTreeContentProvider delegate() {
return mDelegate;
}
/**
* Returns the set of elements known to this content provider. Label
* providers may track this set if they need to be notified about additions
* before the viewer sees the added element, and notified about removals
* after the element was removed from the viewer. This is intended for use
* by label providers, as it will always return the items that need labels.
*
* @return readableSet of items that will need labels
*/
public IObservableSet getKnownElements() {
return delegate().getKnownElements();
}
/**
* Returns the set of known elements which have been realized in the viewer.
* Clients may track this set in order to perform custom actions on elements
* while they are known to be present in the viewer.
*
* @return the set of known elements which have been realized in the viewer.
*/
public IObservableSet getRealizedElements() {
return delegate().getRealizedElements();
}
/**
* Factory that creates observable lists of children for a given node.
*/
@ClassVersion("$Id: StrategyEnginesContentProvider.java 16154 2012-07-14 16:34:05Z colin $")
private static class FactoryImpl implements IObservableFactory {
private final static IEMFListProperty children = EMFProperties
.list(StrategyEngineCorePackage.Literals.STRATEGY_ENGINE__DEPLOYED_STRATEGIES);
public IObservable createObservable(final Object target) {
if (target instanceof IObservableList) {
/*
* A new delegating list is created since the content provider
* will dispose it and we do not want to dispose the input list.
*/
return Observables
.unmodifiableObservableList((IObservableList) target);
} else if (target instanceof StrategyEngine) {
return children.observe(target);
}
return null;
}
}
/**
* Helps/optimizes tree rendering. Not overriding getChildren because we
* want the child lists tracked.
*
* @See {@link TreeStructureAdvisor}
*/
@ClassVersion("$Id: StrategyEnginesContentProvider.java 16154 2012-07-14 16:34:05Z colin $")
private static class TreeStructureAdvisorImpl extends TreeStructureAdvisor {
@Override
public Object getParent(Object element) {
if (element instanceof DeployedStrategy) {
return ((DeployedStrategy) element).getEngine();
}
return null;
}
}
}