Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPawel Piech2011-12-01 15:11:58 -0500
committerPawel Piech2011-12-01 15:11:58 -0500
commit442033718d71f1bf4a24506ba2f5a065ffd25221 (patch)
tree6d5007903ef9e9ad6cccc74b31608839b418446f /org.eclipse.debug.ui
parent95d71ceea2950ced3f11676734c7c019051a2c77 (diff)
downloadeclipse.platform.debug-442033718d71f1bf4a24506ba2f5a065ffd25221.tar.gz
eclipse.platform.debug-442033718d71f1bf4a24506ba2f5a065ffd25221.tar.xz
eclipse.platform.debug-442033718d71f1bf4a24506ba2f5a065ffd25221.zip
Bug 161435 - [flex] Promote asynchronous viewer framework to API -v20111201-2011
(merge flex_viewer_refactor branch into master)
Diffstat (limited to 'org.eclipse.debug.ui')
-rw-r--r--org.eclipse.debug.ui/.settings/.api_filters132
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ActionMessages.java2
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ActionMessages.properties1
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ChildrenCountUpdate.java114
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ChildrenUpdate.java102
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ElementCompareRequest.java55
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ElementMementoRequest.java49
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/FilterTransform.java37
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/HasChildrenUpdate.java39
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/IInternalTreeModelViewer.java (renamed from org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelContentProviderTarget.java)146
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/IMementoManager.java43
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelCheckProviderTarget.java50
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelContentProvider.java50
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelLabelProvider.java10
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelLabelProviderTarget.java54
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelViewer.java211
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/InternalTreeModelViewer.java809
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/InternalVirtualTreeModelViewer.java187
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/LabelUpdate.java3
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/MementoUpdate.java15
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ModelContentProvider.java2285
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/SubTreeModelViewer.java62
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/TreeCursor.java724
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/TreeModelContentProvider.java1589
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/TreeModelLabelProvider.java301
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ViewerStateTracker.java1585
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ViewerUpdateMonitor.java97
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/VirtualCopyToClipboardActionDelegate.java413
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/VirtualFindAction.java276
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ICheckUpdate.java6
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ICheckboxModelProxy.java5
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IChildrenCountUpdate.java7
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IChildrenUpdate.java11
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IColumnPresentation.java4
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementCompareRequest.java7
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementContentProvider.java9
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementEditor.java6
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementLabelProvider.java7
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementMementoProvider.java7
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IHasChildrenUpdate.java7
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ILabelUpdate.java17
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelChangedListener.java4
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelDelta.java10
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelProxy.java22
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelProxy2.java42
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelSelectionPolicy.java25
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IStateUpdateListener.java12
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ITreeModelViewer.java278
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IViewerUpdate.java7
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IVirtualItemListener.java28
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IVirtualItemValidator.java38
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ModelDelta.java18
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/PresentationContext.java3
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/TreeModelViewer.java16
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/TreeModelViewerFilter.java36
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ViewerInputService.java7
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/VirtualItem.java (renamed from org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/VirtualItem.java)228
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/VirtualTree.java (renamed from org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/VirtualTree.java)145
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/VirtualTreeModelViewer.java49
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/provisional/AbstractModelProxy.java92
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsView.java2
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/launch/LaunchView.java2
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/launch/LaunchViewCopyToClipboardActionDelegate.java9
63 files changed, 5225 insertions, 5382 deletions
diff --git a/org.eclipse.debug.ui/.settings/.api_filters b/org.eclipse.debug.ui/.settings/.api_filters
index 42b56487b..de6e83394 100644
--- a/org.eclipse.debug.ui/.settings/.api_filters
+++ b/org.eclipse.debug.ui/.settings/.api_filters
@@ -1,74 +1,58 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<component id="org.eclipse.debug.ui" version="2">
- <resource path="ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationViewer.java" type="org.eclipse.debug.internal.ui.launchConfigurations.LaunchConfigurationViewer">
- <filter comment="Known illegal extension" id="571473929">
- <message_arguments>
- <message_argument value="TreeViewer"/>
- <message_argument value="LaunchConfigurationViewer"/>
- </message_arguments>
- </filter>
- </resource>
- <resource path="ui/org/eclipse/debug/internal/ui/preferences/LaunchPerspectivePreferencePage.java" type="org.eclipse.debug.internal.ui.preferences.LaunchPerspectivePreferencePage$PerspectivesTreeViewer">
- <filter comment="Known illegal extension" id="571473929">
- <message_arguments>
- <message_argument value="TreeViewer"/>
- <message_argument value="PerspectivesTreeViewer"/>
- </message_arguments>
- </filter>
- </resource>
- <resource path="ui/org/eclipse/debug/internal/ui/sourcelookup/SourceContainerViewer.java" type="org.eclipse.debug.internal.ui.sourcelookup.SourceContainerViewer">
- <filter comment="Known illegal extension" id="571473929">
- <message_arguments>
- <message_argument value="TreeViewer"/>
- <message_argument value="SourceContainerViewer"/>
- </message_arguments>
- </filter>
- </resource>
- <resource path="ui/org/eclipse/debug/internal/ui/sourcelookup/browsers/ProjectSourceContainerDialog.java" type="org.eclipse.debug.internal.ui.sourcelookup.browsers.ProjectSourceContainerDialog">
- <filter comment="Known illegal extension" id="571473929">
- <message_arguments>
- <message_argument value="ListSelectionDialog"/>
- <message_argument value="ProjectSourceContainerDialog"/>
- </message_arguments>
- </filter>
- </resource>
- <resource path="ui/org/eclipse/debug/internal/ui/viewers/model/InternalTreeModelViewer.java" type="org.eclipse.debug.internal.ui.viewers.model.InternalTreeModelViewer">
- <filter comment="Known illegal extension" id="571473929">
- <message_arguments>
- <message_argument value="TreeViewer"/>
- <message_argument value="InternalTreeModelViewer"/>
- </message_arguments>
- </filter>
- </resource>
- <resource path="ui/org/eclipse/debug/internal/ui/viewers/model/TreeCursor.java" type="org.eclipse.debug.internal.ui.viewers.model.TreeCursor">
- <filter comment="Known illegal reference" id="640708718">
- <message_arguments>
- <message_argument value="TypedListener(SWTEventListener)"/>
- <message_argument value="TreeCursor"/>
- </message_arguments>
- </filter>
- </resource>
- <resource path="ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsViewer.java" type="org.eclipse.debug.internal.ui.views.breakpoints.BreakpointsViewer">
- <filter comment="Known illegal extension" id="571473929">
- <message_arguments>
- <message_argument value="CheckboxTreeViewer"/>
- <message_argument value="BreakpointsViewer"/>
- </message_arguments>
- </filter>
- </resource>
- <resource path="ui/org/eclipse/debug/ui/actions/AbstractLaunchHistoryAction.java" type="org.eclipse.debug.ui.actions.AbstractLaunchHistoryAction">
- <filter comment="Known leaked internal types" id="576725006">
- <message_arguments>
- <message_argument value="ILaunchHistoryChangedListener"/>
- <message_argument value="AbstractLaunchHistoryAction"/>
- </message_arguments>
- </filter>
- <filter comment="Known leaked internal types" id="643842064">
- <message_arguments>
- <message_argument value="LaunchHistory"/>
- <message_argument value="AbstractLaunchHistoryAction"/>
- <message_argument value="getLaunchHistory()"/>
- </message_arguments>
- </filter>
- </resource>
-</component>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<component id="org.eclipse.debug.ui" version="2">
+ <resource path="ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationViewer.java" type="org.eclipse.debug.internal.ui.launchConfigurations.LaunchConfigurationViewer">
+ <filter comment="Known illegal extension" id="571473929">
+ <message_arguments>
+ <message_argument value="TreeViewer"/>
+ <message_argument value="LaunchConfigurationViewer"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="ui/org/eclipse/debug/internal/ui/preferences/LaunchPerspectivePreferencePage.java" type="org.eclipse.debug.internal.ui.preferences.LaunchPerspectivePreferencePage$PerspectivesTreeViewer">
+ <filter comment="Known illegal extension" id="571473929">
+ <message_arguments>
+ <message_argument value="TreeViewer"/>
+ <message_argument value="PerspectivesTreeViewer"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="ui/org/eclipse/debug/internal/ui/sourcelookup/SourceContainerViewer.java" type="org.eclipse.debug.internal.ui.sourcelookup.SourceContainerViewer">
+ <filter comment="Known illegal extension" id="571473929">
+ <message_arguments>
+ <message_argument value="TreeViewer"/>
+ <message_argument value="SourceContainerViewer"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="ui/org/eclipse/debug/internal/ui/sourcelookup/browsers/ProjectSourceContainerDialog.java" type="org.eclipse.debug.internal.ui.sourcelookup.browsers.ProjectSourceContainerDialog">
+ <filter comment="Known illegal extension" id="571473929">
+ <message_arguments>
+ <message_argument value="ListSelectionDialog"/>
+ <message_argument value="ProjectSourceContainerDialog"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsViewer.java" type="org.eclipse.debug.internal.ui.views.breakpoints.BreakpointsViewer">
+ <filter comment="Known illegal extension" id="571473929">
+ <message_arguments>
+ <message_argument value="CheckboxTreeViewer"/>
+ <message_argument value="BreakpointsViewer"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="ui/org/eclipse/debug/ui/actions/AbstractLaunchHistoryAction.java" type="org.eclipse.debug.ui.actions.AbstractLaunchHistoryAction">
+ <filter comment="Known leaked internal types" id="576725006">
+ <message_arguments>
+ <message_argument value="ILaunchHistoryChangedListener"/>
+ <message_argument value="AbstractLaunchHistoryAction"/>
+ </message_arguments>
+ </filter>
+ <filter comment="Known leaked internal types" id="643842064">
+ <message_arguments>
+ <message_argument value="LaunchHistory"/>
+ <message_argument value="AbstractLaunchHistoryAction"/>
+ <message_argument value="getLaunchHistory()"/>
+ </message_arguments>
+ </filter>
+ </resource>
+</component>
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ActionMessages.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ActionMessages.java
index 5c3a331ac..d4ed16c31 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ActionMessages.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ActionMessages.java
@@ -228,8 +228,8 @@ public class ActionMessages extends NLS {
public static String ShowTypesAction_0;
public static String VirtualFindAction_0;
-
public static String VirtualFindAction_1;
+ public static String VirtualFindAction_2;
public static String ToggleBreakpointsTargetManager_defaultToggleTarget_name;
public static String ToggleBreakpointsTargetManager_defaultToggleTarget_description;
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ActionMessages.properties b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ActionMessages.properties
index ad9f0e542..7401d0707 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ActionMessages.properties
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ActionMessages.properties
@@ -212,6 +212,7 @@ RunLastAction_3=Run the previously launched application
OpenLaunchDialogAction_1={0} Configurations...
VirtualFindAction_0=Error
VirtualFindAction_1=Unable to locate {0} in viewer
+VirtualFindAction_2=Element no longer in viewer.
ToggleBreakpointsTargetManager_defaultToggleTarget_name = Default
ToggleBreakpointsTargetManager_defaultToggleTarget_description = Default
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ChildrenCountUpdate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ChildrenCountUpdate.java
index e8201125f..561697522 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ChildrenCountUpdate.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ChildrenCountUpdate.java
@@ -17,7 +17,6 @@ import java.util.List;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.jface.viewers.TreePath;
/**
@@ -25,23 +24,101 @@ import org.eclipse.jface.viewers.TreePath;
*/
class ChildrenCountUpdate extends ViewerUpdateMonitor implements IChildrenCountUpdate {
+ /**
+ * Child count result.
+ */
private int fCount = 0;
+ /**
+ * Other child count updates for the same content provider. Coalesced requests are
+ * batched together into an array.
+ */
private List fBatchedRequests = null;
+ /**
+ * Flag whether filtering is enabled in viewer. If filtering is enabled, then a
+ * children update is performed on child elements to filter them as part of the
+ * child count calculation.
+ */
+ private boolean fShouldFilter = false;
+
+ /**
+ * Children indexes which are currently filtered. When updating child count, also need
+ * to verify that currently filtered children are still filtered.
+ */
+ private int[] fFilteredChildren = null;
+
+ /**
+ * Children update used to filter children.
+ */
+ private ChildrenUpdate fChildrenUpdate;
+
/**
* Constructor
- * @param contentProvider the content provider to use for the update
+ * @param provider the content provider to use for the update
* @param viewerInput the current input
* @param elementPath the path of the element to update
* @param element the element to update
* @param elementContentProvider the content provider for the element
- * @param context the presentation context
*/
- public ChildrenCountUpdate(ModelContentProvider contentProvider, Object viewerInput, TreePath elementPath, Object element, IElementContentProvider elementContentProvider, IPresentationContext context) {
- super(contentProvider, viewerInput, elementPath, element, elementContentProvider, context);
+ public ChildrenCountUpdate(TreeModelContentProvider provider, Object viewerInput, TreePath elementPath, Object element, IElementContentProvider elementContentProvider) {
+ super(provider, viewerInput, elementPath, element, elementContentProvider, provider.getPresentationContext());
+ fShouldFilter = provider.areTreeModelViewerFiltersApplicable(element);
+ fFilteredChildren = provider.getFilteredChildren(elementPath);
+ }
+
+ public synchronized void cancel() {
+ if (fChildrenUpdate != null) {
+ fChildrenUpdate.cancel();
+ }
+ super.cancel();
}
+ protected synchronized void scheduleViewerUpdate() {
+ // If filtering is enabled perform child update on all children in order to update
+ // viewer filters.
+ if (fShouldFilter || fFilteredChildren != null) {
+ if (fChildrenUpdate == null) {
+ int startIdx;
+ int count;
+ if (fShouldFilter) {
+ startIdx = 0;
+ count = getCount();
+ } else {
+ startIdx = fFilteredChildren[0];
+ int endIdx = fFilteredChildren[fFilteredChildren.length - 1];
+ count = endIdx - startIdx + 1;
+ }
+
+ fChildrenUpdate = new ChildrenUpdate(getContentProvider(), getViewerInput(), getElementPath(), getElement(), startIdx, count, getElementContentProvider()) {
+ protected void performUpdate() {
+ performUpdate(true);
+ ChildrenCountUpdate.super.scheduleViewerUpdate();
+ }
+
+ protected void scheduleViewerUpdate() {
+ execInDisplayThread(new Runnable() {
+ public void run() {
+ if (!getContentProvider().isDisposed() && !isCanceled()) {
+ performUpdate();
+ }
+ }
+ });
+ }
+ };
+ execInDisplayThread(new Runnable() {
+ public void run() {
+ fChildrenUpdate.startRequest();
+ }
+ });
+ return;
+ }
+ } else {
+ super.scheduleViewerUpdate();
+ }
+ }
+
+
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.viewers.ViewerUpdateMonitor#performUpdate()
*/
@@ -54,11 +131,17 @@ class ChildrenCountUpdate extends ViewerUpdateMonitor implements IChildrenCountU
getContentProvider().setModelChildCount(elementPath, fCount);
viewCount = getContentProvider().modelToViewChildCount(elementPath, fCount);
}
- if (ModelContentProvider.DEBUG_CONTENT_PROVIDER && ModelContentProvider.DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
+ if (TreeModelContentProvider.DEBUG_CONTENT_PROVIDER && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
System.out.println("setChildCount(" + getElement() + ", modelCount: " + fCount + " viewCount: " + viewCount + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
- getContentProvider().getViewer().setChildCount(elementPath, viewCount);
- getContentProvider().restorePendingStateOnUpdate(getElementPath(), -1, true, true, false);
+ // Special case for element 0 in a set of filtered elements:
+ // Child 0 is automatically updated by the tree at the same time that the child count is requested. Therefore,
+ // If this child count update filtered out this element, it needs to be updated again.
+ if (fShouldFilter && getContentProvider().isFiltered(elementPath, 0)) {
+ getContentProvider().updateElement(elementPath, 0);
+ }
+ getContentProvider().getViewer().setChildCount(elementPath, viewCount);
+ getContentProvider().getStateTracker().restorePendingStateOnUpdate(getElementPath(), -1, true, true, false);
}
public void setChildCount(int numChildren) {
@@ -140,4 +223,19 @@ class ChildrenCountUpdate extends ViewerUpdateMonitor implements IChildrenCountU
}
return path;
}
+
+ int getCount() {
+ return fCount;
+ }
+
+ protected boolean doEquals(ViewerUpdateMonitor update) {
+ return
+ update instanceof ChildrenCountUpdate &&
+ getViewerInput().equals(update.getViewerInput()) &&
+ getElementPath().equals(getElementPath());
+ }
+
+ protected int doHashCode() {
+ return getClass().hashCode() + getViewerInput().hashCode() + getElementPath().hashCode();
+ }
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ChildrenUpdate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ChildrenUpdate.java
index 6375f6bdd..766c7601f 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ChildrenUpdate.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ChildrenUpdate.java
@@ -14,7 +14,6 @@ package org.eclipse.debug.internal.ui.viewers.model;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.jface.viewers.TreePath;
/**
@@ -37,24 +36,25 @@ public class ChildrenUpdate extends ViewerUpdateMonitor implements IChildrenUpda
* @param element the element
* @param index the index of the element
* @param elementContentProvider the content provider for the element
- * @param context the presentation context
*/
- public ChildrenUpdate(ModelContentProvider provider, Object viewerInput, TreePath elementPath, Object element, int index, IElementContentProvider elementContentProvider, IPresentationContext context) {
- super(provider, viewerInput, elementPath, element, elementContentProvider, context);
+ public ChildrenUpdate(TreeModelContentProvider provider, Object viewerInput, TreePath elementPath, Object element, int index, IElementContentProvider elementContentProvider) {
+ super(provider, viewerInput, elementPath, element, elementContentProvider, provider.getPresentationContext());
fIndex = index;
fLength = 1;
}
-
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.debug.ui.viewers.AsynchronousRequestMonitor#performUpdate()
- */
- protected void performUpdate() {
- TreeModelContentProvider provider = (TreeModelContentProvider) getContentProvider();
+
+ public ChildrenUpdate(TreeModelContentProvider provider, Object viewerInput, TreePath elementPath, Object element, int index, int length, IElementContentProvider elementContentProvider) {
+ super(provider, viewerInput, elementPath, element, elementContentProvider, provider.getPresentationContext());
+ fIndex = index;
+ fLength = length;
+ }
+
+
+ protected void performUpdate(boolean updateFilterOnly) {
+ TreeModelContentProvider provider = getContentProvider();
TreePath elementPath = getElementPath();
if (fElements != null) {
- ITreeModelContentProviderTarget viewer = provider.getViewer();
+ IInternalTreeModelViewer viewer = provider.getViewer();
for (int i = 0; i < fElements.length; i++) {
int modelIndex = fIndex + i;
Object element = fElements[i];
@@ -62,36 +62,54 @@ public class ChildrenUpdate extends ViewerUpdateMonitor implements IChildrenUpda
int viewIndex = provider.modelToViewIndex(elementPath, modelIndex);
if (provider.shouldFilter(elementPath, element)) {
if (provider.addFilteredIndex(elementPath, modelIndex, element)) {
- if (ModelContentProvider.DEBUG_CONTENT_PROVIDER && ModelContentProvider.DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("REMOVE(" + getElement() + ", modelIndex: " + modelIndex + " viewIndex: " + viewIndex + ", " + element + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
- }
- viewer.remove(elementPath, viewIndex);
+ if (!updateFilterOnly) {
+ if (TreeModelContentProvider.DEBUG_CONTENT_PROVIDER && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
+ System.out.println("REMOVE(" + getElement() + ", modelIndex: " + modelIndex + " viewIndex: " + viewIndex + ", " + element + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ }
+ viewer.remove(elementPath, viewIndex);
+ }
}
} else {
if (provider.isFiltered(elementPath, modelIndex)) {
provider.clearFilteredChild(elementPath, modelIndex);
- int insertIndex = provider.modelToViewIndex(elementPath, modelIndex);
- if (ModelContentProvider.DEBUG_CONTENT_PROVIDER) {
- System.out.println("insert(" + getElement() + ", modelIndex: " + modelIndex + " insertIndex: " + insertIndex + ", " + element + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
- }
- viewer.insert(elementPath, element, insertIndex);
- } else {
- if (ModelContentProvider.DEBUG_CONTENT_PROVIDER && ModelContentProvider.DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
+ if (!updateFilterOnly) {
+ int insertIndex = provider.modelToViewIndex(elementPath, modelIndex);
+ if (TreeModelContentProvider.DEBUG_CONTENT_PROVIDER) {
+ System.out.println("insert(" + getElement() + ", modelIndex: " + modelIndex + " insertIndex: " + insertIndex + ", " + element + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ }
+ viewer.insert(elementPath, element, insertIndex);
+ }
+ } else if (!updateFilterOnly){
+ if (TreeModelContentProvider.DEBUG_CONTENT_PROVIDER && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
System.out.println("replace(" + getElement() + ", modelIndex: " + modelIndex + " viewIndex: " + viewIndex + ", " + element + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
}
viewer.replace(elementPath, viewIndex, element);
}
- TreePath childPath = elementPath.createChildPath(element);
- provider.updateHasChildren(childPath);
- provider.restorePendingStateOnUpdate(childPath, modelIndex, false, false, false);
+ if (!updateFilterOnly) {
+ TreePath childPath = elementPath.createChildPath(element);
+ provider.updateHasChildren(childPath);
+ provider.getStateTracker().restorePendingStateOnUpdate(childPath, modelIndex, false, false, false);
+ }
}
}
}
- provider.restorePendingStateOnUpdate(elementPath, -1, true, true, true);
- } else {
+ if (!updateFilterOnly) {
+ provider.getStateTracker().restorePendingStateOnUpdate(elementPath, -1, true, true, true);
+ }
+ } else if (!updateFilterOnly) {
provider.updateHasChildren(elementPath);
}
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.debug.ui.viewers.AsynchronousRequestMonitor#performUpdate()
+ */
+ protected void performUpdate() {
+ performUpdate(false);
}
/* (non-Javadoc)
@@ -122,7 +140,7 @@ public class ChildrenUpdate extends ViewerUpdateMonitor implements IChildrenUpda
fIndex = Math.min(fIndex, otherStart);
end = Math.max(end, otherEnd);
fLength = end - fIndex;
- if (ModelContentProvider.DEBUG_CONTENT_PROVIDER && ModelContentProvider.DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
+ if (TreeModelContentProvider.DEBUG_CONTENT_PROVIDER && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
System.out.println("coalesced: " + this.toString()); //$NON-NLS-1$
}
return true;
@@ -166,7 +184,7 @@ public class ChildrenUpdate extends ViewerUpdateMonitor implements IChildrenUpda
buf.append(" {"); //$NON-NLS-1$
buf.append(getOffset());
buf.append("->"); //$NON-NLS-1$
- buf.append(getOffset() + getLength());
+ buf.append(getOffset() + getLength() - 1);
buf.append("}"); //$NON-NLS-1$
return buf.toString();
}
@@ -194,5 +212,25 @@ public class ChildrenUpdate extends ViewerUpdateMonitor implements IChildrenUpda
void setOffset(int offset) {
fIndex = offset;
}
-}
+
+ Object[] getElements() {
+ return fElements;
+ }
+
+ protected boolean doEquals(ViewerUpdateMonitor update) {
+ return
+ update instanceof ChildrenUpdate &&
+ ((ChildrenUpdate)update).getOffset() == getOffset() &&
+ ((ChildrenUpdate)update).getLength() == getLength() &&
+ getViewerInput().equals(update.getViewerInput()) &&
+ getElementPath().equals(getElementPath());
+ }
+
+ protected int doHashCode() {
+ return (int)Math.pow(
+ (getClass().hashCode() + getViewerInput().hashCode() + getElementPath().hashCode()) * (getOffset() + 2),
+
+ getLength() + 2);
+ }
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ElementCompareRequest.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ElementCompareRequest.java
index ffa062c1e..4aea1a9c2 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ElementCompareRequest.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ElementCompareRequest.java
@@ -11,14 +11,11 @@
*******************************************************************************/
package org.eclipse.debug.internal.ui.viewers.model;
-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.model.provisional.IElementCompareRequest;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.ui.IMemento;
-import org.eclipse.ui.progress.UIJob;
/**
* @since 3.3
@@ -33,20 +30,29 @@ public class ElementCompareRequest extends MementoUpdate implements IElementComp
private boolean fCheckChildrenRealized;
- /**
- * @param context
- * @param element
- * @param memento
- */
- public ElementCompareRequest(ModelContentProvider provider, Object viewerInput, Object element,
+ /**
+ * @param provider the content provider to use for the update
+ * @param viewerInput the current input
+ * @param element the element to update
+ * @param elementPath the path of the element to update
+ * @param memento Memento to encode result into
+ * @param delta Delta to write the result comparison into.
+ * @param modelIndex Index of element to compare.
+ * @param knowsHasChildren Flag indicating whether provider knows the has
+ * children state of element.
+ * @param knowsChildCount Flag indicating whether provider knows the
+ * child count state of element.
+ * @param checkChildrenRealized Flag indicating if any realized children should be checked
+ */
+ public ElementCompareRequest(TreeModelContentProvider provider, Object viewerInput, Object element,
TreePath elementPath, IMemento memento, ModelDelta delta, int modelIndex,
- boolean hasChildren, boolean knowsChildCount, boolean checkChildrenRealized)
+ boolean knowsHasChildren, boolean knowsChildCount, boolean checkChildrenRealized)
{
super(provider, viewerInput, provider.getPresentationContext(), element, elementPath, memento);
fProvider = provider;
fDelta = delta;
fModelIndex = modelIndex;
- fKnowsHasChildren = hasChildren;
+ fKnowsHasChildren = knowsHasChildren;
fKnowsChildCount = knowsChildCount;
fCheckChildrenRealized = checkChildrenRealized;
}
@@ -62,17 +68,19 @@ public class ElementCompareRequest extends MementoUpdate implements IElementComp
* @see org.eclipse.core.runtime.IProgressMonitor#done()
*/
public void done() {
- UIJob job = new UIJob("restore delta") { //$NON-NLS-1$
- public IStatus runInUIThread(IProgressMonitor monitor) {
- if (!isCanceled()) {
- fProvider.compareFinished(ElementCompareRequest.this, fDelta);
- }
- return Status.OK_STATUS;
- }
- };
- job.setSystem(true);
- job.schedule();
- }
+ ITreeModelViewer viewer = getContentProvider().getViewer();
+ if (viewer == null) return; // disposed
+ if (viewer.getDisplay().getThread() == Thread.currentThread()) {
+ fProvider.getStateTracker().compareFinished(ElementCompareRequest.this, fDelta);
+ } else {
+ viewer.getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ if (getContentProvider().isDisposed()) return;
+ fProvider.getStateTracker().compareFinished(ElementCompareRequest.this, fDelta);
+ }
+ });
+ }
+ }
public boolean isEqual() {
return fEqual;
@@ -86,6 +94,7 @@ public class ElementCompareRequest extends MementoUpdate implements IElementComp
return fModelIndex;
}
+
void setKnowsHasChildren(boolean hasChildren) {
fKnowsHasChildren = hasChildren;
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ElementMementoRequest.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ElementMementoRequest.java
index 8a09d52e7..684169b5b 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ElementMementoRequest.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ElementMementoRequest.java
@@ -10,28 +10,35 @@
*******************************************************************************/
package org.eclipse.debug.internal.ui.viewers.model;
+import org.eclipse.debug.internal.ui.viewers.model.ViewerStateTracker.IElementMementoCollector;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.ui.IMemento;
/**
+ * Request for element memento.
+ *
* @since 3.3
*/
class ElementMementoRequest extends MementoUpdate implements IElementMementoRequest {
- private IMementoManager fManager;
+ private IElementMementoCollector fManager;
private ModelDelta fDelta;
/**
- * @param context
- * @param element
- * @param memento
+ * @param provider the content provider to use for the update
+ * @param viewerInput the current input
+ * @param collector Collector to report the result to
+ * @param element the element to update
+ * @param elementPath the path of the element to update
+ * @param memento Memento to encode result into
+ * @param delta Delta to write the result comparison into.
*/
- public ElementMementoRequest(ModelContentProvider provider, Object viewerInput, IMementoManager manager, IPresentationContext context, Object element, TreePath elementPath, IMemento memento, ModelDelta delta) {
- super(provider, viewerInput, context, element, elementPath, memento);
- fManager = manager;
+ public ElementMementoRequest(TreeModelContentProvider provider, Object viewerInput, IElementMementoCollector collector, Object element, TreePath elementPath, IMemento memento, ModelDelta delta) {
+ super(provider, viewerInput, provider.getPresentationContext(), element, elementPath, memento);
+ fManager = collector;
fDelta = delta;
}
@@ -39,11 +46,29 @@ class ElementMementoRequest extends MementoUpdate implements IElementMementoRequ
* @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());
+
+ ITreeModelViewer viewer = getContentProvider().getViewer();
+ if (viewer == null) return; // disposed
+ if (viewer.getDisplay().getThread() == Thread.currentThread()) {
+ doComplete();
+ } else {
+ viewer.getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ doComplete();
+ }
+ });
}
- fManager.requestComplete(this);
+
+ }
+
+ private void doComplete() {
+ if (getContentProvider().isDisposed()) return;
+
+ if (!isCanceled() && (getStatus() == null || getStatus().isOK())) {
+ // replace the element with a memento
+ fDelta.setElement(getMemento());
+ }
+ fManager.requestComplete(ElementMementoRequest.this);
}
public String toString() {
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/FilterTransform.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/FilterTransform.java
index 547a7ea5c..9c64eeec9 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/FilterTransform.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/FilterTransform.java
@@ -334,14 +334,14 @@ public class FilterTransform {
* @return whether the filter was added - returns <code>true</code> if the filter is
* added, and <code>false</code> if the index was already filtered
*/
- public synchronized boolean addFilteredIndex(TreePath parentPath, int childIndex, Object element) {
+ public boolean addFilteredIndex(TreePath parentPath, int childIndex, Object element) {
return root.addFilter(parentPath, childIndex, 0, element);
}
/**
* Clears all filtered elements.
*/
- public synchronized void clear() {
+ public void clear() {
root = new Node();
}
@@ -350,7 +350,7 @@ public class FilterTransform {
*
* @param path element path
*/
- public synchronized void clear(TreePath path) {
+ public void clear(TreePath path) {
root.clear(path, 0);
}
@@ -358,13 +358,21 @@ public class FilterTransform {
* Clears the given filtered index of the specified parent. I.e.
* the child still exists, but is no longer filtered.
*
- * @param path parent path
+ * @param parentPath parent path
* @param index index to clear
*/
- public synchronized void clear(TreePath parentPath, int index) {
+ public void clear(TreePath parentPath, int index) {
root.clear(parentPath, index, 0);
}
+ public int indexOfFilteredElement(TreePath parentPath, Object element) {
+ Node parentNode = root.find(parentPath, 0);
+ if (parentNode == null) {
+ return -1;
+ }
+ return parentNode.indexOfFilteredElement(element);
+ }
+
/**
* Translates and returns the given model index (raw index) into
* a view index (filtered index), or -1 if filtered.
@@ -373,7 +381,7 @@ public class FilterTransform {
* @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) {
+ public int modelToViewIndex(TreePath parentPath, int childIndex) {
Node parentNode = root.find(parentPath, 0);
if (parentNode == null) {
return childIndex;
@@ -389,7 +397,7 @@ public class FilterTransform {
* @param childIndex index of child element in view space
* @return the given index in model coordinates
*/
- public synchronized int viewToModelIndex(TreePath parentPath, int childIndex) {
+ public int viewToModelIndex(TreePath parentPath, int childIndex) {
Node parentNode = root.find(parentPath, 0);
if (parentNode == null) {
return childIndex;
@@ -404,7 +412,7 @@ public class FilterTransform {
* @param viewCount number of children in the view
* @return number of children in the model
*/
- public synchronized int viewToModelCount(TreePath parentPath, int viewCount) {
+ public int viewToModelCount(TreePath parentPath, int viewCount) {
Node parentNode = root.find(parentPath, 0);
if (parentNode != null) {
if (parentNode.filteredIndexes != null) {
@@ -422,7 +430,7 @@ public class FilterTransform {
* @param count child count in model space
* @return the given count in view coordinates
*/
- public synchronized int modelToViewCount(TreePath parentPath, int count) {
+ public int modelToViewCount(TreePath parentPath, int count) {
Node parentNode = root.find(parentPath, 0);
if (parentNode == null) {
return count;
@@ -437,7 +445,7 @@ public class FilterTransform {
* @param index index of child element
* @return whether the child is currently filtered
*/
- public synchronized boolean isFiltered(TreePath parentPath, int index) {
+ public boolean isFiltered(TreePath parentPath, int index) {
Node parentNode = root.find(parentPath, 0);
if (parentNode == null) {
return false;
@@ -448,7 +456,7 @@ public class FilterTransform {
/**
* Returns filtered children of the given parent, or <code>null</code> if none.
*
- * @param parentPath
+ * @param parentPath Path of parent element
* @return filtered children or <code>null</code>
*/
public int[] getFilteredChildren(TreePath parentPath) {
@@ -465,7 +473,7 @@ public class FilterTransform {
* @param parentPath path to parent element
* @param childCount child count
*/
- public synchronized void setModelChildCount(TreePath parentPath, int childCount) {
+ public void setModelChildCount(TreePath parentPath, int childCount) {
Node parentNode = root.find(parentPath, 0);
if (parentNode != null) {
parentNode.setModelChildCount(childCount);
@@ -479,7 +487,7 @@ public class FilterTransform {
* @param parentPath path to parent element
* @param index index of child element in model coordinates
*/
- public synchronized void removeElementFromFilters(TreePath parentPath, int index) {
+ public void removeElementFromFilters(TreePath parentPath, int index) {
Node parentNode = root.find(parentPath, 0);
if (parentNode != null) {
parentNode.removeElementFromFilters(index);
@@ -492,8 +500,9 @@ public class FilterTransform {
*
* @param parentPath path to parent element
* @param element removed element
+ * @return true if element was removed
*/
- public synchronized boolean removeElementFromFilters(TreePath parentPath, Object element) {
+ public boolean removeElementFromFilters(TreePath parentPath, Object element) {
Node parentNode = root.find(parentPath, 0);
if (parentNode != null) {
int index = parentNode.indexOfFilteredElement(element);
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/HasChildrenUpdate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/HasChildrenUpdate.java
index e1437c988..a237a90b4 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/HasChildrenUpdate.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/HasChildrenUpdate.java
@@ -17,7 +17,6 @@ import java.util.List;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.jface.viewers.TreePath;
/**
@@ -29,23 +28,29 @@ class HasChildrenUpdate extends ViewerUpdateMonitor implements IHasChildrenUpdat
private List fBatchedRequests = null;
- /**
- * @param contentProvider
- */
- public HasChildrenUpdate(ModelContentProvider contentProvider, Object viewerInput, TreePath elementPath, Object element, IElementContentProvider elementContentProvider, IPresentationContext context) {
- super(contentProvider, viewerInput, elementPath, element, elementContentProvider, context);
+ /**
+ * Constructs a request to update an element
+ *
+ * @param provider the content provider
+ * @param viewerInput the current input
+ * @param elementPath the path to the element being update
+ * @param element the element
+ * @param elementContentProvider the content provider for the element
+ */
+ public HasChildrenUpdate(TreeModelContentProvider provider, Object viewerInput, TreePath elementPath, Object element, IElementContentProvider elementContentProvider) {
+ super(provider, viewerInput, elementPath, element, elementContentProvider, provider.getPresentationContext());
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.viewers.ViewerUpdateMonitor#performUpdate()
*/
protected void performUpdate() {
- ModelContentProvider contentProvider = getContentProvider();
+ TreeModelContentProvider contentProvider = getContentProvider();
TreePath elementPath = getElementPath();
if (!fHasChildren) {
contentProvider.clearFilters(elementPath);
}
- if (ModelContentProvider.DEBUG_CONTENT_PROVIDER && ModelContentProvider.DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
+ if (TreeModelContentProvider.DEBUG_CONTENT_PROVIDER && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
System.out.println("setHasChildren(" + getElement() + " >> " + fHasChildren); //$NON-NLS-1$ //$NON-NLS-2$
}
contentProvider.getViewer().setHasChildren(elementPath, fHasChildren);
@@ -53,7 +58,7 @@ class HasChildrenUpdate extends ViewerUpdateMonitor implements IHasChildrenUpdat
contentProvider.getViewer().autoExpand(elementPath);
}
if (elementPath.getSegmentCount() > 0) {
- getContentProvider().restorePendingStateOnUpdate(getElementPath(), -1, true, false, false);
+ getContentProvider().getStateTracker().restorePendingStateOnUpdate(getElementPath(), -1, true, false, false);
}
}
@@ -137,4 +142,20 @@ class HasChildrenUpdate extends ViewerUpdateMonitor implements IHasChildrenUpdat
}
return path;
}
+
+ boolean hasChildren() {
+ return fHasChildren;
+ }
+
+ protected boolean doEquals(ViewerUpdateMonitor update) {
+ return
+ update instanceof HasChildrenUpdate &&
+ getViewerInput().equals(update.getViewerInput()) &&
+ getElementPath().equals(getElementPath());
+ }
+
+ protected int doHashCode() {
+ return getClass().hashCode() + getViewerInput().hashCode() + getElementPath().hashCode();
+ }
+
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelContentProviderTarget.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/IInternalTreeModelViewer.java
index 4e651832e..a0ed967ea 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelContentProviderTarget.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/IInternalTreeModelViewer.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2010 Wind River Systems and others.
+ * Copyright (c) 2011 Wind River Systems 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
@@ -11,9 +11,13 @@
*******************************************************************************/
package org.eclipse.debug.internal.ui.viewers.model;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer;
+import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.RGB;
/**
* This interface must be implemented by the viewer which uses the
@@ -21,15 +25,15 @@ import org.eclipse.jface.viewers.ViewerFilter;
* provider to update the viewer with information retrieved from the
* content, proxy, memento, and other element-based providers.
*
- * @since 3.5
+ * @since 3.8
*/
-public interface ITreeModelContentProviderTarget extends ITreeModelViewer {
+public interface IInternalTreeModelViewer extends ITreeModelViewer {
/**
* Returns this viewer's filters.
*
* @return an array of viewer filters
- * @see StructuredViewer#setFilters(ViewerFilter[])
+ * @see org.eclipse.jface.viewers.StructuredViewer#setFilters(ViewerFilter[])
*/
public ViewerFilter[] getFilters();
@@ -49,22 +53,6 @@ public interface ITreeModelContentProviderTarget extends ITreeModelViewer {
public void update(Object element);
/**
- * Triggers an update of the given element and its children. If
- * multiple instances of the given element are found in the tree,
- * they will all be updated.
- *
- * @param element Element to update.
- */
- public void refresh(Object element);
-
- /**
- * Triggers a full update of all the elements in the tree.
- *
- * @param element Element to update.
- */
- public void refresh();
-
- /**
* Sets the given object to be the element at the given index of the given parent.
* <p>
* This method should only be called by the viewer framework.
@@ -73,6 +61,7 @@ public interface ITreeModelContentProviderTarget extends ITreeModelViewer {
* @param parentOrTreePath Parent object, or a tree path of the parent element.
* @param index Index at which to set the new element.
* @param element Element object.
+ * @noreference This method is not intended to be referenced by clients.
*/
public void replace(Object parentOrTreePath, final int index, Object element);
@@ -85,7 +74,8 @@ public interface ITreeModelContentProviderTarget extends ITreeModelViewer {
* </p>
*
* @param elementOrTreePath The element, or tree path.
- * @param count
+ * @param count new value
+ * @noreference This method is not intended to be referenced by clients.
*/
public void setChildCount(final Object elementOrTreePath, final int count);
@@ -97,9 +87,9 @@ public interface ITreeModelContentProviderTarget extends ITreeModelViewer {
* This method should only be called by the viewer framework.
* </p>
*
- * @param elementOrTreePath
- * the element, or tree path
- * @param hasChildren
+ * @param elementOrTreePath the element, or tree path
+ * @param hasChildren new value.
+ * @noreference This method is not intended to be referenced by clients.
*/
public void setHasChildren(final Object elementOrTreePath, final boolean hasChildren);
@@ -111,6 +101,7 @@ public interface ITreeModelContentProviderTarget extends ITreeModelViewer {
* </p>
*
* @param elementPath tree path to element to consider for expansion
+ * @noreference This method is not intended to be referenced by clients.
*/
public void autoExpand(TreePath elementPath);
@@ -126,6 +117,8 @@ public interface ITreeModelContentProviderTarget extends ITreeModelViewer {
* @param expanded
* <code>true</code> if the node is expanded, and
* <code>false</code> if collapsed
+ *
+ * @noreference This method is not intended to be referenced by clients.
*/
public void setExpandedState(Object elementOrTreePath, boolean expanded);
@@ -142,20 +135,19 @@ public interface ITreeModelContentProviderTarget extends ITreeModelViewer {
* @param level
* non-negative level, or <code>ALL_LEVELS</code> to expand all
* levels of the tree
+ *
+ * @noreference This method is not intended to be referenced by clients.
*/
public void expandToLevel(Object elementOrTreePath, int level);
-
-
/**
* Removes the given element from the viewer. The selection is updated if
* necessary.
* <p>
* This method should only be called by the viewer framework.
* </p>
- *
- * @param elementsOrTreePaths
- * the element, or the tree path to the element
+ * @param elementOrTreePath the element, or the tree path to the element
+ * @noreference This method is not intended to be referenced by clients.
*/
public void remove(Object elementOrTreePath);
@@ -167,6 +159,7 @@ public interface ITreeModelContentProviderTarget extends ITreeModelViewer {
*
* @param parentOrTreePath the parent element, the input element, or a tree path to the parent element
* @param index child index
+ * @noreference This method is not intended to be referenced by clients.
*/
public void remove(Object parentOrTreePath, final int index);
@@ -178,20 +171,21 @@ public interface ITreeModelContentProviderTarget extends ITreeModelViewer {
* <p>
* This method should only be called by the viewer framework.
* </p>
+ * @param parentOrTreePath the parent element, or the tree path to the parent
*
- * @param parentElementOrTreePath
- * the parent element, or the tree path to the parent
- * @param element
- * the element
- * @param position
- * a 0-based position relative to the model, or -1 to indicate
- * the last position
+ * @param element the element
+ * @param position a 0-based position relative to the model, or -1 to indicate
+ * the last position
+ * @noreference This method is not intended to be referenced by clients.
*/
public void insert(Object parentOrTreePath, Object element, int position);
/**
* Returns whether the candidate selection should override the current
* selection.
+ * @param current Current selection in viewer.
+ * @param candidate Proposed new selection.
+ * @return whether new selection should override the current
*/
public boolean overrideSelection(ISelection current, ISelection candidate);
@@ -207,9 +201,11 @@ public interface ITreeModelContentProviderTarget extends ITreeModelViewer {
public boolean getExpandedState(Object elementOrTreePath);
/**
- * Returns whether the given element has children.
+ * Returns whether the node corresponding to the given element or tree path
+ * has any child elements.
*
- * @since 3.6
+ * @param elementOrTreePath Path to element
+ * @return Returns whether the given element has children.
*/
public boolean getHasChildren(Object elementOrTreePath);
@@ -217,24 +213,37 @@ public interface ITreeModelContentProviderTarget extends ITreeModelViewer {
* Returns the child count of the element at the given path. <br>
* Note: The child count may be incorrect if the element is not
* expanded in the tree.
+ *
+ * @param path Path to get count for.
+ * @return The child count.
*/
public int getChildCount(TreePath path);
/**
* Returns the element which is a child of the element at the
* given path, with the given index.
+ *
+ * @param path Path to parent element.
+ * @param index Index of child element.
+ * @return Child element.
*/
public Object getChildElement(TreePath path, int index);
/**
* Returns the tree path of the element that is at the top of the
* viewer.
+ *
+ * @return the tree path of the element at the top of the
+ * viewer.
*/
public TreePath getTopElementPath();
/**
* Finds the index of the given element with a parent of given path.
*
+ * @param parentPath Path of parent element.
+ * @param element Element to find.
+ *
* @return The element's index, or -1 if not found.
*/
public int findElementIndex(TreePath parentPath, Object element);
@@ -243,10 +252,8 @@ public interface ITreeModelContentProviderTarget extends ITreeModelViewer {
* Returns a boolean indicating whether all the child elements of the
* given parent have been realized already.
*
- * @param parentPath
- * @return
- *
- * @since 3.6
+ * @param parentPath Path of parent element.
+ * @return true if all children realized
*/
public boolean getElementChildrenRealized(TreePath parentPath);
@@ -254,8 +261,59 @@ public interface ITreeModelContentProviderTarget extends ITreeModelViewer {
* Clears the selection in the viewer, if any, without firing
* selection change notification. This is only to be used by
* the platform.
- *
- * @since 3.6
*/
public void clearSelectionQuiet();
+
+ /**
+ * Sets the element's display information.
+ * <p>
+ * This method should only be called by the viewer framework.
+ * </p>
+ *
+ * @param path Element path.
+ * @param numColumns Number of columns in the data.
+ * @param labels Array of labels. The array cannot to be
+ * <code>null</code>, but values within the array may be.
+ * @param images Array of image descriptors, may be <code>null</code>.
+ * @param fontDatas Array of fond data objects, may be <code>null</code>.
+ * @param foregrounds Array of RGB values for foreground colors, may be
+ * <code>null</code>.
+ * @param backgrounds Array of RGB values for background colors, may be
+ * <code>null</code>.
+ * @noreference This method is not intended to be referenced by clients.
+ */
+ public void setElementData(TreePath path, int numColumns, String[] labels, ImageDescriptor[] images, FontData[] fontDatas, RGB[] foregrounds, RGB[] backgrounds);
+
+ /**
+ * 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();
+
+ /**
+ * Sets the element check state data.
+ *
+ * @param path Path of element to check.
+ * @param checked if true, item will be checked
+ * @param grayed if true item will be grayed
+ */
+ public void setElementChecked(TreePath path, boolean checked, boolean grayed);
+
+ /**
+ * Retrieves the element check state.
+ *
+ * @param path Path of element to return check state for.
+ * @return the element checked state
+ */
+ public boolean getElementChecked(TreePath path);
+
+ /**
+ * Retrieves the element's check box grayed state.
+ *
+ * @param path Path of element to return grayed state for.
+ * @return the element grayed state
+ */
+ public boolean getElementGrayed(TreePath path);
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/IMementoManager.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/IMementoManager.java
deleted file mode 100644
index 665c3698b..000000000
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/IMementoManager.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2006, 2010 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.model;
-
-import org.eclipse.debug.internal.ui.viewers.model.provisional.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();
-
- /**
- * Cancels the requests in progress.
- */
- public void cancel();
-}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelCheckProviderTarget.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelCheckProviderTarget.java
deleted file mode 100644
index 1348f254c..000000000
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelCheckProviderTarget.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*****************************************************************
- * Copyright (c) 2009 Texas Instruments 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:
- * Patrick Chuong (Texas Instruments) - Initial API and implementation (Bug 286310)
- *****************************************************************/
-package org.eclipse.debug.internal.ui.viewers.model;
-
-import org.eclipse.jface.viewers.TreePath;
-
-/**
- * This interface can be implemented by the viewer which uses the
- * {@link TreeModelLabelProvider} label provider and supports the
- * {@link org.eclipse.swt.SWT.CHECK} style. It allows the label provider to
- * update the viewer with check-box information retrieved from the
- * element-based label providers.
- *
- * @since 3.6
- */
-public interface ITreeModelCheckProviderTarget extends ITreeModelLabelProviderTarget {
-
- /**
- * Sets the element check state data.
- *
- * @param path
- * @param checked
- * @param grayed
- */
- public void setElementChecked(TreePath path, boolean checked, boolean grayed);
-
- /**
- * Retrieves the element check state.
- *
- * @param path
- * @return checked
- */
- public boolean getElementChecked(TreePath path);
-
- /**
- * Retrieves the element's check box grayed state.
- *
- * @param path
- * @return grayed
- */
- public boolean getElementGrayed(TreePath path);
-}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelContentProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelContentProvider.java
index bad08fb73..d92934949 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelContentProvider.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelContentProvider.java
@@ -15,6 +15,8 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IStateUpdateListener;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener;
import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewerFilter;
+import org.eclipse.jface.viewers.IContentProvider;
import org.eclipse.jface.viewers.ILazyTreePathContentProvider;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.Viewer;
@@ -85,6 +87,20 @@ public interface ITreeModelContentProvider extends ILazyTreePathContentProvider
public int modelToViewIndex(TreePath parentPath, int index);
/**
+ * Returns whether the children of given element should be filtered.
+ * <p>This method is used to determine whether any of the registered filters
+ * that extend {@link TreeModelViewerFilter} are applicable to the given
+ * element. If so, then children of given element should be filtered
+ * prior to populating them in the viewer.
+ *
+ * @param parentElement
+ * the parent element
+ * @return whether there are any {@link TreeModelViewerFilter} filters
+ * applicable to given parent
+ */
+ public boolean areTreeModelViewerFiltersApplicable(Object parentElement);
+
+ /**
* Returns whether the given element is filtered.
*
* @param parentElementOrTreePath
@@ -98,7 +114,7 @@ public interface ITreeModelContentProvider extends ILazyTreePathContentProvider
/**
* Notification the given element is being unmapped.
*
- * @param path
+ * @param path Path to unmap
*/
public void unmapPath(TreePath path);
@@ -107,7 +123,7 @@ public interface ITreeModelContentProvider extends ILazyTreePathContentProvider
* coming from the model. Any delta flags which are hidden by the mask
* will be ignored.
*
- * @param the bit mask for <code>IModelDelta</code> flags
+ * @param mask for <code>IModelDelta</code> flags
*
* @since 3.6
*/
@@ -135,11 +151,13 @@ public interface ITreeModelContentProvider extends ILazyTreePathContentProvider
/**
* Registers the specified listener for view update notifications.
+ * @param listener Listener to add
*/
public void addViewerUpdateListener(IViewerUpdateListener listener);
/**
* Removes the specified listener from update notifications.
+ * @param listener Listener to remove
*/
public void removeViewerUpdateListener(IViewerUpdateListener listener);
@@ -147,23 +165,34 @@ public interface ITreeModelContentProvider extends ILazyTreePathContentProvider
* Registers the given listener for model delta notification.
* This listener is called immediately after the viewer processes
* the delta.
+ * @param listener Listener to add
*/
public void addModelChangedListener(IModelChangedListener listener);
/**
* Removes the given listener from model delta notification.
+ * @param listener Listener to remove
*/
public void removeModelChangedListener(IModelChangedListener listener);
+ /**
+ * Causes the content provider to save the expansion and selection state
+ * of given element. The state is then restored as the tree is lazily
+ * re-populated.
+ * @param path Path of the element to save.
+ */
+ public void preserveState(TreePath path);
/**
* Registers the specified listener for state update notifications.
+ * @param listener Listener to add
* @since 3.6
*/
public void addStateUpdateListener(IStateUpdateListener listener);
/**
* Removes the specified listener from state update notifications.
+ * @param listener Listener to remove
* @since 3.6
*/
public void removeStateUpdateListener(IStateUpdateListener listener);
@@ -196,13 +225,24 @@ public interface ITreeModelContentProvider extends ILazyTreePathContentProvider
/**
* Notifies the content provider that a client called {@link Viewer#setInput(Object)},
- * and the viewer input is about to change.
+ * and the viewer input is changed.
+ * This method is guaranteed to be called after {@link IContentProvider#inputChanged(Viewer, Object, Object)}
*
* @param viewer The viewer that uses this content provider.
* @param oldInput Old input object.
* @param newInput New input object.
*
- * @since 3.7
+ * @since 3.8
+ */
+ public void postInputChanged(IInternalTreeModelViewer viewer, Object oldInput, Object newInput);
+
+ /**
+ * Notifies the receiver that the given element has had its
+ * checked state modified in the viewer.
+ *
+ * @param path Path of the element that had its checked state changed
+ * @param checked The new checked state of the element
+ * @return false if the check state should not change
*/
- public void inputAboutToChange(ITreeModelContentProviderTarget viewer, Object oldInput, Object newInput);
+ public boolean setChecked(TreePath path, boolean checked);
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelLabelProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelLabelProvider.java
index b2c2d5cd9..cf7c9419f 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelLabelProvider.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelLabelProvider.java
@@ -20,7 +20,7 @@ import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
/**
- * {@link TreeModelViewer} label provider interface. In addition to
+ * {@link InternalTreeModelViewer} label provider interface. In addition to
* implementing this interface, the label provider for the TreeModelViewer
* must also extend CellLabelProvider.
*
@@ -28,15 +28,23 @@ import org.eclipse.swt.graphics.RGB;
*/
public interface ITreeModelLabelProvider extends IBaseLabelProvider {
+ /**
+ * Requests an label update label of the given element.
+ * @param elementPath Element to update.
+ * @return true if element label provider is found and update will
+ * be requested.
+ */
public boolean update(TreePath elementPath);
/**
* Registers the specified listener for view label update notifications.
+ * @param listener Listener to add
*/
public void addLabelUpdateListener(ILabelUpdateListener listener);
/**
* Removes the specified listener from view label update notifications.
+ * @param listener Listener to remove
*/
public void removeLabelUpdateListener(ILabelUpdateListener listener);
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelLabelProviderTarget.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelLabelProviderTarget.java
deleted file mode 100644
index add8a89be..000000000
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelLabelProviderTarget.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2009 Wind River Systems 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:
- * Wind River Systems - initial API and implementation
- *******************************************************************************/
-package org.eclipse.debug.internal.ui.viewers.model;
-
-import org.eclipse.jface.resource.ImageDescriptor;
-import org.eclipse.jface.viewers.TreePath;
-import org.eclipse.swt.graphics.FontData;
-import org.eclipse.swt.graphics.RGB;
-
-/**
- * This interface must be implemented by the viewer which uses the
- * {@link TreeModelLabelProvider} label provider. It allows the label
- * provider to update the viewer with information retrieved from the
- * element-based label providers.
- *
- * @since 3.5
- */
-public interface ITreeModelLabelProviderTarget extends ITreeModelViewer {
-
- /**
- * Sets the element's display information.
- * <p>
- * This method should only be called by the viewer framework.
- * </p>
- *
- * @param path Element path.
- * @param numColumns Number of columns in the data.
- * @param labels Array of labels. The array cannot to be
- * <code>null</code>, but values within the array may be.
- * @param images Array of image descriptors, may be <code>null</code>.
- * @param fontDatas Array of fond data objects, may be <code>null</code>.
- * @param foregrounds Array of RGB values for foreground colors, may be
- * <code>null</code>.
- * @param backgrounds Array of RGB values for background colors, may be
- * <code>null</code>.
- */
- public void setElementData(TreePath path, int numColumns, String[] labels, ImageDescriptor[] images, FontData[] fontDatas, RGB[] foregrounds, RGB[] backgrounds);
-
- /**
- * 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();
-}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelViewer.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelViewer.java
index 95b345b30..e85d818fa 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelViewer.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ITreeModelViewer.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2010 Wind River Systems and others.
+ * Copyright (c) 2011 Wind River Systems 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
@@ -7,213 +7,16 @@
*
* Contributors:
* Wind River Systems - initial API and implementation
- * IBM Corporation - ongoing bug fixes and enhancements
*******************************************************************************/
package org.eclipse.debug.internal.ui.viewers.model;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelChangedListener;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IStateUpdateListener;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualTreeModelViewer;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.ISelectionProvider;
-import org.eclipse.jface.viewers.TreePath;
-import org.eclipse.jface.viewers.ViewerLabel;
-import org.eclipse.swt.widgets.Display;
-
/**
- * Interface of an tree model viewer. It declares the common methods for the
- * JFace-based {@link TreeModelViewer} and the UI-less
- * {@link VirtualTreeModelViewer}.
- *
- * @since 3.5
+ * This interface was moved to the {@link org.eclipse.debug.internal.ui.viewers.model.provisional}
+ * package. This stub was left for backward compatibility for packages that
+ * referenced this internal interface.
+ *
+ * @deprecated This internal interface was replaced by {@link org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer}.
*/
-public interface ITreeModelViewer extends ISelectionProvider {
-
- /**
- * Constant indicating that all levels of the tree should be expanded or
- * collapsed.
- *
- * @see #setAutoExpandLevel(int)
- * @see #getAutoExpandLevel()
- */
- public static final int ALL_LEVELS = -1;
-
- /**
- * Returns the Display object that this viewer is in. The
- * display object can be used by clients to access the display thread
- * to call the viewer methods.
- */
- public Display getDisplay();
-
- /**
- * Returns this viewer's presentation context.
- *
- * @return presentation context
- */
- public IPresentationContext getPresentationContext();
-
- /**
- * Returns the current input of this viewer, or <code>null</code>
- * if none. The viewer's input provides the "model" for the viewer's
- * content.
- */
- public Object getInput();
-
- /**
- * Sets the input of this viewer. Setting the input resets the
- * viewer's contents and triggers an update starting at the input
- * element.
- * @param object Input element, or <code>null</code> if none.
- */
- public void setInput(Object object);
-
- /**
- * Returns the current selection in viewer.
- */
- public ISelection getSelection();
-
- /**
- * Sets a new selection for this viewer and optionally makes it visible.
- * The selection is not set if the model selection policy overrides the
- * attempt to set the selection.
- *
- * @param selection the new selection
- * @param reveal <code>true</code> if the selection is to be made
- * visible, and <code>false</code> otherwise
- * @param force <code>true</code> if the selection should override the
- * model selection policy
- */
- public void setSelection(ISelection selection, boolean reveal, boolean force);
-
- /**
- * Attempts to set the selection for this viewer and optionally makes it visible.
- * The selection is not set if the model selection policy overrides the
- * attempt to set the selection.
- *
- * @param selection the new selection
- * @param reveal whether to make the selection visible after successfully setting
- * the selection
- * @param force whether to force the selection (override the model selection policy)
- * @return <code>true</code> if the selection was set and <code>false</code> if the
- * model selection policy overrides the selection attempt
- */
- public boolean trySelection(ISelection selection, boolean reveal, boolean force);
-
- /**
- * Returns the auto-expand level.
- *
- * @return non-negative level, or <code>ALL_LEVELS</code> if all levels of
- * the tree are expanded automatically
- * @see #setAutoExpandLevel
- */
- public int getAutoExpandLevel();
+public interface ITreeModelViewer extends org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer {
- /**
- * Sets the auto-expand level to be used when the input of the viewer is set
- * using {@link #setInput(Object)}. The value 0 means that there is no
- * auto-expand; 1 means that the invisible root element is expanded (since
- * most concrete implementations do not show the root element, there is usually
- * no practical difference between using the values 0 and 1); 2 means that
- * top-level elements are expanded, but not their children; 3 means that
- * top-level elements are expanded, and their children, but not
- * grandchildren; and so on.
- * <p>
- * The value <code>ALL_LEVELS</code> means that all subtrees should be
- * expanded.
- * </p>
- *
- * @param level
- * non-negative level, or <code>ALL_LEVELS</code> to expand all
- * levels of the tree
- */
- public void setAutoExpandLevel(int level);
-
- /**
- * Returns the label data for the given element and for the given column,
- * Returns <code>null</code> if the given element is not found or is not
- * materialized in the virtual viewer. Clients may listen to label update
- * events to be notified when element labels are updated.
- *
- * @param path Path of the element.
- * @param columnIdx ID of the column for which to return the label data.
- * @return Label object containing the label information. Can be
- * <code>null</code> if the given element is not found or is not
- * materialized in the virtual viewer.
- */
- public ViewerLabel getElementLabel(TreePath path, String columnId);
-
- /**
- * Registers the specified listener for view update notifications.
- */
- public void addViewerUpdateListener(IViewerUpdateListener listener);
-
- /**
- * Removes the specified listener from update notifications.
- */
- public void removeViewerUpdateListener(IViewerUpdateListener listener);
-
- /**
- * Registers the specified listener for state update notifications.
- * @since 3.6
- */
- public void addStateUpdateListener(IStateUpdateListener listener);
-
- /**
- * Removes the specified listener from state update notifications.
- * @since 3.6
- */
- public void removeStateUpdateListener(IStateUpdateListener listener);
-
- /**
- * Registers the specified listener for view label update notifications.
- */
- public void addLabelUpdateListener(ILabelUpdateListener listener);
-
- /**
- * Removes the specified listener from view label update notifications.
- */
- public void removeLabelUpdateListener(ILabelUpdateListener listener);
-
- /**
- * Registers the given listener for model delta notification.
- * This listener is called immediately after the viewer processes
- * the delta.
- */
- public void addModelChangedListener(IModelChangedListener listener);
-
- /**
- * Removes the given listener from model delta notification.
- */
- public void removeModelChangedListener(IModelChangedListener listener);
-
- /**
- * Writes state information into a delta for the sub-tree at the given
- * path. It adds delta nodes and IModelDelta.EXPAND and IModelDelta.SELECT
- * as it parses the sub-tree.
- * @param path Path where to start saving the state.
- * @param delta The delta where the state is to be saved.
- * @param flagsToSave The flags to preserve during the state save. The
- * supported flags are <code>IModelDelta.SELECT</code>,
- * <code>IModelDelta.EXPAND</code>, <code>IModelDelta.COLLAPSE</code>.
- * @return Returns whether the state was saved for the given path. Will
- * return <code>false</code> if an element at the given path cannot
- * be found.
- *
- * @since 3.6
- */
- public boolean saveElementState(TreePath path, ModelDelta delta, int flagsToSave);
-
- /**
- * Causes the viewer to process the given delta as if it came from a
- * model proxy. This method is intended to be used to restore state
- * saved using {@link #saveElementState(TreePath, ModelDelta)}.
- *
- * @param delta Delta to process.
- */
- public void updateViewer(IModelDelta delta);
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/InternalTreeModelViewer.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/InternalTreeModelViewer.java
index f07334d9f..9ddd2bada 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/InternalTreeModelViewer.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/InternalTreeModelViewer.java
@@ -12,36 +12,26 @@
*******************************************************************************/
package org.eclipse.debug.internal.ui.viewers.model;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.Map.Entry;
+import java.util.Set;
-import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.debug.internal.core.IInternalDebugCoreConstants;
-import org.eclipse.debug.internal.core.commands.Request;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ICheckUpdate;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.ICheckboxModelProxy;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation2;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelChangedListener;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IStateUpdateListener;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
@@ -87,7 +77,7 @@ import org.eclipse.ui.IMemento;
* @since 3.3
*/
public class InternalTreeModelViewer extends TreeViewer
- implements ITreeModelViewer, ITreeModelContentProviderTarget, ITreeModelLabelProviderTarget, ITreeModelCheckProviderTarget
+ implements IInternalTreeModelViewer, org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer
{
private IPresentationContext fContext;
@@ -271,734 +261,6 @@ public class InternalTreeModelViewer extends TreeViewer
private CellModifierProxy fCellModifier;
- /**
- * A handle to an element in a model.
- */
- class VirtualElement {
- /**
- * Tree item associated with the element, or <code>null</code> for the root element
- */
- private TreeItem fItem;
-
- /**
- * Model element (can be <code>null</code> until retrieved)
- */
- private Object fElement;
-
- /**
- * Associated label update or <code>null</code> if the element was already
- * present in the tree.
- */
- private VirtualLabelUpdate fLabel;
-
- /**
- * Children elements or <code>null</code> if none
- */
- private VirtualElement[] fChildren = null;
-
- /**
- * Whether this element would be filtered from the viewer
- */
- private boolean fFiltered = false;
-
- /**
- * Listens for update when populating this virtual element in the tree viewer
- */
- class UpdateListener implements IViewerUpdateListener {
-
- /**
- * The parent pending update
- */
- private TreePath fParentPath;
-
- /**
- * The child index pending update
- */
- private int fIndex;
-
- /**
- * Whether the update has completed
- */
- private boolean fDone = false;
-
- /**
- * Constructs a new listener waiting
- * @param parentPath the parent path
- * @param childIndex the current child index
- */
- UpdateListener(TreePath parentPath, int childIndex) {
- fParentPath = parentPath;
- fIndex = childIndex;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener#updateComplete(org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate)
- */
- public void updateComplete(IViewerUpdate update) {
- if (update instanceof IChildrenUpdate) {
- IChildrenUpdate cu = (IChildrenUpdate) update;
- if (cu.getElementPath().equals(fParentPath)) {
- if (fIndex >= cu.getOffset() && fIndex <= (cu.getOffset() + cu.getLength())) {
- fDone = true;
- }
- }
- }
- }
-
- /**
- * Returns whether the update has completed.
- *
- * @return whether the update has completed
- */
- boolean isComplete() {
- return fDone;
- }
-
- public void updateStarted(IViewerUpdate update) {
- }
- public void viewerUpdatesBegin() {
- }
- public void viewerUpdatesComplete() {
- }
- }
-
- /**
- * Constructs a new virtual element for the given tree item and all
- * of its expanded children. Has to be called in the UI thread.
- * The model is used to count unrealized elements.
- *
- * Note only never re-use objects already in the tree as they may be out
- * of synch.
- *
- * @param item tree item
- * @param model virtual model
- * @param root subtree to consider or <code>null</code> if all
- * @param indexes children to consider or <code>null</code>
- */
- VirtualElement(TreeItem item, VirtualModel model, TreePath root, int[] indexes) {
- fItem = item;
- model.incVirtual();
- if (item.getExpanded()) {
- TreeItem[] items = item.getItems();
- fChildren = createChildren(items, model, root, indexes);
- }
- }
-
- /**
- * Constructs a new virtual element for the given tree and all expanded
- * children. The model is passed in to count unrealized elements.
- *
- * @param tree tree
- * @param model virtual model
- * @param root subtree scope or <code>null</code> for all
- * @param indexes child indexes to consider or <code>null</code>
- */
- VirtualElement(Tree tree, VirtualModel model, TreePath root, int[] indexes) {
- fElement = tree.getData();
- TreeItem[] items = tree.getItems();
- if (items.length > 0) {
- fChildren = createChildren(items, model, root, indexes);
- }
- }
-
- /**
- * Creates and returns children elements.
- *
- * @param items tree items
- * @param model model
- * @param root subtree to consider or all if <code>null</code>
- * @param indexes children of the root to consider or <code>null</code>
- * @return children
- */
- private VirtualElement[] createChildren(TreeItem[] items, VirtualModel model, TreePath root, int[] indexes) {
- VirtualElement[] kids = new VirtualElement[items.length];
- if (root == null || root.getSegmentCount() == 0) {
- if (indexes == null) {
- for (int i = 0; i < items.length; i++) {
- kids[i] = new VirtualElement(items[i], model, null, null);
- }
- } else {
- for (int i = 0; i < indexes.length; i++) {
- int index = indexes[i];
- kids[index] = new VirtualElement(items[index], model, null, null);
- }
- }
- } else {
- for (int i = 0; i < items.length; i++) {
- TreeItem treeItem = items[i];
- if (treeItem.getData() != null) {
- TreePath path = getTreePathFromItem(treeItem);
- if (root.startsWith(path, null)) {
- if (root.getSegmentCount() > path.getSegmentCount()) {
- kids[i] = new VirtualElement(treeItem, model, root, indexes);
- } else {
- kids[i] = new VirtualElement(treeItem, model, null, indexes);
- }
- break;
- }
- }
- }
- }
- return kids;
- }
-
- /**
- * Returns whether this element would be filtered from the viewer.
- *
- * @return whether filtered
- */
- public boolean isFiltered() {
- return fFiltered;
- }
-
- /**
- * Causes the tree item associated with this model element to be realized.
- * Must be called in the UI thread.
- *
- * @return tree path to associated element, or <code>null</code> if the operation
- * fails
- */
- public TreePath realize() {
- if (fItem.getData() != null) {
- return getTreePathFromItem(fItem);
- }
- int index = -1;
- TreePath parentPath = null;
- if (fItem.getParentItem() == null) {
- index = getTree().indexOf(fItem);
- parentPath = TreePath.EMPTY;
- } else {
- index = fItem.getParentItem().indexOf(fItem);
- parentPath = getTreePathFromItem(fItem.getParentItem());
- }
- UpdateListener listener = new UpdateListener(parentPath, index);
- addViewerUpdateListener(listener);
- ((ILazyTreePathContentProvider)getContentProvider()).updateElement(parentPath, index);
- Display display = getTree().getDisplay();
- while (!listener.isComplete()) {
- if (!display.readAndDispatch()) {
- display.sleep();
- }
- }
- removeViewerUpdateListener(listener);
- if (fItem.getData() != null) {
- return getTreePathFromItem(fItem);
- }
- return null;
- }
-
- /**
- * Schedules updates to retrieve unrealized children of this node.
- *
- * @param parentPath path to this element
- * @param model model
- */
- void retrieveChildren(TreePath parentPath, VirtualModel model) {
- VirtualChildrenUpdate update = null;
- if (fChildren != null) {
- int prevModelIndex = Integer.MAX_VALUE;
- for (int i = 0; i < fChildren.length; i++) {
- VirtualElement element = fChildren[i];
- if (element == null) {
- if (update != null) {
- // non-consecutive updates, schedule and keep going
- model.scheduleUpdate(update);
- update = null;
- }
- } else {
- int modelIndex = ((ITreeModelContentProvider)getContentProvider()).viewToModelIndex(parentPath, i);
- if (update == null) {
- update = new VirtualChildrenUpdate(parentPath, this, model);
- } else if ((modelIndex - prevModelIndex) > 1) {
- // non-consecutive updates, schedule and keep going
- model.scheduleUpdate(update);
- update = new VirtualChildrenUpdate(parentPath, this, model);
- }
- update.add(modelIndex);
- prevModelIndex = modelIndex;
- }
- }
- }
- if (update != null) {
- model.scheduleUpdate(update);
- }
- }
-
- /**
- * Sets the underlying model object.
- * @param data the model object
- */
- void setElement(Object data) {
- fElement = data;
- }
-
- /**
- * Sets the label update associated with this element
- *
- * @param update the new label update
- */
- void setLabelUpdate(VirtualLabelUpdate update) {
- fLabel = update;
- }
-
- /**
- * Returns the image for this element or <code>null</code> if none
- *
- * @return image or <code>null</code> if none
- */
- public Image getImage() {
- if (fLabel == null) {
- return fItem.getImage();
- } else {
- return ((ITreeModelLabelProvider)getLabelProvider()).getImage(fLabel.fImage);
- }
- }
-
- /**
- * Returns the labels for the element - one for each column requested.
- *
- * @return column labels
- */
- public String[] getLabel() {
- if (fLabel == null) {
- String[] visibleColumns = getVisibleColumns();
- String[] label = new String[visibleColumns == null ? 1 : visibleColumns.length];
- for (int i = 0; i < label.length; i++) {
- label[i] = fItem.getText(i);
- }
- return label;
- }
- return fLabel.fText;
-
- }
-
- /**
- * Returns the children of this element or <code>null</code> if none.
- *
- * @return children or <code>null</code> if none
- */
- public VirtualElement[] getChildren() {
- return fChildren;
- }
-
- }
-
- /**
- * Common function for virtual updates.
- */
- class VirtualUpdate extends Request implements IViewerUpdate {
-
- /**
- * Path to the element being updated, or EMPTY for viewer input.
- */
- private TreePath fPath;
-
- /**
- * Element being updated.
- */
- VirtualElement fVirtualElement;
-
- /**
- * Associated virtual model
- */
- VirtualModel fModel = null;
-
- /**
- * Creates a new update based for the given element and model
- * @param model the backing model
- * @param element the element to update
- * @param elementPath the path of the element
- */
- public VirtualUpdate(VirtualModel model, VirtualElement element, TreePath elementPath) {
- fPath = elementPath;
- fModel = model;
- fVirtualElement = element;
- }
-
- /**
- * Returns the associated virtual element.
- *
- * @return virtual element
- */
- protected VirtualElement getVirtualElement() {
- return fVirtualElement;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate#getElement()
- */
- public Object getElement() {
- if (fPath.getSegmentCount() == 0) {
- return getViewerInput();
- }
- return fPath.getLastSegment();
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate#getElementPath()
- */
- public TreePath getElementPath() {
- return fPath;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate#getPresentationContext()
- */
- public IPresentationContext getPresentationContext() {
- return InternalTreeModelViewer.this.getPresentationContext();
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate#getViewerInput()
- */
- public Object getViewerInput() {
- return InternalTreeModelViewer.this.getInput();
- }
-
- }
-
- /**
- * Represents all expanded items in this viewer's tree. The model is virtual - i.e. not
- * all items have their associated model elements/labels retrieved from the model. The
- * model can be populated in a non-UI thread.
- */
- class VirtualModel {
-
- /**
- * Update requests in progress (children updates and label updates)
- */
- private List fPendingUpdates = new ArrayList();
-
- /**
- * Whether population has been canceled.
- */
- private boolean fCanceled = false;
-
- /**
- * Root element in the model.
- */
- private VirtualElement fRoot = null;
-
- /**
- * Progress monitor to use during retrieval of virtual elements
- */
- private IProgressMonitor fMonitor = null;
-
- /**
- * Column IDs to generate labels for or <code>null</code> if no columns.
- */
- private String[] fColumnIds;
-
- /**
- * Count of the number of virtual (unrealized) elements in this model
- * when it was created.
- */
- private int fVirtualCount = 0;
-
- /**
- * Creates a virtual model for this tree viewer limited to the given
- * subtrees. Includes the entire model if root is <code>null</code>.
- *
- * @param root limits model to given subtree scope, or <code>null</code>
- * @param childIndexes children of the root to consider or <code>null</code>
- */
- VirtualModel(TreePath root, int[] childIndexes) {
- fRoot = new VirtualElement(getTree(), this, root, childIndexes);
- }
-
- /**
- * Increments the counter of virtual elements in the model.
- */
- void incVirtual() {
- fVirtualCount++;
- }
-
- /**
- * update progress monitor
- *
- * @param work the number of units worked
- */
- void worked(int work) {
- fMonitor.worked(work);
- }
-
- /**
- * Schedules a children update.
- * @param update the update to schedule
- */
- private synchronized void scheduleUpdate(IChildrenUpdate update) {
- Object element = update.getElement();
- if (element == null) {
- element = getInput();
- }
- IElementContentProvider provider = ViewerAdapterService.getContentProvider(element);
- if (provider != null) {
- fPendingUpdates.add(update);
- provider.update(new IChildrenUpdate[]{update});
- }
- }
-
- /**
- * Populates this models elements that have not yet been retrieved from the model,
- * returning all elements in the model, or <code>null</code> if canceled.
- *
- * @param monitor progress monitor for progress reporting and for checking if canceled
- * @param taskName used in progress monitor, for example "Find..."
- * @param columnIds labels to generate or <code>null</code> if no columns are to be used
- * @return model elements or <code>null</code> if canceled
- */
- public VirtualElement populate(IProgressMonitor monitor, String taskName, String[] columnIds) {
- fMonitor = monitor;
- fColumnIds = columnIds;
- monitor.beginTask(taskName, fVirtualCount * 2);
- boolean done = false;
- fRoot.retrieveChildren(TreePath.EMPTY, this);
- synchronized (this) {
- done = fPendingUpdates.isEmpty();
- }
- while (!done) {
- synchronized (this) {
- try {
- wait(500);
- } catch (InterruptedException e) {
- }
- }
- if (monitor.isCanceled()) {
- cancel();
- return null;
- }
- synchronized (this) {
- done = fPendingUpdates.isEmpty();
- }
- }
- monitor.done();
- return fRoot;
- }
-
- /**
- * Cancels all pending updates.
- */
- void cancel() {
- synchronized (this) {
- fCanceled = true;
- Iterator iterator = fPendingUpdates.iterator();
- while (iterator.hasNext()) {
- IViewerUpdate update = (IViewerUpdate) iterator.next();
- update.cancel();
- }
- fPendingUpdates.clear();
- }
- }
- private synchronized boolean isCanceled() {
- return fCanceled;
- }
-
- /**
- * Notification the given children update is complete. Schedules associated label
- * updates if the request or the population of the model has not been canceled.
- *
- * @param update completed children update request
- */
- synchronized void done(VirtualChildrenUpdate update) {
- if (!isCanceled()) {
- fPendingUpdates.remove(update);
- if (!update.isCanceled()) {
- VirtualElement[] children = update.fVirtualElement.fChildren;
- TreePath parent = update.getElementPath();
- IElementLabelProvider provider = null;
- List requests = new ArrayList();
- int start = update.getOffset();
- int end = start + update.getLength();
- for (int i = start; i < end; i++) {
- int viewIndex = ((ITreeModelContentProvider)getContentProvider()).modelToViewIndex(parent, i);
- VirtualElement proxy = children[viewIndex];
- if (proxy.fFiltered) {
- fMonitor.worked(1); // don't need the label, this one is already done
- } else {
- Object element = proxy.fElement;
- if (element != null) { // null indicates other updates coming later
- VirtualLabelUpdate labelUpdate = new VirtualLabelUpdate(update.fModel, proxy, parent.createChildPath(element));
- proxy.setLabelUpdate(labelUpdate);
- IElementLabelProvider next = ViewerAdapterService.getLabelProvider(element);
- if (next != null) {
- fPendingUpdates.add(labelUpdate);
- }
- if (provider == null) {
- provider = next;
- requests.add(labelUpdate);
- } else if (next != null) {
- if (provider.equals(next)) {
- requests.add(labelUpdate);
- } else {
- // schedule queued requests, label provider has changed
- provider.update((ILabelUpdate[])requests.toArray(new ILabelUpdate[requests.size()]));
- requests.clear();
- requests.add(labelUpdate);
- provider = next;
- }
- }
- }
- }
- }
- if (provider != null && !requests.isEmpty()) {
- provider.update((ILabelUpdate[])requests.toArray(new ILabelUpdate[requests.size()]));
- }
- }
- notifyAll();
- }
- }
-
- /**
- * Notification the given label update is complete. Updates progress reporting
- * and updates pending updates.
- *
- * @param update label update that was completed
- */
- synchronized void done(VirtualLabelUpdate update) {
- if (!isCanceled()) {
- fPendingUpdates.remove(update);
- fMonitor.worked(1);
- }
- if (fPendingUpdates.isEmpty()) {
- notifyAll();
- }
- }
- }
-
- /**
- * Request to update a range of children.
- */
- class VirtualChildrenUpdate extends VirtualUpdate implements IChildrenUpdate {
-
- private int fOffset = -1;
- private int fLength = 0;
-
- /**
- * @param parentPath the parent path
- * @param parent the parent element
- * @param model the model
- */
- public VirtualChildrenUpdate(TreePath parentPath, VirtualElement parent, VirtualModel model) {
- super(model, parent, parentPath);
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate#getLength()
- */
- public int getLength() {
- return fLength;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate#getOffset()
- */
- public int getOffset() {
- return fOffset;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate#setChild(java.lang.Object, int)
- */
- public void setChild(Object child, int offset) {
- int viewIndex = ((ITreeModelContentProvider)getContentProvider()).modelToViewIndex(getElementPath(), offset);
- VirtualElement virtualChild = getVirtualElement().fChildren[viewIndex];
- virtualChild.setElement(child);
- ITreeModelContentProvider provider = (ITreeModelContentProvider) getContentProvider();
- virtualChild.fFiltered = provider.shouldFilter(getElementPath(), child);
- if (!virtualChild.fFiltered) {
- virtualChild.retrieveChildren(getElementPath().createChildPath(child), fModel);
- }
- fModel.worked(1);
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.core.commands.Request#done()
- */
- public void done() {
- fModel.done(this);
- }
-
- /**
- * @param i the new offset
- */
- void add(int i) {
- if (fOffset == -1) {
- fOffset = i;
- }
- fLength++;
- }
-
- }
-
- class VirtualLabelUpdate extends VirtualUpdate implements ILabelUpdate {
-
- /**
- * Constructs a label request for the given element;
- * @param coordinator the model
- * @param element the element to update
- * @param elementPath the element path
- */
- public VirtualLabelUpdate(VirtualModel coordinator, VirtualElement element, TreePath elementPath) {
- super(coordinator, element, elementPath);
- }
-
- private String[] fText;
- private ImageDescriptor fImage;
-
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate#getColumnIds()
- */
- public String[] getColumnIds() {
- return fModel.fColumnIds;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate#setBackground(org.eclipse.swt.graphics.RGB, int)
- */
- public void setBackground(RGB background, int columnIndex) {
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate#setFontData(org.eclipse.swt.graphics.FontData, int)
- */
- public void setFontData(FontData fontData, int columnIndex) {
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate#setForeground(org.eclipse.swt.graphics.RGB, int)
- */
- public void setForeground(RGB foreground, int columnIndex) {
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate#setImageDescriptor(org.eclipse.jface.resource.ImageDescriptor, int)
- */
- public void setImageDescriptor(ImageDescriptor image, int columnIndex) {
- fImage = image;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate#setLabel(java.lang.String, int)
- */
- public void setLabel(String text, int columnIndex) {
- if (fText == null) {
- if (getColumnIds() == null) {
- fText = new String[1];
- } else {
- fText = new String[getColumnIds().length];
- }
- }
- fText[columnIndex] = text;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.core.commands.Request#done()
- */
- public void done() {
- fModel.done(this);
- }
-
- }
/**
* @param parent the parent composite
@@ -1192,7 +454,7 @@ public class InternalTreeModelViewer extends TreeViewer
if (widget instanceof Item) {
widget.setData(TREE_PATH_KEY, getTreePathFromItem((Item)widget));
} else {
- widget.setData(TREE_PATH_KEY, ModelContentProvider.EMPTY_TREE_PATH);
+ widget.setData(TREE_PATH_KEY, TreeModelContentProvider.EMPTY_TREE_PATH);
}
}
@@ -1237,12 +499,13 @@ public class InternalTreeModelViewer extends TreeViewer
* @see org.eclipse.jface.viewers.AbstractTreeViewer#inputChanged(java.lang.Object, java.lang.Object)
*/
protected void inputChanged(Object input, Object oldInput) {
- ((ITreeModelContentProvider)getContentProvider()).inputAboutToChange(this, oldInput, input);
- // Clear items map now that we've called inputAboutToChange.
+ // Clear items map now that ITreeModelContentProvider.inputChanged() was already called.
// Bug 326917
super.unmapAllElements();
+ ((ITreeModelContentProvider)getContentProvider()).postInputChanged(this, oldInput, input);
super.inputChanged(input, oldInput);
- resetColumns(input);
+
+ resetColumns(input);
}
/**
@@ -1362,6 +625,27 @@ public class InternalTreeModelViewer extends TreeViewer
refreshColumns();
}
}
+
+ protected void internalRefresh(Object element, boolean updateLabels) {
+ ITreeModelContentProvider contentProvider = (ITreeModelContentProvider)getContentProvider();
+
+ if (element == null) {
+ internalRefresh(getControl(), getRoot(), true, updateLabels);
+ contentProvider.preserveState(TreePath.EMPTY);
+ } else {
+ Widget[] items = findItems(element);
+ if (items.length != 0) {
+ for (int i = 0; i < items.length; i++) {
+ if (items[i] instanceof TreeItem) {
+ contentProvider.preserveState(getTreePathFromItem((TreeItem)items[i]));
+ } else {
+ contentProvider.preserveState(TreePath.EMPTY);
+ }
+ }
+ }
+ }
+ super.internalRefresh(element, updateLabels);
+ }
/**
* Refreshes the columns in the view, based on the viewer input.
@@ -1845,22 +1129,6 @@ public class InternalTreeModelViewer extends TreeViewer
}
}
- /**
- * Collects all expanded items from this tree viewer and returns them as part of
- * a virtual model. This must be called in a UI thread to traverse the tree items.
- * The model can the be populated in a non-UI thread.
- *
- * Alternatively a root element can be specified with a set of child indexes to
- * consider. All children of the specified children are added to the model.
- *
- * @param root subtree to consider or <code>null</code> if all
- * @param childIndexes indexes of root element to consider, or <code>null</code> if all
- * @return virtual model
- */
- VirtualModel buildVirtualModel(TreePath root, int[] childIndexes) {
- return new VirtualModel(root, childIndexes);
- }
-
public void addLabelUpdateListener(ILabelUpdateListener listener) {
((ITreeModelLabelProvider)getLabelProvider()).addLabelUpdateListener(listener);
}
@@ -2479,6 +1747,19 @@ public class InternalTreeModelViewer extends TreeViewer
return false;
}
+ public TreePath[] getElementPaths(Object element) {
+ Widget[] items = internalFindItems(element);
+ TreePath[] paths = new TreePath[items.length];
+ for (int i = 0; i < items.length; i++) {
+ if (items[i] instanceof Tree) {
+ paths[i] = TreePath.EMPTY;
+ } else {
+ paths[i] = getTreePathFromItem((Item)items[i]);
+ }
+ }
+ return paths;
+ }
+
/*
* (non-Javadoc)
* @see org.eclipse.jface.viewers.StructuredViewer#handleSelect(org.eclipse.swt.events.SelectionEvent)
@@ -2495,11 +1776,7 @@ public class InternalTreeModelViewer extends TreeViewer
if (event.detail == SWT.CHECK) {
boolean checked = item.getChecked();
- boolean accepted = false;
- IModelProxy elementProxy = ((TreeModelContentProvider) contentProvider).getElementProxy(path);
- if (elementProxy instanceof ICheckboxModelProxy) {
- accepted = ((ICheckboxModelProxy) elementProxy).setChecked(getPresentationContext(), getInput(), path, checked);
- }
+ boolean accepted = ((ITreeModelContentProvider) contentProvider).setChecked(path, checked);
// if the listen rejects the change or there is not ICheckboxModelProxy, than revert the check state
if (!accepted) {
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/InternalVirtualTreeModelViewer.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/InternalVirtualTreeModelViewer.java
index 301bc3840..0b7083b74 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/InternalVirtualTreeModelViewer.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/InternalVirtualTreeModelViewer.java
@@ -17,13 +17,13 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.Map.Entry;
+import java.util.Set;
-import org.eclipse.debug.internal.ui.viewers.model.VirtualItem.Index;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelChangedListener;
@@ -31,9 +31,15 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IStateUpdateListener;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IVirtualItemListener;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IVirtualItemValidator;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualItem;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualItem.Index;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualTree;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.IContentProvider;
import org.eclipse.jface.viewers.ISelection;
@@ -59,10 +65,9 @@ import org.eclipse.ui.IMemento;
* @since 3.5
*/
public class InternalVirtualTreeModelViewer extends Viewer
- implements VirtualTree.IVirtualItemListener,
+ implements IVirtualItemListener,
ITreeModelViewer,
- ITreeModelContentProviderTarget,
- ITreeModelLabelProviderTarget
+ IInternalTreeModelViewer
{
/**
@@ -92,6 +97,11 @@ public class InternalVirtualTreeModelViewer extends Viewer
private static final String TREE_PATH_KEY = "TREE_PATH_KEY"; //$NON-NLS-1$
/**
+ * Viewer filters currently configured for viewer.
+ */
+ private ViewerFilter[] fFilters = new ViewerFilter[0];
+
+ /**
* The display that this virtual tree viewer is associated with. It is used
* for access to the UI thread.
*/
@@ -178,10 +188,10 @@ public class InternalVirtualTreeModelViewer extends Viewer
*/
private Runnable fValidateRunnable;
- public InternalVirtualTreeModelViewer(Display display, int style, IPresentationContext context) {
+ public InternalVirtualTreeModelViewer(Display display, int style, IPresentationContext context, IVirtualItemValidator itemValidator) {
fDisplay = display;
fContext = context;
- fTree = new VirtualTree(style);
+ fTree = new VirtualTree(style, itemValidator);
fTree.addItemListener(this);
fContentProvider = new TreeModelContentProvider();
@@ -208,12 +218,13 @@ public class InternalVirtualTreeModelViewer extends Viewer
public void setInput(Object input) {
Object oldInput = fInput;
- getContentProvider().inputAboutToChange(this, oldInput , input);
- fItemsMap.clear();
getContentProvider().inputChanged(this, oldInput, input);
+ fItemsMap.clear();
fInput = input;
+ getContentProvider().postInputChanged(this, oldInput , input);
fTree.setData(fInput);
- inputChanged(oldInput, fInput);
+ fTree.setSelection(EMPTY_ITEMS_ARRAY);
+ inputChanged(fInput, oldInput);
refresh();
}
@@ -265,7 +276,7 @@ public class InternalVirtualTreeModelViewer extends Viewer
validate();
}
- VirtualTree getTree() {
+ public VirtualTree getTree() {
return fTree;
}
@@ -376,8 +387,66 @@ public class InternalVirtualTreeModelViewer extends Viewer
return selection;
}
+// private VirtualTreeSelection adjustSelectionForReplace(VirtualTreeSelection selection, VirtualItem item,
+// Object element, Object parentElement)
+// {
+// if (selection.getItems().containsKey(item)) {
+// if (item.getData() == null) {
+// // The current item was selected, but its data is null.
+// // The data will be replaced by the given element, so to keep
+// // it selected, we have to add it to the selection.
+//
+// // set the element temporarily so that we can call getTreePathFromItem
+// item.setData(element);
+// TreePath path = getTreePathFromItem(item);
+// item.setData(null);
+//
+// Map map = new LinkedHashMap(selection.getItems());
+// map.put(item, path);
+// TreePath[] paths = new TreePath[selection.getPaths().length + 1];
+// int i = 0;
+// for (Iterator itr = map.values().iterator(); itr.hasNext();) {
+// TreePath nextPath = (TreePath)itr.next();
+// if (nextPath != null) {
+// paths[i++] = nextPath;
+// }
+// }
+// return new VirtualTreeSelection(map, paths);
+// } else if (!item.getData().equals(element)) {
+// // The current item was selected by the new element is
+// // different than the previous element in the item.
+// // Remove this item from selection.
+// Map map = new LinkedHashMap(selection.getItems());
+// map.remove(item);
+// TreePath[] paths = new TreePath[selection.getPaths().length - 1];
+// int i = 0;
+// for (Iterator itr = map.values().iterator(); itr.hasNext();) {
+// TreePath nextPath = (TreePath)itr.next();
+// if (nextPath != null) {
+// paths[i++] = nextPath;
+// }
+// }
+// return new VirtualTreeSelection(map, paths);
+// }
+// }
+// if (item.getData() != null || selection.getItems().size() == selection.size() || parentElement == null) {
+// // Don't do anything - we are not seeing an instance of bug 185673
+// return selection;
+// }
+// if (item.getData() == null && selection.getItems().containsKey(item)) {
+// }
+// // The item was not selected, return the given selection
+// return selection;
+// }
+
public void reveal(TreePath path, final int index) {
+ VirtualItem parentItem = findItem(path);
+ if (parentItem != null && parentItem.getItemCount() >= index) {
+ VirtualItem revealItem = parentItem.getItem(new Index(index));
+ getTree().showItem(revealItem);
+ getTree().validate();
+ }
// TODO: implement reveal()
}
@@ -425,6 +494,8 @@ public class InternalVirtualTreeModelViewer extends Viewer
}
private void refresh(VirtualItem item) {
+ getContentProvider().preserveState(getTreePathFromItem(item));
+
if (!item.needsDataUpdate()) {
if (item.getParent() != null) {
item.setNeedsLabelUpdate();
@@ -488,7 +559,7 @@ public class InternalVirtualTreeModelViewer extends Viewer
fAutoExpandToLevel = level;
}
- private VirtualItem findItem(TreePath path) {
+ public VirtualItem findItem(TreePath path) {
VirtualItem item = fTree;
if (path.getSegmentCount() == 0) {
return fTree;
@@ -503,7 +574,7 @@ public class InternalVirtualTreeModelViewer extends Viewer
static private final VirtualItem[] EMPTY_ITEMS_ARRAY = new VirtualItem[0];
- private VirtualItem[] findItems(Object elementOrTreePath) {
+ public VirtualItem[] findItems(Object elementOrTreePath) {
if (elementOrTreePath instanceof TreePath) {
VirtualItem item = findItem((TreePath) elementOrTreePath);
return item == null ? EMPTY_ITEMS_ARRAY : new VirtualItem[] { item };
@@ -626,8 +697,8 @@ public class InternalVirtualTreeModelViewer extends Viewer
if (fNotifyUnmap) {
// TODO: should we update the filter with the "new non-identical element"?
IContentProvider provider = getContentProvider();
- if (provider instanceof ModelContentProvider) {
- ((ModelContentProvider) provider).unmapPath((TreePath) item.getData(TREE_PATH_KEY));
+ if (provider instanceof TreeModelContentProvider) {
+ ((TreeModelContentProvider) provider).unmapPath((TreePath) item.getData(TREE_PATH_KEY));
}
}
@@ -820,11 +891,18 @@ public class InternalVirtualTreeModelViewer extends Viewer
}
VirtualItem[] items = fTree.getSelection();
ArrayList list = new ArrayList(items.length);
+ Map map = new LinkedHashMap(items.length * 4/3);
+
for (int i = 0; i < items.length; i++) {
+ TreePath path = null;
+
if (items[i].getData() != null) {
- list.add(getTreePathFromItem(items[i]));
+ path = getTreePathFromItem(items[i]);
+ list.add(path);
}
+ map.put(items[i], path);
}
+ //return new VirtualTreeSelection(map, (TreePath[]) list.toArray(new TreePath[list.size()]));
return new TreeSelection((TreePath[]) list.toArray(new TreePath[list.size()]));
}
@@ -929,9 +1007,9 @@ public class InternalVirtualTreeModelViewer extends Viewer
* Returns whether the candidate selection should override the current
* selection.
*
- * @param current
- * @param curr
- * @return
+ * @param current Current selection in viewer
+ * @param candidate New potential selection requested by model.
+ * @return true if candidate selection should be set to viewer.
*/
public boolean overrideSelection(ISelection current, ISelection candidate) {
IModelSelectionPolicy selectionPolicy = ViewerAdapterService.getSelectionPolicy(current, getPresentationContext());
@@ -944,11 +1022,19 @@ public class InternalVirtualTreeModelViewer extends Viewer
return !selectionPolicy.isSticky(current, getPresentationContext());
}
- private static ViewerFilter[] EMPTY_FILTER_ARRAY = new ViewerFilter[0];
-
public ViewerFilter[] getFilters() {
- // TODO: Add filter support
- return EMPTY_FILTER_ARRAY;
+ return fFilters;
+ }
+
+ public void addFilter(ViewerFilter filter) {
+ ViewerFilter[] newFilters = new ViewerFilter[fFilters.length + 1];
+ System.arraycopy(fFilters, 0, newFilters, 0, fFilters.length);
+ newFilters[fFilters.length] = filter;
+ fFilters = newFilters;
+ }
+
+ public void setFilters(ViewerFilter[] filters) {
+ fFilters = filters;
}
public void dispose() {
@@ -981,7 +1067,7 @@ public class InternalVirtualTreeModelViewer extends Viewer
/**
* Configures the columns for the given viewer input.
*
- * @param input
+ * @param input new viewer input
*/
private void resetColumns(Object input) {
if (input != null) {
@@ -1019,8 +1105,6 @@ public class InternalVirtualTreeModelViewer extends Viewer
/**
* Configures the columns based on the current settings.
- *
- * @param input
*/
protected void configureColumns() {
if (fColumnPresentation != null) {
@@ -1063,9 +1147,7 @@ public class InternalVirtualTreeModelViewer extends Viewer
}
/**
- * Returns whether columns are being displayed currently.
- *
- * @return
+ * @return Returns true if columns are being displayed currently.
*/
public boolean isShowColumns() {
if (fColumnPresentation != null) {
@@ -1094,7 +1176,7 @@ public class InternalVirtualTreeModelViewer extends Viewer
/**
* Creates new columns for the given presentation.
*
- * @param presentation
+ * @param presentation presentation context to build columns for.
*/
protected void buildColumns(IColumnPresentation presentation) {
PresentationContext presentationContext = (PresentationContext) getPresentationContext();
@@ -1158,9 +1240,6 @@ public class InternalVirtualTreeModelViewer extends Viewer
}
}
-
-
-
/**
* Returns the current column presentation for this viewer, or <code>null</code>
* if none.
@@ -1174,7 +1253,7 @@ public class InternalVirtualTreeModelViewer extends Viewer
/**
* Save viewer state into the given memento.
*
- * @param memento
+ * @param memento Memento to write state to.
*/
public void saveState(IMemento memento) {
if (!fShowColumns.isEmpty()) {
@@ -1210,7 +1289,7 @@ public class InternalVirtualTreeModelViewer extends Viewer
/**
* Initializes viewer state from the memento
*
- * @param memento
+ * @param memento Memento to read state from.
*/
public void initState(IMemento memento) {
IMemento[] mementos = memento.getChildren(SHOW_COLUMNS);
@@ -1342,7 +1421,7 @@ public class InternalVirtualTreeModelViewer extends Viewer
VirtualItem parent = findItem(path);
if (parent != null) {
- delta.setChildCount(((ModelContentProvider)getContentProvider()).viewToModelCount(path, parent.getItemCount()));
+ delta.setChildCount(((TreeModelContentProvider)getContentProvider()).viewToModelCount(path, parent.getItemCount()));
if (parent.getExpanded()) {
if ((flagsToSave & IModelDelta.EXPAND) != 0) {
delta.setFlags(delta.getFlags() | IModelDelta.EXPAND);
@@ -1381,9 +1460,9 @@ public class InternalVirtualTreeModelViewer extends Viewer
flags = flags | IModelDelta.SELECT;
}
if (expanded || flags != IModelDelta.NO_CHANGE) {
- int modelIndex = ((ModelContentProvider)getContentProvider()).viewToModelIndex(parentPath, item.getIndex().intValue());
+ int modelIndex = ((TreeModelContentProvider)getContentProvider()).viewToModelIndex(parentPath, item.getIndex().intValue());
TreePath elementPath = parentPath.createChildPath(element);
- int numChildren = ((ModelContentProvider)getContentProvider()).viewToModelCount(elementPath, item.getItemCount());
+ int numChildren = ((TreeModelContentProvider)getContentProvider()).viewToModelCount(elementPath, item.getItemCount());
ModelDelta childDelta = delta.addNode(element, modelIndex, flags, numChildren);
if (expanded) {
VirtualItem[] items = item.getItems();
@@ -1432,7 +1511,17 @@ public class InternalVirtualTreeModelViewer extends Viewer
return null;
}
- private String getText(VirtualItem item, int columnIdx) {
+ public TreePath[] getElementPaths(Object element) {
+ VirtualItem[] items = findItems(element);
+ TreePath[] paths = new TreePath[items.length];
+ for (int i = 0; i < items.length; i++) {
+ paths[i] = getTreePathFromItem(items[i]);
+ }
+ return paths;
+ }
+
+
+ public String getText(VirtualItem item, int columnIdx) {
String[] texts = (String[])item.getData(VirtualItem.LABEL_KEY);
if (texts != null && texts.length > columnIdx) {
return texts[columnIdx];
@@ -1440,7 +1529,7 @@ public class InternalVirtualTreeModelViewer extends Viewer
return null;
}
- private Image getImage(VirtualItem item, int columnIdx) {
+ public Image getImage(VirtualItem item, int columnIdx) {
ImageDescriptor[] imageDescriptors = (ImageDescriptor[]) item.getData(VirtualItem.IMAGE_KEY);
if (imageDescriptors != null && imageDescriptors.length > columnIdx) {
return getLabelProvider().getImage(imageDescriptors[columnIdx]);
@@ -1448,7 +1537,7 @@ public class InternalVirtualTreeModelViewer extends Viewer
return null;
}
- private Font getFont(VirtualItem item, int columnIdx) {
+ public Font getFont(VirtualItem item, int columnIdx) {
FontData[] fontDatas = (FontData[]) item.getData(VirtualItem.FONT_KEY);
if (fontDatas != null) {
return getLabelProvider().getFont(fontDatas[columnIdx]);
@@ -1478,4 +1567,20 @@ public class InternalVirtualTreeModelViewer extends Viewer
public void clearSelectionQuiet() {
getTree().setSelection(EMPTY_ITEMS_ARRAY);
}
+
+ public boolean getElementChecked(TreePath path) {
+ // Not supported
+ return false;
+ }
+
+ public boolean getElementGrayed(TreePath path) {
+ // Not supported
+ return false;
+ }
+
+ public void setElementChecked(TreePath path, boolean checked, boolean grayed) {
+ // Not supported
+ }
+
+
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/LabelUpdate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/LabelUpdate.java
index 764eecc60..d323b006e 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/LabelUpdate.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/LabelUpdate.java
@@ -44,7 +44,6 @@ class LabelUpdate extends Request implements ILabelUpdate, ICheckUpdate {
/**
* @param viewerInput input at the time the request was made
* @param elementPath element the label is for
- * @param item item the label is for
* @param provider label provider to callback to
* @param columnIds column identifiers or <code>null</code>
* @param context presentation context
@@ -152,7 +151,7 @@ class LabelUpdate extends Request implements ILabelUpdate, ICheckUpdate {
/**
* Applies settings to viewer cell
*/
- public void update() {
+ public void performUpdate() {
fProvider.setElementData(fElementPath, fNumColumns, fLabels, fImageDescriptors, fFontDatas, fForegrounds, fBackgrounds, fChecked, fGrayed);
fProvider.updateComplete(this);
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/MementoUpdate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/MementoUpdate.java
index 67681686e..13f822129 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/MementoUpdate.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/MementoUpdate.java
@@ -25,17 +25,20 @@ abstract class MementoUpdate extends Request implements IViewerUpdate {
private Object fElement;
private TreePath fElementPath;
private IMemento fMemento;
- protected ModelContentProvider fProvider;
+ protected TreeModelContentProvider fProvider;
protected Object fViewerInput;
/**
* Constructs a viewer state request.
+ * @param provider the content provider to use for the update
+ * @param viewerInput the current input
+ * @param elementPath the path of the element to update
+ * @param element the element to update
+ * @param memento Memento to update
+ * @param context the presentation context
*
- * @param viewer viewer
- * @param element element
- * @param memento memento
*/
- public MementoUpdate(ModelContentProvider provider, Object viewerInput, IPresentationContext context, Object element, TreePath elementPath, IMemento memento) {
+ public MementoUpdate(TreeModelContentProvider provider, Object viewerInput, IPresentationContext context, Object element, TreePath elementPath, IMemento memento) {
fContext = context;
fElement = element;
fElementPath = elementPath;
@@ -69,7 +72,7 @@ abstract class MementoUpdate extends Request implements IViewerUpdate {
return fMemento;
}
- public ModelContentProvider getContentProvider() {
+ public TreeModelContentProvider getContentProvider() {
return fProvider;
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ModelContentProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ModelContentProvider.java
deleted file mode 100644
index 29f769ec1..000000000
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ModelContentProvider.java
+++ /dev/null
@@ -1,2285 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2006, 2011 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * IBM Corporation - initial API and implementation
- * Pawel Piech - Wind River - Bug 205335: ModelContentProvider does not cancel stale updates when switching viewer input
- * Wind River Systems - Fix for viewer state save/restore [188704]
- * Pawel Piech (Wind River) - added support for a virtual tree model viewer (Bug 242489)
- * Dorin Ciuca - Top index fix (Bug 324100)
- *******************************************************************************/
-package org.eclipse.debug.internal.ui.viewers.model;
-
-import java.io.IOException;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-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.Platform;
-import org.eclipse.core.runtime.SafeRunner;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.core.runtime.jobs.Job;
-import org.eclipse.debug.core.IRequest;
-import org.eclipse.debug.internal.ui.DebugUIPlugin;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelChangedListener;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDeltaVisitor;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory2;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IStateUpdateListener;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
-import org.eclipse.jface.viewers.IContentProvider;
-import org.eclipse.jface.viewers.TreePath;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.jface.viewers.ViewerFilter;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.ui.IMemento;
-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 ITreeModelContentProviderTarget fViewer;
-
- /**
- * Mask used to filter delta updates coming from the model.
- */
- private int fModelDeltaMask = ~0;
-
- /**
- * Map tree paths to model proxy responsible for element
- *
- * Used to install different model proxy instances for one element depending
- * on the tree path.
- */
- private Map fTreeModelProxies = new HashMap(); // tree model proxy by
- // element tree path
-
- /**
- * Map element to model proxy responsible for it.
- *
- * Used to install a single model proxy which is responsible for all
- * instances of an element in the model tree.
- */
- 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();
-
- /**
- * Viewer update listeners
- */
- private ListenerList fUpdateListeners = new ListenerList();
-
- /**
- * State update listeners
- */
- private ListenerList fStateUpdateListeners = new ListenerList();
-
- /**
- * Map of updates in progress: element path -> list of requests
- */
- protected Map fRequestsInProgress = new HashMap();
-
- /**
- * Map of dependent requests waiting for parent requests to complete:
- * element path -> list of requests
- */
- protected Map fWaitingRequests = new HashMap();
-
- /**
- * Map of viewer states keyed by viewer input mementos
- */
- private Map fViewerStates = Collections.synchronizedMap(new LRUMap(20));
-
- /**
- * Pending viewer state to be restored
- */
- protected ModelDelta fPendingState = null;
-
- /**
- * Flag indicating that the content provider is performing
- * state restore operations.
- */
- private boolean fInStateRestore = false;
-
- protected interface IPendingRevealDelta extends IViewerUpdateListener {
- /**
- *
- * @return delta that should be revealed
- */
- ModelDelta getDelta();
-
- /**
- * Dispose the pending operation
- */
- void dispose();
- }
-
- /**
- * Postpone restoring REVEAL element until the current updates are complete.
- * See bug 324100
- */
- protected IPendingRevealDelta fPendingSetTopItem = null;
-
- private static class CompareRequestKey {
- CompareRequestKey(TreePath path, IModelDelta delta) {
- fPath = path;
- fDelta = delta;
- }
-
- TreePath fPath;
-
- IModelDelta fDelta;
-
- public boolean equals(Object obj) {
- if (obj instanceof CompareRequestKey) {
- CompareRequestKey key = (CompareRequestKey) obj;
- return key.fDelta.equals(fDelta) && key.fPath.equals(fPath);
- }
- return false;
- }
-
- public int hashCode() {
- return fDelta.hashCode() + fPath.hashCode();
- }
- }
-
- private Map fCompareRequestsInProgress = new LinkedHashMap();
-
- /**
- * Set of IMementoManager's that are currently saving state
- */
- private Set fPendingStateSaves = new HashSet();
-
- /**
- * Used to queue a viewer input for state restore
- */
- private Object fQueuedRestore = null;
-
- /**
- * Dummy marker element used in the state delta. The marker indicates that a
- * given element in the pending state delta has been removed. It replaces
- * the original element so that it may optionally be garbage collected.
- */
- private final static String ELEMENT_REMOVED = "ELEMENT_REMOVED"; //$NON-NLS-1$
-
- /**
- * 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
- */
- static final int UPDATE_SEQUENCE_BEGINS = 0;
-
- static final int UPDATE_SEQUENCE_COMPLETE = 1;
-
- static final int UPDATE_BEGINS = 2;
-
- static final int UPDATE_COMPLETE = 3;
-
- /**
- * Additional state update type constants
- */
- static final int STATE_SAVE_SEQUENCE_BEGINS = 4;
-
- static final int STATE_SAVE_SEQUENCE_COMPLETE = 5;
-
- static final int STATE_RESTORE_SEQUENCE_BEGINS = 6;
-
- static final int STATE_RESTORE_SEQUENCE_COMPLETE = 7;
-
- /**
- * Constant for an empty tree path.
- */
- protected static final TreePath EMPTY_TREE_PATH = new TreePath(new Object[] {});
-
- // debug flags
- public static String DEBUG_PRESENTATION_ID = null;
-
- public static boolean DEBUG_CONTENT_PROVIDER = false;
-
- public static boolean DEBUG_UPDATE_SEQUENCE = false;
-
- public static boolean DEBUG_STATE_SAVE_RESTORE = false;
-
- public static boolean DEBUG_DELTAS = false;
-
- public static boolean DEBUG_TEST_PRESENTATION_ID(IPresentationContext context) {
- if (context == null) {
- return true;
- }
- return DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(context.getId());
- }
-
- static {
- DEBUG_PRESENTATION_ID = Platform.getDebugOption("org.eclipse.debug.ui/debug/viewers/presentationId"); //$NON-NLS-1$
- if (!DebugUIPlugin.DEBUG || "".equals(DEBUG_PRESENTATION_ID)) { //$NON-NLS-1$
- DEBUG_PRESENTATION_ID = null;
- }
- DEBUG_CONTENT_PROVIDER = DebugUIPlugin.DEBUG && "true".equals( //$NON-NLS-1$
- Platform.getDebugOption("org.eclipse.debug.ui/debug/viewers/contentProvider")); //$NON-NLS-1$
- DEBUG_UPDATE_SEQUENCE = DebugUIPlugin.DEBUG && "true".equals( //$NON-NLS-1$
- Platform.getDebugOption("org.eclipse.debug.ui/debug/viewers/updateSequence")); //$NON-NLS-1$
- DEBUG_STATE_SAVE_RESTORE = DebugUIPlugin.DEBUG && "true".equals( //$NON-NLS-1$
- Platform.getDebugOption("org.eclipse.debug.ui/debug/viewers/stateSaveRestore")); //$NON-NLS-1$
- DEBUG_DELTAS = DebugUIPlugin.DEBUG && "true".equals( //$NON-NLS-1$
- Platform.getDebugOption("org.eclipse.debug.ui/debug/viewers/deltas")); //$NON-NLS-1$
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.jface.viewers.IContentProvider#dispose()
- */
- public void dispose() {
- // cancel pending updates
- synchronized (fRequestsInProgress) {
- Iterator iterator = fRequestsInProgress.values().iterator();
- while (iterator.hasNext()) {
- List requests = (List) iterator.next();
- Iterator reqIter = requests.iterator();
- while (reqIter.hasNext()) {
- ((IRequest) reqIter.next()).cancel();
- }
- }
- fWaitingRequests.clear();
- }
-
- synchronized(this) {
- for (Iterator itr = fPendingStateSaves.iterator(); itr.hasNext(); ) {
- ((IMementoManager)itr.next()).cancel();
- }
-
- fModelListeners.clear();
- fUpdateListeners.clear();
- fStateUpdateListeners.clear();
- disposeAllModelProxies();
- fViewer = null;
- }
- }
-
- public synchronized boolean isDisposed() {
- return fViewer == null;
- }
-
- /**
- * @param viewer the viewer whose input will change
- * @param oldInput the old input
- * @param newInput the new input
- */
- public synchronized void inputAboutToChange(ITreeModelContentProviderTarget viewer, Object oldInput, Object newInput) {
- if (newInput != oldInput && oldInput != null) {
- for (Iterator itr = fCompareRequestsInProgress.values().iterator(); itr.hasNext();) {
- ((ElementCompareRequest) itr.next()).cancel();
- itr.remove();
- }
- saveViewerState(oldInput);
- }
- }
-
- /*
- * (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 = (ITreeModelContentProviderTarget) viewer;
- if (newInput != oldInput) {
- cancelSubtreeUpdates(TreePath.EMPTY);
- disposeAllModelProxies();
- cancelSubtreeUpdates(TreePath.EMPTY);
- fTransform.clear();
- if (newInput != null) {
- installModelProxy(newInput, TreePath.EMPTY);
- restoreViewerState(newInput);
- }
- }
- }
-
- /**
- * Restores the viewer state unless a save is taking place. If a save is
- * taking place, the restore is queued.
- *
- * @param input
- * viewer input
- */
- protected synchronized void restoreViewerState(final Object input) {
- fPendingState = null;
- if (isSavingState()) {
- fQueuedRestore = input;
- } else {
- startRestoreViewerState(input);
- }
- }
-
- /**
- * Restores viewer state for the given input
- *
- * @param input
- * viewer input
- */
- private synchronized void startRestoreViewerState(final Object input) {
- fPendingState = null;
- final IElementMementoProvider defaultProvider = ViewerAdapterService.getMementoProvider(input);
- if (defaultProvider != 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.viewers.model.provisional.viewers
- * .
- * IMementoManager#requestComplete(org.eclipse.debug.internal.ui
- * .viewers.model.provisional.IElementMementoRequest)
- */
- public void requestComplete(IElementMementoRequest request) {
- notifyStateUpdate(input, UPDATE_COMPLETE, request);
-
- if (!request.isCanceled() && (request.getStatus() == null || request.getStatus().isOK())) {
- XMLMemento keyMemento = (XMLMemento) delta.getElement();
- StringWriter writer = new StringWriter();
- try {
- keyMemento.save(writer);
- final String keyMementoString = writer.toString();
- ModelDelta stateDelta = (ModelDelta) fViewerStates.get(keyMementoString);
- if (stateDelta != null) {
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("STATE RESTORE INPUT COMARE ENDED : " + fRequest + " - MATCHING STATE FOUND"); //$NON-NLS-1$ //$NON-NLS-2$
- }
-
- // begin restoration
- UIJob job = new UIJob("restore state") { //$NON-NLS-1$
- public IStatus runInUIThread(IProgressMonitor monitor) {
- if (!isDisposed() && input.equals(getViewer().getInput())) {
- ModelDelta stateDelta2 = (ModelDelta) fViewerStates.remove(keyMementoString);
- if (stateDelta2 != null) {
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("STATE RESTORE BEGINS"); //$NON-NLS-1$
- System.out.println("\tRESTORE: " + stateDelta2.toString()); //$NON-NLS-1$
- notifyStateUpdate(input, STATE_RESTORE_SEQUENCE_BEGINS, null);
- }
- stateDelta2.setElement(input);
- fPendingState = stateDelta2;
- doInitialRestore(fPendingState);
- }
- } else {
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("STATE RESTORE CANCELED."); //$NON-NLS-1$
- }
- }
- return Status.OK_STATUS;
- }
-
- };
- job.setSystem(true);
- job.schedule();
- } else {
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("STATE RESTORE INPUT COMARE ENDED : " + fRequest + " - NO MATCHING STATE"); //$NON-NLS-1$ //$NON-NLS-2$
- }
- }
- } catch (IOException e) {
- DebugUIPlugin.log(e);
- }
- } else {
- notifyStateUpdate(input, STATE_RESTORE_SEQUENCE_BEGINS, null);
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
- * org.eclipse.debug.internal.ui.viewers.model.provisional.viewers
- * .IMementoManager#processReqeusts()
- */
- public void processReqeusts() {
- notifyStateUpdate(input, STATE_RESTORE_SEQUENCE_BEGINS, null);
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("STATE RESTORE INPUT COMARE BEGIN : " + fRequest); //$NON-NLS-1$
- }
- notifyStateUpdate(input, UPDATE_BEGINS, fRequest);
- defaultProvider.encodeElements(new IElementMementoRequest[] { fRequest });
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
- * org.eclipse.debug.internal.ui.viewers.model.provisional.viewers
- * .
- * IMementoManager#addRequest(org.eclipse.debug.internal.ui.viewers
- * .model.provisional.IElementMementoRequest)
- */
- public void addRequest(IElementMementoRequest req) {
- fRequest = req;
- }
-
- public void cancel() {
- // not used
- }
-
- };
- manager.addRequest(new ElementMementoRequest(ModelContentProvider.this, getViewer().getInput(), manager,
- getPresentationContext(), delta.getElement(), getViewerTreePath(delta), inputMemento, delta));
- manager.processReqeusts();
- } else {
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("STATE RESTORE: No input memento provider"); //$NON-NLS-1$
- }
- }
- }
-
- /**
- * Restore selection/expansion based on items already in the viewer
- * @param delta the {@link ModelDelta} to restore from
- */
- protected abstract void doInitialRestore(ModelDelta delta);
-
- /**
- * @param delta the {@link ModelDelta} to restore from
- * @param knowsHasChildren if the content provider has computed its children
- * @param knowsChildCount if the content provider has already computed the child count
- * @param checkChildrenRealized if any realized children should be checked
- */
- abstract void restorePendingStateNode(final ModelDelta delta, boolean knowsHasChildren, boolean knowsChildCount, boolean checkChildrenRealized);
-
- public void cancelRestore(final TreePath path, final int flags) {
- if (fInStateRestore) {
- // If we are currently processing pending state already, ignore
- // cancelRestore requests. These requests may be triggered in the viewer
- // by changes to the tree state (Bug 295585).
- return;
- }
-
- if ((flags & IModelDelta.REVEAL) != 0 && fPendingSetTopItem != null) {
- fPendingSetTopItem.dispose();
- return;
- }
-
- // Nothing else to do
- if (fPendingState == null) {
- return;
- }
-
- if ((flags & (IModelDelta.SELECT | IModelDelta.REVEAL)) != 0) {
- // If we're canceling reveal and this is waiting for updates to complete
- // then just cancel it and return
-
- // If we're canceling select or reveal, cancel it for all of pending deltas
- final int mask = flags & (IModelDelta.SELECT | IModelDelta.REVEAL);
- fPendingState.accept(new IModelDeltaVisitor() {
- public boolean visit(IModelDelta delta, int depth) {
- int deltaFlags = delta.getFlags();
- int newFlags = deltaFlags & ~mask;
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- if (deltaFlags != newFlags) {
- System.out.println("\tCANCEL: " + delta.getElement() + "(" + Integer.toHexString(deltaFlags & mask) + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- }
- }
- ((ModelDelta)delta).setFlags(newFlags);
- return true;
- }
- });
- }
- if ((flags & ~(IModelDelta.SELECT | IModelDelta.REVEAL)) != 0) {
- final int mask = flags & ~(IModelDelta.SELECT | IModelDelta.REVEAL);
- // For other flags (EXPAND/COLLAPSE), cancel only from the matching path.
- fPendingState.accept(new IModelDeltaVisitor() {
- public boolean visit(IModelDelta delta, int depth) {
- if (depth < path.getSegmentCount()) {
- // Descend until we reach a matching depth.
- TreePath deltaPath = getViewerTreePath(delta);
- if (path.startsWith(deltaPath, null)) {
- return true;
- } else {
- return false;
- }
- }
- else if (depth == path.getSegmentCount()) {
- TreePath deltaPath = getViewerTreePath(delta);
- if (deltaPath.equals(path)) {
- int deltaFlags = delta.getFlags();
- int newFlags = deltaFlags & ~mask;
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- if (deltaFlags != newFlags) {
- System.out.println("\tCANCEL: " + delta.getElement() + "(" + Integer.toHexString(deltaFlags & mask) + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- }
- }
- ((ModelDelta)delta).setFlags(newFlags);
- if ((flags & IModelDelta.EXPAND) != 0) {
- // Descend delta to clear the EXPAND flags of a canceled expand
- return true;
- }
- }
- return false;
- } else {
- // We're clearing out flags of a matching sub-tree
- // assert (flags & IModelDelta.EXPAND) != 0;
-
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- if (delta.getFlags() != IModelDelta.NO_CHANGE) {
- System.out.println("\tCANCEL: " + delta.getElement() + "(" + Integer.toHexString(delta.getFlags()) + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- }
- }
- ((ModelDelta)delta).setFlags(IModelDelta.NO_CHANGE);
- return true;
- }
- }
- });
- }
- }
-
- protected void appendToPendingStateDelta(final TreePath path) {
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("STATE APPEND BEGIN: " + path.getLastSegment()); //$NON-NLS-1$
- }
-
- // build a model delta representing expansion and selection state
- final ModelDelta appendDeltaRoot = new ModelDelta(getViewer().getInput(), IModelDelta.NO_CHANGE);
- ModelDelta delta = appendDeltaRoot;
- for (int i = 0; i < path.getSegmentCount(); i++) {
- delta = delta.addNode(path.getSegment(i), IModelDelta.NO_CHANGE);
- }
-
- if (!fViewer.saveElementState(path, delta, IModelDelta.COLLAPSE | IModelDelta.EXPAND | IModelDelta.SELECT)) {
- // Path to save the state was not found or there was no
- // (expansion) state to save! Abort.
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("STATE APPEND CANCEL: Element " + path.getLastSegment() + " not found."); //$NON-NLS-1$ //$NON-NLS-2$
- }
- return;
- }
-
- // Append a marker CONTENT flag to all the delta nodes that contain the
- // EXPAND node. These
- // markers are used by the restore logic to know when a delta node can
- // be removed.
- delta.accept(new IModelDeltaVisitor() {
- public boolean visit(IModelDelta d, int depth) {
- if ((d.getFlags() & IModelDelta.EXPAND) != 0) {
- ((ModelDelta) d).setFlags(d.getFlags() | IModelDelta.CONTENT);
- }
- return true;
- }
- });
-
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("\tAPPEND DELTA: " + appendDeltaRoot); //$NON-NLS-1$
- }
-
- if (fPendingState != null) {
- // If the restore for the current input was never completed,
- // preserve
- // that restore along with the restore that was completed.
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("\tAPPEND OUTSTANDING RESTORE: " + fPendingState); //$NON-NLS-1$
- }
-
- // If the append delta is generated for a sub-tree, copy the pending dela
- // attributes into the pending delta.
- if (path.getSegmentCount() > 0) {
- fPendingState.accept( new IModelDeltaVisitor() {
- public boolean visit(IModelDelta pendingDeltaNode, int depth) {
- TreePath pendingDeltaPath = getViewerTreePath(pendingDeltaNode);
- if (path.startsWith(pendingDeltaPath, null))
- {
- ModelDelta appendDelta = findDeltaForPath(appendDeltaRoot, pendingDeltaPath);
- appendDelta.setFlags(pendingDeltaNode.getFlags());
- appendDelta.setChildCount(pendingDeltaNode.getChildCount());
- appendDelta.setIndex(pendingDeltaNode.getIndex());
- return true;
- }
- return false;
- }
- });
- }
-
- // Copy the pending state into the new appended state.
- fPendingState.accept( new IModelDeltaVisitor() {
- public boolean visit(IModelDelta pendingDeltaNode, int depth) {
- // Skip the top element
- if (pendingDeltaNode.getParentDelta() == null) {
- return true;
- }
-
- // Find the node in the save delta which is the parent
- // of to the current pending delta node.
- // If the parent node cannot be found, it means that
- // most likely the user collapsed the parent node before
- // the children were ever expanded.
- // If the pending state node already exists in the parent
- // node, it is already processed and we can skip it.
- // If the pending state node does not contain any flags,
- // we can also skip it.
- ModelDelta saveDeltaNode = findSubDeltaParent(appendDeltaRoot, pendingDeltaNode);
- if (saveDeltaNode != null &&
- !isDeltaInParent(pendingDeltaNode, saveDeltaNode) &&
- pendingDeltaNode.getFlags() != IModelDelta.NO_CHANGE)
- {
- saveDeltaNode.setChildCount(pendingDeltaNode.getParentDelta().getChildCount());
- copyIntoDelta(pendingDeltaNode, saveDeltaNode);
- } else {
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("\tSKIPPED: " + pendingDeltaNode.getElement()); //$NON-NLS-1$
- }
- }
-
- // If the pending delta node has a memento element, its
- // children should also be mementos therefore the copy
- // delta operation should have added all the children
- // of this pending delta node into the save delta.
- if (pendingDeltaNode.getElement() instanceof IMemento) {
- return false;
- } else {
- return pendingDeltaNode.getChildCount() > 0;
- }
- }
-
- });
- }
-
- if (appendDeltaRoot.getChildDeltas().length > 0) {
- // Set the new delta root as the pending state delta.
- if (fPendingState == null) {
- notifyStateUpdate(appendDeltaRoot.getElement(), STATE_RESTORE_SEQUENCE_BEGINS, null);
- }
- fPendingState = appendDeltaRoot;
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("STATE APPEND COMPLETE " + fPendingState); //$NON-NLS-1$
- }
- } else {
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("STATE APPEND CANCELED: No Data"); //$NON-NLS-1$
- }
- }
- }
-
- /**
- * Perform any restoration required for the given tree path.
- *
- * @param path the tree path to update
- * @param modelIndex the index in the current model
- * @param knowsHasChildren if the content provider knows it has children already
- * @param knowsChildCount if the content provider knows the current child count already
- * @param checkChildrenRealized if any realized children should be checked or not
- */
- protected synchronized void restorePendingStateOnUpdate(final TreePath path, final int modelIndex, final boolean knowsHasChildren,
- final boolean knowsChildCount, final boolean checkChildrenRealized) {
- if (fPendingState == null) {
- return;
- }
-
- IModelDeltaVisitor visitor = new IModelDeltaVisitor() {
- public boolean visit(final IModelDelta delta, int depth) {
-
- Object element = delta.getElement();
- Object potentialMatch = depth != 0 ? path.getSegment(depth - 1) : getViewer().getInput();
- // Only process if the depth in the delta matches the tree path.
- if (depth == path.getSegmentCount()) {
- if (element instanceof IMemento) {
- IElementMementoProvider provider = ViewerAdapterService.getMementoProvider(potentialMatch);
- if (provider == null) {
- provider = ViewerAdapterService.getMementoProvider(getViewer().getInput());
- }
- if (provider != null) {
- CompareRequestKey key = new CompareRequestKey(path, delta);
- ElementCompareRequest existingRequest = (ElementCompareRequest) fCompareRequestsInProgress
- .get(key);
- if (existingRequest != null) {
- // Check all the running compare updates for a
- // matching tree path.
- // If found, just update the flags.
- existingRequest.setKnowsHasChildren(knowsHasChildren);
- existingRequest.setKnowsChildCount(knowsChildCount);
- existingRequest.setCheckChildrenRealized(checkChildrenRealized);
- } else {
- // Start a new compare request
- ElementCompareRequest compareRequest = new ElementCompareRequest(
- ModelContentProvider.this, getViewer().getInput(), potentialMatch, path,
- (IMemento) element, (ModelDelta) delta, modelIndex, knowsHasChildren,
- knowsChildCount, checkChildrenRealized);
- fCompareRequestsInProgress.put(key, compareRequest);
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("\tSTATE BEGIN: " + compareRequest); //$NON-NLS-1$
- }
- notifyStateUpdate(element, UPDATE_BEGINS, compareRequest);
- provider.compareElements(new IElementCompareRequest[] { compareRequest });
- }
- }
- } else if (element.equals(potentialMatch)) {
- // Element comparison already succeeded, and it matches
- // our element.
- // Call restore with delta to process the delta flags.
- restorePendingStateNode((ModelDelta) delta, knowsHasChildren, knowsChildCount, checkChildrenRealized);
- }
- return false;
- }
- // Only follow the paths that match the delta.
- return element.equals(potentialMatch);
- }
- };
-
- try {
- fInStateRestore = true;
- fPendingState.accept(visitor);
- }
- finally {
- fInStateRestore = false;
- }
- checkIfRestoreComplete();
- }
-
- void compareFinished(ElementCompareRequest request, ModelDelta delta) {
- notifyStateUpdate(request.getViewerInput(), UPDATE_COMPLETE, request);
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("\tSTATE END: " + request + " = " + false); //$NON-NLS-1$ //$NON-NLS-2$
- }
-
- fCompareRequestsInProgress.remove(new CompareRequestKey(request.getElementPath(), delta));
- if (!request.isCanceled()) {
- if (request.isEqual()) {
- delta.setElement(request.getElement());
- restorePendingStateNode(delta, request.knowsHasChildren(), request.knowChildCount(), request.checkChildrenRealized());
- } else if (request.getModelIndex() != -1) {
- // Comparison failed.
- // Check if the delta has a reveal flag, and if its index
- // matches the index of the element that it was compared
- // against. If this is the case, strip the reveal flag from
- // the delta as it is most likely not applicable anymore.
- if ((delta.getFlags() & IModelDelta.REVEAL) != 0 && delta.getIndex() == request.getModelIndex()) {
- delta.setFlags(delta.getFlags() & ~IModelDelta.REVEAL);
- }
- }
- }
- checkIfRestoreComplete();
- }
-
- /**
- * Saves the viewer's state for the previous input. * @param oldInput
- * @param input the {@link ModelDelta} input
- */
- protected void saveViewerState(Object input) {
- IElementMementoProvider stateProvider = ViewerAdapterService.getMementoProvider(input);
- if (stateProvider != null) {
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("STATE SAVE BEGIN: " + input); //$NON-NLS-1$
- }
-
- // build a model delta representing expansion and selection state
- final ModelDelta saveDeltaRoot = new ModelDelta(input, IModelDelta.NO_CHANGE);
- buildViewerState(saveDeltaRoot);
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("\tSAVE DELTA FROM VIEW:\n" + saveDeltaRoot); //$NON-NLS-1$
- }
-
- // check if pending restore reveal
- if (fPendingSetTopItem != null) {
- // set back the pending reveal flag
- ModelDelta revealDelta = fPendingSetTopItem.getDelta();
- revealDelta.setFlags(revealDelta.getFlags() | IModelDelta.REVEAL);
-
- fPendingSetTopItem.dispose();
-
- ModelDelta saveDeltaNode = findSubDeltaParent(saveDeltaRoot, revealDelta);
- if (saveDeltaNode != null) {
- clearRevealFlag(saveDeltaRoot);
- boolean childFounded = false;
- for (int i = 0; i < saveDeltaNode.getChildDeltas().length; i++) {
- ModelDelta child = (ModelDelta)saveDeltaNode.getChildDeltas()[i];
- if (deltasEqual(child, revealDelta)) {
- child.setFlags(child.getFlags() | IModelDelta.REVEAL);
- childFounded = true;
- break;
- }
- }
-
- // the node should be added if not found
- if (!childFounded) {
- saveDeltaNode.setChildCount(revealDelta.getParentDelta().getChildCount());
- copyIntoDelta(revealDelta, saveDeltaNode);
- }
- } else {
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("\tSKIPPED: " + revealDelta.getElement()); //$NON-NLS-1$
- }
- }
- }
-
- if (fPendingState != null) {
- // If the restore for the current input was never completed,
- // preserve
- // that restore along with the restore that was completed.
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("\tSAVE OUTSTANDING RESTORE: " + fPendingState); //$NON-NLS-1$
- }
-
- IModelDeltaVisitor pendingStateVisitor = new IModelDeltaVisitor() {
- public boolean visit(IModelDelta pendingDeltaNode, int depth) {
- // Ignore the top element.
- if (pendingDeltaNode.getParentDelta() == null) {
- return true;
- }
-
- // Find the node in the save delta which is the parent
- // of to the current pending delta node.
- // If the parent node cannot be found, it means that
- // most likely the user collapsed the parent node before
- // the children were ever expanded.
- // If the pending state node already exists in the
- // parent
- // node, it is already processed and we can skip it.
- // If the pending state node does not contain any flags,
- // we can also skip it.
- ModelDelta saveDeltaNode = findSubDeltaParent(saveDeltaRoot, pendingDeltaNode);
- if (saveDeltaNode != null && !isDeltaInParent(pendingDeltaNode, saveDeltaNode)
- && pendingDeltaNode.getFlags() != IModelDelta.NO_CHANGE) {
- // There should be only one delta element with
- // the REVEAL flag in the entire save delta. The
- // reveal flag in the pending delta trumps the one
- // in the save delta because most likely the restore
- // operation did not yet complete the reveal
- // operation.
- if ((pendingDeltaNode.getFlags() & IModelDelta.REVEAL) != 0) {
- clearRevealFlag(saveDeltaRoot);
- }
- saveDeltaNode.setChildCount(pendingDeltaNode.getParentDelta().getChildCount());
- copyIntoDelta(pendingDeltaNode, saveDeltaNode);
- } else {
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("\tSKIPPED: " + pendingDeltaNode.getElement()); //$NON-NLS-1$
- }
- }
-
- // If the pending delta node has a memento element, its
- // children should also be mementos therefore the copy
- // delta operation should have added all the children
- // of this pending delta node into the save delta.
- if (pendingDeltaNode.getElement() instanceof IMemento) {
- return false;
- } else {
- return pendingDeltaNode.getChildCount() > 0;
- }
- }
- };
- fPendingState.accept(pendingStateVisitor);
- }
-
- if (saveDeltaRoot.getChildDeltas().length > 0) {
- // encode delta with mementos in place of elements, in non-UI
- // thread
- encodeDelta(saveDeltaRoot, stateProvider);
- } else {
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("STATE SAVE CANCELED, NO DATA"); //$NON-NLS-1$
- }
- }
- }
- }
-
- private void clearRevealFlag(ModelDelta saveRootDelta) {
- IModelDeltaVisitor clearDeltaVisitor = new IModelDeltaVisitor() {
- public boolean visit(IModelDelta delta, int depth) {
- if ((delta.getFlags() & IModelDelta.REVEAL) != 0) {
- ((ModelDelta) delta).setFlags(delta.getFlags() & ~IModelDelta.REVEAL);
- }
- return true;
- }
- };
- saveRootDelta.accept(clearDeltaVisitor);
- }
-
- private ModelDelta findSubDeltaParent(ModelDelta destinationDeltaRoot, IModelDelta subDelta) {
- // Create a path of elements to the sub-delta.
- LinkedList deltaPath = new LinkedList();
- IModelDelta delta = subDelta;
- while (delta.getParentDelta() != null) {
- delta = delta.getParentDelta();
- deltaPath.addFirst(delta);
- }
-
- // For each element in the path of the sub-delta, find the corresponding
- // element in the destination delta
- Iterator itr = deltaPath.iterator();
- // Skip the root element
- itr.next();
- ModelDelta saveDelta = destinationDeltaRoot;
- outer: while (itr.hasNext()) {
- IModelDelta itrDelta = (IModelDelta) itr.next();
- for (int i = 0; i < saveDelta.getChildDeltas().length; i++) {
- if (deltasEqual(saveDelta.getChildDeltas()[i], itrDelta)) {
- saveDelta = (ModelDelta) saveDelta.getChildDeltas()[i];
- continue outer;
- }
- }
- return null;
- }
- return saveDelta;
- }
-
- private ModelDelta findDeltaForPath(ModelDelta root, TreePath path) {
- ModelDelta delta = root;
- for (int i = 0; i < path.getSegmentCount(); i++) {
- delta = delta.getChildDelta(path.getSegment(i));
- if (delta == null) {
- return null;
- }
- }
- return delta;
- }
-
- private boolean deltasEqual(IModelDelta d1, IModelDelta d2) {
- // Note: don't compare the child count, because it is
- // incorrect for nodes which have not been expanded yet.
- return d1.getElement().equals(d2.getElement()) && d1.getIndex() == d2.getIndex();
- }
-
- private boolean isDeltaInParent(IModelDelta delta, ModelDelta destParent) {
- for (int i = 0; i < destParent.getChildDeltas().length; i++) {
- if (deltasEqual(destParent.getChildDeltas()[i], delta)) {
- return true;
- }
- }
- return false;
- }
-
- private void copyIntoDelta(IModelDelta delta, ModelDelta destParent) {
- ModelDelta newDelta = destParent.addNode(delta.getElement(), delta.getIndex(), delta.getFlags(), delta
- .getChildCount());
- for (int i = 0; i < delta.getChildDeltas().length; i++) {
- copyIntoDelta(delta.getChildDeltas()[i], newDelta);
- }
- }
-
- /**
- * Encodes delta elements into mementos using the given provider.
- * @param rootDelta the {@link ModelDelta} to encode
- * @param defaultProvider the default provider to use when processing the given delta
- *
- */
- protected void encodeDelta(final ModelDelta rootDelta, final IElementMementoProvider defaultProvider) {
- final Object input = rootDelta.getElement();
- 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() {
-
- /**
- * list of memento fRequests
- */
- private List fRequests = new ArrayList();
-
- /**
- * Flag indicating whether the encoding of delta has been canceled.
- */
- private boolean fCanceled = false;
-
- /*
- * (non-Javadoc)
- *
- * @see
- * org.eclipse.debug.internal.ui.viewers.model.provisional.viewers
- * .IMementoManager
- * #requestComplete(org.eclipse.debug.internal.ui.viewers
- * .model.provisional.IElementMementoRequest)
- */
- public void requestComplete(IElementMementoRequest request) {
- notifyStateUpdate(input, UPDATE_COMPLETE, request);
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("\tSTATE END: " + request); //$NON-NLS-1$
- }
-
- if (!request.isCanceled() && (request.getStatus() == null || request.getStatus().isOK())) {
- boolean requestsComplted = false;
- synchronized(this) {
- if (!fCanceled) {
- fRequests.remove(request);
- requestsComplted = fRequests.isEmpty();
- }
- }
- if (requestsComplted) {
- XMLMemento keyMemento = (XMLMemento) rootDelta.getElement();
- StringWriter writer = new StringWriter();
- try {
- keyMemento.save(writer);
- fViewerStates.put(writer.toString(), rootDelta);
- } catch (IOException e) {
- DebugUIPlugin.log(e);
- }
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("STATE SAVE COMPLETED: " + rootDelta); //$NON-NLS-1$
- }
- stateSaveComplete(input, this);
- }
- } else {
- cancel();
- }
- }
-
- public void cancel() {
- synchronized (this) {
- if (fCanceled) {
- return;
- }
-
- fCanceled = true;
- Iterator iterator = fRequests.iterator();
- while (iterator.hasNext()) {
- IElementMementoRequest req = (IElementMementoRequest) iterator.next();
- req.cancel();
- }
- fRequests.clear();
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("STATE SAVE ABORTED: " + rootDelta.getElement()); //$NON-NLS-1$
- }
- }
- stateSaveComplete(input, this);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
- * org.eclipse.debug.internal.ui.viewers.model.provisional.viewers
- * .IMementoManager#processReqeusts()
- */
- public synchronized void processReqeusts() {
- Map providers = new HashMap();
- Iterator iterator = fRequests.iterator();
- while (iterator.hasNext()) {
- IElementMementoRequest request = (IElementMementoRequest) iterator.next();
- notifyStateUpdate(input, UPDATE_BEGINS, request);
- IElementMementoProvider provider = ViewerAdapterService.getMementoProvider(request.getElement());
- if (provider == null) {
- provider = defaultProvider;
- }
- List reqs = (List) providers.get(provider);
- if (reqs == null) {
- reqs = new ArrayList();
- providers.put(provider, reqs);
- }
- reqs.add(request);
- }
- iterator = providers.entrySet().iterator();
- while (iterator.hasNext()) {
- Entry entry = (Entry) iterator.next();
- IElementMementoProvider provider = (IElementMementoProvider) entry.getKey();
- List reqs = (List) entry.getValue();
- provider.encodeElements((IElementMementoRequest[]) reqs.toArray(new IElementMementoRequest[reqs
- .size()]));
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
- * org.eclipse.debug.internal.ui.viewers.model.provisional.viewers
- * .IMementoManager
- * #addRequest(org.eclipse.debug.internal.ui.viewers.
- * model.provisional.IElementMementoRequest)
- */
- public synchronized void addRequest(IElementMementoRequest request) {
- fRequests.add(request);
- }
-
- };
- IModelDeltaVisitor visitor = new IModelDeltaVisitor() {
- public boolean visit(IModelDelta delta, int depth) {
- // Add the CONTENT flag to all nodes with an EXPAND flag.
- // During restoring, this flag is used as a marker indicating
- // whether all the content of a given element has been
- // retrieved.
- if ((delta.getFlags() | IModelDelta.EXPAND) != 0) {
- ((ModelDelta)delta).setFlags(delta.getFlags() | IModelDelta.CONTENT);
- }
-
- // This is the root element, save the root element memento in 'inputMemento'.
- if (delta.getParentDelta() == null) {
- manager.addRequest(new ElementMementoRequest(ModelContentProvider.this, input, manager,
- getPresentationContext(), delta.getElement(), getViewerTreePath(delta), inputMemento,
- (ModelDelta) delta));
- } else {
- // If this is another node element, save the memento to a children memento.
- if (!(delta.getElement() instanceof XMLMemento)) {
- manager.addRequest(new ElementMementoRequest(ModelContentProvider.this, input, manager,
- getPresentationContext(), delta.getElement(), getViewerTreePath(delta), childrenMemento
- .createChild("CHILD_ELEMENT"), (ModelDelta) delta)); //$NON-NLS-1$
- }
- }
- return true;
- }
- };
- rootDelta.accept(visitor);
- stateSaveStarted(input, manager);
- manager.processReqeusts();
- }
-
- /**
- * Called when a state save is starting.
- * @param input the {@link ModelDelta} input
- * @param manager the manager to notify
- */
- private synchronized void stateSaveStarted(Object input, IMementoManager manager) {
- notifyStateUpdate(input, STATE_SAVE_SEQUENCE_BEGINS, null);
- fPendingStateSaves.add(manager);
- }
-
- /**
- * Called when a state save is complete.
- * @param input the {@link ModelDelta} input
- * @param manager the manager to notify
- */
- private synchronized void stateSaveComplete(Object input, IMementoManager manager) {
- notifyStateUpdate(input, STATE_SAVE_SEQUENCE_COMPLETE, null);
- fPendingStateSaves.remove(manager);
- if (fQueuedRestore != null) {
- Object temp = fQueuedRestore;
- fQueuedRestore = null;
- restoreViewerState(temp);
- }
- }
-
- /**
- * Returns whether any state saving is in progress.
- *
- * @return whether any state saving is in progress
- */
- private synchronized boolean isSavingState() {
- return !fPendingStateSaves.isEmpty();
- }
-
- /**
- * 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 path the {@link TreePath} to dispose the model proxy for
- */
- protected synchronized void disposeModelProxy(TreePath path) {
- IModelProxy proxy = (IModelProxy) fTreeModelProxies.remove(path);
- if (proxy != null) {
- proxy.dispose();
- }
- proxy = (IModelProxy) fModelProxies.remove(path.getLastSegment());
- 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();
-
- updatePolicies = fTreeModelProxies.values().iterator();
- while (updatePolicies.hasNext()) {
- IModelProxy proxy = (IModelProxy) updatePolicies.next();
- proxy.dispose();
- }
- fTreeModelProxies.clear();
- }
-
- protected synchronized IModelProxy[] getModelProxies() {
- IModelProxy[] proxies = new IModelProxy[fTreeModelProxies.size() + fModelProxies.size()];
- fTreeModelProxies.values().toArray(proxies);
- System.arraycopy(fModelProxies.values().toArray(), 0, proxies, fModelProxies.size(), fModelProxies.size());
- return proxies;
- }
-
- protected synchronized IModelProxy getElementProxy(TreePath path) {
- while (path != null) {
- IModelProxy proxy = (IModelProxy) fTreeModelProxies.get(path);
- if (proxy != null) {
- return proxy;
- }
-
- Object element = path.getSegmentCount() == 0 ? getViewer().getInput() : path.getLastSegment();
- proxy = (IModelProxy) fModelProxies.get(element);
- if (proxy != null) {
- return proxy;
- }
-
- path = path.getParentPath();
- }
- return null;
- }
-
- /**
- * Installs the model proxy for the given element into this content provider
- * if not already installed.
- * @param input the input to install the model proxy on
- * @param path the {@link TreePath} to install the proxy for
- */
- protected synchronized void installModelProxy(Object input, TreePath path) {
- if (!fTreeModelProxies.containsKey(path) && !fModelProxies.containsKey(path.getLastSegment())) {
- Object element = path.getSegmentCount() != 0 ? path.getLastSegment() : input;
- IModelProxy proxy = null;
- IModelProxyFactory2 modelProxyFactory2 = ViewerAdapterService.getModelProxyFactory2(element);
- if (modelProxyFactory2 != null) {
- proxy = modelProxyFactory2.createTreeModelProxy(input, path, getPresentationContext());
- if (proxy != null) {
- fTreeModelProxies.put(path, proxy);
- }
- }
- if (proxy == null) {
- IModelProxyFactory modelProxyFactory = ViewerAdapterService.getModelProxyFactory(element);
- if (modelProxyFactory != null) {
- proxy = modelProxyFactory.createModelProxy(element, getPresentationContext());
- if (proxy != null) {
- fModelProxies.put(element, proxy);
- }
- }
- }
-
- if (proxy != null) {
- final IModelProxy finalProxy = proxy;
- if (proxy != null) {
- Job job = new Job("Model Proxy installed notification job") {//$NON-NLS-1$
- protected IStatus run(IProgressMonitor monitor) {
- if (!monitor.isCanceled()) {
- IPresentationContext context = null;
- Viewer viewer = null;
- synchronized (ModelContentProvider.this) {
- if (!isDisposed()) {
- context = getPresentationContext();
- viewer = (Viewer) getViewer();
- }
- }
- if (context != null && !finalProxy.isDisposed()) {
- finalProxy.init(context);
- finalProxy.addModelChangedListener(ModelContentProvider.this);
- finalProxy.installed(viewer);
- }
- }
- return Status.OK_STATUS;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.core.runtime.jobs.Job#shouldRun()
- */
- public boolean shouldRun() {
- return !isDisposed();
- }
- };
- job.setSystem(true);
- job.schedule();
- }
- }
- }
- }
-
- /**
- * 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, final IModelProxy proxy) {
- Display display = null;
-
- // Check if the viewer is still available, i.e. if the content provider
- // is not disposed.
- synchronized(this) {
- if (fViewer != null && !proxy.isDisposed()) {
- display = fViewer.getDisplay();
- }
- }
- if (display != null) {
- // If we're in display thread, process the delta immediately to
- // avoid "skid" in processing events.
- if (Thread.currentThread().equals(display.getThread())) {
- doModelChanged(delta, proxy);
- }
- else {
- WorkbenchJob job = new WorkbenchJob(fViewer.getDisplay(), "process model delta") { //$NON-NLS-1$
- public IStatus runInUIThread(IProgressMonitor monitor) {
- doModelChanged(delta, proxy);
- return Status.OK_STATUS;
- }
- };
- job.setSystem(true);
- job.schedule();
- }
- }
- }
-
- private void doModelChanged(IModelDelta delta, IModelProxy proxy) {
- if (!proxy.isDisposed()) {
- if (DEBUG_DELTAS && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- DebugUIPlugin.debug("RECEIVED DELTA: " + delta.toString()); //$NON-NLS-1$
- }
-
- updateModel(delta, getModelDeltaMask());
-
- // Call model listeners after updating the viewer model.
- Object[] listeners = fModelListeners.getListeners();
- for (int i = 0; i < listeners.length; i++) {
- ((IModelChangedListener) listeners[i]).modelChanged(delta, proxy);
- }
- }
- }
-
- /**
- * @param mask the new mask to set
- * @see ITreeModelContentProvider for a list of masks
- */
- public void setModelDeltaMask(int mask) {
- fModelDeltaMask = mask;
- }
-
- /**
- * @return the current model delta mask
- * @see IModelDelta for a list of masks
- */
- public int getModelDeltaMask() {
- return fModelDeltaMask;
- }
-
- public void updateModel(IModelDelta delta, int mask) {
- IModelDelta[] deltaArray = new IModelDelta[] { delta };
- updateNodes(deltaArray, mask & (IModelDelta.REMOVED | IModelDelta.UNINSTALL));
- updateNodes(deltaArray, mask & ITreeModelContentProvider.UPDATE_MODEL_DELTA_FLAGS
- & ~(IModelDelta.REMOVED | IModelDelta.UNINSTALL));
- updateNodes(deltaArray, mask & ITreeModelContentProvider.CONTROL_MODEL_DELTA_FLAGS);
-
- checkIfRestoreComplete();
- }
-
- /**
- * Updates the viewer with the following deltas.
- *
- * @param nodes Model deltas to be processed.
- * @param mask the model delta mask
- * @see IModelDelta for a list of masks
- */
- protected void updateNodes(IModelDelta[] nodes, int mask) {
- for (int i = 0; i < nodes.length; i++) {
- IModelDelta node = nodes[i];
- int flags = node.getFlags() & mask;
-
- if ((flags & IModelDelta.ADDED) != 0) {
- handleAdd(node);
- }
- if ((flags & IModelDelta.REMOVED) != 0) {
- handleRemove(node);
- }
- if ((flags & IModelDelta.CONTENT) != 0) {
- handleContent(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);
- }
- if ((flags & IModelDelta.EXPAND) != 0) {
- handleExpand(node);
- }
- if ((flags & IModelDelta.COLLAPSE) != 0) {
- handleCollapse(node);
- }
- if ((flags & IModelDelta.SELECT) != 0) {
- handleSelect(node);
- }
- if ((flags & IModelDelta.REVEAL) != 0) {
- handleReveal(node);
- }
- updateNodes(node.getChildDeltas(), mask);
- }
- }
-
- protected abstract void handleState(IModelDelta delta);
-
- protected abstract void handleSelect(IModelDelta delta);
-
- protected abstract void handleExpand(IModelDelta delta);
-
- protected abstract void handleCollapse(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 abstract void handleReveal(IModelDelta delta);
-
- protected void handleInstall(IModelDelta delta) {
- installModelProxy(getViewer().getInput(), getFullTreePath(delta));
- }
-
- protected void handleUninstall(IModelDelta delta) {
- disposeModelProxy(getFullTreePath(delta));
- }
-
- /**
- * Returns a tree path for the node including the root element.
- *
- * @param node
- * model delta
- * @return corresponding tree path
- */
- protected TreePath getFullTreePath(IModelDelta node) {
- ArrayList list = new ArrayList();
- while (node.getParentDelta() != null) {
- list.add(0, node.getElement());
- node = node.getParentDelta();
- }
- return new TreePath(list.toArray());
- }
-
- /**
- * Returns a tree path for the node, *not* including the root element.
- *
- * @param node
- * model delta
- * @return corresponding tree path
- */
- protected TreePath getViewerTreePath(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 ITreeModelContentProviderTarget getViewer() {
- return fViewer;
- }
-
- /**
- * 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 or -1 if
- * filtered
- */
- public 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
- */
- public 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
- * @param element
- * the filtered element
- * @return whether the child was already filtered
- */
- protected boolean addFilteredIndex(TreePath parentPath, int index, Object element) {
- return fTransform.addFilteredIndex(parentPath, index, element);
- }
-
- /**
- * Notes that the element at the given index has been removed from its
- * parent and filtered indexes should be updated accordingly.
- *
- * @param parentPath
- * path to parent element
- * @param index
- * index of element that was removed
- */
- protected void removeElementFromFilters(TreePath parentPath, int index) {
- fTransform.removeElementFromFilters(parentPath, index);
- }
-
- /**
- * Removes the given element from filtered elements of the given parent
- * element. Return true if the element was removed, otherwise false.
- *
- * @param parentPath
- * path to parent element
- * @param element
- * element to remove
- * @return whether the element was removed
- */
- protected boolean removeElementFromFilters(TreePath parentPath, Object element) {
- return fTransform.removeElementFromFilters(parentPath, element);
- }
-
- /**
- * The child count for a parent has been computed. Ensure any filtered items
- * above the given count are cleared.
- *
- * @param parentPath
- * path to parent element
- * @param childCount
- * number of children
- */
- protected void setModelChildCount(TreePath parentPath, int childCount) {
- fTransform.setModelChildCount(parentPath, childCount);
- }
-
- /**
- * 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
- */
- public boolean shouldFilter(Object parentElementOrTreePath, Object element) {
- ViewerFilter[] filters = fViewer.getFilters();
- if (filters.length > 0) {
- for (int j = 0; j < filters.length; j++) {
- if (!(filters[j].select((Viewer) fViewer, parentElementOrTreePath, element))) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Returns whether the given index of the specified parent was previously
- * filtered.
- *
- * @param parentPath the parent path
- * @param index the index of parent path
- * @return whether the element at the given index was filtered
- */
- protected boolean isFiltered(TreePath parentPath, int index) {
- return fTransform.isFiltered(parentPath, index);
- }
-
- /**
- * Notification the given element is being unmapped.
- *
- * @param path the path to remove from the {@link FilterTransform} and cancel updates from
- */
- public void unmapPath(TreePath path) {
- // System.out.println("Unmap " + path.getLastSegment());
- fTransform.clear(path);
- cancelSubtreeUpdates(path);
- }
-
- /**
- * Returns filtered children or <code>null</code>
- *
- * @param parent the parent path to get children for
- * @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);
- }
-
- protected synchronized void checkIfRestoreComplete() {
- if (fPendingState == null) {
- return;
- }
-
- /**
- * 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) {
- // Filster out the CONTENT flags from the delta flags, the content
- // flag is only used as a marker indicating that all the sub-elements
- // of a given delta have been retrieved.
- int flags = (delta.getFlags() & ~IModelDelta.CONTENT);
-
- if (flags != IModelDelta.NO_CHANGE) {
- IModelDelta parentDelta = delta.getParentDelta();
- // Remove the delta if :
- // - The parent delta has no more flags on it (the content flag is removed as well),
- // which means that parent element's children have been completely exposed.
- // - There are no more pending updates for the element.
- // - If element is a memento, there are no state requests pending.
- if (parentDelta != null && parentDelta.getFlags() == IModelDelta.NO_CHANGE) {
- TreePath deltaPath = getViewerTreePath(delta);
- if ( !areElementUpdatesPending(deltaPath) &&
- (!(delta.getElement() instanceof IMemento) || !areMementoUpdatesPending(delta)) )
- {
- removeDelta(delta);
- return false;
- }
- }
-
- if (flags != IModelDelta.REVEAL || (delta.getElement() instanceof IMemento)) {
- complete = false;
- return false;
- }
- }
- return true;
- }
-
- public boolean isComplete() {
- return complete;
- }
-
- private boolean areElementUpdatesPending(TreePath path) {
- synchronized (fRequestsInProgress) {
- TreePath parentPath = path.getParentPath();
- List requests = (List) fWaitingRequests.get(path);
- if (requests != null) {
- for (int i = 0; i < requests.size(); i++) {
- ViewerUpdateMonitor update = (ViewerUpdateMonitor) requests.get(i);
- if (update instanceof ChildrenUpdate) {
- return true;
- }
- }
- }
- requests = (List) fWaitingRequests.get(parentPath);
- if (requests != null) {
- for (int i = 0; i < requests.size(); i++) {
- ViewerUpdateMonitor update = (ViewerUpdateMonitor) requests.get(i);
- if (update.containsUpdate(path)) {
- return true;
- }
- }
- }
- requests = (List) fRequestsInProgress.get(path);
- if (requests != null) {
- for (int i = 0; i < requests.size(); i++) {
- ViewerUpdateMonitor update = (ViewerUpdateMonitor) requests.get(i);
- if (update instanceof ChildrenUpdate) {
- return true;
- }
- }
- }
- requests = (List) fRequestsInProgress.get(parentPath);
- if (requests != null) {
- for (int i = 0; i < requests.size(); i++) {
- ViewerUpdateMonitor update = (ViewerUpdateMonitor) requests.get(i);
- if (update.getElement().equals(path.getLastSegment())) {
- return true;
- }
- }
- }
- }
- return false;
- }
-
- private boolean areMementoUpdatesPending(IModelDelta delta) {
- for (Iterator itr = fCompareRequestsInProgress.keySet().iterator(); itr.hasNext();) {
- CompareRequestKey key = (CompareRequestKey) itr.next();
- if (delta.getElement().equals(key.fDelta.getElement())) {
- return true;
- }
- }
- return false;
- }
-
- private void removeDelta(IModelDelta delta) {
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("\tRESTORE REMOVED: " + delta.getElement()); //$NON-NLS-1$
- }
-
- delta.accept(new IModelDeltaVisitor() {
- public boolean visit(IModelDelta _visitorDelta, int depth) {
- ModelDelta visitorDelta = (ModelDelta) _visitorDelta;
- visitorDelta.setElement(ELEMENT_REMOVED);
- visitorDelta.setFlags(IModelDelta.NO_CHANGE);
- return true;
- }
- });
-
- }
- }
-
- CheckState state = new CheckState();
- fPendingState.accept(state);
- if (state.isComplete()) {
- // notify restore complete if REVEAL was restored also, otherwise
- // postpone until then.
- if (fPendingSetTopItem == null) {
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("STATE RESTORE COMPELTE: " + fPendingState); //$NON-NLS-1$
- }
-
- notifyStateUpdate(fPendingState.getElement(), STATE_RESTORE_SEQUENCE_COMPLETE, null);
- }
-
- fPendingState = null;
- }
- }
-
- public void addViewerUpdateListener(IViewerUpdateListener listener) {
- fUpdateListeners.add(listener);
- }
-
- public void removeViewerUpdateListener(IViewerUpdateListener listener) {
- fUpdateListeners.remove(listener);
- }
-
- /**
- * Notification an update request has started
- *
- * @param update the update to notify about
- */
- void updateStarted(ViewerUpdateMonitor update) {
- boolean begin = false;
- synchronized (fRequestsInProgress) {
- begin = fRequestsInProgress.isEmpty();
- List requests = (List) fRequestsInProgress.get(update.getSchedulingPath());
- if (requests == null) {
- requests = new ArrayList();
- fRequestsInProgress.put(update.getSchedulingPath(), requests);
- }
- requests.add(update);
- }
- if (begin) {
- if (DEBUG_UPDATE_SEQUENCE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("MODEL SEQUENCE BEGINS"); //$NON-NLS-1$
- }
- notifyUpdate(UPDATE_SEQUENCE_BEGINS, null);
- }
- if (DEBUG_UPDATE_SEQUENCE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("\tBEGIN - " + update); //$NON-NLS-1$
- }
- notifyUpdate(UPDATE_BEGINS, update);
- }
-
- /**
- * Notification an update request has completed
- *
- * @param update the update to notify
- */
- void updateComplete(final ViewerUpdateMonitor update) {
- notifyUpdate(UPDATE_COMPLETE, update);
- if (DEBUG_UPDATE_SEQUENCE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("\tEND - " + update); //$NON-NLS-1$
- }
-
- new UIJob("Update complete") { //$NON-NLS-1$
- { setSystem(true); }
-
- public IStatus runInUIThread(IProgressMonitor monitor) {
- boolean end = false;
- synchronized (fRequestsInProgress) {
- List requests = (List) fRequestsInProgress.get(update.getSchedulingPath());
- if (requests != null) {
- requests.remove(update);
- trigger(update);
- if (requests.isEmpty()) {
- fRequestsInProgress.remove(update.getSchedulingPath());
- }
- }
- end = fRequestsInProgress.isEmpty();
- }
- if (end) {
- if (DEBUG_UPDATE_SEQUENCE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("MODEL SEQUENCE ENDS"); //$NON-NLS-1$
- }
- notifyUpdate(UPDATE_SEQUENCE_COMPLETE, null);
- }
- return Status.OK_STATUS;
- }
- }.schedule();
- }
-
- protected void notifyUpdate(final int type, final IViewerUpdate 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);
- }
- });
- }
- }
- }
-
- public void addStateUpdateListener(IStateUpdateListener listener) {
- fStateUpdateListeners.add(listener);
- }
-
- public void removeStateUpdateListener(IStateUpdateListener listener) {
- fStateUpdateListeners.remove(listener);
- }
-
- protected void notifyStateUpdate(final Object input, final int type, final IViewerUpdate update) {
- if (!fStateUpdateListeners.isEmpty()) {
- Object[] listeners = fStateUpdateListeners.getListeners();
- for (int i = 0; i < listeners.length; i++) {
- final IStateUpdateListener listener = (IStateUpdateListener) listeners[i];
- SafeRunner.run(new ISafeRunnable() {
- public void run() throws Exception {
- switch (type) {
- case STATE_SAVE_SEQUENCE_BEGINS:
- listener.stateSaveUpdatesBegin(input);
- break;
- case STATE_SAVE_SEQUENCE_COMPLETE:
- listener.stateSaveUpdatesComplete(input);
- break;
- case STATE_RESTORE_SEQUENCE_BEGINS:
- listener.stateRestoreUpdatesBegin(input);
- break;
- case STATE_RESTORE_SEQUENCE_COMPLETE:
- listener.stateRestoreUpdatesComplete(input);
- break;
- case UPDATE_BEGINS:
- listener.stateUpdateStarted(input, update);
- break;
- case UPDATE_COMPLETE:
- listener.stateUpdateComplete(input, update);
- break;
- }
- }
-
- public void handleException(Throwable exception) {
- DebugUIPlugin.log(exception);
- }
- });
- }
- }
- }
-
- protected void cancelSubtreeUpdates(TreePath path) {
- synchronized (fRequestsInProgress) {
- Iterator iterator = fRequestsInProgress.entrySet().iterator();
- while (iterator.hasNext()) {
- Entry entry = (Entry) iterator.next();
- TreePath entryPath = (TreePath) entry.getKey();
- if (entryPath.startsWith(path, null)) {
- List requests = (List) entry.getValue();
- Iterator reqIter = requests.iterator();
- while (reqIter.hasNext()) {
- ((IRequest) reqIter.next()).cancel();
- }
- }
- }
- List purge = new ArrayList();
- iterator = fWaitingRequests.keySet().iterator();
- while (iterator.hasNext()) {
- TreePath entryPath = (TreePath) iterator.next();
- if (entryPath.startsWith(path, null)) {
- purge.add(entryPath);
- }
- }
- iterator = purge.iterator();
- while (iterator.hasNext()) {
- fWaitingRequests.remove(iterator.next());
- }
- }
- for (Iterator itr = fCompareRequestsInProgress.keySet().iterator(); itr.hasNext();) {
- CompareRequestKey key = (CompareRequestKey) itr.next();
- if (key.fPath.startsWith(path, null)) {
- ElementCompareRequest compareRequest = (ElementCompareRequest) fCompareRequestsInProgress.get(key);
- compareRequest.cancel();
- itr.remove();
- }
- }
- }
-
- /**
- * Returns whether this given request should be run, or should wait for
- * parent update to complete.
- *
- * @param update the update the schedule
- */
- void schedule(ViewerUpdateMonitor update) {
- synchronized (fRequestsInProgress) {
- TreePath schedulingPath = update.getSchedulingPath();
- List requests = (List) fWaitingRequests.get(schedulingPath);
- if (requests == null) {
- // no waiting requests
- TreePath parentPath = schedulingPath;
- while (fRequestsInProgress.get(parentPath) == null) {
- parentPath = parentPath.getParentPath();
- if (parentPath == null) {
- // no running requests: start request
- update.start();
- return;
- }
- }
- // request running on parent, add to waiting list
- requests = new ArrayList();
- requests.add(update);
- fWaitingRequests.put(schedulingPath, requests);
- } else {
- // there are waiting requests: coalesce with existing request?
- Iterator reqIter = requests.iterator();
- while (reqIter.hasNext()) {
- ViewerUpdateMonitor waiting = (ViewerUpdateMonitor) reqIter.next();
- if (waiting.coalesce(update)) {
- // coalesced with existing request, done
- return;
- }
- }
- // add to list of waiting requests
- requests.add(update);
- return;
- }
- }
- }
-
- protected boolean getElementChildrenRealized(TreePath path) {
- synchronized (fRequestsInProgress) {
- List requests = (List) fWaitingRequests.get(path);
- if (requests != null) {
- for (int i = 0; i < requests.size(); i++) {
- if (requests.get(i) instanceof ChildrenUpdate) {
- return false;
- }
- }
- }
- requests = (List) fRequestsInProgress.get(path);
- if (requests != null) {
- int numChildrenUpdateRequests = 0;
- for (int i = 0; i < requests.size(); i++) {
- if (requests.get(i) instanceof ChildrenUpdate) {
- if (++numChildrenUpdateRequests > 1) {
- return false;
- }
- }
- }
- }
- }
-
- return getViewer().getElementChildrenRealized(path);
- }
-
- /**
- * Triggers waiting requests based on the given request that just completed.
- *
- * TODO: should we cancel child updates if a request has been canceled?
- *
- * @param request the request that just completed
- */
- void trigger(ViewerUpdateMonitor request) {
- if (fWaitingRequests.isEmpty()) {
- return;
- }
- TreePath schedulingPath = request.getSchedulingPath();
- List waiting = (List) fWaitingRequests.get(schedulingPath);
- if (waiting == null) {
- // no waiting, update the entry with the shortest path
- int length = Integer.MAX_VALUE;
- Iterator entries = fWaitingRequests.entrySet().iterator();
- Entry candidate = null;
- while (entries.hasNext()) {
- Entry entry = (Entry) entries.next();
- TreePath key = (TreePath) entry.getKey();
- if (key.getSegmentCount() < length) {
- candidate = entry;
- length = key.getSegmentCount();
- }
- }
- if (candidate != null) {
- startHighestPriorityRequest((TreePath) candidate.getKey(), (List) candidate.getValue());
- }
- } else {
- // start the highest priority request
- startHighestPriorityRequest(schedulingPath, waiting);
- }
- }
-
- /**
- * @param key the {@link TreePath}
- * @param waiting the list of waiting requests
- */
- private void startHighestPriorityRequest(TreePath key, List waiting) {
- int priority = 4;
- ViewerUpdateMonitor next = null;
- Iterator requests = waiting.iterator();
- while (requests.hasNext()) {
- ViewerUpdateMonitor vu = (ViewerUpdateMonitor) requests.next();
- if (vu.getPriority() < priority) {
- next = vu;
- priority = next.getPriority();
- }
- }
- if (next != null) {
- waiting.remove(next);
- if (waiting.isEmpty()) {
- fWaitingRequests.remove(key);
- }
- next.start();
- }
- }
-
- /**
- * Registers the given listener for model delta notification.
- *
- * @param listener
- * model delta listener
- */
- public void addModelChangedListener(IModelChangedListener listener) {
- fModelListeners.add(listener);
- }
-
- /**
- * Unregisters the given listener from model delta notification.
- *
- * @param listener
- * model delta listener
- */
- public void removeModelChangedListener(IModelChangedListener listener) {
- fModelListeners.remove(listener);
- }
-
- /**
- * Returns the element corresponding to the given tree path.
- *
- * @param path
- * tree path
- * @return model element
- */
- protected Object getElement(TreePath path) {
- if (path.getSegmentCount() > 0) {
- return path.getLastSegment();
- }
- return getViewer().getInput();
- }
-
- /**
- * Reschedule any children updates in progress for the given parent that
- * have a start index greater than the given index. An element has been
- * removed at this index, invalidating updates in progress.
- *
- * @param parentPath
- * view tree path to parent element
- * @param modelIndex
- * index at which an element was removed
- */
- protected void rescheduleUpdates(TreePath parentPath, int modelIndex) {
- synchronized (fRequestsInProgress) {
- List requests = (List) fRequestsInProgress.get(parentPath);
- List reCreate = null;
- if (requests != null) {
- Iterator iterator = requests.iterator();
- while (iterator.hasNext()) {
- IViewerUpdate update = (IViewerUpdate) iterator.next();
- if (update instanceof IChildrenUpdate) {
- IChildrenUpdate childrenUpdate = (IChildrenUpdate) update;
- if (childrenUpdate.getOffset() > modelIndex) {
- childrenUpdate.cancel();
- if (reCreate == null) {
- reCreate = new ArrayList();
- }
- reCreate.add(childrenUpdate);
- if (DEBUG_CONTENT_PROVIDER && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("canceled update in progress handling REMOVE: " + childrenUpdate); //$NON-NLS-1$
- }
- }
- }
- }
- }
- requests = (List) fWaitingRequests.get(parentPath);
- if (requests != null) {
- Iterator iterator = requests.iterator();
- while (iterator.hasNext()) {
- IViewerUpdate update = (IViewerUpdate) iterator.next();
- if (update instanceof IChildrenUpdate) {
- IChildrenUpdate childrenUpdate = (IChildrenUpdate) update;
- if (childrenUpdate.getOffset() > modelIndex) {
- ((ChildrenUpdate) childrenUpdate).setOffset(childrenUpdate.getOffset() - 1);
- if (DEBUG_CONTENT_PROVIDER && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("modified waiting update handling REMOVE: " + childrenUpdate); //$NON-NLS-1$
- }
- }
- }
- }
- }
- // re-schedule canceled updates at new position.
- // have to do this last else the requests would be waiting and
- // get modified.
- if (reCreate != null) {
- Iterator iterator = reCreate.iterator();
- while (iterator.hasNext()) {
- IChildrenUpdate childrenUpdate = (IChildrenUpdate) iterator.next();
- int start = childrenUpdate.getOffset() - 1;
- int end = start + childrenUpdate.getLength();
- for (int i = start; i < end; i++) {
- ((TreeModelContentProvider) this).doUpdateElement(parentPath, i);
- }
- }
- }
- }
- }
-}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/SubTreeModelViewer.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/SubTreeModelViewer.java
index 6d46f29a2..c9cebd5d3 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/SubTreeModelViewer.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/SubTreeModelViewer.java
@@ -53,7 +53,7 @@ public class SubTreeModelViewer extends TreeModelViewer {
private DelegatingTreeModelViewer fDelegatingViewer;
/**
- * Returns the root element's model tree path.
+ * @return Returns the root element's model tree path.
*/
public TreePath getRootPath() {
return fRootPath;
@@ -80,7 +80,7 @@ public class SubTreeModelViewer extends TreeModelViewer {
* full model paths that the providers expect.
*/
public class DelegatingTreeModelViewer extends Viewer
- implements ITreeModelLabelProviderTarget, ITreeModelContentProviderTarget
+ implements IInternalTreeModelViewer
{
public void reveal(TreePath path, int index) {
if (path.startsWith(fRootPath, null)) {
@@ -338,10 +338,19 @@ public class SubTreeModelViewer extends TreeModelViewer {
SubTreeModelViewer.this.updateViewer(delta);
}
+
public ViewerFilter[] getFilters() {
return SubTreeModelViewer.this.getFilters();
}
+ public void addFilter(ViewerFilter filter) {
+ SubTreeModelViewer.this.addFilter(filter);
+ }
+
+ public void setFilters(ViewerFilter[] filters) {
+ SubTreeModelViewer.this.setFilters(filters);
+ }
+
public boolean overrideSelection(ISelection current, ISelection candidate) {
return SubTreeModelViewer.this.overrideSelection(current, candidate);
}
@@ -357,6 +366,27 @@ public class SubTreeModelViewer extends TreeModelViewer {
public void clearSelectionQuiet() {
SubTreeModelViewer.this.clearSelectionQuiet();
}
+
+ public TreePath[] getElementPaths(Object element) {
+ TreePath[] subViewerPaths = SubTreeModelViewer.this.getElementPaths(element);
+ TreePath[] retVal = new TreePath[subViewerPaths.length];
+ for (int i = 0; i < subViewerPaths.length; i++) {
+ retVal[i] = createFullPath(subViewerPaths[i]);
+ }
+ return retVal;
+ }
+
+ public boolean getElementChecked(TreePath path) {
+ return SubTreeModelViewer.this.getElementChecked(createSubPath(path));
+ }
+
+ public boolean getElementGrayed(TreePath path) {
+ return SubTreeModelViewer.this.getElementGrayed(createSubPath(path));
+ }
+
+ public void setElementChecked(TreePath path, boolean checked, boolean grayed) {
+ SubTreeModelViewer.this.setElementChecked(createSubPath(path), checked, grayed);
+ }
}
@@ -396,6 +426,10 @@ public class SubTreeModelViewer extends TreeModelViewer {
fBaseProvider.addModelChangedListener(listener);
}
+ public void preserveState(TreePath subPath) {
+ fBaseProvider.preserveState(createFullPath(subPath));
+ }
+
public void addStateUpdateListener(IStateUpdateListener listener) {
fBaseProvider.addStateUpdateListener(listener);
}
@@ -432,6 +466,10 @@ public class SubTreeModelViewer extends TreeModelViewer {
fBaseProvider.setModelDeltaMask(mask);
}
+ public boolean areTreeModelViewerFiltersApplicable(Object parentElement) {
+ return fBaseProvider.areTreeModelViewerFiltersApplicable(parentElement);
+ }
+
public boolean shouldFilter(Object parentElementOrTreePath, Object element) {
if (parentElementOrTreePath instanceof TreePath) {
TreePath path = (TreePath)parentElementOrTreePath;
@@ -467,9 +505,15 @@ public class SubTreeModelViewer extends TreeModelViewer {
fBaseProvider.inputChanged(fDelegatingViewer, oldInput, newInput);
}
- public void inputAboutToChange(ITreeModelContentProviderTarget viewer, Object oldInput, Object newInput) {
- fBaseProvider.inputAboutToChange(viewer, oldInput, newInput);
+ public void postInputChanged(IInternalTreeModelViewer viewer,
+ Object oldInput, Object newInput) {
+ fBaseProvider.postInputChanged(viewer, oldInput, newInput);
+ }
+
+ public boolean setChecked(TreePath path, boolean checked) {
+ return fBaseProvider.setChecked(createFullPath(path), checked);
}
+
}
/**
@@ -482,7 +526,7 @@ public class SubTreeModelViewer extends TreeModelViewer {
private TreeModelLabelProvider fBaseProvider;
- public SubTreeModelLabelProvider(ITreeModelLabelProviderTarget viewer) {
+ public SubTreeModelLabelProvider(IInternalTreeModelViewer viewer) {
fBaseProvider = new TreeModelLabelProvider(viewer);
}
@@ -529,6 +573,10 @@ public class SubTreeModelViewer extends TreeModelViewer {
}
private TreePath createFullPath(TreePath subPath) {
+ if (fRootPath == null) {
+ return TreePath.EMPTY;
+ }
+
Object[] segments = new Object[fRootPath.getSegmentCount() + subPath.getSegmentCount()];
for (int i = 0; i < fRootPath.getSegmentCount(); i++) {
segments[i] = fRootPath.getSegment(i);
@@ -540,6 +588,10 @@ public class SubTreeModelViewer extends TreeModelViewer {
}
private TreePath createSubPath(TreePath fullPath) {
+ if (fRootPath == null) {
+ return TreePath.EMPTY;
+ }
+
if (fullPath.getSegmentCount() <= fRootPath.getSegmentCount()) {
return TreePath.EMPTY;
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/TreeCursor.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/TreeCursor.java
deleted file mode 100644
index 2b420b284..000000000
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/TreeCursor.java
+++ /dev/null
@@ -1,724 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2010 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.model;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.SWTException;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.graphics.Color;
-import org.eclipse.swt.graphics.GC;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.widgets.Canvas;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Listener;
-import org.eclipse.swt.widgets.ScrollBar;
-import org.eclipse.swt.widgets.Tree;
-import org.eclipse.swt.widgets.TreeColumn;
-import org.eclipse.swt.widgets.TreeItem;
-import org.eclipse.swt.widgets.TypedListener;
-import org.eclipse.swt.widgets.Widget;
-
-import org.eclipse.debug.internal.core.IInternalDebugCoreConstants;
-
-/**
- * A TreeCursor provides a way for the user to navigate around a Tree with columns using the
- * keyboard. It also provides a mechanism for selecting an individual cell in a tree.
- *
- * <p>
- * Here is an example of using a TreeCursor to navigate to a cell and then edit it.
- *
- * <code><pre>
- * public static void main(String[] args) {
- * Display display = new Display();
- * Shell shell = new Shell(display);
- * shell.setLayout(new GridLayout());
- *
- * // create a a tree with 3 columns and fill with data
- * final Tree tree = new Tree(shell, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION);
- * tree.setLayoutData(new GridData(GridData.FILL_BOTH));
- * TreeColumn column1 = new TreeColumn(tree, SWT.NONE);
- * TreeColumn column2 = new TreeColumn(tree, SWT.NONE);
- * TreeColumn column3 = new TreeColumn(tree, SWT.NONE);
- * for (int i = 0; i &lt; 100; i++) {
- * TreeItem item = new TreeItem(tree, SWT.NONE);
- * item.setText(new String[] { "cell "+i+" 0", "cell "+i+" 1", "cell "+i+" 2"});
- * }
- * column1.pack();
- * column2.pack();
- * column3.pack();
- *
- * // create a TreeCursor to navigate around the tree
- * final TreeCursor cursor = new TreeCursor(tree, SWT.NONE);
- * // create an editor to edit the cell when the user hits "ENTER"
- * // while over a cell in the tree
- * final ControlEditor editor = new ControlEditor(cursor);
- * editor.grabHorizontal = true;
- * editor.grabVertical = true;
- *
- * cursor.addSelectionListener(new SelectionAdapter() {
- * // when the TreeEditor is over a cell, select the corresponding row in
- * // the tree
- * public void widgetSelected(SelectionEvent e) {
- * tree.setSelection(new TreeItem[] {cursor.getRow()});
- * }
- * // when the user hits "ENTER" in the TreeCursor, pop up a text editor so that
- * // they can change the text of the cell
- * public void widgetDefaultSelected(SelectionEvent e){
- * final Text text = new Text(cursor, SWT.NONE);
- * TreeItem row = cursor.getRow();
- * int column = cursor.getColumn();
- * text.setText(row.getText(column));
- * text.addKeyListener(new KeyAdapter() {
- * public void keyPressed(KeyEvent e) {
- * // close the text editor and copy the data over
- * // when the user hits "ENTER"
- * if (e.character == SWT.CR) {
- * TreeItem row = cursor.getRow();
- * int column = cursor.getColumn();
- * row.setText(column, text.getText());
- * text.dispose();
- * }
- * // close the text editor when the user hits "ESC"
- * if (e.character == SWT.ESC) {
- * text.dispose();
- * }
- * }
- * });
- * editor.setEditor(text);
- * text.setFocus();
- * }
- * });
- * // Hide the TreeCursor when the user hits the "MOD1" or "MOD2" key.
- * // This alows the user to select multiple items in the tree.
- * cursor.addKeyListener(new KeyAdapter() {
- * public void keyPressed(KeyEvent e) {
- * if (e.keyCode == SWT.MOD1 ||
- * e.keyCode == SWT.MOD2 ||
- * (e.stateMask & SWT.MOD1) != 0 ||
- * (e.stateMask & SWT.MOD2) != 0) {
- * cursor.setVisible(false);
- * }
- * }
- * });
- * // Show the TreeCursor when the user releases the "MOD2" or "MOD1" key.
- * // This signals the end of the multiple selection task.
- * tree.addKeyListener(new KeyAdapter() {
- * public void keyReleased(KeyEvent e) {
- * if (e.keyCode == SWT.MOD1 && (e.stateMask & SWT.MOD2) != 0) return;
- * if (e.keyCode == SWT.MOD2 && (e.stateMask & SWT.MOD1) != 0) return;
- * if (e.keyCode != SWT.MOD1 && (e.stateMask & SWT.MOD1) != 0) return;
- * if (e.keyCode != SWT.MOD2 && (e.stateMask & SWT.MOD2) != 0) return;
- *
- * TreeItem[] selection = tree.getSelection();
- * TreeItem row = (selection.length == 0) ? tree.getItem(tree.indexOf(tree.getTopItem())) : selection[0];
- * tree.showItem(row);
- * cursor.setSelection(row, 0);
- * cursor.setVisible(true);
- * cursor.setFocus();
- * }
- * });
- *
- * shell.open();
- * while (!shell.isDisposed()) {
- * if (!display.readAndDispatch())
- * display.sleep();
- * }
- * display.dispose();
- * }
- * </pre></code>
- *
- * <dl>
- * <dt><b>Styles:</b></dt>
- * <dd>BORDER</dd>
- * <dt><b>Events:</b></dt>
- * <dd>Selection, DefaultSelection</dd>
- * </dl>
- *
- * @since 3.3
- *
- */
-public class TreeCursor extends Canvas {
- Tree tree;
-
- TreeItem row= null;
-
- TreeColumn column= null;
-
- Listener treeListener, resizeListener, disposeItemListener, disposeColumnListener;
-
- // By default, invert the list selection colors
- static final int BACKGROUND= SWT.COLOR_LIST_SELECTION_TEXT;
-
- static final int FOREGROUND= SWT.COLOR_LIST_SELECTION;
-
- /**
- * Constructs a new instance of this class given its parent table and a style value describing
- * its behavior and appearance.
- * <p>
- * The style value is either one of the style constants defined in class <code>SWT</code> which
- * is applicable to instances of this class, or must be built by <em>bitwise OR</em>'ing
- * together (that is, using the <code>int</code> "|" operator) two or more of those
- * <code>SWT</code> style constants. The class description lists the style constants that are
- * applicable to the class. Style bits are also inherited from superclasses.
- * </p>
- *
- * @param parent a Tree control which will be the parent of the new instance (cannot be null)
- * @param style the style of control to construct
- *
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
- * </ul>
- * @exception SWTException <ul>
- * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created
- * the parent</li>
- * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
- * </ul>
- *
- * @see SWT#BORDER
- * @see Widget#checkSubclass()
- * @see Widget#getStyle()
- */
- public TreeCursor(Tree parent, int style) {
- super(parent, style);
- tree= parent;
- setBackground(null);
- setForeground(null);
-
- Listener listener= new Listener() {
- public void handleEvent(Event event) {
- switch (event.type) {
- case SWT.Dispose:
- treeCursorDispose(event);
- break;
- case SWT.FocusIn:
- case SWT.FocusOut:
- redraw();
- break;
- case SWT.KeyDown:
- treeCursorKeyDown(event);
- break;
- case SWT.Paint:
- treeCursorPaint(event);
- break;
- case SWT.Traverse:
- treeCursorTraverse(event);
- break;
- }
- }
- };
- int[] events= new int[] { SWT.Dispose, SWT.FocusIn, SWT.FocusOut, SWT.KeyDown, SWT.Paint, SWT.Traverse };
- for (int i= 0; i < events.length; i++) {
- addListener(events[i], listener);
- }
-
- treeListener= new Listener() {
- public void handleEvent(Event event) {
- switch (event.type) {
- case SWT.MouseDown:
- tableMouseDown(event);
- break;
- case SWT.FocusIn:
- tableFocusIn(event);
- break;
- }
- }
- };
- tree.addListener(SWT.FocusIn, treeListener);
- tree.addListener(SWT.MouseDown, treeListener);
-
- disposeItemListener= new Listener() {
- public void handleEvent(Event event) {
- row= null;
- column= null;
- _resize();
- }
- };
- disposeColumnListener= new Listener() {
- public void handleEvent(Event event) {
- row= null;
- column= null;
- _resize();
- }
- };
- resizeListener= new Listener() {
- public void handleEvent(Event event) {
- _resize();
- }
- };
- ScrollBar hBar= tree.getHorizontalBar();
- if (hBar != null) {
- hBar.addListener(SWT.Selection, resizeListener);
- }
- ScrollBar vBar= tree.getVerticalBar();
- if (vBar != null) {
- vBar.addListener(SWT.Selection, resizeListener);
- }
- }
-
- /**
- * Adds the listener to the collection of listeners who will be notified when the receiver's
- * selection changes, by sending it one of the messages defined in the
- * <code>SelectionListener</code> interface.
- * <p>
- * When <code>widgetSelected</code> is called, the item field of the event object is valid. If
- * the receiver has <code>SWT.CHECK</code> style set and the check selection changes, the event
- * object detail field contains the value <code>SWT.CHECK</code>.
- * <code>widgetDefaultSelected</code> is typically called when an item is double-clicked.
- * </p>
- *
- * @param listener the listener which should be notified
- *
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
- * </ul>
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created
- * the receiver</li>
- * </ul>
- *
- * @see SelectionListener
- * @see SelectionEvent
- * @see #removeSelectionListener(SelectionListener)
- *
- */
- public void addSelectionListener(SelectionListener listener) {
- checkWidget();
- if (listener == null)
- SWT.error(SWT.ERROR_NULL_ARGUMENT);
- TypedListener typedListener= new TypedListener(listener);
- addListener(SWT.Selection, typedListener);
- addListener(SWT.DefaultSelection, typedListener);
- }
-
- /**
- * @param event
- */
- void treeCursorDispose(Event event) {
- tree.removeListener(SWT.FocusIn, treeListener);
- tree.removeListener(SWT.MouseDown, treeListener);
- if (column != null) {
- column.removeListener(SWT.Dispose, disposeColumnListener);
- column.removeListener(SWT.Move, resizeListener);
- column.removeListener(SWT.Resize, resizeListener);
- column= null;
- }
- if (row != null) {
- row.removeListener(SWT.Dispose, disposeItemListener);
- row= null;
- }
- ScrollBar hBar= tree.getHorizontalBar();
- if (hBar != null) {
- hBar.removeListener(SWT.Selection, resizeListener);
- }
- ScrollBar vBar= tree.getVerticalBar();
- if (vBar != null) {
- vBar.removeListener(SWT.Selection, resizeListener);
- }
- }
-
- void treeCursorKeyDown(Event event) {
- if (row == null)
- return;
- switch (event.character) {
- case SWT.CR:
- notifyListeners(SWT.DefaultSelection, new Event());
- return;
- }
- int rowIndex= tree.indexOf(row);
- int columnIndex= column == null ? 0 : tree.indexOf(column);
- switch (event.keyCode) {
- case SWT.ARROW_UP:
- setRowColumn(Math.max(0, rowIndex - 1), columnIndex, true);
- break;
- case SWT.ARROW_DOWN:
- setRowColumn(Math.min(rowIndex + 1, tree.getItemCount() - 1), columnIndex, true);
- break;
- case SWT.ARROW_LEFT:
- case SWT.ARROW_RIGHT: {
- int columnCount= tree.getColumnCount();
- if (columnCount == 0)
- break;
- int[] order= tree.getColumnOrder();
- int index= 0;
- while (index < order.length) {
- if (order[index] == columnIndex)
- break;
- index++;
- }
- if (index == order.length)
- index= 0;
- int leadKey= (getStyle() & SWT.RIGHT_TO_LEFT) != 0 ? SWT.ARROW_RIGHT : SWT.ARROW_LEFT;
- if (event.keyCode == leadKey) {
- setRowColumn(rowIndex, order[Math.max(0, index - 1)], true);
- } else {
- setRowColumn(rowIndex, order[Math.min(columnCount - 1, index + 1)], true);
- }
- break;
- }
- case SWT.HOME:
- setRowColumn(0, columnIndex, true);
- break;
- case SWT.END: {
- int i= tree.getItemCount() - 1;
- setRowColumn(i, columnIndex, true);
- break;
- }
- case SWT.PAGE_UP: {
- int index= tree.indexOf(tree.getTopItem());
- if (index == rowIndex) {
- Rectangle rect= tree.getClientArea();
- TreeItem item= tree.getItem(index);
- Rectangle itemRect= item.getBounds(0);
- rect.height-= itemRect.y;
- int height= tree.getItemHeight();
- int page= Math.max(1, rect.height / height);
- index= Math.max(0, index - page + 1);
- }
- setRowColumn(index, columnIndex, true);
- break;
- }
- case SWT.PAGE_DOWN: {
- int index= tree.indexOf(tree.getTopItem());
- Rectangle rect= tree.getClientArea();
- TreeItem item= tree.getItem(index);
- Rectangle itemRect= item.getBounds(0);
- rect.height-= itemRect.y;
- int height= tree.getItemHeight();
- int page= Math.max(1, rect.height / height);
- int end= tree.getItemCount() - 1;
- index= Math.min(end, index + page - 1);
- if (index == rowIndex) {
- index= Math.min(end, index + page - 1);
- }
- setRowColumn(index, columnIndex, true);
- break;
- }
- }
- }
-
- void treeCursorPaint(Event event) {
- if (row == null)
- return;
- int columnIndex= column == null ? 0 : tree.indexOf(column);
- GC gc= event.gc;
- Display display= getDisplay();
- gc.setBackground(getBackground());
- gc.setForeground(getForeground());
- gc.fillRectangle(event.x, event.y, event.width, event.height);
- int x= 0;
- Point size= getSize();
- Image image= row.getImage(columnIndex);
- if (image != null) {
- Rectangle imageSize= image.getBounds();
- int imageY= (size.y - imageSize.height) / 2;
- gc.drawImage(image, x, imageY);
- x+= imageSize.width;
- }
- String text= row.getText(columnIndex);
- if (text != IInternalDebugCoreConstants.EMPTY_STRING) {
- Rectangle bounds= row.getBounds(columnIndex);
- Point extent= gc.stringExtent(text);
- // Temporary code - need a better way to determine table trim
- String platform= SWT.getPlatform();
- if ("win32".equals(platform)) { //$NON-NLS-1$
- if (tree.getColumnCount() == 0 || columnIndex == 0) {
- x+= 2;
- } else {
- int alignmnent= column.getAlignment();
- switch (alignmnent) {
- case SWT.LEFT:
- x+= 6;
- break;
- case SWT.RIGHT:
- x= bounds.width - extent.x - 6;
- break;
- case SWT.CENTER:
- x+= (bounds.width - x - extent.x) / 2;
- break;
- }
- }
- } else {
- if (tree.getColumnCount() == 0) {
- x+= 5;
- } else {
- int alignmnent= column.getAlignment();
- switch (alignmnent) {
- case SWT.LEFT:
- x+= 5;
- break;
- case SWT.RIGHT:
- x= bounds.width - extent.x - 2;
- break;
- case SWT.CENTER:
- x+= (bounds.width - x - extent.x) / 2 + 2;
- break;
- }
- }
- }
- int textY= (size.y - extent.y) / 2;
- gc.drawString(text, x, textY);
- }
- if (isFocusControl()) {
- gc.setBackground(display.getSystemColor(SWT.COLOR_BLACK));
- gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE));
- gc.drawFocus(0, 0, size.x, size.y);
- }
- }
-
- /**
- * @param event
- */
- void tableFocusIn(Event event) {
- if (isDisposed())
- return;
- if (isVisible())
- setFocus();
- }
-
- void tableMouseDown(Event event) {
- if (isDisposed() || !isVisible())
- return;
- Point pt= new Point(event.x, event.y);
- int lineWidth= tree.getLinesVisible() ? tree.getGridLineWidth() : 0;
- TreeItem item= tree.getItem(pt);
- if ((tree.getStyle() & SWT.FULL_SELECTION) != 0) {
- if (item == null)
- return;
- } else {
- int start= item != null ? tree.indexOf(item) : tree.indexOf(tree.getTopItem());
- int end= tree.getItemCount();
- Rectangle clientRect= tree.getClientArea();
- for (int i= start; i < end; i++) {
- TreeItem nextItem= tree.getItem(i);
- Rectangle rect= nextItem.getBounds(0);
- if (pt.y >= rect.y && pt.y < rect.y + rect.height + lineWidth) {
- item= nextItem;
- break;
- }
- if (rect.y > clientRect.y + clientRect.height)
- return;
- }
- if (item == null)
- return;
- }
- TreeColumn newColumn= null;
- int columnCount= tree.getColumnCount();
- if (columnCount > 0) {
- for (int i= 0; i < columnCount; i++) {
- Rectangle rect= item.getBounds(i);
- rect.width+= lineWidth;
- rect.height+= lineWidth;
- if (rect.contains(pt)) {
- newColumn= tree.getColumn(i);
- break;
- }
- }
- if (newColumn == null) {
- newColumn= tree.getColumn(0);
- }
- }
- setRowColumn(item, newColumn, true);
- setFocus();
- return;
- }
-
- void treeCursorTraverse(Event event) {
- switch (event.detail) {
- case SWT.TRAVERSE_ARROW_NEXT:
- case SWT.TRAVERSE_ARROW_PREVIOUS:
- case SWT.TRAVERSE_RETURN:
- event.doit= false;
- return;
- }
- event.doit= true;
- }
-
- void setRowColumn(int row, int column, boolean notify) {
- TreeItem item= row == -1 ? null : tree.getItem(row);
- TreeColumn col= column == -1 || tree.getColumnCount() == 0 ? null : tree.getColumn(column);
- setRowColumn(item, col, notify);
- }
-
- void setRowColumn(TreeItem row, TreeColumn column, boolean notify) {
- if (this.row == row && this.column == column) {
- return;
- }
- if (this.row != null && this.row != row) {
- this.row.removeListener(SWT.Dispose, disposeItemListener);
- this.row= null;
- }
- if (this.column != null && this.column != column) {
- this.column.removeListener(SWT.Dispose, disposeColumnListener);
- this.column.removeListener(SWT.Move, resizeListener);
- this.column.removeListener(SWT.Resize, resizeListener);
- this.column= null;
- }
- if (row != null) {
- if (this.row != row) {
- this.row= row;
- row.addListener(SWT.Dispose, disposeItemListener);
- tree.showItem(row);
- }
- if (this.column != column && column != null) {
- this.column= column;
- column.addListener(SWT.Dispose, disposeColumnListener);
- column.addListener(SWT.Move, resizeListener);
- column.addListener(SWT.Resize, resizeListener);
- tree.showColumn(column);
- }
- int columnIndex= column == null ? 0 : tree.indexOf(column);
- setBounds(row.getBounds(columnIndex));
- redraw();
- if (notify) {
- notifyListeners(SWT.Selection, new Event());
- }
- }
- }
-
- public void setVisible(boolean visible) {
- checkWidget();
- if (visible)
- _resize();
- super.setVisible(visible);
- }
-
- /**
- * Removes the listener from the collection of listeners who will be notified when the
- * receiver's selection changes.
- *
- * @param listener the listener which should no longer be notified
- *
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
- * </ul>
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created
- * the receiver</li>
- * </ul>
- *
- * @see SelectionListener
- * @see #addSelectionListener(SelectionListener)
- *
- * @since 3.0
- */
- public void removeSelectionListener(SelectionListener listener) {
- checkWidget();
- if (listener == null) {
- SWT.error(SWT.ERROR_NULL_ARGUMENT);
- }
- removeListener(SWT.Selection, listener);
- removeListener(SWT.DefaultSelection, listener);
- }
-
- void _resize() {
- if (row == null) {
- setBounds(-200, -200, 0, 0);
- } else {
- int columnIndex= column == null ? 0 : tree.indexOf(column);
- setBounds(row.getBounds(columnIndex));
- }
- }
-
- /**
- * Returns the column over which the TreeCursor is positioned.
- *
- * @return the column for the current position
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created
- * the receiver</li>
- * </ul>
- */
- public int getColumn() {
- checkWidget();
- return column == null ? 0 : tree.indexOf(column);
- }
-
- /**
- * Returns the row over which the TreeCursor is positioned.
- *
- * @return the item for the current position
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created
- * the receiver</li>
- * </ul>
- */
- public TreeItem getRow() {
- checkWidget();
- return row;
- }
-
- public void setBackground(Color color) {
- if (color == null)
- color= getDisplay().getSystemColor(BACKGROUND);
- super.setBackground(color);
- redraw();
- }
-
- public void setForeground(Color color) {
- if (color == null)
- color= getDisplay().getSystemColor(FOREGROUND);
- super.setForeground(color);
- redraw();
- }
-
- /**
- * Positions the TreeCursor over the cell at the given row and column in the parent table.
- *
- * @param row the index of the row for the cell to select
- * @param column the index of column for the cell to select
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created
- * the receiver</li>
- * </ul>
- *
- */
- public void setSelection(int row, int column) {
- checkWidget();
- int columnCount= tree.getColumnCount();
- int maxColumnIndex= columnCount == 0 ? 0 : columnCount - 1;
- if (row < 0 || row >= tree.getItemCount() || column < 0 || column > maxColumnIndex)
- SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- setRowColumn(row, column, false);
- }
-
- /**
- * Positions the TreeCursor over the cell at the given row and column in the parent table.
- *
- * @param row the TreeItem of the row for the cell to select
- * @param column the index of column for the cell to select
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created
- * the receiver</li>
- * </ul>
- *
- */
- public void setSelection(TreeItem row, int column) {
- checkWidget();
- int columnCount= tree.getColumnCount();
- int maxColumnIndex= columnCount == 0 ? 0 : columnCount - 1;
- if (row == null || row.isDisposed() || column < 0 || column > maxColumnIndex)
- SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- setRowColumn(tree.indexOf(row), column, false);
- }
-}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/TreeModelContentProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/TreeModelContentProvider.java
index aa1e21dac..18b37ec53 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/TreeModelContentProvider.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/TreeModelContentProvider.java
@@ -13,17 +13,46 @@
*******************************************************************************/
package org.eclipse.debug.internal.ui.viewers.model;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
import org.eclipse.core.runtime.Assert;
+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.Platform;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.core.IRequest;
+import org.eclipse.debug.internal.ui.DebugUIPlugin;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ICheckboxModelProxy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelChangedListener;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDeltaVisitor;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy2;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory2;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IStateUpdateListener;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewerFilter;
+import org.eclipse.jface.viewers.IContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.ITreeSelection;
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.swt.widgets.Display;
/**
@@ -31,54 +60,1072 @@ import org.eclipse.swt.widgets.Display;
*
* @since 3.3
*/
-public class TreeModelContentProvider extends ModelContentProvider implements ITreeModelContentProvider {
-
- /**
- * 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) {
- for (int i = 0; i < filteredChildren.length; i++) {
- doUpdateElement(path, filteredChildren[i]);
- }
- }
- }
- }
-
- protected synchronized void doUpdateChildCount(TreePath path) {
+public class TreeModelContentProvider implements ITreeModelContentProvider, IContentProvider, IModelChangedListener {
+
+ /**
+ * Tree model viewer that this content provider is used with.
+ */
+ private IInternalTreeModelViewer fViewer;
+
+ /**
+ * Mask used to filter delta updates coming from the model.
+ */
+ private int fModelDeltaMask = ~0;
+
+ /**
+ * Map tree paths to model proxy responsible for element
+ *
+ * Used to install different model proxy instances for one element depending
+ * on the tree path.
+ */
+ private Map fTreeModelProxies = new HashMap(); // tree model proxy by
+ // element tree path
+
+ /**
+ * Map element to model proxy responsible for it.
+ *
+ * Used to install a single model proxy which is responsible for all
+ * instances of an element in the model tree.
+ */
+ 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();
+
+ /**
+ * Viewer update listeners
+ */
+ private ListenerList fUpdateListeners = new ListenerList();
+
+ /**
+ * Map of updates in progress: element path -> list of requests
+ */
+ private Map fRequestsInProgress = new HashMap();
+
+ /**
+ * Map of dependent requests waiting for parent requests to complete:
+ * element path -> list of requests
+ */
+ private Map fWaitingRequests = new HashMap();
+
+ private List fCompletedUpdates = new ArrayList();
+
+ private Runnable fCompletedUpdatesJob;
+
+ private ViewerStateTracker fStateTracker = new ViewerStateTracker(this);
+
+ /**
+ * Update type constants
+ */
+ static final int UPDATE_SEQUENCE_BEGINS = 0;
+
+ static final int UPDATE_SEQUENCE_COMPLETE = 1;
+
+ static final int UPDATE_BEGINS = 2;
+
+ static final int UPDATE_COMPLETE = 3;
+
+
+ /**
+ * Constant for an empty tree path.
+ */
+ static final TreePath EMPTY_TREE_PATH = new TreePath(new Object[] {});
+
+ // debug flags
+ public static String DEBUG_PRESENTATION_ID = null;
+ public static boolean DEBUG_CONTENT_PROVIDER = false;
+ public static boolean DEBUG_UPDATE_SEQUENCE = false;
+ public static boolean DEBUG_DELTAS = false;
+ public static boolean DEBUG_TEST_PRESENTATION_ID(IPresentationContext context) {
+ if (context == null) {
+ return true;
+ }
+ return DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(context.getId());
+ }
+
+ static {
+ DEBUG_PRESENTATION_ID = Platform.getDebugOption("org.eclipse.debug.ui/debug/viewers/presentationId"); //$NON-NLS-1$
+ if (!DebugUIPlugin.DEBUG || "".equals(DEBUG_PRESENTATION_ID)) { //$NON-NLS-1$
+ DEBUG_PRESENTATION_ID = null;
+ }
+ DEBUG_CONTENT_PROVIDER = DebugUIPlugin.DEBUG && "true".equals( //$NON-NLS-1$
+ Platform.getDebugOption("org.eclipse.debug.ui/debug/viewers/contentProvider")); //$NON-NLS-1$
+ DEBUG_UPDATE_SEQUENCE = DebugUIPlugin.DEBUG && "true".equals( //$NON-NLS-1$
+ Platform.getDebugOption("org.eclipse.debug.ui/debug/viewers/updateSequence")); //$NON-NLS-1$
+ ViewerStateTracker.DEBUG_STATE_SAVE_RESTORE = DebugUIPlugin.DEBUG && "true".equals( //$NON-NLS-1$
+ Platform.getDebugOption("org.eclipse.debug.ui/debug/viewers/stateSaveRestore")); //$NON-NLS-1$
+ DEBUG_DELTAS = DebugUIPlugin.DEBUG && "true".equals( //$NON-NLS-1$
+ Platform.getDebugOption("org.eclipse.debug.ui/debug/viewers/deltas")); //$NON-NLS-1$
+ }
+
+ public void dispose() {
+ Assert.isTrue( getViewer().getDisplay().getThread() == Thread.currentThread() );
+
+ // cancel pending updates
+ Iterator iterator = fRequestsInProgress.values().iterator();
+ while (iterator.hasNext()) {
+ List requests = (List) iterator.next();
+ Iterator reqIter = requests.iterator();
+ while (reqIter.hasNext()) {
+ ((IRequest) reqIter.next()).cancel();
+ }
+ }
+ fWaitingRequests.clear();
+
+ fStateTracker.dispose();
+ fModelListeners.clear();
+ fUpdateListeners.clear();
+ disposeAllModelProxies();
+
+ synchronized(this) {
+ fViewer = null;
+ }
+ }
+
+ /**
+ * @return Returns whether the content provider is disposed.
+ */
+ boolean isDisposed() {
+ synchronized(this) {
+ return fViewer == null;
+ }
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ synchronized(this) {
+ fViewer = (IInternalTreeModelViewer) viewer;
+ }
+
+ Assert.isTrue( fViewer.getDisplay().getThread() == Thread.currentThread() );
+
+ if (oldInput != null) {
+ fStateTracker.saveViewerState(oldInput);
+ }
+ }
+
+ public void postInputChanged(IInternalTreeModelViewer viewer, Object oldInput, Object newInput) {
+ Assert.isTrue( getViewer().getDisplay().getThread() == Thread.currentThread() );
+
+ cancelSubtreeUpdates(TreePath.EMPTY);
+ disposeAllModelProxies();
+ cancelSubtreeUpdates(TreePath.EMPTY);
+ fTransform.clear();
+ if (newInput != null) {
+ installModelProxy(newInput, TreePath.EMPTY);
+ fStateTracker.restoreViewerState(newInput);
+ }
+ }
+
+ public void addViewerUpdateListener(IViewerUpdateListener listener) {
+ fUpdateListeners.add(listener);
+ }
+
+ public void removeViewerUpdateListener(IViewerUpdateListener listener) {
+ fUpdateListeners.remove(listener);
+ }
+
+ public void addStateUpdateListener(IStateUpdateListener listener) {
+ fStateTracker.addStateUpdateListener(listener);
+ }
+
+ public void preserveState(TreePath path) {
+ fStateTracker.appendToPendingStateDelta(path);
+ }
+
+ public void removeStateUpdateListener(IStateUpdateListener listener) {
+ fStateTracker.removeStateUpdateListener(listener);
+ }
+
+ public void addModelChangedListener(IModelChangedListener listener) {
+ fModelListeners.add(listener);
+ }
+
+ public void removeModelChangedListener(IModelChangedListener listener) {
+ fModelListeners.remove(listener);
+ }
+
+ public void cancelRestore(final TreePath path, final int flags) {
+ fStateTracker.cancelRestore(path, flags);
+ }
+
+ public boolean setChecked(TreePath path, boolean checked) {
+ IModelProxy elementProxy = getElementProxy(path);
+ if (elementProxy instanceof ICheckboxModelProxy) {
+ return ((ICheckboxModelProxy) elementProxy).setChecked(getPresentationContext(), getViewer().getInput(), path, checked);
+ }
+ return false;
+ }
+
+ /**
+ * Installs the model proxy for the given element into this content provider
+ * if not already installed.
+ * @param input the input to install the model proxy on
+ * @param path the {@link TreePath} to install the proxy for
+ */
+ private void installModelProxy(Object input, TreePath path) {
+
+ if (!fTreeModelProxies.containsKey(path) && !fModelProxies.containsKey(path.getLastSegment())) {
+ Object element = path.getSegmentCount() != 0 ? path.getLastSegment() : input;
+ IModelProxy proxy = null;
+ IModelProxyFactory2 modelProxyFactory2 = ViewerAdapterService.getModelProxyFactory2(element);
+ if (modelProxyFactory2 != null) {
+ proxy = modelProxyFactory2.createTreeModelProxy(input, path, getPresentationContext());
+ if (proxy != null) {
+ fTreeModelProxies.put(path, proxy);
+ }
+ }
+ if (proxy == null) {
+ IModelProxyFactory modelProxyFactory = ViewerAdapterService.getModelProxyFactory(element);
+ if (modelProxyFactory != null) {
+ proxy = modelProxyFactory.createModelProxy(element, getPresentationContext());
+ if (proxy != null) {
+ fModelProxies.put(element, proxy);
+ }
+ }
+ }
+
+ if (proxy instanceof IModelProxy2) {
+ proxy.addModelChangedListener(this);
+ ((IModelProxy2)proxy).initialize(getViewer());
+ } else if (proxy != null) {
+ final IModelProxy finalProxy = proxy;
+ Job job = new Job("Model Proxy installed notification job") {//$NON-NLS-1$
+ protected IStatus run(IProgressMonitor monitor) {
+ if (!monitor.isCanceled()) {
+ IPresentationContext context = null;
+ Viewer viewer = null;
+ synchronized (TreeModelContentProvider.this) {
+ if (!isDisposed()) {
+ context = getPresentationContext();
+ viewer = (Viewer) getViewer();
+ }
+ }
+ if (viewer != null && context != null && !finalProxy.isDisposed()) {
+ finalProxy.init(context);
+ finalProxy.addModelChangedListener(TreeModelContentProvider.this);
+ finalProxy.installed(viewer);
+ }
+ }
+ return Status.OK_STATUS;
+ }
+
+ public boolean shouldRun() {
+ return !isDisposed();
+ }
+ };
+ job.setSystem(true);
+ job.schedule();
+ }
+ }
+ }
+
+ /**
+ * Finds the model proxy that an element with a given path is associated with.
+ * @param path Path of the elemnt.
+ * @return Element's model proxy.
+ */
+ private IModelProxy getElementProxy(TreePath path) {
+ while (path != null) {
+ IModelProxy proxy = (IModelProxy) fTreeModelProxies.get(path);
+ if (proxy != null) {
+ return proxy;
+ }
+
+ Object element = path.getSegmentCount() == 0 ? getViewer().getInput() : path.getLastSegment();
+ proxy = (IModelProxy) fModelProxies.get(element);
+ if (proxy != null) {
+ return proxy;
+ }
+
+ path = path.getParentPath();
+ }
+ return null;
+ }
+
+ /**
+ * Uninstalls each model proxy
+ */
+ private void disposeAllModelProxies() {
+ Assert.isTrue( getViewer().getDisplay().getThread() == Thread.currentThread() );
+
+ Iterator updatePolicies = fModelProxies.values().iterator();
+ while (updatePolicies.hasNext()) {
+ IModelProxy proxy = (IModelProxy) updatePolicies.next();
+ proxy.dispose();
+ }
+ fModelProxies.clear();
+
+ updatePolicies = fTreeModelProxies.values().iterator();
+ while (updatePolicies.hasNext()) {
+ IModelProxy proxy = (IModelProxy) updatePolicies.next();
+ proxy.dispose();
+ }
+ fTreeModelProxies.clear();
+ }
+
+ /**
+ * Uninstalls the model proxy installed for the given element, if any.
+ * @param path the {@link TreePath} to dispose the model proxy for
+ */
+ private void disposeModelProxy(TreePath path) {
+ IModelProxy proxy = (IModelProxy) fTreeModelProxies.remove(path);
+ if (proxy != null) {
+ proxy.dispose();
+ }
+ proxy = (IModelProxy) fModelProxies.remove(path.getLastSegment());
+ if (proxy != null) {
+ proxy.dispose();
+ }
+ }
+
+ public void modelChanged(final IModelDelta delta, final IModelProxy proxy) {
+ Display display = null;
+
+ // Check if the viewer is still available, i.e. if the content provider
+ // is not disposed.
+ synchronized(this) {
+ if (fViewer != null && !proxy.isDisposed()) {
+ display = fViewer.getDisplay();
+ }
+ }
+ if (display != null) {
+ // If we're in display thread, process the delta immediately to
+ // avoid "skid" in processing events.
+ if (Thread.currentThread().equals(display.getThread())) {
+ doModelChanged(delta, proxy);
+ }
+ else {
+ fViewer.getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ doModelChanged(delta, proxy);
+ }
+ });
+ }
+ }
+ }
+
+ /**
+ * Executes the mdoel proxy in UI thread.
+ * @param delta Delta to process
+ * @param proxy Proxy that fired the delta.
+ */
+ private void doModelChanged(IModelDelta delta, IModelProxy proxy) {
+ if (!proxy.isDisposed()) {
+ if (DEBUG_DELTAS && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
+ DebugUIPlugin.debug("RECEIVED DELTA: " + delta.toString()); //$NON-NLS-1$
+ }
+
+ updateModel(delta, getModelDeltaMask());
+
+ // Initiate model update sequence before notifying of the model changed.
+ trigger(null);
+
+ // Call model listeners after updating the viewer model.
+ Object[] listeners = fModelListeners.getListeners();
+ for (int i = 0; i < listeners.length; i++) {
+ ((IModelChangedListener) listeners[i]).modelChanged(delta, proxy);
+ }
+ }
+ }
+
+ public void setModelDeltaMask(int mask) {
+ fModelDeltaMask = mask;
+ }
+
+ public int getModelDeltaMask() {
+ return fModelDeltaMask;
+ }
+
+ public void updateModel(IModelDelta delta, int mask) {
+ IModelDelta[] deltaArray = new IModelDelta[] { delta };
+ updateNodes(deltaArray, mask & (IModelDelta.REMOVED | IModelDelta.UNINSTALL));
+ updateNodes(deltaArray, mask & ITreeModelContentProvider.UPDATE_MODEL_DELTA_FLAGS
+ & ~(IModelDelta.REMOVED | IModelDelta.UNINSTALL));
+ updateNodes(deltaArray, mask & ITreeModelContentProvider.CONTROL_MODEL_DELTA_FLAGS);
+
+ fStateTracker.checkIfRestoreComplete();
+ }
+
+ /**
+ * Returns a tree path for the node including the root element.
+ *
+ * @param node
+ * model delta
+ * @return corresponding tree path
+ */
+ TreePath getFullTreePath(IModelDelta node) {
+ ArrayList list = new ArrayList();
+ while (node.getParentDelta() != null) {
+ list.add(0, node.getElement());
+ node = node.getParentDelta();
+ }
+ return new TreePath(list.toArray());
+ }
+
+ /**
+ * Returns a tree path for the node, *not* including the root element.
+ *
+ * @param node
+ * model delta
+ * @return corresponding tree path
+ */
+ TreePath getViewerTreePath(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 IInternalTreeModelViewer getViewer() {
+ synchronized(this) {
+ return fViewer;
+ }
+ }
+
+ public int viewToModelIndex(TreePath parentPath, int index) {
+ return fTransform.viewToModelIndex(parentPath, index);
+ }
+
+ public int viewToModelCount(TreePath parentPath, int count) {
+ return fTransform.viewToModelCount(parentPath, count);
+ }
+
+ public int modelToViewIndex(TreePath parentPath, int index) {
+ return fTransform.modelToViewIndex(parentPath, index);
+ }
+
+ public int modelToViewChildCount(TreePath parentPath, int count) {
+ return fTransform.modelToViewCount(parentPath, count);
+ }
+
+ public boolean areTreeModelViewerFiltersApplicable(Object parentElement) {
+ ViewerFilter[] filters = fViewer.getFilters();
+ if (filters.length > 0) {
+ for (int j = 0; j < filters.length; j++) {
+ if (filters[j] instanceof TreeModelViewerFilter &&
+ ((TreeModelViewerFilter)filters[j]).isApplicable(fViewer, parentElement))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public boolean shouldFilter(Object parentElementOrTreePath, Object element) {
+ ViewerFilter[] filters = fViewer.getFilters();
+ if (filters.length > 0) {
+ for (int j = 0; j < filters.length; j++) {
+ if (filters[j] instanceof TreeModelViewerFilter) {
+ // Skip the filter if not applicable to parent element
+ Object parentElement = parentElementOrTreePath instanceof TreePath
+ ? ((TreePath)parentElementOrTreePath).getLastSegment() : parentElementOrTreePath;
+ if (parentElement == null) parentElement = fViewer.getInput();
+ if (!((TreeModelViewerFilter)filters[j]).isApplicable(fViewer, parentElement)) {
+ continue;
+ }
+ }
+
+ if (!(filters[j].select((Viewer) fViewer, parentElementOrTreePath, element))) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public void unmapPath(TreePath path) {
+ Assert.isTrue( getViewer().getDisplay().getThread() == Thread.currentThread() );
+ fTransform.clear(path);
+ cancelSubtreeUpdates(path);
+ }
+
+
+ boolean addFilteredIndex(TreePath parentPath, int index, Object element) {
+ Assert.isTrue( getViewer().getDisplay().getThread() == Thread.currentThread() );
+ return fTransform.addFilteredIndex(parentPath, index, element);
+ }
+
+ void removeElementFromFilters(TreePath parentPath, int index) {
+ Assert.isTrue( getViewer().getDisplay().getThread() == Thread.currentThread() );
+ fTransform.removeElementFromFilters(parentPath, index);
+ }
+
+ boolean removeElementFromFilters(TreePath parentPath, Object element) {
+ Assert.isTrue( getViewer().getDisplay().getThread() == Thread.currentThread() );
+ return fTransform.removeElementFromFilters(parentPath, element);
+ }
+
+ void setModelChildCount(TreePath parentPath, int childCount) {
+ Assert.isTrue( getViewer().getDisplay().getThread() == Thread.currentThread() );
+ fTransform.setModelChildCount(parentPath, childCount);
+ }
+
+ boolean isFiltered(TreePath parentPath, int index) {
+ Assert.isTrue( getViewer().getDisplay().getThread() == Thread.currentThread() );
+ return fTransform.isFiltered(parentPath, index);
+ }
+
+ int[] getFilteredChildren(TreePath parent) {
+ Assert.isTrue( getViewer().getDisplay().getThread() == Thread.currentThread() );
+ return fTransform.getFilteredChildren(parent);
+ }
+
+ void clearFilteredChild(TreePath parent, int modelIndex) {
+ Assert.isTrue( getViewer().getDisplay().getThread() == Thread.currentThread() );
+ fTransform.clear(parent, modelIndex);
+ }
+
+ void clearFilters(TreePath parent) {
+ Assert.isTrue( getViewer().getDisplay().getThread() == Thread.currentThread() );
+ fTransform.clear(parent);
+ }
+
+ /**
+ * Notification an update request has started
+ *
+ * @param update the update to notify about
+ */
+ void updateStarted(ViewerUpdateMonitor update) {
+ Assert.isTrue( getViewer().getDisplay().getThread() == Thread.currentThread() );
+
+ boolean begin = fRequestsInProgress.isEmpty();
+ List requests = (List) fRequestsInProgress.get(update.getSchedulingPath());
+ if (requests == null) {
+ requests = new ArrayList();
+ fRequestsInProgress.put(update.getSchedulingPath(), requests);
+ }
+ requests.add(update);
+ if (begin) {
+ if (DEBUG_UPDATE_SEQUENCE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
+ System.out.println("MODEL SEQUENCE BEGINS"); //$NON-NLS-1$
+ }
+ notifyUpdate(UPDATE_SEQUENCE_BEGINS, null);
+ }
+ if (DEBUG_UPDATE_SEQUENCE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
+ System.out.println("\tBEGIN - " + update); //$NON-NLS-1$
+ }
+ notifyUpdate(UPDATE_BEGINS, update);
+ }
+
+ /**
+ * Notification an update request has completed
+ *
+ * @param updates the updates to notify
+ */
+ void updatesComplete(final List updates) {
+ for (int i = 0; i < updates.size(); i++) {
+ ViewerUpdateMonitor update = (ViewerUpdateMonitor)updates.get(i);
+ notifyUpdate(UPDATE_COMPLETE, update);
+ if (DEBUG_UPDATE_SEQUENCE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
+ System.out.println("\tEND - " + update); //$NON-NLS-1$
+ }
+ }
+
+ // Wait a single cycle to allow viewer to queue requests triggered by completed updates.
+ getViewer().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ if (isDisposed()) return;
+
+ for (int i = 0; i < updates.size(); i++) {
+ ViewerUpdateMonitor update = (ViewerUpdateMonitor)updates.get(i);
+
+ // Search for update in list using identity test. Otherwise a completed canceled
+ // update may trigger removal of up-to-date running update on the same element.
+ List requests = (List) fRequestsInProgress.get(update.getSchedulingPath());
+ boolean found = false;
+ if (requests != null) {
+ for (int j = 0; j < requests.size(); j++) {
+ if (requests.get(j) == update) {
+ found = true;
+ requests.remove(j);
+ break;
+ }
+ }
+ }
+
+ if (found) {
+ // Trigger may initiate new updates, so wait to remove requests array from
+ // fRequestsInProgress map. This way updateStarted() will not send a
+ // redundant "UPDATE SEQUENCE STARTED" notification.
+ trigger(update.getSchedulingPath());
+ if (requests.isEmpty()) {
+ fRequestsInProgress.remove(update.getSchedulingPath());
+ }
+ } else {
+ // Update may be removed from in progress list if it was canceled by schedule().
+ Assert.isTrue( update.isCanceled() );
+ }
+ }
+ if (fRequestsInProgress.isEmpty() && fWaitingRequests.isEmpty()) {
+ if (DEBUG_UPDATE_SEQUENCE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
+ System.out.println("MODEL SEQUENCE ENDS"); //$NON-NLS-1$
+ }
+ notifyUpdate(UPDATE_SEQUENCE_COMPLETE, null);
+ }
+ }
+ });
+
+ }
+
+ /**
+ * @return Returns true if there are outstanding updates in the viewer.
+ */
+ boolean areRequestsPending() {
+ return !fRequestsInProgress.isEmpty() || !fWaitingRequests.isEmpty();
+ }
+
+ /**
+ * @return Returns the state tracker for the content provider.
+ */
+ ViewerStateTracker getStateTracker() {
+ return fStateTracker;
+ }
+
+ /**
+ * Notifies listeners about given update.
+ * @param type Type of update to call listeners with.
+ * @param update Update to notify about.
+ */
+ private void notifyUpdate(final int type, final IViewerUpdate 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);
+ }
+ });
+ }
+ }
+ }
+
+ /**
+ * Cancels outstanding updates for the element at given path and its
+ * children.
+ * @param path Path of element.
+ */
+ private void cancelSubtreeUpdates(TreePath path) {
+ Assert.isTrue( getViewer().getDisplay().getThread() == Thread.currentThread() );
+
+ Iterator iterator = fRequestsInProgress.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Entry entry = (Entry) iterator.next();
+ TreePath entryPath = (TreePath) entry.getKey();
+ if (entryPath.startsWith(path, null)) {
+ List requests = (List) entry.getValue();
+ Iterator reqIter = requests.iterator();
+ while (reqIter.hasNext()) {
+ // Cancel update and remove from requests list. Removing from
+ // fRequestsInProgress ensures that isRequestBlocked() won't be triggered
+ // by a canceled update.
+ ((IRequest) reqIter.next()).cancel();
+ reqIter.remove();
+ }
+ }
+ }
+ List purge = new ArrayList();
+ iterator = fWaitingRequests.keySet().iterator();
+ while (iterator.hasNext()) {
+ TreePath entryPath = (TreePath) iterator.next();
+ if (entryPath.startsWith(path, null)) {
+ purge.add(entryPath);
+ }
+ }
+ iterator = purge.iterator();
+ while (iterator.hasNext()) {
+ fWaitingRequests.remove(iterator.next());
+ }
+
+ fStateTracker.cancelStateSubtreeUpdates(path);
+ }
+
+ /**
+ * Returns whether this given request should be run, or should wait for
+ * parent update to complete.
+ *
+ * @param update the update the schedule
+ */
+ private void schedule(final ViewerUpdateMonitor update) {
+ TreePath schedulingPath = update.getSchedulingPath();
+ List requests = (List) fWaitingRequests.get(schedulingPath);
+ if (requests == null) {
+ requests = new LinkedList();
+ requests.add(update);
+ fWaitingRequests.put(schedulingPath, requests);
+
+ List inProgressList = (List)fRequestsInProgress.get(schedulingPath);
+ if (inProgressList != null) {
+ int staleUpdateIndex = inProgressList.indexOf(update);
+ if (staleUpdateIndex >= 0) {
+ // Cancel update and remove from requests list. Removing from
+ // fRequestsInProgress ensures that isRequestBlocked() won't be triggered
+ // by a canceled update.
+ ViewerUpdateMonitor staleUpdate = (ViewerUpdateMonitor)inProgressList.remove(staleUpdateIndex);
+ staleUpdate.cancel();
+ // Note: Do not reset the inProgressList to null. This would cause the
+ // updateStarted() method to think that a new update sequence is
+ // being started. Since there are waiting requests for this scheduling
+ // path, the list will be cleaned up later.
+ }
+ }
+ if (inProgressList == null || inProgressList.isEmpty()) {
+ getViewer().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ trigger(update.getSchedulingPath());
+ }
+ });
+ }
+ } else {
+ // there are waiting requests: coalesce with existing request and add to list
+ requests.add(coalesce(requests, update));
+ }
+ }
+
+ /**
+ * Tries to coalesce the given request with any request in the list. If a match is found,
+ * the resulting request is then coalesced again with candidates in list.
+ * @param requests List of waiting requests to coalesce with
+ * @param toCoalesce request to coalesce
+ * @return Returns either the coalesced request. If no match was found it returns the
+ * toCoalesce parameter request. Either way the returned request needs to be added to the
+ * waiting requests list.
+ */
+ private ViewerUpdateMonitor coalesce(List requests, ViewerUpdateMonitor toCoalesce) {
+ Iterator reqIter = requests.iterator();
+ while (reqIter.hasNext()) {
+ ViewerUpdateMonitor waiting = (ViewerUpdateMonitor) reqIter.next();
+ if (waiting.coalesce(toCoalesce)) {
+ requests.remove(waiting);
+ // coalesced with existing request, done
+ // try to coalesce the combined requests with other waiting requests
+ return coalesce(requests, waiting);
+ }
+ }
+ return toCoalesce;
+ }
+
+ /**
+ * Returns whether there are outstanding ChildrenUpdate updates for the given path.
+ * This method is expected to be called during processing of a ChildrenRequest,
+ * therefore one running children request is ignored.
+ * @param path Path of element to check.
+ * @return True if there are outstanding children updates for given element.
+ */
+ boolean areChildrenUpdatesPending(TreePath path) {
+ Assert.isTrue( getViewer().getDisplay().getThread() == Thread.currentThread() );
+
+ List requests = (List) fWaitingRequests.get(path);
+ if (requests != null) {
+ for (int i = 0; i < requests.size(); i++) {
+ if (requests.get(i) instanceof ChildrenUpdate) {
+ return true;
+ }
+ }
+ }
+ requests = (List) fRequestsInProgress.get(path);
+ if (requests != null) {
+ int numChildrenUpdateRequests = 0;
+ for (int i = 0; i < requests.size(); i++) {
+ if (requests.get(i) instanceof ChildrenUpdate) {
+ if (++numChildrenUpdateRequests > 1) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Triggers waiting requests based on the given request that just
+ * completed.
+ * <p>
+ * Requests are processed in order such that updates to
+ * children are delayed until updates for parent elements are completed.
+ * This allows the expansion/selection state of the elements to be
+ * properly restored as new elements are retreived from model.
+ * </p>
+ *
+ * @param The schedulingPath path or requests to start processing. May
+ * be <code>null</code> to start the shortest path request.
+ */
+ private void trigger(TreePath schedulingPath) {
+ if (fWaitingRequests.isEmpty()) {
+ return;
+ }
+ List waiting = (List) fWaitingRequests.get(schedulingPath);
+ if (waiting == null) {
+ // no waiting, update the entry with the shortest path
+ int length = Integer.MAX_VALUE;
+ Iterator entries = fWaitingRequests.entrySet().iterator();
+ Entry candidate = null;
+ while (entries.hasNext()) {
+ Entry entry = (Entry) entries.next();
+ TreePath key = (TreePath) entry.getKey();
+ if (key.getSegmentCount() < length && !isRequestBlocked(key)) {
+ candidate = entry;
+ length = key.getSegmentCount();
+ }
+ }
+ if (candidate != null) {
+ startHighestPriorityRequest((TreePath) candidate.getKey(), (List) candidate.getValue());
+ }
+ } else if (!isRequestBlocked(schedulingPath)) {
+ // start the highest priority request
+ startHighestPriorityRequest(schedulingPath, waiting);
+ }
+ }
+
+ /**
+ * Returns true if there are running requests for any parent element of
+ * the given tree path.
+ * @param requestPath Path of element to check.
+ * @return Returns true if requests are running.
+ */
+ private boolean isRequestBlocked(TreePath requestPath) {
+ TreePath parentPath = requestPath;
+ List parentRequests = (List)fRequestsInProgress.get(parentPath);
+ while (parentRequests == null || parentRequests.isEmpty()) {
+ parentPath = parentPath.getParentPath();
+ if (parentPath == null) {
+ // no running requests: start request
+ return false;
+ }
+ parentRequests = (List)fRequestsInProgress.get(parentPath);
+ }
+ return true;
+ }
+
+ /**
+ * @param key the {@link TreePath}
+ * @param waiting the list of waiting requests
+ */
+ private void startHighestPriorityRequest(TreePath key, List waiting) {
+ int priority = 4;
+ ViewerUpdateMonitor next = null;
+ Iterator requests = waiting.iterator();
+ while (requests.hasNext()) {
+ ViewerUpdateMonitor vu = (ViewerUpdateMonitor) requests.next();
+ if (vu.getPriority() < priority) {
+ next = vu;
+ priority = next.getPriority();
+ }
+ }
+ if (next != null) {
+ waiting.remove(next);
+ if (waiting.isEmpty()) {
+ fWaitingRequests.remove(key);
+ }
+ next.start();
+ }
+ }
+
+ /**
+ * Returns the element corresponding to the given tree path.
+ *
+ * @param path
+ * tree path
+ * @return model element
+ */
+ protected Object getElement(TreePath path) {
+ if (path.getSegmentCount() > 0) {
+ return path.getLastSegment();
+ }
+ return getViewer().getInput();
+ }
+
+ /**
+ * Reschedule any children updates in progress for the given parent that
+ * have a start index greater than the given index. An element has been
+ * removed at this index, invalidating updates in progress.
+ *
+ * @param parentPath
+ * view tree path to parent element
+ * @param modelIndex
+ * index at which an element was removed
+ */
+ private void rescheduleUpdates(TreePath parentPath, int modelIndex) {
+ Assert.isTrue( getViewer().getDisplay().getThread() == Thread.currentThread() );
+
+ List requests = (List) fRequestsInProgress.get(parentPath);
+ List reCreate = null;
+ if (requests != null) {
+ Iterator iterator = requests.iterator();
+ while (iterator.hasNext()) {
+ IViewerUpdate update = (IViewerUpdate) iterator.next();
+ if (update instanceof IChildrenUpdate) {
+ IChildrenUpdate childrenUpdate = (IChildrenUpdate) update;
+ if (childrenUpdate.getOffset() > modelIndex) {
+ // Cancel update and remove from requests list. Removing from
+ // fRequestsInProgress ensures that isRequestBlocked() won't be triggered
+ // by a canceled update.
+ childrenUpdate.cancel();
+ iterator.remove();
+ if (reCreate == null) {
+ reCreate = new ArrayList();
+ }
+ reCreate.add(childrenUpdate);
+ if (DEBUG_CONTENT_PROVIDER && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
+ System.out.println("canceled update in progress handling REMOVE: " + childrenUpdate); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+ }
+ requests = (List) fWaitingRequests.get(parentPath);
+ if (requests != null) {
+ Iterator iterator = requests.iterator();
+ while (iterator.hasNext()) {
+ IViewerUpdate update = (IViewerUpdate) iterator.next();
+ if (update instanceof IChildrenUpdate) {
+ IChildrenUpdate childrenUpdate = (IChildrenUpdate) update;
+ if (childrenUpdate.getOffset() > modelIndex) {
+ ((ChildrenUpdate) childrenUpdate).setOffset(childrenUpdate.getOffset() - 1);
+ if (DEBUG_CONTENT_PROVIDER && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
+ System.out.println("modified waiting update handling REMOVE: " + childrenUpdate); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+ }
+ // re-schedule canceled updates at new position.
+ // have to do this last else the requests would be waiting and
+ // get modified.
+ if (reCreate != null) {
+ Iterator iterator = reCreate.iterator();
+ while (iterator.hasNext()) {
+ IChildrenUpdate childrenUpdate = (IChildrenUpdate) iterator.next();
+ int start = childrenUpdate.getOffset() - 1;
+ int end = start + childrenUpdate.getLength();
+ for (int i = start; i < end; i++) {
+ doUpdateElement(parentPath, i);
+ }
+ }
+ }
+ }
+
+ private void doUpdateChildCount(TreePath path) {
+ Assert.isTrue( getViewer().getDisplay().getThread() == Thread.currentThread() );
+
Object element = getElement(path);
IElementContentProvider contentAdapter = ViewerAdapterService.getContentProvider(element);
if (contentAdapter != null) {
- ChildrenCountUpdate request = new ChildrenCountUpdate(this, getViewer().getInput(), path, element, contentAdapter, getPresentationContext());
+ ChildrenCountUpdate request = new ChildrenCountUpdate(this, getViewer().getInput(), path, element, contentAdapter);
schedule(request);
}
}
- protected synchronized void doUpdateElement(TreePath parentPath, int modelIndex) {
+ void doUpdateElement(TreePath parentPath, int modelIndex) {
+ Assert.isTrue( getViewer().getDisplay().getThread() == Thread.currentThread() );
+
Object parent = getElement(parentPath);
IElementContentProvider contentAdapter = ViewerAdapterService.getContentProvider(parent);
if (contentAdapter != null) {
- ChildrenUpdate request = new ChildrenUpdate(this, getViewer().getInput(), parentPath, parent, modelIndex, contentAdapter, getPresentationContext());
+ ChildrenUpdate request = new ChildrenUpdate(this, getViewer().getInput(), parentPath, parent, modelIndex, contentAdapter);
schedule(request);
}
}
- protected synchronized void doUpdateHasChildren(TreePath path) {
+ private void doUpdateHasChildren(TreePath path) {
+ Assert.isTrue( getViewer().getDisplay().getThread() == Thread.currentThread() );
+
Object element = getElement(path);
IElementContentProvider contentAdapter = ViewerAdapterService.getContentProvider(element);
if (contentAdapter != null) {
- HasChildrenUpdate request = new HasChildrenUpdate(this, getViewer().getInput(), path, element, contentAdapter, getPresentationContext());
+ HasChildrenUpdate request = new HasChildrenUpdate(this, getViewer().getInput(), path, element, contentAdapter);
schedule(request);
}
}
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.model.provisional.viewers.ModelContentProvider#getPresentationContext()
+ /**
+ * Checks if there are outstanding updates that may replace the element
+ * at given path.
+ * @param path Path of element to check.
+ * @return Returns true if there are outsanding updates.
*/
+ boolean areElementUpdatesPending(TreePath path) {
+ Assert.isTrue( getViewer().getDisplay().getThread() == Thread.currentThread() );
+
+ TreePath parentPath = path.getParentPath();
+ List requests = (List) fWaitingRequests.get(path);
+ if (requests != null) {
+ for (int i = 0; i < requests.size(); i++) {
+ ViewerUpdateMonitor update = (ViewerUpdateMonitor) requests.get(i);
+ if (update instanceof ChildrenUpdate) {
+ return true;
+ }
+ }
+ }
+ requests = (List) fWaitingRequests.get(parentPath);
+ if (requests != null) {
+ for (int i = 0; i < requests.size(); i++) {
+ ViewerUpdateMonitor update = (ViewerUpdateMonitor) requests.get(i);
+ if (update.containsUpdate(path)) {
+ return true;
+ }
+ }
+ }
+ requests = (List) fRequestsInProgress.get(path);
+ if (requests != null) {
+ for (int i = 0; i < requests.size(); i++) {
+ ViewerUpdateMonitor update = (ViewerUpdateMonitor) requests.get(i);
+ if (update instanceof ChildrenUpdate) {
+ return true;
+ }
+ }
+ }
+ requests = (List) fRequestsInProgress.get(parentPath);
+ if (requests != null) {
+ for (int i = 0; i < requests.size(); i++) {
+ ViewerUpdateMonitor update = (ViewerUpdateMonitor) requests.get(i);
+ if (update.getElement().equals(path.getLastSegment())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the presentation context for this content provider.
+ *
+ * @return presentation context
+ */
protected IPresentationContext getPresentationContext() {
ITreeModelViewer viewer = getViewer();
if (viewer != null) {
@@ -87,10 +1134,67 @@ public class TreeModelContentProvider extends ModelContentProvider implements IT
return null;
}
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.model.provisional.viewers.ModelContentProvider#handleAdd(org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta)
- */
- protected void handleAdd(IModelDelta delta) {
+ /**
+ * Updates the viewer with the following deltas.
+ *
+ * @param nodes Model deltas to be processed.
+ * @param mask the model delta mask
+ * @see IModelDelta for a list of masks
+ */
+ private void updateNodes(IModelDelta[] nodes, int mask) {
+ for (int i = 0; i < nodes.length; i++) {
+ IModelDelta node = nodes[i];
+ int flags = node.getFlags() & mask;
+
+ if ((flags & IModelDelta.ADDED) != 0) {
+ handleAdd(node);
+ }
+ if ((flags & IModelDelta.REMOVED) != 0) {
+ handleRemove(node);
+ }
+ if ((flags & IModelDelta.CONTENT) != 0) {
+ handleContent(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);
+ }
+ if ((flags & IModelDelta.EXPAND) != 0) {
+ handleExpand(node);
+ }
+ if ((flags & IModelDelta.COLLAPSE) != 0) {
+ handleCollapse(node);
+ }
+ if ((flags & IModelDelta.SELECT) != 0) {
+ handleSelect(node);
+ }
+ if ((flags & IModelDelta.REVEAL) != 0) {
+ handleReveal(node);
+ }
+ updateNodes(node.getChildDeltas(), mask);
+ }
+ }
+
+ protected void handleInstall(IModelDelta delta) {
+ installModelProxy(getViewer().getInput(), getFullTreePath(delta));
+ }
+
+ protected void handleUninstall(IModelDelta delta) {
+ disposeModelProxy(getFullTreePath(delta));
+ }
+
+ protected void handleAdd(IModelDelta delta) {
IModelDelta parentDelta = delta.getParentDelta();
TreePath parentPath = getViewerTreePath(parentDelta);
Object element = delta.getElement();
@@ -122,7 +1226,7 @@ public class TreeModelContentProvider extends ModelContentProvider implements IT
getViewer().replace(parentPath, viewIndex, element);
TreePath childPath = parentPath.createChildPath(element);
updateHasChildren(childPath);
- restorePendingStateOnUpdate(childPath, modelIndex, false, false, false);
+ fStateTracker.restorePendingStateOnUpdate(childPath, modelIndex, false, false, false);
}
} else {
if (DEBUG_CONTENT_PROVIDER && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
@@ -135,7 +1239,7 @@ public class TreeModelContentProvider extends ModelContentProvider implements IT
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.viewers.ModelContentProvider#handleContent(org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta)
*/
- protected void handleContent(IModelDelta delta) {
+ protected void handleContent(IModelDelta delta) {
if (delta.getParentDelta() == null && delta.getChildCount() == 0) {
// if the delta is for the root, ensure the root still matches viewer input
if (!delta.getElement().equals(getViewer().getInput())) {
@@ -144,14 +1248,13 @@ public class TreeModelContentProvider extends ModelContentProvider implements IT
}
TreePath treePath = getViewerTreePath(delta);
cancelSubtreeUpdates(treePath);
- appendToPendingStateDelta(treePath);
getViewer().refresh(getElement(treePath));
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.model.ModelContentProvider#handleCollapse(org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta)
*/
- protected void handleCollapse(IModelDelta delta) {
+ protected void handleCollapse(IModelDelta delta) {
TreePath elementPath = getViewerTreePath(delta);
getViewer().setExpandedState(elementPath, false);
cancelRestore(elementPath, IModelDelta.EXPAND);
@@ -160,7 +1263,7 @@ public class TreeModelContentProvider extends ModelContentProvider implements IT
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.viewers.ModelContentProvider#handleExpand(org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta)
*/
- protected void handleExpand(IModelDelta delta) {
+ protected void handleExpand(IModelDelta delta) {
// expand each parent, then this node
IModelDelta parentDelta = delta.getParentDelta();
if (parentDelta != null) {
@@ -181,10 +1284,14 @@ public class TreeModelContentProvider extends ModelContentProvider implements IT
}
}
- protected void expand(IModelDelta delta) {
+ /**
+ * Expands the element pointed to by given delta.
+ * @param delta Delta that points to the element to expand.
+ */
+ private void expand(IModelDelta delta) {
int childCount = delta.getChildCount();
int modelIndex = delta.getIndex();
- ITreeModelContentProviderTarget treeViewer = getViewer();
+ IInternalTreeModelViewer treeViewer = getViewer();
TreePath elementPath = getViewerTreePath(delta);
if (modelIndex >= 0) {
TreePath parentPath = elementPath.getParentPath();
@@ -227,9 +1334,10 @@ public class TreeModelContentProvider extends ModelContentProvider implements IT
* @param parentPath viewer tree path to parent element
* @param element element to insert
* @param modelIndex index of the element in the model
- * @return
+ * @return Returns the view index of the newly inserted element
+ * or -1 if not inserted.
*/
- protected int unfilterElement(TreePath parentPath, Object element, int modelIndex) {
+ private int unfilterElement(TreePath parentPath, Object element, int modelIndex) {
// Element is filtered - if no longer filtered, insert the element
if (shouldFilter(parentPath, element)) {
if (DEBUG_CONTENT_PROVIDER && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
@@ -253,23 +1361,17 @@ public class TreeModelContentProvider extends ModelContentProvider implements IT
}
}
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.model.provisional.viewers.ModelContentProvider#handleInsert(org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta)
- */
protected void handleInsert(IModelDelta delta) {
// TODO: filters
getViewer().insert(getViewerTreePath(delta.getParentDelta()), delta.getElement(), delta.getIndex());
}
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.model.provisional.viewers.ModelContentProvider#handleRemove(org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta)
- */
protected void handleRemove(IModelDelta delta) {
if (DEBUG_CONTENT_PROVIDER && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
System.out.println("handleRemove(" + delta.getElement() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
}
IModelDelta parentDelta = delta.getParentDelta();
- ITreeModelContentProviderTarget treeViewer = getViewer();
+ IInternalTreeModelViewer treeViewer = getViewer();
TreePath parentPath = getViewerTreePath(parentDelta);
Object element = delta.getElement();
if (removeElementFromFilters(parentPath, element)) {
@@ -333,20 +1435,43 @@ public class TreeModelContentProvider extends ModelContentProvider implements IT
getViewer().refresh(parentDelta.getElement());
}
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.model.provisional.viewers.ModelContentProvider#handleReplace(org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta)
- */
protected void handleReplace(IModelDelta delta) {
TreePath parentPath = getViewerTreePath(delta.getParentDelta());
- getViewer().replace(parentPath, delta.getIndex(), delta.getElement());
+ int index = delta.getIndex();
+ if (index < 0) {
+ index = fTransform.indexOfFilteredElement(parentPath, delta.getElement());
+ }
+ if (index >= 0) {
+ boolean filtered = isFiltered(parentPath, index);
+ boolean shouldFilter = shouldFilter(parentPath, delta.getReplacementElement());
+
+ // Update the filter transform
+ if (filtered) {
+ clearFilteredChild(parentPath, index);
+ }
+ if (shouldFilter) {
+ addFilteredIndex(parentPath, index, delta.getElement());
+ }
+
+ // Update the viewer
+ if (filtered) {
+ if (!shouldFilter) {
+ getViewer().insert(parentPath, delta.getReplacementElement(), modelToViewIndex(parentPath, index));
+ }
+ //else do nothing
+ } else {
+ if (shouldFilter) {
+ getViewer().remove(parentPath, modelToViewIndex(parentPath, index));
+ } else {
+ getViewer().replace(parentPath, delta.getIndex(), delta.getReplacementElement());
+ }
+ }
+ }
}
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.model.provisional.viewers.ModelContentProvider#handleSelect(org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta)
- */
protected void handleSelect(IModelDelta delta) {
int modelIndex = delta.getIndex();
- ITreeModelContentProviderTarget treeViewer = getViewer();
+ IInternalTreeModelViewer treeViewer = getViewer();
// check if selection is allowed
IStructuredSelection candidate = new TreeSelection(getViewerTreePath(delta));
if ((delta.getFlags() & IModelDelta.FORCE) == 0 &&
@@ -382,16 +1507,10 @@ public class TreeModelContentProvider extends ModelContentProvider implements IT
}
}
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.model.provisional.viewers.ModelContentProvider#handleState(org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta)
- */
protected void handleState(IModelDelta delta) {
getViewer().update(delta.getElement());
}
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.model.ModelContentProvider#handleReveal(org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta)
- */
protected void handleReveal(IModelDelta delta) {
IModelDelta parentDelta = delta.getParentDelta();
if (parentDelta != null) {
@@ -401,9 +1520,13 @@ public class TreeModelContentProvider extends ModelContentProvider implements IT
}
}
- protected void reveal(IModelDelta delta) {
+ /**
+ * Reveals the element pointed to by given delta.
+ * @param delta Delta pointing to the element to reveal.
+ */
+ private void reveal(IModelDelta delta) {
int modelIndex = delta.getIndex();
- ITreeModelContentProviderTarget treeViewer = getViewer();
+ IInternalTreeModelViewer treeViewer = getViewer();
TreePath elementPath = getViewerTreePath(delta);
if (modelIndex >= 0) {
TreePath parentPath = elementPath.getParentPath();
@@ -433,90 +1556,7 @@ public class TreeModelContentProvider extends ModelContentProvider implements IT
}
}
}
-
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.model.provisional.viewers.ModelContentProvider#buildViewerState(org.eclipse.debug.internal.ui.viewers.provisional.ModelDelta)
- */
- protected void buildViewerState(ModelDelta delta) {
- ITreeModelContentProviderTarget viewer = getViewer();
- viewer.saveElementState(EMPTY_TREE_PATH, delta, IModelDelta.SELECT | IModelDelta.EXPAND);
-
- // Add memento for top item if it is mapped to an element. The reveal memento
- // is in its own path to avoid requesting unnecessary data when restoring it.
- TreePath topElementPath = viewer.getTopElementPath();
- if (topElementPath != null) {
- ModelDelta parentDelta = delta;
- TreePath parentPath = EMPTY_TREE_PATH;
- for (int i = 0; i < topElementPath.getSegmentCount(); i++) {
- Object element = topElementPath.getSegment(i);
- int index = viewer.findElementIndex(parentPath, element);
- ModelDelta childDelta = parentDelta.getChildDelta(element);
- if (childDelta == null) {
- parentDelta = parentDelta.addNode(element, index, IModelDelta.NO_CHANGE);
- } else {
- parentDelta = childDelta;
- }
- parentPath = parentPath.createChildPath(element);
- }
- parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.REVEAL);
- }
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.model.provisional.viewers.ModelContentProvider#doInitialRestore()
- */
- protected void doInitialRestore(ModelDelta delta) {
- // Find the reveal delta and mark nodes on its path
- // to reveal as elements are updated.
- markRevealDelta(delta);
-
- // Restore visible items.
- // Note (Pawel Piech): the initial list of items is normally
- // empty, so in most cases the code below does not do anything.
- // Instead doRestore() is called when various updates complete.
- int count = getViewer().getChildCount(TreePath.EMPTY);
- for (int i = 0; i < count; i++) {
- Object data = getViewer().getChildElement(TreePath.EMPTY, i);
- if (data != null) {
- restorePendingStateOnUpdate(new TreePath(new Object[]{data}), i, false, false, false);
- }
- }
-
- }
-
- /**
- * Finds the delta with the reveal flag, then it walks up this
- * delta and marks all the parents of it with the reveal flag.
- * These flags are then used by the restore logic to restore
- * and reveal all the nodes leading up to the element that should
- * be ultimately at the top.
- * @return The node just under the rootDelta which contains
- * the reveal flag. <code>null</code> if no reveal flag was found.
- */
- private ModelDelta markRevealDelta(ModelDelta rootDelta) {
- final ModelDelta[] revealDelta = new ModelDelta[1];
- IModelDeltaVisitor visitor = new IModelDeltaVisitor() {
- public boolean visit(IModelDelta delta, int depth) {
- if ( (delta.getFlags() & IModelDelta.REVEAL) != 0) {
- revealDelta[0] = (ModelDelta)delta;
- }
- // Keep recursing only if we haven't found our delta yet.
- return revealDelta[0] == null;
- }
- };
-
- rootDelta.accept(visitor);
- if (revealDelta[0] != null) {
- ModelDelta parentDelta = (ModelDelta)revealDelta[0].getParentDelta();
- while(parentDelta.getParentDelta() != null) {
- revealDelta[0] = parentDelta;
- revealDelta[0].setFlags(revealDelta[0].getFlags() | IModelDelta.REVEAL);
- parentDelta = (ModelDelta)parentDelta.getParentDelta();
- }
- }
- return revealDelta[0];
- }
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ILazyTreePathContentProvider#getParents(java.lang.Object)
@@ -528,20 +1568,21 @@ public class TreeModelContentProvider extends ModelContentProvider implements IT
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ILazyTreePathContentProvider#updateChildCount(org.eclipse.jface.viewers.TreePath, int)
*/
- public synchronized void updateChildCount(TreePath treePath, int currentChildCount) {
+ public void updateChildCount(TreePath treePath, int currentChildCount) {
+ Assert.isTrue( getViewer().getDisplay().getThread() == Thread.currentThread() );
+
if (DEBUG_CONTENT_PROVIDER && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
System.out.println("updateChildCount(" + getElement(treePath) + ", " + currentChildCount + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
- refilterChildren(treePath);
- //re-filter children when asked to update the child count for an element (i.e.
- // when refreshing, see if filtered children are still filtered)
doUpdateChildCount(treePath);
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ILazyTreePathContentProvider#updateElement(org.eclipse.jface.viewers.TreePath, int)
*/
- public synchronized void updateElement(TreePath parentPath, int viewIndex) {
+ public void updateElement(TreePath parentPath, int viewIndex) {
+ Assert.isTrue( getViewer().getDisplay().getThread() == Thread.currentThread() );
+
int modelIndex = viewToModelIndex(parentPath, viewIndex);
if (DEBUG_CONTENT_PROVIDER && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
System.out.println("updateElement("+ getElement(parentPath) + ", " + viewIndex + ") > modelIndex = " + modelIndex); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
@@ -552,7 +1593,9 @@ public class TreeModelContentProvider extends ModelContentProvider implements IT
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ILazyTreePathContentProvider#updateHasChildren(org.eclipse.jface.viewers.TreePath)
*/
- public synchronized void updateHasChildren(TreePath path) {
+ public void updateHasChildren(TreePath path) {
+ Assert.isTrue( getViewer().getDisplay().getThread() == Thread.currentThread() );
+
if (DEBUG_CONTENT_PROVIDER && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
System.out.println("updateHasChildren(" + getElement(path)); //$NON-NLS-1$
}
@@ -560,198 +1603,58 @@ public class TreeModelContentProvider extends ModelContentProvider implements IT
}
/**
- * @param delta
+ * Schedules given update to be performed on the viewer.
+ * Updates are queued up if they are completed in the same
+ * UI cycle.
+ * @param update Update to perform.
*/
- void restorePendingStateNode(final ModelDelta delta, boolean knowsHasChildren, boolean knowsChildCount, boolean checkChildrenRealized) {
- final TreePath treePath = getViewerTreePath(delta);
- final ITreeModelContentProviderTarget viewer = getViewer();
-
- // Attempt to expand the node only if the children are known.
- if (knowsHasChildren) {
- if ((delta.getFlags() & IModelDelta.EXPAND) != 0) {
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("\tRESTORE EXPAND: " + treePath.getLastSegment()); //$NON-NLS-1$
- }
- viewer.expandToLevel(treePath, 1);
- delta.setFlags(delta.getFlags() & ~IModelDelta.EXPAND);
- }
- if ((delta.getFlags() & IModelDelta.COLLAPSE) != 0) {
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("\tRESTORE COLLAPSE: " + treePath.getLastSegment()); //$NON-NLS-1$
- }
- // Check auto-expand before collapsing an element (bug 335734)
- int autoexpand = getViewer().getAutoExpandLevel();
- if (autoexpand != ITreeModelViewer.ALL_LEVELS && autoexpand < (treePath.getSegmentCount() + 1)) {
- getViewer().setExpandedState(treePath, false);
- }
- delta.setFlags(delta.getFlags() & ~IModelDelta.COLLAPSE);
- }
- }
-
- if ((delta.getFlags() & IModelDelta.SELECT) != 0) {
- delta.setFlags(delta.getFlags() & ~IModelDelta.SELECT);
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("\tRESTORE SELECT: " + treePath.getLastSegment()); //$NON-NLS-1$
- }
- ITreeSelection currentSelection = (ITreeSelection)viewer.getSelection();
- if (currentSelection == null || currentSelection.isEmpty()) {
- viewer.setSelection(new TreeSelection(treePath), false, false);
- } else {
- TreePath[] currentPaths = currentSelection.getPaths();
- boolean pathInSelection = false;
- for (int i = 0; i < currentPaths.length; i++) {
- if (currentPaths[i].equals(treePath)) {
- pathInSelection = true;
- break;
- }
- }
- // Only set the selection if the element is not yet in
- // selection. Otherwise the setSelection() call will
- // update selection listeners needlessly.
- if (!pathInSelection) {
- TreePath[] newPaths = new TreePath[currentPaths.length + 1];
- System.arraycopy(currentPaths, 0, newPaths, 0, currentPaths.length);
- newPaths[newPaths.length - 1] = treePath;
- viewer.setSelection(new TreeSelection(newPaths), false, false);
- }
- }
- }
-
- if ((delta.getFlags() & IModelDelta.REVEAL) != 0) {
- delta.setFlags(delta.getFlags() & ~IModelDelta.REVEAL);
- // Look for the reveal flag in the child deltas. If
- // A child delta has the reveal flag, do not set the
- // top element yet.
- boolean setTopItem = true;
- IModelDelta[] childDeltas = delta.getChildDeltas();
- for (int i = 0; i < childDeltas.length; i++) {
- IModelDelta childDelta = childDeltas[i];
- int modelIndex = childDelta.getIndex();
- if (modelIndex >= 0 && (childDelta.getFlags() & IModelDelta.REVEAL) != 0) {
- setTopItem = false;
- }
- }
-
- if (setTopItem) {
- Assert.isTrue(fPendingSetTopItem == null);
- final TreePath parentPath = treePath.getParentPath();
-
- // listen when current updates are complete and only
- // then do the REVEAL
- fPendingSetTopItem = new IPendingRevealDelta() {
- // Revealing some elements can trigger expanding some of elements
- // that have been just revealed. Therefore, we have to check one
- // more time after the new triggered updates are completed if we
- // have to set again the top index
- private int counter = 0;
- private Object modelInput = fPendingState.getElement();
-
- public void viewerUpdatesBegin() {
- }
-
- public void viewerUpdatesComplete() {
- // assume that fRequestsInProgress is empty if we got here
- Assert.isTrue(fRequestsInProgress.isEmpty());
-
- final Display viewerDisplay = viewer.getDisplay();
- if (fWaitingRequests.isEmpty() && !viewerDisplay.isDisposed()) {
- viewerDisplay.asyncExec(new Runnable() {
- public void run() {
- if (TreeModelContentProvider.this.isDisposed()) {
- return;
- }
-
- TreePath topPath = viewer.getTopElementPath();
- if (!treePath.equals(topPath)) {
- int index = viewer.findElementIndex(parentPath, treePath.getLastSegment());
- if (index >= 0) {
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("\tRESTORE REVEAL: " + treePath.getLastSegment()); //$NON-NLS-1$
- }
- viewer.reveal(parentPath, index);
-
- }
- }
- }
- });
-
- counter++;
- // in case the pending state was already set to null, we assume that
- // all others elements are restored, so we don't expect that REVEAL will
- // trigger other updates
- if (counter > 1 || fPendingState == null) {
- dispose();
- }
- }
-
- }
-
- public void updateStarted(IViewerUpdate update) {
- }
-
- public void updateComplete(IViewerUpdate update) {
- }
-
- public ModelDelta getDelta() {
- return delta;
- }
-
- public void dispose() {
- // remove myself as viewer update listener
- viewer.removeViewerUpdateListener(this);
-
- // top item is set
- fPendingSetTopItem = null;
-
- if (fPendingState == null) {
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("STATE RESTORE COMPELTE: " + fPendingState); //$NON-NLS-1$
- }
- notifyStateUpdate(modelInput, STATE_RESTORE_SEQUENCE_COMPLETE, null);
- } else {
- checkIfRestoreComplete();
- }
- }
-
- };
- viewer.addViewerUpdateListener(fPendingSetTopItem);
- }
- }
+ void scheduleViewerUpdate(ViewerUpdateMonitor update) {
+ Display display;
+ synchronized(this) {
+ if (isDisposed()) return;
+ display = getViewer().getDisplay();
+ fCompletedUpdates.add(update);
+ if (fCompletedUpdatesJob == null) {
+ fCompletedUpdatesJob = new Runnable() {
+ public void run() {
+ if (!isDisposed()) {
+ performUpdates();
+ }
+ }
+ };
+ display.asyncExec(fCompletedUpdatesJob);
+ }
+ }
+ }
- // If we know the child count of the element, look for the reveal
- // flag in the child deltas. For the children with reveal flag start
- // a new update.
- // If the child delta's index is out of range, strip the reveal flag
- // since it is no longer applicable.
- if (knowsChildCount) {
- int childCount = viewer.getChildCount(treePath);
- if (childCount >= 0) {
- ModelDelta[] childDeltas = (ModelDelta[])delta.getChildDeltas();
- for (int i = 0; i < childDeltas.length; i++) {
- ModelDelta childDelta = childDeltas[i];
- int modelIndex = childDelta.getIndex();
- if (modelIndex >= 0 && (childDelta.getFlags() & IModelDelta.REVEAL) != 0) {
- if (modelIndex < childCount) {
- doUpdateElement(treePath, modelIndex);
- } else {
- childDelta.setFlags(childDelta.getFlags() & ~IModelDelta.REVEAL);
- }
- }
- }
- }
- }
-
- // Some children of this element were just updated. If all its
- // children are now realized, clear out any elements that still
- // have flags, because they represent elements that were removed.
- if ((checkChildrenRealized && getElementChildrenRealized(treePath)) ||
- (knowsHasChildren && !viewer.getHasChildren(treePath)) )
- {
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("\tRESTORE CONTENT: " + treePath.getLastSegment()); //$NON-NLS-1$
+ /**
+ * Perform the updates pointed to by given array on the viewer.
+ */
+ private void performUpdates() {
+ Assert.isTrue( getViewer().getDisplay().getThread() == Thread.currentThread() );
+
+ List jobCompletedUpdates;
+ synchronized(TreeModelContentProvider.this) {
+ if (isDisposed()) {
+ return;
}
- delta.setFlags(delta.getFlags() & ~IModelDelta.CONTENT);
+ jobCompletedUpdates = fCompletedUpdates;
+ fCompletedUpdatesJob = null;
+ fCompletedUpdates = new ArrayList();
}
+ // necessary to check if viewer is disposed
+ try {
+ for (int i = 0; i < jobCompletedUpdates.size(); i++) {
+ ViewerUpdateMonitor completedUpdate = (ViewerUpdateMonitor)jobCompletedUpdates.get(i);
+ if (!completedUpdate.isCanceled() && !isDisposed()) {
+ IStatus status = completedUpdate.getStatus();
+ if (status == null || status.isOK()) {
+ completedUpdate.performUpdate();
+ }
+ }
+ }
+ } finally {
+ updatesComplete(jobCompletedUpdates);
+ }
}
-
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/TreeModelLabelProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/TreeModelLabelProvider.java
index 833124807..513c2dc07 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/TreeModelLabelProvider.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/TreeModelLabelProvider.java
@@ -19,12 +19,10 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Assert;
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.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
@@ -43,7 +41,6 @@ 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
@@ -52,7 +49,11 @@ public class TreeModelLabelProvider extends ColumnLabelProvider
implements ITreeModelLabelProvider, IModelChangedListener
{
- private ITreeModelLabelProviderTarget fViewer;
+ private IInternalTreeModelViewer fViewer;
+
+ /**
+ * Note: access this variable should be synchronized with <code>this</code>.
+ */
private List fComplete;
/**
@@ -84,23 +85,15 @@ public class TreeModelLabelProvider extends ColumnLabelProvider
/**
* Updates waiting to be sent to the label provider. The map contains
* lists of updates, keyed using the provider.
- * <p>
- * Note: this variable should only be accessed inside a synchronized section
- * using the enclosing label provider instance.
- * </p>
*/
private Map fPendingUpdates = new HashMap();
/**
- * A job that will send the label update requests.
+ * A runnable that will send the label update requests.
* This variable allows the job to be canceled and re-scheduled if
* new updates are requested.
- * <p>
- * Note: this variable should only be accessed inside a synchronized section
- * using the enclosing label provider instance.
- * </p>
*/
- private UIJob fPendingUpdatesJob;
+ private Runnable fPendingUpdatesRunnable;
/**
* List of updates in progress
@@ -111,7 +104,7 @@ public class TreeModelLabelProvider extends ColumnLabelProvider
* Delta visitor actively cancels the outstanding label updates for
* elements that are changed and are about to be updated.
*/
- class Visitor implements IModelDeltaVisitor {
+ class CancelPendingUpdatesVisitor implements IModelDeltaVisitor {
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.provisional.IModelDeltaVisitor#visit(org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta, int)
*/
@@ -130,12 +123,13 @@ public class TreeModelLabelProvider extends ColumnLabelProvider
/**
* Delta visitor
*/
- private Visitor fVisitor = new Visitor();
+ private CancelPendingUpdatesVisitor fCancelPendingUpdatesVisitor = new CancelPendingUpdatesVisitor();
/**
* Constructs a new label provider on the given display
+ * @param viewer Viewer that this label provieer is used with.
*/
- public TreeModelLabelProvider(ITreeModelLabelProviderTarget viewer) {
+ public TreeModelLabelProvider(IInternalTreeModelViewer viewer) {
fViewer = viewer;
fViewer.addModelChangedListener(this);
}
@@ -210,20 +204,38 @@ public class TreeModelLabelProvider extends ColumnLabelProvider
* @see org.eclipse.jface.viewers.BaseLabelProvider#dispose()
*/
public void dispose() {
+ Assert.isTrue(fViewer.getDisplay().getThread() == Thread.currentThread());
+
fViewer.removeModelChangedListener(this);
- synchronized (fUpdatesInProgress) {
- Iterator updatesInProgress = fUpdatesInProgress.iterator();
- while (updatesInProgress.hasNext()) {
- ILabelUpdate currentUpdate = (ILabelUpdate) updatesInProgress.next();
- currentUpdate.cancel();
- }
+ fViewer = null;
+
+ List complete = null;
+ synchronized(this) {
+ complete = fComplete;
+ fComplete = null;
+ }
+ if (complete != null) {
+ for (Iterator itr = complete.iterator(); itr.hasNext();) {
+ ((ILabelUpdate)itr.next()).cancel();
+ }
+ }
+
+ Iterator updatesInProgress = fUpdatesInProgress.iterator();
+ while (updatesInProgress.hasNext()) {
+ ILabelUpdate currentUpdate = (ILabelUpdate) updatesInProgress.next();
+ currentUpdate.cancel();
}
- synchronized (this) {
- if (fPendingUpdatesJob != null) {
- fPendingUpdatesJob.cancel();
- fPendingUpdatesJob = null;
- }
+
+ if (fPendingUpdatesRunnable != null) {
+ fPendingUpdatesRunnable = null;
+ }
+ for (Iterator itr = fPendingUpdates.values().iterator(); itr.hasNext();) {
+ List updateList = (List)itr.next();
+ for (Iterator listItr = updateList.iterator(); listItr.hasNext();) {
+ ((LabelUpdate)listItr.next()).cancel();
+ }
}
+ fPendingUpdates.clear();
Iterator images = fImageCache.values().iterator();
while (images.hasNext()) {
Image image = (Image) images.next();
@@ -248,11 +260,17 @@ public class TreeModelLabelProvider extends ColumnLabelProvider
super.dispose();
}
- public synchronized void update(ViewerCell cell) {
+ private boolean isDisposed() {
+ return fViewer == null;
+ }
+
+ public void update(ViewerCell cell) {
// NOT USED - the viewer updates each row instead
}
- public synchronized boolean update(TreePath elementPath) {
+ public boolean update(TreePath elementPath) {
+ Assert.isTrue(fViewer.getDisplay().getThread() == Thread.currentThread());
+
cancelPathUpdates(elementPath);
String[] visibleColumns = fViewer.getVisibleColumns();
@@ -265,17 +283,13 @@ public class TreeModelLabelProvider extends ColumnLabelProvider
fPendingUpdates.put(presentation, updates);
}
updates.add(new LabelUpdate(fViewer.getInput(), elementPath, this, visibleColumns, fViewer.getPresentationContext()));
- if (fPendingUpdatesJob != null) {
- fPendingUpdatesJob.cancel();
- }
- fPendingUpdatesJob = new UIJob(fViewer.getDisplay(), "Schedule Pending Label Updates") { //$NON-NLS-1$
- public IStatus runInUIThread(IProgressMonitor monitor) {
- startRequests(this);
- return Status.OK_STATUS;
- }
- };
- fPendingUpdatesJob.setSystem(true);
- fPendingUpdatesJob.schedule();
+ fPendingUpdatesRunnable = new Runnable() {
+ public void run() {
+ if (isDisposed()) return;
+ startRequests(this);
+ }
+ };
+ fViewer.getDisplay().asyncExec(fPendingUpdatesRunnable);
return true;
} else {
return false;
@@ -284,15 +298,16 @@ public class TreeModelLabelProvider extends ColumnLabelProvider
/**
* Cancel any outstanding updates that are running for this element.
+ * @param elementPath Element to cancel updates for.
*/
- protected void cancelPathUpdates(TreePath elementPath) {
- synchronized (fUpdatesInProgress) {
- Iterator updatesInProgress = fUpdatesInProgress.iterator();
- while (updatesInProgress.hasNext()) {
- ILabelUpdate currentUpdate = (ILabelUpdate) updatesInProgress.next();
- if (elementPath.equals(currentUpdate.getElementPath())) {
- currentUpdate.cancel();
- }
+ private void cancelPathUpdates(TreePath elementPath) {
+ Assert.isTrue(fViewer.getDisplay().getThread() == Thread.currentThread());
+
+ Iterator updatesInProgress = fUpdatesInProgress.iterator();
+ while (updatesInProgress.hasNext()) {
+ ILabelUpdate currentUpdate = (ILabelUpdate) updatesInProgress.next();
+ if (elementPath.equals(currentUpdate.getElementPath())) {
+ currentUpdate.cancel();
}
}
}
@@ -300,41 +315,46 @@ public class TreeModelLabelProvider extends ColumnLabelProvider
/**
* Sets the element's display information in the viewer.
*
+ * @param path Element path.
+ * @param numColumns Number of columns in the data.
+ * @param labels Array of labels. The array cannot to be
+ * <code>null</code>, but values within the array may be.
+ * @param images Array of image descriptors, may be <code>null</code>.
+ * @param fontDatas Array of fond data objects, may be <code>null</code>.
+ * @param foregrounds Array of RGB values for foreground colors, may be
+ * <code>null</code>.
+ * @param backgrounds Array of RGB values for background colors, may be
+ * <code>null</code>.
+ * @param checked Whether given item should be checked.
+ * @param grayed Whether given item's checkbox shoudl be grayed.
* @see ITreeModelLabelProviderTarget#setElementData(TreePath, int, String[], ImageDescriptor[], FontData[], RGB[], RGB[])
* @see ITreeModelCheckProviderTarget#setElementChecked(TreePath, boolean, boolean)
*/
- protected void setElementData(TreePath path, int numColumns, String[] labels, ImageDescriptor[] images,
+ void setElementData(TreePath path, int numColumns, String[] labels, ImageDescriptor[] images,
FontData[] fontDatas, RGB[] foregrounds, RGB[] backgrounds, boolean checked, boolean grayed)
{
fViewer.setElementData(path, numColumns, labels, images, fontDatas, foregrounds, backgrounds);
-
- if (fViewer instanceof ITreeModelCheckProviderTarget)
- ((ITreeModelCheckProviderTarget) fViewer).setElementChecked(path, checked, grayed);
+ fViewer.setElementChecked(path, checked, grayed);
}
- private void startRequests(UIJob updateJob) {
- // Avoid calling providers inside a synchronized section. Instead
- // copy the updates map into a new variable.
- Map updates = null;
- synchronized(this) {
- if (updateJob == fPendingUpdatesJob) {
- updates = fPendingUpdates;
- fPendingUpdates = new HashMap();
- fPendingUpdatesJob = null;
- }
- }
+ private void startRequests(Runnable runnable) {
+ if (runnable != fPendingUpdatesRunnable) {
+ return;
+ }
- if (updates != null) {
- for (Iterator itr = updates.keySet().iterator(); itr.hasNext();) {
- IElementLabelProvider presentation = (IElementLabelProvider)itr.next();
- List list = (List)updates.get(presentation);
+ if (!fPendingUpdates.isEmpty()) {
+ for (Iterator itr = fPendingUpdates.keySet().iterator(); itr.hasNext();) {
+ IElementLabelProvider provider = (IElementLabelProvider)itr.next();
+ List list = (List)fPendingUpdates.get(provider);
for (Iterator listItr = list.iterator(); listItr.hasNext();) {
updateStarted((ILabelUpdate)listItr.next());
}
- presentation.update( (ILabelUpdate[])list.toArray(new ILabelUpdate[list.size()]) );
+ provider.update( (ILabelUpdate[])list.toArray(new ILabelUpdate[list.size()]) );
}
}
+ fPendingUpdates.clear();
+ fPendingUpdatesRunnable = null;
}
/**
@@ -345,29 +365,27 @@ public class TreeModelLabelProvider extends ColumnLabelProvider
* @param searchFullPath flag whether to look for the element in the full path
* of the update
*/
- protected void cancelElementUpdates(Object element, boolean searchFullPath) {
- synchronized (fUpdatesInProgress) {
- Iterator updatesInProgress = fUpdatesInProgress.iterator();
- while (updatesInProgress.hasNext()) {
- ILabelUpdate currentUpdate = (ILabelUpdate) updatesInProgress.next();
-
- if (searchFullPath) {
- if (element.equals(fViewer.getInput())) {
- currentUpdate.cancel();
- } else {
- TreePath updatePath = currentUpdate.getElementPath();
- for (int i = 0; i < updatePath.getSegmentCount(); i++) {
- if (element.equals(updatePath.getSegment(i))) {
- currentUpdate.cancel();
- break; // Exit the for loop, stay in the while loop
- }
- }
- }
+ private void cancelElementUpdates(Object element, boolean searchFullPath) {
+ Iterator updatesInProgress = fUpdatesInProgress.iterator();
+ while (updatesInProgress.hasNext()) {
+ ILabelUpdate currentUpdate = (ILabelUpdate) updatesInProgress.next();
+
+ if (searchFullPath) {
+ if (element.equals(fViewer.getInput())) {
+ currentUpdate.cancel();
} else {
- if (element.equals(currentUpdate.getElement())) {
- currentUpdate.cancel();
+ TreePath updatePath = currentUpdate.getElementPath();
+ for (int i = 0; i < updatePath.getSegmentCount(); i++) {
+ if (element.equals(updatePath.getSegment(i))) {
+ currentUpdate.cancel();
+ break; // Exit the for loop, stay in the while loop
+ }
}
}
+ } else {
+ if (element.equals(currentUpdate.getElement())) {
+ currentUpdate.cancel();
+ }
}
}
}
@@ -377,39 +395,40 @@ public class TreeModelLabelProvider extends ColumnLabelProvider
*
* @return presentation context
*/
- protected IPresentationContext getPresentationContext() {
+ private IPresentationContext getPresentationContext() {
return fViewer.getPresentationContext();
}
/**
* A label update is complete.
*
- * @param update
+ * @param update Update that is to be completed.
*/
- protected synchronized void complete(ILabelUpdate update) {
- if (update.isCanceled()){
- updateComplete(update);
- } else {
- 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;
- }
- for (int i = 0; i < updates.length; i++) {
- updates[i].update();
- }
- return Status.OK_STATUS;
- }
- };
- job.setSystem(true);
- job.schedule(10L);
- }
- fComplete.add(update);
+ synchronized void complete(ILabelUpdate update) {
+ if (fViewer == null) return;
+
+ if (fComplete == null) {
+ fComplete = new LinkedList();
+ fViewer.getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ if (isDisposed()) return;
+ List updates = null;
+ synchronized (TreeModelLabelProvider.this) {
+ updates = fComplete;
+ fComplete = null;
+ }
+ for (Iterator itr = updates.iterator(); itr.hasNext();) {
+ LabelUpdate itrUpdate = (LabelUpdate)itr.next();
+ if (itrUpdate.isCanceled()) {
+ updateComplete(itrUpdate);
+ } else {
+ itrUpdate.performUpdate();
+ }
+ }
+ }
+ });
}
+ fComplete.add(update);
}
public void addLabelUpdateListener(ILabelUpdateListener listener) {
@@ -423,50 +442,47 @@ public class TreeModelLabelProvider extends ColumnLabelProvider
/**
* Notification an update request has started
*
- * @param update
+ * @param update Update that was started
*/
void updateStarted(ILabelUpdate update) {
- boolean begin = false;
- synchronized (fUpdatesInProgress) {
- begin = fUpdatesInProgress.isEmpty();
- fUpdatesInProgress.add(update);
- }
+ Assert.isTrue(fViewer.getDisplay().getThread() == Thread.currentThread());
+
+ boolean begin = fUpdatesInProgress.isEmpty();
+ fUpdatesInProgress.add(update);
+
if (begin) {
- if (ModelContentProvider.DEBUG_UPDATE_SEQUENCE && ModelContentProvider.DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
+ if (TreeModelContentProvider.DEBUG_UPDATE_SEQUENCE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
System.out.println("LABEL SEQUENCE BEGINS"); //$NON-NLS-1$
}
- notifyUpdate(ModelContentProvider.UPDATE_SEQUENCE_BEGINS, null);
+ notifyUpdate(TreeModelContentProvider.UPDATE_SEQUENCE_BEGINS, null);
}
- if (ModelContentProvider.DEBUG_UPDATE_SEQUENCE && ModelContentProvider.DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
+ if (TreeModelContentProvider.DEBUG_UPDATE_SEQUENCE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
System.out.println("\tBEGIN - " + update); //$NON-NLS-1$
}
- notifyUpdate(ModelContentProvider.UPDATE_BEGINS, update);
+ notifyUpdate(TreeModelContentProvider.UPDATE_BEGINS, update);
}
/**
* Notification an update request has completed
*
- * @param update
+ * @param update Update that completed.
*/
void updateComplete(ILabelUpdate update) {
- boolean end = false;
- synchronized (fUpdatesInProgress) {
- fUpdatesInProgress.remove(update);
- end = fUpdatesInProgress.isEmpty();
- }
- if (ModelContentProvider.DEBUG_UPDATE_SEQUENCE && ModelContentProvider.DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
+ fUpdatesInProgress.remove(update);
+
+ if (TreeModelContentProvider.DEBUG_UPDATE_SEQUENCE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
System.out.println("\tEND - " + update); //$NON-NLS-1$
}
- notifyUpdate(ModelContentProvider.UPDATE_COMPLETE, update);
- if (end) {
- if (ModelContentProvider.DEBUG_UPDATE_SEQUENCE && ModelContentProvider.DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
+ notifyUpdate(TreeModelContentProvider.UPDATE_COMPLETE, update);
+ if (fUpdatesInProgress.isEmpty()) {
+ if (TreeModelContentProvider.DEBUG_UPDATE_SEQUENCE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
System.out.println("LABEL SEQUENCE ENDS"); //$NON-NLS-1$
}
- notifyUpdate(ModelContentProvider.UPDATE_SEQUENCE_COMPLETE, null);
+ notifyUpdate(TreeModelContentProvider.UPDATE_SEQUENCE_COMPLETE, null);
}
}
- protected void notifyUpdate(final int type, final ILabelUpdate update) {
+ private void notifyUpdate(final int type, final ILabelUpdate update) {
if (!fLabelListeners.isEmpty()) {
Object[] listeners = fLabelListeners.getListeners();
for (int i = 0; i < listeners.length; i++) {
@@ -474,16 +490,16 @@ public class TreeModelLabelProvider extends ColumnLabelProvider
SafeRunner.run(new ISafeRunnable() {
public void run() throws Exception {
switch (type) {
- case ModelContentProvider.UPDATE_SEQUENCE_BEGINS:
+ case TreeModelContentProvider.UPDATE_SEQUENCE_BEGINS:
listener.labelUpdatesBegin();
break;
- case ModelContentProvider.UPDATE_SEQUENCE_COMPLETE:
+ case TreeModelContentProvider.UPDATE_SEQUENCE_COMPLETE:
listener.labelUpdatesComplete();
break;
- case ModelContentProvider.UPDATE_BEGINS:
+ case TreeModelContentProvider.UPDATE_BEGINS:
listener.labelUpdateStarted(update);
break;
- case ModelContentProvider.UPDATE_COMPLETE:
+ case TreeModelContentProvider.UPDATE_COMPLETE:
listener.labelUpdateComplete(update);
break;
}
@@ -496,9 +512,8 @@ public class TreeModelLabelProvider extends ColumnLabelProvider
}
}
-
public void modelChanged(IModelDelta delta, IModelProxy proxy) {
- delta.accept(fVisitor);
+ delta.accept(fCancelPendingUpdatesVisitor);
}
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ViewerStateTracker.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ViewerStateTracker.java
new file mode 100644
index 000000000..a116ca77a
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ViewerStateTracker.java
@@ -0,0 +1,1585 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.debug.internal.ui.viewers.model;
+
+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.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.debug.internal.ui.DebugUIPlugin;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDeltaVisitor;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IStateUpdateListener;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
+import org.eclipse.jface.viewers.ITreeSelection;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.jface.viewers.TreeSelection;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.XMLMemento;
+
+/**
+ * Class containing logic to save and restore expanded state of the tree model
+ * viewer.
+ * <p>
+ * When the input to the viewer is changes, the tree model viewer attempts to
+ * save the expansion state of elements as well as currently selected element and
+ * scroll position. Each expanded element is queried for its memento and all the
+ * collected mementos are saved into a delta tree then serialized by the viewer.<br>
+ * When a new input is set to the viewer, the viewer compares the input's memento
+ * with the stored mementos and if a match is found, it attempts to restore the
+ * previous expansion state to the viewer. As elements are revealed and realized
+ * in the viewer, the element's memento is compared against the memento stored in
+ * the saved state delta. If matching elements are found in the delta, the expansion
+ * and selection state is then restored to those elements.
+ * </p><p>
+ * Additionally to saving restoring state on input change, the viewer also
+ * saves/restores elements' state when the model requests viewer to refresh model
+ * structure. Since the viewer items are matched to the model elements using items'
+ * indexes, inserting or removing elements in model can cause the expansion state
+ * of elements to shift after a refresh. To compensate for this, the viewer saves
+ * the elements before a refresh is performed into a delta, but without encoding
+ * elements using mementos. As the refresh of the tree progresses, the save state
+ * is restored to the tree and elements are expanded or collapsed as needed to
+ * compensate for changes in model structure.
+ * </p>
+ * @see TreeModelContentProvider
+ */
+class ViewerStateTracker {
+
+ // Debugging flag.
+ static boolean DEBUG_STATE_SAVE_RESTORE = false;
+
+ // State update type constants used in notifying listeners
+ static final int STATE_SAVE_SEQUENCE_BEGINS = 4;
+ static final int STATE_SAVE_SEQUENCE_COMPLETE = 5;
+ static final int STATE_RESTORE_SEQUENCE_BEGINS = 6;
+ static final int STATE_RESTORE_SEQUENCE_COMPLETE = 7;
+
+ /**
+ * Dummy marker element used in the state delta. The marker indicates that a
+ * given element in the pending state delta has been removed. It replaces
+ * the original element so that it may optionally be garbage collected.
+ */
+ private final static String ELEMENT_REMOVED = "ELEMENT_REMOVED"; //$NON-NLS-1$
+
+ /**
+ * Collector of memento encoding requests.
+ */
+ interface IElementMementoCollector {
+
+ /**
+ * Adds the request to this manager.
+ *
+ * @param request to add
+ */
+ public void addRequest(ElementMementoRequest request);
+
+ /**
+ * Notification the request is complete.
+ *
+ * @param request that was completed
+ */
+ public void requestComplete(ElementMementoRequest request);
+
+ /**
+ * Process the queued requests. Accepts no more new requests.
+ */
+ public void processReqeusts();
+
+ /**
+ * Cancels the requests in progress.
+ */
+ public void cancel();
+ }
+
+ /**
+ * 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;
+ }
+ }
+
+ /**
+ * Content provider that is using this state tracker.
+ */
+ private TreeModelContentProvider fContentProvider;
+
+ ViewerStateTracker(TreeModelContentProvider contentProvider) {
+ fContentProvider = contentProvider;
+ }
+
+ /**
+ * 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;
+
+ /**
+ * Flag indicating that the content provider is performing
+ * state restore operations.
+ */
+ private boolean fInStateRestore = false;
+
+ /**
+ * State update listeners
+ */
+ private ListenerList fStateUpdateListeners = new ListenerList();
+
+ /**
+ * Postpone restoring REVEAL element until the current updates are complete.
+ * See bug 324100
+ */
+ protected PendingRevealDelta fPendingSetTopItem = null;
+
+ /**
+ * Set of IMementoManager's that are currently saving state
+ */
+ private Set fPendingStateSaves = new HashSet();
+
+ /**
+ * Used to queue a viewer input for state restore
+ */
+ private Object fQueuedRestore = null;
+
+ /**
+ * Object used to key compare requests in map.
+ */
+ private static class CompareRequestKey {
+
+ CompareRequestKey(TreePath path, IModelDelta delta) {
+ fPath = path;
+ fDelta = delta;
+ }
+
+ TreePath fPath;
+ IModelDelta fDelta;
+
+ public boolean equals(Object obj) {
+ if (obj instanceof CompareRequestKey) {
+ CompareRequestKey key = (CompareRequestKey) obj;
+ return key.fDelta.equals(fDelta) && key.fPath.equals(fPath);
+ }
+ return false;
+ }
+
+ public int hashCode() {
+ return fDelta.hashCode() + fPath.hashCode();
+ }
+ }
+
+ /**
+ * Compare requests that are currently running.
+ */
+ private Map fCompareRequestsInProgress = new LinkedHashMap();
+
+
+ /**
+ * Cancels pending updates.
+ */
+ void dispose() {
+ Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() );
+
+ for (Iterator itr = fPendingStateSaves.iterator(); itr.hasNext(); ) {
+ ((IElementMementoCollector)itr.next()).cancel();
+ }
+ fStateUpdateListeners.clear();
+
+ for (Iterator itr = fCompareRequestsInProgress.values().iterator(); itr.hasNext();) {
+ ((ElementCompareRequest)itr.next()).cancel();
+ }
+ fCompareRequestsInProgress.clear();
+
+ if (fPendingSetTopItem != null) {
+ fPendingSetTopItem.dispose();
+ }
+ }
+
+ /**
+ * Restores viewer state for the given input
+ *
+ * @param input
+ * viewer input
+ */
+ private void startRestoreViewerState(final Object input) {
+ Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() );
+
+ fPendingState = null;
+ final IElementMementoProvider defaultProvider = ViewerAdapterService.getMementoProvider(input);
+ if (defaultProvider != 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 IElementMementoCollector manager = new IElementMementoCollector() {
+
+ private IElementMementoRequest fRequest;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.debug.internal.ui.viewers.model.provisional.viewers
+ * .
+ * IMementoManager#requestComplete(org.eclipse.debug.internal.ui
+ * .viewers.model.provisional.IElementMementoRequest)
+ */
+ public void requestComplete(ElementMementoRequest request) {
+ if (fContentProvider.isDisposed()) return;
+
+ notifyStateUpdate(input, TreeModelContentProvider.UPDATE_COMPLETE, request);
+
+ if (!request.isCanceled() && (request.getStatus() == null || request.getStatus().isOK())) {
+ XMLMemento keyMemento = (XMLMemento) delta.getElement();
+ StringWriter writer = new StringWriter();
+ try {
+ keyMemento.save(writer);
+ final String keyMementoString = writer.toString();
+ ModelDelta stateDelta = (ModelDelta) fViewerStates.get(keyMementoString);
+ if (stateDelta != null) {
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("STATE RESTORE INPUT COMARE ENDED : " + fRequest + " - MATCHING STATE FOUND"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ // Process start of restore in an async cycle because we may still be inside inputChanged()
+ // call. I.e. the "input.equals(fContentProvider.getViewer().getInput())" test may fail.
+ fContentProvider.getViewer().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ if (!fContentProvider.isDisposed() && input.equals(fContentProvider.getViewer().getInput())) {
+ ModelDelta stateDelta2 = (ModelDelta) fViewerStates.remove(keyMementoString);
+ if (stateDelta2 != null) {
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("STATE RESTORE BEGINS"); //$NON-NLS-1$
+ System.out.println("\tRESTORE: " + stateDelta2.toString()); //$NON-NLS-1$
+ notifyStateUpdate(input, STATE_RESTORE_SEQUENCE_BEGINS, null);
+ }
+ stateDelta2.setElement(input);
+ fPendingState = stateDelta2;
+ doInitialRestore(fPendingState);
+ }
+ } else {
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("STATE RESTORE CANCELED."); //$NON-NLS-1$
+ }
+ }
+ }
+ });
+ } else {
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("STATE RESTORE INPUT COMARE ENDED : " + fRequest + " - NO MATCHING STATE"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ } catch (IOException e) {
+ DebugUIPlugin.log(e);
+ }
+ } else {
+ notifyStateUpdate(input, STATE_RESTORE_SEQUENCE_BEGINS, null);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.debug.internal.ui.viewers.model.provisional.viewers
+ * .IMementoManager#processReqeusts()
+ */
+ public void processReqeusts() {
+ notifyStateUpdate(input, STATE_RESTORE_SEQUENCE_BEGINS, null);
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("STATE RESTORE INPUT COMARE BEGIN : " + fRequest); //$NON-NLS-1$
+ }
+ notifyStateUpdate(input, TreeModelContentProvider.UPDATE_BEGINS, fRequest);
+ defaultProvider.encodeElements(new IElementMementoRequest[] { fRequest });
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.debug.internal.ui.viewers.model.provisional.viewers
+ * .
+ * IMementoManager#addRequest(org.eclipse.debug.internal.ui.viewers
+ * .model.provisional.IElementMementoRequest)
+ */
+ public void addRequest(ElementMementoRequest req) {
+ fRequest = req;
+ }
+
+ public void cancel() {
+ // not used
+ }
+
+ };
+ manager.addRequest(
+ new ElementMementoRequest(fContentProvider, fContentProvider.getViewer().getInput(), manager,
+ delta.getElement(), fContentProvider.getViewerTreePath(delta), inputMemento, delta));
+ manager.processReqeusts();
+ } else {
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("STATE RESTORE: No input memento provider"); //$NON-NLS-1$
+ }
+ }
+ }
+
+ /**
+ * Appends the state of the given subtree to the current pending delta.
+ * @param path Path to subtree to restore.
+ */
+ void appendToPendingStateDelta(final TreePath path) {
+ if (fContentProvider.getViewer() == null) return; // Not initialized yet.
+
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("STATE APPEND BEGIN: " + path.getLastSegment()); //$NON-NLS-1$
+ }
+
+ // build a model delta representing expansion and selection state
+ final ModelDelta appendDeltaRoot = new ModelDelta(fContentProvider.getViewer().getInput(), IModelDelta.NO_CHANGE);
+ ModelDelta delta = appendDeltaRoot;
+ for (int i = 0; i < path.getSegmentCount(); i++) {
+ delta = delta.addNode(path.getSegment(i), IModelDelta.NO_CHANGE);
+ }
+
+ if (!fContentProvider.getViewer().saveElementState(path, delta, IModelDelta.COLLAPSE | IModelDelta.EXPAND | IModelDelta.SELECT)) {
+ // Path to save the state was not found or there was no
+ // (expansion) state to save! Abort.
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("STATE APPEND CANCEL: Element " + path.getLastSegment() + " not found."); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ return;
+ }
+
+ // Append a marker CONTENT flag to all the delta nodes that contain the
+ // EXPAND node. These
+ // markers are used by the restore logic to know when a delta node can
+ // be removed.
+ delta.accept(new IModelDeltaVisitor() {
+ public boolean visit(IModelDelta d, int depth) {
+ if ((d.getFlags() & IModelDelta.EXPAND) != 0) {
+ ((ModelDelta) d).setFlags(d.getFlags() | IModelDelta.CONTENT);
+ }
+ return true;
+ }
+ });
+
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("\tAPPEND DELTA: " + appendDeltaRoot); //$NON-NLS-1$
+ }
+
+ if (fPendingState != null) {
+ // If the restore for the current input was never completed,
+ // preserve
+ // that restore along with the restore that was completed.
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("\tAPPEND OUTSTANDING RESTORE: " + fPendingState); //$NON-NLS-1$
+ }
+
+ // If the append delta is generated for a sub-tree, copy the pending dela
+ // attributes into the pending delta.
+ if (path.getSegmentCount() > 0) {
+ fPendingState.accept( new IModelDeltaVisitor() {
+ public boolean visit(IModelDelta pendingDeltaNode, int depth) {
+ TreePath pendingDeltaPath = fContentProvider.getViewerTreePath(pendingDeltaNode);
+ if (path.startsWith(pendingDeltaPath, null))
+ {
+ ModelDelta appendDelta = findDeltaForPath(appendDeltaRoot, pendingDeltaPath);
+ appendDelta.setFlags(pendingDeltaNode.getFlags());
+ appendDelta.setChildCount(pendingDeltaNode.getChildCount());
+ appendDelta.setIndex(pendingDeltaNode.getIndex());
+ return true;
+ }
+ return false;
+ }
+ });
+ }
+
+ // Copy the pending state into the new appended state.
+ fPendingState.accept( new IModelDeltaVisitor() {
+ public boolean visit(IModelDelta pendingDeltaNode, int depth) {
+ // Skip the top element
+ if (pendingDeltaNode.getParentDelta() == null) {
+ return true;
+ }
+
+ // Find the node in the save delta which is the parent
+ // of to the current pending delta node.
+ // If the parent node cannot be found, it means that
+ // most likely the user collapsed the parent node before
+ // the children were ever expanded.
+ // If the pending state node already exists in the parent
+ // node, it is already processed and we can skip it.
+ // If the pending state node does not contain any flags,
+ // we can also skip it.
+ ModelDelta saveDeltaNode = findSubDeltaParent(appendDeltaRoot, pendingDeltaNode);
+ if (saveDeltaNode != null &&
+ !isDeltaInParent(pendingDeltaNode, saveDeltaNode) &&
+ pendingDeltaNode.getFlags() != IModelDelta.NO_CHANGE)
+ {
+ saveDeltaNode.setChildCount(pendingDeltaNode.getParentDelta().getChildCount());
+ copyIntoDelta(pendingDeltaNode, saveDeltaNode);
+ } else {
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("\tSKIPPED: " + pendingDeltaNode.getElement()); //$NON-NLS-1$
+ }
+ }
+
+ // If the pending delta node has a memento element, its
+ // children should also be mementos therefore the copy
+ // delta operation should have added all the children
+ // of this pending delta node into the save delta.
+ if (pendingDeltaNode.getElement() instanceof IMemento) {
+ return false;
+ } else {
+ return pendingDeltaNode.getChildCount() > 0;
+ }
+ }
+
+ });
+ }
+
+ if (appendDeltaRoot.getChildDeltas().length > 0) {
+ // Set the new delta root as the pending state delta.
+ if (fPendingState == null) {
+ notifyStateUpdate(appendDeltaRoot.getElement(), STATE_RESTORE_SEQUENCE_BEGINS, null);
+ }
+ fPendingState = appendDeltaRoot;
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("STATE APPEND COMPLETE " + fPendingState); //$NON-NLS-1$
+ }
+ } else {
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("STATE APPEND CANCELED: No Data"); //$NON-NLS-1$
+ }
+ }
+ }
+
+ /**
+ * Saves the viewer's state for the previous input. * @param oldInput
+ * @param input the {@link ModelDelta} input
+ */
+ protected void saveViewerState(Object input) {
+ for (Iterator itr = fCompareRequestsInProgress.values().iterator(); itr.hasNext();) {
+ ((ElementCompareRequest) itr.next()).cancel();
+ itr.remove();
+ }
+
+ IElementMementoProvider stateProvider = ViewerAdapterService.getMementoProvider(input);
+ if (stateProvider != null) {
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("STATE SAVE BEGIN: " + input); //$NON-NLS-1$
+ }
+
+ // build a model delta representing expansion and selection state
+ final ModelDelta saveDeltaRoot = new ModelDelta(input, IModelDelta.NO_CHANGE);
+ buildViewerState(saveDeltaRoot);
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("\tSAVE DELTA FROM VIEW:\n" + saveDeltaRoot); //$NON-NLS-1$
+ }
+
+ // check if pending restore reveal
+ if (fPendingSetTopItem != null) {
+ // set back the pending reveal flag
+ ModelDelta revealDelta = fPendingSetTopItem.getDelta();
+ revealDelta.setFlags(revealDelta.getFlags() | IModelDelta.REVEAL);
+
+ fPendingSetTopItem.dispose();
+
+ ModelDelta saveDeltaNode = findSubDeltaParent(saveDeltaRoot, revealDelta);
+ if (saveDeltaNode != null) {
+ clearRevealFlag(saveDeltaRoot);
+ boolean childFounded = false;
+ for (int i = 0; i < saveDeltaNode.getChildDeltas().length; i++) {
+ ModelDelta child = (ModelDelta)saveDeltaNode.getChildDeltas()[i];
+ if (deltasEqual(child, revealDelta)) {
+ child.setFlags(child.getFlags() | IModelDelta.REVEAL);
+ childFounded = true;
+ break;
+ }
+ }
+
+ // the node should be added if not found
+ if (!childFounded) {
+ saveDeltaNode.setChildCount(revealDelta.getParentDelta().getChildCount());
+ copyIntoDelta(revealDelta, saveDeltaNode);
+ }
+ } else {
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("\tSKIPPED: " + revealDelta.getElement()); //$NON-NLS-1$
+ }
+ }
+ }
+
+ if (fPendingState != null) {
+ // If the restore for the current input was never completed,
+ // preserve
+ // that restore along with the restore that was completed.
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("\tSAVE OUTSTANDING RESTORE: " + fPendingState); //$NON-NLS-1$
+ }
+
+ IModelDeltaVisitor pendingStateVisitor = new IModelDeltaVisitor() {
+ public boolean visit(IModelDelta pendingDeltaNode, int depth) {
+ // Ignore the top element.
+ if (pendingDeltaNode.getParentDelta() == null) {
+ return true;
+ }
+
+ // Find the node in the save delta which is the parent
+ // of to the current pending delta node.
+ // If the parent node cannot be found, it means that
+ // most likely the user collapsed the parent node before
+ // the children were ever expanded.
+ // If the pending state node already exists in the
+ // parent
+ // node, it is already processed and we can skip it.
+ // If the pending state node does not contain any flags,
+ // we can also skip it.
+ ModelDelta saveDeltaNode = findSubDeltaParent(saveDeltaRoot, pendingDeltaNode);
+ if (saveDeltaNode != null && !isDeltaInParent(pendingDeltaNode, saveDeltaNode)
+ && pendingDeltaNode.getFlags() != IModelDelta.NO_CHANGE) {
+ // There should be only one delta element with
+ // the REVEAL flag in the entire save delta. The
+ // reveal flag in the pending delta trumps the one
+ // in the save delta because most likely the restore
+ // operation did not yet complete the reveal
+ // operation.
+ if ((pendingDeltaNode.getFlags() & IModelDelta.REVEAL) != 0) {
+ clearRevealFlag(saveDeltaRoot);
+ }
+ saveDeltaNode.setChildCount(pendingDeltaNode.getParentDelta().getChildCount());
+ copyIntoDelta(pendingDeltaNode, saveDeltaNode);
+ } else {
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("\tSKIPPED: " + pendingDeltaNode.getElement()); //$NON-NLS-1$
+ }
+ }
+
+ // If the pending delta node has a memento element, its
+ // children should also be mementos therefore the copy
+ // delta operation should have added all the children
+ // of this pending delta node into the save delta.
+ if (pendingDeltaNode.getElement() instanceof IMemento) {
+ return false;
+ } else {
+ return pendingDeltaNode.getChildCount() > 0;
+ }
+ }
+ };
+ fPendingState.accept(pendingStateVisitor);
+ }
+
+ if (saveDeltaRoot.getChildDeltas().length > 0) {
+ // encode delta with mementos in place of elements, in non-UI
+ // thread
+ encodeDelta(saveDeltaRoot, stateProvider);
+ } else {
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("STATE SAVE CANCELED, NO DATA"); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ private void clearRevealFlag(ModelDelta saveRootDelta) {
+ IModelDeltaVisitor clearDeltaVisitor = new IModelDeltaVisitor() {
+ public boolean visit(IModelDelta delta, int depth) {
+ if ((delta.getFlags() & IModelDelta.REVEAL) != 0) {
+ ((ModelDelta) delta).setFlags(delta.getFlags() & ~IModelDelta.REVEAL);
+ }
+ return true;
+ }
+ };
+ saveRootDelta.accept(clearDeltaVisitor);
+ }
+
+ private ModelDelta findSubDeltaParent(ModelDelta destinationDeltaRoot, IModelDelta subDelta) {
+ // Create a path of elements to the sub-delta.
+ LinkedList deltaPath = new LinkedList();
+ IModelDelta delta = subDelta;
+ while (delta.getParentDelta() != null) {
+ delta = delta.getParentDelta();
+ deltaPath.addFirst(delta);
+ }
+
+ // For each element in the path of the sub-delta, find the corresponding
+ // element in the destination delta
+ Iterator itr = deltaPath.iterator();
+ // Skip the root element
+ itr.next();
+ ModelDelta saveDelta = destinationDeltaRoot;
+ outer: while (itr.hasNext()) {
+ IModelDelta itrDelta = (IModelDelta) itr.next();
+ for (int i = 0; i < saveDelta.getChildDeltas().length; i++) {
+ if (deltasEqual(saveDelta.getChildDeltas()[i], itrDelta)) {
+ saveDelta = (ModelDelta) saveDelta.getChildDeltas()[i];
+ continue outer;
+ }
+ }
+ return null;
+ }
+ return saveDelta;
+ }
+
+ private ModelDelta findDeltaForPath(ModelDelta root, TreePath path) {
+ ModelDelta delta = root;
+ for (int i = 0; i < path.getSegmentCount(); i++) {
+ delta = delta.getChildDelta(path.getSegment(i));
+ if (delta == null) {
+ return null;
+ }
+ }
+ return delta;
+ }
+
+ private boolean deltasEqual(IModelDelta d1, IModelDelta d2) {
+ // Note: don't compare the child count, because it is
+ // incorrect for nodes which have not been expanded yet.
+ return d1.getElement().equals(d2.getElement()) && d1.getIndex() == d2.getIndex();
+ }
+
+ private boolean isDeltaInParent(IModelDelta delta, ModelDelta destParent) {
+ for (int i = 0; i < destParent.getChildDeltas().length; i++) {
+ if (deltasEqual(destParent.getChildDeltas()[i], delta)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void copyIntoDelta(IModelDelta delta, ModelDelta destParent) {
+ ModelDelta newDelta = destParent.addNode(delta.getElement(), delta.getIndex(), delta.getFlags(), delta
+ .getChildCount());
+ for (int i = 0; i < delta.getChildDeltas().length; i++) {
+ copyIntoDelta(delta.getChildDeltas()[i], newDelta);
+ }
+ }
+
+ /**
+ * Encodes delta elements into mementos using the given provider.
+ * @param rootDelta the {@link ModelDelta} to encode
+ * @param defaultProvider the default provider to use when processing the given delta
+ *
+ */
+ protected void encodeDelta(final ModelDelta rootDelta, final IElementMementoProvider defaultProvider) {
+ final Object input = rootDelta.getElement();
+ final XMLMemento inputMemento = XMLMemento.createWriteRoot("VIEWER_INPUT_MEMENTO"); //$NON-NLS-1$
+ final XMLMemento childrenMemento = XMLMemento.createWriteRoot("CHILDREN_MEMENTO"); //$NON-NLS-1$
+ final IElementMementoCollector manager = new IElementMementoCollector() {
+
+ /**
+ * list of memento fRequests
+ */
+ private List fRequests = new ArrayList();
+
+ /**
+ * Flag indicating whether the encoding of delta has been canceled.
+ */
+ private boolean fCanceled = false;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.debug.internal.ui.viewers.model.provisional.viewers
+ * .IMementoManager
+ * #requestComplete(org.eclipse.debug.internal.ui.viewers
+ * .model.provisional.IElementMementoRequest)
+ */
+ public void requestComplete(ElementMementoRequest request) {
+ Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() );
+
+ notifyStateUpdate(input, TreeModelContentProvider.UPDATE_COMPLETE, request);
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("\tSTATE END: " + request); //$NON-NLS-1$
+ }
+
+ if (!request.isCanceled() && (request.getStatus() == null || request.getStatus().isOK())) {
+ boolean requestsComplted = false;
+ if (!fCanceled) {
+ fRequests.remove(request);
+ requestsComplted = fRequests.isEmpty();
+ }
+ if (requestsComplted) {
+ XMLMemento keyMemento = (XMLMemento) rootDelta.getElement();
+ StringWriter writer = new StringWriter();
+ try {
+ keyMemento.save(writer);
+ fViewerStates.put(writer.toString(), rootDelta);
+ } catch (IOException e) {
+ DebugUIPlugin.log(e);
+ }
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("STATE SAVE COMPLETED: " + rootDelta); //$NON-NLS-1$
+ }
+ stateSaveComplete(input, this);
+ }
+ } else {
+ cancel();
+ }
+ }
+
+ public void cancel() {
+ Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() );
+
+ if (fCanceled) {
+ return;
+ }
+
+ fCanceled = true;
+ Iterator iterator = fRequests.iterator();
+ while (iterator.hasNext()) {
+ IElementMementoRequest req = (IElementMementoRequest) iterator.next();
+ req.cancel();
+ }
+ fRequests.clear();
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("STATE SAVE ABORTED: " + rootDelta.getElement()); //$NON-NLS-1$
+ }
+ stateSaveComplete(input, this);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.debug.internal.ui.viewers.model.provisional.viewers
+ * .IMementoManager#processReqeusts()
+ */
+ public void processReqeusts() {
+ Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() );
+
+ Map providers = new HashMap();
+ Iterator iterator = fRequests.iterator();
+ while (iterator.hasNext()) {
+ IElementMementoRequest request = (IElementMementoRequest) iterator.next();
+ notifyStateUpdate(input, TreeModelContentProvider.UPDATE_BEGINS, request);
+ IElementMementoProvider provider = ViewerAdapterService.getMementoProvider(request.getElement());
+ if (provider == null) {
+ provider = defaultProvider;
+ }
+ List reqs = (List) providers.get(provider);
+ if (reqs == null) {
+ reqs = new ArrayList();
+ providers.put(provider, reqs);
+ }
+ reqs.add(request);
+ }
+ iterator = providers.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Entry entry = (Entry) iterator.next();
+ IElementMementoProvider provider = (IElementMementoProvider) entry.getKey();
+ List reqs = (List) entry.getValue();
+ provider.encodeElements((IElementMementoRequest[]) reqs.toArray(new IElementMementoRequest[reqs
+ .size()]));
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.debug.internal.ui.viewers.model.provisional.viewers
+ * .IMementoManager
+ * #addRequest(org.eclipse.debug.internal.ui.viewers.
+ * model.provisional.IElementMementoRequest)
+ */
+ public void addRequest(ElementMementoRequest request) {
+ Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() );
+
+ fRequests.add(request);
+ }
+
+ };
+ IModelDeltaVisitor visitor = new IModelDeltaVisitor() {
+ public boolean visit(IModelDelta delta, int depth) {
+ // Add the CONTENT flag to all nodes with an EXPAND flag.
+ // During restoring, this flag is used as a marker indicating
+ // whether all the content of a given element has been
+ // retrieved.
+ if ((delta.getFlags() | IModelDelta.EXPAND) != 0) {
+ ((ModelDelta)delta).setFlags(delta.getFlags() | IModelDelta.CONTENT);
+ }
+
+ // This is the root element, save the root element memento in 'inputMemento'.
+ if (delta.getParentDelta() == null) {
+ manager.addRequest(new ElementMementoRequest(fContentProvider, input, manager,
+ delta.getElement(), fContentProvider.getViewerTreePath(delta), inputMemento,
+ (ModelDelta) delta));
+ } else {
+ // If this is another node element, save the memento to a children memento.
+ if (!(delta.getElement() instanceof XMLMemento)) {
+ manager.addRequest(new ElementMementoRequest(fContentProvider, input, manager,
+ delta.getElement(), fContentProvider.getViewerTreePath(delta), childrenMemento
+ .createChild("CHILD_ELEMENT"), (ModelDelta) delta)); //$NON-NLS-1$
+ }
+ }
+ return true;
+ }
+ };
+ rootDelta.accept(visitor);
+ stateSaveStarted(input, manager);
+ manager.processReqeusts();
+ }
+
+ /**
+ * Called when a state save is starting.
+ * @param input the {@link ModelDelta} input
+ * @param manager the manager to notify
+ */
+ private void stateSaveStarted(Object input, IElementMementoCollector manager) {
+ Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() );
+
+ notifyStateUpdate(input, STATE_SAVE_SEQUENCE_BEGINS, null);
+ fPendingStateSaves.add(manager);
+ }
+
+ /**
+ * Called when a state save is complete.
+ * @param input the {@link ModelDelta} input
+ * @param manager the manager to notify
+ */
+ private void stateSaveComplete(Object input, IElementMementoCollector manager) {
+ Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() );
+
+ notifyStateUpdate(input, STATE_SAVE_SEQUENCE_COMPLETE, null);
+ fPendingStateSaves.remove(manager);
+ if (fQueuedRestore != null) {
+ Object temp = fQueuedRestore;
+ fQueuedRestore = null;
+ restoreViewerState(temp);
+ }
+ }
+
+ /**
+ * Returns whether any state saving is in progress.
+ *
+ * @return whether any state saving is in progress
+ */
+ private boolean isSavingState() {
+ Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() );
+
+ return !fPendingStateSaves.isEmpty();
+ }
+
+ /**
+ * Restores the viewer state unless a save is taking place. If a save is
+ * taking place, the restore is queued.
+ *
+ * @param input
+ * viewer input
+ */
+ protected void restoreViewerState(final Object input) {
+ Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() );
+
+ fPendingState = null;
+ if (isSavingState()) {
+ fQueuedRestore = input;
+ } else {
+ startRestoreViewerState(input);
+ }
+ }
+
+
+ public void cancelRestore(final TreePath path, final int flags) {
+ if (fInStateRestore) {
+ // If we are currently processing pending state already, ignore
+ // cancelRestore requests. These requests may be triggered in the viewer
+ // by changes to the tree state (Bug 295585).
+ return;
+ }
+
+ if ((flags & IModelDelta.REVEAL) != 0 && fPendingSetTopItem != null) {
+ fPendingSetTopItem.dispose();
+ return;
+ }
+
+ // Nothing else to do
+ if (fPendingState == null) {
+ return;
+ }
+
+ if ((flags & (IModelDelta.SELECT | IModelDelta.REVEAL)) != 0) {
+ // If we're canceling reveal and this is waiting for updates to complete
+ // then just cancel it and return
+
+ // If we're canceling select or reveal, cancel it for all of pending deltas
+ final int mask = flags & (IModelDelta.SELECT | IModelDelta.REVEAL);
+ fPendingState.accept(new IModelDeltaVisitor() {
+ public boolean visit(IModelDelta delta, int depth) {
+ int deltaFlags = delta.getFlags();
+ int newFlags = deltaFlags & ~mask;
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ if (deltaFlags != newFlags) {
+ System.out.println("\tCANCEL: " + delta.getElement() + "(" + Integer.toHexString(deltaFlags & mask) + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ }
+ ((ModelDelta)delta).setFlags(newFlags);
+ return true;
+ }
+ });
+ }
+ if ((flags & ~(IModelDelta.SELECT | IModelDelta.REVEAL)) != 0) {
+ final int mask = flags & ~(IModelDelta.SELECT | IModelDelta.REVEAL);
+ // For other flags (EXPAND/COLLAPSE), cancel only from the matching path.
+ fPendingState.accept(new IModelDeltaVisitor() {
+ public boolean visit(IModelDelta delta, int depth) {
+ if (depth < path.getSegmentCount()) {
+ // Descend until we reach a matching depth.
+ TreePath deltaPath = fContentProvider.getViewerTreePath(delta);
+ if (path.startsWith(deltaPath, null)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ else if (depth == path.getSegmentCount()) {
+ TreePath deltaPath = fContentProvider.getViewerTreePath(delta);
+ if (deltaPath.equals(path)) {
+ int deltaFlags = delta.getFlags();
+ int newFlags = deltaFlags & ~mask;
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ if (deltaFlags != newFlags) {
+ System.out.println("\tCANCEL: " + delta.getElement() + "(" + Integer.toHexString(deltaFlags & mask) + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ }
+ ((ModelDelta)delta).setFlags(newFlags);
+ if ((flags & IModelDelta.EXPAND) != 0) {
+ // Descend delta to clear the EXPAND flags of a canceled expand
+ return true;
+ }
+ }
+ return false;
+ } else {
+ // We're clearing out flags of a matching sub-tree
+ // assert (flags & IModelDelta.EXPAND) != 0;
+
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ if (delta.getFlags() != IModelDelta.NO_CHANGE) {
+ System.out.println("\tCANCEL: " + delta.getElement() + "(" + Integer.toHexString(delta.getFlags()) + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ }
+ ((ModelDelta)delta).setFlags(IModelDelta.NO_CHANGE);
+ return true;
+ }
+ }
+ });
+ }
+ }
+
+
+ /**
+ * Perform any restoration required for the given tree path.
+ * <p>
+ * This method is called after every viewer update completion to continue
+ * restoring the expansion state that was previously saved.
+ *
+ * @param path the tree path to update
+ * @param modelIndex the index in the current model
+ * @param knowsHasChildren if the content provider knows it has children already
+ * @param knowsChildCount if the content provider knows the current child count already
+ * @param checkChildrenRealized if any realized children should be checked or not
+ */
+ void restorePendingStateOnUpdate(final TreePath path, final int modelIndex, final boolean knowsHasChildren,
+ final boolean knowsChildCount, final boolean checkChildrenRealized)
+ {
+ Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() );
+
+ if (fPendingState == null) {
+ return;
+ }
+
+ IModelDeltaVisitor visitor = new IModelDeltaVisitor() {
+ public boolean visit(final IModelDelta delta, int depth) {
+
+ Object element = delta.getElement();
+ Object potentialMatch = depth != 0 ? path.getSegment(depth - 1) : fContentProvider.getViewer().getInput();
+ // Only process if the depth in the delta matches the tree path.
+ if (depth == path.getSegmentCount()) {
+ if (element instanceof IMemento) {
+ IElementMementoProvider provider = ViewerAdapterService.getMementoProvider(potentialMatch);
+ if (provider == null) {
+ provider = ViewerAdapterService.getMementoProvider(fContentProvider.getViewer().getInput());
+ }
+ if (provider != null) {
+ CompareRequestKey key = new CompareRequestKey(path, delta);
+ ElementCompareRequest existingRequest = (ElementCompareRequest) fCompareRequestsInProgress
+ .get(key);
+ if (existingRequest != null) {
+ // Check all the running compare updates for a
+ // matching tree path.
+ // If found, just update the flags.
+ existingRequest.setKnowsHasChildren(knowsHasChildren);
+ existingRequest.setKnowsChildCount(knowsChildCount);
+ existingRequest.setCheckChildrenRealized(checkChildrenRealized);
+ } else {
+ // Start a new compare request
+ ElementCompareRequest compareRequest = new ElementCompareRequest(
+ fContentProvider, fContentProvider.getViewer().getInput(), potentialMatch, path,
+ (IMemento) element, (ModelDelta) delta, modelIndex, knowsHasChildren,
+ knowsChildCount, checkChildrenRealized);
+ fCompareRequestsInProgress.put(key, compareRequest);
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("\tSTATE BEGIN: " + compareRequest); //$NON-NLS-1$
+ }
+ notifyStateUpdate(element, TreeModelContentProvider.UPDATE_BEGINS, compareRequest);
+ provider.compareElements(new IElementCompareRequest[] { compareRequest });
+ }
+ }
+ } else if (element.equals(potentialMatch)) {
+ // Element comparison already succeeded, and it matches
+ // our element.
+ // Call restore with delta to process the delta flags.
+ restorePendingStateNode((ModelDelta) delta, knowsHasChildren, knowsChildCount, checkChildrenRealized);
+ }
+ return false;
+ }
+ // Only follow the paths that match the delta.
+ return element.equals(potentialMatch);
+ }
+ };
+
+ try {
+ fInStateRestore = true;
+ fPendingState.accept(visitor);
+ }
+ finally {
+ fInStateRestore = false;
+ }
+ checkIfRestoreComplete();
+ }
+
+ /**
+ * Checks whether restoring pending state is already complete.
+ */
+ void checkIfRestoreComplete() {
+ Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() );
+
+ if (fPendingState == null) {
+ return;
+ }
+
+ /**
+ * 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) {
+ // Filster out the CONTENT flags from the delta flags, the content
+ // flag is only used as a marker indicating that all the sub-elements
+ // of a given delta have been retrieved.
+ int flags = (delta.getFlags() & ~IModelDelta.CONTENT);
+
+ if (flags != IModelDelta.NO_CHANGE) {
+ IModelDelta parentDelta = delta.getParentDelta();
+ // Remove the delta if :
+ // - The parent delta has no more flags on it (the content flag is removed as well),
+ // which means that parent element's children have been completely exposed.
+ // - There are no more pending updates for the element.
+ // - If element is a memento, there are no state requests pending.
+ if (parentDelta != null && parentDelta.getFlags() == IModelDelta.NO_CHANGE) {
+ TreePath deltaPath = fContentProvider.getViewerTreePath(delta);
+ if ( !fContentProvider.areElementUpdatesPending(deltaPath) &&
+ (!(delta.getElement() instanceof IMemento) || !areMementoUpdatesPending(delta)) )
+ {
+ removeDelta(delta);
+ return false;
+ }
+ }
+
+ if (flags != IModelDelta.REVEAL || (delta.getElement() instanceof IMemento)) {
+ complete = false;
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean isComplete() {
+ return complete;
+ }
+
+ private boolean areMementoUpdatesPending(IModelDelta delta) {
+ for (Iterator itr = fCompareRequestsInProgress.keySet().iterator(); itr.hasNext();) {
+ CompareRequestKey key = (CompareRequestKey) itr.next();
+ if (delta.getElement().equals(key.fDelta.getElement())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void removeDelta(IModelDelta delta) {
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("\tRESTORE REMOVED: " + delta.getElement()); //$NON-NLS-1$
+ }
+
+ delta.accept(new IModelDeltaVisitor() {
+ public boolean visit(IModelDelta _visitorDelta, int depth) {
+ ModelDelta visitorDelta = (ModelDelta) _visitorDelta;
+ visitorDelta.setElement(ELEMENT_REMOVED);
+ visitorDelta.setFlags(IModelDelta.NO_CHANGE);
+ return true;
+ }
+ });
+
+ }
+ }
+
+ CheckState state = new CheckState();
+ fPendingState.accept(state);
+ if (state.isComplete()) {
+ // notify restore complete if REVEAL was restored also, otherwise
+ // postpone until then.
+ if (fPendingSetTopItem == null) {
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("STATE RESTORE COMPELTE: " + fPendingState); //$NON-NLS-1$
+ }
+
+ notifyStateUpdate(fPendingState.getElement(), STATE_RESTORE_SEQUENCE_COMPLETE, null);
+ }
+
+ fPendingState = null;
+ }
+ }
+
+ /**
+ * Restores the pending state in the given delta node. This method is called
+ * once the state tracker has found the element which matches the element in
+ * the given delta node.
+ * @param delta the {@link ModelDelta} to restore from
+ * @param knowsHasChildren if the content provider has computed its children
+ * @param knowsChildCount if the content provider has already computed the child count
+ * @param checkChildrenRealized if any realized children should be checked
+ */
+ void restorePendingStateNode(final ModelDelta delta, boolean knowsHasChildren, boolean knowsChildCount, boolean checkChildrenRealized) {
+ final TreePath treePath = fContentProvider.getViewerTreePath(delta);
+ final IInternalTreeModelViewer viewer = fContentProvider.getViewer();
+
+ // Attempt to expand the node only if the children are known.
+ if (knowsHasChildren) {
+ if ((delta.getFlags() & IModelDelta.EXPAND) != 0) {
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("\tRESTORE EXPAND: " + treePath.getLastSegment()); //$NON-NLS-1$
+ }
+ viewer.expandToLevel(treePath, 1);
+ delta.setFlags(delta.getFlags() & ~IModelDelta.EXPAND);
+ }
+ if ((delta.getFlags() & IModelDelta.COLLAPSE) != 0) {
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("\tRESTORE COLLAPSE: " + treePath.getLastSegment()); //$NON-NLS-1$
+ }
+ // Check auto-expand before collapsing an element (bug 335734)
+ int autoexpand = fContentProvider.getViewer().getAutoExpandLevel();
+ if (autoexpand != ITreeModelViewer.ALL_LEVELS && autoexpand < (treePath.getSegmentCount() + 1)) {
+ fContentProvider.getViewer().setExpandedState(treePath, false);
+ }
+ delta.setFlags(delta.getFlags() & ~IModelDelta.COLLAPSE);
+ }
+ }
+
+ if ((delta.getFlags() & IModelDelta.SELECT) != 0) {
+ delta.setFlags(delta.getFlags() & ~IModelDelta.SELECT);
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("\tRESTORE SELECT: " + treePath.getLastSegment()); //$NON-NLS-1$
+ }
+ ITreeSelection currentSelection = (ITreeSelection)viewer.getSelection();
+ if (currentSelection == null || currentSelection.isEmpty()) {
+ viewer.setSelection(new TreeSelection(treePath), false, false);
+ } else {
+ TreePath[] currentPaths = currentSelection.getPaths();
+ boolean pathInSelection = false;
+ for (int i = 0; i < currentPaths.length; i++) {
+ if (currentPaths[i].equals(treePath)) {
+ pathInSelection = true;
+ break;
+ }
+ }
+ // Only set the selection if the element is not yet in
+ // selection. Otherwise the setSelection() call will
+ // update selection listeners needlessly.
+ if (!pathInSelection) {
+ TreePath[] newPaths = new TreePath[currentPaths.length + 1];
+ System.arraycopy(currentPaths, 0, newPaths, 0, currentPaths.length);
+ newPaths[newPaths.length - 1] = treePath;
+ viewer.setSelection(new TreeSelection(newPaths), false, false);
+ }
+ }
+ }
+
+ if ((delta.getFlags() & IModelDelta.REVEAL) != 0) {
+ delta.setFlags(delta.getFlags() & ~IModelDelta.REVEAL);
+ // Look for the reveal flag in the child deltas. If
+ // A child delta has the reveal flag, do not set the
+ // top element yet.
+ boolean setTopItem = true;
+ IModelDelta[] childDeltas = delta.getChildDeltas();
+ for (int i = 0; i < childDeltas.length; i++) {
+ IModelDelta childDelta = childDeltas[i];
+ int modelIndex = childDelta.getIndex();
+ if (modelIndex >= 0 && (childDelta.getFlags() & IModelDelta.REVEAL) != 0) {
+ setTopItem = false;
+ }
+ }
+
+ if (setTopItem) {
+ Assert.isTrue(fPendingSetTopItem == null);
+
+ fPendingSetTopItem = new PendingRevealDelta(treePath, delta);
+ viewer.addViewerUpdateListener(fPendingSetTopItem);
+ }
+ }
+
+ // If we know the child count of the element, look for the reveal
+ // flag in the child deltas. For the children with reveal flag start
+ // a new update.
+ // If the child delta's index is out of range, strip the reveal flag
+ // since it is no longer applicable.
+ if (knowsChildCount) {
+ int childCount = viewer.getChildCount(treePath);
+ if (childCount >= 0) {
+ ModelDelta[] childDeltas = (ModelDelta[])delta.getChildDeltas();
+ for (int i = 0; i < childDeltas.length; i++) {
+ ModelDelta childDelta = childDeltas[i];
+ int modelIndex = childDelta.getIndex();
+ if (modelIndex >= 0 && (childDelta.getFlags() & IModelDelta.REVEAL) != 0) {
+ if (modelIndex < childCount) {
+ fContentProvider.doUpdateElement(treePath, modelIndex);
+ } else {
+ childDelta.setFlags(childDelta.getFlags() & ~IModelDelta.REVEAL);
+ }
+ }
+ }
+ }
+ }
+
+ // Some children of this element were just updated. If all its
+ // children are now realized, clear out any elements that still
+ // have flags, because they represent elements that were removed.
+ if ((checkChildrenRealized &&
+ !fContentProvider.areChildrenUpdatesPending(treePath) &&
+ fContentProvider.getViewer().getElementChildrenRealized(treePath)) ||
+ (knowsHasChildren && !viewer.getHasChildren(treePath)) )
+ {
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("\tRESTORE CONTENT: " + treePath.getLastSegment()); //$NON-NLS-1$
+ }
+ delta.setFlags(delta.getFlags() & ~IModelDelta.CONTENT);
+ }
+ }
+
+ /**
+ * Utility that reveals the saved top item in the viewer. It listens for
+ * all content updates to complete in order to avoid having the desired top item
+ * scroll out as view content is filled in.
+ * <br>
+ * Revealing some elements can trigger expanding some of elements
+ * that have been just revealed. Therefore, we have to check one
+ * more time after the new triggered updates are completed if we
+ * have to set again the top index
+ */
+ private class PendingRevealDelta implements IViewerUpdateListener {
+
+ private final TreePath fPathToReveal;
+ private final ModelDelta fRevealDelta;
+
+ PendingRevealDelta(TreePath pathToReveal, ModelDelta revealDelta) {
+ fPathToReveal = pathToReveal;
+ fRevealDelta = revealDelta;
+ }
+
+ /**
+ * Counter that tracks how many time the viewer updates were completed.
+ */
+ private int fCounter = 0;
+ private Object fModelInput = fPendingState.getElement();
+
+ public void viewerUpdatesComplete() {
+ Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() );
+
+ IInternalTreeModelViewer viewer = fContentProvider.getViewer();
+ if (viewer == null || fPendingSetTopItem != this) {
+ return;
+ }
+
+ TreePath topPath = viewer.getTopElementPath();
+ if (!fPathToReveal.equals(topPath)) {
+ TreePath parentPath = fPathToReveal.getParentPath();
+ int index = viewer.findElementIndex(parentPath, fPathToReveal.getLastSegment());
+ if (index >= 0) {
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("\tRESTORE REVEAL: " + fPathToReveal.getLastSegment()); //$NON-NLS-1$
+ }
+ viewer.reveal(parentPath, index);
+
+ }
+ }
+
+ fCounter++;
+ // in case the pending state was already set to null, we assume that
+ // all others elements are restored, so we don't expect that REVEAL will
+ // trigger other updates
+ if (fCounter > 1 || fPendingState == null) {
+ dispose();
+ }
+ }
+
+ public void viewerUpdatesBegin() {}
+ public void updateStarted(IViewerUpdate update) {}
+ public void updateComplete(IViewerUpdate update) {}
+
+ /**
+ * Returns delta that is used to reveal the item.
+ * @return delta to be revealed.
+ */
+ public ModelDelta getDelta() {
+ return fRevealDelta;
+ }
+
+ /**
+ * Resets the item
+ */
+ public void dispose() {
+ // top item is set
+ fPendingSetTopItem = null;
+
+ IInternalTreeModelViewer viewer = fContentProvider.getViewer();
+ if (viewer == null) return;
+
+ // remove myself as viewer update listener
+ viewer.removeViewerUpdateListener(this);
+
+ if (fPendingState == null) {
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("STATE RESTORE COMPELTE: " + fPendingState); //$NON-NLS-1$
+ }
+ notifyStateUpdate(fModelInput, STATE_RESTORE_SEQUENCE_COMPLETE, null);
+ } else {
+ checkIfRestoreComplete();
+ }
+ }
+
+ }
+
+ /**
+ * Restore selection/expansion based on items already in the viewer
+ * @param delta the {@link ModelDelta} to restore from
+ */
+ protected void doInitialRestore(ModelDelta delta) {
+ // Find the reveal delta and mark nodes on its path
+ // to reveal as elements are updated.
+ markRevealDelta(delta);
+
+ // Restore visible items.
+ // Note (Pawel Piech): the initial list of items is normally
+ // empty, so in most cases the code below does not do anything.
+ // Instead doRestore() is called when various updates complete.
+ int count = fContentProvider.getViewer().getChildCount(TreePath.EMPTY);
+ for (int i = 0; i < count; i++) {
+ Object data = fContentProvider.getViewer().getChildElement(TreePath.EMPTY, i);
+ if (data != null) {
+ restorePendingStateOnUpdate(new TreePath(new Object[]{data}), i, false, false, false);
+ }
+ }
+
+ }
+
+ /**
+ * Finds the delta with the reveal flag, then it walks up this
+ * delta and marks all the parents of it with the reveal flag.
+ * These flags are then used by the restore logic to restore
+ * and reveal all the nodes leading up to the element that should
+ * be ultimately at the top.
+ * @param rootDelta Delta to search
+ * @return The node just under the rootDelta which contains
+ * the reveal flag. <code>null</code> if no reveal flag was found.
+ */
+ private ModelDelta markRevealDelta(ModelDelta rootDelta) {
+ final ModelDelta[] revealDelta = new ModelDelta[1];
+ IModelDeltaVisitor visitor = new IModelDeltaVisitor() {
+ public boolean visit(IModelDelta delta, int depth) {
+ if ( (delta.getFlags() & IModelDelta.REVEAL) != 0) {
+ revealDelta[0] = (ModelDelta)delta;
+ }
+ // Keep recursing only if we haven't found our delta yet.
+ return revealDelta[0] == null;
+ }
+ };
+
+ rootDelta.accept(visitor);
+ if (revealDelta[0] != null) {
+ ModelDelta parentDelta = (ModelDelta)revealDelta[0].getParentDelta();
+ while(parentDelta.getParentDelta() != null) {
+ revealDelta[0] = parentDelta;
+ revealDelta[0].setFlags(revealDelta[0].getFlags() | IModelDelta.REVEAL);
+ parentDelta = (ModelDelta)parentDelta.getParentDelta();
+ }
+ }
+ return revealDelta[0];
+ }
+
+ /**
+ * Builds a delta with the given root delta for expansion/selection state.
+ *
+ * @param delta
+ * root delta
+ */
+ private void buildViewerState(ModelDelta delta) {
+ IInternalTreeModelViewer viewer = fContentProvider.getViewer();
+ viewer.saveElementState(TreeModelContentProvider.EMPTY_TREE_PATH, delta, IModelDelta.SELECT | IModelDelta.EXPAND);
+
+ // Add memento for top item if it is mapped to an element. The reveal memento
+ // is in its own path to avoid requesting unnecessary data when restoring it.
+ TreePath topElementPath = viewer.getTopElementPath();
+ if (topElementPath != null) {
+ ModelDelta parentDelta = delta;
+ TreePath parentPath = TreeModelContentProvider.EMPTY_TREE_PATH;
+ for (int i = 0; i < topElementPath.getSegmentCount(); i++) {
+ Object element = topElementPath.getSegment(i);
+ int index = viewer.findElementIndex(parentPath, element);
+ ModelDelta childDelta = parentDelta.getChildDelta(element);
+ if (childDelta == null) {
+ parentDelta = parentDelta.addNode(element, index, IModelDelta.NO_CHANGE);
+ } else {
+ parentDelta = childDelta;
+ }
+ parentPath = parentPath.createChildPath(element);
+ }
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.REVEAL);
+ }
+ }
+
+ /**
+ * Cancels any outstanding compare requests for given element and its children.
+ * @param path Path of element to cancel updates for.
+ */
+ void cancelStateSubtreeUpdates(TreePath path) {
+ for (Iterator itr = fCompareRequestsInProgress.keySet().iterator(); itr.hasNext();) {
+ CompareRequestKey key = (CompareRequestKey) itr.next();
+ if (key.fPath.startsWith(path, null)) {
+ ElementCompareRequest compareRequest = (ElementCompareRequest) fCompareRequestsInProgress.get(key);
+ compareRequest.cancel();
+ itr.remove();
+ }
+ }
+ }
+
+ void compareFinished(ElementCompareRequest request, ModelDelta delta) {
+ notifyStateUpdate(request.getViewerInput(), TreeModelContentProvider.UPDATE_COMPLETE, request);
+ if (DEBUG_STATE_SAVE_RESTORE && TreeModelContentProvider.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) {
+ System.out.println("\tSTATE END: " + request + " = " + false); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ fCompareRequestsInProgress.remove(new CompareRequestKey(request.getElementPath(), delta));
+ if (!request.isCanceled()) {
+ if (request.isEqual()) {
+ delta.setElement(request.getElement());
+ restorePendingStateNode(delta, request.knowsHasChildren(), request.knowChildCount(), request.checkChildrenRealized());
+ } else if (request.getModelIndex() != -1) {
+ // Comparison failed.
+ // Check if the delta has a reveal flag, and if its index
+ // matches the index of the element that it was compared
+ // against. If this is the case, strip the reveal flag from
+ // the delta as it is most likely not applicable anymore.
+ if ((delta.getFlags() & IModelDelta.REVEAL) != 0 && delta.getIndex() == request.getModelIndex()) {
+ delta.setFlags(delta.getFlags() & ~IModelDelta.REVEAL);
+ }
+ }
+ }
+ checkIfRestoreComplete();
+ }
+
+
+ void addStateUpdateListener(IStateUpdateListener listener) {
+ fStateUpdateListeners.add(listener);
+ }
+
+ void removeStateUpdateListener(IStateUpdateListener listener) {
+ fStateUpdateListeners.remove(listener);
+ }
+
+ void notifyStateUpdate(final Object input, final int type, final IViewerUpdate update) {
+ if (!fStateUpdateListeners.isEmpty()) {
+ Object[] listeners = fStateUpdateListeners.getListeners();
+ for (int i = 0; i < listeners.length; i++) {
+ final IStateUpdateListener listener = (IStateUpdateListener) listeners[i];
+ SafeRunner.run(new ISafeRunnable() {
+ public void run() throws Exception {
+ switch (type) {
+ case STATE_SAVE_SEQUENCE_BEGINS:
+ listener.stateSaveUpdatesBegin(input);
+ break;
+ case STATE_SAVE_SEQUENCE_COMPLETE:
+ listener.stateSaveUpdatesComplete(input);
+ break;
+ case STATE_RESTORE_SEQUENCE_BEGINS:
+ listener.stateRestoreUpdatesBegin(input);
+ break;
+ case STATE_RESTORE_SEQUENCE_COMPLETE:
+ listener.stateRestoreUpdatesComplete(input);
+ break;
+ case TreeModelContentProvider.UPDATE_BEGINS:
+ listener.stateUpdateStarted(input, update);
+ break;
+ case TreeModelContentProvider.UPDATE_COMPLETE:
+ listener.stateUpdateComplete(input, update);
+ break;
+ }
+ }
+
+ public void handleException(Throwable exception) {
+ DebugUIPlugin.log(exception);
+ }
+ });
+ }
+ }
+ }
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ViewerUpdateMonitor.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ViewerUpdateMonitor.java
index 9ba15c551..267cba74b 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ViewerUpdateMonitor.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ViewerUpdateMonitor.java
@@ -11,24 +11,22 @@
*******************************************************************************/
package org.eclipse.debug.internal.ui.viewers.model;
-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.core.commands.Request;
import org.eclipse.debug.internal.ui.viewers.AsynchronousSchedulingRuleFactory;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
import org.eclipse.jface.viewers.TreePath;
-import org.eclipse.ui.progress.WorkbenchJob;
+import org.eclipse.swt.widgets.Display;
/**
* @since 3.3
*/
public abstract class ViewerUpdateMonitor extends Request implements IViewerUpdate {
- private ModelContentProvider fContentProvider;
+ private TreeModelContentProvider fContentProvider;
/**
* Element's tree path
@@ -71,42 +69,23 @@ public abstract class ViewerUpdateMonitor extends Request implements IViewerUpda
*/
private IPresentationContext fContext;
-
- protected WorkbenchJob fViewerUpdateJob;
-
/**
* Constructs an update for the given content provider
*
* @param contentProvider content provider
+ * @param viewerInput Viewer input for update
* @param elementPath path to associated model element - empty for root element
* @param element associated model element
+ * @param elementContentProvider Content provider for this update.
+ * @param context Presentation contest for this update
*/
- public ViewerUpdateMonitor(ModelContentProvider contentProvider, Object viewerInput, TreePath elementPath, Object element, IElementContentProvider elementContentProvider, IPresentationContext context) {
+ public ViewerUpdateMonitor(TreeModelContentProvider contentProvider, Object viewerInput, TreePath elementPath, Object element, IElementContentProvider elementContentProvider, IPresentationContext context) {
fContext = context;
fViewerInput = viewerInput;
fElementContentProvider = elementContentProvider;
fContentProvider = contentProvider;
fElement = element;
fElementPath = elementPath;
- // serialize updates per viewer
- fViewerUpdateJob = new WorkbenchJob(contentProvider.getViewer().getDisplay(), "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()) {
- performUpdate();
- }
- }
- } finally {
- getContentProvider().updateComplete(ViewerUpdateMonitor.this);
- }
- return Status.OK_STATUS;
- }
- };
- fViewerUpdateJob.setRule(getUpdateSchedulingRule());
- fViewerUpdateJob.setSystem(true);
}
/**
@@ -123,7 +102,7 @@ public abstract class ViewerUpdateMonitor extends Request implements IViewerUpda
*
* @return the model content provider this update is being performed for
*/
- protected ModelContentProvider getContentProvider() {
+ protected TreeModelContentProvider getContentProvider() {
return fContentProvider;
}
@@ -152,18 +131,14 @@ public abstract class ViewerUpdateMonitor extends Request implements IViewerUpda
/**
* Returns whether this request is done yet.
*
- * @return
+ * @return True if this update is done.
*/
protected synchronized boolean isDone() {
return fDone;
}
protected void scheduleViewerUpdate() {
- if(!isCanceled()) {
- fViewerUpdateJob.schedule();
- } else {
- getContentProvider().updateComplete(this);
- }
+ getContentProvider().scheduleViewerUpdate(this);
}
/**
@@ -205,6 +180,9 @@ public abstract class ViewerUpdateMonitor extends Request implements IViewerUpda
/**
* Returns whether this update or any coalesced updates is for an
* element at the given path.
+ * @param path Element path to check.
+ * @return True if this update contains the given update path.
+ *
* @since 3.6
*/
abstract boolean containsUpdate(TreePath path);
@@ -212,7 +190,7 @@ public abstract class ViewerUpdateMonitor extends Request implements IViewerUpda
/**
* Starts this request. Subclasses must override startRequest().
*/
- final void start() {
+ protected void start() {
synchronized (this) {
if (fStarted) {
return;
@@ -273,4 +251,51 @@ public abstract class ViewerUpdateMonitor extends Request implements IViewerUpda
public boolean isDelegated() {
return fIsDelegated;
}
+
+ public boolean equals(Object obj) {
+ if (obj instanceof ViewerUpdateMonitor) {
+ return doEquals((ViewerUpdateMonitor)obj);
+ }
+ return false;
+ }
+
+ public int hashCode() {
+ return doHashCode();
+ }
+
+ /**
+ * Checks whether the given update is equal as this. The update is equal if it's
+ * the same type of update and its updating the same elements.
+ * @param update Update to compare to.
+ * @return True if the given update is equals
+ * @since 3.8
+ */
+ abstract protected boolean doEquals(ViewerUpdateMonitor update);
+
+ /**
+ * Calculates the hash code of the given update using the same parameters as doEquals().
+ * @return Update's hash code.
+ * @since 3.8
+ */
+ abstract protected int doHashCode();
+
+ /**
+ * Executes the given runnable in the UI thread. If method is called in
+ * UI thread, then runnable is executed immediately, otherwise it's executed
+ * using <code>Display.asyncExec()</code>. Runnable is not executed if update is
+ * canceled or content provider is disposed.
+ * @since 3.8
+ */
+ protected void execInDisplayThread(Runnable runnable) {
+ ITreeModelViewer viewer = getContentProvider().getViewer();
+ if (viewer != null && !isCanceled()) {
+ Display display = viewer.getDisplay();
+ if (Thread.currentThread() == display.getThread()) {
+ runnable.run();
+ } else {
+ display.asyncExec(runnable);
+ }
+ }
+ }
+
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/VirtualCopyToClipboardActionDelegate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/VirtualCopyToClipboardActionDelegate.java
index abccaae9b..bc41949c5 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/VirtualCopyToClipboardActionDelegate.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/VirtualCopyToClipboardActionDelegate.java
@@ -7,45 +7,117 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Wind River Systems - refactored on top of VirtualTreeModelViewer
*******************************************************************************/
package org.eclipse.debug.internal.ui.viewers.model;
import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.debug.internal.core.IInternalDebugCoreConstants;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.actions.AbstractDebugActionDelegate;
import org.eclipse.debug.internal.ui.actions.ActionMessages;
-import org.eclipse.debug.internal.ui.viewers.model.InternalTreeModelViewer.VirtualElement;
-import org.eclipse.debug.internal.ui.viewers.model.InternalTreeModelViewer.VirtualModel;
+import org.eclipse.debug.internal.ui.elements.adapters.VariableColumnPresentation;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDeltaVisitor;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IVirtualItemValidator;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualItem;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualItem.Index;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualTreeModelViewer;
import org.eclipse.debug.ui.IDebugView;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
-import org.eclipse.jface.viewers.ContentViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTError;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
-import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
public class VirtualCopyToClipboardActionDelegate extends AbstractDebugActionDelegate {
- private ContentViewer fViewer;
+ private TreeModelViewer fClientViewer;
private static final String TAB = "\t"; //$NON-NLS-1$
private static final String SEPARATOR = "line.separator"; //$NON-NLS-1$
+ private class VirtualViewerListener implements IViewerUpdateListener, ILabelUpdateListener {
+
+ private IProgressMonitor fProgressMonitor;
+ private int fRemainingUpdatesCount;
+ private boolean fViewerUpdatesComplete;
+ private boolean fLabelUpdatesComplete;
+ private int fSelectionRootDepth;
+
+ public void labelUpdateStarted(ILabelUpdate update) {}
+ public void labelUpdateComplete(ILabelUpdate update) {
+ incrementProgress(1);
+ }
+ public void labelUpdatesBegin() {
+ fLabelUpdatesComplete = false;
+ }
+ public void labelUpdatesComplete() {
+ fLabelUpdatesComplete = true;
+ completeProgress();
+ }
+
+ public void updateStarted(IViewerUpdate update) {}
+ public void updateComplete(IViewerUpdate update) {
+ if (update instanceof IChildrenUpdate) {
+ incrementProgress(((IChildrenUpdate)update).getLength());
+ }
+ }
+ public void viewerUpdatesBegin() {
+ fViewerUpdatesComplete = false;
+ }
+ public void viewerUpdatesComplete() {
+ fViewerUpdatesComplete = true;
+ completeProgress();
+ }
+
+ private void completeProgress() {
+ IProgressMonitor pm;
+ synchronized (VirtualCopyToClipboardActionDelegate.this) {
+ pm = fProgressMonitor;
+ }
+ if (pm != null && fLabelUpdatesComplete && fViewerUpdatesComplete) {
+ pm.done();
+ }
+ }
+
+ private void incrementProgress(int count) {
+ IProgressMonitor pm;
+ synchronized (VirtualCopyToClipboardActionDelegate.this) {
+ pm = fProgressMonitor;
+ fRemainingUpdatesCount -= count;
+ }
+ if (pm != null && fLabelUpdatesComplete && fViewerUpdatesComplete) {
+ pm.worked(count);
+ }
+ }
+
+ }
+
+
/**
* @see AbstractDebugActionDelegate#initialize(IAction, ISelection)
*/
@@ -53,8 +125,8 @@ public class VirtualCopyToClipboardActionDelegate extends AbstractDebugActionDel
if (!isInitialized()) {
IDebugView adapter= (IDebugView)getView().getAdapter(IDebugView.class);
if (adapter != null) {
- if (adapter.getViewer() instanceof ContentViewer) {
- setViewer((ContentViewer) adapter.getViewer());
+ if (adapter.getViewer() instanceof TreeModelViewer) {
+ setViewer((TreeModelViewer) adapter.getViewer());
}
adapter.setAction(getActionId(), action);
}
@@ -71,15 +143,17 @@ public class VirtualCopyToClipboardActionDelegate extends AbstractDebugActionDel
* Appends the representation of the specified element (using the label provider and indent)
* to the buffer. For elements down to stack frames, children representations
* are append to the buffer as well.
+ * @param item Item to append to string
+ * @param buffer String buffer for copy text.
+ * @param indent Current indentation in tree text.
*/
- protected void append(VirtualElement item, StringBuffer buffer, int indent) {
+ protected void append(VirtualItem item, StringBuffer buffer, int indent) {
for (int i= 0; i < indent; i++) {
buffer.append(TAB);
}
- String[] labels = item.getLabel();
- int count = labels.length;
- if(count > 0) {
- for (int i = 0; i < count; i++) {
+ String[] labels = (String[]) item.getData(VirtualItem.LABEL_KEY);
+ if(labels != null && labels.length > 0) {
+ for (int i = 0; i < labels.length; i++) {
String text = labels[i];
if(text != null && !text.trim().equals(IInternalDebugCoreConstants.EMPTY_STRING)) {
buffer.append(text+TAB);
@@ -89,108 +163,184 @@ public class VirtualCopyToClipboardActionDelegate extends AbstractDebugActionDel
}
}
+ private IPresentationContext makeVirtualPresentationContext(final IPresentationContext clientViewerContext) {
+ return new PresentationContext(clientViewerContext.getId()) {
+
+ {
+ String[] clientProperties = clientViewerContext.getProperties();
+ for (int i = 0; i < clientProperties.length; i++) {
+ setProperty(clientProperties[i], clientViewerContext.getProperty(clientProperties[i]));
+ }
+
+ }
+
+ public String[] getColumns() {
+ String[] clientColumns = super.getColumns();
+
+ if (clientColumns == null || clientColumns.length == 0) {
+ // No columns are used.
+ return null;
+ }
+
+ // Try to find the name column.
+ for (int i = 0; i < clientColumns.length; i++) {
+ if (VariableColumnPresentation.COLUMN_VARIABLE_NAME.equals(clientColumns[i])) {
+ return new String[] { VariableColumnPresentation.COLUMN_VARIABLE_NAME };
+ }
+ }
+
+ return new String[] { clientColumns[0] };
+ }
+ };
+ }
+
+ private int calcUpdatesCount(IModelDelta stateDelta) {
+ final int[] count = new int[] {0};
+ stateDelta.accept( new IModelDeltaVisitor() {
+ public boolean visit(IModelDelta delta, int depth) {
+ if ((delta.getFlags() & (IModelDelta.EXPAND | IModelDelta.SELECT)) != 0) {
+ count[0]++;
+ return true;
+ }
+ return false;
+ }
+ });
+
+ // Double it to account for separate element and label update ticks.
+ return count[0] * 2;
+ }
+
+ private class ItemsToCopyVirtualItemValidator implements IVirtualItemValidator {
+
+ Set fItemsToCopy = Collections.EMPTY_SET;
+
+ public boolean isItemVisible(VirtualItem item) {
+ return fItemsToCopy.contains(item);
+ }
+
+ public void showItem(VirtualItem item) {
+ }
+ }
+
+ private VirtualTreeModelViewer initVirtualViewer(TreeModelViewer clientViewer, VirtualViewerListener listener, ItemsToCopyVirtualItemValidator validator) {
+ Object input = clientViewer.getInput();
+ ModelDelta stateDelta = new ModelDelta(input, IModelDelta.NO_CHANGE);
+ clientViewer.saveElementState(TreePath.EMPTY, stateDelta, IModelDelta.EXPAND);
+ listener.fRemainingUpdatesCount = calcUpdatesCount(stateDelta);
+ VirtualTreeModelViewer virtualViewer = new VirtualTreeModelViewer(
+ clientViewer.getDisplay(),
+ SWT.VIRTUAL,
+ makeVirtualPresentationContext(clientViewer.getPresentationContext()),
+ validator);
+ virtualViewer.addViewerUpdateListener(listener);
+ virtualViewer.addLabelUpdateListener(listener);
+ virtualViewer.setInput(input);
+ virtualViewer.updateViewer(stateDelta);
+
+ // Parse selected items from client viewer and add them to the virtual viewer selection.
+ listener.fSelectionRootDepth = Integer.MAX_VALUE;
+ TreeItem[] selection = clientViewer.getTree().getSelection();
+ Set vSelection = new HashSet(selection.length * 4/3);
+ for (int i = 0; i < selection.length; i++) {
+ TreePath parentPath = fClientViewer.getTreePathFromItem(selection[i].getParentItem());
+ listener.fSelectionRootDepth = Math.min(parentPath.getSegmentCount() + 1, listener.fSelectionRootDepth);
+ VirtualItem parentVItem = virtualViewer.findItem(parentPath);
+ if (parentVItem != null) {
+ int index = -1;
+ TreeItem parentItem = selection[i].getParentItem();
+ if (parentItem != null) {
+ index = parentItem.indexOf(selection[i]);
+ } else {
+ Tree parentTree = selection[i].getParent();
+ index = parentTree.indexOf(selection[i]);
+ }
+ vSelection.add( parentVItem.getItem(new Index(index)) );
+ if (!selection[i].getExpanded()) {
+ listener.fRemainingUpdatesCount += 2;
+ }
+ }
+ }
+ validator.fItemsToCopy = vSelection;
+ virtualViewer.getTree().validate();
+ return virtualViewer;
+ }
+
+ protected TreeItem[] getSelectedItems(TreeModelViewer clientViewer) {
+ return clientViewer.getTree().getSelection();
+ }
+
/**
* Do the specific action using the current selection.
+ * @param action Action that is running.
*/
public void run(final IAction action) {
- if (fViewer instanceof InternalTreeModelViewer) {
- InternalTreeModelViewer viewer = (InternalTreeModelViewer) fViewer;
- TreeItem[] items = getPrunedSelection();
- TreePath root = null;
- int[] indexes = null;
- if (items.length != 0) {
- TreeItem anItem = items[0];
- TreeItem rootItem = anItem.getParentItem();
- if (rootItem == null) {
- root = TreePath.EMPTY;
- } else {
- root = viewer.getTreePathFromItem(rootItem);
- }
- indexes = new int[items.length];
- for (int i = 0; i < items.length; i++) {
- TreeItem child = items[i];
- if (rootItem == null) {
- indexes[i] = viewer.getTree().indexOf(child);
- } else {
- indexes[i] = rootItem.indexOf(child);
- }
- }
- }
- final VirtualModel model = viewer.buildVirtualModel(root, indexes);
- ProgressMonitorDialog dialog = new TimeTriggeredProgressMonitorDialog(fViewer.getControl().getShell(), 500);
- final IProgressMonitor monitor = dialog.getProgressMonitor();
- dialog.setCancelable(true);
-
- final String[] columns = viewer.getPresentationContext().getColumns();
- final Object[] result = new Object[1];
- IRunnableWithProgress runnable = new IRunnableWithProgress() {
- public void run(final IProgressMonitor m) throws InvocationTargetException, InterruptedException {
- result[0] = model.populate(m, DebugUIPlugin.removeAccelerators(getAction().getText()), columns);
- }
- };
- try {
- dialog.run(true, true, runnable);
- } catch (InvocationTargetException e) {
- DebugUIPlugin.log(e);
- return;
- } catch (InterruptedException e) {
- return;
- }
-
- VirtualElement modelRoot = (VirtualElement) result[0];
- if (!monitor.isCanceled()) {
- if (root != null) {
- // walk down to nested root
- int depth = root.getSegmentCount();
- for (int i = 0; i < depth; i++) {
- VirtualElement[] children = modelRoot.getChildren();
- for (int j = 0; j < children.length; j++) {
- VirtualElement ve = children[j];
- if (ve != null) {
- modelRoot = ve;
- break;
- }
- }
- }
- }
- VirtualElement[] children = modelRoot.getChildren();
- if (children != null) {
- StringBuffer buffer = new StringBuffer();
- for (int i = 0; i < children.length; i++) {
- if (children[i] != null) {
- copy(children[i], buffer, 0);
- }
- }
- TextTransfer plainTextTransfer = TextTransfer.getInstance();
- Clipboard clipboard= new Clipboard(fViewer.getControl().getDisplay());
- try {
- doCopy(clipboard, plainTextTransfer, buffer);
- } finally {
- clipboard.dispose();
- }
- }
+ if (fClientViewer.getSelection().isEmpty()) {
+ writeBufferToClipboard(new StringBuffer(""));
+ return;
+ }
+
+ final VirtualViewerListener listener = new VirtualViewerListener();
+ ItemsToCopyVirtualItemValidator validator = new ItemsToCopyVirtualItemValidator();
+ VirtualTreeModelViewer virtualViewer = initVirtualViewer(fClientViewer, listener, validator);
+
+ ProgressMonitorDialog dialog = new TimeTriggeredProgressMonitorDialog(fClientViewer.getControl().getShell(), 500);
+ final IProgressMonitor monitor = dialog.getProgressMonitor();
+ dialog.setCancelable(true);
+
+ IRunnableWithProgress runnable = new IRunnableWithProgress() {
+ public void run(final IProgressMonitor m) throws InvocationTargetException, InterruptedException {
+ synchronized(listener) {
+ listener.fProgressMonitor = m;
+ listener.fProgressMonitor.beginTask(DebugUIPlugin.removeAccelerators(getAction().getText()), listener.fRemainingUpdatesCount);
+ }
+
+ while ((!listener.fLabelUpdatesComplete || !listener.fViewerUpdatesComplete) && !listener.fProgressMonitor.isCanceled()) {
+ Thread.sleep(1);
+ }
+ synchronized(listener) {
+ listener.fProgressMonitor = null;
+ }
}
-
+ };
+ try {
+ dialog.run(true, true, runnable);
+ } catch (InvocationTargetException e) {
+ DebugUIPlugin.log(e);
+ return;
+ } catch (InterruptedException e) {
+ return;
}
+
+ if (!monitor.isCanceled()) {
+ copySelectionToClipboard(virtualViewer, validator.fItemsToCopy, listener.fSelectionRootDepth);
+ }
+
+ virtualViewer.removeLabelUpdateListener(listener);
+ virtualViewer.removeViewerUpdateListener(listener);
+ virtualViewer.dispose();
+ }
+
+ private void copySelectionToClipboard(VirtualTreeModelViewer virtualViewer, Set itemsToCopy, int selectionRootDepth) {
+ StringBuffer buffer = new StringBuffer();
+ writeItemToBuffer (virtualViewer.getTree(), itemsToCopy, buffer, -selectionRootDepth);
+ writeBufferToClipboard(buffer);
}
- /**
- * @param item
- * @param buffer
- */
- protected void copy(VirtualElement item, StringBuffer buffer, int indent) {
- if (!item.isFiltered()) {
- append(item, buffer, indent);
- VirtualElement[] children = item.getChildren();
- if (children != null) {
- for (int i = 0; i < children.length; i++) {
- copy(children[i], buffer, indent + 1);
- }
+ protected void writeItemToBuffer(VirtualItem item, Set itemsToCopy, StringBuffer buffer, int indent) {
+ if (itemsToCopy.contains(item)) {
+ append(item, buffer, indent);
+ }
+ VirtualItem[] children = item.getItems();
+ if (children != null) {
+ for (int i = 0; i < children.length; i++) {
+ writeItemToBuffer(children[i], itemsToCopy, buffer, indent + 1);
}
}
}
- protected void doCopy(Clipboard clipboard, TextTransfer plainTextTransfer, StringBuffer buffer) {
+ protected void writeBufferToClipboard(StringBuffer buffer) {
+ TextTransfer plainTextTransfer = TextTransfer.getInstance();
+ Clipboard clipboard= new Clipboard(fClientViewer.getControl().getDisplay());
try {
clipboard.setContents(
new String[]{buffer.toString()},
@@ -199,59 +349,20 @@ public class VirtualCopyToClipboardActionDelegate extends AbstractDebugActionDel
if (e.code != DND.ERROR_CANNOT_SET_CLIPBOARD) {
throw e;
}
- if (MessageDialog.openQuestion(fViewer.getControl().getShell(), ActionMessages.CopyToClipboardActionDelegate_Problem_Copying_to_Clipboard_1, ActionMessages.CopyToClipboardActionDelegate_There_was_a_problem_when_accessing_the_system_clipboard__Retry__2)) { //
- doCopy(clipboard, plainTextTransfer, buffer);
- }
- }
- }
-
- /**
- * Returns the selected items in the tree, pruning children
- * if from selected parents.
- */
- protected TreeItem[] getPrunedSelection() {
- Control control = fViewer.getControl();
- List items = new ArrayList();
- if (control instanceof Tree) {
- Tree tree = (Tree) control;
- TreeItem[] selection = tree.getSelection();
- if (selection.length == 0) {
- selection = tree.getItems();
- }
-
- for (int i = 0; i < selection.length; i++) {
- TreeItem item = selection[i];
- if (isEnabledFor(item.getData())) {
- if (walkHierarchy(item, items)) {
- items.add(item);
- }
- }
+ if (MessageDialog.openQuestion(fClientViewer.getControl().getShell(), ActionMessages.CopyToClipboardActionDelegate_Problem_Copying_to_Clipboard_1, ActionMessages.CopyToClipboardActionDelegate_There_was_a_problem_when_accessing_the_system_clipboard__Retry__2)) { //
+ writeBufferToClipboard(buffer);
}
+ } finally {
+ clipboard.dispose();
}
- return (TreeItem[]) items.toArray(new TreeItem[items.size()]);
}
- /**
- * Returns whether the parent of the specified
- * element is already contained in the collection.
- */
- protected boolean walkHierarchy(TreeItem item, List elements) {
- TreeItem parent= item.getParentItem();
- if (parent == null) {
- return true;
- }
- if (elements.contains(parent)) {
- return false;
- }
- return walkHierarchy(parent, elements);
- }
-
- protected ContentViewer getViewer() {
- return fViewer;
+ protected TreeModelViewer getViewer() {
+ return fClientViewer;
}
- protected void setViewer(ContentViewer viewer) {
- fViewer = viewer;
+ protected void setViewer(TreeModelViewer viewer) {
+ fClientViewer = viewer;
}
/**
* @see AbstractDebugActionDelegate#doAction(Object)
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/VirtualFindAction.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/VirtualFindAction.java
index 4cea30d2b..598d78f69 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/VirtualFindAction.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/VirtualFindAction.java
@@ -8,91 +8,224 @@
* Contributors:
* IBM Corporation - initial implementation
* Pawel Piech (Wind River) - added a breadcrumb mode to Debug view (Bug 252677)
+ * Wind River Systems - refactored on top of VirtualTreeModelViewer
*******************************************************************************/
package org.eclipse.debug.internal.ui.viewers.model;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.IDebugHelpContextIds;
import org.eclipse.debug.internal.ui.actions.ActionMessages;
+import org.eclipse.debug.internal.ui.elements.adapters.VariableColumnPresentation;
import org.eclipse.debug.internal.ui.viewers.FindElementDialog;
-import org.eclipse.debug.internal.ui.viewers.model.InternalTreeModelViewer.VirtualElement;
-import org.eclipse.debug.internal.ui.viewers.model.InternalTreeModelViewer.VirtualModel;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDeltaVisitor;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualItem;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualTreeModelViewer;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TreePath;
-import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
-
import org.eclipse.ui.IWorkbenchCommandConstants;
import org.eclipse.ui.PlatformUI;
-
import org.eclipse.ui.texteditor.IUpdate;
import com.ibm.icu.text.MessageFormat;
/**
- * Action which prompts the user to find/navigate to an element in a virtual tree.
+ * Action which prompts user with a filtered list selection dialog to find an element in tree.
*
* @since 3.3
*/
public class VirtualFindAction extends Action implements IUpdate {
- private InternalTreeModelViewer fViewer;
+ private TreeModelViewer fClientViewer;
- class FindLabelProvider extends LabelProvider {
-
- public FindLabelProvider() {
- }
+ private class VirtualViewerListener implements IViewerUpdateListener, ILabelUpdateListener {
+
+ private boolean fViewerUpdatesComplete = false;
+ private boolean fLabelUpdatesComplete = false;
+ private IProgressMonitor fProgressMonitor;
+ private int fRemainingUpdatesCount = 0;
+
+ public void labelUpdateStarted(ILabelUpdate update) {}
+ public void labelUpdateComplete(ILabelUpdate update) {
+ incrementProgress(1);
+ }
+ public void labelUpdatesBegin() {
+ fLabelUpdatesComplete = false;
+ }
+ public void labelUpdatesComplete() {
+ fLabelUpdatesComplete = true;
+ completeProgress();
+ }
+
+ public void updateStarted(IViewerUpdate update) {}
+ public void updateComplete(IViewerUpdate update) {
+ if (update instanceof IChildrenUpdate) {
+ incrementProgress(((IChildrenUpdate)update).getLength());
+ }
+ }
+ public void viewerUpdatesBegin() {
+ fViewerUpdatesComplete = false;
+ }
+ public void viewerUpdatesComplete() {
+ fViewerUpdatesComplete = true;
+ completeProgress();
+ }
+
+ private void completeProgress() {
+ IProgressMonitor pm;
+ synchronized (this) {
+ pm = fProgressMonitor;
+ }
+ if (pm != null && fLabelUpdatesComplete && fViewerUpdatesComplete) {
+ pm.done();
+ }
+ }
+
+ private void incrementProgress(int count) {
+ IProgressMonitor pm;
+ synchronized (this) {
+ pm = fProgressMonitor;
+ fRemainingUpdatesCount -= count;
+ }
+ if (pm != null && fLabelUpdatesComplete && fViewerUpdatesComplete) {
+ pm.worked(count);
+ }
+ }
+ }
+
+ private static class FindLabelProvider extends LabelProvider {
+ private VirtualTreeModelViewer fVirtualViewer;
+ private Map fTextCache = new HashMap();
+ public FindLabelProvider(VirtualTreeModelViewer viewer, List items) {
+ fVirtualViewer = viewer;
+ for (int i = 0; i < items.size(); i++) {
+ VirtualItem item = (VirtualItem)items.get(i);
+ fTextCache.put(item, fVirtualViewer.getText(item, 0));
+ }
+ }
+
public Image getImage(Object element) {
- return ((VirtualElement)element).getImage();
+ return fVirtualViewer.getImage((VirtualItem) element, 0);
}
public String getText(Object element) {
- return ((VirtualElement)element).getLabel()[0];
+ return (String)fTextCache.get(element);
}
-
}
- public VirtualFindAction(InternalTreeModelViewer viewer) {
+ public VirtualFindAction(TreeModelViewer viewer) {
+ fClientViewer = viewer;
+
setText(ActionMessages.FindAction_0);
setId(DebugUIPlugin.getUniqueIdentifier() + ".FindElementAction"); //$NON-NLS-1$
PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IDebugHelpContextIds.FIND_ELEMENT_ACTION);
setActionDefinitionId(IWorkbenchCommandConstants.EDIT_FIND_AND_REPLACE);
- fViewer = viewer;
+ fClientViewer = viewer;
}
+ private VirtualTreeModelViewer initVirtualViewer(TreeModelViewer clientViewer, VirtualViewerListener listener) {
+ Object input = clientViewer.getInput();
+ ModelDelta stateDelta = new ModelDelta(input, IModelDelta.NO_CHANGE);
+ clientViewer.saveElementState(TreePath.EMPTY, stateDelta, IModelDelta.EXPAND);
+ listener.fRemainingUpdatesCount = calcUpdatesCount(stateDelta);
+ VirtualTreeModelViewer fVirtualViewer = new VirtualTreeModelViewer(
+ clientViewer.getDisplay(),
+ SWT.NONE,
+ makeVirtualPresentationContext(clientViewer.getPresentationContext()));
+ fVirtualViewer.addViewerUpdateListener(listener);
+ fVirtualViewer.addLabelUpdateListener(listener);
+ fVirtualViewer.setInput(input);
+ if (fVirtualViewer.canToggleColumns()) {
+ fVirtualViewer.setShowColumns(clientViewer.isShowColumns());
+ }
+ fVirtualViewer.updateViewer(stateDelta);
+ return fVirtualViewer;
+ }
+
+ private IPresentationContext makeVirtualPresentationContext(final IPresentationContext clientViewerContext) {
+ return new PresentationContext(clientViewerContext.getId()) {
+
+ {
+ String[] clientProperties = clientViewerContext.getProperties();
+ for (int i = 0; i < clientProperties.length; i++) {
+ setProperty(clientProperties[i], clientViewerContext.getProperty(clientProperties[i]));
+ }
+
+ }
+
+ public String[] getColumns() {
+ String[] clientColumns = super.getColumns();
+
+ if (clientColumns == null || clientColumns.length == 0) {
+ // No columns are used.
+ return null;
+ }
+
+ // Try to find the name column.
+ for (int i = 0; i < clientColumns.length; i++) {
+ if (VariableColumnPresentation.COLUMN_VARIABLE_NAME.equals(clientColumns[i])) {
+ return new String[] { VariableColumnPresentation.COLUMN_VARIABLE_NAME };
+ }
+ }
+
+ return new String[] { clientColumns[0] };
+ }
+ };
+ }
+
public void run() {
- final VirtualModel model = fViewer.buildVirtualModel(null, null);
- ProgressMonitorDialog dialog = new TimeTriggeredProgressMonitorDialog(fViewer.getControl().getShell(), 500);
+ final VirtualViewerListener listener = new VirtualViewerListener();
+ VirtualTreeModelViewer virtualViewer = initVirtualViewer(fClientViewer, listener);
+
+ ProgressMonitorDialog dialog = new TimeTriggeredProgressMonitorDialog(fClientViewer.getControl().getShell(), 500);
final IProgressMonitor monitor = dialog.getProgressMonitor();
dialog.setCancelable(true);
- String[] columns = fViewer.getPresentationContext().getColumns();
- String[] temp = null;
- if (columns == null || columns.length == 0) {
- temp = null;
- } else {
- temp = new String[]{columns[0]};
- }
- final String[] IDs = temp;
- final Object[] result = new Object[1];
- IRunnableWithProgress runnable = new IRunnableWithProgress() {
- public void run(final IProgressMonitor m) throws InvocationTargetException, InterruptedException {
- result[0] = model.populate(m, DebugUIPlugin.removeAccelerators(getText()), IDs);
- }
- };
try {
- dialog.run(true, true, runnable);
+ dialog.run(
+ true, true,
+ new IRunnableWithProgress() {
+ public void run(final IProgressMonitor m) throws InvocationTargetException, InterruptedException {
+ synchronized(listener) {
+ listener.fProgressMonitor = m;
+ listener.fProgressMonitor.beginTask(DebugUIPlugin.removeAccelerators(getText()), listener.fRemainingUpdatesCount);
+ }
+
+ while ((!listener.fLabelUpdatesComplete || !listener.fViewerUpdatesComplete) && !listener.fProgressMonitor.isCanceled()) {
+ Thread.sleep(1);
+ }
+ synchronized(listener) {
+ listener.fProgressMonitor = null;
+ }
+ }
+ });
} catch (InvocationTargetException e) {
DebugUIPlugin.log(e);
return;
@@ -100,25 +233,43 @@ public class VirtualFindAction extends Action implements IUpdate {
return;
}
- VirtualElement root = (VirtualElement) result[0];
+ VirtualItem root = virtualViewer.getTree();
if (!monitor.isCanceled()) {
List list = new ArrayList();
collectAllChildren(root, list);
- performFind(list.toArray());
+ FindLabelProvider labelProvider = new FindLabelProvider(virtualViewer, list);
+ VirtualItem result = performFind(list, labelProvider);
+ if (result != null) {
+ setSelectionToClient(virtualViewer, labelProvider, result);
+ }
}
+ virtualViewer.removeLabelUpdateListener(listener);
+ virtualViewer.removeViewerUpdateListener(listener);
+ virtualViewer.dispose();
}
- /**
- * Adds all children to the given list recursively.
- *
- * @param collect
- */
- private void collectAllChildren(VirtualElement element, List collect) {
- VirtualElement[] children = element.getChildren();
+ private int calcUpdatesCount(IModelDelta stateDelta) {
+ final int[] count = new int[] {0};
+ stateDelta.accept( new IModelDeltaVisitor() {
+ public boolean visit(IModelDelta delta, int depth) {
+ if ((delta.getFlags() & IModelDelta.EXPAND) != 0) {
+ count[0] += delta.getChildCount();
+ return true;
+ }
+ return false;
+ }
+ });
+
+ // Double it to account for separate element and label update ticks.
+ return count[0] * 2;
+ }
+
+ private void collectAllChildren(VirtualItem element, List collect) {
+ VirtualItem[] children = element.getItems();
if (children != null) {
for (int i = 0; i < children.length; i++) {
- if (!children[i].isFiltered()) {
+ if (!children[i].needsLabelUpdate()) {
collect.add(children[i]);
collectAllChildren(children[i], collect);
}
@@ -126,28 +277,43 @@ public class VirtualFindAction extends Action implements IUpdate {
}
}
- protected void performFind(Object[] items) {
- FindElementDialog dialog = new FindElementDialog(fViewer.getControl().getShell(), new FindLabelProvider(), items);
+ protected VirtualItem performFind(List items, FindLabelProvider labelProvider) {
+ FindElementDialog dialog = new FindElementDialog(
+ fClientViewer.getControl().getShell(),
+ labelProvider,
+ items.toArray());
dialog.setTitle(ActionMessages.FindDialog_3);
dialog.setMessage(ActionMessages.FindDialog_1);
if (dialog.open() == Window.OK) {
Object[] elements = dialog.getResult();
if (elements.length == 1) {
- VirtualElement element = (VirtualElement)elements[0];
- TreePath path = element.realize();
- if (path != null) {
- fViewer.setSelection(new TreeSelection(path), true, true);
- } else {
- DebugUIPlugin.errorDialog(fViewer.getControl().getShell(), ActionMessages.VirtualFindAction_0,
- MessageFormat.format(ActionMessages.VirtualFindAction_1, new String[]{element.getLabel()[0]}),
- (IStatus)null);
- }
+ return (VirtualItem)elements[0];
}
}
+ return null;
+ }
+
+ protected void setSelectionToClient(VirtualTreeModelViewer virtualViewer, ILabelProvider labelProvider, VirtualItem findItem) {
+ virtualViewer.getTree().setSelection(new VirtualItem[] { findItem } );
+ ModelDelta stateDelta = new ModelDelta(virtualViewer.getInput(), IModelDelta.NO_CHANGE);
+ virtualViewer.saveElementState(TreePath.EMPTY, stateDelta, IModelDelta.SELECT);
+ fClientViewer.updateViewer(stateDelta);
+
+ ISelection selection = fClientViewer.getSelection();
+ if (!selection.isEmpty() &&
+ selection instanceof IStructuredSelection &&
+ ((IStructuredSelection)selection).getFirstElement().equals(findItem.getData()) ) {
+ } else {
+ DebugUIPlugin.errorDialog(
+ fClientViewer.getControl().getShell(),
+ ActionMessages.VirtualFindAction_0,
+ MessageFormat.format(ActionMessages.VirtualFindAction_1, new String[]{ labelProvider.getText(findItem) }),
+ new Status(IStatus.ERROR, DebugUIPlugin.getUniqueIdentifier(), ActionMessages.VirtualFindAction_1));
+ }
}
public void update() {
- setEnabled(fViewer.getInput() != null);
+ setEnabled(fClientViewer.getInput() != null);
}
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ICheckUpdate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ICheckUpdate.java
index 91d90ef10..7e31d3589 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ICheckUpdate.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ICheckUpdate.java
@@ -1,5 +1,5 @@
/*****************************************************************
- * Copyright (c) 2009 Texas Instruments and others
+ * Copyright (c) 2009, 2011 Texas Instruments 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
@@ -28,8 +28,8 @@ public interface ICheckUpdate extends ILabelUpdate {
/**
* Sets the check state of the tree node.
*
- * @param checked
- * @param grayed
+ * @param checked Whether element should be checked.
+ * @param grayed Whether element should be grayed out.
*/
public void setChecked(boolean checked, boolean grayed);
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ICheckboxModelProxy.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ICheckboxModelProxy.java
index d1f720358..3513b2adf 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ICheckboxModelProxy.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ICheckboxModelProxy.java
@@ -1,5 +1,5 @@
/*****************************************************************
- * Copyright (c) 2009 Texas Instruments and others
+ * Copyright (c) 2009, 2011 Texas Instruments 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
@@ -19,8 +19,9 @@ import org.eclipse.jface.viewers.TreePath;
* notification for check state changes in the tree.
*
* @since 3.6
+ * @see IModelProxy
*/
-public interface ICheckboxModelProxy extends IModelProxy {
+public interface ICheckboxModelProxy {
/**
* Notifies the receiver that the given element has had its
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IChildrenCountUpdate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IChildrenCountUpdate.java
index 09cb08993..55818113c 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IChildrenCountUpdate.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IChildrenCountUpdate.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006 IBM Corporation and others.
+ * Copyright (c) 2006, 2011 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
@@ -14,9 +14,8 @@ package org.eclipse.debug.internal.ui.viewers.model.provisional;
/**
* Request monitor used to collect the number of children for an element in a viewer.
- * <p>
- * Clients are not intended to implement this interface.
- * </p>
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
* @since 3.3
*/
public interface IChildrenCountUpdate extends IViewerUpdate {
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IChildrenUpdate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IChildrenUpdate.java
index 643a8379d..9ee12df28 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IChildrenUpdate.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IChildrenUpdate.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006 IBM Corporation and others.
+ * Copyright (c) 2006, 2011 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
@@ -14,9 +14,8 @@ package org.eclipse.debug.internal.ui.viewers.model.provisional;
/**
* Context sensitive children update request for a parent and subrange of its
* children.
- * <p>
- * Clients are not intended to implement this interface.
- * </p>
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
* @since 3.3
*/
public interface IChildrenUpdate extends IViewerUpdate {
@@ -40,9 +39,7 @@ public interface IChildrenUpdate extends IViewerUpdate {
* 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>
+ * @param offset child offset
*/
public void setChild(Object child, int offset);
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IColumnPresentation.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IColumnPresentation.java
index acdd43c22..991765351 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IColumnPresentation.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IColumnPresentation.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2007 IBM Corporation and others.
+ * Copyright (c) 2006, 2011 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
@@ -25,7 +25,7 @@ public interface IColumnPresentation {
* Initializes this column presentation to be used in the
* given context.
*
- * @param context
+ * @param context Presentation context.
*/
public void init(IPresentationContext context);
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementCompareRequest.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementCompareRequest.java
index 7f6dfc45b..d6258f468 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementCompareRequest.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementCompareRequest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006 IBM Corporation and others.
+ * Copyright (c) 2006, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -13,9 +13,8 @@ package org.eclipse.debug.internal.ui.viewers.model.provisional;
/**
* Request to compare an element to a previously created memento.
- * <p>
- * Clients are not intended to implement this interface.
- * </p>
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
* @since 3.3
*/
public interface IElementCompareRequest extends IElementMementoRequest {
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementContentProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementContentProvider.java
index b98cdbcc0..d3b682880 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementContentProvider.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementContentProvider.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2008 IBM Corporation and others.
+ * Copyright (c) 2006, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -13,7 +13,12 @@ package org.eclipse.debug.internal.ui.viewers.model.provisional;
/**
- * Provides content for an element in a virtual viewer.
+ * Provides content for an element in a tree model viewer.
+ * <p>
+ * Note: provider methods are called in the Display thread of the viewer.
+ * To avoid blocking the UI, long running operations should be performed
+ * asynchronously.
+ * </p>
*
* @since 3.3
*/
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementEditor.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementEditor.java
index 9d04de4f8..e1890aa4f 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementEditor.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementEditor.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2007 IBM Corporation and others.
+ * Copyright (c) 2006, 2011 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
@@ -26,7 +26,7 @@ public interface IElementEditor {
* if none.
*
* @param context presentation context
- * @param id column id
+ * @param columnId column id
* @param element object to be edited
* @param parent parent control to create the cell editor in
* @return cell editor or <code>null</code>
@@ -36,6 +36,8 @@ public interface IElementEditor {
/**
* Returns a cell modifier for the specified element in the given context
* or <code>null</code> if none.
+ * @param context Presentation context
+ * @param element Model element.
*
* @return cell modifier or <code>null</code>
*/
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementLabelProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementLabelProvider.java
index 0aaba8c6b..90551a572 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementLabelProvider.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementLabelProvider.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2008 IBM Corporation and others.
+ * Copyright (c) 2006, 2011 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
@@ -14,6 +14,11 @@ package org.eclipse.debug.internal.ui.viewers.model.provisional;
/**
* Provides context sensitive labels. Can be registered as an adapter for an element,
* or implemented directly.
+ * <p>
+ * Note: provider methods are called in the Display thread of the viewer.
+ * To avoid blocking the UI, long running operations should be performed
+ * asynchronously.
+ * </p>
*
* @since 3.3
*/
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementMementoProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementMementoProvider.java
index e4da42cd5..416072148 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementMementoProvider.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IElementMementoProvider.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2008 IBM Corporation and others.
+ * Copyright (c) 2006, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -15,6 +15,11 @@ package org.eclipse.debug.internal.ui.viewers.model.provisional;
* 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.
+ * <p>
+ * Note: provider methods are called in the Display thread of the viewer.
+ * To avoid blocking the UI, long running operations should be performed
+ * asynchronously.
+ * </p>
*
* @since 3.3
*/
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IHasChildrenUpdate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IHasChildrenUpdate.java
index 6c7fab0ea..85232d9ed 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IHasChildrenUpdate.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IHasChildrenUpdate.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006 IBM Corporation and others.
+ * Copyright (c) 2006, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -13,9 +13,8 @@ package org.eclipse.debug.internal.ui.viewers.model.provisional;
/**
* Context sensitive update request for whether an element has children.
- * <p>
- * Clients are not intended to implement this interface.
- * </p>
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
* @since 3.3
*/
public interface IHasChildrenUpdate extends IViewerUpdate {
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ILabelUpdate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ILabelUpdate.java
index eebe886ec..451fd2a6d 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ILabelUpdate.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ILabelUpdate.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2008 IBM Corporation and others.
+ * Copyright (c) 2006, 2011 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
@@ -16,9 +16,8 @@ import org.eclipse.swt.graphics.RGB;
/**
* Context sensitive label update request for an element.
- * <p>
- * Clients are not intended to implement this interface.
- * </p>
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
* @since 3.3
*/
public interface ILabelUpdate extends IViewerUpdate {
@@ -36,7 +35,7 @@ public interface ILabelUpdate extends IViewerUpdate {
/**
* Sets the text of the label of the specified column. Cannot be <code>null</code>.
*
- * @param text
+ * @param text to set to viewer
* @param columnIndex column index (0 when no columns)
*/
public void setLabel(String text, int columnIndex);
@@ -44,7 +43,7 @@ public interface ILabelUpdate extends IViewerUpdate {
/**
* Sets the font of the label.
*
- * @param fontData
+ * @param fontData to set to viewer
* @param columnIndex column index (0 when no columns)
*/
public void setFontData(FontData fontData, int columnIndex);
@@ -52,7 +51,7 @@ public interface ILabelUpdate extends IViewerUpdate {
/**
* Sets the image of the label.
*
- * @param image
+ * @param image to set to viewer
* @param columnIndex column index (0 when no columns)
*/
public void setImageDescriptor(ImageDescriptor image, int columnIndex);
@@ -60,7 +59,7 @@ public interface ILabelUpdate extends IViewerUpdate {
/**
* Sets the foreground color of the label.
*
- * @param foreground
+ * @param foreground to set to viewer
* @param columnIndex column index (0 when no columns)
*/
public void setForeground(RGB foreground, int columnIndex);
@@ -68,7 +67,7 @@ public interface ILabelUpdate extends IViewerUpdate {
/**
* Sets the background color of the label.
*
- * @param background
+ * @param background to set to viewer
* @param columnIndex column index (0 when no columns)
*/
public void setBackground(RGB background, int columnIndex);
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelChangedListener.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelChangedListener.java
index f812ee94b..98470bc83 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelChangedListener.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelChangedListener.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2006 IBM Corporation and others.
+ * Copyright (c) 2005, 2011 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
@@ -16,7 +16,7 @@ package org.eclipse.debug.internal.ui.viewers.model.provisional;
*
* @since 3.2
* @see IModelProxy
- * @see IModelDeltaNode
+ * @see IModelDelta
*/
public interface IModelChangedListener {
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelDelta.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelDelta.java
index 18fd862ed..3fb1dd65c 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelDelta.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelDelta.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2009 IBM Corporation and others.
+ * Copyright (c) 2005, 2011 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
@@ -26,10 +26,8 @@ package org.eclipse.debug.internal.ui.viewers.model.provisional;
* </ul>
* </p>
* <p>
- * Clients are not intended to implement this interface directly. Instead, clients
- * creating and firing model deltas should create instances of
- * {@link org.eclipse.debug.internal.ui.viewers.update.ModelDelta}.
- * </p>
+ * @noimplement Clients are not intended to implement this interface directly. Instead, clients
+ * creating and firing model deltas should create instances of {@link ModelDelta}.
* </p>
* @since 3.2
*/
@@ -185,7 +183,7 @@ public interface IModelDelta {
/**
* Accepts the given visitor.
*
- * @param visitor
+ * @param visitor delta visitor to accept
* @since 3.3
*/
public void accept(IModelDeltaVisitor visitor);
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelProxy.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelProxy.java
index e661b1e97..adabf4e78 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelProxy.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelProxy.java
@@ -26,38 +26,48 @@ import org.eclipse.jface.viewers.Viewer;
* within that model for a specific presentation context.
* </p>
* <p>
- * Clients may implement this interface. Implementations of this interface
- * must subclass {@link AbstractModelProxy}.
+ * Note: provider methods are called in the Display thread of the viewer.
+ * To avoid blocking the UI, long running operations should be performed
+ * asynchronously.
* </p>
+ *
+ * @noimplement Clients are not intended to implement this interface directly. Instead, clients
+ * creating and firing model deltas should create instances of {@link AbstractModelProxy}.
* @see IModelDelta
* @see IModelProxyFactory
* @see IModelChangedListener
* @see ICheckboxModelProxy
+ * @see IModelProxy2
* @since 3.2
*/
public interface IModelProxy {
-
+
/**
* Notification this model proxy has been created and is about to be installed
* in the following context. This is the first method called after a model proxy
- * is created.
+ * is created and it's called in a job thread and not on a display thread.
* <p>
* This method is called by the asynchronous viewer framework and should not
* be called by clients.
* </p>
* @param context presentation context in which the proxy will be installed
+ * @see IModelProxy2#initialize(ITreeModelViewer)
*/
public void init(IPresentationContext context);
/**
* Notification this model proxy has been installed in the specified
* viewer. This indicates that the model proxy has been created and registered
- * model change listeners are ready to process deltas.
+ * model change listeners are ready to process deltas. This method is called
+ * by the {@link AbstractModelProxy} base class using a job and NOT in viewers
+ * display thread. It allows the client to initialize the proxy without
+ * blocking the UI. The default implementaiton is a no-op.
* <p>
* This method is called by the asynchronous viewer framework and should not
* be called by clients.
* </p>
- * @param viewer viewer
+ * @param viewer viewer
+ * @see IModelProxy2#initialize(ITreeModelViewer)
* @since 3.3
*/
public void installed(Viewer viewer);
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelProxy2.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelProxy2.java
new file mode 100644
index 000000000..7187edc48
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelProxy2.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.debug.internal.ui.viewers.model.provisional;
+
+import org.eclipse.debug.internal.ui.viewers.provisional.AbstractModelProxy;
+import org.eclipse.jface.viewers.Viewer;
+
+/**
+ * Extension to the model proxy interface which allows the proxy to be initialized
+ * on the viewer's Display thread
+ *
+ * @noimplement Clients are not intended to implement this interface directly. Instead, clients
+ * creating and firing model deltas should create instances of {@link AbstractModelProxy}.
+ * @since 3.8
+ */
+public interface IModelProxy2 extends IModelProxy {
+
+ /**
+ * Initialize model proxy with given tree model viewer. This method is
+ * called on the viewer's Display thread and is guaranteed to be called
+ * before the dispose() method is called on the same proxy. The default
+ * implementation of this method calls {@link #init(IPresentationContext)}
+ * and {@link #installed(Viewer)} asynchornously and not in the Display
+ * thread.
+ * <p>
+ * This method is called by the asynchronous viewer framework and should
+ * not be called by clients.
+ * </p>
+ * @param viewer Viewer that is installing this model proxy.
+ *
+ */
+ public void initialize(ITreeModelViewer viewer);
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelSelectionPolicy.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelSelectionPolicy.java
index c0fec6504..f672adef1 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelSelectionPolicy.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IModelSelectionPolicy.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * Copyright (c) 2005, 2011 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
@@ -34,12 +34,11 @@ import org.eclipse.jface.viewers.ISelection;
public interface IModelSelectionPolicy {
/**
- * Returns whether the given selection is contained in
- * this model.
+ * Returns whether the given selection is contained in this model.
*
- * @param selection
- * @param context
- * @return
+ * @param selection Selection to check
+ * @param context Presentation context of the viewer.
+ * @return true if selection is contained in model.
*/
public boolean contains(ISelection selection, IPresentationContext context);
@@ -48,10 +47,10 @@ public interface IModelSelectionPolicy {
* existing selection. The policy is only asked about selections
* that it contains.
*
- * @param existing
- * @param candidate
- * @param context
- * @return
+ * @param existing Existing selection to check.
+ * @param candidate New proposed selection.
+ * @param context Presentation context of viewer.
+ * @return true if candidate selection should be set to viewer
*/
public boolean overrides(ISelection existing, ISelection candidate, IPresentationContext context);
@@ -59,9 +58,9 @@ public interface IModelSelectionPolicy {
* Returns whether the given selection should be maintained in the
* face of a selection attempt from a different model.
*
- * @param selection
- * @param context
- * @return
+ * @param selection selection to test
+ * @param context Presentation context of viewer.
+ * @return true if selection is sticky
*/
public boolean isSticky(ISelection selection, IPresentationContext context);
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IStateUpdateListener.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IStateUpdateListener.java
index efa321fdb..49830e0af 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IStateUpdateListener.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IStateUpdateListener.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009 IBM Corporation and others.
+ * Copyright (c) 2009, 2011 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
@@ -20,23 +20,31 @@ public interface IStateUpdateListener {
/**
* Notification that a sequence of state saving updates are starting.
+ *
+ * @param input Input object for the state operation.
*/
public void stateSaveUpdatesBegin(Object input);
/**
* Notification that viewer updates are complete. Corresponds to
* a <code>viewerUpdatesBegin()</code> notification.
+ *
+ * @param input Input object for the state operation.
*/
public void stateSaveUpdatesComplete(Object input);
/**
* Notification that a sequence of viewer updates are starting.
+ *
+ * @param input Input object for the state operation.
*/
public void stateRestoreUpdatesBegin(Object input);
/**
* Notification that viewer updates are complete. Corresponds to
* a <code>viewerUpdatesBegin()</code> notification.
+ *
+ * @param input Input object for the state operation.
*/
public void stateRestoreUpdatesComplete(Object input);
@@ -44,6 +52,7 @@ public interface IStateUpdateListener {
* Notification that a specific update has started within
* a sequence of updates.
*
+ * @param input Input object for the state operation.
* @param update update
*/
public void stateUpdateStarted(Object input, IViewerUpdate update);
@@ -52,6 +61,7 @@ public interface IStateUpdateListener {
* Notification that a specific update has completed within a
* sequence of updates.
*
+ * @param input Input object for the state operation.
* @param update update
*/
public void stateUpdateComplete(Object input, IViewerUpdate update);
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ITreeModelViewer.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ITreeModelViewer.java
new file mode 100644
index 000000000..25a04bc4c
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ITreeModelViewer.java
@@ -0,0 +1,278 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ * IBM Corporation - ongoing bug fixes and enhancements
+ *******************************************************************************/
+package org.eclipse.debug.internal.ui.viewers.model.provisional;
+
+import org.eclipse.debug.internal.ui.viewers.model.ILabelUpdateListener;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.jface.viewers.ViewerLabel;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * Interface of an tree model viewer. It declares the common methods for the
+ * JFace-based {@link TreeModelViewer} and the UI-less
+ * {@link VirtualTreeModelViewer}.
+ *
+ * @since 3.8
+ */
+public interface ITreeModelViewer extends ISelectionProvider {
+
+ /**
+ * Constant indicating that all levels of the tree should be expanded or
+ * collapsed.
+ *
+ * @see #setAutoExpandLevel(int)
+ * @see #getAutoExpandLevel()
+ */
+ public static final int ALL_LEVELS = -1;
+
+ /**
+ * Returns the Display object that this viewer is in. The
+ * display object can be used by clients to access the display thread
+ * to call the viewer methods.
+ *
+ * @return The display.
+ */
+ public Display getDisplay();
+
+ /**
+ * Returns this viewer's presentation context.
+ *
+ * @return presentation context
+ */
+ public IPresentationContext getPresentationContext();
+
+ /**
+ * Returns the current input of this viewer, or <code>null</code>
+ * if none. The viewer's input provides the "model" for the viewer's
+ * content.
+ *
+ * @return Input object
+ */
+ public Object getInput();
+
+ /**
+ * Sets the input of this viewer. Setting the input resets the
+ * viewer's contents and triggers an update starting at the input
+ * element.
+ *
+ * @param object Input element, or <code>null</code> if none.
+ */
+ public void setInput(Object object);
+
+ /**
+ * Returns the current selection in viewer.
+ *
+ * @return selection object
+ */
+ public ISelection getSelection();
+
+ /**
+ * Sets a new selection for this viewer and optionally makes it visible.
+ * The selection is not set if the model selection policy overrides the
+ * attempt to set the selection.
+ *
+ * @param selection the new selection
+ * @param reveal <code>true</code> if the selection is to be made
+ * visible, and <code>false</code> otherwise
+ * @param force <code>true</code> if the selection should override the
+ * model selection policy
+ */
+ public void setSelection(ISelection selection, boolean reveal, boolean force);
+
+ /**
+ * Attempts to set the selection for this viewer and optionally makes it visible.
+ * The selection is not set if the model selection policy overrides the
+ * attempt to set the selection.
+ *
+ * @param selection the new selection
+ * @param reveal whether to make the selection visible after successfully setting
+ * the selection
+ * @param force whether to force the selection (override the model selection policy)
+ * @return <code>true</code> if the selection was set and <code>false</code> if the
+ * model selection policy overrides the selection attempt
+ */
+ public boolean trySelection(ISelection selection, boolean reveal, boolean force);
+
+ /**
+ * Returns the auto-expand level.
+ *
+ * @return non-negative level, or <code>ALL_LEVELS</code> if all levels of
+ * the tree are expanded automatically
+ * @see #setAutoExpandLevel
+ */
+ public int getAutoExpandLevel();
+
+ /**
+ * Sets the auto-expand level to be used when the input of the viewer is set
+ * using {@link #setInput(Object)}. The value 0 means that there is no
+ * auto-expand; 1 means that the invisible root element is expanded (since
+ * most concrete implementations do not show the root element, there is usually
+ * no practical difference between using the values 0 and 1); 2 means that
+ * top-level elements are expanded, but not their children; 3 means that
+ * top-level elements are expanded, and their children, but not
+ * grandchildren; and so on.
+ * <p>
+ * The value <code>ALL_LEVELS</code> means that all subtrees should be
+ * expanded.
+ * </p>
+ *
+ * @param level
+ * non-negative level, or <code>ALL_LEVELS</code> to expand all
+ * levels of the tree
+ */
+ public void setAutoExpandLevel(int level);
+
+ /**
+ * Returns the label data for the given element and for the given column,
+ * Returns <code>null</code> if the given element is not found or is not
+ * materialized in the virtual viewer. Clients may listen to label update
+ * events to be notified when element labels are updated.
+ *
+ * @param path Path of the element.
+ * @param columnId ID of the column for which to return the label data.
+ * @return Label object containing the label information. Can be
+ * <code>null</code> if the given element is not found or is not
+ * materialized in the virtual viewer.
+ */
+ public ViewerLabel getElementLabel(TreePath path, String columnId);
+
+ /**
+ * Registers the specified listener for view update notifications.
+ *
+ * @param listener Listener to add
+ */
+ public void addViewerUpdateListener(IViewerUpdateListener listener);
+
+ /**
+ * Removes the specified listener from update notifications.
+ *
+ * @param listener Listener to remove
+ */
+ public void removeViewerUpdateListener(IViewerUpdateListener listener);
+
+ /**
+ * Registers the specified listener for state update notifications.
+ *
+ * @param listener Listener to add
+ */
+ public void addStateUpdateListener(IStateUpdateListener listener);
+
+ /**
+ * Removes the specified listener from state update notifications.
+ *
+ * @param listener Listener to remove
+ */
+ public void removeStateUpdateListener(IStateUpdateListener listener);
+
+ /**
+ * Registers the specified listener for view label update notifications.
+ *
+ * @param listener Listener to add
+ */
+ public void addLabelUpdateListener(ILabelUpdateListener listener);
+
+ /**
+ * Removes the specified listener from view label update notifications.
+ *
+ * @param listener Listener to remove
+ */
+ public void removeLabelUpdateListener(ILabelUpdateListener listener);
+
+ /**
+ * Registers the given listener for model delta notification.
+ * This listener is called immediately after the viewer processes
+ * the delta.
+ *
+ * @param listener Listener to add
+ */
+ public void addModelChangedListener(IModelChangedListener listener);
+
+ /**
+ * Removes the given listener from model delta notification.
+ *
+ * @param listener Listener to remove
+ */
+ public void removeModelChangedListener(IModelChangedListener listener);
+
+ /**
+ * Writes state information into a delta for the sub-tree at the given
+ * path. It adds delta nodes and IModelDelta.EXPAND and IModelDelta.SELECT
+ * as it parses the sub-tree.
+ *
+ * @param path Path where to start saving the state.
+ * @param delta The delta where the state is to be saved.
+ * @param flagsToSave The flags to preserve during the state save. The
+ * supported flags are <code>IModelDelta.SELECT</code>,
+ * <code>IModelDelta.EXPAND</code>, <code>IModelDelta.COLLAPSE</code>.
+ * @return Returns whether the state was saved for the given path. Will
+ * return <code>false</code> if an element at the given path cannot
+ * be found.
+ */
+ public boolean saveElementState(TreePath path, ModelDelta delta, int flagsToSave);
+
+ /**
+ * Causes the viewer to process the given delta as if it came from a
+ * model proxy. This method is intended to be used to restore state
+ * saved using {@link #saveElementState(TreePath, ModelDelta, int)}.
+ *
+ * @param delta Delta to process.
+ */
+ public void updateViewer(IModelDelta delta);
+
+ /**
+ * Triggers an update of the given element and its children. If
+ * multiple instances of the given element are found in the tree,
+ * they will all be updated.
+ *
+ * @param element Element to update.
+ */
+ public void refresh(Object element);
+
+ /**
+ * Triggers a full update of all the elements in the tree.
+ */
+ public void refresh();
+
+ /**
+ * Returns the paths at which the given element is found realized in viewer
+ * or an empty array if not found.
+ *
+ * @param element Element to find.
+ * @return Array of paths for given element.
+ */
+ public TreePath[] getElementPaths(Object element);
+
+ /**
+ * Returns filters currently configured in viewer.
+ *
+ * @return filter array in viewer.
+ */
+ public ViewerFilter[] getFilters();
+
+ /**
+ * Add a new filter to use in viewer.
+ *
+ * @param filter Filter to add.
+ */
+ public void addFilter(ViewerFilter filter);
+
+ /**
+ * Sets viewer filters to the filters in array.
+ *
+ * @param filters New filter array to use.
+ */
+ public void setFilters(ViewerFilter[] filters);
+
+ }
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IViewerUpdate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IViewerUpdate.java
index f2a5be0a3..baa6971ce 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IViewerUpdate.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IViewerUpdate.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2008 IBM Corporation and others.
+ * Copyright (c) 2006, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -15,9 +15,8 @@ import org.eclipse.jface.viewers.TreePath;
/**
* A context sensitive viewer update request.
- * <p>
- * Clients are not intended to implement this interface.
- * </p>
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
* @since 3.3
*/
public interface IViewerUpdate extends IRequest {
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IVirtualItemListener.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IVirtualItemListener.java
new file mode 100644
index 000000000..4f5944752
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IVirtualItemListener.java
@@ -0,0 +1,28 @@
+package org.eclipse.debug.internal.ui.viewers.model.provisional;
+
+/**
+ * Interface for listeners that need to be notified when items
+ * are disposed or revealed. It should be implemented by the viewer.
+ *
+ * @see VirtualTreeModelViewer
+ * @since 3.8
+ */
+public interface IVirtualItemListener {
+
+ /**
+ * Called when the item has been shown in the virtual viewer's
+ * view-port. This indicates to the viewer that it should check
+ * the item's status and request needed data.
+ *
+ * @param item The item that was revealed.
+ */
+ public void revealed(VirtualItem item);
+
+ /**
+ * Called when an item is disposed. It tells the viewer to
+ * clean up any remaining mappings and cached data of this item.
+ *
+ * @param item The itam that was disposed.
+ */
+ public void disposed(VirtualItem item);
+} \ No newline at end of file
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IVirtualItemValidator.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IVirtualItemValidator.java
new file mode 100644
index 000000000..b460c486c
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IVirtualItemValidator.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.debug.internal.ui.viewers.model.provisional;
+
+
+/**
+ * A validator to be used with a VirtualTreeModelViewer to determine which viewer
+ * items should be updated by the viewer.
+ *
+ * @see VirtualTreeModelViewer
+ * @since 3.8
+ */
+public interface IVirtualItemValidator {
+
+ /**
+ * Allows the validator to determine whether the given item is to be deemed
+ * visible in the virtual tree.
+ *
+ * @param item Item to be tested.
+ * @return returns true if the item should be considered visible.
+ */
+ public boolean isItemVisible(VirtualItem item);
+
+ /**
+ * Indicates that the viewer requested to reveal the given item in viewer.
+ *
+ * @param item Item to show.
+ */
+ public void showItem(VirtualItem item);
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ModelDelta.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ModelDelta.java
index 455573e42..1f4052251 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ModelDelta.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ModelDelta.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2009 IBM Corporation and others.
+ * Copyright (c) 2005, 2011 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
@@ -11,16 +11,14 @@
*******************************************************************************/
package org.eclipse.debug.internal.ui.viewers.model.provisional;
-
-
-
/**
* A model delta. Used to create model deltas.
* <p>
- * Clients may instantiate this class; not intended to be subclassed.
+ * Clients may instantiate this class; not intended to be sub-classed.
* </p>
- * @see org.eclipse.debug.internal.ui.viewers.IModelDelta
+ * @see IModelDelta
* @since 3.2
+ * @noextend This class is not intended to be sub-classed by clients.
*/
public class ModelDelta implements IModelDelta {
@@ -332,7 +330,7 @@ public class ModelDelta implements IModelDelta {
/**
* Sets this delta's element
*
- * @param element
+ * @param element element to set
*/
public void setElement(Object element) {
fElement = element;
@@ -341,7 +339,7 @@ public class ModelDelta implements IModelDelta {
/**
* Sets this delta's flags.
*
- * @param flags
+ * @param flags new flags to set
*/
public void setFlags(int flags) {
fFlags = flags;
@@ -350,7 +348,7 @@ public class ModelDelta implements IModelDelta {
/**
* Sets this delta's index
*
- * @param index
+ * @param index new index to set.
* @since 3.6
*/
public void setIndex(int index) {
@@ -360,7 +358,7 @@ public class ModelDelta implements IModelDelta {
/**
* Sets this delta's child count.
*
- * @param count
+ * @param count New child count to set.
*/
public void setChildCount(int count) {
fChildCount = count;
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/PresentationContext.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/PresentationContext.java
index 1a4b03389..574964040 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/PresentationContext.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/PresentationContext.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2010 IBM Corporation and others.
+ * Copyright (c) 2005, 2011 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
@@ -84,7 +84,6 @@ public class PresentationContext implements IPresentationContext {
* Constructs a presentation context for the given id and part.
* The presentation context id and window are derived from the part.
*
- * @param id presentation context id
* @param part presentation context part, can NOT be <code>null</code>
*/
public PresentationContext(IWorkbenchPart part) {
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/TreeModelViewer.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/TreeModelViewer.java
index af173fea2..0c26078f9 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/TreeModelViewer.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/TreeModelViewer.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2010 IBM Corporation and others.
+ * Copyright (c) 2006, 2011 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
@@ -20,7 +20,7 @@ import org.eclipse.ui.IMemento;
/**
* A tree viewer for a model.
* <p>
- * Style flags supported by this viewer are the same as for {@link TreeViewer},
+ * Style flags supported by this viewer are the same as for {@link org.eclipse.jface.viewers.TreeViewer},
* except:
* <ul>
* <li>SWT.VIRTUAL - Indicates that the viewer should be in lazy mode. This
@@ -117,7 +117,7 @@ public class TreeModelViewer extends InternalTreeModelViewer {
/**
* Initializes viewer state from the memento
*
- * @param memento
+ * @param memento the {@link IMemento} to read from
*/
public void initState(IMemento memento) {
super.initState(memento);
@@ -126,17 +126,15 @@ public class TreeModelViewer extends InternalTreeModelViewer {
/**
* Save viewer state into the given memento.
*
- * @param memento
+ * @param memento the {@link IMemento} to save to
*/
public void saveState(IMemento memento) {
super.saveState(memento);
}
- /**
- * Returns whether columns are being displayed currently.
- *
- * @return
- */
+ /**
+ * @return Returns true if columns are being displayed currently.
+ */
public boolean isShowColumns() {
return super.isShowColumns();
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/TreeModelViewerFilter.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/TreeModelViewerFilter.java
new file mode 100644
index 000000000..077938619
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/TreeModelViewerFilter.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.debug.internal.ui.viewers.model.provisional;
+
+import org.eclipse.jface.viewers.ViewerFilter;
+
+/**
+ * Viewer filter for the Tree Model Viewer which allows more efficient filtering
+ * in the lazy viewer.
+ * <p>
+ * The standard {@link ViewerFilter} class must be applied to all elements in the
+ * tree, thus forcing the lazy viewer to retrieve all children of all elements and
+ * defeating the lazy loading behavior. This class adds an {@link #isApplicable(ITreeModelViewer, Object)}
+ * method, which can be used by the filter to discern which parent elements the
+ * filter should apply to.
+ * </p>
+ *
+ * @since 3.8
+ */
+abstract public class TreeModelViewerFilter extends ViewerFilter {
+
+ /**
+ * Determines whether the filter applies to the given parent element.
+ * @return Returns true if the viewer should use the given filter on the
+ * given element.
+ */
+ abstract public boolean isApplicable(ITreeModelViewer viewer, Object parentElement);
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ViewerInputService.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ViewerInputService.java
index e24ecc3cb..f595c60c4 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ViewerInputService.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ViewerInputService.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2009 IBM Corporation and others.
+ * Copyright (c) 2007, 2011 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
@@ -18,9 +18,10 @@ import org.eclipse.debug.internal.ui.viewers.model.ViewerInputUpdate;
* Service to compute a viewer input from a source object
* for a given presentation context.
* <p>
- * This class may be instantiated. Not intended to be subclassed.
+ * This class may be instantiated, but it not intended to be sub-classed.
* </p>
* @since 3.4
+ * @noextend This class is not intended to be subclassed by clients.
*/
public class ViewerInputService {
@@ -55,8 +56,8 @@ public class ViewerInputService {
/**
* Constructs a viewer input service for the given requester and presentation context.
*
+ * @param viewer for which inputs are required
* @param requestor client requesting viewer inputs
- * @param context context for which inputs are required
*/
public ViewerInputService(TreeModelViewer viewer, IViewerInputRequestor requestor) {
fRequestor = requestor;
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/VirtualItem.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/VirtualItem.java
index 1365c5ff2..0a190b278 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/VirtualItem.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/VirtualItem.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2008, 2009 Wind River Systems and others.
+ * Copyright (c) 2011 Wind River Systems 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
@@ -8,7 +8,7 @@
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
-package org.eclipse.debug.internal.ui.viewers.model;
+package org.eclipse.debug.internal.ui.viewers.model.provisional;
import java.util.HashMap;
import java.util.Iterator;
@@ -18,20 +18,22 @@ import java.util.TreeMap;
import org.eclipse.core.runtime.Assert;
/**
- * Virtual item, which is analogous to the SWT's tree item.
+ * Virtual item, which is analogous to the SWT's tree item. This class is used
+ * by the {@link VirtualTreeModelViewer}.
*
- * @since 3.5
+ * @see VirtualTreeModelViewer
+ * @since 3.8
*/
-class VirtualItem {
+public class VirtualItem {
// Data keys for display attributes of an item.
- static String LABEL_KEY = "LABEL_KEY"; //$NON-NLS-1$
- static String IMAGE_KEY = "IMAGE_KEY"; //$NON-NLS-1$
- static String FONT_KEY = "FONT_KEY"; //$NON-NLS-1$
- static String FOREGROUND_KEY = "FOREGROUND_KEY"; //$NON-NLS-1$
- static String BACKGROUND_KEY = "BACKGROUND_KEY"; //$NON-NLS-1$
+ public static String LABEL_KEY = "LABEL_KEY"; //$NON-NLS-1$
+ public static String IMAGE_KEY = "IMAGE_KEY"; //$NON-NLS-1$
+ public static String FONT_KEY = "FONT_KEY"; //$NON-NLS-1$
+ public static String FOREGROUND_KEY = "FOREGROUND_KEY"; //$NON-NLS-1$
+ public static String BACKGROUND_KEY = "BACKGROUND_KEY"; //$NON-NLS-1$
- static String ELEMENT_DATA_KEY = "element"; //$NON-NLS-1$
+ public static String ELEMENT_DATA_KEY = "element"; //$NON-NLS-1$
/**
* Index object of a tree item. It allows the indexes to be modified
@@ -103,7 +105,7 @@ class VirtualItem {
private boolean fExpanded = false;
/**
- * The cound of child items. <code>-1</code> indicates that the count
+ * The count of child items. <code>-1</code> indicates that the count
* is not known.
*/
private int fItemCount = -1;
@@ -134,41 +136,49 @@ class VirtualItem {
*/
private boolean fDisposed = false;
-
- VirtualItem(VirtualItem parent, Index index) {
+
+ /**
+ * Virtual item constructor.
+ * @param parent parent virtual item
+ * @param index index of the item in the parent
+ */
+ public VirtualItem(VirtualItem parent, Index index) {
fParent = parent;
fIndex = index;
}
- void setNeedsCountUpdate() {
- fNeedsCountUpdate = true;
- fItemCount = -1;
- }
-
- void setNeedsLabelUpdate() {
- fNeedsLabelUpdate = true;
- }
-
- void setNeedsDataUpdate() {
- fNeedsDataUpdate = true;
- }
-
- void clear(Index index) {
+ /**
+ * Clears the child item at the given index.
+ * @param index index of item to clear.
+ */
+ public void clear(Index index) {
VirtualItem item = (VirtualItem)fItems.remove(index);
if (item != null) {
item.dispose();
}
}
- VirtualItem getParent() {
+ /**
+ * Returns the parent item.
+ * @return parent item.
+ */
+ public VirtualItem getParent() {
return fParent;
}
- Index getIndex() {
+ /**
+ * @return Returns the index of this item.
+ */
+ public Index getIndex() {
return fIndex;
}
- VirtualItem findItem(Object element) {
+ /**
+ * Finds the given item in the child items of this element.
+ * @param element Data object of the item to be found.
+ * @return Item if found, <code>null</code> if not.
+ */
+ public VirtualItem findItem(Object element) {
for (Iterator itr = fItems.values().iterator(); itr.hasNext();) {
VirtualItem next = (VirtualItem)itr.next();
Object nextData = next.getData();
@@ -179,35 +189,81 @@ class VirtualItem {
return null;
}
- boolean needsDataUpdate() {
+ /**
+ * @return Returns whether the data element of this item is stale.
+ */
+ public boolean needsDataUpdate() {
return fNeedsDataUpdate;
}
- void clearNeedsDataUpdate() {
+ /**
+ * Marks the item as having a stale data item.
+ */
+ public void setNeedsDataUpdate() {
+ fNeedsDataUpdate = true;
+ }
+
+ /**
+ * Clears the stale status of the item's data element.
+ */
+ public void clearNeedsDataUpdate() {
fNeedsDataUpdate = false;
}
- boolean needsCountUpdate() {
+ /**
+ * @return Returns whether the item has stale item count.
+ */
+ public boolean needsCountUpdate() {
return fNeedsCountUpdate;
}
+
+ /**
+ * Marks the item as having a stale child count.
+ */
+ public void setNeedsCountUpdate() {
+ fNeedsCountUpdate = true;
+ fItemCount = -1;
+ }
- void clearNeedsCountUpdate() {
+ /**
+ * Clears the stale status of the item's child count.
+ */
+ public void clearNeedsCountUpdate() {
fNeedsCountUpdate = false;
}
- boolean needsLabelUpdate() {
+ /**
+ * @return Returns whether the item has stale label.
+ */
+ public boolean needsLabelUpdate() {
return fNeedsLabelUpdate;
}
- void clearNeedsLabelUpdate() {
+ /**
+ * Marks the item as having a stale label data.
+ */
+ public void setNeedsLabelUpdate() {
+ fNeedsLabelUpdate = true;
+ }
+
+ /**
+ * Clears the stale status of the item's label.
+ */
+ public void clearNeedsLabelUpdate() {
fNeedsLabelUpdate = false;
}
- boolean isDisposed() {
+ /**
+ * @return Returns whether the item has been disposed.
+ */
+ public boolean isDisposed() {
return fDisposed;
}
- void dispose() {
+ /**
+ * Disposes the item.
+ */
+ public void dispose() {
fData.clear();
for (Iterator itr = fItems.values().iterator(); itr.hasNext();) {
((VirtualItem)itr.next()).dispose();
@@ -218,23 +274,43 @@ class VirtualItem {
findTree().fireItemDisposed(this);
}
- Object getData (String key) {
+ /**
+ * @param key Key to retrieve data for.
+ * @return Returns item data corresponding to given key.
+ */
+ public Object getData (String key) {
return fData.get(key);
}
- void setData(String key, Object data) {
+ /**
+ * Sets given data element for given key.
+ * @param key Key for data.
+ * @param data Data value.
+ */
+ public void setData(String key, Object data) {
fData.put(key, data);
}
- void setData(Object data) {
+ /**
+ * Sets the item's data element.
+ * @param data Item's new element.
+ */
+ public void setData(Object data) {
fData.put(ELEMENT_DATA_KEY, data);
}
- Object getData () {
+ /**
+ * @return Returns item's data element.
+ */
+ public Object getData () {
return fData.get(ELEMENT_DATA_KEY);
}
-
- void setExpanded(boolean expanded) {
+
+ /**
+ * Marks the given item as expanded or collapsed.
+ * @param expanded If true, item will be marked as expanded.
+ */
+ public void setExpanded(boolean expanded) {
if (fExpanded == expanded) {
return;
}
@@ -255,11 +331,18 @@ class VirtualItem {
}
}
- boolean getExpanded() {
+ /**
+ * @return Returns item's expanded state.
+ */
+ public boolean getExpanded() {
return fExpanded;
}
- void setHasItems(boolean hasChildren) {
+ /**
+ * Sets the flag indicating whether item has child items.
+ * @param hasChildren Set to true if child has items.
+ */
+ public void setHasItems(boolean hasChildren) {
fHasItems = hasChildren;
if (!fHasItems) {
if (getItemCount() != 0) {
@@ -270,11 +353,18 @@ class VirtualItem {
}
}
- boolean hasItems() {
+ /**
+ * @return Returns true if item has child items.
+ */
+ public boolean hasItems() {
return fHasItems;
}
- void setItemCount(int count) {
+ /**
+ * Sets the item's child count.
+ * @param count Child count.
+ */
+ public void setItemCount(int count) {
fItemCount = count;
for (Iterator itr = fItems.entrySet().iterator(); itr.hasNext();) {
Map.Entry entry = (Map.Entry)itr.next();
@@ -299,11 +389,20 @@ class VirtualItem {
}
}
- int getItemCount() {
+ /**
+ * @return Returns item's child count.
+ */
+ public int getItemCount() {
return fItemCount;
}
- VirtualItem getItem(Index index) {
+ /**
+ * Returns the child item at given index. Child item is created if needed.
+ *
+ * @param index Index of the child item.
+ * @return Child item.
+ */
+ public VirtualItem getItem(Index index) {
ensureItems();
VirtualItem item = (VirtualItem)fItems.get(index);
@@ -314,7 +413,10 @@ class VirtualItem {
return item;
}
- boolean childrenNeedDataUpdate() {
+ /**
+ * @return Returns true if any of the child items need a data update.
+ */
+ public boolean childrenNeedDataUpdate() {
if (getItemCount() == 0) {
return false;
}
@@ -330,11 +432,23 @@ class VirtualItem {
return false;
}
- VirtualItem[] getItems() {
+ /**
+ * Returns an array of current child items. The returned array contains
+ * only the items that have been created. It may not contain as many items as the
+ * item count.
+ *
+ * @return Child items array.
+ */
+ public VirtualItem[] getItems() {
return (VirtualItem[]) fItems.values().toArray(new VirtualItem[fItems.size()]);
}
- VirtualItem addItem(int position) {
+ /**
+ * Adds a child item at the given index position.
+ * @param position The index position to inser the new item at.
+ * @return Returns the added item.
+ */
+ public VirtualItem addItem(int position) {
if (!fHasItems) {
fHasItems = true;
}
@@ -360,7 +474,11 @@ class VirtualItem {
return newChild;
}
- void remove(Index position) {
+ /**
+ * Removes the item at the given index.
+ * @param position Index of the item to remove.
+ */
+ public void remove(Index position) {
fItemCount--;
if (fItemCount < 0) {
fHasItems = false;
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/VirtualTree.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/VirtualTree.java
index 9cd993390..661a1ea76 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/VirtualTree.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/VirtualTree.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2008, 2009 Wind River Systems and others.
+ * Copyright (c) 2011 Wind River Systems 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
@@ -8,7 +8,7 @@
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
-package org.eclipse.debug.internal.ui.viewers.model;
+package org.eclipse.debug.internal.ui.viewers.model.provisional;
import java.util.HashSet;
import java.util.Iterator;
@@ -18,11 +18,13 @@ import org.eclipse.swt.SWT;
/**
- * Tree of virtual items that is analogous to SWT's tree control.
+ * Tree of virtual items that is analogous to SWT's tree control. The tree is used
+ * by the {@link VirtualTreeModelViewer}.
*
- * @since 3.5
+ * @see VirtualTreeModelViewer
+ * @since 3.8
*/
-class VirtualTree extends VirtualItem {
+public class VirtualTree extends VirtualItem {
/**
* Lazy virtual tree does not retrieve elements or labels,
@@ -30,33 +32,25 @@ class VirtualTree extends VirtualItem {
*/
private boolean fLazy;
- /**
- * The item currently at the top of the "virtual" view-port.
- */
- private VirtualItem fTopItem;
+ private IVirtualItemValidator fValidator;
- /**
- * Interface for listeners that need to be notified when items
- * are disposed or revealed. It should be implemented by the viewer.
- */
- public static interface IVirtualItemListener {
-
- /**
- * Called when the item has been shown in the virtual viewer's
- * view-port. This indicates to the viewer that it should check
- * the item's status and request needed data.
- *
- * @param item The item that was revealed.
- */
- public void revealed(VirtualItem item);
+ private class SelectedItemValidator implements IVirtualItemValidator {
+ public boolean isItemVisible(VirtualItem item) {
+ // visible items. For now only mark the selected items as visible.
+ for (int i = 0; i < fSelection.length; i++) {
+ VirtualItem selectionItem = fSelection[i];
+ while (selectionItem != null) {
+ if (item.equals(selectionItem)) {
+ return true;
+ }
+ selectionItem = selectionItem.getParent();
+ }
+ }
+ return false;
+ }
- /**
- * Called when an item is disposed. It tells the viewer to
- * clean up any remaining mappings and cached data of this item.
- *
- * @param item The itam that was disposed.
- */
- public void disposed(VirtualItem item);
+ public void showItem(VirtualItem item) {
+ }
}
/**
@@ -70,83 +64,95 @@ class VirtualTree extends VirtualItem {
*/
private VirtualItem[] fSelection = new VirtualItem[0];
- VirtualTree(int style) {
+ /**
+ * Constructs the virtual tree with the given style and validator.
+ *
+ * @param style The style flag. Only SWT.VIRTUAL flag is used.
+ * @param validator Item validator used to determine item visibility.
+ */
+ public VirtualTree(int style, IVirtualItemValidator validator) {
super(null, new VirtualItem.Index(0));
fLazy = (style & SWT.VIRTUAL) != 0;
+ if (fLazy && validator == null) {
+ fValidator = new SelectedItemValidator();
+ } else {
+ fValidator = validator;
+ }
clearNeedsLabelUpdate();
clearNeedsDataUpdate();
}
- void dispose() {
+ /**
+ * Disposes the virtual tree.
+ */
+ public void dispose() {
super.dispose();
fVirtualItemListeners.clear();
}
- void setNeedsCountUpdate() {
+ public void setNeedsCountUpdate() {
super.setNeedsCountUpdate();
clearNeedsLabelUpdate();
clearNeedsDataUpdate();
}
- void setNeedsLabelUpdate() {
+ public void setNeedsLabelUpdate() {
// no-op
}
- void setData(String key, Object data) {
+ public void setData(String key, Object data) {
super.setData(key, data);
if (data == null) {
clearNeedsDataUpdate();
}
}
- void addItemListener(IVirtualItemListener listener) {
+ /**
+ * Adds a listener for when virtual items are revealed in the view.
+ * @param listener Listener to add to list of listeners.
+ */
+ public void addItemListener(IVirtualItemListener listener) {
fVirtualItemListeners.add(listener);
}
- void removeItemListener(IVirtualItemListener listener) {
+ public void removeItemListener(IVirtualItemListener listener) {
fVirtualItemListeners.remove(listener);
}
- VirtualItem[] getSelection() {
+ public VirtualItem[] getSelection() {
return fSelection;
}
- void setSelection(VirtualItem[] items) {
+ public void setSelection(VirtualItem[] items) {
fSelection = items;
}
- void showItem(VirtualItem item) {
- setTopItem(item);
+ public void showItem(VirtualItem item) {
+ if (fValidator != null) {
+ fValidator.showItem(item);
+ }
}
- void fireItemDisposed(VirtualItem item) {
+ public void fireItemDisposed(VirtualItem item) {
for (Iterator itr = fVirtualItemListeners.iterator(); itr.hasNext();) {
((IVirtualItemListener)itr.next()).disposed(item);
}
}
- void fireItemRevealed(VirtualItem item) {
+ public void fireItemRevealed(VirtualItem item) {
for (Iterator itr = fVirtualItemListeners.iterator(); itr.hasNext();) {
((IVirtualItemListener)itr.next()).revealed(item);
}
}
- void setData(Object data) {
+ public void setData(Object data) {
super.setData(data);
// The root item always has children as long as the input is non-null,
// so that it should be expanded.
setHasItems(data != null);
}
- void setTopItem(VirtualItem item) {
- fTopItem = item;
- }
-
- VirtualItem getTopItem() {
- return fTopItem;
- }
-
- void setHasItems(boolean hasChildren) {
+ public void setHasItems(boolean hasChildren) {
super.setHasItems(hasChildren);
// The root item is always expanded as long as it has children.
if (hasChildren) {
@@ -154,30 +160,25 @@ class VirtualTree extends VirtualItem {
}
}
- boolean isItemVisible(VirtualItem item) {
- if (!fLazy) {
- // If not in lazy mode, all items are visible.
- return true;
- } else {
- // TODO: use top item and visible item count to determine list of
- // visible items. For now only mark the selected items as visible.
- for (int i = 0; i < fSelection.length; i++) {
- VirtualItem selectionItem = fSelection[i];
- while (selectionItem != null) {
- if (item.equals(selectionItem)) {
- return true;
- }
- selectionItem = selectionItem.getParent();
- }
- }
- return false;
+ /**
+ * Returns whether the given item is considered visible by the tree as
+ * determined by its virtual item validator.
+ *
+ * @param item Item to check.
+ * @return true if items is vislble.
+ * @see IVirtualItemValidator
+ */
+ public boolean isItemVisible(VirtualItem item) {
+ if (fLazy) {
+ return fValidator.isItemVisible(item);
}
+ return true;
}
/**
* Validates the entire tree.
*/
- void validate() {
+ public void validate() {
validate(VirtualTree.this);
}
@@ -187,7 +188,7 @@ class VirtualTree extends VirtualItem {
*
* @param item The item which to validate.
*/
- void validate(VirtualItem item) {
+ public void validate(VirtualItem item) {
if (item.needsDataUpdate()) {
if (isItemVisible(item)) {
fireItemRevealed(item);
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/VirtualTreeModelViewer.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/VirtualTreeModelViewer.java
index 7db158ddb..1b57cb020 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/VirtualTreeModelViewer.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/VirtualTreeModelViewer.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2008, 2010 Wind River Systems and others.
+ * Copyright (c) 2008, 2011 Wind River Systems 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
@@ -31,15 +31,37 @@ import org.eclipse.ui.IMemento;
* </ul>
* </p>
* @since 3.5
- * @noextend
+ * @noextend This class is not intended to be sub-classed by clients.
*/
public class VirtualTreeModelViewer extends InternalVirtualTreeModelViewer {
+ /**
+ * Creates a virtual tree model viewer.
+ * @param display Display used by the viewer to call the data providers
+ * on the UI thread.
+ * @param style Stlye flags.
+ * @param context Viewer's presentation context.
+ */
public VirtualTreeModelViewer(Display display, int style, IPresentationContext context) {
- super(display, style, context);
+ super(display, style, context, null);
}
+ /**
+ * Creates a virtual tree model viewer.
+ * @param display Display used by the viewer to call the data providers
+ * on the UI thread.
+ * @param style style flags.
+ * @param context Viewer's presentation context.
+ * @param validator Optional validator that is used to determine which items should be
+ * considered visible when SWT.VIRTUAL style is used. If <code>null</code> then the
+ * standard validator is used that updates only the selected items.
+ *
+ * @since 3.8
+ */
+ public VirtualTreeModelViewer(Display display, int style, IPresentationContext context, IVirtualItemValidator validator) {
+ super(display, style, context, validator);
+ }
/**
* Returns this viewer's presentation context.
@@ -119,7 +141,7 @@ public class VirtualTreeModelViewer extends InternalVirtualTreeModelViewer {
/**
* Initializes viewer state from the memento
*
- * @param memento
+ * @param memento the {@link IMemento} to read from
*/
public void initState(IMemento memento) {
super.initState(memento);
@@ -128,17 +150,15 @@ public class VirtualTreeModelViewer extends InternalVirtualTreeModelViewer {
/**
* Save viewer state into the given memento.
*
- * @param memento
+ * @param memento the {@link IMemento} to save to
*/
public void saveState(IMemento memento) {
super.saveState(memento);
}
/**
- * Returns whether columns are being displayed currently.
- *
- * @return
- */
+ * @return Returns true if columns are being displayed currently.
+ */
public boolean isShowColumns() {
return super.isShowColumns();
}
@@ -172,4 +192,15 @@ public class VirtualTreeModelViewer extends InternalVirtualTreeModelViewer {
public ViewerLabel getElementLabel(TreePath path, String columnId) {
return super.getElementLabel(path, columnId);
}
+
+ public VirtualItem[] findItems(Object elementOrTreePath) {
+ return super.findItems(elementOrTreePath);
+ }
+
+ public VirtualItem findItem(TreePath path) {
+ return super.findItem(path);
+ }
+
+
+
}
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 e3da944d9..9d944ad27 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
@@ -10,15 +10,20 @@
*******************************************************************************/
package org.eclipse.debug.internal.ui.viewers.provisional;
+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.Platform;
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.viewers.model.provisional.IModelChangedListener;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy2;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer;
import org.eclipse.jface.viewers.Viewer;
/**
@@ -28,12 +33,15 @@ import org.eclipse.jface.viewers.Viewer;
* </p>
* @since 3.2
*/
-public abstract class AbstractModelProxy implements IModelProxy {
+public abstract class AbstractModelProxy implements IModelProxy2 {
private IPresentationContext fContext;
- private Viewer fViewer;
+ private boolean fInstalled = false;
+ private ITreeModelViewer fViewer;
private boolean fDisposed = false;
-
+ private Job fInstallJob;
+
+
private ListenerList fListeners = new ListenerList();
// debug flags
@@ -74,6 +82,10 @@ public abstract class AbstractModelProxy implements IModelProxy {
* @param delta model delta to broadcast
*/
public void fireModelChanged(IModelDelta delta) {
+ synchronized(this) {
+ if (!fInstalled || fDisposed) return;
+ }
+
final IModelDelta root = getRootDelta(delta);
Object[] listeners = getListeners();
for (int i = 0; i < listeners.length; i++) {
@@ -111,16 +123,58 @@ public abstract class AbstractModelProxy implements IModelProxy {
* @see org.eclipse.debug.internal.ui.viewers.IModelProxy#dispose()
*/
public synchronized void dispose() {
+ if (fInstallJob != null) {
+ fInstallJob.cancel();
+ fInstallJob = null;
+ }
fDisposed = true;
fContext = null;
fViewer = null;
}
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.ui.viewers.IModelProxy#init(org.eclipse.debug.internal.ui.viewers.IPresentationContext)
- */
- public void init(IPresentationContext context) {
- fContext = context;
+ protected synchronized void setInstalled(boolean installed) {
+ fInstalled = installed;
+ }
+
+ protected synchronized boolean isInstalled() {
+ return fInstalled;
+ }
+
+ protected synchronized void setDisposed(boolean disposed) {
+ fDisposed = disposed;
+ }
+
+ public void initialize(ITreeModelViewer viewer) {
+ setDisposed(false);
+
+ synchronized(this) {
+ fViewer = viewer;
+ fContext = viewer.getPresentationContext();
+ fInstallJob = new Job("Model Proxy installed notification job") {//$NON-NLS-1$
+ protected IStatus run(IProgressMonitor monitor) {
+ synchronized(this) {
+ fInstallJob = null;
+ }
+ if (!monitor.isCanceled()) {
+ init(getTreeModelViewer().getPresentationContext());
+ setInstalled(true);
+ installed(getViewer());
+ }
+ return Status.OK_STATUS;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.core.runtime.jobs.Job#shouldRun()
+ */
+ public boolean shouldRun() {
+ return !isDisposed();
+ }
+ };
+ fInstallJob.setSystem(true);
+ }
+ fInstallJob.schedule();
}
/**
@@ -129,18 +183,23 @@ public abstract class AbstractModelProxy implements IModelProxy {
* @return presentation context, or <code>null</code> if this
* model proxy has been disposed
*/
- public IPresentationContext getPresentationContext() {
+ public synchronized IPresentationContext getPresentationContext() {
return fContext;
}
/* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.IModelProxy#init(org.eclipse.debug.internal.ui.viewers.IPresentationContext)
+ */
+ public void init(IPresentationContext context) {
+ }
+
+ /* (non-Javadoc)
*
* Subclasses should override as required.
*
* @see org.eclipse.debug.internal.ui.viewers.provisional.IModelProxy#installed(org.eclipse.jface.viewers.Viewer)
*/
public void installed(Viewer viewer) {
- fViewer = viewer;
}
/**
@@ -149,8 +208,17 @@ public abstract class AbstractModelProxy implements IModelProxy {
* @return viewer or <code>null</code> if not installed
*/
protected Viewer getViewer() {
- return fViewer;
+ return (Viewer)fViewer;
}
+
+ /**
+ * Returns the viewer this proxy is installed in.
+ *
+ * @return viewer or <code>null</code> if not installed
+ */
+ protected ITreeModelViewer getTreeModelViewer() {
+ return fViewer;
+ }
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy#isDisposed()
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsView.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsView.java
index 131a58c7b..10e6855e4 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsView.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsView.java
@@ -69,9 +69,9 @@ import org.eclipse.debug.internal.ui.breakpoints.provisional.IBreakpointOrganize
import org.eclipse.debug.internal.ui.breakpoints.provisional.IBreakpointUIConstants;
import org.eclipse.debug.internal.ui.elements.adapters.DefaultBreakpointsViewInput;
import org.eclipse.debug.internal.ui.preferences.IDebugPreferenceConstants;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener;
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 c3a97a3ed..6234f3208 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
@@ -532,7 +532,7 @@ public class LaunchView extends AbstractDebugView
fAddToFavoritesAction = new AddToFavoritesAction();
fEditSourceAction = new EditSourceLookupPathAction(this);
fLookupAction = new LookupSourceAction(this);
- setAction(FIND_ACTION, new VirtualFindAction((InternalTreeModelViewer) getViewer()));
+ setAction(FIND_ACTION, new VirtualFindAction((TreeModelViewer) getViewer()));
addCapabilityAction(new TerminateCommandAction(), TERMINATE);
addCapabilityAction(new DisconnectCommandAction(), DISCONNECT);
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/launch/LaunchViewCopyToClipboardActionDelegate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/launch/LaunchViewCopyToClipboardActionDelegate.java
index bcd222e33..b4c203002 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/launch/LaunchViewCopyToClipboardActionDelegate.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/launch/LaunchViewCopyToClipboardActionDelegate.java
@@ -12,6 +12,7 @@ package org.eclipse.debug.internal.ui.views.launch;
import org.eclipse.debug.internal.ui.viewers.model.InternalTreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.VirtualCopyToClipboardActionDelegate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.jface.viewers.TreePath;
@@ -24,7 +25,7 @@ import org.eclipse.swt.widgets.Widget;
*/
public class LaunchViewCopyToClipboardActionDelegate extends VirtualCopyToClipboardActionDelegate {
- protected TreeItem[] getPrunedSelection() {
+ protected TreeItem[] getSelectedItems(TreeModelViewer clientViewer) {
LaunchView view = (LaunchView)getView();
if (view.isBreadcrumbVisible()) {
ISelection selection = getSelection();
@@ -33,15 +34,15 @@ public class LaunchViewCopyToClipboardActionDelegate extends VirtualCopyToClipbo
if (!selection.isEmpty()) {
path = ((ITreeSelection)selection).getPaths()[0];
}
- return getSelectedItems((InternalTreeModelViewer)getViewer(), path);
+ return getSelectedItemsInTreeViewer((TreeModelViewer)getViewer(), path);
}
return new TreeItem[0];
} else {
- return super.getPrunedSelection();
+ return super.getSelectedItems(clientViewer);
}
}
- private TreeItem[] getSelectedItems(InternalTreeModelViewer viewer, TreePath path) {
+ private TreeItem[] getSelectedItemsInTreeViewer(TreeModelViewer viewer, TreePath path) {
Widget item = viewer.findItem(path);
if (item instanceof TreeItem) {
return new TreeItem[] { (TreeItem)item };

Back to the top