Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
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.java1521
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;

Back to the top