Fix for Bug 184755 [DataBinding] internal tree content provider does not work
diff --git a/bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/databinding/observable/set/AbstractObservableSet.java b/bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/databinding/observable/set/AbstractObservableSet.java
index a60608e..39a058b 100644
--- a/bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/databinding/observable/set/AbstractObservableSet.java
+++ b/bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/databinding/observable/set/AbstractObservableSet.java
@@ -42,7 +42,15 @@
 	protected AbstractObservableSet() {
 		this(Realm.getDefault());
 	}
+	
+	protected void firstListenerAdded() {
+		super.firstListenerAdded();
+	}
 
+	protected void lastListenerRemoved() {
+		super.lastListenerRemoved();
+	}
+	
 	protected AbstractObservableSet(Realm realm) {
 		super(realm);
 		changeSupport = new ChangeSupport(realm){
diff --git a/bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/internal/databinding/observable/tree/IUnorderedTreeProvider.java b/bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/internal/databinding/observable/tree/IUnorderedTreeProvider.java
index 6b5e5f6..81941c8 100644
--- a/bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/internal/databinding/observable/tree/IUnorderedTreeProvider.java
+++ b/bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/internal/databinding/observable/tree/IUnorderedTreeProvider.java
@@ -15,27 +15,22 @@
 import org.eclipse.core.databinding.observable.set.IObservableSet;
 
 /**
- * Objects that implement this interface are capable of describing a tree by
- * returning the set of children of any given element in the tree.
- * 
- * @since 3.3
+ * @since 1.0
+ *
  */
 public interface IUnorderedTreeProvider {
-
 	/**
-	 * @return the realm shared by all child sets
+	 * @return the realm for the createChildSet method
 	 */
 	public Realm getRealm();
-
+	
 	/**
-	 * Returns the children of the given element, or null if the element is a
-	 * leaf node. The caller of this method is expected to dispose the result
-	 * set when it is no longer needed.
+	 * Returns the children of the given element, or null if the element is a leaf node.
+	 * The caller of this method is expected to dispose the result set when it is no
+	 * longer needed.
 	 * 
-	 * @param element
-	 *            the tree path of the element to query
-	 * @return the children of the given element, or null if the element is a
-	 *         leaf node
+	 * @param element element to query
+	 * @return the children of the given element, or null if the element is a leaf node
 	 */
-	public IObservableSet createChildSet(TreePath element);
+	IObservableSet createChildSet(Object element);
 }
diff --git a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/databinding/observable/set/AbstractObservableSet.java b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/databinding/observable/set/AbstractObservableSet.java
index a60608e..39a058b 100644
--- a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/databinding/observable/set/AbstractObservableSet.java
+++ b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/databinding/observable/set/AbstractObservableSet.java
@@ -42,7 +42,15 @@
 	protected AbstractObservableSet() {
 		this(Realm.getDefault());
 	}
+	
+	protected void firstListenerAdded() {
+		super.firstListenerAdded();
+	}
 
+	protected void lastListenerRemoved() {
+		super.lastListenerRemoved();
+	}
+	
 	protected AbstractObservableSet(Realm realm) {
 		super(realm);
 		changeSupport = new ChangeSupport(realm){
diff --git a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/observable/tree/IUnorderedTreeProvider.java b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/observable/tree/IUnorderedTreeProvider.java
index 6b5e5f6..81941c8 100644
--- a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/observable/tree/IUnorderedTreeProvider.java
+++ b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/observable/tree/IUnorderedTreeProvider.java
@@ -15,27 +15,22 @@
 import org.eclipse.core.databinding.observable.set.IObservableSet;
 
 /**
- * Objects that implement this interface are capable of describing a tree by
- * returning the set of children of any given element in the tree.
- * 
- * @since 3.3
+ * @since 1.0
+ *
  */
 public interface IUnorderedTreeProvider {
-
 	/**
-	 * @return the realm shared by all child sets
+	 * @return the realm for the createChildSet method
 	 */
 	public Realm getRealm();
-
+	
 	/**
-	 * Returns the children of the given element, or null if the element is a
-	 * leaf node. The caller of this method is expected to dispose the result
-	 * set when it is no longer needed.
+	 * Returns the children of the given element, or null if the element is a leaf node.
+	 * The caller of this method is expected to dispose the result set when it is no
+	 * longer needed.
 	 * 
-	 * @param element
-	 *            the tree path of the element to query
-	 * @return the children of the given element, or null if the element is a
-	 *         leaf node
+	 * @param element element to query
+	 * @return the children of the given element, or null if the element is a leaf node
 	 */
-	public IObservableSet createChildSet(TreePath element);
+	IObservableSet createChildSet(Object element);
 }
diff --git a/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/internal/viewers/IPrefetchingTree.java b/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/internal/viewers/IPrefetchingTree.java
deleted file mode 100644
index ca443cf..0000000
--- a/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/internal/viewers/IPrefetchingTree.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2006, 2007 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
- *******************************************************************************/
-package org.eclipse.jface.internal.databinding.internal.viewers;
-
-/**
- * @since 3.3
- *
- */
-public interface IPrefetchingTree {
-    /**
-     * Returns true if and only if the content provider should
-     * try to prefetch the children of the given node.
-     * Prefetching uses unused CPU cycles to fetch the children 
-     * of visible nodes so that they expand faster. This will 
-     * generally cause the application to run faster so should 
-     * usually be enabled. 
-     * <p> 
-     * In some circumstances computing the children of a node may 
-     * require network resources that need to be conserved, so 
-     * prefetching can be explicitly disabled these nodes. This
-     * means that the user will need to wait for a "pending" node
-     * every time they expand the parent node.
-     * </p> 
-     * 
-     * @param parentNode
-     * @return true iff the children should be eagerly fetched
-     */
-    boolean shouldPrefetch(Object parentNode);
-}
diff --git a/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/internal/viewers/OrderedTreeContentProvider.java b/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/internal/viewers/OrderedTreeContentProvider.java
deleted file mode 100644
index 783ded3..0000000
--- a/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/internal/viewers/OrderedTreeContentProvider.java
+++ /dev/null
@@ -1,433 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2006, 2007 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
- *******************************************************************************/
-package org.eclipse.jface.internal.databinding.internal.viewers;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-
-import org.eclipse.core.databinding.observable.Diffs;
-import org.eclipse.core.databinding.observable.list.IObservableList;
-import org.eclipse.core.databinding.observable.set.AbstractObservableSet;
-import org.eclipse.core.databinding.observable.set.IObservableSet;
-import org.eclipse.core.databinding.observable.set.SetDiff;
-import org.eclipse.core.internal.databinding.observable.tree.IOrderedTreeProvider;
-import org.eclipse.jface.viewers.ITreePathContentProvider;
-import org.eclipse.jface.viewers.ITreeViewerListener;
-import org.eclipse.jface.viewers.TreeExpansionEvent;
-import org.eclipse.jface.viewers.TreePath;
-import org.eclipse.jface.viewers.TreeViewer;
-import org.eclipse.jface.viewers.Viewer;
-
-/**
- * Converts an IOrderedTreeProvider into an ITreeContentProvider that is
- * suitable for use with a JFace TreeViewer.
- * 
- * <p>
- * This content provider works correctly with trees containing duplicate
- * elements.
- * </p>
- * 
- * @since 3.3
- */
-public class OrderedTreeContentProvider implements ITreePathContentProvider {
-
-	private HashMap mapElementToTreeNode = new HashMap();
-
-	private LinkedList enqueuedPrefetches = new LinkedList();
-
-	class KnownElementsSet extends AbstractObservableSet {
-
-		/**
-		 */
-		protected KnownElementsSet() {
-			super(provider.getRealm());
-		}
-
-		/*
-		 * (non-Javadoc)
-		 * 
-		 * @see org.eclipse.jface.internal.databinding.provisional.observable.set.AbstractObservableSet#getWrappedSet()
-		 */
-		protected Set getWrappedSet() {
-			return mapElementToTreeNode.keySet();
-		}
-
-		void doFireDiff(Set added, Set removed) {
-			fireSetChange(Diffs.createSetDiff(added, removed));
-		}
-
-		void doFireStale(boolean isStale) {
-			if (isStale) {
-				fireStale();
-			} else {
-				fireSetChange(Diffs.createSetDiff(Collections.EMPTY_SET,
-						Collections.EMPTY_SET));
-			}
-		}
-
-		public Object getElementType() {
-			return Object.class;
-		}
-
-		protected void fireSetChange(SetDiff diff) {
-			super.fireSetChange(diff);
-		}
-	}
-
-	KnownElementsSet elements;
-
-	private ITreeViewerListener expandListener = new ITreeViewerListener() {
-		public void treeCollapsed(TreeExpansionEvent event) {
-		}
-
-		public void treeExpanded(TreeExpansionEvent event) {
-		}
-	};
-
-	private IPrefetchingTree prefetchingTree;
-
-	private IOrderedTreeProvider provider;
-
-	private Object pendingNode;
-
-	private int avoidViewerUpdates;
-
-	private TreeViewer treeViewer;
-
-	private int staleCount = 0;
-
-	private boolean useRefresh;
-
-	private int maxPrefetches = -1;
-
-	/**
-	 * Constructs a content provider that will render the given tree in a
-	 * TreeViewer.
-	 * 
-	 * @param provider
-	 *            IObservableTree that provides the contents of the tree. The
-	 *            given provider may optionally implement IPrefetchingTree if it
-	 *            wants to selectively enable or disable prefetching from
-	 *            particular nodes.
-	 * @param pendingNode
-	 *            element to insert whenever a node is being fetched in the
-	 *            background
-	 */
-	public OrderedTreeContentProvider(IOrderedTreeProvider provider,
-			Object pendingNode) {
-		this(provider, pendingNode, false);
-	}
-
-	/**
-	 * Constructs a content provider that will render the given tree in a
-	 * TreeViewer.
-	 * 
-	 * @param provider
-	 *            IObservableTree that provides the contents of the tree
-	 * @param pendingNode
-	 *            element to insert whenever a node is being fetched in the
-	 *            background
-	 * @param useRefresh
-	 *            true = notify the viewer of changes by calling refresh(...),
-	 *            false = notify the viewer of changes by calling add(...) and
-	 *            remove(...). Using false is more efficient, but may not work
-	 *            with TreeViewer subclasses.
-	 */
-	public OrderedTreeContentProvider(IOrderedTreeProvider provider,
-			Object pendingNode, boolean useRefresh) {
-		this.provider = provider;
-		this.prefetchingTree = PrefetchingTree.getPrefetchingTree(provider);
-		this.pendingNode = pendingNode;
-		this.useRefresh = useRefresh;
-		elements = new KnownElementsSet();
-	}
-
-	/**
-	 * Sets the maximum number of pending prefetches.
-	 * 
-	 * @param maxPrefetches
-	 */
-	public void setMaxPrefetches(int maxPrefetches) {
-		this.maxPrefetches = maxPrefetches;
-	}
-
-	/* package */IObservableList createChildList(TreePath treePath) {
-		Object[] segments = new Object[treePath.getSegmentCount()];
-		for (int i = 0; i < segments.length; i++) {
-			segments[i] = treePath.getSegment(i);
-		}
-		return provider.createChildList(new org.eclipse.core.internal.databinding.observable.tree.TreePath(segments));
-	}
-
-	/* package */void remove(Object element, List removals, boolean lastElement) {
-		if (avoidViewerUpdates == 0) {
-			for (Iterator iter = removals.iterator(); iter.hasNext();) {
-				Object next = iter.next();
-
-				OrderedTreeNode nextNode = (OrderedTreeNode) mapElementToTreeNode
-						.get(next);
-				if (nextNode != null) {
-					nextNode.removeParent(element);
-					removeIfUnused(nextNode);
-				}
-			}
-
-			if (lastElement || useRefresh) {
-				treeViewer.refresh(element);
-			} else {
-				treeViewer.remove(element, removals.toArray());
-			}
-		}
-	}
-
-	/* package */void add(TreePath element, List additions) {
-		if (avoidViewerUpdates == 0) {
-			// Handle new parents
-			addParent(element, additions);
-			if (useRefresh) {
-				treeViewer.refresh(element);
-			} else {
-				treeViewer.add(element, additions);
-			}
-		}
-	}
-
-	/* package */void insert(TreePath element, Object addition, int position) {
-		if (avoidViewerUpdates == 0) {
-			// Handle new parents
-			addParent(element, Collections.singletonList(addition));
-			if (useRefresh) {
-				treeViewer.refresh(element);
-			} else {
-				treeViewer.insert(element, addition, position);
-			}
-		}
-	}
-	
-	/**
-	 * Ensures that the given set of children have the given parent as one of
-	 * their parents.
-	 * 
-	 * @param parentPath
-	 * @param children
-	 */
-	private void addParent(TreePath parentPath, List children) {
-		for (Iterator iter = children.iterator(); iter.hasNext();) {
-			Object next = iter.next();
-
-			OrderedTreeNode nextNode = getNode(parentPath.createChildPath(next));
-			nextNode.addParent(parentPath);
-		}
-	}
-
-	/**
-	 * Returns the element that should be inserted into the tree when fetching
-	 * the children of the node that is both stale and empty.
-	 * 
-	 * @return the element that should be inserted into the tree when fetching
-	 *         the children of a node that is stale and empty
-	 */
-	public final Object getPendingNode() {
-		return pendingNode;
-	}
-
-	/**
-	 * Returns the IObservableList representing the children of the given node.
-	 * Never null.
-	 * 
-	 * @param parent
-	 *            parent element. Must be a valid node from the tree.
-	 * @return the list of children of the given parent node
-	 */
-	public IObservableList getChildrenList(TreePath parent) {
-		IObservableList result = getNode(parent).getChildrenList();
-
-		return result;
-	}
-
-	public void dispose() {
-		if (treeViewer != null) {
-			try {
-				avoidViewerUpdates++;
-				enqueuedPrefetches.clear();
-				Object[] keys = mapElementToTreeNode.keySet().toArray();
-
-				for (int i = 0; i < keys.length; i++) {
-					Object key = keys[i];
-
-					OrderedTreeNode result = (OrderedTreeNode) mapElementToTreeNode.get(key);
-					if (result != null) {
-						result.dispose();
-					}
-				}
-			} finally {
-				avoidViewerUpdates--;
-			}
-		}
-	}
-
-	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
-		// This should only ever be called for a single viewer
-		setViewer(viewer);
-
-		if (oldInput != null && newInput != null && oldInput.equals(newInput)) {
-			return;
-		}
-
-		try {
-			avoidViewerUpdates++;
-			removeIfUnused(oldInput);
-		} finally {
-			avoidViewerUpdates--;
-		}
-	}
-
-	private void removeIfUnused(Object element) {
-		OrderedTreeNode result = (OrderedTreeNode) mapElementToTreeNode
-				.get(element);
-		if (result != null && result.getParent() == null) {
-			mapElementToTreeNode.remove(element);
-			elements.doFireDiff(Collections.EMPTY_SET, Collections
-					.singleton(element));
-			result.dispose();
-		}
-	}
-
-	private void setViewer(Viewer viewer) {
-		if (!(viewer instanceof TreeViewer)) {
-			throw new IllegalArgumentException(
-					"This content provider can only be used with TreeViewers"); //$NON-NLS-1$
-		}
-		TreeViewer newTreeViewer = (TreeViewer) viewer;
-
-		if (newTreeViewer != treeViewer) {
-			if (treeViewer != null) {
-				treeViewer.removeTreeListener(expandListener);
-			}
-
-			this.treeViewer = newTreeViewer;
-			if (newTreeViewer != null) {
-				newTreeViewer.addTreeListener(expandListener);
-			}
-		}
-	}
-
-	public Object[] getChildren(TreePath parentElement) {
-		List result = getNode(parentElement).getChildren();
-
-		addParent(parentElement, result);
-
-		return result.toArray();
-	}
-
-	private OrderedTreeNode getNode(TreePath parentElement) {
-		OrderedTreeNode result = (OrderedTreeNode) mapElementToTreeNode
-				.get(parentElement);
-		if (result == null) {
-			result = new OrderedTreeNode(parentElement, this);
-			mapElementToTreeNode.put(parentElement, result);
-			elements.fireSetChange(Diffs.createSetDiff(Collections
-					.singleton(parentElement), Collections.EMPTY_SET));
-		}
-		return result;
-	}
-
-	/**
-	 * Returns the set of all elements that have been discovered in this tree so
-	 * far. Callers must not dispose this set. Never null.
-	 * 
-	 * @return the set of all elements that have been discovered in this tree so
-	 *         far.
-	 */
-	public IObservableSet getKnownElements() {
-		return elements;
-	}
-
-	/* package */void changeStale(int staleDelta) {
-		staleCount += staleDelta;
-		processPrefetches();
-		elements.setStale(staleCount != 0);
-	}
-
-	/**
-	 * Returns the associated tree viewer.
-	 * 
-	 * @return the associated tree viewer
-	 */
-	public TreeViewer getViewer() {
-		return treeViewer;
-	}
-
-	/**
-	 * Returns true iff the given element is stale.
-	 * 
-	 * @param element
-	 *            the element to query for staleness. Must exist in the tree.
-	 * @return true iff the given element is stale
-	 */
-	public boolean isDirty(TreePath element) {
-		return getChildrenList(element).isStale();
-	}
-
-	/* package */void enqueuePrefetch(OrderedTreeNode node) {
-		if (prefetchingTree.shouldPrefetch(node.getElement())) {
-			if (staleCount == 0) {
-				// Call node.getChildren()... this will cause us to start
-				// listening to the
-				// node and will trigger prefetching. Don't call prefetch since
-				// this method
-				// is intended to be called inside getters (which will simply
-				// return the
-				// fetched nodes) and prefetch() is intended to be called inside
-				// an asyncExec,
-				// which will notify the viewer directly of the newly discovered
-				// nodes.
-				node.getChildren();
-			} else {
-				enqueuedPrefetches.add(node);
-				while (maxPrefetches >= 0
-						&& enqueuedPrefetches.size() > maxPrefetches) {
-					enqueuedPrefetches.removeFirst();
-				}
-			}
-		}
-	}
-
-	private void processPrefetches() {
-		while (staleCount == 0 && !enqueuedPrefetches.isEmpty()) {
-			OrderedTreeNode next = (OrderedTreeNode) enqueuedPrefetches.removeLast();
-
-			// Note that we don't remove nodes from the prefetch queue when they
-			// are disposed,
-			// so we may encounter disposed nodes at this time.
-			if (!next.isDisposed()) {
-				next.prefetch();
-			}
-		}
-	}
-
-	public TreePath[] getParents(Object element) {
-		return new TreePath[0];
-	}
-
-	public boolean hasChildren(TreePath path) {
-		return getNode(path).shouldShowPlus();
-	}
-
-	public Object[] getElements(Object inputElement) {
-		return getChildren(new TreePath(new Object[]{inputElement}));
-	}
-
-}
diff --git a/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/internal/viewers/OrderedTreeNode.java b/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/internal/viewers/OrderedTreeNode.java
deleted file mode 100644
index 6fd08ae..0000000
--- a/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/internal/viewers/OrderedTreeNode.java
+++ /dev/null
@@ -1,306 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2006, 2007 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
- *******************************************************************************/
-package org.eclipse.jface.internal.databinding.internal.viewers;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.eclipse.core.databinding.observable.IStaleListener;
-import org.eclipse.core.databinding.observable.Observables;
-import org.eclipse.core.databinding.observable.StaleEvent;
-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.list.ListDiffEntry;
-import org.eclipse.jface.viewers.TreePath;
-
-/* package */class OrderedTreeNode implements IListChangeListener,
-		IStaleListener {
-	private OrderedTreeContentProvider contentProvider;
-
-	private TreePath element;
-
-	// Stores the set of parents (null if there are less than 2)
-	private HashSet parents = null;
-
-	// Stores one representative parent. If there is more than one parent,
-	// the complete set of parents can be found in the parents set.
-	Object parent;
-
-	/**
-	 * List of child elements.
-	 */
-	private IObservableList children;
-
-	private boolean hasPendingNode = false;
-
-	private boolean isStale;
-
-	private boolean listeningToChildren = false;
-
-	private boolean prefetchEnqueued = false;
-
-	/**
-	 * @param treePath
-	 * @param cp
-	 */
-	public OrderedTreeNode(TreePath treePath, OrderedTreeContentProvider cp) {
-		this.element = treePath;
-		this.contentProvider = cp;
-		children = contentProvider.createChildList(treePath);
-		if (children == null) {
-			children = Observables.emptyObservableList(contentProvider.getKnownElements().getRealm());
-			listeningToChildren = true;
-		}
-		hasPendingNode = children.isStale();
-	}
-
-	/**
-	 * @param parent
-	 */
-	public void addParent(Object parent) {
-		if (this.parent == null) {
-			this.parent = parent;
-		} else {
-			if (parent.equals(this.parent)) {
-				return;
-			}
-			if (parents == null) {
-				parents = new HashSet();
-				parents.add(this.parent);
-			}
-			parents.add(parent);
-		}
-	}
-
-	/**
-	 * @param parent
-	 */
-	public void removeParent(Object parent) {
-		if (this.parents != null) {
-			parents.remove(parent);
-		}
-
-		if (parent == this.parent) {
-			if (parents == null || parents.isEmpty()) {
-				this.parent = null;
-			} else {
-				this.parent = parents.iterator().next();
-			}
-		}
-
-		if (this.parents != null && this.parents.size() <= 1) {
-			this.parents = null;
-		}
-	}
-
-	/**
-	 * Returns the list of children for this node. If new children are
-	 * discovered later, they will be added directly to the viewer.
-	 * 
-	 * @return the list of children of this node
-	 */
-	public List getChildren() {
-		if (!listeningToChildren) {
-			listeningToChildren = true;
-			children.addListChangeListener(this);
-			hasPendingNode = children.isEmpty() && children.isStale();
-			children.addStaleListener(this);
-			updateStale();
-		}
-
-		// If the child set is stale and empty, show the "pending" node
-		if (hasPendingNode) {
-			Object pendingNode = contentProvider.getPendingNode();
-			return Collections.singletonList(pendingNode);
-		}
-		return children;
-	}
-
-	/**
-	 * @return the observable list of children for this node
-	 */
-	public IObservableList getChildrenList() {
-		return children;
-	}
-
-	private void updateStale() {
-		boolean willBeStale = children.isStale();
-		if (willBeStale != isStale) {
-			isStale = willBeStale;
-
-			contentProvider.changeStale(isStale ? 1 : -1);
-		}
-	}
-
-	/**
-	 * @return whether this node's children will change soon
-	 */
-	public boolean isStale() {
-		return isStale;
-	}
-
-	/**
-	 * Returns true if the viewer should show a plus sign for expanding this
-	 * node.
-	 * 
-	 * @return <code>true</code> if this node has children
-	 */
-	public boolean shouldShowPlus() {
-		if (children == null) {
-			// if (!hasPendingNode) {
-			// hasPendingNode = true;
-			// contentProvider.add(element,
-			// Collections.singleton(contentProvider.getPendingNode()));
-			// }
-			return true;
-		}
-		if (!listeningToChildren && !prefetchEnqueued) {
-			prefetchEnqueued = true;
-			contentProvider.enqueuePrefetch(this);
-		}
-		return !listeningToChildren || hasPendingNode || !children.isEmpty();
-	}
-
-	/**
-	 * Disposes this node and removes all remaining children.
-	 */
-	public void dispose() {
-		if (children != null) {
-			if (listeningToChildren) {
-				contentProvider.remove(element, children, true);
-				children.removeListChangeListener(this);
-				children.removeStaleListener(this);
-			}
-			children.dispose();
-			children = null;
-
-			if (listeningToChildren && isStale) {
-				contentProvider.changeStale(-1);
-			}
-		}
-	}
-
-	/**
-	 * @return <code>true</code> if this node is disposed
-	 */
-	public boolean isDisposed() {
-		return children == null;
-	}
-
-	/**
-	 * Returns one representative parent, or null if this node is unparented.
-	 * Use getParents() to get the complete set of known parents.
-	 * 
-	 * @return a parent node, or <code>null</code>
-	 */
-	public Object getParent() {
-		return parent;
-	}
-
-	/**
-	 * @return the set of known parent nodes
-	 */
-	public Set getParents() {
-		if (parents == null) {
-			if (parent == null) {
-				return Collections.EMPTY_SET;
-			}
-			return Collections.singleton(parent);
-		}
-		return parents;
-	}
-
-	/**
-	 * Called when the child set changes. Should not be called directly by the
-	 * viewer.
-	 */
-	public void handleListChange(ListChangeEvent event) {
-		boolean shouldHavePendingNode = children.isEmpty()
-				&& children.isStale();
-
-		List removals = new ArrayList();
-		ListDiffEntry[] differences = event.diff.getDifferences();
-		for (int i = 0; i < differences.length; i++) {
-			ListDiffEntry diffEntry = differences[i];
-			if (diffEntry.isAddition()) {
-				contentProvider.insert(element, diffEntry.getElement(),
-						diffEntry.getPosition());
-			} else {
-				removals.add(diffEntry.getElement());
-			}
-		}
-
-		// Check if we should add the pending node
-		if (shouldHavePendingNode && !hasPendingNode) {
-			contentProvider
-					.insert(element, contentProvider.getPendingNode(), 0);
-			hasPendingNode = true;
-		}
-
-		// Check if we should remove the pending node
-		if (!shouldHavePendingNode && hasPendingNode) {
-			removals.add(contentProvider.getPendingNode());
-			hasPendingNode = false;
-		}
-		if (!removals.isEmpty()) {
-			contentProvider.remove(element, removals, children.isEmpty()
-					&& !hasPendingNode);
-		}
-
-		updateStale();
-	}
-
-	public void handleStale(StaleEvent event) {
-		boolean shouldHavePendingNode = children.isEmpty()
-				&& children.isStale();
-
-		// Check if we should add the pending node
-		if (shouldHavePendingNode && !hasPendingNode) {
-			hasPendingNode = shouldHavePendingNode;
-			contentProvider.insert(element, Collections
-					.singletonList(contentProvider.getPendingNode()), 0);
-		}
-
-		// Check if we should remove the pending node
-		if (!shouldHavePendingNode && hasPendingNode) {
-			hasPendingNode = shouldHavePendingNode;
-			contentProvider.remove(element, Collections
-					.singletonList(contentProvider.getPendingNode()), true);
-		}
-
-		updateStale();
-	}
-
-	/**
-	 * @return the element
-	 */
-	public Object getElement() {
-		return element;
-	}
-
-	/**
-	 * 
-	 */
-	public void prefetch() {
-		List children = getChildren();
-		if (!children.isEmpty()) {
-			contentProvider.add(element, children);
-		} else {
-			// We need to remove the + sign, and adding/removing elements won't
-			// do the trick
-			contentProvider.getViewer().refresh(element);
-		}
-	}
-}
diff --git a/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/internal/viewers/PrefetchingTree.java b/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/internal/viewers/PrefetchingTree.java
deleted file mode 100644
index ac33cd5..0000000
--- a/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/internal/viewers/PrefetchingTree.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2006, 2007 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
- *******************************************************************************/
-package org.eclipse.jface.internal.databinding.internal.viewers;
-
-
-
-/* package */ class PrefetchingTree implements IPrefetchingTree {
-
-    private static IPrefetchingTree instance;
-
-    private PrefetchingTree() {
-    }
-
-    public boolean shouldPrefetch(Object parentNode) {
-        return true;
-    }
-    
-    /**
-     * @param treeProvider
-     * @return a prefetching tree
-     */
-    public static IPrefetchingTree getPrefetchingTree(Object treeProvider) {
-        if (treeProvider instanceof IPrefetchingTree) {
-            return (IPrefetchingTree)treeProvider;
-        }
-        if (instance == null) {
-            instance = new PrefetchingTree();
-        }
-        return instance;
-    }
-
-}
diff --git a/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/internal/viewers/UnorderedTreeContentProvider.java b/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/internal/viewers/UnorderedTreeContentProvider.java
deleted file mode 100644
index fbd7dbd..0000000
--- a/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/internal/viewers/UnorderedTreeContentProvider.java
+++ /dev/null
@@ -1,422 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2006, 2007 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
- *******************************************************************************/
-package org.eclipse.jface.internal.databinding.internal.viewers;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Set;
-
-import org.eclipse.core.databinding.observable.Diffs;
-import org.eclipse.core.databinding.observable.set.AbstractObservableSet;
-import org.eclipse.core.databinding.observable.set.IObservableSet;
-import org.eclipse.core.databinding.observable.set.SetDiff;
-import org.eclipse.core.internal.databinding.observable.tree.IUnorderedTreeProvider;
-import org.eclipse.jface.viewers.ITreePathContentProvider;
-import org.eclipse.jface.viewers.ITreeViewerListener;
-import org.eclipse.jface.viewers.TreeExpansionEvent;
-import org.eclipse.jface.viewers.TreePath;
-import org.eclipse.jface.viewers.TreeViewer;
-import org.eclipse.jface.viewers.Viewer;
-
-/**
- * Converts an ITreeProvider into an ITreeContentProvider that is suitable for
- * use with a JFace TreeViewer.
- * 
- * <p>
- * This content provider works correctly with trees containing duplicate
- * elements.
- * </p>
- * 
- * @since 3.3
- */
-public class UnorderedTreeContentProvider implements ITreePathContentProvider {
-
-	private HashMap mapElementToTreeNode = new HashMap();
-
-	private LinkedList enqueuedPrefetches = new LinkedList();
-
-	class KnownElementsSet extends AbstractObservableSet {
-
-		/**
-		 */
-		protected KnownElementsSet() {
-			super(provider.getRealm());
-		}
-
-		/*
-		 * (non-Javadoc)
-		 * 
-		 * @see org.eclipse.jface.internal.databinding.provisional.observable.set.AbstractObservableSet#getWrappedSet()
-		 */
-		protected Set getWrappedSet() {
-			return mapElementToTreeNode.keySet();
-		}
-
-		void doFireDiff(Set added, Set removed) {
-			fireSetChange(Diffs.createSetDiff(added, removed));
-		}
-
-		void doFireStale(boolean isStale) {
-			if (isStale) {
-				fireStale();
-			} else {
-				fireSetChange(Diffs.createSetDiff(Collections.EMPTY_SET,
-						Collections.EMPTY_SET));
-			}
-		}
-
-		public Object getElementType() {
-			return new Object();
-		}
-
-		protected void fireSetChange(SetDiff diff) {
-			super.fireSetChange(diff);
-		}
-	}
-
-	KnownElementsSet elements;
-
-	private ITreeViewerListener expandListener = new ITreeViewerListener() {
-		public void treeCollapsed(TreeExpansionEvent event) {
-		}
-
-		public void treeExpanded(TreeExpansionEvent event) {
-		}
-	};
-
-	private IPrefetchingTree prefetchingTree;
-
-	private IUnorderedTreeProvider provider;
-
-	private Object pendingNode;
-
-	private int avoidViewerUpdates;
-
-	private TreeViewer treeViewer;
-
-	private int staleCount = 0;
-
-	private boolean useRefresh;
-
-	private int maxPrefetches = -1;
-
-	/**
-	 * Constructs a content provider that will render the given tree in a
-	 * TreeViewer.
-	 * 
-	 * @param provider
-	 *            IObservableTree that provides the contents of the tree. The
-	 *            given provider map optionally implement IPrefetchingTree if it
-	 *            wants to selectively enable or disable prefetching from
-	 *            particular nodes.
-	 * @param pendingNode
-	 *            element to insert whenever a node is being fetched in the
-	 *            background
-	 */
-	public UnorderedTreeContentProvider(IUnorderedTreeProvider provider,
-			Object pendingNode) {
-		this(provider, pendingNode, false);
-	}
-
-	/**
-	 * Constructs a content provider that will render the given tree in a
-	 * TreeViewer.
-	 * 
-	 * @param provider
-	 *            IObservableTree that provides the contents of the tree
-	 * @param pendingNode
-	 *            element to insert whenever a node is being fetched in the
-	 *            background
-	 * @param useRefresh
-	 *            true = notify the viewer of changes by calling refresh(...),
-	 *            false = notify the viewer of changes by calling add(...) and
-	 *            remove(...). Using false is more efficient, but may not work
-	 *            with TreeViewer subclasses.
-	 */
-	public UnorderedTreeContentProvider(IUnorderedTreeProvider provider,
-			Object pendingNode, boolean useRefresh) {
-		this.provider = provider;
-		this.prefetchingTree = PrefetchingTree.getPrefetchingTree(provider);
-		this.pendingNode = pendingNode;
-		this.useRefresh = useRefresh;
-		elements = new KnownElementsSet();
-	}
-
-	/**
-	 * Sets the maximum number of pending prefetches.
-	 * 
-	 * @param maxPrefetches
-	 */
-	public void setMaxPrefetches(int maxPrefetches) {
-		this.maxPrefetches = maxPrefetches;
-	}
-
-	/* package */IObservableSet createChildSet(TreePath treePath) {
-		Object[] segments = new Object[treePath.getSegmentCount()];
-		for (int i = 0; i < segments.length; i++) {
-			segments[i] = treePath.getSegment(i);
-		}
-		return provider
-				.createChildSet(new org.eclipse.core.internal.databinding.observable.tree.TreePath(
-						segments));
-	}
-
-	/* package */void remove(Object element, Set removals, boolean lastElement) {
-		if (avoidViewerUpdates == 0) {
-			for (Iterator iter = removals.iterator(); iter.hasNext();) {
-				Object next = iter.next();
-
-				UnorderedTreeNode nextNode = (UnorderedTreeNode) mapElementToTreeNode
-						.get(next);
-				if (nextNode != null) {
-					nextNode.removeParent(element);
-					removeIfUnused(nextNode);
-				}
-			}
-
-			if (lastElement || useRefresh) {
-				treeViewer.refresh(element);
-			} else {
-				treeViewer.remove(element, removals.toArray());
-			}
-		}
-	}
-
-	/* package */void add(TreePath treePath, Set additions) {
-		if (avoidViewerUpdates == 0) {
-			// Handle new parents
-			addParent(treePath, additions);
-			if (useRefresh) {
-				treeViewer.refresh(treePath);
-			} else {
-				treeViewer.add(treePath, additions.toArray());
-			}
-		}
-	}
-
-	/**
-	 * Ensures that the given set of children have the given parent as one of
-	 * their parents.
-	 * 
-	 * @param parent
-	 * @param children
-	 */
-	private void addParent(TreePath parent, Set children) {
-		for (Iterator iter = children.iterator(); iter.hasNext();) {
-			Object next = iter.next();
-
-			UnorderedTreeNode nextNode = getNode(parent.createChildPath(next));
-			nextNode.addParent(parent);
-		}
-	}
-
-	/**
-	 * Returns the element that should be inserted into the tree when fetching
-	 * the children of the node that is both stale and empty.
-	 * 
-	 * @return the element that should be inserted into the tree when fetching
-	 *         the children of a node that is stale and empty
-	 */
-	public final Object getPendingNode() {
-		return pendingNode;
-	}
-
-	/**
-	 * Returns the IObservableSet representing the children of the given node.
-	 * Never null.
-	 * 
-	 * @param parent
-	 *            parent element. Must be a valid node from the tree.
-	 * @return the set of children of the given parent node
-	 */
-	public IObservableSet getChildrenSet(TreePath parent) {
-		IObservableSet result = getNode(parent).getChildrenSet();
-
-		return result;
-	}
-
-	public void dispose() {
-		if (treeViewer != null) {
-			try {
-				avoidViewerUpdates++;
-				enqueuedPrefetches.clear();
-				Object[] keys = mapElementToTreeNode.keySet().toArray();
-
-				for (int i = 0; i < keys.length; i++) {
-					Object key = keys[i];
-
-					UnorderedTreeNode result = (UnorderedTreeNode) mapElementToTreeNode
-							.get(key);
-					if (result != null) {
-						result.dispose();
-					}
-				}
-			} finally {
-				avoidViewerUpdates--;
-			}
-		}
-	}
-
-	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
-		// This should only ever be called for a single viewer
-		setViewer(viewer);
-
-		if (oldInput != null && newInput != null && oldInput.equals(newInput)) {
-			return;
-		}
-
-		try {
-			avoidViewerUpdates++;
-			removeIfUnused(oldInput);
-		} finally {
-			avoidViewerUpdates--;
-		}
-	}
-
-	private void removeIfUnused(Object element) {
-		UnorderedTreeNode result = (UnorderedTreeNode) mapElementToTreeNode
-				.get(element);
-		if (result != null && result.getParent() == null) {
-			mapElementToTreeNode.remove(element);
-			elements.doFireDiff(Collections.EMPTY_SET, Collections
-					.singleton(element));
-			result.dispose();
-		}
-	}
-
-	private void setViewer(Viewer viewer) {
-		if (!(viewer instanceof TreeViewer)) {
-			throw new IllegalArgumentException(
-					"This content provider can only be used with TreeViewers"); //$NON-NLS-1$
-		}
-		TreeViewer newTreeViewer = (TreeViewer) viewer;
-
-		if (newTreeViewer != treeViewer) {
-			if (treeViewer != null) {
-				treeViewer.removeTreeListener(expandListener);
-			}
-
-			this.treeViewer = newTreeViewer;
-			if (newTreeViewer != null) {
-				newTreeViewer.addTreeListener(expandListener);
-			}
-		}
-	}
-
-	public Object[] getChildren(TreePath parentPath) {
-		Set result = getNode(parentPath).getChildren();
-
-		addParent(parentPath, result);
-
-		return result.toArray();
-	}
-
-	private UnorderedTreeNode getNode(TreePath parentPath) {
-		UnorderedTreeNode result = (UnorderedTreeNode) mapElementToTreeNode
-				.get(parentPath);
-		if (result == null) {
-			result = new UnorderedTreeNode(parentPath, this);
-			mapElementToTreeNode.put(parentPath, result);
-			elements.fireSetChange(Diffs.createSetDiff(Collections
-					.singleton(parentPath), Collections.EMPTY_SET));
-		}
-		return result;
-	}
-
-	public TreePath[] getParents(Object element) {
-		return new TreePath[0];
-	}
-
-	public boolean hasChildren(TreePath element) {
-		return getNode(element).shouldShowPlus();
-	}
-
-	public Object[] getElements(Object inputElement) {
-		return getChildren(new TreePath(new Object[]{inputElement}));
-	}
-
-	/**
-	 * Returns the set of all elements that have been discovered in this tree so
-	 * far. Callers must not dispose this set. Never null.
-	 * 
-	 * @return the set of all elements that have been discovered in this tree so
-	 *         far.
-	 */
-	public IObservableSet getKnownElements() {
-		return elements;
-	}
-
-	/* package */void changeStale(int staleDelta) {
-		staleCount += staleDelta;
-		processPrefetches();
-		elements.setStale(staleCount != 0);
-	}
-
-	/**
-	 * Returns the associated tree viewer.
-	 * 
-	 * @return the associated tree viewer
-	 */
-	public TreeViewer getViewer() {
-		return treeViewer;
-	}
-
-	/**
-	 * Returns true iff the given element is stale.
-	 * 
-	 * @param element
-	 *            the element to query for staleness. Must exist in the tree.
-	 * @return true iff the given element is stale
-	 */
-	public boolean isDirty(TreePath element) {
-		return getChildrenSet(element).isStale();
-	}
-
-	/* package */void enqueuePrefetch(UnorderedTreeNode node) {
-		if (prefetchingTree.shouldPrefetch(node.getElement())) {
-			if (staleCount == 0) {
-				// Call node.getChildren()... this will cause us to start
-				// listening to the
-				// node and will trigger prefetching. Don't call prefetch since
-				// this method
-				// is intended to be called inside getters (which will simply
-				// return the
-				// fetched nodes) and prefetch() is intended to be called inside
-				// an asyncExec,
-				// which will notify the viewer directly of the newly discovered
-				// nodes.
-				node.getChildren();
-			} else {
-				enqueuedPrefetches.add(node);
-				while (maxPrefetches >= 0
-						&& enqueuedPrefetches.size() > maxPrefetches) {
-					enqueuedPrefetches.removeFirst();
-				}
-			}
-		}
-	}
-
-	private void processPrefetches() {
-		while (staleCount == 0 && !enqueuedPrefetches.isEmpty()) {
-			UnorderedTreeNode next = (UnorderedTreeNode) enqueuedPrefetches
-					.removeLast();
-
-			// Note that we don't remove nodes from the prefetch queue when they
-			// are disposed,
-			// so we may encounter disposed nodes at this time.
-			if (!next.isDisposed()) {
-				next.prefetch();
-			}
-		}
-	}
-}
diff --git a/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/provisional/viewers/IParentProvider.java b/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/provisional/viewers/IParentProvider.java
new file mode 100644
index 0000000..f4b35bf
--- /dev/null
+++ b/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/provisional/viewers/IParentProvider.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 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
+ *     Stefan Xenos, IBM - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jface.internal.databinding.provisional.viewers;
+
+/**
+ * Returns the parent of elements in a tree.
+ * 
+ * @since 3.3
+ */
+public interface IParentProvider {
+	
+    /**
+     * TODO: comment me
+     * 
+     * @param child
+     * @return TODO: comment
+     */
+    public Object getParent(Object child);
+}
diff --git a/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/internal/viewers/UnorderedTreeNode.java b/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/provisional/viewers/TreeNode.java
similarity index 70%
rename from bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/internal/viewers/UnorderedTreeNode.java
rename to bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/provisional/viewers/TreeNode.java
index f9abf73..9748ff8 100644
--- a/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/internal/viewers/UnorderedTreeNode.java
+++ b/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/provisional/viewers/TreeNode.java
@@ -7,8 +7,9 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ *     Stefan Xenos, IBM - initial API and implementation
  *******************************************************************************/
-package org.eclipse.jface.internal.databinding.internal.viewers;
+package org.eclipse.jface.internal.databinding.provisional.viewers;
 
 import java.util.Collections;
 import java.util.HashSet;
@@ -20,11 +21,13 @@
 import org.eclipse.core.databinding.observable.set.IObservableSet;
 import org.eclipse.core.databinding.observable.set.ISetChangeListener;
 import org.eclipse.core.databinding.observable.set.SetChangeEvent;
-import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.core.databinding.observable.set.SetDiff;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.widgets.Control;
 
-/* package */ class UnorderedTreeNode implements ISetChangeListener, IStaleListener {
+/* package */ class TreeNode implements ISetChangeListener, IStaleListener {
     private UnorderedTreeContentProvider contentProvider;
-    private TreePath treePath;
+    private Object element;
     
     // Stores the set of parents (null if there are less than 2)
     private HashSet parents = null;
@@ -47,12 +50,12 @@
      * @param element
      * @param cp
      */
-    public UnorderedTreeNode(TreePath element, UnorderedTreeContentProvider cp) {
-        this.treePath = element;
+    public TreeNode(Object element, UnorderedTreeContentProvider cp) {
+        this.element = element;
         this.contentProvider = cp;
         children = contentProvider.createChildSet(element);
         if (children == null) {
-            children = Observables.emptyObservableSet(contentProvider.getKnownElements().getRealm());
+            children = Observables.emptyObservableSet();
             listeningToChildren = true;
         }
         hasPendingNode = children.isStale();
@@ -101,7 +104,7 @@
      * Returns the set of children for this node. If new children are discovered later, they
      * will be added directly to the viewer.
      *  
-     * @return the set of children
+     * @return TODO
      */
     public Set getChildren() {
         if (!listeningToChildren) {
@@ -121,7 +124,7 @@
     }
     
     /**
-     * @return the observable set of children
+     * @return TODO
      */
     public IObservableSet getChildrenSet() {
         return children;
@@ -137,7 +140,7 @@
     }
     
     /**
-     * @return <code>true</code> if the children of this node will change soon
+     * @return TODO
      */
     public boolean isStale() {
         return isStale;
@@ -147,7 +150,7 @@
      * Returns true if the viewer should show a plus sign for expanding this 
      * node. 
      * 
-     * @return <code>true</code> if this node may have children
+     * @return TODO
      */
     public boolean shouldShowPlus() {
         if (children == null) {
@@ -170,7 +173,7 @@
     public void dispose() {
         if (children != null) {
             if (listeningToChildren) {
-                contentProvider.remove(treePath, children, true);
+                contentProvider.remove(element, children, true);
                 children.removeSetChangeListener(this);
                 children.removeStaleListener(this);
             }
@@ -184,7 +187,7 @@
     }
     
     /**
-     * @return <code>true</code> if this node is disposed
+     * @return TODO
      */
     public boolean isDisposed() {
         return children == null;
@@ -194,32 +197,49 @@
      * Returns one representative parent, or null if this node is unparented. Use
      * getParents() to get the complete set of known parents.
      * 
-     * @return a parent node, or null
+     * @return TODO
      */
     public Object getParent() {
         return parent;
     }
     
     /**
-     * @return the set of known parent nodes
+     * 
+     * @return the set of all known parents for this node
      */
     public Set getParents() {
         if (parents == null) {
             if (parent == null) {
                 return Collections.EMPTY_SET;
+            } else {
+                return Collections.singleton(parent);
             }
-			return Collections.singleton(parent);
+        } else {
+            return parents;
         }
-		return parents;
     }
     
     /**
      * Called when the child set changes. Should not be called directly by the viewer.
      */
     public void handleSetChange(SetChangeEvent event) {
+        SetDiff diff = event.diff;
+        TreeViewer viewer = this.contentProvider.getViewer();
+        if (viewer != null) {
+            Control control = viewer.getControl();
+            if (control != null) {
+                if (control.isDisposed()) {
+                    // If the widgetry was disposed without notifying the content provider, then
+                    // dispose the content provider now and stop processing events.
+                    contentProvider.dispose();
+                    return;
+                }
+            }
+        }
+        
         boolean shouldHavePendingNode = children.isEmpty() && children.isStale();
         
-        Set additions = event.diff.getAdditions();
+        Set additions = diff.getAdditions();
         // Check if we should add the pending node
         if (shouldHavePendingNode && !hasPendingNode) {
             HashSet newAdditions = new HashSet();
@@ -229,7 +249,7 @@
             hasPendingNode = true;
         }
 
-        Set removals = event.diff.getRemovals();
+        Set removals = diff.getRemovals();
         // Check if we should remove the pending node
         if (!shouldHavePendingNode && hasPendingNode) {
             HashSet newRemovals = new HashSet();
@@ -239,50 +259,75 @@
             hasPendingNode = false;
         }
         if (!additions.isEmpty()) {
-            contentProvider.add(treePath, additions);
+            contentProvider.add(element, additions);
         }
         if (!removals.isEmpty()) {
-            contentProvider.remove(treePath, removals, children.isEmpty() && !hasPendingNode);
+            contentProvider.remove(element, removals, children.isEmpty() && !hasPendingNode);
         }
         
         updateStale();
     }
 
-    public void handleStale(StaleEvent event) {
+    public void handleStale(StaleEvent staleEvent) {
+        TreeViewer viewer = this.contentProvider.getViewer();
+        if (viewer != null) {
+            Control control = viewer.getControl();
+            if (control != null) {
+                if (control.isDisposed()) {
+                    // If the widgetry was disposed without notifying the content provider, then
+                    // dispose the content provider now and stop processing events.
+                    contentProvider.dispose();
+                    return;
+                }
+            }
+        }
+        
         boolean shouldHavePendingNode = children.isEmpty() && children.isStale();
         
         // Check if we should add the pending node
         if (shouldHavePendingNode && !hasPendingNode) {
             hasPendingNode = shouldHavePendingNode;
-            contentProvider.add(treePath, Collections.singleton(contentProvider.getPendingNode()));
+            contentProvider.add(element, Collections.singleton(contentProvider.getPendingNode()));
         }
         
         // Check if we should remove the pending node
         if (!shouldHavePendingNode && hasPendingNode) {
             hasPendingNode = shouldHavePendingNode;
-            contentProvider.remove(treePath, Collections.singleton(contentProvider.getPendingNode()), true);
+            contentProvider.remove(element, Collections.singleton(contentProvider.getPendingNode()), true);
         }
         
         updateStale();
     }
 
     /**
-     * @return the element
+     * @return TODO
      */
     public Object getElement() {
-        return treePath;
+        return element;
     }
 
     /**
      * 
      */
     public void prefetch() {
+        TreeViewer viewer = this.contentProvider.getViewer();
+        if (viewer != null) {
+            Control control = viewer.getControl();
+            if (control != null) {
+                if (control.isDisposed()) {
+                    // If the widgetry has been disposed, then avoid sending anything
+                    // to the viewer.
+                    return;
+                }
+            }
+        }
+        
         Set children = getChildren();
         if (!children.isEmpty()) {
-            contentProvider.add(treePath, children);
+            contentProvider.add(element, children);
         } else {
             // We need to remove the + sign, and adding/removing elements won't do the trick
-            contentProvider.getViewer().refresh(treePath);
+            contentProvider.getViewer().refresh(element);
         }
     }
 }
diff --git a/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/provisional/viewers/UnorderedTreeContentProvider.java b/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/provisional/viewers/UnorderedTreeContentProvider.java
new file mode 100644
index 0000000..4a00edb
--- /dev/null
+++ b/bundles/org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/provisional/viewers/UnorderedTreeContentProvider.java
@@ -0,0 +1,528 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 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
+ *     Stefan Xenos, IBM - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jface.internal.databinding.provisional.viewers;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.databinding.observable.Diffs;
+import org.eclipse.core.databinding.observable.set.AbstractObservableSet;
+import org.eclipse.core.databinding.observable.set.IObservableSet;
+import org.eclipse.core.databinding.observable.set.SetDiff;
+import org.eclipse.core.internal.databinding.observable.tree.IUnorderedTreeProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.ITreePathContentProvider;
+import org.eclipse.jface.viewers.ITreeViewerListener;
+import org.eclipse.jface.viewers.TreeExpansionEvent;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+
+/**
+ * TODO: comment
+ * @since 3.3
+ *
+ */
+public class UnorderedTreeContentProvider implements ITreeContentProvider, ITreePathContentProvider {
+
+    private HashMap mapElementToTreeNode = new HashMap();
+    private LinkedList enqueuedPrefetches = new LinkedList();
+    private IParentProvider rootParentProvider = null;
+    private boolean useTreePaths = false;
+    
+    class KnownElementsSet extends AbstractObservableSet {
+        
+        protected KnownElementsSet() {
+            super(); 
+        }
+
+        /* (non-Javadoc)
+         * @see org.eclipse.jface.internal.databinding.provisional.observable.set.AbstractObservableSet#getWrappedSet()
+         */
+        protected Set getWrappedSet() {
+            return mapElementToTreeNode.keySet();
+        }
+        
+        void doFireDiff(Set added, Set removed) {
+            fireSetChange(Diffs.createSetDiff(added, removed));
+        }
+        
+        public void fireSetChange(SetDiff diff) {
+        	super.fireSetChange(diff);
+        }
+
+        void doFireStale(boolean isStale) {
+            if (isStale) {
+                fireStale();
+            } else {
+                fireSetChange(Diffs.createSetDiff(Collections.EMPTY_SET, Collections.EMPTY_SET));
+            }
+        }
+        
+        /* (non-Javadoc)
+         * @see org.eclipse.jface.internal.databinding.provisional.observable.set.IObservableSet#getElementType()
+         */
+        public Object getElementType() {
+            return new Object();
+        }
+    }
+    
+    KnownElementsSet elements = new KnownElementsSet();
+    
+    private ITreeViewerListener expandListener = new ITreeViewerListener() {
+        public void treeCollapsed(TreeExpansionEvent event) {
+        }
+
+        public void treeExpanded(TreeExpansionEvent event) {
+        }
+    };
+
+    private IUnorderedTreeProvider provider;
+    private Object pendingNode;
+
+    private int avoidViewerUpdates;
+
+    private TreeViewer treeViewer;
+
+    private int staleCount = 0;
+    private boolean useRefresh;
+    private int maxPrefetches = 0;
+
+    /**
+     * Constructs a content provider that will render the given tree in a TreeViewer. 
+     * 
+     * @param provider IObservableTree that provides the contents of the tree
+     * @param pendingNode element to insert whenever a node is being fetched in the background
+     * @param useRefresh true = notify the viewer of changes by calling refresh(...), false =
+     *        notify the viewer of changes by calling add(...) and remove(...). Using false
+     *        is more efficient, but may not work with TreeViewer subclasses. 
+     */
+    public UnorderedTreeContentProvider(IUnorderedTreeProvider provider, 
+            Object pendingNode, boolean useRefresh) {
+        this.provider = provider;
+        this.pendingNode = pendingNode;
+        this.useRefresh = useRefresh;
+    }
+ 
+    /**
+     * Sets whether this content provider should add/remove elements using
+     * TreePaths (true) or elements (false).
+     * 
+     * <p></p>
+     * <p>When using elements:</p>
+     * 
+     * <ul>
+     * <li>Cycles are permitted (elements can be their own ancestor)</li>
+     * <li>Addition, removal, and refresh are slightly faster</li>
+     * <li>It is not possible to have more than one content provider per tree</li>
+     * <li>The setRootPath(...) method is ignored</li>
+     * </ul>
+     * 
+     * <p></p>
+     * <p>When using TreePaths:</p>
+     * 
+     * <ul>
+     * <li>Cycles are not permitted (elements cannot be their own parent)</li>
+     * <li>Addition, removal, and refresh are slightly slower</li>
+     * <li>It is possible to use more than one content provider in the same tree</li>
+     * <li>The setRootPath(...) method can be used to direct the output to a particular
+     *     subtree</li>
+     * </ul>
+     * 
+     * @param usePaths
+     */
+    public void useTreePaths(boolean usePaths) {
+        this.useTreePaths = usePaths;
+    }
+    
+    /**
+     * @param rootParentProvider
+     */
+    public void setRootPath(IParentProvider rootParentProvider) {
+    	this.rootParentProvider = rootParentProvider;
+    }
+    
+    /**
+     * @param maxPrefetches
+     */
+    public void setMaxPrefetches(int maxPrefetches) {
+        this.maxPrefetches = maxPrefetches; 
+    }
+    
+    /* package */ IObservableSet createChildSet(Object element) {
+        return provider.createChildSet(element);
+    }
+
+    /* package */ void remove(Object element, Set removals, boolean lastElement) {
+        if (removals.isEmpty()) {
+            return;
+        }
+        if (avoidViewerUpdates == 0) {
+            if (lastElement || useRefresh) {
+                doRefresh(element);
+            } else {
+                if (useTreePaths) {
+                    List toRemove = new ArrayList();
+                    TreePath[] parents = getParents(element);
+                    for (int i = 0; i < parents.length; i++) {
+                        TreePath parent = parents[i];
+
+                        for (Iterator iter = removals.iterator(); iter.hasNext();) {
+                            Object elementToRemove = (Object) iter.next();
+                            
+                            toRemove.add(parent.createChildPath(element).createChildPath(elementToRemove));
+                        }
+                    }
+                    
+                    treeViewer.remove((TreePath[]) toRemove.toArray(new TreePath[toRemove.size()]));
+                } else {
+                    treeViewer.remove(element, removals.toArray());
+                }
+            }
+            for (Iterator iter = removals.iterator(); iter.hasNext();) {
+                Object next = (Object) iter.next();
+                
+                TreeNode nextNode = (TreeNode)mapElementToTreeNode.get(next);
+                if (nextNode != null) {
+                    nextNode.removeParent(element);
+                    removeIfUnused(nextNode);
+                }
+            }
+        }
+    }
+
+    /* package */ void add(Object element, Set additions) {
+        if (additions.isEmpty()) {
+            return;
+        }
+        if (avoidViewerUpdates == 0) {
+            // Handle new parents
+            addParent(element, additions);
+            if (useRefresh) {
+                doRefresh(element);
+            } else {
+                if (useTreePaths) {
+                    TreePath[] parents = getParents(element);
+                    for (int i = 0; i < parents.length; i++) {
+                        TreePath parent = parents[i];
+                        
+                        treeViewer.add(parent.createChildPath(element), additions.toArray());
+                    }
+                } else {
+                    treeViewer.add(element, additions.toArray());
+                }
+            }
+        }
+    }
+
+    private void doRefresh(Object element) {
+        treeViewer.refresh(element);
+    }
+    
+    /**
+     * Ensures that the given set of children have the given parent as 
+     * one of their parents.
+     *  
+     * @param parent
+     * @param children
+     */
+    private void addParent(Object parent, Set children) {
+        for (Iterator iter = children.iterator(); iter.hasNext();) {
+            Object next = (Object) iter.next();
+            
+            TreeNode nextNode = getNode(next);
+            nextNode.addParent(parent);
+        }
+    }
+
+    /**
+     * @return saouesnth
+     */
+    public final Object getPendingNode() {
+        return pendingNode;
+    }
+    
+    /**
+     * @param parent
+     * @return aueosnht
+     */
+    public IObservableSet getChildrenSet(Object parent) {
+        IObservableSet result = getNode(parent).getChildrenSet();
+        
+        return result;
+    }
+    
+    public void dispose() {
+        if (treeViewer != null) {
+            try {
+                avoidViewerUpdates++;
+                enqueuedPrefetches.clear();
+                Object[] keys = mapElementToTreeNode.keySet().toArray();
+    
+                for (int i = 0; i < keys.length; i++) {
+                    Object key = keys[i];
+    
+                    TreeNode result = (TreeNode)mapElementToTreeNode.get(key);
+                    if (result != null) {
+                        result.dispose();
+                    }
+                }
+                setViewer(null);
+            } finally {
+                avoidViewerUpdates--;
+            }
+        }
+    }
+    
+    public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+        // This should only ever be called for a single viewer
+        setViewer(viewer);
+        
+        if (oldInput != null && newInput != null && oldInput.equals(newInput)) {
+            return;
+        }
+        
+        try {
+            avoidViewerUpdates++;
+            TreeNode oldNode = (TreeNode)mapElementToTreeNode.get(oldInput);
+            if (oldNode != null) {
+                removeIfUnused(oldNode);
+            }
+        } finally {
+            avoidViewerUpdates--;
+        }
+    }
+    
+    private void removeIfUnused(TreeNode toRemove) {
+        //TreeNode result = (TreeNode)mapElementToTreeNode.get(element);
+        Object element = toRemove.getElement();
+        if (toRemove.getParent() == null) {
+            mapElementToTreeNode.remove(element);
+            elements.doFireDiff(Collections.EMPTY_SET, Collections.singleton(element));
+            toRemove.dispose();
+        }
+    }
+
+    private void setViewer(Viewer viewer) {
+        if (viewer != null && !(viewer instanceof TreeViewer)) {
+            throw new IllegalArgumentException("This content provider can only be used with TreeViewers"); //$NON-NLS-1$
+        }
+        TreeViewer newTreeViewer = (TreeViewer) viewer;
+        
+        if (newTreeViewer != treeViewer) {
+            if (treeViewer != null) {
+                treeViewer.removeTreeListener(expandListener);
+            }
+            
+            this.treeViewer = newTreeViewer;
+            if (newTreeViewer != null) {
+                newTreeViewer.addTreeListener(expandListener);
+            }
+        }
+    }
+
+    public Object[] getChildren(Object parentElement) {
+        Set result = getNode(parentElement).getChildren();
+        
+        addParent(parentElement, result);
+        
+        return result.toArray();
+    }
+
+    private TreeNode getNode(Object parentElement) {
+        TreeNode result = (TreeNode)mapElementToTreeNode.get(parentElement);
+        if (result == null) {
+            result = new TreeNode(parentElement, this);
+            mapElementToTreeNode.put(parentElement, result);
+            elements.fireSetChange(Diffs.createSetDiff(Collections.singleton(parentElement), 
+                    Collections.EMPTY_SET));
+        }
+        return result;
+    }
+
+    public Object getParent(Object element) {
+        Object result = getNode(element).getParent();
+        if (result == null && rootParentProvider != null) {
+            result = rootParentProvider.getParent(element);
+        }
+        return result;
+    }
+
+    public boolean hasChildren(Object element) {
+        return getNode(element).shouldShowPlus();
+    }
+
+    public Object[] getElements(Object inputElement) {
+        return getChildren(inputElement);
+    }
+    
+    /**
+     * @return aouesnth
+     */
+    public IObservableSet getKnownElements() {
+        return elements;
+    }
+    
+    /* package */ void changeStale(int staleDelta) {
+        staleCount += staleDelta;
+        processPrefetches();
+        elements.setStale(staleCount != 0);
+    }
+
+    /**
+     * @return aoueesnth      
+     */
+    public TreeViewer getViewer() {
+        return treeViewer;
+    }
+
+    /**
+     * @param element
+     * @return aoeusnth
+     */
+    public boolean isDirty(Object element) {
+        return false;
+    }
+
+    /* package */ void enqueuePrefetch(TreeNode node) {
+        if (maxPrefetches > 0 || maxPrefetches == -1) {
+            if (staleCount == 0) {
+                // Call node.getChildren()... this will cause us to start listening to the 
+                // node and will trigger prefetching. Don't call prefetch since this method
+                // is intended to be called inside getters (which will simply return the
+                // fetched nodes) and prefetch() is intended to be called inside an asyncExec,
+                // which will notify the viewer directly of the newly discovered nodes.
+                node.getChildren();
+            } else {
+                enqueuedPrefetches.add(node);
+                while (maxPrefetches >= 0 && enqueuedPrefetches.size() > maxPrefetches) {
+                    enqueuedPrefetches.removeFirst();
+                }
+            }
+        }
+    }
+
+    private void processPrefetches() {
+        while (staleCount == 0 && !enqueuedPrefetches.isEmpty()) {
+            TreeNode next = (TreeNode)enqueuedPrefetches.removeLast();
+            
+            // Note that we don't remove nodes from the prefetch queue when they are disposed,
+            // so we may encounter disposed nodes at this time. 
+            if (!next.isDisposed()) {
+                next.prefetch();
+            }
+        }
+    }
+
+    public Object[] getChildren(TreePath parentPath) {
+        return getChildren(parentPath.getLastSegment());
+    }
+
+    public TreePath[] getParents(Object element) {
+        // Compute all paths that do not contain cycles
+    	/**
+    	 * List of Lists
+    	 */
+        List parentPaths = computeParents(element, new HashSet());
+        
+        /**
+         * List of TreePath
+         */
+        List result = new ArrayList();
+       
+        for (Iterator iterator = parentPaths.iterator(); iterator.hasNext();) {
+			List nextPath = (List) iterator.next();
+			            
+            LinkedList resultPath = new LinkedList();
+            resultPath.addAll(nextPath);
+        	Object nextParent = resultPath.isEmpty() ? element : resultPath.getFirst();
+            for(;nextParent != null;) {
+            	if (rootParentProvider != null) {
+            		nextParent = rootParentProvider.getParent(nextParent);
+                    if (nextParent != null) {
+                        resultPath.addFirst(nextParent);
+                    }
+            	} else {
+            		nextParent = null;
+            	}
+            }
+            
+            result.add(new TreePath(resultPath.toArray()));
+        }
+        
+        if (result.isEmpty() && rootParentProvider != null) {
+            Object nextParent = rootParentProvider.getParent(element);
+            if (nextParent != null) {
+                LinkedList resultPath = new LinkedList();
+                while (nextParent != null) {
+                    resultPath.addFirst(nextParent);
+                    nextParent = rootParentProvider.getParent(nextParent);
+                }
+                
+                result.add(new TreePath(resultPath.toArray()));
+            }
+            
+        }
+        
+        return (TreePath[]) result.toArray(new TreePath[result.size()]);
+    }
+    
+    /**
+     * 
+     * @param node
+     * @param toIgnore
+     * @return a list of Lists, indicating all known paths to the given node
+     */
+    private List computeParents(Object node, HashSet toIgnore) {
+        List result = new ArrayList();
+        boolean containedNode = toIgnore.add(node);
+        
+        TreeNode tn = getNode(node);
+        
+        HashSet parents = new HashSet();
+        parents.addAll(tn.getParents());
+        parents.removeAll(toIgnore);
+        if (parents.isEmpty()) {
+            ArrayList newPath = new ArrayList();
+            result.add(newPath);
+        } else {
+        	for (Iterator iterator = parents.iterator(); iterator.hasNext();) {
+				Object parent = iterator.next();
+				
+				List parentPaths = computeParents(parent, toIgnore);
+
+				for (Iterator iterator2 = parentPaths.iterator(); iterator2
+						.hasNext();) {
+					List parentPath = (List) iterator2.next();
+					
+                    parentPath.add(parent);
+                    result.add(parentPath);
+                }
+			}
+        }
+        
+        if (containedNode) {
+            toIgnore.remove(node);
+        }
+        return result;
+    }
+
+    public boolean hasChildren(TreePath path) {
+        return hasChildren(path.getLastSegment());
+    }
+}
diff --git a/examples/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/contentprovider/test/TreeContentProviderTest.java b/examples/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/contentprovider/test/TreeContentProviderTest.java
index 5f38985..8019357 100644
--- a/examples/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/contentprovider/test/TreeContentProviderTest.java
+++ b/examples/org.eclipse.jface.examples.databinding/src/org/eclipse/jface/examples/databinding/contentprovider/test/TreeContentProviderTest.java
@@ -16,8 +16,8 @@
 import org.eclipse.core.databinding.observable.set.UnionSet;
 import org.eclipse.core.databinding.observable.set.WritableSet;
 import org.eclipse.core.internal.databinding.observable.tree.IUnorderedTreeProvider;
-import org.eclipse.core.internal.databinding.observable.tree.TreePath;
-import org.eclipse.jface.internal.databinding.internal.viewers.UnorderedTreeContentProvider;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.internal.databinding.provisional.viewers.UnorderedTreeContentProvider;
 import org.eclipse.jface.internal.databinding.provisional.viewers.ViewerLabelProvider;
 import org.eclipse.jface.layout.GridLayoutFactory;
 import org.eclipse.jface.layout.LayoutConstants;
@@ -36,40 +36,41 @@
 import org.eclipse.swt.widgets.Shell;
 
 /**
- * Tests UpdatableTreeContentProvider and DirtyIndicationLabelProvider.
- * Creates a tree containing three randomly-generated sets of integers,
- * and one node that contains the union of the other sets.
+ * Tests UpdatableTreeContentProvider and DirtyIndicationLabelProvider. Creates
+ * a tree containing three randomly-generated sets of integers, and one node
+ * that contains the union of the other sets.
  * 
  * @since 3.2
  */
 public class TreeContentProviderTest {
-	
+
 	private Shell shell;
 	private TreeViewer tree;
-	
+
 	// Three randomly-generated sets of doubles
 	private AsynchronousTestSet set1;
 	private AsynchronousTestSet set2;
 	private AsynchronousTestSet set3;
-	
+
 	// The union of the above three sets
 	private UnionSet union;
 	private Button randomize;
+
 	public TreeContentProviderTest() {
-		
+
 		// Create the data model
 		set1 = new AsynchronousTestSet();
 		set2 = new AsynchronousTestSet();
 		set3 = new AsynchronousTestSet();
-		
+
 		// A union of the above sets
-		union = new UnionSet(new IObservableSet[] {set1, set2, set3});
-		
+		union = new UnionSet(new IObservableSet[] { set1, set2, set3 });
+
 		// Create shell
 		shell = new Shell(Display.getCurrent());
-		
+
 		createTree();
-		
+
 		Composite buttonBar = new Composite(shell, SWT.NONE);
 		{
 			buttonBar.setLayout(new FillLayout(SWT.HORIZONTAL));
@@ -81,14 +82,17 @@
 					super.widgetSelected(e);
 				}
 			});
-			
+
 			GridLayoutFactory.fillDefaults().generateLayout(buttonBar);
 		}
-		
-		GridLayoutFactory.fillDefaults().margins(LayoutConstants.getMargins()).generateLayout(shell);
-		
+
+		GridLayoutFactory.fillDefaults().margins(LayoutConstants.getMargins())
+				.generateLayout(shell);
+
 		shell.addDisposeListener(new DisposeListener() {
-			/* (non-Javadoc)
+			/*
+			 * (non-Javadoc)
+			 * 
 			 * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent)
 			 */
 			public void widgetDisposed(DisposeEvent e) {
@@ -108,34 +112,42 @@
 	}
 
 	private void createTree() {
-		// Create the tree provider. This provides the structure of the tree. This tree will
-		// have an instance of RootNode as the root (which is really a placeholder), several
-		// SimpleNodes as top-level nodes, and sets of randomly generated Doubles below each
+		// Create the tree provider. This provides the structure of the tree.
+		// This tree will
+		// have an instance of RootNode as the root (which is really a
+		// placeholder), several
+		// SimpleNodes as top-level nodes, and sets of randomly generated
+		// Doubles below each
 		// SimpleNode.
 		IUnorderedTreeProvider treeProvider = new IUnorderedTreeProvider() {
-			public IObservableSet createChildSet(TreePath treePath) {
-				// If the parent is the root node, return the union of some randomly-generated
+			public IObservableSet createChildSet(Object element) {
+				// If the parent is the root node, return the union of some
+				// randomly-generated
 				// nodes and some hardcoded nodes
-				if (treePath.getSegmentCount()==0 || treePath.getLastSegment() == tree.getInput()) {
+				if (element == tree.getInput()) {
 					// Set of hardcoded nodes
 					WritableSet topElements = new WritableSet();
 					topElements.add(new SimpleNode("Random Set 1", set1));
 					topElements.add(new SimpleNode("Random Set 2", set2));
 					topElements.add(new SimpleNode("Random Set 3", set3));
-					topElements.add(new SimpleNode("Union of the other sets", union));
+					topElements.add(new SimpleNode("Union of the other sets",
+							union));
 					return topElements;
 				}
-				
-				// If the parent is a RandomChildrenNode, return a randomly-generated
+
+				// If the parent is a RandomChildrenNode, return a
+				// randomly-generated
 				// set of Doubles for its children
-				Object element = treePath.getLastSegment();
 				if (element instanceof SimpleNode) {
-					// We return a new DelegatingObservableSet in order to prevent the 
+					// We return a new DelegatingObservableSet in order to
+					// prevent the
 					// original from being disposed.
-					return Observables.proxyObservableSet(((SimpleNode)element).getChildren());
+					return Observables
+							.proxyObservableSet(((SimpleNode) element)
+									.getChildren());
 				}
-				
-				// Otherwise the node is a Double, which will have no children  
+
+				// Otherwise the node is a Double, which will have no children
 				return null;
 			}
 
@@ -144,52 +156,58 @@
 				return null;
 			}
 		};
-		
+
 		// Label provider for the tree
 		IViewerLabelProvider labelProvider = new ViewerLabelProvider() {
 			public void updateLabel(ViewerLabel label, Object element) {
 				if (element instanceof SimpleNode) {
 					SimpleNode node = (SimpleNode) element;
-					
+
 					label.setText(node.getNodeName());
 				}
-				
+
 				if (element instanceof Integer) {
 					Integer node = (Integer) element;
-					
+
 					label.setText("Integer " + node);
 				}
 			}
 		};
-		
+
 		// Create tree viewer
 		tree = new TreeViewer(shell, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
-		
-		// UpdatableTreeContentProvider converts an ITreeProvider into a standard JFace content provider
-		UnorderedTreeContentProvider contentProvider = new UnorderedTreeContentProvider(treeProvider,
-				"pending...");
-		
+
+		// UpdatableTreeContentProvider converts an ITreeProvider into a
+		// standard JFace content provider
+		UnorderedTreeContentProvider contentProvider = new UnorderedTreeContentProvider(
+				treeProvider, "pending...", false);
+
 		tree.setContentProvider(contentProvider);
 		tree.setLabelProvider(labelProvider);
-		
-		// For the ITreeProvider above, it doesn't matter what we select as the input.
+
+		// For the ITreeProvider above, it doesn't matter what we select as the
+		// input.
 		tree.setInput(new Object());
 	}
-	
+
 	/**
 	 * @param args
 	 */
 	public static void main(String[] args) {
-		Display display = Display.getDefault();
-		TreeContentProviderTest test = new TreeContentProviderTest();
-		Shell s = test.getShell();
-		s.pack();
-		s.setVisible(true);
+		final Display display = Display.getDefault();
+		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+			public void run() {
+				TreeContentProviderTest test = new TreeContentProviderTest();
+				Shell s = test.getShell();
+				s.pack();
+				s.setVisible(true);
 
-		while (!s.isDisposed()) {
-			if (!display.readAndDispatch())
-				display.sleep();
-		}
+				while (!s.isDisposed()) {
+					if (!display.readAndDispatch())
+						display.sleep();
+				}
+			}
+		});
 		display.dispose();
 	}