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