diff options
Diffstat (limited to 'org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ViewerStateTracker.java')
-rw-r--r-- | org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ViewerStateTracker.java | 2086 |
1 files changed, 1043 insertions, 1043 deletions
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ViewerStateTracker.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ViewerStateTracker.java index 4fb884148..4ddb63f31 100644 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ViewerStateTracker.java +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ViewerStateTracker.java @@ -77,208 +77,208 @@ import org.eclipse.ui.XMLMemento; */ class ViewerStateTracker { - // State update type constants used in notifying listeners - static final int STATE_SAVE_SEQUENCE_BEGINS = 4; - static final int STATE_SAVE_SEQUENCE_COMPLETE = 5; - static final int STATE_RESTORE_SEQUENCE_BEGINS = 6; - static final int STATE_RESTORE_SEQUENCE_COMPLETE = 7; - - /** - * Dummy marker element used in the state delta. The marker indicates that a - * given element in the pending state delta has been removed. It replaces - * the original element so that it may optionally be garbage collected. - */ - private final static String ELEMENT_REMOVED = "ELEMENT_REMOVED"; //$NON-NLS-1$ - - /** - * Collector of memento encoding requests. - */ - interface IElementMementoCollector { - - /** - * Adds the request to this manager. - * - * @param request to add - */ - void addRequest(ElementMementoRequest request); - - /** - * Notification the request is complete. - * - * @param request that was completed - */ - void requestComplete(ElementMementoRequest request); - - /** - * Process the queued requests. Accepts no more new requests. - */ - void processReqeusts(); - - /** - * Cancels the requests in progress. - */ - void cancel(); - } - - /** - * LRU cache for viewer states - */ + // State update type constants used in notifying listeners + static final int STATE_SAVE_SEQUENCE_BEGINS = 4; + static final int STATE_SAVE_SEQUENCE_COMPLETE = 5; + static final int STATE_RESTORE_SEQUENCE_BEGINS = 6; + static final int STATE_RESTORE_SEQUENCE_COMPLETE = 7; + + /** + * Dummy marker element used in the state delta. The marker indicates that a + * given element in the pending state delta has been removed. It replaces + * the original element so that it may optionally be garbage collected. + */ + private final static String ELEMENT_REMOVED = "ELEMENT_REMOVED"; //$NON-NLS-1$ + + /** + * Collector of memento encoding requests. + */ + interface IElementMementoCollector { + + /** + * Adds the request to this manager. + * + * @param request to add + */ + void addRequest(ElementMementoRequest request); + + /** + * Notification the request is complete. + * + * @param request that was completed + */ + void requestComplete(ElementMementoRequest request); + + /** + * Process the queued requests. Accepts no more new requests. + */ + void processReqeusts(); + + /** + * Cancels the requests in progress. + */ + void cancel(); + } + + /** + * LRU cache for viewer states + */ class LRUMap<K, V> extends LinkedHashMap<K, V> { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - private int fMaxSize; + private int fMaxSize; - LRUMap(int maxSize) { - super(); - fMaxSize = maxSize; - } + LRUMap(int maxSize) { + super(); + fMaxSize = maxSize; + } - @Override + @Override protected boolean removeEldestEntry(Entry<K, V> eldest) { - return size() > fMaxSize; - } - } - - /** - * Content provider that is using this state tracker. - */ - private TreeModelContentProvider fContentProvider; - - ViewerStateTracker(TreeModelContentProvider contentProvider) { - fContentProvider = contentProvider; - } - - /** - * Map of viewer states keyed by viewer input mementos - */ + return size() > fMaxSize; + } + } + + /** + * Content provider that is using this state tracker. + */ + private TreeModelContentProvider fContentProvider; + + ViewerStateTracker(TreeModelContentProvider contentProvider) { + fContentProvider = contentProvider; + } + + /** + * Map of viewer states keyed by viewer input mementos + */ private Map<String, ModelDelta> fViewerStates = new LRUMap<>(20); - /** - * Pending viewer state to be restored - */ - private ModelDelta fPendingState = null; + /** + * Pending viewer state to be restored + */ + private ModelDelta fPendingState = null; - /** - * Flag indicating that the content provider is performing - * state restore operations. - */ - private boolean fInStateRestore = false; + /** + * Flag indicating that the content provider is performing + * state restore operations. + */ + private boolean fInStateRestore = false; - /** - * State update listeners - */ + /** + * State update listeners + */ private ListenerList<IStateUpdateListener> fStateUpdateListeners = new ListenerList<>(); - /** - * Postpone restoring REVEAL element until the current updates are complete. - * See bug 324100 - */ - protected PendingRevealDelta fPendingSetTopItem = null; + /** + * Postpone restoring REVEAL element until the current updates are complete. + * See bug 324100 + */ + protected PendingRevealDelta fPendingSetTopItem = null; - /** - * Set of IMementoManager's that are currently saving state - */ + /** + * Set of IMementoManager's that are currently saving state + */ private Set<IElementMementoCollector> fPendingStateSaves = new HashSet<>(); - /** - * Used to queue a viewer input for state restore - */ - private Object fQueuedRestore = null; + /** + * Used to queue a viewer input for state restore + */ + private Object fQueuedRestore = null; - /** - * Object used to key compare requests in map. - */ - private static class CompareRequestKey { + /** + * Object used to key compare requests in map. + */ + private static class CompareRequestKey { - CompareRequestKey(TreePath path, IModelDelta delta) { - fPath = path; - fDelta = delta; - } + CompareRequestKey(TreePath path, IModelDelta delta) { + fPath = path; + fDelta = delta; + } - TreePath fPath; - IModelDelta fDelta; + TreePath fPath; + IModelDelta fDelta; - @Override + @Override public boolean equals(Object obj) { - if (obj instanceof CompareRequestKey) { - CompareRequestKey key = (CompareRequestKey) obj; - return key.fDelta.equals(fDelta) && key.fPath.equals(fPath); - } - return false; - } - - @Override + if (obj instanceof CompareRequestKey) { + CompareRequestKey key = (CompareRequestKey) obj; + return key.fDelta.equals(fDelta) && key.fPath.equals(fPath); + } + return false; + } + + @Override public int hashCode() { - return fDelta.hashCode() + fPath.hashCode(); - } - } + return fDelta.hashCode() + fPath.hashCode(); + } + } - /** - * Compare requests that are currently running. - */ + /** + * Compare requests that are currently running. + */ private Map<CompareRequestKey, ElementCompareRequest> fCompareRequestsInProgress = new LinkedHashMap<>(); - /** - * Cancels pending updates. - */ - void dispose() { - Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); + /** + * Cancels pending updates. + */ + void dispose() { + Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); for (IElementMementoCollector emc : fPendingStateSaves) { emc.cancel(); - } - fStateUpdateListeners.clear(); + } + fStateUpdateListeners.clear(); for (ElementCompareRequest ecr : fCompareRequestsInProgress.values()) { ecr.cancel(); - } - fCompareRequestsInProgress.clear(); - - if (fPendingSetTopItem != null) { - fPendingSetTopItem.dispose(); - } - } - - /** - * Restores viewer state for the given input - * - * @param input - * viewer input - */ - private void startRestoreViewerState(final Object input) { - Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); - - fPendingState = null; - final IElementMementoProvider defaultProvider = ViewerAdapterService.getMementoProvider(input); - if (defaultProvider != null) { - // build a model delta representing expansion and selection state - final ModelDelta delta = new ModelDelta(input, IModelDelta.NO_CHANGE); - final XMLMemento inputMemento = XMLMemento.createWriteRoot("VIEWER_INPUT_MEMENTO"); //$NON-NLS-1$ - final IElementMementoCollector manager = new IElementMementoCollector() { - - private IElementMementoRequest fRequest; - - @Override + } + fCompareRequestsInProgress.clear(); + + if (fPendingSetTopItem != null) { + fPendingSetTopItem.dispose(); + } + } + + /** + * Restores viewer state for the given input + * + * @param input + * viewer input + */ + private void startRestoreViewerState(final Object input) { + Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); + + fPendingState = null; + final IElementMementoProvider defaultProvider = ViewerAdapterService.getMementoProvider(input); + if (defaultProvider != null) { + // build a model delta representing expansion and selection state + final ModelDelta delta = new ModelDelta(input, IModelDelta.NO_CHANGE); + final XMLMemento inputMemento = XMLMemento.createWriteRoot("VIEWER_INPUT_MEMENTO"); //$NON-NLS-1$ + final IElementMementoCollector manager = new IElementMementoCollector() { + + private IElementMementoRequest fRequest; + + @Override public void requestComplete(ElementMementoRequest request) { - if (fContentProvider.isDisposed()) { + if (fContentProvider.isDisposed()) { return; } - notifyStateUpdate(input, TreeModelContentProvider.UPDATE_COMPLETE, request); - - if (!request.isCanceled() && (request.getStatus() == null || request.getStatus().isOK())) { - XMLMemento keyMemento = (XMLMemento) delta.getElement(); - StringWriter writer = new StringWriter(); - try { - keyMemento.save(writer); - final String keyMementoString = writer.toString(); - ModelDelta stateDelta = fViewerStates.get(keyMementoString); - if (stateDelta != null) { - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("STATE RESTORE INPUT COMARE ENDED : " + fRequest + " - MATCHING STATE FOUND"); //$NON-NLS-1$ //$NON-NLS-2$ - } - - // Process start of restore in an async cycle because we may still be inside inputChanged() - // call. I.e. the "input.equals(fContentProvider.getViewer().getInput())" test may fail. + notifyStateUpdate(input, TreeModelContentProvider.UPDATE_COMPLETE, request); + + if (!request.isCanceled() && (request.getStatus() == null || request.getStatus().isOK())) { + XMLMemento keyMemento = (XMLMemento) delta.getElement(); + StringWriter writer = new StringWriter(); + try { + keyMemento.save(writer); + final String keyMementoString = writer.toString(); + ModelDelta stateDelta = fViewerStates.get(keyMementoString); + if (stateDelta != null) { + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("STATE RESTORE INPUT COMARE ENDED : " + fRequest + " - MATCHING STATE FOUND"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + // Process start of restore in an async cycle because we may still be inside inputChanged() + // call. I.e. the "input.equals(fContentProvider.getViewer().getInput())" test may fail. fContentProvider.getViewer().getDisplay().asyncExec(() -> { if (!fContentProvider.isDisposed() && input.equals(fContentProvider.getViewer().getInput())) { @@ -303,85 +303,85 @@ class ViewerStateTracker { } } }); - } else { - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("STATE RESTORE INPUT COMARE ENDED : " + fRequest + " - NO MATCHING STATE"); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - } catch (IOException e) { - DebugUIPlugin.log(e); - } - } else { - notifyStateUpdate(input, STATE_RESTORE_SEQUENCE_BEGINS, null); - } - } - - @Override + } else { + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("STATE RESTORE INPUT COMARE ENDED : " + fRequest + " - NO MATCHING STATE"); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + } catch (IOException e) { + DebugUIPlugin.log(e); + } + } else { + notifyStateUpdate(input, STATE_RESTORE_SEQUENCE_BEGINS, null); + } + } + + @Override public void processReqeusts() { - notifyStateUpdate(input, STATE_RESTORE_SEQUENCE_BEGINS, null); - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("STATE RESTORE INPUT COMARE BEGIN : " + fRequest); //$NON-NLS-1$ - } - notifyStateUpdate(input, TreeModelContentProvider.UPDATE_BEGINS, fRequest); - defaultProvider.encodeElements(new IElementMementoRequest[] { fRequest }); - } - - @Override + notifyStateUpdate(input, STATE_RESTORE_SEQUENCE_BEGINS, null); + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("STATE RESTORE INPUT COMARE BEGIN : " + fRequest); //$NON-NLS-1$ + } + notifyStateUpdate(input, TreeModelContentProvider.UPDATE_BEGINS, fRequest); + defaultProvider.encodeElements(new IElementMementoRequest[] { fRequest }); + } + + @Override public void addRequest(ElementMementoRequest req) { - fRequest = req; - } + fRequest = req; + } - @Override + @Override public void cancel() { - // not used - } - - }; - manager.addRequest( - new ElementMementoRequest(fContentProvider, fContentProvider.getViewer().getInput(), manager, - delta.getElement(), fContentProvider.getViewerTreePath(delta), inputMemento, delta)); - manager.processReqeusts(); - } else { - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("STATE RESTORE: No input memento provider"); //$NON-NLS-1$ - } - } - } - - /** - * Appends the state of the given subtree to the current pending delta. - * @param path Path to subtree to restore. - */ - void appendToPendingStateDelta(final TreePath path) { - if (fContentProvider.getViewer() == null) + // not used + } + + }; + manager.addRequest( + new ElementMementoRequest(fContentProvider, fContentProvider.getViewer().getInput(), manager, + delta.getElement(), fContentProvider.getViewerTreePath(delta), inputMemento, delta)); + manager.processReqeusts(); + } else { + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("STATE RESTORE: No input memento provider"); //$NON-NLS-1$ + } + } + } + + /** + * Appends the state of the given subtree to the current pending delta. + * @param path Path to subtree to restore. + */ + void appendToPendingStateDelta(final TreePath path) { + if (fContentProvider.getViewer() == null) { return; // Not initialized yet. } - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("STATE APPEND BEGIN: " + path.getLastSegment()); //$NON-NLS-1$ - } - - // build a model delta representing expansion and selection state - final ModelDelta appendDeltaRoot = new ModelDelta(fContentProvider.getViewer().getInput(), IModelDelta.NO_CHANGE); - ModelDelta delta = appendDeltaRoot; - for (int i = 0; i < path.getSegmentCount(); i++) { - delta = delta.addNode(path.getSegment(i), IModelDelta.NO_CHANGE); - } - - if (!fContentProvider.getViewer().saveElementState(path, delta, IModelDelta.COLLAPSE | IModelDelta.EXPAND | IModelDelta.SELECT)) { - // Path to save the state was not found or there was no - // (expansion) state to save! Abort. - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("STATE APPEND CANCEL: Element " + path.getLastSegment() + " not found."); //$NON-NLS-1$ //$NON-NLS-2$ - } - return; - } - - // Append a marker CONTENT flag to all the delta nodes that contain the - // EXPAND node. These - // markers are used by the restore logic to know when a delta node can - // be removed. + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("STATE APPEND BEGIN: " + path.getLastSegment()); //$NON-NLS-1$ + } + + // build a model delta representing expansion and selection state + final ModelDelta appendDeltaRoot = new ModelDelta(fContentProvider.getViewer().getInput(), IModelDelta.NO_CHANGE); + ModelDelta delta = appendDeltaRoot; + for (int i = 0; i < path.getSegmentCount(); i++) { + delta = delta.addNode(path.getSegment(i), IModelDelta.NO_CHANGE); + } + + if (!fContentProvider.getViewer().saveElementState(path, delta, IModelDelta.COLLAPSE | IModelDelta.EXPAND | IModelDelta.SELECT)) { + // Path to save the state was not found or there was no + // (expansion) state to save! Abort. + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("STATE APPEND CANCEL: Element " + path.getLastSegment() + " not found."); //$NON-NLS-1$ //$NON-NLS-2$ + } + return; + } + + // Append a marker CONTENT flag to all the delta nodes that contain the + // EXPAND node. These + // markers are used by the restore logic to know when a delta node can + // be removed. delta.accept((d, depth) -> { if ((d.getFlags() & IModelDelta.EXPAND) != 0) { ((ModelDelta) d).setFlags(d.getFlags() | IModelDelta.CONTENT); @@ -389,21 +389,21 @@ class ViewerStateTracker { return true; }); - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("\tAPPEND DELTA: " + appendDeltaRoot); //$NON-NLS-1$ - } - - if (fPendingState != null) { - // If the restore for the current input was never completed, - // preserve - // that restore along with the restore that was completed. - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("\tAPPEND OUTSTANDING RESTORE: " + fPendingState); //$NON-NLS-1$ - } - - // If the append delta is generated for a sub-tree, copy the pending delta - // attributes into the pending delta. - if (path.getSegmentCount() > 0) { + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("\tAPPEND DELTA: " + appendDeltaRoot); //$NON-NLS-1$ + } + + if (fPendingState != null) { + // If the restore for the current input was never completed, + // preserve + // that restore along with the restore that was completed. + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("\tAPPEND OUTSTANDING RESTORE: " + fPendingState); //$NON-NLS-1$ + } + + // If the append delta is generated for a sub-tree, copy the pending delta + // attributes into the pending delta. + if (path.getSegmentCount() > 0) { fPendingState.accept((pendingDeltaNode, depth) -> { TreePath pendingDeltaPath = fContentProvider.getViewerTreePath(pendingDeltaNode); if (path.startsWith(pendingDeltaPath, null)) { @@ -415,9 +415,9 @@ class ViewerStateTracker { } return false; }); - } + } - // Copy the pending state into the new appended state. + // Copy the pending state into the new appended state. fPendingState.accept((pendingDeltaNode, depth) -> { // Skip the top element if (pendingDeltaNode.getParentDelta() == null) { @@ -455,80 +455,80 @@ class ViewerStateTracker { return pendingDeltaNode.getChildCount() > 0; } }); - } - - if (appendDeltaRoot.getChildDeltas().length > 0) { - // Set the new delta root as the pending state delta. - if (fPendingState == null) { - notifyStateUpdate(appendDeltaRoot.getElement(), STATE_RESTORE_SEQUENCE_BEGINS, null); - } - fPendingState = appendDeltaRoot; - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("STATE APPEND COMPLETE " + fPendingState); //$NON-NLS-1$ - } - } else { - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("STATE APPEND CANCELED: No Data"); //$NON-NLS-1$ - } - } - } - - /** - * Saves the viewer's state for the previous input. * @param oldInput - * @param input the {@link ModelDelta} input - */ - protected void saveViewerState(Object input) { + } + + 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 (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("STATE APPEND COMPLETE " + fPendingState); //$NON-NLS-1$ + } + } else { + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("STATE APPEND CANCELED: No Data"); //$NON-NLS-1$ + } + } + } + + /** + * Saves the viewer's state for the previous input. * @param oldInput + * @param input the {@link ModelDelta} input + */ + protected void saveViewerState(Object input) { for (Iterator<ElementCompareRequest> itr = fCompareRequestsInProgress.values().iterator(); itr.hasNext();) { - itr.next().cancel(); - itr.remove(); - } - - IElementMementoProvider stateProvider = ViewerAdapterService.getMementoProvider(input); - if (stateProvider != null) { - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("STATE SAVE BEGIN: " + input); //$NON-NLS-1$ - } - - // build a model delta representing expansion and selection state - final ModelDelta saveDeltaRoot = new ModelDelta(input, IModelDelta.NO_CHANGE); - buildViewerState(saveDeltaRoot); - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("\tSAVE DELTA FROM VIEW:\n" + saveDeltaRoot); //$NON-NLS-1$ - } - - // check if pending restore reveal - if (fPendingSetTopItem != null) { - // set back the pending reveal flag - ModelDelta revealDelta = fPendingSetTopItem.getDelta(); - revealDelta.setFlags(revealDelta.getFlags() | IModelDelta.REVEAL); - - fPendingSetTopItem.dispose(); - - ModelDelta saveDeltaNode = findSubDeltaParent(saveDeltaRoot, revealDelta); - if (saveDeltaNode != null) { - clearRevealFlag(saveDeltaRoot); - ModelDelta child = saveDeltaNode.getChildDelta(revealDelta.getElement(), revealDelta.getIndex()); - if (child != null) { - child.setFlags(child.getFlags() | IModelDelta.REVEAL); - } else { - // the node should be added if not found - saveDeltaNode.setChildCount(revealDelta.getParentDelta().getChildCount()); - copyIntoDelta(revealDelta, saveDeltaNode); - } - } else { - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("\tSKIPPED: " + revealDelta.getElement()); //$NON-NLS-1$ - } - } - } - - if (fPendingState != null) { - // If the restore for the current input was never completed, - // preserve - // that restore along with the restore that was completed. - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("\tSAVE OUTSTANDING RESTORE: " + fPendingState); //$NON-NLS-1$ - } + itr.next().cancel(); + itr.remove(); + } + + IElementMementoProvider stateProvider = ViewerAdapterService.getMementoProvider(input); + if (stateProvider != null) { + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("STATE SAVE BEGIN: " + input); //$NON-NLS-1$ + } + + // build a model delta representing expansion and selection state + final ModelDelta saveDeltaRoot = new ModelDelta(input, IModelDelta.NO_CHANGE); + buildViewerState(saveDeltaRoot); + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("\tSAVE DELTA FROM VIEW:\n" + saveDeltaRoot); //$NON-NLS-1$ + } + + // check if pending restore reveal + if (fPendingSetTopItem != null) { + // set back the pending reveal flag + ModelDelta revealDelta = fPendingSetTopItem.getDelta(); + revealDelta.setFlags(revealDelta.getFlags() | IModelDelta.REVEAL); + + fPendingSetTopItem.dispose(); + + ModelDelta saveDeltaNode = findSubDeltaParent(saveDeltaRoot, revealDelta); + if (saveDeltaNode != null) { + clearRevealFlag(saveDeltaRoot); + ModelDelta child = saveDeltaNode.getChildDelta(revealDelta.getElement(), revealDelta.getIndex()); + if (child != null) { + child.setFlags(child.getFlags() | IModelDelta.REVEAL); + } else { + // the node should be added if not found + saveDeltaNode.setChildCount(revealDelta.getParentDelta().getChildCount()); + copyIntoDelta(revealDelta, saveDeltaNode); + } + } else { + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("\tSKIPPED: " + revealDelta.getElement()); //$NON-NLS-1$ + } + } + } + + if (fPendingState != null) { + // If the restore for the current input was never completed, + // preserve + // that restore along with the restore that was completed. + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("\tSAVE OUTSTANDING RESTORE: " + fPendingState); //$NON-NLS-1$ + } IModelDeltaVisitor pendingStateVisitor = (pendingDeltaNode, depth) -> { // Ignore the top element. @@ -577,184 +577,184 @@ class ViewerStateTracker { return pendingDeltaNode.getChildCount() > 0; } }; - fPendingState.accept(pendingStateVisitor); - } - - if (saveDeltaRoot.getChildDeltas().length > 0) { - // encode delta with mementos in place of elements, in non-UI - // thread - encodeDelta(saveDeltaRoot, stateProvider); - } else { - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("STATE SAVE CANCELED, NO DATA"); //$NON-NLS-1$ - } - } - } - } - - private void clearRevealFlag(ModelDelta saveRootDelta) { + 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 (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("STATE SAVE CANCELED, NO DATA"); //$NON-NLS-1$ + } + } + } + } + + private void clearRevealFlag(ModelDelta saveRootDelta) { IModelDeltaVisitor clearDeltaVisitor = (delta, depth) -> { if ((delta.getFlags() & IModelDelta.REVEAL) != 0) { ((ModelDelta) delta).setFlags(delta.getFlags() & ~IModelDelta.REVEAL); } return true; }; - saveRootDelta.accept(clearDeltaVisitor); - } + saveRootDelta.accept(clearDeltaVisitor); + } - private ModelDelta findSubDeltaParent(ModelDelta destinationDeltaRoot, IModelDelta subDelta) { - // Create a path of elements to the sub-delta. + private ModelDelta findSubDeltaParent(ModelDelta destinationDeltaRoot, IModelDelta subDelta) { + // Create a path of elements to the sub-delta. LinkedList<IModelDelta> deltaPath = new LinkedList<>(); - IModelDelta delta = subDelta; - while (delta.getParentDelta() != null) { - delta = delta.getParentDelta(); - deltaPath.addFirst(delta); - } - - // For each element in the path of the sub-delta, find the corresponding - // element in the destination delta + IModelDelta delta = subDelta; + while (delta.getParentDelta() != null) { + delta = delta.getParentDelta(); + deltaPath.addFirst(delta); + } + + // For each element in the path of the sub-delta, find the corresponding + // element in the destination delta Iterator<IModelDelta> itr = deltaPath.iterator(); - // Skip the root element - itr.next(); - ModelDelta saveDelta = destinationDeltaRoot; - while (saveDelta != null && itr.hasNext()) { - IModelDelta itrDelta = itr.next(); - saveDelta = saveDelta.getChildDelta(itrDelta.getElement(), itrDelta.getIndex()); - } - return saveDelta; - } - - private ModelDelta findDeltaForPath(ModelDelta root, TreePath path) { - ModelDelta delta = root; - for (int i = 0; i < path.getSegmentCount(); i++) { - delta = delta.getChildDelta(path.getSegment(i)); - if (delta == null) { - return null; - } - } - return delta; - } - - private boolean isDeltaInParent(IModelDelta delta, ModelDelta destParent) { - return destParent.getChildDelta(delta.getElement(), delta.getIndex()) != null; - } - - private void copyIntoDelta(IModelDelta delta, ModelDelta destParent) { - ModelDelta newDelta = destParent.addNode(delta.getElement(), delta.getIndex(), delta.getFlags(), delta - .getChildCount()); - for (int i = 0; i < delta.getChildDeltas().length; i++) { - copyIntoDelta(delta.getChildDeltas()[i], newDelta); - } - } - - /** - * Encodes delta elements into mementos using the given provider. - * @param rootDelta the {@link ModelDelta} to encode - * @param defaultProvider the default provider to use when processing the given delta - * - */ - protected void encodeDelta(final ModelDelta rootDelta, final IElementMementoProvider defaultProvider) { - final Object input = rootDelta.getElement(); - final XMLMemento inputMemento = XMLMemento.createWriteRoot("VIEWER_INPUT_MEMENTO"); //$NON-NLS-1$ - final XMLMemento childrenMemento = XMLMemento.createWriteRoot("CHILDREN_MEMENTO"); //$NON-NLS-1$ - final IElementMementoCollector manager = new IElementMementoCollector() { - - /** - * list of memento fRequests - */ + // Skip the root element + itr.next(); + ModelDelta saveDelta = destinationDeltaRoot; + while (saveDelta != null && itr.hasNext()) { + IModelDelta itrDelta = itr.next(); + saveDelta = saveDelta.getChildDelta(itrDelta.getElement(), itrDelta.getIndex()); + } + return saveDelta; + } + + private ModelDelta findDeltaForPath(ModelDelta root, TreePath path) { + ModelDelta delta = root; + for (int i = 0; i < path.getSegmentCount(); i++) { + delta = delta.getChildDelta(path.getSegment(i)); + if (delta == null) { + return null; + } + } + return delta; + } + + private boolean isDeltaInParent(IModelDelta delta, ModelDelta destParent) { + return destParent.getChildDelta(delta.getElement(), delta.getIndex()) != null; + } + + private void copyIntoDelta(IModelDelta delta, ModelDelta destParent) { + ModelDelta newDelta = destParent.addNode(delta.getElement(), delta.getIndex(), delta.getFlags(), delta + .getChildCount()); + for (int i = 0; i < delta.getChildDeltas().length; i++) { + copyIntoDelta(delta.getChildDeltas()[i], newDelta); + } + } + + /** + * Encodes delta elements into mementos using the given provider. + * @param rootDelta the {@link ModelDelta} to encode + * @param defaultProvider the default provider to use when processing the given delta + * + */ + protected void encodeDelta(final ModelDelta rootDelta, final IElementMementoProvider defaultProvider) { + final Object input = rootDelta.getElement(); + final XMLMemento inputMemento = XMLMemento.createWriteRoot("VIEWER_INPUT_MEMENTO"); //$NON-NLS-1$ + final XMLMemento childrenMemento = XMLMemento.createWriteRoot("CHILDREN_MEMENTO"); //$NON-NLS-1$ + final IElementMementoCollector manager = new IElementMementoCollector() { + + /** + * list of memento fRequests + */ private List<IElementMementoRequest> fRequests = new ArrayList<>(); - /** - * Flag indicating whether the encoding of delta has been canceled. - */ - private boolean fCanceled = false; + /** + * Flag indicating whether the encoding of delta has been canceled. + */ + private boolean fCanceled = false; - @Override + @Override public void requestComplete(ElementMementoRequest request) { - Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); - - notifyStateUpdate(input, TreeModelContentProvider.UPDATE_COMPLETE, request); - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("\tSTATE END: " + request); //$NON-NLS-1$ - } - - if (!request.isCanceled() && (request.getStatus() == null || request.getStatus().isOK())) { - boolean requestsComplted = false; - if (!fCanceled) { - fRequests.remove(request); - requestsComplted = fRequests.isEmpty(); - } - if (requestsComplted) { - XMLMemento keyMemento = (XMLMemento) rootDelta.getElement(); - StringWriter writer = new StringWriter(); - try { - keyMemento.save(writer); - fViewerStates.put(writer.toString(), rootDelta); - } catch (IOException e) { - DebugUIPlugin.log(e); - } - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("STATE SAVE COMPLETED: " + rootDelta); //$NON-NLS-1$ - } - stateSaveComplete(input, this); - } - } else { - cancel(); - } - } - - @Override + Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); + + notifyStateUpdate(input, TreeModelContentProvider.UPDATE_COMPLETE, request); + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("\tSTATE END: " + request); //$NON-NLS-1$ + } + + if (!request.isCanceled() && (request.getStatus() == null || request.getStatus().isOK())) { + boolean requestsComplted = false; + if (!fCanceled) { + fRequests.remove(request); + requestsComplted = fRequests.isEmpty(); + } + if (requestsComplted) { + XMLMemento keyMemento = (XMLMemento) rootDelta.getElement(); + StringWriter writer = new StringWriter(); + try { + keyMemento.save(writer); + fViewerStates.put(writer.toString(), rootDelta); + } catch (IOException e) { + DebugUIPlugin.log(e); + } + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("STATE SAVE COMPLETED: " + rootDelta); //$NON-NLS-1$ + } + stateSaveComplete(input, this); + } + } else { + cancel(); + } + } + + @Override public void cancel() { - Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); + Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); - if (fCanceled) { - return; - } + if (fCanceled) { + return; + } - fCanceled = true; + fCanceled = true; for (IElementMementoRequest req : fRequests) { - req.cancel(); - } - fRequests.clear(); - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("STATE SAVE ABORTED: " + rootDelta.getElement()); //$NON-NLS-1$ - } - stateSaveComplete(input, this); - } - - @Override + req.cancel(); + } + fRequests.clear(); + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("STATE SAVE ABORTED: " + rootDelta.getElement()); //$NON-NLS-1$ + } + stateSaveComplete(input, this); + } + + @Override public void processReqeusts() { - Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); + Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); Map<IElementMementoProvider, List<IElementMementoRequest>> providers = new HashMap<>(); for (IElementMementoRequest request : fRequests) { - notifyStateUpdate(input, TreeModelContentProvider.UPDATE_BEGINS, request); - IElementMementoProvider provider = ViewerAdapterService.getMementoProvider(request.getElement()); - if (provider == null) { - provider = defaultProvider; - } + notifyStateUpdate(input, TreeModelContentProvider.UPDATE_BEGINS, request); + IElementMementoProvider provider = ViewerAdapterService.getMementoProvider(request.getElement()); + if (provider == null) { + provider = defaultProvider; + } List<IElementMementoRequest> reqs = providers.get(provider); - if (reqs == null) { + if (reqs == null) { reqs = new ArrayList<>(); - providers.put(provider, reqs); - } - reqs.add(request); - } + providers.put(provider, reqs); + } + reqs.add(request); + } for (Entry<IElementMementoProvider, List<IElementMementoRequest>> entry : providers.entrySet()) { - IElementMementoProvider provider = entry.getKey(); + IElementMementoProvider provider = entry.getKey(); List<IElementMementoRequest> reqs = entry.getValue(); provider.encodeElements(reqs.toArray(new IElementMementoRequest[reqs.size()])); - } - } + } + } - @Override + @Override public void addRequest(ElementMementoRequest request) { - Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); + Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); - fRequests.add(request); - } + fRequests.add(request); + } - }; + }; IModelDeltaVisitor visitor = (delta, depth) -> { // Add the CONTENT flag to all nodes with an EXPAND flag. // During restoring, this flag is used as a marker indicating @@ -778,94 +778,94 @@ class ViewerStateTracker { } return true; }; - rootDelta.accept(visitor); - stateSaveStarted(input, manager); - manager.processReqeusts(); - } - - /** - * Called when a state save is starting. - * @param input the {@link ModelDelta} input - * @param manager the manager to notify - */ - private void stateSaveStarted(Object input, IElementMementoCollector manager) { - Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); - - notifyStateUpdate(input, STATE_SAVE_SEQUENCE_BEGINS, null); - fPendingStateSaves.add(manager); - } - - /** - * Called when a state save is complete. - * @param input the {@link ModelDelta} input - * @param manager the manager to notify - */ - private void stateSaveComplete(Object input, IElementMementoCollector manager) { - Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); - - notifyStateUpdate(input, STATE_SAVE_SEQUENCE_COMPLETE, null); - fPendingStateSaves.remove(manager); - if (fQueuedRestore != null) { - Object temp = fQueuedRestore; - fQueuedRestore = null; - restoreViewerState(temp); - } - } - - /** - * Returns whether any state saving is in progress. - * - * @return whether any state saving is in progress - */ - private boolean isSavingState() { - Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); - - return !fPendingStateSaves.isEmpty(); - } - - /** - * Restores the viewer state unless a save is taking place. If a save is - * taking place, the restore is queued. - * - * @param input - * viewer input - */ - protected void restoreViewerState(final Object input) { - Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); - - fPendingState = null; - if (isSavingState()) { - fQueuedRestore = input; - } else { - startRestoreViewerState(input); - } - } - - - public void cancelRestore(final TreePath path, final int flags) { - if (fInStateRestore) { - // If we are currently processing pending state already, ignore - // cancelRestore requests. These requests may be triggered in the viewer - // by changes to the tree state (Bug 295585). - return; - } - - if ((flags & IModelDelta.REVEAL) != 0 && fPendingSetTopItem != null) { - fPendingSetTopItem.dispose(); - return; - } - - // Nothing else to do - if (fPendingState == null) { - return; - } - - if ((flags & (IModelDelta.SELECT | IModelDelta.REVEAL)) != 0) { - // If we're canceling reveal and this is waiting for updates to complete - // then just cancel it and return - - // If we're canceling select or reveal, cancel it for all of pending deltas - final int mask = flags & (IModelDelta.SELECT | IModelDelta.REVEAL); + rootDelta.accept(visitor); + stateSaveStarted(input, manager); + manager.processReqeusts(); + } + + /** + * Called when a state save is starting. + * @param input the {@link ModelDelta} input + * @param manager the manager to notify + */ + private void stateSaveStarted(Object input, IElementMementoCollector manager) { + Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); + + notifyStateUpdate(input, STATE_SAVE_SEQUENCE_BEGINS, null); + fPendingStateSaves.add(manager); + } + + /** + * Called when a state save is complete. + * @param input the {@link ModelDelta} input + * @param manager the manager to notify + */ + private void stateSaveComplete(Object input, IElementMementoCollector manager) { + Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); + + notifyStateUpdate(input, STATE_SAVE_SEQUENCE_COMPLETE, null); + fPendingStateSaves.remove(manager); + if (fQueuedRestore != null) { + Object temp = fQueuedRestore; + fQueuedRestore = null; + restoreViewerState(temp); + } + } + + /** + * Returns whether any state saving is in progress. + * + * @return whether any state saving is in progress + */ + private boolean isSavingState() { + Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); + + return !fPendingStateSaves.isEmpty(); + } + + /** + * Restores the viewer state unless a save is taking place. If a save is + * taking place, the restore is queued. + * + * @param input + * viewer input + */ + protected void restoreViewerState(final Object input) { + Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); + + fPendingState = null; + if (isSavingState()) { + fQueuedRestore = input; + } else { + startRestoreViewerState(input); + } + } + + + public void cancelRestore(final TreePath path, final int flags) { + if (fInStateRestore) { + // If we are currently processing pending state already, ignore + // cancelRestore requests. These requests may be triggered in the viewer + // by changes to the tree state (Bug 295585). + return; + } + + if ((flags & IModelDelta.REVEAL) != 0 && fPendingSetTopItem != null) { + fPendingSetTopItem.dispose(); + return; + } + + // Nothing else to do + if (fPendingState == null) { + return; + } + + if ((flags & (IModelDelta.SELECT | IModelDelta.REVEAL)) != 0) { + // If we're canceling reveal and this is waiting for updates to complete + // then just cancel it and return + + // If we're canceling select or reveal, cancel it for all of pending deltas + final int mask = flags & (IModelDelta.SELECT | IModelDelta.REVEAL); fPendingState.accept((delta, depth) -> { int deltaFlags = delta.getFlags(); int newFlags = deltaFlags & ~mask; @@ -879,10 +879,10 @@ class ViewerStateTracker { ((ModelDelta) delta).setFlags(newFlags); return true; }); - } - if ((flags & ~(IModelDelta.SELECT | IModelDelta.REVEAL)) != 0) { - final int mask = flags & ~(IModelDelta.SELECT | IModelDelta.REVEAL); - // For other flags (EXPAND/COLLAPSE), cancel only from the matching path. + } + if ((flags & ~(IModelDelta.SELECT | IModelDelta.REVEAL)) != 0) { + final int mask = flags & ~(IModelDelta.SELECT | IModelDelta.REVEAL); + // For other flags (EXPAND/COLLAPSE), cancel only from the matching path. fPendingState.accept((delta, depth) -> { if (depth < path.getSegmentCount()) { // Descend until we reach a matching depth. @@ -926,30 +926,30 @@ class ViewerStateTracker { return true; } }); - } - } - - - /** - * Perform any restoration required for the given tree path. - * <p> - * This method is called after every viewer update completion to continue - * restoring the expansion state that was previously saved. - * - * @param path the tree path to update - * @param modelIndex the index in the current model - * @param knowsHasChildren if the content provider knows it has children already - * @param knowsChildCount if the content provider knows the current child count already - * @param checkChildrenRealized if any realized children should be checked or not - */ - void restorePendingStateOnUpdate(final TreePath path, final int modelIndex, final boolean knowsHasChildren, - final boolean knowsChildCount, final boolean checkChildrenRealized) - { - Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); - - if (fPendingState == null) { - return; - } + } + } + + + /** + * Perform any restoration required for the given tree path. + * <p> + * This method is called after every viewer update completion to continue + * restoring the expansion state that was previously saved. + * + * @param path the tree path to update + * @param modelIndex the index in the current model + * @param knowsHasChildren if the content provider knows it has children already + * @param knowsChildCount if the content provider knows the current child count already + * @param checkChildrenRealized if any realized children should be checked or not + */ + void restorePendingStateOnUpdate(final TreePath path, final int modelIndex, final boolean knowsHasChildren, + final boolean knowsChildCount, final boolean checkChildrenRealized) + { + Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); + + if (fPendingState == null) { + return; + } IModelDeltaVisitor visitor = (delta, depth) -> { @@ -1000,81 +1000,81 @@ class ViewerStateTracker { return element.equals(potentialMatch); }; - try { - fInStateRestore = true; - fPendingState.accept(visitor); - } - finally { - fInStateRestore = false; - } - checkIfRestoreComplete(); - } - - /** - * Checks whether restoring pending state is already complete. - */ - void checkIfRestoreComplete() { - Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); - - if (fPendingState == null) { - return; - } - - /** - * Used to determine when restoration delta has been processed - */ - class CheckState implements IModelDeltaVisitor { - private boolean complete = true; - - @Override + try { + fInStateRestore = true; + fPendingState.accept(visitor); + } + finally { + fInStateRestore = false; + } + checkIfRestoreComplete(); + } + + /** + * Checks whether restoring pending state is already complete. + */ + void checkIfRestoreComplete() { + Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); + + if (fPendingState == null) { + return; + } + + /** + * Used to determine when restoration delta has been processed + */ + class CheckState implements IModelDeltaVisitor { + private boolean complete = true; + + @Override public boolean visit(IModelDelta delta, int depth) { - // Filter out the CONTENT flags from the delta flags, the content - // flag is only used as a marker indicating that all the sub-elements - // of a given delta have been retrieved. - int flags = (delta.getFlags() & ~IModelDelta.CONTENT); - - if (flags != IModelDelta.NO_CHANGE) { - IModelDelta parentDelta = delta.getParentDelta(); - // Remove the delta if : - // - The parent delta has no more flags on it (the content flag is removed as well), - // which means that parent element's children have been completely exposed. - // - There are no more pending updates for the element. - // - If element is a memento, there are no state requests pending. - if (parentDelta != null && parentDelta.getFlags() == IModelDelta.NO_CHANGE) { - TreePath deltaPath = fContentProvider.getViewerTreePath(delta); - if ( !fContentProvider.areElementUpdatesPending(deltaPath) && - (!(delta.getElement() instanceof IMemento) || !areMementoUpdatesPending(delta)) ) - { - removeDelta(delta); - return false; - } - } - - if (flags != IModelDelta.REVEAL || (delta.getElement() instanceof IMemento)) { - complete = false; - return false; - } - } - return true; - } - - public boolean isComplete() { - return complete; - } - - private boolean areMementoUpdatesPending(IModelDelta delta) { + // Filter out the CONTENT flags from the delta flags, the content + // flag is only used as a marker indicating that all the sub-elements + // of a given delta have been retrieved. + int flags = (delta.getFlags() & ~IModelDelta.CONTENT); + + if (flags != IModelDelta.NO_CHANGE) { + IModelDelta parentDelta = delta.getParentDelta(); + // Remove the delta if : + // - The parent delta has no more flags on it (the content flag is removed as well), + // which means that parent element's children have been completely exposed. + // - There are no more pending updates for the element. + // - If element is a memento, there are no state requests pending. + if (parentDelta != null && parentDelta.getFlags() == IModelDelta.NO_CHANGE) { + TreePath deltaPath = fContentProvider.getViewerTreePath(delta); + if ( !fContentProvider.areElementUpdatesPending(deltaPath) && + (!(delta.getElement() instanceof IMemento) || !areMementoUpdatesPending(delta)) ) + { + removeDelta(delta); + return false; + } + } + + if (flags != IModelDelta.REVEAL || (delta.getElement() instanceof IMemento)) { + complete = false; + return false; + } + } + return true; + } + + public boolean isComplete() { + return complete; + } + + private boolean areMementoUpdatesPending(IModelDelta delta) { for (CompareRequestKey key : fCompareRequestsInProgress.keySet()) { - if (delta.getElement().equals(key.fDelta.getElement())) { - return true; - } - } - return false; - } - - private void removeDelta(IModelDelta delta) { - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("\tRESTORE REMOVED: " + delta.getElement()); //$NON-NLS-1$ - } + if (delta.getElement().equals(key.fDelta.getElement())) { + return true; + } + } + return false; + } + + private void removeDelta(IModelDelta delta) { + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("\tRESTORE REMOVED: " + delta.getElement()); //$NON-NLS-1$ + } delta.accept((_visitorDelta, depth) -> { ModelDelta visitorDelta = (ModelDelta) _visitorDelta; @@ -1083,285 +1083,285 @@ class ViewerStateTracker { return true; }); - } - } - - CheckState state = new CheckState(); - fPendingState.accept(state); - if (state.isComplete()) { - // notify restore complete if REVEAL was restored also, otherwise - // postpone until then. - if (fPendingSetTopItem == null) { - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("STATE RESTORE COMPELTE: " + fPendingState); //$NON-NLS-1$ - } - - notifyStateUpdate(fPendingState.getElement(), STATE_RESTORE_SEQUENCE_COMPLETE, null); - } - - fPendingState = null; - } - } - - /** - * Restores the pending state in the given delta node. This method is called - * once the state tracker has found the element which matches the element in - * the given delta node. - * @param delta the {@link ModelDelta} to restore from - * @param knowsHasChildren if the content provider has computed its children - * @param knowsChildCount if the content provider has already computed the child count - * @param checkChildrenRealized if any realized children should be checked - */ - void restorePendingStateNode(final ModelDelta delta, boolean knowsHasChildren, boolean knowsChildCount, boolean checkChildrenRealized) { - final TreePath treePath = fContentProvider.getViewerTreePath(delta); - final IInternalTreeModelViewer viewer = fContentProvider.getViewer(); - - // Attempt to expand the node only if the children are known. - if (knowsHasChildren) { - if ((delta.getFlags() & IModelDelta.EXPAND) != 0) { - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("\tRESTORE EXPAND: " + treePath.getLastSegment()); //$NON-NLS-1$ - } - viewer.expandToLevel(treePath, 1); - delta.setFlags(delta.getFlags() & ~IModelDelta.EXPAND); - } - if ((delta.getFlags() & IModelDelta.COLLAPSE) != 0) { - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("\tRESTORE COLLAPSE: " + treePath.getLastSegment()); //$NON-NLS-1$ - } - // Check auto-expand before collapsing an element (bug 335734) - int autoexpand = fContentProvider.getViewer().getAutoExpandLevel(); - if (autoexpand != ITreeModelViewer.ALL_LEVELS && autoexpand < (treePath.getSegmentCount() + 1)) { - fContentProvider.getViewer().setExpandedState(treePath, false); - } - delta.setFlags(delta.getFlags() & ~IModelDelta.COLLAPSE); - } - } - - if ((delta.getFlags() & IModelDelta.SELECT) != 0) { - delta.setFlags(delta.getFlags() & ~IModelDelta.SELECT); - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("\tRESTORE SELECT: " + treePath.getLastSegment()); //$NON-NLS-1$ - } - ITreeSelection currentSelection = (ITreeSelection)viewer.getSelection(); - if (currentSelection == null || currentSelection.isEmpty()) { - viewer.setSelection(new TreeSelection(treePath), false, false); - } else { - TreePath[] currentPaths = currentSelection.getPaths(); - boolean pathInSelection = false; - for (int i = 0; i < currentPaths.length; i++) { - if (currentPaths[i].equals(treePath)) { - pathInSelection = true; - break; - } - } - // Only set the selection if the element is not yet in - // selection. Otherwise the setSelection() call will - // update selection listeners needlessly. - if (!pathInSelection) { - TreePath[] newPaths = new TreePath[currentPaths.length + 1]; - System.arraycopy(currentPaths, 0, newPaths, 0, currentPaths.length); - newPaths[newPaths.length - 1] = treePath; - viewer.setSelection(new TreeSelection(newPaths), false, false); - } - } - } - - if ((delta.getFlags() & IModelDelta.REVEAL) != 0) { - delta.setFlags(delta.getFlags() & ~IModelDelta.REVEAL); - // Look for the reveal flag in the child deltas. If - // A child delta has the reveal flag, do not set the - // top element yet. - boolean setTopItem = true; - IModelDelta[] childDeltas = delta.getChildDeltas(); - for (int i = 0; i < childDeltas.length; i++) { - IModelDelta childDelta = childDeltas[i]; - int modelIndex = childDelta.getIndex(); - if (modelIndex >= 0 && (childDelta.getFlags() & IModelDelta.REVEAL) != 0) { - setTopItem = false; - } - } - - if (setTopItem) { - Assert.isTrue(fPendingSetTopItem == null); - - fPendingSetTopItem = new PendingRevealDelta(treePath, delta); - viewer.addViewerUpdateListener(fPendingSetTopItem); - } - } - - // If we know the child count of the element, look for the reveal - // flag in the child deltas. For the children with reveal flag start - // a new update. - // If the child delta's index is out of range, strip the reveal flag - // since it is no longer applicable. - if (knowsChildCount) { - int childCount = viewer.getChildCount(treePath); - if (childCount >= 0) { - ModelDelta[] childDeltas = (ModelDelta[])delta.getChildDeltas(); - for (int i = 0; i < childDeltas.length; i++) { - ModelDelta childDelta = childDeltas[i]; - int modelIndex = childDelta.getIndex(); - if (modelIndex >= 0 && (childDelta.getFlags() & IModelDelta.REVEAL) != 0) { - if (modelIndex < childCount) { - fContentProvider.doUpdateElement(treePath, modelIndex); - } else { - childDelta.setFlags(childDelta.getFlags() & ~IModelDelta.REVEAL); - } - } - } - } - } - - // Some children of this element were just updated. If all its - // children are now realized, clear out any elements that still - // have flags, because they represent elements that were removed. - if ((checkChildrenRealized && - !fContentProvider.areChildrenUpdatesPending(treePath) && - fContentProvider.getViewer().getElementChildrenRealized(treePath)) || - (knowsHasChildren && !viewer.getHasChildren(treePath)) ) - { - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("\tRESTORE CONTENT: " + treePath.getLastSegment()); //$NON-NLS-1$ - } - delta.setFlags(delta.getFlags() & ~IModelDelta.CONTENT); - } - } - - /** - * Utility that reveals the saved top item in the viewer. It listens for - * all content updates to complete in order to avoid having the desired top item - * scroll out as view content is filled in. - * <br> - * Revealing some elements can trigger expanding some of elements - * that have been just revealed. Therefore, we have to check one - * more time after the new triggered updates are completed if we - * have to set again the top index - */ - private class PendingRevealDelta implements IViewerUpdateListener { - - private final TreePath fPathToReveal; - private final ModelDelta fRevealDelta; - - PendingRevealDelta(TreePath pathToReveal, ModelDelta revealDelta) { - fPathToReveal = pathToReveal; - fRevealDelta = revealDelta; - } - - /** - * Counter that tracks how many time the viewer updates were completed. - */ - private int fCounter = 0; - private Object fModelInput = fPendingState.getElement(); - - @Override + } + } + + CheckState state = new CheckState(); + fPendingState.accept(state); + if (state.isComplete()) { + // notify restore complete if REVEAL was restored also, otherwise + // postpone until then. + if (fPendingSetTopItem == null) { + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("STATE RESTORE COMPELTE: " + fPendingState); //$NON-NLS-1$ + } + + notifyStateUpdate(fPendingState.getElement(), STATE_RESTORE_SEQUENCE_COMPLETE, null); + } + + fPendingState = null; + } + } + + /** + * Restores the pending state in the given delta node. This method is called + * once the state tracker has found the element which matches the element in + * the given delta node. + * @param delta the {@link ModelDelta} to restore from + * @param knowsHasChildren if the content provider has computed its children + * @param knowsChildCount if the content provider has already computed the child count + * @param checkChildrenRealized if any realized children should be checked + */ + void restorePendingStateNode(final ModelDelta delta, boolean knowsHasChildren, boolean knowsChildCount, boolean checkChildrenRealized) { + final TreePath treePath = fContentProvider.getViewerTreePath(delta); + final IInternalTreeModelViewer viewer = fContentProvider.getViewer(); + + // Attempt to expand the node only if the children are known. + if (knowsHasChildren) { + if ((delta.getFlags() & IModelDelta.EXPAND) != 0) { + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("\tRESTORE EXPAND: " + treePath.getLastSegment()); //$NON-NLS-1$ + } + viewer.expandToLevel(treePath, 1); + delta.setFlags(delta.getFlags() & ~IModelDelta.EXPAND); + } + if ((delta.getFlags() & IModelDelta.COLLAPSE) != 0) { + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("\tRESTORE COLLAPSE: " + treePath.getLastSegment()); //$NON-NLS-1$ + } + // Check auto-expand before collapsing an element (bug 335734) + int autoexpand = fContentProvider.getViewer().getAutoExpandLevel(); + if (autoexpand != ITreeModelViewer.ALL_LEVELS && autoexpand < (treePath.getSegmentCount() + 1)) { + fContentProvider.getViewer().setExpandedState(treePath, false); + } + delta.setFlags(delta.getFlags() & ~IModelDelta.COLLAPSE); + } + } + + if ((delta.getFlags() & IModelDelta.SELECT) != 0) { + delta.setFlags(delta.getFlags() & ~IModelDelta.SELECT); + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("\tRESTORE SELECT: " + treePath.getLastSegment()); //$NON-NLS-1$ + } + ITreeSelection currentSelection = (ITreeSelection)viewer.getSelection(); + if (currentSelection == null || currentSelection.isEmpty()) { + viewer.setSelection(new TreeSelection(treePath), false, false); + } else { + TreePath[] currentPaths = currentSelection.getPaths(); + boolean pathInSelection = false; + for (int i = 0; i < currentPaths.length; i++) { + if (currentPaths[i].equals(treePath)) { + pathInSelection = true; + break; + } + } + // Only set the selection if the element is not yet in + // selection. Otherwise the setSelection() call will + // update selection listeners needlessly. + if (!pathInSelection) { + TreePath[] newPaths = new TreePath[currentPaths.length + 1]; + System.arraycopy(currentPaths, 0, newPaths, 0, currentPaths.length); + newPaths[newPaths.length - 1] = treePath; + viewer.setSelection(new TreeSelection(newPaths), false, false); + } + } + } + + if ((delta.getFlags() & IModelDelta.REVEAL) != 0) { + delta.setFlags(delta.getFlags() & ~IModelDelta.REVEAL); + // Look for the reveal flag in the child deltas. If + // A child delta has the reveal flag, do not set the + // top element yet. + boolean setTopItem = true; + IModelDelta[] childDeltas = delta.getChildDeltas(); + for (int i = 0; i < childDeltas.length; i++) { + IModelDelta childDelta = childDeltas[i]; + int modelIndex = childDelta.getIndex(); + if (modelIndex >= 0 && (childDelta.getFlags() & IModelDelta.REVEAL) != 0) { + setTopItem = false; + } + } + + if (setTopItem) { + Assert.isTrue(fPendingSetTopItem == null); + + fPendingSetTopItem = new PendingRevealDelta(treePath, delta); + viewer.addViewerUpdateListener(fPendingSetTopItem); + } + } + + // If we know the child count of the element, look for the reveal + // flag in the child deltas. For the children with reveal flag start + // a new update. + // If the child delta's index is out of range, strip the reveal flag + // since it is no longer applicable. + if (knowsChildCount) { + int childCount = viewer.getChildCount(treePath); + if (childCount >= 0) { + ModelDelta[] childDeltas = (ModelDelta[])delta.getChildDeltas(); + for (int i = 0; i < childDeltas.length; i++) { + ModelDelta childDelta = childDeltas[i]; + int modelIndex = childDelta.getIndex(); + if (modelIndex >= 0 && (childDelta.getFlags() & IModelDelta.REVEAL) != 0) { + if (modelIndex < childCount) { + fContentProvider.doUpdateElement(treePath, modelIndex); + } else { + childDelta.setFlags(childDelta.getFlags() & ~IModelDelta.REVEAL); + } + } + } + } + } + + // Some children of this element were just updated. If all its + // children are now realized, clear out any elements that still + // have flags, because they represent elements that were removed. + if ((checkChildrenRealized && + !fContentProvider.areChildrenUpdatesPending(treePath) && + fContentProvider.getViewer().getElementChildrenRealized(treePath)) || + (knowsHasChildren && !viewer.getHasChildren(treePath)) ) + { + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("\tRESTORE CONTENT: " + treePath.getLastSegment()); //$NON-NLS-1$ + } + delta.setFlags(delta.getFlags() & ~IModelDelta.CONTENT); + } + } + + /** + * Utility that reveals the saved top item in the viewer. It listens for + * all content updates to complete in order to avoid having the desired top item + * scroll out as view content is filled in. + * <br> + * Revealing some elements can trigger expanding some of elements + * that have been just revealed. Therefore, we have to check one + * more time after the new triggered updates are completed if we + * have to set again the top index + */ + private class PendingRevealDelta implements IViewerUpdateListener { + + private final TreePath fPathToReveal; + private final ModelDelta fRevealDelta; + + PendingRevealDelta(TreePath pathToReveal, ModelDelta revealDelta) { + fPathToReveal = pathToReveal; + fRevealDelta = revealDelta; + } + + /** + * Counter that tracks how many time the viewer updates were completed. + */ + private int fCounter = 0; + private Object fModelInput = fPendingState.getElement(); + + @Override public void viewerUpdatesComplete() { - Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); - - IInternalTreeModelViewer viewer = fContentProvider.getViewer(); - if (viewer == null || fPendingSetTopItem != this) { - return; - } - - TreePath topPath = viewer.getTopElementPath(); - if (!fPathToReveal.equals(topPath)) { - TreePath parentPath = fPathToReveal.getParentPath(); - int index = viewer.findElementIndex(parentPath, fPathToReveal.getLastSegment()); - if (index >= 0) { - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("\tRESTORE REVEAL: " + fPathToReveal.getLastSegment()); //$NON-NLS-1$ - } - viewer.reveal(parentPath, index); - - } - } - - fCounter++; - // in case the pending state was already set to null, we assume that - // all others elements are restored, so we don't expect that REVEAL will - // trigger other updates - if (fCounter > 1 || fPendingState == null) { - dispose(); - } - } - - @Override + Assert.isTrue( fContentProvider.getViewer().getDisplay().getThread() == Thread.currentThread() ); + + IInternalTreeModelViewer viewer = fContentProvider.getViewer(); + if (viewer == null || fPendingSetTopItem != this) { + return; + } + + TreePath topPath = viewer.getTopElementPath(); + if (!fPathToReveal.equals(topPath)) { + TreePath parentPath = fPathToReveal.getParentPath(); + int index = viewer.findElementIndex(parentPath, fPathToReveal.getLastSegment()); + if (index >= 0) { + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("\tRESTORE REVEAL: " + fPathToReveal.getLastSegment()); //$NON-NLS-1$ + } + viewer.reveal(parentPath, index); + + } + } + + fCounter++; + // in case the pending state was already set to null, we assume that + // all others elements are restored, so we don't expect that REVEAL will + // trigger other updates + if (fCounter > 1 || fPendingState == null) { + dispose(); + } + } + + @Override public void viewerUpdatesBegin() {} - @Override + @Override public void updateStarted(IViewerUpdate update) {} - @Override + @Override public void updateComplete(IViewerUpdate update) {} - /** - * Returns delta that is used to reveal the item. - * @return delta to be revealed. - */ - public ModelDelta getDelta() { - return fRevealDelta; - } - - /** - * Resets the item - */ - public void dispose() { - // top item is set - fPendingSetTopItem = null; - - IInternalTreeModelViewer viewer = fContentProvider.getViewer(); - if (viewer == null) { + /** + * Returns delta that is used to reveal the item. + * @return delta to be revealed. + */ + public ModelDelta getDelta() { + return fRevealDelta; + } + + /** + * Resets the item + */ + public void dispose() { + // top item is set + fPendingSetTopItem = null; + + IInternalTreeModelViewer viewer = fContentProvider.getViewer(); + if (viewer == null) { return; } - // remove myself as viewer update listener - viewer.removeViewerUpdateListener(this); - - if (fPendingState == null) { - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("STATE RESTORE COMPELTE: " + fPendingState); //$NON-NLS-1$ - } - notifyStateUpdate(fModelInput, STATE_RESTORE_SEQUENCE_COMPLETE, null); - } else { - checkIfRestoreComplete(); - } - } - - } - - /** - * Restore selection/expansion based on items already in the viewer - * @param delta the {@link ModelDelta} to restore from - */ - protected void doInitialRestore(ModelDelta delta) { - // Find the reveal delta and mark nodes on its path - // to reveal as elements are updated. - markRevealDelta(delta); - - // Restore visible items. - // Note (Pawel Piech): the initial list of items is normally - // empty, so in most cases the code below does not do anything. - // Instead doRestore() is called when various updates complete. - int count = fContentProvider.getViewer().getChildCount(TreePath.EMPTY); - for (int i = 0; i < count; i++) { - Object data = fContentProvider.getViewer().getChildElement(TreePath.EMPTY, i); - if (data != null) { - restorePendingStateOnUpdate(new TreePath(new Object[]{data}), i, false, false, false); - } - } - - } - - /** - * Finds the delta with the reveal flag, then it walks up this - * delta and marks all the parents of it with the reveal flag. - * These flags are then used by the restore logic to restore - * and reveal all the nodes leading up to the element that should - * be ultimately at the top. - * @param rootDelta Delta to search - * @return The node just under the rootDelta which contains - * the reveal flag. <code>null</code> if no reveal flag was found. - */ - private ModelDelta markRevealDelta(ModelDelta rootDelta) { - final ModelDelta[] revealDelta = new ModelDelta[1]; + // remove myself as viewer update listener + viewer.removeViewerUpdateListener(this); + + if (fPendingState == null) { + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("STATE RESTORE COMPELTE: " + fPendingState); //$NON-NLS-1$ + } + notifyStateUpdate(fModelInput, STATE_RESTORE_SEQUENCE_COMPLETE, null); + } else { + checkIfRestoreComplete(); + } + } + + } + + /** + * Restore selection/expansion based on items already in the viewer + * @param delta the {@link ModelDelta} to restore from + */ + protected void doInitialRestore(ModelDelta delta) { + // Find the reveal delta and mark nodes on its path + // to reveal as elements are updated. + markRevealDelta(delta); + + // Restore visible items. + // Note (Pawel Piech): the initial list of items is normally + // empty, so in most cases the code below does not do anything. + // Instead doRestore() is called when various updates complete. + int count = fContentProvider.getViewer().getChildCount(TreePath.EMPTY); + for (int i = 0; i < count; i++) { + Object data = fContentProvider.getViewer().getChildElement(TreePath.EMPTY, i); + if (data != null) { + restorePendingStateOnUpdate(new TreePath(new Object[]{data}), i, false, false, false); + } + } + + } + + /** + * Finds the delta with the reveal flag, then it walks up this + * delta and marks all the parents of it with the reveal flag. + * These flags are then used by the restore logic to restore + * and reveal all the nodes leading up to the element that should + * be ultimately at the top. + * @param rootDelta Delta to search + * @return The node just under the rootDelta which contains + * the reveal flag. <code>null</code> if no reveal flag was found. + */ + private ModelDelta markRevealDelta(ModelDelta rootDelta) { + final ModelDelta[] revealDelta = new ModelDelta[1]; IModelDeltaVisitor visitor = (delta, depth) -> { if ((delta.getFlags() & IModelDelta.REVEAL) != 0) { revealDelta[0] = (ModelDelta) delta; @@ -1370,106 +1370,106 @@ class ViewerStateTracker { return revealDelta[0] == null; }; - rootDelta.accept(visitor); - if (revealDelta[0] != null) { - ModelDelta parentDelta = (ModelDelta)revealDelta[0].getParentDelta(); - while(parentDelta.getParentDelta() != null) { - revealDelta[0] = parentDelta; - revealDelta[0].setFlags(revealDelta[0].getFlags() | IModelDelta.REVEAL); - parentDelta = (ModelDelta)parentDelta.getParentDelta(); - } - } - return revealDelta[0]; - } - - /** - * Builds a delta with the given root delta for expansion/selection state. - * - * @param delta - * root delta - */ - private void buildViewerState(ModelDelta delta) { - IInternalTreeModelViewer viewer = fContentProvider.getViewer(); - viewer.saveElementState(TreeModelContentProvider.EMPTY_TREE_PATH, delta, IModelDelta.SELECT | IModelDelta.EXPAND); - - // Add memento for top item if it is mapped to an element. The reveal memento - // is in its own path to avoid requesting unnecessary data when restoring it. - TreePath topElementPath = viewer.getTopElementPath(); - if (topElementPath != null) { - ModelDelta parentDelta = delta; - TreePath parentPath = TreeModelContentProvider.EMPTY_TREE_PATH; - for (int i = 0; i < topElementPath.getSegmentCount(); i++) { - Object element = topElementPath.getSegment(i); - int index = viewer.findElementIndex(parentPath, element); - ModelDelta childDelta = parentDelta.getChildDelta(element); - if (childDelta == null) { - parentDelta = parentDelta.addNode(element, index, IModelDelta.NO_CHANGE); - } else { - parentDelta = childDelta; - } - parentPath = parentPath.createChildPath(element); - } - parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.REVEAL); - } - } - - /** - * Cancels any outstanding compare requests for given element and its children. - * @param path Path of element to cancel updates for. - */ - void cancelStateSubtreeUpdates(TreePath path) { + rootDelta.accept(visitor); + if (revealDelta[0] != null) { + ModelDelta parentDelta = (ModelDelta)revealDelta[0].getParentDelta(); + while(parentDelta.getParentDelta() != null) { + revealDelta[0] = parentDelta; + revealDelta[0].setFlags(revealDelta[0].getFlags() | IModelDelta.REVEAL); + parentDelta = (ModelDelta)parentDelta.getParentDelta(); + } + } + return revealDelta[0]; + } + + /** + * Builds a delta with the given root delta for expansion/selection state. + * + * @param delta + * root delta + */ + private void buildViewerState(ModelDelta delta) { + IInternalTreeModelViewer viewer = fContentProvider.getViewer(); + viewer.saveElementState(TreeModelContentProvider.EMPTY_TREE_PATH, delta, IModelDelta.SELECT | IModelDelta.EXPAND); + + // Add memento for top item if it is mapped to an element. The reveal memento + // is in its own path to avoid requesting unnecessary data when restoring it. + TreePath topElementPath = viewer.getTopElementPath(); + if (topElementPath != null) { + ModelDelta parentDelta = delta; + TreePath parentPath = TreeModelContentProvider.EMPTY_TREE_PATH; + for (int i = 0; i < topElementPath.getSegmentCount(); i++) { + Object element = topElementPath.getSegment(i); + int index = viewer.findElementIndex(parentPath, element); + ModelDelta childDelta = parentDelta.getChildDelta(element); + if (childDelta == null) { + parentDelta = parentDelta.addNode(element, index, IModelDelta.NO_CHANGE); + } else { + parentDelta = childDelta; + } + parentPath = parentPath.createChildPath(element); + } + parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.REVEAL); + } + } + + /** + * Cancels any outstanding compare requests for given element and its children. + * @param path Path of element to cancel updates for. + */ + void cancelStateSubtreeUpdates(TreePath path) { for (Iterator<CompareRequestKey> itr = fCompareRequestsInProgress.keySet().iterator(); itr.hasNext();) { CompareRequestKey key = itr.next(); - if (key.fPath.startsWith(path, null)) { - ElementCompareRequest compareRequest = fCompareRequestsInProgress.get(key); - compareRequest.cancel(); - itr.remove(); - } - } - } - - void compareFinished(ElementCompareRequest request, ModelDelta delta) { - notifyStateUpdate(request.getViewerInput(), TreeModelContentProvider.UPDATE_COMPLETE, request); - if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { - DebugUIPlugin.trace("\tSTATE END: " + request + " = " + false); //$NON-NLS-1$ //$NON-NLS-2$ - } - - fCompareRequestsInProgress.remove(new CompareRequestKey(request.getElementPath(), delta)); - if (!request.isCanceled()) { - if (request.isEqual()) { - delta.setElement(request.getElement()); - restorePendingStateNode(delta, request.knowsHasChildren(), request.knowChildCount(), request.checkChildrenRealized()); - } else if (request.getModelIndex() != -1) { - // Comparison failed. - // Check if the delta has a reveal flag, and if its index - // matches the index of the element that it was compared - // against. If this is the case, strip the reveal flag from - // the delta as it is most likely not applicable anymore. - if ((delta.getFlags() & IModelDelta.REVEAL) != 0 && delta.getIndex() == request.getModelIndex()) { - delta.setFlags(delta.getFlags() & ~IModelDelta.REVEAL); - } - } - } - checkIfRestoreComplete(); - } - - - void addStateUpdateListener(IStateUpdateListener listener) { - fStateUpdateListeners.add(listener); - } - - void removeStateUpdateListener(IStateUpdateListener listener) { - fStateUpdateListeners.remove(listener); - } - - void notifyStateUpdate(final Object input, final int type, final IViewerUpdate update) { - if (!fStateUpdateListeners.isEmpty()) { + if (key.fPath.startsWith(path, null)) { + ElementCompareRequest compareRequest = fCompareRequestsInProgress.get(key); + compareRequest.cancel(); + itr.remove(); + } + } + } + + void compareFinished(ElementCompareRequest request, ModelDelta delta) { + notifyStateUpdate(request.getViewerInput(), TreeModelContentProvider.UPDATE_COMPLETE, request); + if (DebugUIPlugin.DEBUG_STATE_SAVE_RESTORE && DebugUIPlugin.DEBUG_TEST_PRESENTATION_ID(fContentProvider.getPresentationContext())) { + DebugUIPlugin.trace("\tSTATE END: " + request + " = " + false); //$NON-NLS-1$ //$NON-NLS-2$ + } + + fCompareRequestsInProgress.remove(new CompareRequestKey(request.getElementPath(), delta)); + if (!request.isCanceled()) { + if (request.isEqual()) { + delta.setElement(request.getElement()); + restorePendingStateNode(delta, request.knowsHasChildren(), request.knowChildCount(), request.checkChildrenRealized()); + } else if (request.getModelIndex() != -1) { + // Comparison failed. + // Check if the delta has a reveal flag, and if its index + // matches the index of the element that it was compared + // against. If this is the case, strip the reveal flag from + // the delta as it is most likely not applicable anymore. + if ((delta.getFlags() & IModelDelta.REVEAL) != 0 && delta.getIndex() == request.getModelIndex()) { + delta.setFlags(delta.getFlags() & ~IModelDelta.REVEAL); + } + } + } + checkIfRestoreComplete(); + } + + + void addStateUpdateListener(IStateUpdateListener listener) { + fStateUpdateListeners.add(listener); + } + + void removeStateUpdateListener(IStateUpdateListener listener) { + fStateUpdateListeners.remove(listener); + } + + void notifyStateUpdate(final Object input, final int type, final IViewerUpdate update) { + if (!fStateUpdateListeners.isEmpty()) { for (IStateUpdateListener iStateUpdateListener : fStateUpdateListeners) { final IStateUpdateListener listener = iStateUpdateListener; - SafeRunner.run(new ISafeRunnable() { - @Override + SafeRunner.run(new ISafeRunnable() { + @Override public void run() throws Exception { - switch (type) { + switch (type) { case STATE_SAVE_SEQUENCE_BEGINS: listener.stateSaveUpdatesBegin(input); break; @@ -1490,15 +1490,15 @@ class ViewerStateTracker { break; default: break; - } - } + } + } - @Override + @Override public void handleException(Throwable exception) { - DebugUIPlugin.log(exception); - } - }); - } - } - } + DebugUIPlugin.log(exception); + } + }); + } + } + } } |