diff options
8 files changed, 484 insertions, 138 deletions
diff --git a/org.eclipse.debug.ui/.options b/org.eclipse.debug.ui/.options index cba192bd8..2bf4af3b5 100644 --- a/org.eclipse.debug.ui/.options +++ b/org.eclipse.debug.ui/.options @@ -6,3 +6,4 @@ org.eclipse.debug.ui/debug/viewers/contentProvider = false org.eclipse.debug.ui/debug/viewers/updateSequence = false org.eclipse.debug.ui/debug/contextlaunching = false org.eclipse.debug.ui/debug/launchhistory = false +org.eclipse.debug.ui/debug/viewers/stateSaveRestore = false diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ChildrenCountUpdate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ChildrenCountUpdate.java index f09f06ff5..3879f93c3 100644 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ChildrenCountUpdate.java +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ChildrenCountUpdate.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2007 IBM Corporation and others. + * Copyright (c) 2006, 2008 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Wind River Systems - Fix for viewer state save/restore [188704] *******************************************************************************/ package org.eclipse.debug.internal.ui.viewers.model; @@ -51,6 +52,7 @@ class ChildrenCountUpdate extends ViewerUpdateMonitor implements IChildrenCountU System.out.println("setChildCount(" + getElement() + ", modelCount: " + fCount + " viewCount: " + viewCount + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ } ((TreeViewer)(getContentProvider().getViewer())).setChildCount(elementPath, viewCount); + getContentProvider().doRestore(getElementPath(), -1, true, true); } public void setChildCount(int numChildren) { diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ChildrenUpdate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ChildrenUpdate.java index 3818599ce..2d9f89842 100644 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ChildrenUpdate.java +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ChildrenUpdate.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2007 IBM Corporation and others. + * Copyright (c) 2006, 2008 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Wind River Systems - Fix for viewer state save/restore [188704] *******************************************************************************/ package org.eclipse.debug.internal.ui.viewers.model; @@ -76,6 +77,7 @@ public class ChildrenUpdate extends ViewerUpdateMonitor implements IChildrenUpda } TreePath childPath = elementPath.createChildPath(element); provider.updateHasChildren(childPath); + provider.doRestore(childPath, modelIndex, false, false); } } } 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 bcabac9f2..66b44cc5f 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006 IBM Corporation and others. + * Copyright (c) 2006, 2008 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 @@ -7,13 +7,18 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Wind River Systems - Fix for viewer state save/restore [188704] *******************************************************************************/ package org.eclipse.debug.internal.ui.viewers.model; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest; import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta; import org.eclipse.jface.viewers.TreePath; import org.eclipse.ui.IMemento; +import org.eclipse.ui.progress.UIJob; /** * @since 3.3 @@ -21,16 +26,24 @@ import org.eclipse.ui.IMemento; class ElementCompareRequest extends MementoUpdate implements IElementCompareRequest { private boolean fEqual; + private final int fModelIndex; private ModelDelta fDelta; + private boolean fKnowsHasChildren; + private boolean fKnowsChildCount; + + /** * @param context * @param element * @param memento */ - public ElementCompareRequest(ModelContentProvider provider, Object viewerInput, Object element, TreePath elementPath, IMemento memento, ModelDelta delta) { + public ElementCompareRequest(ModelContentProvider provider, Object viewerInput, Object element, TreePath elementPath, IMemento memento, ModelDelta delta, int modelIndex, boolean hasChildren, boolean knowsChildCount) { super(provider, viewerInput, provider.getPresentationContext(), element, elementPath, memento); fProvider = provider; fDelta = delta; + fModelIndex = modelIndex; + fKnowsHasChildren = hasChildren; + fKnowsChildCount = knowsChildCount; } /* (non-Javadoc) @@ -44,14 +57,43 @@ class ElementCompareRequest extends MementoUpdate implements IElementCompareRequ * @see org.eclipse.core.runtime.IProgressMonitor#done() */ public void done() { - if (isEqual()) { - fDelta.setElement(getElement()); - fProvider.doRestore(fDelta); - } + UIJob job = new UIJob("restore delta") { //$NON-NLS-1$ + public IStatus runInUIThread(IProgressMonitor monitor) { + if (!isCanceled()) { + fProvider.compareFinished(ElementCompareRequest.this, fDelta); + } + return Status.OK_STATUS; + } + }; + job.setSystem(true); + job.schedule(); } boolean isEqual() { return fEqual; } + + ModelDelta getDelta() { + return fDelta; + } + + int getModelIndex() { + return fModelIndex; + } + void setKnowsHasChildren(boolean hasChildren) { + fKnowsHasChildren = hasChildren; + } + + boolean knowsHasChildren() { + return fKnowsHasChildren; + } + + void setKnowsChildCount(boolean childCount) { + fKnowsChildCount = childCount; + } + + boolean knowChildCount() { + return fKnowsChildCount; + } } diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/HasChildrenUpdate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/HasChildrenUpdate.java index f7ad83330..9f5110b9f 100644 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/HasChildrenUpdate.java +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/HasChildrenUpdate.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2007 IBM Corporation and others. + * Copyright (c) 2006, 2008 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Wind River Systems - Fix for viewer state save/restore [188704] *******************************************************************************/ package org.eclipse.debug.internal.ui.viewers.model; @@ -52,7 +53,7 @@ class HasChildrenUpdate extends ViewerUpdateMonitor implements IHasChildrenUpdat ((InternalTreeModelViewer)contentProvider.getViewer()).autoExpand(elementPath); } if (elementPath.getSegmentCount() > 0) { - contentProvider.doRestore(elementPath); + getContentProvider().doRestore(getElementPath(), -1, true, false); } } 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 15032c187..6fb2940c5 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2007 IBM Corporation and others. + * Copyright (c) 2006, 2008 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 @@ -8,6 +8,7 @@ * Contributors: * IBM Corporation - initial API and implementation * Pawel Piech - Wind River - Bug 205335: ModelContentProvider does not cancel stale updates when switching viewer input + * Wind River Systems - Fix for viewer state save/restore [188704] *******************************************************************************/ package org.eclipse.debug.internal.ui.viewers.model; @@ -18,6 +19,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -102,6 +104,29 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi * 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 @@ -174,12 +199,15 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi // debug flags public static boolean DEBUG_CONTENT_PROVIDER = false; public static boolean DEBUG_UPDATE_SEQUENCE = false; + public static boolean DEBUG_STATE_SAVE_RESTORE = false; static { 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$ } /* @@ -219,9 +247,14 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi public synchronized void inputChanged(Viewer viewer, Object oldInput, Object newInput) { fViewer = 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(); @@ -251,7 +284,7 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi * * @param input viewer input */ - private synchronized void startRestoreViewerState(final Object input) { + private synchronized void startRestoreViewerState(final Object input) { fPendingState = null; final IElementMementoProvider defaultProvider = ViewerAdapterService.getMementoProvider(input); if (defaultProvider != null) { @@ -271,18 +304,20 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi StringWriter writer = new StringWriter(); try { keyMemento.save(writer); - final ModelDelta stateDelta = (ModelDelta) fViewerStates.remove(writer.toString()); + final String keyMementoString = writer.toString(); + final ModelDelta stateDelta = (ModelDelta) fViewerStates.get(keyMementoString); if (stateDelta != null) { - if (DEBUG_CONTENT_PROVIDER) { - System.out.println("RESTORE: " + stateDelta.toString()); //$NON-NLS-1$ - } 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) { + System.out.println("RESTORE: " + stateDelta.toString()); //$NON-NLS-1$ + } + fViewerStates.remove(keyMementoString); fPendingState = stateDelta; - doInitialRestore(); + doInitialRestore(fPendingState); } return Status.OK_STATUS; } @@ -318,71 +353,240 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi } } + /** + * Restore selection/expansion based on items already in the viewer + */ + protected abstract void doInitialRestore(ModelDelta delta); + /** - * Restore selection/expansion based on items already in the viewer - */ - abstract protected void doInitialRestore(); - - /** - * @param delta - */ - abstract void doRestore(final ModelDelta delta); - + * @param delta + */ + abstract void doRestore(final ModelDelta delta, boolean knowsHasChildren, boolean knowsChildCount); + /** * Perform any restoration required for the given tree path. * * @param path */ - protected synchronized void doRestore(final TreePath path) { + protected synchronized void doRestore(final TreePath path, final int modelIndex, final boolean knowsHasChildren, final boolean knowsChildCount) { if (fPendingState == null) { return; } + IModelDeltaVisitor visitor = new IModelDeltaVisitor() { - public boolean visit(IModelDelta delta, int depth) { - if (delta.getParentDelta() == null) { - return true; - } + public boolean visit(final IModelDelta delta, int depth) { + Object element = delta.getElement(); - Object potentialMatch = path.getSegment(depth - 1); - if (element instanceof IMemento) { - IElementMementoProvider provider = ViewerAdapterService.getMementoProvider(potentialMatch); - if (provider == null) { - provider = ViewerAdapterService.getMementoProvider(getViewer().getInput()); - } - if (provider != null) { - provider.compareElements(new IElementCompareRequest[]{ - new ElementCompareRequest(ModelContentProvider.this, getViewer().getInput(), - potentialMatch, path, (IMemento) element, (ModelDelta)delta)}); - } - } else { - if (element.equals(potentialMatch)) { - // already processed - visit children - return path.getSegmentCount() > depth; + 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); + } else { + // Start a new compare request + ElementCompareRequest compareRequest = new ElementCompareRequest( + ModelContentProvider.this, getViewer().getInput(), potentialMatch, path, (IMemento) element, (ModelDelta)delta, modelIndex, knowsHasChildren, knowsChildCount); + 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); } - } - return false; + 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()); + } 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 + * * @param oldInput */ protected void saveViewerState(Object input) { IElementMementoProvider stateProvider = ViewerAdapterService.getMementoProvider(input); if (stateProvider != null) { + if (DEBUG_STATE_SAVE_RESTORE) { + System.out.println("SAVE BEGIN: " + input); //$NON-NLS-1$ + } + // build a model delta representing expansion and selection state - ModelDelta delta = new ModelDelta(input, IModelDelta.NO_CHANGE); - buildViewerState(delta); - if (delta.getChildDeltas().length > 0) { + final ModelDelta saveDeltaRoot = new ModelDelta(input, IModelDelta.NO_CHANGE); + buildViewerState(saveDeltaRoot); + if (DEBUG_STATE_SAVE_RESTORE) { + System.out.println("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) { + System.out.println("SAVE OUTSTANDING RESTORE: " + fPendingState); //$NON-NLS-1$ + } + + IModelDeltaVisitor pendingStateVisitor = new IModelDeltaVisitor() { + public boolean visit(IModelDelta pendingDeltaNode, int depth) { + // Ignore the top element. + if (pendingDeltaNode.getParentDelta() == null) { + return true; + } + + // Find the node in the save delta which is the parent + // of to the current pending delta node. + // If the parent node cannot be found, it means that + // most likely the user collapsed the parent node before + // the children were ever expanded. + // If the pending state node already exists in the parent + // node, it is already processed and we can skip it. + // If the pending state node does not contain any flags, + // we can also skip it. + ModelDelta saveDeltaNode = 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 + // reveal flag in the pending delta trumps the one + // in the save delta because most likely the restore + // operation did not yet complete the reveal + // operation. + if ( (pendingDeltaNode.getFlags() & IModelDelta.REVEAL) != 0) { + clearRevealFlag(saveDeltaRoot); + } + saveDeltaNode.setChildCount(pendingDeltaNode.getParentDelta().getChildCount()); + copyIntoDelta(pendingDeltaNode, saveDeltaNode); + } else { + if (DEBUG_STATE_SAVE_RESTORE) { + System.out.println(" Skipping: " + pendingDeltaNode.getElement()); //$NON-NLS-1$ + } + } + + // If the pending delta node has a memento element, its + // children should also be mementos therefore the copy + // delta operation should have added all the children + // of this pending delta node into the save delta. + if (pendingDeltaNode.getElement() instanceof IMemento) { + return false; + } else { + return pendingDeltaNode.getChildCount() > 0; + } + } + }; + fPendingState.accept(pendingStateVisitor); + } + + if (saveDeltaRoot.getChildDeltas().length > 0) { // encode delta with mementos in place of elements, in non-UI thread - encodeDelta(delta, stateProvider); + encodeDelta(saveDeltaRoot, stateProvider); + } else { + if (DEBUG_STATE_SAVE_RESTORE) { + System.out.println("SAVE CANCELED, NO DATA"); //$NON-NLS-1$ + } } } } + + private void clearRevealFlag(ModelDelta saveRootDelta) { + IModelDeltaVisitor clearDeltaVisitor = new IModelDeltaVisitor() { + public boolean visit(IModelDelta delta, int depth) { + if ( (delta.getFlags() & IModelDelta.REVEAL) != 0) { + ((ModelDelta)delta).setFlags(delta.getFlags() & ~IModelDelta.REVEAL); + } + return true; + } + }; + saveRootDelta.accept(clearDeltaVisitor); + } + + private ModelDelta 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 patch 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) ) { + 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. + + 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. @@ -417,6 +621,9 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi } catch (IOException e) { DebugUIPlugin.log(e); } + if (DEBUG_STATE_SAVE_RESTORE) { + System.out.println("SAVE COMPLETED: " + rootDelta); //$NON-NLS-1$ + } stateSaveComplete(this); } } else { @@ -427,6 +634,9 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi req.cancel(); } requests.clear(); + if (DEBUG_STATE_SAVE_RESTORE) { + System.out.println("SAVE ABORTED: " + rootDelta.getElement()); //$NON-NLS-1$ + } stateSaveComplete(this); } } @@ -473,14 +683,16 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi if (delta.getParentDelta() == null) { manager.addRequest( new ElementMementoRequest(ModelContentProvider.this, getViewer().getInput(), manager, getPresentationContext(), - delta.getElement(), getViewerTreePath(delta), inputMemento, (ModelDelta)delta)); - } else { + 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; + } } + return true; + } }; rootDelta.accept(visitor); stateSaveStarted(manager); @@ -869,20 +1081,18 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi fTransform.clear(parent); } - protected synchronized IModelDelta checkIfRestoreComplete() { + protected synchronized void checkIfRestoreComplete() { if (fPendingState == null) { - return null; + return; } CheckState state = new CheckState(); fPendingState.accept(state); if (state.isComplete()) { + if (DEBUG_STATE_SAVE_RESTORE) { + System.out.println("RESTORE COMPELTE: " + fPendingState); //$NON-NLS-1$ + } fPendingState = null; - if (DEBUG_CONTENT_PROVIDER) { - System.out.println("RESTORE COMPELTE"); //$NON-NLS-1$ - } - return state.getTopItemDelta(); } - return null; } void addViewerUpdateListener(IViewerUpdateListener listener) { @@ -1008,6 +1218,14 @@ abstract class ModelContentProvider implements IContentProvider, IModelChangedLi 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(); + } + } } /** 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 086016cc5..fc77a6d3b 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2007 IBM Corporation and others. + * Copyright (c) 2006, 2008 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 @@ -7,17 +7,18 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Wind River Systems - Fix for viewer state save/restore [188704] *******************************************************************************/ package org.eclipse.debug.internal.ui.viewers.model; import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; import java.util.Set; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDeltaVisitor; import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta; import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer; @@ -30,7 +31,6 @@ import org.eclipse.swt.widgets.Item; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.swt.widgets.Widget; -import org.eclipse.ui.progress.UIJob; /** * Content provider for a virtual tree. @@ -358,21 +358,29 @@ public class TreeModelContentProvider extends ModelContentProvider implements IL for (int i = 0; i < items.length; i++) { buildViewerState(EMPTY_TREE_PATH, delta, items[i], set, i); } - // add memento for top item if it is mapped to an element + // Add memento for top item if it is mapped to an element. The reveal memento + // is in its own path to avoid requesting unnecessary data when restoring it. TreeItem topItem = tree.getTopItem(); if (topItem != null && topItem.getData() != null) { - TreePath path = ((InternalTreeModelViewer)getTreeViewer()).getTreePathFromItem(topItem); + LinkedList itemsInPath = new LinkedList(); + TreeItem item = topItem; + while (item != null) { + itemsInPath.addFirst(item); + item = item.getParentItem(); + } ModelDelta parentDelta = delta; - for (int i = 0; i < path.getSegmentCount(); i++) { - Object element = path.getSegment(i); - ModelDelta childDelta = parentDelta.getChildDelta(element); - if (childDelta == null) { - parentDelta = parentDelta.addNode(element, IModelDelta.NO_CHANGE); - } else { - parentDelta = childDelta; - } + for (Iterator itr = itemsInPath.iterator(); itr.hasNext();) { + TreeItem next = (TreeItem)itr.next(); + Object element = next.getData(); + int index = next.getParentItem() == null ? tree.indexOf(next) : next.getParentItem().indexOf(next); + ModelDelta childDelta = parentDelta.getChildDelta(element); + if (childDelta == null) { + parentDelta = parentDelta.addNode(element, index, IModelDelta.NO_CHANGE); + } else { + parentDelta = childDelta; + } } - parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.REVEAL); + parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.REVEAL); } } @@ -412,17 +420,60 @@ public class TreeModelContentProvider extends ModelContentProvider implements IL /* (non-Javadoc) * @see org.eclipse.debug.internal.ui.viewers.model.provisional.viewers.ModelContentProvider#doInitialRestore() */ - protected void doInitialRestore() { - Tree tree = (Tree) getViewer().getControl(); - TreeItem[] items = tree.getItems(); - for (int i = 0; i < items.length; i++) { - TreeItem item = items[i]; - Object data = item.getData(); - if (data != null) { - doRestore(new TreePath(new Object[]{data})); - } - } - } + protected void doInitialRestore(ModelDelta delta) { + // First restore the reveal delta. + ModelDelta revealDelta = findRevealDelta(delta); + /*if (revealDelta != null) { + doUpdateElement(TreePath.EMPTY, revealDelta.getIndex()); + }*/ + + // Restore visible items. + // Note (Pawel Piech): the initial list of items is normally + // empty, so I'm not sure if the code below ever does anything. + Tree tree = (Tree) getViewer().getControl(); + TreeItem[] items = tree.getItems(); + for (int i = 0; i < items.length; i++) { + TreeItem item = items[i]; + Object data = item.getData(); + if (data != null) { + doRestore(new TreePath(new Object[]{data}), i, false, false); + } + } + + } + + /** + * Finds the delta with the reveal flag, then it walks up this + * delta and marks all the parents of it with the reveal flag. + * These flags are then used by the restore logic to restore + * and reveal all the nodes leading up to the element that should + * be ultimately at the top. + * @return The node just under the rootDelta which contains + * the reveal flag. <code>null</code> if no reveal flag was found. + */ + private ModelDelta findRevealDelta(ModelDelta rootDelta) { + final ModelDelta[] revealDelta = new ModelDelta[1]; + IModelDeltaVisitor visitor = new IModelDeltaVisitor() { + public boolean visit(IModelDelta delta, int depth) { + if ( (delta.getFlags() & IModelDelta.REVEAL) != 0) { + revealDelta[0] = (ModelDelta)delta; + } + // Keep recursing only if we haven't found our delta yet. + return revealDelta[0] == null; + } + }; + + rootDelta.accept(visitor); + if (revealDelta[0] != null) { + ModelDelta parentDelta = (ModelDelta)revealDelta[0].getParentDelta(); + while(parentDelta.getParentDelta() != null) { + revealDelta[0] = parentDelta; + revealDelta[0].setFlags(revealDelta[0].getFlags() | IModelDelta.REVEAL); + parentDelta = (ModelDelta)parentDelta.getParentDelta(); + } + } + return revealDelta[0]; + } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ILazyTreePathContentProvider#getParents(java.lang.Object) @@ -468,45 +519,56 @@ public class TreeModelContentProvider extends ModelContentProvider implements IL /** * @param delta */ - void doRestore(final ModelDelta delta) { - if (delta.getFlags() != IModelDelta.NO_CHANGE) { - UIJob job = new UIJob("restore delta") { //$NON-NLS-1$ - public IStatus runInUIThread(IProgressMonitor monitor) { - TreePath treePath = getViewerTreePath(delta); - InternalTreeModelViewer viewer = (InternalTreeModelViewer)getViewer(); - if ((delta.getFlags() & IModelDelta.EXPAND) != 0) { - viewer.expandToLevel(treePath, 1); - } - if ((delta.getFlags() & IModelDelta.SELECT) != 0) { - viewer.setSelection(new TreeSelection(treePath)); - } - int flag = IModelDelta.NO_CHANGE; - if ((delta.getFlags() & IModelDelta.REVEAL) != 0) { - flag = IModelDelta.REVEAL; - } - delta.setFlags(flag); - IModelDelta topItemDelta = checkIfRestoreComplete(); - // force child deltas to update, so viewer is populated - IModelDelta[] childDeltas = delta.getChildDeltas(); - for (int i = 0; i < childDeltas.length; i++) { - IModelDelta childDelta = childDeltas[i]; - int modelIndex = childDelta.getIndex(); - if (modelIndex >= 0) { - doUpdateElement(treePath, modelIndex); - } - } - if (topItemDelta != null) { - TreePath itemPath = getViewerTreePath(topItemDelta); - Widget topItem = viewer.findItem(itemPath); - if (topItem instanceof TreeItem) { - viewer.getTree().setTopItem((TreeItem) topItem); - } - } - return Status.OK_STATUS; - } - }; - job.setSystem(true); - job.schedule(); + void doRestore(ModelDelta delta, boolean knowsHasChildren, boolean knowsChildCount) { + TreePath treePath = getViewerTreePath(delta); + InternalTreeModelViewer viewer = (InternalTreeModelViewer)getViewer(); + // Attempt to expand the node only if the children are known. + if (knowsHasChildren && (delta.getFlags() & IModelDelta.EXPAND) != 0) { + viewer.expandToLevel(treePath, 1); + delta.setFlags(delta.getFlags() & ~IModelDelta.EXPAND); + } + if ((delta.getFlags() & IModelDelta.SELECT) != 0) { + viewer.setSelection(new TreeSelection(treePath), false); + delta.setFlags(delta.getFlags() & ~IModelDelta.SELECT); } + if ((delta.getFlags() & IModelDelta.REVEAL) != 0) { + delta.setFlags(delta.getFlags() & ~IModelDelta.REVEAL); + // Look for the reveal flag in the child deltas. If + // A child delta has the reveal flag, do not set the + // top element yet. + boolean setTopItem = true; + IModelDelta[] childDeltas = delta.getChildDeltas(); + for (int i = 0; i < childDeltas.length; i++) { + IModelDelta childDelta = childDeltas[i]; + int modelIndex = childDelta.getIndex(); + if (modelIndex >= 0 && (childDelta.getFlags() & IModelDelta.REVEAL) != 0) { + setTopItem = false; + } + } + + if (setTopItem) { + TreePath itemPath = getViewerTreePath(delta); + Widget topItem = viewer.findItem(itemPath); + if (topItem instanceof TreeItem) { + viewer.getTree().setTopItem((TreeItem) topItem); + } + } + } + + // If we know the children, look for the reveal delta in + // the child deltas. For the children with reveal + // flag start a new update. + if (knowsChildCount) { + IModelDelta[] childDeltas = delta.getChildDeltas(); + for (int i = 0; i < childDeltas.length; i++) { + IModelDelta childDelta = childDeltas[i]; + int modelIndex = childDelta.getIndex(); + if (modelIndex >= 0 && (childDelta.getFlags() & IModelDelta.REVEAL) != 0) { + doUpdateElement(treePath, modelIndex); + } + } + } + + checkIfRestoreComplete(); } } diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ModelDelta.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ModelDelta.java index d41500402..321550301 100644 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ModelDelta.java +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ModelDelta.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 IBM Corporation and others. + * Copyright (c) 2005, 2008 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Wind River Systems - Fix for viewer state save/restore [188704] *******************************************************************************/ package org.eclipse.debug.internal.ui.viewers.model.provisional; @@ -235,16 +236,18 @@ public class ModelDelta implements IModelDelta { public String toString() { StringBuffer buf = new StringBuffer(); buf.append("Model Delta Start\n"); //$NON-NLS-1$ - appendDetail(buf, this); + appendDetail(" ", buf, this); //$NON-NLS-1$ buf.append("Model Delta End\n"); //$NON-NLS-1$ return buf.toString(); } - private void appendDetail(StringBuffer buf, IModelDelta delta) { - buf.append("\tElement: "); //$NON-NLS-1$ + private void appendDetail(String indent, StringBuffer buf, IModelDelta delta) { + buf.append(indent); + buf.append("Element: "); //$NON-NLS-1$ buf.append(delta.getElement()); buf.append('\n'); - buf.append("\t\tFlags: "); //$NON-NLS-1$ + buf.append(indent); + buf.append(" Flags: "); //$NON-NLS-1$ int flags = delta.getFlags(); if (flags == 0) { buf.append("NO_CHANGE"); //$NON-NLS-1$ @@ -279,16 +282,21 @@ public class ModelDelta implements IModelDelta { if ((flags & IModelDelta.UNINSTALL) > 0) { buf.append("UNINSTALL | "); //$NON-NLS-1$ } + if ((flags & IModelDelta.REVEAL) > 0) { + buf.append("REVEAL | "); //$NON-NLS-1$ + } + } buf.append('\n'); - buf.append("\t\tIndex: "); //$NON-NLS-1$ + buf.append(indent); + buf.append(" Index: "); //$NON-NLS-1$ buf.append(delta.getIndex()); buf.append(" Child Count: "); //$NON-NLS-1$ buf.append(delta.getChildCount()); buf.append('\n'); IModelDelta[] nodes = delta.getChildDeltas(); for (int i = 0; i < nodes.length; i++) { - appendDetail(buf, nodes[i]); + appendDetail(indent + " ", buf, nodes[i]); //$NON-NLS-1$ } } @@ -332,4 +340,14 @@ public class ModelDelta implements IModelDelta { public void setFlags(int flags) { fFlags = flags; } + + /** + * Sets this delta's child count. + * + * @param count + */ + public void setChildCount(int count) { + fChildCount = count; + } + } |