diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/expression/ExpressionVMProvider.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/expression/ExpressionVMProvider.java index 9b82c745d9b..0356fc87ca3 100644 --- a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/expression/ExpressionVMProvider.java +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/expression/ExpressionVMProvider.java @@ -16,6 +16,9 @@ import org.eclipse.dd.dsf.debug.ui.viewmodel.formatsupport.IFormattedValuePrefer import org.eclipse.dd.dsf.debug.ui.viewmodel.register.RegisterGroupLayoutNode; import org.eclipse.dd.dsf.debug.ui.viewmodel.register.RegisterLayoutNode; import org.eclipse.dd.dsf.debug.ui.viewmodel.register.SyncRegisterDataAccess; +import org.eclipse.dd.dsf.debug.ui.viewmodel.variable.SyncVariableDataAccess; +import org.eclipse.dd.dsf.debug.ui.viewmodel.variable.VariableLocalsLayoutNode; +import org.eclipse.dd.dsf.debug.ui.viewmodel.variable.VariableSubExpressionsLayoutNode; import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter; import org.eclipse.dd.dsf.ui.viewmodel.IVMContext; @@ -58,16 +61,54 @@ public class ExpressionVMProvider extends AbstractDMVMProvider } protected void configureLayout() { - SyncRegisterDataAccess syncDataAccess = new SyncRegisterDataAccess(); - // Configure the layout nodes + /* + * Allocate the synchronous data providers. + */ + SyncRegisterDataAccess syncRegDataAccess = new SyncRegisterDataAccess(); + SyncVariableDataAccess syncvarDataAccess = new SyncVariableDataAccess() ; + + /* + * Create the top level node which provides the anchor starting point. + */ IVMRootLayoutNode debugViewSelectionNode = new DebugViewSelectionRootLayoutNode(this); + + /* + * Now the Overarching management node. + */ ExpressionManagerLayoutNode expressionManagerNode = new ExpressionManagerLayoutNode(this); debugViewSelectionNode.setChildNodes(new IVMLayoutNode[] {expressionManagerNode}); - IExpressionLayoutNode registerGroupNode = new RegisterGroupLayoutNode(this, getSession(), syncDataAccess); - expressionManagerNode.setExpressionLayoutNodes(new IExpressionLayoutNode[] { registerGroupNode }); - IVMLayoutNode registerNode = new RegisterLayoutNode(this, this, getSession(), syncDataAccess); + + /* + * The expression view wants to support fully all of the components of the register view. + */ + IExpressionLayoutNode registerGroupNode = new RegisterGroupLayoutNode(this, getSession(), syncRegDataAccess); + IVMLayoutNode registerNode = new RegisterLayoutNode(this, this, getSession(), syncRegDataAccess); registerGroupNode.setChildNodes(new IVMLayoutNode[] { registerNode }); + + /* + * Create the local variables nodes next. They represent the first level shown in the view. + */ + IExpressionLayoutNode localsNode = new VariableLocalsLayoutNode(this, this, getSession(), syncvarDataAccess); + IVMLayoutNode subExpressioNode = new VariableSubExpressionsLayoutNode(this, getSession(), syncvarDataAccess); + localsNode.setChildNodes(new IVMLayoutNode[] { subExpressioNode }); + + /* + * Tell the expression node which subnodes it will directly support. It is very important + * that the variables node be the last in this chain. The model assumes that there is some + * form of metalanguage expression syntax which each of the nodes evaluates and decides if + * they are dealing with it or not. The variables node assumes that the expression is fully + * qualified and there is no analysis or subdivision of the expression it will parse. So it + * it currently the case that the location of the nodes within the array being passed in is + * the order of search/evaluation. Thus variables wants to be last. Otherwise it would just + * assume what it was passed was for it and the real node which wants to handle it would be + * left out in the cold. + */ + expressionManagerNode.setExpressionLayoutNodes(new IExpressionLayoutNode[] { registerGroupNode, localsNode }); + + /* + * Let the work know which is the top level node. + */ setRootLayoutNode(debugViewSelectionNode); } diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/variable/SyncVariableDataAccess.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/variable/SyncVariableDataAccess.java new file mode 100644 index 00000000000..98cdf977268 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/variable/SyncVariableDataAccess.java @@ -0,0 +1,487 @@ +/* + * SyncVariableDataAccess.java + * Created on May 22, 2007 + * + * Copyright 2007 Wind River Systems Inc. All rights reserved. +*/ +package org.eclipse.dd.dsf.debug.ui.viewmodel.variable; + +import java.util.concurrent.ExecutionException; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.DsfExecutor; +import org.eclipse.dd.dsf.concurrent.Query; +import org.eclipse.dd.dsf.concurrent.ThreadSafeAndProhibitedFromDsfExecutor; +import org.eclipse.dd.dsf.debug.service.IExpressions; +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMContext; +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMData; +import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMContext; +import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMData; +import org.eclipse.dd.dsf.debug.service.IFormattedValues.IFormattedDataDMContext; +import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.service.IDsfService; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.util.tracker.ServiceTracker; + +@ThreadSafeAndProhibitedFromDsfExecutor("") +public class SyncVariableDataAccess { + + /** + * Need to use the OSGi service tracker here (instead of DsfServiceTracker), + * because we're accessing it in non-dispatch thread. DsfServiceTracker is + * not thread-safe. + */ + private ServiceTracker fServiceTracker; + + private synchronized IExpressions getService(String filter) { + + if (fServiceTracker == null) { + try { + fServiceTracker = new ServiceTracker(DsfDebugUIPlugin + .getBundleContext(), DsfDebugUIPlugin.getBundleContext() + .createFilter(filter), null); + fServiceTracker.open(); + } catch (InvalidSyntaxException e) { + assert false : "Invalid filter in DMC: " + filter; //$NON-NLS-1$ + return null; + } + } else { + /* + * All of the DMCs that this cell modifier is invoked for should + * originate from the same service. This assertion checks this + * assumption by comparing the service reference in the tracker to + * the filter string in the DMC. + */ + try { + assert DsfDebugUIPlugin.getBundleContext().createFilter(filter) + .match(fServiceTracker.getServiceReference()); + } catch (InvalidSyntaxException e) { + } + } + return (IExpressions) fServiceTracker.getService(); + } + + public void dispose() { + if (fServiceTracker != null) { + fServiceTracker.close(); + } + } + + public IExpressionDMContext getVariableDMC(Object element) { + if (element instanceof IAdaptable) { + return (IExpressionDMContext) ((IAdaptable) element).getAdapter(IExpressionDMContext.class); + } + return null; + } + + + public class GetVariableValueQuery extends Query { + + private IExpressionDMContext fDmc; + + public GetVariableValueQuery(DsfExecutor executor, IExpressionDMContext dmc) { + super(executor); + fDmc = dmc; + } + + @Override + protected void execute(final DataRequestMonitor rm) { + /* + * Guard agains the session being disposed. If session is disposed + * it could mean that the executor is shut-down, which in turn could + * mean that we can't complete the RequestMonitor argument. in that + * case, cancel to notify waiting thread. + */ + final DsfSession session = DsfSession.getSession(fDmc.getSessionId()); + if (session == null) { + cancel(false); + return; + } + + IExpressions service = getService(fDmc.getServiceFilter()); + if (service == null) { + rm.setStatus(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, IDsfService.INVALID_STATE, "Service not available", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + service.getModelData(fDmc, new DataRequestMonitor(session.getExecutor(), rm) { + @Override + protected void handleCompleted() { + /* + * We're in another dispatch, so we must guard against + * executor shutdown again. + */ + if (!DsfSession.isSessionActive(session.getId())) { + GetVariableValueQuery.this.cancel(false); + return; + } + super.handleCompleted(); + } + + @Override + protected void handleOK() { + /* + * All good set return value. + */ + rm.setData(getData()); + rm.done(); + } + }); + } + } + + public IExpressionDMContext getExpressionDMC(Object element) { + if (element instanceof IAdaptable) { + return (IExpressionDMContext) ((IAdaptable) element).getAdapter(IExpressionDMContext.class); + } + return null; + } + + public IExpressionDMData readVariable(Object element) { + /* + * Get the DMC and the session. If element is not an register DMC, or + * session is stale, then bail out. + */ + IExpressionDMContext dmc = getExpressionDMC(element); + if (dmc == null) return null; + DsfSession session = DsfSession.getSession(dmc.getSessionId()); + if (session == null) return null; + + /* + * Create the query to request the value from service. Note: no need to + * guard agains RejectedExecutionException, because + * DsfSession.getSession() above would only return an active session. + */ + GetVariableValueQuery query = new GetVariableValueQuery(session.getExecutor(), dmc); + session.getExecutor().execute(query); + + /* + * Now we have the data, go and get it. Since the call is completed now + * the ".get()" will not suspend it will immediately return with the + * data. + */ + try { + return query.get(); + } catch (InterruptedException e) { + assert false; + return null; + } catch (ExecutionException e) { + return null; + } + } + + public class SetVariableValueQuery extends Query { + + private IExpressionDMContext fDmc; + private String fValue; + private String fFormatId; + + public SetVariableValueQuery(DsfExecutor executor, IExpressionDMContext dmc, String value, String formatId) { + super(executor); + fDmc = dmc; + fValue = value; + fFormatId = formatId; + } + + @Override + protected void execute(final DataRequestMonitor rm) { + /* + * We're in another dispatch, so we must guard against executor + * shutdown again. + */ + final DsfSession session = DsfSession.getSession(fDmc.getSessionId()); + if (session == null) { + cancel(false); + return; + } + + /* + * Guard against a disposed service + */ + IExpressions service = getService(fDmc.getServiceFilter()); + if (service == null) { + rm.setStatus(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, IDsfService.INVALID_STATE, "Service unavailable", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + /* + * Write the bit field using a string/format style. + */ + service.writeExpression( + fDmc, + fValue, + fFormatId, + new DataRequestMonitor(session.getExecutor(), rm) { + @Override + protected void handleCompleted() { + /* + * We're in another dispatch, so we must guard + * against executor shutdown again. + */ + if (!DsfSession.isSessionActive(session.getId())) { + SetVariableValueQuery.this.cancel(false); + return; + } + super.handleCompleted(); + } + + @Override + protected void handleOK() { + /* + * All good set return value. + */ + rm.setData(new Object()); + rm.done(); + } + } + ); + } + } + + public void writeVariable(Object element, String value, String formatId) { + + /* + * Get the DMC and the session. If element is not an register DMC, or + * session is stale, then bail out. + */ + IExpressionDMContext dmc = getExpressionDMC(element); + if (dmc == null) return; + DsfSession session = DsfSession.getSession(dmc.getSessionId()); + if (session == null) return; + + /* + * Create the query to write the value to the service. Note: no need to + * guard agains RejectedExecutionException, because + * DsfSession.getSession() above would only return an active session. + */ + SetVariableValueQuery query = new SetVariableValueQuery(session.getExecutor(), dmc, value, formatId); + session.getExecutor().execute(query); + + /* + * Now we have the data, go and get it. Since the call is completed now + * the ".get()" will not suspend it will immediately return with the + * data. + */ + try { + /* + * Return value is irrelevant, any error would come through with an + * exception. + */ + query.get(); + } catch (InterruptedException e) { + assert false; + } catch (ExecutionException e) { + /* + * View must be shutting down, no need to show error dialog. + */ + } + } + + public IFormattedDataDMContext getFormattedDMC(Object element) { + if (element instanceof IAdaptable) { + return (IFormattedDataDMContext) ((IAdaptable) element).getAdapter(IFormattedDataDMContext.class); + } + return null; + } + + public class GetSupportFormatsValueQuery extends Query { + + IFormattedDataDMContext fDmc; + + public GetSupportFormatsValueQuery(DsfExecutor executor, IFormattedDataDMContext dmc) { + super(executor); + fDmc = dmc; + } + + @Override + protected void execute(final DataRequestMonitor rm) { + /* + * We're in another dispatch, so we must guard against executor + * shutdown again. + */ + final DsfSession session = DsfSession.getSession(fDmc.getSessionId()); + if (session == null) { + cancel(false); + return; + } + + /* + * Guard against a disposed service + */ + IExpressions service = getService(fDmc.getServiceFilter()); + if (service == null) { + rm.setStatus(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, IDsfService.INVALID_STATE, "Service unavailable", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + /* + * Write the bit field using a string/format style. + */ + service.getAvailableFormattedValues( + fDmc, + new DataRequestMonitor(session.getExecutor(), rm) { + @Override + protected void handleCompleted() { + /* + * We're in another dispatch, so we must + * guard against executor shutdown again. + */ + if (!DsfSession.isSessionActive(session.getId())) { + GetSupportFormatsValueQuery.this.cancel(false); + return; + } + super.handleCompleted(); + } + + @Override + protected void handleOK() { + /* + * All good set return value. + */ + rm.setData(new Object()); + rm.done(); + } + } + ); + } + } + + public String[] getSupportedFormats(Object element) { + + /* + * Get the DMC and the session. If element is not an register DMC, or + * session is stale, then bail out. + */ + IFormattedDataDMContext dmc = getFormattedDMC(element); + if (dmc == null) return null; + DsfSession session = DsfSession.getSession(dmc.getSessionId()); + if (session == null) return null; + + /* + * Create the query to write the value to the service. Note: no need to + * guard agains RejectedExecutionException, because + * DsfSession.getSession() above would only return an active session. + */ + GetSupportFormatsValueQuery query = new GetSupportFormatsValueQuery(session.getExecutor(), dmc); + session.getExecutor().execute(query); + + /* + * Now we have the data, go and get it. Since the call is completed now + * the ".get()" will not suspend it will immediately return with the + * data. + */ + try { + return (String[]) query.get(); + } catch (InterruptedException e) { + assert false; + return null; + } catch (ExecutionException e) { + return null; + } + } + + public class GetFormattedValueValueQuery extends Query { + + private IFormattedDataDMContext fDmc; + private String fFormatId; + + public GetFormattedValueValueQuery(DsfExecutor executor, IFormattedDataDMContext dmc, String formatId) { + super(executor); + fDmc = dmc; + fFormatId = formatId; + } + + @Override + protected void execute(final DataRequestMonitor rm) { + /* + * We're in another dispatch, so we must guard against executor + * shutdown again. + */ + final DsfSession session = DsfSession.getSession(fDmc.getSessionId()); + if (session == null) { + cancel(false); + return; + } + + /* + * Guard against a disposed service + */ + IExpressions service = getService(fDmc.getServiceFilter()); + if (service == null) { + rm .setStatus(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, IDsfService.INVALID_STATE, "Service unavailable", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + /* + * Convert to the proper formatting DMC then go get the formatted value. + */ + + FormattedValueDMContext formDmc = service.getFormattedValue(fDmc, fFormatId); + + service.getModelData(formDmc, new DataRequestMonitor(session.getExecutor(), rm) { + @Override + protected void handleCompleted() { + /* + * We're in another dispatch, so we must guard against executor shutdown again. + */ + if (!DsfSession.isSessionActive(session.getId())) { + GetFormattedValueValueQuery.this.cancel(false); + return; + } + super.handleCompleted(); + } + + @Override + protected void handleOK() { + /* + * All good set return value. + */ + rm.setData(getData().getFormattedValue()); + rm.done(); + } + }); + } + } + + public String getFormattedValue(Object element, String formatId) { + + /* + * Get the DMC and the session. If element is not an register DMC, or + * session is stale, then bail out. + */ + IFormattedDataDMContext dmc = getFormattedDMC(element); + if (dmc == null) return null; + DsfSession session = DsfSession.getSession(dmc.getSessionId()); + if (session == null) return null; + + /* + * Create the query to write the value to the service. Note: no need to + * guard agains RejectedExecutionException, because + * DsfSession.getSession() above would only return an active session. + */ + GetFormattedValueValueQuery query = new GetFormattedValueValueQuery(session.getExecutor(), dmc, formatId); + session.getExecutor().execute(query); + + /* + * Now we have the data, go and get it. Since the call is completed now + * the ".get()" will not suspend it will immediately return with the + * data. + */ + try { + return (String) query.get(); + } catch (InterruptedException e) { + assert false; + return null; + } catch (ExecutionException e) { + return null; + } + } +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/variable/VariableLayoutValueCellModifier.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/variable/VariableLayoutValueCellModifier.java new file mode 100644 index 00000000000..ab3a27ac600 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/variable/VariableLayoutValueCellModifier.java @@ -0,0 +1,91 @@ +/* + * VariableLayoutValueCellModifier.java + * Created on May 22, 2007 + * + * Copyright 2007 Wind River Systems Inc. All rights reserved. +*/ +package org.eclipse.dd.dsf.debug.ui.viewmodel.variable; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMContext; +import org.eclipse.dd.dsf.debug.ui.viewmodel.IDebugVMConstants; +import org.eclipse.dd.dsf.debug.ui.viewmodel.expression.WatchExpressionCellModifier; +import org.eclipse.dd.dsf.debug.ui.viewmodel.formatsupport.IFormattedValuePreferenceStore; + +public class VariableLayoutValueCellModifier extends WatchExpressionCellModifier { + + private SyncVariableDataAccess fDataAccess = null; + private IFormattedValuePreferenceStore fFormattedValuePreferenceStore; + + public VariableLayoutValueCellModifier(IFormattedValuePreferenceStore formattedValuePreferenceStore, SyncVariableDataAccess access) { + fDataAccess = access; + fFormattedValuePreferenceStore = formattedValuePreferenceStore; + } + + /* + * Used to make sure we are dealing with a valid variable. + */ + private IExpressionDMContext getVariableDMC(Object element) { + if (element instanceof IAdaptable) { + return (IExpressionDMContext)((IAdaptable)element).getAdapter(IExpressionDMContext.class); + } + return null; + } + + @Override + public boolean canModify(Object element, String property) { + // If we're in the column value, modify the register data. Otherwise, call the super-class to edit + // the watch expression. + + if (IDebugVMConstants.COLUMN_ID__VALUE.equals(property)) { + // Make sure we are are dealing with a valid set of information. + + if (getVariableDMC(element) == null) + return false; + + return true ; + } + + return super.canModify(element, property); + } + + @Override + public Object getValue(Object element, String property) { + // If we're in the column value, modify the variable value. Otherwise, call the super-class to edit + // the watch expression. + + if (IDebugVMConstants.COLUMN_ID__VALUE.equals(property)) { + // Make sure we are working on the editable areas. + + // Write the value in the currently requested format. Since they could + // have freeformed typed in any format this is just a guess and may not + // really accomplish anything. + + String value = fDataAccess.getFormattedValue(element, fFormattedValuePreferenceStore.getDefaultFormatId()); + + if (value == null) + return "..."; //$NON-NLS-1$ + + return value; + } + + return super.getValue(element, property); + } + + @Override + public void modify(Object element, String property, Object value) { + // If we're in the column value, modify the register data. Otherwise, call the super-class to edit + // the watch expression. + + if (IDebugVMConstants.COLUMN_ID__VALUE.equals(property)) { + if (value instanceof String) { + // PREFPAGE : We are using a default format until the preference page is created. + fDataAccess.writeVariable(element, (String) value, fFormattedValuePreferenceStore.getDefaultFormatId()); + } + } + else { + super.modify(element, property, value); + } + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/variable/VariableLocalsLayoutNode.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/variable/VariableLocalsLayoutNode.java index 815b71281d9..03edcdbd631 100644 --- a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/variable/VariableLocalsLayoutNode.java +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/variable/VariableLocalsLayoutNode.java @@ -12,10 +12,12 @@ package org.eclipse.dd.dsf.debug.ui.viewmodel.variable; import java.util.ArrayList; import java.util.List; +import org.eclipse.core.runtime.CoreException; import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; import org.eclipse.dd.dsf.concurrent.DsfExecutor; import org.eclipse.dd.dsf.concurrent.MultiRequestMonitor; import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.datamodel.IDMContext; import org.eclipse.dd.dsf.datamodel.IDMEvent; import org.eclipse.dd.dsf.datamodel.IDMService; import org.eclipse.dd.dsf.debug.service.IExpressions; @@ -30,23 +32,130 @@ import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext; import org.eclipse.dd.dsf.debug.service.IStack.IVariableDMContext; import org.eclipse.dd.dsf.debug.service.IStack.IVariableDMData; +import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin; import org.eclipse.dd.dsf.debug.ui.viewmodel.IDebugVMConstants; +import org.eclipse.dd.dsf.debug.ui.viewmodel.expression.AbstractExpressionLayoutNode; +import org.eclipse.dd.dsf.debug.ui.viewmodel.formatsupport.IFormattedValuePreferenceStore; +import org.eclipse.dd.dsf.debug.ui.viewmodel.formatsupport.IFormattedValueVMContext; import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.dsf.service.IDsfService; import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMProvider; +import org.eclipse.dd.dsf.ui.viewmodel.IVMContext; import org.eclipse.dd.dsf.ui.viewmodel.VMDelta; -import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.IExpression; +import org.eclipse.debug.core.model.IValue; +import org.eclipse.debug.core.model.IVariable; import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor; import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; +import org.eclipse.debug.ui.actions.IWatchExpressionFactoryAdapterExtension; +import org.eclipse.jface.viewers.CellEditor; +import org.eclipse.jface.viewers.ICellModifier; +import org.eclipse.jface.viewers.TextCellEditor; +import org.eclipse.swt.widgets.Composite; @SuppressWarnings({"restriction", "nls"}) -public class VariableLocalsLayoutNode extends AbstractDMVMLayoutNode { +public class VariableLocalsLayoutNode extends AbstractExpressionLayoutNode implements IElementEditor { + private final IFormattedValuePreferenceStore fFormattedPrefStore; + + private final SyncVariableDataAccess fSyncVariableDataAccess; + + protected class VariableLocalsVMC extends DMVMContext implements IFormattedValueVMContext, IVariable { + + private IExpression fExpression; + + public VariableLocalsVMC(IDMContext dmc) { + super(dmc); + } - public VariableLocalsLayoutNode(AbstractVMProvider provider, DsfSession session) { - super(provider, session, IExpressions.IExpressionDMContext.class); + public IFormattedValuePreferenceStore getPreferenceStore() { + return fFormattedPrefStore; + } + + public void setExpression(IExpression expression) { + fExpression = expression; + } + + @Override + @SuppressWarnings("unchecked") + public Object getAdapter(Class adapter) { + if (fExpression != null && adapter.isAssignableFrom(fExpression.getClass())) { + return fExpression; + } else if (adapter.isAssignableFrom(IWatchExpressionFactoryAdapterExtension.class)) { + return fVariableLocalsExpressionFactory; + } else { + return super.getAdapter(adapter); + } + } + + @Override + public boolean equals(Object other) { + if (other instanceof VariableLocalsVMC && super.equals(other)) { + VariableLocalsVMC otherGroup = (VariableLocalsVMC)other; + return (otherGroup.fExpression == null && fExpression == null) || + (otherGroup.fExpression != null && otherGroup.fExpression.equals(fExpression)); + } + return false; + } + + @Override + public int hashCode() { + return super.hashCode() + (fExpression != null ? fExpression.hashCode() : 0); + } + + public String getName() throws DebugException { return toString(); } + public String getReferenceTypeName() throws DebugException { return ""; } //$NON-NLS-1$ + public IValue getValue() throws DebugException { return null; } + public boolean hasValueChanged() throws DebugException { return false; } + public void setValue(IValue value) throws DebugException {} + public void setValue(String expression) throws DebugException {} + public boolean supportsValueModification() { return false; } + public boolean verifyValue(IValue value) throws DebugException { return false; } + public boolean verifyValue(String expression) throws DebugException { return false; } + public IDebugTarget getDebugTarget() { return null;} + public ILaunch getLaunch() { return null; } + public String getModelIdentifier() { return DsfDebugUIPlugin.PLUGIN_ID; } + } + + protected class VariableLocalsExpressionFactory implements IWatchExpressionFactoryAdapterExtension { + + public boolean canCreateWatchExpression(IVariable variable) { + return variable instanceof VariableLocalsVMC; + } + + public String createWatchExpression(IVariable variable) throws CoreException { + + //VariableLocalsVMC registerVmc = ((VariableLocalsVMC)variable); + + /* + * This needs to be completed by filling in the fully qualified expression. + * Currently the ExpressionDMC does not support that. This will be changed + * shortly. For now I am creating a bugzilla about this not being complete + * and checking this in. + */ + return null; + } } + final protected VariableLocalsExpressionFactory fVariableLocalsExpressionFactory = new VariableLocalsExpressionFactory(); + + public VariableLocalsLayoutNode(IFormattedValuePreferenceStore prefStore, AbstractVMProvider provider, + DsfSession session, SyncVariableDataAccess syncVariableDataAccess) { + super(provider, session, IExpressions.IExpressionDMContext.class); + fFormattedPrefStore = prefStore; + fSyncVariableDataAccess = syncVariableDataAccess; + } + + @Override + protected IVMContext createVMContext(IDMContext dmc) { + return new VariableLocalsVMC(dmc); + } + /** * We override this method because we now need to perform an extra level of data fetch to get the * formatted value of the expression. @@ -97,6 +206,8 @@ public class VariableLocalsLayoutNode extends AbstractDMVMLayoutNode rm) { + /* + * Since we are overriding "getElementForExpression" we do not need to do anything here. But + * we are forced to supply this routine because it is abstract in the extending class. + */ + } + + public int getExpressionLength(String expression) { + /* + * Since we are overriding "getElementForExpression" we do not need to do anything here. + * We just assume the entire expression is for us. + */ + return expression.length() ; + } } diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/variable/VariableSubExpressionsLayoutNode.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/variable/VariableSubExpressionsLayoutNode.java index e31de76dfcc..9b9a8984a70 100644 --- a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/variable/VariableSubExpressionsLayoutNode.java +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/variable/VariableSubExpressionsLayoutNode.java @@ -40,9 +40,12 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; @SuppressWarnings("restriction") public class VariableSubExpressionsLayoutNode extends AbstractDMVMLayoutNode { + + private SyncVariableDataAccess fSyncVariableDataAccess; - public VariableSubExpressionsLayoutNode(AbstractVMProvider provider, DsfSession session) { + public VariableSubExpressionsLayoutNode(AbstractVMProvider provider, DsfSession session, SyncVariableDataAccess syncVariableDataAccess) { super(provider, session, IExpressions.IExpressionDMContext.class); + fSyncVariableDataAccess = syncVariableDataAccess; } /** diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/variable/VariableVMProvider.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/variable/VariableVMProvider.java index 9b0ed88eeb4..e8c0001aa37 100644 --- a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/variable/VariableVMProvider.java +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/variable/VariableVMProvider.java @@ -8,7 +8,9 @@ */ package org.eclipse.dd.dsf.debug.ui.viewmodel.variable; +import org.eclipse.dd.dsf.debug.service.IFormattedValues; import org.eclipse.dd.dsf.debug.ui.viewmodel.DebugViewSelectionRootLayoutNode; +import org.eclipse.dd.dsf.debug.ui.viewmodel.formatsupport.IFormattedValuePreferenceStore; import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter; import org.eclipse.dd.dsf.ui.viewmodel.IVMLayoutNode; @@ -20,11 +22,18 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationCont @SuppressWarnings("restriction") public class VariableVMProvider extends AbstractDMVMProvider implements - IColumnPresentationFactory { + IColumnPresentationFactory, IFormattedValuePreferenceStore { + + private String defaultFormatId = IFormattedValues.NATURAL_FORMAT; public VariableVMProvider(AbstractVMAdapter adapter, IPresentationContext context, DsfSession session) { super(adapter, context, session); - + + /* + * Create the variable data access routines. + */ + SyncVariableDataAccess varAccess = new SyncVariableDataAccess() ; + /* * Create the top level node to deal with the root selection. */ @@ -33,13 +42,13 @@ public class VariableVMProvider extends AbstractDMVMProvider implements /* * Create the local variables nodes next. They represent the first level shown in the view. */ - IVMLayoutNode localsNode = new VariableLocalsLayoutNode(this, getSession()); + IVMLayoutNode localsNode = new VariableLocalsLayoutNode(this, this, getSession(), varAccess); debugViewSelection.setChildNodes(new IVMLayoutNode[] { localsNode }); /* * Create the next level which represents members of structs/unions/enums and elements of arrays. */ - IVMLayoutNode subExpressioNode = new VariableSubExpressionsLayoutNode(this, getSession()); + IVMLayoutNode subExpressioNode = new VariableSubExpressionsLayoutNode(this, getSession(), varAccess); localsNode.setChildNodes(new IVMLayoutNode[] { subExpressioNode }); /* @@ -57,4 +66,20 @@ public class VariableVMProvider extends AbstractDMVMProvider implements public String getColumnPresentationId(IPresentationContext context, Object element) { return VariableColumnPresentation.ID; } + + /* + * (non-Javadoc) + * @see org.eclipse.dd.dsf.debug.ui.viewmodel.formatsupport.IFormattedValuePreferenceStore#getDefaultFormatId() + */ + public String getDefaultFormatId() { + return defaultFormatId; + } + + /* + * (non-Javadoc) + * @see org.eclipse.dd.dsf.debug.ui.viewmodel.formatsupport.IFormattedValuePreferenceStore#setDefaultFormatId(java.lang.String) + */ + public void setDefaultFormatId(String id) { + defaultFormatId = id; + } } diff --git a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IExpressions.java b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IExpressions.java index 6b76e046870..c4f2121246f 100644 --- a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IExpressions.java +++ b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IExpressions.java @@ -14,6 +14,7 @@ import java.util.Map; import org.eclipse.cdt.core.IAddress; import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; import org.eclipse.dd.dsf.datamodel.IDMContext; import org.eclipse.dd.dsf.datamodel.IDMData; import org.eclipse.dd.dsf.datamodel.IDMEvent; @@ -167,4 +168,17 @@ public interface IExpressions extends IDMService, IFormattedValues { * @param rm: Request completion monitor. */ void getBaseExpressions(IExpressionDMContext exprContext, DataRequestMonitor rm); + + /** + * This method supports the writing/modifying the value of the expression. + * + * @param expressionContext: The data model context representing an expression. + * + * @param expressionValue: The new value of the expression as a String. + * + * @param formatId: The format ID specifying the format of parameter expressionValue. + * + * @param rm: Request completion monitor. + */ + void writeExpression(IDMContext expressionContext, String exressionValue, String formatId, RequestMonitor rm); }