/******************************************************************************* * Copyright (c) 2005 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.debug.internal.ui.viewers; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.util.Assert; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.viewers.ViewerSorter; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.TreeEvent; import org.eclipse.swt.events.TreeListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.swt.widgets.Widget; import org.eclipse.ui.progress.WorkbenchJob; /** * A tree viewer that retrieves children and labels asynchronously via adapters * and supports duplicate elements in the tree with different parents. * Retrieving children and labels asynchrnously allows for arbitrary latency * without blocking the UI thread. *
* TODO: tree editor not implemented TODO: table tree - what implications does * it have on IPresentationAdapter? * * TODO: Deprecate the public/abstract deferred workbench adapter in favor of * the presentation adapter. *
** Clients may instantiate and subclass this class. *
* * @since 3.2 */ public class AsynchronousTreeViewer extends AsynchronousViewer implements Listener { private static final Rectangle NOT_VISIBLE = new Rectangle(0, 0, 0, 0); /** * A map of widget to parent widgets used to avoid requirement for parent * access in UI thread. Currently used by update objects to detect/cancel * updates on updates of children. */ private Map fItemToParentItem = new HashMap(); private AsynchronousTreeViewerContentManager fContentManager = new AsynchronousTreeViewerContentManager(); /** * The tree */ private Tree fTree; /** * Collection of tree paths to be expanded. A path is removed from the * collection when it is expanded. The entire list is cleared when the input * to the viewer changes. */ private List fPendingExpansion = new ArrayList(); /** * Creates an asynchronous tree viewer on a newly-created tree control under * the given parent. The tree control is created using the SWT style bits *MULTI, H_SCROLL, V_SCROLL,
and BORDER
. The
* viewer has no input, no content provider, a default label provider, no
* sorter, and no filters.
*
* @param parent
* the parent control
*/
public AsynchronousTreeViewer(Composite parent) {
this(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.VIRTUAL);
}
/**
* Creates an asynchronous tree viewer on a newly-created tree control under
* the given parent. The tree control is created using the given SWT style
* bits. The viewer has no input.
*
* @param parent
* the parent control
* @param style
* the SWT style bits used to create the tree.
*/
public AsynchronousTreeViewer(Composite parent, int style) {
this(new Tree(parent, style));
}
/**
* Creates an asynchronous tree viewer on the given tree control. The viewer
* has no input, no content provider, a default label provider, no sorter,
* and no filters.
*
* @param tree
* the tree control
*/
public AsynchronousTreeViewer(Tree tree) {
super();
Assert.isTrue((tree.getStyle() & SWT.VIRTUAL) != 0);
fTree = tree;
hookControl(fTree);
setUseHashlookup(false);
tree.addTreeListener(new TreeListener() {
public void treeExpanded(TreeEvent e) {
((TreeItem) e.item).setExpanded(true);
internalRefresh(e.item.getData(), e.item);
}
public void treeCollapsed(TreeEvent e) {
}
});
tree.addMouseListener(new MouseListener() {
public void mouseUp(MouseEvent e) {
}
public void mouseDown(MouseEvent e) {
}
public void mouseDoubleClick(MouseEvent e) {
TreeItem item = ((Tree) e.widget).getItem(new Point(e.x, e.y));
if (item != null) {
if (item.getExpanded()) {
item.setExpanded(false);
} else {
item.setExpanded(true);
internalRefresh(item.getData(), item);
}
}
}
});
tree.addListener(SWT.SetData, this);
}
/**
* Returns the tree control for this viewer.
*
* @return the tree control for this viewer
*/
public Tree getTree() {
return fTree;
}
/**
* Updates whether the given element has children.
*
* @param element
* element to update
* @param widget
* widget associated with the element in this viewer's tree
*/
protected void updateHasChildren(Object element, Widget widget) {
IAsynchronousContentAdapter adapter = getContentAdapter(element);
if (adapter != null) {
IContainerRequestMonitor update = new ContainerRequestMonitor(widget, this);
schedule(update);
adapter.isContainer(element, getPresentationContext(), update);
}
}
/**
* Updates the children of the given element.
*
* @param parent
* element of which to update children
* @param widget
* widget associated with the element in this viewer's tree
*/
protected void updateChildren(Object parent, Widget widget) {
IAsynchronousContentAdapter adapter = getContentAdapter(parent);
if (adapter != null) {
IChildrenRequestMonitor update = new ChildrenRequestMonitor(widget, this);
schedule(update);
adapter.retrieveChildren(parent, getPresentationContext(), update);
}
}
/**
* Returns the tree element adapter for the given element or
* null
if none.
*
* @param element
* element to retrieve adapter for
* @return presentation adapter or null
*/
protected IAsynchronousContentAdapter getContentAdapter(Object element) {
IAsynchronousContentAdapter adapter = null;
if (element instanceof IAsynchronousContentAdapter) {
adapter = (IAsynchronousContentAdapter) element;
} else if (element instanceof IAdaptable) {
IAdaptable adaptable = (IAdaptable) element;
adapter = (IAsynchronousContentAdapter) adaptable.getAdapter(IAsynchronousContentAdapter.class);
}
return adapter;
}
/**
* Expands all elements in the given tree selection.
*
* @param selection
*/
public synchronized void expand(ISelection selection) {
if (selection instanceof TreeSelection) {
TreePath[] paths = ((TreeSelection) selection).getPaths();
for (int i = 0; i < paths.length; i++) {
fPendingExpansion.add(paths[i]);
}
if (getControl().getDisplay().getThread() == Thread.currentThread()) {
attemptExpansion();
} else {
WorkbenchJob job = new WorkbenchJob("attemptExpansion") { //$NON-NLS-1$
public IStatus runInUIThread(IProgressMonitor monitor) {
attemptExpansion();
return Status.OK_STATUS;
}
};
job.setSystem(true);
job.schedule();
}
}
}
/**
* Attempts to expand all pending expansions.
*/
synchronized void attemptExpansion() {
if (fPendingExpansion != null) {
for (Iterator i = fPendingExpansion.iterator(); i.hasNext();) {
TreePath path = (TreePath) i.next();
if (attemptExpansion(path)) {
i.remove();
}
}
}
}
/**
* Attempts to expand the given tree path and returns whether the expansion
* was completed.
*
* @param path path to expand
* @return whether the expansion was completed
*/
synchronized boolean attemptExpansion(TreePath path) {
int segmentCount = path.getSegmentCount();
for (int j = segmentCount - 1; j >= 0; j--) {
Object element = path.getSegment(j);
Widget[] treeItems = getWidgets(element);
if (treeItems != null) {
for (int k = 0; k < treeItems.length; k++) {
if (treeItems[k] instanceof TreeItem) {
TreeItem treeItem = (TreeItem) treeItems[k];
TreePath treePath = getTreePath(treeItem);
if (path.startsWith(treePath)) {
if (!treeItem.isDisposed() && !treeItem.getExpanded() && treeItem.getItemCount() > 0) {
update(element);
updateChildren(element, treeItem);
expand(treeItem);
if (path.getSegmentCount() == treePath.getSegmentCount()) {
return true;
}
return false;
}
}
}
}
}
}
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.Viewer#getControl()
*/
public Control getControl() {
return fTree;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.StructuredViewer#unmapAllElements()
*/
protected synchronized void unmapAllElements() {
super.unmapAllElements();
fItemToParentItem.clear();
fContentManager.clearAll();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.Viewer#inputChanged(java.lang.Object,
* java.lang.Object)
*/
synchronized protected void inputChanged(Object input, Object oldInput) {
fPendingExpansion.clear();
super.inputChanged(input, oldInput);
map(input, fTree);
refresh();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.ui.viewers.AsynchronousViewer#map(java.lang.Object,
* org.eclipse.swt.widgets.Widget)
*/
protected void map(Object element, Widget item) {
super.map(element, item);
if (item instanceof TreeItem) {
TreeItem treeItem = (TreeItem) item;
TreeItem parentItem = treeItem.getParentItem();
if (parentItem != null) {
fItemToParentItem.put(treeItem, parentItem);
}
}
}
/**
* Returns all paths to the given element or null
if none.
*
* @param element
* @return paths to the given element or null
*/
public synchronized TreePath[] getTreePaths(Object element) {
Widget[] widgets = getWidgets(element);
if (widgets == null) {
return null;
}
TreePath[] paths = new TreePath[widgets.length];
for (int i = 0; i < widgets.length; i++) {
List path = new ArrayList();
path.add(element);
Widget widget = widgets[i];
TreeItem parent = null;
if (widget instanceof TreeItem) {
TreeItem treeItem = (TreeItem) widget;
parent = getParentItem(treeItem);
}
while (parent != null) {
Object data = getElement(parent);
if (data == null) {
// if the parent is unmapped while attempting selection
return null;
}
path.add(0, data);
parent = getParentItem(parent);
}
if (!path.get(0).equals(getInput())) {
path.add(0, getInput());
}
paths[i] = new TreePath(path.toArray());
if (widget instanceof TreeItem) {
paths[i].setTreeItem((TreeItem) widget);
}
}
return paths;
}
/**
* Constructs and returns a tree path for the given item. Must be called
* from the UI thread.
*
* @param item
* item to constuct a path for
* @return tree path for the item
*/
protected synchronized TreePath getTreePath(TreeItem item) {
TreeItem parent = item;
List path = new ArrayList();
while (parent != null && !parent.isDisposed()) {
Object parentElement = parent.getData();
if (parentElement == null) {
return new TreePath(new Object[0]);
}
path.add(0, parentElement);
parent = parent.getParentItem();
}
path.add(0, fTree.getData());
return new TreePath(path.toArray());
}
/**
* Called by ContainerRequestMonitor
after it is determined
* if the widget contains children.
*
* @param widget
* @param containsChildren
*/
synchronized void setIsContainer(Widget widget, boolean containsChildren) {
TreeItem[] prevChildren = getItems(widget);
if (containsChildren) {
if (prevChildren.length == 0) {
setItemCount(widget, 1);
if (widget instanceof Tree) {
updateChildren(widget.getData(), widget);
} else {
TreeItem treeItem = (TreeItem) widget;
if (treeItem.getExpanded()) {
updateChildren(widget.getData(), widget);
}
}
} else {
if (widget instanceof Tree || ((TreeItem) widget).getExpanded()) {
// if expanded, update the children
updateChildren(widget.getData(), widget);
}
}
} else {
for (int i = 0; i < prevChildren.length; i++) {
TreeItem item = prevChildren[i];
Object element = getElement(item);
unmap(element, item);
}
setItemCount(widget, 0);
}
attemptExpansion();
attemptSelection(true);
}
/**
* Adds a child at end of parent.
*
* @param parent
* @param child
*/
protected synchronized void add(Widget parentWidget, Object child) {
Object[] children = filter(new Object[] { child });
if (children.length == 0) {
return; // added element was filtered out.
}
//TODO sort???
fContentManager.addChildElement(parentWidget, child);
int childCount = fContentManager.getChildCount(parentWidget);
setItemCount(parentWidget, childCount);
attemptExpansion();
attemptSelection(false);
}
/**
* Called by ChildrenRequestMonitor
after children have been
* retrieved.
*
* @param widget
* @param newChildren
*/
protected synchronized void setChildren(final Widget widget, final List newChildren) {
// apply filters
final Object[] children = filter(newChildren.toArray());
// sort filtered children
ViewerSorter viewerSorter = getSorter();
if (viewerSorter != null) {
viewerSorter.sort(AsynchronousTreeViewer.this, children);
}
preservingSelection(new Runnable() {
public void run() {
//unmap all old children
TreeItem[] currentChildItems = getItems(widget);
for (int i = 0; i < currentChildItems.length; i++) {
TreeItem item = currentChildItems[i];
if (!item.isDisposed()) {
Object oldElement = item.getData();
if (oldElement != null) {
unmap(oldElement, item);
}
}
}
//map new children
for (int i = 0; i < currentChildItems.length; i++) {
TreeItem item = currentChildItems[i];
if (i >= children.length) {
item.dispose();
} else if (isVisible(item)) {
map(children[i], item);
internalRefresh(children[i], item);
} else {
clear(item);
}
}
// update parent to children map
fContentManager.setChildElements(widget, children);
//set item count
setItemCount(widget, children.length);
}
});
attemptExpansion();
attemptSelection(true);
}
protected void doUpdateItem(Widget item, Object element, boolean fullMap) {
super.doUpdateItem(item, element, fullMap);
updateHasChildren(element, item);
}
private void setItemCount(Widget widget, int itemCount) {
if (widget == fTree) {
fTree.setItemCount(itemCount);
} else {
((TreeItem) widget).setItemCount(itemCount);
}
}
private TreeItem[] getItems(Widget widget) {
if (widget instanceof TreeItem) {
return ((TreeItem) widget).getItems();
} else {
return fTree.getItems();
}
}
public synchronized void handleEvent(final Event event) {
// TODO: workaround for bug 125499: don't preserve selection when item is revealed
// preservingSelection(new Runnable() {
// public void run() {
TreeItem item = (TreeItem) event.item;
Widget parentItem = item.getParentItem();
int index = 0;
if (parentItem != null) {
index = ((TreeItem) parentItem).indexOf(item);
} else {
parentItem = fTree;
index = fTree.indexOf(item);
}
Object element = fContentManager.getChildElement(parentItem, index);
if (element != null) {
map(element, item);
internalRefresh(element, item);
}
// }
// });
}
/**
* Expands the given tree item and all of its parents. Does *not* update
* elements or retrieve children.
*
* @param child
* item to expand
*/
private void expand(TreeItem child) {
if (!child.getExpanded()) {
child.setExpanded(true);
TreeItem parent = child.getParentItem();
if (parent != null) {
expand(parent);
}
}
}
/**
* Unmaps the given item, and unmaps and disposes of all children of that
* item. Does not dispose of the given item.
*
* @param kid
* @param oldItem
*/
protected synchronized void unmap(Object element, Widget widget) {
TreeItem[] selection = fTree.getSelection();
if (selection.length == 1 && isChild(widget, selection[0])) {
setSelection(null);
}
TreeItem[] items = getItems(widget);
for (int i = 0; i < items.length; i++) {
TreeItem childItem = items[i];
Object childElement = getElement(childItem);
if (childElement != null) {
unmap(childElement, childItem);
}
}
super.unmap(element, widget);
fItemToParentItem.remove(widget);
fContentManager.remove(widget);
}
private void clear(Widget widget) {
if (widget instanceof TreeItem) {
TreeItem item = (TreeItem) widget;
item.clearAll(true);
} else {
fTree.clearAll(true);
}
}
private boolean isVisible(TreeItem item) {
Rectangle itemBounds = item.getBounds();
return !NOT_VISIBLE.equals(itemBounds);
}
private boolean isChild(Widget parent, TreeItem child) {
if (child == null) {
return false;
} else if (parent == child) {
return true;
}
return isChild(parent, child.getParentItem());
}
/**
* Returns the parent item for an item or null
if none.
*
* @param item
* item for which parent is requested
* @return parent item or null
*/
protected synchronized TreeItem getParentItem(TreeItem item) {
return (TreeItem) fItemToParentItem.get(item);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.StructuredViewer#doFindInputItem(java.lang.Object)
*/
protected Widget doFindInputItem(Object element) {
if (element.equals(getInput())) {
return fTree;
}
return null;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.StructuredViewer#doFindItem(java.lang.Object)
*/
protected Widget doFindItem(Object element) {
Widget[] widgets = getWidgets(element);
if (widgets != null && widgets.length > 0) {
return widgets[0];
}
return null;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.internal.ui.viewers.AsynchronousViewer#newSelectionFromWidget()
*/
protected ISelection newSelectionFromWidget() {
Control control = getControl();
if (control == null || control.isDisposed()) {
return StructuredSelection.EMPTY;
}
List list = getSelectionFromWidget();
return new TreeSelection((TreePath[]) list.toArray());
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.StructuredViewer#getSelectionFromWidget()
*/
protected synchronized List getSelectionFromWidget() {
TreeItem[] selection = fTree.getSelection();
TreePath[] paths = new TreePath[selection.length];
for (int i = 0; i < selection.length; i++) {
paths[i] = getTreePath(selection[i]);
}
return Arrays.asList(paths);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.ui.viewers.AsynchronousViewer#internalRefresh(java.lang.Object,
* org.eclipse.swt.widgets.Widget)
*/
protected synchronized void internalRefresh(Object element, Widget item) {
super.internalRefresh(element, item);
updateHasChildren(element, item);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.StructuredViewer#reveal(java.lang.Object)
*/
public void reveal(Object element) {
Widget[] widgets = getWidgets(element);
if (widgets != null && widgets.length > 0) {
// TODO: only reveals the first occurrence - should we reveal all?
TreeItem item = (TreeItem) widgets[0];
Tree tree = (Tree) getControl();
tree.showItem(item);
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.ui.viewers.AsynchronousViewer#doAttemptSelectionToWidget(org.eclipse.jface.viewers.ISelection,
* boolean)
*/
protected synchronized ISelection doAttemptSelectionToWidget(ISelection selection, boolean reveal) {
List remaining = new ArrayList();
if (!selection.isEmpty()) {
List toSelect = new ArrayList();
List theElements = new ArrayList();
TreeSelection treeSelection = (TreeSelection) selection;
TreePath[] paths = treeSelection.getPaths();
for (int i = 0; i < paths.length; i++) {
TreePath path = paths[i];
if (path == null) {
continue;
}
TreePath[] treePaths = getTreePaths(path.getLastSegment());
boolean selected = false;
if (treePaths != null) {
for (int j = 0; j < treePaths.length; j++) {
TreePath existingPath = treePaths[j];
if (existingPath.equals(path)) {
TreeItem treeItem = existingPath.getTreeItem();
if (!treeItem.isDisposed()) {
toSelect.add(treeItem);
theElements.add(path.getLastSegment());
selected = true;
break;
}
}
}
}
if (!selected) {
remaining.add(path);
}
}
if (!toSelect.isEmpty()) {
final TreeItem[] items = (TreeItem[]) toSelect.toArray(new TreeItem[toSelect.size()]);
// TODO: hack to ensure selection contains 'selected' element
// instead of 'equivalent' element. Handles synch problems
// between
// set selection & refresh
for (int i = 0; i < items.length; i++) {
TreeItem item = items[i];
Object element = theElements.get(i);
if (!item.isDisposed() && item.getData() != element) {
remap(element, item);
}
}
fTree.setSelection(items);
if (reveal) {
fTree.showItem(items[0]);
}
}
} else {
fTree.setSelection(new TreeItem[0]);
}
return new TreeSelection((TreePath[]) remaining.toArray(new TreePath[remaining.size()]));
}
/**
* Collapses all items in the tree.
*/
public void collapseAll() {
TreeItem[] items = fTree.getItems();
for (int i = 0; i < items.length; i++) {
TreeItem item = items[i];
if (item.getExpanded())
collapse(item);
}
}
/**
* Collaspes the given item and all of its children items.
*
* @param item
* item to collapose recursively
*/
protected void collapse(TreeItem item) {
TreeItem[] items = item.getItems();
for (int i = 0; i < items.length; i++) {
TreeItem child = items[i];
if (child.getExpanded()) {
collapse(child);
}
}
item.setExpanded(false);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.ui.viewers.AsynchronousViewer#setColor(org.eclipse.swt.widgets.Widget,
* org.eclipse.swt.graphics.RGB, org.eclipse.swt.graphics.RGB)
*/
void setColors(Widget widget, RGB[] foregrounds, RGB[] backgrounds) {
if (widget instanceof TreeItem) {
TreeItem item = (TreeItem) widget;
Color[] fgs = getColor(foregrounds);
Color[] bgs = getColor(backgrounds);
for (int i = 0; i < bgs.length; i++) {
item.setForeground(i, fgs[i]);
item.setBackground(i, bgs[i]);
}
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.ui.viewers.AsynchronousViewer#setFont(org.eclipse.swt.widgets.Widget,
* org.eclipse.swt.graphics.FontData)
*/
void setFonts(Widget widget, FontData[] fontData) {
if (widget instanceof TreeItem) {
TreeItem item = (TreeItem) widget;
Font[] fonts = getFonts(fontData);
for (int i = 0; i < fonts.length; i++) {
item.setFont(i, fonts[i]);
}
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.ui.viewers.AsynchronousViewer#getParent(org.eclipse.swt.widgets.Widget)
*/
protected Widget getParent(Widget widget) {
return (Widget) fItemToParentItem.get(widget);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.ui.viewers.AsynchronousViewer#acceptsSelection(org.eclipse.jface.viewers.ISelection)
*/
protected boolean acceptsSelection(ISelection selection) {
return selection instanceof TreeSelection;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.ui.viewers.AsynchronousViewer#getEmptySelection()
*/
protected ISelection getEmptySelection() {
return new TreeSelection(new TreePath[0]);
}
/**
* Adds the item specified by the given tree path to this tree. Can be
* called in a non-UI thread.
*
* @param treePath
*/
public synchronized void add(TreePath treePath) {
Object element = treePath.getLastSegment();
int parentIndex = treePath.getSegmentCount() - 2;
Object parentElement = getInput();
if (parentIndex > 0) {
parentElement = treePath.getSegment(parentIndex);
}
ViewerFilter[] filters = getFilters();
for (int i = 0; i < filters.length; i++) {
ViewerFilter filter = filters[i];
boolean select = filter.select(this, parentElement, element);
if (!select) {
return; // added item filtered out.
}
}
//TODO Sorting... if there's a sorter, it needs to be consulted
if (parentIndex >= 0) {
// find the paths to the parent, if it's present
Object parent = treePath.getSegment(parentIndex);
TreePath[] paths = getTreePaths(parent);
if (paths != null) {
// find the right path
for (int i = 0; i < paths.length; i++) {
TreePath path = paths[i];
if (treePath.startsWith(path)) {
Widget widget = path.getTreeItem();
if (widget == null) {
widget = getTree();
}
AddRequestMonitor addRequest = new AddRequestMonitor(widget, treePath, this);
schedule(addRequest);
addRequest.done();
return;
}
}
}
// refresh the leaf parent, if any
for (int i = parentIndex - 1; i >= 0; i++) {
parent = treePath.getSegment(i);
paths = getTreePaths(parent);
if (paths != null) {
for (int j = 0; j < paths.length; j++) {
TreePath path = paths[j];
if (treePath.startsWith(path)) {
Widget widget = path.getTreeItem();
if (widget == null) {
widget = getTree();
}
internalRefresh(parent, widget);
return;
}
}
}
}
}
}
/**
* Removes the item specified in the given tree path from this tree. Can be
* called in a non-UI thread.
*
* @param treePath
*/
public synchronized void remove(TreePath treePath) {
for (Iterator i = fPendingExpansion.iterator(); i.hasNext();) {
TreePath expansionPath = (TreePath) i.next();
if (expansionPath.startsWith(treePath)) {
i.remove();
}
}
if (treePath.getSegmentCount() > 1) {
// find the paths to the element, if it's present
Object element = treePath.getLastSegment();
TreePath[] paths = getTreePaths(element);
if (paths != null) {
// find the right path
for (int i = 0; i < paths.length; i++) {
TreePath path = paths[i];
if (treePath.equals(path)) {
TreeItem item = path.getTreeItem();
RemoveRequestMonitor request = new RemoveRequestMonitor(item, treePath, this);
schedule(request);
request.done();
return;
}
}
}
// refresh the parent, if present
if (treePath.getSegmentCount() >= 2) {
element = treePath.getSegment(treePath.getSegmentCount() - 2);
paths = getTreePaths(element);
if (paths != null) {
// find the right path
for (int i = 0; i < paths.length; i++) {
TreePath path = paths[i];
if (treePath.startsWith(path)) {
Widget widget = path.getTreeItem();
if (widget == null) {
widget = getTree();
}
internalRefresh(element, widget);
return;
}
}
}
}
}
}
synchronized void remove(final Widget widget) {
preservingSelection(new Runnable() {
public void run() {
if (!(widget instanceof TreeItem)) {
return;
}
fContentManager.remove(widget);
TreeItem item = (TreeItem) widget;
Widget parentWidget = item.getParentItem();
if (parentWidget == null)
parentWidget = fTree;
Object element = getElement(widget);
if (element != null)
unmap(element, widget);
item.dispose();
setItemCount(parentWidget, fContentManager.getChildCount(parentWidget));
}
});
}
synchronized void setLabels(Widget widget, String[] text, ImageDescriptor[] image) {
if (widget instanceof TreeItem) {
TreeItem item = (TreeItem) widget;
if (!item.isDisposed()) {
item.setText(text);
item.setImage(getImages(image));
}
}
}
}