From 33547d9aaebfdbd4f4eb0c17710f97cb436d14a6 Mon Sep 17 00:00:00 2001 From: Darin Wright Date: Thu, 17 Apr 2008 16:21:11 +0000 Subject: Bug 226203 - Invoking Find action in Registers views with large group "hangs" IDE --- .../debug/internal/ui/actions/ActionMessages.java | 4 + .../internal/ui/actions/ActionMessages.properties | 4 +- .../ui/model/elements/ElementLabelProvider.java | 24 +- .../ui/viewers/model/InternalTreeModelViewer.java | 754 ++++++++++++++++++++- .../VirtualCopyToClipboardActionDelegate.java | 136 ++-- .../ui/viewers/model/VirtualFindAction.java | 125 ++-- 6 files changed, 879 insertions(+), 168 deletions(-) (limited to 'org.eclipse.debug.ui') diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ActionMessages.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ActionMessages.java index c13649d6d..058b9668c 100644 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ActionMessages.java +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ActionMessages.java @@ -210,4 +210,8 @@ public class ActionMessages extends NLS { public static String DeleteWorkingsetsMessageDialog_1; public static String ShowTypesAction_0; + + public static String VirtualFindAction_0; + + public static String VirtualFindAction_1; } \ No newline at end of file diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ActionMessages.properties b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ActionMessages.properties index 136c648c2..53b28e508 100644 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ActionMessages.properties +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ActionMessages.properties @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2000, 2007 IBM Corporation and others. +# Copyright (c) 2000, 2008 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 @@ -199,3 +199,5 @@ RunLastAction_3=Run the previously launched application # a specific mode - for example "Debug Configurations..." ## OpenLaunchDialogAction_1={0} Configurations... +VirtualFindAction_0=Error +VirtualFindAction_1=Unable to locate {0} in viewer diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ElementLabelProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ElementLabelProvider.java index 74e747aa9..111b9bdc7 100644 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ElementLabelProvider.java +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ElementLabelProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2007 IBM Corporation and others. + * Copyright (c) 2006, 2008 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 @@ -149,16 +149,18 @@ public abstract class ElementLabelProvider implements IElementLabelProvider { ILabelUpdate update = getNextUpdate(); while (update != null) { ISchedulingRule rule = getRule(update); - try { - if (rule != null) { - Job.getJobManager().beginRule(rule, null); - } - retrieveLabel(update); - } catch (CoreException e) { - update.setStatus(e.getStatus()); - } finally { - if (rule != null) { - Job.getJobManager().endRule(rule); + if (!update.isCanceled()) { + try { + if (rule != null) { + Job.getJobManager().beginRule(rule, null); + } + retrieveLabel(update); + } catch (CoreException e) { + update.setStatus(e.getStatus()); + } finally { + if (rule != null) { + Job.getJobManager().endRule(rule); + } } } update.done(); 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 index f57d42587..885f9c3ec 100644 --- 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 @@ -10,17 +10,26 @@ *******************************************************************************/ package org.eclipse.debug.internal.ui.viewers.model; +import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Map.Entry; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.debug.internal.core.commands.Request; +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.IModelSelectionPolicy; import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; +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.PresentationContext; import org.eclipse.jface.resource.ImageDescriptor; @@ -40,9 +49,12 @@ import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; 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; @@ -240,6 +252,712 @@ public class InternalTreeModelViewer extends TreeViewer { private CellModifierProxy fCellModifier; + /** + * A handle to an element in a model. + */ + class VirtualElement { + /** + * Tree item associated with the element, or null for the root element + */ + private TreeItem fItem; + + /** + * Model element (can be null until retrieved) + */ + private Object fElement; + + /** + * Associated label update or null if the element was already + * present in the tree. + */ + private VirtualLabelUpdate fLabel; + + /** + * Children elements or null 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 null if all + * @param indexes children to consider or null + */ + 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 null for all + * @param indexes child indexes to consider or null + */ + 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 null + * @param indexes children of the root to consider or null + * @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 null 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) { + 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 { + if (update == null) { + update = new VirtualChildrenUpdate(parentPath, this, model); + } + update.add(i); + } + } + } + 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 null if none + * + * @return image or null if none + */ + public Image getImage() { + if (fLabel == null) { + return fItem.getImage(); + } else { + return ((TreeModelLabelProvider)getLabelProvider()).getImage(fLabel.fImage); + } + } + + /** + * Returns the labels for the element - one for each column requested. + * + * @return column labels + */ + public String[] getLabel() { + return fLabel.fText; + + } + + /** + * Returns the children of this element or null if none. + * + * @return children or null 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 null 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 null. + * + * @param root limits model to given subtree scope, or null + * @param childIndexes children of the root to consider or null + */ + 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 null 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 null if no columns are to be used + * @return model elements or null 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++) { + VirtualElement proxy = children[i]; + 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); + } + } + } + } + } + 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) { + VirtualElement virtualChild = getVirtualElement().fChildren[offset]; + virtualChild.setElement(child); + ModelContentProvider provider = (ModelContentProvider) 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 @@ -992,31 +1710,21 @@ public class InternalTreeModelViewer extends TreeViewer { } /** - * Forces unmapped virtual items to populate - */ - boolean populateVitrualItems() { - Tree tree = getTree(); - return populateVitrualItems(TreePath.EMPTY, tree.getItems()); - } - - /** - * @param items + * 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 null if all + * @param childIndexes indexes of root element to consider, or null if all + * @return virtual model */ - private boolean populateVitrualItems(TreePath parentPath, TreeItem[] items) { - boolean queued = false; - for (int i = 0; i < items.length; i++) { - TreeItem treeItem = items[i]; - if (treeItem.getData() == null) { - queued = true; - ((ILazyTreePathContentProvider)getContentProvider()).updateElement(parentPath, i); - } - if (treeItem.getExpanded()) { - queued = populateVitrualItems(parentPath.createChildPath(treeItem.getData()), treeItem.getItems()) | queued; - } - } - return queued; + VirtualModel buildVirtualModel(TreePath root, int[] childIndexes) { + return new VirtualModel(root, childIndexes); } - + void addLabelUpdateListener(ILabelUpdateListener listener) { ((TreeModelLabelProvider)getLabelProvider()).addLabelUpdateListener(listener); } diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/VirtualCopyToClipboardActionDelegate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/VirtualCopyToClipboardActionDelegate.java index 6c9f2af7e..286693625 100644 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/VirtualCopyToClipboardActionDelegate.java +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/VirtualCopyToClipboardActionDelegate.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. + * Copyright (c) 2000, 2008 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 @@ -13,7 +13,6 @@ package org.eclipse.debug.internal.ui.viewers.model; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import org.eclipse.core.runtime.IProgressMonitor; @@ -21,7 +20,8 @@ import org.eclipse.debug.internal.core.IInternalDebugCoreConstants; import org.eclipse.debug.internal.ui.DebugUIPlugin; import org.eclipse.debug.internal.ui.actions.AbstractDebugActionDelegate; import org.eclipse.debug.internal.ui.actions.ActionMessages; -import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; +import org.eclipse.debug.internal.ui.viewers.model.InternalTreeModelViewer.VirtualElement; +import org.eclipse.debug.internal.ui.viewers.model.InternalTreeModelViewer.VirtualModel; import org.eclipse.debug.ui.IDebugView; import org.eclipse.jface.action.IAction; import org.eclipse.jface.dialogs.MessageDialog; @@ -29,6 +29,7 @@ import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.viewers.ContentViewer; import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.TreePath; import org.eclipse.swt.SWTError; import org.eclipse.swt.dnd.Clipboard; import org.eclipse.swt.dnd.DND; @@ -43,7 +44,6 @@ public class VirtualCopyToClipboardActionDelegate extends AbstractDebugActionDel private ContentViewer fViewer; private static final String TAB = "\t"; //$NON-NLS-1$ private static final String SEPARATOR = "line.separator"; //$NON-NLS-1$ - private boolean fDone = false; /** * @see AbstractDebugActionDelegate#initialize(IAction, ISelection) @@ -71,19 +71,11 @@ public class VirtualCopyToClipboardActionDelegate extends AbstractDebugActionDel * to the buffer. For elements down to stack frames, children representations * are append to the buffer as well. */ - protected void append(TreeItem item, StringBuffer buffer, int indent) { + protected void append(VirtualElement item, StringBuffer buffer, int indent) { for (int i= 0; i < indent; i++) { buffer.append(TAB); } - String[] labels = null; - if (((InternalTreeModelViewer)fViewer).isShowColumns()) { - labels = new String[((InternalTreeModelViewer)fViewer).getPresentationContext().getColumns().length]; - for (int i = 0; i < labels.length; i++) { - labels[i] = item.getText(i); - } - } else { - labels = new String[]{item.getText()}; - } + String[] labels = item.getLabel(); int count = labels.length; if(count > 0) { for (int i = 0; i < count; i++) { @@ -102,61 +94,70 @@ public class VirtualCopyToClipboardActionDelegate extends AbstractDebugActionDel public void run(final IAction action) { if (fViewer instanceof InternalTreeModelViewer) { InternalTreeModelViewer viewer = (InternalTreeModelViewer) fViewer; - fDone = false; - final Object lock = new Object(); + TreeItem[] items = getPrunedSelection(); + TreePath root = null; + int[] indexes = null; + if (items.length != 0) { + TreeItem anItem = items[0]; + TreeItem rootItem = anItem.getParentItem(); + if (rootItem == null) { + root = TreePath.EMPTY; + } else { + root = viewer.getTreePathFromItem(rootItem); + } + indexes = new int[items.length]; + for (int i = 0; i < items.length; i++) { + TreeItem child = items[i]; + if (rootItem == null) { + indexes[i] = viewer.getTree().indexOf(child); + } else { + indexes[i] = rootItem.indexOf(child); + } + } + } + final VirtualModel model = viewer.buildVirtualModel(root, indexes); ProgressMonitorDialog dialog = new ProgressMonitorDialog(fViewer.getControl().getShell()); final IProgressMonitor monitor = dialog.getProgressMonitor(); dialog.setCancelable(true); - - boolean queued = false; - ILabelUpdateListener listener = new ILabelUpdateListener() { - public void labelUpdatesComplete() { - synchronized (lock) { - fDone = true; - lock.notifyAll(); - } - } - public void labelUpdatesBegin() { - } - public void labelUpdateStarted(ILabelUpdate update) { - } - public void labelUpdateComplete(ILabelUpdate update) { - monitor.worked(1); + + final String[] columns = viewer.getPresentationContext().getColumns(); + final Object[] result = new Object[1]; + IRunnableWithProgress runnable = new IRunnableWithProgress() { + public void run(final IProgressMonitor m) throws InvocationTargetException, InterruptedException { + result[0] = model.populate(m, DebugUIPlugin.removeAccelerators(getAction().getText()), columns); } }; - viewer.addLabelUpdateListener(listener); - queued = viewer.populateVitrualItems(); + try { + dialog.run(true, true, runnable); + } catch (InvocationTargetException e) { + DebugUIPlugin.log(e); + return; + } catch (InterruptedException e) { + return; + } - if (queued) { - IRunnableWithProgress runnable = new IRunnableWithProgress() { - public void run(final IProgressMonitor m) throws InvocationTargetException, InterruptedException { - m.beginTask(DebugUIPlugin.removeAccelerators(getAction().getText()), IProgressMonitor.UNKNOWN); - synchronized (lock) { - if (!fDone) { - lock.wait(); + VirtualElement modelRoot = (VirtualElement) result[0]; + if (!monitor.isCanceled()) { + if (root != null) { + // walk down to nested root + int depth = root.getSegmentCount(); + for (int i = 0; i < depth; i++) { + VirtualElement[] children = modelRoot.getChildren(); + for (int j = 0; j < children.length; j++) { + VirtualElement ve = children[j]; + if (ve != null) { + modelRoot = ve; + break; } } - m.done(); } - }; - try { - dialog.run(true, true, runnable); - } catch (InvocationTargetException e) { - DebugUIPlugin.log(e); - return; - } catch (InterruptedException e) { - return; } - } - - viewer.removeLabelUpdateListener(listener); - if (!monitor.isCanceled()) { - List roots = getPrunedSelection(); - Iterator iterator = roots.iterator(); StringBuffer buffer = new StringBuffer(); - while (iterator.hasNext()) { - TreeItem item = (TreeItem) iterator.next(); - copy(item, buffer, 0); + VirtualElement[] children = modelRoot.getChildren(); + for (int i = 0; i < children.length; i++) { + if (children[i] != null) { + copy(children[i], buffer, 0); + } } TextTransfer plainTextTransfer = TextTransfer.getInstance(); Clipboard clipboard= new Clipboard(fViewer.getControl().getDisplay()); @@ -166,6 +167,7 @@ public class VirtualCopyToClipboardActionDelegate extends AbstractDebugActionDel clipboard.dispose(); } } + } } @@ -173,12 +175,14 @@ public class VirtualCopyToClipboardActionDelegate extends AbstractDebugActionDel * @param item * @param buffer */ - protected void copy(TreeItem item, StringBuffer buffer, int indent) { - append(item, buffer, indent); - if (item.getExpanded()) { - TreeItem[] items = item.getItems(); - for (int i = 0; i < items.length; i++) { - copy(items[i], buffer, indent + 1); + protected void copy(VirtualElement item, StringBuffer buffer, int indent) { + if (!item.isFiltered()) { + append(item, buffer, indent); + VirtualElement[] children = item.getChildren(); + if (children != null) { + for (int i = 0; i < children.length; i++) { + copy(children[i], buffer, indent + 1); + } } } } @@ -202,7 +206,7 @@ public class VirtualCopyToClipboardActionDelegate extends AbstractDebugActionDel * Returns the selected items in the tree, pruning children * if from selected parents. */ - protected List getPrunedSelection() { + protected TreeItem[] getPrunedSelection() { Control control = fViewer.getControl(); List items = new ArrayList(); if (control instanceof Tree) { @@ -218,7 +222,7 @@ public class VirtualCopyToClipboardActionDelegate extends AbstractDebugActionDel } } } - return items; + return (TreeItem[]) items.toArray(new TreeItem[items.size()]); } /** diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/VirtualFindAction.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/VirtualFindAction.java index 4adf19a3d..41207a119 100644 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/VirtualFindAction.java +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/VirtualFindAction.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2006 IBM Corporation and others. + * Copyright (c) 2004, 2008 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 @@ -15,11 +15,13 @@ import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; import org.eclipse.debug.internal.ui.DebugUIPlugin; import org.eclipse.debug.internal.ui.IDebugHelpContextIds; import org.eclipse.debug.internal.ui.actions.ActionMessages; import org.eclipse.debug.internal.ui.viewers.FindElementDialog; -import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; +import org.eclipse.debug.internal.ui.viewers.model.InternalTreeModelViewer.VirtualElement; +import org.eclipse.debug.internal.ui.viewers.model.InternalTreeModelViewer.VirtualModel; import org.eclipse.jface.action.Action; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; @@ -28,12 +30,12 @@ import org.eclipse.jface.viewers.TreePath; import org.eclipse.jface.viewers.TreeSelection; import org.eclipse.jface.window.Window; import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.widgets.Tree; -import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.texteditor.IUpdate; import org.eclipse.ui.texteditor.IWorkbenchActionDefinitionIds; +import com.ibm.icu.text.MessageFormat; + /** * Action which prompts the user to find/navigate to an element in a virtual tree. * @@ -42,7 +44,6 @@ import org.eclipse.ui.texteditor.IWorkbenchActionDefinitionIds; public class VirtualFindAction extends Action implements IUpdate { private InternalTreeModelViewer fViewer; - private boolean fDone = false; class FindLabelProvider extends LabelProvider { @@ -50,11 +51,11 @@ public class VirtualFindAction extends Action implements IUpdate { } public Image getImage(Object element) { - return ((TreeItem)element).getImage(); + return ((VirtualElement)element).getImage(); } public String getText(Object element) { - return ((TreeItem)element).getText(); + return ((VirtualElement)element).getLabel()[0]; } } @@ -68,86 +69,76 @@ public class VirtualFindAction extends Action implements IUpdate { } public void run() { - fDone = false; - final Object lock = new Object(); + final VirtualModel model = fViewer.buildVirtualModel(null, null); ProgressMonitorDialog dialog = new ProgressMonitorDialog(fViewer.getControl().getShell()); final IProgressMonitor monitor = dialog.getProgressMonitor(); dialog.setCancelable(true); - - boolean queued = false; - ILabelUpdateListener listener = new ILabelUpdateListener() { - public void labelUpdatesComplete() { - synchronized (lock) { - fDone = true; - lock.notifyAll(); - } - } - public void labelUpdatesBegin() { - } - public void labelUpdateStarted(ILabelUpdate update) { - } - public void labelUpdateComplete(ILabelUpdate update) { - monitor.worked(1); + + String[] columns = fViewer.getPresentationContext().getColumns(); + String[] temp = null; + if (columns == null || columns.length == 0) { + temp = null; + } else { + temp = new String[]{columns[0]}; + } + final String[] IDs = temp; + final Object[] result = new Object[1]; + IRunnableWithProgress runnable = new IRunnableWithProgress() { + public void run(final IProgressMonitor m) throws InvocationTargetException, InterruptedException { + result[0] = model.populate(m, DebugUIPlugin.removeAccelerators(getText()), IDs); } }; - fViewer.addLabelUpdateListener(listener); - queued = fViewer.populateVitrualItems(); - - if (queued) { - IRunnableWithProgress runnable = new IRunnableWithProgress() { - public void run(final IProgressMonitor m) throws InvocationTargetException, InterruptedException { - m.beginTask(DebugUIPlugin.removeAccelerators(getText()), IProgressMonitor.UNKNOWN); - synchronized (lock) { - if (!fDone) { - lock.wait(); - } - } - m.done(); - } - }; - try { - dialog.run(true, true, runnable); - } catch (InvocationTargetException e) { - DebugUIPlugin.log(e); - return; - } catch (InterruptedException e) { - return; - } + try { + dialog.run(true, true, runnable); + } catch (InvocationTargetException e) { + DebugUIPlugin.log(e); + return; + } catch (InterruptedException e) { + return; } - fViewer.removeLabelUpdateListener(listener); + VirtualElement root = (VirtualElement) result[0]; if (!monitor.isCanceled()) { - Tree tree = (Tree) fViewer.getControl(); - List items = new ArrayList(); - collectItems(items, tree.getItems()); - performFind(items); + List list = new ArrayList(); + collectAllChildren(root, list); + performFind(list.toArray()); } + } - private void collectItems(List list, TreeItem[] items) { - for (int i = 0; i < items.length; i++) { - TreeItem treeItem = items[i]; - list.add(treeItem); - if (treeItem.getExpanded()) { - collectItems(list, treeItem.getItems()); + /** + * Adds all children to the given list recursively. + * + * @param collect + */ + private void collectAllChildren(VirtualElement element, List collect) { + VirtualElement[] children = element.getChildren(); + if (children != null) { + for (int i = 0; i < children.length; i++) { + if (!children[i].isFiltered()) { + collect.add(children[i]); + collectAllChildren(children[i], collect); + } } } } - - protected void performFind(List items) { - FindElementDialog dialog = new FindElementDialog(fViewer.getControl().getShell(), new FindLabelProvider(), items.toArray()); + + protected void performFind(Object[] items) { + FindElementDialog dialog = new FindElementDialog(fViewer.getControl().getShell(), new FindLabelProvider(), items); dialog.setTitle(ActionMessages.FindDialog_3); dialog.setMessage(ActionMessages.FindDialog_1); if (dialog.open() == Window.OK) { Object[] elements = dialog.getResult(); if (elements.length == 1) { - TreeItem item = (TreeItem) elements[0]; - List path = new ArrayList(); - while (item != null) { - path.add(0, item.getData()); - item = item.getParentItem(); + VirtualElement element = (VirtualElement)elements[0]; + TreePath path = element.realize(); + if (path != null) { + fViewer.setSelection(new TreeSelection(path)); + } else { + DebugUIPlugin.errorDialog(fViewer.getControl().getShell(), ActionMessages.VirtualFindAction_0, + MessageFormat.format(ActionMessages.VirtualFindAction_1, new String[]{element.getLabel()[0]}), + (IStatus)null); } - fViewer.setSelection(new TreeSelection(new TreePath(path.toArray()))); } } } -- cgit v1.2.3