diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/expression/ExpressionManagerLayoutNode.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/expression/ExpressionManagerLayoutNode.java index f8adf60a30b..d658cf26866 100644 --- a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/expression/ExpressionManagerLayoutNode.java +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/expression/ExpressionManagerLayoutNode.java @@ -10,9 +10,7 @@ *******************************************************************************/ package org.eclipse.dd.dsf.debug.ui.viewmodel.expression; -import java.util.HashMap; import java.util.List; -import java.util.Map; import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor; import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; @@ -42,11 +40,31 @@ import org.eclipse.jface.viewers.ICellModifier; import org.eclipse.jface.viewers.TextCellEditor; import org.eclipse.swt.widgets.Composite; +/** + * This is the top-level layout node in the expressions view. Its job is to: + *
IExpression
object,+ * This node is not intended to have any standard child layout nodes, therefore + * the implementation of {@link #setChildNodes(IVMLayoutNode[])} throws an exception. + * Instead users should call {@link #setExpressionLayoutNodes(IExpressionLayoutNode[])} + * to configure layout nodes that this node will delegate to when processing expressions. + *
+ */ @SuppressWarnings("restriction") public class ExpressionManagerLayoutNode extends AbstractVMLayoutNode implements IElementLabelProvider, IElementEditor { + /** + * VMC of an expression object that failed to get parsed by any of the + * configured expression layout nodes. It is only used to display an + * error message in the view, and to allow the user to edit the + * expression. + */ private class InvalidExpressionVMC extends AbstractVMContext { final IExpression fExpression; @@ -76,8 +94,13 @@ public class ExpressionManagerLayoutNode extends AbstractVMLayoutNode } } + /** Array of expression nodes which parse the user expressions and handle model events */ private IExpressionLayoutNode[] fExpressionNodes = new IExpressionLayoutNode[0]; + + /** Local reference to the global expression manager */ private IExpressionManager fManager = DebugPlugin.getDefault().getExpressionManager(); + + /** Cached reference to a cell modifier for editing expression strings of invalid expressions */ private WatchExpressionCellModifier fWatchExpressionCellModifier = new WatchExpressionCellModifier(); public ExpressionManagerLayoutNode(AbstractVMProvider provider) { @@ -85,6 +108,10 @@ public class ExpressionManagerLayoutNode extends AbstractVMLayoutNode } public void updateHasElements(IHasChildrenUpdate[] updates) { + // Test availability of children based on whether there are any expressions + // in the manager. We assume that the getExpressions() will just read + // local state data, so we don't bother using a job to perform this + // operation. for (int i = 0; i < updates.length; i++) { updates[i].setHasChilren(fManager.getExpressions().length != 0); updates[i].done(); @@ -99,6 +126,11 @@ public class ExpressionManagerLayoutNode extends AbstractVMLayoutNode public void updateElements(final IChildrenUpdate update) { final IExpression[] expressions = fManager.getExpressions(); + // For each (expression) element in update, find the layout node that can + // parse it. And for each expression that has a corresponding layout node, + // call IExpressionLayoutNode#getElementForExpression to generate a VMC. + // Since the last is an async call, we need to create a multi-RM to wait + // for all the calls to complete. final CountingRequestMonitor multiRm = new CountingRequestMonitor(getExecutor(), null) { @Override protected void handleCompleted() { @@ -107,10 +139,9 @@ public class ExpressionManagerLayoutNode extends AbstractVMLayoutNode }; int expressionRmCount = 0; - for (int i = update.getOffset(); i < update.getOffset() + update.getLength() && i < expressions.length; i++) { - // Check the array boundries as the expression manager could change asynchronously. + // Check the array boundaries as the expression manager could change asynchronously. // The expression manager change should lead to a refresh in the view. if (i > expressions.length) { continue; @@ -124,6 +155,10 @@ public class ExpressionManagerLayoutNode extends AbstractVMLayoutNode update.setChild(new InvalidExpressionVMC(expression), i); } else { expressionRmCount++; + // getElementForExpression() accepts a IElementsUpdate as an argument. + // Construct an instance of VMElementsUpdate which will call a + // the request monitor when it is finished. The request monitor + // will in turn set the element in the update argument in this method. VMElementsUpdate expressionElementUpdate = new VMElementsUpdate( update, 0, 1, new DataRequestMonitor+ * Note: The nodes specified in the array will be called to parse expressions, + * in the order as they are in the array. Therefore if one node is a "greedy" + * parser, and will accept any expression string, it should appear last in the list + * of the nodes. + *
+ * @param nodes Array of expression layout nodes to configure with the manager. + */ public void setExpressionLayoutNodes(IExpressionLayoutNode[] nodes) { fExpressionNodes = nodes; } @@ -209,19 +270,20 @@ public class ExpressionManagerLayoutNode extends AbstractVMLayoutNode super.dispose(); } - /** - * If any of the children nodes have delta flags, that means that this - * node has to generate a delta as well. - */ @Override public int getDeltaFlags(Object event) { int retVal = 0; - // Add a flag if the list of expressions has changed. + // Add a flag if the list of expressions in the global expression manager has changed. if (event instanceof ExpressionsChangedEvent) { retVal |= IModelDelta.CONTENT; } + // If any of the expressions nodes have delta flags, that means that this + // node probably needs to generate a delta as well. Ideally, we would call + // IExpressionLayoutNode.getDeltaFlagsForExpression() here, but getDeltaFlags() + // is an optimization call anyway, and it's OK if it generates some false + // positives. We will call getDeltaFlagsForExpression in buildDelta() instead.. for (IExpressionLayoutNode node : fExpressionNodes) { retVal |= node.getDeltaFlags(event); } @@ -236,6 +298,9 @@ public class ExpressionManagerLayoutNode extends AbstractVMLayoutNode parentDelta.addFlags(IModelDelta.CONTENT); } + // Once again, for each expression, find its corresponding layout node and ask that + // layout node for its delta flags for given event. If there are delta flags to be + // generated, call the asynchronous method to do so. CountingRequestMonitor multiRm = new CountingRequestMonitor(getExecutor(), requestMonitor); int buildDeltaForExpressionCallCount = 0; @@ -263,22 +328,6 @@ public class ExpressionManagerLayoutNode extends AbstractVMLayoutNode } } - /** - * Convenience method that returns the child layout nodes which return - *true
to the hasDeltaFlags()
test for the given
- * event.
- */
- protected Map