Fixes for two bugs: Bug 122756 [Viewers] Support for TreePath based content providers, and Bug 126506 [Viewers] TreePath based sorting
diff --git a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/AbstractTreeViewer.java b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/AbstractTreeViewer.java
index 0d3591b..8c93d86 100644
--- a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/AbstractTreeViewer.java
+++ b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/AbstractTreeViewer.java
@@ -110,25 +110,67 @@
      * reflect the model. This method only affects the viewer, not the model.
      * </p>
      * 
-     * @param parentElement
+     * @param parentElementOrTreePath
      *           the parent element
      * @param childElements
      *           the child elements to add
      */
-    public void add(Object parentElement, Object[] childElements) {
-        Assert.isNotNull(parentElement);
+    public void add(Object parentElementOrTreePath, Object[] childElements) {
+        Assert.isNotNull(parentElementOrTreePath);
         assertElementsNotNull(childElements);
 
-        Widget[] widgets = findItems(parentElement);
+        Widget[] widgets = internalFindItems(parentElementOrTreePath);
         // If parent hasn't been realized yet, just ignore the add.
         if (widgets.length == 0)
             return;
 
 		for (int i = 0; i < widgets.length; i++) {
-			internalAdd(widgets[i], parentElement, childElements);
+			internalAdd(widgets[i], parentElementOrTreePath, childElements);
 		}        
     }
 
+    /**
+     * Find the items for the given element of tree path
+     * @param parentElementOrTreePath the element or tree path
+     * @return the items for that element
+     */
+	private Widget[] internalFindItems(Object parentElementOrTreePath) {
+		Widget[] widgets = findItems(parentElementOrTreePath);
+        if (parentElementOrTreePath instanceof TreePath) {
+			TreePath path = (TreePath) parentElementOrTreePath;
+			Widget w = internalFindItem(path);
+			if (w == null) {
+				widgets = new Widget[] { };
+			} else {
+				widgets = new Widget[] { w };
+			}
+		} else {
+			widgets = findItems(parentElementOrTreePath);
+		}
+		return widgets;
+	}
+
+	/**
+	 * Return the item at the given path or <code>null</code>
+	 * @param path the path
+	 * @return the item at that path
+	 * TODO could probably do better than this
+	 */
+	private Widget internalFindItem(TreePath path) {
+		Widget[] widgets = findItems(path.getLastSegment());
+		for (int i = 0; i < widgets.length; i++) {
+			Widget widget = widgets[i];
+			if (widget instanceof Item) {
+				Item item = (Item) widget;
+				TreePath p = getTreePathFromItem(item);
+				if (p.equals(path)) {
+					return widget;
+				}			
+			}
+		}
+		return null;
+	}
+
 	/**
      * Adds the given child elements to this viewer as children of the given
      * parent element.
@@ -143,20 +185,29 @@
      *
      * @param widget 
      *           the widget for the parent element
-     * @param parentElement
+     * @param parentElementOrTreePath
      *           the parent element
      * @param childElements
      *           the child elements to add
      * @since 3.1
      */
-    protected void internalAdd(Widget widget, Object parentElement, Object[] childElements) {
-		
+    protected void internalAdd(Widget widget, Object parentElementOrTreePath, Object[] childElements) {
+    	Object parent;
+    	TreePath path;
+    	if (parentElementOrTreePath instanceof TreePath) {
+			path = (TreePath) parentElementOrTreePath;
+			parent = path.getLastSegment();
+		} else {
+			parent = parentElementOrTreePath;
+			path = null;
+		}
+    	
 		// optimization!
         // if the widget is not expanded we just invalidate the subtree
         if (widget instanceof Item) {
             Item ti = (Item) widget;
             if (!getExpanded(ti)) {
-                boolean needDummy = isExpandable(parentElement);
+                boolean needDummy = isExpandable(ti, path, parent);
                 boolean haveDummy = false;
                 // remove all children
                 Item[] items = getItems(ti);
@@ -180,14 +231,49 @@
         }
 
         if (childElements.length > 0) {
-            Object[] filtered = filter(childElements);
-			if(getSorter() != null)
-				getSorter().sort(this,filtered);
+        	// TODO: Add filtering back?
+            Object[] filtered = filter(parentElementOrTreePath, childElements);
+			ViewerSorter sorter = getSorter();
+			if(sorter != null) {
+				if (sorter instanceof TreePathViewerSorter) {
+					TreePathViewerSorter tpvs = (TreePathViewerSorter) sorter;
+					if (path == null)
+						path = internalGetSorterParentPath(widget, sorter);
+					tpvs.sort(this, path, filtered);
+				} else {
+					sorter.sort(this,filtered);
+				}
+			}
             createAddedElements(widget, filtered);
         }
 	}
 
 	/**
+	 * Filter the children elements.
+	 * @param parentElementOrTreePath the parent element or path
+	 * @param elements the child elements
+	 * @return the filter list of children
+	 */
+	private Object[] filter(Object parentElementOrTreePath, Object[] elements) {
+		ViewerFilter[] filters = getFilters();
+		if (filters != null) {
+			ArrayList filtered = new ArrayList(elements.length);
+			for (int i = 0; i < elements.length; i++) {
+				boolean add = true;
+				for (int j = 0; j < filters.length; j++) {
+					add = filters[j].select(this, parentElementOrTreePath, elements[i]);
+					if (!add)
+						break;
+				}
+				if (add)
+					filtered.add(elements[i]);
+			}
+			return filtered.toArray();
+		}
+		return elements;
+	}
+
+	/**
      * Create the new elements in the parent widget. If the
      * child already exists do nothing.
      * @param widget
@@ -201,6 +287,7 @@
 		}
 		
 		ViewerSorter sorter = getSorter ();
+		TreePath parentPath = internalGetSorterParentPath(widget, sorter);
 		Item[] items = getChildren(widget);
 		
 		//As the items are sorted already we optimize for a 
@@ -227,12 +314,12 @@
 				index = -1;
 			}
 			else{
-				lastInsertion = insertionPosition(items,sorter,lastInsertion, element);
+				lastInsertion = insertionPosition(items,sorter,lastInsertion, element, parentPath);
 				//As we are only searching the original array we keep track of those positions only
 				if(lastInsertion == items.length)
 					index = -1;
 				else{//See if we should just refresh
-					while(lastInsertion < items.length && sorter.compare(this,element,items[lastInsertion].getData()) == 0){
+					while(lastInsertion < items.length && internalCompare(sorter,parentPath,element,items[lastInsertion].getData()) == 0){
 						//As we cannot assume the sorter is consistent with equals() - therefore we can
 						// just check against the item prior to this index (if any)
 						if (items[lastInsertion].getData().equals(element)) {
@@ -285,12 +372,14 @@
      *            themself.
      * @param element
      *            element to find position for.
+     * @param parentPath the tree path for the element's parent or <code>null</code>
+     * if the element is a root element or the sorter is not a {@link TreePathViewerSorter}
      * @return the index to use when inserting the element.
      * 
      */
 	
-	private int insertionPosition(Item[] items,  ViewerSorter sorter, int lastInsertion, Object element) {
-	    
+	private int insertionPosition(Item[] items,  ViewerSorter sorter, int lastInsertion, Object element, TreePath parentPath) {
+		
 		int size = items.length;
 		if (sorter == null)
 			return size;
@@ -299,7 +388,7 @@
 		while (min <= max) {
             int mid = (min + max) / 2;
             Object data = items[mid].getData();
-            int compare = sorter.compare(this, data, element);
+            int compare = internalCompare(sorter, parentPath, data, element);
             if (compare == 0) {
                 return mid;//Return if we already match
             }
@@ -343,7 +432,7 @@
      */
     protected int indexForElement(Widget parent, Object element) {
         ViewerSorter sorter = getSorter();
-		
+        TreePath parentPath = internalGetSorterParentPath(parent, sorter);
 		
 		Item[] items = getChildren(parent);
 		int count = items.length;
@@ -355,7 +444,7 @@
         while (min <= max) {
             int mid = (min + max) / 2;
             Object data = items[mid].getData();
-            int compare = sorter.compare(this, data, element);
+            int compare = internalCompare(sorter, parentPath, data, element);
             if (compare == 0) {
                 // find first item > element
                 while (compare == 0) {
@@ -364,7 +453,7 @@
                         break;
                     }
                     data = items[mid].getData();
-                    compare = sorter.compare(this, data, element);
+                    compare = internalCompare(sorter, parentPath, data, element);
                 }
                 return mid;
             }
@@ -377,6 +466,93 @@
     }
 
     /**
+     * Return the tree path that should be used as the parent path for the
+     * given widget and sorter. A <code>null</code> is returned if either
+     * the sorter is not a {@link TreePathViewerSorter} or if the parent
+     * widget is not an {@link Item} (i.e. is the root of the tree).
+     * 
+     * @param parent the parent widget
+     * @param sorter the sorter
+     * @return the tree path that should be used as the parent path for the
+     * given widget and sorter
+     */
+	private TreePath internalGetSorterParentPath(Widget parent, ViewerSorter sorter) {
+		TreePath path;
+		if (sorter instanceof TreePathViewerSorter && parent instanceof Item) {
+			Item item = (Item) parent;
+			path = getTreePathFromItem(item);
+		} else {
+			path = null;
+		}
+		return path;
+	}
+
+	/**
+	 * Compare the two elements using the given sorter. If the
+	 * sorter is a {@link TreePathViewerSorter}, the provided
+	 * tree path will be used. If the tree path is null and the
+	 * sorter is a tree path sorter, then the elements are root elements
+	 * @param sorter the sorter
+	 * @param parentPath the path of the elements' parent
+	 * @param e1 the first element
+	 * @param e2 the seocnd element
+	 * @return the result of comparing the two elements
+	 */
+	private int internalCompare(ViewerSorter sorter, TreePath parentPath, Object e1, Object e2) {
+		if (sorter instanceof TreePathViewerSorter) {
+			TreePathViewerSorter tpvs = (TreePathViewerSorter) sorter;
+			return tpvs.compare(this, parentPath, e1, e2);
+		}
+		return sorter.compare(this, e1, e2);
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.jface.viewers.StructuredViewer#getSortedChildren(java.lang.Object)
+	 */
+	protected Object[] getSortedChildren(Object parentElementOrTreePath) {
+		Object[] result =  getFilteredChildren(parentElementOrTreePath);
+		ViewerSorter sorter = getSorter();
+		if (sorter instanceof TreePathViewerSorter) {
+			TreePathViewerSorter tpvs = (TreePathViewerSorter) sorter;
+			
+			// be sure we're not modifying the original array from the model
+			result = (Object[]) result.clone();
+			
+			TreePath path = null;
+	    	if (parentElementOrTreePath instanceof TreePath) {
+	    		path = (TreePath) parentElementOrTreePath;
+			} else {
+				Object parent = parentElementOrTreePath;
+				Widget w = internalGetWidgetToSelect(parent);
+				if (w != null) {
+					path = internalGetSorterParentPath(w, sorter);
+				}
+				if (path == null)
+					path = TreePath.EMPTY.createChildPath(parentElementOrTreePath);
+			}
+	    	tpvs.sort(this, path, result);
+		} else if (sorter != null) {
+			// be sure we're not modifying the original array from the model
+			result = (Object[]) result.clone();
+			sorter.sort(this, result);
+		}
+		return result;
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.jface.viewers.StructuredViewer#getFilteredChildren(java.lang.Object)
+	 */
+	protected Object[] getFilteredChildren(Object parentElementOrTreePath) {
+		Object[] result = getRawChildren(parentElementOrTreePath);
+		ViewerFilter[] filters = getFilters();
+		for (int i = 0; i < filters.length; i++) {
+			ViewerFilter filter = filters[i];
+			result = filter.filter(this, parentElementOrTreePath, result);
+		}
+		return result;
+	}
+	
+    /**
      * Adds the given child element to this viewer as a child of the given
      * parent element. If this viewer does not have a sorter, the element is
      * added at the end of the parent's list of children; otherwise, the
@@ -389,13 +565,13 @@
      * the simultaneous addition of multiple elements.
      * </p>
      * 
-     * @param parentElement
-     *           the parent element
+     * @param parentElementOrTreePath
+     *           the parent element or path
      * @param childElement
      *           the child element
      */
-    public void add(Object parentElement, Object childElement) {
-        add(parentElement, new Object[] { childElement });
+    public void add(Object parentElementOrTreePath, Object childElement) {
+        add(parentElementOrTreePath, new Object[] { childElement });
     }
 
     /**
@@ -514,12 +690,19 @@
                 Object d = widget.getData();
                 if (d != null) {
                     Object parentElement = d;
-                    Object[] children = getSortedChildren(parentElement);
+                    Object[] children;
+                    if (isTreePathContentProvider() && widget instanceof Item) {
+                    	TreePath path = getTreePathFromItem((Item)widget);
+                    	children = getSortedChildren(path);
+                    } else {
+                    	children = getSortedChildren(parentElement);
+                    }
                     for (int i = 0; i < children.length; i++) {
                         createTreeItem(widget, children[i], -1);
                     }
                 }
             }
+
         });
     }
 
@@ -907,16 +1090,42 @@
     }
 
     /* (non-Javadoc) Method declared on StructuredViewer. */
-    protected Object[] getRawChildren(Object parent) {
+    protected Object[] getRawChildren(Object parentElementOrTreePath) {
+    	Object parent;
+    	TreePath path;
+    	if (parentElementOrTreePath instanceof TreePath) {
+			path = (TreePath) parentElementOrTreePath;
+			parent = path.getLastSegment();
+		} else {
+			parent = parentElementOrTreePath;
+			path = null;
+		}
         if (parent != null) {
             if (equals(parent, getRoot()))
                 return super.getRawChildren(parent);
-            ITreeContentProvider cp = (ITreeContentProvider) getContentProvider();
-            if (cp != null) {
-                Object[] result = cp.getChildren(parent);
+            IContentProvider cp = getContentProvider();
+             if (cp instanceof ITreePathContentProvider) {
+    			ITreePathContentProvider tpcp = (ITreePathContentProvider) cp;
+    			if (path == null) {
+    				// A path was not provided so try and find one
+    				Widget w = findItem(parent);
+    				if (w instanceof Item) {
+    					Item item = (Item) w;
+    					path = getTreePathFromItem(item);
+    				}
+    				if (path == null) {
+    					path = new TreePath(new Object[] { parent });
+    				}
+    			}
+    			Object[] result = tpcp.getChildren(path);
                 if (result != null)
                     return result;
-            }
+    		} else if (cp instanceof ITreeContentProvider) {
+    			ITreeContentProvider tcp = (ITreeContentProvider) cp;
+                Object[] result = tcp.getChildren(parent);
+                if (result != null)
+                    return result;
+    		}
         }
         return new Object[0];
     }
@@ -1140,11 +1349,21 @@
     		}
 			return (treePath).getParentPath();
     	}
-        ITreeContentProvider cp = (ITreeContentProvider) getContentProvider();
-        if (cp == null) {
-            return null;
+        IContentProvider cp = getContentProvider();
+        if (cp instanceof ITreePathContentProvider) {
+			ITreePathContentProvider tpcp = (ITreePathContentProvider) cp;
+			TreePath[] paths = tpcp.getParents(elementOrTreePath);
+			if (paths.length > 0) {
+				if (paths[0].getSegmentCount() == 0)
+					return getInput();
+				return paths[0].getLastSegment();
+			}
+		}
+        if (cp instanceof ITreeContentProvider) {
+        	ITreeContentProvider tcp = (ITreeContentProvider) cp;
+        	return tcp.getParent(elementOrTreePath);
         }
-        return cp.getParent(elementOrTreePath);
+        return null;
 	}
 
 	/**
@@ -1362,21 +1581,22 @@
      * multiple equal elements. 
      * </p>
      * 
-     * @param elements
-     *           the elements to remove
+     * @param elementsOrPaths
+     *           the elements or element paths to remove
      * @since 3.1
      */
-    protected void internalRemove(Object[] elements) {
+    protected void internalRemove(Object[] elementsOrPaths) {
         Object input = getInput();
         // Note: do not use the comparer here since the hashtable
         // contains SWT Items, not model elements.
         CustomHashtable parentItems = new CustomHashtable(5);
-        for (int i = 0; i < elements.length; ++i) {
-            if (equals(elements[i], input)) {
+        for (int i = 0; i < elementsOrPaths.length; ++i) {
+            Object element = elementsOrPaths[i];
+			if (equals(element, input)) {
                 setInput(null);
                 return;
             }
-            Widget[] childItems = findItems(elements[i]);
+            Widget[] childItems = internalFindItems(element);
 			for (int j = 0; j < childItems.length; j++) {
 				Widget childItem = childItems[j];
 				if (childItem instanceof Item) {
@@ -1403,7 +1623,7 @@
             	continue;
             if (!getExpanded(parentItem) && getItemCount(parentItem) == 0) {
                 // append a dummy if necessary
-                if (isExpandable(parentItem.getData())) {
+                if (isExpandable(parentItem, null, parentItem.getData())) {
                     newItem(parentItem, SWT.NULL, -1);
                 } else {
                     // XXX: Workaround (PR missing)
@@ -1521,23 +1741,73 @@
 	}
 
     /**
-     * Return whether the tree node representing the given element can be
-     * expanded.
+     * Return whether the tree node representing the given element or path can be
+     * expanded. Clients should query expandablity by path if the viewer's
+     * content provider is an {@link ITreePathContentProvider}.
      * <p>
      * The default implementation of this framework method calls <code>hasChildren</code>
      * on this viewer's content provider. It may be overridden if necessary.
      * </p>
      * 
-     * @param element
-     *           the element
+     * @param elementOrTreePath
+     *           the element or path
      * @return <code>true</code> if the tree node representing the given
      *         element can be expanded, or <code>false</code> if not
      */
-    public boolean isExpandable(Object element) {
-        ITreeContentProvider cp = (ITreeContentProvider) getContentProvider();
-        return cp != null && cp.hasChildren(element);
+    public boolean isExpandable(Object elementOrTreePath) {
+    	Object element;
+    	TreePath path;
+    	if (elementOrTreePath instanceof TreePath) {
+			path = (TreePath) elementOrTreePath;
+			element = path.getLastSegment();
+		} else {
+			element = elementOrTreePath;
+			path = null;
+		}
+        IContentProvider cp = getContentProvider();
+        if (cp instanceof ITreePathContentProvider) {
+			ITreePathContentProvider tpcp = (ITreePathContentProvider) cp;
+			if (path == null) {
+				// A path was not provided so try and find one
+				Widget w = findItem(element);
+				if (w instanceof Item) {
+					Item item = (Item) w;
+					path = getTreePathFromItem(item);
+				}
+				if (path == null) {
+					path = new TreePath(new Object[] { element });
+				}
+			}
+			return tpcp.hasChildren(path);
+		}
+        if (cp instanceof ITreeContentProvider) {
+			ITreeContentProvider tcp = (ITreeContentProvider) cp;
+			return tcp.hasChildren(element);	
+		}
+		return false;
     }
-
+    
+    /**
+     * Return whether the given element is expandable.
+     * @param item the tree item for the element
+     * @param parentPath the parent path if it is knwon or <code>null</code> if it needs to be determines
+     * @param element the element
+     * @return whether the given element is expandable
+     */
+    private boolean isExpandable(Item item, TreePath parentPath, Object element) {
+    	if (isTreePathContentProvider()) {
+    		TreePath path;
+    		if (parentPath != null) {
+    			path = parentPath.createChildPath(element);
+    		} else {
+    			path = getTreePathFromItem(item);
+    		}
+    		ITreePathContentProvider cp = (ITreePathContentProvider) getContentProvider();
+    		return cp != null && cp.hasChildren(path);
+    	}
+    	return isExpandable(element);
+    }
+    
     /* (non-Javadoc) Method declared on Viewer. */
     protected void labelProviderChanged() {
         // we have to walk the (visible) tree and update every item
@@ -1572,17 +1842,17 @@
      * the model.
      * </p>
      * 
-     * @param elements
+     * @param elementsOrTreePaths
      *           the elements to remove
      */
-    public void remove(final Object[] elements) {
-        assertElementsNotNull(elements);
-        if (elements.length == 0) {
+    public void remove(final Object[] elementsOrTreePaths) {
+        assertElementsNotNull(elementsOrTreePaths);
+        if (elementsOrTreePaths.length == 0) {
         	return;
         }
         preservingSelection(new Runnable() {
             public void run() {
-                internalRemove(elements);
+                internalRemove(elementsOrTreePaths);
             }
         });
     }
@@ -1625,11 +1895,11 @@
      * the simultaneous removal of multiple elements.
      * </p>
      * 
-     * @param element
+     * @param elementsOrTreePaths
      *           the element
      */
-    public void remove(Object element) {
-        remove(new Object[] { element });
+    public void remove(Object elementsOrTreePaths) {
+        remove(new Object[] { elementsOrTreePaths });
     }
 
     /**
@@ -1728,7 +1998,7 @@
     }
     
 	protected void assertContentProviderType(IContentProvider provider) {
-		Assert.isTrue(provider instanceof ITreeContentProvider);
+		Assert.isTrue(provider instanceof ITreeContentProvider || provider instanceof ITreePathContentProvider);
 	}
 
     /**
@@ -1925,7 +2195,7 @@
             if (!getExpanded(ti)) {
                 // need a dummy node if element is expandable;
                 // but try to avoid recreating the dummy node
-                boolean needDummy = isExpandable(parent);
+                boolean needDummy = isExpandable(ti, null, parent);
                 boolean haveDummy = false;
                 // remove all children
                 Item[] items = getItems(ti);
@@ -1952,7 +2222,12 @@
         // If the children weren't passed in, get them now since they're needed
         // below.
         if (elementChildren == null) {
-            elementChildren = getSortedChildren(parent);
+        	if (isTreePathContentProvider() && widget instanceof Item) {
+				TreePath path = getTreePathFromItem((Item)widget);
+				elementChildren = getSortedChildren(path);
+			} else {
+				elementChildren = getSortedChildren(parent);
+			}
         }
 
         Control tree = getControl();
@@ -2094,7 +2369,7 @@
      */
     protected void updatePlus(Item item, Object element) {
         boolean hasPlus = getItemCount(item) > 0;
-        boolean needsPlus = isExpandable(element);
+        boolean needsPlus = isExpandable(item, null, element);
         boolean removeAll = false;
         boolean addDummy = false;
         Object data = item.getData();
@@ -2223,5 +2498,9 @@
         }
         return (TreePath[]) result.toArray(new TreePath[items.size()]);
     }
+    
+	private boolean isTreePathContentProvider() {
+		return getContentProvider() instanceof ITreePathContentProvider;
+	}
 
 }
diff --git a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/DecoratingLabelProvider.java b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/DecoratingLabelProvider.java
index 0648ebd..247ce5d 100644
--- a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/DecoratingLabelProvider.java
+++ b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/DecoratingLabelProvider.java
@@ -23,7 +23,7 @@
  * the nested label provider.
  */
 public class DecoratingLabelProvider extends LabelProvider implements
-        ILabelProvider, IViewerLabelProvider, IColorProvider, IFontProvider {
+        ILabelProvider, IViewerLabelProvider, IColorProvider, IFontProvider, ITreePathLabelProvider {
 	
 	/**
 	 * The UPDATE_LABEL flag indicates that the label should 
@@ -312,4 +312,42 @@
 		Assert.isNotNull(decorationContext);
 		this.decorationContext = decorationContext;
 	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.jface.viewers.ITreePathLabelProvider#updateLabel(org.eclipse.jface.viewers.ViewerLabel, org.eclipse.jface.viewers.TreePath)
+	 */
+	public void updateLabel(ViewerLabel settings, TreePath elementPath) {
+        ILabelDecorator currentDecorator = getLabelDecorator();
+        String oldText = settings.getText();
+        Object element = elementPath.getLastSegment();
+        boolean decorationReady = true;
+        if (currentDecorator instanceof IDelayedLabelDecorator) {
+            IDelayedLabelDecorator delayedDecorator = (IDelayedLabelDecorator) currentDecorator;
+            if (!delayedDecorator.prepareDecoration(element, oldText)) {
+                // The decoration is not ready but has been queued for processing
+                decorationReady = false;
+            }
+        }
+        // update icon and label
+
+        if (provider instanceof ITreePathLabelProvider) {
+			ITreePathLabelProvider pprov = (ITreePathLabelProvider) provider;
+			if (decorationReady || oldText == null
+	                || settings.getText().length() == 0)
+				pprov.updateLabel(settings, elementPath);
+		} else {
+	        if (decorationReady || oldText == null
+	                || settings.getText().length() == 0)
+	            settings.setText(getText(element));
+	
+	        Image oldImage = settings.getImage();
+	        if (decorationReady || oldImage == null) {
+	            settings.setImage(getImage(element));
+	        }
+	 
+	        if(decorationReady)
+	        	updateForDecorationReady(settings,element);
+		}
+
+	}
 }
diff --git a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/ITreePathContentProvider.java b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/ITreePathContentProvider.java
new file mode 100644
index 0000000..ce87dab
--- /dev/null
+++ b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/ITreePathContentProvider.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.viewers;
+
+/**
+ * An interface to content providers for tree-structure-oriented viewers that
+ * provides content based on the path of elements in the tree viewer..
+ * 
+ * @see AbstractTreeViewer
+ * @since 3.2
+ */
+public interface ITreePathContentProvider extends IStructuredContentProvider {
+
+	/**
+	 * Returns the child elements of the last element in the given path.
+	 * Implementors may want to use the additional context of the complete path
+	 * of a parent element in order to decide which children to return.
+	 * <p>
+	 * The provided path is relative to the input. The root elements must
+	 * be obtained by calling
+	 * {@link IStructuredContentProvider#getElements(Object)}.
+	 * </p>
+	 * The result is not modified by the viewer.
+	 * 
+	 * @param parentPath
+	 *            the path of the parent element
+	 * @return an array of child elements
+	 */
+	public Object[] getChildren(TreePath parentPath);
+
+	/**
+	 * Returns whether the last element of the given path has children.
+	 * <p>
+	 * Intended as an optimization for when the viewer does not need the actual
+	 * children. Clients may be able to implement this more efficiently than
+	 * <code>getChildren</code>.
+	 * </p>
+	 * 
+	 * @param path
+	 *            the path
+	 * @return <code>true</code> if the lat element of the path has children,
+	 *         and <code>false</code> if it has no children
+	 */
+	public boolean hasChildren(TreePath path);
+
+	/**
+	 * Return the possible parent paths for the given element. An empty array
+	 * can be returned if the paths cannot be computed. If the element is 
+	 * a potential child of the input of the viewer, an empty tree path
+	 * should be an entry in the returned array.
+	 * 
+	 * @param element
+	 *            the element
+	 * @return the possible parent paths for the given element
+	 */
+	public TreePath[] getParents(Object element);
+}
diff --git a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/ITreePathLabelProvider.java b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/ITreePathLabelProvider.java
new file mode 100644
index 0000000..d9d03d6
--- /dev/null
+++ b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/ITreePathLabelProvider.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.viewers;
+
+/**
+ * An extension to {@link ILabelProvider} that is given the 
+ * path of the element being decoratd, when it is available.
+ * @since 3.2
+ */
+public interface ITreePathLabelProvider extends IBaseLabelProvider {
+    
+    /**
+     * Updates the label for the given element.
+     * 
+     * @param label the label to update
+     * @param elementPath the path of the element being decorated
+     */
+    public void updateLabel(ViewerLabel label, TreePath elementPath);
+}
diff --git a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/StructuredViewer.java b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/StructuredViewer.java
index df4bcf5..3afd3a7 100644
--- a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/StructuredViewer.java
+++ b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/StructuredViewer.java
@@ -1966,6 +1966,29 @@
 	/**
 	 * Build a label up for the element using the supplied label provider.
 	 * @param updateLabel The ViewerLabel to collect the result in
+	 * @param elementPath The path of the element being decorated.
+	 * @param labelProvider ILabelProvider the labelProvider for the receiver.
+	 */
+	void buildLabel(ViewerLabel updateLabel, TreePath elementPath,ITreePathLabelProvider labelProvider){
+
+			labelProvider.updateLabel(updateLabel, elementPath);
+            		
+			colorAndFontCollector.setUsedDecorators();
+			
+			if(updateLabel.hasNewBackground())
+				colorAndFontCollector.setBackground(updateLabel.getBackground());
+			
+			if(updateLabel.hasNewForeground())
+				colorAndFontCollector.setForeground(updateLabel.getForeground());
+			
+			if(updateLabel.hasNewFont())
+				colorAndFontCollector.setFont(updateLabel.getFont());
+	
+	}
+	
+	/**
+	 * Build a label up for the element using the supplied label provider.
+	 * @param updateLabel The ViewerLabel to collect the result in
 	 * @param element The element being decorated.
 	 * @param labelProvider ILabelProvider the labelProvider for the receiver.
 	 */
diff --git a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/TreePath.java b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/TreePath.java
index 8ec12b2..2b5d98e 100644
--- a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/TreePath.java
+++ b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/TreePath.java
@@ -23,6 +23,12 @@
  * @since 3.2
  */
 public final class TreePath {
+	
+	/**
+	 * Constant for representing an empty tree path.
+	 */
+	public static final TreePath EMPTY = new TreePath(new Object[0]);
+	
 	private Object[] segments;
 
 	private int hash;
diff --git a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/TreeViewer.java b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/TreeViewer.java
index c0ae778..137a7c6 100644
--- a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/TreeViewer.java
+++ b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/TreeViewer.java
@@ -213,6 +213,7 @@
 		ITableLabelProvider tprov = null;
 		ILabelProvider lprov = null;
 		IViewerLabelProvider vprov = null;
+		ITreePathLabelProvider pprov = null;
 		
 		if(prov instanceof ILabelProvider)
 			lprov = (ILabelProvider) prov;
@@ -225,6 +226,10 @@
 			tprov = (ITableLabelProvider) prov;
 		}
 		
+		if (prov instanceof ITreePathLabelProvider) {
+			pprov = (ITreePathLabelProvider) prov;
+		}
+		
 		
 		int columnCount = tree.getColumnCount();
 		if (columnCount == 0) {// If no columns were created use the label
@@ -232,12 +237,16 @@
 
 			ViewerLabel updateLabel = new ViewerLabel(treeItem.getText(),
 					treeItem.getImage());
-			if(vprov != null)
-				buildLabel(updateLabel,element,vprov);
-			else{
-				if(lprov != null)
-					buildLabel(updateLabel,element,lprov);
-			}
+			if (pprov != null) {
+				TreePath path = getTreePathFromItem(item);
+				buildLabel(updateLabel,path,pprov);
+			} else 
+				if(vprov != null)
+					buildLabel(updateLabel,element,vprov);
+				else{
+					if(lprov != null)
+						buildLabel(updateLabel,element,lprov);
+				}
 
 			// As it is possible for user code to run the event
 			// loop check here.
@@ -295,6 +304,27 @@
 		}
 		getColorAndFontCollector().applyFontsAndColors(treeItem);
 	}
+	
+	/**
+	 * Override to handle tree paths.
+	 * @see org.eclipse.jface.viewers.StructuredViewer#buildLabel(org.eclipse.jface.viewers.ViewerLabel, java.lang.Object)
+	 */
+	protected void buildLabel(ViewerLabel updateLabel, Object elementOrPath) {
+		Object element;
+		if (elementOrPath instanceof TreePath) {
+			TreePath path = (TreePath) elementOrPath;
+			IBaseLabelProvider provider = getLabelProvider();
+			if (provider instanceof ITreePathLabelProvider) {
+				ITreePathLabelProvider pprov = (ITreePathLabelProvider) provider;
+				buildLabel(updateLabel, path, pprov);
+				return;
+			}
+			element = path.getLastSegment();
+		} else {
+			element = elementOrPath;
+		}
+		super.buildLabel(updateLabel, element);
+	}
 
 	/**
 	 * Starts editing the given element.
diff --git a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/ViewerFilter.java b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/ViewerFilter.java
index d640ee9..d2af319 100644
--- a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/ViewerFilter.java
+++ b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/ViewerFilter.java
@@ -55,6 +55,24 @@
     }
 
     /**
+     * Filters the given elements for the given viewer.
+     * The input array is not modified.
+     * <p>
+     * The default implementation of this method calls 
+     * {@link #filter(Viewer, Object, Object[])} with the 
+     * parent from the path. Subclasses may override
+     * </p>
+     * @param viewer the viewer
+     * @param parentPath the path of the parent element
+     * @param elements the elements to filter
+     * @return the filtered elements
+     * @since 3.2
+     */
+    public Object[] filter(Viewer viewer, TreePath parentPath, Object[] elements) {
+        return filter(viewer, parentPath.getLastSegment(), elements);
+    }
+    
+    /**
      * Returns whether this viewer filter would be affected 
      * by a change to the given property of the given element.
      * <p>