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>