diff options
Diffstat (limited to 'org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/InternalTreeModelViewer.java')
-rw-r--r-- | org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/InternalTreeModelViewer.java | 2439 |
1 files changed, 0 insertions, 2439 deletions
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/InternalTreeModelViewer.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/InternalTreeModelViewer.java deleted file mode 100644 index 1177bb805..000000000 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/InternalTreeModelViewer.java +++ /dev/null @@ -1,2439 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2009 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 - * Pawel Piech (Wind River) - added support for a virtual tree model viewer (Bug 242489) - * Patrick Chuong (Texas Instruments) - added support for checkbox (Bug 286310) - *******************************************************************************/ -package org.eclipse.debug.internal.ui.viewers.model; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Map.Entry; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.debug.internal.core.IInternalDebugCoreConstants; -import org.eclipse.debug.internal.core.commands.Request; -import org.eclipse.debug.internal.ui.viewers.model.provisional.ICheckUpdate; -import org.eclipse.debug.internal.ui.viewers.model.provisional.ICheckboxModelProxy; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider; -import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelChangedListener; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IStateUpdateListener; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener; -import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta; -import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.jface.viewers.CellEditor; -import org.eclipse.jface.viewers.IBasicPropertyConstants; -import org.eclipse.jface.viewers.ICellModifier; -import org.eclipse.jface.viewers.IContentProvider; -import org.eclipse.jface.viewers.ILazyTreePathContentProvider; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.TreePath; -import org.eclipse.jface.viewers.TreeSelection; -import org.eclipse.jface.viewers.TreeViewer; -import org.eclipse.jface.viewers.ViewerLabel; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ControlEvent; -import org.eclipse.swt.events.ControlListener; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.PaintEvent; -import org.eclipse.swt.events.PaintListener; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Color; -import org.eclipse.swt.graphics.Font; -import org.eclipse.swt.graphics.FontData; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.RGB; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Item; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.Tree; -import org.eclipse.swt.widgets.TreeColumn; -import org.eclipse.swt.widgets.TreeItem; -import org.eclipse.swt.widgets.Widget; -import org.eclipse.ui.IMemento; - -/** - * A tree viewer that displays a model. - * - * @since 3.3 - */ -public class InternalTreeModelViewer extends TreeViewer - implements ITreeModelViewer, ITreeModelContentProviderTarget, ITreeModelLabelProviderTarget, ITreeModelCheckProviderTarget -{ - - private IPresentationContext fContext; - - /** - * Current column presentation or <code>null</code> - */ - private IColumnPresentation fColumnPresentation = null; - - /** - * Map of columns presentation id to its visible columns id's (String[]) - * When a columns presentation is not in the map, default settings are used. - */ - private Map fVisibleColumns = new HashMap(); - - /** - * Map of column id's to persisted sizes - */ - private Map fColumnSizes = new HashMap(); - - /** - * Map of column presentation id's to an array of integers representing the column order - * for that presentation, or <code>null</code> if default. - */ - private Map fColumnOrder = new HashMap(); - - /** - * Map of column presentation id to whether columns should be displayed - * for that presentation (the user can toggle columns on/off when a - * presentation is optional. - */ - private Map fShowColumns = new HashMap(); - - /** - * Item's tree path cache - */ - private static final String TREE_PATH_KEY = "TREE_PATH_KEY"; //$NON-NLS-1$ - - /** - * Memento type for column sizes. Sizes are keyed by column presentation id - */ - private static final String COLUMN_SIZES = "COLUMN_SIZES"; //$NON-NLS-1$ - /** - * Memento type for the column order for a presentation context. - * A memento is created for each column presentation - */ - private static final String COLUMN_ORDER = "COLUMN_ORDER"; //$NON-NLS-1$ - /** - * Memento type for the visible columns for a presentation context. - * A memento is created for each column presentation keyed by column number - */ - private static final String VISIBLE_COLUMNS = "VISIBLE_COLUMNS"; //$NON-NLS-1$ - /** - * Memento type for whether columns are visible for a presentation context. - * Booleans are keyed by column presentation id - */ - private static final String SHOW_COLUMNS = "SHOW_COLUMNS"; //$NON-NLS-1$ - /** - * Memento key for the number of visible columns in a VISIBLE_COLUMNS memento - * or for the width of a column - */ - private static final String SIZE = "SIZE"; //$NON-NLS-1$ - /** - * Memento key prefix a visible column - */ - private static final String COLUMN = "COLUMN"; //$NON-NLS-1$ - - /** - * True while performing an insert... we allow insert with filters - */ - private boolean fInserting = false; - - /** - * Whether to notify the content provider when an element is unmapped - */ - private boolean fNotifyUnmap = true; - - /** - * Flag indicating whether the viewer is a pop-up viewer. A pop-up viewer - * is transient and does not automatically expand and select elements up - * when requested by the model. It also does not dispose the presentation - * context when its control is disposed. - * - * @since 3.5 - */ - private boolean fIsPopup; - - /** - * Persist column sizes when they change. - * - * @since 3.2 - */ - class ColumnListener implements ControlListener { - /* (non-Javadoc) - * @see org.eclipse.swt.events.ControlListener#controlMoved(org.eclipse.swt.events.ControlEvent) - */ - public void controlMoved(ControlEvent e) { - persistColumnOrder(); - } - - /* (non-Javadoc) - * @see org.eclipse.swt.events.ControlListener#controlResized(org.eclipse.swt.events.ControlEvent) - */ - public void controlResized(ControlEvent e) { - persistColumnSizes(); - } - } - - private ColumnListener fListener = new ColumnListener(); - - /** - * Proxy to cell modifier/editor support - */ - class CellModifierProxy implements ICellModifier { - - private ICellModifier fModifier; - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.ICellModifier#canModify(java.lang.Object, java.lang.String) - */ - public boolean canModify(Object element, String property) { - IElementEditor editor = ViewerAdapterService.getElementEditor(element); - if (editor != null) { - fModifier = editor.getCellModifier(getPresentationContext(), element); - if (fModifier != null) { - if (fModifier.canModify(element, property)) { - // install cell editor - CellEditor cellEditor = editor.getCellEditor(getPresentationContext(), property, element, (Composite)getControl()); - if (cellEditor != null) { - disposeCellEditors(); - CellEditor[] newEditors = new CellEditor[getVisibleColumns().length]; - for (int i = 0; i < newEditors.length; i++) { - newEditors[i] = cellEditor; - } - setCellEditors(newEditors); - return true; - } - } - } - } - return false; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.ICellModifier#getValue(java.lang.Object, java.lang.String) - */ - public Object getValue(Object element, String property) { - if (fModifier != null) { - return fModifier.getValue(element, property); - } - return null; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.ICellModifier#modify(java.lang.Object, java.lang.String, java.lang.Object) - */ - public void modify(Object element, String property, Object value) { - if (fModifier != null) { - if (element instanceof Item) { - element = ((Item)element).getData(); - } - fModifier.modify(element, property, value); - } - } - - /** - * Disposes client's column editor and cell editors - */ - protected void dispose() { - fModifier = null; - disposeCellEditors(); - setCellEditors(null); - } - - /** - * Disposes current cell editors - */ - protected void disposeCellEditors() { - CellEditor[] cellEditors = getCellEditors(); - if (cellEditors != null) { - for (int i = 0; i < cellEditors.length; i++) { - CellEditor editor = cellEditors[i]; - if (editor != null) { - editor.dispose(); - } - } - } - } - - } - - private CellModifierProxy fCellModifier; - - /** - * A handle to an element in a model. - */ - class VirtualElement { - /** - * Tree item associated with the element, or <code>null</code> for the root element - */ - private TreeItem fItem; - - /** - * Model element (can be <code>null</code> until retrieved) - */ - private Object fElement; - - /** - * Associated label update or <code>null</code> if the element was already - * present in the tree. - */ - private VirtualLabelUpdate fLabel; - - /** - * Children elements or <code>null</code> if none - */ - private VirtualElement[] fChildren = null; - - /** - * Whether this element would be filtered from the viewer - */ - private boolean fFiltered = false; - - /** - * Listens for update when populating this virtual element in the tree viewer - */ - class UpdateListener implements IViewerUpdateListener { - - /** - * The parent pending update - */ - private TreePath fParentPath; - - /** - * The child index pending update - */ - private int fIndex; - - /** - * Whether the update has completed - */ - private boolean fDone = false; - - /** - * Constructs a new listener waiting - * @param parentPath - * @param childIndex - */ - UpdateListener(TreePath parentPath, int childIndex) { - fParentPath = parentPath; - fIndex = childIndex; - } - - /* (non-Javadoc) - * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener#updateComplete(org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate) - */ - public void updateComplete(IViewerUpdate update) { - if (update instanceof IChildrenUpdate) { - IChildrenUpdate cu = (IChildrenUpdate) update; - if (cu.getElementPath().equals(fParentPath)) { - if (fIndex >= cu.getOffset() && fIndex <= (cu.getOffset() + cu.getLength())) { - fDone = true; - } - } - } - } - - /** - * Returns whether the update has completed. - * - * @return whether the update has completed - */ - boolean isComplete() { - return fDone; - } - - public void updateStarted(IViewerUpdate update) { - } - public void viewerUpdatesBegin() { - } - public void viewerUpdatesComplete() { - } - } - - /** - * Constructs a new virtual element for the given tree item and all - * of its expanded children. Has to be called in the UI thread. - * The model is used to count unrealized elements. - * - * Note only never re-use objects already in the tree as they may be out - * of synch. - * - * @param item tree item - * @param model virtual model - * @param root subtree to consider or <code>null</code> if all - * @param indexes children to consider or <code>null</code> - */ - VirtualElement(TreeItem item, VirtualModel model, TreePath root, int[] indexes) { - fItem = item; - model.incVirtual(); - if (item.getExpanded()) { - TreeItem[] items = item.getItems(); - fChildren = createChildren(items, model, root, indexes); - } - } - - /** - * Constructs a new virtual element for the given tree and all expanded - * children. The model is passed in to count unrealized elements. - * - * @param tree tree - * @param model virtual model - * @param root subtree scope or <code>null</code> for all - * @param indexes child indexes to consider or <code>null</code> - */ - VirtualElement(Tree tree, VirtualModel model, TreePath root, int[] indexes) { - fElement = tree.getData(); - TreeItem[] items = tree.getItems(); - if (items.length > 0) { - fChildren = createChildren(items, model, root, indexes); - } - } - - /** - * Creates and returns children elements. - * - * @param items tree items - * @param model model - * @param root subtree to consider or all if <code>null</code> - * @param indexes children of the root to consider or <code>null</code> - * @return children - */ - private VirtualElement[] createChildren(TreeItem[] items, VirtualModel model, TreePath root, int[] indexes) { - VirtualElement[] kids = new VirtualElement[items.length]; - if (root == null || root.getSegmentCount() == 0) { - if (indexes == null) { - for (int i = 0; i < items.length; i++) { - kids[i] = new VirtualElement(items[i], model, null, null); - } - } else { - for (int i = 0; i < indexes.length; i++) { - int index = indexes[i]; - kids[index] = new VirtualElement(items[index], model, null, null); - } - } - } else { - for (int i = 0; i < items.length; i++) { - TreeItem treeItem = items[i]; - if (treeItem.getData() != null) { - TreePath path = getTreePathFromItem(treeItem); - if (root.startsWith(path, null)) { - if (root.getSegmentCount() > path.getSegmentCount()) { - kids[i] = new VirtualElement(treeItem, model, root, indexes); - } else { - kids[i] = new VirtualElement(treeItem, model, null, indexes); - } - break; - } - } - } - } - return kids; - } - - /** - * Returns whether this element would be filtered from the viewer. - * - * @return whether filtered - */ - public boolean isFiltered() { - return fFiltered; - } - - /** - * Causes the tree item associated with this model element to be realized. - * Must be called in the UI thread. - * - * @return tree path to associated element, or <code>null</code> if the operation - * fails - */ - public TreePath realize() { - if (fItem.getData() != null) { - return getTreePathFromItem(fItem); - } - int index = -1; - TreePath parentPath = null; - if (fItem.getParentItem() == null) { - index = getTree().indexOf(fItem); - parentPath = TreePath.EMPTY; - } else { - index = fItem.getParentItem().indexOf(fItem); - parentPath = getTreePathFromItem(fItem.getParentItem()); - } - UpdateListener listener = new UpdateListener(parentPath, index); - addViewerUpdateListener(listener); - ((ILazyTreePathContentProvider)getContentProvider()).updateElement(parentPath, index); - Display display = getTree().getDisplay(); - while (!listener.isComplete()) { - if (!display.readAndDispatch()) { - display.sleep(); - } - } - removeViewerUpdateListener(listener); - if (fItem.getData() != null) { - return getTreePathFromItem(fItem); - } - return null; - } - - /** - * Schedules updates to retrieve unrealized children of this node. - * - * @param parentPath path to this element - * @param model model - */ - void retrieveChildren(TreePath parentPath, VirtualModel model) { - VirtualChildrenUpdate update = null; - if (fChildren != null) { - int prevModelIndex = Integer.MAX_VALUE; - for (int i = 0; i < fChildren.length; i++) { - VirtualElement element = fChildren[i]; - if (element == null) { - if (update != null) { - // non-consecutive updates, schedule and keep going - model.scheduleUpdate(update); - update = null; - } - } else { - int modelIndex = ((ITreeModelContentProvider)getContentProvider()).viewToModelIndex(parentPath, i); - if (update == null) { - update = new VirtualChildrenUpdate(parentPath, this, model); - } else if ((modelIndex - prevModelIndex) > 1) { - // non-consecutive updates, schedule and keep going - model.scheduleUpdate(update); - update = new VirtualChildrenUpdate(parentPath, this, model); - } - update.add(modelIndex); - prevModelIndex = modelIndex; - } - } - } - if (update != null) { - model.scheduleUpdate(update); - } - } - - /** - * Sets the underlying model object. - * - * @param path path to the element - */ - void setElement(Object data) { - fElement = data; - } - - /** - * Sets the label update associated with this element - * - * @param update - */ - void setLabelUpdate(VirtualLabelUpdate update) { - fLabel = update; - } - - /** - * Returns the image for this element or <code>null</code> if none - * - * @return image or <code>null</code> if none - */ - public Image getImage() { - if (fLabel == null) { - return fItem.getImage(); - } else { - return ((ITreeModelLabelProvider)getLabelProvider()).getImage(fLabel.fImage); - } - } - - /** - * Returns the labels for the element - one for each column requested. - * - * @return column labels - */ - public String[] getLabel() { - if (fLabel == null) { - String[] visibleColumns = getVisibleColumns(); - String[] label = new String[visibleColumns == null ? 1 : visibleColumns.length]; - for (int i = 0; i < label.length; i++) { - label[i] = fItem.getText(i); - } - return label; - } - return fLabel.fText; - - } - - /** - * Returns the children of this element or <code>null</code> if none. - * - * @return children or <code>null</code> if none - */ - public VirtualElement[] getChildren() { - return fChildren; - } - - } - - /** - * Common function for virtual updates. - */ - class VirtualUpdate extends Request implements IViewerUpdate { - - /** - * Path to the element being updated, or EMPTY for viewer input. - */ - private TreePath fPath; - - /** - * Element being updated. - */ - VirtualElement fVirtualElement; - - /** - * Associated virtual model - */ - VirtualModel fModel = null; - - /** - * Creates a new update based for the given element and model - */ - public VirtualUpdate(VirtualModel model, VirtualElement element, TreePath elementPath) { - fPath = elementPath; - fModel = model; - fVirtualElement = element; - } - - /** - * Returns the associated virtual element. - * - * @return virtual element - */ - protected VirtualElement getVirtualElement() { - return fVirtualElement; - } - - /* (non-Javadoc) - * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate#getElement() - */ - public Object getElement() { - if (fPath.getSegmentCount() == 0) { - return getViewerInput(); - } - return fPath.getLastSegment(); - } - - /* (non-Javadoc) - * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate#getElementPath() - */ - public TreePath getElementPath() { - return fPath; - } - - /* (non-Javadoc) - * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate#getPresentationContext() - */ - public IPresentationContext getPresentationContext() { - return InternalTreeModelViewer.this.getPresentationContext(); - } - - /* (non-Javadoc) - * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate#getViewerInput() - */ - public Object getViewerInput() { - return InternalTreeModelViewer.this.getInput(); - } - - } - - /** - * Represents all expanded items in this viewer's tree. The model is virtual - i.e. not - * all items have their associated model elements/labels retrieved from the model. The - * model can be populated in a non-UI thread. - */ - class VirtualModel { - - /** - * Update requests in progress (children updates and label updates) - */ - private List fPendingUpdates = new ArrayList(); - - /** - * Whether population has been canceled. - */ - private boolean fCanceled = false; - - /** - * Root element in the model. - */ - private VirtualElement fRoot = null; - - /** - * Progress monitor to use during retrieval of virtual elements - */ - private IProgressMonitor fMonitor = null; - - /** - * Column IDs to generate labels for or <code>null</code> if no columns. - */ - private String[] fColumnIds; - - /** - * Count of the number of virtual (unrealized) elements in this model - * when it was created. - */ - private int fVirtualCount = 0; - - /** - * Creates a virtual model for this tree viewer limited to the given - * subtrees. Includes the entire model if root is <code>null</code>. - * - * @param root limits model to given subtree scope, or <code>null</code> - * @param childIndexes children of the root to consider or <code>null</code> - */ - VirtualModel(TreePath root, int[] childIndexes) { - fRoot = new VirtualElement(getTree(), this, root, childIndexes); - } - - /** - * Increments the counter of virtual elements in the model. - */ - void incVirtual() { - fVirtualCount++; - } - - /** - * update progress monitor - * - * @param work - */ - void worked(int work) { - fMonitor.worked(work); - } - - /** - * Schedules a children update. - */ - private synchronized void scheduleUpdate(IChildrenUpdate update) { - Object element = update.getElement(); - if (element == null) { - element = getInput(); - } - IElementContentProvider provider = ViewerAdapterService.getContentProvider(element); - if (provider != null) { - fPendingUpdates.add(update); - provider.update(new IChildrenUpdate[]{update}); - } - } - - /** - * Populates this models elements that have not yet been retrieved from the model, - * returning all elements in the model, or <code>null</code> if canceled. - * - * @param monitor progress monitor for progress reporting and for checking if canceled - * @param taskName used in progress monitor, for example "Find..." - * @param columnIds labels to generate or <code>null</code> if no columns are to be used - * @return model elements or <code>null</code> if canceled - */ - public VirtualElement populate(IProgressMonitor monitor, String taskName, String[] columnIds) { - fMonitor = monitor; - fColumnIds = columnIds; - monitor.beginTask(taskName, fVirtualCount * 2); - boolean done = false; - fRoot.retrieveChildren(TreePath.EMPTY, this); - synchronized (this) { - done = fPendingUpdates.isEmpty(); - } - while (!done) { - synchronized (this) { - try { - wait(500); - } catch (InterruptedException e) { - } - } - if (monitor.isCanceled()) { - cancel(); - return null; - } - synchronized (this) { - done = fPendingUpdates.isEmpty(); - } - } - monitor.done(); - return fRoot; - } - - /** - * Cancels all pending updates. - */ - void cancel() { - synchronized (this) { - fCanceled = true; - Iterator iterator = fPendingUpdates.iterator(); - while (iterator.hasNext()) { - IViewerUpdate update = (IViewerUpdate) iterator.next(); - update.cancel(); - } - fPendingUpdates.clear(); - } - } - private synchronized boolean isCanceled() { - return fCanceled; - } - - /** - * Notification the given children update is complete. Schedules associated label - * updates if the request or the population of the model has not been canceled. - * - * @param update completed children update request - */ - synchronized void done(VirtualChildrenUpdate update) { - if (!isCanceled()) { - fPendingUpdates.remove(update); - if (!update.isCanceled()) { - VirtualElement[] children = update.fVirtualElement.fChildren; - TreePath parent = update.getElementPath(); - IElementLabelProvider provider = null; - List requests = new ArrayList(); - int start = update.getOffset(); - int end = start + update.getLength(); - for (int i = start; i < end; i++) { - int viewIndex = ((ITreeModelContentProvider)getContentProvider()).modelToViewIndex(parent, i); - VirtualElement proxy = children[viewIndex]; - if (proxy.fFiltered) { - fMonitor.worked(1); // don't need the label, this one is already done - } else { - Object element = proxy.fElement; - if (element != null) { // null indicates other updates coming later - VirtualLabelUpdate labelUpdate = new VirtualLabelUpdate(update.fModel, proxy, parent.createChildPath(element)); - proxy.setLabelUpdate(labelUpdate); - IElementLabelProvider next = ViewerAdapterService.getLabelProvider(element); - if (next != null) { - fPendingUpdates.add(labelUpdate); - } - if (provider == null) { - provider = next; - requests.add(labelUpdate); - } else if (next != null) { - if (provider.equals(next)) { - requests.add(labelUpdate); - } else { - // schedule queued requests, label provider has changed - provider.update((ILabelUpdate[])requests.toArray(new ILabelUpdate[requests.size()])); - requests.clear(); - requests.add(labelUpdate); - provider = next; - } - } - } - } - } - if (provider != null && !requests.isEmpty()) { - provider.update((ILabelUpdate[])requests.toArray(new ILabelUpdate[requests.size()])); - } - } - notifyAll(); - } - } - - /** - * Notification the given label update is complete. Updates progress reporting - * and updates pending updates. - * - * @param update label update that was completed - */ - synchronized void done(VirtualLabelUpdate update) { - if (!isCanceled()) { - fPendingUpdates.remove(update); - fMonitor.worked(1); - } - if (fPendingUpdates.isEmpty()) { - notifyAll(); - } - } - } - - /** - * Request to update a range of children. - */ - class VirtualChildrenUpdate extends VirtualUpdate implements IChildrenUpdate { - - private int fOffset = -1; - private int fLength = 0; - - /** - * @param elementPath - */ - public VirtualChildrenUpdate(TreePath parentPath, VirtualElement parent, VirtualModel model) { - super(model, parent, parentPath); - } - - /* (non-Javadoc) - * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate#getLength() - */ - public int getLength() { - return fLength; - } - - /* (non-Javadoc) - * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate#getOffset() - */ - public int getOffset() { - return fOffset; - } - - /* (non-Javadoc) - * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate#setChild(java.lang.Object, int) - */ - public void setChild(Object child, int offset) { - int viewIndex = ((ITreeModelContentProvider)getContentProvider()).modelToViewIndex(getElementPath(), offset); - VirtualElement virtualChild = getVirtualElement().fChildren[viewIndex]; - virtualChild.setElement(child); - ITreeModelContentProvider provider = (ITreeModelContentProvider) getContentProvider(); - virtualChild.fFiltered = provider.shouldFilter(getElementPath(), child); - if (!virtualChild.fFiltered) { - virtualChild.retrieveChildren(getElementPath().createChildPath(child), fModel); - } - fModel.worked(1); - } - - /* (non-Javadoc) - * @see org.eclipse.debug.internal.core.commands.Request#done() - */ - public void done() { - fModel.done(this); - } - - /** - * @param treeItem - * @param i - */ - void add(int i) { - if (fOffset == -1) { - fOffset = i; - } - fLength++; - } - - } - - class VirtualLabelUpdate extends VirtualUpdate implements ILabelUpdate { - - /** - * Constructs a label request for the given element; - * - * @param elementPath - */ - public VirtualLabelUpdate(VirtualModel coordinator, VirtualElement element, TreePath elementPath) { - super(coordinator, element, elementPath); - } - - private String[] fText; - private ImageDescriptor fImage; - - /* (non-Javadoc) - * @see org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate#getColumnIds() - */ - public String[] getColumnIds() { - return fModel.fColumnIds; - } - - /* (non-Javadoc) - * @see org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate#setBackground(org.eclipse.swt.graphics.RGB, int) - */ - public void setBackground(RGB background, int columnIndex) { - } - - /* (non-Javadoc) - * @see org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate#setFontData(org.eclipse.swt.graphics.FontData, int) - */ - public void setFontData(FontData fontData, int columnIndex) { - } - - /* (non-Javadoc) - * @see org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate#setForeground(org.eclipse.swt.graphics.RGB, int) - */ - public void setForeground(RGB foreground, int columnIndex) { - } - - /* (non-Javadoc) - * @see org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate#setImageDescriptor(org.eclipse.jface.resource.ImageDescriptor, int) - */ - public void setImageDescriptor(ImageDescriptor image, int columnIndex) { - fImage = image; - } - - /* (non-Javadoc) - * @see org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate#setLabel(java.lang.String, int) - */ - public void setLabel(String text, int columnIndex) { - if (fText == null) { - if (getColumnIds() == null) { - fText = new String[1]; - } else { - fText = new String[getColumnIds().length]; - } - } - fText[columnIndex] = text; - } - - /* (non-Javadoc) - * @see org.eclipse.debug.internal.core.commands.Request#done() - */ - public void done() { - fModel.done(this); - } - - } - - /** - * @param parent - * @param style - */ - public InternalTreeModelViewer(Composite parent, int style, IPresentationContext context) { - super(parent, style); - if ((style & SWT.VIRTUAL) == 0) { - throw new IllegalArgumentException("style must include SWT.VIRTUAL"); //$NON-NLS-1$ - } - setUseHashlookup(true); - fCellModifier = new CellModifierProxy(); - fContext = context; - setContentProvider(createContentProvider()); - setLabelProvider(createLabelProvider()); - - fIsPopup = (style & SWT.POP_UP) != 0; - if (fIsPopup) { - ((ITreeModelContentProvider)getContentProvider()).setModelDeltaMask( - ~ITreeModelContentProvider.ALL_MODEL_DELTA_FLAGS & ~ITreeModelContentProvider.CONTROL_MODEL_DELTA_FLAGS); - } - if ((style & SWT.CHECK) != 0) { - context.setProperty(ICheckUpdate.PROP_CHECK, Boolean.TRUE); - } - } - - /** - * @return content provider for this tree viewer - */ - protected ITreeModelContentProvider createContentProvider() - { - return new TreeModelContentProvider(); - } - - /** - * @return label provider for this tree viewer - */ - protected ITreeModelLabelProvider createLabelProvider() - { - return new TreeModelLabelProvider(this); - } - - /* (non-Javadoc) - * - * Workaround for bug 159461: when an item is cleared it's label is cleared. To avoid - * flashing, restore its label to its previous value. - * - * @see org.eclipse.jface.viewers.TreeViewer#hookControl(org.eclipse.swt.widgets.Control) - */ - protected void hookControl(Control control) { - Tree treeControl = (Tree) control; - treeControl.addListener(SWT.SetData, new Listener() { - public void handleEvent(Event event) { - // to avoid flash, reset previous label data - TreeItem item = (TreeItem) event.item; - preserveItem(item); - } - }); - super.hookControl(control); - } - - /** - * @param item - */ - private void preserveItem(TreeItem item) { - Object[] labels = (Object[]) item.getData(PREV_LABEL_KEY); - if (labels != null) { - for (int i = 0; i < labels.length; i++) { - if (labels[i] != null) { - item.setText(i, (String)labels[i]); - } - } - } - Object[] images = (Object[]) item.getData(PREV_IMAGE_KEY); - if (images != null) { - for (int i = 0; i < images.length; i++) { - item.setImage(i, (Image) images[i]); - } - } - Object[] fonts = (Object[]) item.getData(PREV_FONT_KEY); - if (fonts != null) { - for (int i = 0; i < fonts.length; i++) { - item.setFont(i, (Font) fonts[i]); - } - } - Object[] foregrounds = (Object[]) item.getData(PREV_FOREGROUND_KEY); - if (foregrounds != null) { - for (int i = 0; i < foregrounds.length; i++) { - item.setForeground(i, (Color) foregrounds[i]); - } - } - Object[] backgrounds = (Object[]) item.getData(PREV_BACKGROUND_KEY); - if (backgrounds != null) { - for (int i = 0; i < backgrounds.length; i++) { - item.setBackground(i, (Color) backgrounds[i]); - } - } - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.StructuredViewer#handleInvalidSelection - * - * Override the default handler for invalid selection to allow model - * selection policy to select the new selection. - */ - protected void handleInvalidSelection(ISelection selection, ISelection newSelection) { - IModelSelectionPolicy selectionPolicy = ViewerAdapterService.getSelectionPolicy(selection, getPresentationContext()); - if (selectionPolicy != null) { - while (!selection.equals(newSelection)) { - ISelection temp = newSelection; - selection = selectionPolicy.replaceInvalidSelection(selection, newSelection); - if (selection == null) { - selection = TreeSelection.EMPTY; - } - if (!temp.equals(selection)) { - setSelectionToWidget(selection, false); - newSelection = getSelection(); - } else { - break; - } - } - } - super.handleInvalidSelection(selection, newSelection); - } - - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.ContentViewer#handleDispose(org.eclipse.swt.events.DisposeEvent) - */ - protected void handleDispose(DisposeEvent event) { - if (fColumnPresentation != null) { - fColumnPresentation.dispose(); - } - fCellModifier.dispose(); - - if (!fIsPopup) { - fContext.dispose(); - } - super.handleDispose(event); - } - - /** - * Returns this viewer's presentation context. - * - * @return presentation context - */ - public IPresentationContext getPresentationContext() { - return fContext; - } - - protected void unmapElement(Object element, Widget widget) { - if (fNotifyUnmap) { - // TODO: should we update the filter with the "new non-identical element"? - ((ITreeModelContentProvider) getContentProvider()).unmapPath((TreePath) widget.getData(TREE_PATH_KEY)); - } - super.unmapElement(element, widget); - } - - protected void associate(Object element, Item item) { - // see AbstractTreeViewer.associate(...) - Object data = item.getData(); - if (data != null && data != element && equals(data, element)) { - // elements are equal but not identical - // -> being removed from map, but should not change filters - try { - fNotifyUnmap = false; - super.associate(element, item); - } finally { - fNotifyUnmap = true; - } - } else { - super.associate(element, item); - } - } - - /* (non-Javadoc) - * - * We need tree paths when disposed/unmapped in any order so cache the tree path. - * - * @see org.eclipse.jface.viewers.TreeViewer#mapElement(java.lang.Object, org.eclipse.swt.widgets.Widget) - */ - protected void mapElement(Object element, Widget widget) { - super.mapElement(element, widget); - if (widget instanceof Item) { - widget.setData(TREE_PATH_KEY, getTreePathFromItem((Item)widget)); - } else { - widget.setData(TREE_PATH_KEY, ModelContentProvider.EMPTY_TREE_PATH); - } - } - - /* (non-Javadoc) - * - * Override because we allow inserting with filters present. - * - * @see org.eclipse.jface.viewers.AbstractTreeViewer#insert(java.lang.Object, java.lang.Object, int) - */ - public void insert(Object parentElementOrTreePath, Object element, int position) { - try { - fInserting = true; - super.insert(parentElementOrTreePath, element, position); - } finally { - fInserting = false; - } - } - - /* (non-Javadoc) - * - * Override because we allow inserting with filters present. - * - * @see org.eclipse.jface.viewers.StructuredViewer#hasFilters() - */ - protected boolean hasFilters() { - if (fInserting) { - return false; - } - return super.hasFilters(); - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.AbstractTreeViewer#inputChanged(java.lang.Object, java.lang.Object) - */ - protected void inputChanged(Object input, Object oldInput) { - super.inputChanged(input, oldInput); - resetColumns(input); - } - - /** - * Configures the columns for the given viewer input. - * - * @param input - */ - protected void resetColumns(Object input) { - if (input != null) { - // only change columns if the input is non-null (persist when empty) - IColumnPresentationFactory factory = ViewerAdapterService.getColumnPresentationFactory(input); - PresentationContext context = (PresentationContext) getPresentationContext(); - String type = null; - if (factory != null) { - type = factory.getColumnPresentationId(context, input); - } - if (type != null) { - if (fColumnPresentation != null) { - if (!fColumnPresentation.getId().equals(type)) { - // dispose old, create new - fColumnPresentation.dispose(); - fColumnPresentation = null; - } - } - if (fColumnPresentation == null) { - fColumnPresentation = factory.createColumnPresentation(context, input); - if (fColumnPresentation != null) { - fColumnPresentation.init(context); - configureColumns(); - } - } - } else { - if (fColumnPresentation != null) { - fColumnPresentation.dispose(); - fColumnPresentation = null; - configureColumns(); - } - } - } - } - - /** - * Configures the columns based on the current settings. - * - * @param input - */ - protected void configureColumns() { - if (fColumnPresentation != null) { - IColumnPresentation build = null; - if (isShowColumns(fColumnPresentation.getId())) { - build = fColumnPresentation; - } - buildColumns(build); - } else { - // get rid of columns - buildColumns(null); - } - } - - /** - * Toggles columns on/off for the current column presentation, if any. - * - * @param show whether to show columns if the current input supports - * columns - */ - public void setShowColumns(boolean show) { - if (show) { - if (!isShowColumns()) { - fShowColumns.remove(fColumnPresentation.getId()); - } - } else { - if (isShowColumns()){ - fShowColumns.put(fColumnPresentation.getId(), Boolean.FALSE); - } - } - refreshColumns(); - } - - /** - * Resets any persisted column size for the given columns - */ - public void resetColumnSizes(String[] columnIds) { - for (int i = 0; i < columnIds.length; i++) { - fColumnSizes.remove(columnIds[i]); - } - } - - /** - * Sets the id's of visible columns, or <code>null</code> to set default columns. - * Only effects the current column presentation. - * - * @param ids visible columns - */ - public void setVisibleColumns(String[] ids) { - if (ids != null && ids.length == 0) { - ids = null; - } - IColumnPresentation presentation = getColumnPresentation(); - if (presentation != null) { - fColumnOrder.remove(presentation.getId()); - fVisibleColumns.remove(presentation.getId()); - if (ids != null) { - // put back in table if not default - String[] columns = presentation.getInitialColumns(); - if (columns.length == ids.length) { - for (int i = 0; i < columns.length; i++) { - if (!ids[i].equals(columns[i])) { - fVisibleColumns.put(presentation.getId(), ids); - break; - } - } - } else { - fVisibleColumns.put(presentation.getId(), ids); - } - } - PresentationContext presentationContext = (PresentationContext) getPresentationContext(); - presentationContext.setColumns(getVisibleColumns()); - refreshColumns(); - } - } - - /** - * Refreshes the columns in the view, based on the viewer input. - */ - protected void refreshColumns() { - configureColumns(); - refresh(); - } - - /** - * Returns whether columns are being displayed currently. - * - * @return - */ - public boolean isShowColumns() { - if (fColumnPresentation != null) { - return isShowColumns(fColumnPresentation.getId()); - } - return false; - } - - /** - * Returns whether columns can be toggled on/off for the current input. - * - * @return whether columns can be toggled on/off for the current input - */ - public boolean canToggleColumns() { - return fColumnPresentation != null && fColumnPresentation.isOptional(); - } - - protected boolean isShowColumns(String columnPresentationId) { - Boolean bool = (Boolean) fShowColumns.get(columnPresentationId); - if (bool == null) { - return true; - } - return bool.booleanValue(); - } - - /** - * Creates new columns for the given presentation. - * - * TODO: does this need to be asynchronous? - * - * @param presentation - */ - protected void buildColumns(IColumnPresentation presentation) { - // dispose current columns, persisting their weights - Tree tree = getTree(); - final TreeColumn[] columns = tree.getColumns(); - String[] visibleColumnIds = getVisibleColumns(); - for (int i = 0; i < columns.length; i++) { - TreeColumn treeColumn = columns[i]; - treeColumn.removeControlListener(fListener); - treeColumn.dispose(); - } - PresentationContext presentationContext = (PresentationContext) getPresentationContext(); - if (presentation != null) { - for (int i = 0; i < visibleColumnIds.length; i++) { - String id = visibleColumnIds[i]; - String header = presentation.getHeader(id); - // TODO: allow client to specify style - TreeColumn column = new TreeColumn(tree, SWT.LEFT, i); - column.setMoveable(true); - column.setText(header); - column.setWidth(1); - ImageDescriptor image = presentation.getImageDescriptor(id); - if (image != null) { - column.setImage(((ITreeModelLabelProvider)getLabelProvider()).getImage(image)); - } - column.setData(id); - } - int[] order = (int[]) fColumnOrder.get(presentation.getId()); - if (order != null) { - tree.setColumnOrder(order); - } - tree.setHeaderVisible(true); - tree.setLinesVisible(true); - presentationContext.setColumns(getVisibleColumns()); - setColumnProperties(getVisibleColumns()); - setCellModifier(fCellModifier); - } else { - tree.setHeaderVisible(false); - tree.setLinesVisible(false); - presentationContext.setColumns(null); - setCellModifier(null); - setColumnProperties(null); - } - - - int avg = tree.getSize().x; - if (visibleColumnIds != null) - avg /= visibleColumnIds.length; - - if (avg == 0) { - tree.addPaintListener(new PaintListener() { - public void paintControl(PaintEvent e) { - Tree tree2 = getTree(); - String[] visibleColumns = getVisibleColumns(); - if (visibleColumns != null) { - int avg1 = tree2.getSize().x / visibleColumns.length; - initColumns(avg1); - } - tree2.removePaintListener(this); - } - }); - } else { - initColumns(avg); - } - } - - private void initColumns(int widthHint) { - TreeColumn[] columns = getTree().getColumns(); - for (int i = 0; i < columns.length; i++) { - TreeColumn treeColumn = columns[i]; - Integer width = (Integer) fColumnSizes.get(treeColumn.getData()); - if (width == null) { - treeColumn.setWidth(widthHint); - } else { - treeColumn.setWidth(width.intValue()); - } - treeColumn.addControlListener(fListener); - } - } - - /** - * Returns the current column presentation for this viewer, or <code>null</code> - * if none. - * - * @return column presentation or <code>null</code> - */ - public IColumnPresentation getColumnPresentation() { - return fColumnPresentation; - } - - /** - * Returns identifiers of the visible columns in this viewer, or <code>null</code> - * if there is currently no column presentation. - * - * @return visible columns or <code>null</code> - */ - public String[] getVisibleColumns() { - if (isShowColumns()) { - IColumnPresentation presentation = getColumnPresentation(); - if (presentation != null) { - String[] columns = (String[]) fVisibleColumns.get(presentation.getId()); - if (columns == null) { - return presentation.getInitialColumns(); - } - return columns; - } - } - return null; - } - - /** - * Persists column sizes in cache - */ - protected void persistColumnSizes() { - Tree tree = getTree(); - TreeColumn[] columns = tree.getColumns(); - for (int i = 0; i < columns.length; i++) { - TreeColumn treeColumn = columns[i]; - Object id = treeColumn.getData(); - fColumnSizes.put(id, new Integer(treeColumn.getWidth())); - } - } - - /** - * Persists column ordering - */ - protected void persistColumnOrder() { - IColumnPresentation presentation = getColumnPresentation(); - if (presentation != null) { - Tree tree = getTree(); - int[] order = tree.getColumnOrder(); - if (order.length > 0) { - for (int i = 0; i < order.length; i++) { - if (i != order[i]) { - // non default order - fColumnOrder.put(presentation.getId(), order); - return; - } - } - } - // default order - fColumnOrder.remove(presentation.getId()); - } - } - - /** - * Save viewer state into the given memento. - * - * @param memento - */ - public void saveState(IMemento memento) { - if (!fColumnSizes.isEmpty()) { - Iterator iterator = fColumnSizes.entrySet().iterator(); - while (iterator.hasNext()) { - Map.Entry entry = (Entry) iterator.next(); - IMemento sizes = memento.createChild(COLUMN_SIZES, (String)entry.getKey()); - sizes.putInteger(SIZE, ((Integer)entry.getValue()).intValue()); - } - } - if (!fShowColumns.isEmpty()) { - Iterator iterator = fShowColumns.entrySet().iterator(); - while (iterator.hasNext()) { - Map.Entry entry = (Entry) iterator.next(); - IMemento sizes = memento.createChild(SHOW_COLUMNS, (String)entry.getKey()); - sizes.putString(SHOW_COLUMNS, ((Boolean)entry.getValue()).toString()); - } - } - if (!fVisibleColumns.isEmpty()) { - Iterator iterator = fVisibleColumns.entrySet().iterator(); - while (iterator.hasNext()) { - Map.Entry entry = (Entry) iterator.next(); - String id = (String) entry.getKey(); - IMemento visible = memento.createChild(VISIBLE_COLUMNS, id); - String[] columns = (String[]) entry.getValue(); - visible.putInteger(SIZE, columns.length); - for (int i = 0; i < columns.length; i++) { - visible.putString(COLUMN+Integer.toString(i), columns[i]); - } - } - } - if (!fColumnOrder.isEmpty()) { - Iterator iterator = fColumnOrder.entrySet().iterator(); - while (iterator.hasNext()) { - Map.Entry entry = (Entry) iterator.next(); - String id = (String) entry.getKey(); - IMemento orderMemento = memento.createChild(COLUMN_ORDER, id); - int[] order = (int[]) entry.getValue(); - orderMemento.putInteger(SIZE, order.length); - for (int i = 0; i < order.length; i++) { - orderMemento.putInteger(COLUMN+Integer.toString(i), order[i]); - } - } - } - // save presentation context properties - IPresentationContext context = getPresentationContext(); - if (context instanceof PresentationContext) { - PresentationContext pc = (PresentationContext) context; - pc.saveProperites(memento); - - } - } - - /** - * Initializes viewer state from the memento - * - * @param memento - */ - public void initState(IMemento memento) { - IMemento[] mementos = memento.getChildren(COLUMN_SIZES); - for (int i = 0; i < mementos.length; i++) { - IMemento child = mementos[i]; - String id = child.getID(); - Integer size = child.getInteger(SIZE); - if (size != null) { - fColumnSizes.put(id, size); - } - } - mementos = memento.getChildren(SHOW_COLUMNS); - for (int i = 0; i < mementos.length; i++) { - IMemento child = mementos[i]; - String id = child.getID(); - Boolean bool = Boolean.valueOf(child.getString(SHOW_COLUMNS)); - if (!bool.booleanValue()) { - fShowColumns.put(id, bool); - } - } - mementos = memento.getChildren(VISIBLE_COLUMNS); - for (int i = 0; i < mementos.length; i++) { - IMemento child = mementos[i]; - String id = child.getID(); - Integer integer = child.getInteger(SIZE); - if (integer != null) { - int length = integer.intValue(); - String[] columns = new String[length]; - for (int j = 0; j < length; j++) { - columns[j] = child.getString(COLUMN+Integer.toString(j)); - } - fVisibleColumns.put(id, columns); - } - } - mementos = memento.getChildren(COLUMN_ORDER); - for (int i = 0; i < mementos.length; i++) { - IMemento child = mementos[i]; - String id = child.getID(); - Integer integer = child.getInteger(SIZE); - if (integer != null) { - int length = integer.intValue(); - int[] order = new int[length]; - for (int j = 0; j < length; j++) { - order[j] = child.getInteger(COLUMN+Integer.toString(j)).intValue(); - } - fColumnOrder.put(id, order); - } - } - // restore presentation context properties - // save presentation context properties - IPresentationContext context = getPresentationContext(); - if (context instanceof PresentationContext) { - PresentationContext pc = (PresentationContext) context; - pc.initProperties(memento); - } - } - - /** - * Returns whether the candidate selection should override the current - * selection. - * - * @param current - * @param curr - * @return - */ - public boolean overrideSelection(ISelection current, ISelection candidate) { - IModelSelectionPolicy selectionPolicy = ViewerAdapterService.getSelectionPolicy(current, getPresentationContext()); - if (selectionPolicy == null) { - return true; - } - if (selectionPolicy.contains(candidate, getPresentationContext())) { - return selectionPolicy.overrides(current, candidate, getPresentationContext()); - } - return !selectionPolicy.isSticky(current, getPresentationContext()); - } - - /* (non-Javadoc) - * - * Consider selection policy - * - * @see org.eclipse.jface.viewers.StructuredViewer#setSelection(org.eclipse.jface.viewers.ISelection, boolean) - */ - public void setSelection(ISelection selection, boolean reveal) { - if (!overrideSelection(getSelection(), selection)) { - return; - } - super.setSelection(selection, reveal); - } - - /** - * Sets the selection in the viewer to the specified selection. - * - * @param selection the selection - * @param reveal whether to reveal the selection - * @param force whether to force the selection (i.e. <code>true</code> to - * override the model selection policy) - */ - public void setSelection(ISelection selection, boolean reveal, boolean force) { - if (force) { - super.setSelection(selection, reveal); - } else { - setSelection(selection, reveal); - } - } - - /** - * Registers the specified listener for view update notifications. - * - * @param listener listener - */ - public void addViewerUpdateListener(IViewerUpdateListener listener) { - ((ITreeModelContentProvider)getContentProvider()).addViewerUpdateListener(listener); - } - - /** - * Removes the specified listener from update notifications. - * - * @param listener listener - */ - public void removeViewerUpdateListener(IViewerUpdateListener listener) { - ITreeModelContentProvider cp = (ITreeModelContentProvider)getContentProvider(); - if (cp != null) { - cp.removeViewerUpdateListener(listener); - } - } - - /** - * Registers the given listener for model delta notification. - * - * @param listener model delta listener - */ - public void addModelChangedListener(IModelChangedListener listener) { - ((ITreeModelContentProvider)getContentProvider()).addModelChangedListener(listener); - } - - /** - * Unregisters the given listener from model delta notification. - * - * @param listener model delta listener - */ - public void removeModelChangedListener(IModelChangedListener listener) { - ITreeModelContentProvider cp = (ITreeModelContentProvider)getContentProvider(); - if (cp != null) { - cp.removeModelChangedListener(listener); - } - } - - public void addStateUpdateListener(IStateUpdateListener listener) { - ((ITreeModelContentProvider)getContentProvider()).addStateUpdateListener(listener); - } - - public void removeStateUpdateListener(IStateUpdateListener listener) { - ITreeModelContentProvider cp = (ITreeModelContentProvider)getContentProvider(); - if (cp != null) { - cp.removeStateUpdateListener(listener); - } - } - - /* - * (non-Javadoc) Method declared in AbstractTreeViewer. - */ - protected void doUpdateItem(final Item item, Object element) { - if (!(item instanceof TreeItem)) { - return; - } - TreeItem treeItem = (TreeItem) item; - if (treeItem.isDisposed()) { - unmapElement(element, treeItem); - return; - } - - if ( !((ITreeModelLabelProvider)getLabelProvider()).update(getTreePathFromItem(item)) ) { - if (element instanceof String) { - item.setData(PREV_LABEL_KEY, new String[] { (String)element } ); - } - } - - - // As it is possible for user code to run the event - // loop check here. - if (item.isDisposed()) { - unmapElement(element, item); - } - } - - /** - * Collects all expanded items from this tree viewer and returns them as part of - * a virtual model. This must be called in a UI thread to traverse the tree items. - * The model can the be populated in a non-UI thread. - * - * Alternatively a root element can be specified with a set of child indexes to - * consider. All children of the specified children are added to the model. - * - * @param root subtree to consider or <code>null</code> if all - * @param childIndexes indexes of root element to consider, or <code>null</code> if all - * @return virtual model - */ - VirtualModel buildVirtualModel(TreePath root, int[] childIndexes) { - return new VirtualModel(root, childIndexes); - } - - public void addLabelUpdateListener(ILabelUpdateListener listener) { - ((ITreeModelLabelProvider)getLabelProvider()).addLabelUpdateListener(listener); - } - - public void removeLabelUpdateListener(ILabelUpdateListener listener) { - if (!getControl().isDisposed()) { - ((ITreeModelLabelProvider)getLabelProvider()).removeLabelUpdateListener(listener); - } - } - - /** - * Returns the item for the element at the given tree path or <code>null</code> - * if none. - * - * @param path tree path - * @return item or <code>null</code> - */ - public Widget findItem(TreePath path) { - if (path.getSegmentCount() == 0) { - return getTree(); - } - Widget[] items = super.findItems(path.getLastSegment()); - if (items.length == 1) { - return items[0]; - } - for (int i = 0; i < items.length; i++) { - if (getTreePathFromItem((Item)items[i]).equals(path)) { - return items[i]; - } - } - return null; - } - - public Item[] getChildren(Widget widget) { - return super.getChildren(widget); - } - - /** - * Returns the tree path for the given item. - * @param item - * @return {@link TreePath} - */ - protected TreePath getTreePathFromItem(Item item) { - return super.getTreePathFromItem(item); - } - -//************************************************************************** -// These methods were copied from TreeViewer as a workaround for bug 183463: -// Expanded nodes in tree viewer flash on refresh - - /* - * (non-Javadoc) - * - * workaround for bug 183463 - * - * @see org.eclipse.jface.viewers.AbstractTreeViewer#internalRefreshStruct(org.eclipse.swt.widgets.Widget, - * java.lang.Object, boolean) - */ - protected void internalRefreshStruct(Widget widget, Object element, - boolean updateLabels) { - // clear all starting with the given widget - if (widget instanceof Tree) { - ((Tree) widget).clearAll(true); - } else if (widget instanceof TreeItem) { - ((TreeItem) widget).clearAll(true); - } - int index = 0; - Widget parent = null; - if (widget instanceof TreeItem) { - TreeItem treeItem = (TreeItem) widget; - parent = treeItem.getParentItem(); - if (parent == null) { - parent = treeItem.getParent(); - } - if (parent instanceof Tree) { - index = ((Tree) parent).indexOf(treeItem); - } else { - index = ((TreeItem) parent).indexOf(treeItem); - } - } - virtualRefreshExpandedItems(parent, widget, element, index); - } - - /** - * Traverses the visible (expanded) part of the tree and updates child - * counts. - * <p> - * workaround for bug 183463 - * </p> - * @param parent the parent of the widget, or <code>null</code> if the widget is the tree - * @param widget - * @param element - * @param index the index of the widget in the children array of its parent, or 0 if the widget is the tree - */ - private void virtualRefreshExpandedItems(Widget parent, Widget widget, Object element, int index) { - if (widget instanceof Tree) { - if (element == null) { - ((Tree) widget).setItemCount(0); - return; - } - virtualLazyUpdateChildCount(widget, getChildren(widget).length); - } else if (((TreeItem) widget).getExpanded()) { - // prevent SetData callback - preserveItem((TreeItem)widget); - //((TreeItem)widget).setText(" "); //$NON-NLS-1$ - virtualLazyUpdateWidget(parent, index); - } else { - return; - } - Item[] items = getChildren(widget); - for (int i = 0; i < items.length; i++) { - Item item = items[i]; - Object data = item.getData(); - virtualRefreshExpandedItems(widget, item, data, i); - } - } - - /** - * workaround for bug 183463 - * - * Update the child count - * @param widget - * @param currentChildCount - */ - private void virtualLazyUpdateChildCount(Widget widget, int currentChildCount) { - TreePath treePath; - if (widget instanceof Item) { - treePath = getTreePathFromItem((Item) widget); - } else { - treePath = TreePath.EMPTY; - } - ((ILazyTreePathContentProvider) getContentProvider()) - .updateChildCount(treePath, currentChildCount); - } - - /** - * Update the widget at index. - * <p> - * workaround for bug 183463 - * </p> - * @param widget - * @param index - */ - private void virtualLazyUpdateWidget(Widget widget, int index) { - TreePath treePath; - if (widget instanceof Item) { - if (widget.getData() == null) { - // we need to materialize the parent first - // see bug 167668 - // however, that would be too risky - // see bug 182782 and bug 182598 - // so we just ignore this call altogether - // and don't do this: virtualMaterializeItem((TreeItem) widget); - return; - } - treePath = getTreePathFromItem((Item) widget); - } else { - treePath = TreePath.EMPTY; - } - ((ILazyTreePathContentProvider) getContentProvider()) - .updateElement(treePath, index); - } - -//************************************************************************** -// Another couple of methods copied from TreeViewer to workaround the UI bug 266189. -// - protected void createChildren(Widget widget) { - Object element = widget.getData(); - if (element == null && widget instanceof TreeItem) { - // parent has not been materialized - virtualMaterializeItem((TreeItem) widget); - // try getting the element now that updateElement was called - element = widget.getData(); - } - if (element == null) { - // give up because the parent is still not materialized - return; - } - Item[] children = getChildren(widget); - if (children.length == 1 && children[0].getData() == null) { - // found a dummy node - virtualLazyUpdateChildCount(widget, children.length); - children = getChildren(widget); - } - // DO NOT touch all children - return; - } - - private void virtualMaterializeItem(TreeItem treeItem) { - if (treeItem.getData() != null) { - // already materialized - return; - } - - int index; - Widget parent = treeItem.getParentItem(); - if (parent == null) { - parent = treeItem.getParent(); - } - Object parentElement = parent.getData(); - if (parentElement != null) { - if (parent instanceof Tree) { - index = ((Tree) parent).indexOf(treeItem); - } else { - index = ((TreeItem) parent).indexOf(treeItem); - } - virtualLazyUpdateWidget(parent, index); - } - } - - - /** - * Performs auto expand on an element at the specified path if the auto expand - * level dictates the element should be expanded. - * - * @param elementPath tree path to element to consider for expansion - */ - public void autoExpand(TreePath elementPath) { - int level = getAutoExpandLevel(); - if (level > 0 || level == ITreeModelViewer.ALL_LEVELS) { - if (level == ITreeModelViewer.ALL_LEVELS || level >= elementPath.getSegmentCount()) { - expandToLevel(elementPath, 1); - } - } - } - - public int findElementIndex(TreePath parentPath, Object element) { - Widget parentItem = findItem(parentPath); - if (parentItem != null) { - Item[] children = getChildren(parentItem); - for (int i = 0; i < children.length; i++) { - Item item = children[i]; - Object data = item.getData(); - if ( (element != null && element.equals(data)) || (element == null && data == null) ) { - return i; - } - } - } - return -1; - } - - public boolean getElementChildrenRealized(TreePath parentPath) { - Widget parentItem = findItem(parentPath); - if (parentItem != null) { - Item[] children = getChildren(parentItem); - for (int i = 0; i < children.length; i++) { - if (children[i].getData() == null) { - return false; - } - } - } - return true; - } - - public Display getDisplay() { - Control control = getControl(); - if (control != null) { - return control.getDisplay(); - } - return null; - } - - protected static final String[] STATE_PROPERTIES = new String[]{ IBasicPropertyConstants.P_TEXT, IBasicPropertyConstants.P_IMAGE }; - - public void update(Object element) { - update(element, STATE_PROPERTIES); - } - - /** - * Label data cache keys - * TODO: workaround for bug 159461 - */ - static String PREV_LABEL_KEY = "PREV_LABEL_KEY"; //$NON-NLS-1$ - static String PREV_IMAGE_KEY = "PREV_IMAGE_KEY"; //$NON-NLS-1$ - static String PREV_FONT_KEY = "PREV_FONT_KEY"; //$NON-NLS-1$ - static String PREV_FOREGROUND_KEY = "PREV_FOREGROUND_KEY"; //$NON-NLS-1$ - static String PREV_BACKGROUND_KEY = "PREV_BACKGROUND_KEY"; //$NON-NLS-1$ - - public void setElementData(TreePath path, int numColumns, String[] labels, ImageDescriptor[] imageDescriptors, - FontData[] fontDatas, RGB[] _foregrounds, RGB[] _backgrounds) - { - Widget widget = findItem(path); - String[] columnIds = getVisibleColumns(); - - if (widget != null && widget instanceof TreeItem && !widget.isDisposed()) { - TreeItem item = (TreeItem)widget; - /*Object data = item.getData(); - int itemCount = item.getItemCount(); - item.clearAll(false); - item.setData(data); - item.setItemCount(itemCount);*/ - - for (int i=0; i<numColumns; i++){ - // text might be null if the launch has been terminated - item.setText(i,(labels[i] == null ? IInternalDebugCoreConstants.EMPTY_STRING : labels[i])); - } - item.setData(PREV_LABEL_KEY, labels); - - if (imageDescriptors == null) { - for (int i=0; i<numColumns; i++){ - item.setImage(i,null); - } - item.setData(PREV_IMAGE_KEY, null); - } else { - Image[] images = new Image[imageDescriptors.length]; - for (int i = 0; i < imageDescriptors.length; i++) { - images[i] = ((ITreeModelLabelProvider)getLabelProvider()).getImage(imageDescriptors[i]); - } - if (columnIds == null) { - item.setImage(images[0]); - } else { - item.setImage(images); - } - item.setData(PREV_IMAGE_KEY, images); - } - - if (_foregrounds == null) { - for (int i=0; i<numColumns; i++){ - item.setForeground(i,null); - } - item.setData(PREV_FOREGROUND_KEY, null); - } else { - Color[] foregrounds = new Color[_foregrounds.length]; - for (int i = 0; i< foregrounds.length; i++) { - foregrounds[i] = ((ITreeModelLabelProvider)getLabelProvider()).getColor(_foregrounds[i]); - } - if (columnIds == null) { - item.setForeground(0,foregrounds[0]); - } else { - for (int i = 0; i< foregrounds.length; i++) { - item.setForeground(i, foregrounds[i]); - } - } - item.setData(PREV_FOREGROUND_KEY, foregrounds); - } - - if (_backgrounds == null) { - for (int i=0; i<numColumns; i++){ - item.setBackground(i,null); - } - item.setData(PREV_BACKGROUND_KEY, null); - } else { - Color[] backgrounds = new Color[_backgrounds.length]; - for (int i = 0; i< backgrounds.length; i++) { - backgrounds[i] = ((ITreeModelLabelProvider)getLabelProvider()).getColor(_backgrounds[i]); - } - if (columnIds == null) { - item.setBackground(0,backgrounds[0]); - } else { - for (int i = 0; i< backgrounds.length; i++) { - item.setBackground(i, backgrounds[i]); - } - } - item.setData(PREV_BACKGROUND_KEY, backgrounds); - } - - if (fontDatas == null) { - for (int i=0; i<numColumns; i++){ - item.setFont(i,null); - } - item.setData(PREV_FONT_KEY, null); - } else { - Font[] fonts = new Font[fontDatas.length]; - for (int i = 0; i < fontDatas.length; i++) { - fonts[i] = ((ITreeModelLabelProvider)getLabelProvider()).getFont(fontDatas[i]); - } - if (columnIds == null) { - item.setFont(0,fonts[0]); - } else { - for (int i = 0; i < fonts.length; i++) { - item.setFont(i, fonts[i]); - } - } - item.setData(PREV_FONT_KEY, fonts); - } - } - } - - public ViewerLabel getElementLabel(TreePath path, String columnId) { - if (path.getSegmentCount() == 0) { - return null; - } - - int columnIdx = -1; - String[] visibleColumns = getVisibleColumns(); - if (columnId != null && visibleColumns != null) { - int i = 0; - for (i = 0; i < visibleColumns.length; i++) { - if (columnId.equals(getVisibleColumns()[i])) { - columnIdx = i; - break; - } - } - if (i == visibleColumns.length) { - return null; - } - } else { - columnIdx = 0; - } - TreeItem item = (TreeItem)findItem(path); - - if (item != null) { - ViewerLabel label = new ViewerLabel(item.getText(columnIdx), item.getImage(columnIdx)); - label.setFont(item.getFont(columnIdx)); - label.setBackground(item.getBackground(columnIdx)); - label.setForeground(item.getForeground(columnIdx)); - return label; - } - return null; - } - - public void reveal(TreePath path, int index) { - Widget item = findItem(path); - TreeItem[] children = null; - if (item instanceof TreeItem) { - children = ((TreeItem)item).getItems(); - } else if (item instanceof Tree) { - children = ((Tree)item).getItems(); - } - if (children != null && index < children.length) { - getTree().setTopItem(children[index]); - } - } - - public int getChildCount(TreePath path) { - if (path.getSegmentCount() == 0) { - return ((Tree)getControl()).getItemCount(); - } else { - Widget[] items = internalFindItems(path); - if (items.length > 0) { - if (items[0] instanceof TreeItem) { - return ((TreeItem)items[0]).getItemCount(); - } - } - } - return -1; - } - - public Object getChildElement(TreePath path, int index) { - TreeItem childItem = null; - if (path.getSegmentCount() == 0) { - Tree tree = (Tree)getControl(); - try { - childItem = tree.getItem(index); - } catch (IllegalArgumentException e) {} - } else { - try { - Widget[] items = internalFindItems(path); - if (items.length > 0) { - if (items[0] instanceof TreeItem) { - childItem = ((TreeItem)items[0]).getItem(index); - } - } - } catch (IllegalArgumentException e) {} - } - if (childItem != null) { - return childItem.getData(); - } - return null; - } - - public TreePath getTopElementPath() { - TreeItem topItem = ((Tree)getControl()).getTopItem(); - if (topItem != null && topItem.getData() != null) { - return getTreePathFromItem(topItem); - } - return null; - } - - public void saveElementState(TreePath path, ModelDelta delta, int flagsToSave) { - Tree tree = (Tree) getControl(); - TreeItem[] selection = tree.getSelection(); - Set set = new HashSet(); - for (int i = 0; i < selection.length; i++) { - set.add(selection[i]); - } - - TreeItem[] items = null; - Widget w = internalGetWidgetToSelect(path); - if (w instanceof Tree) { - delta.setChildCount( - ((ITreeModelContentProvider)getContentProvider()).viewToModelCount(path, tree.getItemCount())); - if ((flagsToSave & IModelDelta.EXPAND) != 0) { - delta.setFlags(delta.getFlags() | IModelDelta.EXPAND); - } - items = tree.getItems(); - } else if (w instanceof TreeItem) { - TreeItem item = (TreeItem)w; - int itemCount = item.getItemCount(); - delta.setChildCount(((ITreeModelContentProvider)getContentProvider()).viewToModelCount(path, itemCount)); - if (item.getExpanded()) { - if ((flagsToSave & IModelDelta.EXPAND) != 0) { - delta.setFlags(delta.getFlags() | IModelDelta.EXPAND); - } - } else if ((flagsToSave & IModelDelta.COLLAPSE) != 0 && itemCount > 0){ - delta.setFlags(delta.getFlags() | IModelDelta.COLLAPSE); - } - - if (set.contains(item) && (flagsToSave & IModelDelta.SELECT) != 0) { - delta.setFlags(delta.getFlags() | IModelDelta.SELECT); - } - items = ((TreeItem)w).getItems(); - } - if (items != null) { - for (int i = 0; i < items.length; i++) { - doSaveElementState(path, delta, items[i], set, i, flagsToSave); - } - } - } - - private void doSaveElementState(TreePath parentPath, ModelDelta delta, TreeItem item, Collection set, int index, int flagsToSave) { - Object element = item.getData(); - if (element != null) { - boolean expanded = item.getExpanded(); - boolean selected = set.contains(item); - int itemCount = item.getItemCount(); - int flags = IModelDelta.NO_CHANGE; - if (expanded && (flagsToSave & IModelDelta.EXPAND) != 0) { - flags = flags | IModelDelta.EXPAND; - } - if (!expanded && (flagsToSave & IModelDelta.COLLAPSE) != 0 && itemCount > 0) { - flags = flags | IModelDelta.COLLAPSE; - } - if (selected && (flagsToSave & IModelDelta.SELECT) != 0) { - flags = flags | IModelDelta.SELECT; - } - if (expanded || flags != IModelDelta.NO_CHANGE) { - int modelIndex = ((ITreeModelContentProvider)getContentProvider()).viewToModelIndex(parentPath, index); - TreePath elementPath = parentPath.createChildPath(element); - int numChildren = ((ITreeModelContentProvider)getContentProvider()).viewToModelCount(elementPath, itemCount); - ModelDelta childDelta = delta.addNode(element, modelIndex, flags, numChildren); - if (expanded) { - TreeItem[] items = item.getItems(); - for (int i = 0; i < items.length; i++) { - doSaveElementState(elementPath, childDelta, items[i], set, i, flagsToSave); - } - } - } - } - } - - public void updateViewer(IModelDelta delta) { - ((ITreeModelContentProvider)getContentProvider()).updateModel(delta, ITreeModelContentProvider.ALL_MODEL_DELTA_FLAGS); - } - - /* - * (non-Javadoc) - * @see org.eclipse.debug.internal.ui.viewers.model.ITreeModelCheckProvider#setElementChecked(org.eclipse.jface.viewers.TreePath, boolean, boolean) - */ - public void setElementChecked(TreePath path, boolean checked, boolean grayed) { - Widget widget = findItem(path); - - if (widget != null && widget instanceof TreeItem && !widget.isDisposed()) { - TreeItem item = (TreeItem)widget; - - item.setChecked(checked); - item.setGrayed(grayed); - } - } - - public boolean getElementChecked(TreePath path) { - Widget widget = findItem(path); - - if (widget != null && widget instanceof TreeItem && !widget.isDisposed()) { - TreeItem item = (TreeItem)widget; - - return item.getChecked(); - } - return false; - } - - /** - * Retrieves the element's check box grayed state. - * - * @param path - * @return grayed - */ - public boolean getElementGrayed(TreePath path) { - Widget widget = findItem(path); - - if (widget != null && widget instanceof TreeItem && !widget.isDisposed()) { - TreeItem item = (TreeItem)widget; - - return item.getGrayed(); - } - return false; - } - - public boolean getHasChildren(Object elementOrTreePath) { - if (elementOrTreePath instanceof TreePath && - ((TreePath)elementOrTreePath).getSegmentCount() == 0) - { - return getTree().getItemCount() > 0; - } - - Widget[] items = internalFindItems(elementOrTreePath); - if (items != null && items.length > 0) { - if (items[0] instanceof TreeItem) { - return ((TreeItem)items[0]).getItemCount() > 0; - } else { - return ((Tree)items[0]).getItemCount() > 0; - } - } - - return false; - } - - /* - * (non-Javadoc) - * @see org.eclipse.jface.viewers.StructuredViewer#handleSelect(org.eclipse.swt.events.SelectionEvent) - */ - protected void handleSelect(SelectionEvent event) { - if (event.detail == SWT.CHECK) { - TreeItem item = (TreeItem) event.item; - super.handleSelect(event); - - Object element = item.getData(); - if (element != null) { - boolean checked = item.getChecked(); - - TreePath path = getTreePathFromItem(item); - - boolean accepted = false; - IContentProvider contentProvider = getContentProvider(); - if (contentProvider instanceof TreeModelContentProvider) { - IModelProxy elementProxy = ((TreeModelContentProvider) contentProvider).getElementProxy(path); - if (elementProxy instanceof ICheckboxModelProxy) { - accepted = ((ICheckboxModelProxy) elementProxy).setChecked(getPresentationContext(), getInput(), path, checked); - } - } - - // if the listen rejects the change or there is not ICheckboxModelProxy, than revert the check state - if (!accepted) - item.setChecked(!checked); - } - } else { - super.handleSelect(event); - } - } -} |