Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarin Wright2006-10-05 18:37:10 +0000
committerDarin Wright2006-10-05 18:37:10 +0000
commitcf474ed184c0610b30ea631e5aa46aeec73d7d86 (patch)
treeb01e222ed781543850e7c8eb463e45c2529c9fae
parente555894ac7dcf4809b9acb73ccc78a6aed6b1833 (diff)
downloadeclipse.platform.debug-cf474ed184c0610b30ea631e5aa46aeec73d7d86.tar.gz
eclipse.platform.debug-cf474ed184c0610b30ea631e5aa46aeec73d7d86.tar.xz
eclipse.platform.debug-cf474ed184c0610b30ea631e5aa46aeec73d7d86.zip
(branch) Bug 153500 Asynchronous model viewer
-rw-r--r--org.eclipse.debug.core/core/org/eclipse/debug/internal/core/ExpressionManager.java49
-rw-r--r--org.eclipse.debug.core/core/org/eclipse/debug/internal/core/WatchExpression.java12
-rw-r--r--org.eclipse.debug.ui/META-INF/MANIFEST.MF3
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/CollapseAllAction.java6
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ConfigureColumnsAction.java6
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/RemoveExpressionAction.java2
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IChildrenCountUpdate.java35
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IChildrenUpdate.java52
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IElementCompareRequest.java42
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IElementContentProvider.java36
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IElementLabelProvider.java28
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IElementMementoProvider.java38
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IElementMementoRequest.java35
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/ILabelUpdate.java72
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IPresentationUpdate.java29
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/DebugElementLabelProvider.java109
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/DebugTargetContentProvider.java44
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ElementContentProvider.java207
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ElementLabelProvider.java255
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ElementMementoProvider.java94
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ExpressionContentProvider.java40
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ExpressionLabelProvider.java33
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ExpressionManagerContentProvider.java44
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/LaunchContentProvider.java44
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/LaunchManagerContentProvider.java44
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/StackFrameContentProvider.java55
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ThreadContentProvider.java44
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/VariableContentProvider.java213
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/VariableLabelProvider.java143
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/VariablesViewElementMementoProvider.java65
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/ChildrenCountUpdate.java113
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/ChildrenUpdate.java146
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/ElementCompareRequest.java58
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/ElementMementoRequest.java48
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/FilterTransform.java365
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/IMementoManager.java38
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/IViewerUpdateListener.java48
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/LabelUpdate.java122
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/MementoUpdate.java55
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/ModelContentProvider.java915
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/TreeModelContentProvider.java317
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/TreeModelLabelProvider.java237
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/TreeModelViewer.java998
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/ViewerUpdateMonitor.java124
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/PresentationContext.java2
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/TableUpdatePolicy.java2
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/TreeUpdatePolicy.java6
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/provisional/AbstractModelProxy.java3
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/provisional/IModelDelta.java42
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/provisional/IModelDeltaVisitor.java31
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/provisional/ModelDelta.java94
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DebugEventHandler.java10
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DebugTargetEventHandler.java2
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DebugTargetProxy.java12
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DefaultModelProxyFactory.java3
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DefaultVariableViewModelProxy.java2
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/ExpressionEventHandler.java9
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/ExpressionManagerModelProxy.java25
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/LaunchManagerProxy.java52
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/ProcessProxy.java26
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/ThreadEventHandler.java90
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/expression/ExpressionView.java51
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/launch/DebugElementAdapterFactory.java78
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/launch/LaunchView.java9
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/memory/MemoryViewTreeViewer.java2
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/variables/ToggleShowColumnsAction.java6
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/variables/VariablesView.java299
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/variables/VariablesViewer.java56
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/ui/InspectPopupDialog.java68
69 files changed, 6024 insertions, 419 deletions
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/ExpressionManager.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/ExpressionManager.java
index bb57a7a89..9a54149d9 100644
--- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/ExpressionManager.java
+++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/ExpressionManager.java
@@ -12,7 +12,6 @@ package org.eclipse.debug.internal.core;
import java.io.IOException;
-import com.ibm.icu.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@@ -34,9 +33,7 @@ import org.eclipse.core.runtime.PlatformObject;
import org.eclipse.core.runtime.Preferences;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.core.runtime.Status;
-import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugPlugin;
-import org.eclipse.debug.core.IDebugEventSetListener;
import org.eclipse.debug.core.IExpressionListener;
import org.eclipse.debug.core.IExpressionManager;
import org.eclipse.debug.core.IExpressionsListener;
@@ -48,14 +45,16 @@ import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
+import com.ibm.icu.text.MessageFormat;
+
/**
* The expression manager manages all registered expressions
- * for the debug plugin. It is instantiated by the debug plugin
+ * for the debug plug-in. It is instantiated by the debug plug-in
* at startup.
*
* @see IExpressionManager
*/
-public class ExpressionManager extends PlatformObject implements IExpressionManager, IDebugEventSetListener {
+public class ExpressionManager extends PlatformObject implements IExpressionManager {
/**
* Collection of registered expressions.
@@ -68,7 +67,7 @@ public class ExpressionManager extends PlatformObject implements IExpressionMana
private ListenerList fListeners = null;
/**
- * List of (multi) expressions listeners
+ * List of expressions listeners (plural)
*/
private ListenerList fExpressionsListeners = null;
@@ -166,7 +165,6 @@ public class ExpressionManager extends PlatformObject implements IExpressionMana
return;
}
NodeList list= root.getChildNodes();
- boolean expressionsAdded= false;
for (int i= 0, numItems= list.getLength(); i < numItems; i++) {
Node node= list.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
@@ -183,15 +181,11 @@ public class ExpressionManager extends PlatformObject implements IExpressionMana
fExpressions= new Vector(list.getLength());
}
fExpressions.add(expression);
- expressionsAdded= true;
} else {
DebugPlugin.logMessage("Invalid expression entry encountered while loading watch expressions. Expression text is empty.", null); //$NON-NLS-1$
}
}
}
- if (expressionsAdded) {
- DebugPlugin.getDefault().addDebugEventListener(this);
- }
}
/**
@@ -275,7 +269,6 @@ public class ExpressionManager extends PlatformObject implements IExpressionMana
fExpressions = new Vector(expressions.length);
}
boolean addedWatchExpression= false;
- boolean wasEmpty = fExpressions.isEmpty();
List added = new ArrayList(expressions.length);
for (int i = 0; i < expressions.length; i++) {
IExpression expression = expressions[i];
@@ -287,9 +280,6 @@ public class ExpressionManager extends PlatformObject implements IExpressionMana
}
}
}
- if (wasEmpty) {
- DebugPlugin.getDefault().addDebugEventListener(this);
- }
if (!added.isEmpty()) {
fireUpdate((IExpression[])added.toArray(new IExpression[added.size()]), ADDED);
}
@@ -351,9 +341,6 @@ public class ExpressionManager extends PlatformObject implements IExpressionMana
expression.dispose();
}
}
- if (fExpressions.isEmpty()) {
- DebugPlugin.getDefault().removeDebugEventListener(this);
- }
if (!removed.isEmpty()) {
fireUpdate((IExpression[])removed.toArray(new IExpression[removed.size()]), REMOVED);
storeWatchExpressions();
@@ -381,32 +368,6 @@ public class ExpressionManager extends PlatformObject implements IExpressionMana
}
/**
- * @see IDebugEventSetListener#handleDebugEvent(DebugEvent)
- */
- public void handleDebugEvents(DebugEvent[] events) {
- List changed = null;
- for (int i = 0; i < events.length; i++) {
- DebugEvent event = events[i];
- if (event.getSource() instanceof IExpression) {
- switch (event.getKind()) {
- case DebugEvent.CHANGE:
- if (changed == null) {
- changed = new ArrayList(1);
- }
- changed.add(event.getSource());
- break;
- default:
- break;
- }
- }
- }
- if (changed != null) {
- IExpression[] array = (IExpression[])changed.toArray(new IExpression[changed.size()]);
- fireUpdate(array, CHANGED);
- }
- }
-
- /**
* The given watch expression has changed. Update the persisted
* expressions to store this change as indicated
*
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/WatchExpression.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/WatchExpression.java
index c02fcdefd..d146514c1 100644
--- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/WatchExpression.java
+++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/WatchExpression.java
@@ -127,7 +127,15 @@ public class WatchExpression implements IWatchExpression {
*/
public void setResult(IWatchExpressionResult result) {
fResult= result;
- DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] {new DebugEvent(this, DebugEvent.CHANGE)});
+ fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CONTENT));
+ }
+
+ /**
+ * Fires the given debug event
+ * @param event
+ */
+ protected void fireEvent(DebugEvent event) {
+ DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] {event});
}
/**
@@ -241,7 +249,7 @@ public class WatchExpression implements IWatchExpression {
*/
protected void setPending(boolean pending) {
fPending= pending;
- watchExpressionChanged(false);
+ fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.STATE));
}
/* (non-Javadoc)
diff --git a/org.eclipse.debug.ui/META-INF/MANIFEST.MF b/org.eclipse.debug.ui/META-INF/MANIFEST.MF
index 31d230098..67dc4a421 100644
--- a/org.eclipse.debug.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.debug.ui/META-INF/MANIFEST.MF
@@ -21,6 +21,9 @@ Export-Package: org.eclipse.debug.internal.ui;x-internal:=true,
org.eclipse.debug.internal.ui.launchConfigurations;x-internal:=true,
org.eclipse.debug.internal.ui.memory;x-internal:=true,
org.eclipse.debug.internal.ui.memory.provisional;x-internal:=true,
+ org.eclipse.debug.internal.ui.model;x-internal:=true,
+ org.eclipse.debug.internal.ui.model.elements;x-internal:=true,
+ org.eclipse.debug.internal.ui.model.viewers;x-internal:=true,
org.eclipse.debug.internal.ui.preferences;x-internal:=true,
org.eclipse.debug.internal.ui.sourcelookup;x-internal:=true,
org.eclipse.debug.internal.ui.sourcelookup.browsers;x-internal:=true,
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/CollapseAllAction.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/CollapseAllAction.java
index ec3e10397..76c1110be 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/CollapseAllAction.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/CollapseAllAction.java
@@ -12,17 +12,17 @@ package org.eclipse.debug.internal.ui.actions;
import org.eclipse.debug.internal.ui.DebugPluginImages;
import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
-import org.eclipse.debug.internal.ui.viewers.AsynchronousTreeViewer;
import org.eclipse.jface.action.Action;
+import org.eclipse.jface.viewers.TreeViewer;
/**
* CollapseAllAction
*/
public class CollapseAllAction extends Action {
- private AsynchronousTreeViewer fViewer;
+ private TreeViewer fViewer;
- public CollapseAllAction(AsynchronousTreeViewer viewer) {
+ public CollapseAllAction(TreeViewer viewer) {
super(ActionMessages.CollapseAllAction_0, DebugPluginImages.getImageDescriptor(IInternalDebugUIConstants.IMG_ELCL_COLLAPSE_ALL));
setToolTipText(ActionMessages.CollapseAllAction_0);
setDisabledImageDescriptor(DebugPluginImages.getImageDescriptor(IInternalDebugUIConstants.IMG_DLCL_COLLAPSE_ALL));
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ConfigureColumnsAction.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ConfigureColumnsAction.java
index 059c11a7a..353b7bbba 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ConfigureColumnsAction.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ConfigureColumnsAction.java
@@ -18,7 +18,7 @@ import java.util.Map;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.IDebugHelpContextIds;
-import org.eclipse.debug.internal.ui.viewers.AsynchronousTreeViewer;
+import org.eclipse.debug.internal.ui.model.viewers.TreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.resource.ImageDescriptor;
@@ -38,7 +38,7 @@ import org.eclipse.ui.texteditor.IUpdate;
*/
public class ConfigureColumnsAction extends Action implements IUpdate {
- private AsynchronousTreeViewer fViewer;
+ private TreeModelViewer fViewer;
class ColumnContentProvider implements IStructuredContentProvider {
@@ -98,7 +98,7 @@ public class ConfigureColumnsAction extends Action implements IUpdate {
}
- public ConfigureColumnsAction(AsynchronousTreeViewer viewer) {
+ public ConfigureColumnsAction(TreeModelViewer viewer) {
setText(ActionMessages.ConfigureColumnsAction_0);
setId(DebugUIPlugin.getUniqueIdentifier() + ".ConfigureColumnsAction"); //$NON-NLS-1$
PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IDebugHelpContextIds.CONFIGURE_COLUMNS_ACTION);
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/RemoveExpressionAction.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/RemoveExpressionAction.java
index 603f5a68c..4382ccbae 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/RemoveExpressionAction.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/expressions/RemoveExpressionAction.java
@@ -34,7 +34,7 @@ public class RemoveExpressionAction extends AbstractRemoveActionDelegate {
List expressions = new ArrayList();
for (int i = paths.length-1; i >=0; i--) {
TreePath path = paths[i];
- Object segment = path.getSegment(1);
+ Object segment = path.getFirstSegment();
if (segment instanceof IExpression) {
expressions.add(segment);
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IChildrenCountUpdate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IChildrenCountUpdate.java
new file mode 100644
index 000000000..b17e86425
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IChildrenCountUpdate.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model;
+
+
+/**
+ * Request monitor used to collect the number of children for an element in a viewer.
+ *
+ * @since 3.3
+ */
+public interface IChildrenCountUpdate extends IPresentationUpdate {
+
+ /**
+ * Returns the parent elements that children counts have been requested for.
+ *
+ * @return parent elements
+ */
+ public Object[] getParents();
+
+ /**
+ * Sets the number of children for the given parent.
+ *
+ * @param parent parent element
+ * @param numChildren number of children
+ */
+ public void setChildCount(Object parent, int numChildren);
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IChildrenUpdate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IChildrenUpdate.java
new file mode 100644
index 000000000..0e7528444
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IChildrenUpdate.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model;
+
+/**
+ * Context sensitive children update request for a parent and subrange of its
+ * children.
+ *
+ * @since 3.3
+ */
+public interface IChildrenUpdate extends IPresentationUpdate {
+
+ /**
+ * Returns the parent element that children are being requested for.
+ *
+ * @return parent element
+ */
+ public Object getParent();
+
+ /**
+ * Returns the offset at which children have been requested for. This is
+ * the index of the first child being requested.
+ *
+ * @return offset at which children have been requested for
+ */
+ public int getOffset();
+
+ /**
+ * Returns the number of children requested.
+ *
+ * @return number of children requested
+ */
+ public int getLength();
+
+ /**
+ * Sets the child for this request's parent at the given offset.
+ *
+ * @param child child
+ * @param index child offset
+ *
+ * TODO: what to do with <code>null</code>
+ */
+ public void setChild(Object child, int offset);
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IElementCompareRequest.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IElementCompareRequest.java
new file mode 100644
index 000000000..aafd86812
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IElementCompareRequest.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model;
+
+import org.eclipse.ui.IMemento;
+
+/**
+ * Request to compare an element to a previously created memento.
+ *
+ * @since 3.3
+ */
+public interface IElementCompareRequest extends IPresentationUpdate {
+
+ /**
+ * The element to compare against this request's memento.
+ *
+ * @return element
+ */
+ public Object getElement();
+
+ /**
+ * The memento to compare this request's element.
+ *
+ * @return memento
+ */
+ public IMemento getMemento();
+
+ /**
+ * Sets whether this request's memento represents this requests's element.
+ *
+ * @param equal whether the memento represents the element
+ */
+ public void setEqual(boolean equal);
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IElementContentProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IElementContentProvider.java
new file mode 100644
index 000000000..ba6c68f28
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IElementContentProvider.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model;
+
+
+/**
+ * Provides content for an element in a virtual viewer.
+ *
+ * @since 3.3
+ */
+public interface IElementContentProvider {
+
+ /**
+ * Updates the number of children for the given parent elements in the
+ * specified request.
+ *
+ * @param update specifies counts to update and stores result
+ */
+ public void update(IChildrenCountUpdate update);
+
+ /**
+ * Updates children as requested by the update.
+ *
+ * @param update specifies children to update and stores result
+ */
+ public void update(IChildrenUpdate update);
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IElementLabelProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IElementLabelProvider.java
new file mode 100644
index 000000000..ffa41b992
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IElementLabelProvider.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model;
+
+/**
+ * Provides context sensitive labels. Can be registered as an adapter for an element,
+ * or implemented directly.
+ *
+ * @since 3.3
+ */
+public interface IElementLabelProvider {
+
+ /**
+ * Updates the specified label.
+ *
+ * @param update specifies the element and context for which a label is requested and
+ * stores updated label attributes
+ */
+ public void update(ILabelUpdate update);
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IElementMementoProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IElementMementoProvider.java
new file mode 100644
index 000000000..06b69f00e
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IElementMementoProvider.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model;
+
+/**
+ * Used to save and restore viewer selection/expansion state. A memento
+ * provider adapter should be available from a viewer input element
+ * in order to support viewer state save/restore.
+ *
+ * @since 3.3
+ */
+public interface IElementMementoProvider {
+
+ /**
+ * Creates and stores a memento for the element specified in the request.
+ * The request should be cancelled if a memento is not supported for the
+ * specified element or context.
+ *
+ * @param request specifies element and provides memento store
+ */
+ public void encodeElement(IElementMementoRequest request);
+
+ /**
+ * Determines if a memento represents the element specified in the request.
+ *
+ * @param request specifies element and previously created memento
+ */
+ public void compareElement(IElementCompareRequest request);
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IElementMementoRequest.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IElementMementoRequest.java
new file mode 100644
index 000000000..b0900ca8b
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IElementMementoRequest.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model;
+
+import org.eclipse.ui.IMemento;
+
+/**
+ * Request to store a memento for an element in a specific context.
+ *
+ * @since 3.3
+ */
+public interface IElementMementoRequest extends IPresentationUpdate {
+
+ /**
+ * Returns the element for which the memento has been requested.
+ *
+ * @return element
+ */
+ public Object getElement();
+
+ /**
+ * Returns the memento used to persist the element.
+ *
+ * @return memento
+ */
+ public IMemento getMemento();
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/ILabelUpdate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/ILabelUpdate.java
new file mode 100644
index 000000000..d4aee312d
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/ILabelUpdate.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.RGB;
+
+/**
+ * Context sensitive label update request for an element.
+ *
+ * @since 3.3
+ */
+public interface ILabelUpdate extends IPresentationUpdate {
+
+ /**
+ * Returns the element the label update is for.
+ *
+ * @return associated element
+ */
+ public Object getElement();
+
+ /**
+ * Returns the column the label is for, or <code>null</code> if no columns.
+ *
+ * @return column id or <code>null</code>
+ */
+ public String getColumnId();
+
+ /**
+ * Sets the text of the label. Cannot be <code>null</code>.
+ *
+ * @param text
+ */
+ public void setLabel(String text);
+
+ /**
+ * Sets the font of the label.
+ *
+ * @param fontData
+ */
+ public void setFontData(FontData fontData);
+
+ /**
+ * Sets the image of the label.
+ *
+ * @param image
+ */
+ public void setImageDescriptor(ImageDescriptor image);
+
+ /**
+ * Sets the foreground color of the label.
+ *
+ * @param foreground
+ */
+ public void setForeground(RGB foreground);
+
+ /**
+ * Sets the background color of the label.
+ *
+ * @param background
+ */
+ public void setBackground(RGB background);
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IPresentationUpdate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IPresentationUpdate.java
new file mode 100644
index 000000000..d64454b0a
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/IPresentationUpdate.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model;
+
+import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousRequestMonitor;
+import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
+
+/**
+ * A context sensitive update request.
+ *
+ * @since 3.3
+ */
+public interface IPresentationUpdate extends IAsynchronousRequestMonitor {
+
+ /**
+ * Returns the presentation context this update was requested in.
+ *
+ * @return context this update was requested in
+ */
+ public IPresentationContext getPresentationContext();
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/DebugElementLabelProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/DebugElementLabelProvider.java
new file mode 100644
index 000000000..421413df4
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/DebugElementLabelProvider.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.elements;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.model.IDebugElement;
+import org.eclipse.debug.internal.ui.DelegatingModelPresentation;
+import org.eclipse.debug.internal.ui.LazyModelPresentation;
+import org.eclipse.debug.internal.ui.model.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.views.launch.DebugElementHelper;
+import org.eclipse.debug.ui.IDebugModelPresentation;
+import org.eclipse.debug.ui.IDebugView;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * @since 3.3
+ */
+public class DebugElementLabelProvider extends ElementLabelProvider {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#retrieveLabel(org.eclipse.debug.internal.ui.model.ILabelUpdate)
+ */
+ protected void retrieveLabel(ILabelUpdate update) throws CoreException {
+ DelegatingModelPresentation presentation = DebugElementHelper.getPresentation();
+ // Honor view specific settings in a debug view by copying model presentation settings
+ // into the debug element helper's presentation before we get the label. This allows
+ // for qualified name and type name settings to remain in tact.
+ Object element = update.getElement();
+ IPresentationContext context = update.getPresentationContext();
+ if (element instanceof IDebugElement && context.getPart() instanceof IDebugView) {
+ IWorkbenchPart part = context.getPart();
+ if (part instanceof IDebugView) {
+ IDebugModelPresentation pres = ((IDebugView)part).getPresentation(((IDebugElement)element).getModelIdentifier());
+ Map settings = null;
+ synchronized (presentation) {
+ if (pres instanceof DelegatingModelPresentation) {
+ settings = ((DelegatingModelPresentation)pres).getAttributes();
+ } else if (pres instanceof LazyModelPresentation) {
+ settings = ((LazyModelPresentation)pres).getAttributes();
+ }
+ if (settings != null) {
+ Iterator iterator = settings.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Map.Entry entry = (Entry) iterator.next();
+ presentation.setAttribute((String) entry.getKey(), entry.getValue());
+ }
+ super.retrieveLabel(update);
+ return;
+ }
+ }
+ }
+ }
+ super.retrieveLabel(update);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#getLabel(java.lang.Object, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext, java.lang.String)
+ */
+ protected String getLabel(Object element, IPresentationContext presentationContext, String columnId) throws CoreException {
+ return DebugElementHelper.getLabel(element);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#getBackground(java.lang.Object, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext, java.lang.String)
+ */
+ protected RGB getBackground(Object element, IPresentationContext presentationContext, String columnId) throws CoreException {
+ return DebugElementHelper.getBackground(element);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#getFontDatas(java.lang.Object, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext, java.lang.String)
+ */
+ protected FontData getFontData(Object element, IPresentationContext presentationContext, String columnId) throws CoreException {
+ return DebugElementHelper.getFont(element);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#getForeground(java.lang.Object, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext, java.lang.String)
+ */
+ protected RGB getForeground(Object element, IPresentationContext presentationContext, String columnId) throws CoreException {
+ return DebugElementHelper.getForeground(element);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#getImageDescriptor(java.lang.Object, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext, java.lang.String)
+ */
+ protected ImageDescriptor getImageDescriptor(Object element, IPresentationContext presentationContext, String columnId) throws CoreException {
+ return DebugElementHelper.getImageDescriptor(element);
+ }
+
+
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/DebugTargetContentProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/DebugTargetContentProvider.java
new file mode 100644
index 000000000..9e3a0a8fc
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/DebugTargetContentProvider.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.elements;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.model.IDebugTarget;
+import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
+import org.eclipse.debug.ui.IDebugUIConstants;
+
+/**
+ * @since 3.3
+ */
+public class DebugTargetContentProvider extends ElementContentProvider {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#getChildCount(java.lang.Object, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext)
+ */
+ protected int getChildCount(Object element, IPresentationContext context) throws CoreException {
+ return ((IDebugTarget)element).getThreads().length;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#supportsContextId(java.lang.String)
+ */
+ protected boolean supportsContextId(String id) {
+ return IDebugUIConstants.ID_DEBUG_VIEW.equals(id);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#getChildren(java.lang.Object, int, int, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext)
+ */
+ protected Object[] getChildren(Object parent, int index, int length, IPresentationContext context) throws CoreException {
+ return getElements(((IDebugTarget)parent).getThreads(), index, length);
+ }
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ElementContentProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ElementContentProvider.java
new file mode 100644
index 000000000..4e02a4105
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ElementContentProvider.java
@@ -0,0 +1,207 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.elements;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.internal.ui.model.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.model.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.model.IElementContentProvider;
+import org.eclipse.debug.internal.ui.viewers.AsynchronousSchedulingRuleFactory;
+import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
+
+/**
+ * @since 3.3
+ */
+public abstract class ElementContentProvider implements IElementContentProvider {
+
+ protected static final Object[] EMPTY = new Object[0];
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.IElementContentProvider#updateChildren(java.lang.Object, int, int, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext, org.eclipse.debug.internal.ui.model.IElementRequestMonitor)
+ */
+ public void update(final IChildrenUpdate update) {
+ Job job = new Job("Retrieving Children") { //$NON-NLS-1$
+ protected IStatus run(IProgressMonitor monitor) {
+ if (!monitor.isCanceled()) {
+ retrieveChildren(update);
+ }
+ return Status.OK_STATUS;
+ }
+ };
+ job.setSystem(true);
+ job.setRule(getRetrieveChildRule(update.getParent(), update.getPresentationContext())); // TODO:
+ job.schedule();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.IElementContentProvider#update(org.eclipse.debug.internal.ui.model.IChildrenCountUpdate)
+ */
+ public void update(final IChildrenCountUpdate update) {
+ Job job = new Job("Computing hasChildren") { //$NON-NLS-1$
+ protected IStatus run(IProgressMonitor monitor) {
+ if (!monitor.isCanceled()) {
+ retrieveChildCount(update);
+ }
+ return Status.OK_STATUS;
+ }
+ };
+ job.setSystem(true);
+ // TODO: rule
+ job.schedule();
+ }
+
+ /**
+ * Returns the scheduling rule for jobs retrieving children.
+ *
+ * @param parent
+ * @param context
+ * @return scheduling rule or <code>null</code>
+ */
+ protected ISchedulingRule getRetrieveChildRule(Object parent, IPresentationContext context) {
+ return AsynchronousSchedulingRuleFactory.getDefault().newSerialPerPartRule(context);
+ }
+
+ /**
+ * Returns the scheduling rule for jobs determining an element's child count.
+ *
+ * @param parent
+ * @param context
+ * @return scheduling rule or <code>null</code>
+ */
+ protected ISchedulingRule getRetrieveChildCountRule(Object parent, IPresentationContext context) {
+ return AsynchronousSchedulingRuleFactory.getDefault().newSerialPerPartRule(context);
+ }
+
+ /**
+ * Computes the children for the given parent in the specified context.
+ *
+ * @param update update request
+ */
+ protected void retrieveChildren(IChildrenUpdate update) {
+ if (!update.isCanceled()) {
+ IStatus status = Status.OK_STATUS;
+ try {
+ IPresentationContext context = update.getPresentationContext();
+ if (supportsContext(context)) {
+ int offset = update.getOffset();
+ Object[] children = getChildren(update.getParent(), offset, update.getLength(), context);
+ if (children != null) {
+ for (int i = 0; i < children.length; i++) {
+ update.setChild(children[i], offset + i);
+ }
+ }
+ }
+ } catch (CoreException e) {
+ status = e.getStatus();
+ }
+ update.setStatus(status);
+ update.done();
+ }
+ }
+
+ /**
+ * Computes whether the given element is a container.
+ *
+ * @param parent potential parent
+ * @param context presentation context
+ * @param monitor result to report to
+ */
+ protected void retrieveChildCount(IChildrenCountUpdate update) {
+ if (!update.isCanceled()) {
+ IStatus status = Status.OK_STATUS;
+ try {
+ IPresentationContext context = update.getPresentationContext();
+ Object[] parents = update.getParents();
+ if (supportsContext(context)) {
+ for (int i = 0; i < parents.length; i++) {
+ Object parent = parents[i];
+ update.setChildCount(parent, getChildCount(parent, context));
+ }
+ } else {
+ for (int i = 0; i < parents.length; i++) {
+ Object parent = parents[i];
+ update.setChildCount(parent, 0);
+ }
+ }
+ } catch (CoreException e) {
+ status = e.getStatus();
+ }
+ update.setStatus(status);
+ update.done();
+ }
+ }
+
+ /**
+ * Returns the children for the given parent at the specified index in the specified context
+ * or <code>null</code> if none.
+ *
+ * @param parent element to retrieve children for
+ * @param index child index
+ * @param length number of children to retrieve
+ * @param context context children will be presented in
+ * @return child or <code>null</code>
+ * @throws CoreException if an exception occurs retrieving child
+ */
+ protected abstract Object[] getChildren(Object parent, int index, int length, IPresentationContext context) throws CoreException;
+
+ /**
+ * Returns the number of children for the given element.
+ *
+ * @param element element that may have children
+ * @param context context element will be presented in
+ * @return number of children
+ * @throws CoreException if an exception occurs determining child count
+ */
+ protected abstract int getChildCount(Object element, IPresentationContext context) throws CoreException;
+
+ /**
+ * Returns whether this adapter supports the given context.
+ *
+ * @param context
+ * @return whether this adapter supports the given context
+ */
+ protected boolean supportsContext(IPresentationContext context) {
+ return supportsContextId(context.getId());
+ }
+
+ /**
+ * Returns whether this adapter provides content in the specified context id.
+ *
+ * @param id part id
+ * @return whether this adapter provides content in the specified context id
+ */
+ protected abstract boolean supportsContextId(String id);
+
+ /**
+ * Returns the element at the given index or <code>null</code> if none.
+ *
+ * @param elements
+ * @param index
+ * @return element or <code>null</code>
+ */
+ protected Object[] getElements(Object[] elements, int index, int length) {
+ int max = elements.length;
+ if (index < max && ((index + length) > max)) {
+ length = max - index;
+ }
+ if ((index + length) <= elements.length) {
+ Object[] sub = new Object[length];
+ System.arraycopy(elements, index, sub, 0, length);
+ return sub;
+ }
+ return null;
+ }
+}
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
new file mode 100644
index 000000000..63118d413
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ElementLabelProvider.java
@@ -0,0 +1,255 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.elements;
+
+import java.util.LinkedList;
+import java.util.NoSuchElementException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.internal.ui.model.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.model.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.ui.progress.UIJob;
+
+/**
+ * @since 3.3
+ */
+public abstract class ElementLabelProvider implements IElementLabelProvider {
+
+ private Job fLabelJob = null;
+
+ interface ILabelJob {
+ /**
+ * Returns whether the update was queued.
+ *
+ * @param update update
+ * @return whether the update was queued
+ */
+ public boolean queue(ILabelUpdate update);
+ }
+
+ class LabelJob extends Job implements ILabelJob {
+
+ private LabelUpdater fUpdater = new LabelUpdater();
+
+ public LabelJob() {
+ super("Label Job"); //$NON-NLS-1$
+ setSystem(true);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ protected IStatus run(IProgressMonitor monitor) {
+ fUpdater.run();
+ return Status.OK_STATUS;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider.ILabelJob#queue(org.eclipse.debug.internal.ui.model.ILabelUpdate)
+ */
+ public boolean queue(ILabelUpdate update) {
+ return fUpdater.queue(update);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.jobs.Job#shouldRun()
+ */
+ public boolean shouldRun() {
+ return fUpdater.shouldRun();
+ }
+
+ }
+
+ class UILabelJob extends UIJob implements ILabelJob {
+
+ private LabelUpdater fUpdater = new LabelUpdater();
+
+ public UILabelJob() {
+ super("Label Job"); //$NON-NLS-1$
+ setSystem(true);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ fUpdater.run();
+ return Status.OK_STATUS;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider.ILabelJob#queue(org.eclipse.debug.internal.ui.model.ILabelUpdate)
+ */
+ public boolean queue(ILabelUpdate update) {
+ return fUpdater.queue(update);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.jobs.Job#shouldRun()
+ */
+ public boolean shouldRun() {
+ return fUpdater.shouldRun();
+ }
+ }
+
+ /**
+ * Queue of label updates
+ */
+ class LabelUpdater implements Runnable {
+
+ LinkedList fQueue = new LinkedList();
+
+ public synchronized boolean queue(ILabelUpdate update) {
+ if (fQueue == null) {
+ return false;
+ } else {
+ fQueue.addLast(update);
+ return true;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Runnable#run()
+ */
+ public void run() {
+ ILabelUpdate update = getNextUpdate();
+ while (update != null) {
+ try {
+ retrieveLabel(update);
+ } catch (CoreException e) {
+ update.setStatus(e.getStatus());
+ }
+ update.done();
+ update = getNextUpdate();
+ }
+ }
+
+ public synchronized ILabelUpdate getNextUpdate() {
+ if (fQueue == null) {
+ return null;
+ }
+ ILabelUpdate update = null;
+ try {
+ update = (ILabelUpdate) fQueue.removeFirst();
+ } catch (NoSuchElementException e) {
+ fQueue = null;
+ }
+ return update;
+ }
+
+ public boolean shouldRun() {
+ return fQueue != null;
+ }
+ }
+
+ /**
+ * Retrieves label attributes for the specified update.
+ *
+ * @param update
+ */
+ protected void retrieveLabel(ILabelUpdate update) throws CoreException {
+ String columnId = update.getColumnId();
+ IPresentationContext presentationContext = update.getPresentationContext();
+ Object element = update.getElement();
+ update.setLabel(getLabel(element, presentationContext, columnId));
+ update.setImageDescriptor(getImageDescriptor(element, presentationContext, columnId));
+ update.setBackground(getBackground(element, presentationContext, columnId));
+ update.setForeground(getForeground(element, presentationContext, columnId));
+ update.setFontData(getFontData(element, presentationContext, columnId));
+ }
+
+ /**
+ * @param element
+ * @param presentationContext
+ * @param columnId
+ * @return font information or <code>null</code>
+ */
+ protected FontData getFontData(Object element, IPresentationContext presentationContext, String columnId) throws CoreException {
+ return null;
+ }
+
+ /**
+ * @param element
+ * @param presentationContext
+ * @param columnId
+ * @return color or <code>null</code>
+ */
+ protected RGB getForeground(Object element, IPresentationContext presentationContext, String columnId) throws CoreException {
+ return null;
+ }
+
+ /**
+ * @param element
+ * @param presentationContext
+ * @param columnId
+ * @return color or <code>null</code>
+ */
+ protected RGB getBackground(Object element, IPresentationContext presentationContext, String columnId) throws CoreException {
+ return null;
+ }
+
+ /**
+ * @param element
+ * @param presentationContext
+ * @param columnId
+ * @return image descriptor or <code>null</code>
+ */
+ protected ImageDescriptor getImageDescriptor(Object element, IPresentationContext presentationContext, String columnId) throws CoreException {
+ return null;
+ }
+
+ /**
+ * @param element
+ * @param presentationContext
+ * @param columnId
+ * @return label
+ */
+ protected abstract String getLabel(Object element, IPresentationContext presentationContext, String columnId) throws CoreException;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.IElementLabelProvider#updateLabel(org.eclipse.debug.internal.ui.model.ILabelUpdate)
+ */
+ public synchronized void update(ILabelUpdate update) {
+ if (fLabelJob == null) {
+ fLabelJob = newLabelJob(update);
+ }
+ if (!((ILabelJob)fLabelJob).queue(update)) {
+ fLabelJob = newLabelJob(update);
+ ((ILabelJob)fLabelJob).queue(update);
+ }
+ // TODO: rule
+ fLabelJob.schedule();
+ }
+
+ private Job newLabelJob(ILabelUpdate update) {
+ if (requiresUIJob(update)) {
+ return new UILabelJob();
+ } else {
+ return new LabelJob();
+ }
+ }
+
+ /**
+ * Returns whether a UI job should be used for updates versus a non-UI job.
+ */
+ protected boolean requiresUIJob(ILabelUpdate update) {
+ return false;
+ }
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ElementMementoProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ElementMementoProvider.java
new file mode 100644
index 000000000..32d6447b4
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ElementMementoProvider.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.elements;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.internal.ui.model.IElementCompareRequest;
+import org.eclipse.debug.internal.ui.model.IElementMementoProvider;
+import org.eclipse.debug.internal.ui.model.IElementMementoRequest;
+import org.eclipse.ui.IMemento;
+
+/**
+ * @since 3.3
+ */
+public abstract class ElementMementoProvider implements IElementMementoProvider {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.IElementMementoProvider#compareElement(org.eclipse.debug.internal.ui.model.IElementCompareRequest)
+ */
+ public void compareElement(final IElementCompareRequest request) {
+ Job job = new Job("compare element") { //$NON-NLS-1$
+ protected IStatus run(IProgressMonitor monitor) {
+ Object element = request.getElement();
+ IMemento memento = request.getMemento();
+ try {
+ request.setEqual(isEqual(element, memento));
+ } catch (CoreException e) {
+ request.setStatus(e.getStatus());
+ }
+ request.done();
+ return Status.OK_STATUS;
+ }
+ };
+ job.setSystem(true);
+ // TODO: rule
+ job.schedule();
+ }
+
+ /**
+ * Returns whether the memento represents the given element.
+ *
+ * @param element
+ * @param memento
+ * @return whether the memento represents the given element
+ */
+ protected abstract boolean isEqual(Object element, IMemento memento) throws CoreException;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.IElementMementoProvider#encodeElement(org.eclipse.debug.internal.ui.model.IElementMementoRequest)
+ */
+ public void encodeElement(final IElementMementoRequest request) {
+ Job job = new Job("encode element") { //$NON-NLS-1$
+ protected IStatus run(IProgressMonitor monitor) {
+ Object element = request.getElement();
+ IMemento memento = request.getMemento();
+ try {
+ if (!encodeElement(element, memento)) {
+ request.setCanceled(true);
+ }
+ } catch (CoreException e) {
+ request.setStatus(e.getStatus());
+ }
+ request.done();
+ return Status.OK_STATUS;
+ }
+ };
+ job.setSystem(true);
+ // TODO: rule
+ job.schedule();
+ }
+
+ /**
+ * Encodes the specified element into the given memento.
+ * Returns whether the element could be encoded
+ *
+ * @param element
+ * @param memento
+ * @return false if cancelled/not supported
+ * @throws CoreException
+ */
+ protected abstract boolean encodeElement(Object element, IMemento memento) throws CoreException;
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ExpressionContentProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ExpressionContentProvider.java
new file mode 100644
index 000000000..e83e1ad3f
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ExpressionContentProvider.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.elements;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.model.IErrorReportingExpression;
+import org.eclipse.debug.core.model.IExpression;
+import org.eclipse.debug.core.model.IValue;
+import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
+
+/**
+ * @since 3.3
+ */
+public class ExpressionContentProvider extends VariableContentProvider {
+
+ protected Object[] getAllChildren(Object parent, IPresentationContext context) throws CoreException {
+ if (parent instanceof IErrorReportingExpression) {
+ IErrorReportingExpression expression = (IErrorReportingExpression) parent;
+ if (expression.hasErrors()) {
+ return expression.getErrorMessages();
+ }
+ }
+ if (parent instanceof IExpression) {
+ IExpression expression = (IExpression) parent;
+ IValue value = expression.getValue();
+ if (value != null) {
+ return getValueChildren(expression, value, context);
+ }
+ }
+ return EMPTY;
+ }
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ExpressionLabelProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ExpressionLabelProvider.java
new file mode 100644
index 000000000..b09c72a82
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ExpressionLabelProvider.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.elements;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.model.IErrorReportingExpression;
+import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
+import org.eclipse.swt.graphics.RGB;
+
+/**
+ * @since 3.3
+ */
+public class ExpressionLabelProvider extends VariableLabelProvider {
+
+ protected RGB getForeground(Object element, IPresentationContext presentationContext, String columnId) throws CoreException {
+ if (element instanceof IErrorReportingExpression) {
+ IErrorReportingExpression expression = (IErrorReportingExpression) element;
+ if (expression.hasErrors()) {
+ return new RGB(255, 0, 0);
+ }
+ }
+ return super.getForeground(element, presentationContext, columnId);
+ }
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ExpressionManagerContentProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ExpressionManagerContentProvider.java
new file mode 100644
index 000000000..3979c7a23
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ExpressionManagerContentProvider.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.elements;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.IExpressionManager;
+import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
+import org.eclipse.debug.ui.IDebugUIConstants;
+
+/**
+ *
+ */
+public class ExpressionManagerContentProvider extends ElementContentProvider {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#getChildCount(java.lang.Object, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext)
+ */
+ protected int getChildCount(Object element, IPresentationContext context) throws CoreException {
+ return ((IExpressionManager) element).getExpressions().length;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#getChildren(java.lang.Object, int, int, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext)
+ */
+ protected Object[] getChildren(Object parent, int index, int length, IPresentationContext context) throws CoreException {
+ return ((IExpressionManager) parent).getExpressions();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#supportsContextId(java.lang.String)
+ */
+ protected boolean supportsContextId(String id) {
+ return id.equals(IDebugUIConstants.ID_EXPRESSION_VIEW);
+ }
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/LaunchContentProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/LaunchContentProvider.java
new file mode 100644
index 000000000..22b5a9c52
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/LaunchContentProvider.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.elements;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
+import org.eclipse.debug.ui.IDebugUIConstants;
+
+/**
+ * @since 3.3
+ */
+public class LaunchContentProvider extends ElementContentProvider {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#getChildCount(java.lang.Object, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext)
+ */
+ protected int getChildCount(Object element, IPresentationContext context) throws CoreException {
+ return ((ILaunch)element).getChildren().length;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#supportsContextId(java.lang.String)
+ */
+ protected boolean supportsContextId(String id) {
+ return IDebugUIConstants.ID_DEBUG_VIEW.equals(id);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#getChildren(java.lang.Object, int, int, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext)
+ */
+ protected Object[] getChildren(Object parent, int index, int length, IPresentationContext context) throws CoreException {
+ return getElements(((ILaunch)parent).getChildren(), index, length);
+ }
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/LaunchManagerContentProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/LaunchManagerContentProvider.java
new file mode 100644
index 000000000..cc8f1cabf
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/LaunchManagerContentProvider.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.elements;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
+import org.eclipse.debug.ui.IDebugUIConstants;
+
+/**
+ * @since 3.3
+ */
+public class LaunchManagerContentProvider extends ElementContentProvider {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#getChildCount(java.lang.Object, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext)
+ */
+ protected int getChildCount(Object element, IPresentationContext context) throws CoreException {
+ return ((ILaunchManager)element).getLaunches().length;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#supportsContextId(java.lang.String)
+ */
+ protected boolean supportsContextId(String id) {
+ return IDebugUIConstants.ID_DEBUG_VIEW.equals(id);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#getChildren(java.lang.Object, int, int, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext)
+ */
+ protected Object[] getChildren(Object parent, int index, int length, IPresentationContext context) throws CoreException {
+ return getElements(((ILaunchManager)parent).getLaunches(),index, length);
+ }
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/StackFrameContentProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/StackFrameContentProvider.java
new file mode 100644
index 000000000..8ef0348e4
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/StackFrameContentProvider.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.elements;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.model.IStackFrame;
+import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
+import org.eclipse.debug.ui.IDebugUIConstants;
+
+/**
+ * @since 3.3
+ */
+public class StackFrameContentProvider extends ElementContentProvider {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#getChildCount(java.lang.Object, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext)
+ */
+ protected int getChildCount(Object element, IPresentationContext context) throws CoreException {
+ return getAllChildren(element, context).length;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#getChildren(java.lang.Object, int, int, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext)
+ */
+ protected Object[] getChildren(Object parent, int index, int length, IPresentationContext context) throws CoreException {
+ return getElements(getAllChildren(parent, context), index, length);
+ }
+
+ protected Object[] getAllChildren(Object parent, IPresentationContext context) throws CoreException {
+ String id = context.getId();
+ IStackFrame frame = (IStackFrame) parent;
+ if (id.equals(IDebugUIConstants.ID_VARIABLE_VIEW)) {
+ return frame.getVariables();
+ } else if (id.equals(IDebugUIConstants.ID_REGISTER_VIEW)) {
+ return frame.getRegisterGroups();
+ }
+ return EMPTY;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#supportsContextId(java.lang.String)
+ */
+ protected boolean supportsContextId(String id) {
+ return id.equals(IDebugUIConstants.ID_VARIABLE_VIEW) || id.equals(IDebugUIConstants.ID_REGISTER_VIEW);
+ }
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ThreadContentProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ThreadContentProvider.java
new file mode 100644
index 000000000..16d67a25d
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ThreadContentProvider.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.elements;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.model.IThread;
+import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
+import org.eclipse.debug.ui.IDebugUIConstants;
+
+/**
+ * @since 3.3
+ */
+public class ThreadContentProvider extends ElementContentProvider {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#getChildCount(java.lang.Object, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext)
+ */
+ protected int getChildCount(Object element, IPresentationContext context) throws CoreException {
+ return ((IThread)element).getStackFrames().length;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#supportsContextId(java.lang.String)
+ */
+ protected boolean supportsContextId(String id) {
+ return IDebugUIConstants.ID_DEBUG_VIEW.equals(id);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#getChildren(java.lang.Object, int, int, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext)
+ */
+ protected Object[] getChildren(Object parent, int index, int length, IPresentationContext context) throws CoreException {
+ return getElements(((IThread)parent).getStackFrames(), index, length);
+ }
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/VariableContentProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/VariableContentProvider.java
new file mode 100644
index 000000000..94e7a57e5
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/VariableContentProvider.java
@@ -0,0 +1,213 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.elements;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILogicalStructureType;
+import org.eclipse.debug.core.model.IDebugElement;
+import org.eclipse.debug.core.model.IIndexedValue;
+import org.eclipse.debug.core.model.IValue;
+import org.eclipse.debug.core.model.IVariable;
+import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.views.variables.IndexedVariablePartition;
+import org.eclipse.debug.internal.ui.views.variables.VariablesView;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * @since 3.3
+ */
+public class VariableContentProvider extends ElementContentProvider {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#getChildCount(java.lang.Object, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext)
+ */
+ protected int getChildCount(Object element, IPresentationContext context) throws CoreException {
+ return getAllChildren(element, context).length;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#getChildren(java.lang.Object, int, int, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext)
+ */
+ protected Object[] getChildren(Object parent, int index, int length, IPresentationContext context) throws CoreException {
+ return getElements(getAllChildren(parent, context), index, length);
+ }
+
+ protected Object[] getAllChildren(Object parent, IPresentationContext context) throws CoreException {
+ IVariable variable = (IVariable) parent;
+ IValue value = variable.getValue();
+ if (value != null) {
+ return getValueChildren(variable, value, context);
+ }
+ return EMPTY;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#supportsContextId(java.lang.String)
+ */
+ protected boolean supportsContextId(String id) {
+ return id.equals(IDebugUIConstants.ID_EXPRESSION_VIEW) || id.equals(IDebugUIConstants.ID_VARIABLE_VIEW) || id.equals(IDebugUIConstants.ID_REGISTER_VIEW);
+ }
+
+ /**
+ * Return whether to show compute a logical structure or a raw structure
+ * in the specified context
+ *
+ * @return whether to show compute a logical structure or a raw structure
+ * in the specified context
+ */
+ protected boolean isShowLogicalStructure(IPresentationContext context) {
+ IWorkbenchPart part = context.getPart();
+ if (part instanceof VariablesView) {
+ return ((VariablesView) part).isShowLogicalStructure();
+ }
+ return false;
+ }
+
+ /**
+ * Returns the number of entries that should be displayed in each partition
+ * of an indexed collection.
+ *
+ * @return the number of entries that should be displayed in each partition
+ * of an indexed collection
+ */
+ protected int getArrayPartitionSize() {
+ // TODO: should fix this with a user preference
+ return 100;
+ }
+
+ /**
+ * Returns any logical value for the raw value in the specified context
+ *
+ * @param value
+ * @param context
+ * @return
+ */
+ protected IValue getLogicalValue(IValue value, IPresentationContext context) {
+ return getLogicalValue(value, new ArrayList(), context);
+ }
+
+ /**
+ * Returns children for the given value, creating array partitions if
+ * required
+ *
+ * @param parent expression or variable containing the given value
+ * @param value the value to retrieve children for
+ * @param context the context in which children have been requested
+ * @return children for the given value, creating array partitions if
+ * required
+ * @throws CoreException
+ */
+ protected Object[] getValueChildren(IDebugElement parent, IValue value, IPresentationContext context) throws CoreException {
+ if (value == null) {
+ return EMPTY;
+ }
+ IValue logicalValue = getLogicalValue(value, context);
+ if (logicalValue instanceof IIndexedValue) {
+ IIndexedValue indexedValue = (IIndexedValue) logicalValue;
+ int partitionSize = computeParitionSize(indexedValue);
+ if (partitionSize > 1) {
+ int offset = indexedValue.getInitialOffset();
+ int length = indexedValue.getSize();
+ int numPartitions = length / partitionSize;
+ int remainder = length % partitionSize;
+ if (remainder > 0) {
+ numPartitions++;
+ }
+ IVariable[] partitions = new IVariable[numPartitions];
+ for (int i = 0; i < (numPartitions - 1); i++) {
+ partitions[i] = new IndexedVariablePartition(parent, indexedValue, offset, partitionSize);
+ offset = offset + partitionSize;
+ }
+ if (remainder == 0) {
+ remainder = partitionSize;
+ }
+ partitions[numPartitions - 1] = new IndexedVariablePartition(parent, indexedValue, offset, remainder);
+ return partitions;
+ }
+ }
+ if (logicalValue == null) {
+ // safeguard against an structure type returning null
+ logicalValue = value;
+ }
+ return logicalValue.getVariables();
+ }
+
+ /**
+ * Returns the partition size to use for the given indexed value. The
+ * partition size is computed by determining the number of levels that an
+ * indexed collection must be nested in order to partition the collection
+ * sub-collections of the preferred partition size.
+ *
+ * @param value
+ * indexed value
+ * @return size of paritions the value should be subdivided into
+ */
+ protected int computeParitionSize(IIndexedValue value) {
+ int partitionSize = 1;
+ try {
+ int length = value.getSize();
+ int partitionDepth = 0;
+ int preferredSize = getArrayPartitionSize();
+ int remainder = length % preferredSize;
+ length = length / preferredSize;
+ while (length > 0) {
+ if (remainder == 0 && length == 1) {
+ break;
+ }
+ partitionDepth++;
+ remainder = length % preferredSize;
+ length = length / preferredSize;
+ }
+ for (int i = 0; i < partitionDepth; i++) {
+ partitionSize = partitionSize * preferredSize;
+ }
+ } catch (DebugException e) {
+ }
+ return partitionSize;
+ }
+
+ /**
+ * Returns any logical value for the raw value. This method will recurse
+ * over the returned value until the same structure is encountered again (to
+ * avoid infinite recursion).
+ *
+ * @param value
+ * @param previousStructureIds
+ * the list of logical structures that have already been applied
+ * to the returned value during the recursion of this method.
+ * Callers should always pass in a new, empty list.
+ * @return
+ */
+ protected IValue getLogicalValue(IValue value, List previousStructureIds, IPresentationContext context) {
+ if (isShowLogicalStructure(context)) {
+ ILogicalStructureType[] types = DebugPlugin.getLogicalStructureTypes(value);
+ if (types.length > 0) {
+ ILogicalStructureType type = DebugPlugin.getDefaultStructureType(types);
+ if (type != null && !previousStructureIds.contains(type.getId())) {
+ try {
+ value = type.getLogicalStructure(value);
+ previousStructureIds.add(type.getId());
+ return getLogicalValue(value, previousStructureIds, context);
+ } catch (CoreException e) {
+ // unable to display logical structure
+ }
+ }
+ }
+ }
+ return value;
+ }
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/VariableLabelProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/VariableLabelProvider.java
new file mode 100644
index 000000000..dc33c79df
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/VariableLabelProvider.java
@@ -0,0 +1,143 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.elements;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.model.IValue;
+import org.eclipse.debug.core.model.IVariable;
+import org.eclipse.debug.internal.ui.DebugUIPlugin;
+import org.eclipse.debug.internal.ui.DefaultLabelProvider;
+import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
+import org.eclipse.debug.internal.ui.elements.adapters.VariableColumnPresentation;
+import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.RGB;
+
+/**
+ * @since 3.3
+ */
+public class VariableLabelProvider extends DebugElementLabelProvider {
+
+ protected RGB getBackground(Object element, IPresentationContext presentationContext, String columnId) throws CoreException {
+ if (columnId != null) {
+ if (element instanceof IVariable) {
+ IVariable variable = (IVariable) element;
+ if (variable.hasValueChanged()) {
+ return DebugUIPlugin.getPreferenceColor(IInternalDebugUIConstants.PREF_CHANGED_VALUE_BACKGROUND).getRGB();
+ }
+ }
+ }
+ return super.getBackground(element, presentationContext, columnId);
+ }
+
+ protected RGB getForeground(Object element, IPresentationContext presentationContext, String columnId) throws CoreException {
+ if (columnId == null) {
+ if (element instanceof IVariable) {
+ IVariable variable = (IVariable) element;
+ if (variable.hasValueChanged()) {
+ return DebugUIPlugin.getPreferenceColor(IDebugUIConstants.PREF_CHANGED_DEBUG_ELEMENT_COLOR).getRGB();
+ }
+ }
+ }
+ return super.getForeground(element, presentationContext, columnId);
+ }
+
+ protected ImageDescriptor getImageDescriptor(Object element, IPresentationContext presentationContext, String columnId) throws CoreException {
+ if (columnId == null || VariableColumnPresentation.COLUMN_VARIABLE_NAME.equals(columnId)) {
+ return super.getImageDescriptor(element, presentationContext, columnId);
+ }
+ return null;
+ }
+
+ protected String getLabel(Object element, IPresentationContext context, String columnId) throws CoreException {
+ if (columnId == null) {
+ return escapeSpecialChars(super.getLabel(element, context, columnId));
+ } else {
+ IVariable variable = (IVariable) element;
+ IValue value = variable.getValue();
+ return getColumnText(variable, value, context, columnId);
+ }
+ }
+
+ /**
+ * Returns text for a specific columns for the variable/value.
+ *
+ * @param variable
+ * @param value
+ * @param context
+ * @param columnId
+ * @return
+ * @throws CoreException
+ */
+ protected String getColumnText(IVariable variable, IValue value, IPresentationContext context, String columnId) throws CoreException {
+ if (VariableColumnPresentation.COLUMN_VARIABLE_NAME.equals(columnId)) {
+ return getVariableName(variable, context);
+ } else if (VariableColumnPresentation.COLUMN_VARIABLE_TYPE.equals(columnId)) {
+ return getVariableTypeName(variable, context);
+ } else if (VariableColumnPresentation.COLUMN_VARIABLE_VALUE.equals(columnId)) {
+ return getValueText(variable, value, context);
+ } else if (VariableColumnPresentation.COLUMN_VALUE_TYPE.equals(columnId)) {
+ return getValueTypeName(variable, value, context);
+ }
+ return null;
+ }
+
+ /**
+ * Returns the name of the given variable to display in <code>COLUMN_VARIABLE_NAME</code>.
+ *
+ * @param variable
+ * @return variable name
+ * @throws CoreException
+ */
+ protected String getVariableName(IVariable variable, IPresentationContext context) throws CoreException {
+ return variable.getName();
+ }
+
+ /**
+ * Returns the type name of the given variable to display in <code>COLUMN_VARIABLE_TYPE</code>.
+ *
+ * @param variable
+ * @return variable type name
+ * @throws CoreException
+ */
+ protected String getVariableTypeName(IVariable variable, IPresentationContext context) throws CoreException {
+ return variable.getReferenceTypeName();
+ }
+
+ /**
+ * Returns the label for the given value's type to display in <code>COLUMN_VARIABLE_VALUE</code>
+ *
+ * @param variable
+ * @param value
+ * @return value label
+ * @throws CoreException
+ */
+ protected String getValueTypeName(IVariable variable, IValue value, IPresentationContext context) throws CoreException {
+ return value.getReferenceTypeName();
+ }
+
+ /**
+ * Returns the label for the given value to display in <code>COLUMN_VALUE_TYPE</code>
+ *
+ * @param variable
+ * @param value
+ * @return value label
+ * @throws CoreException
+ */
+ protected String getValueText(IVariable variable, IValue value, IPresentationContext context) throws CoreException {
+ return escapeSpecialChars(value.getValueString());
+ }
+
+ protected String escapeSpecialChars(String label) {
+ return DefaultLabelProvider.escapeSpecialChars(label);
+ }
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/VariablesViewElementMementoProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/VariablesViewElementMementoProvider.java
new file mode 100644
index 000000000..2ebac02be
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/VariablesViewElementMementoProvider.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.elements;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.model.IStackFrame;
+import org.eclipse.debug.core.model.IVariable;
+import org.eclipse.ui.IMemento;
+
+/**
+ * @since 3.3
+ */
+public class VariablesViewElementMementoProvider extends ElementMementoProvider {
+
+ /**
+ * memento attribute
+ */
+ private static final String ELEMENT_NAME = "ELEMENT_NAME"; //$NON-NLS-1$
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementMementoProvider#encodeElement(java.lang.Object, org.eclipse.ui.IMemento)
+ */
+ protected boolean encodeElement(Object element, IMemento memento) throws CoreException {
+ if (element instanceof IStackFrame) {
+ IStackFrame frame = (IStackFrame) element;
+ memento.putString(ELEMENT_NAME, frame.getName());
+ } else if (element instanceof IVariable) {
+ IVariable variable = (IVariable) element;
+ memento.putString(ELEMENT_NAME, variable.getName());
+ } else {
+ return false;
+ }
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementMementoProvider#isEqual(java.lang.Object, org.eclipse.ui.IMemento)
+ */
+ protected boolean isEqual(Object element, IMemento memento) throws CoreException {
+ String mementoName = memento.getString(ELEMENT_NAME);
+ if (mementoName != null) {
+ String elementName = null;
+ if (element instanceof IStackFrame) {
+ IStackFrame frame = (IStackFrame) element;
+ elementName = frame.getName();
+ } else if (element instanceof IVariable) {
+ IVariable variable = (IVariable) element;
+ elementName = variable.getName();
+ }
+ if (elementName != null) {
+ return elementName.equals(mementoName);
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/ChildrenCountUpdate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/ChildrenCountUpdate.java
new file mode 100644
index 000000000..689093bc9
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/ChildrenCountUpdate.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.viewers;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import org.eclipse.debug.internal.ui.model.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.model.IElementContentProvider;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.jface.viewers.TreeViewer;
+
+/**
+ * @since 3.3
+ */
+class ChildrenCountUpdate extends ViewerUpdateMonitor implements IChildrenCountUpdate {
+
+ private Map fCounts;
+ private Set fParents = new HashSet();
+ private boolean fStarted = false;
+ private IElementContentProvider fPresentation;
+
+ /**
+ * @param contentProvider
+ */
+ public ChildrenCountUpdate(ModelContentProvider contentProvider, IElementContentProvider presentation) {
+ super(contentProvider);
+ fPresentation = presentation;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.viewers.ViewerUpdateMonitor#performUpdate()
+ */
+ protected void performUpdate() {
+ Iterator iterator = fCounts.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Entry entry = (Entry) iterator.next();
+ int count = ((Integer)(entry.getValue())).intValue();
+ Object parent = entry.getKey();
+ TreePath[] treePaths = getContentProvider().getTreePaths(parent);
+ int viewCount = count;
+ if (treePaths.length > 0) {
+ // all children are filtered the same per parent occurrence
+ if (count == 0) {
+ getContentProvider().clearFilters(treePaths[0]);
+ } else {
+ viewCount = getContentProvider().modelToViewChildCount(treePaths[0], count);
+ }
+ }
+ //System.out.println("setChildCount(" + parent + ", modelCount: " + count + " viewCount: " + viewCount + ")");
+ ((TreeViewer)(getContentProvider().getViewer())).setChildCount(parent, viewCount);
+ if (treePaths.length > 0) {
+ if (treePaths[0].getSegmentCount() > 0) {
+ getContentProvider().doRestore(treePaths[0]);
+ }
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.IChildCountRequestMonitor#setChildCount(int)
+ */
+ public void setChildCount(Object parent, int numChildren) {
+ if (fCounts == null) {
+ fCounts = new HashMap();
+ }
+ fCounts.put(parent, new Integer(numChildren));
+ }
+
+ /**
+ * @param element
+ * @return
+ */
+ protected boolean coalesce(Object element) {
+ fParents.add(element);
+ return true;
+ }
+
+ /**
+ *
+ */
+ protected void start() {
+ synchronized (this) {
+ if (fStarted) {
+ return;
+ }
+ fStarted = true;
+ }
+ TreeModelContentProvider contentProvider = (TreeModelContentProvider)getContentProvider();
+ contentProvider.countRequestStarted(fPresentation);
+ fPresentation.update(this);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.IChildrenCountUpdate#getParents()
+ */
+ public Object[] getParents() {
+ return fParents.toArray();
+ }
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/ChildrenUpdate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/ChildrenUpdate.java
new file mode 100644
index 000000000..8d6eef274
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/ChildrenUpdate.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.viewers;
+
+import org.eclipse.debug.internal.ui.model.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.model.IElementContentProvider;
+import org.eclipse.jface.viewers.TreePath;
+
+/**
+ * @since 3.3
+ */
+class ChildrenUpdate extends ViewerUpdateMonitor implements IChildrenUpdate {
+
+ private Object fParent;
+ private TreePath fParentPath;
+ private Object[] fElements;
+ private int fIndex;
+ private int fLength;
+ private IElementContentProvider fContentProvider;
+ private boolean fStarted = false;
+
+ /**
+ * Constructs a request to update an element
+ *
+ * @param node node to update
+ * @param model model containing the node
+ */
+ public ChildrenUpdate(ModelContentProvider provider, Object parent, TreePath parentPath, int index, IElementContentProvider presentation) {
+ super(provider);
+ fParentPath = parentPath;
+ fIndex = index;
+ fLength = 1;
+ fContentProvider = presentation;
+ fParent = parent;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.debug.ui.viewers.AsynchronousRequestMonitor#performUpdate()
+ */
+ protected void performUpdate() {
+ TreeModelContentProvider provider = (TreeModelContentProvider) getContentProvider();
+ if (fElements != null) {
+ TreeModelViewer viewer = (TreeModelViewer) provider.getViewer();
+ for (int i = 0; i < fElements.length; i++) {
+ int modelIndex = fIndex + i;
+ Object element = fElements[i];
+ if (element != null) {
+ int viewIndex = provider.modelToViewIndex(fParentPath, modelIndex);
+ if (provider.shouldFilter(fParentPath, element)) {
+ if (provider.addFilteredIndex(fParentPath, modelIndex)) {
+ //System.out.println("REMOVE(" + fParent + ", modelIndex: " + modelIndex + " viewIndex: " + viewIndex + ", " + element + ")");
+ viewer.remove(fParent, viewIndex);
+ }
+ } else {
+ if (provider.isFiltered(fParentPath, modelIndex)) {
+ provider.clearFilteredChild(fParentPath, modelIndex);
+ int insertIndex = provider.modelToViewIndex(fParentPath, modelIndex);
+ //System.out.println("insert(" + fParentPath.getLastSegment() + ", modelIndex: " + modelIndex + " insertIndex: " + insertIndex + ", " + element + ")");
+ if (fParentPath.getSegmentCount() == 0) {
+ viewer.insert(fParent, element, insertIndex);
+ } else {
+ viewer.insert(fParentPath, element, insertIndex);
+ }
+ } else {
+ //System.out.println("replace(" + fParent + ", modelIndex: " + modelIndex + " viewIndex: " + viewIndex + ", " + element + ")");
+ viewer.replace(fParent, viewIndex, element);
+ }
+ provider.updateChildCount(element, 0);
+ }
+ }
+ }
+ } else {
+ provider.updateChildCount(fParent, 0);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.IChildrenUpdate#setChild(java.lang.Object, int)
+ */
+ public void setChild(Object child, int index) {
+ if (fElements == null) {
+ fElements = new Object[fLength];
+ }
+ fElements[index - fIndex] = child;
+ }
+
+ /**
+ * Coalesce the request with the given index. Return whether the requests can be
+ * coalesced.
+ *
+ * @param index
+ * @return whether it worked
+ */
+ public boolean coalesce(int index) {
+ if (index == fIndex + fLength) {
+ fLength++;
+ return true;
+ }
+ return false;
+ }
+
+ public void start() {
+ synchronized (this) {
+ if (fStarted) {
+ return;
+ }
+ fStarted = true;
+ }
+ //System.out.println("\tRequest (" + fParent + "): " + fIndex + " length: " + fLength);
+ TreeModelContentProvider contentProvider = (TreeModelContentProvider)getContentProvider();
+ contentProvider.childRequestStarted(this);
+ fContentProvider.update(this);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.IChildrenUpdate#getLength()
+ */
+ public int getLength() {
+ return fLength;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.IChildrenUpdate#getOffset()
+ */
+ public int getOffset() {
+ return fIndex;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.IChildrenUpdate#getParent()
+ */
+ public Object getParent() {
+ return fParent;
+ }
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/ElementCompareRequest.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/ElementCompareRequest.java
new file mode 100644
index 000000000..d6d580b5b
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/ElementCompareRequest.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.viewers;
+
+import org.eclipse.debug.internal.ui.model.IElementCompareRequest;
+import org.eclipse.debug.internal.ui.viewers.provisional.ModelDelta;
+import org.eclipse.ui.IMemento;
+
+/**
+ * @since 3.3
+ */
+public class ElementCompareRequest extends MementoUpdate implements IElementCompareRequest {
+
+ private boolean fEqual;
+ private ModelDelta fDelta;
+ private ModelContentProvider fProvider;
+
+ /**
+ * @param context
+ * @param element
+ * @param memento
+ */
+ public ElementCompareRequest(ModelContentProvider provider, Object element, IMemento memento, ModelDelta delta) {
+ super(provider.getPresentationContext(), element, memento);
+ fProvider = provider;
+ fDelta = delta;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.IElementCompareRequest#setEqual(boolean)
+ */
+ public void setEqual(boolean equal) {
+ fEqual = equal;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IProgressMonitor#done()
+ */
+ public void done() {
+ if (isEqual()) {
+ fDelta.setElement(getElement());
+ fProvider.doRestore(fDelta);
+ }
+ }
+
+ boolean isEqual() {
+ return fEqual;
+ }
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/ElementMementoRequest.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/ElementMementoRequest.java
new file mode 100644
index 000000000..24b14b1bb
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/ElementMementoRequest.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.viewers;
+
+import org.eclipse.debug.internal.ui.model.IElementMementoRequest;
+import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.provisional.ModelDelta;
+import org.eclipse.ui.IMemento;
+
+/**
+ * @since 3.3
+ */
+public class ElementMementoRequest extends MementoUpdate implements IElementMementoRequest {
+
+ private IMementoManager fManager;
+ private ModelDelta fDelta;
+
+ /**
+ * @param context
+ * @param element
+ * @param memento
+ */
+ public ElementMementoRequest(IMementoManager manager, IPresentationContext context, Object element, IMemento memento, ModelDelta delta) {
+ super(context, element, memento);
+ fManager = manager;
+ fDelta = delta;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IProgressMonitor#done()
+ */
+ public void done() {
+ if (!isCanceled() && (getStatus() == null || getStatus().isOK())) {
+ // replace the element with a memento
+ fDelta.setElement(getMemento());
+ }
+ fManager.requestComplete(this);
+ }
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/FilterTransform.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/FilterTransform.java
new file mode 100644
index 000000000..88a9b30f5
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/FilterTransform.java
@@ -0,0 +1,365 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.viewers;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.jface.viewers.TreePath;
+
+
+/**
+ * Helper class to support filtering in virtual tree viewer.
+ * Translates indexes from viewer to model coordinate space (and visa versa).
+ * <p>
+ * This filter transform maintains a tree representing filtered elements in the
+ * viewer. The filtering is performed dynamically as elements are 'replaced' in the tree
+ * by a lazy tree content provider.
+ * </p>
+ * <p>
+ * This class not intended to be subclassed or instantiated. For internal use only.
+ * </p>
+ * <p>
+ * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
+ * part of a work in progress. There is no guarantee that this API will
+ * remain unchanged during the 3.3 release cycle. Please do not use this API
+ * without consulting with the Platform/Debug team.
+ * </p>
+ * @since 3.3
+ */
+class FilterTransform {
+
+ private Node root = new Node();
+
+ class Node {
+ private int[] filteredChildren = null; // only set for leaves
+ private Map children = null; // only set for parent nodes, indexed by child
+
+ Node() {
+ }
+
+ boolean addFilter(TreePath path, int childIndex, int pathIndex) {
+ if (pathIndex == path.getSegmentCount()) {
+ if (filteredChildren == null) {
+ filteredChildren = new int[]{childIndex};
+ return true;
+ }
+ int location = Arrays.binarySearch(filteredChildren, childIndex);
+ if (location >= 0) {
+ return false;
+ }
+ location = 0 - (location + 1);
+ int[] next = new int[filteredChildren.length + 1];
+ if (location == 0) {
+ next[0] = childIndex;
+ System.arraycopy(filteredChildren, 0, next, 1, filteredChildren.length);
+ } else if (location == filteredChildren.length) {
+ next[filteredChildren.length] = childIndex;
+ System.arraycopy(filteredChildren, 0, next, 0, filteredChildren.length);
+ } else {
+ System.arraycopy(filteredChildren, 0, next, 0, location);
+ next[location] = childIndex;
+ System.arraycopy(filteredChildren, location, next, location + 1, filteredChildren.length - location);
+ }
+ filteredChildren = next;
+ return true;
+ }
+
+ if (children == null) {
+ children = new HashMap();
+ }
+ Object element = path.getSegment(pathIndex);
+ Node node = (Node) children.get(element);
+ if (node == null) {
+ node = new Node();
+ children.put(element, node);
+ }
+ return node.addFilter(path, childIndex, pathIndex + 1);
+ }
+
+ boolean clear(TreePath path, int pathIndex) {
+ if (pathIndex == path.getSegmentCount()) {
+ return true;
+ }
+ if (children == null) {
+ return false;
+ }
+ Object child = path.getSegment(pathIndex);
+ Node node = (Node) children.get(child);
+ if (node != null) {
+ if (node.clear(path, pathIndex + 1)) {
+ children.remove(child);
+ }
+ }
+ return children.isEmpty();
+ }
+
+ boolean clear(TreePath path, int childIndex, int pathIndex) {
+ if (pathIndex == path.getSegmentCount()) {
+ if (filteredChildren != null) {
+ int location = Arrays.binarySearch(filteredChildren, childIndex);
+ if (location >= 0) {
+ // remove it
+ if (location == 0) {
+ if (filteredChildren.length == 1) {
+ filteredChildren = null;
+ return true;
+ } else {
+ int[] next = new int[filteredChildren.length - 1];
+ System.arraycopy(filteredChildren, 1, next, 0, next.length);
+ filteredChildren = next;
+ }
+ } else if (location == (filteredChildren.length - 1)) {
+ int[] next = new int[filteredChildren.length - 1];
+ System.arraycopy(filteredChildren, 0, next, 0, location);
+ filteredChildren = next;
+ } else {
+ int[] next = new int[filteredChildren.length - 1];
+ System.arraycopy(filteredChildren, 0, next, 0, location);
+ System.arraycopy(filteredChildren, location + 1, next, location, next.length - location);
+ filteredChildren = next;
+ }
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ if (children == null) {
+ return false;
+ }
+ Object element = path.getSegment(pathIndex);
+ Node node = (Node) children.get(element);
+ if (node == null) {
+ return false;
+ }
+ boolean remove = node.clear(path, childIndex, pathIndex + 1);
+ if (remove) {
+ children.remove(element);
+ return filteredChildren == null && children.isEmpty();
+ } else {
+ return false;
+ }
+ }
+
+ Node find(TreePath path, int pathIndex) {
+ if (pathIndex == path.getSegmentCount())
+ return this;
+ if (children == null) {
+ return null;
+ }
+ Object child = path.getSegment(pathIndex);
+ Node node = (Node) children.get(child);
+ if (node != null) {
+ return node.find(path, pathIndex + 1);
+ }
+ return null;
+ }
+
+ int viewToModel(int childIndex) {
+ if (filteredChildren == null) {
+ return childIndex;
+ }
+ // If there are filtered children, then we want to find the
+ // (n+1)th missing number in the list of filtered indexes (missing
+ // entries are visible in the view). For example, if the request
+ // has asked for the model index corresponding to the 4th viewer
+ // index, then we want to find the 5th missing number in the
+ // filtered index sequence.
+
+ int count = -1; // count from 0, 1, 2...
+ int missingNumbers = 0; // how many numbers missing from the filtered index
+ int offset = 0; // offset into the filtered index
+
+ while (missingNumbers < (childIndex + 1)) {
+ count++;
+ if (offset < filteredChildren.length) {
+ if (filteredChildren[offset] == count) {
+ // not missing
+ offset++;
+ } else {
+ // missing
+ missingNumbers++;
+ }
+ } else {
+ missingNumbers++;
+ }
+ }
+ return count;
+ }
+
+ int modelToView(int childIndex) {
+ if (filteredChildren == null) {
+ return childIndex;
+ }
+ int offset = 0;
+ for (int i = 0; i < filteredChildren.length; i++) {
+ if (childIndex == filteredChildren[i] ) {
+ return -1;
+ } else if (childIndex > filteredChildren[i]) {
+ offset++;
+ } else {
+ break;
+ }
+ }
+ return childIndex - offset;
+ }
+
+ int modelToViewCount(int childCount) {
+ if (filteredChildren == null) {
+ return childCount;
+ }
+ return childCount - filteredChildren.length;
+ }
+
+ boolean isFiltered(int index) {
+ if (filteredChildren != null) {
+ int location = Arrays.binarySearch(filteredChildren, index);
+ return location >= 0;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Filters the specified child of the given parent and returns
+ * whether the child was already filtered.
+ *
+ * @param parentPath path to parent element
+ * @param childIndex index of filtered child relative to parent (in model coordinates)
+ * @return whether the child was already filtered
+ */
+ public synchronized boolean addFilteredIndex(TreePath parentPath, int childIndex) {
+ return root.addFilter(parentPath, childIndex, 0);
+ }
+
+ /**
+ * Clears all filtered elements.
+ */
+ public synchronized void clear() {
+ root = new Node();
+ }
+
+ /**
+ * Clears all filters in the subtree of the given element.
+ *
+ * @param path element path
+ */
+ public synchronized void clear(TreePath path) {
+ root.clear(path, 0);
+ }
+
+ /**
+ * Clears the given filtered index of the specified parent.
+ *
+ * @param path parent path
+ * @param index index to clear
+ */
+ public synchronized void clear(TreePath parentPath, int index) {
+ root.clear(parentPath, index, 0);
+ }
+
+ /**
+ * Translates and returns the given model index (raw index) into
+ * a view index (filtered index), or -1 if filtered.
+ *
+ * @param parentPath path to parent element
+ * @param childIndex index of child element in model space
+ * @return the given index in view coordinates, or -1 if filtered.
+ */
+ public synchronized int modelToViewIndex(TreePath parentPath, int childIndex) {
+ Node parentNode = root.find(parentPath, 0);
+ if (parentNode == null) {
+ return childIndex;
+ }
+ return parentNode.modelToView(childIndex);
+ }
+
+ /**
+ * Translates and returns the given view index (filtered) into
+ * a model index (raw index).
+ *
+ * @param parentPath path to parent element
+ * @param childIndex index of child element in view space
+ * @return the given index in model coordinates
+ */
+ public synchronized int viewToModelIndex(TreePath parentPath, int childIndex) {
+ Node parentNode = root.find(parentPath, 0);
+ if (parentNode == null) {
+ return childIndex;
+ }
+ return parentNode.viewToModel(childIndex);
+ }
+
+ /**
+ * Returns the number of children for the given parent, in the model.
+ *
+ * @param parentPath path to parent element
+ * @param viewCount number of children in the view
+ * @return number of children in the model
+ */
+ public synchronized int viewToModelCount(TreePath parentPath, int viewCount) {
+ Node parentNode = root.find(parentPath, 0);
+ if (parentNode != null) {
+ if (parentNode.filteredChildren != null) {
+ return viewCount + parentNode.filteredChildren.length;
+ }
+ }
+ return viewCount;
+ }
+
+ /**
+ * Translates and returns the given model child count (raw) into
+ * a view count (filtered).
+ *
+ * @param parentPath path to parent element
+ * @param count child count in model space
+ * @return the given count in view coordinates
+ */
+ public synchronized int modelToViewCount(TreePath parentPath, int count) {
+ Node parentNode = root.find(parentPath, 0);
+ if (parentNode == null) {
+ return count;
+ }
+ return parentNode.modelToViewCount(count);
+ }
+
+ /**
+ * Returns whether the given index of the specified parent is currently filtered.
+ *
+ * @param parentPath path to parent element
+ * @param index index of child element
+ * @return whether the child is currently filtered
+ */
+ public synchronized boolean isFiltered(TreePath parentPath, int index) {
+ Node parentNode = root.find(parentPath, 0);
+ if (parentNode == null) {
+ return false;
+ }
+ return parentNode.isFiltered(index);
+ }
+
+ /**
+ * Returns filtered children of the given parent, or <code>null</code> if none.
+ *
+ * @param parentPath
+ * @return filtered children or <code>null</code>
+ */
+ public int[] getFilteredChildren(TreePath parentPath) {
+ Node parentNode = root.find(parentPath, 0);
+ if (parentNode == null) {
+ return null;
+ }
+ return parentNode.filteredChildren;
+ }
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/IMementoManager.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/IMementoManager.java
new file mode 100644
index 000000000..5350dbb11
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/IMementoManager.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.viewers;
+
+import org.eclipse.debug.internal.ui.model.IElementMementoRequest;
+
+/**
+ * @since 3.3
+ */
+interface IMementoManager {
+
+ /**
+ * Adds the request to this manager.
+ *
+ * @param memento request
+ */
+ public void addRequest(IElementMementoRequest request);
+
+ /**
+ * Notification the request is complete.
+ *
+ * @param request
+ */
+ public void requestComplete(IElementMementoRequest request);
+
+ /**
+ * Process the queued requests. Accepts no more new requests.
+ */
+ public void processReqeusts();
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/IViewerUpdateListener.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/IViewerUpdateListener.java
new file mode 100644
index 000000000..9925e7c8f
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/IViewerUpdateListener.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.viewers;
+
+import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousRequestMonitor;
+
+/**
+ * Notified of viewer updates.
+ *
+ * @since 3.3
+ */
+public interface IViewerUpdateListener {
+
+ /**
+ * Notification that a sequence of viewer updates are starting.
+ */
+ public void viewerUpdatesBegin();
+
+ /**
+ * Notification that viewer updates are complete. Corresponds to
+ * a <code>viewerUpdatesBegin()</code> notification.
+ */
+ public void viewerUpdatesComplete();
+
+ /**
+ * Notification that a specific update has started within
+ * a sequence of updates.
+ *
+ * @param update update
+ */
+ public void updateStarted(IAsynchronousRequestMonitor update);
+
+ /**
+ * Notification that a specific update has completed within a
+ * sequence of updates.
+ *
+ * @param update update
+ */
+ public void updateComplete(IAsynchronousRequestMonitor update);
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/LabelUpdate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/LabelUpdate.java
new file mode 100644
index 000000000..61e2a2ab7
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/LabelUpdate.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.viewers;
+
+import org.eclipse.debug.internal.ui.actions.context.AbstractRequestMonitor;
+import org.eclipse.debug.internal.ui.model.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.ViewerRow;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.RGB;
+
+/**
+ * @since 3.3
+ */
+class LabelUpdate extends AbstractRequestMonitor implements ILabelUpdate {
+
+ private Object fElement;
+ private String fColumnId;
+ private RGB fBackground;
+ private RGB fForeground;
+ private ImageDescriptor fImageDescriptor;
+ private String fLabel;
+ private FontData fFontData;
+ private TreeModelLabelProvider fProvider;
+ private int fColumnIndex;
+
+ /**
+ * @param element element the label is for
+ * @param provider label provider to callback to
+ * @param columnId column identifier or <code>null</code>
+ */
+ public LabelUpdate(Object element, TreeModelLabelProvider provider, String columnId, int columnIndex) {
+ fElement = element;
+ fProvider = provider;
+ fColumnId = columnId;
+ fColumnIndex = columnIndex;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.ILabelUpdate#getColumnId()
+ */
+ public String getColumnId() {
+ return fColumnId;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.ILabelUpdate#getElement()
+ */
+ public Object getElement() {
+ return fElement;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.ILabelUpdate#setBackground(org.eclipse.swt.graphics.RGB)
+ */
+ public void setBackground(RGB background) {
+ fBackground = background;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.ILabelUpdate#setFontData(org.eclipse.swt.graphics.FontData)
+ */
+ public void setFontData(FontData fontData) {
+ fFontData = fontData;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.ILabelUpdate#setForeground(org.eclipse.swt.graphics.RGB)
+ */
+ public void setForeground(RGB foreground) {
+ fForeground = foreground;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.ILabelUpdate#setImageDescriptor(org.eclipse.jface.resource.ImageDescriptor)
+ */
+ public void setImageDescriptor(ImageDescriptor image) {
+ fImageDescriptor = image;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.ILabelUpdate#setLabel(java.lang.String)
+ */
+ public void setLabel(String text) {
+ fLabel = text;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.IPresentationUpdate#getPresentationContext()
+ */
+ public IPresentationContext getPresentationContext() {
+ return fProvider.getPresentationContext();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IProgressMonitor#done()
+ */
+ public void done() {
+ fProvider.complete(this);
+ }
+
+ /**
+ * Applies settings to viewer cell
+ */
+ public void update(ViewerRow row) {
+ row.setText(fColumnIndex, fLabel);
+ row.setImage(fColumnIndex, fProvider.getImage(fImageDescriptor));
+ row.setForeground(fColumnIndex, fProvider.getColor(fForeground));
+ row.setBackground(fColumnIndex, fProvider.getColor(fBackground));
+ row.setFont(fColumnIndex, fProvider.getFont(fFontData));
+ }
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/MementoUpdate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/MementoUpdate.java
new file mode 100644
index 000000000..f789d7834
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/MementoUpdate.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.viewers;
+
+import org.eclipse.debug.internal.ui.actions.context.AbstractRequestMonitor;
+import org.eclipse.debug.internal.ui.model.IPresentationUpdate;
+import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
+import org.eclipse.ui.IMemento;
+
+/**
+ * @since 3.3
+ */
+abstract class MementoUpdate extends AbstractRequestMonitor implements IPresentationUpdate {
+
+ private IPresentationContext fContext;
+ private Object fElement;
+ private IMemento fMemento;
+
+ /**
+ * Constructs a viewer state request.
+ *
+ * @param viewer viewer
+ * @param element element
+ * @param memento memento
+ */
+ public MementoUpdate(IPresentationContext context, Object element, IMemento memento) {
+ fContext = context;
+ fElement = element;
+ fMemento = memento;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.IPresentationUpdate#getPresentationContext()
+ */
+ public IPresentationContext getPresentationContext() {
+ return fContext;
+ }
+
+ public Object getElement() {
+ return fElement;
+ }
+
+ public IMemento getMemento() {
+ return fMemento;
+ }
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/ModelContentProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/ModelContentProvider.java
new file mode 100644
index 000000000..f408c0155
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/ModelContentProvider.java
@@ -0,0 +1,915 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.viewers;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.internal.ui.DebugUIPlugin;
+import org.eclipse.debug.internal.ui.model.IElementContentProvider;
+import org.eclipse.debug.internal.ui.model.IElementMementoProvider;
+import org.eclipse.debug.internal.ui.model.IElementMementoRequest;
+import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousRequestMonitor;
+import org.eclipse.debug.internal.ui.viewers.provisional.IModelChangedListener;
+import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.provisional.IModelDeltaVisitor;
+import org.eclipse.debug.internal.ui.viewers.provisional.IModelProxy;
+import org.eclipse.debug.internal.ui.viewers.provisional.IModelProxyFactoryAdapter;
+import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.provisional.ModelDelta;
+import org.eclipse.debug.ui.AbstractDebugView;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.jface.viewers.StructuredViewer;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.jface.viewers.TreeSelection;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.XMLMemento;
+import org.eclipse.ui.progress.UIJob;
+import org.eclipse.ui.progress.WorkbenchJob;
+
+/**
+ * Content provider for a virtual viewer.
+ *
+ * @since 3.3
+ */
+abstract class ModelContentProvider implements IContentProvider,
+ IModelChangedListener {
+
+ private Viewer fViewer;
+
+ private Map fModelProxies = new HashMap(); // model proxy by element
+
+ /**
+ * Map of nodes that have been filtered from the viewer.
+ */
+ private FilterTransform fTransform = new FilterTransform();
+
+ /**
+ * Model listeners
+ */
+ private ListenerList fModelListeners = new ListenerList();
+
+ /**
+ * Update listeners
+ */
+ private ListenerList fUpdateListeners = new ListenerList();
+
+ /**
+ * Nesting count of updates
+ */
+ private int fUpdateNestingCount = 0;
+
+ /**
+ * Map of viewer states keyed by viewer input mementos
+ */
+ private Map fViewerStates = new LRUMap(20);
+
+ /**
+ * Pending viewer state to be restored
+ */
+ private ModelDelta fPendingState = null;
+
+ /**
+ * Used to determine when restoration delta has been processed
+ */
+ class CheckState implements IModelDeltaVisitor {
+ private boolean complete = true;
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.provisional.IModelDeltaVisitor#visit(org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta, int)
+ */
+ public boolean visit(IModelDelta delta, int depth) {
+ if (delta.getFlags() != IModelDelta.NO_CHANGE) {
+ complete = false;
+ return false;
+ }
+ return true;
+ }
+
+ public boolean isComplete() {
+ return complete;
+ }
+ }
+
+ /**
+ * LRU cache for viewer states
+ */
+ class LRUMap extends LinkedHashMap {
+ private static final long serialVersionUID= 1L;
+ private int fMaxSize;
+ LRUMap(int maxSize) {
+ super();
+ fMaxSize = maxSize;
+ }
+ protected boolean removeEldestEntry(Entry eldest) {
+ return size() > fMaxSize;
+ }
+ }
+
+ /**
+ * Update type constants
+ */
+ private static final int UPDATE_SEQUENCE_BEGINS = 0;
+ private static final int UPDATE_SEQUENCE_COMPLETE = 1;
+ private static final int UPDATE_BEGINS = 2;
+ private static final int UPDATE_COMPLETE = 3;
+
+ /**
+ * Constant for an empty tree path.
+ */
+ protected static final TreePath EMPTY_TREE_PATH = new TreePath(new Object[]{});
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.viewers.IContentProvider#dispose()
+ */
+ public synchronized void dispose() {
+ fModelListeners.clear();
+ fUpdateListeners.clear();
+ disposeAllModelProxies();
+ fViewer = null;
+ }
+
+ public synchronized boolean isDisposed() {
+ return fViewer == null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer,
+ * java.lang.Object, java.lang.Object)
+ */
+ public synchronized void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ fViewer = viewer;
+ if (oldInput != null) {
+ saveViewerState(oldInput);
+ }
+ if (newInput != oldInput) {
+ disposeAllModelProxies();
+ fTransform.clear();
+ if (newInput != null) {
+ installModelProxy(newInput);
+ restoreViewerState(newInput);
+ }
+ }
+ }
+
+ /**
+ * Restores viewer state for the new input
+ *
+ * @param newInput
+ */
+ protected void restoreViewerState(final Object input) {
+ fPendingState = null;
+ final IElementMementoProvider stateProvider = getViewerStateAdapter(input);
+ if (stateProvider != null) {
+ // build a model delta representing expansion and selection state
+ final ModelDelta delta = new ModelDelta(input, IModelDelta.NO_CHANGE);
+ final XMLMemento inputMemento = XMLMemento.createWriteRoot("VIEWER_INPUT_MEMENTO"); //$NON-NLS-1$
+ final IMementoManager manager = new IMementoManager() {
+
+ private IElementMementoRequest fRequest;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.viewers.IMementoManager#requestComplete(org.eclipse.debug.internal.ui.model.IElementMementoRequest)
+ */
+ public synchronized void requestComplete(IElementMementoRequest request) {
+ if (!request.isCanceled() && (request.getStatus() == null || request.getStatus().isOK())) {
+ XMLMemento keyMemento = (XMLMemento) delta.getElement();
+ StringWriter writer = new StringWriter();
+ try {
+ keyMemento.save(writer);
+ final ModelDelta stateDelta = (ModelDelta) fViewerStates.remove(writer.toString());
+ if (stateDelta != null) {
+ //System.out.println("RESTORE: " + stateDelta.toString());
+ stateDelta.setElement(input);
+ // begin restoration
+ UIJob job = new UIJob("restore state") {
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ if (input.equals(getViewer().getInput())) {
+ fPendingState = stateDelta;
+ doInitialRestore();
+ }
+ return Status.OK_STATUS;
+ }
+
+ };
+ job.setSystem(true);
+ job.schedule();
+ }
+ } catch (IOException e) {
+ // TODO log
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.viewers.IMementoManager#processReqeusts()
+ */
+ public void processReqeusts() {
+ stateProvider.encodeElement(fRequest);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.viewers.IMementoManager#addRequest(org.eclipse.debug.internal.ui.model.IElementMementoRequest)
+ */
+ public synchronized void addRequest(IElementMementoRequest req) {
+ fRequest = req;
+ }
+
+ };
+ manager.addRequest(new ElementMementoRequest(manager, getPresentationContext(),
+ delta.getElement(), inputMemento, delta));
+ manager.processReqeusts();
+ }
+ }
+
+ /**
+ * Restore selection/expansion based on items already in the tree
+ */
+ abstract protected void doInitialRestore();
+
+ /**
+ * Perform any restoration required for the given tree path.
+ *
+ * @param path
+ */
+ protected void doRestore(final TreePath path) {
+ if (fPendingState == null) {
+ return;
+ }
+ IModelDeltaVisitor visitor = new IModelDeltaVisitor() {
+ public boolean visit(IModelDelta delta, int depth) {
+ if (delta.getParentDelta() == null) {
+ return true;
+ }
+ Object element = delta.getElement();
+ Object potentialMatch = path.getSegment(depth - 1);
+ if (element instanceof IMemento) {
+ IElementMementoProvider provider = getViewerStateAdapter(getViewer().getInput());
+ if (provider != null) {
+ provider.compareElement(
+ new ElementCompareRequest(ModelContentProvider.this,
+ potentialMatch, (IMemento) element, (ModelDelta)delta));
+ }
+ } else {
+ if (element.equals(potentialMatch)) {
+ // already processed - visit children
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+ fPendingState.accept(visitor);
+ }
+
+ /**
+ * Saves the viewer's state for the previous input.
+ *
+ * @param oldInput
+ */
+ protected void saveViewerState(Object input) {
+ IElementMementoProvider stateProvider = getViewerStateAdapter(input);
+ if (stateProvider != null) {
+ // build a model delta representing expansion and selection state
+ ModelDelta delta = new ModelDelta(input, IModelDelta.NO_CHANGE);
+ buildViewerState(delta);
+ if (delta.getChildDeltas().length > 0) {
+ // encode delta with mementos in place of elements, in non-UI thread
+ encodeDelta(delta, stateProvider);
+ }
+ }
+ }
+
+ /**
+ * Encodes delta elements into mementos using the given provider.
+ *
+ * @param delta
+ * @param stateProvider
+ */
+ protected void encodeDelta(final ModelDelta rootDelta, final IElementMementoProvider stateProvider) {
+ final XMLMemento inputMemento = XMLMemento.createWriteRoot("VIEWER_INPUT_MEMENTO"); //$NON-NLS-1$
+ final XMLMemento childrenMemento = XMLMemento.createWriteRoot("CHILDREN_MEMENTO"); //$NON-NLS-1$
+ final IMementoManager manager = new IMementoManager() {
+
+ private Set requests = new HashSet();
+ private boolean abort = false;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.viewers.IMementoManager#requestComplete(org.eclipse.debug.internal.ui.model.IElementMementoRequest)
+ */
+ public synchronized void requestComplete(IElementMementoRequest request) {
+ if (!abort) {
+ if (!request.isCanceled() && (request.getStatus() == null || request.getStatus().isOK())) {
+ requests.remove(request);
+ if (requests.isEmpty()) {
+ XMLMemento keyMemento = (XMLMemento) rootDelta.getElement();
+ StringWriter writer = new StringWriter();
+ try {
+ keyMemento.save(writer);
+ fViewerStates.put(writer.toString(), rootDelta);
+ } catch (IOException e) {
+ // TODO log
+ }
+ }
+ } else {
+ abort = true;
+ Iterator iterator = requests.iterator();
+ while (iterator.hasNext()) {
+ IElementMementoRequest req = (IElementMementoRequest) iterator.next();
+ req.setCanceled(true);
+ }
+ requests.clear();
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.viewers.IMementoManager#processReqeusts()
+ */
+ public void processReqeusts() {
+ IElementMementoRequest[] req = (IElementMementoRequest[]) requests.toArray(new IElementMementoRequest[requests.size()]);
+ for (int i = 0; i < req.length; i++) {
+ stateProvider.encodeElement(req[i]);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.viewers.IMementoManager#addRequest(org.eclipse.debug.internal.ui.model.IElementMementoRequest)
+ */
+ public synchronized void addRequest(IElementMementoRequest request) {
+ requests.add(request);
+ }
+
+ };
+ IModelDeltaVisitor visitor = new IModelDeltaVisitor() {
+ public boolean visit(IModelDelta delta, int depth) {
+ if (delta.getParentDelta() == null) {
+ manager.addRequest(
+ new ElementMementoRequest(manager, getPresentationContext(),
+ delta.getElement(), inputMemento, (ModelDelta)delta));
+ } else {
+ manager.addRequest(
+ new ElementMementoRequest(manager, getPresentationContext(),
+ delta.getElement(), childrenMemento.createChild("CHILD_ELEMENT"), (ModelDelta)delta)); //$NON-NLS-1$
+ }
+ return true;
+ }
+ };
+ rootDelta.accept(visitor);
+ manager.processReqeusts();
+ }
+
+ /**
+ * Builds a delta with the given root delta for expansion/selection state.
+ *
+ * @param delta root delta
+ */
+ protected abstract void buildViewerState(ModelDelta delta);
+
+ /**
+ * Uninstalls the model proxy installed for the given element, if any.
+ *
+ * @param element
+ */
+ protected synchronized void disposeModelProxy(Object element) {
+ IModelProxy proxy = (IModelProxy) fModelProxies.remove(element);
+ if (proxy != null) {
+ proxy.dispose();
+ }
+ }
+
+ /**
+ * Uninstalls each model proxy
+ */
+ protected synchronized void disposeAllModelProxies() {
+ Iterator updatePolicies = fModelProxies.values().iterator();
+ while (updatePolicies.hasNext()) {
+ IModelProxy proxy = (IModelProxy) updatePolicies.next();
+ proxy.dispose();
+ }
+ fModelProxies.clear();
+ }
+
+ /**
+ * Installs the model proxy for the given element into this content provider
+ * if not already installed.
+ *
+ * @param element
+ * element to install an update policy for
+ */
+ protected synchronized void installModelProxy(Object element) {
+ if (!fModelProxies.containsKey(element)) {
+ IModelProxyFactoryAdapter modelProxyFactory = getModelProxyFactoryAdapter(element);
+ if (modelProxyFactory != null) {
+ final IModelProxy proxy = modelProxyFactory.createModelProxy(
+ element, getPresentationContext());
+ if (proxy != null) {
+ fModelProxies.put(element, proxy);
+ Job job = new Job("Model Proxy installed notification job") {//$NON-NLS-1$
+ protected IStatus run(IProgressMonitor monitor) {
+ if (!monitor.isCanceled()) {
+ proxy.init(getPresentationContext());
+ Object[] mcls = fModelListeners.getListeners();
+ for (int i = 0; i < mcls.length; i++) {
+ proxy.addModelChangedListener((IModelChangedListener) mcls[i]);
+ }
+ proxy
+ .addModelChangedListener(ModelContentProvider.this);
+ proxy.installed();
+ }
+ return Status.OK_STATUS;
+ }
+ };
+ job.setSystem(true);
+ job.schedule();
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the model proxy factory for the given element or
+ * <code>null</code> if none.
+ *
+ * @param element
+ * element to retrieve adapter for
+ * @return model proxy factory adapter or <code>null</code>
+ */
+ protected IModelProxyFactoryAdapter getModelProxyFactoryAdapter(Object element) {
+ IModelProxyFactoryAdapter adapter = null;
+ if (element instanceof IModelProxyFactoryAdapter) {
+ adapter = (IModelProxyFactoryAdapter) element;
+ } else if (element instanceof IAdaptable) {
+ IAdaptable adaptable = (IAdaptable) element;
+ adapter = (IModelProxyFactoryAdapter) adaptable.getAdapter(IModelProxyFactoryAdapter.class);
+ }
+ return adapter;
+ }
+
+ /**
+ * Returns the viewer state adapter for the given element or
+ * <code>null</code> if none.
+ *
+ * @param element
+ * element to retrieve adapter for
+ * @return viewer state adapter or <code>null</code>
+ */
+ protected IElementMementoProvider getViewerStateAdapter(Object element) {
+ IElementMementoProvider adapter = null;
+ if (element instanceof IElementMementoProvider) {
+ adapter = (IElementMementoProvider) element;
+ } else if (element instanceof IAdaptable) {
+ IAdaptable adaptable = (IAdaptable) element;
+ adapter = (IElementMementoProvider) adaptable.getAdapter(IElementMementoProvider.class);
+ }
+ return adapter;
+ }
+
+ /**
+ * Returns the presentation context for this content provider.
+ *
+ * @return presentation context
+ */
+ protected abstract IPresentationContext getPresentationContext();
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.debug.internal.ui.viewers.provisional.IModelChangedListener#modelChanged(org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta)
+ */
+ public void modelChanged(final IModelDelta delta) {
+ WorkbenchJob job = new WorkbenchJob("process model delta") { //$NON-NLS-1$
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ updateNodes(new IModelDelta[] { delta });
+ return Status.OK_STATUS;
+ }
+ };
+ job.setSystem(true);
+ job.schedule();
+
+ }
+
+ protected void updateNodes(IModelDelta[] nodes) {
+ for (int i = 0; i < nodes.length; i++) {
+ IModelDelta node = nodes[i];
+ int flags = node.getFlags();
+
+ if ((flags & IModelDelta.ADDED) != 0) {
+ handleAdd(node);
+ }
+ if ((flags & IModelDelta.REMOVED) != 0) {
+ handleRemove(node);
+ }
+ if ((flags & IModelDelta.CONTENT) != 0) {
+ handleContent(node);
+ }
+ if ((flags & IModelDelta.EXPAND) != 0) {
+ handleExpand(node);
+ }
+ if ((flags & IModelDelta.SELECT) != 0) {
+ handleSelect(node);
+ }
+ if ((flags & IModelDelta.STATE) != 0) {
+ handleState(node);
+ }
+ if ((flags & IModelDelta.INSERTED) != 0) {
+ handleInsert(node);
+ }
+ if ((flags & IModelDelta.REPLACED) != 0) {
+ handleReplace(node);
+ }
+ if ((flags & IModelDelta.INSTALL) != 0) {
+ handleInstall(node);
+ }
+ if ((flags & IModelDelta.UNINSTALL) != 0) {
+ handleUninstall(node);
+ }
+ updateNodes(node.getChildDeltas());
+ }
+ }
+
+ /**
+ * Returns the content adapter for the given element or
+ * <code>null</code> if none.
+ *
+ * @param element
+ * element to retrieve adapter for
+ * @return content adapter or <code>null</code>
+ */
+ protected IElementContentProvider getContentAdapter(Object element) {
+ IElementContentProvider adapter = null;
+ if (element instanceof IElementContentProvider) {
+ adapter = (IElementContentProvider) element;
+ } else if (element instanceof IAdaptable) {
+ IAdaptable adaptable = (IAdaptable) element;
+ adapter = (IElementContentProvider) adaptable.getAdapter(IElementContentProvider.class);
+ }
+ return adapter;
+ }
+
+ protected abstract void handleState(IModelDelta delta);
+
+ protected abstract void handleSelect(IModelDelta delta);
+
+ protected abstract void handleExpand(IModelDelta delta);
+
+ protected abstract void handleContent(IModelDelta delta);
+
+ protected abstract void handleRemove(IModelDelta delta);
+
+ protected abstract void handleAdd(IModelDelta delta);
+
+ protected abstract void handleInsert(IModelDelta delta);
+
+ protected abstract void handleReplace(IModelDelta delta);
+
+ protected void handleInstall(IModelDelta delta) {
+ installModelProxy(delta.getElement());
+ }
+
+ protected void handleUninstall(IModelDelta delta) {
+ disposeModelProxy(delta.getElement());
+ }
+
+ /**
+ * Returns a tree path for the node, *not* including the root element.
+ *
+ * @param node
+ * model delta
+ * @return corresponding tree path
+ */
+ protected TreePath getTreePath(IModelDelta node) {
+ ArrayList list = new ArrayList();
+ IModelDelta parentDelta = node.getParentDelta();
+ while (parentDelta != null) {
+ list.add(0, node.getElement());
+ node = parentDelta;
+ parentDelta = node.getParentDelta();
+ }
+ return new TreePath(list.toArray());
+ }
+
+ /**
+ * Returns the viewer this content provider is working for.
+ *
+ * @return viewer
+ */
+ protected Viewer getViewer() {
+ return fViewer;
+ }
+
+ protected void handlePresentationFailure(IAsynchronousRequestMonitor request, IStatus status) {
+ IWorkbenchPart part = getPresentationContext().getPart();
+ if (part instanceof AbstractDebugView) {
+ AbstractDebugView view = (AbstractDebugView) part;
+ view.showMessage(status.getMessage());
+ }
+ }
+
+
+ /**
+ * Translates and returns the given child index from the viewer coordinate
+ * space to the model coordinate space.
+ *
+ * @param parentPath path to parent element
+ * @param index index of child element in viewer (filtered) space
+ * @return index of child element in model (raw) space
+ */
+ public /* protected */ int viewToModelIndex(TreePath parentPath, int index) {
+ return fTransform.viewToModelIndex(parentPath, index);
+ }
+
+ /**
+ * Translates and returns the given child count from the viewer coordinate
+ * space to the model coordinate space.
+ *
+ * @param parentPath path to parent element
+ * @param count number of child elements in viewer (filtered) space
+ * @return number of child elements in model (raw) space
+ */
+ public /* protected */ int viewToModelCount(TreePath parentPath, int count) {
+ return fTransform.viewToModelCount(parentPath, count);
+ }
+
+ /**
+ * Translates and returns the given child index from the model coordinate
+ * space to the viewer coordinate space.
+ *
+ * @param parentPath path to parent element
+ * @param index index of child element in model (raw) space
+ * @return index of child element in viewer (filtered) space
+ */
+ protected int modelToViewIndex(TreePath parentPath, int index) {
+ return fTransform.modelToViewIndex(parentPath, index);
+ }
+
+ /**
+ * Translates and returns the given child count from the model coordinate
+ * space to the viewer coordinate space.
+ *
+ * @param parentPath path to parent element
+ * @param count child count element in model (raw) space
+ * @return child count in viewer (filtered) space
+ */
+ protected int modelToViewChildCount(TreePath parentPath, int count) {
+ return fTransform.modelToViewCount(parentPath, count);
+ }
+
+ /**
+ * Notes that the child at the specified index of the given parent element
+ * has been filtered from the viewer. Returns whether the child at the given
+ * index was already filtered.
+ *
+ * @param parentPath path to parent element
+ * @param index index of child element to be filtered
+ * @return whether the child was already filtered
+ */
+ protected boolean addFilteredIndex(TreePath parentPath, int index) {
+ return fTransform.addFilteredIndex(parentPath, index);
+ }
+
+ /**
+ * Returns whether the given element is filtered.
+ *
+ * @param parentElementOrTreePath
+ * the parent element or path
+ * @param element
+ * the child element
+ * @return whether to filter the element
+ */
+ protected boolean shouldFilter(Object parentElementOrTreePath, Object element) {
+ ViewerFilter[] filters = ((StructuredViewer)fViewer).getFilters();
+ if (filters.length > 0) {
+ for (int j = 0; j < filters.length; j++) {
+ if (!(filters[j].select(fViewer, parentElementOrTreePath, element))) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether the given index of the specified parent was previously filtered.
+ *
+ * @param parentPath
+ * @param index
+ * @return whether the element at the given index was filtered
+ */
+ protected boolean isFiltered(TreePath parentPath, int index) {
+ return fTransform.isFiltered(parentPath, index);
+ }
+
+ /**
+ * Notification that a structural refresh is occurring at the specified path
+ *
+ * @param path
+ */
+ protected void refreshingStructure(TreePath path) {
+ }
+
+ /**
+ * Notification the given element is being unmapped.
+ *
+ * @param path
+ */
+ protected void unmapPath(TreePath path) {
+ //System.out.println("Unmap " + path.getLastSegment());
+ fTransform.clear(path);
+ }
+
+ /**
+ * Return tree paths to the given element in the viewer or <code>null</code>
+ *
+ * @param element
+ * @return tree paths or <code>null</code>
+ */
+ protected TreePath[] getTreePaths(Object element) {
+ if (fViewer instanceof TreeModelViewer) {
+ TreeModelViewer tmv = (TreeModelViewer) fViewer;
+ return tmv.getTreePaths(element);
+ }
+ return null;
+ }
+
+ /**
+ * Returns filtered children or <code>null</code>
+ * @param parent
+ * @return filtered children or <code>null</code>
+ */
+ protected int[] getFilteredChildren(TreePath parent) {
+ return fTransform.getFilteredChildren(parent);
+ }
+
+ protected void clearFilteredChild(TreePath parent, int modelIndex) {
+ fTransform.clear(parent, modelIndex);
+ }
+
+ protected void clearFilters(TreePath parent) {
+ fTransform.clear(parent);
+ }
+
+ /**
+ * @param delta
+ */
+ void doRestore(final ModelDelta delta) {
+ if (delta.getFlags() != IModelDelta.NO_CHANGE) {
+ UIJob job = new UIJob("restore delta") { //$NON-NLS-1$
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ TreePath treePath = getTreePath(delta);
+ TreeModelViewer viewer = (TreeModelViewer)getViewer();
+ if ((delta.getFlags() & IModelDelta.EXPAND) != 0) {
+ viewer.expandToLevel(treePath, 1);
+ }
+ if ((delta.getFlags() & IModelDelta.SELECT) != 0) {
+ viewer.setSelection(new TreeSelection(treePath));
+ }
+ delta.setFlags(IModelDelta.NO_CHANGE);
+ checkIfRestoreComplete();
+ return Status.OK_STATUS;
+ }
+ };
+ job.setSystem(true);
+ job.schedule();
+ }
+ }
+
+ protected void checkIfRestoreComplete() {
+ CheckState state = new CheckState();
+ fPendingState.accept(state);
+ if (state.isComplete()) {
+ fPendingState = null;
+ //System.out.println("RESTORE COMPELTE");
+ }
+ }
+
+ void addViewerUpdateListener(IViewerUpdateListener listener) {
+ fUpdateListeners.add(listener);
+ }
+
+ void removeViewerUpdateListener(IViewerUpdateListener listener) {
+ fUpdateListeners.remove(listener);
+ }
+
+ /**
+ * Notification an update request has started
+ *
+ * @param update
+ */
+ void updateStarted(IAsynchronousRequestMonitor update) {
+ boolean begin = false;
+ synchronized (this) {
+ begin = fUpdateNestingCount == 0;
+ fUpdateNestingCount++;
+ }
+ if (begin) {
+ notifyUpdate(UPDATE_SEQUENCE_BEGINS, null);
+ }
+ notifyUpdate(UPDATE_BEGINS, update);
+ }
+
+ /**
+ * Notification an update request has completed
+ *
+ * @param update
+ */
+ void updateComplete(IAsynchronousRequestMonitor update) {
+ boolean end = false;
+ synchronized (this) {
+ fUpdateNestingCount--;
+ end = fUpdateNestingCount == 0;
+ }
+ notifyUpdate(UPDATE_COMPLETE, update);
+ if (end) {
+ notifyUpdate(UPDATE_SEQUENCE_COMPLETE, null);
+ }
+ }
+
+ protected void notifyUpdate(final int type, final IAsynchronousRequestMonitor update) {
+ if (!fUpdateListeners.isEmpty()) {
+ Object[] listeners = fUpdateListeners.getListeners();
+ for (int i = 0; i < listeners.length; i++) {
+ final IViewerUpdateListener listener = (IViewerUpdateListener) listeners[i];
+ SafeRunner.run(new ISafeRunnable() {
+ public void run() throws Exception {
+ switch (type) {
+ case UPDATE_SEQUENCE_BEGINS:
+ listener.viewerUpdatesBegin();
+ break;
+ case UPDATE_SEQUENCE_COMPLETE:
+ listener.viewerUpdatesComplete();
+ break;
+ case UPDATE_BEGINS:
+ listener.updateStarted(update);
+ break;
+ case UPDATE_COMPLETE:
+ listener.updateComplete(update);
+ break;
+ }
+ }
+ public void handleException(Throwable exception) {
+ DebugUIPlugin.log(exception);
+ }
+ });
+ }
+ }
+ }
+
+ /**
+ * Registers the given listener for model delta notification.
+ *
+ * @param listener model delta listener
+ */
+ void addModelChangedListener(IModelChangedListener listener) {
+ fModelListeners.add(listener);
+ Iterator proxies = fModelProxies.values().iterator();
+ while (proxies.hasNext()) {
+ IModelProxy proxy = (IModelProxy) proxies.next();
+ proxy.addModelChangedListener(listener);
+ }
+ }
+
+ /**
+ * Unregisters the given listener from model delta notification.
+ *
+ * @param listener model delta listener
+ */
+ void removeModelChangedListener(IModelChangedListener listener) {
+ fModelListeners.remove(listener);
+ Iterator proxies = fModelProxies.values().iterator();
+ while (proxies.hasNext()) {
+ IModelProxy proxy = (IModelProxy) proxies.next();
+ proxy.removeModelChangedListener(listener);
+ }
+ }
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/TreeModelContentProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/TreeModelContentProvider.java
new file mode 100644
index 000000000..92f810594
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/TreeModelContentProvider.java
@@ -0,0 +1,317 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.viewers;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.eclipse.debug.internal.ui.model.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.model.IElementContentProvider;
+import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.provisional.ModelDelta;
+import org.eclipse.jface.viewers.IBasicPropertyConstants;
+import org.eclipse.jface.viewers.ILazyTreeContentProvider;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.jface.viewers.TreeSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+
+/**
+ * Content provider for a virtual tree.
+ *
+ * @since 3.3
+ */
+class TreeModelContentProvider extends ModelContentProvider implements ILazyTreeContentProvider {
+
+ protected static final String[] STATE_PROPERTIES = new String[]{IBasicPropertyConstants.P_TEXT, IBasicPropertyConstants.P_IMAGE};
+
+ private Map fPendingChildRequests = new HashMap();
+ private Map fPendingCountRequests = new HashMap();
+
+ private Timer fTimer = new Timer();
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ILazyTreeContentProvider#getParent(java.lang.Object)
+ */
+ public Object getParent(Object element) {
+ return null;
+ }
+
+ /**
+ * Re-filters any filtered children of the given parent element.
+ *
+ * @param path parent element
+ */
+ protected void refilterChildren(TreePath path) {
+ if (getViewer() != null) {
+ int[] filteredChildren = getFilteredChildren(path);
+ if (filteredChildren != null) {
+ Object parent = getViewer().getInput();
+ if (path.getSegmentCount() > 0) {
+ parent = path.getLastSegment();
+ }
+ for (int i = 0; i < filteredChildren.length; i++) {
+ doUpdateElement(parent, path, filteredChildren[i]);
+ }
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ILazyTreeContentProvider#updateChildCount(java.lang.Object, int)
+ */
+ public synchronized void updateChildCount(Object element, int currentChildCount) {
+ //System.out.println("updateChildCount(" + element + ")");
+ TreePath[] treePaths = getTreePaths(element);
+ for (int i = 0; i < treePaths.length; i++) {
+ // re-filter children when asked to update the child count for an element (i.e.
+ // when refreshing, see if filtered children are still filtered)
+ refilterChildren(treePaths[i]);
+ }
+ doUpdateChildCount(element, currentChildCount);
+ }
+
+ protected synchronized void doUpdateChildCount(Object element, int currentChildCount) {
+ IElementContentProvider contentAdapter = getContentAdapter(element);
+ if (contentAdapter != null) {
+ ChildrenCountUpdate request = (ChildrenCountUpdate) fPendingCountRequests.get(contentAdapter);
+ if (request != null) {
+ if (request.coalesce(element)) {
+ return;
+ } else {
+ request.start();
+ }
+ }
+ final ChildrenCountUpdate newRequest = new ChildrenCountUpdate(this, contentAdapter);
+ newRequest.coalesce(element);
+ fPendingCountRequests.put(contentAdapter, newRequest);
+ fTimer.schedule(new TimerTask() {
+ public void run() {
+ newRequest.start();
+ }
+ }, 10L);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ILazyTreeContentProvider#updateElement(java.lang.Object, int)
+ */
+ public synchronized void updateElement(Object parent, int viewIndex) {
+ //System.out.println("updateElement(" + parent + ", " + viewIndex + ")");
+ TreePath[] paths = getTreePaths(parent);
+ if (paths.length > 0) {
+ TreePath path = paths[0]; // all children filter the same, per parent occurrence
+ int modelIndex = viewToModelIndex(path, viewIndex);
+ //System.out.println("updateElement("+ parent + ", " + viewIndex + ") > modelIndex = " + modelIndex);
+ doUpdateElement(parent, path, modelIndex);
+ }
+ }
+
+ protected synchronized void doUpdateElement(Object parent, TreePath parentPath, int modelIndex) {
+ ChildrenUpdate request = (ChildrenUpdate) fPendingChildRequests.get(parent);
+ if (request != null) {
+ if (request.coalesce(modelIndex)) {
+ return;
+ } else {
+ request.start();
+ }
+ }
+ IElementContentProvider contentAdapter = getContentAdapter(parent);
+ if (contentAdapter != null) {
+ final ChildrenUpdate newRequest = new ChildrenUpdate(this, parent, parentPath, modelIndex, contentAdapter);
+ fPendingChildRequests.put(parent, newRequest);
+ fTimer.schedule(new TimerTask() {
+ public void run() {
+ newRequest.start();
+ }
+ }, 10L);
+ }
+ }
+
+ protected synchronized void childRequestStarted(IChildrenUpdate update) {
+ fPendingChildRequests.remove(update.getParent());
+ }
+
+ protected synchronized void countRequestStarted(Object key) {
+ fPendingCountRequests.remove(key);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.viewers.ModelContentProvider#getPresentationContext()
+ */
+ protected IPresentationContext getPresentationContext() {
+ return ((TreeModelViewer)getViewer()).getPresentationContext();
+ }
+
+ /**
+ * Returns the tree viewer this content provider is working for
+ *
+ * @return tree viewer
+ */
+ protected TreeViewer getTreeViewer() {
+ return (TreeViewer)getViewer();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.viewers.ModelContentProvider#handleAdd(org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta)
+ */
+ protected void handleAdd(IModelDelta delta) {
+ doUpdateChildCount(delta.getParentDelta().getElement(), 0);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.viewers.ModelContentProvider#handleContent(org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta)
+ */
+ protected void handleContent(IModelDelta delta) {
+ getTreeViewer().refresh(delta.getElement());
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.viewers.ModelContentProvider#handleExpand(org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta)
+ */
+ protected void handleExpand(IModelDelta delta) {
+ // expand each parent, then this node
+ IModelDelta parentDelta = delta.getParentDelta();
+ if (parentDelta != null) {
+ handleExpand(parentDelta);
+ expand(delta);
+ }
+ }
+
+ protected void expand(IModelDelta delta) {
+ int childCount = delta.getChildCount();
+ int index = delta.getIndex();
+ TreeViewer treeViewer = getTreeViewer();
+ if (index >= 0) {
+ treeViewer.replace(delta.getParentDelta().getElement(), index, delta.getElement());
+ }
+ if (childCount > 0) {
+ treeViewer.setChildCount(delta.getElement(), childCount);
+ treeViewer.expandToLevel(getTreePath(delta), 1);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.viewers.ModelContentProvider#handleInsert(org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta)
+ */
+ protected void handleInsert(IModelDelta delta) {
+ // TODO: filters
+ getTreeViewer().insert(getTreePath(delta.getParentDelta()), delta.getElement(), delta.getIndex());
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.viewers.ModelContentProvider#handleRemove(org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta)
+ */
+ protected void handleRemove(IModelDelta delta) {
+ // refresh the parent to properly update for non-visible children
+ getTreeViewer().refresh(delta.getParentDelta().getElement());
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.viewers.ModelContentProvider#handleReplace(org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta)
+ */
+ protected void handleReplace(IModelDelta delta) {
+ getTreeViewer().replace(delta.getParentDelta().getElement(), delta.getIndex(), delta.getElement());
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.viewers.ModelContentProvider#handleSelect(org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta)
+ */
+ protected void handleSelect(IModelDelta delta) {
+ int index = delta.getIndex();
+ TreeViewer treeViewer = getTreeViewer();
+ if (index >= 0) {
+ treeViewer.replace(delta.getParentDelta().getElement(), index, delta.getElement());
+ }
+ treeViewer.setSelection(new TreeSelection(getTreePath(delta)));
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.viewers.ModelContentProvider#handleState(org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta)
+ */
+ protected void handleState(IModelDelta delta) {
+ getTreeViewer().update(delta.getElement(), STATE_PROPERTIES);
+ }
+
+ public synchronized void dispose() {
+ fTimer.cancel();
+ fPendingChildRequests.clear();
+ fPendingCountRequests.clear();
+ super.dispose();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.viewers.ModelContentProvider#buildViewerState(org.eclipse.debug.internal.ui.viewers.provisional.ModelDelta)
+ */
+ protected void buildViewerState(ModelDelta delta) {
+ Tree tree = (Tree) getViewer().getControl();
+ TreeItem[] selection = tree.getSelection();
+ Set set = new HashSet();
+ for (int i = 0; i < selection.length; i++) {
+ set.add(selection[i]);
+ }
+ TreeItem[] items = tree.getItems();
+ for (int i = 0; i < items.length; i++) {
+ buildViewerState(delta, items[i], set);
+ }
+ }
+
+ /**
+ * @param delta parent delta to build on
+ * @param item item
+ * @param set set of selected tree items
+ */
+ private void buildViewerState(ModelDelta delta, TreeItem item, Set set) {
+ Object element = item.getData();
+ if (element != null) {
+ boolean expanded = item.getExpanded();
+ boolean selected = set.contains(item);
+ if (expanded || selected) {
+ int flags = IModelDelta.NO_CHANGE;
+ if (expanded) {
+ flags = flags | IModelDelta.EXPAND;
+ }
+ if (selected) {
+ flags = flags | IModelDelta.SELECT;
+ }
+ ModelDelta childDelta = delta.addNode(element, flags);
+ if (expanded) {
+ TreeItem[] items = item.getItems();
+ for (int i = 0; i < items.length; i++) {
+ buildViewerState(childDelta, items[i], set);
+ }
+ }
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.viewers.ModelContentProvider#doInitialRestore()
+ */
+ protected void doInitialRestore() {
+ Tree tree = (Tree) getViewer().getControl();
+ TreeItem[] items = tree.getItems();
+ for (int i = 0; i < items.length; i++) {
+ TreeItem item = items[i];
+ Object data = item.getData();
+ if (data != null) {
+ doRestore(new TreePath(new Object[]{data}));
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/TreeModelLabelProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/TreeModelLabelProvider.java
new file mode 100644
index 000000000..68a9365e9
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/TreeModelLabelProvider.java
@@ -0,0 +1,237 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.viewers;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.internal.ui.model.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.model.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ViewerCell;
+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.Display;
+import org.eclipse.ui.progress.UIJob;
+
+/**
+ * @since 3.3
+ */
+class TreeModelLabelProvider extends ColumnLabelProvider {
+
+ private TreeModelViewer fViewer;
+ private List fComplete;
+
+ /**
+ * Cache of images used for elements in this label provider. Label updates
+ * use the method <code>getImage(...)</code> to cache images for
+ * image descriptors. The images are disposed with this label provider.
+ */
+ private Map fImageCache = new HashMap();
+
+ /**
+ * Cache of the fonts used for elements in this label provider. Label updates
+ * use the method <code>getFont(...)</code> to cache fonts for
+ * FontData objects. The fonts are disposed with this label provider.
+ */
+ private Map fFontCache = new HashMap();
+
+ /**
+ * Cache of the colors used for elements in this label provider. Label updates
+ * use the method <code>getColor(...)</code> to cache colors for
+ * RGB values. The colors are disposed with this label provider.
+ */
+ private Map fColorCache = new HashMap();
+
+ /**
+ * Constructs a new label provider on the given display
+ */
+ public TreeModelLabelProvider(TreeModelViewer viewer) {
+ fViewer = viewer;
+ }
+
+ /**
+ * 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.
+ *
+ * @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(getDisplay(), descriptor.getImageData());
+ fImageCache.put(descriptor, image);
+ }
+ return image;
+ }
+
+ /**
+ * Returns the display to use for resource allocation.
+ *
+ * @return display
+ */
+ private Display getDisplay() {
+ return fViewer.getControl().getDisplay();
+ }
+
+ /**
+ * Returns a font for the given font data or <code>null</code>. Adds the font to the font
+ * cache if not yet created.
+ *
+ * @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(getDisplay(), fontData);
+ fFontCache.put(fontData, font);
+ }
+ return font;
+ }
+
+ /**
+ * Returns a color for the given RGB or <code>null</code>. Adds the color to the color
+ * cache if not yet created.
+ *
+ * @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(getDisplay(), rgb);
+ fColorCache.put(rgb, color);
+ }
+ return color;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.BaseLabelProvider#dispose()
+ */
+ public 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();
+
+ super.dispose();
+ }
+
+ public synchronized void update(ViewerCell cell) {
+ String[] visibleColumns = fViewer.getVisibleColumns();
+ Object element = cell.getElement();
+ String columnId = null;
+ if (visibleColumns != null) {
+ columnId = visibleColumns[cell.getColumnIndex()];
+ }
+ IElementLabelProvider presentation = getLabelAdapter(element);
+ if (presentation != null) {
+ presentation.update(new LabelUpdate(element, this, columnId, cell.getColumnIndex()));
+ } else if (element instanceof String) {
+ // for example, expression error messages
+ cell.setText((String)element);
+ }
+ }
+
+ /**
+ * Returns the presentation context for this label provider.
+ *
+ * @return presentation context
+ */
+ protected IPresentationContext getPresentationContext() {
+ return fViewer.getPresentationContext();
+ }
+
+ /**
+ * Returns the label provider for the given element or
+ * <code>null</code> if none.
+ *
+ * @param element
+ * element to retrieve adapter for
+ * @return label adapter or <code>null</code>
+ */
+ protected IElementLabelProvider getLabelAdapter(Object element) {
+ IElementLabelProvider adapter = null;
+ if (element instanceof IElementLabelProvider) {
+ adapter = (IElementLabelProvider) element;
+ } else if (element instanceof IAdaptable) {
+ IAdaptable adaptable = (IAdaptable) element;
+ adapter = (IElementLabelProvider) adaptable.getAdapter(IElementLabelProvider.class);
+ }
+ return adapter;
+ }
+
+ /**
+ * A label update is complete.
+ *
+ * @param update
+ */
+ protected synchronized void complete(ILabelUpdate update) {
+ if (fComplete == null) {
+ fComplete = new ArrayList();
+ UIJob job = new UIJob(getDisplay(), "Label Updates") { //$NON-NLS-1$
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ LabelUpdate[] updates = null;
+ synchronized (TreeModelLabelProvider.this) {
+ updates = (LabelUpdate[]) fComplete.toArray(new LabelUpdate[fComplete.size()]);
+ fComplete = null;
+ }
+ //System.out.println("Changed Labels: " + updates.length);
+ fViewer.apply(updates);
+ return Status.OK_STATUS;
+ }
+ };
+ job.setSystem(true);
+ job.schedule(10L);
+ }
+ fComplete.add(update);
+ }
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/TreeModelViewer.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/TreeModelViewer.java
new file mode 100644
index 000000000..5660c15cf
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/TreeModelViewer.java
@@ -0,0 +1,998 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.viewers;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.debug.internal.ui.viewers.PresentationContext;
+import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditor;
+import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditorFactoryAdapter;
+import org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation;
+import org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentationFactoryAdapter;
+import org.eclipse.debug.internal.ui.viewers.provisional.IModelChangedListener;
+import org.eclipse.debug.internal.ui.viewers.provisional.IModelSelectionPolicy;
+import org.eclipse.debug.internal.ui.viewers.provisional.IModelSelectionPolicyFactoryAdapter;
+import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.ICellModifier;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.ViewerRow;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.ControlListener;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.swt.widgets.Widget;
+import org.eclipse.ui.IMemento;
+
+/**
+ * A tree viewer that displays a model.
+ *
+ * @since 3.3
+ */
+public class TreeModelViewer extends TreeViewer {
+
+ private IPresentationContext fContext;
+
+ /**
+ * Current column presentation or <code>null</code>
+ */
+ private IColumnPresentation fColumnPresentation = null;
+
+ /**
+ * Map of columns presentation id to its visible columns id's (String[])
+ * When a columns presentation is not in the map, default settings are used.
+ */
+ private Map fVisibleColumns = new HashMap();
+
+ /**
+ * Map of column id's to persisted sizes
+ */
+ private Map fColumnSizes = new HashMap();
+
+ /**
+ * Map of column presentation id's to an array of integers representing the column order
+ * for that presentation, or <code>null</code> if default.
+ */
+ private Map fColumnOrder = new HashMap();
+
+ /**
+ * Map of column presentation id to whether columns should be displayed
+ * for that presentation (the user can toggle columns on/off when a
+ * presentation is optional.
+ */
+ private Map fShowColumns = new HashMap();
+
+ /**
+ * Item's tree path cache
+ */
+ private static final String TREE_PATH_KEY = "TREE_PATH_KEY"; //$NON-NLS-1$
+
+ /**
+ * Memento type for column sizes. Sizes are keyed by column presentation id
+ */
+ private static final String COLUMN_SIZES = "COLUMN_SIZES"; //$NON-NLS-1$
+ /**
+ * Memento type for the column order for a presentation context.
+ * A memento is created for each column presentation
+ */
+ private static final String COLUMN_ORDER = "COLUMN_ORDER"; //$NON-NLS-1$
+ /**
+ * Memento type for the visible columns for a presentation context.
+ * A memento is created for each column presentation keyed by column number
+ */
+ private static final String VISIBLE_COLUMNS = "VISIBLE_COLUMNS"; //$NON-NLS-1$
+ /**
+ * Memento type for whether columns are visible for a presentation context.
+ * Booleans are keyed by column presentation id
+ */
+ private static final String SHOW_COLUMNS = "SHOW_COLUMNS"; //$NON-NLS-1$
+ /**
+ * Memento key for the number of visible columns in a VISIBLE_COLUMNS memento
+ * or for the width of a column
+ */
+ private static final String SIZE = "SIZE"; //$NON-NLS-1$
+ /**
+ * Memento key prefix a visible column
+ */
+ private static final String COLUMN = "COLUMN"; //$NON-NLS-1$
+
+ /**
+ * True while performing an insert... we allow insert with filters
+ */
+ private boolean fInserting = false;
+
+ /**
+ * Persist column sizes when they change.
+ *
+ * @since 3.2
+ */
+ class ColumnListener implements ControlListener {
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.events.ControlListener#controlMoved(org.eclipse.swt.events.ControlEvent)
+ */
+ public void controlMoved(ControlEvent e) {
+ persistColumnOrder();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.events.ControlListener#controlResized(org.eclipse.swt.events.ControlEvent)
+ */
+ public void controlResized(ControlEvent e) {
+ persistColumnSizes();
+ }
+ }
+
+ private ColumnListener fListener = new ColumnListener();
+
+ /**
+ * Proxy to cell modifier/editor support
+ */
+ class CellModifierProxy implements ICellModifier {
+
+ private IColumnEditor fColumnEditor = null;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ICellModifier#canModify(java.lang.Object, java.lang.String)
+ */
+ public boolean canModify(Object element, String property) {
+ updateColumnEditor(element);
+ if (fColumnEditor != null) {
+ boolean canModify = fColumnEditor.getCellModifier().canModify(element, property);
+ if (canModify) {
+ // install cell editor
+ CellEditor cellEditor = fColumnEditor.getCellEditor(property, element, (Composite)getControl());
+ if (cellEditor == null) {
+ // contradiction, oh well
+ return false;
+ }
+ disposeCellEditors();
+ CellEditor[] newEditors = new CellEditor[getVisibleColumns().length];
+ for (int i = 0; i < newEditors.length; i++) {
+ newEditors[i] = cellEditor;
+ }
+ setCellEditors(newEditors);
+ }
+ return canModify;
+ }
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ICellModifier#getValue(java.lang.Object, java.lang.String)
+ */
+ public Object getValue(Object element, String property) {
+ if (fColumnEditor != null) {
+ return fColumnEditor.getCellModifier().getValue(element, property);
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ICellModifier#modify(java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public void modify(Object element, String property, Object value) {
+ if (fColumnEditor != null) {
+ if (element instanceof Item) {
+ element = ((Item)element).getData();
+ }
+ fColumnEditor.getCellModifier().modify(element, property, value);
+ }
+ }
+
+ /**
+ * Disposes client's column editor and cell editors
+ */
+ protected void dispose() {
+ disposeCellEditors();
+ setCellEditors(null);
+ if (fColumnEditor != null) {
+ fColumnEditor.dispose();
+ }
+ }
+
+ /**
+ * Disposes current cell editors
+ */
+ protected void disposeCellEditors() {
+ CellEditor[] cellEditors = getCellEditors();
+ if (cellEditors != null) {
+ for (int i = 0; i < cellEditors.length; i++) {
+ CellEditor editor = cellEditors[i];
+ if (editor != null) {
+ editor.dispose();
+ }
+ }
+ }
+ }
+
+ /**
+ * Sets the column editor for the given element
+ *
+ * @param element
+ */
+ protected void updateColumnEditor(Object element) {
+ IColumnEditorFactoryAdapter factoryAdapter = getColumnEditorFactoryAdapter(element);
+ if (factoryAdapter != null) {
+ if (fColumnEditor != null) {
+ if (fColumnEditor.getId().equals(factoryAdapter.getColumnEditorId(getPresentationContext(), element))) {
+ // no change
+ return;
+ } else {
+ // dispose current
+ fColumnEditor.dispose();
+ }
+ }
+ // create new one
+ fColumnEditor = factoryAdapter.createColumnEditor(getPresentationContext(), element);
+ if (fColumnEditor != null) {
+ fColumnEditor.init(getPresentationContext());
+ }
+ } else {
+ // no editor - dispose current
+ if (fColumnEditor != null) {
+ fColumnEditor.dispose();
+ fColumnEditor = null;
+ }
+ }
+ }
+
+ /**
+ * Returns the column editor factory for the given element or <code>null</code>.
+ *
+ * @param input
+ * @return column editor factory of <code>null</code>
+ */
+ protected IColumnEditorFactoryAdapter getColumnEditorFactoryAdapter(Object input) {
+ if (input instanceof IColumnEditorFactoryAdapter) {
+ return (IColumnEditorFactoryAdapter) input;
+ }
+ if (input instanceof IAdaptable) {
+ IAdaptable adaptable = (IAdaptable) input;
+ return (IColumnEditorFactoryAdapter) adaptable.getAdapter(IColumnEditorFactoryAdapter.class);
+ }
+ return null;
+ }
+ }
+
+ private CellModifierProxy fCellModifier;
+
+ /**
+ * @param parent
+ * @param style
+ */
+ public TreeModelViewer(Composite parent, int style, IPresentationContext context) {
+ super(parent, style);
+ if ((style & SWT.VIRTUAL) == 0) {
+ throw new IllegalArgumentException("style must include SWT.VIRTUAL"); //$NON-NLS-1$
+ }
+ setUseHashlookup(true);
+ fCellModifier = new CellModifierProxy();
+ fContext = context;
+ setContentProvider(new TreeModelContentProvider());
+ setLabelProvider(new TreeModelLabelProvider(this));
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ContentViewer#handleDispose(org.eclipse.swt.events.DisposeEvent)
+ */
+ protected void handleDispose(DisposeEvent event) {
+ if (fColumnPresentation != null) {
+ fColumnPresentation.dispose();
+ }
+ fCellModifier.dispose();
+ super.handleDispose(event);
+ }
+
+ /**
+ * Returns this viewer's presentation context or <code>null</code> if none.
+ *
+ * @return presentation context or <code>null</code>
+ */
+ public IPresentationContext getPresentationContext() {
+ return fContext;
+ }
+
+ /* (non-Javadoc)
+ *
+ * Clear filters when refreshing an element structurally.
+ *
+ * @see org.eclipse.jface.viewers.AbstractTreeViewer#internalRefresh(org.eclipse.swt.widgets.Widget, java.lang.Object, boolean, boolean)
+ */
+ protected void internalRefresh(Widget widget, Object element, boolean doStruct, boolean updateLabels) {
+ if (doStruct) {
+ IContentProvider provider = getContentProvider();
+ if (provider instanceof ModelContentProvider) {
+ ModelContentProvider mcp = (ModelContentProvider) provider;
+ if (widget instanceof TreeItem) {
+ mcp.refreshingStructure(getTreePathFromItem((TreeItem)widget));
+ } else {
+ mcp.refreshingStructure(ModelContentProvider.EMPTY_TREE_PATH);
+ }
+ }
+ }
+ super.internalRefresh(widget, element, doStruct, updateLabels);
+ }
+
+ protected void unmapElement(Object element, Widget widget) {
+ IContentProvider provider = getContentProvider();
+ if (provider instanceof ModelContentProvider) {
+ ((ModelContentProvider) provider).unmapPath((TreePath) widget.getData(TREE_PATH_KEY));
+ }
+ super.unmapElement(element, widget);
+ }
+
+ /* (non-Javadoc)
+ *
+ * We need tree paths when disposed/unmapped in any order so cache the tree path.
+ *
+ * @see org.eclipse.jface.viewers.TreeViewer#mapElement(java.lang.Object, org.eclipse.swt.widgets.Widget)
+ */
+ protected void mapElement(Object element, Widget widget) {
+ super.mapElement(element, widget);
+ if (widget instanceof Item) {
+ widget.setData(TREE_PATH_KEY, getTreePathFromItem((Item)widget));
+ } else {
+ widget.setData(TREE_PATH_KEY, ModelContentProvider.EMPTY_TREE_PATH);
+ }
+ }
+
+
+ protected TreePath[] getTreePaths(Object element) {
+ Widget[] widgets = findItems(element);
+ TreePath[] paths = new TreePath[widgets.length];
+ for (int i = 0; i < widgets.length; i++) {
+ TreePath path = (TreePath) widgets[i].getData(TREE_PATH_KEY);
+ if (path == null) {
+ if (widgets[i] instanceof Item) {
+ path = getTreePathFromItem((Item)widgets[i]);
+ } else {
+ path = ModelContentProvider.EMPTY_TREE_PATH;
+ }
+ }
+ paths[i] = path;
+ }
+ return paths;
+ }
+
+ /* (non-Javadoc)
+ *
+ * Override because we allow inserting with filters present.
+ *
+ * @see org.eclipse.jface.viewers.AbstractTreeViewer#insert(java.lang.Object, java.lang.Object, int)
+ */
+ public void insert(Object parentElementOrTreePath, Object element, int position) {
+ try {
+ fInserting = true;
+ super.insert(parentElementOrTreePath, element, position);
+ } finally {
+ fInserting = false;
+ }
+ }
+
+ /* (non-Javadoc)
+ *
+ * Override because we allow inserting with filters present.
+ *
+ * @see org.eclipse.jface.viewers.StructuredViewer#hasFilters()
+ */
+ protected boolean hasFilters() {
+ if (fInserting) {
+ return false;
+ }
+ return super.hasFilters();
+ }
+
+ /**
+ * Removes the element at the specified index of the parent.
+ *
+ * @param parent parent element
+ * @param index child index
+ */
+ public void remove(final Object parent, final int index) {
+ preservingSelection(new Runnable() {
+ public void run() {
+ if (parent.equals(getInput())) {
+ Tree tree = (Tree) getControl();
+ if (index < tree.getItemCount()) {
+ TreeItem item = tree.getItem(index);
+ Object element = item.getData();
+ if (element != null) {
+ unmapElement(element, item);
+ }
+ item.dispose();
+ }
+ } else {
+ Widget[] parentItems = findItems(parent);
+ for (int i = 0; i < parentItems.length; i++) {
+ TreeItem parentItem = (TreeItem) parentItems[i];
+ if (index < parentItem.getItemCount()) {
+ TreeItem item = parentItem.getItem(index);
+ Object element = item.getData();
+ if (element != null) {
+ unmapElement(element, item);
+ }
+ item.dispose();
+ }
+ }
+ }
+ }
+ });
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.AbstractTreeViewer#inputChanged(java.lang.Object, java.lang.Object)
+ */
+ protected void inputChanged(Object input, Object oldInput) {
+ super.inputChanged(input, oldInput);
+ resetColumns(input);
+ }
+
+ /**
+ * Configures the columns for the given viewer input.
+ *
+ * @param input
+ */
+ protected void resetColumns(Object input) {
+ if (input != null) {
+ // only change columns if the input is non-null (persist when empty)
+ IColumnPresentationFactoryAdapter factory = getColumnPresenetationFactoryAdapter(input);
+ PresentationContext context = (PresentationContext) getPresentationContext();
+ String type = null;
+ if (factory != null) {
+ type = factory.getColumnPresentationId(context, input);
+ }
+ if (type != null) {
+ if (fColumnPresentation != null) {
+ if (!fColumnPresentation.getId().equals(type)) {
+ // dispose old, create new
+ fColumnPresentation.dispose();
+ fColumnPresentation = null;
+ }
+ }
+ if (fColumnPresentation == null) {
+ fColumnPresentation = factory.createColumnPresentation(context, input);
+ if (fColumnPresentation != null) {
+ fColumnPresentation.init(context);
+ configureColumns();
+ }
+ }
+ } else {
+ if (fColumnPresentation != null) {
+ fColumnPresentation.dispose();
+ fColumnPresentation = null;
+ configureColumns();
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the column presentation factory for the given element or <code>null</code>.
+ *
+ * @param input
+ * @return column presentation factory of <code>null</code>
+ */
+ protected IColumnPresentationFactoryAdapter getColumnPresenetationFactoryAdapter(Object input) {
+ if (input instanceof IColumnPresentationFactoryAdapter) {
+ return (IColumnPresentationFactoryAdapter) input;
+ }
+ if (input instanceof IAdaptable) {
+ IAdaptable adaptable = (IAdaptable) input;
+ return (IColumnPresentationFactoryAdapter) adaptable.getAdapter(IColumnPresentationFactoryAdapter.class);
+ }
+ return null;
+ }
+
+ /**
+ * Configures the columns based on the current settings.
+ *
+ * @param input
+ */
+ protected void configureColumns() {
+ if (fColumnPresentation != null) {
+ IColumnPresentation build = null;
+ if (isShowColumns(fColumnPresentation.getId())) {
+ build = fColumnPresentation;
+ }
+ buildColumns(build);
+ } else {
+ // get rid of columns
+ buildColumns(null);
+ }
+ }
+
+ /**
+ * Toggles columns on/off for the current column presentation, if any.
+ *
+ * @param show whether to show columns if the current input supports
+ * columns
+ */
+ public void setShowColumns(boolean show) {
+ if (show) {
+ if (!isShowColumns()) {
+ fShowColumns.remove(fColumnPresentation.getId());
+ }
+ } else {
+ if (isShowColumns()){
+ fShowColumns.put(fColumnPresentation.getId(), Boolean.FALSE);
+ }
+ }
+ refreshColumns();
+ }
+
+ /**
+ * Resets any persisted column size for the given columns
+ */
+ public void resetColumnSizes(String[] columnIds) {
+ for (int i = 0; i < columnIds.length; i++) {
+ fColumnSizes.remove(columnIds[i]);
+ }
+ }
+
+ /**
+ * Sets the id's of visible columns, or <code>null</code> to set default columns.
+ * Only effects the current column presentation.
+ *
+ * @param ids visible columns
+ */
+ public void setVisibleColumns(String[] ids) {
+ IColumnPresentation presentation = getColumnPresentation();
+ if (presentation != null) {
+ fColumnOrder.remove(presentation.getId());
+ fVisibleColumns.remove(presentation.getId());
+ if (ids != null) {
+ // put back in table if not default
+ String[] columns = presentation.getInitialColumns();
+ if (columns.length == ids.length) {
+ for (int i = 0; i < columns.length; i++) {
+ if (!ids[i].equals(columns[i])) {
+ fVisibleColumns.put(presentation.getId(), ids);
+ break;
+ }
+ }
+ } else {
+ fVisibleColumns.put(presentation.getId(), ids);
+ }
+ }
+ PresentationContext presentationContext = (PresentationContext) getPresentationContext();
+ presentationContext.setColumns(getVisibleColumns());
+ refreshColumns();
+ }
+ }
+
+ /**
+ * Refreshes the columns in the view, based on the viewer input.
+ */
+ public void refreshColumns() {
+ configureColumns();
+ refresh();
+ }
+
+ /**
+ * Returns whether columns are being displayed currently.
+ *
+ * @return
+ */
+ public boolean isShowColumns() {
+ if (fColumnPresentation != null) {
+ return isShowColumns(fColumnPresentation.getId());
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether columns can be toggled on/off for the current input.
+ *
+ * @return whether columns can be toggled on/off for the current input
+ */
+ public boolean canToggleColumns() {
+ return fColumnPresentation != null && fColumnPresentation.isOptional();
+ }
+
+ protected boolean isShowColumns(String columnPresentationId) {
+ Boolean bool = (Boolean) fShowColumns.get(columnPresentationId);
+ if (bool == null) {
+ return true;
+ }
+ return bool.booleanValue();
+ }
+
+ /**
+ * Creates new columns for the given presentation.
+ *
+ * TODO: does this need to be async?
+ *
+ * @param presentation
+ */
+ protected void buildColumns(IColumnPresentation presentation) {
+ // dispose current columns, persisting their weights
+ Tree tree = getTree();
+ final TreeColumn[] columns = tree.getColumns();
+ String[] visibleColumnIds = getVisibleColumns();
+ for (int i = 0; i < columns.length; i++) {
+ TreeColumn treeColumn = columns[i];
+ treeColumn.removeControlListener(fListener);
+ treeColumn.dispose();
+ }
+ PresentationContext presentationContext = (PresentationContext) getPresentationContext();
+ if (presentation != null) {
+ for (int i = 0; i < visibleColumnIds.length; i++) {
+ String id = visibleColumnIds[i];
+ String header = presentation.getHeader(id);
+ // TODO: allow client to specify style
+ TreeColumn column = new TreeColumn(tree, SWT.LEFT, i);
+ column.setMoveable(true);
+ column.setText(header);
+ column.setWidth(1);
+ ImageDescriptor image = presentation.getImageDescriptor(id);
+ if (image != null) {
+ column.setImage(((TreeModelLabelProvider)getLabelProvider()).getImage(image));
+ }
+ column.setData(id);
+ }
+ int[] order = (int[]) fColumnOrder.get(presentation.getId());
+ if (order != null) {
+ tree.setColumnOrder(order);
+ }
+ tree.setHeaderVisible(true);
+ tree.setLinesVisible(true);
+ presentationContext.setColumns(getVisibleColumns());
+ setColumnProperties(getVisibleColumns());
+ setCellModifier(fCellModifier);
+ } else {
+ tree.setHeaderVisible(false);
+ tree.setLinesVisible(false);
+ presentationContext.setColumns(null);
+ setCellModifier(null);
+ setColumnProperties(null);
+ }
+
+
+ int avg = tree.getSize().x;
+ if (visibleColumnIds != null)
+ avg /= visibleColumnIds.length;
+
+ if (avg == 0) {
+ tree.addPaintListener(new PaintListener() {
+ public void paintControl(PaintEvent e) {
+ Tree tree2 = getTree();
+ String[] visibleColumns = getVisibleColumns();
+ if (visibleColumns != null) {
+ int avg1 = tree2.getSize().x / visibleColumns.length;
+ initColumns(avg1);
+ }
+ tree2.removePaintListener(this);
+ }
+ });
+ } else {
+ initColumns(avg);
+ }
+ }
+
+ private void initColumns(int widthHint) {
+ TreeColumn[] columns = getTree().getColumns();
+ for (int i = 0; i < columns.length; i++) {
+ TreeColumn treeColumn = columns[i];
+ Integer width = (Integer) fColumnSizes.get(treeColumn.getData());
+ if (width == null) {
+ treeColumn.setWidth(widthHint);
+ } else {
+ treeColumn.setWidth(width.intValue());
+ }
+ treeColumn.addControlListener(fListener);
+ }
+ }
+
+ /**
+ * Returns the current column presentation for this viewer, or <code>null</code>
+ * if none.
+ *
+ * @return column presentation or <code>null</code>
+ */
+ public IColumnPresentation getColumnPresentation() {
+ return fColumnPresentation;
+ }
+
+ /**
+ * Returns identifiers of the visible columns in this viewer, or <code>null</code>
+ * if there is currently no column presentation.
+ *
+ * @return visible columns or <code>null</code>
+ */
+ public String[] getVisibleColumns() {
+ if (isShowColumns()) {
+ IColumnPresentation presentation = getColumnPresentation();
+ if (presentation != null) {
+ String[] columns = (String[]) fVisibleColumns.get(presentation.getId());
+ if (columns == null) {
+ return presentation.getInitialColumns();
+ }
+ return columns;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Persists column sizes in cache
+ */
+ protected void persistColumnSizes() {
+ Tree tree = getTree();
+ TreeColumn[] columns = tree.getColumns();
+ for (int i = 0; i < columns.length; i++) {
+ TreeColumn treeColumn = columns[i];
+ Object id = treeColumn.getData();
+ fColumnSizes.put(id, new Integer(treeColumn.getWidth()));
+ }
+ }
+
+ /**
+ * Persists column ordering
+ */
+ protected void persistColumnOrder() {
+ IColumnPresentation presentation = getColumnPresentation();
+ if (presentation != null) {
+ Tree tree = getTree();
+ int[] order = tree.getColumnOrder();
+ if (order.length > 0) {
+ for (int i = 0; i < order.length; i++) {
+ if (i != order[i]) {
+ // non default order
+ fColumnOrder.put(presentation.getId(), order);
+ return;
+ }
+ }
+ }
+ // default order
+ fColumnOrder.remove(presentation.getId());
+ }
+ }
+
+ /**
+ * Save viewer state into the given memento.
+ *
+ * @param memento
+ */
+ public void saveState(IMemento memento) {
+ if (!fColumnSizes.isEmpty()) {
+ Iterator iterator = fColumnSizes.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Map.Entry entry = (Entry) iterator.next();
+ IMemento sizes = memento.createChild(COLUMN_SIZES, (String)entry.getKey());
+ sizes.putInteger(SIZE, ((Integer)entry.getValue()).intValue());
+ }
+ }
+ if (!fShowColumns.isEmpty()) {
+ Iterator iterator = fShowColumns.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Map.Entry entry = (Entry) iterator.next();
+ IMemento sizes = memento.createChild(SHOW_COLUMNS, (String)entry.getKey());
+ sizes.putString(SHOW_COLUMNS, ((Boolean)entry.getValue()).toString());
+ }
+ }
+ if (!fVisibleColumns.isEmpty()) {
+ Iterator iterator = fVisibleColumns.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Map.Entry entry = (Entry) iterator.next();
+ String id = (String) entry.getKey();
+ IMemento visible = memento.createChild(VISIBLE_COLUMNS, id);
+ String[] columns = (String[]) entry.getValue();
+ visible.putInteger(SIZE, columns.length);
+ for (int i = 0; i < columns.length; i++) {
+ visible.putString(COLUMN+Integer.toString(i), columns[i]);
+ }
+ }
+ }
+ if (!fColumnOrder.isEmpty()) {
+ Iterator iterator = fColumnOrder.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Map.Entry entry = (Entry) iterator.next();
+ String id = (String) entry.getKey();
+ IMemento orderMemento = memento.createChild(COLUMN_ORDER, id);
+ int[] order = (int[]) entry.getValue();
+ orderMemento.putInteger(SIZE, order.length);
+ for (int i = 0; i < order.length; i++) {
+ orderMemento.putInteger(COLUMN+Integer.toString(i), order[i]);
+ }
+ }
+ }
+ }
+
+ /**
+ * Initializes viewer state from the memento
+ *
+ * @param memento
+ */
+ public void initState(IMemento memento) {
+ IMemento[] mementos = memento.getChildren(COLUMN_SIZES);
+ for (int i = 0; i < mementos.length; i++) {
+ IMemento child = mementos[i];
+ String id = child.getID();
+ Integer size = child.getInteger(SIZE);
+ if (size != null) {
+ fColumnSizes.put(id, size);
+ }
+ }
+ mementos = memento.getChildren(SHOW_COLUMNS);
+ for (int i = 0; i < mementos.length; i++) {
+ IMemento child = mementos[i];
+ String id = child.getID();
+ Boolean bool = Boolean.valueOf(child.getString(SHOW_COLUMNS));
+ if (!bool.booleanValue()) {
+ fShowColumns.put(id, bool);
+ }
+ }
+ mementos = memento.getChildren(VISIBLE_COLUMNS);
+ for (int i = 0; i < mementos.length; i++) {
+ IMemento child = mementos[i];
+ String id = child.getID();
+ Integer integer = child.getInteger(SIZE);
+ if (integer != null) {
+ int length = integer.intValue();
+ String[] columns = new String[length];
+ for (int j = 0; j < length; j++) {
+ columns[j] = child.getString(COLUMN+Integer.toString(j));
+ }
+ fVisibleColumns.put(id, columns);
+ }
+ }
+ mementos = memento.getChildren(COLUMN_ORDER);
+ for (int i = 0; i < mementos.length; i++) {
+ IMemento child = mementos[i];
+ String id = child.getID();
+ Integer integer = child.getInteger(SIZE);
+ if (integer != null) {
+ int length = integer.intValue();
+ int[] order = new int[length];
+ for (int j = 0; j < length; j++) {
+ order[j] = child.getInteger(COLUMN+Integer.toString(j)).intValue();
+ }
+ fColumnOrder.put(id, order);
+ }
+ }
+ }
+
+ /**
+ * @param updates
+ */
+ protected void apply(LabelUpdate[] updates) {
+ Object prevElement = null;
+ Widget[] widgets = null;
+ for (int i = 0; i < updates.length; i++) {
+ LabelUpdate update = updates[i];
+ Object element = update.getElement();
+ if (!element.equals(prevElement)) {
+ prevElement = element;
+ widgets = findItems(element);
+ }
+ for (int j = 0; j < widgets.length; j++) {
+ Widget widget = widgets[j];
+ if (widget instanceof TreeItem) {
+ TreeItem item = (TreeItem) widget;
+ ViewerRow row = getRowPartFromItem(item);
+ update.update(row);
+ }
+ }
+ }
+ }
+
+ /**
+ * 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());
+ }
+
+ /**
+ * 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;
+ IModelSelectionPolicyFactoryAdapter factory = (IModelSelectionPolicyFactoryAdapter) adaptable.getAdapter(IModelSelectionPolicyFactoryAdapter.class);
+ if (factory != null) {
+ return factory.createModelSelectionPolicyAdapter(adaptable, getPresentationContext());
+ }
+ }
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ *
+ * Consider selection policy
+ *
+ * @see org.eclipse.jface.viewers.StructuredViewer#setSelection(org.eclipse.jface.viewers.ISelection, boolean)
+ */
+ public void setSelection(ISelection selection, boolean reveal) {
+ if (!overrideSelection(getSelection(), selection)) {
+ return;
+ }
+ super.setSelection(selection, reveal);
+ }
+
+ /**
+ * Registers the specified listener for view update notifications.
+ *
+ * @param listener listener
+ */
+ public void addViewerUpdateListener(IViewerUpdateListener listener) {
+ ((ModelContentProvider)getContentProvider()).addViewerUpdateListener(listener);
+ }
+
+ /**
+ * Removes the specified listener from update notifications.
+ *
+ * @param listener listener
+ */
+ public void removeViewerUpdateListener(IViewerUpdateListener listener) {
+ ModelContentProvider cp = (ModelContentProvider)getContentProvider();
+ if (cp != null) {
+ cp.removeViewerUpdateListener(listener);
+ }
+ }
+
+ /**
+ * Registers the given listener for model delta notification.
+ *
+ * @param listener model delta listener
+ */
+ public void addModelChangedListener(IModelChangedListener listener) {
+ ((ModelContentProvider)getContentProvider()).addModelChangedListener(listener);
+ }
+
+ /**
+ * Unregisters the given listener from model delta notification.
+ *
+ * @param listener model delta listener
+ */
+ public void removeModelChangedListener(IModelChangedListener listener) {
+ ModelContentProvider cp = (ModelContentProvider)getContentProvider();
+ if (cp != null) {
+ cp.removeModelChangedListener(listener);
+ }
+ }
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/ViewerUpdateMonitor.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/ViewerUpdateMonitor.java
new file mode 100644
index 000000000..5b2e8b8f7
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/viewers/ViewerUpdateMonitor.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.model.viewers;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.debug.internal.ui.actions.context.AbstractRequestMonitor;
+import org.eclipse.debug.internal.ui.model.IPresentationUpdate;
+import org.eclipse.debug.internal.ui.viewers.AsynchronousSchedulingRuleFactory;
+import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
+import org.eclipse.ui.progress.WorkbenchJob;
+
+/**
+ * @since 3.3
+ */
+abstract class ViewerUpdateMonitor extends AbstractRequestMonitor implements IPresentationUpdate {
+
+ private ModelContentProvider fContentProvider;
+
+ /**
+ * Whether this request's 'done' method has been called.
+ */
+ private boolean fDone = false;
+
+ protected WorkbenchJob fViewerUpdateJob = new WorkbenchJob("Asynchronous viewer update") { //$NON-NLS-1$
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ // necessary to check if viewer is disposed
+ try {
+ if (!isCanceled() && !getContentProvider().isDisposed()) {
+ IStatus status = getStatus();
+ if (status != null && !status.isOK()) {
+ getContentProvider().handlePresentationFailure(ViewerUpdateMonitor.this, status);
+ } else {
+ performUpdate();
+ }
+ }
+ } finally {
+ getContentProvider().updateComplete(ViewerUpdateMonitor.this);
+ }
+ return Status.OK_STATUS;
+ }
+ };
+
+ /**
+ * Constructs an update for the given content provider
+ *
+ * @param contentProvider content provider
+ */
+ public ViewerUpdateMonitor(ModelContentProvider contentProvider) {
+ fContentProvider = contentProvider;
+ // serialize updates per viewer
+ fViewerUpdateJob.setRule(getUpdateSchedulingRule());
+ fViewerUpdateJob.setSystem(true);
+ contentProvider.updateStarted(this);
+ }
+
+ /**
+ * Returns the scheduling rule for viewer update job.
+ *
+ * @return rule or <code>null</code>
+ */
+ protected ISchedulingRule getUpdateSchedulingRule() {
+ return AsynchronousSchedulingRuleFactory.getDefault().newSerialPerObjectRule(getContentProvider());
+ }
+
+ /**
+ * Returns the model content provider this update is being performed for.
+ *
+ * @return the model content provider this update is being performed for
+ */
+ protected ModelContentProvider getContentProvider() {
+ return fContentProvider;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IProgressMonitor#done()
+ */
+ public final void done() {
+ synchronized (this) {
+ fDone = true;
+ }
+ scheduleViewerUpdate(0L);
+ }
+
+ /**
+ * Returns whether this request is done yet.
+ *
+ * @return
+ */
+ protected synchronized boolean isDone() {
+ return fDone;
+ }
+
+ protected void scheduleViewerUpdate(long ms) {
+ if(!isCanceled()) {
+ fViewerUpdateJob.schedule(ms);
+ } else {
+ getContentProvider().updateComplete(this);
+ }
+ }
+
+ /**
+ * Notification this update has been completed and should now be applied to
+ * this update's viewer. This method is called in the UI thread.
+ */
+ protected abstract void performUpdate();
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.IPresentationUpdate#getPresentationContext()
+ */
+ public IPresentationContext getPresentationContext() {
+ return fContentProvider.getPresentationContext();
+ }
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/PresentationContext.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/PresentationContext.java
index 24c0549f9..020aedcf2 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/PresentationContext.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/PresentationContext.java
@@ -94,7 +94,7 @@ public class PresentationContext implements IPresentationContext {
*
* @param ids column identifiers
*/
- protected void setColumns(String[] ids) {
+ public void setColumns(String[] ids) {
String[] oldValue = fColumns;
fColumns = ids;
firePropertyChange(IPresentationContext.PROPERTY_COLUMNS, oldValue, ids);
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/TableUpdatePolicy.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/TableUpdatePolicy.java
index 4e81f8631..9281635fa 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/TableUpdatePolicy.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/TableUpdatePolicy.java
@@ -75,7 +75,7 @@ public class TableUpdatePolicy extends org.eclipse.debug.internal.ui.viewers.Abs
handleInsert(node);
}
- IModelDelta[] childNodes = node.getNodes();
+ IModelDelta[] childNodes = node.getChildDeltas();
updateNodes(childNodes);
}
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/TreeUpdatePolicy.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/TreeUpdatePolicy.java
index 2f1a31ad0..4f1342911 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/TreeUpdatePolicy.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/TreeUpdatePolicy.java
@@ -69,7 +69,7 @@ public class TreeUpdatePolicy extends AbstractUpdatePolicy implements IModelChan
// TODO
}
- updateNodes(node.getNodes());
+ updateNodes(node.getChildDeltas());
}
}
@@ -101,8 +101,8 @@ public class TreeUpdatePolicy extends AbstractUpdatePolicy implements IModelChan
if (node != fNode) {
ArrayList list = new ArrayList();
list.add(0, node.getElement());
- while (node.getParent() != null) {
- node = node.getParent();
+ while (node.getParentDelta() != null) {
+ node = node.getParentDelta();
list.add(0, node.getElement());
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/provisional/AbstractModelProxy.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/provisional/AbstractModelProxy.java
index 7608f3732..91c611120 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/provisional/AbstractModelProxy.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/provisional/AbstractModelProxy.java
@@ -118,8 +118,5 @@ public abstract class AbstractModelProxy implements IModelProxy {
*/
public void installed() {
}
-
-
-
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/provisional/IModelDelta.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/provisional/IModelDelta.java
index d945086ae..8db3e5b86 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/provisional/IModelDelta.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/provisional/IModelDelta.java
@@ -84,13 +84,26 @@ public interface IModelDelta {
* Suggests that the element should be selected, as described by its path.
*/
public static int SELECT = 1 << 21;
+
+ /**
+ * Indicates a model proxy should be installed for the given element
+ * @since 3.3
+ */
+ public static int INSTALL = 1 << 22;
+
+ /**
+ * Indicates a model proxy should be uninstalled for the given element
+ * @since 3.3
+ */
+ public static int UNINSTALL = 1 << 23;
+
/**
* Returns the parent of this node, or <code>null</code> if this is
* a root node.
*
* @return parent node or <code>null</code> if this is a root node
*/
- public IModelDelta getParent();
+ public IModelDelta getParentDelta();
/**
* Returns the model element this node describes.
@@ -112,7 +125,7 @@ public interface IModelDelta {
*
* @return changed children, possibly empty
*/
- public ModelDelta[] getNodes();
+ public ModelDelta[] getChildDeltas();
/**
* When a node indicates the <code>IModelDelta.REPLACED</code> flag, this method
@@ -123,12 +136,35 @@ public interface IModelDelta {
public Object getReplacementElement();
/**
+ * Returns this node's index in its parents child collection or -1 if unknown.
+ * This attribute is required when expanding or selecting an element.
+ * <p>
* When a node indicates the <code>IModelDelta.INSERTED</code> flag, this method
* returns the index that the new element should be inserted at relative to its
* parents children, otherwise -1.
- *
+ * </p>
* @return insertion index or -1
*/
public int getIndex();
+ /**
+ * Returns the total number of children this element has, or -1 if unknown. Note
+ * that this number may be greater than the number of child delta nodes for this
+ * node, since not all children may be reporting deltas.
+ * <p>
+ * This attribute is required when expanding or selecting an element.
+ * </p>
+ *
+ * @return total number of child elements this element has
+ */
+ public int getChildCount();
+
+ /**
+ * Accepts the given visitor.
+ *
+ * @param visitor
+ * @since 3.3
+ */
+ public void accept(IModelDeltaVisitor visitor);
+
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/provisional/IModelDeltaVisitor.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/provisional/IModelDeltaVisitor.java
new file mode 100644
index 000000000..8d198cd77
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/provisional/IModelDeltaVisitor.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.provisional;
+
+
+/**
+ * An objects that visits model deltas.
+ *
+ * @since 3.3
+ */
+public interface IModelDeltaVisitor {
+
+ /**
+ * Visits the given model delta.
+ *
+ * @param delta the delta to visit
+ * @param depth depth in the delta where 0 == root node
+ * @return <code>true</code> if the model delta's children should
+ * be visited; <code>false</code> if they should be skipped.
+ */
+ public boolean visit(IModelDelta delta, int depth);
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/provisional/ModelDelta.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/provisional/ModelDelta.java
index 7fe6d8e0c..1f0777aea 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/provisional/ModelDelta.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/provisional/ModelDelta.java
@@ -27,7 +27,8 @@ public class ModelDelta implements IModelDelta {
private int fFlags;
private ModelDelta[] fNodes = EMPTY_NODES;
private Object fReplacement;
- private int fIndex;
+ private int fIndex = -1;
+ private int fChildCount = -1;
private static final ModelDelta[] EMPTY_NODES = new ModelDelta[0];
/**
@@ -68,6 +69,22 @@ public class ModelDelta implements IModelDelta {
fIndex = index;
fFlags = flags;
}
+
+ /**
+ * Constructs a new delta for the given element at the specified index
+ * relative to its parent with the given number of children.
+ *
+ * @param element model element
+ * @param index insertion position
+ * @param flags change flags
+ * @param childCount number of children this node has
+ */
+ public ModelDelta(Object element, int index, int flags, int childCount) {
+ fElement = element;
+ fIndex = index;
+ fFlags = flags;
+ fChildCount = childCount;
+ }
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getElement()
@@ -132,6 +149,23 @@ public class ModelDelta implements IModelDelta {
}
/**
+ * Adds a child delta to this delta at the specified index with the
+ * given number of children, and returns the newly created child delta.
+ *
+ * @param element child element in insert
+ * @param index index of the element relative to parent
+ * @param flags change flags
+ * @param numChildren the number of children the element has
+ * @return newly created child delta
+ */
+ public ModelDelta addNode(Object element, int index, int flags, int numChildren) {
+ ModelDelta node = new ModelDelta(element, index, flags, numChildren);
+ node.setParent(this);
+ addDelta(node);
+ return node;
+ }
+
+ /**
* Sets the parent delta of this delta
*
* @param node parent delta
@@ -143,7 +177,7 @@ public class ModelDelta implements IModelDelta {
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getParent()
*/
- public IModelDelta getParent() {
+ public IModelDelta getParentDelta() {
return fParent;
}
@@ -164,7 +198,7 @@ public class ModelDelta implements IModelDelta {
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getNodes()
*/
- public ModelDelta[] getNodes() {
+ public ModelDelta[] getChildDeltas() {
return fNodes;
}
@@ -220,11 +254,63 @@ public class ModelDelta implements IModelDelta {
if ((flags & IModelDelta.STATE) > 0) {
buf.append("STATE | "); //$NON-NLS-1$
}
+ if ((flags & IModelDelta.INSTALL) > 0) {
+ buf.append("INSTALL | "); //$NON-NLS-1$
+ }
+ if ((flags & IModelDelta.UNINSTALL) > 0) {
+ buf.append("UNINSTALL | "); //$NON-NLS-1$
+ }
}
buf.append('\n');
- ModelDelta[] nodes = delta.getNodes();
+ buf.append("\t\tIndex: "); //$NON-NLS-1$
+ buf.append(fIndex);
+ buf.append(" Child Count: "); //$NON-NLS-1$
+ buf.append(fChildCount);
+ buf.append('\n');
+ ModelDelta[] nodes = delta.getChildDeltas();
for (int i = 0; i < nodes.length; i++) {
appendDetail(buf, nodes[i]);
}
}
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta#getChildCount()
+ */
+ public int getChildCount() {
+ return fChildCount;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta#accept(org.eclipse.debug.internal.ui.viewers.provisional.IModelDeltaVisitor)
+ */
+ public void accept(IModelDeltaVisitor visitor) {
+ doAccept(visitor, 0);
+ }
+
+ protected void doAccept(IModelDeltaVisitor visitor, int depth) {
+ if (visitor.visit(this, depth)) {
+ ModelDelta[] childDeltas = getChildDeltas();
+ for (int i = 0; i < childDeltas.length; i++) {
+ childDeltas[i].doAccept(visitor, depth+1);
+ }
+ }
+ }
+
+ /**
+ * Sets this delta's element
+ *
+ * @param element
+ */
+ public void setElement(Object element) {
+ fElement = element;
+ }
+
+ /**
+ * Sets this delta's flags.
+ *
+ * @param flags
+ */
+ public void setFlags(int flags) {
+ fFlags = flags;
+ }
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DebugEventHandler.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DebugEventHandler.java
index fe26a476c..1b4fbdce6 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DebugEventHandler.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DebugEventHandler.java
@@ -173,4 +173,14 @@ public abstract class DebugEventHandler {
protected synchronized boolean isDisposed() {
return fModelProxy == null;
}
+
+ protected int indexOf(Object[] list, Object element) {
+ for (int i = 0; i < list.length; i++) {
+ if (element.equals(list[i])) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DebugTargetEventHandler.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DebugTargetEventHandler.java
index d569f4519..172ff610e 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DebugTargetEventHandler.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DebugTargetEventHandler.java
@@ -60,7 +60,7 @@ public class DebugTargetEventHandler extends DebugEventHandler {
}
protected void handleTerminate(DebugEvent event) {
- fireDelta((IDebugTarget) event.getSource(), IModelDelta.STATE);
+ fireDelta((IDebugTarget) event.getSource(), IModelDelta.STATE | IModelDelta.UNINSTALL);
}
private void fireDelta(IDebugTarget target, int flags) {
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DebugTargetProxy.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DebugTargetProxy.java
index e5531c2b7..56fd179d9 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DebugTargetProxy.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DebugTargetProxy.java
@@ -80,10 +80,10 @@ public class DebugTargetProxy extends EventHandlerModelProxy {
IStackFrame frame = thread.getTopStackFrame();
if (frame != null) {
ModelDelta delta = new ModelDelta(DebugPlugin.getDefault().getLaunchManager(), IModelDelta.NO_CHANGE);
- ModelDelta node = delta.addNode(target.getLaunch(), IModelDelta.NO_CHANGE);
- node = node.addNode(target, IModelDelta.NO_CHANGE);
- node = node.addNode(thread, IModelDelta.NO_CHANGE | IModelDelta.EXPAND);
- node = node.addNode(frame, IModelDelta.NO_CHANGE | IModelDelta.SELECT);
+ ModelDelta node = delta.addNode(target.getLaunch(), -1, IModelDelta.NO_CHANGE, target.getLaunch().getChildren().length);
+ node = node.addNode(target, 0, IModelDelta.NO_CHANGE, threads.length);
+ node = node.addNode(thread, i, IModelDelta.NO_CHANGE | IModelDelta.EXPAND, thread.getStackFrames().length);
+ node = node.addNode(frame, 0, IModelDelta.NO_CHANGE | IModelDelta.SELECT, 0);
fireModelChanged(delta);
return;
}
@@ -91,8 +91,8 @@ public class DebugTargetProxy extends EventHandlerModelProxy {
}
// expand the target if no suspended thread
ModelDelta delta = new ModelDelta(DebugPlugin.getDefault().getLaunchManager(), IModelDelta.NO_CHANGE);
- ModelDelta node = delta.addNode(target.getLaunch(), IModelDelta.NO_CHANGE);
- node = node.addNode(target, IModelDelta.EXPAND | IModelDelta.SELECT);
+ ModelDelta node = delta.addNode(target.getLaunch(), -1, IModelDelta.NO_CHANGE, target.getLaunch().getChildren().length);
+ node = node.addNode(target, 0, IModelDelta.EXPAND | IModelDelta.SELECT, threads.length);
fireModelChanged(delta);
} catch (DebugException e) {
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DefaultModelProxyFactory.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DefaultModelProxyFactory.java
index 18fb82fc8..c339e2ac7 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DefaultModelProxyFactory.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DefaultModelProxyFactory.java
@@ -49,7 +49,8 @@ public class DefaultModelProxyFactory implements IModelProxyFactoryAdapter {
if (IDebugUIConstants.ID_EXPRESSION_VIEW.equals(id)) {
if (element instanceof IExpressionManager) {
return new ExpressionManagerModelProxy();
- } if (element instanceof IWatchExpression) {
+ }
+ if (element instanceof IWatchExpression) {
IWorkbenchPart part = context.getPart();
if (part == null) {
return null;
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DefaultVariableViewModelProxy.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DefaultVariableViewModelProxy.java
index dc449df61..58642c150 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DefaultVariableViewModelProxy.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/DefaultVariableViewModelProxy.java
@@ -59,5 +59,5 @@ public class DefaultVariableViewModelProxy extends EventHandlerModelProxy {
}
return false;
}
-
+
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/ExpressionEventHandler.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/ExpressionEventHandler.java
index 877bb50a3..e1bd8cabd 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/ExpressionEventHandler.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/ExpressionEventHandler.java
@@ -48,7 +48,14 @@ public class ExpressionEventHandler extends DebugEventHandler {
}
}
if (expression != null) {
- delta.addNode(expression, IModelDelta.CONTENT | IModelDelta.STATE);
+ int flags = IModelDelta.NO_CHANGE;
+ if ((event.getDetail() & DebugEvent.STATE) != 0) {
+ flags = flags | IModelDelta.STATE;
+ }
+ if ((event.getDetail() & DebugEvent.CONTENT) != 0) {
+ flags = flags | IModelDelta.CONTENT;
+ }
+ delta.addNode(expression, flags);
fireDelta(delta);
}
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/ExpressionManagerModelProxy.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/ExpressionManagerModelProxy.java
index c27c4a88c..aac1572b8 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/ExpressionManagerModelProxy.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/ExpressionManagerModelProxy.java
@@ -12,6 +12,7 @@
package org.eclipse.debug.internal.ui.viewers.update;
import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.IExpressionManager;
import org.eclipse.debug.core.IExpressionsListener;
import org.eclipse.debug.core.model.IExpression;
import org.eclipse.debug.internal.ui.viewers.provisional.AbstractModelProxy;
@@ -27,7 +28,21 @@ public class ExpressionManagerModelProxy extends AbstractModelProxy implements I
*/
public void init(IPresentationContext context) {
super.init(context);
- DebugPlugin.getDefault().getExpressionManager().addExpressionListener(this);
+ getExpressionManager().addExpressionListener(this);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.provisional.AbstractModelProxy#installed()
+ */
+ public void installed() {
+ updateExpressions(getExpressionManager().getExpressions(), IModelDelta.INSTALL);
+ }
+
+ /**
+ * @return
+ */
+ protected IExpressionManager getExpressionManager() {
+ return DebugPlugin.getDefault().getExpressionManager();
}
/* (non-Javadoc)
@@ -35,21 +50,21 @@ public class ExpressionManagerModelProxy extends AbstractModelProxy implements I
*/
public synchronized void dispose() {
super.dispose();
- DebugPlugin.getDefault().getExpressionManager().removeExpressionListener(this);
+ getExpressionManager().removeExpressionListener(this);
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.IExpressionsListener#expressionsAdded(org.eclipse.debug.core.model.IExpression[])
*/
public void expressionsAdded(IExpression[] expressions) {
- updateExpressions(expressions, IModelDelta.ADDED);
+ updateExpressions(expressions, IModelDelta.ADDED | IModelDelta.INSTALL);
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.IExpressionsListener#expressionsRemoved(org.eclipse.debug.core.model.IExpression[])
*/
public void expressionsRemoved(IExpression[] expressions) {
- updateExpressions(expressions, IModelDelta.REMOVED);
+ updateExpressions(expressions, IModelDelta.REMOVED | IModelDelta.UNINSTALL);
}
/* (non-Javadoc)
@@ -60,7 +75,7 @@ public class ExpressionManagerModelProxy extends AbstractModelProxy implements I
}
private void updateExpressions(IExpression[] expressions, int flags) {
- ModelDelta delta = new ModelDelta(DebugPlugin.getDefault() .getExpressionManager(), IModelDelta.NO_CHANGE);
+ ModelDelta delta = new ModelDelta(getExpressionManager(), IModelDelta.NO_CHANGE);
for (int i = 0; i < expressions.length; i++) {
IExpression expression = expressions[i];
delta.addNode(expression, flags);
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/LaunchManagerProxy.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/LaunchManagerProxy.java
index ed2aaf2ed..b7e332e60 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/LaunchManagerProxy.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/LaunchManagerProxy.java
@@ -10,6 +10,11 @@
*******************************************************************************/
package org.eclipse.debug.internal.ui.viewers.update;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchManager;
@@ -22,6 +27,11 @@ import org.eclipse.debug.internal.ui.viewers.provisional.ModelDelta;
public class LaunchManagerProxy extends AbstractModelProxy implements ILaunchesListener2 {
private ILaunchManager fLaunchManager;
+ /**
+ * Map of each launch to its previous children. When a child is added,
+ * its model proxy is installed.
+ */
+ private Map fPrevChildren = new HashMap();
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.AbstractModelProxy#init(org.eclipse.debug.internal.ui.viewers.IPresentationContext)
@@ -38,9 +48,7 @@ public class LaunchManagerProxy extends AbstractModelProxy implements ILaunchesL
public void installed() {
// expand existing launches
ILaunch[] launches = fLaunchManager.getLaunches();
- if (launches.length > 0) {
- fireDelta(launches, IModelDelta.EXPAND);
- }
+ launchesAdded(launches);
}
/* (non-Javadoc)
@@ -64,6 +72,10 @@ public class LaunchManagerProxy extends AbstractModelProxy implements ILaunchesL
*/
public void launchesRemoved(ILaunch[] launches) {
fireDelta(launches, IModelDelta.REMOVED);
+ // clear the children cache
+ for (int i = 0; i < launches.length; i++) {
+ fPrevChildren.remove(launches[i]);
+ }
}
/* (non-Javadoc)
@@ -71,6 +83,12 @@ public class LaunchManagerProxy extends AbstractModelProxy implements ILaunchesL
*/
public void launchesAdded(ILaunch[] launches) {
fireDelta(launches, IModelDelta.ADDED | IModelDelta.EXPAND);
+ // install model proxies
+ for (int i = 0; i < launches.length; i++) {
+ ILaunch launch = launches[i];
+ fPrevChildren.put(launch, new HashSet());
+ }
+ installModelProxies(launches);
}
/* (non-Javadoc)
@@ -78,6 +96,34 @@ public class LaunchManagerProxy extends AbstractModelProxy implements ILaunchesL
*/
public void launchesChanged(ILaunch[] launches) {
fireDelta(launches, IModelDelta.STATE | IModelDelta.CONTENT);
+ // install model proxies for new children
+ installModelProxies(launches);
+ }
+
+ /**
+ * Installs model proxies for any new children in the given launches.
+ *
+ * @param launches
+ */
+ protected void installModelProxies(ILaunch[] launches) {
+ boolean changes = false;
+ ModelDelta root = new ModelDelta(fLaunchManager, IModelDelta.NO_CHANGE);
+ for (int i = 0; i < launches.length; i++) {
+ ILaunch launch = launches[i];
+ ModelDelta launchDelta = root.addNode(launch, IModelDelta.NO_CHANGE);
+ Object[] children = launch.getChildren();
+ Set set = (Set) fPrevChildren.get(launch);
+ for (int j = 0; j < children.length; j++) {
+ Object child = children[j];
+ if (set.add(child)) {
+ changes = true;
+ launchDelta.addNode(child, IModelDelta.INSTALL);
+ }
+ }
+ }
+ if (changes) {
+ fireModelChanged(root);
+ }
}
protected void fireDelta(ILaunch[] launches, int launchFlags) {
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/ProcessProxy.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/ProcessProxy.java
index 2157ad040..7139168fe 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/ProcessProxy.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/ProcessProxy.java
@@ -28,29 +28,31 @@ public class ProcessProxy extends EventHandlerModelProxy {
}
protected void handleChange(DebugEvent event) {
+ fireDelta(IModelDelta.STATE);
+ }
+
+ protected void handleCreate(DebugEvent event) {
+ // do nothing - Launch change notification handles this
+ }
+
+ protected void handleTerminate(DebugEvent event) {
+ fireDelta(IModelDelta.STATE | IModelDelta.UNINSTALL);
+ }
+
+ private void fireDelta(int flags) {
ModelDelta delta = null;
synchronized (ProcessProxy.this) {
if (!isDisposed()) {
delta = new ModelDelta(DebugPlugin.getDefault().getLaunchManager(), IModelDelta.NO_CHANGE);
ModelDelta node = delta;
node = node.addNode(fProcess.getLaunch(), IModelDelta.NO_CHANGE);
- node.addNode(fProcess, IModelDelta.STATE);
+ node.addNode(fProcess, flags);
}
}
if (delta != null && !isDisposed()) {
fireModelChanged(delta);
- }
+ }
}
-
- protected void handleCreate(DebugEvent event) {
- // do nothing - Launch change notification handles this
- }
-
- protected void handleTerminate(DebugEvent event) {
- handleChange(event);
- }
-
-
};
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/ThreadEventHandler.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/ThreadEventHandler.java
index 4b19e034d..5f1b5e6cb 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/ThreadEventHandler.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/update/ThreadEventHandler.java
@@ -18,6 +18,8 @@ import java.util.Set;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.debug.core.model.IStackFrame;
import org.eclipse.debug.core.model.IThread;
@@ -157,12 +159,36 @@ public class ThreadEventHandler extends DebugEventHandler {
}
protected ModelDelta buildRootDelta() {
- return new ModelDelta(DebugPlugin.getDefault().getLaunchManager(), IModelDelta.NO_CHANGE);
+ return new ModelDelta(getLaunchManager(), IModelDelta.NO_CHANGE);
+ }
+
+ /**
+ * Returns the launch manager.
+ *
+ * @return the launch manager
+ */
+ protected ILaunchManager getLaunchManager() {
+ return DebugPlugin.getDefault().getLaunchManager();
}
+ /**
+ * Adds nodes into the delta up to but not including the given thread.
+ *
+ * @param delta root delta for the view (includes viewer input)
+ * @param thread thread for which path is requested
+ * @return
+ */
protected ModelDelta addPathToThread(ModelDelta delta, IThread thread) {
- delta = delta.addNode(thread.getLaunch(), IModelDelta.NO_CHANGE);
- return delta.addNode(thread.getDebugTarget(), IModelDelta.NO_CHANGE);
+ ILaunch launch = thread.getLaunch();
+ Object[] children = launch.getChildren();
+ delta = delta.addNode(launch, indexOf(getLaunchManager().getLaunches(), launch), IModelDelta.NO_CHANGE, children.length);
+ IDebugTarget debugTarget = thread.getDebugTarget();
+ int numThreads = -1;
+ try {
+ numThreads = debugTarget.getThreads().length;
+ } catch (DebugException e) {
+ }
+ return delta.addNode(debugTarget, indexOf(children, debugTarget), IModelDelta.NO_CHANGE, numThreads);
}
private void fireDeltaAndClearTopFrame(IThread thread, int flags) {
@@ -187,20 +213,22 @@ public class ThreadEventHandler extends DebugEventHandler {
frame = thread.getTopStackFrame();
} catch (DebugException e) {
}
+ int threadIndex = indexOf(thread);
+ int childCount = childCount(thread);
if (isEqual(frame, prev)) {
if (frame == null) {
if (thread.isSuspended()) {
// no frames, but suspended - update & select
- node = node.addNode(thread, flags | IModelDelta.STATE | IModelDelta.SELECT);
+ node = node.addNode(thread, threadIndex, flags | IModelDelta.STATE | IModelDelta.SELECT, childCount);
}
} else {
- node = node.addNode(thread, flags);
+ node = node.addNode(thread, threadIndex, flags, childCount);
}
} else {
- node = node.addNode(thread, flags | IModelDelta.CONTENT);
+ node = node.addNode(thread, threadIndex, flags | IModelDelta.CONTENT, childCount);
}
if (frame != null) {
- node.addNode(frame, IModelDelta.STATE | IModelDelta.SELECT);
+ node.addNode(frame, indexOf(frame), IModelDelta.STATE | IModelDelta.SELECT, childCount(frame));
}
synchronized (this) {
if (!isDisposed()) {
@@ -210,6 +238,54 @@ public class ThreadEventHandler extends DebugEventHandler {
fireDelta(delta);
}
+ /**
+ * Returns the index of the given thread, relative to its parent in the view.
+ *
+ * @param thread thread
+ * @return index of the thread, relative to its parent
+ */
+ protected int indexOf(IThread thread) {
+ try {
+ return indexOf(thread.getDebugTarget().getThreads(), thread);
+ } catch (DebugException e) {
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the index of the given frame, relative to its parent in the view.
+ *
+ * @param frame frame
+ * @return index of the frame, relative to its thread
+ */
+ protected int indexOf(IStackFrame frame) {
+ return 0;
+ }
+
+ /**
+ * Returns the number of children the given thread has in the view.
+ *
+ * @param thread thread
+ * @return number of children
+ */
+ protected int childCount(IThread thread) {
+ try {
+ return thread.getStackFrames().length;
+ } catch (DebugException e) {
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the number of children the given frame has in the view.
+ *
+ * @param frame frame
+ * @return child count
+ */
+ protected int childCount(IStackFrame frame) {
+ return 0;
+ }
+
private void fireDeltaUpdatingThread(IThread thread, int flags) {
ModelDelta delta = buildRootDelta();
ModelDelta node = addPathToThread(delta, thread);
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/expression/ExpressionView.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/expression/ExpressionView.java
index ce977d9b1..733458279 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/expression/ExpressionView.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/expression/ExpressionView.java
@@ -15,11 +15,9 @@ import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.model.IDebugElement;
import org.eclipse.debug.internal.ui.IDebugHelpContextIds;
import org.eclipse.debug.internal.ui.preferences.IDebugPreferenceConstants;
-import org.eclipse.debug.internal.ui.views.AbstractViewerState;
import org.eclipse.debug.internal.ui.views.variables.AvailableLogicalStructuresAction;
import org.eclipse.debug.internal.ui.views.variables.VariablesView;
import org.eclipse.debug.internal.ui.views.variables.VariablesViewMessages;
-import org.eclipse.debug.internal.ui.views.variables.VariablesViewer;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
@@ -29,7 +27,6 @@ import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPart;
@@ -39,8 +36,6 @@ import org.eclipse.ui.IWorkbenchPart;
*/
public class ExpressionView extends VariablesView {
- private AbstractViewerState fState;
-
/**
* @see AbstractDebugView#getHelpContextId()
*/
@@ -76,7 +71,8 @@ public class ExpressionView extends VariablesView {
menu.add(new Separator(IDebugUIConstants.EMPTY_EXPRESSION_GROUP));
menu.add(new Separator(IDebugUIConstants.EXPRESSION_GROUP));
- menu.add(getAction(FIND_ELEMENT));
+ // TODO:
+ //menu.add(getAction(FIND_ELEMENT));
menu.add(getAction("ChangeVariableValue")); //$NON-NLS-1$
IAction action = new AvailableLogicalStructuresAction(this);
if (action.isEnabled()) {
@@ -128,53 +124,18 @@ public class ExpressionView extends VariablesView {
}
/* (non-Javadoc)
- * @see org.eclipse.debug.ui.AbstractDebugView#createActions()
- */
- protected void createActions() {
- super.createActions();
- setInitialContent();
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.views.variables.VariablesView#restoreState()
- */
- protected void restoreState() {
- if (fState != null) {
- fState.restoreState(getVariablesViewer());
- }
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.views.variables.VariablesView#dispose()
- */
- public void dispose() {
- super.dispose();
- fState = null;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.views.variables.VariablesView#becomesHidden()
- */
- protected void becomesHidden() {
- fState = getViewerState();
- super.becomesHidden();
- getViewer().setInput(null);
- }
-
- /* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.views.variables.VariablesView#becomesVisible()
*/
protected void becomesVisible() {
- super.becomesVisible();
setInitialContent();
- restoreState();
+ super.becomesVisible();
}
/* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.views.variables.VariablesView#createVariablesViewer(org.eclipse.swt.widgets.Composite)
+ * @see org.eclipse.debug.internal.ui.views.variables.VariablesView#getViewerStyle()
*/
- protected VariablesViewer createVariablesViewer(Composite parent) {
- return new VariablesViewer(parent, SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL | SWT.VIRTUAL, this);
+ protected int getViewerStyle() {
+ return SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL | SWT.VIRTUAL;
}
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/launch/DebugElementAdapterFactory.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/launch/DebugElementAdapterFactory.java
index ecd5be667..c1a0c4e24 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/launch/DebugElementAdapterFactory.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/launch/DebugElementAdapterFactory.java
@@ -44,6 +44,21 @@ import org.eclipse.debug.internal.ui.elements.adapters.ThreadContentAdapter;
import org.eclipse.debug.internal.ui.elements.adapters.VariableColumnFactoryAdapter;
import org.eclipse.debug.internal.ui.elements.adapters.VariableContentAdapter;
import org.eclipse.debug.internal.ui.elements.adapters.VariableLabelAdapter;
+import org.eclipse.debug.internal.ui.model.IElementContentProvider;
+import org.eclipse.debug.internal.ui.model.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.model.IElementMementoProvider;
+import org.eclipse.debug.internal.ui.model.elements.DebugElementLabelProvider;
+import org.eclipse.debug.internal.ui.model.elements.DebugTargetContentProvider;
+import org.eclipse.debug.internal.ui.model.elements.ExpressionContentProvider;
+import org.eclipse.debug.internal.ui.model.elements.ExpressionLabelProvider;
+import org.eclipse.debug.internal.ui.model.elements.ExpressionManagerContentProvider;
+import org.eclipse.debug.internal.ui.model.elements.LaunchContentProvider;
+import org.eclipse.debug.internal.ui.model.elements.LaunchManagerContentProvider;
+import org.eclipse.debug.internal.ui.model.elements.StackFrameContentProvider;
+import org.eclipse.debug.internal.ui.model.elements.VariablesViewElementMementoProvider;
+import org.eclipse.debug.internal.ui.model.elements.ThreadContentProvider;
+import org.eclipse.debug.internal.ui.model.elements.VariableContentProvider;
+import org.eclipse.debug.internal.ui.model.elements.VariableLabelProvider;
import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousContentAdapter;
import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousLabelAdapter;
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditorFactoryAdapter;
@@ -72,6 +87,10 @@ public class DebugElementAdapterFactory implements IAdapterFactory {
private static IAsynchronousLabelAdapter fgMemoryBlockLabelAdapter = new MemoryBlockLabelAdapter();
private static IAsynchronousLabelAdapter fgTableRenderingLineLabelAdapter = new MemorySegmentLabelAdapter();
+ private static IElementLabelProvider fgLPDebugElement = new DebugElementLabelProvider();
+ private static IElementLabelProvider fgLPVariable = new VariableLabelProvider();
+ private static IElementLabelProvider fgLPExpression = new ExpressionLabelProvider();
+
private static IAsynchronousContentAdapter fgAsyncLaunchManager = new LauchManagerContentAdapter();
private static IAsynchronousContentAdapter fgAsyncLaunch = new LaunchContentAdapter();
private static IAsynchronousContentAdapter fgAsyncTarget = new DebugTargetContentAdapter();
@@ -85,6 +104,17 @@ public class DebugElementAdapterFactory implements IAdapterFactory {
private static IAsynchronousContentAdapter fgAsyncMemoryRetrieval = new MemoryRetrievalContentAdapter();
private static IAsynchronousContentAdapter fgAsyncMemoryBlock = new MemoryBlockContentAdapter();
+ private static IElementContentProvider fgCPLaunchManger = new LaunchManagerContentProvider();
+ private static IElementContentProvider fgCPLaunch = new LaunchContentProvider();
+ private static IElementContentProvider fgCPTarget = new DebugTargetContentProvider();
+ private static IElementContentProvider fgCPThread = new ThreadContentProvider();
+ private static IElementContentProvider fgCPFrame = new StackFrameContentProvider();
+ private static IElementContentProvider fgCPVariable = new VariableContentProvider();
+ private static IElementContentProvider fgCPExpressionManager = new ExpressionManagerContentProvider();
+ private static IElementContentProvider fgCPExpression = new ExpressionContentProvider();
+
+ private static IElementMementoProvider fgMPFrame = new VariablesViewElementMementoProvider();
+
private static IColumnPresentationFactoryAdapter fgVariableColumnFactory = new VariableColumnFactoryAdapter();
@@ -135,6 +165,33 @@ public class DebugElementAdapterFactory implements IAdapterFactory {
}
}
+ if (adapterType.equals(IElementContentProvider.class)) {
+ if (adaptableObject instanceof ILaunchManager) {
+ return fgCPLaunchManger;
+ }
+ if (adaptableObject instanceof ILaunch) {
+ return fgCPLaunch;
+ }
+ if (adaptableObject instanceof IDebugTarget) {
+ return fgCPTarget;
+ }
+ if (adaptableObject instanceof IThread) {
+ return fgCPThread;
+ }
+ if (adaptableObject instanceof IStackFrame) {
+ return fgCPFrame;
+ }
+ if (adaptableObject instanceof IVariable) {
+ return fgCPVariable;
+ }
+ if (adaptableObject instanceof IExpressionManager) {
+ return fgCPExpressionManager;
+ }
+ if (adaptableObject instanceof IExpression) {
+ return fgCPExpression;
+ }
+ }
+
if (adapterType.equals(IAsynchronousLabelAdapter.class)) {
if (adaptableObject instanceof IExpression) {
return fgExpressionLabelAdapter;
@@ -153,6 +210,16 @@ public class DebugElementAdapterFactory implements IAdapterFactory {
return fgDebugLabelAdapter;
}
+ if (adapterType.equals(IElementLabelProvider.class)) {
+ if (adaptableObject instanceof IVariable) {
+ return fgLPVariable;
+ }
+ if (adaptableObject instanceof IExpression) {
+ return fgLPExpression;
+ }
+ return fgLPDebugElement;
+ }
+
if (adapterType.equals(IModelProxyFactoryAdapter.class)) {
if (adaptableObject instanceof IDebugTarget ||
adaptableObject instanceof IProcess || adaptableObject instanceof ILaunchManager ||
@@ -184,7 +251,13 @@ public class DebugElementAdapterFactory implements IAdapterFactory {
if (adaptableObject instanceof IVariable) {
return fgVariableColumnFactory;
}
- }
+ }
+
+ if (adapterType.equals(IElementMementoProvider.class)) {
+ if (adaptableObject instanceof IStackFrame) {
+ return fgMPFrame;
+ }
+ }
return null;
}
@@ -193,7 +266,8 @@ public class DebugElementAdapterFactory implements IAdapterFactory {
*/
public Class[] getAdapterList() {
return new Class[] {IWorkbenchAdapter.class, IWorkbenchAdapter2.class, IDeferredWorkbenchAdapter.class, IAsynchronousLabelAdapter.class, IAsynchronousContentAdapter.class,
- IModelProxyFactoryAdapter.class, ISourceDisplayAdapter.class, IModelSelectionPolicyFactoryAdapter.class, IColumnPresentationFactoryAdapter.class, IColumnEditorFactoryAdapter.class};
+ IModelProxyFactoryAdapter.class, ISourceDisplayAdapter.class, IModelSelectionPolicyFactoryAdapter.class, IColumnPresentationFactoryAdapter.class, IColumnEditorFactoryAdapter.class,
+ IElementContentProvider.class, IElementLabelProvider.class, IElementMementoProvider.class};
}
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/launch/LaunchView.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/launch/LaunchView.java
index 5755ebe7d..e235e1a9b 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/launch/LaunchView.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/launch/LaunchView.java
@@ -32,7 +32,6 @@ import org.eclipse.debug.internal.ui.DelegatingModelPresentation;
import org.eclipse.debug.internal.ui.IDebugHelpContextIds;
import org.eclipse.debug.internal.ui.actions.AddToFavoritesAction;
import org.eclipse.debug.internal.ui.actions.EditLaunchConfigurationAction;
-import org.eclipse.debug.internal.ui.actions.FindElementAction;
import org.eclipse.debug.internal.ui.actions.context.AbstractDebugContextAction;
import org.eclipse.debug.internal.ui.actions.context.DisconnectAction;
import org.eclipse.debug.internal.ui.actions.context.DropToFrameAction;
@@ -48,6 +47,7 @@ import org.eclipse.debug.internal.ui.actions.context.TerminateAndRemoveAction;
import org.eclipse.debug.internal.ui.contexts.DebugContextManager;
import org.eclipse.debug.internal.ui.contexts.provisional.IDebugContextListener;
import org.eclipse.debug.internal.ui.contexts.provisional.IDebugContextProvider;
+import org.eclipse.debug.internal.ui.model.viewers.TreeModelViewer;
import org.eclipse.debug.internal.ui.sourcelookup.EditSourceLookupPathAction;
import org.eclipse.debug.internal.ui.sourcelookup.LookupSourceAction;
import org.eclipse.debug.internal.ui.viewers.AsynchronousTreeViewer;
@@ -244,7 +244,7 @@ public class LaunchView extends AbstractDebugView implements ISelectionChangedLi
fAddToFavoritesAction = new AddToFavoritesAction();
fEditSourceAction = new EditSourceLookupPathAction(this);
fLookupAction = new LookupSourceAction(this);
- setAction(FIND_ACTION, new FindElementAction(this, (AsynchronousTreeViewer) getViewer()));
+ //setAction(FIND_ACTION, new FindElementAction(this, (AsynchronousTreeViewer) getViewer()));
IWorkbenchWindow window = getSite().getWorkbenchWindow();
@@ -287,8 +287,9 @@ public class LaunchView extends AbstractDebugView implements ISelectionChangedLi
* @see org.eclipse.debug.ui.AbstractDebugView#createViewer(org.eclipse.swt.widgets.Composite)
*/
protected Viewer createViewer(Composite parent) {
- AsynchronousTreeViewer viewer = new LaunchViewer(parent, this);
- viewer.setContext(new PresentationContext(this));
+ TreeModelViewer viewer = new TreeModelViewer(parent,
+ SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.VIRTUAL,
+ new PresentationContext(this));
viewer.addSelectionChangedListener(this);
viewer.getControl().addKeyListener(new KeyAdapter() {
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/memory/MemoryViewTreeViewer.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/memory/MemoryViewTreeViewer.java
index 6001b2e59..a855596d1 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/memory/MemoryViewTreeViewer.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/memory/MemoryViewTreeViewer.java
@@ -97,7 +97,7 @@ public class MemoryViewTreeViewer extends AsynchronousTreeViewer {
if ((flags & IModelDelta.REPLACED) != 0) {
}
- updateNodes(node.getNodes());
+ updateNodes(node.getChildDeltas());
}
}
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/variables/ToggleShowColumnsAction.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/variables/ToggleShowColumnsAction.java
index efae55c12..7e9a1046c 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/variables/ToggleShowColumnsAction.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/variables/ToggleShowColumnsAction.java
@@ -13,7 +13,7 @@ package org.eclipse.debug.internal.ui.views.variables;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.IDebugHelpContextIds;
import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
-import org.eclipse.debug.internal.ui.viewers.AsynchronousTreeViewer;
+import org.eclipse.debug.internal.ui.model.viewers.TreeModelViewer;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
@@ -29,9 +29,9 @@ import org.eclipse.ui.texteditor.IUpdate;
*/
public class ToggleShowColumnsAction extends Action implements IUpdate {
- private AsynchronousTreeViewer fViewer;
+ private TreeModelViewer fViewer;
- public ToggleShowColumnsAction(AsynchronousTreeViewer viewew) {
+ public ToggleShowColumnsAction(TreeModelViewer viewew) {
super(VariablesViewMessages.ToggleShowColumnsAction_0, IAction.AS_CHECK_BOX);
fViewer = viewew;
setToolTipText(VariablesViewMessages.ToggleShowColumnsAction_1);
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/variables/VariablesView.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/variables/VariablesView.java
index 67dc42609..f266369bd 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/variables/VariablesView.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/variables/VariablesView.java
@@ -18,15 +18,11 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.Iterator;
-import java.util.LinkedHashMap;
import java.util.List;
import java.util.ResourceBundle;
import org.eclipse.core.commands.operations.IUndoContext;
-
-import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
@@ -47,18 +43,21 @@ import org.eclipse.debug.internal.ui.LazyModelPresentation;
import org.eclipse.debug.internal.ui.VariablesViewModelPresentation;
import org.eclipse.debug.internal.ui.actions.CollapseAllAction;
import org.eclipse.debug.internal.ui.actions.ConfigureColumnsAction;
-import org.eclipse.debug.internal.ui.actions.FindElementAction;
import org.eclipse.debug.internal.ui.actions.variables.AssignValueAction;
import org.eclipse.debug.internal.ui.actions.variables.ChangeVariableValueAction;
import org.eclipse.debug.internal.ui.actions.variables.ShowTypesAction;
import org.eclipse.debug.internal.ui.actions.variables.ToggleDetailPaneAction;
import org.eclipse.debug.internal.ui.contexts.DebugContextManager;
import org.eclipse.debug.internal.ui.contexts.provisional.IDebugContextListener;
+import org.eclipse.debug.internal.ui.model.viewers.IViewerUpdateListener;
+import org.eclipse.debug.internal.ui.model.viewers.TreeModelViewer;
import org.eclipse.debug.internal.ui.preferences.IDebugPreferenceConstants;
-import org.eclipse.debug.internal.ui.viewers.AsynchronousTreeViewer;
import org.eclipse.debug.internal.ui.viewers.PresentationContext;
+import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousRequestMonitor;
+import org.eclipse.debug.internal.ui.viewers.provisional.IModelChangedListener;
+import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.provisional.IModelDeltaVisitor;
import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
-import org.eclipse.debug.internal.ui.views.AbstractViewerState;
import org.eclipse.debug.internal.ui.views.IDebugExceptionHandler;
import org.eclipse.debug.ui.AbstractDebugView;
import org.eclipse.debug.ui.IDebugModelPresentation;
@@ -100,6 +99,7 @@ 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.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
@@ -132,6 +132,7 @@ import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.operations.OperationHistoryActionHandler;
import org.eclipse.ui.operations.RedoActionHandler;
import org.eclipse.ui.operations.UndoActionHandler;
+import org.eclipse.ui.progress.UIJob;
import org.eclipse.ui.progress.WorkbenchJob;
import org.eclipse.ui.texteditor.FindReplaceAction;
import org.eclipse.ui.texteditor.IAbstractTextEditorHelpContextIds;
@@ -146,9 +147,9 @@ import com.ibm.icu.text.MessageFormat;
* This view shows variables and their values for a particular stack frame
*/
public class VariablesView extends AbstractDebugView implements IDebugContextListener,
- IPropertyChangeListener,
- IDebugExceptionHandler,
- IPerspectiveListener {
+ IPropertyChangeListener, IDebugExceptionHandler,
+ IPerspectiveListener, IModelChangedListener,
+ IViewerUpdateListener {
/**
* Internal interface for a cursor listener. I.e. aggregation
@@ -157,44 +158,6 @@ public class VariablesView extends AbstractDebugView implements IDebugContextLis
*/
interface ICursorListener extends MouseListener, KeyListener {
}
-
- /**
- * Most recently used variant with capped size that only counts
- * {@linkplain #put(Object, Object) put} as access. This is implemented by always removing an
- * element before it gets put back.
- *
- * @since 3.2
- */
- private static final class MRUMap extends LinkedHashMap {
- private static final long serialVersionUID= 1L;
- private final int fMaxSize;
-
- /**
- * Creates a new <code>MRUMap</code> with the given size.
- *
- * @param maxSize the maximum size of the cache, must be &gt; 0
- */
- public MRUMap(int maxSize) {
- Assert.isLegal(maxSize > 0);
- fMaxSize= maxSize;
- }
-
- /*
- * @see java.util.HashMap#put(java.lang.Object, java.lang.Object)
- */
- public Object put(Object key, Object value) {
- Object object= remove(key);
- super.put(key, value);
- return object;
- }
-
- /*
- * @see java.util.LinkedHashMap#removeEldestEntry(java.util.Map.Entry)
- */
- protected boolean removeEldestEntry(java.util.Map.Entry eldest) {
- return size() > fMaxSize;
- }
- }
/**
* The selection provider for the variables view changes depending on whether
@@ -263,14 +226,22 @@ public class VariablesView extends AbstractDebugView implements IDebugContextLis
}
}
public void run() {
- getFindAction().run();
+ IAction findAction = getFindAction();
+ if (findAction != null) {
+ findAction.run();
+ }
}
/* (non-Javadoc)
* @see org.eclipse.ui.texteditor.IUpdate#update()
*/
public void update() {
- setEnabled(getFindAction().isEnabled());
+ IAction findAction = getFindAction();
+ if (findAction != null) {
+ setEnabled(findAction.isEnabled());
+ } else {
+ setEnabled(false);
+ }
}
}
@@ -426,21 +397,6 @@ public class VariablesView extends AbstractDebugView implements IDebugContextLis
private List fSelectionActions = new ArrayList(3);
/**
- * An MRU cache of stack frame hash codes to <code>ViewerState</code>s.
- * Used to restore the expanded state of the variables view on
- * re-selection of the same stack frame. The cache is limited
- * to twenty entries.
- */
- private HashMap fSelectionStates = new MRUMap(20);
-
- /**
- * The last known viewer state. Used to initialize the expansion/selection
- * in the variables view when there is no state to go on for the
- * current stack frame being displayed.
- */
- private AbstractViewerState fLastState = null;
-
- /**
* Remembers which viewer (tree viewer or details viewer) had focus, so we
* can reset the focus properly when re-activated.
*/
@@ -506,6 +462,54 @@ public class VariablesView extends AbstractDebugView implements IDebugContextLis
/** Whether logical structures are showing */
private boolean fShowLogical;
+
+ /**
+ * Visits deltas to determine if details should be displayed
+ */
+ class Visitor implements IModelDeltaVisitor {
+ /**
+ * Whether to trigger details display.
+ *
+ * @since 3.3
+ */
+ private boolean fTriggerDetails = false;
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.provisional.IModelDeltaVisitor#visit(org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta, int)
+ */
+ public boolean visit(IModelDelta delta, int depth) {
+ if ((delta.getFlags() & IModelDelta.CONTENT) > 0) {
+ fTriggerDetails = true;
+ return false;
+ }
+ return true;
+ }
+
+ public void reset() {
+ fTriggerDetails = false;
+ }
+
+ public boolean isTriggerDetails() {
+ return fTriggerDetails;
+ }
+
+ }
+ /**
+ * Delta visitor
+ */
+ private Visitor fVisitor = new Visitor();
+
+ /**
+ * Job to update details in the UI thread.
+ */
+ private Job fTriggerDetailsJob = new UIJob("trigger details") { //$NON-NLS-1$
+
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ populateDetailPane();
+ return Status.OK_STATUS;
+ }
+
+ };
+
/**
* Remove myself as a selection listener
* and preference change listener.
@@ -518,15 +522,12 @@ public class VariablesView extends AbstractDebugView implements IDebugContextLis
getSite().getWorkbenchWindow().removePerspectiveListener(this);
DebugUIPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(this);
JFaceResources.getFontRegistry().removeListener(this);
- Viewer viewer = getViewer();
+ TreeModelViewer viewer = getVariablesViewer();
if (viewer != null) {
getDetailDocument().removeDocumentListener(getDetailDocumentListener());
- if (viewer instanceof AsynchronousTreeViewer) {
- AsynchronousTreeViewer asyncTreeViewer = (AsynchronousTreeViewer) viewer;
- asyncTreeViewer.dispose();
- }
+ viewer.removeModelChangedListener(this);
+ viewer.removeViewerUpdateListener(this);
}
- fSelectionStates.clear();
super.dispose();
}
@@ -549,79 +550,15 @@ public class VariablesView extends AbstractDebugView implements IDebugContextLis
if (current != null && current.equals(context)) {
return;
- }
-
- if (current != null) {
- // save state
- AbstractViewerState state = getViewerState();
- cacheViewerState(current, state);
- fLastState = (AbstractViewerState) state.clone();
- }
+ }
if (context instanceof IDebugElement) {
setDebugModel(((IDebugElement)context).getModelIdentifier());
}
showViewer();
getViewer().setInput(context);
- restoreState();
- }
-
- /**
- * Caches the given viewer state for the given viewer input.
- *
- * @param input viewer input
- * @param state viewer state
- */
- protected void cacheViewerState(Object input, AbstractViewerState state) {
- // generate a key for the input based on its hash code, we don't
- // want to maintain reference real model objects preventing GCs.
- fSelectionStates.put(generateKey(input), state);
- }
-
- /**
- * Generate a key for an input object.
- *
- * @param input
- * @return key
- */
- protected Object generateKey(Object input) {
- return new Integer(input.hashCode());
- }
-
- /**
- * Returns the cached viewer state for the given viewer input or
- * <code>null</code> if none.
- *
- * @param input viewer input
- * @return viewer state or <code>null</code>
- */
- protected AbstractViewerState getCachedViewerState(Object input) {
- return (AbstractViewerState) fSelectionStates.get(generateKey(input));
}
-
- /**
- * Restores the state of the viewer
- */
- protected void restoreState() {
- VariablesViewer viewer = (VariablesViewer) getViewer();
- if (viewer != null) {
- Object context = viewer.getInput();
- if (context != null) {
- AbstractViewerState state = getCachedViewerState(context);
- if (state == null) {
- // attempt to restore selection/expansion based on last
- // frame
- if (fLastState != null) {
- state = fLastState;
- }
- }
- if (state != null) {
- state.restoreState(viewer);
- }
- }
- }
- }
-
+
/**
* Configures the details viewer for the debug model
* currently being displayed
@@ -671,8 +608,7 @@ public class VariablesView extends AbstractDebugView implements IDebugContextLis
* @see org.eclipse.debug.ui.AbstractDebugView#createViewer(Composite)
*/
public Viewer createViewer(Composite parent) {
- VariablesViewer variablesViewer = (VariablesViewer) createTreeViewer(parent);
- variablesViewer.setContext(new PresentationContext(this));
+ TreeModelViewer variablesViewer = createTreeViewer(parent);
variablesViewer.getPresentationContext().addPropertyChangeListener(
new IPropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
@@ -699,6 +635,8 @@ public class VariablesView extends AbstractDebugView implements IDebugContextLis
if (memento != null) {
variablesViewer.initState(memento);
}
+ variablesViewer.addModelChangedListener(this);
+ variablesViewer.addViewerUpdateListener(this);
return variablesViewer;
}
@@ -796,7 +734,7 @@ public class VariablesView extends AbstractDebugView implements IDebugContextLis
/**
* Create and return the main tree viewer that displays variable.
*/
- protected Viewer createTreeViewer(Composite parent) {
+ protected TreeModelViewer createTreeViewer(Composite parent) {
fModelPresentation = new VariablesViewModelPresentation();
DebugUIPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(this);
JFaceResources.getFontRegistry().addListener(this);
@@ -805,7 +743,8 @@ public class VariablesView extends AbstractDebugView implements IDebugContextLis
fSashForm = new SashForm(parent, SWT.NONE);
// add tree viewer
- final VariablesViewer variablesViewer = createVariablesViewer(fSashForm);
+ int style = getViewerStyle();
+ final TreeModelViewer variablesViewer = new TreeModelViewer(fSashForm, style, new PresentationContext(this));
variablesViewer.getControl().addFocusListener(new FocusAdapter() {
/* (non-Javadoc)
* @see org.eclipse.swt.events.FocusListener#focusGained(FocusEvent)
@@ -828,13 +767,12 @@ public class VariablesView extends AbstractDebugView implements IDebugContextLis
}
/**
- * Creates and returns a variables viewer in the given composite.
+ * Returns the style bits for the viewer.
*
- * @param parent
- * @return variables viewer
+ * @return SWT style
*/
- protected VariablesViewer createVariablesViewer(Composite parent) {
- return new VariablesViewer(parent, SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL | SWT.VIRTUAL | SWT.FULL_SELECTION, this);
+ protected int getViewerStyle() {
+ return SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL | SWT.VIRTUAL | SWT.FULL_SELECTION;
}
/**
@@ -1006,7 +944,7 @@ public class VariablesView extends AbstractDebugView implements IDebugContextLis
action = new ToggleLogicalStructureAction(this);
setAction("ToggleContentProviders", action); //$NON-NLS-1$
- action = new CollapseAllAction((AsynchronousTreeViewer)getViewer());
+ action = new CollapseAllAction((TreeViewer)getViewer());
setAction("CollapseAll", action); //$NON-NLS-1$
action = new ChangeVariableValueAction(this);
@@ -1045,8 +983,9 @@ public class VariablesView extends AbstractDebugView implements IDebugContextLis
textAction.setActionDefinitionId(IWorkbenchActionDefinitionIds.PASTE);
setAction(ActionFactory.PASTE.getId(), textAction);
- action= new FindElementAction(this, getVariablesViewer());
- setAction(FIND_ELEMENT, action);
+ //TODO:
+ //action= new FindElementAction(this, getVariablesViewer());
+ //setAction(FIND_ELEMENT, action);
// TODO: Still using "old" resource access
ResourceBundle bundle= ResourceBundle.getBundle("org.eclipse.debug.internal.ui.views.variables.VariablesViewResourceBundleMessages"); //$NON-NLS-1$
@@ -1119,7 +1058,7 @@ public class VariablesView extends AbstractDebugView implements IDebugContextLis
return null;
}
- private void createOrientationActions(VariablesViewer viewer) {
+ private void createOrientationActions(TreeModelViewer viewer) {
IActionBars actionBars = getViewSite().getActionBars();
IMenuManager viewMenu = actionBars.getMenuManager();
@@ -1184,7 +1123,8 @@ public class VariablesView extends AbstractDebugView implements IDebugContextLis
menu.add(new Separator(IDebugUIConstants.EMPTY_VARIABLE_GROUP));
menu.add(new Separator(IDebugUIConstants.VARIABLE_GROUP));
- menu.add(getAction(FIND_ELEMENT));
+ // TODO:
+ //menu.add(getAction(FIND_ELEMENT));
menu.add(getAction("ChangeVariableValue")); //$NON-NLS-1$
IAction action = new AvailableLogicalStructuresAction(this);
if (action.isEnabled()) {
@@ -1270,9 +1210,12 @@ public class VariablesView extends AbstractDebugView implements IDebugContextLis
if (fDetailsJob != null) {
fDetailsJob.cancel();
}
- fDetailsJob = new DetailJob(selection);
- setDetails(""); //$NON-NLS-1$
- fDetailsJob.schedule();
+ if (selection.isEmpty()) {
+ setDetails(""); //$NON-NLS-1$
+ } else {
+ fDetailsJob = new DetailJob(selection);
+ fDetailsJob.schedule();
+ }
}
}
@@ -1595,18 +1538,9 @@ public class VariablesView extends AbstractDebugView implements IDebugContextLis
ISelection selection = DebugContextManager.getDefault().getActiveContext(getSite().getWorkbenchWindow());
contextActivated(selection, null);
}
-
- /**
- * Returns the memento of the expanded and selected items in the viewer.
- *
- * @return the memento of the expanded and selected items in the viewer
- */
- protected AbstractViewerState getViewerState() {
- return new ViewerState(getVariablesViewer());
- }
- protected VariablesViewer getVariablesViewer() {
- return (VariablesViewer) getViewer();
+ protected TreeModelViewer getVariablesViewer() {
+ return (TreeModelViewer) getViewer();
}
/**
@@ -1697,5 +1631,40 @@ public class VariablesView extends AbstractDebugView implements IDebugContextLis
setLastSashWeights(DEFAULT_SASH_WEIGHTS);
fSashForm.setWeights(DEFAULT_SASH_WEIGHTS);
}
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.provisional.IModelChangedListener#modelChanged(org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta)
+ */
+ public void modelChanged(IModelDelta delta) {
+ fVisitor.reset();
+ delta.accept(fVisitor);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.viewers.IViewerUpdateListener#updateComplete(org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousRequestMonitor)
+ */
+ public void updateComplete(IAsynchronousRequestMonitor update) {
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.viewers.IViewerUpdateListener#updateStarted(org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousRequestMonitor)
+ */
+ public void updateStarted(IAsynchronousRequestMonitor update) {
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.viewers.IViewerUpdateListener#viewerUpdatesBegin()
+ */
+ public void viewerUpdatesBegin() {
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.viewers.IViewerUpdateListener#viewerUpdatesComplete()
+ */
+ public void viewerUpdatesComplete() {
+ if (fVisitor.isTriggerDetails()) {
+ fTriggerDetailsJob.schedule();
+ }
}
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/variables/VariablesViewer.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/variables/VariablesViewer.java
deleted file mode 100644
index 2a192de87..000000000
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/variables/VariablesViewer.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2006 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.views.variables;
-
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.debug.internal.ui.viewers.AsynchronousTreeViewer;
-import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousRequestMonitor;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.ui.progress.UIJob;
-
-/**
- * @since 3.2
- *
- */
-public class VariablesViewer extends AsynchronousTreeViewer{
-
- private VariablesView fView;
-
- private UIJob fRestoreJob = new UIJob("restore viewer state") { //$NON-NLS-1$
- public IStatus runInUIThread(IProgressMonitor monitor) {
- fView.restoreState();
- return Status.OK_STATUS;
- }
- };
-
- public VariablesViewer(Composite parent, int style, VariablesView view) {
- super(parent, style);
- fView = view;
- fRestoreJob.setSystem(true);
- }
-
- protected void updateComplete(IAsynchronousRequestMonitor update) {
- if (fView != null && !hasPendingUpdates()) {
- fRestoreJob.schedule();
- fView.populateDetailPane();
- }
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.treeviewer.AsynchronousTreeViewer#handlePresentationFailure(org.eclipse.debug.internal.ui.treeviewer.IPresentationRequestMonitor, org.eclipse.core.runtime.IStatus)
- */
- protected void handlePresentationFailure(IAsynchronousRequestMonitor update, IStatus status) {
- fView.showMessage(status.getMessage());
- }
-
-}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/ui/InspectPopupDialog.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/ui/InspectPopupDialog.java
index 308b5b90f..2a7b2944b 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/ui/InspectPopupDialog.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/ui/InspectPopupDialog.java
@@ -11,9 +11,7 @@
package org.eclipse.debug.ui;
-import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.DebugException;
@@ -23,16 +21,15 @@ import org.eclipse.debug.core.model.IValue;
import org.eclipse.debug.core.model.IVariable;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.VariablesViewModelPresentation;
+import org.eclipse.debug.internal.ui.model.elements.ElementContentProvider;
+import org.eclipse.debug.internal.ui.model.viewers.TreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.PresentationContext;
-import org.eclipse.debug.internal.ui.viewers.provisional.AsynchronousContentAdapter;
import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.views.DebugUIViewsMessages;
import org.eclipse.debug.internal.ui.views.variables.IndexedVariablePartition;
import org.eclipse.debug.internal.ui.views.variables.VariablesView;
-import org.eclipse.debug.internal.ui.views.variables.VariablesViewer;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.TreePath;
-import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
@@ -72,7 +69,7 @@ public class InspectPopupDialog extends DebugPopup {
private static final int MIN_HEIGHT = 200;
- private VariablesViewer fVariablesViewer;
+ private TreeModelViewer fViewer;
private IDebugModelPresentation fModelPresentation;
@@ -112,23 +109,18 @@ public class InspectPopupDialog extends DebugPopup {
fSashForm.setLayoutData(new GridData(GridData.FILL_BOTH));
VariablesView view = getViewToEmulate();
-
- fVariablesViewer = new VariablesViewer(fSashForm, SWT.NO_TRIM | SWT.VIRTUAL, null);
-
IPresentationContext context;
if (view == null) {
context = new PresentationContext(IDebugUIConstants.ID_VARIABLE_VIEW);
} else {
- context = new PresentationContext(view);
+ context = ((TreeModelViewer)view.getViewer()).getPresentationContext();
}
- fVariablesViewer.setContext(context);
+ fViewer = new TreeModelViewer(fSashForm, SWT.NO_TRIM | SWT.VIRTUAL, context);
fModelPresentation = new VariablesViewModelPresentation();
- fVariablesViewer.setLabelProvider(fModelPresentation);
-
fValueDisplay = new StyledText(fSashForm, SWT.NO_TRIM | SWT.WRAP | SWT.V_SCROLL);
fValueDisplay.setEditable(false);
- fTree = fVariablesViewer.getTree();
+ fTree = fViewer.getTree();
fTree.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
try {
@@ -165,41 +157,44 @@ public class InspectPopupDialog extends DebugPopup {
// sashForm.setWeights(getInitialSashWeights());
fSashForm.setWeights(DEFAULT_SASH_WEIGHTS);
- fVariablesViewer.getContentProvider();
+ fViewer.getContentProvider();
if (view != null) {
StructuredViewer structuredViewer = (StructuredViewer) view.getViewer();
if (structuredViewer != null) {
ViewerFilter[] filters = structuredViewer.getFilters();
for (int i = 0; i < filters.length; i++) {
- fVariablesViewer.addFilter(filters[i]);
+ fViewer.addFilter(filters[i]);
}
}
-
- Map map = view.getPresentationAttributes(fExpression.getModelIdentifier());
- Iterator iterator = map.keySet().iterator();
- while (iterator.hasNext()) {
- String key = (String) iterator.next();
- fModelPresentation.setAttribute(key, map.get(key));
- }
}
TreeRoot treeRoot = new TreeRoot();
- fVariablesViewer.setInput(treeRoot);
- fVariablesViewer.expand(new TreeSelection(new TreePath(new Object[] {treeRoot, fExpression})));
+ fViewer.setInput(treeRoot);
+ fViewer.expandToLevel(new TreePath(new Object[] {fExpression}), 1);
return fTree;
}
- private class TreeRoot extends AsynchronousContentAdapter {
- protected Object[] getChildren(Object parent, IPresentationContext context) throws CoreException {
- return new Object[] { fExpression };
- }
- protected boolean hasChildren(Object element, IPresentationContext context) throws CoreException {
- return true;
- }
- protected boolean supportsPartId(String id) {
- return true;
- }
+ private class TreeRoot extends ElementContentProvider {
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#getChildCount(java.lang.Object, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext)
+ */
+ protected int getChildCount(Object element, IPresentationContext context) throws CoreException {
+ return 1;
+ }
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#getChildren(java.lang.Object, int, int, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext)
+ */
+ protected Object[] getChildren(Object parent, int index, int length, IPresentationContext context) throws CoreException {
+ return new Object[] { fExpression };
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.model.elements.ElementContentProvider#supportsContextId(java.lang.String)
+ */
+ protected boolean supportsContextId(String id) {
+ return true;
+ }
}
private void updateValueDisplay(IValue val) {
@@ -242,9 +237,6 @@ public class InspectPopupDialog extends DebugPopup {
* @see org.eclipse.debug.ui.DebugPopup#close()
*/
public boolean close() {
- if(fVariablesViewer != null) {
- fVariablesViewer.dispose();
- }
if(fModelPresentation != null) {
fModelPresentation.dispose();
}

Back to the top