diff options
Diffstat (limited to 'dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/DefaultVMModelProxyStrategy.java')
-rw-r--r-- | dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/DefaultVMModelProxyStrategy.java | 1521 |
1 files changed, 748 insertions, 773 deletions
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/DefaultVMModelProxyStrategy.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/DefaultVMModelProxyStrategy.java index a0696573a70..5fe9191845d 100644 --- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/DefaultVMModelProxyStrategy.java +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/DefaultVMModelProxyStrategy.java @@ -7,11 +7,11 @@ * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 - * + * * Contributors: * IBM Corporation - initial API and implementation * Wind River Systems - adapted to use with DSF - * Dobrin Alexiev (Texas Instruments) - user groups support (bug 240208) + * Dobrin Alexiev (Texas Instruments) - user groups support (bug 240208) * Marc Dumais (Ericsson) - bug 485170 *******************************************************************************/ package org.eclipse.cdt.dsf.ui.viewmodel; @@ -45,266 +45,262 @@ import org.eclipse.jface.viewers.StructuredViewer; import org.eclipse.jface.viewers.TreePath; import org.eclipse.jface.viewers.Viewer; - /** - * This is the default implementation of {@link IModelProxy} interface for + * This is the default implementation of {@link IModelProxy} interface for * use by a view model provider. It implements an algorithm to walk the * tree hierarchy of nodes configured with a provider in order to compose * an {@link IModelDelta} for a given data model event. * <p/> * This class is closely linked with a view model provider which is required * for the constructor. The view model provider is used to access the correct - * executor and the node hierarchy. - * + * executor and the node hierarchy. + * * @since 1.0 */ @ConfinedToDsfExecutor("#getProvider()#getExecutor()") @SuppressWarnings("restriction") public class DefaultVMModelProxyStrategy implements IVMModelProxy { - private final AbstractVMProvider fProvider; - private final Object fRootElement; - private IPresentationContext fContext; - private Viewer fViewer; - private boolean fDisposed = false; - private ListenerList<IModelChangedListener> fListeners = new ListenerList<>(); + private final AbstractVMProvider fProvider; + private final Object fRootElement; + private IPresentationContext fContext; + private Viewer fViewer; + private boolean fDisposed = false; + private ListenerList<IModelChangedListener> fListeners = new ListenerList<>(); private IDoubleClickListener fDoubleClickListener; private boolean fAllowRecursiveVMNodes = false; - - /** - * Creates this model proxy strategy for the given provider. - */ - public DefaultVMModelProxyStrategy(AbstractVMProvider provider, Object rootElement) { - fProvider = provider; - fRootElement = rootElement; - } - - @Override - public boolean isDeltaEvent(Object event) { - return getEventDeltaFlags(event) != IModelDelta.NO_CHANGE; - } - - @Override - public int getEventDeltaFlags(Object event) { - IRootVMNode rootNode = getVMProvider().getRootVMNode(); - if (rootNode != null && - rootNode.isDeltaEvent(getRootElement(), event)) - { - return getDeltaFlags(rootNode, null, event); - } - return IModelDelta.NO_CHANGE; - } - - - /** - * Returns the view model provider that this strategy is configured for. - * @return - */ - protected AbstractVMProvider getVMProvider() { - return fProvider; - } - - - private Object[] getListeners() { - return fListeners.getListeners(); - } - - @Override - public void addModelChangedListener(IModelChangedListener listener) { - fListeners.add(listener); - } - - @Override - public void removeModelChangedListener(IModelChangedListener listener) { - fListeners.remove(listener); - } - - @Override - public Object getRootElement() { - return fRootElement; - } - - /** @since 1.1 */ - @Override - public Object getViewerInput() { - return fRootElement; - } - - /** @since 1.1 */ - @Override - public TreePath getRootPath() { - return TreePath.EMPTY; - } - - /** - * Notifies registered listeners of the given delta. - * - * @param delta model delta to broadcast - */ - @Override - public void fireModelChanged(IModelDelta delta) { - final IModelDelta root = getRootDelta(delta); - Object[] listeners = getListeners(); - for (int i = 0; i < listeners.length; i++) { - final IModelChangedListener listener = (IModelChangedListener) listeners[i]; - ISafeRunnable safeRunnable = new ISafeRunnable() { - @Override - public void handleException(Throwable exception) { - DebugUIPlugin.log(exception); - } - - @Override - public void run() throws Exception { - listener.modelChanged(root, DefaultVMModelProxyStrategy.this); - } - - }; - SafeRunner.run(safeRunnable); - } - } - - /** - * Convenience method that returns the root node of the given delta. - * - * @param delta delta node - * @return returns the root of the given delta - */ - protected IModelDelta getRootDelta(IModelDelta delta) { - IModelDelta parent = delta.getParentDelta(); - while (parent != null) { - delta = parent; - parent = delta.getParentDelta(); - } - return delta; - } - - /* (non-Javadoc) - * @see org.eclipse.debug.internal.ui.viewers.IModelProxy#dispose() - */ - @Override - public void dispose() { - fDisposed = true; - if (fViewer instanceof StructuredViewer && fDoubleClickListener != null) { - ((StructuredViewer) fViewer).removeDoubleClickListener(fDoubleClickListener); - fDoubleClickListener= null; - } - } - - /* (non-Javadoc) - * @see org.eclipse.debug.internal.ui.viewers.IModelProxy#init(org.eclipse.debug.internal.ui.viewers.IPresentationContext) - */ - @Override - public void init(IPresentationContext context) { - fDisposed = false; - fContext = context; - } - - /** - * Returns the context this model proxy is installed in. - * - * @return presentation context, or <code>null</code> if this - * model proxy has been disposed - */ - public IPresentationContext getPresentationContext() { - return fContext; - } - - /* (non-Javadoc) - * - * Subclasses should override as required. - * - * @see org.eclipse.debug.internal.ui.viewers.provisional.IModelProxy#installed(org.eclipse.jface.viewers.Viewer) - */ - @Override - public void installed(final Viewer viewer) { - fViewer = viewer; - getVMProvider().getExecutor().execute( new DsfRunnable() { - @Override - public void run() { - fProvider.handleEvent(new ModelProxyInstalledEvent(DefaultVMModelProxyStrategy.this, viewer, fRootElement)); - } - }); - if (fViewer instanceof StructuredViewer && fDoubleClickListener == null) { - ((StructuredViewer) fViewer).addDoubleClickListener(fDoubleClickListener= new IDoubleClickListener() { - @Override - public void doubleClick(DoubleClickEvent e) { - handleDoubleClick(e); - } - }); - } - } - - /** - * Handle viewer double click. - * + + /** + * Creates this model proxy strategy for the given provider. + */ + public DefaultVMModelProxyStrategy(AbstractVMProvider provider, Object rootElement) { + fProvider = provider; + fRootElement = rootElement; + } + + @Override + public boolean isDeltaEvent(Object event) { + return getEventDeltaFlags(event) != IModelDelta.NO_CHANGE; + } + + @Override + public int getEventDeltaFlags(Object event) { + IRootVMNode rootNode = getVMProvider().getRootVMNode(); + if (rootNode != null && rootNode.isDeltaEvent(getRootElement(), event)) { + return getDeltaFlags(rootNode, null, event); + } + return IModelDelta.NO_CHANGE; + } + + /** + * Returns the view model provider that this strategy is configured for. + * @return + */ + protected AbstractVMProvider getVMProvider() { + return fProvider; + } + + private Object[] getListeners() { + return fListeners.getListeners(); + } + + @Override + public void addModelChangedListener(IModelChangedListener listener) { + fListeners.add(listener); + } + + @Override + public void removeModelChangedListener(IModelChangedListener listener) { + fListeners.remove(listener); + } + + @Override + public Object getRootElement() { + return fRootElement; + } + + /** @since 1.1 */ + @Override + public Object getViewerInput() { + return fRootElement; + } + + /** @since 1.1 */ + @Override + public TreePath getRootPath() { + return TreePath.EMPTY; + } + + /** + * Notifies registered listeners of the given delta. + * + * @param delta model delta to broadcast + */ + @Override + public void fireModelChanged(IModelDelta delta) { + final IModelDelta root = getRootDelta(delta); + Object[] listeners = getListeners(); + for (int i = 0; i < listeners.length; i++) { + final IModelChangedListener listener = (IModelChangedListener) listeners[i]; + ISafeRunnable safeRunnable = new ISafeRunnable() { + @Override + public void handleException(Throwable exception) { + DebugUIPlugin.log(exception); + } + + @Override + public void run() throws Exception { + listener.modelChanged(root, DefaultVMModelProxyStrategy.this); + } + + }; + SafeRunner.run(safeRunnable); + } + } + + /** + * Convenience method that returns the root node of the given delta. + * + * @param delta delta node + * @return returns the root of the given delta + */ + protected IModelDelta getRootDelta(IModelDelta delta) { + IModelDelta parent = delta.getParentDelta(); + while (parent != null) { + delta = parent; + parent = delta.getParentDelta(); + } + return delta; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.IModelProxy#dispose() + */ + @Override + public void dispose() { + fDisposed = true; + if (fViewer instanceof StructuredViewer && fDoubleClickListener != null) { + ((StructuredViewer) fViewer).removeDoubleClickListener(fDoubleClickListener); + fDoubleClickListener = null; + } + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.IModelProxy#init(org.eclipse.debug.internal.ui.viewers.IPresentationContext) + */ + @Override + public void init(IPresentationContext context) { + fDisposed = false; + fContext = context; + } + + /** + * Returns the context this model proxy is installed in. + * + * @return presentation context, or <code>null</code> if this + * model proxy has been disposed + */ + public IPresentationContext getPresentationContext() { + return fContext; + } + + /* (non-Javadoc) + * + * Subclasses should override as required. + * + * @see org.eclipse.debug.internal.ui.viewers.provisional.IModelProxy#installed(org.eclipse.jface.viewers.Viewer) + */ + @Override + public void installed(final Viewer viewer) { + fViewer = viewer; + getVMProvider().getExecutor().execute(new DsfRunnable() { + @Override + public void run() { + fProvider.handleEvent( + new ModelProxyInstalledEvent(DefaultVMModelProxyStrategy.this, viewer, fRootElement)); + } + }); + if (fViewer instanceof StructuredViewer && fDoubleClickListener == null) { + ((StructuredViewer) fViewer).addDoubleClickListener(fDoubleClickListener = new IDoubleClickListener() { + @Override + public void doubleClick(DoubleClickEvent e) { + handleDoubleClick(e); + } + }); + } + } + + /** + * Handle viewer double click. + * * @param e the event - * + * * @since 1.1 */ protected void handleDoubleClick(final DoubleClickEvent e) { - final AbstractVMProvider vmProvider= getVMProvider(); + final AbstractVMProvider vmProvider = getVMProvider(); if (!vmProvider.isDisposed()) { - ISelection selection = e.getSelection(); + ISelection selection = e.getSelection(); if (!selection.isEmpty() && selection instanceof ITreeSelection) { - final TreePath path = ((ITreeSelection)selection).getPaths()[0]; - final Object input = e.getViewer().getInput(); - - vmProvider.getExecutor().execute( new DsfRunnable() { - @Override - public void run() { - Object rootElement = getRootElement(); - boolean eventContainsRootElement = rootElement.equals(input); - for (int i = 0; !eventContainsRootElement && i < path.getSegmentCount(); i++) { - eventContainsRootElement = rootElement.equals(path.getSegment(i)); - } - - if (eventContainsRootElement) { - vmProvider.handleEvent(e); - } - } - }); - } + final TreePath path = ((ITreeSelection) selection).getPaths()[0]; + final Object input = e.getViewer().getInput(); + + vmProvider.getExecutor().execute(new DsfRunnable() { + @Override + public void run() { + Object rootElement = getRootElement(); + boolean eventContainsRootElement = rootElement.equals(input); + for (int i = 0; !eventContainsRootElement && i < path.getSegmentCount(); i++) { + eventContainsRootElement = rootElement.equals(path.getSegment(i)); + } + + if (eventContainsRootElement) { + vmProvider.handleEvent(e); + } + } + }); + } } } /** - * Returns the viewer this proxy is installed in. - * - * @return viewer or <code>null</code> if not installed - * - * @since 1.1 - */ - @Override - public Viewer getViewer() { - return fViewer; - } - - /* (non-Javadoc) - * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy#isDisposed() - */ - @Override - public boolean isDisposed() { - return fDisposed; - } + * Returns the viewer this proxy is installed in. + * + * @return viewer or <code>null</code> if not installed + * + * @since 1.1 + */ + @Override + public Viewer getViewer() { + return fViewer; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy#isDisposed() + */ + @Override + public boolean isDisposed() { + return fDisposed; + } /** * Recursively calls the VM nodes in the hierarchy of the given node to * determine how elements of those types may be (or are) affected by * [event], the answer being a collection of IModelDelta flags. - * + * * A response of IModeDelta.CONTENT has a special meaning. If we return that * flag for an IVMNode, it means the <i>collection</i> of elements of that * type are affected. It is not a statement on the elements themselves. - * + * * Optimization 1: If the first-level child node does not have * <code>IModelDelta.CONTENT</code> but one of its descendants does, then * for optimization reasons we return <code>IModelDelta.STATE</code> * instead. See {@link DefaultVMModelProxyStrategy#buildChildDeltasForAllContexts(IVMNode, Object, VMDelta, int, RequestMonitor)} - * + * * Optimization 2: If the parent delta contains * <code>IModelDelta.CONTENT</code>, we do not need to specify it for its * children. This can shorten delta processing considerably. - * + * * @param node * the IVMNode whose delta flags (and those of its descendants) * are being queried @@ -317,371 +313,357 @@ public class DefaultVMModelProxyStrategy implements IVMModelProxy { * @return the collective set of IModelDelta flags that reflect how [node] * and its descendants may be (or are) affected by [event] */ - protected int getDeltaFlags(IVMNode node, ModelDelta parentDelta, Object event) { - int flags = node.getDeltaFlags(event); - for (IVMNode childNode : getVMProvider().getChildVMNodes(node)) { - if (!childNode.equals(node)) { - int childNodeDeltaFlags = getDeltaFlags(childNode, parentDelta, event); - - // optimization 1; see above - if ((childNodeDeltaFlags & IModelDelta.CONTENT) != 0) { - childNodeDeltaFlags &= ~IModelDelta.CONTENT; - childNodeDeltaFlags |= IModelDelta.STATE; - } - - flags |= childNodeDeltaFlags; - } - } - - // optimization 2; see above - while (parentDelta != null) { - if ( (parentDelta.getFlags() & IModelDelta.CONTENT) != 0 ) { - flags = flags & ~IModelDelta.CONTENT & ~IModelDelta.STATE; - break; - } - parentDelta = (ModelDelta)parentDelta.getParentDelta(); - } - return flags; - } - - /** - * Default implementation creates a delta assuming that the root node - * is the input object into the view. - */ - @Override - public void createDelta(final Object event, final DataRequestMonitor<IModelDelta> rm) { - final IRootVMNode rootNode = getVMProvider().getRootVMNode(); - - // Always create the rootDelta, no matter what delta flags the child nodes have. - rootNode.createRootDelta( - getRootElement(), event, - new DataRequestMonitor<VMDelta>(getVMProvider().getExecutor(), rm) { - @Override - protected void handleSuccess() { - // The resulting delta will have parents if our - // VMProvider is registered to populate only a sub-tree - // of the viewer. Get the root node of the chain--i.e., - // the delta for the root element of the entire viewer. - final IModelDelta viewRootDelta = getRootDelta(getData()); - - // Find the child nodes that (may) have deltas for the given event. - final Map<IVMNode,Integer> childNodesWithDeltaFlags = getChildNodesWithDeltaFlags(rootNode, getData(), event); - - // If no child nodes have deltas we can stop here. - if (childNodesWithDeltaFlags.size() == 0) { - rm.setData(viewRootDelta); - rm.done(); - return; - } - - callChildNodesToBuildDelta( - rootNode, - childNodesWithDeltaFlags, getData(), event, - new RequestMonitor(getVMProvider().getExecutor(), rm) { - @Override - protected void handleSuccess() { - // Get rid of redundant CONTENT and STATE flags in delta and prune - // nodes without flags - rm.setData(pruneDelta((VMDelta)viewRootDelta)); - rm.done(); - } - }); - } - }); - } - - protected VMDelta pruneDelta(VMDelta delta) { - delta.accept(new IModelDeltaVisitor() { - @Override - public boolean visit(IModelDelta deltaNode, int depth) { - if ((deltaNode.getFlags() & (IModelDelta.CONTENT | IModelDelta.STATE)) != 0) { - VMDelta parent = (VMDelta)deltaNode.getParentDelta(); - while (parent != null) { - if ((parent.getFlags() & IModelDelta.CONTENT) != 0) { - ((VMDelta)deltaNode).setFlags(deltaNode.getFlags() & ~(IModelDelta.CONTENT | IModelDelta.STATE)); - break; - } - parent = parent.getParentDelta(); - } - } - return true; - } - }); - return delta; - } - - /** - * Base implementation that handles calling child nodes to build - * the model delta. This method delegates to two other methods: - * {@link #buildChildDeltasForEventContext(IVMContext[], IVMNode, Object, VMDelta, int, RequestMonitor)} - * and {@link #buildChildDeltasForAllContexts(IVMNode, Object, VMDelta, int, RequestMonitor)}, - * depending on the result of calling{@link IVMNode#getContextsForEvent(VMDelta, Object, DataRequestMonitor)}. - * @see IVMNode#buildDelta(Object, ModelDelta, int, RequestMonitor) - */ - protected void buildChildDeltas(final IVMNode node, final Object event, final VMDelta parentDelta, - final int nodeOffset, final RequestMonitor rm) - { - node.getContextsForEvent( - parentDelta, - event, - new DataRequestMonitor<IVMContext[]>(getVMProvider().getExecutor(), rm) { - @Override - protected void handleCompleted() { - if (isSuccess()) { - assert getData() != null; - buildChildDeltasForEventContext(getData(), node, event, parentDelta, nodeOffset, rm); - } - else if (getStatus().getCode() == IDsfStatusConstants.NOT_SUPPORTED) { - // The DMC for this node was not found in the event. Call the - // super-class to resort to the default behavior which will add a - // delta for every element in this node. - buildChildDeltasForAllContexts(node, event, parentDelta, nodeOffset, rm); - } - else { - super.handleCompleted(); - } - } - }); - } - - /** - * Base implementation that handles calling child nodes to build - * the model delta. This method is called with the context obtained - * by calling{@link IVMNode#getContextsForEvent(VMDelta, Object, DataRequestMonitor)}. - * @see IVMNode#buildDelta(Object, ModelDelta, int, RequestMonitor) - */ - protected void buildChildDeltasForEventContext(final IVMContext[] vmcs, final IVMNode node, final Object event, - final VMDelta parentDelta, final int nodeOffset, final RequestMonitor rm) - { - final Map<IVMNode,Integer> childNodesWithDeltaFlags = getChildNodesWithDeltaFlags(node, parentDelta, event); - if (childNodesWithDeltaFlags.size() == 0) { - // There are no child nodes with deltas, just return to parent. - rm.done(); - return; - } - - // Check if any of the child nodes are will generate IModelDelta.SELECT or - // IModelDelta.EXPAND flags. If so, we must calculate the index for this - // VMC. - boolean calculateIndex = false; - if (nodeOffset >= 0) { - for (int childDelta : childNodesWithDeltaFlags.values()) { - if ( (childDelta & (IModelDelta.SELECT | IModelDelta.EXPAND)) != 0 ) { - calculateIndex = true; - break; - } - } - } - - if (calculateIndex) { - // Calculate the index of this node by retrieving all the - // elements and then finding the DMC that the event is for. - getVMProvider().updateNode( - node, - new VMChildrenUpdate( - parentDelta, getVMProvider().getPresentationContext(), -1, -1, - new DataRequestMonitor<List<Object>>(getVMProvider().getExecutor(), rm) { - @Override - protected void handleSuccess() { - // Check for an empty list of elements. If it's empty then we - // don't have to call the children nodes, so return here. - // No need to propagate error, there's no means or need to display it. - if (getData().isEmpty()) { - rm.done(); - return; - } - - CountingRequestMonitor countingRm = - new CountingRequestMonitor(getVMProvider().getExecutor(), rm); - - int count = 0; - for (IVMContext vmc : vmcs) { - // Find the index of the vmc in the full list of elements. - int i; - for (i = 0; i < getData().size(); i++) { - if (vmc.equals(getData().get(i))) break; - } - if (i == getData().size()) { - // Element not found, no need to generate the delta. - continue; - } - - // Optimization: Try to find a delta with a matching element, if found use it. - // Otherwise create a new delta for the event element. - int elementIndex = nodeOffset + i; - VMDelta delta = parentDelta.getChildDelta(vmc); - if (delta == null || delta.getIndex() != elementIndex) { - delta = parentDelta.addNode(vmc, elementIndex, IModelDelta.NO_CHANGE); - } - - callChildNodesToBuildDelta( - node, childNodesWithDeltaFlags, delta, event, countingRm); - count++; - } - countingRm.setDoneCount(count); - } - })); - } else { - CountingRequestMonitor countingRm = - new CountingRequestMonitor(getVMProvider().getExecutor(), rm); - int count = 0; - for (IVMContext vmc : vmcs) { - // Optimization: Try to find a delta with a matching element, if found use it. - // Otherwise create a new delta for the event element. - VMDelta delta = parentDelta.getChildDelta(vmc); - if (delta == null) { - delta = parentDelta.addNode(vmc, IModelDelta.NO_CHANGE); - } - callChildNodesToBuildDelta(node, childNodesWithDeltaFlags, delta, event, countingRm); - count++; - } - countingRm.setDoneCount(count); - } - } - - /** - * Base implementation that handles calling child nodes to build - * the model delta. The child nodes are called with all the elements - * in this node, which could be very inefficient. This method is only - * called if {@link IVMNode#getContextsForEvent(VMDelta, Object, DataRequestMonitor)} - * is not supported by the node for the given element. - * @see IVMNode#buildDelta(Object, ModelDelta, int, RequestMonitor) - */ - protected void buildChildDeltasForAllContexts(final IVMNode node, final Object event, final VMDelta parentDelta, - final int nodeOffset, final RequestMonitor rm) - { - final Map<IVMNode,Integer> childNodesWithDeltaFlags = getChildNodesWithDeltaFlags(node, parentDelta, event); - if (childNodesWithDeltaFlags.size() == 0) { - // There are no child nodes with deltas, just return to parent. - rm.done(); - return; - } + protected int getDeltaFlags(IVMNode node, ModelDelta parentDelta, Object event) { + int flags = node.getDeltaFlags(event); + for (IVMNode childNode : getVMProvider().getChildVMNodes(node)) { + if (!childNode.equals(node)) { + int childNodeDeltaFlags = getDeltaFlags(childNode, parentDelta, event); + + // optimization 1; see above + if ((childNodeDeltaFlags & IModelDelta.CONTENT) != 0) { + childNodeDeltaFlags &= ~IModelDelta.CONTENT; + childNodeDeltaFlags |= IModelDelta.STATE; + } + + flags |= childNodeDeltaFlags; + } + } + + // optimization 2; see above + while (parentDelta != null) { + if ((parentDelta.getFlags() & IModelDelta.CONTENT) != 0) { + flags = flags & ~IModelDelta.CONTENT & ~IModelDelta.STATE; + break; + } + parentDelta = (ModelDelta) parentDelta.getParentDelta(); + } + return flags; + } + + /** + * Default implementation creates a delta assuming that the root node + * is the input object into the view. + */ + @Override + public void createDelta(final Object event, final DataRequestMonitor<IModelDelta> rm) { + final IRootVMNode rootNode = getVMProvider().getRootVMNode(); + + // Always create the rootDelta, no matter what delta flags the child nodes have. + rootNode.createRootDelta(getRootElement(), event, + new DataRequestMonitor<VMDelta>(getVMProvider().getExecutor(), rm) { + @Override + protected void handleSuccess() { + // The resulting delta will have parents if our + // VMProvider is registered to populate only a sub-tree + // of the viewer. Get the root node of the chain--i.e., + // the delta for the root element of the entire viewer. + final IModelDelta viewRootDelta = getRootDelta(getData()); + + // Find the child nodes that (may) have deltas for the given event. + final Map<IVMNode, Integer> childNodesWithDeltaFlags = getChildNodesWithDeltaFlags(rootNode, + getData(), event); + + // If no child nodes have deltas we can stop here. + if (childNodesWithDeltaFlags.size() == 0) { + rm.setData(viewRootDelta); + rm.done(); + return; + } + + callChildNodesToBuildDelta(rootNode, childNodesWithDeltaFlags, getData(), event, + new RequestMonitor(getVMProvider().getExecutor(), rm) { + @Override + protected void handleSuccess() { + // Get rid of redundant CONTENT and STATE flags in delta and prune + // nodes without flags + rm.setData(pruneDelta((VMDelta) viewRootDelta)); + rm.done(); + } + }); + } + }); + } + + protected VMDelta pruneDelta(VMDelta delta) { + delta.accept(new IModelDeltaVisitor() { + @Override + public boolean visit(IModelDelta deltaNode, int depth) { + if ((deltaNode.getFlags() & (IModelDelta.CONTENT | IModelDelta.STATE)) != 0) { + VMDelta parent = (VMDelta) deltaNode.getParentDelta(); + while (parent != null) { + if ((parent.getFlags() & IModelDelta.CONTENT) != 0) { + ((VMDelta) deltaNode) + .setFlags(deltaNode.getFlags() & ~(IModelDelta.CONTENT | IModelDelta.STATE)); + break; + } + parent = parent.getParentDelta(); + } + } + return true; + } + }); + return delta; + } + + /** + * Base implementation that handles calling child nodes to build + * the model delta. This method delegates to two other methods: + * {@link #buildChildDeltasForEventContext(IVMContext[], IVMNode, Object, VMDelta, int, RequestMonitor)} + * and {@link #buildChildDeltasForAllContexts(IVMNode, Object, VMDelta, int, RequestMonitor)}, + * depending on the result of calling{@link IVMNode#getContextsForEvent(VMDelta, Object, DataRequestMonitor)}. + * @see IVMNode#buildDelta(Object, ModelDelta, int, RequestMonitor) + */ + protected void buildChildDeltas(final IVMNode node, final Object event, final VMDelta parentDelta, + final int nodeOffset, final RequestMonitor rm) { + node.getContextsForEvent(parentDelta, event, + new DataRequestMonitor<IVMContext[]>(getVMProvider().getExecutor(), rm) { + @Override + protected void handleCompleted() { + if (isSuccess()) { + assert getData() != null; + buildChildDeltasForEventContext(getData(), node, event, parentDelta, nodeOffset, rm); + } else if (getStatus().getCode() == IDsfStatusConstants.NOT_SUPPORTED) { + // The DMC for this node was not found in the event. Call the + // super-class to resort to the default behavior which will add a + // delta for every element in this node. + buildChildDeltasForAllContexts(node, event, parentDelta, nodeOffset, rm); + } else { + super.handleCompleted(); + } + } + }); + } + + /** + * Base implementation that handles calling child nodes to build + * the model delta. This method is called with the context obtained + * by calling{@link IVMNode#getContextsForEvent(VMDelta, Object, DataRequestMonitor)}. + * @see IVMNode#buildDelta(Object, ModelDelta, int, RequestMonitor) + */ + protected void buildChildDeltasForEventContext(final IVMContext[] vmcs, final IVMNode node, final Object event, + final VMDelta parentDelta, final int nodeOffset, final RequestMonitor rm) { + final Map<IVMNode, Integer> childNodesWithDeltaFlags = getChildNodesWithDeltaFlags(node, parentDelta, event); + if (childNodesWithDeltaFlags.size() == 0) { + // There are no child nodes with deltas, just return to parent. + rm.done(); + return; + } + + // Check if any of the child nodes are will generate IModelDelta.SELECT or + // IModelDelta.EXPAND flags. If so, we must calculate the index for this + // VMC. + boolean calculateIndex = false; + if (nodeOffset >= 0) { + for (int childDelta : childNodesWithDeltaFlags.values()) { + if ((childDelta & (IModelDelta.SELECT | IModelDelta.EXPAND)) != 0) { + calculateIndex = true; + break; + } + } + } + + if (calculateIndex) { + // Calculate the index of this node by retrieving all the + // elements and then finding the DMC that the event is for. + getVMProvider().updateNode(node, new VMChildrenUpdate(parentDelta, getVMProvider().getPresentationContext(), + -1, -1, new DataRequestMonitor<List<Object>>(getVMProvider().getExecutor(), rm) { + @Override + protected void handleSuccess() { + // Check for an empty list of elements. If it's empty then we + // don't have to call the children nodes, so return here. + // No need to propagate error, there's no means or need to display it. + if (getData().isEmpty()) { + rm.done(); + return; + } + + CountingRequestMonitor countingRm = new CountingRequestMonitor( + getVMProvider().getExecutor(), rm); + + int count = 0; + for (IVMContext vmc : vmcs) { + // Find the index of the vmc in the full list of elements. + int i; + for (i = 0; i < getData().size(); i++) { + if (vmc.equals(getData().get(i))) + break; + } + if (i == getData().size()) { + // Element not found, no need to generate the delta. + continue; + } + + // Optimization: Try to find a delta with a matching element, if found use it. + // Otherwise create a new delta for the event element. + int elementIndex = nodeOffset + i; + VMDelta delta = parentDelta.getChildDelta(vmc); + if (delta == null || delta.getIndex() != elementIndex) { + delta = parentDelta.addNode(vmc, elementIndex, IModelDelta.NO_CHANGE); + } + + callChildNodesToBuildDelta(node, childNodesWithDeltaFlags, delta, event, countingRm); + count++; + } + countingRm.setDoneCount(count); + } + })); + } else { + CountingRequestMonitor countingRm = new CountingRequestMonitor(getVMProvider().getExecutor(), rm); + int count = 0; + for (IVMContext vmc : vmcs) { + // Optimization: Try to find a delta with a matching element, if found use it. + // Otherwise create a new delta for the event element. + VMDelta delta = parentDelta.getChildDelta(vmc); + if (delta == null) { + delta = parentDelta.addNode(vmc, IModelDelta.NO_CHANGE); + } + callChildNodesToBuildDelta(node, childNodesWithDeltaFlags, delta, event, countingRm); + count++; + } + countingRm.setDoneCount(count); + } + } + + /** + * Base implementation that handles calling child nodes to build + * the model delta. The child nodes are called with all the elements + * in this node, which could be very inefficient. This method is only + * called if {@link IVMNode#getContextsForEvent(VMDelta, Object, DataRequestMonitor)} + * is not supported by the node for the given element. + * @see IVMNode#buildDelta(Object, ModelDelta, int, RequestMonitor) + */ + protected void buildChildDeltasForAllContexts(final IVMNode node, final Object event, final VMDelta parentDelta, + final int nodeOffset, final RequestMonitor rm) { + final Map<IVMNode, Integer> childNodesWithDeltaFlags = getChildNodesWithDeltaFlags(node, parentDelta, event); + if (childNodesWithDeltaFlags.size() == 0) { + // There are no child nodes with deltas, just return to parent. + rm.done(); + return; + } // Check if the child delta only has an IModelDelta.STATE flag. If // that's the case, we can skip creating a delta for this node, because // the Debug Platform's handling of that flag does not require ancestor // deltas (doesn't need to know the path to the element) - // + // // We can skip the delta for this node even if a deeper IVMNode child // calls for an IModelDelta.CONTENT flag, since what we do in that case // is have the CONTENT flag applied to the first ancestor delta that has // something other than IModelDelta.STATE. - // - // The main benefit of this optimization is that the viewer is left - // to retrieve the elements that need to be refreshed, rather - // than having this proxy do it. Since the viewer is lazy loading - // it may not need to retrieve as many elements in the hierarchy. - // - // For example: suppose the model looks like: - // A- - // |-1 - // |-I - // | |-a - // | |-b - // |-II - // | |-c - // |-III - // |-d - // + // + // The main benefit of this optimization is that the viewer is left + // to retrieve the elements that need to be refreshed, rather + // than having this proxy do it. Since the viewer is lazy loading + // it may not need to retrieve as many elements in the hierarchy. + // + // For example: suppose the model looks like: + // A- + // |-1 + // |-I + // | |-a + // | |-b + // |-II + // | |-c + // |-III + // |-d + // // And if VM Node responsible for element a, b, c, d needs a CONTENT // update, then the delta may look like this: - // - // Element: A - // Flags: CONTENT - // Index: 0 Child Count:-1 - // - // Instead of: - // - // Element: A - // Flags: NO_CHANGE - // Index: 0 Child Count: 1 - // Element: 1 - // Flags: NO_CHANGE - // Index: 0 Child Count: 3 - // Element: I - // Flags: CONTENT - // Index: 0 Child Count: 2 - // Element: II - // Flags: CONTENT - // Index: 1 Child Count: 1 - // Element: III - // Flags: CONTENT - // Index: 2 Child Count: 1 - boolean mustGetElements = false; - boolean _updateFlagsOnly = true; - for (int childDelta : childNodesWithDeltaFlags.values()) { - if ((childDelta & ~IModelDelta.STATE) != 0) { - mustGetElements = true; - } - if ((childDelta & ~(IModelDelta.STATE | IModelDelta.CONTENT)) != 0) { - _updateFlagsOnly = false; - } - } - final boolean updateFlagsOnly = _updateFlagsOnly; - - if (!mustGetElements) { - callChildNodesToBuildDelta( - node, childNodesWithDeltaFlags, parentDelta, event, - new RequestMonitor(getVMProvider().getExecutor(), rm) { - @Override - protected void handleError() { - super.handleError(); - } - }); - } else { - // The given child nodes have deltas potentially for all elements - // from this node. Retrieve all elements and call the child nodes with - // each element as the parent of their delta. - getVMProvider().updateNode( - node, - new VMChildrenUpdate( - parentDelta, getVMProvider().getPresentationContext(), -1, -1, - new DataRequestMonitor<List<Object>>(getVMProvider().getExecutor(), rm) { - @Override - protected void handleCompleted() { - if (fDisposed) return; - - final List<Object> childElements = getData(); - - // Check for an empty list of elements. If the list of elements is empty - // still call the child nodes using the parent delta only. Do this only if - // an optimization was used to build the delta, so that the child node can - // adds the optimized delta flags without the full delta (bug 280770). - if (childElements == null || childElements.size() == 0) { - if (updateFlagsOnly) { - callChildNodesToBuildDelta( - node, childNodesWithDeltaFlags, parentDelta, event, rm); - } else { - rm.done(); - return; - } - } else { - final CountingRequestMonitor countingRM = new CountingRequestMonitor(getVMProvider().getExecutor(), rm); - int rmCount = 0; - - // For each element from this node, create a new delta, - // and then call all the child nodes to build their delta. - for (int i = 0; i < childElements.size(); i++) { - int elementIndex = nodeOffset >= 0 ? nodeOffset + i : -1; - VMDelta delta= parentDelta.getChildDelta(childElements.get(i)); - if (delta == null) { - delta= parentDelta.addNode(childElements.get(i), elementIndex, IModelDelta.NO_CHANGE); - } - callChildNodesToBuildDelta(node, childNodesWithDeltaFlags, delta, event, countingRM); - rmCount++; - } - countingRM.setDoneCount(rmCount); - } - } - }) - ); - } - } + // + // Element: A + // Flags: CONTENT + // Index: 0 Child Count:-1 + // + // Instead of: + // + // Element: A + // Flags: NO_CHANGE + // Index: 0 Child Count: 1 + // Element: 1 + // Flags: NO_CHANGE + // Index: 0 Child Count: 3 + // Element: I + // Flags: CONTENT + // Index: 0 Child Count: 2 + // Element: II + // Flags: CONTENT + // Index: 1 Child Count: 1 + // Element: III + // Flags: CONTENT + // Index: 2 Child Count: 1 + boolean mustGetElements = false; + boolean _updateFlagsOnly = true; + for (int childDelta : childNodesWithDeltaFlags.values()) { + if ((childDelta & ~IModelDelta.STATE) != 0) { + mustGetElements = true; + } + if ((childDelta & ~(IModelDelta.STATE | IModelDelta.CONTENT)) != 0) { + _updateFlagsOnly = false; + } + } + final boolean updateFlagsOnly = _updateFlagsOnly; + + if (!mustGetElements) { + callChildNodesToBuildDelta(node, childNodesWithDeltaFlags, parentDelta, event, + new RequestMonitor(getVMProvider().getExecutor(), rm) { + @Override + protected void handleError() { + super.handleError(); + } + }); + } else { + // The given child nodes have deltas potentially for all elements + // from this node. Retrieve all elements and call the child nodes with + // each element as the parent of their delta. + getVMProvider().updateNode(node, new VMChildrenUpdate(parentDelta, getVMProvider().getPresentationContext(), + -1, -1, new DataRequestMonitor<List<Object>>(getVMProvider().getExecutor(), rm) { + @Override + protected void handleCompleted() { + if (fDisposed) + return; + + final List<Object> childElements = getData(); + + // Check for an empty list of elements. If the list of elements is empty + // still call the child nodes using the parent delta only. Do this only if + // an optimization was used to build the delta, so that the child node can + // adds the optimized delta flags without the full delta (bug 280770). + if (childElements == null || childElements.size() == 0) { + if (updateFlagsOnly) { + callChildNodesToBuildDelta(node, childNodesWithDeltaFlags, parentDelta, event, rm); + } else { + rm.done(); + return; + } + } else { + final CountingRequestMonitor countingRM = new CountingRequestMonitor( + getVMProvider().getExecutor(), rm); + int rmCount = 0; + + // For each element from this node, create a new delta, + // and then call all the child nodes to build their delta. + for (int i = 0; i < childElements.size(); i++) { + int elementIndex = nodeOffset >= 0 ? nodeOffset + i : -1; + VMDelta delta = parentDelta.getChildDelta(childElements.get(i)); + if (delta == null) { + delta = parentDelta.addNode(childElements.get(i), elementIndex, + IModelDelta.NO_CHANGE); + } + callChildNodesToBuildDelta(node, childNodesWithDeltaFlags, delta, event, + countingRM); + rmCount++; + } + countingRM.setDoneCount(rmCount); + } + } + })); + } + } /** * Calls the specified child nodes (of [node]) to build the delta for the * given event. - * + * * @param childNodes * Map of nodes to be invoked, and the corresponding delta flags * that they may (or will) generate. This map is generated with a @@ -695,218 +677,211 @@ public class DefaultVMModelProxyStrategy implements IVMModelProxy { * @param rm * The result monitor to invoke when the delta is completed. */ - protected void callChildNodesToBuildDelta(final IVMNode node, final Map<IVMNode,Integer> childNodes, final VMDelta delta, - final Object event, final RequestMonitor rm) - { - assert childNodes.size() != 0; + protected void callChildNodesToBuildDelta(final IVMNode node, final Map<IVMNode, Integer> childNodes, + final VMDelta delta, final Object event, final RequestMonitor rm) { + assert childNodes.size() != 0; // Check if any of the child nodes might generate a delta that requires // us to calculate the index for this VMC. - boolean calculateOffsets = false; - for (int childDelta : childNodes.values()) { - if ( (childDelta & (IModelDelta.SELECT | IModelDelta.EXPAND | IModelDelta.INSERTED | IModelDelta.REMOVED)) != 0 ) { - calculateOffsets = true; - break; - } - } - - getChildNodesElementOffsets( - node, delta, calculateOffsets, - new DataRequestMonitor<Map<IVMNode, Integer>>(getVMProvider().getExecutor(), rm) { - @Override - protected void handleSuccess() { - final CountingRequestMonitor multiRm = new CountingRequestMonitor(getVMProvider().getExecutor(), rm); - int multiRmCount = 0; - - // Set the total count of number of children in the parent delta. - delta.setChildCount(getData().get(null)); - - for (final IVMNode childNode : childNodes.keySet()) { - - if (node.equals(childNode)) { - - // Avoid descending into recursive node hierarchy's when calculating the delta. - // if recursive nodes are not allowed. - if( !allowRecursiveVMNodes()) - continue; - - // get into recursion to build the delta only if the recursive context is added. - // - // We user current assumption that recursive container can be added as first children - // if the list of VMNodes. If we decide to make the patch more generic ( allow recursive - // node to be at different index) we need to remove this simplification. - // - if (isDeltaElementOfType(delta, childNode)) { - childNode.buildDelta( - event, delta, 0, - new RequestMonitor(getVMProvider().getExecutor(), multiRm) { - @Override - protected void handleSuccess() { - buildChildDeltas( - childNode, event, delta, 0, - new RequestMonitor(getVMProvider().getExecutor(), multiRm)); - } - }); - multiRmCount++; - } - - continue; - } - - final int nodeOffset = getData().get(childNode); - childNode.buildDelta( - event, delta, nodeOffset, - new RequestMonitor(getVMProvider().getExecutor(), multiRm) { - @Override - protected void handleSuccess() { - buildChildDeltas( - childNode, event, delta, nodeOffset, - new RequestMonitor(getVMProvider().getExecutor(), multiRm)); - } - }); - multiRmCount++; - } - multiRm.setDoneCount(multiRmCount); - } - }); - } - - /** - * Calculates the indexes at which the elements of each of the child - * nodes begin. These indexes are necessary to correctly - * calculate the deltas for elements in the child nodes. - * @param delta The delta object to build on. This delta should have been - * generated by this node, unless the full delta path is not being calculated - * due to an optimization. - * @param doCalculdateOffsets If true, the method calls each node to get its - * element count. If false, it causes this method to fill the return data - * structure with dummy values. The dummy values indicate that the indexes - * are not known and are acceptable in the delta if the delta flags being - * generated do not require full index information. - * @param rm Return token containing the results. The result data is a - * mapping between the child nodes and the indexes at which the child nodes' - * elements begin. There is a special value in the map with a <code>null</code> - * key, which contains the full element count for all the nodes. - */ - private void getChildNodesElementOffsets(IVMNode node, IModelDelta delta, boolean calculdateOffsets, final DataRequestMonitor<Map<IVMNode, Integer>> rm) { - final IVMNode[] childNodes = getVMProvider().getChildVMNodes(node); - assert childNodes.length != 0; - - if (calculdateOffsets) { - final Integer[] counts = new Integer[childNodes.length]; - final CountingRequestMonitor crm = new CountingRequestMonitor(getVMProvider().getExecutor(), rm) { - @Override - protected void handleSuccess() { - Map<IVMNode, Integer> data = new HashMap<IVMNode, Integer>(); - int offset = 0; - for (int i = 0; i < childNodes.length; i++) { - data.put(childNodes[i], offset); - offset += counts[i]; - } - // As the final value, put the total count in the return map, with null key. - data.put(null, offset); - rm.setData(data); - rm.done(); - } - }; - int countRM = 0; - - for (int i = 0; i < childNodes.length; i++) { - final int nodeIndex = i; - getVMProvider().updateNode( - childNodes[i], - new VMChildrenCountUpdate( - delta, getVMProvider().getPresentationContext(), - new DataRequestMonitor<Integer>(getVMProvider().getExecutor(), crm) { - @Override - protected void handleCompleted() { - counts[nodeIndex] = getData(); - crm.done(); - } - } - ) - ); - countRM++; - } - crm.setDoneCount(countRM); - } else { - Map<IVMNode, Integer> data = new HashMap<IVMNode, Integer>(); - for (int i = 0; i < childNodes.length; i++) { - data.put(childNodes[i], -1); - } - data.put(null, -1); - rm.setData(data); - rm.done(); - } - } + boolean calculateOffsets = false; + for (int childDelta : childNodes.values()) { + if ((childDelta + & (IModelDelta.SELECT | IModelDelta.EXPAND | IModelDelta.INSERTED | IModelDelta.REMOVED)) != 0) { + calculateOffsets = true; + break; + } + } + + getChildNodesElementOffsets(node, delta, calculateOffsets, + new DataRequestMonitor<Map<IVMNode, Integer>>(getVMProvider().getExecutor(), rm) { + @Override + protected void handleSuccess() { + final CountingRequestMonitor multiRm = new CountingRequestMonitor(getVMProvider().getExecutor(), + rm); + int multiRmCount = 0; + + // Set the total count of number of children in the parent delta. + delta.setChildCount(getData().get(null)); + + for (final IVMNode childNode : childNodes.keySet()) { + + if (node.equals(childNode)) { + + // Avoid descending into recursive node hierarchy's when calculating the delta. + // if recursive nodes are not allowed. + if (!allowRecursiveVMNodes()) + continue; + + // get into recursion to build the delta only if the recursive context is added. + // + // We user current assumption that recursive container can be added as first children + // if the list of VMNodes. If we decide to make the patch more generic ( allow recursive + // node to be at different index) we need to remove this simplification. + // + if (isDeltaElementOfType(delta, childNode)) { + childNode.buildDelta(event, delta, 0, + new RequestMonitor(getVMProvider().getExecutor(), multiRm) { + @Override + protected void handleSuccess() { + buildChildDeltas(childNode, event, delta, 0, + new RequestMonitor(getVMProvider().getExecutor(), multiRm)); + } + }); + multiRmCount++; + } + + continue; + } + + final int nodeOffset = getData().get(childNode); + childNode.buildDelta(event, delta, nodeOffset, + new RequestMonitor(getVMProvider().getExecutor(), multiRm) { + @Override + protected void handleSuccess() { + buildChildDeltas(childNode, event, delta, nodeOffset, + new RequestMonitor(getVMProvider().getExecutor(), multiRm)); + } + }); + multiRmCount++; + } + multiRm.setDoneCount(multiRmCount); + } + }); + } + + /** + * Calculates the indexes at which the elements of each of the child + * nodes begin. These indexes are necessary to correctly + * calculate the deltas for elements in the child nodes. + * @param delta The delta object to build on. This delta should have been + * generated by this node, unless the full delta path is not being calculated + * due to an optimization. + * @param doCalculdateOffsets If true, the method calls each node to get its + * element count. If false, it causes this method to fill the return data + * structure with dummy values. The dummy values indicate that the indexes + * are not known and are acceptable in the delta if the delta flags being + * generated do not require full index information. + * @param rm Return token containing the results. The result data is a + * mapping between the child nodes and the indexes at which the child nodes' + * elements begin. There is a special value in the map with a <code>null</code> + * key, which contains the full element count for all the nodes. + */ + private void getChildNodesElementOffsets(IVMNode node, IModelDelta delta, boolean calculdateOffsets, + final DataRequestMonitor<Map<IVMNode, Integer>> rm) { + final IVMNode[] childNodes = getVMProvider().getChildVMNodes(node); + assert childNodes.length != 0; + + if (calculdateOffsets) { + final Integer[] counts = new Integer[childNodes.length]; + final CountingRequestMonitor crm = new CountingRequestMonitor(getVMProvider().getExecutor(), rm) { + @Override + protected void handleSuccess() { + Map<IVMNode, Integer> data = new HashMap<IVMNode, Integer>(); + int offset = 0; + for (int i = 0; i < childNodes.length; i++) { + data.put(childNodes[i], offset); + offset += counts[i]; + } + // As the final value, put the total count in the return map, with null key. + data.put(null, offset); + rm.setData(data); + rm.done(); + } + }; + int countRM = 0; + + for (int i = 0; i < childNodes.length; i++) { + final int nodeIndex = i; + getVMProvider().updateNode(childNodes[i], + new VMChildrenCountUpdate(delta, getVMProvider().getPresentationContext(), + new DataRequestMonitor<Integer>(getVMProvider().getExecutor(), crm) { + @Override + protected void handleCompleted() { + counts[nodeIndex] = getData(); + crm.done(); + } + })); + countRM++; + } + crm.setDoneCount(countRM); + } else { + Map<IVMNode, Integer> data = new HashMap<IVMNode, Integer>(); + for (int i = 0; i < childNodes.length; i++) { + data.put(childNodes[i], -1); + } + data.put(null, -1); + rm.setData(data); + rm.done(); + } + } /** * Convenience method that returns what each of the child nodes returns from * {@link #getDeltaFlags(IVMNode, ModelDelta, Object)}. Children that return * IModelDelta.NO_CHANGE are omitted. */ - protected Map<IVMNode, Integer> getChildNodesWithDeltaFlags(IVMNode node, ModelDelta parentDelta, Object e) { - Map<IVMNode, Integer> nodes = new HashMap<IVMNode, Integer>(); - for (final IVMNode childNode : getVMProvider().getChildVMNodes(node)) { - if (!childNode.equals(node) || allowRecursiveVMNodes()) { - int delta = getDeltaFlags(childNode, parentDelta, e); - if (delta != IModelDelta.NO_CHANGE) { - nodes.put(childNode, delta); - } - } - } - return nodes; - } - - /** - * Returns whether DefaultVMModelProxyStrategy allows to handle recursive VMNodes hierarchy. - * - * @see setAllowRecursiveVMNodes() - * @return true if this DefaultVMModelProxyStrategy allows recursive containers. - */ - public boolean allowRecursiveVMNodes() { - return fAllowRecursiveVMNodes; - } - - /** - * Allow DefaultVMModelProxyStrategy to handle recursive VMNodes hierarchy. - * - * For example if the client wants the debug view to display container nodes that - * have containers this flag has to be set. - * - * Launch1 - * Container-1 - * Container-1.1 - * Thread-1 - * Container-1.1.1 - * Thread-2 - * Thread-2 - * - * This will allow the client to setup a VMNode to be in the list of its children. - * addChildNodes(containerNode, new IVMNode[] { containerNode, threadsNode }); - * - * The client also needs to make sure the recursive VMNodes and their immediate children: - * 1. Handle buildDelta() by building one level at a time by examining the delta passed as parameter. - * 2. Return the correct level container inside getContextsForEvent() based on the delta passed. - * - * See org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel.launch.ContainerVMNode for sample implementation. - * - * @param allow - whether to allow or not recursive containment of VMNodes. - */ - public void setAllowRecursiveVMNodes(boolean allow) { - fAllowRecursiveVMNodes = allow; - } - - /** - * Compares if the VMNode of element of the provided delta is the same as the provided IVMNode. - * - * @param delta - delta for which to compare the IDMVMContext - * @param node - the IVMNode we want to compare to. - * @return if the VMNode of element of the provided delta is the same as the provided IVMNode. - */ + protected Map<IVMNode, Integer> getChildNodesWithDeltaFlags(IVMNode node, ModelDelta parentDelta, Object e) { + Map<IVMNode, Integer> nodes = new HashMap<IVMNode, Integer>(); + for (final IVMNode childNode : getVMProvider().getChildVMNodes(node)) { + if (!childNode.equals(node) || allowRecursiveVMNodes()) { + int delta = getDeltaFlags(childNode, parentDelta, e); + if (delta != IModelDelta.NO_CHANGE) { + nodes.put(childNode, delta); + } + } + } + return nodes; + } + + /** + * Returns whether DefaultVMModelProxyStrategy allows to handle recursive VMNodes hierarchy. + * + * @see setAllowRecursiveVMNodes() + * @return true if this DefaultVMModelProxyStrategy allows recursive containers. + */ + public boolean allowRecursiveVMNodes() { + return fAllowRecursiveVMNodes; + } + + /** + * Allow DefaultVMModelProxyStrategy to handle recursive VMNodes hierarchy. + * + * For example if the client wants the debug view to display container nodes that + * have containers this flag has to be set. + * + * Launch1 + * Container-1 + * Container-1.1 + * Thread-1 + * Container-1.1.1 + * Thread-2 + * Thread-2 + * + * This will allow the client to setup a VMNode to be in the list of its children. + * addChildNodes(containerNode, new IVMNode[] { containerNode, threadsNode }); + * + * The client also needs to make sure the recursive VMNodes and their immediate children: + * 1. Handle buildDelta() by building one level at a time by examining the delta passed as parameter. + * 2. Return the correct level container inside getContextsForEvent() based on the delta passed. + * + * See org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel.launch.ContainerVMNode for sample implementation. + * + * @param allow - whether to allow or not recursive containment of VMNodes. + */ + public void setAllowRecursiveVMNodes(boolean allow) { + fAllowRecursiveVMNodes = allow; + } + + /** + * Compares if the VMNode of element of the provided delta is the same as the provided IVMNode. + * + * @param delta - delta for which to compare the IDMVMContext + * @param node - the IVMNode we want to compare to. + * @return if the VMNode of element of the provided delta is the same as the provided IVMNode. + */ protected boolean isDeltaElementOfType(VMDelta delta, IVMNode node) { if (delta.getElement() instanceof IDMVMContext) { - IDMVMContext dmvmContext = (IDMVMContext)delta.getElement(); + IDMVMContext dmvmContext = (IDMVMContext) delta.getElement(); return dmvmContext.getVMNode().equals(node); } return false; |