Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerTopIndexTests.java317
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/TestModelUpdatesListener.java1
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/TreeModelViewerAutopopulateAgent.java5
-rw-r--r--org.eclipse.debug.tests/src/org/eclipse/debug/tests/AutomatedSuite.java2
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ModelContentProvider.java83
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/TreeModelContentProvider.java96
6 files changed, 485 insertions, 19 deletions
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
new file mode 100644
index 000000000..f3a764ed7
--- /dev/null
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/JFaceViewerTopIndexTests.java
@@ -0,0 +1,317 @@
+/*******************************************************************************
+ * 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 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.ITreeModelContentProviderTarget;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+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.jface.viewers.TreePath;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * @since 3.6
+ */
+public class JFaceViewerTopIndexTests extends TestCase implements ITestModelUpdatesListenerConstants {
+
+ Display fDisplay;
+ Shell fShell;
+ TreeModelViewer fViewer;
+ TestModelUpdatesListener fListener;
+
+ public JFaceViewerTopIndexTests(String name) {
+ super(name);
+ }
+
+ /**
+ * @throws java.lang.Exception
+ */
+ protected void setUp() throws Exception {
+ fDisplay = PlatformUI.getWorkbench().getDisplay();
+ fShell = new Shell(fDisplay/*, SWT.ON_TOP | SWT.SHELL_TRIM*/);
+ fShell.setSize(300, 100);
+ fShell.setLayout(new FillLayout());
+
+ fViewer = createViewer(fDisplay, fShell);
+
+ fListener = new TestModelUpdatesListener(fViewer, false, false);
+
+ fShell.open ();
+ }
+
+ /**
+ * @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 ()) fDisplay.sleep ();
+ }
+
+ protected void runTest() throws Throwable {
+ try {
+ super.runTest();
+ } catch (Throwable t) {
+ throw new ExecutionException("Test failed: " + t.getMessage() + "\n fListener = " + fListener.toString(), t);
+ }
+ }
+
+ protected ITreeModelContentProviderTarget getCTargetViewer() {
+ return (ITreeModelContentProviderTarget)fViewer;
+ }
+
+ protected TreeModelViewer createViewer(Display display, Shell shell) {
+ return new TreeModelViewer(fShell, SWT.VIRTUAL | SWT.MULTI, new PresentationContext("TestViewer"));
+ }
+
+ /**
+ * Restore REVEAL on simple model with elements without children.
+ *
+ */
+ public void testRestoreTopIndex() {
+ TreeModelViewerAutopopulateAgent autopopulateAgent = new TreeModelViewerAutopopulateAgent(fViewer);
+
+ TestModel model = new TestModel();
+
+ TestElement[] elements = new TestElement[8];
+ for (int i = 0; i < elements.length; i++) {
+ String text = Integer.toString(i + 1);
+ // elements don't have children
+ elements[i] =
+ new TestElement(model, text, new TestElement[0] );
+
+ }
+ model.setRoot(new TestElement(model, "root", elements));
+
+ // Create the listener, only check the first level
+ 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 ()) fDisplay.sleep ();
+ model.validateData(fViewer, TreePath.EMPTY, true);
+
+ // Stop forcing view updates.
+ autopopulateAgent.dispose();
+
+ // scroll to the 5th element
+ int indexRevealElem = 4;
+ getCTargetViewer().reveal(TreePath.EMPTY, indexRevealElem);
+ while(fDisplay.readAndDispatch()) {}
+ final TreePath originalTopPath = getCTargetViewer().getTopElementPath();
+ Assert.assertNotNull("Top item should not be null!", originalTopPath);
+ Assert.assertEquals(elements[indexRevealElem], originalTopPath.getLastSegment());
+
+ // Set the viewer input to null. This will trigger the view to save the viewer state.
+ fListener.reset(true, false);
+ fListener.addStateUpdates(getCTargetViewer(), TreePath.EMPTY, model.getRootElement());
+
+ fViewer.setInput(null);
+ while (!fListener.isFinished(STATE_SAVE_COMPLETE)) if (!fDisplay.readAndDispatch ()) fDisplay.sleep ();
+
+ // Set the viewer input back to the model to trigger RESTORE operation.
+ fListener.reset(false, false);
+ fViewer.setInput(model.getRootElement());
+ while (!fListener.isFinished(ALL_UPDATES_COMPLETE | STATE_RESTORE_COMPLETE)) if (!fDisplay.readAndDispatch ()) fDisplay.sleep ();
+
+ while (fDisplay.readAndDispatch ()) {}
+ // check if REVEAL was restored OK
+ final TreePath topPath = getCTargetViewer().getTopElementPath();
+ Assert.assertNotNull("Top item should not be null!", topPath);
+ Assert.assertEquals(elements[indexRevealElem], topPath.getLastSegment());
+ Assert.assertEquals(originalTopPath, topPath);
+
+ }
+
+ /**
+ * Restore REVEAL when having also to restore an expanded element
+ * that is just above the REVEAL element.
+ *
+ * See bug 324100
+ */
+ public void testRestoreTopAndExpand() {
+ TreeModelViewerAutopopulateAgent autopopulateAgent = new TreeModelViewerAutopopulateAgent(fViewer);
+
+ TestModel model = new TestModel();
+
+ TestElement[] elements = new TestElement[10];
+ for (int i = 0; i < elements.length; i++) {
+ String text = Integer.toString(i + 1);
+ // first element has 2 children
+ if (i == 0) {
+ elements[i] =
+ new TestElement(model, text, new TestElement[] {
+ new TestElement(model, text + ".1", new TestElement[0] ),
+ new TestElement(model, text + ".2", new TestElement[0] )
+ });
+ } else {
+ // rest of elements don't have children
+ elements[i] =
+ new TestElement(model, text, new TestElement[0] );
+ }
+
+ }
+ model.setRoot(new TestElement(model, "root", elements));
+
+ // Create the listener, only check the first level
+ 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 ()) fDisplay.sleep ();
+ model.validateData(fViewer, TreePath.EMPTY, true);
+
+ // Expand first element
+ fListener.reset();
+ fListener.setFailOnRedundantUpdates(false);
+ int indexFirstElem = 0;
+ TestElement firstElem = elements[indexFirstElem];
+ ModelDelta rootDelta = new ModelDelta(model.getRootElement(), IModelDelta.NO_CHANGE);
+ ModelDelta delta = model.getBaseDelta(rootDelta);
+ TreePath firstElemPath = model.findElement(firstElem.getLabel());
+ fListener.addUpdates(
+ firstElemPath, firstElem, 1,
+ CHILD_COUNT_UPDATES | CHILDREN_UPDATES );
+ delta.addNode(firstElem, indexFirstElem, IModelDelta.EXPAND, firstElem.getChildren().length);
+
+ model.postDelta(rootDelta);
+
+ while (!fListener.isFinished(CONTENT_UPDATES_COMPLETE | MODEL_CHANGED_COMPLETE))
+ if (!fDisplay.readAndDispatch ()) fDisplay.sleep ();
+
+ // Validate that the first node is expanded
+ Assert.assertTrue(getCTargetViewer().getExpandedState(firstElemPath) == true);
+
+ // Stop forcing view updates.
+ autopopulateAgent.dispose();
+
+ // scroll to the 2nd element
+ getCTargetViewer().reveal(TreePath.EMPTY, 1);
+ while(fDisplay.readAndDispatch()) {}
+ final TreePath originalTopPath = getCTargetViewer().getTopElementPath();
+ Assert.assertNotNull("Top item should not be null!", originalTopPath);
+ Assert.assertEquals(elements[1], originalTopPath.getLastSegment());
+
+ // Set the viewer input to null. This will trigger the view to save the viewer state.
+ fListener.reset(true, false);
+ fListener.addStateUpdates(getCTargetViewer(), TreePath.EMPTY, model.getRootElement());
+ fViewer.setInput(null);
+ while (!fListener.isFinished(STATE_SAVE_COMPLETE)) if (!fDisplay.readAndDispatch ()) fDisplay.sleep ();
+
+ // Set the viewer input back to the model
+ fListener.reset(false, false);
+ fViewer.setInput(model.getRootElement());
+ while (!fListener.isFinished(ALL_UPDATES_COMPLETE | STATE_RESTORE_COMPLETE)) if (!fDisplay.readAndDispatch ()) fDisplay.sleep ();
+
+ while (fDisplay.readAndDispatch ()) {}
+ // check if REVEAL was restored OK
+ final TreePath topPath = getCTargetViewer().getTopElementPath();
+ Assert.assertNotNull("Top item should not be null!", topPath);
+ Assert.assertEquals(elements[1], topPath.getLastSegment());
+ Assert.assertEquals(originalTopPath, topPath);
+
+ }
+
+ /**
+ * Restore REVEAL when this operation triggers restoring of an expanded
+ * element.
+ *
+ * See bug 324100
+ */
+ public void testRestoreTopTriggersExpand() {
+ TreeModelViewerAutopopulateAgent autopopulateAgent = new TreeModelViewerAutopopulateAgent(fViewer);
+
+ TestModel model = new TestModel();
+
+ TestElement[] elements = new TestElement[10];
+ for (int i = 0; i < elements.length; i++) {
+ String text = Integer.toString(i + 1);
+ // last element has 2 children
+ if (i == elements.length - 1) {
+ elements[i] =
+ new TestElement(model, text, new TestElement[] {
+ new TestElement(model, text + ".1", new TestElement[0] ),
+ new TestElement(model, text + ".2", new TestElement[0] )
+ });
+ } else {
+ // rest of elements don't have children
+ elements[i] =
+ new TestElement(model, text, new TestElement[0] );
+ }
+
+ }
+
+ fViewer.setAutoExpandLevel(-1);
+ model.setRoot(new TestElement(model, "root", elements));
+
+ // Create the listener, only check the first level
+ 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 ()) fDisplay.sleep ();
+ model.validateData(fViewer, TreePath.EMPTY, true);
+
+ int indexLastElem = elements.length-1;
+ TestElement lastElem = elements[indexLastElem];
+ TreePath lastElemePath = model.findElement(lastElem.getLabel());
+
+ // Validate that the last node is expanded
+ Assert.assertTrue(getCTargetViewer().getExpandedState(lastElemePath) == true);
+
+ // Stop forcing view updates.
+ fViewer.setAutoExpandLevel(0);
+ autopopulateAgent.dispose();
+
+ // scroll to the element before last element
+ getCTargetViewer().reveal(TreePath.EMPTY, indexLastElem-1);
+ while(fDisplay.readAndDispatch()) {}
+ final TreePath originalTopPath = getCTargetViewer().getTopElementPath();
+ Assert.assertNotNull("Top item should not be null!", originalTopPath);
+ Assert.assertEquals(elements[indexLastElem-1], originalTopPath.getLastSegment());
+
+ // Set the viewer input to null. This will trigger the view to save the viewer state.
+ fListener.reset(true, false);
+ fListener.addStateUpdates(getCTargetViewer(), TreePath.EMPTY, model.getRootElement());
+
+ fViewer.setInput(null);
+ while (!fListener.isFinished(STATE_SAVE_COMPLETE)) if (!fDisplay.readAndDispatch ()) fDisplay.sleep ();
+
+ // Set the viewer input back to the model.
+ fListener.reset(false, false);
+ fViewer.setInput(model.getRootElement());
+ while (!fListener.isFinished(ALL_UPDATES_COMPLETE | STATE_RESTORE_COMPLETE)) if (!fDisplay.readAndDispatch ()) fDisplay.sleep ();
+
+ while (fDisplay.readAndDispatch ()) {}
+ // check if REVEAL was restored OK
+ final TreePath topPath = getCTargetViewer().getTopElementPath();
+ Assert.assertNotNull("Top item should not be null!", topPath);
+ Assert.assertEquals(elements[indexLastElem-1], topPath.getLastSegment());
+ Assert.assertEquals(originalTopPath, topPath);
+
+ }
+}
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 468e7d1c3..d0b831bdf 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
@@ -470,6 +470,7 @@ public class TestModelUpdatesListener
}
public void stateRestoreUpdatesComplete(Object input) {
+ Assert.assertFalse("RESTORE STATE already complete!", fStateRestoreComplete);
fStateRestoreComplete = true;
}
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/TreeModelViewerAutopopulateAgent.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/TreeModelViewerAutopopulateAgent.java
index 2600fbebb..38f9eb052 100644
--- a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/TreeModelViewerAutopopulateAgent.java
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/viewer/model/TreeModelViewerAutopopulateAgent.java
@@ -36,6 +36,11 @@ public class TreeModelViewerAutopopulateAgent implements IViewerUpdateListener {
fViewer.addViewerUpdateListener(this);
}
+ public void dispose() {
+ fViewer.removeViewerUpdateListener(this);
+ fViewer = null;
+ }
+
public void updateComplete(IViewerUpdate update) {
if (update instanceof IChildrenCountUpdate) {
TreePath path = update.getElementPath();
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 4d9b0b45b..2e33dc384 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
@@ -27,6 +27,7 @@ import org.eclipe.debug.tests.viewer.model.JFaceViewerContentTests;
import org.eclipe.debug.tests.viewer.model.JFaceViewerDeltaTests;
import org.eclipe.debug.tests.viewer.model.JFaceViewerSelectionTests;
import org.eclipe.debug.tests.viewer.model.JFaceViewerStateTests;
+import org.eclipe.debug.tests.viewer.model.JFaceViewerTopIndexTests;
import org.eclipe.debug.tests.viewer.model.JFaceViewerUpdateTests;
import org.eclipe.debug.tests.viewer.model.PresentationContextTests;
import org.eclipe.debug.tests.viewer.model.VirtualViewerContentTests;
@@ -64,6 +65,7 @@ public class AutomatedSuite extends TestSuite {
addTest(new TestSuite(JFaceViewerSelectionTests.class));
addTest(new TestSuite(JFaceViewerStateTests.class));
addTest(new TestSuite(JFaceViewerUpdateTests.class));
+ addTest(new TestSuite(JFaceViewerTopIndexTests.class));
// Virtual viewer tests
addTest(new TestSuite(VirtualViewerDeltaTests.class));
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
index b7cb28824..4aeebd1b7 100644
--- 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
@@ -10,6 +10,7 @@
* 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;
@@ -116,13 +117,13 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi
/**
* Map of updates in progress: element path -> list of requests
*/
- private Map fRequestsInProgress = new HashMap();
+ protected Map fRequestsInProgress = new HashMap();
/**
* Map of dependent requests waiting for parent requests to complete:
* element path -> list of requests
*/
- private Map fWaitingRequests = new HashMap();
+ protected Map fWaitingRequests = new HashMap();
/**
* Map of viewer states keyed by viewer input mementos
@@ -132,7 +133,7 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi
/**
* Pending viewer state to be restored
*/
- private ModelDelta fPendingState = null;
+ protected ModelDelta fPendingState = null;
/**
* Flag indicating that the content provider is performing
@@ -140,6 +141,25 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi
*/
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;
@@ -476,7 +496,7 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi
boolean checkChildrenRealized);
public void cancelRestore(final TreePath path, final int flags) {
- if (fPendingState == null) {
+ if (fPendingState == null && fPendingSetTopItem == null) {
// Nothing to do
return;
}
@@ -489,6 +509,13 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi
}
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 ((flags & IModelDelta.REVEAL) != 0 && fPendingSetTopItem != null) {
+ fPendingSetTopItem.dispose();
+ 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() {
@@ -768,6 +795,39 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi
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
@@ -1755,11 +1815,17 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi
CheckState state = new CheckState();
fPendingState.accept(state);
if (state.isComplete()) {
- if (DEBUG_STATE_SAVE_RESTORE && DEBUG_TEST_PRESENTATION_ID(getPresentationContext())) {
- System.out.println("STATE RESTORE COMPELTE: " + fPendingState); //$NON-NLS-1$
+ // 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);
}
- notifyStateUpdate(fPendingState.getElement(), STATE_RESTORE_SEQUENCE_COMPLETE, null);
- fPendingState = null;
+
+ fPendingState = null;
}
}
@@ -2177,4 +2243,5 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi
}
}
}
+
}
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 86eaba6fb..f8d10a49a 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
@@ -9,18 +9,22 @@
* IBM Corporation - initial API and implementation
* 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 org.eclipse.core.runtime.Assert;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
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.ModelDelta;
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.swt.widgets.Display;
/**
* Content provider for a virtual tree.
@@ -560,9 +564,9 @@ public class TreeModelContentProvider extends ModelContentProvider implements IT
/**
* @param delta
*/
- void restorePendingStateNode(ModelDelta delta, boolean knowsHasChildren, boolean knowsChildCount, boolean checkChildrenRealized) {
- TreePath treePath = getViewerTreePath(delta);
- ITreeModelContentProviderTarget viewer = getViewer();
+ 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) {
@@ -627,15 +631,85 @@ public class TreeModelContentProvider extends ModelContentProvider implements IT
}
if (setTopItem) {
- TreePath parentPath = treePath.getParentPath();
- 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$
+ 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 (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);
}
- viewer.reveal(parentPath, index);
- }
- }
+
+ };
+ viewer.addViewerUpdateListener(fPendingSetTopItem);
+ }
}
// If we know the child count of the element, look for the reveal

Back to the top