diff options
Diffstat (limited to 'org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/AsynchronousViewer.java')
-rw-r--r-- | org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/AsynchronousViewer.java | 1193 |
1 files changed, 0 insertions, 1193 deletions
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/AsynchronousViewer.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/AsynchronousViewer.java deleted file mode 100644 index e5878c461..000000000 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/AsynchronousViewer.java +++ /dev/null @@ -1,1193 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005, 2007 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.debug.internal.ui.viewers; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.eclipse.core.runtime.Assert; -import org.eclipse.core.runtime.IAdaptable; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.Status; -import org.eclipse.debug.internal.ui.DebugUIPlugin; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelChangedListener; -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.IModelSelectionPolicyFactory; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IStatusMonitor; -import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.SelectionChangedEvent; -import org.eclipse.jface.viewers.StructuredSelection; -import org.eclipse.jface.viewers.StructuredViewer; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.swt.SWT; -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.Control; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Item; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.Widget; -import org.eclipse.ui.progress.WorkbenchJob; - -/** - * A viewer that retrieves labels and content asynchronously via adapters and supports - * duplicate elements in the viewer. Retrieving content and labels asynchronously allows - * for arbitrary latency without blocking the UI thread. - * <p> - * This viewer uses adapters to retrieve labels and content rather than - * a label provider and content provider. As such, the label provider for this viewer - * is <code>null</code> by default. The content provider returned by this viewer is - * non-<code>null</code> to conform to the viewer specification, but performs no - * useful function. - * </p> - * <p> - * The selection in this viewer is also set asynchronously. When the selection is set, - * the viewer attempts to perform the selection. If the elements in the specified selection - * are not yet in the viewer, the portion of the selection that could not be honored - * becomes a pending selection. As more elements are added to viewer, the pending selection - * is attempted to be set. - * </p> - * @since 3.2 - */ -public abstract class AsynchronousViewer extends StructuredViewer implements Listener { - - /** - * Model of elements for this viewer - */ - private AsynchronousModel fModel; - - /** - * Cache of images used for elements in this tree viewer. Label updates - * use the method <code>getImage(...)</code> to cache images for - * image descriptors. The images are disposed when this viewer is disposed. - */ - private Map fImageCache = new HashMap(); - - /** - * Cache of the fonts used for elements in this tree viewer. Label updates - * use the method <code>getFont(...)</code> to cache fonts for - * FontData objects. The fonts are disposed with the viewer. - */ - private Map fFontCache = new HashMap(); - - /** - * Cache of the colors used for elements in this tree viewer. Label updates - * use the method <code>getColor(...)</code> to cache colors for - * RGB values. The colors are disposed with the viewer. - */ - private Map fColorCache = new HashMap(); - - /** - * The context in which this viewer is being used - i.e. what part it is contained - * in any any preference settings associated with it. - */ - private IPresentationContext fContext; - - private ISelection fPendingSelection; - - private ISelection fCurrentSelection; - - /** - * Array used to store indices of the path to an item in the viewer being mapped - * by a 'set data' callback. Indices are bottom up. For example when 'set data' for - * the 3rd child of the 4th child of the 2nd root element were being asked for, - * the first 3 indices would look like: [3, 4, 2, ....]. We re-use an array to avoid - * creating a new one all the time. The array grows as needed to accommodate deep - * elements. - */ - private int[] fSetDataIndicies = new int[5]; - - /** - * The update policy for this viewer. - */ - private AbstractUpdatePolicy fUpdatePolicy; - - protected static final String OLD_LABEL = "old_label"; //$NON-NLS-1$ - protected static final String OLD_IMAGE = "old_image"; //$NON-NLS-1$ - - // debug flags - public static boolean DEBUG_VIEWER = false; - - static { - DEBUG_VIEWER = DebugUIPlugin.DEBUG && "true".equals( //$NON-NLS-1$ - Platform.getDebugOption("org.eclipse.debug.ui/debug/viewers/viewer")); //$NON-NLS-1$ - } - - /** - * Creates a new viewer - */ - protected AsynchronousViewer() { - setContentProvider(new NullContentProvider()); - setUseHashlookup(true); - } - - /** - * Hash lookup is required, don't let subclasses change behavior. - */ - public final void setUseHashlookup(boolean enable) { - Assert.isTrue(enable); - super.setUseHashlookup(enable); - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.StructuredViewer#hookControl(org.eclipse.swt.widgets.Control) - */ - protected void hookControl(Control control) { - super.hookControl(control); - control.addListener(SWT.SetData, this); - } - - /** - * Clients must call this methods when this viewer is no longer needed - * so it can perform cleanup. - */ - public synchronized void dispose() { - Iterator images = fImageCache.values().iterator(); - while (images.hasNext()) { - Image image = (Image) images.next(); - image.dispose(); - } - fImageCache.clear(); - - Iterator fonts = fFontCache.values().iterator(); - while (fonts.hasNext()) { - Font font = (Font) fonts.next(); - font.dispose(); - } - fFontCache.clear(); - - Iterator colors = fColorCache.values().iterator(); - while (colors.hasNext()) { - Color color = (Color) colors.next(); - color.dispose(); - } - fColorCache.clear(); - - if (fModel != null) { - fModel.dispose(); - } - if (fUpdatePolicy != null) { - fUpdatePolicy.dispose(); - } - if (fContext != null) { - ((PresentationContext)fContext).dispose(); - } - } - - /** - * Updates all occurrences of the given element in this viewer. - * - * @param element element to update - */ - public void update(Object element) { - ModelNode[] nodes = getModel().getNodes(element); - if (nodes != null) { - for (int i = 0; i < nodes.length; i++) { - updateLabel(nodes[i]); - } - } - } - - /** - * Updates the label for a specific element (node) in the model. - * - * @param node node to update - * @param item its associated item - */ - protected void updateLabel(ModelNode node) { - // the input is not displayed - if (!node.getElement().equals(getInput())) { - getModel().updateLabel(node); - } - } - - /** - * Returns the presentation context to be used in update requests. - * Clients may override this method if required to provide special - * implementations of contexts. - * - * @return presentation context - */ - public IPresentationContext getPresentationContext() { - return fContext; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.StructuredViewer#unmapAllElements() - */ - protected synchronized void unmapAllElements() { - super.unmapAllElements(); - AsynchronousModel model = getModel(); - if (model != null) { - model.dispose(); - } - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.Viewer#inputChanged(java.lang.Object, java.lang.Object) - */ - protected synchronized void inputChanged(Object input, Object oldInput) { - fPendingSelection = null; - if (fCurrentSelection != null) { - updateSelection(new StructuredSelection()); - fCurrentSelection = null; - } - if (fUpdatePolicy == null) { - fUpdatePolicy = createUpdatePolicy(); - fUpdatePolicy.init(this); - } - if (fModel != null) { - fModel.dispose(); - } - fModel = createModel(); - fModel.init(input); - if (input != null) { - mapElement(fModel.getRootNode(), getControl()); - getControl().setData(fModel.getRootNode().getElement()); - } else { - unmapAllElements(); - getControl().setData(null); - } - refresh(); - } - - /** - * Creates a new empty model for this viewer that - * is *not* initialized. - * - * @return a new model - */ - protected abstract AsynchronousModel createModel(); - - /** - * Creates and returns this viewers update policy. - * @return update policy - */ - public abstract AbstractUpdatePolicy createUpdatePolicy(); - - Image[] getImages(ImageDescriptor[] descriptors) { - if (descriptors == null || descriptors.length == 0) { - String[] columns = getPresentationContext().getColumns(); - if (columns == null) { - return new Image[1]; - } else { - return new Image[columns.length]; - } - } - Image[] images = new Image[descriptors.length]; - for (int i = 0; i < images.length; i++) { - images[i] = getImage(descriptors[i]); - } - return images; - } - - /** - * Returns an image for the given image descriptor or <code>null</code>. Adds the image - * to a cache of images if it does not already exist. The cache is cleared when this viewer - * is disposed. - * - * @param descriptor image descriptor or <code>null</code> - * @return image or <code>null</code> - */ - protected Image getImage(ImageDescriptor descriptor) { - if (descriptor == null) { - return null; - } - Image image = (Image) fImageCache.get(descriptor); - if (image == null) { - image = new Image(getControl().getDisplay(), descriptor.getImageData()); - fImageCache.put(descriptor, image); - } - return image; - } - - protected Font[] getFonts(FontData[] fontDatas) { - if (fontDatas == null || fontDatas.length == 0) { - String[] columns = getPresentationContext().getColumns(); - if (columns == null) { - return new Font[1]; - } else { - return new Font[columns.length]; - } - } - - Font[] fonts = new Font[fontDatas.length]; - for (int i = 0; i < fonts.length; i++) { - fonts[i] = getFont(fontDatas[i]); - } - return fonts; - } - - /** - * Returns a font for the given font data or <code>null</code>. Adds the font to this viewer's font - * cache which is disposed when this viewer is disposed. - * - * @param fontData font data or <code>null</code> - * @return font font or <code>null</code> - */ - protected Font getFont(FontData fontData) { - if (fontData == null) { - return null; - } - Font font = (Font) fFontCache.get(fontData); - if (font == null) { - font = new Font(getControl().getDisplay(), fontData); - fFontCache.put(fontData, font); - } - return font; - } - - protected Color[] getColors(RGB[] rgb) { - if (rgb == null || rgb.length == 0) { - String[] columns = getPresentationContext().getColumns(); - if (columns == null) { - return new Color[1]; - } else { - return new Color[columns.length]; - } - } - Color[] colors = new Color[rgb.length]; - for (int i = 0; i < colors.length; i++) { - colors[i] = getColor(rgb[i]); - } - return colors; - } - /** - * Returns a color for the given RGB or <code>null</code>. Adds the color to this viewer's color - * cache which is disposed when this viewer is disposed. - * - * @param rgb RGB or <code>null</code> - * @return color or <code>null</code> - */ - protected Color getColor(RGB rgb) { - if (rgb == null) { - return null; - } - Color color = (Color) fColorCache.get(rgb); - if (color == null) { - color = new Color(getControl().getDisplay(), rgb); - fColorCache.put(rgb, color); - } - return color; - } - - /** - * Sets the context for this viewer. - * - * @param context - */ - public void setContext(IPresentationContext context) { - fContext = context; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.StructuredViewer#doFindItem(java.lang.Object) - */ - protected Widget doFindItem(Object element) { - // this viewer maps model nodes to widgets, so the element is a ModelNode - AsynchronousModel model = getModel(); - if (model != null) { - if (element.equals(model.getRootNode())) { - return doFindInputItem(element); - } - Widget[] widgets = findItems(element); - if (widgets.length > 0) { - return widgets[0]; - } - } - return null; - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.jface.viewers.StructuredViewer#doFindInputItem(java.lang.Object) - */ - protected Widget doFindInputItem(Object element) { - if (element instanceof ModelNode) { - ModelNode node = (ModelNode) element; - if (node.getElement().equals(getInput())) { - return getControl(); - } - } - return null; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.StructuredViewer#doUpdateItem(org.eclipse.swt.widgets.Widget, java.lang.Object, boolean) - */ - protected void doUpdateItem(Widget item, Object element, boolean fullMap) { - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.StructuredViewer#internalRefresh(java.lang.Object) - */ - protected void internalRefresh(Object element) { - // get the nodes in the model - AsynchronousModel model = getModel(); - if (model != null) { - ModelNode[] nodes = model.getNodes(element); - if (nodes != null) { - for (int i = 0; i < nodes.length; i++) { - ModelNode node = nodes[i]; - // get the widget for the node - Widget item = findItem(node); - if (item != null) { - internalRefresh(node); - } - } - } - } - } - - /** - * Refreshes a specific occurrence of an element (a node). - * - * @param node node to update - * - * Subclasses should override and call super - */ - protected void internalRefresh(ModelNode node) { - updateLabel(node); - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.Viewer#setSelection(org.eclipse.jface.viewers.ISelection, boolean) - */ - public synchronized void setSelection(ISelection selection, boolean reveal) { - setSelection(selection, reveal, false); - } - - /** - * Sets the selection in this viewer. - * - * @param selection new selection - * @param reveal whether to reveal the selection - * @param force whether to force the selection change without consulting the model - * selection policy - */ - public synchronized void setSelection(ISelection selection, final boolean reveal, boolean force) { - Control control = getControl(); - if (control == null || control.isDisposed()) { - return; - } - if (!acceptsSelection(selection)) { - selection = getEmptySelection(); - } - if (!force && !overrideSelection(fCurrentSelection, selection)) { - return; - } - - fPendingSelection = selection; - - if (getControl().getDisplay().getThread() == Thread.currentThread()) { - attemptSelection(reveal); - } else { - WorkbenchJob job = new WorkbenchJob("attemptSelection") { //$NON-NLS-1$ - public IStatus runInUIThread(IProgressMonitor monitor) { - attemptSelection(reveal); - return Status.OK_STATUS; - } - - }; - job.setSystem(true); - job.schedule(); - } - } - - - /** - * Returns whether the candidate selection should override the current - * selection. - * - * @param current - * @param curr - * @return - */ - protected boolean overrideSelection(ISelection current, ISelection candidate) { - IModelSelectionPolicy selectionPolicy = getSelectionPolicy(current); - if (selectionPolicy == null) { - return true; - } - if (selectionPolicy.contains(candidate, getPresentationContext())) { - return selectionPolicy.overrides(current, candidate, getPresentationContext()); - } - return !selectionPolicy.isSticky(current, getPresentationContext()); - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.StructuredViewer#getSelection() - */ - public ISelection getSelection() { - Control control = getControl(); - if (control == null || control.isDisposed() || fCurrentSelection == null) { - return StructuredSelection.EMPTY; - } - return fCurrentSelection; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.StructuredViewer#handleSelect(org.eclipse.swt.events.SelectionEvent) - */ - protected void handleSelect(SelectionEvent event) { - // handle case where an earlier selection listener disposed the control. - Control control = getControl(); - if (control != null && !control.isDisposed()) { - updateSelection(newSelectionFromWidget()); - } - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.StructuredViewer#handlePostSelect(org.eclipse.swt.events.SelectionEvent) - */ - protected void handlePostSelect(SelectionEvent e) { - SelectionChangedEvent event = new SelectionChangedEvent(this, newSelectionFromWidget()); - firePostSelectionChanged(event); - } - - /** - * Creates and returns a new selection from this viewer, based on the selected - * elements in the widget. - * - * @return a new selection - */ - protected abstract ISelection newSelectionFromWidget(); - - /** - * Returns the selection policy associated with the given selection - * or <code>null</code> if none. - * - * @param selection or <code>null</code> - * @return selection policy or <code>null</code> - */ - protected IModelSelectionPolicy getSelectionPolicy(ISelection selection) { - if (selection instanceof IStructuredSelection) { - IStructuredSelection ss = (IStructuredSelection) selection; - Object element = ss.getFirstElement(); - if (element instanceof IAdaptable) { - IAdaptable adaptable = (IAdaptable) element; - IModelSelectionPolicyFactory factory = (IModelSelectionPolicyFactory) adaptable.getAdapter(IModelSelectionPolicyFactory.class); - if (factory != null) { - return factory.createModelSelectionPolicyAdapter(adaptable, getPresentationContext()); - } - } - } - return null; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.StructuredViewer#setSelectionToWidget(org.eclipse.jface.viewers.ISelection, boolean) - */ - final protected void setSelectionToWidget(ISelection selection, final boolean reveal) { - // NOT USED - throw new IllegalArgumentException("This method should not be called"); //$NON-NLS-1$ - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.StructuredViewer#setSelectionToWidget(java.util.List, boolean) - */ - final protected void setSelectionToWidget(List l, boolean reveal) { - // NOT USED - throw new IllegalArgumentException("This method should not be called"); //$NON-NLS-1$ - } - - /** - * Attempts to update any pending selection. - * - * @param reveal whether to reveal the selection - */ - protected void attemptSelection(boolean reveal) { - ISelection currentSelection = null; - synchronized (this) { - if (fPendingSelection != null) { - ISelection remaining = doAttemptSelectionToWidget(fPendingSelection, reveal); - if (remaining.isEmpty()) { - remaining = null; - } - if (!fPendingSelection.equals(remaining)) { - fPendingSelection = remaining; - currentSelection = newSelectionFromWidget(); - if (isSuppressEqualSelections() && currentSelection.equals(fCurrentSelection)) { - return; - } - } - } - } - if (currentSelection != null) { - updateSelection(currentSelection); - firePostSelectionChanged(new SelectionChangedEvent(this, currentSelection)); - } - } - - /** - * Controls whether selection change notification is sent even when - * successive selections are equal. - * - * TODO: what we really want is to fire selection change on ACTIVATE model - * change, even when selection is the same. - * - * @return whether to suppress change notification for equal successive - * selections - */ - protected boolean isSuppressEqualSelections() { - return true; - } - - /** - * Attempts to selection the specified selection and returns a selection - * representing the portion of the selection that could not be honored - * and still needs to be selected. - * - * @param selection selection to attempt - * @param reveal whether to reveal the selection - * @return remaining selection - */ - protected abstract ISelection doAttemptSelectionToWidget(ISelection selection, boolean reveal); - - /** - * Returns whether this viewer supports the given selection. - * - * @param selection a selection - * @return whether this viewer supports the given selection - */ - protected abstract boolean acceptsSelection(ISelection selection); - - /** - * Returns an empty selection supported by this viewer. - * - * @return an empty selection supported by this viewer - */ - protected abstract ISelection getEmptySelection(); - - /** - * A content provider that does nothing. - */ - private class NullContentProvider implements IStructuredContentProvider { - public void dispose() { - } - - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - } - - public Object[] getElements(Object inputElement) { - return null; - } - } - - /** - * Notification that a presentation update has failed. - * Subclasses may override as required. The default implementation - * does nothing. - * - * @param monitor monitor for the presentation request that failed - * @param status status of update - */ - protected void handlePresentationFailure(IStatusMonitor monitor, IStatus status) { - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.StructuredViewer#preservingSelection(java.lang.Runnable) - */ - protected synchronized void preservingSelection(Runnable updateCode) { - if (fPendingSelection == null || fPendingSelection.isEmpty()) { - ISelection oldSelection = null; - try { - // preserve selection - oldSelection = fCurrentSelection; - // perform the update - updateCode.run(); - } finally { - // restore selection - if (oldSelection == null) { - oldSelection = new StructuredSelection(); - } - if (getControl().getDisplay().getThread() == Thread.currentThread()) { - if (!oldSelection.equals(newSelectionFromWidget())) { - restoreSelection(oldSelection); - } - } else { - WorkbenchJob job = new WorkbenchJob("attemptSelection") { //$NON-NLS-1$ - public IStatus runInUIThread(IProgressMonitor monitor) { - synchronized (AsynchronousViewer.this) { - if (!getControl().isDisposed()) { - if (fPendingSelection == null || fPendingSelection.isEmpty()) { - ISelection tempSelection = fCurrentSelection; - if (tempSelection == null) { - tempSelection = new StructuredSelection(); - } - if (!tempSelection.equals(newSelectionFromWidget())) { - restoreSelection(tempSelection); - } - } - } - } - return Status.OK_STATUS; - } - - }; - job.setSystem(true); - job.schedule(); - } - } - } else { - updateCode.run(); - } - } - - protected synchronized void restoreSelection(ISelection oldSelection) { - ISelection remaining = doAttemptSelectionToWidget(oldSelection, false); - // send out notification if old and new differ - fCurrentSelection = newSelectionFromWidget(); - if (!selectionExists(fCurrentSelection)) { - if (selectionExists(oldSelection)) { - // old selection exists in the model, but not widget - fCurrentSelection = oldSelection; - } else { - fCurrentSelection = getEmptySelection(); - } - } - if (!fCurrentSelection.equals(oldSelection)) { - handleInvalidSelection(oldSelection, fCurrentSelection); - // if the remaining selection still exists in the model, make it pending - if (selectionExists(remaining)) { - setSelection(remaining); - } - } - } - - /** - * Returns whether the selection exists in the model - */ - protected boolean selectionExists(ISelection selection) { - if (selection.isEmpty()) { - return false; - } - if (selection instanceof IStructuredSelection) { - IStructuredSelection ss = (IStructuredSelection) selection; - Iterator iterator = ss.iterator(); - while (iterator.hasNext()) { - Object element = iterator.next(); - if (getModel().getNodes(element) == null) { - return false; - } - } - } - return true; - } - - /** - * Sets the color attributes of the given widget. - * - * @param widget the widget to update - * @param foreground foreground color of the widget or <code>null</code> if default - * @param background background color of the widget or <code>null</code> if default - */ - protected abstract void setColors(Widget widget, RGB foreground[], RGB background[]); - - /** - * Sets the label attributes of the given widget. - * - * @param widget the widget to update - * @param text label text - * @param image label image or <code>null</code> - */ - protected abstract void setLabels(Widget widget, String[] text, ImageDescriptor[] image); - - /** - * Sets the font attributes of the given widget. - * - * @param widget widget to update - * @param font font of the widget or <code>null</code> if default. - */ - protected abstract void setFonts(Widget widget, FontData[] font); - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.StructuredViewer#updateSelection(org.eclipse.jface.viewers.ISelection) - */ - protected synchronized void updateSelection(ISelection selection) { - fCurrentSelection = selection; - super.updateSelection(selection); - } - - - - /** - * Notification the given model proxy has been added to this viewer's model. - * - * @param proxy - */ - protected void modelProxyAdded(IModelProxy proxy) { - if (fUpdatePolicy instanceof IModelChangedListener) { - proxy.addModelChangedListener((IModelChangedListener)fUpdatePolicy); - } - } - - /** - * Notification the given model proxy has been removed from this viewer's model. - * - * @param proxy - */ - protected void modelProxyRemoved(IModelProxy proxy) { - if (fUpdatePolicy instanceof IModelChangedListener) { - proxy.removeModelChangedListener((IModelChangedListener)fUpdatePolicy); - } - } - - /** - * Returns this viewer's model - * - * @return model - */ - protected AsynchronousModel getModel() { - return fModel; - } - - /** - * A node in the model has been updated - * - * @param node - */ - protected void nodeChanged(ModelNode node) { - Widget widget = findItem(node); - if (widget != null) { - clear(widget); - attemptPendingUpdates(); - } - } - - /** - * @return if there are any more pending updates in the viewer - */ - public synchronized boolean hasPendingUpdates() { - return getModel().hasPendingUpdates(); - } - - /** - * Notification from the model that the update for the given request - * has completed. - * - * @param monitor - */ - protected void updateComplete(IStatusMonitor monitor) { - } - - /** - * Clears the given widget - * - * @param item - */ - protected abstract void clear(Widget item); - - /** - * Clears the children of the widget. - * - * @param item - */ - protected abstract void clearChildren(Widget item); - - /** - * Clears the child at the given index. - * - * @param parent - * @param childIndex - */ - protected abstract void clearChild(Widget parent, int childIndex); - - /** - * Returns the child widget at the given index for the given parent or - * <code>null</code> - * - * @param parent - * @param index - * @return - */ - protected abstract Widget getChildWidget(Widget parent, int index); - - /** - * Sets the item count for a parent widget - * - * @param parent - * @param itemCount - */ - protected abstract void setItemCount(Widget parent, int itemCount); - - /** - * Attempt pending updates. Subclasses may override but should call super. - */ - protected void attemptPendingUpdates() { - attemptSelection(false); - } - - /** - * Notification a node's children have changed. - * Updates the child count for the parent's widget - * and clears children to be updated. - * - * @param parentNode - */ - protected void nodeChildrenChanged(ModelNode parentNode) { - Widget widget = findItem(parentNode); - if (widget != null && !widget.isDisposed()) { - int childCount = parentNode.getChildCount(); - setItemCount(widget, childCount); - clearChildren(widget); - attemptPendingUpdates(); - } - } - - /** - * Notification children have been added to the end - * of the given parent. - * - * @param parentNode - */ - protected void nodeChildrenAdded(ModelNode parentNode) { - Widget widget = findItem(parentNode); - if (widget != null && !widget.isDisposed()) { - int childCount = parentNode.getChildCount(); - setItemCount(widget, childCount); - attemptPendingUpdates(); - } - } - - /** - * Notification children have been added to the end - * of the given parent. - * - * @param parentNode - */ - protected void nodeChildRemoved(ModelNode parentNode, int index) { - Widget widget = findItem(parentNode); - if (widget != null && !widget.isDisposed()) { - Widget childWidget = getChildWidget(widget, index); - int childCount = parentNode.getChildCount(); - // if the child widget exists, dispose it so item state remains, otherwise update child count - if (childWidget == null) { - setItemCount(widget, childCount); - } else { - childWidget.dispose(); - } - for (int i = index; i < childCount; i ++) { - clearChild(widget, i); - } - attemptPendingUpdates(); - } - } - - /** - * Unmaps the node from its widget and all of its children nodes from - * their widgets. - * - * @param node - */ - protected void unmapNode(ModelNode node) { - unmapElement(node); - ModelNode[] childrenNodes = node.getChildrenNodes(); - if (childrenNodes != null) { - for (int i = 0; i < childrenNodes.length; i++) { - unmapNode(childrenNodes[i]); - } - } - } - - /** - * Returns the node corresponding to the given widget or <code>null</code> - * @param widget widget for which a node is requested - * @return node or <code>null</code> - */ - protected ModelNode findNode(Widget widget) { - ModelNode[] nodes = getModel().getNodes(widget.getData()); - if (nodes != null) { - for (int i = 0; i < nodes.length; i++) { - ModelNode node = nodes[i]; - Widget item = findItem(node); - if (widget == item) { - return node; - } - } - } - return null; - } - - /** - * Returns the item for the node or <code>null</code> - * @param node - * @return - */ - protected Widget findItem(ModelNode node) { - return findItem((Object)node); - } - - /* - * (non-Javadoc) - * - * A virtual item has been exposed in the control, map its data. - * - * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event) - */ - public void handleEvent(final Event event) { - update((Item)event.item, event.index); - } - - /** - * Update the given item. - * - * @param item item to update - * @param index index of item in parent's children - */ - protected void update(Item item, int index) { - restoreLabels(item); - int level = 0; - - Widget parentItem = getParentWidget(item); - if (DEBUG_VIEWER) { - DebugUIPlugin.debug("SET DATA [" + index + "]: " + parentItem); //$NON-NLS-1$//$NON-NLS-2$ - } - ModelNode node = null; - // first, see if the parent element is in the model - // and look directly for the child - if (parentItem != null) { - ModelNode[] nodes = getModel().getNodes(parentItem.getData()); - if (nodes != null) { - for (int i = 0; i < nodes.length; i++) { - ModelNode parentNode = nodes[i]; - Widget parentWidget = findItem(parentNode); - if (parentWidget == parentItem) { - ModelNode[] childrenNodes = parentNode.getChildrenNodes(); - if (childrenNodes != null && index < childrenNodes.length) { - node = childrenNodes[index]; - } - } - } - } - } - - // otherwise, build a path to the model node - if (node == null) { - setNodeIndex(index, level); - while (parentItem instanceof Item) { - level++; - Widget parent = getParentWidget(parentItem); - int pindex = indexOf(parent, parentItem); - if (pindex < 0) { - return; - } - setNodeIndex(pindex, level); - parentItem = parent; - } - - node = getModel().getRootNode(); - if (node == null) { - if (DEBUG_VIEWER) { - DebugUIPlugin.debug("\tFAILED - root model node is null"); //$NON-NLS-1$ - } - return; - } - for (int i = level; i >= 0; i--) { - ModelNode[] childrenNodes = node.getChildrenNodes(); - if (childrenNodes == null) { - if (DEBUG_VIEWER) { - DebugUIPlugin.debug("\tFAILED - no children nodes for " + node); //$NON-NLS-1$ - } - return; - } - int pindex = getNodeIndex(i); - if (pindex < childrenNodes.length) { - node = childrenNodes[pindex]; - } else { - if (DEBUG_VIEWER) { - DebugUIPlugin.debug("\tFAILED - no children nodes for " + node); //$NON-NLS-1$ - } - return; - } - } - } - - - // map the node to the element and refresh it - if (node != null) { - mapElement(node, item); - item.setData(node.getElement()); - if (DEBUG_VIEWER) { - DebugUIPlugin.debug("\titem mapped: " + node); //$NON-NLS-1$ - } - internalRefresh(node); - } else { - if (DEBUG_VIEWER) { - DebugUIPlugin.debug("\tFAILED - unable to find corresponding node"); //$NON-NLS-1$ - } - } - } - - /** - * Sets the index of a child node being mapped at the given expansion level - * in the tree. - * - * @param nodeIndex - * @param level - */ - private void setNodeIndex(int nodeIndex, int level) { - if (level > (fSetDataIndicies.length - 1)) { - // grow the array - int[] next = new int[level+5]; - System.arraycopy(fSetDataIndicies, 0, next, 0, fSetDataIndicies.length); - fSetDataIndicies = next; - } - fSetDataIndicies[level] = nodeIndex; - } - - /** - * Returns the index of a child node being mapped at the given expansion level in - * the tree. - * - * @param level - * @return - */ - private int getNodeIndex(int level) { - return fSetDataIndicies[level]; - } - - protected abstract int indexOf(Widget parent, Widget child); - - protected abstract void restoreLabels(Item item); - - /** - * Returns the parent widget for the given widget or <code>null</code> - * - * @param widget - * @return parent widget or <code>null</code> - */ - protected abstract Widget getParentWidget(Widget widget); - - /** - * Updates the children of the given node. - * - * @param parent - * node of which to update children - */ - protected void updateChildren(ModelNode parent) { - getModel().updateChildren(parent); - } -} |