Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/CheckTests.java6
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/ChildrenUpdateTests.java45
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/ContentTests.java11
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/DeltaTests.java64
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/FilterTests.java432
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/ITestModelUpdatesListenerConstants.java14
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerCheckTests.java4
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerContentTests.java4
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerDeltaTests.java4
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerFilterTests.java32
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerLazyTests.java4
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerPerformanceTests.java4
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerPopupTests.java2
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerSelectionTests.java2
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerStateTests.java2
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerTopIndexTests.java10
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerUpdateTests.java2
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/LazyTests.java16
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/PerformanceTests.java176
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/PopupTests.java14
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/SelectionTests.java2
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/StateTests.java351
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/TestModel.java177
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/TestModelUpdatesListener.java204
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/UpdateTests.java224
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerContentTests.java4
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerDeltaTests.java4
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerFilterTests.java32
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerLazyModeTests.java2
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerPerformanceTests.java4
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerPopupTests.java2
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerSelectionTests.java2
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerStateTests.java2
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerUpdateTests.java2
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VisibleVirtualItemValidator.java95
-rw-r--r--org.eclipse.debug.tests/src/org/eclipse/debug/tests/AutomatedSuite.java2
-rw-r--r--org.eclipse.debug.tests/src/org/eclipse/debug/tests/LocalSuite.java2
-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
100 files changed, 6854 insertions, 5712 deletions
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/CheckTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/CheckTests.java
index 4532a81d8..435827411 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/CheckTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/CheckTests.java
@@ -14,8 +14,8 @@ import junit.framework.TestCase;
import org.eclipe.debug.tests.viewer.model.TestModel.TestElement;
import org.eclipse.core.commands.ExecutionException;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelContentProviderTarget;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.IInternalTreeModelViewer;
+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.swt.layout.FillLayout;
@@ -57,7 +57,7 @@ abstract public class CheckTests extends TestCase {
fShell.open ();
}
- abstract protected ITreeModelContentProviderTarget createViewer(Display display, Shell shell);
+ abstract protected IInternalTreeModelViewer createViewer(Display display, Shell shell);
/**
* @throws java.lang.Exception
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/ChildrenUpdateTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/ChildrenUpdateTests.java
index 4095eeff2..290f21f07 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/ChildrenUpdateTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/ChildrenUpdateTests.java
@@ -15,7 +15,7 @@ import junit.framework.TestCase;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.viewers.model.ChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.ILabelUpdateListener;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelContentProviderTarget;
+import org.eclipse.debug.internal.ui.viewers.model.IInternalTreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.TreeModelContentProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelChangedListener;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
@@ -23,11 +23,14 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationCont
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.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.viewers.ViewerLabel;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Display;
/**
@@ -42,8 +45,8 @@ public class ChildrenUpdateTests extends TestCase {
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.model.ModelContentProvider#getViewer()
*/
- protected ITreeModelContentProviderTarget getViewer() {
- return new ITreeModelContentProviderTarget(){
+ protected IInternalTreeModelViewer getViewer() {
+ return new IInternalTreeModelViewer(){
public void setSelection(ISelection selection) {}
public void removeSelectionChangedListener(ISelectionChangedListener listener) {}
@@ -113,7 +116,10 @@ public class ChildrenUpdateTests extends TestCase {
public ViewerFilter[] getFilters() {
return null;
}
-
+
+ public void addFilter(ViewerFilter filter) {}
+ public void setFilters(ViewerFilter[] filters) {}
+
public boolean getExpandedState(Object elementOrTreePath) {
return false;
}
@@ -143,6 +149,27 @@ public class ChildrenUpdateTests extends TestCase {
public boolean getElementChildrenRealized(TreePath parentPath) {
return false;
}
+
+ public boolean getElementChecked(TreePath path) {
+ return false;
+ }
+
+ public boolean getElementGrayed(TreePath path) {
+ return false;
+ }
+
+ public void setElementChecked(TreePath path, boolean checked, boolean grayed) {
+ }
+
+ public TreePath[] getElementPaths(Object element) {
+ return null;
+ }
+ public void setElementData(TreePath path, int numColumns, String[] labels, ImageDescriptor[] images,
+ FontData[] fontDatas, RGB[] foregrounds, RGB[] backgrounds) {
+ }
+ public String[] getVisibleColumns() {
+ return null;
+ }
};
}
}
@@ -164,23 +191,23 @@ public class ChildrenUpdateTests extends TestCase {
public void testCoalesce () {
Object element = new Object();
TreeModelContentProvider cp = getContentProvider();
- ChildrenUpdate update1 = new ChildrenUpdate(cp, element, TreePath.EMPTY, element, 1, null, null);
- ChildrenUpdate update2 = new ChildrenUpdate(cp, element, TreePath.EMPTY, element, 2, null, null);
+ ChildrenUpdate update1 = new ChildrenUpdate(cp, element, TreePath.EMPTY, element, 1, null);
+ ChildrenUpdate update2 = new ChildrenUpdate(cp, element, TreePath.EMPTY, element, 2, null);
assertTrue("Should coalesce", update1.coalesce(update2));
assertEquals("Wrong offset", 1, update1.getOffset());
assertEquals("Wrong length", 2, update1.getLength());
- update2 = new ChildrenUpdate(cp, element, TreePath.EMPTY, element, 3, null, null);
+ update2 = new ChildrenUpdate(cp, element, TreePath.EMPTY, element, 3, null);
assertTrue("Should coalesce", update1.coalesce(update2));
assertEquals("Wrong offset", 1, update1.getOffset());
assertEquals("Wrong length", 3, update1.getLength());
- update2 = new ChildrenUpdate(cp, element, TreePath.EMPTY, element, 2, null, null);
+ update2 = new ChildrenUpdate(cp, element, TreePath.EMPTY, element, 2, null);
assertTrue("Should coalesce", update1.coalesce(update2));
assertEquals("Wrong offset", 1, update1.getOffset());
assertEquals("Wrong length", 3, update1.getLength());
- update2 = new ChildrenUpdate(cp, element, TreePath.EMPTY, element, 5, null, null);
+ update2 = new ChildrenUpdate(cp, element, TreePath.EMPTY, element, 5, null);
assertFalse("Should not coalesce", update1.coalesce(update2));
assertEquals("Wrong offset", 1, update1.getOffset());
assertEquals("Wrong length", 3, update1.getLength());
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/ContentTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/ContentTests.java
index 0725b1fd3..4eb52e6f7 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/ContentTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/ContentTests.java
@@ -19,12 +19,12 @@ import junit.framework.TestCase;
import org.eclipe.debug.tests.viewer.model.TestModel.TestElement;
import org.eclipse.core.commands.ExecutionException;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelContentProviderTarget;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.IInternalTreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ICheckUpdate;
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.ITreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.swt.layout.FillLayout;
@@ -65,7 +65,7 @@ abstract public class ContentTests extends TestCase implements ITestModelUpdates
fShell.open ();
}
- abstract protected ITreeModelContentProviderTarget createViewer(Display display, Shell shell);
+ abstract protected IInternalTreeModelViewer createViewer(Display display, Shell shell);
/**
* @throws java.lang.Exception
@@ -107,6 +107,8 @@ abstract public class ContentTests extends TestCase implements ITestModelUpdates
while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
model.validateData(fViewer, TreePath.EMPTY);
+
+ Assert.assertTrue( fListener.checkCoalesced(TreePath.EMPTY, 0, 6) );
}
public void testSimpleMultiLevel() throws InterruptedException {
@@ -122,6 +124,8 @@ abstract public class ContentTests extends TestCase implements ITestModelUpdates
while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
model.validateData(fViewer, TreePath.EMPTY);
+
+ Assert.assertTrue( fListener.checkCoalesced(TreePath.EMPTY, 0, 3) );
}
/**
@@ -342,5 +346,4 @@ abstract public class ContentTests extends TestCase implements ITestModelUpdates
}
return expectedChildren.isEmpty();
}
-
}
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/DeltaTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/DeltaTests.java
index d78e9367d..e53f17bdc 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/DeltaTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/DeltaTests.java
@@ -18,9 +18,9 @@ import junit.framework.TestCase;
import org.eclipe.debug.tests.viewer.model.TestModel.TestElement;
import org.eclipse.core.commands.ExecutionException;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelContentProviderTarget;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.IInternalTreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+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.ISelection;
import org.eclipse.jface.viewers.ITreeSelection;
@@ -61,7 +61,7 @@ abstract public class DeltaTests extends TestCase implements ITestModelUpdatesLi
fShell.open ();
}
- abstract protected ITreeModelContentProviderTarget createViewer(Display display, Shell shell);
+ abstract protected IInternalTreeModelViewer createViewer(Display display, Shell shell);
/**
* @throws java.lang.Exception
@@ -189,6 +189,38 @@ abstract public class DeltaTests extends TestCase implements ITestModelUpdatesLi
model.validateData(fViewer, TreePath.EMPTY);
}
+ public void testRefreshCoalesceStruct() throws InterruptedException {
+ //TreeModelViewerAutopopulateAgent autopopulateAgent = new TreeModelViewerAutopopulateAgent(fViewer);
+
+ // Create a single level model and add a single child to each element.
+ TestModel model = TestModel.simpleSingleLevel();
+ TestElement[] rootChildren = model.getRootElement().getChildren();
+ for (int i = 0; i < rootChildren.length; i++) {
+ model.setElementChildren(
+ new TreePath(new Object[] { rootChildren[i]} ),
+ new TestElement[] { new TestElement(model, i + ".1", new TestElement[0]) });
+ }
+
+ fViewer.setAutoExpandLevel(-1);
+
+ // Create the listener
+ fListener.reset(TreePath.EMPTY, model.getRootElement(), -1, true, false);
+
+ // Set the input into the view and update the view.
+ fViewer.setInput(model.getRootElement());
+ while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ model.validateData(fViewer, TreePath.EMPTY);
+
+ fListener.reset(TreePath.EMPTY, model.getRootElement(), -1, false, false);
+ model.postDelta(new ModelDelta(model.getRootElement(), IModelDelta.CONTENT));
+ while (!fListener.isFinished(ALL_UPDATES_COMPLETE | MODEL_CHANGED_COMPLETE))
+ if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+
+ model.validateData(fViewer, TreePath.EMPTY);
+ Assert.assertTrue( fListener.checkCoalesced(TreePath.EMPTY, 0, 6) );
+ }
+
+
public void testInsert() throws InterruptedException {
//TreeModelViewerAutopopulateAgent autopopulateAgent = new TreeModelViewerAutopopulateAgent(fViewer);
@@ -378,12 +410,12 @@ abstract public class DeltaTests extends TestCase implements ITestModelUpdatesLi
fListener.reset();
fListener.setFailOnRedundantUpdates(false);
model.postDelta(rootDelta);
- while (!fListener.isFinished(MODEL_CHANGED_COMPLETE | CONTENT_UPDATES_COMPLETE))
+ while (!fListener.isFinished(MODEL_CHANGED_COMPLETE | CONTENT_SEQUENCE_COMPLETE))
if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
// Update the elements that were added.
fListener.reset();
- fListener.addUpdates((ITreeModelContentProviderTarget)fViewer, TreePath.EMPTY, model.getRootElement(), -1, ALL_UPDATES_COMPLETE);
+ fListener.addUpdates((IInternalTreeModelViewer)fViewer, TreePath.EMPTY, model.getRootElement(), -1, ALL_UPDATES_COMPLETE);
rootDelta = new ModelDelta(model.getRootElement(), IModelDelta.CONTENT);
model.getElementDelta(rootDelta, model.findElement("1.1"), true).setFlags(IModelDelta.CONTENT);
model.getElementDelta(rootDelta, model.findElement("1.2"), true).setFlags(IModelDelta.CONTENT);
@@ -395,9 +427,9 @@ abstract public class DeltaTests extends TestCase implements ITestModelUpdatesLi
if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
fListener.reset(parentPath, model.getElement(parentPath), 1, false, true);
- ((ITreeModelContentProviderTarget)fViewer).expandToLevel(parentPath, 1);
+ ((IInternalTreeModelViewer)fViewer).expandToLevel(parentPath, 1);
- while (fListener.isFinished(CONTENT_UPDATES_STARTED) && !fListener.isFinished(CONTENT_UPDATES_COMPLETE))
+ while (fListener.isFinished(CONTENT_SEQUENCE_STARTED) && !fListener.isFinished(CONTENT_SEQUENCE_COMPLETE))
if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
model.validateData(fViewer, parentPath);
@@ -421,17 +453,17 @@ abstract public class DeltaTests extends TestCase implements ITestModelUpdatesLi
// Expand elment "2"
TreePath parentPath = model.findElement("2");
fListener.reset(parentPath, model.getElement(parentPath), 1, false, true);
- ((ITreeModelContentProviderTarget)fViewer).expandToLevel(parentPath, 1);
+ ((IInternalTreeModelViewer)fViewer).expandToLevel(parentPath, 1);
- while (fListener.isFinished(CONTENT_UPDATES_STARTED) && !fListener.isFinished(CONTENT_UPDATES_COMPLETE))
+ while (fListener.isFinished(CONTENT_SEQUENCE_STARTED) && !fListener.isFinished(CONTENT_SEQUENCE_COMPLETE))
if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
// Collapse back element "2"
- ((ITreeModelContentProviderTarget)fViewer).setExpandedState(parentPath, false);
+ ((IInternalTreeModelViewer)fViewer).setExpandedState(parentPath, false);
// Update the children of element "2".
fListener.reset();
- fListener.addUpdates((ITreeModelContentProviderTarget)fViewer, TreePath.EMPTY, model.getRootElement(), -1, ALL_UPDATES_COMPLETE);
+ fListener.addUpdates((IInternalTreeModelViewer)fViewer, TreePath.EMPTY, model.getRootElement(), -1, ALL_UPDATES_COMPLETE);
ModelDelta rootDelta = new ModelDelta(model.getRootElement(), IModelDelta.CONTENT);
model.getElementDelta(rootDelta, model.findElement("2.1"), true).setFlags(IModelDelta.CONTENT);
model.getElementDelta(rootDelta, model.findElement("2.2"), true).setFlags(IModelDelta.CONTENT);
@@ -443,9 +475,9 @@ abstract public class DeltaTests extends TestCase implements ITestModelUpdatesLi
// Expand back element "2"
fListener.reset(parentPath, model.getElement(parentPath), 1, false, true);
- ((ITreeModelContentProviderTarget)fViewer).expandToLevel(parentPath, 1);
+ ((IInternalTreeModelViewer)fViewer).expandToLevel(parentPath, 1);
- while (fListener.isFinished(CONTENT_UPDATES_STARTED) && !fListener.isFinished(CONTENT_UPDATES_COMPLETE))
+ while (fListener.isFinished(CONTENT_SEQUENCE_STARTED) && !fListener.isFinished(CONTENT_SEQUENCE_COMPLETE))
if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
model.validateData(fViewer, parentPath, true);
@@ -533,7 +565,7 @@ abstract public class DeltaTests extends TestCase implements ITestModelUpdatesLi
// Validate the expansion state BEFORE posting the delta.
- ITreeModelContentProviderTarget contentProviderViewer = (ITreeModelContentProviderTarget)fViewer;
+ IInternalTreeModelViewer contentProviderViewer = (IInternalTreeModelViewer)fViewer;
Assert.assertFalse(contentProviderViewer.getExpandedState(path_root_3));
Assert.assertFalse(contentProviderViewer.getExpandedState(path_root_3_2));
Assert.assertFalse(contentProviderViewer.getExpandedState(path_root_3_2_2));
@@ -588,13 +620,13 @@ abstract public class DeltaTests extends TestCase implements ITestModelUpdatesLi
// Validate the expansion state BEFORE posting the delta.
- ITreeModelContentProviderTarget contentProviderViewer = (ITreeModelContentProviderTarget)fViewer;
+ IInternalTreeModelViewer contentProviderViewer = (IInternalTreeModelViewer)fViewer;
Assert.assertFalse(contentProviderViewer.getExpandedState(path_root_3));
model.postDelta(deltaRoot);
while (true) {
if (fListener.isFinished(MODEL_CHANGED_COMPLETE)) {
- if (fListener.isFinished(CONTENT_UPDATES_COMPLETE | LABEL_UPDATES_COMPLETE) ) {
+ if (fListener.isFinished(CONTENT_SEQUENCE_COMPLETE | LABEL_SEQUENCE_COMPLETE) ) {
break;
}
}
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/FilterTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/FilterTests.java
new file mode 100644
index 000000000..46eb8e7e8
--- /dev/null
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/FilterTests.java
@@ -0,0 +1,432 @@
+/*******************************************************************************
+ * 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
+ *
+ * Copyright (c) 2009, 2011 Wind River Systems and others.
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipe.debug.tests.viewer.model;
+
+import java.util.regex.Pattern;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.eclipe.debug.tests.viewer.model.TestModel.TestElement;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.debug.internal.ui.viewers.model.IInternalTreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewerFilter;
+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.layout.FillLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Tests that verify that the viewer property retrieves all the content
+ * from the model.
+ *
+ * @since 3.8
+ */
+abstract public class FilterTests extends TestCase implements ITestModelUpdatesListenerConstants {
+
+ Display fDisplay;
+ Shell fShell;
+ ITreeModelViewer fViewer;
+ TestModelUpdatesListener fListener;
+
+ public FilterTests(String name) {
+ super(name);
+ }
+
+ /**
+ * @throws java.lang.Exception
+ */
+ protected void setUp() throws Exception {
+ fDisplay = PlatformUI.getWorkbench().getDisplay();
+ fShell = new Shell(fDisplay);
+ fShell.setMaximized(true);
+ fShell.setLayout(new FillLayout());
+
+ fViewer = createViewer(fDisplay, fShell);
+
+ fListener = new TestModelUpdatesListener(fViewer, true, true);
+
+ fShell.open ();
+ }
+
+ abstract protected IInternalTreeModelViewer createViewer(Display display, Shell shell);
+
+ /**
+ * @throws java.lang.Exception
+ */
+ protected void tearDown() throws Exception {
+ fListener.dispose();
+ fViewer.getPresentationContext().dispose();
+
+ // Close the shell and exit.
+ fShell.close();
+ while (!fShell.isDisposed()) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ }
+
+ protected void runTest() throws Throwable {
+ try {
+ super.runTest();
+ } catch (Throwable t) {
+ throw new ExecutionException("Test failed: " + t.getMessage() + "\n fListener = " + fListener.toString(), t);
+ }
+ }
+
+ protected IInternalTreeModelViewer getInternalViewer() {
+ return (IInternalTreeModelViewer)fViewer;
+ }
+
+
+ class TestViewerFilter extends ViewerFilter {
+
+ Pattern fPattern;
+ TestViewerFilter(String pattern) {
+ fPattern = Pattern.compile(pattern);
+ }
+
+
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+ if (element instanceof TestElement) {
+ TestElement te = (TestElement)element;
+ return !fPattern.matcher(te.getLabel()).find();
+ }
+
+ return true;
+ }
+ }
+
+ class TestTMVFilter extends TreeModelViewerFilter {
+ Pattern fPattern;
+ Object fParentElement;
+ TestTMVFilter(String pattern, Object parentElement) {
+ fPattern = Pattern.compile(pattern);
+ fParentElement = parentElement;
+ }
+
+ public boolean isApplicable(ITreeModelViewer viewer, Object parentElement) {
+ if (fParentElement != null) {
+ return fParentElement.equals(parentElement);
+ }
+
+ return true;
+ }
+
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+ if (element instanceof TestElement) {
+ TestElement te = (TestElement)element;
+ return !fPattern.matcher(te.getLabel()).find();
+ }
+
+ return true;
+ }
+ }
+
+ public void testSimpleSingleLevel() throws InterruptedException {
+ TestModel model = TestModel.simpleSingleLevel();
+ doTestSimpleLevel(model, new ViewerFilter[] { new TestViewerFilter("2") });
+ }
+
+ public void testSimpleSingleLevelWithTMVFilter() throws InterruptedException {
+ TestModel model = TestModel.simpleSingleLevel();
+ doTestSimpleLevel(model, new ViewerFilter[] { new TestTMVFilter("2", model.getRootElement()) });
+ }
+
+ public void testSimpleSingleLevelWithMixedFilters() throws InterruptedException {
+ TestModel model = TestModel.simpleSingleLevel();
+ doTestSimpleLevel(model, new ViewerFilter[] { new TestTMVFilter("2", model.getRootElement()), new TestViewerFilter("1") });
+ }
+
+ public void testSimpleMultiLevel() throws InterruptedException {
+ TestModel model = TestModel.simpleMultiLevel();
+ doTestSimpleLevel(model, new ViewerFilter[] { new TestViewerFilter(".1"), new TestViewerFilter(".2") });
+ }
+
+ public void testSimpleMultiLevelWithTMVFilter() throws InterruptedException {
+ TestModel model = TestModel.simpleMultiLevel();
+ doTestSimpleLevel(model, new ViewerFilter[] { new TestTMVFilter(".1", null), new TestTMVFilter(".2", null) });
+ }
+
+ public void testSimpleMultiLevelWithMixedFilters() throws InterruptedException {
+ TestModel model = TestModel.simpleMultiLevel();
+ doTestSimpleLevel(model, new ViewerFilter[] { new TestViewerFilter(".1"), new TestTMVFilter(".2", null) });
+ }
+
+ private void doTestSimpleLevel(TestModel model, ViewerFilter[] filters) throws InterruptedException {
+
+ // Make sure that all elements are expanded
+ fViewer.setAutoExpandLevel(-1);
+
+ fViewer.setFilters(filters);
+
+ // Create the listener which determines when the view is finished updating.
+ // fListener.reset(TreePath.EMPTY, model.getRootElement(), filters, -1, false, false);
+ fListener.reset(TreePath.EMPTY, model.getRootElement(), filters, -1, true, true);
+
+ // Set the viewer input (and trigger updates).
+ fViewer.setInput(model.getRootElement());
+
+ // Wait for the updates to complete.
+ while (!fListener.isFinished(ALL_UPDATES_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+
+ model.validateData(fViewer, TreePath.EMPTY, false, filters);
+ }
+
+ public void testLargeSingleLevel() throws InterruptedException {
+ doTestLargeSingleLevel(new ViewerFilter[] { new TestViewerFilter("2") });
+ }
+
+ public void testLargeSingleLevelWithTMVFilter() throws InterruptedException {
+ doTestLargeSingleLevel(new ViewerFilter[] { new TestTMVFilter("2", null) });
+ }
+
+ private void doTestLargeSingleLevel(ViewerFilter[] filters) throws InterruptedException {
+ TestModel model = new TestModel();
+ model.setRoot( new TestElement(model, "root", new TestElement[0] ) );
+ model.setElementChildren(TreePath.EMPTY, TestModel.makeSingleLevelModelElements(model, 3000, "model."));
+
+ // Set filters
+ fViewer.setFilters(filters);
+
+ fListener.setFailOnRedundantUpdates(false);
+ //fListener.setFailOnMultipleLabelUpdateSequences(false);
+ fListener.reset();
+
+ fViewer.setInput(model.getRootElement());
+
+ while (!fListener.isFinished(ALL_UPDATES_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ }
+
+
+ /**
+ * Replace an element that is not visible but filtered out. With an element that is NOT filtered out.
+ * Fire REPLACE delta.
+ */
+ public void testReplacedUnrealizedFilteredElement() throws InterruptedException {
+ doTestReplacedUnrealizedFilteredElement(new ViewerFilter[] { new TestViewerFilter("2") });
+ }
+
+
+ /**
+ * Replace an element that is not visible but filtered out. With an element that is NOT filtered out.
+ * Fire REPLACE delta.
+ */
+ public void testReplacedUnrealizedFilteredElementWithTMVFilter() throws InterruptedException {
+ doTestReplacedUnrealizedFilteredElement(new ViewerFilter[] { new TestTMVFilter("2", null) });
+ }
+
+ private void doTestReplacedUnrealizedFilteredElement(ViewerFilter[] filters) throws InterruptedException {
+
+ // Populate a view with a large model (only first 100 elements will be visible in virtual viewer).
+ TestModel model = new TestModel();
+ model.setRoot( new TestElement(model, "root", new TestElement[0] ) );
+ model.setElementChildren(TreePath.EMPTY, TestModel.makeSingleLevelModelElements(model, 300, "model."));
+
+ fViewer.setFilters(filters);
+
+ fListener.setFailOnRedundantUpdates(false);
+ fListener.reset();
+
+ // Populate the view (all elements containing a "2" will be filtered out.
+ fViewer.setInput(model.getRootElement());
+
+ while (!fListener.isFinished(ALL_UPDATES_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+
+ // Switch out element "201" which is filtered out, with a "replaced element" which should NOT be
+ // filtered out.
+ TestElement replacedElement = new TestElement(model, "replaced element", new TestElement[0]);
+ IModelDelta replaceDelta = model.replaceElementChild(TreePath.EMPTY, 200, replacedElement);
+ fListener.reset();
+ model.postDelta(replaceDelta);
+ while (!fListener.isFinished(MODEL_CHANGED_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+
+ // Reposition the viewer to make element 100 the top element, making the replaced element visible.
+ fListener.reset();
+ ((IInternalTreeModelViewer) fViewer).reveal(TreePath.EMPTY, 150);
+ while (!fListener.isFinished(ALL_UPDATES_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+
+ // Verify that the replaced element is in viewer now (i.e. it's not filtered out.
+ TreePath[] replacedElementPaths = fViewer.getElementPaths(replacedElement);
+ Assert.assertTrue(replacedElementPaths.length != 0);
+ }
+
+
+ public void testRefreshUnrealizedFilteredElement() throws InterruptedException {
+ doTestRefreshUnrealizedFilteredElement(new ViewerFilter[] { new TestViewerFilter("2") });
+ }
+
+ public void testRefreshUnrealizedFilteredElementWithTMVFilter() throws InterruptedException {
+ doTestRefreshUnrealizedFilteredElement(new ViewerFilter[] { new TestTMVFilter("2", null) });
+ }
+
+ /**
+ * Replace an element that is not visible but filtered out. With an element that is NOT filtered out.
+ * Fire CONTENT delta on parent.
+ */
+ private void doTestRefreshUnrealizedFilteredElement(ViewerFilter[] filters) throws InterruptedException {
+ // Populate a view with a large model (only first 100 elements will be visible in virtual viewer).
+ TestModel model = new TestModel();
+ model.setRoot( new TestElement(model, "root", new TestElement[0] ) );
+ model.setElementChildren(TreePath.EMPTY, TestModel.makeSingleLevelModelElements(model, 300, "model."));
+
+ fViewer.setFilters(filters);
+
+ fListener.setFailOnRedundantUpdates(false);
+ fListener.reset();
+
+ // Populate the view (all elements containing a "2" will be filtered out.
+ fViewer.setInput(model.getRootElement());
+
+ while (!fListener.isFinished(ALL_UPDATES_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+
+ // Switch out element "201" which is filtered out, with a "replaced element" which should NOT be
+ // filtered out.
+ TestElement replacedElement = new TestElement(model, "replaced element", new TestElement[0]);
+ model.replaceElementChild(TreePath.EMPTY, 200, replacedElement);
+ fListener.reset();
+ model.postDelta(new ModelDelta(model.getRootElement(), IModelDelta.CONTENT));
+ while (!fListener.isFinished(ALL_UPDATES_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+
+ // Reposition the viewer to make element 100 the top element, making the replaced element visible.
+ fListener.reset();
+ ((IInternalTreeModelViewer) fViewer).reveal(TreePath.EMPTY, 150);
+ while (!fListener.isFinished(ALL_UPDATES_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+
+ // Verify that the replaced element is in viewer now (i.e. it's not filtered out.
+ TreePath[] replacedElementPaths = fViewer.getElementPaths(replacedElement);
+ Assert.assertTrue(replacedElementPaths.length != 0);
+ }
+
+ public void testRefreshToUnfilterElements() throws InterruptedException {
+ doTestRefreshToUnfilterElements(new ViewerFilter[] { new TestViewerFilter(".1"), new TestViewerFilter(".2") });
+ }
+
+ public void testRefreshToUnfilterElementsWithTMVFilter() throws InterruptedException {
+ doTestRefreshToUnfilterElements(new ViewerFilter[] { new TestTMVFilter(".1", null), new TestTMVFilter(".2", null) });
+ }
+
+ public void testRefreshToUnfilterElementsWithMixedFilters() throws InterruptedException {
+ doTestRefreshToUnfilterElements(new ViewerFilter[] { new TestViewerFilter(".1"), new TestTMVFilter(".2", null) });
+ }
+
+ /**
+ * Replace an element that is not visible but filtered out. With an element that is NOT filtered out.
+ * Fire CONTENT delta on parent.
+ */
+ private void doTestRefreshToUnfilterElements(ViewerFilter[] filters) throws InterruptedException {
+ // Populate a view with a large model (only first 100 elements will be visible in virtual viewer).
+ TestModel model = TestModel.simpleMultiLevel();
+
+ fViewer.setFilters(filters);
+
+ fListener.setFailOnRedundantUpdates(false);
+ fListener.reset();
+
+ // Make sure that all elements are expanded
+ fViewer.setAutoExpandLevel(-1);
+
+ // Populate the view (all elements containing a "2" will be filtered out.
+ fViewer.setInput(model.getRootElement());
+
+ while (!fListener.isFinished(ALL_UPDATES_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+
+ // Turn off filters and refresh.
+ filters = new ViewerFilter[0];
+ fViewer.setFilters(filters);
+ fListener.reset();
+ model.postDelta(new ModelDelta(model.getRootElement(), IModelDelta.CONTENT));
+ while (!fListener.isFinished(ALL_UPDATES_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+
+ model.validateData(fViewer, TreePath.EMPTY, false, filters);
+ }
+
+ public void testPreserveExpandedOnMultLevelContent() throws InterruptedException {
+ //TreeModelViewerAutopopulateAgent autopopulateAgent = new TreeModelViewerAutopopulateAgent(fViewer);
+ TestModel model = StateTests.alternatingSubsreesModel(6);
+
+ // NOTE: WE ARE NOT EXPANDING ANY CHILDREN
+
+ // Create the listener, only check the first level
+ fListener.reset(TreePath.EMPTY, model.getRootElement(), 1, true, false);
+
+ // Set the input into the view and update the view.
+ fViewer.setInput(model.getRootElement());
+ while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ model.validateData(fViewer, TreePath.EMPTY, true);
+
+ StateTests.expandAlternateElements(fListener, model, true);
+
+ // Set a selection in view
+ // Set a selection in view
+ TreeSelection originalSelection = new TreeSelection(
+ new TreePath[] { model.findElement("5"), model.findElement("5.1"), model.findElement("6") });
+ fViewer.setSelection(originalSelection);
+ Assert.assertTrue( StateTests.areTreeSelectionsEqual(originalSelection, (ITreeSelection)fViewer.getSelection()) );
+
+ // Set a filter to remove element "1"
+ ViewerFilter[] filters = new ViewerFilter[] { new TestViewerFilter("^1$") };
+ fViewer.setFilters(filters);
+
+ // Note: Re-expanding nodes causes redundant updates.
+ fListener.reset(false, false);
+ fListener.addUpdates(getInternalViewer(), TreePath.EMPTY, model.getRootElement(), filters, -1, ALL_UPDATES_COMPLETE);
+
+ // Post the refresh delta
+ model.postDelta(new ModelDelta(model.getRootElement(), IModelDelta.CONTENT));
+ while (!fListener.isFinished(ALL_UPDATES_COMPLETE | STATE_RESTORE_COMPLETE))
+ if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+
+ // Validate data
+ model.validateData(fViewer, TreePath.EMPTY, true, filters);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("2")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("4")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("5")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("5.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("6")) == false);
+ Assert.assertTrue( StateTests.areTreeSelectionsEqual(originalSelection, (ITreeSelection)fViewer.getSelection()) );
+
+ // Note: in past it was observed sub-optimal coalescing in this test due
+ // to scattered update requests from viewer.
+ Assert.assertTrue( fListener.checkCoalesced(TreePath.EMPTY, 0, 6) );
+
+ // Clear the filter, to re-add the element
+ filters = new ViewerFilter[0];
+ fViewer.setFilters(filters);
+
+ // Refresh again to get the filtered element back
+ fListener.reset();
+ fListener.addUpdates(getInternalViewer(), TreePath.EMPTY, model.getRootElement(), filters, -1, ALL_UPDATES_COMPLETE);
+ model.postDelta(new ModelDelta(model.getRootElement(), IModelDelta.CONTENT));
+ while (!fListener.isFinished(ALL_UPDATES_COMPLETE | STATE_RESTORE_COMPLETE))
+ if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+
+ // Validate data
+ model.validateData(fViewer, TreePath.EMPTY, true, filters);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("2")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("4")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("5")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("5.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("6")) == false);
+ Assert.assertTrue( StateTests.areTreeSelectionsEqual(originalSelection, (ITreeSelection)fViewer.getSelection()) );
+
+ }
+
+}
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/ITestModelUpdatesListenerConstants.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/ITestModelUpdatesListenerConstants.java
index 0d47d6ed5..4437d40e1 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/ITestModelUpdatesListenerConstants.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/ITestModelUpdatesListenerConstants.java
@@ -17,11 +17,11 @@ package org.eclipe.debug.tests.viewer.model;
*/
public interface ITestModelUpdatesListenerConstants {
- public static final int LABEL_UPDATES_COMPLETE = 0X00000001;
- public static final int CONTENT_UPDATES_COMPLETE = 0X00000002;
- public static final int CONTENT_UPDATES_STARTED = 0X00020000;
+ public static final int LABEL_SEQUENCE_COMPLETE = 0X00000001;
+ public static final int CONTENT_SEQUENCE_COMPLETE = 0X00000002;
+ public static final int CONTENT_SEQUENCE_STARTED = 0X00020000;
public static final int LABEL_UPDATES = 0X00000004;
- public static final int LABEL_UPDATES_STARTED = 0X00040000;
+ public static final int LABEL_SEQUENCE_STARTED = 0X00040000;
public static final int HAS_CHILDREN_UPDATES = 0X00000008;
public static final int HAS_CHILDREN_UPDATES_STARTED = 0X00080000;
public static final int CHILD_COUNT_UPDATES = 0X00000010;
@@ -40,11 +40,11 @@ public interface ITestModelUpdatesListenerConstants {
public static final int VIEWER_UPDATES_RUNNING = 0X00001000;
public static final int LABEL_UPDATES_RUNNING = 0X00002000;
- public static final int VIEWER_UPDATES_STARTED = HAS_CHILDREN_UPDATES_STARTED | CHILD_COUNT_UPDATES_STARTED | CHILDREN_UPDATES_STARTED;
+ public static final int ALL_VIEWER_UPDATES_STARTED = HAS_CHILDREN_UPDATES_STARTED | CHILD_COUNT_UPDATES_STARTED | CHILDREN_UPDATES_STARTED;
- public static final int LABEL_COMPLETE = LABEL_UPDATES_COMPLETE | LABEL_UPDATES | LABEL_UPDATES_RUNNING;
+ public static final int LABEL_COMPLETE = LABEL_SEQUENCE_COMPLETE | LABEL_UPDATES | LABEL_UPDATES_RUNNING;
public static final int CONTENT_COMPLETE =
- CONTENT_UPDATES_COMPLETE | HAS_CHILDREN_UPDATES | CHILD_COUNT_UPDATES | CHILDREN_UPDATES | VIEWER_UPDATES_RUNNING;
+ CONTENT_SEQUENCE_COMPLETE | HAS_CHILDREN_UPDATES | CHILD_COUNT_UPDATES | CHILDREN_UPDATES | VIEWER_UPDATES_RUNNING;
public static final int ALL_UPDATES_COMPLETE = LABEL_COMPLETE | CONTENT_COMPLETE | MODEL_PROXIES_INSTALLED | LABEL_UPDATES_RUNNING | VIEWER_UPDATES_RUNNING;
}
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerCheckTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerCheckTests.java
index 7cb15a0ee..d596f1443 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerCheckTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerCheckTests.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipe.debug.tests.viewer.model;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelContentProviderTarget;
+import org.eclipse.debug.internal.ui.viewers.model.IInternalTreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
import org.eclipse.swt.SWT;
@@ -26,7 +26,7 @@ public class JFaceViewerCheckTests extends CheckTests {
super(name);
}
- protected ITreeModelContentProviderTarget createViewer(Display display, Shell shell) {
+ protected IInternalTreeModelViewer createViewer(Display display, Shell shell) {
return new TreeModelViewer(fShell, SWT.VIRTUAL | SWT.CHECK, new PresentationContext("TestViewer"));
}
}
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerContentTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerContentTests.java
index 10213a3a3..29b127d2a 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerContentTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerContentTests.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipe.debug.tests.viewer.model;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelContentProviderTarget;
+import org.eclipse.debug.internal.ui.viewers.model.IInternalTreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
import org.eclipse.swt.SWT;
@@ -26,7 +26,7 @@ public class JFaceViewerContentTests extends ContentTests {
super(name);
}
- protected ITreeModelContentProviderTarget createViewer(Display display, Shell shell) {
+ protected IInternalTreeModelViewer createViewer(Display display, Shell shell) {
return new TreeModelViewer(fShell, SWT.VIRTUAL, new PresentationContext("TestViewer"));
}
}
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerDeltaTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerDeltaTests.java
index ed613bd6f..c25961b3e 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerDeltaTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerDeltaTests.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipe.debug.tests.viewer.model;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelContentProviderTarget;
+import org.eclipse.debug.internal.ui.viewers.model.IInternalTreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
import org.eclipse.swt.SWT;
@@ -26,7 +26,7 @@ public class JFaceViewerDeltaTests extends DeltaTests {
super(name);
}
- protected ITreeModelContentProviderTarget createViewer(Display display, Shell shell) {
+ protected IInternalTreeModelViewer createViewer(Display display, Shell shell) {
return new TreeModelViewer(fShell, SWT.VIRTUAL, new PresentationContext("TestViewer"));
}
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerFilterTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerFilterTests.java
new file mode 100644
index 000000000..853d2e7c1
--- /dev/null
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerFilterTests.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * 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.eclipe.debug.tests.viewer.model;
+
+import org.eclipse.debug.internal.ui.viewers.model.IInternalTreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * @since 3.8
+ */
+public class JFaceViewerFilterTests extends FilterTests {
+
+ public JFaceViewerFilterTests(String name) {
+ super(name);
+ }
+
+ protected IInternalTreeModelViewer createViewer(Display display, Shell shell) {
+ return new TreeModelViewer(fShell, SWT.VIRTUAL | SWT.MULTI, new PresentationContext("TestViewer"));
+ }
+}
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerLazyTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerLazyTests.java
index fa6183d61..e1955a726 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerLazyTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerLazyTests.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipe.debug.tests.viewer.model;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelContentProviderTarget;
+import org.eclipse.debug.internal.ui.viewers.model.IInternalTreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
import org.eclipse.swt.SWT;
@@ -26,7 +26,7 @@ public class JFaceViewerLazyTests extends LazyTests {
super(name);
}
- protected ITreeModelContentProviderTarget createViewer(Display display, Shell shell) {
+ protected IInternalTreeModelViewer createViewer(Display display, Shell shell) {
return new TreeModelViewer(fShell, SWT.VIRTUAL, new PresentationContext("TestViewer"));
}
}
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerPerformanceTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerPerformanceTests.java
index 865db9508..4b3bdc06f 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerPerformanceTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerPerformanceTests.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipe.debug.tests.viewer.model;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelContentProviderTarget;
+import org.eclipse.debug.internal.ui.viewers.model.IInternalTreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
import org.eclipse.swt.SWT;
@@ -26,7 +26,7 @@ public class JFaceViewerPerformanceTests extends PerformanceTests {
super(name);
}
- protected ITreeModelContentProviderTarget createViewer(Display display, Shell shell) {
+ protected IInternalTreeModelViewer createViewer(Display display, Shell shell) {
return new TreeModelViewer(fShell, SWT.VIRTUAL, new PresentationContext("TestViewer"));
}
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerPopupTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerPopupTests.java
index 70f41bd3c..43954104d 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerPopupTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerPopupTests.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipe.debug.tests.viewer.model;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
import org.eclipse.swt.SWT;
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerSelectionTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerSelectionTests.java
index 6cde1fbfc..511c497d7 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerSelectionTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerSelectionTests.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipe.debug.tests.viewer.model;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
import org.eclipse.swt.SWT;
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerStateTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerStateTests.java
index 07104a79b..49fcb40bd 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerStateTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerStateTests.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipe.debug.tests.viewer.model;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
import org.eclipse.swt.SWT;
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerTopIndexTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerTopIndexTests.java
index 668612860..51597c8a8 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerTopIndexTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerTopIndexTests.java
@@ -17,7 +17,7 @@ import junit.framework.TestCase;
import org.eclipe.debug.tests.viewer.model.TestModel.TestElement;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.Platform;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelContentProviderTarget;
+import org.eclipse.debug.internal.ui.viewers.model.IInternalTreeModelViewer;
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.ModelDelta;
@@ -80,7 +80,7 @@ public class JFaceViewerTopIndexTests extends TestCase implements ITestModelUpda
}
}
- protected ITreeModelContentProviderTarget getCTargetViewer() {
+ protected IInternalTreeModelViewer getCTargetViewer() {
return fViewer;
}
@@ -211,7 +211,7 @@ public class JFaceViewerTopIndexTests extends TestCase implements ITestModelUpda
model.postDelta(rootDelta);
- while (!fListener.isFinished(CONTENT_UPDATES_COMPLETE | MODEL_CHANGED_COMPLETE))
+ while (!fListener.isFinished(CONTENT_SEQUENCE_COMPLETE | MODEL_CHANGED_COMPLETE))
if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
// Validate that the first node is expanded
@@ -379,7 +379,7 @@ public class JFaceViewerTopIndexTests extends TestCase implements ITestModelUpda
// Wait for the second model delta to process
fListener.reset();
model.postDelta(revealDelta);
- while (!fListener.isFinished(MODEL_CHANGED_COMPLETE | CONTENT_UPDATES_COMPLETE))
+ while (!fListener.isFinished(MODEL_CHANGED_COMPLETE | CONTENT_SEQUENCE_COMPLETE))
if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
// Clear view then reset it again.
@@ -512,7 +512,7 @@ public class JFaceViewerTopIndexTests extends TestCase implements ITestModelUpda
fListener.reset(false, false);
fListener.addUpdates(getCTargetViewer(), originalTopPath, (TestElement)originalTopPath.getLastSegment(), 0, STATE_UPDATES);
fViewer.setInput(model.getRootElement());
- while (!fListener.isFinished(STATE_UPDATES | CONTENT_UPDATES_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ while (!fListener.isFinished(STATE_UPDATES | CONTENT_SEQUENCE_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
while (fDisplay.readAndDispatch ()) {}
// check if REVEAL was restored OK
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerUpdateTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerUpdateTests.java
index 983b8d77f..ee06a4b46 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerUpdateTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerUpdateTests.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipe.debug.tests.viewer.model;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
import org.eclipse.swt.SWT;
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/LazyTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/LazyTests.java
index f6566d9bc..986868bee 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/LazyTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/LazyTests.java
@@ -15,7 +15,7 @@ import junit.framework.TestCase;
import org.eclipe.debug.tests.viewer.model.TestModel.TestElement;
import org.eclipse.core.commands.ExecutionException;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelContentProviderTarget;
+import org.eclipse.debug.internal.ui.viewers.model.IInternalTreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.jface.viewers.IStructuredSelection;
@@ -36,7 +36,7 @@ abstract public class LazyTests extends TestCase implements ITestModelUpdatesLis
Display fDisplay;
Shell fShell;
- ITreeModelContentProviderTarget fViewer;
+ IInternalTreeModelViewer fViewer;
TestModelUpdatesListener fListener;
public LazyTests(String name) {
@@ -59,7 +59,7 @@ abstract public class LazyTests extends TestCase implements ITestModelUpdatesLis
fShell.open ();
}
- abstract protected ITreeModelContentProviderTarget createViewer(Display display, Shell shell);
+ abstract protected IInternalTreeModelViewer createViewer(Display display, Shell shell);
/**
* @throws java.lang.Exception
*/
@@ -140,7 +140,7 @@ abstract public class LazyTests extends TestCase implements ITestModelUpdatesLis
}
model.postDelta(rootDelta);
- while (!fListener.isFinished(CONTENT_UPDATES_COMPLETE | MODEL_CHANGED_COMPLETE | LABEL_UPDATES_COMPLETE))
+ while (!fListener.isFinished(CONTENT_SEQUENCE_COMPLETE | MODEL_CHANGED_COMPLETE | LABEL_SEQUENCE_COMPLETE))
if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
}
@@ -165,7 +165,7 @@ abstract public class LazyTests extends TestCase implements ITestModelUpdatesLis
fListener.setFailOnRedundantUpdates(false);
fViewer.setInput(model.getRootElement());
fListener.addLabelUpdate(model.findElement("1.0"));
- while (!fListener.isFinished(CONTENT_UPDATES_COMPLETE | LABEL_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ while (!fListener.isFinished(CONTENT_SEQUENCE_COMPLETE | LABEL_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
// Set selection so that the initial selection is not empty
fViewer.setSelection(new TreeSelection(new TreePath[] { model.findElement("1.0")} ));
@@ -209,7 +209,7 @@ abstract public class LazyTests extends TestCase implements ITestModelUpdatesLis
// Populate initial view content
fListener.reset(TreePath.EMPTY, model.getRootElement(), -1, true, true);
fViewer.setInput(model.getRootElement());
- while (!fListener.isFinished(CONTENT_UPDATES_COMPLETE | LABEL_UPDATES_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ while (!fListener.isFinished(CONTENT_SEQUENCE_COMPLETE | LABEL_SEQUENCE_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
// Turn off autoexpand
fViewer.setAutoExpandLevel(0);
@@ -218,7 +218,7 @@ abstract public class LazyTests extends TestCase implements ITestModelUpdatesLis
fListener.reset();
fListener.setFailOnRedundantUpdates(false);
fViewer.reveal(model.findElement("1"), 500);
- while (!fListener.isFinished(CONTENT_UPDATES_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ while (!fListener.isFinished(CONTENT_SEQUENCE_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
// Create delta to refresh the "1" element.
TestElement rootElement = model.getRootElement();
@@ -248,7 +248,7 @@ abstract public class LazyTests extends TestCase implements ITestModelUpdatesLis
}
model.postDelta(rootDelta);
- while (!fListener.isFinished(CONTENT_UPDATES_COMPLETE | MODEL_CHANGED_COMPLETE))
+ while (!fListener.isFinished(CONTENT_SEQUENCE_COMPLETE | MODEL_CHANGED_COMPLETE))
if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
}
}
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/PerformanceTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/PerformanceTests.java
index 55a140e2c..2a5b06759 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/PerformanceTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/PerformanceTests.java
@@ -14,11 +14,14 @@ import junit.framework.TestCase;
import org.eclipe.debug.tests.viewer.model.TestModel.TestElement;
import org.eclipse.core.commands.ExecutionException;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelContentProviderTarget;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.IInternalTreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+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.jface.viewers.TreeSelection;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
@@ -55,7 +58,7 @@ abstract public class PerformanceTests extends TestCase implements ITestModelUpd
fShell.open ();
}
- abstract protected ITreeModelContentProviderTarget createViewer(Display display, Shell shell);
+ abstract protected IInternalTreeModelViewer createViewer(Display display, Shell shell);
/**
* @throws java.lang.Exception
@@ -87,7 +90,7 @@ abstract public class PerformanceTests extends TestCase implements ITestModelUpd
public void testRefreshStruct() throws InterruptedException {
TestModel model = new TestModel();
model.setRoot( new TestElement(model, "root", new TestElement[0] ) );
- model.setElementChildren(TreePath.EMPTY, makeModelElements(model, getTestModelDepth(), "model"));
+ model.setElementChildren(TreePath.EMPTY, TestModel.makeMultiLevelElements(model, getTestModelDepth(), "model."));
fViewer.setAutoExpandLevel(-1);
@@ -105,7 +108,6 @@ abstract public class PerformanceTests extends TestCase implements ITestModelUpd
for (int i = 0; i < 100; i++) {
// Update the model
model.setAllAppendix(" - pass " + i);
- //model.setElementChildren(TreePath.EMPTY, makeModelElements(model, getTestModelDepth(), "pass " + i));
TestElement element = model.getRootElement();
fListener.reset(TreePath.EMPTY, element, -1, false, false);
@@ -114,7 +116,6 @@ abstract public class PerformanceTests extends TestCase implements ITestModelUpd
model.postDelta(new ModelDelta(element, IModelDelta.CONTENT));
while (!fListener.isFinished(ALL_UPDATES_COMPLETE | MODEL_CHANGED_COMPLETE))
if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
- model.validateData(fViewer, TreePath.EMPTY);
meter.stop();
System.gc();
}
@@ -129,7 +130,7 @@ abstract public class PerformanceTests extends TestCase implements ITestModelUpd
public void testRefreshStructReplaceElements() throws InterruptedException {
TestModel model = new TestModel();
model.setRoot( new TestElement(model, "root", new TestElement[0] ) );
- model.setElementChildren(TreePath.EMPTY, makeModelElements(model, getTestModelDepth(), "model"));
+ model.setElementChildren(TreePath.EMPTY, TestModel.makeMultiLevelElements(model, getTestModelDepth(), "model."));
fViewer.setAutoExpandLevel(-1);
@@ -144,9 +145,9 @@ abstract public class PerformanceTests extends TestCase implements ITestModelUpd
Performance perf = Performance.getDefault();
PerformanceMeter meter = perf.createPerformanceMeter(perf.getDefaultScenarioId(this));
try {
- for (int i = 0; i < 2000; i++) {
+ for (int i = 0; i < 100; i++) {
// Update the model
- model.setElementChildren(TreePath.EMPTY, makeModelElements(model, getTestModelDepth(), "pass " + i));
+ model.setElementChildren(TreePath.EMPTY, TestModel.makeMultiLevelElements(model, getTestModelDepth(), "pass " + i + "."));
TestElement element = model.getRootElement();
fListener.reset(TreePath.EMPTY, element, -1, false, false);
@@ -155,7 +156,6 @@ abstract public class PerformanceTests extends TestCase implements ITestModelUpd
model.postDelta(new ModelDelta(element, IModelDelta.CONTENT));
while (!fListener.isFinished(ALL_UPDATES_COMPLETE | MODEL_CHANGED_COMPLETE))
if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
- model.validateData(fViewer, TreePath.EMPTY);
meter.stop();
System.gc();
}
@@ -167,12 +167,156 @@ abstract public class PerformanceTests extends TestCase implements ITestModelUpd
}
}
- private TestElement[] makeModelElements(TestModel model, int depth, String prefix) {
- TestElement[] elements = new TestElement[depth];
- for (int i = 0; i < depth; i++) {
- String name = prefix + "." + i;
- elements[i] = new TestElement(model, name, makeModelElements(model, i, name));
+
+ public void testRefreshList() throws InterruptedException {
+ TestModel model = new TestModel();
+ model.setRoot( new TestElement(model, "root", new TestElement[0] ) );
+ int numElements = (int)Math.pow(2, getTestModelDepth());
+ model.setElementChildren(TreePath.EMPTY, TestModel.makeSingleLevelModelElements(model, numElements, "model."));
+
+ fViewer.setAutoExpandLevel(-1);
+
+ // Create the listener
+ fListener.reset(TreePath.EMPTY, model.getRootElement(), -1, true, false);
+
+ // Set the input into the view and update the view.
+ fViewer.setInput(model.getRootElement());
+ while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ model.validateData(fViewer, TreePath.EMPTY);
+
+ Performance perf = Performance.getDefault();
+ PerformanceMeter meter = perf.createPerformanceMeter(perf.getDefaultScenarioId(this));
+ try {
+ for (int i = 0; i < 100; i++) {
+ // Update the model
+ model.setAllAppendix(" - pass " + i);
+
+ TestElement element = model.getRootElement();
+ fListener.reset(TreePath.EMPTY, element, -1, false, false);
+
+ meter.start();
+ model.postDelta(new ModelDelta(element, IModelDelta.CONTENT));
+ while (!fListener.isFinished(ALL_UPDATES_COMPLETE | MODEL_CHANGED_COMPLETE))
+ if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ meter.stop();
+ System.gc();
+ }
+
+ meter.commit();
+ perf.assertPerformance(meter);
+ } finally {
+ meter.dispose();
}
- return elements;
}
+
+ public void testSaveAndRestore() throws InterruptedException {
+ //TreeModelViewerAutopopulateAgent autopopulateAgent = new TreeModelViewerAutopopulateAgent(fViewer);
+ TestModel model = TestModel.simpleMultiLevel();
+
+ // expand all elements
+ fViewer.setAutoExpandLevel(-1);
+
+ // Create the listener, only check the first level
+ fListener.reset(TreePath.EMPTY, model.getRootElement(), -1, true, false);
+
+ // Set the input into the view and update the view.
+ fViewer.setInput(model.getRootElement());
+ while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ model.validateData(fViewer, TreePath.EMPTY);
+
+ // Set a selection in view
+ fViewer.setSelection(new TreeSelection(model.findElement("3.2.3")));
+
+ // Turn off the auto-expand now since we want to text the auto-expand logic
+ fViewer.setAutoExpandLevel(-1);
+
+ Performance perf = Performance.getDefault();
+ PerformanceMeter meter = perf.createPerformanceMeter(perf.getDefaultScenarioId(this));
+ try {
+ for (int i = 0; i < 100; i++) {
+ // Update the model
+ model.setAllAppendix(" - pass " + i);
+
+ // Set the viewer input to null. This will trigger the view to save the viewer state.
+ fListener.reset(true, false);
+
+ meter.start();
+ fViewer.setInput(null);
+ while (!fListener.isFinished(STATE_SAVE_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+
+ // Set the viewer input back to the model. When view updates are complete
+ // the viewer
+ // Note: disable redundant updates because the reveal delta triggers one.
+ fListener.reset(TreePath.EMPTY, model.getRootElement(), 1, false, false);
+ // TODO: add state updates somehow?
+ fViewer.setInput(model.getRootElement());
+ while (!fListener.isFinished(ALL_UPDATES_COMPLETE | STATE_RESTORE_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ meter.stop();
+ System.gc();
+ }
+
+ meter.commit();
+ perf.assertPerformance(meter);
+ } finally {
+ meter.dispose();
+ }
+
+ }
+
+ public void testRefreshListFiltered() throws InterruptedException {
+ TestModel model = new TestModel();
+ model.setRoot( new TestElement(model, "root", new TestElement[0] ) );
+ int numElements = (int)Math.pow(2, getTestModelDepth());
+ model.setElementChildren(TreePath.EMPTY, TestModel.makeSingleLevelModelElements(model, 1000, "model."));
+
+ fViewer.setAutoExpandLevel(-1);
+
+ // Create the listener
+ fListener.reset(TreePath.EMPTY, model.getRootElement(), -1, true, false);
+
+ fViewer.addFilter(new ViewerFilter() {
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+ if (element instanceof TestElement) {
+ String id = ((TestElement)element).getID();
+ if (id.startsWith("model.")) {
+ id = id.substring("model.".length());
+ }
+ if (id.length() >= 2 && (id.charAt(1) == '1' || id.charAt(1) == '3' || id.charAt(1) == '5' || id.charAt(1) == '7' || id.charAt(1) == '9')) {
+ return false;
+ }
+ }
+ return true;
+ }
+ });
+
+ // Set the input into the view and update the view.
+ fViewer.setInput(model.getRootElement());
+ while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ model.validateData(fViewer, TreePath.EMPTY);
+
+ Performance perf = Performance.getDefault();
+ PerformanceMeter meter = perf.createPerformanceMeter(perf.getDefaultScenarioId(this));
+ try {
+ for (int i = 0; i < 100; i++) {
+ // Update the model
+ model.setAllAppendix(" - pass " + i);
+
+ TestElement element = model.getRootElement();
+ fListener.reset(TreePath.EMPTY, element, -1, false, false);
+
+ meter.start();
+ model.postDelta(new ModelDelta(element, IModelDelta.CONTENT));
+ while (!fListener.isFinished(ALL_UPDATES_COMPLETE | MODEL_CHANGED_COMPLETE))
+ if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ meter.stop();
+ System.gc();
+ }
+
+ meter.commit();
+ perf.assertPerformance(meter);
+ } finally {
+ meter.dispose();
+ }
+ }
+
}
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/PopupTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/PopupTests.java
index 19247755d..e760cd39c 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/PopupTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/PopupTests.java
@@ -19,9 +19,9 @@ import junit.framework.Assert;
import junit.framework.TestCase;
import org.eclipe.debug.tests.viewer.model.TestModel.TestElement;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelContentProviderTarget;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.IInternalTreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+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.ISelection;
import org.eclipse.jface.viewers.ITreeSelection;
@@ -65,8 +65,8 @@ abstract public class PopupTests extends TestCase implements ITestModelUpdatesLi
fShell.open ();
}
- protected ITreeModelContentProviderTarget getCTargetViewer() {
- return (ITreeModelContentProviderTarget)fViewer;
+ protected IInternalTreeModelViewer getCTargetViewer() {
+ return (IInternalTreeModelViewer)fViewer;
}
@@ -147,14 +147,14 @@ abstract public class PopupTests extends TestCase implements ITestModelUpdatesLi
// Validate the expansion state BEFORE posting the delta.
- ITreeModelContentProviderTarget contentProviderViewer = (ITreeModelContentProviderTarget)fViewer;
+ IInternalTreeModelViewer contentProviderViewer = (IInternalTreeModelViewer)fViewer;
Assert.assertFalse(contentProviderViewer.getExpandedState(path_root_3));
model.postDelta(deltaRoot);
while (true) {
if (fListener.isFinished(MODEL_CHANGED_COMPLETE)) {
- if (fListener.isFinished(CONTENT_UPDATES_STARTED)) {
- if (fListener.isFinished(CONTENT_UPDATES_COMPLETE)) {
+ if (fListener.isFinished(CONTENT_SEQUENCE_STARTED)) {
+ if (fListener.isFinished(CONTENT_SEQUENCE_COMPLETE)) {
break;
}
} else {
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/SelectionTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/SelectionTests.java
index 3ebb062a0..3deb65e5d 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/SelectionTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/SelectionTests.java
@@ -15,10 +15,10 @@ import java.util.List;
import junit.framework.TestCase;
-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.IModelSelectionPolicy;
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.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/StateTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/StateTests.java
index 9f1b85aa4..3ad16f93b 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/StateTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/StateTests.java
@@ -19,9 +19,9 @@ import junit.framework.TestCase;
import org.eclipe.debug.tests.viewer.model.TestModel.TestElement;
import org.eclipse.core.commands.ExecutionException;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelContentProviderTarget;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.IInternalTreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+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.ITreeSelection;
import org.eclipse.jface.viewers.TreePath;
@@ -86,8 +86,8 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
}
}
- protected ITreeModelContentProviderTarget getCTargetViewer() {
- return (ITreeModelContentProviderTarget)fViewer;
+ protected IInternalTreeModelViewer getInternalViewer() {
+ return (IInternalTreeModelViewer)fViewer;
}
public void testUpdateViewer() throws InterruptedException {
@@ -138,7 +138,7 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
fListener.addLabelUpdate(path3);
fViewer.updateViewer(updateDelta);
- while (!fListener.isFinished(CONTENT_UPDATES_COMPLETE | LABEL_UPDATES))
+ while (!fListener.isFinished(CONTENT_SEQUENCE_COMPLETE | LABEL_UPDATES))
if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
// Extract the new state from viewer
@@ -189,7 +189,7 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
* (size).1
* (size).1.1
*/
- private TestModel alternatingSubsreesModel(int size) {
+ static TestModel alternatingSubsreesModel(int size) {
TestModel model = new TestModel();
TestElement[] elements = new TestElement[size];
@@ -207,7 +207,7 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
return model;
}
- private boolean areTreeSelectionsEqual(ITreeSelection sel1, ITreeSelection sel2) {
+ static boolean areTreeSelectionsEqual(ITreeSelection sel1, ITreeSelection sel2) {
Set sel1Set = new HashSet();
sel1Set.addAll( Arrays.asList(sel1.getPaths()) );
@@ -217,9 +217,9 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
return sel1Set.equals(sel2Set);
}
- private void expandAlternateElements(TestModel model, boolean waitForAllUpdates) throws InterruptedException {
- fListener.reset();
- fListener.setFailOnRedundantUpdates(false);
+ static void expandAlternateElements(TestModelUpdatesListener listener, TestModel model, boolean waitForAllUpdates) throws InterruptedException {
+ listener.reset();
+ listener.setFailOnRedundantUpdates(false);
TestElement rootElement = model.getRootElement();
TestElement[] children = rootElement.getChildren();
@@ -237,7 +237,7 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
int index = i;
while (element.getChildren().length != 0) {
TreePath elementPath = model.findElement(element.getLabel());
- fListener.addUpdates(
+ listener.addUpdates(
elementPath, element, 1,
CHILD_COUNT_UPDATES | (waitForAllUpdates ? CHILDREN_UPDATES : 0) );
delta = delta.addNode(element, index, IModelDelta.EXPAND, element.getChildren().length);
@@ -247,8 +247,8 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
}
model.postDelta(rootDelta);
- while (!fListener.isFinished(CONTENT_UPDATES_COMPLETE | MODEL_CHANGED_COMPLETE))
- if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ while (!listener.isFinished(CONTENT_SEQUENCE_COMPLETE | MODEL_CHANGED_COMPLETE))
+ if (!Display.getDefault().readAndDispatch ()) Thread.sleep(0);
}
public void testPreserveExpandedOnRemove() throws InterruptedException {
@@ -265,7 +265,7 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
model.validateData(fViewer, TreePath.EMPTY, true);
- expandAlternateElements(model, true);
+ expandAlternateElements(fListener, model, true);
// Set a selection in view
TreeSelection originalSelection = new TreeSelection(model.findElement("5.1"));
@@ -282,13 +282,13 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
// Validate data
model.validateData(fViewer, TreePath.EMPTY, true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("2")) == false);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3.1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("4")) == false);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("5")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("5.1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("6")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("2")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("4")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("5")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("5.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("6")) == false);
Assert.assertTrue( areTreeSelectionsEqual(originalSelection, (ITreeSelection)fViewer.getSelection()) );
}
@@ -306,7 +306,7 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
model.validateData(fViewer, TreePath.EMPTY, true);
- expandAlternateElements(model, true);
+ expandAlternateElements(fListener, model, true);
// Set a selection in view
TreeSelection originalSelection = new TreeSelection(model.findElement("5.1"));
@@ -326,15 +326,15 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
// Validate data
model.validateData(fViewer, TreePath.EMPTY, true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("1.1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("2")) == false);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3.1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("4")) == false);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("5")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("5.1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("6")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("1.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("2")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("4")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("5")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("5.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("6")) == false);
Assert.assertTrue( areTreeSelectionsEqual(originalSelection, (ITreeSelection)fViewer.getSelection()) );
}
@@ -352,7 +352,7 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
model.validateData(fViewer, TreePath.EMPTY, true);
- expandAlternateElements(model, true);
+ expandAlternateElements(fListener, model, true);
// Set a selection in view
// Set a selection in view
@@ -366,7 +366,7 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
// Note: Re-expanding nodes causes redundant updates.
fListener.reset(false, false);
- fListener.addUpdates(getCTargetViewer(), TreePath.EMPTY, model.getRootElement(), -1, ALL_UPDATES_COMPLETE);
+ fListener.addUpdates(getInternalViewer(), TreePath.EMPTY, model.getRootElement(), -1, ALL_UPDATES_COMPLETE);
// Create the delta which has nodes with CONTENT flag set at multiple levels.
ModelDelta rootDelta = new ModelDelta(model.getRootElement(), IModelDelta.CONTENT);
@@ -380,14 +380,18 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
// Validate data
model.validateData(fViewer, TreePath.EMPTY, true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("2")) == false);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3.1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("4")) == false);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("5")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("5.1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("6")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("2")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("4")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("5")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("5.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("6")) == false);
Assert.assertTrue( areTreeSelectionsEqual(originalSelection, (ITreeSelection)fViewer.getSelection()) );
+
+ // Note: in past it was observed sub-optimal coalescing in this test due
+ // to scattered update requests from viewer.
+ Assert.assertTrue( fListener.checkCoalesced(TreePath.EMPTY, 0, 6) );
}
@@ -424,7 +428,7 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
// Note: Re-expanding nodes causes redundant updates.
fListener.reset(false, false);
- fListener.addUpdates(getCTargetViewer(), elementPath, model.getElement(elementPath), -1, ALL_UPDATES_COMPLETE);
+ fListener.addUpdates(getInternalViewer(), elementPath, model.getElement(elementPath), -1, ALL_UPDATES_COMPLETE);
// Post the sub-tree update
model.postDelta(rootDelta);
@@ -433,16 +437,16 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
// Validate data
model.validateData(fViewer, TreePath.EMPTY, true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3")) == true);
// On windows, getExpandedState() may return true for an element with no children:
// Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3.0 - new")) == false);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3.1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3.2")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3.3")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3.2")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3.3")) == true);
Assert.assertTrue( areTreeSelectionsEqual(originalSelection, (ITreeSelection)fViewer.getSelection()) );
}
- public void _X_testPreserveExpandedOnContentStress() throws InterruptedException {
+ public void testPreserveExpandedOnContentStress() throws InterruptedException {
//TreeModelViewerAutopopulateAgent autopopulateAgent = new TreeModelViewerAutopopulateAgent(fViewer);
TestModel model = alternatingSubsreesModel(6);
@@ -456,7 +460,7 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
model.validateData(fViewer, TreePath.EMPTY, true);
- expandAlternateElements(model, true);
+ expandAlternateElements(fListener, model, true);
// Set a selection in view
// TreeSelection originalSelection = new TreeSelection(
@@ -473,20 +477,20 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
// Note: Re-expanding nodes causes redundant updates.
fListener.reset(false, false);
- fListener.addUpdates(getCTargetViewer(), TreePath.EMPTY, model.getRootElement(), -1, ALL_UPDATES_COMPLETE);
+ fListener.addUpdates(getInternalViewer(), TreePath.EMPTY, model.getRootElement(), -1, ALL_UPDATES_COMPLETE);
model.postDelta(new ModelDelta(model.getRootElement(), IModelDelta.CONTENT));
while (!fListener.isFinished(ALL_UPDATES_COMPLETE | STATE_RESTORE_COMPLETE))
if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
// Validate data
model.validateData(fViewer, TreePath.EMPTY, true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("2")) == false);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3.1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("4")) == false);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("5")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("5.1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("6")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("2")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("4")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("5")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("5.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("6")) == false);
Assert.assertTrue( areTreeSelectionsEqual(originalSelection, (ITreeSelection)fViewer.getSelection()) );
// Update the model again
@@ -494,25 +498,25 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
// Note: Re-expanding nodes causes redundant updates.
fListener.reset(false, false);
- fListener.addUpdates(getCTargetViewer(), TreePath.EMPTY, model.getRootElement(), -1, ALL_UPDATES_COMPLETE);
+ fListener.addUpdates(getInternalViewer(), TreePath.EMPTY, model.getRootElement(), -1, ALL_UPDATES_COMPLETE);
model.postDelta(new ModelDelta(model.getRootElement(), IModelDelta.CONTENT));
while (!fListener.isFinished(ALL_UPDATES_COMPLETE | STATE_RESTORE_COMPLETE))
if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
// Validate data
model.validateData(fViewer, TreePath.EMPTY, true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("2")) == false);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3.1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("4")) == false);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("5")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("5.1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("6")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("2")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("4")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("5")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("5.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("6")) == false);
Assert.assertTrue( areTreeSelectionsEqual(originalSelection, (ITreeSelection)fViewer.getSelection()) );
}
}
- public void _X_testPreserveLargeModelOnContent() throws InterruptedException {
+ public void testPreserveLargeModelOnContent() throws InterruptedException {
//TreeModelViewerAutopopulateAgent autopopulateAgent = new TreeModelViewerAutopopulateAgent(fViewer);
TestModel model = alternatingSubsreesModel(100);
@@ -523,10 +527,10 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
// Set the input into the view and update the view.
fViewer.setInput(model.getRootElement());
- while (!fListener.isFinished(CONTENT_UPDATES_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ while (!fListener.isFinished(CONTENT_SEQUENCE_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
// model.validateData(fViewer, TreePath.EMPTY, true);
- expandAlternateElements(model, false);
+ expandAlternateElements(fListener, model, false);
// Set a selection in view
TreeSelection originalSelection = new TreeSelection(model.findElement("5.1.1"));
@@ -539,16 +543,16 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
// Note: Re-expanding nodes causes redundant updates.
fListener.reset(false, false);
model.postDelta(new ModelDelta(model.getRootElement(), IModelDelta.CONTENT));
- while (!fListener.isFinished(CONTENT_UPDATES_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ while (!fListener.isFinished(CONTENT_SEQUENCE_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
// Validate data
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("2")) == false);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3.1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("4")) == false);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("5")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("5.1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("6")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("2")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("4")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("5")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("5.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("6")) == false);
Assert.assertTrue( areTreeSelectionsEqual(originalSelection, (ITreeSelection)fViewer.getSelection()) );
// Update the model again
@@ -557,16 +561,16 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
// Note: Re-expanding nodes causes redundant updates.
fListener.reset(false, false);
model.postDelta(new ModelDelta(model.getRootElement(), IModelDelta.CONTENT));
- while (!fListener.isFinished(CONTENT_UPDATES_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ while (!fListener.isFinished(CONTENT_SEQUENCE_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
// Validate data
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("2")) == false);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3.1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("4")) == false);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("5")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("5.1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("6")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("2")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("4")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("5")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("5.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("6")) == false);
Assert.assertTrue( areTreeSelectionsEqual(originalSelection, (ITreeSelection)fViewer.getSelection()) );
}
@@ -675,7 +679,7 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
// Check to make sure that the state restore didn't change the selection.
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3.1")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3.1")) == false);
}
public void testPreserveExpandDeltaAfterContent() throws InterruptedException {
@@ -716,7 +720,7 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
// Check to make sure that the state restore didn't change the selection.
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3.1")) == true);
}
@@ -735,7 +739,7 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
model.validateData(fViewer, TreePath.EMPTY, true);
// Expand some, but not all elements
- expandAlternateElements(model, true);
+ expandAlternateElements(fListener, model, true);
// Set a selection in view
fViewer.setSelection(new TreeSelection(new TreePath[] { model.findElement("5.1"), model.findElement("5.1.1"), model.findElement("6.1.1") } ));
@@ -746,7 +750,7 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
// Set the viewer input to null. This will trigger the view to save the viewer state.
fListener.reset(false, false);
- fListener.addStateUpdates(getCTargetViewer(), originalState, IModelDelta.EXPAND | IModelDelta.SELECT | IModelDelta.REVEAL);
+ fListener.addStateUpdates(getInternalViewer(), originalState, IModelDelta.EXPAND | IModelDelta.SELECT | IModelDelta.REVEAL);
fViewer.setInput(null);
while (!fListener.isFinished(STATE_SAVE_COMPLETE | STATE_UPDATES))
if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
@@ -796,7 +800,7 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
// Set the viewer input to null. This will trigger the view to save the viewer state.
fListener.reset(true, false);
- fListener.addStateUpdates(getCTargetViewer(), originalState, IModelDelta.EXPAND | IModelDelta.SELECT | IModelDelta.REVEAL);
+ fListener.addStateUpdates(getInternalViewer(), originalState, IModelDelta.EXPAND | IModelDelta.SELECT | IModelDelta.REVEAL);
fViewer.setInput(null);
while (!fListener.isFinished(STATE_SAVE_COMPLETE | STATE_UPDATES))
@@ -819,6 +823,93 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
}
}
+ public void testSaveAndRestoreInputInstance() throws InterruptedException {
+ //TreeModelViewerAutopopulateAgent autopopulateAgent = new TreeModelViewerAutopopulateAgent(fViewer);
+ TestModel model = alternatingSubsreesModel(6);
+
+ // NOTE: WE ARE NOT EXPANDING ANY CHILDREN
+
+ // Create the listener, only check the first level
+ fListener.reset(TreePath.EMPTY, model.getRootElement(), 1, true, false);
+
+ // Set the input into the view and update the view.
+ fViewer.setInput(model.getRootElement());
+ while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ model.validateData(fViewer, TreePath.EMPTY, true);
+
+ // Expand some, but not all elements
+ expandAlternateElements(fListener, model, true);
+
+ // Set a selection in view
+ fViewer.setSelection(new TreeSelection(new TreePath[] { model.findElement("5.1"), model.findElement("5.1.1"), model.findElement("6.1.1") } ));
+
+ // Extract the original state from viewer
+ ModelDelta originalState = new ModelDelta(model.getRootElement(), IModelDelta.NO_CHANGE);
+ fViewer.saveElementState(TreePath.EMPTY, originalState, IModelDelta.EXPAND | IModelDelta.SELECT);
+
+ // Do not reset to null, just reset input to the same object.
+
+ // Set the viewer input back to the model. When view updates are complete
+ // the viewer
+ // Note: disable redundant updates because the reveal delta triggers one.
+ fListener.reset(TreePath.EMPTY, model.getRootElement(), 1, false, false);
+ fViewer.setInput(model.getRootElement());
+ while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+
+ // Extract the restored state from viewer
+ ModelDelta restoredState = new ModelDelta(model.getRootElement(), IModelDelta.NO_CHANGE);
+ fViewer.saveElementState(TreePath.EMPTY, restoredState, IModelDelta.EXPAND | IModelDelta.SELECT);
+
+ if (!deltaMatches(originalState, restoredState)) {
+ Assert.fail("Expected:\n" + originalState.toString() + "\nGot:\n" + restoredState);
+ }
+ }
+
+ public void testSaveAndRestoreInputInstanceEquals() throws InterruptedException {
+ //TreeModelViewerAutopopulateAgent autopopulateAgent = new TreeModelViewerAutopopulateAgent(fViewer);
+ TestModel model = alternatingSubsreesModel(6);
+
+ // NOTE: WE ARE NOT EXPANDING ANY CHILDREN
+
+ // Create the listener, only check the first level
+ fListener.reset(TreePath.EMPTY, model.getRootElement(), 1, true, false);
+
+ // Set the input into the view and update the view.
+ fViewer.setInput(model.getRootElement());
+ while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ model.validateData(fViewer, TreePath.EMPTY, true);
+
+ // Expand some, but not all elements
+ expandAlternateElements(fListener, model, true);
+
+ // Set a selection in view
+ fViewer.setSelection(new TreeSelection(new TreePath[] { model.findElement("5.1"), model.findElement("5.1.1"), model.findElement("6.1.1") } ));
+
+ // Extract the original state from viewer
+ ModelDelta originalState = new ModelDelta(model.getRootElement(), IModelDelta.NO_CHANGE);
+ fViewer.saveElementState(TreePath.EMPTY, originalState, IModelDelta.EXPAND | IModelDelta.SELECT);
+
+ // Create a copy of the input object and set it to model.
+ TestElement newRoot = new TestElement(model, model.getRootElement().getID(), model.getRootElement().getChildren());
+ model.setRoot(newRoot);
+
+ // Set the viewer input back to the model. When view updates are complete
+ // the viewer
+ // Note: disable redundant updates because the reveal delta triggers one.
+ fListener.reset(TreePath.EMPTY, model.getRootElement(), 1, false, false);
+
+ fViewer.setInput(model.getRootElement());
+ while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+
+ // Extract the restored state from viewer
+ ModelDelta restoredState = new ModelDelta(model.getRootElement(), IModelDelta.NO_CHANGE);
+ fViewer.saveElementState(TreePath.EMPTY, restoredState, IModelDelta.EXPAND | IModelDelta.SELECT);
+
+ if (!deltaMatches(originalState, restoredState)) {
+ Assert.fail("Expected:\n" + originalState.toString() + "\nGot:\n" + restoredState);
+ }
+ }
+
public void testSaveAndRestoreLarge() throws InterruptedException {
//TreeModelViewerAutopopulateAgent autopopulateAgent = new TreeModelViewerAutopopulateAgent(fViewer);
@@ -831,9 +922,9 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
// Set the input into the view and update the view.
fViewer.setInput(model.getRootElement());
- while (!fListener.isFinished(CONTENT_UPDATES_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ while (!fListener.isFinished(CONTENT_SEQUENCE_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
- expandAlternateElements(model, false);
+ expandAlternateElements(fListener, model, false);
// Set a selection in view
TreeSelection originalSelection = new TreeSelection(model.findElement("5.1.1"));
@@ -846,7 +937,7 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
// Set the viewer input to null. This will trigger the view to save the viewer state.
fListener.reset();
- fListener.addStateUpdates(getCTargetViewer(), originalState, IModelDelta.EXPAND | IModelDelta.SELECT | IModelDelta.REVEAL);
+ fListener.addStateUpdates(getInternalViewer(), originalState, IModelDelta.EXPAND | IModelDelta.SELECT | IModelDelta.REVEAL);
fViewer.setInput(null);
while (!fListener.isFinished(STATE_SAVE_COMPLETE | STATE_UPDATES))
@@ -857,18 +948,18 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
// Note: disable redundant updates because the reveal delta triggers one.
fListener.reset();
fViewer.setInput(model.getRootElement());
- while (!fListener.isFinished(CONTENT_UPDATES_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ while (!fListener.isFinished(CONTENT_SEQUENCE_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
// Validate data (only select visible elements).
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("1.1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("2")) == false);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3.1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("4")) == false);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("5")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("5.1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("6")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("1.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("2")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("4")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("5")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("5.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("6")) == false);
Assert.assertTrue( areTreeSelectionsEqual(originalSelection, (ITreeSelection)fViewer.getSelection()) );
}
@@ -888,9 +979,9 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
// Set the input into the view and update the view.
fViewer.setInput(model.getRootElement());
- while (!fListener.isFinished(CONTENT_UPDATES_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ while (!fListener.isFinished(CONTENT_SEQUENCE_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
- expandAlternateElements(model, false);
+ expandAlternateElements(fListener, model, false);
// Set a selection in view
TreeSelection originalSelection = new TreeSelection(model.findElement("5.1.1"));
@@ -903,7 +994,7 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
// Set the viewer input to null. This will trigger the view to save the viewer state.
fListener.reset();
- fListener.addStateUpdates(getCTargetViewer(), originalState, IModelDelta.EXPAND | IModelDelta.SELECT | IModelDelta.REVEAL);
+ fListener.addStateUpdates(getInternalViewer(), originalState, IModelDelta.EXPAND | IModelDelta.SELECT | IModelDelta.REVEAL);
fViewer.setInput(null);
while (!fListener.isFinished(STATE_SAVE_COMPLETE | STATE_UPDATES))
@@ -922,18 +1013,18 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
fViewer.setInput(model.getRootElement());
// MONITOR FOR THE STATE RESTORE TO COMPLETE
- while (!fListener.isFinished(CONTENT_UPDATES_COMPLETE| STATE_RESTORE_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ while (!fListener.isFinished(CONTENT_SEQUENCE_COMPLETE| STATE_RESTORE_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
// Validate data
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("1.1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("2")) == false);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3.1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("4")) == false);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("5")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("5.1")) == true);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("6")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("1.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("2")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("4")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("5")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("5.1")) == true);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("6")) == false);
Assert.assertTrue( areTreeSelectionsEqual(originalSelection, (ITreeSelection)fViewer.getSelection()) );
}
@@ -998,9 +1089,39 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi
if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
// Check to make sure that the state restore didn't change the selection.
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("2")) == false);
- Assert.assertTrue(getCTargetViewer().getExpandedState(model.findElement("3")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("2")) == false);
+ Assert.assertTrue(getInternalViewer().getExpandedState(model.findElement("3")) == false);
Assert.assertEquals(new TreeSelection(model.findElement("1")), fViewer.getSelection());
}
+ /**
+ * Test for bug 359859.<br>
+ * This test verifies that RESTORE state is handled after SAVE previous state was completed
+ */
+ public void testSaveRestoreOrder() throws InterruptedException {
+ //TreeModelViewerAutopopulateAgent autopopulateAgent = new TreeModelViewerAutopopulateAgent(fViewer);
+ TestModel model = TestModel.simpleMultiLevel();
+
+ // Expand all
+ fViewer.setAutoExpandLevel(-1);
+
+ // Create the listener.
+ fListener.reset(TreePath.EMPTY, model.getRootElement(), -1, false, false);
+
+ // Set the input into the view and update the view.
+ fViewer.setInput(model.getRootElement());
+ while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ model.validateData(fViewer, TreePath.EMPTY, true);
+
+ // a new similar model
+ TestModel copyModel = TestModel.simpleMultiLevel();
+
+ // Trigger save - restore sequence.
+ fListener.reset();
+ fListener.expectRestoreAfterSaveComplete();
+ fViewer.setInput(copyModel.getRootElement());
+ while (!fListener.isFinished(STATE_RESTORE_STARTED)) Thread.sleep(0);
+ Assert.assertTrue("RESTORE started before SAVE to complete", fListener.isFinished(STATE_SAVE_COMPLETE));
+ }
+
}
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/TestModel.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/TestModel.java
index 6647bd226..e497d5837 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/TestModel.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/TestModel.java
@@ -10,14 +10,15 @@
*******************************************************************************/
package org.eclipe.debug.tests.viewer.model;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
import junit.framework.Assert;
import org.eclipse.core.runtime.PlatformObject;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelCheckProviderTarget;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelContentProviderTarget;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.IInternalTreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ICheckUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
@@ -34,10 +35,13 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactor
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicyFactory;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.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.provisional.AbstractModelProxy;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
/**
* Test model for the use in unit tests. This test model contains a set of
@@ -158,7 +162,8 @@ public class TestModel implements IElementContentProvider, IElementLabelProvider
private TreePath fRootPath = TreePath.EMPTY;
private ModelProxy fModelProxy;
private IModelSelectionPolicy fModelSelectionPolicy;
-
+ private boolean fQueueingUpdates = false;
+ private List fQueuedUpdates = new LinkedList();
/**
* Constructor private. Use static factory methods instead.
@@ -207,46 +212,109 @@ public class TestModel implements IElementContentProvider, IElementLabelProvider
return depth;
}
+ public void setQeueueingUpdate(boolean queueingUpdates) {
+ fQueueingUpdates = queueingUpdates;
+ if (!fQueueingUpdates) {
+ processQueuedUpdates();
+ }
+ }
+
+ public List getQueuedUpdates() {
+ return fQueuedUpdates;
+ }
+
+ public void processQueuedUpdates() {
+ List updates = new ArrayList(fQueuedUpdates);
+ fQueuedUpdates.clear();
+ for (int i = 0; i < updates.size(); i++) {
+ processUpdate((IViewerUpdate)updates.get(i));
+ }
+ }
+
+ public void processUpdate(IViewerUpdate update) {
+ if (update instanceof IHasChildrenUpdate) {
+ doUpdate((IHasChildrenUpdate)update);
+ } else if (update instanceof IChildrenCountUpdate) {
+ doUpdate((IChildrenCountUpdate)update);
+ } else if (update instanceof IChildrenUpdate) {
+ doUpdate((IChildrenUpdate)update);
+ } else if (update instanceof ILabelUpdate) {
+ doUpdate((ILabelUpdate)update);
+ }
+ }
+
public void update(IHasChildrenUpdate[] updates) {
- for (int i = 0; i < updates.length; i++) {
- TestElement element = (TestElement)updates[i].getElement();
- updates[i].setHasChilren(element.getChildren().length > 0);
- updates[i].done();
+ if (fQueueingUpdates) {
+ fQueuedUpdates.addAll(Arrays.asList(updates));
+ } else {
+ for (int i = 0; i < updates.length; i++) {
+ doUpdate(updates[i]);
+ }
}
}
+
+ private void doUpdate(IHasChildrenUpdate update) {
+ TestElement element = (TestElement)update.getElement();
+ update.setHasChilren(element.getChildren().length > 0);
+ update.done();
+ }
public void update(IChildrenCountUpdate[] updates) {
- for (int i = 0; i < updates.length; i++) {
- TestElement element = (TestElement)updates[i].getElement();
- updates[i].setChildCount(element.getChildren().length);
- updates[i].done();
+ if (fQueueingUpdates) {
+ fQueuedUpdates.addAll(Arrays.asList(updates));
+ } else {
+ for (int i = 0; i < updates.length; i++) {
+ doUpdate(updates[i]);
+ }
}
}
+
+ private void doUpdate(IChildrenCountUpdate update) {
+ TestElement element = (TestElement)update.getElement();
+ update.setChildCount(element.getChildren().length);
+ update.done();
+ }
public void update(IChildrenUpdate[] updates) {
- for (int i = 0; i < updates.length; i++) {
- TestElement element = (TestElement)updates[i].getElement();
- int endOffset = updates[i].getOffset() + updates[i].getLength();
- for (int j = updates[i].getOffset(); j < endOffset; j++) {
- if (j < element.getChildren().length) {
- updates[i].setChild(element.getChildren()[j], j);
- }
+ if (fQueueingUpdates) {
+ fQueuedUpdates.addAll(Arrays.asList(updates));
+ } else {
+ for (int i = 0; i < updates.length; i++) {
+ doUpdate(updates[i]);
}
- updates[i].done();
}
}
+
+ private void doUpdate(IChildrenUpdate update) {
+ TestElement element = (TestElement)update.getElement();
+ int endOffset = update.getOffset() + update.getLength();
+ for (int j = update.getOffset(); j < endOffset; j++) {
+ if (j < element.getChildren().length) {
+ update.setChild(element.getChildren()[j], j);
+ }
+ }
+ update.done();
+ }
public void update(ILabelUpdate[] updates) {
- for (int i = 0; i < updates.length; i++) {
- TestElement element = (TestElement)updates[i].getElement();
- updates[i].setLabel(element.getLabel(), 0);
- if (updates[i] instanceof ICheckUpdate &&
- Boolean.TRUE.equals(updates[i].getPresentationContext().getProperty(ICheckUpdate.PROP_CHECK)))
- {
- ((ICheckUpdate)updates[i]).setChecked(element.getChecked(), element.getGrayed());
+ if (fQueueingUpdates) {
+ fQueuedUpdates.addAll(Arrays.asList(updates));
+ } else {
+ for (int i = 0; i < updates.length; i++) {
+ doUpdate(updates[i]);
}
- updates[i].done();
- }
+ }
+ }
+
+ private void doUpdate(ILabelUpdate update) {
+ TestElement element = (TestElement)update.getElement();
+ update.setLabel(element.getLabel(), 0);
+ if (update instanceof ICheckUpdate &&
+ Boolean.TRUE.equals(update.getPresentationContext().getProperty(ICheckUpdate.PROP_CHECK)))
+ {
+ ((ICheckUpdate)update).setChecked(element.getChecked(), element.getGrayed());
+ }
+ update.done();
}
public final static String ELEMENT_MEMENTO_ID = "id";
@@ -326,24 +394,32 @@ public class TestModel implements IElementContentProvider, IElementLabelProvider
public void validateData(ITreeModelViewer viewer, TreePath path) {
validateData(viewer, path, false);
}
-
+
public void validateData(ITreeModelViewer _viewer, TreePath path, boolean expandedElementsOnly) {
- ITreeModelContentProviderTarget viewer = (ITreeModelContentProviderTarget)_viewer;
+ validateData(_viewer, path, expandedElementsOnly, TestModelUpdatesListener.EMPTY_FILTER_ARRAY);
+ }
+
+ public void validateData(ITreeModelViewer _viewer, TreePath path, boolean expandedElementsOnly, ViewerFilter[] filters) {
+ IInternalTreeModelViewer viewer = (IInternalTreeModelViewer)_viewer;
TestElement element = getElement(path);
if ( Boolean.TRUE.equals(_viewer.getPresentationContext().getProperty(ICheckUpdate.PROP_CHECK)) ) {
- ITreeModelCheckProviderTarget checkTarget = (ITreeModelCheckProviderTarget)_viewer;
- Assert.assertEquals(element.getChecked(), checkTarget.getElementChecked(path));
- Assert.assertEquals(element.getGrayed(), checkTarget.getElementGrayed(path));
+ Assert.assertEquals(element.getChecked(), viewer.getElementChecked(path));
+ Assert.assertEquals(element.getGrayed(), viewer.getElementGrayed(path));
}
if (!expandedElementsOnly || path.getSegmentCount() == 0 || viewer.getExpandedState(path) ) {
TestElement[] children = element.getChildren();
- Assert.assertEquals(children.length, viewer.getChildCount(path));
+ int viewerIndex = 0;
for (int i = 0; i < children.length; i++) {
- Assert.assertEquals(children[i], viewer.getChildElement(path, i));
- validateData(viewer, path.createChildPath(children[i]), expandedElementsOnly);
+ if (TestModelUpdatesListener.isFiltered(children[i], filters)) {
+ continue;
+ }
+ Assert.assertEquals(children[i], viewer.getChildElement(path, viewerIndex));
+ validateData(viewer, path.createChildPath(children[i]), expandedElementsOnly, filters);
+ viewerIndex++;
}
+ Assert.assertEquals(viewerIndex, viewer.getChildCount(path));
} else if (!viewer.getExpandedState(path)) {
// If element not expanded, verify the plus sign.
Assert.assertEquals(viewer.getHasChildren(path), element.getChildren().length > 0);
@@ -590,17 +666,28 @@ public class TestModel implements IElementContentProvider, IElementLabelProvider
public static TestModel simpleSingleLevel() {
TestModel model = new TestModel();
- model.setRoot( new TestElement(model, "root", new TestElement[] {
- new TestElement(model, "1", true, true, new TestElement[0]),
- new TestElement(model, "2", true, false, new TestElement[0]),
- new TestElement(model, "3", false, true, new TestElement[0]),
- new TestElement(model, "4", false, false, new TestElement[0]),
- new TestElement(model, "5", new TestElement[0]),
- new TestElement(model, "6", new TestElement[0])
- }) );
+ model.setRoot( new TestElement(model, "root", makeSingleLevelModelElements(model, 6, "")));
return model;
}
+
+ public static TestElement[] makeSingleLevelModelElements(TestModel model, int length, String prefix) {
+ TestElement[] elements = new TestElement[length];
+ for (int i = 1; i <= length; i++) {
+ String name = prefix + i;
+ elements[i - 1] = new TestElement(model, name, new TestElement[0]);
+ }
+ return elements;
+ }
+ public static TestElement[] makeMultiLevelElements(TestModel model, int depth, String prefix) {
+ TestElement[] elements = new TestElement[depth];
+ for (int i = 0; i < depth; i++) {
+ String name = prefix + i;
+ elements[i] = new TestElement(model, name, makeMultiLevelElements(model, i, name + "."));
+ }
+ return elements;
+ }
+
public static TestModel simpleMultiLevel() {
TestModel model = new TestModel();
model.setRoot( new TestElement(model, "root", new TestElement[] {
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/TestModelUpdatesListener.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/TestModelUpdatesListener.java
index 31a3523f2..8b540b121 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/TestModelUpdatesListener.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/TestModelUpdatesListener.java
@@ -27,9 +27,8 @@ import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.IJobChangeListener;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.internal.ui.viewers.model.ElementCompareRequest;
+import org.eclipse.debug.internal.ui.viewers.model.IInternalTreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.ILabelUpdateListener;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelContentProviderTarget;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
@@ -38,14 +37,18 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelChangedList
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.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.jface.viewers.TreePath;
+import org.eclipse.jface.viewers.ViewerFilter;
public class TestModelUpdatesListener
implements IViewerUpdateListener, ILabelUpdateListener, IModelChangedListener, ITestModelUpdatesListenerConstants,
IStateUpdateListener, IJobChangeListener
{
+ public static final ViewerFilter[] EMPTY_FILTER_ARRAY = new ViewerFilter[0];
+
private final ITreeModelViewer fViewer;
private IStatus fJobError;
@@ -60,9 +63,7 @@ public class TestModelUpdatesListener
private Set fRedundantLabelUpdateExceptions = new HashSet();
private boolean fFailOnMultipleModelUpdateSequences;
- private boolean fMultipleModelUpdateSequencesObserved;
private boolean fFailOnMultipleLabelUpdateSequences;
- private boolean fMultipleLabelUpdateSequencesObserved;
private Set fHasChildrenUpdatesScheduled = new HashSet();
private Set fHasChildrenUpdatesRunning = new HashSet();
@@ -78,10 +79,14 @@ public class TestModelUpdatesListener
private Set fLabelUpdatesCompleted = new HashSet();
private Set fProxyModels = new HashSet();
private Set fStateUpdates = new HashSet();
- private boolean fViewerUpdatesStarted;
- private boolean fViewerUpdatesComplete;
- private boolean fLabelUpdatesStarted;
- private boolean fLabelUpdatesComplete;
+ private int fViewerUpdatesStarted = 0;
+ private int fViewerUpdatesComplete = 0;
+ private int fViewerUpdatesStartedAtReset;
+ private int fViewerUpdatesCompleteAtReset;
+ private int fLabelUpdatesStarted = 0;
+ private int fLabelUpdatesComplete = 0;
+ private int fLabelUpdatesStartedAtReset;
+ private int fLabelUpdatesCompleteAtReset;
private boolean fModelChangedComplete;
private boolean fStateSaveStarted;
private boolean fStateSaveComplete;
@@ -91,6 +96,10 @@ public class TestModelUpdatesListener
private int fLabelUpdatesCounter;
private int fTimeoutInterval = 60000;
private long fTimeoutTime;
+
+ private boolean fExpectRestoreAfterSaveComplete;
+
+ private RuntimeException fFailExpectation;
public TestModelUpdatesListener(ITreeModelViewer viewer, boolean failOnRedundantUpdates, boolean failOnMultipleModelUpdateSequences) {
@@ -143,6 +152,10 @@ public class TestModelUpdatesListener
public void setFailOnMultipleLabelUpdateSequences(boolean failOnMultipleLabelUpdateSequences) {
fFailOnMultipleLabelUpdateSequences = failOnMultipleLabelUpdateSequences;
}
+
+ public void expectRestoreAfterSaveComplete() {
+ fExpectRestoreAfterSaveComplete = true;
+ }
/**
* Sets the the maximum amount of time (in milliseconds) that the update listener
@@ -153,8 +166,12 @@ public class TestModelUpdatesListener
}
public void reset(TreePath path, TestElement element, int levels, boolean failOnRedundantUpdates, boolean failOnMultipleUpdateSequences) {
+ reset(path, element, EMPTY_FILTER_ARRAY, levels, failOnRedundantUpdates, failOnMultipleUpdateSequences);
+ }
+
+ public void reset(TreePath path, TestElement element, ViewerFilter[] filters, int levels, boolean failOnRedundantUpdates, boolean failOnMultipleUpdateSequences) {
reset();
- addUpdates(path, element, levels);
+ addUpdates(path, element, filters, levels);
addProxies(element);
setFailOnRedundantUpdates(failOnRedundantUpdates);
setFailOnMultipleModelUpdateSequences(failOnMultipleUpdateSequences);
@@ -170,14 +187,13 @@ public class TestModelUpdatesListener
public void reset() {
fJobError = null;
+ fFailExpectation = null;
fRedundantUpdates.clear();
fRedundantLabelUpdates.clear();
fRedundantHasChildrenUpdateExceptions.clear();
fRedundantChildCountUpdateExceptions.clear();
fRedundantChildrenUpdateExceptions.clear();
fRedundantLabelUpdateExceptions.clear();
- fMultipleLabelUpdateSequencesObserved = false;
- fMultipleModelUpdateSequencesObserved = false;
fHasChildrenUpdatesScheduled.clear();
fHasChildrenUpdatesRunning.clear();
fHasChildrenUpdatesCompleted.clear();
@@ -191,15 +207,16 @@ public class TestModelUpdatesListener
fLabelUpdatesRunning.clear();
fLabelUpdatesCompleted.clear();
fProxyModels.clear();
- fViewerUpdatesStarted = false;
- fViewerUpdatesComplete = false;
- fLabelUpdatesStarted = false;
- fLabelUpdatesComplete = false;
+ fViewerUpdatesStartedAtReset = fViewerUpdatesStarted;
+ fViewerUpdatesCompleteAtReset = fViewerUpdatesComplete;
+ fLabelUpdatesStartedAtReset = fLabelUpdatesStarted;
+ fLabelUpdatesCompleteAtReset = fLabelUpdatesComplete;
fStateUpdates.clear();
fStateSaveStarted = false;
fStateSaveComplete = false;
fStateRestoreStarted = false;
fStateRestoreComplete = false;
+ fExpectRestoreAfterSaveComplete = false;
fTimeoutTime = System.currentTimeMillis() + fTimeoutInterval;
resetModelChanged();
}
@@ -252,14 +269,18 @@ public class TestModelUpdatesListener
}
public void addUpdates(TreePath path, TestElement element, int levels) {
- addUpdates(path, element, levels, ALL_UPDATES_COMPLETE);
+ addUpdates(null, path, element, EMPTY_FILTER_ARRAY, levels, ALL_UPDATES_COMPLETE );
+ }
+
+ public void addUpdates(TreePath path, TestElement element, ViewerFilter[] filters, int levels) {
+ addUpdates(null, path, element, filters, levels, ALL_UPDATES_COMPLETE );
}
- public void addStateUpdates(ITreeModelContentProviderTarget viewer, TreePath path, TestElement element) {
+ public void addStateUpdates(IInternalTreeModelViewer viewer, TreePath path, TestElement element) {
addUpdates(viewer, path, element, -1, STATE_UPDATES);
}
- public void addStateUpdates(ITreeModelContentProviderTarget viewer, IModelDelta pendingDelta, int deltaFlags) {
+ public void addStateUpdates(IInternalTreeModelViewer viewer, IModelDelta pendingDelta, int deltaFlags) {
TreePath treePath = getViewerTreePath(pendingDelta);
if ( !TreePath.EMPTY.equals(treePath) && (pendingDelta.getFlags() & deltaFlags) != 0 ) {
addUpdates(viewer, treePath, (TestElement)treePath.getLastSegment(), 0, STATE_UPDATES);
@@ -286,6 +307,33 @@ public class TestModelUpdatesListener
fRedundantLabelUpdateExceptions.add(path);
}
+ public boolean checkCoalesced(TreePath path, int offset, int length) {
+ for (Iterator itr = fChildrenUpdatesCompleted.iterator(); itr.hasNext();) {
+ IChildrenUpdate update = (IChildrenUpdate)itr.next();
+ if (path.equals( update.getElementPath() ) &&
+ offset == update.getOffset() &&
+ length == update.getLength())
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+
+ public Set getHasChildrenUpdatesCompleted() {
+ return fHasChildrenUpdatesCompleted;
+ }
+
+ public Set getChildCountUpdatesCompleted() {
+ return fChildCountUpdatesCompleted;
+ }
+
+ public Set getChildrenUpdatesCompleted() {
+ return fChildrenUpdatesCompleted;
+ }
+
/**
* Returns a tree path for the node, *not* including the root element.
*
@@ -308,7 +356,24 @@ public class TestModelUpdatesListener
addUpdates(null, path, element, levels, flags);
}
- public void addUpdates(ITreeModelContentProviderTarget viewer, TreePath path, TestElement element, int levels, int flags) {
+ public void addUpdates(IInternalTreeModelViewer viewer, TreePath path, TestElement element, int levels, int flags) {
+ addUpdates(viewer, path, element, EMPTY_FILTER_ARRAY, levels, flags);
+ }
+
+ public static boolean isFiltered(Object element, ViewerFilter[] filters) {
+ for (int i = 0; i < filters.length; i++) {
+ if (!filters[i].select(null, null, element)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void addUpdates(IInternalTreeModelViewer viewer, TreePath path, TestElement element, ViewerFilter[] filters, int levels, int flags) {
+ if (isFiltered(path.getLastSegment(), filters)) {
+ return;
+ }
+
if (!path.equals(TreePath.EMPTY)) {
if ((flags & LABEL_UPDATES) != 0) {
fLabelUpdates.add(path);
@@ -331,13 +396,15 @@ public class TestModelUpdatesListener
if ((flags & CHILDREN_UPDATES) != 0) {
Set childrenIndexes = new HashSet();
for (int i = 0; i < children.length; i++) {
- childrenIndexes.add(new Integer(i));
+ if (!isFiltered(children[i], filters)) {
+ childrenIndexes.add(new Integer(i));
+ }
}
fChildrenUpdatesScheduled.put(path, childrenIndexes);
}
for (int i = 0; i < children.length; i++) {
- addUpdates(viewer, path.createChildPath(children[i]), children[i], levels, flags);
+ addUpdates(viewer, path.createChildPath(children[i]), children[i], filters, levels, flags);
}
}
@@ -368,37 +435,41 @@ public class TestModelUpdatesListener
throw new RuntimeException("Timed Out: " + toString(flags));
}
+ if (fFailExpectation != null) {
+ throw fFailExpectation;
+ }
+
if (fJobError != null) {
throw new RuntimeException("Job Error: " + fJobError);
}
-
+
if (fFailOnRedundantUpdates && !fRedundantUpdates.isEmpty()) {
Assert.fail("Redundant Updates: " + fRedundantUpdates.toString());
}
if (fFailOnRedundantLabelUpdates && !fRedundantLabelUpdates.isEmpty()) {
Assert.fail("Redundant Label Updates: " + fRedundantLabelUpdates.toString());
}
- if (fFailOnMultipleLabelUpdateSequences && !fMultipleLabelUpdateSequencesObserved) {
+ if (fFailOnMultipleLabelUpdateSequences && fLabelUpdatesComplete > (fLabelUpdatesCompleteAtReset + 1)) {
Assert.fail("Multiple label update sequences detected");
}
- if (fFailOnMultipleModelUpdateSequences && fMultipleModelUpdateSequencesObserved) {
+ if (fFailOnMultipleModelUpdateSequences && fViewerUpdatesComplete > (fViewerUpdatesCompleteAtReset + 1)) {
Assert.fail("Multiple viewer update sequences detected");
}
- if ( (flags & LABEL_UPDATES_COMPLETE) != 0) {
- if (!fLabelUpdatesComplete) return false;
+ if ( (flags & LABEL_SEQUENCE_COMPLETE) != 0) {
+ if (fLabelUpdatesComplete == fLabelUpdatesCompleteAtReset) return false;
}
- if ( (flags & LABEL_UPDATES_STARTED) != 0) {
- if (!fLabelUpdatesStarted) return false;
+ if ( (flags & LABEL_SEQUENCE_STARTED) != 0) {
+ if (fLabelUpdatesStarted == fLabelUpdatesStartedAtReset) return false;
}
if ( (flags & LABEL_UPDATES) != 0) {
if (!fLabelUpdates.isEmpty()) return false;
}
- if ( (flags & CONTENT_UPDATES_STARTED) != 0) {
- if (!fViewerUpdatesStarted) return false;
+ if ( (flags & CONTENT_SEQUENCE_STARTED) != 0) {
+ if (fViewerUpdatesStarted == fViewerUpdatesStartedAtReset) return false;
}
- if ( (flags & CONTENT_UPDATES_COMPLETE) != 0) {
- if (!fViewerUpdatesComplete) return false;
+ if ( (flags & CONTENT_SEQUENCE_COMPLETE) != 0) {
+ if (fViewerUpdatesComplete == fViewerUpdatesCompleteAtReset) return false;
}
if ( (flags & HAS_CHILDREN_UPDATES_STARTED) != 0) {
if (fHasChildrenUpdatesRunning.isEmpty() && fHasChildrenUpdatesCompleted.isEmpty()) return false;
@@ -517,22 +588,23 @@ public class TestModelUpdatesListener
}
public void viewerUpdatesBegin() {
- if (fFailOnMultipleModelUpdateSequences && fViewerUpdatesComplete) {
- fMultipleModelUpdateSequencesObserved = true;
+ if (fViewerUpdatesStarted > fViewerUpdatesComplete) {
+ fFailExpectation = new RuntimeException("Unmatched updatesStarted/updateCompleted notifications observed.");
}
- fViewerUpdatesStarted = true;
+ fViewerUpdatesStarted++;
}
public void viewerUpdatesComplete() {
- fViewerUpdatesComplete = true;
+ if (fViewerUpdatesStarted <= fViewerUpdatesComplete) {
+ fFailExpectation = new RuntimeException("Unmatched updatesStarted/updateCompleted notifications observed.");
+ }
+ fViewerUpdatesComplete++;
}
public void labelUpdateComplete(ILabelUpdate update) {
- synchronized (this) {
- fLabelUpdatesRunning.remove(update);
- fLabelUpdatesCompleted.add(update);
- fLabelUpdatesCounter--;
- }
+ fLabelUpdatesRunning.remove(update);
+ fLabelUpdatesCompleted.add(update);
+ fLabelUpdatesCounter--;
if (!fLabelUpdates.remove(update.getElementPath()) &&
fFailOnRedundantLabelUpdates &&
!fRedundantLabelUpdateExceptions.contains(update.getElementPath()))
@@ -543,21 +615,22 @@ public class TestModelUpdatesListener
}
public void labelUpdateStarted(ILabelUpdate update) {
- synchronized (this) {
- fLabelUpdatesRunning.add(update);
- fLabelUpdatesCounter++;
- }
+ fLabelUpdatesRunning.add(update);
+ fLabelUpdatesCounter++;
}
public void labelUpdatesBegin() {
- if (fFailOnMultipleLabelUpdateSequences && fLabelUpdatesComplete) {
- fMultipleLabelUpdateSequencesObserved = true;
+ if (fLabelUpdatesStarted > fLabelUpdatesComplete) {
+ fFailExpectation = new RuntimeException("Unmatched labelUpdatesStarted/labelUpdateCompleted notifications observed.");
}
- fLabelUpdatesStarted = true;
+ fLabelUpdatesStarted++;
}
public void labelUpdatesComplete() {
- fLabelUpdatesComplete = true;
+ if (fLabelUpdatesStarted <= fLabelUpdatesComplete) {
+ fFailExpectation = new RuntimeException("Unmatched labelUpdatesStarted/labelUpdateCompleted notifications observed.");
+ }
+ fLabelUpdatesComplete++;
}
public void modelChanged(IModelDelta delta, IModelProxy proxy) {
@@ -573,6 +646,9 @@ public class TestModelUpdatesListener
}
public void stateRestoreUpdatesBegin(Object input) {
+ if (fExpectRestoreAfterSaveComplete && !fStateSaveComplete) {
+ fFailExpectation = new RuntimeException("RESTORE should begin after SAVE completed!");
+ }
fStateRestoreStarted = true;
}
@@ -617,15 +693,7 @@ public class TestModelUpdatesListener
buf.append("\n\t");
buf.append("fRedundantUpdates = " + fRedundantUpdates);
}
- if (fFailOnMultipleLabelUpdateSequences) {
- buf.append("\n\t");
- buf.append("fMultipleLabelUpdateSequencesObserved = " + fMultipleLabelUpdateSequencesObserved);
- }
- if (fFailOnMultipleModelUpdateSequences) {
- buf.append("\n\t");
- buf.append("fMultipleModelUpdateSequencesObserved = " + fMultipleModelUpdateSequencesObserved);
- }
- if ( (flags & LABEL_UPDATES_COMPLETE) != 0) {
+ if ( (flags & LABEL_SEQUENCE_COMPLETE) != 0) {
buf.append("\n\t");
buf.append("fLabelUpdatesComplete = " + fLabelUpdatesComplete);
}
@@ -633,10 +701,10 @@ public class TestModelUpdatesListener
buf.append("\n\t");
buf.append("fLabelUpdatesRunning = " + fLabelUpdatesCounter);
}
- if ( (flags & LABEL_UPDATES_STARTED) != 0) {
+ if ( (flags & LABEL_SEQUENCE_STARTED) != 0) {
buf.append("\n\t");
- buf.append("fLabelUpdatesRunning = ");
- buf.append( fLabelUpdatesRunning );
+ buf.append("fLabelUpdatesStarted = ");
+ buf.append( fLabelUpdatesStarted );
buf.append("\n\t");
buf.append("fLabelUpdatesCompleted = ");
buf.append( fLabelUpdatesCompleted );
@@ -646,14 +714,16 @@ public class TestModelUpdatesListener
buf.append("fLabelUpdates = ");
buf.append( toString(fLabelUpdates) );
}
- if ( (flags & CONTENT_UPDATES_COMPLETE) != 0) {
- buf.append("\n\t");
- buf.append("fViewerUpdatesComplete = " + fViewerUpdatesComplete);
- }
if ( (flags & VIEWER_UPDATES_RUNNING) != 0) {
buf.append("\n\t");
+ buf.append("fViewerUpdatesStarted = " + fViewerUpdatesStarted);
+ buf.append("\n\t");
buf.append("fViewerUpdatesRunning = " + fViewerUpdatesCounter);
}
+ if ( (flags & CONTENT_SEQUENCE_COMPLETE) != 0) {
+ buf.append("\n\t");
+ buf.append("fViewerUpdatesComplete = " + fViewerUpdatesComplete);
+ }
if ( (flags & HAS_CHILDREN_UPDATES_STARTED) != 0) {
buf.append("\n\t");
buf.append("fHasChildrenUpdatesRunning = ");
@@ -761,8 +831,10 @@ public class TestModelUpdatesListener
}
public String toString() {
- return toString(ALL_UPDATES_COMPLETE | MODEL_CHANGED_COMPLETE | STATE_RESTORE_COMPLETE | VIEWER_UPDATES_STARTED | LABEL_UPDATES_STARTED | STATE_UPDATES);
+ return toString(ALL_UPDATES_COMPLETE | MODEL_CHANGED_COMPLETE | STATE_SAVE_COMPLETE | STATE_RESTORE_COMPLETE | ALL_VIEWER_UPDATES_STARTED | LABEL_SEQUENCE_STARTED | STATE_UPDATES);
}
+
+
}
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/UpdateTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/UpdateTests.java
index 2f6a0985a..7e465bdd0 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/UpdateTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/UpdateTests.java
@@ -10,18 +10,27 @@
*******************************************************************************/
package org.eclipe.debug.tests.viewer.model;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
import junit.framework.TestCase;
import org.eclipe.debug.tests.viewer.model.TestModel.TestElement;
import org.eclipse.core.commands.ExecutionException;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+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.jface.viewers.TreePath;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
+import org.junit.Assert;
/**
* Tests to verify that the viewer property updates following changes in the
@@ -181,7 +190,7 @@ abstract public class UpdateTests extends TestCase implements ITestModelUpdatesL
model.postDelta(delta);
if (validate) {
- while (!fListener.isFinished(MODEL_CHANGED_COMPLETE | CONTENT_UPDATES_COMPLETE | LABEL_UPDATES_COMPLETE))
+ while (!fListener.isFinished(MODEL_CHANGED_COMPLETE | CONTENT_SEQUENCE_COMPLETE | LABEL_SEQUENCE_COMPLETE))
if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
model.validateData(fViewer, TreePath.EMPTY);
} else {
@@ -198,7 +207,7 @@ abstract public class UpdateTests extends TestCase implements ITestModelUpdatesL
model.postDelta(delta);
if (validate) {
- while (!fListener.isFinished(MODEL_CHANGED_COMPLETE | CONTENT_UPDATES_COMPLETE | LABEL_UPDATES_COMPLETE))
+ while (!fListener.isFinished(MODEL_CHANGED_COMPLETE | CONTENT_SEQUENCE_COMPLETE | LABEL_SEQUENCE_COMPLETE))
if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
model.validateData(fViewer, TreePath.EMPTY);
} else {
@@ -231,6 +240,33 @@ abstract public class UpdateTests extends TestCase implements ITestModelUpdatesL
addElement(model, "4-new", 4, true);
}
+ /**
+ * This test verifies that when the viewer processes a delta that causes viewer
+ * updates it initiates the model update sequence before it finishes processing
+ * the delta.
+ */
+ public void testNotifyUpdatesTartedOnModelChanged() throws InterruptedException {
+ TestModel model = TestModel.simpleSingleLevel();
+ fViewer.setAutoExpandLevel(-1);
+
+ // Create the listener
+ fListener.reset(TreePath.EMPTY, model.getRootElement(), -1, false, false);
+
+ // Set the input into the view and update the view.
+ fViewer.setInput(model.getRootElement());
+ while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ model.validateData(fViewer, TreePath.EMPTY);
+
+ // Refresh the viewer so that updates are generated.
+ fListener.reset();
+ model.postDelta(new ModelDelta(model.getRootElement(), IModelDelta.CONTENT));
+
+ // Wait for the delta to be processed.
+ while (!fListener.isFinished(MODEL_CHANGED_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+
+ Assert.assertTrue( fListener.isFinished(CONTENT_SEQUENCE_STARTED) );
+ }
+
/**
* This test case attempts to create a race condition between processing
@@ -326,4 +362,186 @@ abstract public class UpdateTests extends TestCase implements ITestModelUpdatesL
}
+ /**
+ * This test forces the viewer to cancel updates then process them at once.
+ * <p>
+ * - Wait until CHILDREN COUNT update started then refresh<br>
+ * - Process queued updates in order.<br>
+ * </p>
+ */
+ public void testCanceledUpdates1() throws InterruptedException {
+ TestModel model = TestModel.simpleSingleLevel();
+ fViewer.setAutoExpandLevel(-1);
+
+ // Create the listener
+ fListener.reset(TreePath.EMPTY, model.getRootElement(), -1, false, false);
+
+ // Set the input into the view and update the view.
+ fViewer.setInput(model.getRootElement());
+ while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ model.validateData(fViewer, TreePath.EMPTY);
+
+
+ model.setQeueueingUpdate(true);
+
+ for (int i = 0; i < 5; i++) {
+ // Refresh the viewer so that updates are generated.
+ fListener.reset();
+ model.postDelta(new ModelDelta(model.getRootElement(), IModelDelta.CONTENT));
+
+ // Wait for the delta to be processed.
+ while (!fListener.isFinished(MODEL_CHANGED_COMPLETE | CHILD_COUNT_UPDATES_STARTED)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+
+ }
+
+ model.setQeueueingUpdate(false);
+ while (!fListener.isFinished(ALL_UPDATES_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+
+ }
+
+ /**
+ * This test forces the viewer to cancel updates then process them at once.
+ * <p>
+ * - Wait until CHILDREN COUNT update started then refresh<br>
+ * - Process queued updates in REVERSE order.<br>
+ * </p>
+ */
+ public void testCanceledUpdates2() throws InterruptedException {
+ TestModel model = TestModel.simpleSingleLevel();
+ fViewer.setAutoExpandLevel(-1);
+
+ // Create the listener
+ fListener.reset(TreePath.EMPTY, model.getRootElement(), -1, false, false);
+
+ // Set the input into the view and update the view.
+ fViewer.setInput(model.getRootElement());
+ while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ model.validateData(fViewer, TreePath.EMPTY);
+
+
+ model.setQeueueingUpdate(true);
+
+ for (int i = 0; i < 5; i++) {
+ // Refresh the viewer so that updates are generated.
+ fListener.reset();
+ model.postDelta(new ModelDelta(model.getRootElement(), IModelDelta.CONTENT));
+
+ // Wait for the delta to be processed.
+ while (!fListener.isFinished(MODEL_CHANGED_COMPLETE | CHILD_COUNT_UPDATES_STARTED)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+
+ }
+
+ List updates = new ArrayList(model.getQueuedUpdates());
+ model.getQueuedUpdates().clear();
+ for (int i = updates.size() - 1; i >= 0; i--) {
+ model.processUpdate((IViewerUpdate)updates.get(i));
+ }
+
+ model.setQeueueingUpdate(false);
+ while (!fListener.isFinished(ALL_UPDATES_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ }
+
+ /**
+ * This test forces the viewer to cancel updates then process them at once.
+ * <p>
+ * - Wait until CHILDREN update started then refresh<br>
+ * - Process queued updates in order.<br>
+ * </p>
+ */
+ public void testCanceledUpdates3() throws InterruptedException {
+ TestModel model = TestModel.simpleSingleLevel();
+ fViewer.setAutoExpandLevel(-1);
+
+ // Create the listener
+ fListener.reset(TreePath.EMPTY, model.getRootElement(), -1, false, false);
+
+ // Set the input into the view and update the view.
+ fViewer.setInput(model.getRootElement());
+ while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ model.validateData(fViewer, TreePath.EMPTY);
+
+
+ model.setQeueueingUpdate(true);
+
+ for (int i = 0; i < 5; i++) {
+ // Refresh the viewer so that updates are generated.
+ fListener.reset();
+ model.postDelta(new ModelDelta(model.getRootElement(), IModelDelta.CONTENT));
+
+ // Wait for the delta to be processed.
+ while (!fListener.isFinished(MODEL_CHANGED_COMPLETE | CHILDREN_UPDATES_STARTED)) {
+ completeQueuedUpdatesOfType(model, IChildrenCountUpdate.class);
+ completeQueuedUpdatesOfType(model, IHasChildrenUpdate.class);
+ if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ }
+ }
+
+ model.setQeueueingUpdate(false);
+ while (!fListener.isFinished(ALL_UPDATES_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+
+ }
+
+ /**
+ * This test forces the viewer to cancel updates then process them at once.
+ * <p>
+ * - Wait until CHILDREN update started then refresh<br>
+ * - Process queued updates in REVERSE order.<br>
+ * </p>
+ */
+ public void testCanceledUpdates4() throws InterruptedException {
+ TestModel model = TestModel.simpleSingleLevel();
+ fViewer.setAutoExpandLevel(-1);
+
+ // Create the listener
+ fListener.reset(TreePath.EMPTY, model.getRootElement(), -1, false, false);
+
+ // Set the input into the view and update the view.
+ fViewer.setInput(model.getRootElement());
+ while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ model.validateData(fViewer, TreePath.EMPTY);
+
+
+ model.setQeueueingUpdate(true);
+
+ for (int i = 0; i < 5; i++) {
+ // Refresh the viewer so that updates are generated.
+ fListener.reset();
+ model.postDelta(new ModelDelta(model.getRootElement(), IModelDelta.CONTENT));
+
+ // Wait for the delta to be processed.
+ while (!fListener.isFinished(MODEL_CHANGED_COMPLETE | CHILDREN_UPDATES_STARTED)) {
+ completeQueuedUpdatesOfType(model, IChildrenCountUpdate.class);
+ completeQueuedUpdatesOfType(model, IHasChildrenUpdate.class);
+ if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ }
+
+ }
+
+ List updates = new ArrayList(model.getQueuedUpdates());
+ model.getQueuedUpdates().clear();
+ for (int i = updates.size() - 1; i >= 0; i--) {
+ model.processUpdate((IViewerUpdate)updates.get(i));
+ }
+
+ model.setQeueueingUpdate(false);
+ while (!fListener.isFinished(ALL_UPDATES_COMPLETE)) if (!fDisplay.readAndDispatch ()) Thread.sleep(0);
+ }
+
+ private void completeQueuedUpdatesOfType(TestModel model, Class updateClass) {
+ List updatesToComplete = new LinkedList();
+
+ for (Iterator itr = model.getQueuedUpdates().iterator(); itr.hasNext();) {
+ IViewerUpdate update = (IViewerUpdate)itr.next();
+ if (updateClass.isInstance(update)) {
+ updatesToComplete.add(update);
+ itr.remove();
+ }
+ }
+ if (updatesToComplete != null) {
+ for (Iterator itr = updatesToComplete.iterator(); itr.hasNext();) {
+ model.processUpdate((IViewerUpdate)itr.next());
+ }
+ }
+ }
+
}
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerContentTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerContentTests.java
index 8cacbe173..994ba3fe7 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerContentTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerContentTests.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipe.debug.tests.viewer.model;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelContentProviderTarget;
+import org.eclipse.debug.internal.ui.viewers.model.IInternalTreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualTreeModelViewer;
import org.eclipse.swt.widgets.Display;
@@ -25,7 +25,7 @@ public class VirtualViewerContentTests extends ContentTests {
super(name);
}
- protected ITreeModelContentProviderTarget createViewer(Display display, Shell shell) {
+ protected IInternalTreeModelViewer createViewer(Display display, Shell shell) {
return new VirtualTreeModelViewer(fDisplay, 0, new PresentationContext("TestViewer"));
}
}
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerDeltaTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerDeltaTests.java
index f3101784f..8fee48bec 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerDeltaTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerDeltaTests.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipe.debug.tests.viewer.model;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelContentProviderTarget;
+import org.eclipse.debug.internal.ui.viewers.model.IInternalTreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualTreeModelViewer;
import org.eclipse.swt.widgets.Display;
@@ -25,7 +25,7 @@ public class VirtualViewerDeltaTests extends DeltaTests {
super(name);
}
- protected ITreeModelContentProviderTarget createViewer(Display display, Shell shell) {
+ protected IInternalTreeModelViewer createViewer(Display display, Shell shell) {
return new VirtualTreeModelViewer(fDisplay, 0, new PresentationContext("TestViewer"));
}
}
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerFilterTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerFilterTests.java
new file mode 100644
index 000000000..b53ac539d
--- /dev/null
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerFilterTests.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * 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.eclipe.debug.tests.viewer.model;
+
+import org.eclipse.debug.internal.ui.viewers.model.IInternalTreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualTreeModelViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * @since 3.6
+ */
+public class VirtualViewerFilterTests extends FilterTests {
+
+ public VirtualViewerFilterTests(String name) {
+ super(name);
+ }
+
+ protected IInternalTreeModelViewer createViewer(Display display, Shell shell) {
+ return new VirtualTreeModelViewer(fDisplay, SWT.VIRTUAL, new PresentationContext("TestViewer"), new VisibleVirtualItemValidator(0, 100));
+ }
+}
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerLazyModeTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerLazyModeTests.java
index 2eb78d354..5ea544562 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerLazyModeTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerLazyModeTests.java
@@ -12,7 +12,7 @@ package org.eclipe.debug.tests.viewer.model;
import junit.framework.TestCase;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualTreeModelViewer;
import org.eclipse.swt.SWT;
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerPerformanceTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerPerformanceTests.java
index 2c4e6cd6b..7bc589bf7 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerPerformanceTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerPerformanceTests.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipe.debug.tests.viewer.model;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelContentProviderTarget;
+import org.eclipse.debug.internal.ui.viewers.model.IInternalTreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualTreeModelViewer;
import org.eclipse.swt.widgets.Display;
@@ -25,7 +25,7 @@ public class VirtualViewerPerformanceTests extends PerformanceTests {
super(name);
}
- protected ITreeModelContentProviderTarget createViewer(Display display, Shell shell) {
+ protected IInternalTreeModelViewer createViewer(Display display, Shell shell) {
return new VirtualTreeModelViewer(fDisplay, 0, new PresentationContext("TestViewer"));
}
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerPopupTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerPopupTests.java
index ee8e9c745..ec6f152f8 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerPopupTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerPopupTests.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipe.debug.tests.viewer.model;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualTreeModelViewer;
import org.eclipse.swt.widgets.Display;
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerSelectionTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerSelectionTests.java
index e716acf03..3bf5b7736 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerSelectionTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerSelectionTests.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipe.debug.tests.viewer.model;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualTreeModelViewer;
import org.eclipse.swt.widgets.Display;
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerStateTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerStateTests.java
index 5a4e4d671..2c5d5c96c 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerStateTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerStateTests.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipe.debug.tests.viewer.model;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualTreeModelViewer;
import org.eclipse.swt.widgets.Display;
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerUpdateTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerUpdateTests.java
index 507be5192..5086fab2c 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerUpdateTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VirtualViewerUpdateTests.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipe.debug.tests.viewer.model;
-import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualTreeModelViewer;
import org.eclipse.swt.widgets.Display;
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VisibleVirtualItemValidator.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VisibleVirtualItemValidator.java
new file mode 100644
index 000000000..b2c122440
--- /dev/null
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/VisibleVirtualItemValidator.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * 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.eclipe.debug.tests.viewer.model;
+
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IVirtualItemValidator;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualItem;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualTree;
+
+/**
+ * Item validator for the virtual viewer which specifies that the given
+ * range of items should be treated as visible.
+ */
+public class VisibleVirtualItemValidator implements IVirtualItemValidator {
+
+ private int fStart = 0;
+ private int fEnd = 0;
+
+ public VisibleVirtualItemValidator(int startPosition, int length) {
+ setVisibleRange(startPosition, length);
+ }
+
+ public void setVisibleRange(int startPosition, int length) {
+ fStart = startPosition;
+ fEnd = startPosition + length;
+ }
+
+ public int getStartPosition() {
+ return fStart;
+ }
+
+ public int getLength() {
+ return fEnd - fStart;
+ }
+
+ public boolean isItemVisible(VirtualItem item) {
+ int position = 0;
+ while (item.getParent() != null) {
+ position += item.getIndex().intValue();
+ item = item.getParent();
+ }
+ return position >= fStart && position < fEnd || isSelected(item);
+ }
+
+ public void showItem(VirtualItem item) {
+ int length = fEnd - fStart;
+ fStart = calcPosition(item);
+ fEnd = fStart + length;
+ }
+
+ private int calcPosition(VirtualItem item) {
+ int position = 0;
+ while (item.getParent() != null) {
+ position += item.getIndex().intValue();
+ item = item.getParent();
+ }
+ return position;
+ }
+
+ private boolean isSelected(VirtualItem item) {
+ VirtualItem[] selection = getSelection(item);
+ for (int i = 0; i < selection.length; i++) {
+ VirtualItem selectionItem = selection[i];
+ while (selectionItem != null) {
+ if (item.equals(selectionItem)) {
+ return true;
+ }
+ selectionItem = selectionItem.getParent();
+ }
+ }
+ return false;
+ }
+
+ private VirtualItem[] getSelection(VirtualItem item) {
+ VirtualTree tree = getTree(item);
+ if (tree != null) {
+ return tree.getSelection();
+ }
+ return new VirtualItem[0];
+ }
+
+ private VirtualTree getTree(VirtualItem item) {
+ while (item != null && !(item instanceof VirtualTree)) {
+ item = item.getParent();
+ }
+ return (VirtualTree)item;
+ }
+}
diff --git a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/AutomatedSuite.java b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/AutomatedSuite.java
index 82ba80b7a..a3cba9bf3 100644
--- a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/AutomatedSuite.java
+++ b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/AutomatedSuite.java
@@ -25,6 +25,7 @@ import org.eclipe.debug.tests.viewer.model.FilterTransformTests;
import org.eclipe.debug.tests.viewer.model.PresentationContextTests;
import org.eclipe.debug.tests.viewer.model.VirtualViewerContentTests;
import org.eclipe.debug.tests.viewer.model.VirtualViewerDeltaTests;
+import org.eclipe.debug.tests.viewer.model.VirtualViewerFilterTests;
import org.eclipe.debug.tests.viewer.model.VirtualViewerLazyModeTests;
import org.eclipe.debug.tests.viewer.model.VirtualViewerSelectionTests;
import org.eclipe.debug.tests.viewer.model.VirtualViewerStateTests;
@@ -62,6 +63,7 @@ public class AutomatedSuite extends TestSuite {
addTest(new TestSuite(VirtualViewerSelectionTests.class));
addTest(new TestSuite(VirtualViewerStateTests.class));
addTest(new TestSuite(VirtualViewerUpdateTests.class));
+ addTest(new TestSuite(VirtualViewerFilterTests.class));
// Viewer neutral tests
addTest(new TestSuite(FilterTransformTests.class));
diff --git a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/LocalSuite.java b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/LocalSuite.java
index 55acd5731..6098eb840 100644
--- a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/LocalSuite.java
+++ b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/LocalSuite.java
@@ -17,6 +17,7 @@ import org.eclipe.debug.tests.viewer.model.ColumnPresentationTests;
import org.eclipe.debug.tests.viewer.model.JFaceViewerCheckTests;
import org.eclipe.debug.tests.viewer.model.JFaceViewerContentTests;
import org.eclipe.debug.tests.viewer.model.JFaceViewerDeltaTests;
+import org.eclipe.debug.tests.viewer.model.JFaceViewerFilterTests;
import org.eclipe.debug.tests.viewer.model.JFaceViewerLazyTests;
import org.eclipe.debug.tests.viewer.model.JFaceViewerSelectionTests;
import org.eclipe.debug.tests.viewer.model.JFaceViewerStateTests;
@@ -53,6 +54,7 @@ public class LocalSuite extends TestSuite {
addTest(new TestSuite(JFaceViewerUpdateTests.class));
addTest(new TestSuite(JFaceViewerLazyTests.class));
addTest(new TestSuite(JFaceViewerTopIndexTests.class));
+ addTest(new TestSuite(JFaceViewerFilterTests.class));
addTest(new TestSuite(ColumnPresentationTests.class));
}
}
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 +