From 0030724c66680f3283e9598926672ce93f2a7b40 Mon Sep 17 00:00:00 2001 From: Pawel Piech Date: Wed, 11 Nov 2009 00:59:15 +0000 Subject: Bug 291267 - Fix for broken state saving and expanding logic in debugger views. --- .../tests/viewer/model/ChildrenUpdateTests.java | 97 +- .../model/ITestModelUpdatesListenerConstants.java | 7 +- .../debug/tests/viewer/model/StateTests.java | 48 + .../eclipe/debug/tests/viewer/model/TestModel.java | 31 +- .../viewer/model/TestModelUpdatesListener.java | 45 +- .../ui/viewers/model/ElementCompareRequest.java | 8 + .../ui/viewers/model/ElementMementoRequest.java | 6 + .../viewers/model/ITreeModelContentProvider.java | 15 + .../ui/viewers/model/ITreeModelViewer.java | 15 + .../ui/viewers/model/InternalTreeModelViewer.java | 16 +- .../model/InternalVirtualTreeModelViewer.java | 15 +- .../ui/viewers/model/ModelContentProvider.java | 3289 +++++++++++--------- .../ui/viewers/model/SubTreeModelViewer.java | 17 + .../ui/viewers/model/TreeModelContentProvider.java | 8 +- .../model/provisional/IStateUpdateListener.java | 58 + 15 files changed, 2070 insertions(+), 1605 deletions(-) create mode 100644 org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IStateUpdateListener.java 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 561104977..c64c9d190 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 @@ -20,6 +20,7 @@ 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; 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.jface.viewers.ISelection; @@ -44,38 +45,32 @@ public class ChildrenUpdateTests extends TestCase { protected ITreeModelContentProviderTarget getViewer() { return new ITreeModelContentProviderTarget(){ - public void setSelection(ISelection selection) { - } - - public void removeSelectionChangedListener(ISelectionChangedListener listener) { - } - - public void addSelectionChangedListener(ISelectionChangedListener listener) { - } - - public void updateViewer(IModelDelta delta) { - } - - public void setSelection(ISelection selection, boolean reveal, boolean force) { - } - - public void setInput(Object object) { - } - - public void setAutoExpandLevel(int level) { - } - - public void saveElementState(TreePath path, ModelDelta delta, int flags) { - } - - public void removeViewerUpdateListener(IViewerUpdateListener listener) { - } - - public void removeModelChangedListener(IModelChangedListener listener) { - } - - public void removeLabelUpdateListener(ILabelUpdateListener listener) { - } + public void setSelection(ISelection selection) {} + public void removeSelectionChangedListener(ISelectionChangedListener listener) {} + public void addSelectionChangedListener(ISelectionChangedListener listener) {} + public void updateViewer(IModelDelta delta) {} + public void setSelection(ISelection selection, boolean reveal, boolean force) {} + public void setInput(Object object) {} + public void setAutoExpandLevel(int level) {} + public void saveElementState(TreePath path, ModelDelta delta, int flags) {} + public void removeStateUpdateListener(IStateUpdateListener listener) {} + public void removeViewerUpdateListener(IViewerUpdateListener listener) {} + public void removeModelChangedListener(IModelChangedListener listener) {} + public void removeLabelUpdateListener(ILabelUpdateListener listener) {} + public void addViewerUpdateListener(IViewerUpdateListener listener) {} + public void addStateUpdateListener(IStateUpdateListener listener) {} + public void addModelChangedListener(IModelChangedListener listener) {} + public void addLabelUpdateListener(ILabelUpdateListener listener) {} + public void update(Object element) {} + public void setHasChildren(Object elementOrTreePath, boolean hasChildren) {} + public void setExpandedState(Object elementOrTreePath, boolean expanded) {} + public void setChildCount(Object elementOrTreePath, int count) {} + public void reveal(TreePath path, int index) {} + public void replace(Object parentOrTreePath, int index, Object element) {} + public void remove(Object parentOrTreePath, int index) {} + public void remove(Object elementOrTreePath) {} + public void refresh() {} + public void refresh(Object element) {} public ISelection getSelection() { return null; @@ -101,44 +96,6 @@ public class ChildrenUpdateTests extends TestCase { return 0; } - public void addViewerUpdateListener(IViewerUpdateListener listener) { - } - - public void addModelChangedListener(IModelChangedListener listener) { - } - - public void addLabelUpdateListener(ILabelUpdateListener listener) { - } - - public void update(Object element) { - } - - public void setHasChildren(Object elementOrTreePath, boolean hasChildren) { - } - - public void setExpandedState(Object elementOrTreePath, boolean expanded) { - } - - public void setChildCount(Object elementOrTreePath, int count) { - } - - public void reveal(TreePath path, int index) { - } - - public void replace(Object parentOrTreePath, int index, Object element) { - } - - public void remove(Object parentOrTreePath, int index) { - } - - public void remove(Object elementOrTreePath) { - } - - public void refresh() { - } - - public void refresh(Object element) { - } public boolean overrideSelection(ISelection current, ISelection candidate) { return false; 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 26570fc5f..10aa25c03 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 @@ -25,9 +25,12 @@ public interface ITestModelUpdatesListenerConstants { public static final int CHILDREN_UPDATES = 0X0020; public static final int MODEL_CHANGED_COMPLETE = 0X0040; public static final int MODEL_PROXIES_INSTALLED = 0X0080; + public static final int STATE_SAVE_COMPLETE = 0X0100; + public static final int STATE_RESTORE_COMPLETE = 0X0200; + public static final int STATE_UPDATES = 0X0400; - public static final int VIEWER_UPDATES_RUNNING = 0X0100; - public static final int LABEL_UPDATES_RUNNING = 0X0200; + public static final int VIEWER_UPDATES_RUNNING = 0X0800; + public static final int LABEL_UPDATES_RUNNING = 0X1000; public static final int LABEL_COMPLETE = LABEL_UPDATES_COMPLETE | LABEL_UPDATES; public static final int CONTENT_COMPLETE = 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 f19df2734..70058c59a 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 @@ -55,6 +55,7 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi fViewer.addViewerUpdateListener(fListener); fViewer.addLabelUpdateListener(fListener); fViewer.addModelChangedListener(fListener); + fViewer.addStateUpdateListener(fListener); fShell.open (); } @@ -68,12 +69,17 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi fViewer.removeLabelUpdateListener(fListener); fViewer.removeViewerUpdateListener(fListener); fViewer.removeModelChangedListener(fListener); + fViewer.addStateUpdateListener(fListener); // Close the shell and exit. fShell.close(); while (!fShell.isDisposed()) if (!fDisplay.readAndDispatch ()) fDisplay.sleep (); } + protected ITreeModelContentProviderTarget getCTargetViewer() { + return (ITreeModelContentProviderTarget)fViewer; + } + public void testUpdateViewer() { //TreeModelViewerAutopopulateAgent autopopulateAgent = new TreeModelViewerAutopopulateAgent(fViewer); @@ -334,4 +340,46 @@ abstract public class StateTests extends TestCase implements ITestModelUpdatesLi Assert.assertTrue(viewer.getExpandedState(model.findElement("6")) == false); } + public void testSaveAndRstoreOnInputChange1() { + //TreeModelViewerAutopopulateAgent autopopulateAgent = new TreeModelViewerAutopopulateAgent(fViewer); + TestModel model = alternatingSubsreesModel(); + + // 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 ()) fDisplay.sleep (); + model.validateData(fViewer, TreePath.EMPTY, true); + + // Expand some, but not all elements + expandAlternateElements(model); + + // Extract the original state from viewer + ModelDelta originalState = new ModelDelta(model.getRootElement(), IModelDelta.NO_CHANGE); + fViewer.saveElementState(TreePath.EMPTY, originalState, IModelDelta.EXPAND | IModelDelta.SELECT); + + // 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. 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()) if (!fDisplay.readAndDispatch ()) fDisplay.sleep (); + + // Extract the restored state from viewer + ModelDelta restoredState = new ModelDelta(model.getRootElement(), IModelDelta.NO_CHANGE); + fViewer.saveElementState(TreePath.EMPTY, restoredState, IModelDelta.EXPAND | IModelDelta.SELECT); + + Assert.assertTrue( deltaMatches(originalState, restoredState) ); + } + } 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 c4f5f348d..363afc39a 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 @@ -21,8 +21,11 @@ import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer; 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; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest; import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider; import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider; +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.IHasChildrenUpdate; import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; @@ -41,7 +44,7 @@ import org.eclipse.jface.viewers.Viewer; * * @since 3.6 */ -public class TestModel implements IElementContentProvider, IElementLabelProvider, IModelProxyFactory2 /*, IElementCheckReceiver */ { +public class TestModel implements IElementContentProvider, IElementLabelProvider, IModelProxyFactory2 , IElementMementoProvider { public static class TestElement extends PlatformObject { private final TestModel fModel; @@ -75,6 +78,10 @@ public class TestModel implements IElementContentProvider, IElementLabelProvider return null; } + public String getID() { + return fID; + } + public void setLabelAppendix(String appendix) { fLabelAppendix = appendix; } @@ -229,6 +236,27 @@ public class TestModel implements IElementContentProvider, IElementLabelProvider } } + public final static String ELEMENT_MEMENTO_ID = "id"; + + public void compareElements(IElementCompareRequest[] updates) { + for (int i = 0; i < updates.length; i++) { + String elementID = ((TestElement)updates[i].getElement()).getID(); + String mementoID = updates[i].getMemento().getString(ELEMENT_MEMENTO_ID); + updates[i].setEqual( elementID.equals(mementoID) ); + updates[i].done(); + } + + } + + public void encodeElements(IElementMementoRequest[] updates) { + for (int i = 0; i < updates.length; i++) { + String elementID = ((TestElement)updates[i].getElement()).getID(); + updates[i].getMemento().putString(ELEMENT_MEMENTO_ID, elementID); + updates[i].done(); + } + } + + public void elementChecked(IPresentationContext context, Object viewerInput, TreePath path, boolean checked) { TestElement element = getElement(path); Assert.assertFalse(element.getGrayed()); @@ -616,5 +644,6 @@ public class TestModel implements IElementContentProvider, IElementLabelProvider return m1; } + } 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 c694e1d1d..ea866c774 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 @@ -28,12 +28,14 @@ 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.IStateUpdateListener; 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; public class TestModelUpdatesListener - implements IViewerUpdateListener, ILabelUpdateListener, IModelChangedListener, ITestModelUpdatesListenerConstants + implements IViewerUpdateListener, ILabelUpdateListener, IModelChangedListener, ITestModelUpdatesListenerConstants, + IStateUpdateListener { private boolean fFailOnRedundantUpdates; private boolean fFailOnMultipleUpdateSequences; @@ -43,9 +45,12 @@ public class TestModelUpdatesListener private Set fChildCountUpdates = new HashSet(); private Set fLabelUpdates = new HashSet(); private Set fProxyModels = new HashSet(); + private Set fStateUpdates = new HashSet(); private boolean fViewerUpdatesComplete; private boolean fLabelUpdatesComplete; private boolean fModelChangedComplete; + private boolean fStateSaveComplete; + private boolean fStateRestoreComplete; private int fViewerUpdatesRunning; private int fLabelUpdatesRunning; @@ -86,6 +91,8 @@ public class TestModelUpdatesListener fViewerUpdatesComplete = false; fLabelUpdatesComplete = false; fModelChangedComplete = false; + fStateSaveComplete = false; + fStateRestoreComplete = false; } public void addHasChildrenUpdate(TreePath path) { @@ -135,10 +142,14 @@ public class TestModelUpdatesListener addUpdates(path, element, levels, ALL_UPDATES_COMPLETE); } + public void addStateUpdates(ITreeModelContentProviderTarget viewer, TreePath path, TestElement element) { + addUpdates(viewer, path, element, -1, STATE_UPDATES); + } + public void addUpdates(TreePath path, TestElement element, int levels, int flags) { addUpdates(null, path, element, levels, flags); } - + public void addUpdates(ITreeModelContentProviderTarget viewer, TreePath path, TestElement element, int levels, int flags) { if (!path.equals(TreePath.EMPTY)) { if ((flags & LABEL_UPDATES) != 0) { @@ -163,6 +174,10 @@ public class TestModelUpdatesListener fChildrenUpdates.put(path, childrenIndexes); } + if ((flags & STATE_UPDATES) != 0 && viewer != null) { + fStateUpdates.add(path); + } + for (int i = 0; i < children.length; i++) { addUpdates(viewer, path.createChildPath(children[i]), children[i], levels, flags); } @@ -208,6 +223,12 @@ public class TestModelUpdatesListener if ( (flags & MODEL_CHANGED_COMPLETE) != 0) { if (!fModelChangedComplete) return false; } + if ( (flags & STATE_SAVE_COMPLETE) != 0) { + if (!fStateSaveComplete) return false; + } + if ( (flags & STATE_RESTORE_COMPLETE) != 0) { + if (!fStateRestoreComplete) return false; + } if ( (flags & MODEL_PROXIES_INSTALLED) != 0) { if (fProxyModels.size() != 0) return false; } @@ -313,6 +334,26 @@ public class TestModelUpdatesListener } } } + + public void stateRestoreUpdatesBegin(Object input) { + } + + public void stateRestoreUpdatesComplete(Object input) { + fStateRestoreComplete = true; + } + + public void stateSaveUpdatesBegin(Object input) { + } + + public void stateSaveUpdatesComplete(Object input) { + fStateSaveComplete = true; + } + + public void stateUpdateComplete(Object input, IViewerUpdate update) { + } + + public void stateUpdateStarted(Object input, IViewerUpdate update) { + } } 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 2b3422ed2..54e592e41 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 @@ -109,4 +109,12 @@ class ElementCompareRequest extends MementoUpdate implements IElementCompareRequ boolean checkChildrenRealized() { return fCheckChildrenRealized; } + + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append("IElementCompareRequest: "); //$NON-NLS-1$ + buf.append(getElement()); + return buf.toString(); + } + } 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 f821e19dc..0b77420d1 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 @@ -46,4 +46,10 @@ class ElementMementoRequest extends MementoUpdate implements IElementMementoRequ fManager.requestComplete(this); } + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append("IElementMementoRequest: "); //$NON-NLS-1$ + buf.append(getElement()); + return buf.toString(); + } } 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 4801352a5..1b7e93e4a 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 @@ -12,7 +12,9 @@ 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.IStateUpdateListener; import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener; +import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer; import org.eclipse.jface.viewers.ILazyTreePathContentProvider; import org.eclipse.jface.viewers.TreePath; @@ -152,6 +154,19 @@ public interface ITreeModelContentProvider extends ILazyTreePathContentProvider */ public void removeModelChangedListener(IModelChangedListener 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); + /** * Instructs the content provider to process the given model delta. This * mechanism can be used to control the view's layout (expanding, selecting 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 9e6198327..a23191780 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 @@ -13,8 +13,11 @@ 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; @@ -137,6 +140,18 @@ public interface ITreeModelViewer extends ISelectionProvider { */ 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. */ 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 1a8bddf79..1177bb805 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 @@ -39,6 +39,7 @@ 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.IViewerUpdateListener; import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta; @@ -1701,7 +1702,7 @@ public class InternalTreeModelViewer extends TreeViewer } /** - * Registers the specified listener for view update notifications. + * Registers the specified listener for view update notifications. * * @param listener listener */ @@ -1741,7 +1742,18 @@ public class InternalTreeModelViewer extends TreeViewer cp.removeModelChangedListener(listener); } } - + + public void addStateUpdateListener(IStateUpdateListener listener) { + ((ITreeModelContentProvider)getContentProvider()).addStateUpdateListener(listener); + } + + public void removeStateUpdateListener(IStateUpdateListener listener) { + ITreeModelContentProvider cp = (ITreeModelContentProvider)getContentProvider(); + if (cp != null) { + cp.removeStateUpdateListener(listener); + } + } + /* * (non-Javadoc) Method declared in AbstractTreeViewer. */ 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 427d49b59..8c545c34f 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 @@ -32,6 +32,7 @@ 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.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.IViewerUpdateListener; import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta; import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext; @@ -1244,7 +1245,7 @@ public class InternalVirtualTreeModelViewer extends Viewer } public void addViewerUpdateListener(IViewerUpdateListener listener) { - ((ModelContentProvider)getContentProvider()).addViewerUpdateListener(listener); + getContentProvider().addViewerUpdateListener(listener); } public void removeViewerUpdateListener(IViewerUpdateListener listener) { @@ -1255,7 +1256,7 @@ public class InternalVirtualTreeModelViewer extends Viewer } public void addModelChangedListener(IModelChangedListener listener) { - ((ModelContentProvider)getContentProvider()).addModelChangedListener(listener); + getContentProvider().addModelChangedListener(listener); } public void removeModelChangedListener(IModelChangedListener listener) { @@ -1265,6 +1266,16 @@ public class InternalVirtualTreeModelViewer extends Viewer } } + public void addStateUpdateListener(IStateUpdateListener listener) { + getContentProvider().addStateUpdateListener(listener); + } + + public void removeStateUpdateListener(IStateUpdateListener listener) { + ITreeModelContentProvider cp = getContentProvider(); + if (cp != null) { + cp.removeStateUpdateListener(listener); + } + } public void addLabelUpdateListener(ILabelUpdateListener listener) { getLabelProvider().addLabelUpdateListener(listener); 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 584d22585..1b793f53b 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 @@ -47,6 +47,7 @@ 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; @@ -66,424 +67,506 @@ import org.eclipse.ui.progress.WorkbenchJob; */ 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(); - - /** - * 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(); - - /** - * 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; - - 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 HashMap(); - - /** - * 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$ - - /** - * Used to determine when restoration delta has been processed - */ - protected class CheckState implements IModelDeltaVisitor { - private boolean complete = true; - private IModelDelta topDelta = null; - /* (non-Javadoc) - * @see org.eclipse.debug.internal.ui.viewers.provisional.IModelDeltaVisitor#visit(org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta, int) - */ - public boolean visit(IModelDelta delta, int depth) { - if (delta.getFlags() != IModelDelta.NO_CHANGE) { - IModelDelta parentDelta = delta.getParentDelta(); - if (parentDelta != null && parentDelta.getFlags() == IModelDelta.NO_CHANGE) { - TreePath deltaPath = getViewerTreePath(delta); - if ( ((delta.getElement() instanceof IMemento) && !areMementoUpdatesPending(deltaPath.getParentPath(), delta)) || - (!(delta.getElement() instanceof IMemento) && !areElementUpdatesPending(deltaPath)) ) - { - removeDelta(delta); - return false; - } - } - - if (delta.getFlags() == IModelDelta.REVEAL && !(delta.getElement() instanceof IMemento)) { - topDelta = delta; - } else { - complete = false; - return false; - } - } - return true; - } - - public boolean isComplete() { - return complete; - } - - public IModelDelta getTopItemDelta() { - return topDelta; - } - - private boolean areElementUpdatesPending(TreePath path) { - synchronized (fRequestsInProgress) { - TreePath parentPath = path.getParentPath(); - List requests = (List)fWaitingRequests.get(path); + 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 + */ + 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(); + + /** + * 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; + + 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$ + + /** + * Used to determine when restoration delta has been processed + */ + protected class CheckState implements IModelDeltaVisitor { + private boolean complete = true; + + private IModelDelta topDelta = null; + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.debug.internal.ui.viewers.provisional.IModelDeltaVisitor + * #visit(org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta, + * int) + */ + public boolean visit(IModelDelta delta, int depth) { + if (delta.getFlags() != IModelDelta.NO_CHANGE) { + IModelDelta parentDelta = delta.getParentDelta(); + // Remove the delta if : + // - The parent delta has no more flags on it. + // - 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 (delta.getFlags() == IModelDelta.REVEAL && !(delta.getElement() instanceof IMemento)) { + topDelta = delta; + } else { + complete = false; + return false; + } + } + return true; + } + + public boolean isComplete() { + return complete; + } + + public IModelDelta getTopItemDelta() { + return topDelta; + } + + 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); + ViewerUpdateMonitor update = (ViewerUpdateMonitor) requests.get(i); if (update instanceof ChildrenUpdate) { return true; } } } - requests = (List)fWaitingRequests.get(parentPath); + requests = (List) fWaitingRequests.get(parentPath); if (requests != null) { for (int i = 0; i < requests.size(); i++) { - ViewerUpdateMonitor update = (ViewerUpdateMonitor)requests.get(i); + ViewerUpdateMonitor update = (ViewerUpdateMonitor) requests.get(i); if (update.getElement().equals(path.getLastSegment())) { return true; } } } - requests = (List)fRequestsInProgress.get(path); + requests = (List) fRequestsInProgress.get(path); if (requests != null) { for (int i = 0; i < requests.size(); i++) { - ViewerUpdateMonitor update = (ViewerUpdateMonitor)requests.get(i); + ViewerUpdateMonitor update = (ViewerUpdateMonitor) requests.get(i); if (update instanceof ChildrenUpdate) { return true; } } } - requests = (List)fRequestsInProgress.get(parentPath); + requests = (List) fRequestsInProgress.get(parentPath); if (requests != null) { for (int i = 0; i < requests.size(); i++) { - ViewerUpdateMonitor update = (ViewerUpdateMonitor)requests.get(i); + ViewerUpdateMonitor update = (ViewerUpdateMonitor) requests.get(i); if (update.getElement().equals(path.getLastSegment())) { return true; } } } - } - return false; - } - - private boolean areMementoUpdatesPending(TreePath path, IModelDelta delta) { - if (fCompareRequestsInProgress.size() > 10) { - return fCompareRequestsInProgress.containsKey(new CompareRequestKey(path, delta)); - } else { - for (Iterator itr = fCompareRequestsInProgress.keySet().iterator(); itr.hasNext(); ) { - CompareRequestKey key = (CompareRequestKey)itr.next(); - if (key.fPath.equals(path) && delta.getElement().equals(key.fDelta.getElement())) { - 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_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { - System.out.println("STATE RESTORE REMOVED: " + delta.getElement()); //$NON-NLS-1$ + private void removeDelta(IModelDelta delta) { + if (DEBUG_STATE_SAVE_RESTORE + && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { + 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; + ModelDelta visitorDelta = (ModelDelta) _visitorDelta; visitorDelta.setElement(ELEMENT_REMOVED); visitorDelta.setFlags(IModelDelta.NO_CHANGE); return true; } }); - } - } - - /** - * 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; - - /** - * Constant for an empty tree path. - */ - protected static final TreePath EMPTY_TREE_PATH = new TreePath(new Object[]{}); - - // debug flags + } + } + + /** + * 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_CONTENT_PROVIDER = false; + + public static boolean DEBUG_UPDATE_SEQUENCE = false; + public static boolean DEBUG_STATE_SAVE_RESTORE = false; + public static boolean DEBUG_DELTAS = false; - static { + 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_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 synchronized 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(); - } - fModelListeners.clear(); - fUpdateListeners.clear(); - disposeAllModelProxies(); - fViewer = null; - } - - public synchronized boolean isDisposed() { - return fViewer == null; - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, - * java.lang.Object, java.lang.Object) - */ - public synchronized void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - fViewer = (ITreeModelContentProviderTarget)viewer; - if (oldInput != null) { - for (Iterator itr = fCompareRequestsInProgress.values().iterator(); itr.hasNext(); ) { - ((ElementCompareRequest)itr.next()).cancel(); - itr.remove(); - } - saveViewerState(oldInput); - } - 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 synchronized void requestComplete(IElementMementoRequest request) { - if (!request.isCanceled() && (request.getStatus() == null || request.getStatus().isOK())) { - XMLMemento keyMemento = (XMLMemento) delta.getElement(); - StringWriter writer = new StringWriter(); - try { - keyMemento.save(writer); - final String keyMementoString = writer.toString(); - final ModelDelta stateDelta = (ModelDelta) fViewerStates.get(keyMementoString); - if (stateDelta != null) { - stateDelta.setElement(input); - // begin restoration - UIJob job = new UIJob("restore state") { //$NON-NLS-1$ - public IStatus runInUIThread(IProgressMonitor monitor) { - if (!isDisposed() && input.equals(getViewer().getInput())) { - if (DEBUG_STATE_SAVE_RESTORE && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { - System.out.println("STATE RESTORE: " + stateDelta.toString()); //$NON-NLS-1$ - } - fViewerStates.remove(keyMementoString); - fPendingState = stateDelta; - doInitialRestore(fPendingState); - } - return Status.OK_STATUS; - } - - }; - job.setSystem(true); - job.schedule(); - } - } catch (IOException e) { - DebugUIPlugin.log(e); - } - } - } - - /* (non-Javadoc) - * @see org.eclipse.debug.internal.ui.viewers.model.provisional.viewers.IMementoManager#processReqeusts() - */ - public void processReqeusts() { - 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 synchronized void addRequest(IElementMementoRequest req) { - fRequest = req; - } - - }; - manager.addRequest(new ElementMementoRequest(ModelContentProvider.this, getViewer().getInput(), manager, getPresentationContext(), - delta.getElement(), getViewerTreePath(delta), inputMemento, delta)); - manager.processReqeusts(); - } - } - + Platform.getDebugOption("org.eclipse.debug.ui/debug/viewers/deltas")); //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.IContentProvider#dispose() + */ + public synchronized 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(); + } + fModelListeners.clear(); + fUpdateListeners.clear(); + fStateUpdateListeners.clear(); + disposeAllModelProxies(); + fViewer = null; + } + + public synchronized boolean isDisposed() { + return fViewer == null; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface + * .viewers.Viewer, java.lang.Object, java.lang.Object) + */ + public synchronized void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + fViewer = (ITreeModelContentProviderTarget) viewer; + if (oldInput != null) { + for (Iterator itr = fCompareRequestsInProgress.values().iterator(); itr.hasNext();) { + ((ElementCompareRequest) itr.next()).cancel(); + itr.remove(); + } + saveViewerState(oldInput); + } + 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 synchronized void requestComplete(IElementMementoRequest request) { + notifyStateUpdate(input, UPDATE_COMPLETE, request); + if (DEBUG_STATE_SAVE_RESTORE + && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext() + .getId()))) { + System.out.println("\tSTATE END: " + request); //$NON-NLS-1$ + } + + 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(); + final ModelDelta stateDelta = (ModelDelta) fViewerStates.get(keyMementoString); + if (stateDelta != null) { + stateDelta.setElement(input); + // begin restoration + UIJob job = new UIJob("restore state") { //$NON-NLS-1$ + public IStatus runInUIThread(IProgressMonitor monitor) { + if (!isDisposed() && input.equals(getViewer().getInput())) { + if (DEBUG_STATE_SAVE_RESTORE + && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID + .equals(getPresentationContext().getId()))) { + System.out.println("\tRESTORE: " + stateDelta.toString()); //$NON-NLS-1$ + } + fViewerStates.remove(keyMementoString); + fPendingState = stateDelta; + doInitialRestore(fPendingState); + } else { + notifyStateUpdate(input, STATE_RESTORE_SEQUENCE_BEGINS, null); + } + return Status.OK_STATUS; + } + + }; + job.setSystem(true); + job.schedule(); + } else { + notifyStateUpdate(input, STATE_RESTORE_SEQUENCE_BEGINS, null); + } + } 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_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext() + .getId()))) { + System.out.println("\tSTATE 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 synchronized void addRequest(IElementMementoRequest req) { + fRequest = req; + } + + }; + manager.addRequest(new ElementMementoRequest(ModelContentProvider.this, getViewer().getInput(), manager, + getPresentationContext(), delta.getElement(), getViewerTreePath(delta), inputMemento, delta)); + manager.processReqeusts(); + } + } + /** * Restore selection/expansion based on items already in the viewer */ - protected abstract void doInitialRestore(ModelDelta delta); + protected abstract void doInitialRestore(ModelDelta delta); - /** + /** * @param delta */ - abstract void doRestore(final ModelDelta delta, boolean knowsHasChildren, boolean knowsChildCount, boolean checkChildrenRealized); + abstract void doRestore(final ModelDelta delta, boolean knowsHasChildren, boolean knowsChildCount, + boolean checkChildrenRealized); - protected void appendToPendingStateDelta(TreePath path) { - if (DEBUG_STATE_SAVE_RESTORE && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { + protected void appendToPendingStateDelta(TreePath path) { + if (DEBUG_STATE_SAVE_RESTORE + && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { System.out.println("STATE APPEND BEGIN: " + path.getLastSegment()); //$NON-NLS-1$ } @@ -495,62 +578,67 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi } fViewer.saveElementState(path, delta, IModelDelta.COLLAPSE | IModelDelta.EXPAND | IModelDelta.SELECT); - - // 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. + + // 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 delta, int depth) { if ((delta.getFlags() & IModelDelta.EXPAND) != 0) { - ((ModelDelta)delta).setFlags(delta.getFlags() | IModelDelta.CONTENT); + ((ModelDelta) delta).setFlags(delta.getFlags() | IModelDelta.CONTENT); } return true; } }); - - if (DEBUG_STATE_SAVE_RESTORE && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { - System.out.println("STATE APPEND DELTA FROM VIEW: " + appendDeltaRoot); //$NON-NLS-1$ + + if (DEBUG_STATE_SAVE_RESTORE + && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { + System.out.println("\tAPPEND DELTA: " + appendDeltaRoot); //$NON-NLS-1$ } - + if (fPendingState != null) { - // If the restore for the current input was never completed, preserve + // 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_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { - System.out.println("STATE APPEND OUTSTANDING RESTORE: " + fPendingState); //$NON-NLS-1$ + if (DEBUG_STATE_SAVE_RESTORE + && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { + System.out.println("\tAPPEND 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 + + // 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 + // 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, + // If the pending state node does not contain any flags, // we can also skip it. ModelDelta saveDeltaNode = findSaveDelta(appendDeltaRoot, pendingDeltaNode); - if (saveDeltaNode != null && - !isDeltaInParent(pendingDeltaNode, saveDeltaNode) && - pendingDeltaNode.getFlags() != IModelDelta.NO_CHANGE) - { + 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_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { - System.out.println("STATE Skipping: " + pendingDeltaNode.getElement()); //$NON-NLS-1$ + if (DEBUG_STATE_SAVE_RESTORE + && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext() + .getId()))) { + System.out.println("\tSKIPPED: " + pendingDeltaNode.getElement()); //$NON-NLS-1$ } } - - // If the pending delta node has a memento element, its + + // 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. + // of this pending delta node into the save delta. if (pendingDeltaNode.getElement() instanceof IMemento) { return false; } else { @@ -559,162 +647,190 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi } }; fPendingState.accept(pendingStateVisitor); - } + } 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_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { - System.out.println("STATE APPEND NEW PENDING STATE DELTA " + fPendingState); //$NON-NLS-1$ + if (DEBUG_STATE_SAVE_RESTORE + && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { + System.out.println("STATE APPEND COMPLETE " + fPendingState); //$NON-NLS-1$ } } else { - if (DEBUG_STATE_SAVE_RESTORE && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { - System.out.println("STATE APPEND CANCELED, NO DATA"); //$NON-NLS-1$ - } + if (DEBUG_STATE_SAVE_RESTORE + && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { + System.out.println("STATE APPEND CANCELED: No Data"); //$NON-NLS-1$ + } + } + } + + /** + * Perform any restoration required for the given tree path. + * + * @param path + */ + protected synchronized void doRestore(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_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID + .equals(getPresentationContext().getId()))) { + System.out.println("\tSTATE BEGIN: " + compareRequest); //$NON-NLS-1$ + } + notifyStateUpdate(fPendingState.getElement(), 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. + doRestore((ModelDelta) delta, knowsHasChildren, knowsChildCount, checkChildrenRealized); + } + return false; + } + // Only follow the paths that match the delta. + return element.equals(potentialMatch); + } + }; + fPendingState.accept(visitor); + } + + void compareFinished(ElementCompareRequest request, ModelDelta delta) { + notifyStateUpdate(request.getViewerInput(), UPDATE_COMPLETE, request); + if (DEBUG_STATE_SAVE_RESTORE + && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { + System.out.println("\tSTATE END: " + request + " = " + false); //$NON-NLS-1$ //$NON-NLS-2$ } - } - - /** - * Perform any restoration required for the given tree path. - * - * @param path - */ - protected synchronized void doRestore(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); - 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. - doRestore((ModelDelta)delta, knowsHasChildren, knowsChildCount, checkChildrenRealized); - } - return false; - } - // Only follow the paths that match the delta. - return element.equals(potentialMatch); - } - }; - fPendingState.accept(visitor); - } - - void compareFinished(ElementCompareRequest request, ModelDelta delta) { - fCompareRequestsInProgress.remove(request); - if (!request.isCanceled()) { - if (request.isEqual()) { - delta.setElement(request.getElement()); - doRestore(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); - } - } - } - } - - /** - * Saves the viewer's state for the previous input. - * * @param oldInput - */ - protected void saveViewerState(Object input) { - IElementMementoProvider stateProvider = ViewerAdapterService.getMementoProvider(input); - if (stateProvider != null) { - if (DEBUG_STATE_SAVE_RESTORE && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { + + fCompareRequestsInProgress.remove(request); + if (!request.isCanceled()) { + if (request.isEqual()) { + delta.setElement(request.getElement()); + doRestore(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); + } + } + } + } + + /** + * Saves the viewer's state for the previous input. * @param oldInput + */ + protected void saveViewerState(Object input) { + IElementMementoProvider stateProvider = ViewerAdapterService.getMementoProvider(input); + if (stateProvider != null) { + if (DEBUG_STATE_SAVE_RESTORE + && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { 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); + // 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_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { - System.out.println("STATE SAVE DELTA FROM VIEW: " + saveDeltaRoot); //$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_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { - System.out.println("STATE SAVE OUTSTANDING RESTORE: " + fPendingState); //$NON-NLS-1$ + if (DEBUG_STATE_SAVE_RESTORE + && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { + System.out.println("\tSAVE DELTA FROM VIEW:\n" + saveDeltaRoot); //$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_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { + 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 + + // 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 + // 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 + // 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, + // If the pending state node does not contain any flags, // we can also skip it. ModelDelta saveDeltaNode = findSaveDelta(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 + 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 did not yet complete the reveal // operation. - if ( (pendingDeltaNode.getFlags() & IModelDelta.REVEAL) != 0) { + if ((pendingDeltaNode.getFlags() & IModelDelta.REVEAL) != 0) { clearRevealFlag(saveDeltaRoot); } saveDeltaNode.setChildCount(pendingDeltaNode.getParentDelta().getChildCount()); copyIntoDelta(pendingDeltaNode, saveDeltaNode); } else { - if (DEBUG_STATE_SAVE_RESTORE && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { - System.out.println("STATE Skipping: " + pendingDeltaNode.getElement()); //$NON-NLS-1$ + if (DEBUG_STATE_SAVE_RESTORE + && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID + .equals(getPresentationContext().getId()))) { + System.out.println("\tSKIPPED: " + pendingDeltaNode.getElement()); //$NON-NLS-1$ } } - - // If the pending delta node has a memento element, its + + // 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. + // of this pending delta node into the save delta. if (pendingDeltaNode.getElement() instanceof IMemento) { return false; } else { @@ -723,456 +839,509 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi } }; 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_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { - System.out.println("STATE SAVE CANCELED, NO DATA"); //$NON-NLS-1$ - } - } - } - } - - private void clearRevealFlag(ModelDelta saveRootDelta) { + } + + 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_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { + 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); + if ((delta.getFlags() & IModelDelta.REVEAL) != 0) { + ((ModelDelta) delta).setFlags(delta.getFlags() & ~IModelDelta.REVEAL); } return true; } }; saveRootDelta.accept(clearDeltaVisitor); - } - - private ModelDelta findSaveDelta(ModelDelta saveDeltaRoot, IModelDelta pendingStateDelta) { - // Create a path of elements to the pendingStateDelta. - LinkedList deltaPath = new LinkedList(); - IModelDelta delta = pendingStateDelta; - while (delta.getParentDelta() != null) { - delta = delta.getParentDelta(); - deltaPath.addFirst(delta); - } - - // For each element in the path of the pendingStateDelta, find the corresponding - // element in the partially restored delta being saved. - Iterator itr = deltaPath.iterator(); - // Skip the root element - itr.next(); - ModelDelta saveDelta = saveDeltaRoot; - 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 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) { + } + + private ModelDelta findSaveDelta(ModelDelta saveDeltaRoot, IModelDelta pendingStateDelta) { + // Create a path of elements to the pendingStateDelta. + LinkedList deltaPath = new LinkedList(); + IModelDelta delta = pendingStateDelta; + while (delta.getParentDelta() != null) { + delta = delta.getParentDelta(); + deltaPath.addFirst(delta); + } + + // For each element in the path of the pendingStateDelta, find the + // corresponding + // element in the partially restored delta being saved. + Iterator itr = deltaPath.iterator(); + // Skip the root element + itr.next(); + ModelDelta saveDelta = saveDeltaRoot; + 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 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) ) { + if (deltasEqual(destParent.getChildDeltas()[i], delta)) { return true; } } return false; - } + } + + private void copyIntoDelta(IModelDelta delta, ModelDelta destParent) { + // Search the destination and make sure that the same delta + // doesn't exist already. - private void copyIntoDelta(IModelDelta delta, ModelDelta destParent) { - // Search the destination and make sure that the same delta - // doesn't exist already. - - ModelDelta newDelta = destParent.addNode(delta.getElement(), delta.getIndex(), delta.getFlags(), delta.getChildCount()); + 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 delta - * @param stateProvider - */ - protected void encodeDelta(final ModelDelta rootDelta, final IElementMementoProvider defaultProvider) { - 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 requests - */ - private List requests = new ArrayList(); - private boolean abort = 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 synchronized void requestComplete(IElementMementoRequest request) { - if (!abort) { - if (!request.isCanceled() && (request.getStatus() == null || request.getStatus().isOK())) { - requests.remove(request); - if (requests.isEmpty()) { - XMLMemento keyMemento = (XMLMemento) rootDelta.getElement(); - StringWriter writer = new StringWriter(); - try { - keyMemento.save(writer); - fViewerStates.put(writer.toString(), rootDelta); - } catch (IOException e) { - DebugUIPlugin.log(e); - } - if (DEBUG_STATE_SAVE_RESTORE && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { - System.out.println("STATE SAVE COMPLETED: " + rootDelta); //$NON-NLS-1$ - } - stateSaveComplete(this); - } - } else { - abort = true; - Iterator iterator = requests.iterator(); - while (iterator.hasNext()) { - IElementMementoRequest req = (IElementMementoRequest) iterator.next(); - req.cancel(); - } - requests.clear(); - if (DEBUG_STATE_SAVE_RESTORE && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { - System.out.println("STATE SAVE ABORTED: " + rootDelta.getElement()); //$NON-NLS-1$ - } - stateSaveComplete(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 = requests.iterator(); - while (iterator.hasNext()) { - IElementMementoRequest request = (IElementMementoRequest) iterator.next(); - 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) { - requests.add(request); - } - - }; - IModelDeltaVisitor visitor = new IModelDeltaVisitor() { - public boolean visit(IModelDelta delta, int depth) { - if (delta.getParentDelta() == null) { - manager.addRequest( - new ElementMementoRequest(ModelContentProvider.this, getViewer().getInput(), manager, getPresentationContext(), - delta.getElement(), getViewerTreePath(delta), inputMemento, (ModelDelta)delta)); - } else { - if (!(delta.getElement() instanceof XMLMemento)) { - manager.addRequest( - new ElementMementoRequest(ModelContentProvider.this, getViewer().getInput(), manager, getPresentationContext(), - delta.getElement(), getViewerTreePath(delta), childrenMemento.createChild("CHILD_ELEMENT"), (ModelDelta)delta)); //$NON-NLS-1$ - } - } - return true; - } - }; - rootDelta.accept(visitor); - stateSaveStarted(manager); - manager.processReqeusts(); - } - - /** - * Called when a state save is starting. - * - * @param manager - */ - private synchronized void stateSaveStarted(IMementoManager manager) { - fPendingStateSaves.add(manager); - } - - /** - * Called when a state save is complete. - * - * @param manager - */ - private synchronized void stateSaveComplete(IMementoManager manager) { - 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 element - */ - 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; - } - - proxy = (IModelProxy)fModelProxies.get(path.getLastSegment()); - 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 element - * element to install an update policy 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 synchronized void modelChanged(final IModelDelta delta, final IModelProxy proxy) { - if (fViewer != null && !proxy.isDisposed()) { - WorkbenchJob job = new WorkbenchJob(fViewer.getDisplay(), "process model delta") { //$NON-NLS-1$ - public IStatus runInUIThread(IProgressMonitor monitor) { - if (!proxy.isDisposed()) { - if (DEBUG_DELTAS && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { - 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); - } - } - return Status.OK_STATUS; - } - }; - job.setSystem(true); - job.schedule(); - } - } - - /** - * @see ITreeModelContentProvider#setModelDeltaMask(int) - */ - public void setModelDeltaMask(int mask) { - fModelDeltaMask = mask; } - + /** - * @see ITreeModelContentProvider#getModelDeltaMask() + * Encodes delta elements into mementos using the given provider. + * + * @param delta + * @param stateProvider + */ + 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 requests + */ + private List requests = new ArrayList(); + + private boolean abort = 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 synchronized void requestComplete(IElementMementoRequest request) { + notifyStateUpdate(input, UPDATE_COMPLETE, request); + if (DEBUG_STATE_SAVE_RESTORE + && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { + System.out.println("\tSTATE END: " + request); //$NON-NLS-1$ + } + + if (!abort) { + if (!request.isCanceled() && (request.getStatus() == null || request.getStatus().isOK())) { + requests.remove(request); + if (requests.isEmpty()) { + XMLMemento keyMemento = (XMLMemento) rootDelta.getElement(); + StringWriter writer = new StringWriter(); + try { + keyMemento.save(writer); + fViewerStates.put(writer.toString(), rootDelta); + } catch (IOException e) { + DebugUIPlugin.log(e); + } + if (DEBUG_STATE_SAVE_RESTORE + && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID + .equals(getPresentationContext().getId()))) { + System.out.println("STATE SAVE COMPLETED: " + rootDelta); //$NON-NLS-1$ + } + stateSaveComplete(input, this); + } + } else { + abort = true; + Iterator iterator = requests.iterator(); + while (iterator.hasNext()) { + IElementMementoRequest req = (IElementMementoRequest) iterator.next(); + req.cancel(); + } + requests.clear(); + if (DEBUG_STATE_SAVE_RESTORE + && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext() + .getId()))) { + 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 = requests.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) { + requests.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 manager + */ + 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 manager + */ + 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 element + */ + 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; + } + + proxy = (IModelProxy) fModelProxies.get(path.getLastSegment()); + 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 element + * element to install an update policy 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 synchronized void modelChanged(final IModelDelta delta, final IModelProxy proxy) { + if (fViewer != null && !proxy.isDisposed()) { + WorkbenchJob job = new WorkbenchJob(fViewer.getDisplay(), "process model delta") { //$NON-NLS-1$ + public IStatus runInUIThread(IProgressMonitor monitor) { + if (!proxy.isDisposed()) { + if (DEBUG_DELTAS + && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext() + .getId()))) { + 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); + } + } + return Status.OK_STATUS; + } + }; + job.setSystem(true); + job.schedule(); + } + } + + /** + * @see ITreeModelContentProvider#setModelDeltaMask(int) + */ + public void setModelDeltaMask(int mask) { + fModelDeltaMask = mask; + } + + /** + * @see ITreeModelContentProvider#getModelDeltaMask() */ 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); - } - + 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); + } + /** - * Updates the viewer with the following deltas. + * Updates the viewer with the following deltas. * - * @param nodes Model deltas to be processed. - * @param override If true, it overrides the mode which suppresses - * processing of SELECT, REVEAL, EXPAND, COLLAPSE flags of - * {@link IModelDelta}. - */ - 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); - } + * @param nodes + * Model deltas to be processed. + * @param override + * If true, it overrides the mode which suppresses processing of + * SELECT, REVEAL, EXPAND, COLLAPSE flags of {@link IModelDelta}. + */ + 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); } @@ -1185,432 +1354,502 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi 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 - * @param index - * @return whether the element at the given index was filtered - */ - protected boolean isFiltered(TreePath parentPath, int index) { - return fTransform.isFiltered(parentPath, index); - } - - /** - * Notification the given element is being unmapped. - * - * @param path - */ - public void unmapPath(TreePath path) { - //System.out.println("Unmap " + path.getLastSegment()); - fTransform.clear(path); - cancelSubtreeUpdates(path); - } - - /** - * Returns filtered children or null - * @param parent - * @return filtered children or null - */ - 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; - } - CheckState state = new CheckState(); - fPendingState.accept(state); - if (state.isComplete()) { - if (DEBUG_STATE_SAVE_RESTORE && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { + 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 + * @param index + * @return whether the element at the given index was filtered + */ + protected boolean isFiltered(TreePath parentPath, int index) { + return fTransform.isFiltered(parentPath, index); + } + + /** + * Notification the given element is being unmapped. + * + * @param path + */ + public void unmapPath(TreePath path) { + // System.out.println("Unmap " + path.getLastSegment()); + fTransform.clear(path); + cancelSubtreeUpdates(path); + } + + /** + * Returns filtered children or null + * + * @param parent + * @return filtered children or null + */ + 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; + } + CheckState state = new CheckState(); + fPendingState.accept(state); + if (state.isComplete()) { + if (DEBUG_STATE_SAVE_RESTORE + && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { System.out.println("STATE RESTORE COMPELTE: " + fPendingState); //$NON-NLS-1$ } - 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 - */ - 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_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { - System.out.println("MODEL SEQUENCE BEGINS"); //$NON-NLS-1$ - } - notifyUpdate(UPDATE_SEQUENCE_BEGINS, null); - } - if (DEBUG_UPDATE_SEQUENCE && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { - System.out.println("\tBEGIN - " + update); //$NON-NLS-1$ - } - notifyUpdate(UPDATE_BEGINS, update); - } - - /** - * Notification an update request has completed - * - * @param update - */ - void updateComplete(ViewerUpdateMonitor update) { - 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(); - } - notifyUpdate(UPDATE_COMPLETE, update); - if (DEBUG_UPDATE_SEQUENCE && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { - System.out.println("\tEND - " + update); //$NON-NLS-1$ - } - if (end) { - if (DEBUG_UPDATE_SEQUENCE && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { - System.out.println("MODEL SEQUENCE ENDS"); //$NON-NLS-1$ - } - notifyUpdate(UPDATE_SEQUENCE_COMPLETE, null); - } - } - - 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); - } - }); - } - } - } - - 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 - * @return whether to start the given request - */ - 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); + 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 + */ + 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_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { + System.out.println("MODEL SEQUENCE BEGINS"); //$NON-NLS-1$ + } + notifyUpdate(UPDATE_SEQUENCE_BEGINS, null); + } + if (DEBUG_UPDATE_SEQUENCE + && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { + System.out.println("\tBEGIN - " + update); //$NON-NLS-1$ + } + notifyUpdate(UPDATE_BEGINS, update); + } + + /** + * Notification an update request has completed + * + * @param update + */ + void updateComplete(ViewerUpdateMonitor update) { + 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(); + } + notifyUpdate(UPDATE_COMPLETE, update); + if (DEBUG_UPDATE_SEQUENCE + && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { + System.out.println("\tEND - " + update); //$NON-NLS-1$ + } + if (end) { + if (DEBUG_UPDATE_SEQUENCE + && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { + System.out.println("MODEL SEQUENCE ENDS"); //$NON-NLS-1$ + } + notifyUpdate(UPDATE_SEQUENCE_COMPLETE, null); + } + } + + 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 + * @return whether to start the given request + */ + 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) { @@ -1618,173 +1857,179 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi } } } - 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; - } - } - } - } - } - + 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 - */ - 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 - * @param waiting - */ - 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(); - } - } - 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 && getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID)) { - 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_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { - 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); - } - } - } - } - } + + /** + * 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 + */ + 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 + * @param waiting + */ + 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(); + } + } + 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 + && getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID)) { + 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_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID + .equals(getPresentationContext().getId()))) { + 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 bc3c04cc5..f30f9b3cb 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 @@ -13,6 +13,7 @@ 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; @@ -276,6 +277,10 @@ public class SubTreeModelViewer extends TreeModelViewer { SubTreeModelViewer.this.addModelChangedListener(listener); } + public void addStateUpdateListener(IStateUpdateListener listener) { + SubTreeModelViewer.this.addStateUpdateListener(listener); + } + public void addViewerUpdateListener(IViewerUpdateListener listener) { SubTreeModelViewer.this.addViewerUpdateListener(listener); } @@ -304,6 +309,10 @@ public class SubTreeModelViewer extends TreeModelViewer { SubTreeModelViewer.this.removeModelChangedListener(listener); } + public void removeStateUpdateListener(IStateUpdateListener listener) { + SubTreeModelViewer.this.removeStateUpdateListener(listener); + } + public void removeViewerUpdateListener(IViewerUpdateListener listener) { SubTreeModelViewer.this.removeViewerUpdateListener(listener); } @@ -378,6 +387,10 @@ public class SubTreeModelViewer extends TreeModelViewer { fBaseProvider.addModelChangedListener(listener); } + public void addStateUpdateListener(IStateUpdateListener listener) { + fBaseProvider.addStateUpdateListener(listener); + } + public void addViewerUpdateListener(IViewerUpdateListener listener) { fBaseProvider.addViewerUpdateListener(listener); } @@ -398,6 +411,10 @@ public class SubTreeModelViewer extends TreeModelViewer { fBaseProvider.removeModelChangedListener(listener); } + public void removeStateUpdateListener(IStateUpdateListener listener) { + fBaseProvider.removeStateUpdateListener(listener); + } + public void removeViewerUpdateListener(IViewerUpdateListener listener) { fBaseProvider.removeViewerUpdateListener(listener); } 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 2149b3896..abd200ebc 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 @@ -547,14 +547,14 @@ public class TreeModelContentProvider extends ModelContentProvider implements IT if (knowsHasChildren) { if ((delta.getFlags() & IModelDelta.EXPAND) != 0) { if (DEBUG_STATE_SAVE_RESTORE && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { - System.out.println("STATE RESTORE EXPAND: " + treePath.getLastSegment()); //$NON-NLS-1$ + 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_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { - System.out.println("STATE RESTORE COLLAPSE: " + treePath.getLastSegment()); //$NON-NLS-1$ + System.out.println("\tRESTORE COLLAPSE: " + treePath.getLastSegment()); //$NON-NLS-1$ } getViewer().setExpandedState(treePath, false); delta.setFlags(delta.getFlags() & ~IModelDelta.COLLAPSE); @@ -584,7 +584,7 @@ public class TreeModelContentProvider extends ModelContentProvider implements IT int index = viewer.findElementIndex(parentPath, treePath.getLastSegment()); if (index >= 0) { if (DEBUG_STATE_SAVE_RESTORE && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { - System.out.println("STATE RESTORE REVEAL: " + treePath.getLastSegment()); //$NON-NLS-1$ + System.out.println("\tRESTORE REVEAL: " + treePath.getLastSegment()); //$NON-NLS-1$ } viewer.reveal(parentPath, index); } @@ -621,7 +621,7 @@ public class TreeModelContentProvider extends ModelContentProvider implements IT (knowsHasChildren && !viewer.getHasChildren(treePath)) ) { if (DEBUG_STATE_SAVE_RESTORE && (DEBUG_PRESENTATION_ID == null || DEBUG_PRESENTATION_ID.equals(getPresentationContext().getId()))) { - System.out.println("STATE RESTORE CONTENT: " + treePath.getLastSegment()); //$NON-NLS-1$ + System.out.println("\tRESTORE CONTENT: " + treePath.getLastSegment()); //$NON-NLS-1$ } delta.setFlags(delta.getFlags() & ~IModelDelta.CONTENT); } diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IStateUpdateListener.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IStateUpdateListener.java new file mode 100644 index 000000000..d88ae2946 --- /dev/null +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IStateUpdateListener.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2006, 2007 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.provisional; + + +/** + * Listener for viewer state updates. + * + * @since 3.6 + */ +public interface IStateUpdateListener { + + /** + * Notification that a sequence of state saving updates are starting. + */ + public void stateSaveUpdatesBegin(Object input); + + /** + * Notification that viewer updates are complete. Corresponds to + * a viewerUpdatesBegin() notification. + */ + public void stateSaveUpdatesComplete(Object input); + + /** + * Notification that a sequence of viewer updates are starting. + */ + public void stateRestoreUpdatesBegin(Object input); + + /** + * Notification that viewer updates are complete. Corresponds to + * a viewerUpdatesBegin() notification. + */ + public void stateRestoreUpdatesComplete(Object input); + + /** + * Notification that a specific update has started within + * a sequence of updates. + * + * @param update update + */ + public void stateUpdateStarted(Object input, IViewerUpdate update); + + /** + * Notification that a specific update has completed within a + * sequence of updates. + * + * @param update update + */ + public void stateUpdateComplete(Object input, IViewerUpdate update); +} -- cgit v1.2.3