1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

[192019] View Model framework refactoring.

This commit is contained in:
Pawel Piech 2008-01-19 00:34:30 +00:00
parent 7cfa374584
commit 7d83b3a7dd
98 changed files with 5705 additions and 4532 deletions

View file

@ -25,7 +25,6 @@ Export-Package:
org.eclipse.dd.dsf.debug.ui.actions,
org.eclipse.dd.dsf.debug.ui.sourcelookup,
org.eclipse.dd.dsf.debug.ui.viewmodel,
org.eclipse.dd.dsf.debug.ui.viewmodel.dm,
org.eclipse.dd.dsf.debug.ui.viewmodel.expression,
org.eclipse.dd.dsf.debug.ui.viewmodel.launch,
org.eclipse.dd.dsf.debug.ui.viewmodel.modules,

View file

@ -2,6 +2,7 @@ source.. = src/
output.. = bin/
bin.includes = META-INF/,\
plugin.xml,\
plugin.properties,\
about.html,\
.,\
icons/

View file

@ -86,126 +86,23 @@
</action>
</viewContribution>
<viewContribution
id="org.eclipse.dd.dsf.debug.ui.update.UpdatePopup"
id="org.eclipse.dd.dsf.debug.ui.update.variable.updatePolicies"
targetID="org.eclipse.debug.ui.VariableView">
<menu
id="org.eclipse.dd.dsf.debug.ui.update.UpdateModeSubMenu"
label="Update Mode"
path="additions">
<groupMarker
name="content">
</groupMarker>
<separator
name="additions">
</separator>
</menu>
<action
class="org.eclipse.dd.dsf.debug.ui.viewmodel.update.actions.RefreshManualActionDelegate"
icon="icons/refreshmanual.gif"
id="org.eclipse.dd.dsf.debug.ui.update.registers.RefreshManual"
label="Manual"
menubarPath="org.eclipse.dd.dsf.debug.ui.update.UpdateModeSubMenu/content"
style="radio"
toolbarPath="additions">
</action>
<action
class="org.eclipse.dd.dsf.debug.ui.viewmodel.update.actions.RefreshOnBreakActionDelegate"
id="org.eclipse.dd.dsf.debug.ui.update.registers.RefreshOnBreak"
label="On Breakpoint Hit"
menubarPath="org.eclipse.dd.dsf.debug.ui.update.UpdateModeSubMenu/content"
style="radio">
</action>
<action
class="org.eclipse.dd.dsf.debug.ui.viewmodel.update.actions.RefreshAlwaysActionDelegate"
icon="icons/refreshalways.gif"
id="org.eclipse.dd.dsf.debug.ui.update.registers.RefreshAlways"
label="Always"
menubarPath="org.eclipse.dd.dsf.debug.ui.update.UpdateModeSubMenu/content"
state="true"
style="radio"
toolbarPath="additions">
class="org.eclipse.dd.dsf.debug.ui.viewmodel.update.actions.SelectUpdatePolicyAction"
id="org.eclipse.dd.dsf.debug.ui.update.selectUpdatePolicy"
label="Update Policy"
menubarPath="additions">
</action>
</viewContribution>
<viewContribution
id="org.eclipse.dd.dsf.debug.ui.update.UpdatePopup"
targetID="org.eclipse.debug.ui.ExpressionView">
<menu
id="org.eclipse.dd.dsf.debug.ui.update.UpdateModeSubMenu"
label="Update Mode"
path="additions">
<groupMarker
name="content">
</groupMarker>
<separator
name="additions">
</separator>
</menu>
<action
class="org.eclipse.dd.dsf.debug.ui.viewmodel.update.actions.RefreshManualActionDelegate"
icon="icons/refreshmanual.gif"
id="org.eclipse.dd.dsf.debug.ui.update.registers.RefreshManual"
label="Manual"
menubarPath="org.eclipse.dd.dsf.debug.ui.update.UpdateModeSubMenu/content"
style="radio"
toolbarPath="additions">
</action>
<action
class="org.eclipse.dd.dsf.debug.ui.viewmodel.update.actions.RefreshOnBreakActionDelegate"
id="org.eclipse.dd.dsf.debug.ui.update.registers.RefreshOnBreak"
label="On Breakpoint Hit"
menubarPath="org.eclipse.dd.dsf.debug.ui.update.UpdateModeSubMenu/content"
style="radio">
</action>
<action
class="org.eclipse.dd.dsf.debug.ui.viewmodel.update.actions.RefreshAlwaysActionDelegate"
icon="icons/refreshalways.gif"
id="org.eclipse.dd.dsf.debug.ui.update.registers.RefreshAlways"
label="Always"
menubarPath="org.eclipse.dd.dsf.debug.ui.update.UpdateModeSubMenu/content"
state="true"
style="radio"
toolbarPath="additions">
</action>
</viewContribution>
<viewContribution
id="org.eclipse.dd.dsf.debug.ui.update.UpdatePopup"
id="org.eclipse.dd.dsf.debug.ui.update.register.updatePolicies"
targetID="org.eclipse.debug.ui.RegisterView">
<menu
id="org.eclipse.dd.dsf.debug.ui.update.UpdateModeSubMenu"
label="Update Mode"
path="additions">
<groupMarker
name="content">
</groupMarker>
<separator
name="additions">
</separator>
</menu>
<action
class="org.eclipse.dd.dsf.debug.ui.viewmodel.update.actions.RefreshManualActionDelegate"
icon="icons/refreshmanual.gif"
id="org.eclipse.dd.dsf.debug.ui.update.registers.RefreshManual"
label="Manual"
menubarPath="org.eclipse.dd.dsf.debug.ui.update.UpdateModeSubMenu/content"
style="radio"
toolbarPath="additions">
</action>
<action
class="org.eclipse.dd.dsf.debug.ui.viewmodel.update.actions.RefreshOnBreakActionDelegate"
id="org.eclipse.dd.dsf.debug.ui.update.registers.RefreshOnBreak"
label="On Breakpoint Hit"
menubarPath="org.eclipse.dd.dsf.debug.ui.update.UpdateModeSubMenu/content"
style="radio">
</action>
<action
class="org.eclipse.dd.dsf.debug.ui.viewmodel.update.actions.RefreshAlwaysActionDelegate"
icon="icons/refreshalways.gif"
id="org.eclipse.dd.dsf.debug.ui.update.registers.RefreshAlways"
label="Always"
menubarPath="org.eclipse.dd.dsf.debug.ui.update.UpdateModeSubMenu/content"
state="true"
style="radio"
toolbarPath="additions">
class="org.eclipse.dd.dsf.debug.ui.viewmodel.update.actions.SelectUpdatePolicyAction"
id="org.eclipse.dd.dsf.debug.ui.update.selectUpdatePolicy"
label="Update Policy"
menubarPath="additions">
</action>
</viewContribution>
</extension>

View file

@ -20,11 +20,9 @@ import org.eclipse.dd.dsf.debug.service.IStepQueueManager;
import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext;
import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin;
import org.eclipse.dd.dsf.service.DsfServicesTracker;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode.DMVMContext;
import org.eclipse.dd.dsf.ui.viewmodel.dm.IDMVMContext;
import org.eclipse.debug.core.commands.IDebugCommandRequest;
@SuppressWarnings("restriction")
@Immutable
public abstract class DsfCommandRunnable extends DsfRunnable {
private final IExecutionDMContext fContext;
@ -41,12 +39,9 @@ public abstract class DsfCommandRunnable extends DsfRunnable {
public DsfCommandRunnable(DsfServicesTracker servicesTracker, Object element, IDebugCommandRequest request) {
fTracker = servicesTracker;
if (element instanceof DMVMContext) {
// Javac doesn't like the cast to "(AbstractDMVMLayoutNode<?>.DMVMContext)" need to use the
// construct below and suppress warnings.
@SuppressWarnings("unchecked")
AbstractDMVMLayoutNode.DMVMContext vmc = (AbstractDMVMLayoutNode.DMVMContext)element;
fContext = DMContexts.getAncestorOfType(vmc.getDMC(), IExecutionDMContext.class);
if (element instanceof IDMVMContext) {
IDMVMContext vmc = (IDMVMContext)element;
fContext = DMContexts.getAncestorOfType(vmc.getDMContext(), IExecutionDMContext.class);
} else {
fContext = null;
}

View file

@ -40,7 +40,7 @@ import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin;
import org.eclipse.dd.dsf.service.DsfServiceEventHandler;
import org.eclipse.dd.dsf.service.DsfServicesTracker;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode.DMVMContext;
import org.eclipse.dd.dsf.ui.viewmodel.dm.IDMVMContext;
import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;
import org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant;
import org.eclipse.debug.ui.IDebugUIConstants;
@ -81,7 +81,6 @@ import org.eclipse.ui.texteditor.ITextEditor;
* dispatch thread to synchronize access to the state data of the running jobs.
*/
@ThreadSafe
@SuppressWarnings("restriction")
public class MISourceDisplayAdapter implements ISourceDisplay
{
/**
@ -427,10 +426,8 @@ public class MISourceDisplayAdapter implements ISourceDisplay
* @see org.eclipse.debug.ui.contexts.ISourceDisplayAdapter#displaySource(java.lang.Object, org.eclipse.ui.IWorkbenchPage, boolean)
*/
public void displaySource(Object context, final IWorkbenchPage page, final boolean force) {
if (!(context instanceof DMVMContext)) return;
// Correct cast: (AbstractDMVMLayoutNode<?>.DMVMContext) breaks the javac compiler
@SuppressWarnings("unchecked")
final IDMContext dmc = ((DMVMContext)context).getDMC();
if (!(context instanceof IDMVMContext)) return;
final IDMContext dmc = ((IDMVMContext)context).getDMContext();
// Quick test. DMC is checked again in source lookup participant, but
// it's much quicker to test here.

View file

@ -0,0 +1,104 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Ted R Williams (Wind River Systems, Inc.) - initial implementation
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.actions;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.dd.dsf.ui.viewmodel.IVMAdapter;
import org.eclipse.dd.dsf.ui.viewmodel.IVMProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
import org.eclipse.debug.ui.AbstractDebugView;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.contexts.DebugContextEvent;
import org.eclipse.debug.ui.contexts.IDebugContextListener;
import org.eclipse.debug.ui.contexts.IDebugContextService;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.widgets.Event;
import org.eclipse.ui.IActionDelegate2;
import org.eclipse.ui.IViewActionDelegate;
import org.eclipse.ui.IViewPart;
@SuppressWarnings("restriction")
abstract public class AbstractVMProviderActionDelegate implements IViewActionDelegate, IDebugContextListener, IActionDelegate2 {
private IViewPart fView = null;
private IAction fAction = null;
private ISelection fDebugContext;
public void init(IViewPart view) {
fView = view;
// Get the current selection from the DebugView so we can determine if we want this menu action to be live or not.
IDebugContextService debugContextService = DebugUITools.getDebugContextManager().getContextService(view.getSite().getWorkbenchWindow());
debugContextService.addPostDebugContextListener(this);
fDebugContext = debugContextService.getActiveContext();
}
public void selectionChanged(IAction action, ISelection selection) {
if (fAction != action) {
fAction = action;
}
}
public void runWithEvent(IAction action, Event event) {
run(action);
}
public void init(IAction action) {
fAction = action;
}
public void dispose() {
DebugUITools.getDebugContextManager().getContextService(getView().getSite().getWorkbenchWindow()).removePostDebugContextListener(this);
}
public void debugContextChanged(DebugContextEvent event) {
fDebugContext = event.getContext();
}
protected IViewPart getView() { return fView; }
protected IAction getAction() { return fAction; }
protected Object getViewerInput() {
if (fDebugContext instanceof IStructuredSelection) {
return ((IStructuredSelection)fDebugContext).getFirstElement();
}
return null;
}
protected IVMProvider getVMProvider() {
Object viewerInput = getViewerInput();
IPresentationContext presentationContext = getPresentationContext();
if (viewerInput instanceof IAdaptable && presentationContext != null) {
IVMAdapter adapter = (IVMAdapter) ((IAdaptable)viewerInput).getAdapter(IVMAdapter.class);
if ( adapter != null ) {
return adapter.getVMProvider(presentationContext);
}
}
return null;
}
protected IPresentationContext getPresentationContext() {
if (fView instanceof AbstractDebugView &&
((AbstractDebugView) fView).getViewer() instanceof TreeModelViewer)
{
return ((TreeModelViewer) ((AbstractDebugView) fView).getViewer()).getPresentationContext();
}
return null;
}
}

View file

@ -1,44 +0,0 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Ted R Williams (Wind River Systems, Inc.) - initial implementation
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.dm;
import org.eclipse.dd.dsf.debug.ui.viewmodel.update.VMCacheRefreshAlways;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMProviderWithCache;
import org.eclipse.dd.dsf.ui.viewmodel.update.VMCacheManager;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
/*
* The purpose of this class is to satisfy package structure requirements while enabling VM update modes.
* The non-debug centric VMCacheManager and VMCache live under org.eclipse.dd.dsf.*. The debug data view
* caches (VMCacheRefreshAlways/Manual/OnBreak) live under org.eclipse.dd.dsf.debug.* because of their
* awareness of debug specific events. There is a need to instantiate a default (always) cache on view
* startup. AbstractDMVMProviderWithCache would be a good place to accomplish this task, but like the
* VMCacheManager, this class cannot access the *dsf.debug* VMCacheRefreshAlways. AbstractDebugDMVMProviderWithCache
* is meant to solve this problem.
*/
@SuppressWarnings("restriction")
public class AbstractDebugDMVMProviderWithCache extends
AbstractDMVMProviderWithCache
{
public AbstractDebugDMVMProviderWithCache(AbstractVMAdapter adapter, IPresentationContext presentationContext, DsfSession session) {
super(adapter, presentationContext, session);
VMCacheManager.getVMCacheManager().registerCache(presentationContext, new VMCacheRefreshAlways());
}
}

View file

@ -1,305 +0,0 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.expression;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
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.debug.ui.DsfDebugUIPlugin;
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.IVMLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
import org.eclipse.dd.dsf.ui.viewmodel.VMElementsUpdate;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode;
import org.eclipse.debug.core.model.IExpression;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.jface.viewers.TreePath;
/**
*
*/
@SuppressWarnings("restriction")
public abstract class AbstractExpressionLayoutNode extends AbstractDMVMLayoutNode
implements IExpressionLayoutNode
{
public AbstractExpressionLayoutNode(AbstractVMProvider provider, DsfSession session, Class<? extends IDMContext> dmcClassType) {
super(provider, session, dmcClassType);
}
public void getElementForExpression(final IChildrenUpdate update, final String expressionText, final IExpression expression) {
final int exprLength = getExpressionLength(expressionText);
if (exprLength < 0) {
update.setStatus(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, "Invalid expression", null)); //$NON-NLS-1$
update.done();
return;
}
final String nodeExpressionText = exprLength > 0 ? expressionText.substring(0, exprLength) : expressionText;
getElementForExpressionPart(
update, nodeExpressionText,
new DataRequestMonitor<Object>(getExecutor(), null) {
@Override
protected void handleOK() {
/**
* If the current expression is the whole expression from the argument,
* return the VMC. Otherwise, call the child nodes to continue evaluating
* the expression.
*/
if (exprLength == expressionText.length()) {
Object element = getData();
associateExpression(element, expression);
update.setChild(element, 0);
update.done();
} else {
getVMContextForExpressionFromChildNodes(
update, getData(), expressionText.substring(exprLength), expression);
}
}
@Override
protected void handleErrorOrCancel() {
update.setStatus(getStatus());
update.done();
}
});
}
protected void getElementForExpressionPart(final IChildrenUpdate update, final String expressionPartText, final DataRequestMonitor<Object> rm) {
updateElements(new VMElementsUpdate(
update, -1, -1,
new DataRequestMonitor<List<Object>>(getExecutor(), rm) {
@Override
protected void handleOK() {
if (getData().size() == 0) {
rm.setStatus(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, "No contexts", null)); //$NON-NLS-1$
rm.done();
} else {
final List<Object> elements = getData();
final MultiRequestMonitor<DataRequestMonitor<Boolean>> multiRm = new MultiRequestMonitor<DataRequestMonitor<Boolean>>(getExecutor(), rm) {
@Override
protected void handleOK() {
boolean foundMatchingContext = false;
for (int i = 0; i < getRequestMonitors().size(); i++) {
if (getRequestMonitors().get(i).getData()) {
rm.setData(elements.get(i));
foundMatchingContext = true;
break;
}
}
if (!foundMatchingContext) {
rm.setStatus(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, "Context not found", null)); //$NON-NLS-1$
}
rm.done();
}
};
for (Object element : elements) {
testContextForExpression(
element, expressionPartText,
multiRm.add(
new DataRequestMonitor<Boolean>(getExecutor(), null) {
@Override
protected void handleCompleted() {
multiRm.requestMonitorDone(this);
}
}));
}
}
}
@Override
protected void handleErrorOrCancel() {
update.setStatus(getStatus());
update.done();
}
})
);
}
@ConfinedToDsfExecutor("#getSession#getExecutor")
protected abstract void testContextForExpression(Object element, final String expression, final DataRequestMonitor<Boolean> rm);
protected abstract void associateExpression(Object element, IExpression expression);
protected void getVMContextForExpressionFromChildNodes(final IChildrenUpdate update, Object parentElement, String childExpression, IExpression expression) {
IChildrenUpdate childUpdate = new ChildExpressionElementUpdate(
update, update.getElementPath().createChildPath(parentElement),
new DataRequestMonitor<List<Object>>(getExecutor(), null) {
@Override
protected void handleOK() {
update.setChild(getData().get(0), 0);
update.done();
}
@Override
protected void handleErrorOrCancel() {
update.setStatus(getStatus());
update.done();
}
});
for (int i = 0; i < getChildLayoutNodes().length; i++) {
if (getChildLayoutNodes()[i] instanceof IExpressionLayoutNode) {
IExpressionLayoutNode childNode = (IExpressionLayoutNode)getChildLayoutNodes()[i];
if (childNode.getExpressionLength(childExpression) > 0) {
// The child node will call update.done();
childNode.getElementForExpression(childUpdate, childExpression, expression);
return;
}
}
}
// If we didn't find a matching child node in the for loop above, return an error.
update.setStatus(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, "Invalid expression", null)); //$NON-NLS-1$
update.done();
}
public int getDeltaFlagsForExpression(String expressionText, Object event) {
int exprLength = getExpressionLength(expressionText);
if (exprLength >= 0) {
if (exprLength == expressionText.length()) {
return getDeltaFlags(event);
} else {
int retVal = getDeltaFlagsForExpressionPart(event);
String childExpression = expressionText.substring(exprLength);
for (int i = 0; i < getChildLayoutNodes().length; i++) {
if (getChildLayoutNodes()[i] instanceof IExpressionLayoutNode) {
IExpressionLayoutNode exprNode = (IExpressionLayoutNode)getChildLayoutNodes()[i];
if (exprNode.getExpressionLength(childExpression) > 0) {
// The child node will call update.done();
retVal |= exprNode.getDeltaFlagsForExpression(childExpression, event);
}
}
}
return retVal;
}
}
return IModelDelta.NO_CHANGE;
}
protected abstract int getDeltaFlagsForExpressionPart(Object event);
public void buildDeltaForExpression(final IExpression expression, final int elementIdx, final String expressionText, final Object event, final VMDelta parentDelta, final TreePath path, final RequestMonitor rm)
{
// Find the expression part that belong to this node. If expression
// is not recognized, do nothing.
final int exprLength = getExpressionLength(expressionText);
if (exprLength < 0) {
rm.done();
return;
}
final String nodeExpressionText = exprLength > 0 ? expressionText.substring(0, exprLength) : expressionText;
getElementForExpressionPart(
new ElementsUpdate(new DataRequestMonitor<List<Object>>(getExecutor(), null), path),
nodeExpressionText,
new DataRequestMonitor<Object>(getExecutor(), null) {
@Override
protected void handleOK() {
if (exprLength == expressionText.length()) {
associateExpression(getData(), expression);
buildDeltaForExpressionElement(getData(), elementIdx, event, parentDelta, rm);
} else {
TreePath newPath = path.createChildPath(getData());
callChildExpressionNodesToBuildDelta(
expression, elementIdx, expressionText.substring(exprLength), event, parentDelta, newPath, rm);
}
}
@Override
protected void handleErrorOrCancel() {
// There is no matching element for given expression. That's OK, it just
// means that the expression is invalid.
rm.done();
}
});
}
protected void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, VMDelta parentDelta, final RequestMonitor rm)
{
// Find the child nodes that have deltas for the given event.
final Map<IVMLayoutNode,Integer> childNodesWithDeltaFlags = getChildNodesWithDeltaFlags(event);
// If no child layout nodes have deltas we can stop here.
if (childNodesWithDeltaFlags.size() == 0) {
rm.done();
return;
}
callChildNodesToBuildDelta(
childNodesWithDeltaFlags, parentDelta.addNode(element, elementIdx, IModelDelta.NO_CHANGE), event, rm);
}
protected void callChildExpressionNodesToBuildDelta(IExpression expression, int elementIdx, String expressionRemainder, Object event, VMDelta parentDelta, TreePath path, final RequestMonitor rm)
{
final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), null) {
@Override
protected void handleCompleted() {
rm.done();
}
};
int childRmCount = 0;
for (int i = 0; i < getChildLayoutNodes().length; i++) {
if (getChildLayoutNodes()[i] instanceof IExpressionLayoutNode) {
IExpressionLayoutNode childNode = (IExpressionLayoutNode)getChildLayoutNodes()[i];
if (childNode.getExpressionLength(expressionRemainder) > 0 &&
childNode.getDeltaFlagsForExpression(expressionRemainder, event) != IModelDelta.NO_CHANGE)
{
childNode.buildDeltaForExpression(
expression, elementIdx, expressionRemainder, event, parentDelta, path, countingRm);
childRmCount++;
// The child node will call update.done();
}
}
}
countingRm.setDoneCount(childRmCount);
}
class ChildExpressionElementUpdate extends VMElementsUpdate {
private final TreePath fPath;
ChildExpressionElementUpdate(IChildrenUpdate clientUpdate, TreePath path, DataRequestMonitor<List<Object>> rm) {
super(clientUpdate, 0, 1, rm);
fPath = path;
}
@Override
public Object getElement() {
return fPath.getLastSegment();
}
@Override
public TreePath getElementPath() {
return fPath;
}
}
}

View file

@ -0,0 +1,119 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.expression;
import java.util.List;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.MultiRequestMonitor;
import org.eclipse.dd.dsf.datamodel.IDMContext;
import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.service.IDsfService;
import org.eclipse.dd.dsf.ui.concurrent.ViewerDataRequestMonitor;
import org.eclipse.dd.dsf.ui.viewmodel.VMChildrenUpdate;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMProvider;
import org.eclipse.debug.core.model.IExpression;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
/**
*
*/
@SuppressWarnings("restriction")
public abstract class AbstractExpressionVMNode extends AbstractDMVMNode
implements IExpressionVMNode
{
public AbstractExpressionVMNode(AbstractDMVMProvider provider, DsfSession session, Class<? extends IDMContext> dmcClassType) {
super(provider, session, dmcClassType);
}
public void update(final IExpressionUpdate update) {
if (!canParseExpression(update.getExpression())) {
update.setStatus(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, "Invalid expression", null)); //$NON-NLS-1$
update.done();
return;
}
update(new IChildrenUpdate[] { new VMChildrenUpdate(
update, -1, -1,
new ViewerDataRequestMonitor<List<Object>>(getExecutor(), update) {
@Override
protected void handleOK() {
if (getData().size() == 0) {
update.setStatus(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, "No contexts", null)); //$NON-NLS-1$
update.done();
} else {
final List<Object> elements = getData();
final MultiRequestMonitor<DataRequestMonitor<Boolean>> multiRm = new MultiRequestMonitor<DataRequestMonitor<Boolean>>(getExecutor(), null) {
@Override
protected void handleCompleted() {
if (getStatus().isOK()) {
boolean foundMatchingContext = false;
for (int i = 0; i < getRequestMonitors().size(); i++) {
if (getRequestMonitors().get(i).getData()) {
Object element = elements.get(i);
associateExpression(element, update.getExpression());
update.setExpressionElement(element);
foundMatchingContext = true;
break;
}
}
if (!foundMatchingContext) {
update.setStatus(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, "Context not found", null)); //$NON-NLS-1$
}
} else {
update.setStatus(getStatus());
}
update.done();
}
};
for (Object element : elements) {
testElementForExpression(
element, update.getExpression(),
multiRm.add(
new DataRequestMonitor<Boolean>(getExecutor(), null) {
@Override
protected void handleCompleted() {
multiRm.requestMonitorDone(this);
}
}));
}
}
}
@Override
protected void handleErrorOrCancel() {
update.setStatus(getStatus());
update.done();
}
})}
);
}
@ConfinedToDsfExecutor("#getSession#getExecutor")
protected void testElementForExpression(Object element, IExpression expression, final DataRequestMonitor<Boolean> rm) {
rm.setData(false);
rm.done();
}
protected void associateExpression(Object element, IExpression expression) {
}
}

View file

@ -10,6 +10,7 @@
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.expression;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor;
@ -17,12 +18,10 @@ import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.debug.ui.viewmodel.IDebugVMConstants;
import org.eclipse.dd.dsf.debug.ui.viewmodel.expression.ExpressionVMProvider.ExpressionsChangedEvent;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.IVMLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
import org.eclipse.dd.dsf.ui.viewmodel.VMElementsUpdate;
import org.eclipse.dd.dsf.ui.viewmodel.update.VMCacheManager;
import org.eclipse.dd.dsf.ui.concurrent.ViewerCountingRequestMonitor;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMContext;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.IVMNode;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IExpressionManager;
import org.eclipse.debug.core.model.IExpression;
@ -35,30 +34,32 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdat
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.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.swt.widgets.Composite;
/**
* This is the top-level layout node in the expressions view. Its job is to:
* This is the top-level view model node in the expressions view. Its job is to:
* <li>
* <ol> retrieve the {@link IExpression} objects from the global {@link IExpressionManager},</ol>
* <ol> retrieve the expression string from the <code>IExpression</code> object,</ol>
* <ol> then to call the configured expression nodes to parse the expression string.</ol>
* </li>
* <p>
* 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.
* This node is not intended to have any standard child nodes, therefore
* the implementation of {@link #setChildNodes(IVMNode[])} throws an exception.
* Instead users should call {@link #setExpressionNodes(IExpressionVMNode[])}
* to configure the nodes that this node will delegate to when processing expressions.
* </p>
*/
@SuppressWarnings("restriction")
public class ExpressionManagerLayoutNode extends AbstractVMLayoutNode
public class ExpressionManagerVMNode extends AbstractVMNode
implements IElementLabelProvider, IElementEditor
{
@ -68,11 +69,11 @@ public class ExpressionManagerLayoutNode extends AbstractVMLayoutNode
* error message in the view, and to allow the user to edit the
* expression.
*/
private class InvalidExpressionVMC extends AbstractVMContext {
final IExpression fExpression;
static class InvalidExpressionVMContext extends AbstractVMContext {
final private IExpression fExpression;
public InvalidExpressionVMC(IExpression expression) {
super(getVMProvider().getVMAdapter(), ExpressionManagerLayoutNode.this);
public InvalidExpressionVMContext(ExpressionManagerVMNode node, IExpression expression) {
super(node.getVMProvider().getVMAdapter(), node);
fExpression = expression;
}
@ -86,9 +87,13 @@ public class ExpressionManagerLayoutNode extends AbstractVMLayoutNode
}
}
public IExpression getExpression() {
return fExpression;
}
@Override
public boolean equals(Object obj) {
return obj instanceof InvalidExpressionVMC && ((InvalidExpressionVMC)obj).fExpression.equals(fExpression);
return obj instanceof InvalidExpressionVMContext && ((InvalidExpressionVMContext)obj).fExpression.equals(fExpression);
}
@Override
@ -96,14 +101,14 @@ public class ExpressionManagerLayoutNode extends AbstractVMLayoutNode
return fExpression.hashCode();
}
}
/**
* VMC for a new expression object to be added. When user clicks on this node to
* edit it, he will create a new expression.
*/
public class NewExpressionVMC extends AbstractVMContext {
class NewExpressionVMC extends AbstractVMContext {
public NewExpressionVMC() {
super(getVMProvider().getVMAdapter(), ExpressionManagerLayoutNode.this);
super(getVMProvider().getVMAdapter(), ExpressionManagerVMNode.this);
}
@Override
@ -123,20 +128,21 @@ 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) {
public ExpressionManagerVMNode(ExpressionVMProvider provider) {
super(provider);
}
public void updateHasElements(IHasChildrenUpdate[] updates) {
private ExpressionVMProvider getExpressionVMProvider() {
return (ExpressionVMProvider)getVMProvider();
}
public void update(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
@ -147,70 +153,70 @@ public class ExpressionManagerLayoutNode extends AbstractVMLayoutNode
}
}
public void updateElementCount(IChildrenCountUpdate update) {
// We assume that the getExpressions() will just read local state data,
// so we don't bother using a job to perform this operation.
update.setChildCount(fManager.getExpressions().length + 1);
update.done();
public void update(IChildrenCountUpdate[] updates) {
for (IChildrenCountUpdate update : updates) {
if (!checkUpdate(update)) continue;
// We assume that the getExpressions() will just read local state data,
// so we don't bother using a job to perform this operation.
update.setChildCount(fManager.getExpressions().length + 1);
update.done();
}
}
public void updateElements(final IChildrenUpdate update) {
public void update(final IChildrenUpdate[] updates) {
for (IChildrenUpdate update : updates) {
doUpdateChildren(update);
}
}
public void doUpdateChildren(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() {
update.done();
}
};
final CountingRequestMonitor multiRm = new ViewerCountingRequestMonitor(getVMProvider().getExecutor(), update);
int multiRmCount = 0;
int expressionRmCount = 0;
for (int i = update.getOffset(); i < update.getOffset() + update.getLength() && i < expressions.length + 1; i++) {
// The last element is the "new expression"
if (i == expressions.length) {
update.setChild(new NewExpressionVMC(), i);
} else {
final String expressionText = expressions[i].getExpressionText();
final int expressionIdx = i;
if (i < expressions.length) {
multiRmCount++;
final int childIndex = i;
final IExpression expression = expressions[i];
IExpressionLayoutNode expressionNode = findNodeForExpression(expressionText);
if (expressionNode == null) {
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<List<Object>>(getExecutor(), multiRm) {
// 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.
((ExpressionVMProvider)getVMProvider()).update(
new VMExpressionUpdate(
update, expression,
new DataRequestMonitor<Object>(getVMProvider().getExecutor(), multiRm) {
@Override
protected void handleOK() {
update.setChild(getData().get(0), expressionIdx);
update.setChild(getData(), childIndex);
multiRm.done();
}
@Override
protected void handleError() {
update.setChild(new InvalidExpressionVMC(expression), expressionIdx);
update.setChild(new InvalidExpressionVMContext(ExpressionManagerVMNode.this, expression), childIndex);
multiRm.done();
}
});
expressionNode.getElementForExpression(expressionElementUpdate, expressionText, expression);
}
})
);
} else {
// Last element in the list of expressions is the "add new expression"
// dummy entry.
update.setChild(new NewExpressionVMC(), i);
}
}
// If no expressions were parsed, we're finished.
// Set the count to the counting RM.
multiRm.setDoneCount(expressionRmCount);
multiRm.setDoneCount(multiRmCount);
}
public void update(ILabelUpdate[] updates) {
@ -218,8 +224,8 @@ public class ExpressionManagerLayoutNode extends AbstractVMLayoutNode
// The expression layout nodes are responsible for supplying label providers
// for their VMCs.
for (ILabelUpdate update : updates) {
if (update.getElement() instanceof InvalidExpressionVMC) {
updateInvalidExpressionVMCLabel(update, (InvalidExpressionVMC) update.getElement());
if (update.getElement() instanceof InvalidExpressionVMContext) {
updateInvalidExpressionVMCLabel(update, (InvalidExpressionVMContext) update.getElement());
} else if (update.getElement() instanceof NewExpressionVMC) {
updateNewExpressionVMCLabel(update, (NewExpressionVMC) update.getElement());
} else {
@ -231,16 +237,16 @@ public class ExpressionManagerLayoutNode extends AbstractVMLayoutNode
/**
* Updates the label for the InvalidExpressionVMC.
*/
private void updateInvalidExpressionVMCLabel(ILabelUpdate update, InvalidExpressionVMC vmc) {
private void updateInvalidExpressionVMCLabel(ILabelUpdate update, InvalidExpressionVMContext vmc) {
String[] columnIds = update.getColumnIds() != null ?
update.getColumnIds() : new String[] { IDebugVMConstants.COLUMN_ID__NAME };
for (int i = 0; i < columnIds.length; i++) {
if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(columnIds[i])) {
update.setLabel(vmc.fExpression.getExpressionText(), i);
update.setLabel(vmc.getExpression().getExpressionText(), i);
update.setImageDescriptor(DebugUITools.getImageDescriptor( IDebugUIConstants.IMG_OBJS_EXPRESSION ), i);
} else if (IDebugVMConstants.COLUMN_ID__NAME.equals(columnIds[i])) {
update.setLabel(vmc.fExpression.getExpressionText(), i);
update.setLabel(vmc.getExpression().getExpressionText(), i);
update.setImageDescriptor(DebugUITools.getImageDescriptor( IDebugUIConstants.IMG_OBJS_EXPRESSION ), i);
} else if (IDebugVMConstants.COLUMN_ID__VALUE.equals(columnIds[i])) {
update.setLabel(MessagesForExpressionVM.ExpressionManagerLayoutNode__invalidExpression_valueColumn_label, i);
@ -275,54 +281,6 @@ public class ExpressionManagerLayoutNode extends AbstractVMLayoutNode
update.done();
}
/**
* Convenience call that iterates through all the configured expression
* layout nodes and finds the first one that can parse the given expression.
*/
private IExpressionLayoutNode findNodeForExpression(String expressionText) {
for (IExpressionLayoutNode node : fExpressionNodes) {
if (node.getExpressionLength(expressionText) > 0) {
return node;
}
}
return null;
}
/**
* ExpressionManagerLayoutNode does not support child layout nodes.
* @see #setExpressionLayoutNodes(IExpressionLayoutNode[])
*/
@Override
public void setChildNodes(IVMLayoutNode[] childNodes) {
throw new UnsupportedOperationException("This node does not support children."); //$NON-NLS-1$
}
/**
* Configures the set of expression layout nodes that the expression manager layout
* node will use to parse the expressions.
* <p>
* <i>Note: The nodes specified in the array will be called to parse expressions,
* in the order as they are in the array</i>. Therefore if one node is a "greedy"
* parser, and will accept any expression string, it should appear last in the list
* of the nodes.
* </p>
* @param nodes Array of expression layout nodes to configure with the manager.
*/
public void setExpressionLayoutNodes(IExpressionLayoutNode[] nodes) {
fExpressionNodes = nodes;
}
@Override
public void dispose() {
for (IExpressionLayoutNode exprNode : fExpressionNodes) {
exprNode.dispose();
}
super.dispose();
}
@Override
public int getDeltaFlags(Object event) {
int retVal = 0;
@ -331,52 +289,53 @@ public class ExpressionManagerLayoutNode extends AbstractVMLayoutNode
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);
for (IExpression expression : fManager.getExpressions()) {
retVal |= getExpressionVMProvider().getDeltaFlagsForExpression(expression, event);
}
return retVal;
}
@Override
public void buildDelta(final Object event, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor requestMonitor) {
public void buildDelta(final Object event, final ModelDelta parentDelta, final int nodeOffset, final RequestMonitor requestMonitor) {
// Add a flag if the list of expressions has changed.
if (event instanceof ExpressionsChangedEvent) {
VMCacheManager.getVMCacheManager().flush(super.getVMProvider().getPresentationContext());
parentDelta.addFlags(IModelDelta.CONTENT);
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
}
// Once again, for each expression, find its corresponding layout node and ask that
// Once again, for each expression, find its corresponding 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);
CountingRequestMonitor multiRm = new CountingRequestMonitor(getExecutor(), requestMonitor);
int buildDeltaForExpressionCallCount = 0;
IExpression[] expressions = fManager.getExpressions();
for (int i = 0; i < expressions.length; i++ ) {
String expressionText = expressions[i].getExpressionText();
IExpressionLayoutNode node = findNodeForExpression(expressionText);
if (node == null) continue;
int flags = node.getDeltaFlagsForExpression(expressionText, event);
// If the given node has no delta flags, skip it.
int flags = getExpressionVMProvider().getDeltaFlagsForExpression(expressions[i], event);
// If the given expression has no delta flags, skip it.
if (flags == IModelDelta.NO_CHANGE) continue;
node.buildDeltaForExpression(expressions[i], i + nodeOffset, expressionText, event, parentDelta,
getTreePathFromDelta(parentDelta),
new RequestMonitor(getExecutor(), multiRm));
int elementOffset = nodeOffset >= 0 ? nodeOffset + i : -1;
getExpressionVMProvider().buildDeltaForExpression(
expressions[i], elementOffset, event, parentDelta, getTreePathFromDelta(parentDelta),
new RequestMonitor(getExecutor(), multiRm));
buildDeltaForExpressionCallCount++;
}
multiRm.setDoneCount(buildDeltaForExpressionCallCount);
}
private TreePath getTreePathFromDelta(IModelDelta delta) {
List<Object> elementList = new LinkedList<Object>();
IModelDelta listDelta = delta;
elementList.add(0, listDelta.getElement());
while (listDelta.getParentDelta() != null) {
elementList.add(0, listDelta.getElement());
listDelta = listDelta.getParentDelta();
}
return new TreePath(elementList.toArray());
}
public CellEditor getCellEditor(IPresentationContext context, String columnId, Object element, Composite parent) {
if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(columnId)) {

View file

@ -10,51 +10,175 @@
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.expression;
import org.eclipse.dd.dsf.debug.ui.viewmodel.dm.AbstractDebugDMVMProviderWithCache;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.debug.ui.viewmodel.numberformat.FormattedValuePreferenceStore;
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.RegisterGroupVMNode;
import org.eclipse.dd.dsf.debug.ui.viewmodel.register.RegisterVMNode;
import org.eclipse.dd.dsf.debug.ui.viewmodel.register.SyncRegisterDataAccess;
import org.eclipse.dd.dsf.debug.ui.viewmodel.update.BreakpointHitUpdatePolicy;
import org.eclipse.dd.dsf.debug.ui.viewmodel.variable.SyncVariableDataAccess;
import org.eclipse.dd.dsf.debug.ui.viewmodel.variable.VariableLayoutNode;
import org.eclipse.dd.dsf.debug.ui.viewmodel.variable.VariableVMNode;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter;
import org.eclipse.dd.dsf.ui.viewmodel.IVMContext;
import org.eclipse.dd.dsf.ui.viewmodel.IVMLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.IVMRootLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.dm.DMVMRootLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.IVMModelProxy;
import org.eclipse.dd.dsf.ui.viewmodel.IVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.DefaultVMContentProviderStrategy;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.dm.RootDMVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.update.AutomaticUpdatePolicy;
import org.eclipse.dd.dsf.ui.viewmodel.update.IVMUpdatePolicy;
import org.eclipse.dd.dsf.ui.viewmodel.update.ManualUpdatePolicy;
import org.eclipse.dd.dsf.ui.viewmodel.update.UserEditEvent;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.model.IExpression;
import org.eclipse.debug.internal.core.IExpressionsListener2;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.TreePath;
/**
*
*/
* The expression provider is used to populate the contents of the expressions
* view. The node hierarchy in this view is a little different than in a typical
* provider: the expression manager node should be registered as the single child
* of the root node and no nodes should be registered as children of expression node.
* Instead the top level expression nodes should be registered with a call to
* {@link #setExpressionNodes(IExpressionVMNode[])}. And each expression node can
* have its own sub-hierarchy of elements as needed. However all nodes configured
* with this provider (with the exception of the root and the expression manager)
* should implement {@link IExpressionVMNode}.
*/
@SuppressWarnings("restriction")
public class ExpressionVMProvider extends AbstractDebugDMVMProviderWithCache implements IExpressionsListener2
public class ExpressionVMProvider extends AbstractDMVMProvider
implements IPropertyChangeListener, IExpressionsListener2
{
public static class ExpressionsChangedEvent {
/**
* Object representing a change in configured expressions. This event is
* object is used when generating a model delta.
*/
public static class ExpressionsChangedEvent extends UserEditEvent {
enum Type {ADDED, CHANGED, REMOVED, MOVED, INSERTED}
public final Type fType;
public final IExpression[] fExpressions;
public ExpressionsChangedEvent(Type type, IExpression[] expressions) {
public ExpressionsChangedEvent(Type type, Set<Object> elements) {
super(elements);
fType = type;
fExpressions = expressions;
}
}
private IExpressionVMNode[] fExpressionNodes;
public ExpressionVMProvider(AbstractVMAdapter adapter, IPresentationContext context, DsfSession session) {
super(adapter, context, session);
context.addPropertyChangeListener(this);
// The VM provider has to handle all events that result in model deltas.
// Add the provider as listener to expression changes events.
DebugPlugin.getDefault().getExpressionManager().addExpressionListener(this);
configureLayout();
}
@Override
protected DefaultVMContentProviderStrategy createContentStrategy() {
return new ExpressionVMProviderContentStragegy(this);
}
@Override
protected IVMModelProxy createModelProxyStrategy(Object rootElement) {
return new ExpressionVMProviderModelProxyStrategy(this, rootElement);
}
/**
* Updates the given expression element. This method is used by the
* expression manager node to obtain a view model element based on the
* {@link IExpression} retrieved from the expression manager. The
* implementation of this method (which is in the content strategy),
* checks the configured expression nodes to see which one can
* process the given expression, when it finds it it delegates
* to that expression node's {@link IExpressionVMNode#update(IExpressionUpdate)}
* method.
* @param update Expression update to process.
*/
public void update(IExpressionUpdate update) {
((ExpressionVMProviderContentStragegy)getContentStrategy()).update(update);
}
/**
* Retrieves the delta flags that can be generated for the given expression
* and the given event. This method is used by the
* expression manager node to obtain the delta flags based on the
* {@link IExpression} retrieved from the expression manager. The
* implementation of this method (which is in the model proxy strategy),
* checks the configured expression nodes to see which one can
* process the given expression, when it finds it it delegates
* to that expression node's {@link IExpressionVMNode#getDeltaFlagsForExpression(IExpression, Object)}
* method.
*/
public int getDeltaFlagsForExpression(IExpression expression, Object event) {
// Workaround: find the first active proxy and use it.
if (!getActiveModelProxies().isEmpty()) {
return ((ExpressionVMProviderModelProxyStrategy)getActiveModelProxies().get(0)).getDeltaFlagsForExpression(expression, event);
}
return 0;
}
/**
* Builds the model delta based on the given expression
* and the given event. This method is used by the
* expression manager to build the delta based on the
* {@link IExpression} retrieved from the expression manager. The
* implementation of this method (which is in the model proxy strategy),
* checks the configured expression nodes to see which one can
* process the given expression, when it finds it it delegates
* to that expression node's {@link IExpressionVMNode#buildDeltaForExpression(IExpression, int, Object, ModelDelta, TreePath, RequestMonitor)}
* and {@link IExpressionVMNode#buildDeltaForExpressionElement(Object, int, Object, ModelDelta, RequestMonitor)
* methods.
*/
public void buildDeltaForExpression(final IExpression expression, final int expressionElementIdx, final Object event,
final ModelDelta parentDelta, final TreePath path, final RequestMonitor rm)
{
// Workaround: find the first active proxy and use it.
if (!getActiveModelProxies().isEmpty()) {
((ExpressionVMProviderModelProxyStrategy)getActiveModelProxies().get(0)).buildDeltaForExpression(
expression, expressionElementIdx, event, parentDelta, path, rm);
} else {
rm.done();
}
}
/**
* Configures the given nodes as the top-level expression nodes.
*/
protected void setExpressionNodes(IExpressionVMNode[] nodes) {
fExpressionNodes = nodes;
// Call the base class to make sure that the nodes are also
// returned by the getAllNodes method.
for (IExpressionVMNode node : nodes) {
addNode(node);
}
}
/**
* Returns the list of configured top-level expression nodes.
* @return
*/
public IExpressionVMNode[] getExpressionNodes() {
return fExpressionNodes;
}
/**
* Configures the nodes of this provider. This method may be overriden by
* sub classes to create an alternate configuration in this provider.
*/
protected void configureLayout() {
/*
@ -66,29 +190,30 @@ public class ExpressionVMProvider extends AbstractDebugDMVMProviderWithCache imp
/*
* Create the top level node which provides the anchor starting point.
*/
IVMRootLayoutNode debugViewSelectionNode = new DMVMRootLayoutNode(this);
IRootVMNode rootNode = new RootDMVMNode(this);
/*
* Now the Overarching management node.
*/
ExpressionManagerLayoutNode expressionManagerNode = new ExpressionManagerLayoutNode(this);
debugViewSelectionNode.setChildNodes(new IVMLayoutNode[] {expressionManagerNode});
ExpressionManagerVMNode expressionManagerNode = new ExpressionManagerVMNode(this);
addChildNodes(rootNode, new IVMNode[] {expressionManagerNode});
/*
* 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(FormattedValuePreferenceStore.getDefault(), this, getSession(), syncRegDataAccess);
registerGroupNode.setChildNodes(new IVMLayoutNode[] { registerNode });
IExpressionVMNode registerGroupNode = new RegisterGroupVMNode(this, getSession(), syncRegDataAccess);
IExpressionVMNode registerNode = new RegisterVMNode(FormattedValuePreferenceStore.getDefault(), this, getSession(), syncRegDataAccess);
addChildNodes(registerGroupNode, new IExpressionVMNode[] {registerNode});
/*
* Create the support for the SubExpressions. Anything which is brought into the expressions
* view comes in as a fully qualified expression so we go directly to the SubExpression layout
* node.
*/
IExpressionLayoutNode subExpressioNode =
new VariableLayoutNode(FormattedValuePreferenceStore.getDefault(), this, getSession(), syncvarDataAccess);
IExpressionVMNode variableNode =
new VariableVMNode(FormattedValuePreferenceStore.getDefault(), this, getSession(), syncvarDataAccess);
addChildNodes(variableNode, new IExpressionVMNode[] {variableNode});
/*
* Tell the expression node which subnodes it will directly support. It is very important
@ -101,17 +226,54 @@ public class ExpressionVMProvider extends AbstractDebugDMVMProviderWithCache imp
* 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, subExpressioNode });
setExpressionNodes(new IExpressionVMNode[] {registerGroupNode, variableNode});
/*
* Let the work know which is the top level node.
*/
setRootLayoutNode(debugViewSelectionNode);
setRootNode(rootNode);
}
/**
* Finds the expression node which can parse the given expression. This
* method is used by the expression content and model proxy strategies.
*
* @param parentNode The parent of the nodes to search. If <code>null</code>,
* then the top level expressions will be searched.
* @param expression The expression object.
* @return The matching expression node.
*/
public IExpressionVMNode findNodeToParseExpression(IExpressionVMNode parentNode, IExpression expression) {
IVMNode[] childNOdes;
if (parentNode == null) {
childNOdes = getExpressionNodes();
} else {
childNOdes = getChildVMNodes(parentNode);
}
for (IVMNode childNode : childNOdes) {
if (childNode instanceof IExpressionVMNode) {
IExpressionVMNode childExpressionNode = (IExpressionVMNode)childNode;
if (childExpressionNode.canParseExpression(expression)) {
return childExpressionNode;
} else if (!childExpressionNode.equals(parentNode)) {
// The above check is to make sure that child isn't the same as
// parent to avoid recursive loops.
IExpressionVMNode matchingNode =
findNodeToParseExpression(childExpressionNode, expression);
if (matchingNode != null) {
return matchingNode;
}
}
}
}
return null;
}
@Override
public void dispose() {
DebugPlugin.getDefault().getExpressionManager().removeExpressionListener(this);
getPresentationContext().removePropertyChangeListener(this);
super.dispose();
}
@ -125,49 +287,42 @@ public class ExpressionVMProvider extends AbstractDebugDMVMProviderWithCache imp
return ExpressionColumnPresentation.ID;
}
/**
* Override this operation to avoid the standard test of isOurLayoutNode(),
* which does not take into account {@link ExpressionManagerLayoutNode.setExpressionLayoutNodes}
* nodes.
*/
@Override
protected IVMLayoutNode getLayoutNodeForElement(Object element) {
/*
* First check to see if the parent object is the root object of the
* hierarchy. If that's the case, then retrieve the correcponding
* root VMC from the root node, and pass this root vmc to the root's
* child layout nodes.
*/
IVMRootLayoutNode rootLayoutNode = getRootLayoutNode();
if (rootLayoutNode == null) {
return null;
}
else if (element.equals(getRootElement())) {
return rootLayoutNode;
}
else if (element instanceof IVMContext){
return ((IVMContext)element).getLayoutNode();
}
return null;
protected IVMUpdatePolicy[] createUpdateModes() {
return new IVMUpdatePolicy[] { new AutomaticUpdatePolicy(), new ManualUpdatePolicy(), new BreakpointHitUpdatePolicy() };
}
public void propertyChange(PropertyChangeEvent event) {
handleEvent(event);
}
public void expressionsAdded(IExpression[] expressions) {
handleEvent(new ExpressionsChangedEvent(ExpressionsChangedEvent.Type.ADDED, expressions));
}
public void expressionsChanged(IExpression[] expressions) {
handleEvent(new ExpressionsChangedEvent(ExpressionsChangedEvent.Type.CHANGED, expressions));
expressionsListChanged(ExpressionsChangedEvent.Type.ADDED);
}
public void expressionsRemoved(IExpression[] expressions) {
handleEvent(new ExpressionsChangedEvent(ExpressionsChangedEvent.Type.REMOVED, expressions));
expressionsListChanged(ExpressionsChangedEvent.Type.REMOVED);
}
public void expressionsInserted(IExpression[] expressions, int index) {
handleEvent(new ExpressionsChangedEvent(ExpressionsChangedEvent.Type.INSERTED, expressions));
expressionsListChanged(ExpressionsChangedEvent.Type.INSERTED);
}
public void expressionsMoved(IExpression[] expressions, int index) {
handleEvent(new ExpressionsChangedEvent(ExpressionsChangedEvent.Type.MOVED, expressions));
expressionsListChanged(ExpressionsChangedEvent.Type.MOVED);
}
public void expressionsChanged(IExpression[] expressions) {
Set<Object> expressionsSet = new HashSet<Object>();
expressionsSet.addAll(Arrays.asList(expressions));
handleEvent(new ExpressionsChangedEvent(ExpressionsChangedEvent.Type.CHANGED, expressionsSet));
}
private void expressionsListChanged(ExpressionsChangedEvent.Type type) {
Set<Object> rootElements = new HashSet<Object>();
for (IVMModelProxy proxy : getActiveModelProxies()) {
rootElements.add(proxy.getRootElement());
}
handleEvent(new ExpressionsChangedEvent(type, rootElements));
}
}

View file

@ -0,0 +1,87 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.expression;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin;
import org.eclipse.dd.dsf.service.IDsfService;
import org.eclipse.dd.dsf.ui.concurrent.ViewerDataRequestMonitor;
import org.eclipse.dd.dsf.ui.viewmodel.DefaultVMContentProviderStrategy;
/**
* The IElementContentProvider implementation to be used with an expression
* view model provider.
*
* @see ExpressionVMProvider
*/
@SuppressWarnings("restriction")
public class ExpressionVMProviderContentStragegy extends DefaultVMContentProviderStrategy {
public ExpressionVMProviderContentStragegy(ExpressionVMProvider provider) {
super(provider);
}
private ExpressionVMProvider getExpressionVMProvider() {
return (ExpressionVMProvider)getVMProvider();
}
public void update(final IExpressionUpdate update) {
final IExpressionVMNode matchingNode =
getExpressionVMProvider().findNodeToParseExpression(null, update.getExpression());
if (matchingNode != null) {
updateExpressionWithNode(matchingNode, update);
} else {
update.setStatus(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, "Cannot parse expression", null)); //$NON-NLS-1$
update.done();
}
}
private void updateExpressionWithNode(final IExpressionVMNode node, final IExpressionUpdate update) {
// Call the expression node to parse the expression and fill in the value.
node.update(
new VMExpressionUpdate(
update, update.getExpression(),
new ViewerDataRequestMonitor<Object>(getVMProvider().getExecutor(), update) {
@Override
protected void handleOK() {
// Check if the evaluated node has child expression nodes.
// If it does, check if any of those nodes can evaluate the given
// expression further. If they can, call the child node to further
// process the expression. Otherwise we found our element and
// we're done.
final IExpressionVMNode matchingNode = getExpressionVMProvider().
findNodeToParseExpression(node, update.getExpression());
if (matchingNode != null && !matchingNode.equals(node)) {
updateExpressionWithNode(
matchingNode,
new VMExpressionUpdate(
update.getElementPath().createChildPath(getData()), update.getViewerInput(),
update.getPresentationContext(), update.getExpression(),
new ViewerDataRequestMonitor<Object>(getVMProvider().getExecutor(), update) {
@Override
protected void handleOK() {
update.setExpressionElement(getData());
update.done();
}
})
);
} else {
update.setExpressionElement(getData());
update.done();
}
}
})
);
}
}

View file

@ -0,0 +1,134 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.expression;
import java.util.Map;
import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.ui.viewmodel.IVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.DefaultVMModelProxyStrategy;
import org.eclipse.debug.core.model.IExpression;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.jface.viewers.TreePath;
/**
* The IModelProxy implementation to be used with an expression
* view model provider.
*
* @see ExpressionVMProvider
*/
@SuppressWarnings("restriction")
public class ExpressionVMProviderModelProxyStrategy extends DefaultVMModelProxyStrategy {
public ExpressionVMProviderModelProxyStrategy(ExpressionVMProvider provider, Object rootElement) {
super(provider, rootElement);
}
private ExpressionVMProvider getExpressionVMProvider() {
return (ExpressionVMProvider)getVMProvider();
}
public int getDeltaFlagsForExpression(IExpression expression, Object event) {
final IExpressionVMNode matchingNode = getExpressionVMProvider().findNodeToParseExpression(null, expression);
if (matchingNode != null) {
return getNodeDeltaFlagsForExpression(matchingNode, expression, event);
}
return IModelDelta.NO_CHANGE;
}
private int getNodeDeltaFlagsForExpression(IExpressionVMNode node, IExpression expression, Object event) {
int flags = node.getDeltaFlagsForExpression(expression, event);
IExpressionVMNode matchingNode = getExpressionVMProvider().findNodeToParseExpression(node, expression);
if (matchingNode != null && !matchingNode.equals(node)) {
flags = flags | getNodeDeltaFlagsForExpression(matchingNode, expression, event);
}
return flags;
}
public void buildDeltaForExpression(IExpression expression, int expressionElementIdx, Object event,
ModelDelta parentDelta, TreePath path, RequestMonitor rm)
{
final IExpressionVMNode matchingNode = getExpressionVMProvider().findNodeToParseExpression(null, expression);
if (matchingNode != null) {
buildNodeDeltaForExpression(matchingNode, expression, expressionElementIdx, event,
parentDelta, path, rm);
} else {
rm.done();
}
}
private void buildNodeDeltaForExpression(final IExpressionVMNode node, final IExpression expression,
final int expressionElementIdx, final Object event, final ModelDelta parentDelta, final TreePath path,
final RequestMonitor rm)
{
node.buildDeltaForExpression(
expression, expressionElementIdx, event, parentDelta, path,
new RequestMonitor(getVMProvider().getExecutor(), rm) {
@Override
protected void handleOK() {
final IExpressionVMNode matchingNode =
getExpressionVMProvider().findNodeToParseExpression(node, expression);
if (matchingNode != null && !matchingNode.equals(node)) {
buildNodeDeltaForExpression(
matchingNode, expression, expressionElementIdx, event, parentDelta, path, rm);
} else {
getExpressionVMProvider().update(new VMExpressionUpdate(
parentDelta, getVMProvider().getPresentationContext(), expression,
new DataRequestMonitor<Object>(getVMProvider().getExecutor(), rm) {
@Override
protected void handleOK() {
buildDeltaForExpressionElement(
node, getData(), expressionElementIdx, event, parentDelta, path, rm);
}
@Override
protected void handleError() {
// Avoid propagating the error to avoid processing the delta by
// all nodes.
rm.done();
}
}));
}
}
});
}
private void buildDeltaForExpressionElement(final IExpressionVMNode node, Object expressionElement,
final int expressionElementIdx, final Object event, final ModelDelta parentDelta, final TreePath path,
final RequestMonitor rm)
{
CountingRequestMonitor multiRm = new CountingRequestMonitor(getVMProvider().getExecutor(), rm);
int multiRmCount = 0;
node.buildDeltaForExpressionElement(expressionElement, expressionElementIdx, event, parentDelta, multiRm);
multiRmCount++;
// Find the child nodes that have deltas for the given event.
Map<IVMNode,Integer> childNodesWithDeltaFlags = getChildNodesWithDeltaFlags(node, parentDelta, event);
// If no child layout nodes have deltas we can stop here.
if (childNodesWithDeltaFlags.size() != 0) {
callChildNodesToBuildDelta(
node, childNodesWithDeltaFlags,
parentDelta.addNode(expressionElement, expressionElementIdx, IModelDelta.NO_CHANGE),
event, multiRm);
multiRmCount++;
}
multiRm.setDoneCount(multiRmCount);
}
}

View file

@ -1,55 +0,0 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.expression;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.ui.viewmodel.IVMLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
import org.eclipse.debug.core.model.IExpression;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.jface.viewers.TreePath;
/**
* Interface for layout nodes that can be used within the expression view.
* The methods of this interface allow the {@link ExpressionManagerLayoutNode}
* to use this layout node to delegate expression parsing to this node, and to
* generate deltas for expressions that are owned by this node.
*/
@SuppressWarnings("restriction")
public interface IExpressionLayoutNode extends IVMLayoutNode {
/**
* Returns the length of the portion of the expression that can be parsed
* by this node.
* @param expression String to parse
* @return length of the expression recognized by this node. Length of less than 1
* indicates that this node cannot parse this expression.
*/
int getExpressionLength(String expression);
/**
* Retrieves the element for the given expression. The node implementing
* this method should parse the expression and set a valid view model
* context (VMC) element in the update provided as an argument.
* @param update to fill in with the element. The tree path in this update
* object may contain elements which are not actually displayed in the viewer.
* These element may have been added to the original path by other expression
* layout nodes that have parsed preceding parts of the expression.
* @param expressionText expression string to parse
* @param expression expression object that the returned element should contain
*/
void getElementForExpression(IChildrenUpdate update, String expressionText, IExpression expression);
int getDeltaFlagsForExpression(String expressionText, Object event);
void buildDeltaForExpression(IExpression expression, int elementIdx, String expressionText, Object event,
VMDelta parentDelta, TreePath path, RequestMonitor rm);
}

View file

@ -0,0 +1,34 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.expression;
import org.eclipse.debug.core.model.IExpression;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
/**
* An update for an element based on the given expression. The provider processing
* this update needs to create an expression element based on the tree path and the
* expression object in this update.
*/
@SuppressWarnings("restriction")
public interface IExpressionUpdate extends IViewerUpdate {
/**
* Returns the expression object for this update.
*/
public IExpression getExpression();
/**
* Sets the element to the update. The element is to be calculated by the provider
* handling the update.
*/
public void setExpressionElement(Object element);
}

View file

@ -0,0 +1,60 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.expression;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.ui.viewmodel.IVMNode;
import org.eclipse.debug.core.model.IExpression;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.jface.viewers.TreePath;
/**
* Interface for view model nodes that can be used within the expression view.
* The methods of this interface allow the {@link ExpressionManagerVMNode}
* to use this node to delegate expression parsing to this node, and to
* generate deltas for expressions that are owned by this node.
*/
@SuppressWarnings("restriction")
public interface IExpressionVMNode extends IVMNode {
/**
* Returns whether the given expression node recognizes and can parse the given
* expression.
* @param expression Expression that needs to be parsed.
* @return true if expression can be parsed
*/
public boolean canParseExpression(IExpression expression);
/**
* Asynchronously fills in the given expression update.
* @param update Update to complete.
*/
public void update(IExpressionUpdate update);
/**
* Returns the flags that this node can generate for the given expression and
* event.
*/
public int getDeltaFlagsForExpression(IExpression expression, Object event);
/**
* Adds delta flags to the given parent delta based on the expression object
* given.
*/
public void buildDeltaForExpression(IExpression expression, int elementIdx, Object event, ModelDelta parentDelta,
TreePath path, RequestMonitor rm);
/**
* Adds delta to the given parent delta based on the given element which was created base on
* an expression parsed by this node.
*/
public void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, ModelDelta parentDelta, final RequestMonitor rm);
}

View file

@ -0,0 +1,79 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.expression;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.service.IDsfService;
import org.eclipse.dd.dsf.ui.DsfUIPlugin;
import org.eclipse.dd.dsf.ui.viewmodel.VMViewerUpdate;
import org.eclipse.debug.core.model.IExpression;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
import org.eclipse.jface.viewers.TreePath;
/**
*
*/
@SuppressWarnings("restriction")
class VMExpressionUpdate extends VMViewerUpdate implements IExpressionUpdate {
private final IExpression fExpression;
private Object fExpressionElement;
public VMExpressionUpdate(IViewerUpdate clientUpdate, IExpression expression, DataRequestMonitor<Object> rm)
{
super(clientUpdate, rm);
fExpression = expression;
}
public VMExpressionUpdate(IModelDelta delta, IPresentationContext presentationContext, IExpression expression, DataRequestMonitor<Object> rm)
{
super(delta, presentationContext, rm);
fExpression = expression;
}
public VMExpressionUpdate(TreePath elementPath, Object viewerInput, IPresentationContext presentationContext, IExpression expression, DataRequestMonitor<Object> rm)
{
super(elementPath, viewerInput, presentationContext, rm);
fExpression = expression;
}
public IExpression getExpression() {
return fExpression;
}
public void setExpressionElement(Object element) {
fExpressionElement = element;
}
@Override
public String toString() {
return "VMExpressionUpdate for elements under parent = " + getElement() + ", in for expression " + getExpression().getExpressionText(); //$NON-NLS-1$ //$NON-NLS-2$
}
@Override
public void done() {
@SuppressWarnings("unchecked")
DataRequestMonitor<Object> rm = (DataRequestMonitor<Object>)getRequestMonitor();
if (fExpressionElement != null) {
rm.setData(fExpressionElement);
} else if (rm.getStatus().isOK()) {
rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, "Incomplete elements of updates", null)); //$NON-NLS-1$
}
super.done();
}
}

View file

@ -13,7 +13,7 @@ package org.eclipse.dd.dsf.debug.ui.viewmodel.expression;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.dd.dsf.concurrent.ThreadSafeAndProhibitedFromDsfExecutor;
import org.eclipse.dd.dsf.debug.ui.viewmodel.IDebugVMConstants;
import org.eclipse.dd.dsf.debug.ui.viewmodel.expression.ExpressionManagerLayoutNode.NewExpressionVMC;
import org.eclipse.dd.dsf.debug.ui.viewmodel.expression.ExpressionManagerVMNode.NewExpressionVMC;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IExpressionManager;
import org.eclipse.debug.core.model.IWatchExpression;
@ -22,7 +22,6 @@ import org.eclipse.jface.viewers.ICellModifier;
/**
*
*/
@SuppressWarnings("restriction")
@ThreadSafeAndProhibitedFromDsfExecutor("")
public class WatchExpressionCellModifier implements ICellModifier {

View file

@ -12,15 +12,15 @@ package org.eclipse.dd.dsf.debug.ui.viewmodel.launch;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin;
import org.eclipse.dd.dsf.service.IDsfService;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.VMRootLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.IVMLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.IVMRootLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.RootVMNode;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
@ -28,6 +28,7 @@ import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.model.IDebugElement;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
/**
* Layout node for the standard ILaunch object. This node can only be used at
@ -35,8 +36,8 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
* functionality, so the default adapters should be used to retrieve the label.
*/
@SuppressWarnings("restriction")
public class StandardLaunchRootLayoutNode extends VMRootLayoutNode
implements IVMRootLayoutNode
public class LaunchRootVMNode extends RootVMNode
implements IRootVMNode
{
public static class LaunchesEvent {
public enum Type { ADDED, REMOVED, CHANGED, TERMINATED }
@ -49,92 +50,76 @@ public class StandardLaunchRootLayoutNode extends VMRootLayoutNode
}
}
final private ILaunch fLaunch;
public StandardLaunchRootLayoutNode(AbstractVMProvider provider, ILaunch launch) {
public LaunchRootVMNode(AbstractVMProvider provider) {
super(provider);
fLaunch = launch;
}
@Override
public int getDeltaFlags(Object e) {
public boolean isDeltaEvent(Object rootObject, Object e) {
if (e instanceof DebugEvent) {
DebugEvent de = (DebugEvent)e;
if (de.getSource() instanceof IProcess &&
!((IProcess)de.getSource()).getLaunch().equals(fLaunch) )
!((IProcess)de.getSource()).getLaunch().equals(rootObject) )
{
return IModelDelta.NO_CHANGE;
return false;
}
else if (de.getSource() instanceof IDebugElement &&
!fLaunch.equals(((IDebugElement)de.getSource()).getLaunch()))
!rootObject.equals(((IDebugElement)de.getSource()).getLaunch()))
{
return IModelDelta.NO_CHANGE;
return false;
}
}
return true;
}
@Override
public int getDeltaFlags(Object e) {
int flags = 0;
if (e instanceof LaunchesEvent) {
LaunchesEvent le = (LaunchesEvent)e;
for (ILaunch launch : le.fLaunches) {
if (fLaunch == launch) {
if (le.fType == LaunchesEvent.Type.CHANGED) {
flags = IModelDelta.STATE | IModelDelta.CONTENT;
} else if (le.fType == LaunchesEvent.Type.TERMINATED) {
flags = IModelDelta.STATE | IModelDelta.CONTENT;
}
}
if (le.fType == LaunchesEvent.Type.CHANGED || le.fType == LaunchesEvent.Type.TERMINATED) {
flags = IModelDelta.STATE | IModelDelta.CONTENT;
}
}
return flags | super.getDeltaFlags(e);
return flags;
}
@Override
public void createDelta(Object event, final DataRequestMonitor<IModelDelta> rm) {
public void createRootDelta(Object rootObject, Object event, final DataRequestMonitor<ModelDelta> rm) {
if (!(rootObject instanceof ILaunch)) {
rm.setStatus(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, IDsfService.INVALID_STATE, "Invalid root element configured with launch root node.", null)); //$NON-NLS-1$
return;
}
ILaunch rootLaunch = (ILaunch)rootObject;
/*
* Create the root of the delta. Since the launch object is not at the
* root of the view, create the delta with the path to the launch, then
* pass that to the child layout nodes.
* root of the view, create the delta with the path to the launch.
*/
ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager();
List<ILaunch> launchList = Arrays.asList(manager.getLaunches());
final VMDelta viewRootDelta = new VMDelta(manager, 0, IModelDelta.NO_CHANGE, launchList.size());
final VMDelta rootDelta = viewRootDelta.addNode(getRootObject(), launchList.indexOf(fLaunch), IModelDelta.NO_CHANGE);
final ModelDelta viewRootDelta = new ModelDelta(manager, 0, IModelDelta.NO_CHANGE, launchList.size());
final ModelDelta rootDelta = viewRootDelta.addNode(rootLaunch, launchList.indexOf(rootLaunch), IModelDelta.NO_CHANGE);
// Generate delta for launch node.
if (event instanceof LaunchesEvent) {
LaunchesEvent le = (LaunchesEvent)event;
for (ILaunch launch : le.fLaunches) {
if (fLaunch == launch) {
if (rootLaunch == launch) {
if (le.fType == LaunchesEvent.Type.CHANGED) {
rootDelta.addFlags(IModelDelta.STATE | IModelDelta.CONTENT);
rootDelta.setFlags(rootDelta.getFlags() | IModelDelta.STATE | IModelDelta.CONTENT);
} else if (le.fType == LaunchesEvent.Type.TERMINATED) {
rootDelta.addFlags(IModelDelta.STATE | IModelDelta.CONTENT);
rootDelta.setFlags(rootDelta.getFlags() | IModelDelta.STATE | IModelDelta.CONTENT);
}
}
}
}
// Call the child nodes to generate their delta.
Map<IVMLayoutNode,Integer> childNodeDeltas = getChildNodesWithDeltaFlags(event);
if (childNodeDeltas.size() != 0) {
callChildNodesToBuildDelta(
childNodeDeltas, rootDelta, event,
new RequestMonitor(getExecutor(), rm) {
@Override
public void handleOK() {
if (isDisposed()) return;
rm.setData(viewRootDelta);
rm.done();
}
});
} else {
rm.setData(viewRootDelta);
rm.done();
}
rm.setData(rootDelta);
rm.done();
}
@Override
public Object getRootObject() {
return fLaunch;
}
}

View file

@ -11,11 +11,12 @@
package org.eclipse.dd.dsf.debug.ui.viewmodel.launch;
import java.util.List;
import java.util.concurrent.RejectedExecutionException;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.DsfRunnable;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.datamodel.DMContexts;
import org.eclipse.dd.dsf.datamodel.IDMEvent;
import org.eclipse.dd.dsf.debug.service.IRunControl;
import org.eclipse.dd.dsf.debug.service.IStack;
import org.eclipse.dd.dsf.debug.service.IStepQueueManager;
@ -28,50 +29,51 @@ import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext;
import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMData;
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.dd.dsf.ui.viewmodel.update.VMCacheManager;
import org.eclipse.dd.dsf.ui.viewmodel.VMChildrenUpdate;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.dm.IDMVMContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
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.IViewerUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.IDebugUIConstants;
@SuppressWarnings("restriction")
public class StackFramesLayoutNode extends AbstractDMVMLayoutNode {
public class StackFramesVMNode extends AbstractDMVMNode
implements IElementLabelProvider
{
public IVMContext[] fCachedOldFrameVMCs;
public StackFramesLayoutNode(AbstractVMProvider provider, DsfSession session) {
public StackFramesVMNode(AbstractDMVMProvider provider, DsfSession session) {
super(provider, session, IStack.IFrameDMContext.class);
}
@Override
protected void updateHasElementsInSessionThread(IHasChildrenUpdate[] updates) {
protected void updateHasElementsInSessionThread(IHasChildrenUpdate update) {
if (!checkService(IStack.class, null, update)) return;
for (IHasChildrenUpdate update : updates) {
if (!checkService(IStack.class, null, update)) return;
IExecutionDMContext execDmc = findDmcInPath(update.getElementPath(), IExecutionDMContext.class);
if (execDmc == null) {
handleFailedUpdate(update);
return;
}
update.setHasChilren(getServicesTracker().getService(IStack.class).isStackAvailable(execDmc));
update.done();
}
IExecutionDMContext execDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExecutionDMContext.class);
if (execDmc == null) {
handleFailedUpdate(update);
return;
}
update.setHasChilren(getServicesTracker().getService(IStack.class).isStackAvailable(execDmc));
update.done();
}
@Override
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
if (!checkService(IStack.class, null, update)) return;
final IExecutionDMContext execDmc = findDmcInPath(update.getElementPath(), IExecutionDMContext.class);
final IExecutionDMContext execDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExecutionDMContext.class);
if (execDmc == null) {
handleFailedUpdate(update);
return;
@ -110,7 +112,7 @@ public class StackFramesLayoutNode extends AbstractDMVMLayoutNode {
* @see #getElements(IVMContext, DataRequestMonitor)
*/
private void getElementsTopStackFrameOnly(final IChildrenUpdate update) {
final IExecutionDMContext execDmc = findDmcInPath(update.getElementPath(), IExecutionDMContext.class);
final IExecutionDMContext execDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExecutionDMContext.class);
if (execDmc == null) {
handleFailedUpdate(update);
return;
@ -118,7 +120,7 @@ public class StackFramesLayoutNode extends AbstractDMVMLayoutNode {
getServicesTracker().getService(IStack.class).getTopFrame(
execDmc,
new DataRequestMonitor<IFrameDMContext>(getSession().getExecutor(), null) {
new DataRequestMonitor<IFrameDMContext>(getExecutor(), null) {
@Override
public void handleCompleted() {
if (!getStatus().isOK()) {
@ -126,7 +128,7 @@ public class StackFramesLayoutNode extends AbstractDMVMLayoutNode {
return;
}
IVMContext topFrameVmc = new DMVMContext(getData());
IVMContext topFrameVmc = createVMContext(getData());
update.setChild(topFrameVmc, 0);
// If there are old frames cached, use them and only substitute the top frame object. Otherwise, create
@ -143,14 +145,29 @@ public class StackFramesLayoutNode extends AbstractDMVMLayoutNode {
});
}
@Override
public void update(final ILabelUpdate[] updates) {
try {
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
updateLabelInSessionThread(updates);
}});
} catch (RejectedExecutionException e) {
for (ILabelUpdate update : updates) {
handleFailedUpdate(update);
}
}
}
protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
for (final ILabelUpdate update : updates) {
final IFrameDMContext dmc = findDmcInPath(update.getElementPath(), IFrameDMContext.class);
final IFrameDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IFrameDMContext.class);
if (!checkDmc(dmc, update) || !checkService(IStack.class, null, update)) continue;
VMCacheManager.getVMCacheManager().getCache(update.getPresentationContext())
.getModelData(getServicesTracker().getService(IStack.class, null),
getDMVMProvider().getModelData(
this, update,
getServicesTracker().getService(IStack.class, null),
dmc,
new DataRequestMonitor<IFrameDMData>(getSession().getExecutor(), null) {
@Override
@ -190,7 +207,7 @@ public class StackFramesLayoutNode extends AbstractDMVMLayoutNode {
{
if (idx != 0) return;
final IExecutionDMContext execDmc = findDmcInPath(update.getElementPath(), IExecutionDMContext.class);
final IExecutionDMContext execDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExecutionDMContext.class);
IRunControl runControlService = getServicesTracker().getService(IRunControl.class);
IStepQueueManager stepQueueMgrService = getServicesTracker().getService(IStepQueueManager.class);
if (execDmc == null || runControlService == null || stepQueueMgrService == null) return;
@ -253,8 +270,7 @@ public class StackFramesLayoutNode extends AbstractDMVMLayoutNode {
}
@Override
protected int getNodeDeltaFlagsForDMEvent(org.eclipse.dd.dsf.datamodel.IDMEvent<?> e) {
public int getDeltaFlags(Object e) {
// This node generates delta if the timers have changed, or if the
// label has changed.
if (e instanceof ISuspendedDMEvent) {
@ -268,15 +284,14 @@ public class StackFramesLayoutNode extends AbstractDMVMLayoutNode {
} else if (e instanceof IStepQueueManager.ISteppingTimedOutEvent) {
return IModelDelta.CONTENT;
}
return 0;
return IModelDelta.NO_CHANGE;
}
@Override
protected void buildDeltaForDMEvent(final IDMEvent<?> e, final VMDelta parent, final int nodeOffset, final RequestMonitor rm) {
public void buildDelta(final Object e, final ModelDelta parent, final int nodeOffset, final RequestMonitor rm) {
if (e instanceof IContainerSuspendedDMEvent) {
IExecutionDMContext threadDmc = null;
if (parent.getElement() instanceof AbstractDMVMLayoutNode.DMVMContext) {
threadDmc = DMContexts.getAncestorOfType( ((DMVMContext)parent.getElement()).getDMC(), IExecutionDMContext.class);
if (parent.getElement() instanceof IDMVMContext) {
threadDmc = DMContexts.getAncestorOfType( ((IDMVMContext)parent.getElement()).getDMContext(), IExecutionDMContext.class);
}
buildDeltaForSuspendedEvent((ISuspendedDMEvent)e, threadDmc, ((IContainerSuspendedDMEvent)e).getTriggeringContext(), parent, nodeOffset, rm);
} else if (e instanceof ISuspendedDMEvent) {
@ -287,17 +302,16 @@ public class StackFramesLayoutNode extends AbstractDMVMLayoutNode {
} else if (e instanceof IStepQueueManager.ISteppingTimedOutEvent) {
buildDeltaForSteppingTimedOutEvent((IStepQueueManager.ISteppingTimedOutEvent)e, parent, nodeOffset, rm);
} else {
// Call super-class to build sub-node delta's.
super.buildDeltaForDMEvent(e, parent, nodeOffset, rm);
rm.done();
}
}
private void buildDeltaForSuspendedEvent(final ISuspendedDMEvent e, final IExecutionDMContext executionCtx, final IExecutionDMContext triggeringCtx, final VMDelta parent, final int nodeOffset, final RequestMonitor rm) {
private void buildDeltaForSuspendedEvent(final ISuspendedDMEvent e, final IExecutionDMContext executionCtx, final IExecutionDMContext triggeringCtx, final ModelDelta parentDelta, final int nodeOffset, final RequestMonitor rm) {
IRunControl runControlService = getServicesTracker().getService(IRunControl.class);
IStack stackService = getServicesTracker().getService(IStack.class);
if (stackService == null || runControlService == null) {
// Required services have not initialized yet. Ignore the event.
super.buildDeltaForDMEvent(e, parent, nodeOffset, rm);
rm.done();
return;
}
@ -305,46 +319,45 @@ public class StackFramesLayoutNode extends AbstractDMVMLayoutNode {
// which case, the refresh will occur when the stepping sequence slows down or stops. Trying to
// refresh the whole stack trace with every step would slow down stepping too much.
if (!runControlService.isStepping(triggeringCtx)) {
parent.addFlags(IModelDelta.CONTENT);
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
}
// Check if we are building a delta for the thread that triggered the event.
// Only then expand the stack frames and select the top one.
if (executionCtx.equals(triggeringCtx)) {
// Always expand the thread node to show the stack frames.
parent.addFlags(IModelDelta.EXPAND);
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.EXPAND);
// Retrieve the list of stack frames, and mark the top frame to be selected.
getElementsTopStackFrameOnly(
new ElementsUpdate(
new DataRequestMonitor<List<Object>>(getSession().getExecutor(), null) {
new VMChildrenUpdate(
parentDelta, getVMProvider().getPresentationContext(), -1, -1,
new DataRequestMonitor<List<Object>>(getExecutor(), null) {
@Override
public void handleCompleted() {
if (getStatus().isOK() && getData().size() != 0) {
parent.addNode( getData().get(0), IModelDelta.SELECT | IModelDelta.STATE);
parentDelta.addNode( getData().get(0), 0, IModelDelta.SELECT | IModelDelta.STATE);
// If second frame is available repaint it, so that a "..." appears. This gives a better
// impression that the frames are not up-to date.
if (getData().size() >= 2) {
parent.addNode( getData().get(1), IModelDelta.STATE);
parentDelta.addNode( getData().get(1), 1, IModelDelta.STATE);
}
}
// Even in case of errors, call super-class to complete building of the delta.
StackFramesLayoutNode.super.buildDeltaForDMEvent(e, parent, nodeOffset, rm);
// Even in case of errors, complete the request monitor.
rm.done();
}
},
parent)
})
);
} else {
// Don't forget to call the super class to complete building the delta (and call child nodes.)
StackFramesLayoutNode.super.buildDeltaForDMEvent(e, parent, nodeOffset, rm);
rm.done();
}
}
private void buildDeltaForResumedEvent(final IResumedDMEvent e, final VMDelta parent, final int nodeOffset, final RequestMonitor rm) {
private void buildDeltaForResumedEvent(final IResumedDMEvent e, final ModelDelta parentDelta, final int nodeOffset, final RequestMonitor rm) {
IStack stackService = getServicesTracker().getService(IStack.class);
if (stackService == null) {
// Required services have not initialized yet. Ignore the event.
super.buildDeltaForDMEvent(e, parent, nodeOffset, rm);
rm.done();
return;
}
@ -352,15 +365,15 @@ public class StackFramesLayoutNode extends AbstractDMVMLayoutNode {
if (resumedEvent.getReason() != StateChangeReason.STEP) {
// Refresh the list of stack frames only if the run operation is not a step. Also, clear the list
// of cached frames.
parent.addFlags(IModelDelta.CONTENT);
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
fCachedOldFrameVMCs = null;
}
super.buildDeltaForDMEvent(e, parent, nodeOffset, rm);
rm.done();
}
private void buildDeltaForSteppingTimedOutEvent(final IStepQueueManager.ISteppingTimedOutEvent e, final VMDelta parent, final int nodeOffset, final RequestMonitor rm) {
private void buildDeltaForSteppingTimedOutEvent(final IStepQueueManager.ISteppingTimedOutEvent e, final ModelDelta parentDelta, final int nodeOffset, final RequestMonitor rm) {
// Repaint the stack frame images to have the running symbol.
parent.addFlags(IModelDelta.CONTENT);
super.buildDeltaForDMEvent(e, parent, nodeOffset, rm);
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
rm.done();
}
}

View file

@ -11,11 +11,11 @@
package org.eclipse.dd.dsf.debug.ui.viewmodel.launch;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMContext;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.IVMContext;
import org.eclipse.dd.dsf.ui.viewmodel.IVMLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
import org.eclipse.dd.dsf.ui.viewmodel.IVMNode;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.ILaunch;
@ -25,6 +25,7 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpd
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.debug.internal.ui.viewers.provisional.ILabelRequestMonitor;
import org.eclipse.jface.viewers.TreePath;
@ -35,7 +36,7 @@ import org.eclipse.jface.viewers.TreePath;
* adapters should be used to retrieve the label.
*/
@SuppressWarnings("restriction")
public class StandardProcessLayoutNode extends AbstractVMLayoutNode {
public class StandardProcessVMNode extends AbstractVMNode {
/**
* VMC element implementation, it is a proxy for the IProcess class, to
@ -47,12 +48,12 @@ public class StandardProcessLayoutNode extends AbstractVMLayoutNode {
private final IProcess fProcess;
VMC(IProcess process) {
super(getVMProvider().getVMAdapter(), StandardProcessLayoutNode.this);
super(getVMProvider().getVMAdapter(), StandardProcessVMNode.this);
fProcess = process;
}
@Override
public IVMLayoutNode getLayoutNode() { return StandardProcessLayoutNode.this; }
public IVMNode getVMNode() { return StandardProcessVMNode.this; }
@Override
@SuppressWarnings("unchecked")
public Object getAdapter(Class adapter) {
@ -83,46 +84,51 @@ public class StandardProcessLayoutNode extends AbstractVMLayoutNode {
public int hashCode() { return fProcess.hashCode(); }
}
public StandardProcessLayoutNode(AbstractVMProvider provider) {
public StandardProcessVMNode(AbstractVMProvider provider) {
super(provider);
}
public void updateElements(IChildrenUpdate update) {
ILaunch launch = findLaunch(update.getElementPath());
if (launch == null) {
// There is no launch in the parent of this node. This means that the
// layout is misconfigured.
assert false;
public void update(IChildrenUpdate[] updates) {
for (IChildrenUpdate update : updates) {
ILaunch launch = findLaunch(update.getElementPath());
if (launch == null) {
// There is no launch in the parent of this node. This means that the
// layout is misconfigured.
assert false;
update.done();
continue;
}
/*
* Assume that the process objects are stored within the launch, and
* retrieve them on dispatch thread.
*/
IProcess[] processes = launch.getProcesses();
for (int i = 0; i < processes.length; i++) {
update.setChild(new VMC(processes[i]), i);
}
update.done();
return;
}
/*
* Assume that the process objects are stored within the launch, and
* retrieve them on dispatch thread.
*/
IProcess[] processes = launch.getProcesses();
for (int i = 0; i < processes.length; i++) {
update.setChild(new VMC(processes[i]), i);
}
update.done();
}
public void updateElementCount(IChildrenCountUpdate update) {
ILaunch launch = findLaunch(update.getElementPath());
if (launch == null) {
assert false;
update.setChildCount(0);
public void update(final IChildrenCountUpdate[] updates) {
for (IChildrenCountUpdate update : updates) {
if (!checkUpdate(update)) continue;
ILaunch launch = findLaunch(update.getElementPath());
if (launch == null) {
assert false;
update.setChildCount(0);
update.done();
return;
}
update.setChildCount(launch.getProcesses().length);
update.done();
return;
}
update.setChildCount(launch.getProcesses().length);
update.done();
}
// @see org.eclipse.dd.dsf.ui.viewmodel.IViewModelLayoutNode#hasElements(org.eclipse.dd.dsf.ui.viewmodel.IVMContext, org.eclipse.dd.dsf.concurrent.DataRequestMonitor)
public void updateHasElements(IHasChildrenUpdate[] updates) {
public void update(IHasChildrenUpdate[] updates) {
for (IHasChildrenUpdate update : updates) {
ILaunch launch = findLaunch(update.getElementPath());
if (launch == null) {
@ -138,7 +144,7 @@ public class StandardProcessLayoutNode extends AbstractVMLayoutNode {
}
// @see org.eclipse.dd.dsf.ui.viewmodel.IViewModelLayoutNode#retrieveLabel(org.eclipse.dd.dsf.ui.viewmodel.IVMContext, org.eclipse.debug.internal.ui.viewers.provisional.ILabelRequestMonitor)
public void updateLabel(@SuppressWarnings("unused")IVMContext vmc, ILabelRequestMonitor result, @SuppressWarnings("unused") String[] columns) {
public void updateLabel(IVMContext vmc, ILabelRequestMonitor result, String[] columns) {
/*
* The implementation of IAdapterFactory that uses this node should not
@ -163,7 +169,6 @@ public class StandardProcessLayoutNode extends AbstractVMLayoutNode {
return null;
}
@Override
public int getDeltaFlags(Object e) {
int myFlags = 0;
if (e instanceof DebugEvent) {
@ -176,11 +181,10 @@ public class StandardProcessLayoutNode extends AbstractVMLayoutNode {
myFlags = IModelDelta.STATE;
}
}
return myFlags | super.getDeltaFlags(e);
return myFlags;
}
@Override
public void buildDelta(Object e, VMDelta parent, int nodeOffset, RequestMonitor requestMonitor) {
public void buildDelta(Object e, ModelDelta parent, int nodeOffset, RequestMonitor requestMonitor) {
if (e instanceof DebugEvent && ((DebugEvent)e).getSource() instanceof IProcess) {
DebugEvent de = (DebugEvent)e;
if (de.getKind() == DebugEvent.CHANGE) {
@ -194,21 +198,19 @@ public class StandardProcessLayoutNode extends AbstractVMLayoutNode {
* No other node should need to process events related to process.
* Therefore, just invoke the request monitor without calling super.buildDelta().
*/
requestMonitor.done();
} else {
super.buildDelta(e, parent, nodeOffset, requestMonitor);
}
}
requestMonitor.done();
}
protected void handleChange(DebugEvent event, VMDelta parent) {
protected void handleChange(DebugEvent event, ModelDelta parent) {
parent.addNode(new VMC((IProcess)event.getSource()), IModelDelta.STATE);
}
protected void handleCreate(@SuppressWarnings("unused") DebugEvent event, @SuppressWarnings("unused") VMDelta parent) {
protected void handleCreate(DebugEvent event, ModelDelta parent) {
// do nothing - Launch change notification handles this
}
protected void handleTerminate(DebugEvent event, VMDelta parent) {
protected void handleTerminate(DebugEvent event, ModelDelta parent) {
handleChange(event, parent);
}

View file

@ -35,7 +35,7 @@ import org.eclipse.dd.dsf.debug.ui.viewmodel.numberformat.detail.TextViewerActio
import org.eclipse.dd.dsf.service.DsfServicesTracker;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.service.IDsfService;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.dm.IDMVMContext;
import org.eclipse.debug.core.model.IDebugElement;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.IDebugHelpContextIds;
@ -389,8 +389,8 @@ public class ModuleDetailPane extends AbstractDetailPane implements IAdaptable,
// service.getModuleData(modDmc, modData);
// }
IModuleDMContext dmc = null;
if (fElement instanceof AbstractDMVMLayoutNode.DMVMContext) {
IDMContext vmcdmc = ((AbstractDMVMLayoutNode.DMVMContext)fElement).getDMC();
if (fElement instanceof IDMVMContext) {
IDMContext vmcdmc = ((IDMVMContext)fElement).getDMContext();
dmc = DMContexts.getAncestorOfType(vmcdmc, IModuleDMContext.class);
}

View file

@ -41,8 +41,8 @@ public class ModuleDetailPaneFactory implements IDetailPaneFactory {
return null;
}
public Set getDetailPaneTypes(IStructuredSelection selection) {
Set possibleIDs = new HashSet(1);
public Set<?> getDetailPaneTypes(IStructuredSelection selection) {
Set<String> possibleIDs = new HashSet<String>(1);
possibleIDs.add(ModuleDetailPane.ID);
return possibleIDs;
}

View file

@ -10,32 +10,34 @@
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.modules;
import java.util.concurrent.RejectedExecutionException;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.DsfRunnable;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.datamodel.IDMEvent;
import org.eclipse.dd.dsf.debug.service.IModules;
import org.eclipse.dd.dsf.debug.service.IRegisters;
import org.eclipse.dd.dsf.debug.service.IRunControl;
import org.eclipse.dd.dsf.debug.service.IModules.IModuleDMContext;
import org.eclipse.dd.dsf.debug.service.IModules.IModuleDMData;
import org.eclipse.dd.dsf.debug.service.IModules.ISymbolDMContext;
import org.eclipse.dd.dsf.debug.service.IRegisters.IGroupChangedDMEvent;
import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin;
import org.eclipse.dd.dsf.debug.ui.IDsfDebugUIConstants;
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.VMDelta;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.update.VMCacheManager;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
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.ModelDelta;
@SuppressWarnings("restriction")
public class ModulesLayoutNode extends AbstractDMVMLayoutNode
public class ModulesVMNode extends AbstractDMVMNode
implements IElementLabelProvider
{
public ModulesLayoutNode(AbstractVMProvider provider, DsfSession session) {
public ModulesVMNode(AbstractDMVMProvider provider, DsfSession session) {
super(provider, session, IModuleDMContext.class);
}
@ -43,7 +45,7 @@ public class ModulesLayoutNode extends AbstractDMVMLayoutNode
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
if (!checkService(IRegisters.class, null, update)) return;
final ISymbolDMContext symDmc = findDmcInPath(update.getElementPath(), ISymbolDMContext.class) ;
final ISymbolDMContext symDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), ISymbolDMContext.class) ;
if (symDmc != null) {
getServicesTracker().getService(IModules.class).getModules(
@ -64,10 +66,24 @@ public class ModulesLayoutNode extends AbstractDMVMLayoutNode
}
@Override
public void update(final ILabelUpdate[] updates) {
try {
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
updateLabelInSessionThread(updates);
}});
} catch (RejectedExecutionException e) {
for (ILabelUpdate update : updates) {
handleFailedUpdate(update);
}
}
}
protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
for (final ILabelUpdate update : updates) {
final IModuleDMContext dmc = findDmcInPath(update.getElementPath(), IModuleDMContext.class);
final IModuleDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IModuleDMContext.class);
if (!checkDmc(dmc, update) || !checkService(IModules.class, null, update)) continue;
// Use different image for loaded and unloaded symbols when event to report loading of symbols is implemented.
update.setImageDescriptor(DsfDebugUIPlugin.getImageDescriptor(IDsfDebugUIConstants.IMG_OBJS_SHARED_LIBRARY_SYMBOLS_LOADED), 0);
@ -119,41 +135,19 @@ public class ModulesLayoutNode extends AbstractDMVMLayoutNode
}
}
@Override
protected int getNodeDeltaFlagsForDMEvent(IDMEvent<?> e) {
public int getDeltaFlags(Object e) {
if (e instanceof IRunControl.ISuspendedDMEvent) {
return IModelDelta.CONTENT;
}
else if (e instanceof IRegisters.IGroupsChangedDMEvent) {
return IModelDelta.CONTENT;
}
else if (e instanceof IRegisters.IGroupChangedDMEvent) {
return IModelDelta.STATE;
}
return IModelDelta.NO_CHANGE;
}
@Override
protected void buildDeltaForDMEvent(IDMEvent<?> e, VMDelta parent, int nodeOffset, RequestMonitor rm) {
public void buildDelta(Object e, ModelDelta parentDelta, int nodeOffset, RequestMonitor rm) {
if (e instanceof IRunControl.ISuspendedDMEvent) {
// Create a delta that indicates all groups have changed
parent.addFlags(IModelDelta.CONTENT);
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
}
else if (e instanceof IRegisters.IGroupsChangedDMEvent) {
// flush the cache
VMCacheManager.getVMCacheManager().flush(super.getVMProvider().getPresentationContext());
// Create a delta that indicates all groups have changed
parent.addFlags(IModelDelta.CONTENT);
}
else if (e instanceof IRegisters.IGroupChangedDMEvent) {
// flush the cache
VMCacheManager.getVMCacheManager().flush(super.getVMProvider().getPresentationContext());
// Create a delta that indicates that specific group changed
parent.addNode( createVMContext(((IGroupChangedDMEvent)e).getDMContext()), IModelDelta.STATE );
}
super.buildDeltaForDMEvent(e, parent, nodeOffset, rm);
rm.done();
}
}

View file

@ -12,10 +12,10 @@ package org.eclipse.dd.dsf.debug.ui.viewmodel.modules;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter;
import org.eclipse.dd.dsf.ui.viewmodel.IVMLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.IVMRootLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.IVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.dm.DMVMRootLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.dm.RootDMVMNode;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
/**
@ -32,17 +32,17 @@ public class ModulesVMProvider extends AbstractDMVMProvider {
/*
* Create the top level node to deal with the root selection.
*/
IVMRootLayoutNode debugViewSelection = new DMVMRootLayoutNode(this);
IRootVMNode rootNode = new RootDMVMNode(this);
/*
* Create the Group nodes next. They represent the first level shown in the view.
*/
IVMLayoutNode modulesNode = new ModulesLayoutNode(this, getSession());
debugViewSelection.setChildNodes(new IVMLayoutNode[] { modulesNode });
IVMNode modulesNode = new ModulesVMNode(this, getSession());
addChildNodes(rootNode, new IVMNode[] { modulesNode });
/*
* Now set this schema set as the layout set.
*/
setRootLayoutNode(debugViewSelection);
setRootNode(rootNode);
}
}

View file

@ -10,12 +10,9 @@
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.numberformat;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.dd.dsf.debug.service.IFormattedValues;
import org.eclipse.dd.dsf.debug.ui.viewmodel.IDebugVMConstants;
import org.eclipse.dd.dsf.ui.viewmodel.IVMAdapter;
import org.eclipse.dd.dsf.ui.viewmodel.IVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode.DMVMContext;
import org.eclipse.dd.dsf.ui.viewmodel.dm.IDMVMContext;
import org.eclipse.debug.core.model.IDebugElement;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
@ -126,25 +123,6 @@ public class AbstractSetFormatStyle implements IViewActionDelegate, IDebugContex
* Store the new style. So it will be picked up by the view when the view changes.
*/
context.setProperty( IDebugVMConstants.CURRENT_FORMAT_STORAGE, getFormatStyle() );
/*
* Now go tell the view to update. We do so by finding the VM provider for this view
* and telling it to redraw the entire view.
*/
if (fViewInput instanceof IAdaptable) {
IVMAdapter adapter = (IVMAdapter) ((IAdaptable)fViewInput).getAdapter(IVMAdapter.class);
if ( adapter != null ) {
IVMProvider provider = adapter.getVMProvider(context);
if ( provider != null ) {
/*
* "null" means redraw the entire view.
*/
provider.refresh( null );
}
}
}
}
}
}
@ -169,7 +147,7 @@ public class AbstractSetFormatStyle implements IViewActionDelegate, IDebugContex
Object element = ( (IStructuredSelection) selection ).getFirstElement();
if ( element instanceof DMVMContext ) { fViewInput = element; }
if (element instanceof IDMVMContext ) { fViewInput = element; }
else {
/*
* We deliberately do nothing here. A valid structured selection has already been
@ -202,7 +180,7 @@ public class AbstractSetFormatStyle implements IViewActionDelegate, IDebugContex
{
fAction.setEnabled(true);
}
else if ( fViewInput instanceof DMVMContext )
else if ( fViewInput instanceof IDMVMContext )
{
fAction.setEnabled(true);
}

View file

@ -38,7 +38,7 @@ import org.eclipse.dd.dsf.debug.service.IRegisters.IBitFieldDMContext;
import org.eclipse.dd.dsf.debug.service.IRegisters.IRegisterDMContext;
import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin;
import org.eclipse.dd.dsf.service.DsfServicesTracker;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode.DMVMContext;
import org.eclipse.dd.dsf.ui.viewmodel.dm.IDMVMContext;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.IDebugElement;
import org.eclipse.debug.core.model.IExpression;
@ -53,6 +53,7 @@ import org.eclipse.debug.internal.ui.actions.variables.details.DetailPaneMaxLeng
import org.eclipse.debug.internal.ui.actions.variables.details.DetailPaneWordWrapAction;
import org.eclipse.debug.internal.ui.preferences.IDebugPreferenceConstants;
import org.eclipse.debug.internal.ui.views.variables.IndexedValuePartition;
import org.eclipse.debug.internal.ui.views.variables.StatusLineContributionItem;
import org.eclipse.debug.internal.ui.views.variables.details.DetailMessages;
import org.eclipse.debug.ui.IDebugModelPresentation;
import org.eclipse.debug.ui.IDebugUIConstants;
@ -65,7 +66,6 @@ import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.action.StatusLineContributionItem;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
@ -315,7 +315,7 @@ public class NumberFormatDetailPane implements IDetailPane, IAdaptable, IPropert
/*
* Make sure this is an element we want to deal with.
*/
if ( element instanceof DMVMContext) {
if (element instanceof IDMVMContext) {
IFormattedValues service = null;
IFormattedDataDMContext dmc = null ;
@ -341,23 +341,23 @@ public class NumberFormatDetailPane implements IDetailPane, IAdaptable, IPropert
* register not the bit field.
*/
DsfServicesTracker tracker = new DsfServicesTracker(DsfDebugUIPlugin.getBundleContext(), ((DMVMContext) element).getDMC().getSessionId());
DsfServicesTracker tracker = new DsfServicesTracker(DsfDebugUIPlugin.getBundleContext(), ((IDMVMContext) element).getDMContext().getSessionId());
IBitFieldDMContext bitfieldDmc = DMContexts.getAncestorOfType(((DMVMContext) element).getDMC(), IBitFieldDMContext.class);
IBitFieldDMContext bitfieldDmc = DMContexts.getAncestorOfType(((IDMVMContext) element).getDMContext(), IBitFieldDMContext.class);
if ( bitfieldDmc != null ) {
dmc = bitfieldDmc ;
service = tracker.getService(IRegisters.class);
}
else {
IRegisterDMContext regDmc = DMContexts.getAncestorOfType(((DMVMContext) element).getDMC(), IRegisterDMContext.class);
IRegisterDMContext regDmc = DMContexts.getAncestorOfType(((IDMVMContext) element).getDMContext(), IRegisterDMContext.class);
if ( regDmc != null ) {
dmc = regDmc ;
service = tracker.getService(IRegisters.class);
}
else {
IExpressionDMContext exprDmc = DMContexts.getAncestorOfType(((DMVMContext) element).getDMC(), IExpressionDMContext.class);
IExpressionDMContext exprDmc = DMContexts.getAncestorOfType(((IDMVMContext) element).getDMContext(), IExpressionDMContext.class);
if ( exprDmc != null ) {
dmc = exprDmc ;

View file

@ -16,21 +16,27 @@ 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.numberformat.IFormattedValuePreferenceStore;
import org.eclipse.dd.dsf.ui.viewmodel.IVMContext;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.dm.IDMVMContext;
import org.eclipse.dd.dsf.ui.viewmodel.update.AbstractCachingVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.update.UserEditEvent;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
@SuppressWarnings("restriction")
public class RegisterBitFieldLayoutCellModifier extends WatchExpressionCellModifier {
public class RegisterBitFieldCellModifier extends WatchExpressionCellModifier {
public static enum BitFieldEditorStyle { NOTHING, BITFIELDCOMBO, BITFIELDTEXT }
private AbstractCachingVMProvider fProvider;
private BitFieldEditorStyle fStyle;
private IBitFieldDMData fBitFieldData = null;
private Object fElement = null;
private SyncRegisterDataAccess fDataAccess = null;
private IFormattedValuePreferenceStore fFormatPrefStore;
public RegisterBitFieldLayoutCellModifier( IFormattedValuePreferenceStore formatPrefStore, BitFieldEditorStyle style, SyncRegisterDataAccess access ) {
public RegisterBitFieldCellModifier(AbstractCachingVMProvider provider,
IFormattedValuePreferenceStore formatPrefStore, BitFieldEditorStyle style, SyncRegisterDataAccess access )
{
fProvider = provider;
fStyle = style;
fDataAccess = access;
fFormatPrefStore = formatPrefStore;
@ -40,8 +46,8 @@ public class RegisterBitFieldLayoutCellModifier extends WatchExpressionCellModif
* Used to make sure we are dealing with a valid register.
*/
private IBitFieldDMContext getBitFieldDMC(Object element) {
if (element instanceof AbstractDMVMLayoutNode.DMVMContext) {
IDMContext dmc = ((AbstractDMVMLayoutNode.DMVMContext)element).getDMC();
if (element instanceof IDMVMContext) {
IDMContext dmc = ((IDMVMContext)element).getDMContext();
return DMContexts.getAncestorOfType(dmc, IBitFieldDMContext.class);
}
return null;
@ -98,7 +104,7 @@ public class RegisterBitFieldLayoutCellModifier extends WatchExpressionCellModif
* Find the presentation context and then use it to get the current desired format.
*/
IVMContext ctx = (IVMContext) element;
IPresentationContext presCtx = ctx.getLayoutNode().getVMProvider().getPresentationContext();
IPresentationContext presCtx = ctx.getVMNode().getVMProvider().getPresentationContext();
formatId = fFormatPrefStore.getCurrentNumericFormat(presCtx);
}
@ -156,7 +162,7 @@ public class RegisterBitFieldLayoutCellModifier extends WatchExpressionCellModif
* Find the presentation context and then use it to get the current desired format.
*/
IVMContext ctx = (IVMContext) element;
IPresentationContext presCtx = ctx.getLayoutNode().getVMProvider().getPresentationContext();
IPresentationContext presCtx = ctx.getVMNode().getVMProvider().getPresentationContext();
formatId = fFormatPrefStore.getCurrentNumericFormat(presCtx);
}
@ -164,6 +170,7 @@ public class RegisterBitFieldLayoutCellModifier extends WatchExpressionCellModif
formatId = IFormattedValues.NATURAL_FORMAT;
}
fDataAccess.writeBitField(element, (String) value, formatId);
fProvider.handleEvent(new UserEditEvent(element));
}
}
else {
@ -177,6 +184,7 @@ public class RegisterBitFieldLayoutCellModifier extends WatchExpressionCellModif
* Write the bit field using the selected mnemonic.
*/
fDataAccess.writeBitField(element, fBitFieldData.getMnemonics()[val.intValue()]);
fProvider.handleEvent(new UserEditEvent(element));
}
}
} else {

View file

@ -10,14 +10,16 @@
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.register;
import java.util.concurrent.RejectedExecutionException;
import org.eclipse.core.runtime.CoreException;
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.DsfRunnable;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.datamodel.DMContexts;
import org.eclipse.dd.dsf.datamodel.IDMContext;
import org.eclipse.dd.dsf.datamodel.IDMEvent;
import org.eclipse.dd.dsf.debug.service.IFormattedValues;
import org.eclipse.dd.dsf.debug.service.IRegisters;
import org.eclipse.dd.dsf.debug.service.IRunControl;
@ -32,17 +34,15 @@ import org.eclipse.dd.dsf.debug.service.IRegisters.IRegisterGroupDMContext;
import org.eclipse.dd.dsf.debug.service.IRunControl.ISuspendedDMEvent;
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.expression.AbstractExpressionVMNode;
import org.eclipse.dd.dsf.debug.ui.viewmodel.numberformat.IFormattedValuePreferenceStore;
import org.eclipse.dd.dsf.debug.ui.viewmodel.numberformat.IFormattedValueVMContext;
import org.eclipse.dd.dsf.debug.ui.viewmodel.register.RegisterBitFieldLayoutCellModifier.BitFieldEditorStyle;
import org.eclipse.dd.dsf.debug.ui.viewmodel.register.RegisterBitFieldCellModifier.BitFieldEditorStyle;
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.dd.dsf.ui.viewmodel.update.VMCacheManager;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.dm.IDMVMContext;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.model.IDebugTarget;
@ -51,10 +51,13 @@ 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.IElementLabelProvider;
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.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.debug.ui.actions.IWatchExpressionFactoryAdapterExtension;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ComboBoxCellEditor;
import org.eclipse.jface.viewers.ICellModifier;
@ -63,7 +66,9 @@ import org.eclipse.jface.viewers.TreePath;
import org.eclipse.swt.widgets.Composite;
@SuppressWarnings("restriction")
public class RegisterBitFieldLayoutNode extends AbstractExpressionLayoutNode implements IElementEditor {
public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
implements IElementEditor, IElementLabelProvider
{
protected class BitFieldVMC extends DMVMContext
implements IVariable, IFormattedValueVMContext
@ -133,7 +138,7 @@ public class RegisterBitFieldLayoutNode extends AbstractExpressionLayoutNode imp
StringBuffer exprBuf = new StringBuffer();
IRegisterGroupDMContext groupDmc =
DMContexts.getAncestorOfType(bitFieldVmc.getDMC(), IRegisterGroupDMContext.class);
DMContexts.getAncestorOfType(bitFieldVmc.getDMContext(), IRegisterGroupDMContext.class);
if (groupDmc != null) {
exprBuf.append("$$\""); //$NON-NLS-1$
exprBuf.append(groupDmc.getName());
@ -141,14 +146,14 @@ public class RegisterBitFieldLayoutNode extends AbstractExpressionLayoutNode imp
}
IRegisterDMContext registerDmc =
DMContexts.getAncestorOfType(bitFieldVmc.getDMC(), IRegisterDMContext.class);
DMContexts.getAncestorOfType(bitFieldVmc.getDMContext(), IRegisterDMContext.class);
if (registerDmc != null) {
exprBuf.append('$');
exprBuf.append(registerDmc.getName());
}
IBitFieldDMContext bitFieldDmc =
DMContexts.getAncestorOfType(bitFieldVmc.getDMC(), IBitFieldDMContext.class);
DMContexts.getAncestorOfType(bitFieldVmc.getDMContext(), IBitFieldDMContext.class);
if (bitFieldDmc != null) {
exprBuf.append('.');
exprBuf.append(bitFieldDmc.getName());
@ -162,7 +167,7 @@ public class RegisterBitFieldLayoutNode extends AbstractExpressionLayoutNode imp
final protected BitFieldExpressionFactory fBitFieldExpressionFactory = new BitFieldExpressionFactory();
private final IFormattedValuePreferenceStore fFormattedPrefStore;
public RegisterBitFieldLayoutNode(IFormattedValuePreferenceStore prefStore, AbstractVMProvider provider, DsfSession session, SyncRegisterDataAccess access) {
public RegisterBitFieldVMNode(IFormattedValuePreferenceStore prefStore, AbstractDMVMProvider provider, DsfSession session, SyncRegisterDataAccess access) {
super(provider, session, IRegisters.IBitFieldDMContext.class);
fDataAccess = access;
fFormattedPrefStore = prefStore;
@ -237,9 +242,8 @@ public class RegisterBitFieldLayoutNode extends AbstractExpressionLayoutNode imp
*/
FormattedValueDMContext valueDmc = regService.getFormattedValueContext(dmc, finalFormatId);
VMCacheManager.getVMCacheManager().getCache(update.getPresentationContext())
.getModelData(regService,
valueDmc,
getDMVMProvider().getModelData(
RegisterBitFieldVMNode.this, update, regService, valueDmc,
new DataRequestMonitor<FormattedValueDMData>(getSession().getExecutor(), null) {
@Override
public void handleCompleted() {
@ -269,22 +273,29 @@ public class RegisterBitFieldLayoutNode extends AbstractExpressionLayoutNode imp
);
}
/*
* We override the Abstract method because we now need to perform an extra level of data fetch
* to get the formatted value represenatation of the register. Before we obtained the data from
* the IDMData returned for the Register DMC. Now basically the level of information returned
* is attribute information and the formatted value requires a separate transaction.
*
* @see org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode#updateLabelInSessionThread(org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate[])
*/
@Override
public void update(final ILabelUpdate[] updates) {
try {
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
updateLabelInSessionThread(updates);
}});
} catch (RejectedExecutionException e) {
for (ILabelUpdate update : updates) {
handleFailedUpdate(update);
}
}
}
protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
for (final ILabelUpdate update : updates) {
final IBitFieldDMContext dmc = findDmcInPath(update.getElementPath(), IRegisters.IBitFieldDMContext.class);
final IBitFieldDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IRegisters.IBitFieldDMContext.class);
VMCacheManager.getVMCacheManager().getCache(update.getPresentationContext())
.getModelData(getServicesTracker().getService(IRegisters.class),
getDMVMProvider().getModelData(
this, update,
getServicesTracker().getService(IRegisters.class),
dmc,
new DataRequestMonitor<IBitFieldDMData>(getSession().getExecutor(), null) {
@Override
@ -367,7 +378,7 @@ public class RegisterBitFieldLayoutNode extends AbstractExpressionLayoutNode imp
@Override
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
final IRegisterDMContext regDmc = findDmcInPath(update.getElementPath(), IRegisterDMContext.class);
final IRegisterDMContext regDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IRegisterDMContext.class);
if (regDmc == null) {
handleFailedUpdate(update);
@ -391,61 +402,49 @@ public class RegisterBitFieldLayoutNode extends AbstractExpressionLayoutNode imp
}
@Override
protected IVMContext createVMContext(IDMContext dmc) {
protected IDMVMContext createVMContext(IDMContext dmc) {
return new BitFieldVMC(dmc);
}
@Override
protected int getNodeDeltaFlagsForDMEvent(IDMEvent<?> e) {
// In theory we want each node to act independently in terms of events. It might be
// the case that we would only have elements of this type at the root level. It is
// the case that the current layout model always starts with the GROUPS followed by
// REGISTERS followed by BITFIELDS. But if we do this when a run-control event has
// occured we generate a DELTA for every element, which can create a massive list
// of entries all of which say update the entire view. So for now we will just have
// the GROUP LAYOUT node do this. Later we need to revisit the logic and make sure
// there is a way for the nodes to operate independently and efficiently.
//
//if (e instanceof IRunControl.ISuspendedDMEvent) {
// return IModelDelta.CONTENT;
//}
public int getDeltaFlags(Object e) {
if (e instanceof IRunControl.ISuspendedDMEvent) {
return IModelDelta.CONTENT;
}
if (e instanceof IRegisters.IBitFieldChangedDMEvent) {
return IModelDelta.STATE;
}
if (e instanceof PropertyChangeEvent &&
((PropertyChangeEvent)e).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE)
{
return IModelDelta.CONTENT;
}
return IModelDelta.NO_CHANGE;
}
@Override
protected void buildDeltaForDMEvent(IDMEvent<?> e, VMDelta parent, int nodeOffset, RequestMonitor rm) {
// In theory we want each node to act independently in terms of events. It might be
// the case that we would only have elements of this type at the root level. It is
// the case that the current layout model always starts with the GROUPS followed by
// REGISTERS followed by BITFIELDS. But if we do this when a run-control event has
// occured we generate a DELTA for every element, which can create a massive list
// of entries all of which say update the entire view. So for now we will just have
// the GROUP LAYOUT node do this. Later we need to revisit the logic and make sure
// there is a way for the nodes to operate independently and efficiently.
//
// if (e instanceof IRunControl.ISuspendedDMEvent) {
// // Create a delta that the whole register group has changed.
// parent.addFlags(IModelDelta.CONTENT);
// }
public void buildDelta(Object e, ModelDelta parentDelta, int nodeOffset, RequestMonitor rm) {
if (e instanceof IRunControl.ISuspendedDMEvent) {
// Create a delta that the whole register group has changed.
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
}
if (e instanceof IRegisters.IBitFieldChangedDMEvent) {
/*
* Flush the cache.
*/
VMCacheManager.getVMCacheManager().flush(super.getVMProvider().getPresentationContext());
/*
* Create a delta indicating the bit field has changed.
*/
parent.addNode( createVMContext(((IRegisters.IBitFieldChangedDMEvent)e).getDMContext()), IModelDelta.STATE );
parentDelta.addNode( createVMContext(((IRegisters.IBitFieldChangedDMEvent)e).getDMContext()), IModelDelta.STATE );
}
if (e instanceof PropertyChangeEvent &&
((PropertyChangeEvent)e).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE)
{
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
}
super.buildDeltaForDMEvent(e, parent, nodeOffset, rm);
rm.done();
}
public CellEditor getCellEditor(IPresentationContext context, String columnId, Object element, Composite parent) {
@ -510,13 +509,15 @@ public class RegisterBitFieldLayoutNode extends AbstractExpressionLayoutNode imp
/*
* Note we are complex COMBO and return the right editor.
*/
return new RegisterBitFieldLayoutCellModifier( fFormattedPrefStore, BitFieldEditorStyle.BITFIELDCOMBO, fDataAccess );
return new RegisterBitFieldCellModifier(
getDMVMProvider(), fFormattedPrefStore, BitFieldEditorStyle.BITFIELDCOMBO, fDataAccess );
}
else {
/*
* Text editor even if we need to clamp the value entered.
*/
return new RegisterBitFieldLayoutCellModifier( fFormattedPrefStore, BitFieldEditorStyle.BITFIELDTEXT, fDataAccess );
return new RegisterBitFieldCellModifier(
getDMVMProvider(), fFormattedPrefStore, BitFieldEditorStyle.BITFIELDTEXT, fDataAccess );
}
}
else {
@ -525,22 +526,22 @@ public class RegisterBitFieldLayoutNode extends AbstractExpressionLayoutNode imp
}
@Override
protected void testContextForExpression(Object element, final String expression, final DataRequestMonitor<Boolean> rm) {
if (!(element instanceof AbstractDMVMLayoutNode.DMVMContext)) {
protected void testElementForExpression(Object element, IExpression expression, DataRequestMonitor<Boolean> rm) {
if (!(element instanceof IDMVMContext)) {
rm.setStatus(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, IDsfService.INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
rm.done();
return;
}
final IBitFieldDMContext dmc = DMContexts.getAncestorOfType(((DMVMContext)element).getDMC(), IBitFieldDMContext.class);
final IBitFieldDMContext dmc = DMContexts.getAncestorOfType(((IDMVMContext)element).getDMContext(), IBitFieldDMContext.class);
if (dmc == null) {
rm.setStatus(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, IDsfService.INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
rm.done();
return;
}
String bitFieldName = expression.substring(1);
if (bitFieldName.equals(dmc.getName())) {
String bitFieldName = parseExpressionForBitFieldName(expression.getExpressionText());
if (dmc.getName().equals(bitFieldName)) {
rm.setData(Boolean.TRUE);
} else {
rm.setData(Boolean.FALSE);
@ -548,6 +549,38 @@ public class RegisterBitFieldLayoutNode extends AbstractExpressionLayoutNode imp
rm.done();
}
public boolean canParseExpression(IExpression expression) {
return parseExpressionForBitFieldName(expression.getExpressionText()) != null;
}
/**
* Expected format: $$"Group Name"$Register_Name.Bit_Field_Name
*/
private String parseExpressionForBitFieldName(String expression) {
if (expression.startsWith("$$\"")) { //$NON-NLS-1$
int secondQuoteIdx = expression.indexOf('"', "$$\"".length()); //$NON-NLS-1$
if (secondQuoteIdx > 0) {
String registerSubString = expression.substring(secondQuoteIdx + 1);
if (registerSubString.length() != 0 &&
registerSubString.charAt(0) == '$' &&
Character.isLetterOrDigit(registerSubString.charAt(1)))
{
int registerEnd = 1;
while ( registerEnd < registerSubString.length() &&
Character.isLetterOrDigit(registerSubString.charAt(registerEnd)) )
{
registerEnd++;
}
if ((registerEnd + 1) < registerSubString.length() && '.' == registerSubString.charAt(registerEnd)) {
return registerSubString.substring(registerEnd + 1);
}
}
}
}
return null;
}
public int getExpressionLength(String expression) {
if (expression.charAt(0) == '.' && Character.isLetterOrDigit(expression.charAt(1))) {
int length = 1;
@ -567,35 +600,43 @@ public class RegisterBitFieldLayoutNode extends AbstractExpressionLayoutNode imp
}
}
@Override
protected int getDeltaFlagsForExpressionPart(Object event) {
public int getDeltaFlagsForExpression(IExpression expression, Object event) {
if (event instanceof IRunControl.ISuspendedDMEvent) {
return IModelDelta.CONTENT;
}
if (event instanceof PropertyChangeEvent &&
((PropertyChangeEvent)event).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE)
{
return IModelDelta.CONTENT;
}
return IModelDelta.NO_CHANGE;
}
@Override
public void buildDeltaForExpression(final IExpression expression, final int elementIdx, final String expressionText, final Object event, final VMDelta parentDelta, final TreePath path, final RequestMonitor rm)
public void buildDeltaForExpression(final IExpression expression, final int elementIdx, final Object event, final ModelDelta parentDelta, final TreePath path, final RequestMonitor rm)
{
if (event instanceof ISuspendedDMEvent) {
// Mark the partent delta indicating that elements were added and/or removed.
parentDelta.addFlags(IModelDelta.CONTENT);
// Mark the parent delta indicating that elements were added and/or removed.
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
} else if (event instanceof IRegisters.IRegisterChangedDMEvent) {
parentDelta.addFlags(IModelDelta.CONTENT);
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
}
super.buildDeltaForExpression(expression, elementIdx, expressionText, event, parentDelta, path, rm);
rm.done();
}
@Override
protected void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, VMDelta parentDelta, final RequestMonitor rm)
public void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, ModelDelta parentDelta, final RequestMonitor rm)
{
if (event instanceof IBitFieldChangedDMEvent) {
parentDelta.addNode(element, IModelDelta.STATE);
}
super.buildDeltaForExpressionElement(element, elementIdx, event, parentDelta, rm);
if (event instanceof PropertyChangeEvent &&
((PropertyChangeEvent)event).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE)
{
parentDelta.addNode(element, IModelDelta.CONTENT);
}
rm.done();
}
}

View file

@ -19,16 +19,22 @@ 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.numberformat.IFormattedValuePreferenceStore;
import org.eclipse.dd.dsf.ui.viewmodel.IVMContext;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.dm.IDMVMContext;
import org.eclipse.dd.dsf.ui.viewmodel.update.AbstractCachingVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.update.UserEditEvent;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
@SuppressWarnings("restriction")
public class RegisterLayoutValueCellModifier extends WatchExpressionCellModifier {
public class RegisterCellModifier extends WatchExpressionCellModifier {
private AbstractCachingVMProvider fProvider;
private SyncRegisterDataAccess fDataAccess = null;
private IFormattedValuePreferenceStore fFormattedValuePreferenceStore;
public RegisterLayoutValueCellModifier(IFormattedValuePreferenceStore formattedValuePreferenceStore, SyncRegisterDataAccess access) {
public RegisterCellModifier(AbstractCachingVMProvider provider,
IFormattedValuePreferenceStore formattedValuePreferenceStore, SyncRegisterDataAccess access)
{
fProvider = provider;
fDataAccess = access;
fFormattedValuePreferenceStore = formattedValuePreferenceStore;
}
@ -44,8 +50,8 @@ public class RegisterLayoutValueCellModifier extends WatchExpressionCellModifier
* Used to make sure we are dealing with a valid register.
*/
protected IRegisterDMContext getRegisterDMC(Object element) {
if (element instanceof AbstractDMVMLayoutNode.DMVMContext) {
IDMContext dmc = ((AbstractDMVMLayoutNode.DMVMContext)element).getDMC();
if (element instanceof IDMVMContext) {
IDMContext dmc = ((IDMVMContext)element).getDMContext();
return DMContexts.getAncestorOfType(dmc, IRegisterDMContext.class);
}
return null;
@ -95,7 +101,7 @@ public class RegisterLayoutValueCellModifier extends WatchExpressionCellModifier
* Find the presentation context and then use it to get the current desired format.
*/
IVMContext ctx = (IVMContext) element;
IPresentationContext presCtx = ctx.getLayoutNode().getVMProvider().getPresentationContext();
IPresentationContext presCtx = ctx.getVMNode().getVMProvider().getPresentationContext();
formatId = fFormattedValuePreferenceStore.getCurrentNumericFormat(presCtx);
}
@ -134,7 +140,7 @@ public class RegisterLayoutValueCellModifier extends WatchExpressionCellModifier
* Find the presentation context and then use it to get the current desired format.
*/
IVMContext ctx = (IVMContext) element;
IPresentationContext presCtx = ctx.getLayoutNode().getVMProvider().getPresentationContext();
IPresentationContext presCtx = ctx.getVMNode().getVMProvider().getPresentationContext();
formatId = fFormattedValuePreferenceStore.getCurrentNumericFormat(presCtx);
}
@ -143,6 +149,7 @@ public class RegisterLayoutValueCellModifier extends WatchExpressionCellModifier
}
fDataAccess.writeRegister(element, (String) value, formatId);
fProvider.handleEvent(new UserEditEvent(element));
}
} else {
super.modify(element, property, value);

View file

@ -10,14 +10,16 @@
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.register;
import java.util.concurrent.RejectedExecutionException;
import org.eclipse.core.runtime.CoreException;
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.DsfRunnable;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.datamodel.DMContexts;
import org.eclipse.dd.dsf.datamodel.IDMContext;
import org.eclipse.dd.dsf.datamodel.IDMEvent;
import org.eclipse.dd.dsf.debug.service.IRegisters;
import org.eclipse.dd.dsf.debug.service.IRunControl;
import org.eclipse.dd.dsf.debug.service.IRegisters.IGroupChangedDMEvent;
@ -25,16 +27,14 @@ import org.eclipse.dd.dsf.debug.service.IRegisters.IRegisterGroupDMContext;
import org.eclipse.dd.dsf.debug.service.IRegisters.IRegisterGroupDMData;
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.expression.AbstractExpressionVMNode;
import org.eclipse.dd.dsf.debug.ui.viewmodel.expression.WatchExpressionCellModifier;
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.dd.dsf.ui.viewmodel.dm.AbstractDMVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.dm.CompositeDMVMContext;
import org.eclipse.dd.dsf.ui.viewmodel.update.VMCacheManager;
import org.eclipse.dd.dsf.ui.viewmodel.dm.IDMVMContext;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.model.IDebugTarget;
@ -44,9 +44,11 @@ import org.eclipse.debug.core.model.IVariable;
import org.eclipse.debug.internal.ui.DebugPluginImages;
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.IElementLabelProvider;
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.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.debug.ui.actions.IWatchExpressionFactoryAdapterExtension;
import org.eclipse.jface.viewers.CellEditor;
@ -56,8 +58,8 @@ import org.eclipse.jface.viewers.TreePath;
import org.eclipse.swt.widgets.Composite;
@SuppressWarnings("restriction")
public class RegisterGroupLayoutNode extends AbstractExpressionLayoutNode
implements IElementEditor
public class RegisterGroupVMNode extends AbstractExpressionVMNode
implements IElementEditor, IElementLabelProvider
{
protected class RegisterGroupVMC extends DMVMContext implements IVariable
@ -122,7 +124,7 @@ public class RegisterGroupLayoutNode extends AbstractExpressionLayoutNode
RegisterGroupVMC registerVmc = ((RegisterGroupVMC)variable);
StringBuffer exprBuf = new StringBuffer();
IRegisterGroupDMContext groupDmc = DMContexts.getAncestorOfType(registerVmc.getDMC(), IRegisterGroupDMContext.class);
IRegisterGroupDMContext groupDmc = DMContexts.getAncestorOfType(registerVmc.getDMContext(), IRegisterGroupDMContext.class);
if (groupDmc != null) {
exprBuf.append("$$\""); //$NON-NLS-1$
exprBuf.append(groupDmc.getName());
@ -138,7 +140,7 @@ public class RegisterGroupLayoutNode extends AbstractExpressionLayoutNode
final protected RegisterGroupExpressionFactory fRegisterGroupExpressionFactory = new RegisterGroupExpressionFactory();
private WatchExpressionCellModifier fWatchExpressionCellModifier = new WatchExpressionCellModifier();
public RegisterGroupLayoutNode(AbstractVMProvider provider, DsfSession session, SyncRegisterDataAccess syncDataAccess) {
public RegisterGroupVMNode(AbstractDMVMProvider provider, DsfSession session, SyncRegisterDataAccess syncDataAccess) {
super(provider, session, IRegisters.IRegisterGroupDMContext.class);
fSyncRegisterDataAccess = syncDataAccess;
}
@ -149,11 +151,8 @@ public class RegisterGroupLayoutNode extends AbstractExpressionLayoutNode
@Override
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
if (!checkService(IRegisters.class, null, update)) return;
CompositeDMVMContext compositeDmc = new CompositeDMVMContext(getVMProvider().getRootElement(), update.getElementPath());
getServicesTracker().getService(IRegisters.class).getRegisterGroups(
compositeDmc,
new CompositeDMVMContext(update),
new DataRequestMonitor<IRegisterGroupDMContext[]>(getSession().getExecutor(), null) {
@Override
public void handleCompleted() {
@ -167,19 +166,33 @@ public class RegisterGroupLayoutNode extends AbstractExpressionLayoutNode
}
@Override
protected IVMContext createVMContext(IDMContext dmc) {
protected IDMVMContext createVMContext(IDMContext dmc) {
return new RegisterGroupVMC(dmc);
}
@Override
public void update(final ILabelUpdate[] updates) {
try {
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
updateLabelInSessionThread(updates);
}});
} catch (RejectedExecutionException e) {
for (ILabelUpdate update : updates) {
handleFailedUpdate(update);
}
}
}
protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
for (final ILabelUpdate update : updates) {
final IRegisterGroupDMContext dmc = findDmcInPath(update.getElementPath(), IRegisterGroupDMContext.class);
final IRegisterGroupDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IRegisterGroupDMContext.class);
if (!checkDmc(dmc, update) || !checkService(IRegisters.class, null, update)) continue;
VMCacheManager.getVMCacheManager().getCache(update.getPresentationContext())
.getModelData(getServicesTracker().getService(IRegisters.class, null),
getDMVMProvider().getModelData(
this, update,
getServicesTracker().getService(IRegisters.class, null),
dmc,
new DataRequestMonitor<IRegisterGroupDMData>(getSession().getExecutor(), null) {
@Override
@ -247,8 +260,7 @@ public class RegisterGroupLayoutNode extends AbstractExpressionLayoutNode
}
}
@Override
protected int getNodeDeltaFlagsForDMEvent(IDMEvent<?> e) {
public int getDeltaFlags(Object e) {
if (e instanceof IRunControl.ISuspendedDMEvent) {
return IModelDelta.CONTENT;
}
@ -261,28 +273,37 @@ public class RegisterGroupLayoutNode extends AbstractExpressionLayoutNode
return IModelDelta.NO_CHANGE;
}
@Override
protected void buildDeltaForDMEvent(IDMEvent<?> e, VMDelta parent, int nodeOffset, RequestMonitor rm) {
public void buildDelta(Object e, ModelDelta parentDelta, int nodeOffset, RequestMonitor rm) {
if (e instanceof IRunControl.ISuspendedDMEvent) {
// Create a delta that indicates all groups have changed
parent.addFlags(IModelDelta.CONTENT);
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
}
else if (e instanceof IRegisters.IGroupsChangedDMEvent) {
// flush the cache
VMCacheManager.getVMCacheManager().flush(super.getVMProvider().getPresentationContext());
// Create a delta that indicates all groups have changed
parent.addFlags(IModelDelta.CONTENT);
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
}
else if (e instanceof IRegisters.IGroupChangedDMEvent) {
// flush the cache
VMCacheManager.getVMCacheManager().flush(super.getVMProvider().getPresentationContext());
// Create a delta that indicates that specific group changed
parent.addNode( createVMContext(((IGroupChangedDMEvent)e).getDMContext()), IModelDelta.STATE );
parentDelta.addNode( createVMContext(((IGroupChangedDMEvent)e).getDMContext()), IModelDelta.STATE );
}
super.buildDeltaForDMEvent(e, parent, nodeOffset, rm);
rm.done();
}
public boolean canParseExpression(IExpression expression) {
return parseExpressionForGroupName(expression.getExpressionText()) != null;
}
/**
* Expected format: $$"Group Name"$Register_Name.Bit_Field_Name
*/
private String parseExpressionForGroupName(String expression) {
if (expression.startsWith("$$\"")) { //$NON-NLS-1$
int secondQuoteIdx = expression.indexOf('"', "$$\"".length()); //$NON-NLS-1$
if (secondQuoteIdx > 0) {
return expression.substring(3, secondQuoteIdx);
}
}
return null;
}
public int getExpressionLength(String expression) {
@ -295,8 +316,7 @@ public class RegisterGroupLayoutNode extends AbstractExpressionLayoutNode
return -1;
}
@Override
protected int getDeltaFlagsForExpressionPart(Object event) {
public int getDeltaFlagsForExpression(IExpression expression, Object event) {
if (event instanceof IRunControl.ISuspendedDMEvent) {
return IModelDelta.CONTENT;
}
@ -304,19 +324,17 @@ public class RegisterGroupLayoutNode extends AbstractExpressionLayoutNode
return IModelDelta.NO_CHANGE;
}
@Override
public void buildDeltaForExpression(final IExpression expression, final int elementIdx, final String expressionText, final Object event, final VMDelta parentDelta, final TreePath path, final RequestMonitor rm)
public void buildDeltaForExpression(IExpression expression, int elementIdx, Object event, ModelDelta parentDelta,
TreePath path, RequestMonitor rm)
{
if (event instanceof IRunControl.ISuspendedDMEvent) {
// Mark the partent delta indicating that elements were added and/or removed.
parentDelta.addFlags(IModelDelta.CONTENT);
// Mark the parent delta indicating that elements were added and/or removed.
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
}
super.buildDeltaForExpression(expression, elementIdx, expressionText, event, parentDelta, path, rm);
rm.done();
}
@Override
protected void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, VMDelta parentDelta, final RequestMonitor rm)
public void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, ModelDelta parentDelta, final RequestMonitor rm)
{
if (event instanceof IRegisters.IGroupsChangedDMEvent) {
parentDelta.addNode(element, IModelDelta.CONTENT);
@ -324,28 +342,25 @@ public class RegisterGroupLayoutNode extends AbstractExpressionLayoutNode
if (event instanceof IRegisters.IGroupChangedDMEvent) {
parentDelta.addNode(element, IModelDelta.STATE);
}
super.buildDeltaForExpressionElement(element, elementIdx, event, parentDelta, rm);
rm.done();
}
@Override
protected void testContextForExpression(Object element, final String expression, final DataRequestMonitor<Boolean> rm) {
if (!(element instanceof AbstractDMVMLayoutNode.DMVMContext)) {
protected void testElementForExpression(Object element, IExpression expression, DataRequestMonitor<Boolean> rm) {
if (!(element instanceof IDMVMContext)) {
rm.setStatus(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, IDsfService.INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
rm.done();
return;
}
final IRegisterGroupDMContext dmc = DMContexts.getAncestorOfType(((DMVMContext)element).getDMC(), IRegisterGroupDMContext.class);
final IRegisterGroupDMContext dmc = DMContexts.getAncestorOfType(((IDMVMContext)element).getDMContext(), IRegisterGroupDMContext.class);
if (dmc == null) {
rm.setStatus(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, IDsfService.INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
rm.done();
return;
}
int startIdx = "$$\"".length(); //$NON-NLS-1$
int endIdx = expression.indexOf('"', startIdx);
String groupName = expression.substring(startIdx, endIdx);
if (groupName.equals(dmc.getName())) {
String groupName = parseExpressionForGroupName(expression.getExpressionText());
if (dmc.getName().equals(groupName)) {
rm.setData(Boolean.TRUE);
} else {
rm.setData(Boolean.FALSE);

View file

@ -10,14 +10,16 @@
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.register;
import java.util.concurrent.RejectedExecutionException;
import org.eclipse.core.runtime.CoreException;
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.DsfRunnable;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.datamodel.DMContexts;
import org.eclipse.dd.dsf.datamodel.IDMContext;
import org.eclipse.dd.dsf.datamodel.IDMEvent;
import org.eclipse.dd.dsf.debug.service.IFormattedValues;
import org.eclipse.dd.dsf.debug.service.IRegisters;
import org.eclipse.dd.dsf.debug.service.IRunControl;
@ -29,17 +31,15 @@ import org.eclipse.dd.dsf.debug.service.IRegisters.IRegisterDMData;
import org.eclipse.dd.dsf.debug.service.IRegisters.IRegisterGroupDMContext;
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.expression.AbstractExpressionVMNode;
import org.eclipse.dd.dsf.debug.ui.viewmodel.numberformat.IFormattedValuePreferenceStore;
import org.eclipse.dd.dsf.debug.ui.viewmodel.numberformat.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.dd.dsf.ui.viewmodel.dm.AbstractDMVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.dm.CompositeDMVMContext;
import org.eclipse.dd.dsf.ui.viewmodel.update.VMCacheManager;
import org.eclipse.dd.dsf.ui.viewmodel.dm.IDMVMContext;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.model.IDebugTarget;
@ -51,11 +51,14 @@ import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
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.IElementLabelProvider;
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.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.debug.ui.actions.IWatchExpressionFactoryAdapterExtension;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.TextCellEditor;
@ -63,8 +66,8 @@ import org.eclipse.jface.viewers.TreePath;
import org.eclipse.swt.widgets.Composite;
@SuppressWarnings("restriction")
public class RegisterLayoutNode extends AbstractExpressionLayoutNode
implements IElementEditor
public class RegisterVMNode extends AbstractExpressionVMNode
implements IElementEditor, IElementLabelProvider
{
protected class RegisterVMC extends DMVMContext
implements IVariable, IFormattedValueVMContext
@ -134,7 +137,7 @@ public class RegisterLayoutNode extends AbstractExpressionLayoutNode
StringBuffer exprBuf = new StringBuffer();
IRegisterGroupDMContext groupDmc =
DMContexts.getAncestorOfType(registerVmc.getDMC(), IRegisterGroupDMContext.class);
DMContexts.getAncestorOfType(registerVmc.getDMContext(), IRegisterGroupDMContext.class);
if (groupDmc != null) {
exprBuf.append("$$\""); //$NON-NLS-1$
exprBuf.append(groupDmc.getName());
@ -142,7 +145,7 @@ public class RegisterLayoutNode extends AbstractExpressionLayoutNode
}
IRegisterDMContext registerDmc =
DMContexts.getAncestorOfType(registerVmc.getDMC(), IRegisterDMContext.class);
DMContexts.getAncestorOfType(registerVmc.getDMContext(), IRegisterDMContext.class);
if (registerDmc != null) {
exprBuf.append('$');
exprBuf.append(registerDmc.getName());
@ -157,7 +160,7 @@ public class RegisterLayoutNode extends AbstractExpressionLayoutNode
final private SyncRegisterDataAccess fSyncRegisterDataAccess;
private final IFormattedValuePreferenceStore fFormattedPrefStore;
public RegisterLayoutNode(IFormattedValuePreferenceStore prefStore, AbstractVMProvider provider, DsfSession session, SyncRegisterDataAccess syncDataAccess) {
public RegisterVMNode(IFormattedValuePreferenceStore prefStore, AbstractDMVMProvider provider, DsfSession session, SyncRegisterDataAccess syncDataAccess) {
super(provider, session, IRegisters.IRegisterDMContext.class);
fSyncRegisterDataAccess = syncDataAccess;
fFormattedPrefStore = prefStore;
@ -237,8 +240,8 @@ public class RegisterLayoutNode extends AbstractExpressionLayoutNode
*/
final FormattedValueDMContext valueDmc = regService.getFormattedValueContext(dmc, finalFormatId);
VMCacheManager.getVMCacheManager().getCache( context ).getModelData(regService,
valueDmc,
getDMVMProvider().getModelData(
RegisterVMNode.this, update, regService, valueDmc,
new DataRequestMonitor<FormattedValueDMData>(getSession().getExecutor(), null) {
@Override
public void handleCompleted() {
@ -252,8 +255,9 @@ public class RegisterLayoutNode extends AbstractExpressionLayoutNode
update.setLabel(getData().getFormattedValue(), labelIndex);
// color based on change history
FormattedValueDMData oldData = (FormattedValueDMData) VMCacheManager.getVMCacheManager()
.getCache(context).getArchivedModelData(valueDmc);
FormattedValueDMData oldData = (FormattedValueDMData) getDMVMProvider().getArchivedModelData(
RegisterVMNode.this, update, valueDmc);
if(oldData != null && !oldData.getFormattedValue().equals(getData().getFormattedValue())) {
update.setBackground(
DebugUIPlugin.getPreferenceColor(
@ -269,112 +273,116 @@ public class RegisterLayoutNode extends AbstractExpressionLayoutNode
}
);
}
public void update(final ILabelUpdate[] updates) {
try {
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
updateLabelInSessionThread(updates);
}});
} catch (RejectedExecutionException e) {
for (ILabelUpdate update : updates) {
handleFailedUpdate(update);
}
}
}
/*
* We override the Abstract method because we now need to perform an extra level of data fetch
* to get the formatted value represenatation of the register. Before we obtained the data from
* the IDMData returned for the Register DMC. Now basically the level of information returned
* is attribute information and the formatted value requires a separate transaction.
*
* @see org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode#updateLabelInSessionThread(org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate[])
*/
@Override
protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
for (final ILabelUpdate update : updates) {
final IRegisterDMContext dmc = findDmcInPath(update.getElementPath(), IRegisters.IRegisterDMContext.class);
final IRegisterDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IRegisters.IRegisterDMContext.class);
if (!checkDmc(dmc, update) || !checkService(IRegisters.class, null, update)) continue;
VMCacheManager.getVMCacheManager().getCache(update.getPresentationContext())
.getModelData(getServicesTracker().getService(IRegisters.class),
dmc,
new DataRequestMonitor<IRegisterDMData>(getSession().getExecutor(), null) {
@Override
protected void handleCompleted() {
/*
* Check that the request was evaluated and data is still
* valid. The request could fail if the state of the
* service changed during the request, but the view model
* has not been updated yet.
*/
if (!getStatus().isOK()) {
assert getStatus().isOK() ||
getStatus().getCode() != IDsfService.INTERNAL_ERROR ||
getStatus().getCode() != IDsfService.NOT_SUPPORTED;
handleFailedUpdate(update);
return;
}
/*
* If columns are configured, extract the selected values for each
* understood column. First we fill all of those columns which can
* be filled without the extra data mining. We also note if we do
* have to datamine. Any columns need to set the processing flag
* so we know we have further work to do. If there are more columns
* which need data extraction they need to be added in both "for"
* loops.
*/
String[] localColumns = update.getPresentationContext().getColumns();
if (localColumns == null) localColumns = new String[] { IDebugVMConstants.COLUMN_ID__NAME };
boolean weAreExtractingFormattedData = false;
for (int idx = 0; idx < localColumns.length; idx++) {
if (IDebugVMConstants.COLUMN_ID__NAME.equals(localColumns[idx])) {
getDMVMProvider().getModelData(
this, update,
getServicesTracker().getService(IRegisters.class),
dmc,
new DataRequestMonitor<IRegisterDMData>(getSession().getExecutor(), null) {
@Override
protected void handleCompleted() {
/*
* Check that the request was evaluated and data is still
* valid. The request could fail if the state of the
* service changed during the request, but the view model
* has not been updated yet.
*/
if (!getStatus().isOK()) {
assert getStatus().isOK() ||
getStatus().getCode() != IDsfService.INTERNAL_ERROR ||
getStatus().getCode() != IDsfService.NOT_SUPPORTED;
handleFailedUpdate(update);
return;
}
/*
* If columns are configured, extract the selected values for each
* understood column. First we fill all of those columns which can
* be filled without the extra data mining. We also note if we do
* have to datamine. Any columns need to set the processing flag
* so we know we have further work to do. If there are more columns
* which need data extraction they need to be added in both "for"
* loops.
*/
String[] localColumns = update.getPresentationContext().getColumns();
if (localColumns == null) localColumns = new String[] { IDebugVMConstants.COLUMN_ID__NAME };
boolean weAreExtractingFormattedData = false;
for (int idx = 0; idx < localColumns.length; idx++) {
if (IDebugVMConstants.COLUMN_ID__NAME.equals(localColumns[idx])) {
update.setLabel(getData().getName(), idx);
update.setImageDescriptor(DebugPluginImages.getImageDescriptor(IDebugUIConstants.IMG_OBJS_REGISTER), idx);
} else if (IDebugVMConstants.COLUMN_ID__VALUE.equals(localColumns[idx])) {
weAreExtractingFormattedData = true;
} else if (IDebugVMConstants.COLUMN_ID__TYPE.equals(localColumns[idx])) {
IRegisterDMData data = getData();
String typeStr = "Unsigned"; //$NON-NLS-1$
String ReadAttrStr = "ReadNone"; //$NON-NLS-1$
String WriteAddrStr = "WriteNone"; //$NON-NLS-1$
if ( data.isFloat() ) { typeStr = "Floating Point"; } //$NON-NLS-1$
if ( data.isReadOnce() ) { ReadAttrStr = "ReadOnce"; } //$NON-NLS-1$
else if ( data.isReadable() ) { ReadAttrStr = "Readable"; } //$NON-NLS-1$
if ( data.isReadOnce() ) { WriteAddrStr = "WriteOnce"; } //$NON-NLS-1$
else if ( data.isReadable() ) { WriteAddrStr = "Writeable"; } //$NON-NLS-1$
typeStr += " - " + ReadAttrStr + "/" + WriteAddrStr; //$NON-NLS-1$ //$NON-NLS-2$
update.setLabel(typeStr, idx);
} else if (IDebugVMConstants.COLUMN_ID__DESCRIPTION.equals(localColumns[idx])) {
update.setLabel(getData().getDescription(), idx);
} else if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(localColumns[idx])) {
IVMContext vmc = (IVMContext)update.getElement();
IExpression expression = (IExpression)vmc.getAdapter(IExpression.class);
if (expression != null) {
update.setLabel(expression.getExpressionText(), idx);
} else {
update.setLabel(getData().getName(), idx);
update.setImageDescriptor(DebugPluginImages.getImageDescriptor(IDebugUIConstants.IMG_OBJS_REGISTER), idx);
} else if (IDebugVMConstants.COLUMN_ID__VALUE.equals(localColumns[idx])) {
weAreExtractingFormattedData = true;
} else if (IDebugVMConstants.COLUMN_ID__TYPE.equals(localColumns[idx])) {
IRegisterDMData data = getData();
String typeStr = "Unsigned"; //$NON-NLS-1$
String ReadAttrStr = "ReadNone"; //$NON-NLS-1$
String WriteAddrStr = "WriteNone"; //$NON-NLS-1$
if ( data.isFloat() ) { typeStr = "Floating Point"; } //$NON-NLS-1$
if ( data.isReadOnce() ) { ReadAttrStr = "ReadOnce"; } //$NON-NLS-1$
else if ( data.isReadable() ) { ReadAttrStr = "Readable"; } //$NON-NLS-1$
if ( data.isReadOnce() ) { WriteAddrStr = "WriteOnce"; } //$NON-NLS-1$
else if ( data.isReadable() ) { WriteAddrStr = "Writeable"; } //$NON-NLS-1$
typeStr += " - " + ReadAttrStr + "/" + WriteAddrStr; //$NON-NLS-1$ //$NON-NLS-2$
update.setLabel(typeStr, idx);
} else if (IDebugVMConstants.COLUMN_ID__DESCRIPTION.equals(localColumns[idx])) {
update.setLabel(getData().getDescription(), idx);
} else if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(localColumns[idx])) {
IVMContext vmc = (IVMContext)update.getElement();
IExpression expression = (IExpression)vmc.getAdapter(IExpression.class);
if (expression != null) {
update.setLabel(expression.getExpressionText(), idx);
} else {
update.setLabel(getData().getName(), idx);
}
}
}
}
if ( ! weAreExtractingFormattedData ) {
update.done();
} else {
for (int idx = 0; idx < localColumns.length; idx++) {
if (IDebugVMConstants.COLUMN_ID__VALUE.equals(localColumns[idx])) {
updateFormattedRegisterValue(update, idx, dmc);
}
}
if ( ! weAreExtractingFormattedData ) {
update.done();
} else {
for (int idx = 0; idx < localColumns.length; idx++) {
if (IDebugVMConstants.COLUMN_ID__VALUE.equals(localColumns[idx])) {
updateFormattedRegisterValue(update, idx, dmc);
}
}
}
},
getSession().getExecutor()
);
}
},
getSession().getExecutor());
}
}
@Override
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
CompositeDMVMContext compositeDmc = new CompositeDMVMContext(getVMProvider().getRootElement(), update.getElementPath());
getServicesTracker().getService(IRegisters.class).getRegisters(
compositeDmc,
new CompositeDMVMContext(update),
new DataRequestMonitor<IRegisterDMContext[]>(getSession().getExecutor(), null) {
@Override
public void handleCompleted() {
@ -389,12 +397,11 @@ public class RegisterLayoutNode extends AbstractExpressionLayoutNode
}
@Override
protected IVMContext createVMContext(IDMContext dmc) {
protected IDMVMContext createVMContext(IDMContext dmc) {
return new RegisterVMC(dmc);
}
@Override
protected int getNodeDeltaFlagsForDMEvent(IDMEvent<?> e) {
public int getDeltaFlags(Object e) {
// In theory we want each node to act independently in terms of events. It might be
// the case that we would only have elements of this type at the root level. It is
// the case that the current layout model always starts with the GROUPS followed by
@ -404,62 +411,83 @@ public class RegisterLayoutNode extends AbstractExpressionLayoutNode
// the GROUP LAYOUT node do this. Later we need to revisit the logic and make sure
// there is a way for the nodes to operate independently and efficiently.
//
// if (e instanceof IRunControl.ISuspendedDMEvent) {
// return IModelDelta.CONTENT;
// }
if (e instanceof IRunControl.ISuspendedDMEvent) {
return IModelDelta.CONTENT;
}
if (e instanceof IRegisters.IRegistersChangedDMEvent) {
/*
* Flush the cache.
*/
VMCacheManager.getVMCacheManager().flush(super.getVMProvider().getPresentationContext());
return IModelDelta.CONTENT;
}
if (e instanceof IRegisters.IRegisterChangedDMEvent) {
/*
* Flush the cache.
*/
VMCacheManager.getVMCacheManager().flush(super.getVMProvider().getPresentationContext());
/*
* Logically one would think that STATE should be specified here. But we specifiy CONTENT
* as well so that if there are subregisters ( BIT FIELDS ) they will be forced to update
* and show new values when the total register changes.
*/
return IModelDelta.CONTENT | IModelDelta.STATE;
return IModelDelta.CONTENT;
}
if (e instanceof PropertyChangeEvent &&
((PropertyChangeEvent)e).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE)
{
return IModelDelta.CONTENT;
}
return IModelDelta.NO_CHANGE;
}
@Override
protected void buildDeltaForDMEvent(IDMEvent<?> e, VMDelta parent, int nodeOffset, RequestMonitor rm) {
// In theory we want each node to act independently in terms of events. It might be
// the case that we would only have elements of this type at the root level. It is
// the case that the current layout model always starts with the GROUPS followed by
// REGISTERS followed by BITFIELDS. But if we do this when a run-control event has
// occured we generate a DELTA for every element, which can create a massive list
// of entries all of which say update the entire view. So for now we will just have
// the GROUP LAYOUT node do this. Later we need to revisit the logic and make sure
// there is a way for the nodes to operate independently and efficiently.
//
// if (e instanceof IRunControl.ISuspendedDMEvent) {
// // Create a delta that the whole register group has changed.
// parent.addFlags(IModelDelta.CONTENT);
// }
public void buildDelta(Object e, ModelDelta parentDelta, int nodeOffset, RequestMonitor rm) {
if (e instanceof IRunControl.ISuspendedDMEvent) {
// Create a delta that the whole register group has changed.
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
}
if (e instanceof IRegisters.IRegistersChangedDMEvent) {
parent.addFlags(IModelDelta.CONTENT);;
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);;
}
if (e instanceof IRegisters.IRegisterChangedDMEvent) {
parent.addNode( createVMContext(((IRegisterChangedDMEvent)e).getDMContext()), IModelDelta.CONTENT | IModelDelta.STATE );
parentDelta.addNode( createVMContext(((IRegisterChangedDMEvent)e).getDMContext()), IModelDelta.CONTENT | IModelDelta.STATE );
}
if (e instanceof PropertyChangeEvent &&
((PropertyChangeEvent)e).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE)
{
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
}
super.buildDeltaForDMEvent(e, parent, nodeOffset, rm);
rm.done();
}
public boolean canParseExpression(IExpression expression) {
return parseExpressionForRegisterName(expression.getExpressionText()) != null;
}
/**
* Expected format: $$"Group Name"$Register_Name.Bit_Field_Name
*/
private String parseExpressionForRegisterName(String expression) {
if (expression.startsWith("$$\"")) { //$NON-NLS-1$
int secondQuoteIdx = expression.indexOf('"', "$$\"".length()); //$NON-NLS-1$
if (secondQuoteIdx > 0) {
String registerSubString = expression.substring(secondQuoteIdx + 1);
if (registerSubString.length() != 0 &&
registerSubString.charAt(0) == '$' &&
Character.isLetterOrDigit(registerSubString.charAt(1)))
{
int registerEnd = 1;
while ( registerEnd < registerSubString.length() &&
Character.isLetterOrDigit(registerSubString.charAt(registerEnd)) )
{
registerEnd++;
}
return registerSubString.substring(1, registerEnd);
}
}
}
return null;
}
public int getExpressionLength(String expression) {
if (expression.charAt(0) == '$' && Character.isLetterOrDigit(expression.charAt(1))) {
int length = 1;
@ -473,21 +501,21 @@ public class RegisterLayoutNode extends AbstractExpressionLayoutNode
}
@Override
protected void testContextForExpression(Object element, final String expression, final DataRequestMonitor<Boolean> rm) {
if (!(element instanceof AbstractDMVMLayoutNode.DMVMContext)) {
protected void testElementForExpression(Object element, IExpression expression, DataRequestMonitor<Boolean> rm) {
if (!(element instanceof IDMVMContext)) {
rm.setStatus(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, IDsfService.INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
rm.done();
return;
}
final IRegisterDMContext dmc = DMContexts.getAncestorOfType(((DMVMContext)element).getDMC(), IRegisterDMContext.class);
final IRegisterDMContext dmc = DMContexts.getAncestorOfType(((IDMVMContext)element).getDMContext(), IRegisterDMContext.class);
if (dmc == null) {
rm.setStatus(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, IDsfService.INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
rm.done();
return;
}
String regName = expression.substring(1);
if (regName.equals(dmc.getName())) {
String regName = parseExpressionForRegisterName(expression.getExpressionText());
if (dmc.getName().equals(regName)) {
rm.setData(Boolean.TRUE);
} else {
rm.setData(Boolean.FALSE);
@ -502,28 +530,30 @@ public class RegisterLayoutNode extends AbstractExpressionLayoutNode
}
}
@Override
protected int getDeltaFlagsForExpressionPart(Object event) {
public int getDeltaFlagsForExpression(IExpression expression, Object event) {
if (event instanceof IRunControl.ISuspendedDMEvent) {
return IModelDelta.CONTENT;
}
if (event instanceof PropertyChangeEvent &&
((PropertyChangeEvent)event).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE)
{
return IModelDelta.CONTENT;
}
return IModelDelta.NO_CHANGE;
}
@Override
public void buildDeltaForExpression(final IExpression expression, final int elementIdx, final String expressionText, final Object event, final VMDelta parentDelta, final TreePath path, final RequestMonitor rm)
public void buildDeltaForExpression(IExpression expression, int elementIdx, Object event, ModelDelta parentDelta,
TreePath path, RequestMonitor rm)
{
if (event instanceof IRunControl.ISuspendedDMEvent) {
// Mark the parent delta indicating that elements were added and/or removed.
parentDelta.addFlags(IModelDelta.CONTENT);
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
}
super.buildDeltaForExpression(expression, elementIdx, expressionText, event, parentDelta, path, rm);
rm.done();
}
@Override
protected void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, VMDelta parentDelta, final RequestMonitor rm)
public void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, ModelDelta parentDelta, final RequestMonitor rm)
{
if (event instanceof IRegisters.IRegisterChangedDMEvent) {
parentDelta.addNode(element, IModelDelta.STATE);
@ -533,7 +563,13 @@ public class RegisterLayoutNode extends AbstractExpressionLayoutNode
parentDelta.addNode(element, IModelDelta.STATE);
}
super.buildDeltaForExpressionElement(element, elementIdx, event, parentDelta, rm);
if (event instanceof PropertyChangeEvent &&
((PropertyChangeEvent)event).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE)
{
parentDelta.addNode(element, IModelDelta.CONTENT);
}
rm.done();
}
@ -556,7 +592,7 @@ public class RegisterLayoutNode extends AbstractExpressionLayoutNode
}
public ICellModifier getCellModifier(IPresentationContext context, Object element) {
return new RegisterLayoutValueCellModifier( fFormattedPrefStore, fSyncRegisterDataAccess );
return new RegisterCellModifier(
getDMVMProvider(), fFormattedPrefStore, fSyncRegisterDataAccess );
}
}

View file

@ -10,27 +10,36 @@
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.register;
import org.eclipse.dd.dsf.debug.ui.viewmodel.dm.AbstractDebugDMVMProviderWithCache;
import org.eclipse.dd.dsf.debug.ui.viewmodel.numberformat.FormattedValuePreferenceStore;
import org.eclipse.dd.dsf.debug.ui.viewmodel.update.BreakpointHitUpdatePolicy;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter;
import org.eclipse.dd.dsf.ui.viewmodel.IVMLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.IVMRootLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.dm.DMVMRootLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.IVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.dm.RootDMVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.update.AutomaticUpdatePolicy;
import org.eclipse.dd.dsf.ui.viewmodel.update.IVMUpdatePolicy;
import org.eclipse.dd.dsf.ui.viewmodel.update.ManualUpdatePolicy;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
/**
* Provides the VIEW MODEL for the DEBUG MODEL REGISTER view.
*/
@SuppressWarnings("restriction")
public class RegisterVMProvider extends AbstractDebugDMVMProviderWithCache
public class RegisterVMProvider extends AbstractDMVMProvider
implements IPropertyChangeListener
{
/*
* Current default for register formatting.
*/
public RegisterVMProvider(AbstractVMAdapter adapter, IPresentationContext context, DsfSession session) {
super(adapter, context, session);
context.addPropertyChangeListener(this);
/*
* Create the register data access routines.
@ -40,30 +49,41 @@ public class RegisterVMProvider extends AbstractDebugDMVMProviderWithCache
/*
* Create the top level node to deal with the root selection.
*/
IVMRootLayoutNode debugViewSelection = new DMVMRootLayoutNode(this);
IRootVMNode rootNode = new RootDMVMNode(this);
/*
* Create the Group nodes next. They represent the first level shown in the view.
*/
IVMLayoutNode registerGroupNode = new RegisterGroupLayoutNode(this, getSession(), regAccess);
debugViewSelection.setChildNodes(new IVMLayoutNode[] { registerGroupNode });
IVMNode registerGroupNode = new RegisterGroupVMNode(this, getSession(), regAccess);
addChildNodes(rootNode, new IVMNode[] { registerGroupNode });
/*
* Create the next level which is the registers themselves.
*/
IVMLayoutNode registerNode = new RegisterLayoutNode(FormattedValuePreferenceStore.getDefault(), this, getSession(), regAccess);
registerGroupNode.setChildNodes(new IVMLayoutNode[] { registerNode });
IVMNode registerNode = new RegisterVMNode(FormattedValuePreferenceStore.getDefault(), this, getSession(), regAccess);
addChildNodes(registerGroupNode, new IVMNode[] { registerNode });
/*
* Create the next level which is the bitfield level.
*/
IVMLayoutNode bitFieldNode = new RegisterBitFieldLayoutNode(FormattedValuePreferenceStore.getDefault(), this, getSession(), regAccess);
registerNode.setChildNodes(new IVMLayoutNode[] { bitFieldNode });
IVMNode bitFieldNode = new RegisterBitFieldVMNode(FormattedValuePreferenceStore.getDefault(), this, getSession(), regAccess);
addChildNodes(registerNode, new IVMNode[] { bitFieldNode });
/*
* Now set this schema set as the layout set.
*/
setRootLayoutNode(debugViewSelection);
setRootNode(rootNode);
}
@Override
protected IVMUpdatePolicy[] createUpdateModes() {
return new IVMUpdatePolicy[] { new AutomaticUpdatePolicy(), new ManualUpdatePolicy(), new BreakpointHitUpdatePolicy() };
}
@Override
public void dispose() {
getPresentationContext().removePropertyChangeListener(this);
super.dispose();
}
@Override
@ -75,4 +95,8 @@ public class RegisterVMProvider extends AbstractDebugDMVMProviderWithCache
public String getColumnPresentationId(IPresentationContext context, Object element) {
return RegisterColumnPresentation.ID;
}
public void propertyChange(PropertyChangeEvent event) {
handleEvent(event);
}
}

View file

@ -35,7 +35,7 @@ import org.eclipse.dd.dsf.debug.service.IRegisters.IRegisterGroupDMData;
import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.service.IDsfService;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.dm.IDMVMContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.util.tracker.ServiceTracker;
@ -154,8 +154,8 @@ public class SyncRegisterDataAccess {
}
public IBitFieldDMContext getBitFieldDMC(Object element) {
if (element instanceof AbstractDMVMLayoutNode.DMVMContext) {
IDMContext dmc = ((AbstractDMVMLayoutNode.DMVMContext)element).getDMC();
if (element instanceof IDMVMContext) {
IDMContext dmc = ((IDMVMContext)element).getDMContext();
return DMContexts.getAncestorOfType(dmc, IBitFieldDMContext.class);
}
return null;
@ -410,24 +410,24 @@ public class SyncRegisterDataAccess {
}
public IRegisterGroupDMContext getRegisterGroupDMC(Object element) {
if (element instanceof AbstractDMVMLayoutNode.DMVMContext) {
IDMContext dmc = ((AbstractDMVMLayoutNode.DMVMContext)element).getDMC();
if (element instanceof IDMVMContext) {
IDMContext dmc = ((IDMVMContext)element).getDMContext();
return DMContexts.getAncestorOfType(dmc, IRegisterGroupDMContext.class);
}
return null;
}
public IRegisterDMContext getRegisterDMC(Object element) {
if (element instanceof AbstractDMVMLayoutNode.DMVMContext) {
IDMContext dmc = ((AbstractDMVMLayoutNode.DMVMContext)element).getDMC();
if (element instanceof IDMVMContext) {
IDMContext dmc = ((IDMVMContext)element).getDMContext();
return DMContexts.getAncestorOfType(dmc, IRegisterDMContext.class);
}
return null;
}
public IFormattedDataDMContext getFormattedDMC(Object element) {
if (element instanceof AbstractDMVMLayoutNode.DMVMContext) {
IDMContext dmc = ((AbstractDMVMLayoutNode.DMVMContext)element).getDMC();
if (element instanceof IDMVMContext) {
IDMContext dmc = ((IDMVMContext)element).getDMContext();
IRegisterDMContext regdmc = DMContexts.getAncestorOfType(dmc, IRegisterDMContext.class);
return DMContexts.getAncestorOfType(regdmc, IFormattedDataDMContext.class);
}
@ -795,8 +795,8 @@ public class SyncRegisterDataAccess {
* session is stale, then bail out.
*/
IFormattedDataDMContext dmc = null;
if (element instanceof AbstractDMVMLayoutNode.DMVMContext) {
IDMContext vmcdmc = ((AbstractDMVMLayoutNode.DMVMContext)element).getDMC();
if (element instanceof IDMVMContext) {
IDMContext vmcdmc = ((IDMVMContext)element).getDMContext();
IRegisterDMContext regdmc = DMContexts.getAncestorOfType(vmcdmc, IRegisterDMContext.class);
dmc = DMContexts.getAncestorOfType(regdmc, IFormattedDataDMContext.class);
}
@ -899,8 +899,8 @@ public class SyncRegisterDataAccess {
* session is stale, then bail out.
*/
IFormattedDataDMContext dmc = null;
if (element instanceof AbstractDMVMLayoutNode.DMVMContext) {
IDMContext vmcdmc = ((AbstractDMVMLayoutNode.DMVMContext)element).getDMC();
if (element instanceof IDMVMContext) {
IDMContext vmcdmc = ((IDMVMContext)element).getDMContext();
IRegisterDMContext regdmc = DMContexts.getAncestorOfType(vmcdmc, IRegisterDMContext.class);
dmc = DMContexts.getAncestorOfType(regdmc, IFormattedDataDMContext.class);
}
@ -939,8 +939,8 @@ public class SyncRegisterDataAccess {
* session is stale, then bail out.
*/
IFormattedDataDMContext dmc = null;
if (element instanceof AbstractDMVMLayoutNode.DMVMContext) {
IDMContext vmcdmc = ((AbstractDMVMLayoutNode.DMVMContext)element).getDMC();
if (element instanceof IDMVMContext) {
IDMContext vmcdmc = ((IDMVMContext)element).getDMContext();
IBitFieldDMContext bitfielddmc = DMContexts.getAncestorOfType(vmcdmc, IBitFieldDMContext.class);
dmc = DMContexts.getAncestorOfType(bitfielddmc, IFormattedDataDMContext.class);
}

View file

@ -0,0 +1,45 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.update;
import org.eclipse.dd.dsf.debug.service.IRunControl.ISuspendedDMEvent;
import org.eclipse.dd.dsf.debug.service.IRunControl.StateChangeReason;
import org.eclipse.dd.dsf.ui.viewmodel.update.IElementUpdateTester;
import org.eclipse.dd.dsf.ui.viewmodel.update.ManualUpdatePolicy;
/**
*
*/
public class BreakpointHitUpdatePolicy extends ManualUpdatePolicy {
public static String BREAKPOINT_HIT_UPDATE_POLICY_ID = "org.eclipse.dd.dsf.debug.ui.viewmodel.update.breakpointHitUpdatePolicy"; //$NON-NLS-1$
@Override
public String getID() {
return BREAKPOINT_HIT_UPDATE_POLICY_ID;
}
@Override
public String getName() {
return "Breakpoint Hit";
}
@Override
public IElementUpdateTester getTesterTester(Object event) {
if(event instanceof ISuspendedDMEvent) {
ISuspendedDMEvent suspendedEvent = (ISuspendedDMEvent)event;
if(suspendedEvent.getReason().equals(StateChangeReason.BREAKPOINT)) {
return super.getTesterTester(REFRESH_EVENT);
}
}
return super.getTesterTester(event);
}
}

View file

@ -1,36 +0,0 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Ted R Williams (Wind River Systems, Inc.) - initial implementation
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.update;
import org.eclipse.dd.dsf.datamodel.IDMEvent;
import org.eclipse.dd.dsf.debug.service.IRunControl;
import org.eclipse.dd.dsf.ui.viewmodel.update.VMCache;
public class VMCacheRefreshAlways extends VMCache
{
public VMCacheRefreshAlways()
{
super();
}
public VMCacheRefreshAlways(VMCache oldCache)
{
super(oldCache);
}
@SuppressWarnings("unchecked")
@Override
public void handleEvent(IDMEvent event) {
if(event instanceof IRunControl.ISuspendedDMEvent)
flush(true);
}
}

View file

@ -1,32 +0,0 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Ted R Williams (Wind River Systems, Inc.) - initial implementation
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.update;
import org.eclipse.dd.dsf.datamodel.IDMEvent;
import org.eclipse.dd.dsf.ui.viewmodel.update.VMCache;
public class VMCacheRefreshManual extends VMCache
{
public VMCacheRefreshManual()
{
super();
}
public VMCacheRefreshManual(VMCache oldCache)
{
super(oldCache);
}
@SuppressWarnings("unchecked")
@Override
public void handleEvent(IDMEvent event) {}
}

View file

@ -1,42 +0,0 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Ted R Williams (Wind River Systems, Inc.) - initial implementation
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.update;
import org.eclipse.dd.dsf.datamodel.IDMEvent;
import org.eclipse.dd.dsf.debug.service.IRunControl;
import org.eclipse.dd.dsf.debug.service.IRunControl.StateChangeReason;
import org.eclipse.dd.dsf.ui.viewmodel.update.VMCache;
public class VMCacheRefreshOnBreak extends VMCache
{
public VMCacheRefreshOnBreak()
{
super();
}
public VMCacheRefreshOnBreak(VMCache oldCache)
{
super(oldCache);
}
@SuppressWarnings("unchecked")
@Override
public void handleEvent(IDMEvent event) {
if(event instanceof IRunControl.ISuspendedDMEvent)
{
if(((IRunControl.ISuspendedDMEvent) event).getReason().equals(StateChangeReason.BREAKPOINT))
flush(true);
}
}
}

View file

@ -6,131 +6,45 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Ted R Williams (Wind River Systems, Inc.) - initial implementation
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.update.actions;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.dd.dsf.ui.viewmodel.IVMAdapter;
import org.eclipse.dd.dsf.debug.ui.viewmodel.actions.AbstractVMProviderActionDelegate;
import org.eclipse.dd.dsf.ui.viewmodel.IVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMProviderWithCache;
import org.eclipse.dd.dsf.ui.viewmodel.update.VMCacheManager;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
import org.eclipse.debug.ui.AbstractDebugView;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.dd.dsf.ui.viewmodel.update.ICachingVMProvider;
import org.eclipse.debug.ui.contexts.DebugContextEvent;
import org.eclipse.debug.ui.contexts.IDebugContextListener;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.ui.IViewActionDelegate;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IViewSite;
@SuppressWarnings("restriction")
public class RefreshActionDelegate implements IViewActionDelegate, IDebugContextListener {
/**
*
*/
public class RefreshActionDelegate extends AbstractVMProviderActionDelegate {
protected IViewPart fView = null;
private Object fViewInput = null;
public void init(IViewPart view) {
/*
* Save the view information for later reference and data retrieval.
*/
fView = view;
/*
* Get the current selection from the DebugView so we can determine if we want this menu action to be live or not.
*/
IViewSite site = (IViewSite) view.getSite();
String combinedViewId = site.getId() + (site.getSecondaryId() != null ? (":" + site.getSecondaryId()) : ""); //$NON-NLS-1$ //$NON-NLS-2$
DebugUITools.getDebugContextManager().getContextService(view.getSite().getWorkbenchWindow()).addPostDebugContextListener(this, combinedViewId);
ISelection sel = DebugUITools.getDebugContextManager().getContextService(view.getSite().getWorkbenchWindow()).getActiveContext();
if ( sel instanceof IStructuredSelection ) {
/*
* Save the view selection as well so we can later determine if we want our action to be valid or not.
*/
fViewInput = ( (IStructuredSelection) sel ).getFirstElement();
}
}
/*
* (non-Javadoc)
* @see org.eclipse.debug.ui.contexts.IDebugContextListener#debugContextChanged(org.eclipse.debug.ui.contexts.DebugContextEvent)
*/
public void debugContextChanged(DebugContextEvent event) {
/*
* This handler is called whenever a selection in the debug view is changed. So here is
* where we will know when we need to reenable the menu actions.
*/
ISelection sel = event.getContext();
if (sel instanceof IStructuredSelection) {
fViewInput = ((IStructuredSelection)sel).getFirstElement();
public void run(IAction action) {
IVMProvider provider = getVMProvider();
if (provider instanceof ICachingVMProvider) {
((ICachingVMProvider)provider).refresh();
}
}
@Override
public void init(IViewPart view) {
super.init(view);
getAction().setEnabled(getVMProvider() instanceof ICachingVMProvider);
}
@Override
public void debugContextChanged(DebugContextEvent event) {
super.debugContextChanged(event);
getAction().setEnabled(getVMProvider() instanceof ICachingVMProvider);
}
public void run(IAction action) {
/*
* Make sure we have a valid set of information. Otherwise we cannot go forward.
*/
if ( fView instanceof AbstractDebugView && fViewInput != null )
{
Viewer viewer = ( (AbstractDebugView) fView).getViewer();
/*
* Now we need to make sure this is one of the Flexible Hierarchy viewws.
*/
if ( viewer instanceof TreeModelViewer ) {
/*
* Get the presentation context and see if there is a numeric property there. If so then this
* is a view implementation which supports changing the format.
*/
TreeModelViewer treeViewer = (TreeModelViewer) viewer;
IPresentationContext context = treeViewer.getPresentationContext();
/*
* Now go tell the view to update. We do so by finding the VM provider for this view
* and telling it to redraw the entire view.
*/
if (fViewInput instanceof IAdaptable) {
IVMAdapter adapter = (IVMAdapter) ((IAdaptable)fViewInput).getAdapter(IVMAdapter.class);
if ( adapter != null ) {
IVMProvider provider = adapter.getVMProvider(context);
if ( provider != null ) {
if ( provider instanceof AbstractDMVMProviderWithCache ) {
AbstractDMVMProviderWithCache prov = (AbstractDMVMProviderWithCache) provider;
prov.flush();
return;
}
}
}
}
}
}
/*
* As a fallback we will flush the cache without involving the provider if it for some
* reason does not measure up.
*/
VMCacheManager.getVMCacheManager().flush(getContext());
}
public void selectionChanged(IAction action, ISelection selection) {
}
private Object getContext()
{
return ((TreeModelViewer) ((AbstractDebugView) fView).getViewer()).getPresentationContext();
}
@Override
public void selectionChanged(IAction action, ISelection selection) {
super.selectionChanged(action, selection);
getAction().setEnabled(getVMProvider() instanceof ICachingVMProvider);
}
}

View file

@ -1,35 +0,0 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Ted R Williams (Wind River Systems, Inc.) - initial implementation
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.update.actions;
import org.eclipse.dd.dsf.debug.ui.viewmodel.update.VMCacheRefreshAlways;
import org.eclipse.dd.dsf.ui.viewmodel.update.VMCache;
import org.eclipse.dd.dsf.ui.viewmodel.update.VMCacheManager;
import org.eclipse.dd.dsf.ui.viewmodel.update.actions.AbstractRefreshActionDelegate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
import org.eclipse.debug.ui.AbstractDebugView;
@SuppressWarnings("restriction")
public class RefreshAlwaysActionDelegate extends AbstractRefreshActionDelegate
{
@Override
public Object getContext()
{
return ((TreeModelViewer) ((AbstractDebugView) fView).getViewer()).getPresentationContext();
}
@Override
public VMCache createCache()
{
return new VMCacheRefreshAlways(VMCacheManager.getVMCacheManager().getCache(getContext()));
}
}

View file

@ -1,35 +0,0 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Ted R Williams (Wind River Systems, Inc.) - initial implementation
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.update.actions;
import org.eclipse.dd.dsf.debug.ui.viewmodel.update.VMCacheRefreshManual;
import org.eclipse.dd.dsf.ui.viewmodel.update.VMCache;
import org.eclipse.dd.dsf.ui.viewmodel.update.VMCacheManager;
import org.eclipse.dd.dsf.ui.viewmodel.update.actions.AbstractRefreshActionDelegate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
import org.eclipse.debug.ui.AbstractDebugView;
@SuppressWarnings("restriction")
public class RefreshManualActionDelegate extends AbstractRefreshActionDelegate
{
@Override
public Object getContext()
{
return ((TreeModelViewer) ((AbstractDebugView) fView).getViewer()).getPresentationContext();
}
@Override
public VMCache createCache()
{
return new VMCacheRefreshManual(VMCacheManager.getVMCacheManager().getCache(getContext()));
}
}

View file

@ -1,35 +0,0 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Ted R Williams (Wind River Systems, Inc.) - initial implementation
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.update.actions;
import org.eclipse.dd.dsf.debug.ui.viewmodel.update.VMCacheRefreshOnBreak;
import org.eclipse.dd.dsf.ui.viewmodel.update.VMCache;
import org.eclipse.dd.dsf.ui.viewmodel.update.VMCacheManager;
import org.eclipse.dd.dsf.ui.viewmodel.update.actions.AbstractRefreshActionDelegate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
import org.eclipse.debug.ui.AbstractDebugView;
@SuppressWarnings("restriction")
public class RefreshOnBreakActionDelegate extends AbstractRefreshActionDelegate
{
@Override
public Object getContext()
{
return ((TreeModelViewer) ((AbstractDebugView) fView).getViewer()).getPresentationContext();
}
@Override
public VMCache createCache()
{
return new VMCacheRefreshOnBreak(VMCacheManager.getVMCacheManager().getCache(getContext()));
}
}

View file

@ -0,0 +1,128 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.update.actions;
import org.eclipse.dd.dsf.debug.ui.viewmodel.actions.AbstractVMProviderActionDelegate;
import org.eclipse.dd.dsf.ui.viewmodel.IVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.update.ICachingVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.update.IVMUpdatePolicy;
import org.eclipse.debug.ui.contexts.DebugContextEvent;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuCreator;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.events.MenuAdapter;
import org.eclipse.swt.events.MenuEvent;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.ui.IViewPart;
/**
*
*/
public class SelectUpdatePolicyAction extends AbstractVMProviderActionDelegate implements IMenuCreator {
class SelectPolicy extends Action {
private ICachingVMProvider fVMProvider;
private IVMUpdatePolicy fUpdatePolicy;
@Override
public void run() {
if (isChecked()) {
fVMProvider.setActiveUpdatePolicy(fUpdatePolicy);
}
}
public SelectPolicy(ICachingVMProvider provider, IVMUpdatePolicy updatePolicy) {
super(updatePolicy.getName(), IAction.AS_RADIO_BUTTON);
fVMProvider = provider;
fUpdatePolicy = updatePolicy;
}
}
public Menu getMenu(Control parent) {
// Never called
return null;
}
@Override
public void init(IViewPart view) {
super.init(view);
getAction().setEnabled(getVMProvider() instanceof ICachingVMProvider);
}
@Override
public void init(IAction action) {
super.init(action);
action.setMenuCreator(this);
}
public void run(IAction action) {
// Do nothing, this is a pull-down menu
}
@Override
public void selectionChanged(IAction action, ISelection selection) {
if (action != getAction()) {
action.setMenuCreator(this);
}
super.selectionChanged(action, selection);
getAction().setEnabled(getVMProvider() instanceof ICachingVMProvider);
}
@Override
public void debugContextChanged(DebugContextEvent event) {
super.debugContextChanged(event);
getAction().setEnabled(getVMProvider() instanceof ICachingVMProvider);
}
public Menu getMenu(Menu parent) {
Menu menu = new Menu(parent);
menu.addMenuListener(new MenuAdapter() {
@Override
public void menuShown(MenuEvent e) {
Menu m = (Menu)e.widget;
MenuItem[] items = m.getItems();
for (int i=0; i < items.length; i++) {
items[i].dispose();
}
fillMenu(m);
}
});
return menu;
}
private void fillMenu(Menu menu) {
IVMUpdatePolicy[] updatePolicies = new IVMUpdatePolicy[0];
IVMUpdatePolicy activePolicy = null;
IVMProvider provider = getVMProvider();
if (provider instanceof ICachingVMProvider) {
ICachingVMProvider cachingProvider = (ICachingVMProvider)provider;
updatePolicies = cachingProvider.getAvailableUpdatePolicies();
activePolicy = cachingProvider.getActiveUpdatePolicy();
for (IVMUpdatePolicy updatePolicy : updatePolicies) {
SelectPolicy action = new SelectPolicy(cachingProvider, updatePolicy);
if (updatePolicy.equals(activePolicy)) {
action.setChecked(true);
}
ActionContributionItem item = new ActionContributionItem(action);
item.fill(menu, -1);
}
}
}
}

View file

@ -13,15 +13,21 @@ 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.numberformat.IFormattedValuePreferenceStore;
import org.eclipse.dd.dsf.ui.viewmodel.IVMContext;
import org.eclipse.dd.dsf.ui.viewmodel.update.AbstractCachingVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.update.UserEditEvent;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
@SuppressWarnings("restriction")
public class VariableLayoutValueCellModifier extends WatchExpressionCellModifier {
public class VariableCellModifier extends WatchExpressionCellModifier {
private AbstractCachingVMProvider fProvider;
private SyncVariableDataAccess fDataAccess = null;
private IFormattedValuePreferenceStore fPrefStore;
public VariableLayoutValueCellModifier(IFormattedValuePreferenceStore formattedValuePreferenceStore, SyncVariableDataAccess access) {
public VariableCellModifier(AbstractCachingVMProvider provider,
IFormattedValuePreferenceStore formattedValuePreferenceStore, SyncVariableDataAccess access)
{
fProvider = provider;
fDataAccess = access;
fPrefStore = formattedValuePreferenceStore;
}
@ -69,7 +75,7 @@ public class VariableLayoutValueCellModifier extends WatchExpressionCellModifier
* Find the presentation context and then use it to get the current desired format.
*/
IVMContext ctx = (IVMContext) element;
IPresentationContext presCtx = ctx.getLayoutNode().getVMProvider().getPresentationContext();
IPresentationContext presCtx = ctx.getVMNode().getVMProvider().getPresentationContext();
formatId = fPrefStore.getCurrentNumericFormat(presCtx);
}
@ -107,7 +113,7 @@ public class VariableLayoutValueCellModifier extends WatchExpressionCellModifier
* Find the presentation context and then use it to get the current desired format.
*/
IVMContext ctx = (IVMContext) element;
IPresentationContext presCtx = ctx.getLayoutNode().getVMProvider().getPresentationContext();
IPresentationContext presCtx = ctx.getVMNode().getVMProvider().getPresentationContext();
formatId = fPrefStore.getCurrentNumericFormat(presCtx);
}
@ -115,7 +121,7 @@ public class VariableLayoutValueCellModifier extends WatchExpressionCellModifier
formatId = IFormattedValues.NATURAL_FORMAT;
}
fDataAccess.writeVariable(element, (String) value, formatId);
fProvider.handleEvent(new UserEditEvent(element));
}
}
else {

View file

@ -11,10 +11,14 @@ package org.eclipse.dd.dsf.debug.ui.viewmodel.variable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.RejectedExecutionException;
import org.eclipse.core.runtime.CoreException;
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.DsfRunnable;
import org.eclipse.dd.dsf.concurrent.MultiRequestMonitor;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.datamodel.DMContexts;
@ -23,6 +27,7 @@ import org.eclipse.dd.dsf.debug.service.IExpressions;
import org.eclipse.dd.dsf.debug.service.IFormattedValues;
import org.eclipse.dd.dsf.debug.service.IRunControl;
import org.eclipse.dd.dsf.debug.service.IStack;
import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionChangedDMEvent;
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;
@ -32,17 +37,16 @@ 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.expression.AbstractExpressionVMNode;
import org.eclipse.dd.dsf.debug.ui.viewmodel.expression.IExpressionUpdate;
import org.eclipse.dd.dsf.debug.ui.viewmodel.numberformat.IFormattedValuePreferenceStore;
import org.eclipse.dd.dsf.debug.ui.viewmodel.numberformat.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.IVMLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.dm.CompositeDMVMContext;
import org.eclipse.dd.dsf.ui.viewmodel.update.VMCacheManager;
import org.eclipse.dd.dsf.ui.viewmodel.dm.IDMVMContext;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.model.IDebugTarget;
@ -53,32 +57,27 @@ import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
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.IElementLabelProvider;
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.internal.ui.viewers.model.provisional.IViewerUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.debug.ui.actions.IWatchExpressionFactoryAdapterExtension;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.swt.widgets.Composite;
@SuppressWarnings({"restriction", "nls"})
public class VariableLayoutNode extends AbstractExpressionLayoutNode implements IElementEditor {
/**
* List of child nodes containing only a reference to this. This is what enables the view model
* provider to know about the recursive nature of subexpression nodes.
*/
private final IVMLayoutNode[] fChildLayoutNodes = { this };
@Override
public IVMLayoutNode[] getChildLayoutNodes() {
return fChildLayoutNodes;
}
public class VariableVMNode extends AbstractExpressionVMNode
implements IElementEditor, IElementLabelProvider
{
private final static int MAX_STRING_VALUE_LENGTH = 40;
@Override
public int getDeltaFlags(Object e) {
/*
* @see buildDelta()
@ -91,22 +90,23 @@ public class VariableLayoutNode extends AbstractExpressionLayoutNode implements
if ( e instanceof IExpressions.IExpressionChangedDMEvent) {
return IModelDelta.STATE;
}
if (e instanceof PropertyChangeEvent &&
((PropertyChangeEvent)e).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE)
{
return IModelDelta.CONTENT;
}
return IModelDelta.NO_CHANGE;
}
@Override
public void buildDelta(final Object event, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor requestMonitor) {
public void buildDelta(final Object event, final ModelDelta parentDelta, final int nodeOffset, final RequestMonitor requestMonitor) {
if (event instanceof IRunControl.ISuspendedDMEvent) {
parentDelta.addFlags(IModelDelta.CONTENT);
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
}
else if ( event instanceof IExpressions.IExpressionChangedDMEvent) {
/*
* Flush the cache.
*/
VMCacheManager.getVMCacheManager().flush(super.getVMProvider().getPresentationContext());
if ( event instanceof IExpressions.IExpressionChangedDMEvent) {
/*
* Logically one would think that STATE should be specified here. But we specifiy CONTENT
* as well so that if there sub expressions which are affected in some way ( such as with
@ -114,6 +114,12 @@ public class VariableLayoutNode extends AbstractExpressionLayoutNode implements
*/
parentDelta.addNode( createVMContext(((IExpressions.IExpressionChangedDMEvent)event).getDMContext()), IModelDelta.CONTENT | IModelDelta.STATE );
}
if (event instanceof PropertyChangeEvent &&
((PropertyChangeEvent)event).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE)
{
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
}
requestMonitor.done();
}
@ -189,7 +195,7 @@ public class VariableLayoutNode extends AbstractExpressionLayoutNode implements
VariableExpressionVMC exprVmc = (VariableExpressionVMC) variable;
IExpressionDMContext exprDmc = DMContexts.getAncestorOfType(exprVmc.getDMC(), IExpressionDMContext.class);
IExpressionDMContext exprDmc = DMContexts.getAncestorOfType(exprVmc.getDMContext(), IExpressionDMContext.class);
if (exprDmc != null) {
return exprDmc.getExpression();
}
@ -200,32 +206,42 @@ public class VariableLayoutNode extends AbstractExpressionLayoutNode implements
final protected VariableExpressionFactory fVariableExpressionFactory = new VariableExpressionFactory();
public VariableLayoutNode(IFormattedValuePreferenceStore prefStore, AbstractVMProvider provider,
DsfSession session, SyncVariableDataAccess syncVariableDataAccess) {
public VariableVMNode(IFormattedValuePreferenceStore prefStore, AbstractDMVMProvider provider,
DsfSession session, SyncVariableDataAccess syncVariableDataAccess)
{
super(provider, session, IExpressions.IExpressionDMContext.class);
fFormattedPrefStore = prefStore;
fSyncVariableDataAccess = syncVariableDataAccess;
}
@Override
protected IVMContext createVMContext(IDMContext dmc) {
protected IDMVMContext createVMContext(IDMContext dmc) {
return new VariableExpressionVMC(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.
*
* @return void
*/
@Override
public void update(final ILabelUpdate[] updates) {
try {
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
updateLabelInSessionThread(updates);
}});
} catch (RejectedExecutionException e) {
for (ILabelUpdate update : updates) {
handleFailedUpdate(update);
}
}
}
protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
for (final ILabelUpdate update : updates) {
final IExpressionDMContext dmc = findDmcInPath(update.getElementPath(), IExpressions.IExpressionDMContext.class);
final IExpressionDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExpressions.IExpressionDMContext.class);
VMCacheManager.getVMCacheManager().getCache(update.getPresentationContext())
.getModelData(getServicesTracker().getService(IExpressions.class, null),
getDMVMProvider().getModelData(
this, update,
getServicesTracker().getService(IExpressions.class, null),
dmc,
new DataRequestMonitor<IExpressionDMData>(getSession().getExecutor(), null) {
@Override
@ -381,8 +397,9 @@ public class VariableLayoutNode extends AbstractExpressionLayoutNode implements
*/
final FormattedValueDMContext valueDmc = expressionService.getFormattedValueContext(dmc, finalFormatId);
VMCacheManager.getVMCacheManager().getCache(update.getPresentationContext())
.getModelData(expressionService,
getDMVMProvider().getModelData(
VariableVMNode.this, update,
expressionService,
valueDmc,
new DataRequestMonitor<FormattedValueDMData>(getSession().getExecutor(), null) {
@Override
@ -403,11 +420,11 @@ public class VariableLayoutNode extends AbstractExpressionLayoutNode implements
update.setLabel(stringValueBuf.toString(), labelIndex);
// Color based on change history
FormattedValueDMData oldData = (FormattedValueDMData) VMCacheManager.getVMCacheManager()
.getCache(VariableLayoutNode.this.getVMProvider().getPresentationContext())
.getArchivedModelData(valueDmc);
FormattedValueDMData oldData = (FormattedValueDMData) getDMVMProvider().getArchivedModelData(
VariableVMNode.this, update, valueDmc);
IExpressionDMData oldDMData = (IExpressionDMData) VMCacheManager.getVMCacheManager().getCache(update.getPresentationContext()).getArchivedModelData(dmc);
IExpressionDMData oldDMData = (IExpressionDMData) getDMVMProvider().getArchivedModelData(
VariableVMNode.this, update, dmc);
String oldStringValue = oldDMData == null ? null : oldDMData.getStringValue();
// highlight the value if either the value (address) has changed or the string (memory at the value) has changed
@ -441,19 +458,51 @@ public class VariableLayoutNode extends AbstractExpressionLayoutNode implements
}
public ICellModifier getCellModifier(IPresentationContext context, Object element) {
return new VariableLayoutValueCellModifier(fFormattedPrefStore, fSyncVariableDataAccess);
return new VariableCellModifier(getDMVMProvider(), fFormattedPrefStore, fSyncVariableDataAccess);
}
public boolean canParseExpression(IExpression expression) {
// Indicate that we can parse any expression that does not start with
// the reserved '$' and '#' characters.
String expressionText = expression.getExpressionText();
return !expressionText.startsWith("$") && !expressionText.startsWith("#");
}
@Override
protected void getElementForExpressionPart(IChildrenUpdate update, String expressionPartText, DataRequestMonitor<Object> rm) {
CompositeDMVMContext compositeDmc = new CompositeDMVMContext(getVMProvider().getRootElement(), update.getElementPath());
final IExpressions expressionService = getServicesTracker().getService(IExpressions.class);
IExpressionDMContext expressionDMC = expressionService.createExpression(compositeDmc, expressionPartText);
rm.setData(createVMContext(expressionDMC));
rm.done();
public void update(final IExpressionUpdate update) {
try {
getSession().getExecutor().execute(new Runnable() {
public void run() {
final IExpressions expressionService = getServicesTracker().getService(IExpressions.class);
if (expressionService != null) {
IExpressionDMContext expressionDMC = expressionService.createExpression(
new CompositeDMVMContext(update),
update.getExpression().getExpressionText());
VariableExpressionVMC variableVmc = new VariableExpressionVMC(expressionDMC);
variableVmc.setExpression(update.getExpression());
update.setExpressionElement(variableVmc);
update.done();
} else {
handleFailedUpdate(update);
}
}
});
} catch (RejectedExecutionException e) {
handleFailedUpdate(update);
}
}
@Override
protected void handleFailedUpdate(IViewerUpdate update) {
if (update instanceof IExpressionUpdate) {
update.setStatus(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, IDsfService.INVALID_STATE, "Update failed", null)); //$NON-NLS-1$
update.done();
} else {
super.handleFailedUpdate(update);
}
}
@Override
protected void associateExpression(Object element, IExpression expression) {
if (element instanceof VariableExpressionVMC) {
@ -461,36 +510,60 @@ public class VariableLayoutNode extends AbstractExpressionLayoutNode implements
}
}
@Override
protected int getDeltaFlagsForExpressionPart(Object event) {
public int getDeltaFlagsForExpression(IExpression expression, Object event) {
if (event instanceof IRunControl.ISuspendedDMEvent) {
return IModelDelta.CONTENT;
}
if (event instanceof IExpressionChangedDMEvent) {
return IModelDelta.CONTENT;
}
if (event instanceof PropertyChangeEvent &&
((PropertyChangeEvent)event).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE)
{
return IModelDelta.CONTENT;
}
return IModelDelta.NO_CHANGE;
}
@Override
protected void testContextForExpression(Object element, String expression, DataRequestMonitor<Boolean> 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 void buildDeltaForExpression(IExpression expression, int elementIdx, Object event, ModelDelta parentDelta,
TreePath path, RequestMonitor rm)
{
rm.done();
}
public void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, ModelDelta parentDelta,
RequestMonitor rm)
{
if (event instanceof IRunControl.ISuspendedDMEvent) {
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
}
if ( event instanceof IExpressions.IExpressionChangedDMEvent) {
/*
* Logically one would think that STATE should be specified here. But we specify CONTENT
* as well so that if there sub expressions which are affected in some way ( such as with
* an expanded union then they will show the changes also.
*/
parentDelta.addNode(element, IModelDelta.CONTENT);
}
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() ;
if (event instanceof PropertyChangeEvent &&
((PropertyChangeEvent)event).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE)
{
parentDelta.addNode(element, IModelDelta.CONTENT);
}
rm.done();
}
@Override
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
// Get the data model context object for the current node in the hierarchy.
final IExpressionDMContext expressionDMC = findDmcInPath(update.getElementPath(), IExpressionDMContext.class);
final IExpressionDMContext expressionDMC = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExpressionDMContext.class);
if ( expressionDMC != null ) {
getSubexpressionsUpdateElementsInSessionThread( update );
@ -502,7 +575,7 @@ public class VariableLayoutNode extends AbstractExpressionLayoutNode implements
private void getSubexpressionsUpdateElementsInSessionThread(final IChildrenUpdate update) {
final IExpressionDMContext expressionDMC = findDmcInPath(update.getElementPath(), IExpressionDMContext.class);
final IExpressionDMContext expressionDMC = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExpressionDMContext.class);
if ( expressionDMC != null ) {
@ -542,7 +615,7 @@ public class VariableLayoutNode extends AbstractExpressionLayoutNode implements
private void getLocalsUpdateElementsInSessionThread(final IChildrenUpdate update) {
final IFrameDMContext frameDmc = findDmcInPath(update.getElementPath(), IFrameDMContext.class);
final IFrameDMContext frameDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IFrameDMContext.class);
// Get the services we need to use.
@ -641,8 +714,7 @@ public class VariableLayoutNode extends AbstractExpressionLayoutNode implements
mrm.add(rm);
VMCacheManager.getVMCacheManager().getCache(VariableLayoutNode.this.getVMProvider().getPresentationContext())
.getModelData(stackFrameService, localDMC, rm, getExecutor());
getDMVMProvider().getModelData(VariableVMNode.this, update, stackFrameService, localDMC, rm, getExecutor());
}
}
};

View file

@ -8,23 +8,33 @@
*/
package org.eclipse.dd.dsf.debug.ui.viewmodel.variable;
import org.eclipse.dd.dsf.debug.ui.viewmodel.dm.AbstractDebugDMVMProviderWithCache;
import org.eclipse.dd.dsf.debug.ui.viewmodel.numberformat.FormattedValuePreferenceStore;
import org.eclipse.dd.dsf.debug.ui.viewmodel.update.BreakpointHitUpdatePolicy;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter;
import org.eclipse.dd.dsf.ui.viewmodel.IVMLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.IVMRootLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.dm.DMVMRootLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.IVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.dm.RootDMVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.update.AutomaticUpdatePolicy;
import org.eclipse.dd.dsf.ui.viewmodel.update.IVMUpdatePolicy;
import org.eclipse.dd.dsf.ui.viewmodel.update.ManualUpdatePolicy;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
@SuppressWarnings("restriction")
public class VariableVMProvider extends AbstractDebugDMVMProviderWithCache implements IColumnPresentationFactory {
public class VariableVMProvider extends AbstractDMVMProvider
implements IPropertyChangeListener, IColumnPresentationFactory
{
public VariableVMProvider(AbstractVMAdapter adapter, IPresentationContext context, DsfSession session) {
super(adapter, context, session);
context.addPropertyChangeListener(this);
/*
* Create the variable data access routines.
*/
@ -33,18 +43,24 @@ public class VariableVMProvider extends AbstractDebugDMVMProviderWithCache imple
/*
* Create the top level node to deal with the root selection.
*/
IVMRootLayoutNode debugViewSelection = new DMVMRootLayoutNode(this);
IRootVMNode rootNode = new RootDMVMNode(this);
setRootNode(rootNode);
/*
* Create the next level which represents members of structs/unions/enums and elements of arrays.
*/
IVMLayoutNode subExpressioNode = new VariableLayoutNode(FormattedValuePreferenceStore.getDefault(), this, getSession(), varAccess);
debugViewSelection.setChildNodes(new IVMLayoutNode[] { subExpressioNode });
/*
* Now set this schema set as the layout set.
*/
setRootLayoutNode(debugViewSelection);
IVMNode subExpressioNode = new VariableVMNode(FormattedValuePreferenceStore.getDefault(), this, getSession(), varAccess);
addChildNodes(rootNode, new IVMNode[] { subExpressioNode });
// Configure the sub-expression node to be a child of itself. This way the content
// provider will recursively drill-down the variable hierarchy.
addChildNodes(subExpressioNode, new IVMNode[] { subExpressioNode });
}
@Override
public void dispose() {
getPresentationContext().removePropertyChangeListener(this);
super.dispose();
}
@Override
@ -56,4 +72,14 @@ public class VariableVMProvider extends AbstractDebugDMVMProviderWithCache imple
public String getColumnPresentationId(IPresentationContext context, Object element) {
return VariableColumnPresentation.ID;
}
public void propertyChange(PropertyChangeEvent event) {
handleEvent(event);
}
@Override
protected IVMUpdatePolicy[] createUpdateModes() {
return new IVMUpdatePolicy[] { new AutomaticUpdatePolicy(), new ManualUpdatePolicy(), new BreakpointHitUpdatePolicy() };
}
}

View file

@ -3,4 +3,5 @@ output.. = bin/
bin.includes = META-INF/,\
.,\
plugin.xml,\
plugin.properties,\
about.html

View file

@ -15,6 +15,5 @@ Export-Package: org.eclipse.dd.dsf.ui.concurrent,
org.eclipse.dd.dsf.ui.viewmodel,
org.eclipse.dd.dsf.ui.viewmodel.dm,
org.eclipse.dd.dsf.ui.viewmodel.properties,
org.eclipse.dd.dsf.ui.viewmodel.update,
org.eclipse.dd.dsf.ui.viewmodel.update.actions
org.eclipse.dd.dsf.ui.viewmodel.update
Bundle-RequiredExecutionEnvironment: J2SE-1.5

View file

@ -3,4 +3,5 @@ output.. = bin/
bin.includes = META-INF/,\
.,\
plugin.xml,\
plugin.properties,\
about.html

View file

@ -22,11 +22,18 @@ import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.eclipse.dd.dsf.concurrent.DefaultDsfExecutor;
import org.eclipse.dd.dsf.concurrent.DsfExecutable;
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.widgets.Display;
/**
* DSF executor which uses the display thread to run the submitted runnables
* and callables. The implementation is based on the default DSF executor
* which still creates its own thread. However this thread blocks when running
* each executable in the display thread.
*/
public class DisplayDsfExecutor extends DefaultDsfExecutor
{
/**
@ -61,6 +68,15 @@ public class DisplayDsfExecutor extends DefaultDsfExecutor
fDisplay = display;
}
/**
* Override to check if we're in the display thread rather than the helper
* thread of the super-class.
*/
@Override
public boolean isInExecutorThread() {
return Thread.currentThread().equals(fDisplay.getThread());
}
/**
* Creates a callable wrapper, which delegates to the display to perform the
* operation. The callable blocks the executor thread while each call
@ -70,7 +86,13 @@ public class DisplayDsfExecutor extends DefaultDsfExecutor
* @return Wrapper callable.
*/
private <V> Callable<V> createSWTDispatchCallable(final Callable<V> callable) {
return new Callable<V>() {
// Check if executable wasn't executed already.
if (DEBUG_EXECUTOR && callable instanceof DsfExecutable) {
assert !((DsfExecutable)callable).getSubmitted() : "Executable was previously executed."; //$NON-NLS-1$
((DsfExecutable)callable).setSubmitted();
}
return new Callable<V>() {
@SuppressWarnings("unchecked")
public V call() throws Exception {
final Object[] v = new Object[1];
@ -110,7 +132,14 @@ public class DisplayDsfExecutor extends DefaultDsfExecutor
* @return Wrapper runnable.
*/
private Runnable createSWTDispatchRunnable(final Runnable runnable) {
return new Runnable() {
// Check if executable wasn't executed already.
if (DEBUG_EXECUTOR && runnable instanceof DsfExecutable) {
assert !((DsfExecutable)runnable).getSubmitted() : "Executable was previously executed."; //$NON-NLS-1$
((DsfExecutable)runnable).setSubmitted();
}
return new Runnable() {
public void run() {
final Throwable[] e = new Throwable[1];
try {

View file

@ -0,0 +1,55 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.ui.concurrent;
import java.util.concurrent.Executor;
import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
/**
* Counting multi data request monitor that takes a <code>IViewerUpdate</code>
* as a parent. If the IViewerUpdate is canceled, this request monitor becomes
* canceled as well.
*
* @see IViewerUpdate.
*/
@SuppressWarnings("restriction")
public class ViewerCountingRequestMonitor extends CountingRequestMonitor {
private final IViewerUpdate fUpdate;
public ViewerCountingRequestMonitor(Executor executor, IViewerUpdate update) {
super(executor, null);
fUpdate = update;
}
@Override
public synchronized boolean isCanceled() {
return fUpdate.isCanceled() || super.isCanceled();
}
@Override
protected void handleOK() {
fUpdate.done();
}
@Override
protected void handleError() {
fUpdate.setStatus(getStatus());
fUpdate.done();
}
@Override
protected void handleCancel() {
fUpdate.setStatus(getStatus());
fUpdate.done();
}
}

View file

@ -0,0 +1,53 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.ui.concurrent;
import java.util.concurrent.Executor;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
/**
* Data Request monitor that takean <code>IViewerUpdate</code> as a parent.
* If the IViewerUpdate is canceled, this request monitor becomes canceled as well.
* @see IViewerUpdate
*/
@SuppressWarnings("restriction")
public class ViewerDataRequestMonitor<V> extends DataRequestMonitor<V> {
private final IViewerUpdate fUpdate;
public ViewerDataRequestMonitor(Executor executor, IViewerUpdate update) {
super(executor, null);
fUpdate = update;
}
@Override
public synchronized boolean isCanceled() {
return fUpdate.isCanceled() || super.isCanceled();
}
@Override
protected void handleOK() {
fUpdate.done();
}
@Override
protected void handleError() {
fUpdate.setStatus(getStatus());
fUpdate.done();
}
@Override
protected void handleCancel() {
fUpdate.setStatus(getStatus());
fUpdate.done();
}
}

View file

@ -17,9 +17,6 @@ import java.util.concurrent.RejectedExecutionException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.dd.dsf.concurrent.DefaultDsfExecutor;
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
import org.eclipse.dd.dsf.concurrent.DsfRunnable;
import org.eclipse.dd.dsf.concurrent.ThreadSafe;
import org.eclipse.dd.dsf.service.IDsfService;
import org.eclipse.dd.dsf.ui.DsfUIPlugin;
@ -41,7 +38,6 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
@SuppressWarnings("restriction")
abstract public class AbstractVMAdapter implements IVMAdapter
{
private final DsfExecutor fExecutor;
private boolean fDisposed;
private final Map<IPresentationContext, IVMProvider> fViewModelProviders =
@ -56,18 +52,8 @@ abstract public class AbstractVMAdapter implements IVMAdapter
* @param session
*/
public AbstractVMAdapter() {
fExecutor = new DefaultDsfExecutor();
}
/**
* Returns the executor that will be used to communicate with the providers
* and the layout nodes.
* @return
*/
public DsfExecutor getExecutor() {
return fExecutor;
}
@ThreadSafe
public IVMProvider getVMProvider(IPresentationContext context) {
synchronized(fViewModelProviders) {
@ -85,93 +71,84 @@ abstract public class AbstractVMAdapter implements IVMAdapter
}
public void dispose() {
// Execute the shutdown in adapter's dispatch thread.
getExecutor().execute(new DsfRunnable() {
public void run() {
synchronized(fViewModelProviders) {
fDisposed = true;
for (IVMProvider provider : fViewModelProviders.values()) {
IVMProvider[] providers = new IVMProvider[0];
synchronized(fViewModelProviders) {
providers = fViewModelProviders.values().toArray(new IVMProvider[fViewModelProviders.size()]);
fViewModelProviders.clear();
fDisposed = true;
}
for (final IVMProvider provider : providers) {
try {
provider.getExecutor().execute(new Runnable() {
public void run() {
provider.dispose();
}
fViewModelProviders.clear();
}
fExecutor.shutdown();
}
});
});
} catch (RejectedExecutionException e) {
// Not much we can do at this point.
}
}
}
public void update(IHasChildrenUpdate[] updates) {
handleUpdates(updates);
IVMProvider provider = getVMProvider(updates[0].getPresentationContext());
if (provider != null) {
updateProvider(provider, updates);
} else {
for (IViewerUpdate update : updates) {
update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR,
"No model provider for update " + update, null)); //$NON-NLS-1$
}
}
}
public void update(IChildrenCountUpdate[] updates) {
handleUpdates(updates);
IVMProvider provider = getVMProvider(updates[0].getPresentationContext());
if (provider != null) {
updateProvider(provider, updates);
} else {
for (IViewerUpdate update : updates) {
update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR,
"No model provider for update " + update, null)); //$NON-NLS-1$
}
}
}
public void update(final IChildrenUpdate[] updates) {
handleUpdates(updates);
}
private void handleUpdates(final IViewerUpdate[] updates) {
try {
getExecutor().execute(new DsfRunnable() {
public void run() {
IPresentationContext context = null;
int firstIdx = 0;
int curIdx = 0;
for (curIdx = 0; curIdx < updates.length; curIdx++) {
if (!updates[curIdx].getPresentationContext().equals(context)) {
if (context != null) {
callProviderWithUpdate(updates, firstIdx, curIdx);
}
context = updates[curIdx].getPresentationContext();
firstIdx = curIdx;
}
}
callProviderWithUpdate(updates, firstIdx, curIdx);
}
});
} catch(RejectedExecutionException e) {
for (IViewerUpdate update : updates) {
update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, "VM adapter executor not available", e)); //$NON-NLS-1$
update.done();
}
}
}
private void callProviderWithUpdate(IViewerUpdate[] updates, int startIdx, int endIdx) {
final IVMProvider provider = getVMProvider(updates[0].getPresentationContext());
if (provider == null) {
IVMProvider provider = getVMProvider(updates[0].getPresentationContext());
if (provider != null) {
updateProvider(provider, updates);
} else {
for (IViewerUpdate update : updates) {
update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR,
"No model provider for update " + update, null)); //$NON-NLS-1$
update.done();
}
return;
}
if (startIdx == 0 && endIdx == updates.length) {
if (updates instanceof IHasChildrenUpdate[]) provider.update((IHasChildrenUpdate[])updates);
else if (updates instanceof IChildrenCountUpdate[]) provider.update((IChildrenCountUpdate[])updates);
else if (updates instanceof IChildrenUpdate[]) provider.update((IChildrenUpdate[])updates);
} else {
if (updates instanceof IHasChildrenUpdate[]) {
IHasChildrenUpdate[] providerUpdates = new IHasChildrenUpdate[endIdx - startIdx];
System.arraycopy(updates, startIdx, providerUpdates, 0, endIdx - startIdx);
provider.update(providerUpdates);
}
else if (updates instanceof IChildrenCountUpdate[]) {
IChildrenCountUpdate[] providerUpdates = new IChildrenCountUpdate[endIdx - startIdx];
System.arraycopy(updates, startIdx, providerUpdates, 0, endIdx - startIdx);
provider.update(providerUpdates);
}
else if (updates instanceof IChildrenUpdate[]) {
IChildrenUpdate[] providerUpdates = new IChildrenUpdate[endIdx - startIdx];
System.arraycopy(updates, startIdx, providerUpdates, 0, endIdx - startIdx);
provider.update(providerUpdates);
"No model provider for update " + update, null)); //$NON-NLS-1$
}
}
}
private void updateProvider(final IVMProvider provider, final IViewerUpdate[] updates) {
try {
provider.getExecutor().execute(new Runnable() {
public void run() {
if (updates instanceof IHasChildrenUpdate[]) {
provider.update((IHasChildrenUpdate[])updates);
} else if (updates instanceof IChildrenCountUpdate[]) {
provider.update((IChildrenCountUpdate[])updates);
} else if (updates instanceof IChildrenUpdate[]) {
provider.update((IChildrenUpdate[])updates);
}
}
});
} catch (RejectedExecutionException e) {
for (IViewerUpdate update : updates) {
update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR,
"Display is disposed, cannot complete update " + update, null)); //$NON-NLS-1$
update.done();
}
}
}
public IModelProxy createModelProxy(Object element, IPresentationContext context) {
IVMProvider provider = getVMProvider(context);
if (provider != null) {

View file

@ -0,0 +1,57 @@
package org.eclipse.dd.dsf.ui.viewmodel;
import org.eclipse.dd.dsf.ui.viewmodel.properties.IElementPropertiesProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory;
/**
* Implementation of basic view model context interface. The main
* purpose of the VMC wrapper is to re-direct adapter queries to the IVMAdapter
* and the layout node that the given context was created by.
* <p/>
* Note: Deriving classes must override the Object.equals/hashCode methods.
* This is because the view model context objects are just wrappers that are
* created by the view model on demand, so the equals methods must use the
* object being wrapped to perform a meaningful comparison.
*/
@SuppressWarnings("restriction")
abstract public class AbstractVMContext implements IVMContext {
protected final IVMAdapter fVMAdapter;
protected final IVMNode fNode;
public AbstractVMContext(IVMAdapter adapter, IVMNode node) {
fVMAdapter = adapter;
fNode = node;
}
public IVMNode getVMNode() { return fNode; }
/**
* IAdapter implementation returns the {@link IVMAdapter} instance for
* the interfaces that are actually implemented by the VM Adapter.
* These should at least include {@link IElementContentProvider},
* {@link IModelProxyFactory}, and {@link IColumnPresentationFactory}.
* It also returns the {@link IVMNode} instance for adapters implemented
* by the context's node. The interfaces typically implemented by the
* node include {@link IElementLabelProvider} and {@link IElementPropertiesProvider}.
*/
@SuppressWarnings("unchecked")
public Object getAdapter(Class adapter) {
if (adapter.isInstance(fVMAdapter)) {
return fVMAdapter;
} else if (adapter.isInstance(fNode)) {
return fNode;
}
return null;
}
/** Deriving classes must override. */
@Override
abstract public boolean equals(Object obj);
/** Deriving classes must override. */
@Override
abstract public int hashCode();
}

View file

@ -1,517 +0,0 @@
/*******************************************************************************
* Copyright (c) 2006 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.RejectedExecutionException;
import org.eclipse.core.runtime.IStatus;
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.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
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.IModelProxyFactory;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
import org.eclipse.jface.viewers.TreePath;
/**
* Base implementation of the View Model layout node.
* The main functionality implemented here is for building the view model
* deltas (IModelDelta), based on the flags returned by child nodes.
*/
@SuppressWarnings("restriction")
abstract public class AbstractVMLayoutNode implements IVMLayoutNode {
private final AbstractVMProvider fProvider;
private boolean fDisposed = false;
/** Child schema nodes of this node. */
private IVMLayoutNode[] fChildNodes = new IVMLayoutNode[0];
public AbstractVMLayoutNode(AbstractVMProvider provider) {
fProvider = provider;
}
/**
* Accessor method for sub-classes.
*/
protected DsfExecutor getExecutor() {
return fProvider.getExecutor();
}
public IVMProvider getVMProvider() {
return fProvider;
}
public void setChildNodes(IVMLayoutNode[] childNodes) {
fChildNodes = childNodes;
}
public IVMLayoutNode[] getChildLayoutNodes() {
return fChildNodes;
}
public void dispose() {
fDisposed = true;
for (IVMLayoutNode childNode : getChildLayoutNodes()) {
childNode.dispose();
}
}
/**
* If any of the children nodes have delta flags, that means that this
* node has to generate a delta as well.
* <p> Note: If a child node has a <code>IModelDelta.CONTENT</code> delta
* flag, it means that this flag will be added to this node's element.
* To allow for optimization change the child's <code>IModelDelta.CONTENT</code>
* flag into a <code>IModelDelta.STATE</code> flag.
*/
public int getDeltaFlags(Object e) {
int retVal = 0;
for (IVMLayoutNode childNode : getChildLayoutNodes()) {
int childNodeDeltaFlags = childNode.getDeltaFlags(e);
if ((childNodeDeltaFlags | IModelDelta.CONTENT) != 0) {
childNodeDeltaFlags &= ~IModelDelta.CONTENT;
childNodeDeltaFlags |= IModelDelta.STATE;
}
retVal |= childNode.getDeltaFlags(e);
}
return retVal;
}
/**
* Base implementation that handles calling child layout nodes to build
* the model delta. The child nodes are called with all the elements
* in this node, which could be very inefficient. In order to build delta
* only for specific elements in this node, the class extending
* <code>AbstractVMLayoutNode</code> should override this method.
* @see IVMLayoutNode#buildDelta(Object, VMDelta, int, RequestMonitor)
*/
public void buildDelta(final Object event, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor requestMonitor) {
// Find the child nodes that have deltas for the given event.
final Map<IVMLayoutNode,Integer> childNodesWithDeltaFlags = getChildNodesWithDeltaFlags(event);
// If no child layout nodes have deltas we can stop here.
if (childNodesWithDeltaFlags.size() == 0) {
requestMonitor.done();
return;
}
// Check if the child delta only has an IModelDelta.CONTENT or
// IModelDelta.STATE flags. If that's the case, we can skip
// creating a delta for this node, because the TreeUpdatePolicy does not
// use the full path from the delta to handle these flags.
// Similarly, the index argument is not necessary either.
boolean mustGetElements = false;
for (int childDelta : childNodesWithDeltaFlags.values()) {
if ((childDelta & ~IModelDelta.STATE) != 0) {
mustGetElements = true;
}
}
if (!mustGetElements) {
callChildNodesToBuildDelta(childNodesWithDeltaFlags, parentDelta, event, requestMonitor);
} else {
// The given child layout 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.
updateElements(new ElementsUpdate(
new DataRequestMonitor<List<Object>>(getExecutor(), null) {
@Override
protected void handleCompleted() {
if (fDisposed) return;
// 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 (!getStatus().isOK() || getData().size() == 0) {
requestMonitor.done();
return;
}
final MultiRequestMonitor<RequestMonitor> elementsDeltasMultiRequestMon =
new MultiRequestMonitor<RequestMonitor>(getExecutor(), null) {
@Override
protected void handleCompleted() {
if (isDisposed()) return;
requestMonitor.done();
}
};
// 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 < getData().size(); i++) {
VMDelta delta = parentDelta.addNode(getData().get(i), nodeOffset + i, IModelDelta.NO_CHANGE);
callChildNodesToBuildDelta(
childNodesWithDeltaFlags, delta, event,
elementsDeltasMultiRequestMon.add(new RequestMonitor(getExecutor(), null) {
@Override
protected void handleCompleted() {
elementsDeltasMultiRequestMon.requestMonitorDone(this);
}
}));
}
}
},
parentDelta));
}
}
/**
* Calls the specified child layout nodes to build the delta for the given event.
* @param nodes Map of layout nodes to be invoked, and the corresponding delta
* flags that they will generate. This map is generated with a call to
* {@link #getChildNodesWithDeltaFlags(Object)}.
* @param delta The delta object to build on. This delta should have been
* gerated by this node, unless the full delta path is not being calculated
* due to an optimization.
* @param event The event object that the delta is being built for.
* @param requestMonitor The result token to invoke when the delta is completed.
*/
protected void callChildNodesToBuildDelta(final Map<IVMLayoutNode,Integer> nodes, final VMDelta delta, final Object event, final RequestMonitor requestMonitor) {
assert nodes.size() != 0;
// Check if any of the child nodes are will generate IModelDelta.SELECT or
// IModelDelta.EXPAND flags. If so, we must calcuate the index for this
// VMC.
boolean calculateOffsets = false;
for (int childDelta : nodes.values()) {
if ( (childDelta & (IModelDelta.SELECT | IModelDelta.EXPAND)) != 0 ) {
calculateOffsets = true;
break;
}
}
getChildNodesElementOffsets(
delta, !calculateOffsets,
new DataRequestMonitor<Map<IVMLayoutNode, Integer>>(getExecutor(), null) {
@Override
protected void handleCompleted() {
if (isDisposed()) return;
final MultiRequestMonitor<RequestMonitor> childrenBuildDeltaDoneCollector =
new MultiRequestMonitor<RequestMonitor>(getExecutor(), null) {
@Override
protected void handleCompleted() {
if (isDisposed()) return;
requestMonitor.done();
}
};
// Set the total count of number of children in the parent delta.
delta.setChildCount(getData().get(null));
for (IVMLayoutNode node : nodes.keySet()) {
node.buildDelta(
event, delta, getData().get(node),
childrenBuildDeltaDoneCollector.add(new RequestMonitor(getExecutor(), null) {
@Override
protected void handleCompleted() {
childrenBuildDeltaDoneCollector.requestMonitorDone(this);
}})
);
}
}
});
}
/**
* Calculates the indexes at which the elements of each of the child
* layout 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
* gerated by this node, unless the full delta path is not being calculated
* due to an optimization.
* @param fakeIt If true, 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(IModelDelta delta, boolean fakeIt, final DataRequestMonitor<Map<IVMLayoutNode, Integer>> rm) {
assert getChildLayoutNodes().length != 0;
if (!fakeIt) {
final Integer[] counts = new Integer[getChildLayoutNodes().length];
final MultiRequestMonitor<RequestMonitor> childrenCountMultiRequestMon =
new MultiRequestMonitor<RequestMonitor>(getExecutor(), rm) {
@Override
protected void handleCompleted() {
if (isDisposed()) return;
super.handleCompleted();
}
@Override
protected void handleOK() {
Map<IVMLayoutNode, Integer> data = new HashMap<IVMLayoutNode, Integer>();
int offset = 0;
for (int i = 0; i < getChildLayoutNodes().length; i++) {
data.put(getChildLayoutNodes()[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();
}
};
for (int i = 0; i < getChildLayoutNodes().length; i++) {
final int nodeIndex = i;
getChildLayoutNodes()[i].updateElementCount(
new ElementsCountUpdate(
childrenCountMultiRequestMon.add(
new DataRequestMonitor<Integer>(getExecutor(), null) {
@Override
protected void handleCompleted() {
counts[nodeIndex] = getData();
childrenCountMultiRequestMon.requestMonitorDone(this);
}
}),
delta)
);
}
} else {
Map<IVMLayoutNode, Integer> data = new HashMap<IVMLayoutNode, Integer>();
for (int i = 0; i < getChildLayoutNodes().length; i++) {
data.put(getChildLayoutNodes()[i], -1);
}
data.put(null, -1);
rm.setData(data);
rm.done();
}
}
protected boolean isDisposed() {
return fDisposed;
}
/**
* Convenience method that returns the child layout nodes which return
* <code>true</code> to the <code>hasDeltaFlags()</code> test for the given
* event.
*/
protected Map<IVMLayoutNode, Integer> getChildNodesWithDeltaFlags(Object e) {
Map<IVMLayoutNode, Integer> nodes = new HashMap<IVMLayoutNode, Integer>();
for (final IVMLayoutNode childNode : getChildLayoutNodes()) {
int delta = childNode.getDeltaFlags(e);
if (delta != IModelDelta.NO_CHANGE) {
nodes.put(childNode, delta);
}
}
return nodes;
}
/**
* Convenience method that returns a token value in case when the services
* that the layout node depends on, are not available.
*/
protected boolean checkUpdate(IViewerUpdate update) {
if (update.isCanceled()) {
update.done();
return false;
}
if (fDisposed) {
handleFailedUpdate(update);
return false;
}
return true;
}
/**
* A convenience method that completes update object in case of an error.
* Different types of update need to have some data configured to exhibit
* desired behavior in the viewer.
* @param update Update to handle.
*/
protected void handleFailedUpdate(IViewerUpdate update) {
if (update instanceof IHasChildrenUpdate) {
((IHasChildrenUpdate)update).setHasChilren(false);
} else if (update instanceof IChildrenCountUpdate) {
((IChildrenCountUpdate)update).setChildCount(0);
} else if (update instanceof ILabelUpdate) {
ILabelUpdate labelUpdate = (ILabelUpdate)update;
String[] columns = labelUpdate.getPresentationContext().getColumns();
for (int i = 0; i < (columns != null ? columns.length : 1); i++) {
labelUpdate.setLabel("...", i); //$NON-NLS-1$
}
}
update.done();
}
/**
* Implementation of basic View Model Context node functionality. The main
* purpose of the VMC wrapper is to re-direct adapter queries to the IVMAdapter
* and the layout node that the given context was created by.
* <p>
* Note: Deriving classes must override the Object.equals/hashCode methods.
* This is because the VMC objects are just wrappers that are created
* by the view model on demand, so the equals methods must use the object
* being wrapped by the VMC to perform a meaningful comparison.
*/
abstract public static class AbstractVMContext implements IVMContext {
protected final IVMAdapter fVMAdapter;
protected final IVMLayoutNode fLayoutNode;
public AbstractVMContext(IVMAdapter adapter, IVMLayoutNode node) {
fVMAdapter = adapter;
fLayoutNode = node;
}
public IVMLayoutNode getLayoutNode() { return fLayoutNode; }
/**
* IAdapter implementation returns the IVMAdapter instance for the
* interfaces that are actually implemented by the VM Adapter. These
* should at least include {@link IElementContentProvider},
* {@link IModelProxyFactory}, and
* {@link IColumnPresentationFactory}.
*/
@SuppressWarnings("unchecked")
public Object getAdapter(Class adapter) {
if (adapter.isInstance(fVMAdapter)) {
return fVMAdapter;
} else if (adapter.isInstance(fLayoutNode)) {
return fLayoutNode;
}
return null;
}
/** Deriving classes must override. */
@Override
abstract public boolean equals(Object obj);
/** Deriving classes must override. */
@Override
abstract public int hashCode();
}
protected TreePath getTreePathFromDelta(IModelDelta delta) {
List<Object> elementList = new LinkedList<Object>();
IModelDelta listDelta = delta;
elementList.add(0, listDelta.getElement());
while (listDelta.getParentDelta() != null) {
elementList.add(0, listDelta.getElement());
listDelta = listDelta.getParentDelta();
}
return new TreePath(elementList.toArray());
}
protected class ViewerUpdate implements IViewerUpdate {
final private RequestMonitor fRequestMonitor;
final private TreePath fTreePath;
private IStatus fStatus;
private boolean fCancelled = false;
public ViewerUpdate(RequestMonitor requestMonitor, IModelDelta delta) {
fRequestMonitor = requestMonitor;
List<Object> elementList = new LinkedList<Object>();
IModelDelta listDelta = delta;
elementList.add(0, listDelta.getElement());
while (listDelta.getParentDelta() != null) {
elementList.add(0, listDelta.getElement());
listDelta = listDelta.getParentDelta();
}
fTreePath = new TreePath(elementList.toArray());
}
public ViewerUpdate(RequestMonitor requestMonitor, TreePath path) {
fRequestMonitor = requestMonitor;
fTreePath = path;
}
public Object getViewerInput() {
return getVMProvider().getRootElement();
}
public Object getElement() {
return getElementPath().getLastSegment();
}
public IPresentationContext getPresentationContext() { return getVMProvider().getPresentationContext(); }
public TreePath getElementPath() { return fTreePath; }
public IStatus getStatus() { return fStatus; }
public void setStatus(IStatus status) { fStatus = status; }
public boolean isCanceled() { return fCancelled; }
public void cancel() { fCancelled = true; }
public void done() {
try {
fRequestMonitor.done();
} catch (RejectedExecutionException e) {
}
}
}
protected class ElementsCountUpdate extends ViewerUpdate implements IChildrenCountUpdate {
private final DataRequestMonitor<Integer> fElementCountRequestMonitor;
public ElementsCountUpdate(DataRequestMonitor<Integer> rm, IModelDelta delta) {
super(rm, delta);
fElementCountRequestMonitor = rm;
}
public void setChildCount(int numChildren) {
fElementCountRequestMonitor.setData(numChildren);
}
}
protected class ElementsUpdate extends ViewerUpdate implements IChildrenUpdate {
private final List<Object> fChildren = new ArrayList<Object>();
private DataRequestMonitor<List<Object>> fElementUpdateRequestMonitor;
public ElementsUpdate(DataRequestMonitor<List<Object>> rm, IModelDelta delta) {
super(rm, delta);
fElementUpdateRequestMonitor = rm;
fElementUpdateRequestMonitor.setData(fChildren);
}
public ElementsUpdate(DataRequestMonitor<List<Object>> rm, TreePath path) {
super(rm, path);
fElementUpdateRequestMonitor = rm;
fElementUpdateRequestMonitor.setData(fChildren);
}
public int getOffset() {
return -1;
}
public int getLength() {
return -1;
}
public void setChild(Object child, int offset) {
fChildren.add(offset, child);
}
@Override
public String toString() {
return "VMElementsUpdate for all elements under parent = " + getElement(); //$NON-NLS-1$
}
}
}

View file

@ -0,0 +1,93 @@
/*******************************************************************************
* Copyright (c) 2006 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel;
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
/**
* Base implementation of the view model node.
* The main functionality implemented here is for building the view model
* deltas (IModelDelta), based on the flags returned by child nodes.
*/
@SuppressWarnings("restriction")
abstract public class AbstractVMNode implements IVMNode {
private final AbstractVMProvider fProvider;
private boolean fDisposed = false;
public AbstractVMNode(AbstractVMProvider provider) {
fProvider = provider;
}
/**
* Accessor method for sub-classes.
*/
protected DsfExecutor getExecutor() {
return fProvider.getExecutor();
}
public IVMProvider getVMProvider() {
return fProvider;
}
public void dispose() {
fDisposed = true;
}
public IVMContext getContextFromEvent(Object event) {
return null;
}
protected boolean isDisposed() {
return fDisposed;
}
/**
* Convenience method that returns a token value in case when the services
* that the layout node depends on, are not available.
*/
protected boolean checkUpdate(IViewerUpdate update) {
if (update.isCanceled()) {
update.done();
return false;
}
if (fDisposed) {
handleFailedUpdate(update);
return false;
}
return true;
}
/**
* A convenience method that completes update object in case of an error.
* Different types of update need to have some data configured to exhibit
* desired behavior in the viewer.
* @param update Update to handle.
*/
protected void handleFailedUpdate(IViewerUpdate update) {
if (update instanceof IHasChildrenUpdate) {
((IHasChildrenUpdate)update).setHasChilren(false);
} else if (update instanceof IChildrenCountUpdate) {
((IChildrenCountUpdate)update).setChildCount(0);
} else if (update instanceof ILabelUpdate) {
ILabelUpdate labelUpdate = (ILabelUpdate)update;
String[] columns = labelUpdate.getPresentationContext().getColumns();
for (int i = 0; i < (columns != null ? columns.length : 1); i++) {
labelUpdate.setLabel("...", i); //$NON-NLS-1$
}
}
update.done();
}
}

View file

@ -12,74 +12,108 @@ package org.eclipse.dd.dsf.ui.viewmodel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
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.concurrent.ThreadSafe;
import org.eclipse.dd.dsf.service.IDsfService;
import org.eclipse.dd.dsf.ui.DsfUIPlugin;
import org.eclipse.dd.dsf.ui.concurrent.DisplayDsfExecutor;
import org.eclipse.dd.dsf.ui.concurrent.ViewerDataRequestMonitor;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
import org.eclipse.debug.internal.ui.viewers.provisional.AbstractModelProxy;
import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousContentAdapter;
import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousLabelAdapter;
import org.eclipse.swt.widgets.Display;
/**
* View model provider implements the asynchronous view model functionality for
* a single view. This provider is just a holder which further delegates the
* model provider functionality to the view model layout nodes that need
* model provider functionality to the view model nodes that need
* to be configured with each provider.
* <p>
*
* <p/>
* The view model provider, often does not provide the model for the entire
* view. Rather, it needs to be able to plug in at any level in the viewer's
* content model and provide data for a sub-tree.
*
* <p/>
* Clients are intended to extend this class.
*
* @see IAsynchronousContentAdapter
* @see IAsynchronousLabelAdapter
* @see IModelProxy
* @see IVMLayoutNode
* @see IVMNode
*/
@ConfinedToDsfExecutor("getVMAdapter#getExecutor")
@SuppressWarnings("restriction")
abstract public class AbstractVMProvider implements IVMProvider
{
/** Reference to the VM adapter that owns this provider */
private final AbstractVMAdapter fVMAdapter;
/** The presentation context that this provider is associated with */
private final IPresentationContext fPresentationContext;
/**
* The current root element of this view model. This element is obtained
* from the argument to {@link #createModelProxy(Object, IPresentationContext)}.
*/
private Object fRootElement;
/**
* The executor that this VM provider operates in. This executor will be
* initialized properly when we can access the display from the
* IPresentationContext object (bug 213629). For now utilize the
* assumption that there is only one display.
*/
private final DsfExecutor fExecutor = DisplayDsfExecutor.getDisplayDsfExecutor(Display.getDefault());
/**
* The element content provider implementation that this provider delegates to.
* Sub-classes may override the content strategy used for custom functionality.
*/
private final IElementContentProvider fContentStrategy;
/**
*
* The list of active model proxies in this provider. A new model
* proxy is created when a viewer has a new input element
* (see {@link #createModelProxy(Object, IPresentationContext)}).
* Typically there will be only one active model proxy in a given
* provider. However, if a view model provider fills only a sub-tree
* in a viewer, and there are several sub-trees active in the same viewer
* at the same time, each of these sub-trees will have it's own model
* proxy.
*/
private List<IVMModelProxy> fActiveModelProxies = new LinkedList<IVMModelProxy>();
/**
* Convencience constant.
*/
private static final IVMNode[] EMPTY_NODES_ARRAY = new IVMNode[0];
/**
* The mapping of parent to child nodes.
*/
private Map<IVMNode,IVMNode[]> fChildNodesMap =
new HashMap<IVMNode,IVMNode[]>();
/**
* Cached array of all the configued view model nodes. It is generated
* based on the child nodes map.
*/
private IVMNode[] fNodesListCache = null;
/**
* Flag indicating that the provider is disposed.
*/
private ModelProxy fModelProxy = new ModelProxy();
private boolean fDisposed = false;
/**
@ -87,7 +121,7 @@ abstract public class AbstractVMProvider implements IVMProvider
* null when first created, to allow sub-classes to prorperly configure the
* root node in the sub-class constructor.
*/
private AtomicReference<IVMRootLayoutNode> fRootLayoutNodeRef = new AtomicReference<IVMRootLayoutNode>();
private IRootVMNode fRootNode;
/**
* Constructs the view model provider for given DSF session. The
@ -98,6 +132,7 @@ abstract public class AbstractVMProvider implements IVMProvider
public AbstractVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext) {
fVMAdapter = adapter;
fPresentationContext = presentationContext;
fContentStrategy = createContentStrategy();
}
public IPresentationContext getPresentationContext() {
@ -109,345 +144,321 @@ abstract public class AbstractVMProvider implements IVMProvider
}
/**
* Sets the root node for this provider.
* Creates the strategy class that will be used to implement the content
* provider interface of this view model provider. This method can be
* overridden by sub-classes to provider custom content provider strategy.
* <p/>
* Note this method can be called by the base class constructor, therefore
* it should not reference any fields initialized in the sub-class.
*
* @return New content provider implementation.
*/
@ThreadSafe
protected void setRootLayoutNode(IVMRootLayoutNode rootLayoutNode) {
final IVMRootLayoutNode oldRootLayoutNode = fRootLayoutNodeRef.getAndSet(rootLayoutNode);
if (oldRootLayoutNode != null) {
oldRootLayoutNode.dispose();
protected IElementContentProvider createContentStrategy() {
return new DefaultVMContentProviderStrategy(this);
}
/**
* Access method for the content provider strategy.
*
* @return Content provider implementation currently being used by this
* class.
*/
protected IElementContentProvider getContentStrategy() {
return fContentStrategy;
}
/**
* Creates the strategy class that will be used to implement the content
* model proxy of this view model provider. It is normally called by
* {@link #createModelProxy(Object, IPresentationContext)} every time the
* input in the viewer is updated. This method can be overridden by
* sub-classes to provider custom model proxy strategy.
*
* @return New model proxy implementation.
*/
protected IVMModelProxy createModelProxyStrategy(Object rootElement) {
return new DefaultVMModelProxyStrategy(this, rootElement);
}
/**
* Returns the list of active proxies in this provider. The returned
* list is not a copy and if a sub-class modifies this list, it will
* modify the current list of active proxies. This allows the
* sub-classes to change how the active proxies are managed and
* retained.
*/
protected List<IVMModelProxy> getActiveModelProxies() {
return fActiveModelProxies;
}
/**
* Processes the given event in the given provider, sending model
* deltas if necessary.
*/
public void handleEvent(final Object event) {
for (final IVMModelProxy proxyStrategy : getActiveModelProxies()) {
if (proxyStrategy.isDeltaEvent(event)) {
proxyStrategy.createDelta(
event,
new DataRequestMonitor<IModelDelta>(getExecutor(), null) {
@Override
public void handleCompleted() {
if (getStatus().isOK()) {
proxyStrategy.fireModelChanged(getData());
}
}
@Override public String toString() {
return "Result of a delta for event: '" + event.toString() + "' in VMP: '" + this + "'" + "\n" + getData().toString(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
});
}
}
}
@ThreadSafe
protected synchronized ModelProxy getModelProxy() {
return fModelProxy;
public IRootVMNode getRootVMNode() {
return fRootNode;
}
public IVMNode[] getAllVMNodes() {
if (fNodesListCache != null) {
return fNodesListCache;
}
List<IVMNode> list = new ArrayList<IVMNode>();
for (IVMNode node : fChildNodesMap.keySet()) {
if (node != null) {
list.add(node);
}
}
fNodesListCache = list.toArray(new IVMNode[list.size()]);;
return fNodesListCache;
}
public IVMNode[] getChildVMNodes(IVMNode node) {
IVMNode[] retVal = fChildNodesMap.get(node);
if (retVal != null) {
return retVal;
}
return EMPTY_NODES_ARRAY;
}
/**
* Configures the given array of nodes as children of the given parent node.
* Sub-classes should call this method to define the hierarchy of nodes.
*/
protected void addChildNodes(IVMNode parentNode, IVMNode[] childNodes) {
// Add to the child nodes array.
IVMNode[] existingChildNodes = fChildNodesMap.get(parentNode);
if (existingChildNodes == null) {
fChildNodesMap.put(parentNode, childNodes);
} else {
IVMNode[] newNodes = new IVMNode[existingChildNodes.length + childNodes.length];
System.arraycopy(existingChildNodes, 0, newNodes, 0, existingChildNodes.length);
System.arraycopy(childNodes, 0, newNodes, existingChildNodes.length, childNodes.length);
fChildNodesMap.put(parentNode, newNodes);
}
// Make sure that each new expression node has an entry of its own.
for (IVMNode childNode : childNodes) {
addNode(childNode);
}
fNodesListCache = null;
}
@ThreadSafe
public synchronized Object getRootElement() {
return fRootElement;
/**
* Adds the given node to configured nodes, without creating any
* parent-child relationship for it. It is useful for providers which do have
* a strict tree hierarchy of ndoes.
*/
protected void addNode(IVMNode node) {
if (!fChildNodesMap.containsKey(node)) {
fChildNodesMap.put(node, EMPTY_NODES_ARRAY);
}
}
@ThreadSafe
public IVMRootLayoutNode getRootLayoutNode() {
return fRootLayoutNodeRef.get();
/**
* Clears all configured nodes. This allows a subclass to reset and
* reconfigure its nodes.
*/
protected void clearNodes() {
for (IVMNode node : fChildNodesMap.keySet()) {
node.dispose();
}
fChildNodesMap.clear();
fRootNode = null;
}
/**
* Sets the root node for this provider.
*/
protected void setRootNode(IRootVMNode rootNode) {
fRootNode = rootNode;
}
/** Called to dispose the provider. */
public void dispose() {
fDisposed = true;
if (fRootLayoutNodeRef.get() != null) {
fRootLayoutNodeRef.get().dispose();
}
clearNodes();
fRootNode = null;
}
public void update(final IHasChildrenUpdate[] updates) {
fContentStrategy.update(updates);
}
public void update(final IChildrenCountUpdate[] updates) {
fContentStrategy.update(updates);
}
public void update(final IChildrenUpdate[] updates) {
fContentStrategy.update(updates);
}
/**
* Allows other subsystems to force the layout mode associated with the specified
* VM context to refresh. If null is passed then the RootLayoutNode is told to refresh.
* Calls the given view model node to perform the given updates. This
* method is called by view model provider and it's helper classes instead
* of calling the IVMNode method directly, in order to allow additional
* processing of the udpate. For example the AbstractCachingVMProvider
* overrides this method to optionally return the results for an update from
* a cache.
*/
public void refresh(final IVMContext element) {
try {
getExecutor().execute(new Runnable() {
public void run() {
if (isDisposed()) return;
protected void updateNode(final IVMNode node, IHasChildrenUpdate[] updates) {
IHasChildrenUpdate[] updateProxies = new IHasChildrenUpdate[updates.length];
for (int i = 0; i < updates.length; i++) {
final IHasChildrenUpdate update = updates[i];
updateProxies[i] = new VMHasChildrenUpdate(
update,
new ViewerDataRequestMonitor<Boolean>(getExecutor(), updates[i]) {
@Override
protected void handleOK() {
update.setHasChilren(getData());
update.done();
}
if ( element == null ) {
VMDelta rootDelta = new VMDelta(getRootElement(), IModelDelta.CONTENT);
getModelProxy().fireModelChangedNonDispatch(rootDelta);
@Override
protected void handleError() {
if (getStatus().getCode() == IDsfService.NOT_SUPPORTED) {
updateNode(
node,
new VMChildrenUpdate[] { new VMChildrenUpdate(
update, -1, -1,
new ViewerDataRequestMonitor<List<Object>>(getExecutor(), update) {
@Override
protected void handleOK() {
update.setHasChilren( !getData().isEmpty() );
update.done();
}
})
});
} else {
update.setStatus(getStatus());
update.done();
}
}
else {
VMDelta elementDelta = new VMDelta(element, IModelDelta.CONTENT);
getModelProxy().fireModelChangedNonDispatch(elementDelta);
}
}});
} catch (RejectedExecutionException e) {
// Ignore. This exception could be thrown if the provider is being
// shut down.
});
}
return;
node.update(updateProxies);
}
/**
* Calls the given view model node to perform the given updates. This
* method is called by view model provider and it's helper classes instead
* of calling the IVMNode method directly, in order to allow additional
* processing of the udpate. For example the AbstractCachingVMProvider
* overrides this method to optionally return the results for an update from
* a cache.
*/
protected void updateNode(final IVMNode node, IChildrenCountUpdate[] updates) {
IChildrenCountUpdate[] updateProxies = new IChildrenCountUpdate[updates.length];
for (int i = 0; i < updates.length; i++) {
final IChildrenCountUpdate update = updates[i];
updateProxies[i] = new VMChildrenCountUpdate(
update,
new ViewerDataRequestMonitor<Integer>(getExecutor(), updates[i]) {
@Override
protected void handleOK() {
update.setChildCount(getData());
update.done();
}
@Override
protected void handleError() {
if (getStatus().getCode() == IDsfService.NOT_SUPPORTED) {
updateNode(
node,
new VMChildrenUpdate[] { new VMChildrenUpdate(
update, -1, -1,
new ViewerDataRequestMonitor<List<Object>>(getExecutor(), update) {
@Override
protected void handleOK() {
update.setChildCount( getData().size() );
update.done();
}
})
});
}
}
});
}
node.update(updateProxies);
}
/**
* Calls the given view model node to perform the given updates. This
* method is called by view model provider and it's helper classes instead
* of calling the IVMNode method directly, in order to allow additional
* processing of the udpate. For example the AbstractCachingVMProvider
* overrides this method to optionally return the results for an update from
* a cache.
*/
protected void updateNode(IVMNode node, IChildrenUpdate[] updates) {
node.update(updates);
}
/**
* Returns whether this provider has been disposed.
*/
protected boolean isDisposed() {
return fDisposed;
}
/**
* Convenience method to access the View Model's executor.
* The abstract provider uses a the display-thread executor so that the
* provider will operate on the same thread as the viewer. This way no
* synchronization is necessary when the provider is called by the viewer.
* Also, the display thread is likely to be shut down long after any of the
* view models are disposed, so the users of this abstract provider do not
* need to worry about the executor throwing the {@link RejectedExecutionException}
* exception.
*/
public DsfExecutor getExecutor() { return fVMAdapter.getExecutor(); }
public void update(IHasChildrenUpdate[] updates) {
// Sort the updates by the layout node.
Map<IVMLayoutNode,List<IHasChildrenUpdate>> nodeUpdatesMap = new HashMap<IVMLayoutNode,List<IHasChildrenUpdate>>();
for (IHasChildrenUpdate update : updates) {
// Get the VM Context for last element in path.
IVMLayoutNode layoutNode = getLayoutNodeForElement(update.getElement());
if (layoutNode == null) {
// Stale update, most likely as a result of the layout nodes being
// changed. Just ignore it.
update.done();
continue;
}
if (!nodeUpdatesMap.containsKey(layoutNode)) {
nodeUpdatesMap.put(layoutNode, new ArrayList<IHasChildrenUpdate>());
}
nodeUpdatesMap.get(layoutNode).add(update);
}
// Iterate through the nodes in the sorted map.
for (IVMLayoutNode node : nodeUpdatesMap.keySet()) {
updateNode(node, nodeUpdatesMap.get(node).toArray(new IHasChildrenUpdate[nodeUpdatesMap.get(node).size()]));
}
}
private void updateNode(IVMLayoutNode node, final IHasChildrenUpdate[] updates) {
// If parent element's layout node has no children, just set the
// result and coninue to next element.
if (node.getChildLayoutNodes().length == 0) {
for (IHasChildrenUpdate update : updates) {
update.setHasChilren(false);
update.done();
}
return;
}
// Create a matrix of element updates:
// The first dimension "i" is the list of children updates that came from the viewer.
// For each of these updates, there are "j" number of elment updates corresponding
// to the number of child layout nodes in this node.
// Each children update from the viewer is complete when all the child layout nodes
// fill in their elements update.
// Once the matrix is constructed, the child layout nodes are given the list of updates
// equal to the updates requested by the viewer.
VMHasElementsUpdate[][] elementsUpdates =
new VMHasElementsUpdate[node.getChildLayoutNodes().length][updates.length];
for (int i = 0; i < updates.length; i ++)
{
final IHasChildrenUpdate update = updates[i];
final MultiRequestMonitor<DataRequestMonitor<Boolean>> hasChildrenMultiRequestMon =
new MultiRequestMonitor<DataRequestMonitor<Boolean>>(getExecutor(), null) {
@Override
protected void handleCompleted() {
// Status is OK, only if all request monitors are OK.
if (getStatus().isOK()) {
boolean isContainer = false;
for (DataRequestMonitor<Boolean> hasElementsDone : getRequestMonitors()) {
isContainer |= hasElementsDone.getStatus().isOK() &&
hasElementsDone.getData().booleanValue();
}
update.setHasChilren(isContainer);
} else {
update.setStatus(getStatus());
}
update.done();
}
};
for (int j = 0; j < node.getChildLayoutNodes().length; j++)
{
elementsUpdates[j][i] = new VMHasElementsUpdate(
update,
hasChildrenMultiRequestMon.add(
new DataRequestMonitor<Boolean>(getExecutor(), null) {
@Override
protected void handleCompleted() {
hasChildrenMultiRequestMon.requestMonitorDone(this);
}
}));
}
}
for (int j = 0; j < node.getChildLayoutNodes().length; j++) {
node.getChildLayoutNodes()[j].updateHasElements(elementsUpdates[j]);
}
public DsfExecutor getExecutor() {
return fExecutor;
}
public void update(final IChildrenCountUpdate[] updates) {
for (final IChildrenCountUpdate update : updates) {
if (update.isCanceled()) {
update.done();
continue;
}
getChildrenCountsForNode(
update,
new DataRequestMonitor<Integer[]>(getExecutor(), null) {
@Override
protected void handleCompleted() {
if (getStatus().isOK()) {
int numChildren = 0;
for (Integer count : getData()) {
numChildren += count.intValue();
}
update.setChildCount(numChildren);
} else {
update.setChildCount(0);
}
update.done();
}
});
}
}
public void update(IChildrenUpdate[] updates) {
for (final IChildrenUpdate update : updates) {
getChildrenCountsForNode(
update,
new DataRequestMonitor<Integer[]>(getExecutor(), null) {
@Override
protected void handleCompleted() {
if (!getStatus().isOK()) {
update.done();
return;
}
updateChildrenWithCounts(update, getData());
}
});
}
}
private void getChildrenCountsForNode(IViewerUpdate update, final DataRequestMonitor<Integer[]> rm) {
if (isDisposed()) return;
public IModelProxy createModelProxy(Object element, IPresentationContext context) {
assert getExecutor().isInExecutorThread();
// Get the VM Context for last element in path.
final IVMLayoutNode layoutNode = getLayoutNodeForElement(update.getElement());
if (layoutNode == null) {
// Stale update. Just ignore.
rm.setStatus(new Status(
IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.INVALID_HANDLE, "Stale update.", null)); //$NON-NLS-1$
rm.done();
return;
}
IVMLayoutNode[] childNodes = layoutNode.getChildLayoutNodes();
// If parent element's layout node has no children, just mark done and
// return.
if (childNodes.length == 0) {
rm.setData(new Integer[0]);
rm.done();
return;
}
// Get the mapping of all the counts.
final Integer[] counts = new Integer[childNodes.length];
final MultiRequestMonitor<RequestMonitor> childrenCountMultiReqMon =
new MultiRequestMonitor<RequestMonitor>(getExecutor(), rm) {
@Override
protected void handleCompleted() {
if (!fDisposed) super.handleCompleted();
}
@Override
protected void handleOK() {
rm.setData(counts);
rm.done();
}
};
for (int i = 0; i < childNodes.length; i++) {
final int nodeIndex = i;
childNodes[i].updateElementCount(
new VMElementsCountUpdate(
update,
childrenCountMultiReqMon.add(
new DataRequestMonitor<Integer>(getExecutor(), null) {
@Override
protected void handleOK() {
counts[nodeIndex] = getData();
}
@Override
protected void handleCompleted() {
super.handleCompleted();
childrenCountMultiReqMon.requestMonitorDone(this);
}
}))
);
}
}
private void updateChildrenWithCounts(final IChildrenUpdate update, Integer[] nodeElementCounts) {
final IVMLayoutNode layoutNode = getLayoutNodeForElement(update.getElement());
if (layoutNode == null) {
// Stale update. Just ignore.
update.done();
return;
}
// Create the multi request monitor to mark update when querying all
// children nodes is finished.
final MultiRequestMonitor<RequestMonitor> elementsMultiRequestMon =
new MultiRequestMonitor<RequestMonitor>(getExecutor(), null) {
@Override
protected void handleCompleted() {
update.done();
}
};
// Iterate through all child nodes and if requested range matches, call them to
// get their elements.
int updateStartIdx = update.getOffset();
int updateEndIdx = update.getOffset() + update.getLength();
int idx = 0;
IVMLayoutNode[] layoutNodes = layoutNode.getChildLayoutNodes();
for (int i = 0; i < layoutNodes.length; i++) {
final int nodeStartIdx = idx;
final int nodeEndIdx = idx + nodeElementCounts[i];
idx = nodeEndIdx;
// Check if update range overlaps the node's range.
if (updateStartIdx <= nodeEndIdx && updateEndIdx > nodeStartIdx) {
final int elementsStartIdx = Math.max(updateStartIdx - nodeStartIdx, 0);
final int elementsEndIdx = Math.min(updateEndIdx - nodeStartIdx, nodeElementCounts[i]);
final int elementsLength = elementsEndIdx - elementsStartIdx;
if (elementsLength > 0) {
layoutNodes[i].updateElements(
new VMElementsUpdate(
update, elementsStartIdx, elementsLength,
elementsMultiRequestMon.add(new DataRequestMonitor<List<Object>>(getExecutor(), null) {
@Override
protected void handleCompleted() {
if (getStatus().isOK()) {
for (int i = 0; i < elementsLength; i++) {
update.setChild(getData().get(i), elementsStartIdx + nodeStartIdx + i);
}
}
elementsMultiRequestMon.requestMonitorDone(this);
}
}))
);
}
// Iterate through the current active proxies to try to find a proxy with the same
// element and re-use it if found. At the same time purge proxies that are no longer
IVMModelProxy proxy = null;
for (Iterator<IVMModelProxy> itr = getActiveModelProxies().iterator(); itr.hasNext();) {
IVMModelProxy next = itr.next();
if (next == null && next.getRootElement().equals(element)) {
proxy = next;
} else if (next.isDisposed()) {
itr.remove();
}
}
// Guard against invalid queries.
if (elementsMultiRequestMon.getRequestMonitors().isEmpty()) {
update.done();
if (proxy == null) {
proxy = createModelProxyStrategy(element);
getActiveModelProxies().add(proxy);
}
}
public ModelProxy createModelProxy(Object element, IPresentationContext context) {
/*
* Model proxy is the object that correlates events from the data model
* into view model deltas that the view can process. This method is called
* by the viewer when a new input object is set to the view. We need to create
* a new instance of the ModelProxy object with every call, because the viewer
* disposes the old proxy before calling this method.
*/
synchronized(this) {
fRootElement = element;
fModelProxy = new ModelProxy();
}
return fModelProxy;
return proxy;
}
/**
@ -466,6 +477,7 @@ abstract public class AbstractVMProvider implements IVMProvider
* @see IColumnPresentationFactory#createColumnPresentation(IPresentationContext, Object)
*/
public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) {
assert fExecutor.isInExecutorThread();
return null;
}
@ -500,119 +512,5 @@ abstract public class AbstractVMProvider implements IVMProvider
public void update(IViewerInputUpdate update) {
update.setInputElement(update.getElement());
update.done();
}
/**
* Convenience method that finds the VMC corresponding to given parent
* argument given to isContainer() or retrieveChildren().
* @param object Object to find the VMC for.
* @return parent VMC, if null it indicates that the object did not originate
* from this view or is stale.
*/
protected IVMLayoutNode getLayoutNodeForElement(Object element) {
/*
* First check to see if the parent object is the root object of the
* hierarchy. If that's the case, then retrieve the correcponding
* root VMC from the root node, and pass this root vmc to the root's
* child layout nodes.
*/
IVMRootLayoutNode rootLayoutNode = getRootLayoutNode();
if (rootLayoutNode == null) {
return null;
}
else if (element.equals(getRootElement())) {
return rootLayoutNode;
}
else if (element instanceof IVMContext){
/*
* The parent is a VMC. Check to make sure that the VMC
* originated from a node in this ViewModelProvider. If it didn't
* it is most likely a result of a change in view layout, and this
* request is a stale request. So just ignore it.
*/
if (isOurLayoutNode( ((IVMContext)element).getLayoutNode(),
new IVMLayoutNode[] { rootLayoutNode } ))
{
return ((IVMContext)element).getLayoutNode();
}
}
return null;
}
/**
* Convenience method which checks whether given layout node is a node
* that is configured in this ViewModelProvider. Implementation
* recursively walks the layout hierarchy, and returns true if it finds
* the node.
*/
private boolean isOurLayoutNode(IVMLayoutNode layoutNode, IVMLayoutNode[] nodesToSearch) {
for (IVMLayoutNode node : nodesToSearch) {
if (node == layoutNode) return true;
if (isOurLayoutNode(layoutNode, node.getChildLayoutNodes())) return true;
}
return false;
}
protected void handleEvent(final Object event) {
// We're in session's executor thread. Re-dispach to VM Adapter
// executor thread and then call root layout node.
try {
getExecutor().execute(new Runnable() {
public void run() {
if (isDisposed()) return;
IVMRootLayoutNode rootLayoutNode = getRootLayoutNode();
if (rootLayoutNode != null && rootLayoutNode.getDeltaFlags(event) != 0) {
rootLayoutNode.createDelta(
event,
new DataRequestMonitor<IModelDelta>(getExecutor(), null) {
@Override
public void handleCompleted() {
if (getStatus().isOK()) {
getModelProxy().fireModelChangedNonDispatch(getData());
}
}
@Override public String toString() {
return "Result of a delta for event: '" + event.toString() + "' in VMP: '" + AbstractVMProvider.this + "'" + "\n" + getData().toString(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
});
}
}});
} catch (RejectedExecutionException e) {
// Ignore. This exception could be thrown if the provider is being
// shut down.
}
}
@ThreadSafe
protected class ModelProxy extends AbstractModelProxy {
/**
* Scheduling rule for running the update jobs.
*/
private ISchedulingRule fModelChangeRule = new ISchedulingRule() {
public boolean contains(ISchedulingRule rule) { return this == rule; }
public boolean isConflicting(ISchedulingRule rule) { return rule == this; }
};
/**
* Fires given delta using a job. Processing the delta on the dispatch
* thread can lead to dead-locks.
* @param delta
*/
public void fireModelChangedNonDispatch(final IModelDelta delta) {
Job job = new Job("Processing view model delta.") { //$NON-NLS-1$
@Override
protected IStatus run(IProgressMonitor monitor) {
fireModelChanged(delta);
return Status.OK_STATUS;
}
};
job.setPriority(Job.INTERACTIVE);
job.setRule(fModelChangeRule);
job.schedule();
}
}
}
}

View file

@ -0,0 +1,370 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.MultiRequestMonitor;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
/**
* The default strategy for implementing the IElementContentProvider
* functionality for an IVMProvider. It implements an algorithm to populate
* contents of the view in accordance with the tree structure of the
* view model nodes configured in the view model provider.
* <p/>
* This class may be used by an <code>IVMProvider</code> directly, or it
* may be be extended to customize for the provider's needs.
* <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.
*/
@ConfinedToDsfExecutor("#getExecutor()")
@SuppressWarnings("restriction")
public class DefaultVMContentProviderStrategy implements IElementContentProvider {
private final AbstractVMProvider fVMProvider;
public DefaultVMContentProviderStrategy(AbstractVMProvider provider) {
fVMProvider = provider;
}
/**
* Returns the view model provider that this strategy is configured for.
* @return
*/
protected AbstractVMProvider getVMProvider() { return fVMProvider; }
public void update(final IHasChildrenUpdate[] updates) {
if (updates.length == 0) return;
// Optimization: if all the updates belong to the same node, avoid creating any new lists/arrays.
boolean allNodesTheSame = true;
IVMNode firstNode = getNodeForElement(updates[0].getElement());
for (int i = 1; i < updates.length; i++) {
if (firstNode != getNodeForElement(updates[i].getElement())) {
allNodesTheSame = false;
break;
}
}
if (allNodesTheSame) {
updateNode(firstNode, updates);
} else {
// Sort the updates by the node.
Map<IVMNode,List<IHasChildrenUpdate>> nodeUpdatesMap = new HashMap<IVMNode,List<IHasChildrenUpdate>>();
for (IHasChildrenUpdate update : updates) {
// Get the VM Context for last element in path.
IVMNode node = getNodeForElement(update.getElement());
if (node == null) {
// Stale update, most likely as a result of the nodes being
// changed. Just ignore it.
update.done();
continue;
}
if (!nodeUpdatesMap.containsKey(node)) {
nodeUpdatesMap.put(node, new ArrayList<IHasChildrenUpdate>());
}
nodeUpdatesMap.get(node).add(update);
}
// Iterate through the nodes in the sorted map.
for (IVMNode node : nodeUpdatesMap.keySet()) {
updateNode(node, nodeUpdatesMap.get(node).toArray(new IHasChildrenUpdate[nodeUpdatesMap.get(node).size()]));
}
}
}
private void updateNode(IVMNode node, final IHasChildrenUpdate[] updates) {
// If parent element's node has no children, just set the
// result and continue to next element.
final IVMNode[] childNodes = getVMProvider().getChildVMNodes(node);
if (childNodes.length == 0) {
for (IHasChildrenUpdate update : updates) {
update.setHasChilren(false);
update.done();
}
return;
}
// Create a matrix of element updates:
// The first dimension "i" is the list of children updates that came from the viewer.
// For each of these updates, there are "j" number of elment updates corresponding
// to the number of child nodes in this node.
// Each children update from the viewer is complete when all the child nodes
// fill in their elements update.
// Once the matrix is constructed, the child nodes are given the list of updates
// equal to the updates requested by the viewer.
VMHasChildrenUpdate[][] elementsUpdates =
new VMHasChildrenUpdate[childNodes.length][updates.length];
for (int i = 0; i < updates.length; i ++)
{
final IHasChildrenUpdate update = updates[i];
final MultiRequestMonitor<DataRequestMonitor<Boolean>> hasChildrenMultiRequestMon =
new MultiRequestMonitor<DataRequestMonitor<Boolean>>(getVMProvider().getExecutor(), null) {
@Override
protected void handleCompleted() {
// Status is OK, only if all request monitors are OK.
if (getStatus().isOK()) {
boolean isContainer = false;
for (DataRequestMonitor<Boolean> hasElementsDone : getRequestMonitors()) {
isContainer |= hasElementsDone.getStatus().isOK() &&
hasElementsDone.getData().booleanValue();
}
update.setHasChilren(isContainer);
} else {
update.setStatus(getStatus());
}
update.done();
}
};
for (int j = 0; j < childNodes.length; j++)
{
elementsUpdates[j][i] = new VMHasChildrenUpdate(
update,
hasChildrenMultiRequestMon.add(
new DataRequestMonitor<Boolean>(getVMProvider().getExecutor(), null) {
@Override
protected void handleCompleted() {
hasChildrenMultiRequestMon.requestMonitorDone(this);
}
}));
}
}
for (int j = 0; j < childNodes.length; j++) {
getVMProvider().updateNode(childNodes[j], elementsUpdates[j]);
}
}
public void update(final IChildrenCountUpdate[] updates) {
for (final IChildrenCountUpdate update : updates) {
IVMNode node = getNodeForElement(update.getElement());
if (node != null && !update.isCanceled()) {
IVMNode[] childNodes = getVMProvider().getChildVMNodes(node);
if (childNodes.length == 0) {
update.setChildCount(0);
update.done();
} else if (childNodes.length == 1) {
getVMProvider().updateNode(childNodes[0], new IChildrenCountUpdate[] { update } );
} else {
getChildrenCountsForNode(
update,
node,
new DataRequestMonitor<Integer[]>(getVMProvider().getExecutor(), null) {
@Override
protected void handleCompleted() {
if (getStatus().isOK()) {
int numChildren = 0;
for (Integer count : getData()) {
numChildren += count.intValue();
}
update.setChildCount(numChildren);
} else {
update.setChildCount(0);
}
update.done();
}
});
}
} else if (update.isCanceled()) {
update.done();
}
}
}
public void update(final IChildrenUpdate[] updates) {
for (final IChildrenUpdate update : updates) {
// Get the VM Context for last element in path.
final IVMNode node = getNodeForElement(update.getElement());
if (node != null && !update.isCanceled()) {
IVMNode[] childNodes = getVMProvider().getChildVMNodes(node);
if (childNodes.length == 0) {
// Invalid update, just mark done.
update.done();
} else if (childNodes.length == 1) {
getVMProvider().updateNode(childNodes[0], new IChildrenUpdate[] { update });
} else {
getChildrenCountsForNode(
update,
node,
new DataRequestMonitor<Integer[]>(getVMProvider().getExecutor(), null) {
@Override
protected void handleCompleted() {
if (!getStatus().isOK()) {
update.done();
return;
}
updateChildrenWithCounts(update, node, getData());
}
});
}
} else {
// Stale update. Just ignore.
update.done();
}
}
}
/**
* Calculates the number of elements in each child node for the element in
* update. These counts are then used to delegate the children update to
* the correct nodes.
*/
private void getChildrenCountsForNode(IViewerUpdate update, IVMNode updateNode, final DataRequestMonitor<Integer[]> rm) {
IVMNode[] childNodes = getVMProvider().getChildVMNodes(updateNode);
// Check for an invalid call
assert childNodes.length != 0;
// Get the mapping of all the counts.
final Integer[] counts = new Integer[childNodes.length];
final MultiRequestMonitor<RequestMonitor> childrenCountMultiReqMon =
new MultiRequestMonitor<RequestMonitor>(getVMProvider().getExecutor(), rm) {
@Override
protected void handleOK() {
rm.setData(counts);
rm.done();
}
};
for (int i = 0; i < childNodes.length; i++) {
final int nodeIndex = i;
getVMProvider().updateNode(
childNodes[i],
new IChildrenCountUpdate[] {
new VMChildrenCountUpdate(
update,
childrenCountMultiReqMon.add(
new DataRequestMonitor<Integer>(getVMProvider().getExecutor(), null) {
@Override
protected void handleOK() {
counts[nodeIndex] = getData();
}
@Override
protected void handleCompleted() {
super.handleCompleted();
childrenCountMultiReqMon.requestMonitorDone(this);
}
}))
});
}
}
/**
* Splits the given children update among the configured child nodes. Then calls
* each child node to complete the update.
*/
private void updateChildrenWithCounts(final IChildrenUpdate update, IVMNode node, Integer[] nodeElementCounts) {
// Create the multi request monitor to mark update when querying all
// children nodes is finished.
final MultiRequestMonitor<RequestMonitor> elementsMultiRequestMon =
new MultiRequestMonitor<RequestMonitor>(getVMProvider().getExecutor(), null) {
@Override
protected void handleCompleted() {
update.done();
}
};
// Iterate through all child nodes and if requested range matches, call them to
// get their elements.
int updateStartIdx = update.getOffset();
int updateEndIdx = update.getOffset() + update.getLength();
int idx = 0;
IVMNode[] nodes = getVMProvider().getChildVMNodes(node);
for (int i = 0; i < nodes.length; i++) {
final int nodeStartIdx = idx;
final int nodeEndIdx = idx + nodeElementCounts[i];
idx = nodeEndIdx;
// Check if update range overlaps the node's range.
if (updateStartIdx <= nodeEndIdx && updateEndIdx > nodeStartIdx) {
final int elementsStartIdx = Math.max(updateStartIdx - nodeStartIdx, 0);
final int elementsEndIdx = Math.min(updateEndIdx - nodeStartIdx, nodeElementCounts[i]);
final int elementsLength = elementsEndIdx - elementsStartIdx;
if (elementsLength > 0) {
getVMProvider().updateNode(
nodes[i],
new IChildrenUpdate[] {
new VMChildrenUpdate(
update, elementsStartIdx, elementsLength,
elementsMultiRequestMon.add(new DataRequestMonitor<List<Object>>(getVMProvider().getExecutor(), null) {
@Override
protected void handleCompleted() {
if (getStatus().isOK()) {
for (int i = 0; i < elementsLength; i++) {
update.setChild(getData().get(i), elementsStartIdx + nodeStartIdx + i);
}
}
elementsMultiRequestMon.requestMonitorDone(this);
}
}))
}
);
}
}
}
// Guard against invalid queries.
assert !elementsMultiRequestMon.getRequestMonitors().isEmpty();
}
/**
* Convenience method that finds the VMC corresponding to given parent
* argument given to isContainer() or retrieveChildren().
* @param object Object to find the VMC for.
* @return parent VMC, if null it indicates that the object did not originate
* from this view or is stale.
*/
protected IVMNode getNodeForElement(Object element) {
if (element instanceof IVMContext) {
IVMNode node = ((IVMContext)element).getVMNode();
if (isOurNode(((IVMContext)element).getVMNode())) {
return node;
}
}
return getVMProvider().getRootVMNode();
}
/**
* Convenience method which checks whether given layout node is a node
* that is configured in this ViewModelProvider.
*/
private boolean isOurNode(IVMNode node) {
for (IVMNode nodeToSearch : getVMProvider().getAllVMNodes()) {
if (nodeToSearch.equals(node)) return true;
}
return false;
}
}

View file

@ -0,0 +1,615 @@
/*******************************************************************************
* Copyright (c) 2005, 2007 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Wind River Systems - adapted to use with DSF
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.MultiRequestMonitor;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelChangedListener;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.jface.viewers.Viewer;
/**
* 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.
*/
@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 fListeners = new ListenerList();
/**
* Debug flag indicating whether the deltas should be traced in stdout.
*/
private static boolean DEBUG_DELTAS = false;
static {
DEBUG_DELTAS = DebugUIPlugin.DEBUG && "true".equals( //$NON-NLS-1$
Platform.getDebugOption("org.eclipse.debug.ui/debug/viewers/deltas")); //$NON-NLS-1$
}
/**
* Creates this model proxy strategy for the given provider.
*/
public DefaultVMModelProxyStrategy(AbstractVMProvider provider, Object rootElement) {
fProvider = provider;
fRootElement = rootElement;
}
public boolean isDeltaEvent(Object event) {
IRootVMNode rootNode = getVMProvider().getRootVMNode();
return rootNode != null &&
rootNode.isDeltaEvent(getRootElement(), event) &&
getDeltaFlags(rootNode, null, event) != 0;
}
/**
* Returns the view model provider that this strategy is configured for.
* @return
*/
protected AbstractVMProvider getVMProvider() {
return fProvider;
}
private Object[] getListeners() {
return fListeners.getListeners();
}
public void addModelChangedListener(IModelChangedListener listener) {
fListeners.add(listener);
}
public void removeModelChangedListener(IModelChangedListener listener) {
fListeners.remove(listener);
}
public Object getRootElement() {
return fRootElement;
}
/**
* Notifies registered listeners of the given delta.
*
* @param delta model delta to broadcast
*/
public void fireModelChanged(IModelDelta delta) {
final IModelDelta root = getRootDelta(delta);
Object[] listeners = getListeners();
if (DEBUG_DELTAS) {
DebugUIPlugin.debug("FIRE DELTA: " + delta.toString()); //$NON-NLS-1$
}
for (int i = 0; i < listeners.length; i++) {
final IModelChangedListener listener = (IModelChangedListener) listeners[i];
ISafeRunnable safeRunnable = new ISafeRunnable() {
public void handleException(Throwable exception) {
DebugUIPlugin.log(exception);
}
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()
*/
public void dispose() {
fDisposed = true;
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.IModelProxy#init(org.eclipse.debug.internal.ui.viewers.IPresentationContext)
*/
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)
*/
public void installed(Viewer viewer) {
fViewer = viewer;
}
/**
* Returns the viewer this proxy is installed in.
*
* @return viewer or <code>null</code> if not installed
*/
protected Viewer getViewer() {
return fViewer;
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy#isDisposed()
*/
public boolean isDisposed() {
return fDisposed;
}
/**
* Recursively calls the VM nodes in the hierarchy of the given node
* to calculate the delta flags that are
* <p/>
* Note: If a child node has a <code>IModelDelta.CONTENT</code> delta
* flag, it means that this flag will be added to this node's element.
* To allow for optimization change the child's <code>IModelDelta.CONTENT</code>
* flag into a <code>IModelDelta.STATE</code> flag.
*
* @param node
* @param event
* @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);
if ((childNodeDeltaFlags & IModelDelta.CONTENT) != 0) {
childNodeDeltaFlags &= ~IModelDelta.CONTENT;
childNodeDeltaFlags |= IModelDelta.STATE;
}
flags |= childNodeDeltaFlags;
}
}
// Optimization: If the parent delta contains the "content" flag, we do
// not need to add it to the child. This can shorten delta processing
// considerably so check for it.
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.
*/
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<ModelDelta>(getVMProvider().getExecutor(), rm) {
@Override
protected void handleOK() {
// Find the root delta for the whole view to use when firing the delta.
// Note: the view root is going to be different than the model root
// in case when the view model provider is registered to populate only
// a sub-tree of a view.
final IModelDelta viewRootDelta = getRootDelta(getData());
// Find the child nodes that 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.done();
rm.setData(viewRootDelta);
return;
}
callChildNodesToBuildDelta(
rootNode,
childNodesWithDeltaFlags, getData(), event,
new RequestMonitor(getVMProvider().getExecutor(), rm) {
@Override
protected void handleOK() {
rm.setData(viewRootDelta);
rm.done();
}
});
}
});
}
protected void buildChildDeltas(final IVMNode node, final Object event, final ModelDelta parentDelta,
final int nodeOffset, final RequestMonitor rm)
{
final IVMContext vmc = node.getContextFromEvent(event);
if (vmc != null) {
buildChildDeltasForEventContext(vmc, node, event, parentDelta, nodeOffset, rm);
} else {
// The DMC for this node was not found in the event. Call the
// super-class to resort to the default behavior which may add a
// delta for every element in this node.
buildChildDeltasForAllContexts(node, event, parentDelta, nodeOffset, rm);
}
}
protected void buildChildDeltasForEventContext(final IVMContext vmc, final IVMNode node, final Object event,
final ModelDelta parentDelta, final int nodeOffset, final RequestMonitor requestMonitor)
{
final Map<IVMNode,Integer> childNodeDeltas = getChildNodesWithDeltaFlags(node, parentDelta, event);
if (childNodeDeltas.size() == 0) {
// There are no child nodes with deltas, just return to parent.
requestMonitor.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 : childNodeDeltas.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 IChildrenUpdate[] {
new VMChildrenUpdate(
parentDelta, getVMProvider().getPresentationContext(), -1, -1,
new DataRequestMonitor<List<Object>>(getVMProvider().getExecutor(), null) {
@Override
protected void handleCompleted() {
if (isDisposed()) return;
// 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 (!getStatus().isOK() || getData().isEmpty()) {
requestMonitor.done();
return;
}
// Find the index.
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.
requestMonitor.done();
return;
}
// 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;
ModelDelta delta = parentDelta.getChildDelta(vmc);
if (delta == null || delta.getIndex() != elementIndex) {
delta = parentDelta.addNode(vmc, elementIndex, IModelDelta.NO_CHANGE);
}
callChildNodesToBuildDelta(node, childNodeDeltas, delta, event, requestMonitor);
}
})
});
} else {
// Optimization: Try to find a delta with a matching element, if found use it.
// Otherwise create a new delta for the event element.
ModelDelta delta = parentDelta.getChildDelta(vmc);
if (delta == null) {
delta = parentDelta.addNode(vmc, IModelDelta.NO_CHANGE);
}
callChildNodesToBuildDelta(node, childNodeDeltas, delta, event, requestMonitor);
}
}
/**
* 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. In order to build delta
* only for specific elements in this node, the class extending
* <code>AbstractVMNode</code> should override this method.
* @see IVMNode#buildDelta(Object, ModelDelta, int, RequestMonitor)
*/
protected void buildChildDeltasForAllContexts(final IVMNode node, final Object event, final ModelDelta parentDelta,
final int nodeOffset, final RequestMonitor requestMonitor)
{
// Find the child nodes that have deltas for the given event.
final Map<IVMNode,Integer> childNodesWithDeltaFlags = getChildNodesWithDeltaFlags(node, parentDelta, event);
// If no child nodes have deltas we can stop here.
if (childNodesWithDeltaFlags.size() == 0) {
requestMonitor.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 TreeUpdatePolicy does not use the full path from the
// delta to handle these flags. Similarly, the index argument is
// not necessary either.
boolean mustGetElements = false;
for (int childDelta : childNodesWithDeltaFlags.values()) {
if ((childDelta & ~IModelDelta.STATE) != 0) {
mustGetElements = true;
}
}
if (!mustGetElements) {
callChildNodesToBuildDelta(node, childNodesWithDeltaFlags, parentDelta, event, requestMonitor);
} 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 IChildrenUpdate[] {
new VMChildrenUpdate(
parentDelta, getVMProvider().getPresentationContext(), -1, -1,
new DataRequestMonitor<List<Object>>(getVMProvider().getExecutor(), null) {
@Override
protected void handleCompleted() {
if (fDisposed) return;
// 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 (!getStatus().isOK() || getData().size() == 0) {
requestMonitor.done();
return;
}
final MultiRequestMonitor<RequestMonitor> elementsDeltasMultiRequestMon =
new MultiRequestMonitor<RequestMonitor>(getVMProvider().getExecutor(), null) {
@Override
protected void handleCompleted() {
if (isDisposed()) return;
requestMonitor.done();
}
};
// 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 < getData().size(); i++) {
int elementIndex = nodeOffset >= 0 ? nodeOffset + i : -1;
ModelDelta delta =
parentDelta.addNode(getData().get(i), elementIndex, IModelDelta.NO_CHANGE);
callChildNodesToBuildDelta(
node, childNodesWithDeltaFlags, delta, event,
elementsDeltasMultiRequestMon.add(new RequestMonitor(getVMProvider().getExecutor(), null) {
@Override
protected void handleCompleted() {
elementsDeltasMultiRequestMon.requestMonitorDone(this);
}
}));
}
}
})
});
}
}
/**
* Calls the specified child nodes to build the delta for the given event.
* @param childNodes Map of nodes to be invoked, and the corresponding delta
* flags that they will generate. This map is generated with a call to
* {@link #getChildNodesWithDeltaFlags(Object)}.
* @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 event The event object that the delta is being built for.
* @param requestMonitor The result token to invoke when the delta is completed.
*/
protected void callChildNodesToBuildDelta(final IVMNode node, final Map<IVMNode,Integer> childNodes, final ModelDelta delta, final Object event, final RequestMonitor requestMonitor) {
assert childNodes.size() != 0;
// 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 calculateOffsets = false;
for (int childDelta : childNodes.values()) {
if ( (childDelta & (IModelDelta.SELECT | IModelDelta.EXPAND)) != 0 ) {
calculateOffsets = true;
break;
}
}
getChildNodesElementOffsets(
node, delta, calculateOffsets,
new DataRequestMonitor<Map<IVMNode, Integer>>(getVMProvider().getExecutor(), null) {
@Override
protected void handleCompleted() {
if (isDisposed()) return;
final CountingRequestMonitor multiRm = new CountingRequestMonitor(getVMProvider().getExecutor(), requestMonitor);
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()) {
// Avoid descending into recursive node hierarchy's when calculating the delta.
if (node.equals(childNode)) continue;
final int nodeOffset = getData().get(childNode);
childNode.buildDelta(
event, delta, nodeOffset,
new RequestMonitor(getVMProvider().getExecutor(), multiRm) {
@Override
protected void handleOK() {
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 MultiRequestMonitor<RequestMonitor> childrenCountMultiRequestMon =
new MultiRequestMonitor<RequestMonitor>(getVMProvider().getExecutor(), rm) {
@Override
protected void handleCompleted() {
if (isDisposed()) return;
super.handleCompleted();
}
@Override
protected void handleOK() {
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();
}
};
for (int i = 0; i < childNodes.length; i++) {
final int nodeIndex = i;
getVMProvider().updateNode(
childNodes[i],
new IChildrenCountUpdate[] {
new VMChildrenCountUpdate(
delta, getVMProvider().getPresentationContext(),
childrenCountMultiRequestMon.add(
new DataRequestMonitor<Integer>(getVMProvider().getExecutor(), null) {
@Override
protected void handleCompleted() {
counts[nodeIndex] = getData();
childrenCountMultiRequestMon.requestMonitorDone(this);
}
})
)
});
}
} 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 the child nodes which return
* <code>true</code> to the <code>hasDeltaFlags()</code> test for the given
* event.
*/
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)) {
int delta = getDeltaFlags(childNode, parentDelta, e);
if (delta != IModelDelta.NO_CHANGE) {
nodes.put(childNode, delta);
}
}
}
return nodes;
}
}

View file

@ -0,0 +1,46 @@
/*******************************************************************************
* Copyright (c) 2006 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
/**
* Special type of the view model node, which can be used as a root node
* for a hierarchy. The root node of a layout hierarchy has to implement this
* interface.
*/
@SuppressWarnings("restriction")
public interface IRootVMNode extends IVMNode{
/**
* Returns whether the given event should be processed for delta generation.
* Root node is different than other nodes in that there is only one root
* element in the view model provider hierarchy. This method allows the root
* node to match up the root object of the provider with the given event. If
* the root node can determine that the given event does not apply to the root
* object, it should return false so that the event is ignored.
*
* @param rootObject The root object of the VM provider
* @param event
* @return
*/
public boolean isDeltaEvent(Object rootObject, Object event);
/**
* Version of the {@link IVMNode#buildDelta(Object, ViewModelDelta, org.eclipse.dd.dsf.concurrent.RequestMonitor)}
* method, which creates and returns the root node of the delta. It does
* not require a parent object for the delta, as this is the root node.
* @param event Event to process.
* @param rm Result notification, contains the root of the delta.
*/
public void createRootDelta(Object rootObject, Object event, DataRequestMonitor<ModelDelta> rm);
}

View file

@ -14,13 +14,16 @@ import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.dd.dsf.concurrent.Immutable;
/**
* View Model element which is stored as the data object of nodes in the viewer.
* View model element which is stored as the data object of nodes in the viewer.
* The implementation of this interface is usually a wrapper object for an object
* from some data model, which is then used to correctly implement the
* {@link #equals(Object)} and {@link #hashCode()} methods of this wrapper.
*/
@Immutable
public interface IVMContext extends IAdaptable {
/**
* Returns the layout node that originated this element.
* Returns the view model node that originated this element.
*/
public IVMLayoutNode getLayoutNode();
public IVMNode getVMNode();
}

View file

@ -0,0 +1,31 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
/**
*
*/
@SuppressWarnings("restriction")
public interface IVMModelProxy extends IModelProxy {
public Object getRootElement();
public boolean isDeltaEvent(Object event);
public void createDelta(final Object event, final DataRequestMonitor<IModelDelta> rm);
public void fireModelChanged(IModelDelta delta);
}

View file

@ -12,82 +12,46 @@ package org.eclipse.dd.dsf.ui.viewmodel;
import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.service.IDsfService;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
/**
* View model layout nodes are combined together into a tree, to collectively
* View model nodes are configured with a view model provider to collectively
* define the layout of a view. Each layout node generates elements of type
* IVMContext which are then stored in the viewer.
* <p>
* Besides the standard Data Model Context based implementation, this
* node could be implemented to present data from any source, not necessarily
* DSF services. It could also define a static node which operates on basis
* of other data in the view tree.
* {@link IVMContext} which are then stored in the viewer.
*
* <p/>
* NOTE: This interface extends <code>IElementContentProvider</code> but it has
* slightly different parameter requirements. For the
* {@link IElementContentProvider#update(IChildrenUpdate[])} method, this class
* can accept an update where {@link IChildrenUpdate#getOffset()} and
* {@link IChildrenUpdate#getLength()} may return -1. In this case the
* implementation should return all available elements for the given parent.<br>
* Also the for the {@link IElementContentProvider#update(IHasChildrenUpdate[])} and
* {@link IElementContentProvider#update(IChildrenCountUpdate[])} methods, the
* implementation may return an error with an error code of {@link IDsfService#NOT_SUPPORTED}.
* In this case the caller of this update should call
* {@link IElementContentProvider#update(IChildrenUpdate[])}
* instead.
*
* @see AbstractDMVMProvider
* @see IElementContentProvider
*/
@ConfinedToDsfExecutor("")
@SuppressWarnings("restriction")
public interface IVMLayoutNode
public interface IVMNode extends IElementContentProvider
{
/**
* Retrieves the associated VM Provider.
* Retrieves the view model provider that this node is configured with.
*/
public IVMProvider getVMProvider();
/**
* Retrieves information whether for a given path in the viewer,
* there are any elements available in this node.
*
* @param updates The update objects which need to be filled in with results
* calculated by this method.
* Even though the "children" interface is reused, the updates refer to the
* elements of this layout node, and not it's children.
*/
public void updateHasElements(IHasChildrenUpdate[] updates);
/**
* Retrieves the number of available elements in this node for the given
* path in the viewer.
*
* @param updates The update object which needs to be filled in with result
* calculated by this method.
* Even though the "children" interface is reused, the updates refer to the
* elements of this layout node, and not it's children.
*/
public void updateElementCount(IChildrenCountUpdate update);
/**
* Retrieves the element objects of this node for the given path in the
* viewer, and for the given range of indexes. <br>
* NOTE: update.getOffset() and update.getLength() may return -1.
* The range of children, denoted by ILabelUpdate.getOffset()
* and ILabelUpdate.getLength(), may not be specified, in which case these
* methods may return -1. This means that all the elements should be
* retrieved for this node.<br>
*
* @param updates The update object which needs to be filled in with result
* calculated by this method.
* Even though the "children" interface is reused, the updates refer to the
* elements of this layout node, and not it's children.
*/
public void updateElements(IChildrenUpdate update);
/**
* Configures the child layout nodes for this node.
* @param childNodes
*/
public void setChildNodes(IVMLayoutNode[] childNodes);
/**
* Returns the list of child layout nodes which are configured for this node.
*/
public IVMLayoutNode[] getChildLayoutNodes();
/**
* Returns the potential delta flags that would be generated by this node
* for the given event.
@ -126,8 +90,24 @@ public interface IVMLayoutNode
* @param requestMonitor Return token, which notifies the caller that the calculation is
* complete.
*/
public void buildDelta(Object event, VMDelta parent, int nodeOffset, RequestMonitor requestMonitor);
public void buildDelta(Object event, ModelDelta parent, int nodeOffset, RequestMonitor requestMonitor);
/**
* Returns the view model element for the given data model event. This method
* is optional and it allows the view model provider to optimize event processing
* by avoiding the need to retrieve all possible elements for the given node.
* </p>
* For example: If a threads node implementation is given a thread stopped event in
* for this method, and the stopped event included a reference to the thread. Then
* the implementation should create a view model context for that thread and return it
* here.
*
* @param event The event to check for the data model object.
* @return A view model object if it can be calculated, <code>null</code>
* if it cannot.
*/
public IVMContext getContextFromEvent(Object event);
/**
* Releases the resources held by this node.
*/

View file

@ -1,6 +1,8 @@
package org.eclipse.dd.dsf.ui.viewmodel;
import org.eclipse.dd.dsf.concurrent.ThreadSafe;
import java.util.concurrent.Executor;
import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory;
@ -8,11 +10,31 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationCont
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputProvider;
/**
* The View Model Provider handles the layout of a given model within a
* The view model provider handles the layout of a given model within a
* single viewer. The View Model Adapter delegates calls for view content to
* this object for a view that this provider handles.
* this object for a view that this provider handles.
*
* <p/>
* A given view model provider is typically configured with a number of
* {@link IVMNode} objects which are organized in a parent-child hierarchy.
* The node hierarchy has a root node which is retrieved using {@link #getRootVMNode()}.
*
* <p/>
* Note on concurency: The view model provider is single-threaded and it has to be
* accessed only using the <code>Executor</code> returned by {@link #getExecutor()}.
* The thread of this executor should be the display thread used by the viewer
* corresponding to the view model provider. Currently the flexible hierarchy
* interfaces that this interface extends do not guarantee that their methods
* will be called on the display thread, although from their use we are making
* this assumption (bug 213629). {@link IElementContentProvider} is an
* exception to this, it is called by the TreeModelViewer on a background
* thread, however it is not expected that the viewer will be calling the
* IVMProvider directly. Rather, it is expected that the viewer will call
* {@link IVMAdapter} which implements <code>IElementContentProvider</code>,
* and <code>IVMAdapter</code> implementation is expected to switch to
* provider's thread before delegating the call to it.
*/
@ThreadSafe
@ConfinedToDsfExecutor("#getExecutor()")
@SuppressWarnings("restriction")
public interface IVMProvider
extends IElementContentProvider, IModelProxyFactory, IColumnPresentationFactory, IViewerInputProvider
@ -23,19 +45,25 @@ public interface IVMProvider
public IVMAdapter getVMAdapter();
/**
* Returns the root layout node that is configured in this provider.
* It may return null, if a root node is not yet configured.
* Returns the executor that needs to be used to access this provider.
*/
public IVMRootLayoutNode getRootLayoutNode();
public Executor getExecutor();
/**
* Returns the root element of the view model. If the given view model is
* used to populate the entire contents of the view, then this is the input
* element for the viewer. If the view model is used to populate only a
* sub-tree section of the view, then this is the root element of that
* sub-tree.
* Returns the root node that is configured in this provider.
* It may return null, if a root node is not yet configured.
*/
public Object getRootElement();
public IRootVMNode getRootVMNode();
/**
* Returns an array of nodes which are configured as child nodes of the given node.
*/
public IVMNode[] getChildVMNodes(IVMNode node);
/**
* Retrieves the list of all nodes configured for this provider.
*/
public IVMNode[] getAllVMNodes();
/**
* Returns the presentation context of the viewer that this provider
@ -43,12 +71,6 @@ public interface IVMProvider
*/
public IPresentationContext getPresentationContext();
/**
* Allows other subsystems to force the layout mode associated with the specified
* VM context to refresh. If null is passed then the RootLayoutNode is told to refresh.
*/
public void refresh(IVMContext element);
/**
* Cleans up the resources associated with this provider.
*/

View file

@ -1,32 +0,0 @@
/*******************************************************************************
* Copyright (c) 2006 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
/**
* Special type of the view model layout node, which can be used as a root node
* for a hierarchy. The root node of a layout hierarchy has to implement this
* interface.
*/
@SuppressWarnings("restriction")
public interface IVMRootLayoutNode extends IVMLayoutNode{
/**
* Version of the {@link IVMLayoutNode#buildDelta(Object, ViewModelDelta, org.eclipse.dd.dsf.concurrent.RequestMonitor)}
* method, which creates and returns the root node of the delta. It does
* not require a parent object for the delta, as this is the root node.
* @param event Event to process.
* @param rm Result notification, contains the root of the delta.
*/
public void createDelta(Object event, DataRequestMonitor<IModelDelta> rm);
}

View file

@ -0,0 +1,69 @@
/*******************************************************************************
* Copyright (c) 2006 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
/**
* Default implementation of a root view model node. This class may be sub-classed
* to implement model-specific event handling.
*/
@SuppressWarnings("restriction")
public class RootVMNode extends AbstractVMNode implements IRootVMNode {
public RootVMNode(AbstractVMProvider provider) {
super(provider);
}
public void update(IChildrenUpdate[] updates) {
throw new UnsupportedOperationException("Root view model node should never be queried for list of elements."); //$NON-NLS-1$
}
public void update(IChildrenCountUpdate[] updates) {
throw new UnsupportedOperationException("Root view model node should never be queried for list of elements."); //$NON-NLS-1$
}
public void update(IHasChildrenUpdate[] updates) {
throw new UnsupportedOperationException("Root view model node should never be queried for list of elements."); //$NON-NLS-1$
}
/**
* Default implementation does not examine the event and assumes that every
* event should be processed to generate a delta.
*/
public boolean isDeltaEvent(Object rootObject, Object event) {
return true;
}
/**
* Default implementation creates a delta assuming that the root layout node
* is the input object into the view.
*/
public void createRootDelta(Object rootObject, Object event, final DataRequestMonitor<ModelDelta> rm) {
rm.setData(new ModelDelta(rootObject, 0, IModelDelta.NO_CHANGE));
rm.done();
}
public int getDeltaFlags(Object event) {
return IModelDelta.NO_CHANGE;
}
public void buildDelta(Object event, ModelDelta parent, int nodeOffset, RequestMonitor requestMonitor) {
requestMonitor.done();
}
}

View file

@ -12,22 +12,35 @@ package org.eclipse.dd.dsf.ui.viewmodel;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
import org.eclipse.jface.viewers.TreePath;
/**
* Helper class implementation of an update object to use with IElementContentProvider.
* @see IElementContentProvider
* Helper class implementation of the {@link IChildrenCountUpdate} update object.
*
* @see VMViewerUpdate
*/
@SuppressWarnings("restriction")
public class VMElementsCountUpdate extends VMViewerUpdate implements IChildrenCountUpdate {
public class VMChildrenCountUpdate extends VMViewerUpdate implements IChildrenCountUpdate {
final private DataRequestMonitor<Integer> fCountRequestMonitor;
public VMElementsCountUpdate(IViewerUpdate clientUpdate, DataRequestMonitor<Integer> rm) {
public VMChildrenCountUpdate(IViewerUpdate clientUpdate, DataRequestMonitor<Integer> rm) {
super(clientUpdate, rm);
fCountRequestMonitor = rm;
}
public VMChildrenCountUpdate(IModelDelta delta, IPresentationContext presentationContext, DataRequestMonitor<Integer> rm) {
super(delta, presentationContext, rm);
fCountRequestMonitor = rm;
}
public VMChildrenCountUpdate(TreePath elementPath, Object viewerInput, IPresentationContext presentationContext, DataRequestMonitor<Integer> rm) {
super(elementPath, viewerInput, presentationContext, rm);
fCountRequestMonitor = rm;
}
public void setChildCount(int count) {
fCountRequestMonitor.setData(count);
}

View file

@ -19,25 +19,49 @@ import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.service.IDsfService;
import org.eclipse.dd.dsf.ui.DsfUIPlugin;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
import org.eclipse.jface.viewers.TreePath;
/**
* Helper class implementation of an update object to use with IElementContentProvider.
* @see IElementContentProvider
* Helper class implementation of the {@link IChildrenUpdate} update object.
*
* @see VMViewerUpdate
*/
@SuppressWarnings("restriction")
public class VMElementsUpdate extends VMViewerUpdate implements IChildrenUpdate {
public class VMChildrenUpdate extends VMViewerUpdate implements IChildrenUpdate {
private final int fOffset;
private final int fLength;
protected final List<Object> fElements;
public VMElementsUpdate(IChildrenUpdate clientUpdate, int offset, int length, DataRequestMonitor<List<Object>> requestMonitor) {
public VMChildrenUpdate(IViewerUpdate clientUpdate, int offset, int length,
DataRequestMonitor<List<Object>> requestMonitor)
{
super(clientUpdate, requestMonitor);
fOffset = offset;
fLength = length;
fElements = length > 0 ? new ArrayList<Object>(length) : new ArrayList<Object>();
}
public VMChildrenUpdate(IModelDelta delta, IPresentationContext presentationContext, int offset, int length,
DataRequestMonitor<List<Object>> rm)
{
super(delta, presentationContext, rm);
fOffset = offset;
fLength = length;
fElements = length > 0 ? new ArrayList<Object>(length) : new ArrayList<Object>();
}
public VMChildrenUpdate(TreePath elementPath, Object viewerInput, IPresentationContext presentationContext,
int offset, int length, DataRequestMonitor<List<Object>> rm)
{
super(elementPath, viewerInput, presentationContext, rm);
fOffset = offset;
fLength = length;
fElements = length > 0 ? new ArrayList<Object>(length) : new ArrayList<Object>();
}
public int getOffset() {
return fOffset;
}
@ -74,10 +98,37 @@ public class VMElementsUpdate extends VMViewerUpdate implements IChildrenUpdate
@Override
public void done() {
@SuppressWarnings("unchecked")
DataRequestMonitor<List<Object>> rm = (DataRequestMonitor<List<Object>>)fRequestMonitor;
if (fElements.size() == fLength || fLength == -1 ) {
rm.setData(fElements);
} else {
DataRequestMonitor<List<Object>> rm = (DataRequestMonitor<List<Object>>)getRequestMonitor();
/* See https://bugs.eclipse.org/bugs/show_bug.cgi?id=202109
*
* A flexible hierarchy bug/optimization causes query with incorrect
* IChildrenUpdate[] array length.
*
* We found this while deleting a register node. Example:
*
* the register view displays:
* PC
* EAX
* EBX
* ECX
* EDX
*
* we delete EBX and force a context refresh.
*
* flexible hierarchy queries for IChildrenUpdate[5] and IChildrenCountUpdate at
* the same time.
*
* VMElementsUpdate, used by VMCache to wrap the IChildrenUpdate, generates an
* IStatus.ERROR with message "Incomplete elements of updates" when fElements
* count (provided by service) does not match the length provided by the original
* update query.
*
* Workaround, always set the elements array in the request monitor, but still set
* the error status.
*/
rm.setData(fElements);
if (rm.getStatus().isOK() && fLength != -1 && fElements.size() != fLength) {
rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, "Incomplete elements of updates", null)); //$NON-NLS-1$
}
super.done();

View file

@ -1,330 +0,0 @@
/*******************************************************************************
* Copyright (c) 2005, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Wind River Systems - adapted to use in DSF
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDeltaVisitor;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
/**
* This delta class mostly just duplicates the ModelDelta implemention, but
* it allows clients to modify the flags after the original object is
* constructed.
*
* @see IModelDelta#getNodes()
*/
@SuppressWarnings("restriction")
public class VMDelta extends ModelDelta {
private VMDelta fParent;
private Object fElement;
private int fFlags;
private VMDelta[] fNodes = EMPTY_NODES;
private Object fReplacement;
private int fIndex;
private static final VMDelta[] EMPTY_NODES = new VMDelta[0];
private int fChildCount = -1;
/**
* Constructs a new delta for the given element.
*
* @param vmcElement model element
* @param flags change flags
*/
public VMDelta(Object element, int flags) {
super(element, flags);
fElement = element;
fFlags = flags;
}
/**
* Constructs a new delta for the given element to be replaced
* with the specified replacement element.
*
* @param vmcElement model element
* @param replacement replacement element
* @param flags change flags
*/
public VMDelta(Object element, Object replacement, int flags) {
super(element, replacement, flags);
fElement = element;
fReplacement = replacement;
fFlags = flags;
}
/**
* Constructs a new delta for the given element to be inserted at
* the specified index.
*
* @param vmcElement model element
* @param index insertion position
* @param flags change flags
*/
public VMDelta(Object element, int index, int flags) {
super(element, index, flags);
fElement = element;
fIndex = index;
fFlags = flags;
}
/**
* Constructs a new delta for the given element at the specified index
* relative to its parent with the given number of children.
*
* @param element model element
* @param index insertion position
* @param flags change flags
* @param childCount number of children this node has
*/
public VMDelta(Object element, int index, int flags, int childCount) {
super(element, index, flags, childCount);
fElement = element;
fIndex = index;
fFlags = flags;
fChildCount = childCount;
}
/**
* Returns the non-VMC element if one is set, otherwise returns the VMC
* element of this delta node.
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getElement()
*/
@Override
public Object getElement() {
return fElement;
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getFlags()
*/
@Override
public int getFlags() {
return fFlags;
}
public void addFlags(int flags) {
fFlags |= flags;
}
public void setChildCount(int count) {
fChildCount = count;
}
/**
* Adds a child node to this delta with the given element and change flags,
* and returns the child delta.
*
* @param element child element to add
* @param flags change flags for child
* @return newly created child delta
*/
@Override
public VMDelta addNode(Object element, int flags) {
VMDelta node = new VMDelta(element, flags);
node.setParent(this);
addDelta(node);
return node;
}
/**
* Adds a child node to this delta to replace the given element with the
* specified replacement element and change flags, and returns the
* newly created child delta.
*
* @param element child element to add to this delta
* @param replacement replacement element for the child element
* @param flags change flags
* @return newly created child delta
*/
@Override
public VMDelta addNode(Object element, Object replacement, int flags) {
VMDelta node = new VMDelta(element, replacement, flags);
node.setParent(this);
addDelta(node);
return node;
}
/**
* Adds a child delta to this delta to insert the specified element at
* the given index, and returns the newly created child delta.
*
* @param element child element in insert
* @param index index of insertion
* @param flags change flags
* @return newly created child delta
*/
@Override
public VMDelta addNode(Object element, int index, int flags) {
VMDelta node = new VMDelta(element, index, flags);
node.setParent(this);
addDelta(node);
return node;
}
/**
* Adds a child delta to this delta at the specified index with the
* given number of children, and returns the newly created child delta.
*
* @param element child element in insert
* @param index index of the element relative to parent
* @param flags change flags
* @param numChildren the number of children the element has
* @return newly created child delta
*/
@Override
public VMDelta addNode(Object element, int index, int flags, int numChildren) {
VMDelta node = new VMDelta(element, index, flags, numChildren);
node.setParent(this);
addDelta(node);
return node;
}
/**
* Sets the parent delta of this delta
*
* @param node parent delta
*/
void setParent(VMDelta node) {
fParent = node;
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getParent()
*/
@Override
public VMDelta getParentDelta() {
return fParent;
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getReplacementElement()
*/
@Override
public Object getReplacementElement() {
return fReplacement;
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getIndex()
*/
@Override
public int getIndex() {
return fIndex;
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getNodes()
*/
@Override
public VMDelta[] getChildDeltas() {
return fNodes;
}
private void addDelta(VMDelta delta) {
if (fNodes.length == 0) {
fNodes = new VMDelta[]{delta};
} else {
VMDelta[] nodes = new VMDelta[fNodes.length + 1];
System.arraycopy(fNodes, 0, nodes, 0, fNodes.length);
nodes[fNodes.length] = delta;
fNodes = nodes;
}
}
@Override
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("Model Delta Start\n"); //$NON-NLS-1$
appendDetail(buf, this);
buf.append("Model Delta End\n"); //$NON-NLS-1$
return buf.toString();
}
private void appendDetail(StringBuffer buf, VMDelta delta) {
buf.append("\tElement: "); //$NON-NLS-1$
buf.append(delta.getElement());
buf.append('\n');
buf.append("\t\tFlags: "); //$NON-NLS-1$
int flags = delta.getFlags();
if (flags == 0) {
buf.append("NO_CHANGE"); //$NON-NLS-1$
} else {
if ((flags & IModelDelta.ADDED) > 0) {
buf.append("ADDED | "); //$NON-NLS-1$
}
if ((flags & IModelDelta.CONTENT) > 0) {
buf.append("CONTENT | "); //$NON-NLS-1$
}
if ((flags & IModelDelta.EXPAND) > 0) {
buf.append("EXPAND | "); //$NON-NLS-1$
}
if ((flags & IModelDelta.INSERTED) > 0) {
buf.append("INSERTED | "); //$NON-NLS-1$
}
if ((flags & IModelDelta.REMOVED) > 0) {
buf.append("REMOVED | "); //$NON-NLS-1$
}
if ((flags & IModelDelta.REPLACED) > 0) {
buf.append("REPLACED | "); //$NON-NLS-1$
}
if ((flags & IModelDelta.SELECT) > 0) {
buf.append("SELECT | "); //$NON-NLS-1$
}
if ((flags & IModelDelta.STATE) > 0) {
buf.append("STATE | "); //$NON-NLS-1$
}
if ((flags & IModelDelta.INSTALL) > 0) {
buf.append("INSTALL | "); //$NON-NLS-1$
}
if ((flags & IModelDelta.UNINSTALL) > 0) {
buf.append("UNINSTALL | "); //$NON-NLS-1$
}
}
buf.append('\n');
buf.append("\t\tIndex: "); //$NON-NLS-1$
buf.append(delta.fIndex);
buf.append(" Child Count: "); //$NON-NLS-1$
buf.append(delta.fChildCount);
buf.append('\n');
IModelDelta[] nodes = delta.getChildDeltas();
for (int i = 0; i < nodes.length; i++) {
appendDetail(buf, (VMDelta)nodes[i]);
}
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta#getChildCount()
*/
@Override
public int getChildCount() {
return fChildCount;
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta#accept(org.eclipse.debug.internal.ui.viewers.provisional.IModelDeltaVisitor)
*/
@Override
public void accept(IModelDeltaVisitor visitor) {
doAccept(visitor, 0);
}
@Override
protected void doAccept(IModelDeltaVisitor visitor, int depth) {
if (visitor.visit(this, depth)) {
ModelDelta[] childDeltas = getChildDeltas();
for (int i = 0; i < childDeltas.length; i++) {
((VMDelta)childDeltas[i]).doAccept(visitor, depth+1);
}
}
}
}

View file

@ -11,23 +11,37 @@
package org.eclipse.dd.dsf.ui.viewmodel;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
import org.eclipse.jface.viewers.TreePath;
/**
* Helper class implementation of an update object to use with IElementContentProvider.
* @see IElementContentProvider
* Helper class implementation of the {@link IHasChildrenUpdate} update object.
*
* @see VMViewerUpdate
*/
@SuppressWarnings("restriction")
public class VMHasElementsUpdate extends VMViewerUpdate implements IHasChildrenUpdate {
public class VMHasChildrenUpdate extends VMViewerUpdate implements IHasChildrenUpdate {
final private DataRequestMonitor<Boolean> fHasElemsRequestMonitor;
public VMHasElementsUpdate(IHasChildrenUpdate clientUpdate, DataRequestMonitor<Boolean> rm) {
public VMHasChildrenUpdate(IViewerUpdate clientUpdate, DataRequestMonitor<Boolean> rm) {
super(clientUpdate, rm);
fHasElemsRequestMonitor = rm;
}
public VMHasChildrenUpdate(IModelDelta delta, IPresentationContext presentationContext, DataRequestMonitor<Boolean> rm) {
super(delta, presentationContext, rm);
fHasElemsRequestMonitor = rm;
}
public VMHasChildrenUpdate(TreePath elementPath, Object viewerInput, IPresentationContext presentationContext, DataRequestMonitor<Boolean> rm) {
super(elementPath, viewerInput, presentationContext, rm);
fHasElemsRequestMonitor = rm;
}
public void setHasChilren(boolean hasChildren) {
fHasElemsRequestMonitor.setData(hasChildren);
}

View file

@ -1,107 +0,0 @@
/*******************************************************************************
* Copyright (c) 2006 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel;
import java.util.Map;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
/**
* Default implementation of a root layout node. This class may be sub-classed
* to implement model-specific event handling.
*/
@SuppressWarnings("restriction")
public class VMRootLayoutNode extends AbstractVMLayoutNode implements IVMRootLayoutNode {
public VMRootLayoutNode(AbstractVMProvider provider) {
super(provider);
}
/**
* This implementation only fulfills the requirements of the super-interface.
* There is no use case for a root node implementing this method, but its
* easier to just implement it for sake of uniformity of model.
*/
public void updateElements(IChildrenUpdate update) {
// Ignore startIdx, endIdx, since there's only one element to be had.
update.setChild(getVMProvider().getRootElement(), 0);
update.done();
}
/**
* This implementation only fulfills the requirements of the super-interface.
* There is no use case for a root node implementing this method, but its
* easier to just impelemnt it for sake of uniformity of model.
*/
public void updateElementCount(IChildrenCountUpdate update) {
update.setChildCount(1);
update.done();
}
/**
* This implementation only fulfills the requirements of the super-interface.
* There is no use case for a root node implementing this method, but its
* easier to just implement it for sake of uniformity of model.
*/
public void updateHasElements(IHasChildrenUpdate[] updates) {
for (IHasChildrenUpdate update : updates) {
update.setHasChilren(true);
update.done();
}
}
/**
* This implementation only fulfills the requirements of the super-interface.
* There is no use case for a root node implementing this method, but its
* easier to just implement it for sake of uniformity of model.
*/
public void updateLabel(@SuppressWarnings("unused")
IVMContext vmc, ILabelUpdate update) {
update.done();
}
/**
* Default implementation creates a delta assuming that the root layout node
* is the input object into the view.
*/
public void createDelta(Object event, final DataRequestMonitor<IModelDelta> rm) {
final Map<IVMLayoutNode,Integer> childNodeDeltas = getChildNodesWithDeltaFlags(event);
assert childNodeDeltas.size() != 0 : "Caller should make sure that there are deltas for given event."; //$NON-NLS-1$
// Always create the rootDelta, no matter what delta flags the child nodes have.
final VMDelta rootDelta = new VMDelta(getVMProvider().getRootElement(), IModelDelta.NO_CHANGE);
callChildNodesToBuildDelta(
childNodeDeltas, rootDelta, event,
new RequestMonitor(getExecutor(), rm) {
@Override
protected void handleCompleted() {
if (!isDisposed()) super.handleCompleted();
}
@Override
public void handleOK() {
rm.setData(rootDelta);
rm.done();
}
});
}
public Object getRootObject() {
return getVMProvider().getRootElement();
}
}

View file

@ -10,41 +10,161 @@
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.ui.DsfUIPlugin;
import org.eclipse.debug.core.IRequest;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
import org.eclipse.jface.viewers.TreePath;
/**
* Helper class implementation of an update object to use with IElementContentProvider.
* @see IElementContentProvider
* Helper class implementation of the update objects used with
* {@link IElementContentProvider}, {@link IElementLabelProvider},
* and {@link IElementMementoProvider}. The viewer update can be constructed
* using a higher level update object or a set of parameters to fulfill the
* <code>IViewerUpdate</code> interface.
*/
@SuppressWarnings("restriction")
public class VMViewerUpdate implements IViewerUpdate {
final protected RequestMonitor fRequestMonitor;
final protected IViewerUpdate fClientUpdate;
/**
* The request monitor to be called when this update is completed.
*/
final private RequestMonitor fRequestMonitor;
/**
* A higher-level update that this update is based on. If specified, the given
* update is used to delegate calls to {@link #cancel()} and {@link #isCanceled()}.
*/
final private IViewerUpdate fClientUpdate;
/**
* The flag indicating whether this update was cancelled. This flag is not used
* if the {@link #fClientUpdate} is initialized.
*/
final private AtomicBoolean fCanceled;
/**
* The viewer input object for this update.
*/
final private Object fViewerInput;
/**
* The element object of this update.
*/
final private Object fElement;
/**
* The element path of this update.
*/
final private TreePath fElementPath;
/**
* The presentation context of this update.
*/
final private IPresentationContext fPresentationContext;
/**
* Creates a viewer update based on a higher-level update. The update element
* information as well as cancel requests are delegated to the given client
* update.
* <p/>
* Note: this update will not automatically call the client update's
* {@link IRequest#done()} method. The user of this update should supply
* a request monitor which properly completes the client update.
*
* @param clientUpdate Client update that this update is based on.
* @param requestMonitor Call-back invoked when this update completes.
*/
public VMViewerUpdate(IViewerUpdate clientUpdate, RequestMonitor requestMonitor) {
fViewerInput = clientUpdate.getViewerInput();
fElement = clientUpdate.getElement();
fElementPath = clientUpdate.getElementPath();
fPresentationContext = clientUpdate.getPresentationContext();
fRequestMonitor = requestMonitor;
fClientUpdate = clientUpdate;
fCanceled = null;
}
public Object getViewerInput() { return fClientUpdate.getViewerInput(); }
public Object getElement() { return fClientUpdate.getElement(); }
public TreePath getElementPath() { return fClientUpdate.getElementPath(); }
public IPresentationContext getPresentationContext() { return fClientUpdate.getPresentationContext(); }
/**
* Request monitor which uses a model delta to calculate the element information.
* This update is useful when calculating a model delta for a given view model node.
*
* @param delta Model delta of a parent element.
* @param presentationContext Presentation context for this update.
* @param requestMonitor Call-back invoked when this update completes.
*/
public VMViewerUpdate(IModelDelta delta, IPresentationContext presentationContext, RequestMonitor requestMonitor) {
List<Object> elementList = new LinkedList<Object>();
IModelDelta listDelta = delta;
elementList.add(0, listDelta.getElement());
while (listDelta.getParentDelta() != null) {
listDelta = listDelta.getParentDelta();
elementList.add(0, listDelta.getElement());
}
fViewerInput = elementList.get(0);
fElement = elementList.get(elementList.size() - 1);
elementList.remove(0);
fElementPath = new TreePath(elementList.toArray());
fPresentationContext = presentationContext;
fRequestMonitor = requestMonitor;
fClientUpdate = null;
fCanceled = new AtomicBoolean(false);
}
/**
* Creates a viewer update with the given parameters.
*
* @param elementPath The path to the element for which the update is generated.
* @param viewerInput Input into the viewer of the update.
* @param presentationContext Presentation context for this update.
* @param requestMonitor Call-back invoked when this update completes.
*/
public VMViewerUpdate(TreePath elementPath, Object viewerInput, IPresentationContext presentationContext, RequestMonitor requestMonitor) {
fViewerInput = viewerInput;
fElement = elementPath.getSegmentCount() != 0 ? elementPath.getLastSegment() : viewerInput;
fElementPath = elementPath;
fPresentationContext = presentationContext;
fRequestMonitor = requestMonitor;
fClientUpdate = null;
fCanceled = new AtomicBoolean(false);
}
protected RequestMonitor getRequestMonitor() {
return fRequestMonitor;
}
public Object getViewerInput() { return fViewerInput; }
public Object getElement() { return fElement; }
public TreePath getElementPath() { return fElementPath; }
public IPresentationContext getPresentationContext() { return fPresentationContext; }
public IStatus getStatus() { return fRequestMonitor.getStatus(); }
public void setStatus(IStatus status) { fRequestMonitor.setStatus(status); }
public boolean isCanceled() { return fClientUpdate.isCanceled(); }
public boolean isCanceled() {
if (fClientUpdate != null) {
return fClientUpdate.isCanceled();
} else {
return fCanceled.get();
}
}
public void cancel() {
fClientUpdate.cancel();
if (fClientUpdate != null) {
fClientUpdate.cancel();
} else {
fCanceled.set(true);
}
}
public void done() {

View file

@ -1,481 +0,0 @@
/*******************************************************************************
* Copyright (c) 2006 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel.dm;
import java.util.List;
import java.util.Map;
import java.util.concurrent.RejectedExecutionException;
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.DsfRunnable;
import org.eclipse.dd.dsf.concurrent.Immutable;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.datamodel.DMContexts;
import org.eclipse.dd.dsf.datamodel.IDMContext;
import org.eclipse.dd.dsf.datamodel.IDMEvent;
import org.eclipse.dd.dsf.service.DsfServicesTracker;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.service.IDsfService;
import org.eclipse.dd.dsf.ui.DsfUIPlugin;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.IVMContext;
import org.eclipse.dd.dsf.ui.viewmodel.IVMLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
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.IViewerUpdate;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.jface.viewers.TreePath;
/**
* View model layout node based on a single Data Model Context type.
* The assumption in this implementation is that elements of this node have
* a single IDMContext associated with them, and all of these contexts
* are of the same class type.
*/
@SuppressWarnings("restriction")
abstract public class AbstractDMVMLayoutNode extends AbstractVMLayoutNode
implements IElementLabelProvider
{
/**
* IVMContext implementation used for this schema node.
*/
@Immutable
public class DMVMContext extends AbstractVMContext {
private final IDMContext fDmc;
public DMVMContext(IDMContext dmc) {
super(getVMProvider().getVMAdapter(), AbstractDMVMLayoutNode.this);
fDmc = dmc;
}
public IDMContext getDMC() { return fDmc; }
/**
* The IAdaptable implementation. If the adapter is the DM context,
* return the context, otherwise delegate to IDMContext.getAdapter().
*/
@Override
@SuppressWarnings("unchecked")
public Object getAdapter(Class adapter) {
Object superAdapter = super.getAdapter(adapter);
if (superAdapter != null) {
return superAdapter;
} else if (adapter.isInstance(fDmc)) {
return fDmc;
} else {
return fDmc.getAdapter(adapter);
}
}
@Override
public boolean equals(Object other) {
if (!(other instanceof AbstractDMVMLayoutNode.DMVMContext)) return false;
DMVMContext otherVmc = (DMVMContext)other;
return AbstractDMVMLayoutNode.this.equals(otherVmc.getLayoutNode()) &&
fDmc.equals(otherVmc.fDmc);
}
@Override
public int hashCode() {
return AbstractDMVMLayoutNode.this.hashCode() + fDmc.hashCode();
}
@Override
public String toString() {
return fDmc.toString();
}
}
private DsfSession fSession;
private DsfServicesTracker fServicesTracker;
/**
* Concrete class type that the elements of this schema node are based on.
* Even though the data model type is a parameter the DMContextVMLayoutNode,
* this type is erased at runtime, so a concrete class typs of the DMC
* is needed for instanceof chacks.
*/
private Class<? extends IDMContext> fDMCClassType;
/**
* Constructor initializes instance data, except for the child nodes.
* Child nodes must be initialized by calling setChildNodes()
* @param session
* @param dmcClassType
* @see #setChildNodes(IVMLayoutNode[])
*/
public AbstractDMVMLayoutNode(AbstractVMProvider provider, DsfSession session, Class<? extends IDMContext> dmcClassType) {
super(provider);
fSession = session;
fServicesTracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), session.getId());
fDMCClassType = dmcClassType;
}
@Override
public void dispose() {
fServicesTracker.dispose();
super.dispose();
}
protected DsfSession getSession() {
return fSession;
}
protected DsfServicesTracker getServicesTracker() {
return fServicesTracker;
}
@Override
protected boolean checkUpdate(IViewerUpdate update) {
if (!super.checkUpdate(update)) return false;
// Extract the VMC from the update (whatever the update sub-class.
Object element = update.getElement();
if (element instanceof AbstractDMVMLayoutNode.DMVMContext) {
// If update element is a DMC, check if session is still alive.
IDMContext dmc = ((DMVMContext)element).getDMC();
if (dmc.getSessionId() != getSession().getId() || !DsfSession.isSessionActive(dmc.getSessionId())) {
handleFailedUpdate(update);
return false;
}
}
return true;
}
/**
* Convenience method that checks whether the given dmc context is null. If it is null, an
* appropriate error message is set in the update.
* @param dmc Data Model Context (DMC) to check.
* @param update Update to handle in case the DMC is null.
* @return true if the DMC is NOT null, indicating that it's OK to proceed.
*/
protected boolean checkDmc(IDMContext dmc, IViewerUpdate update) {
if (dmc == null) {
update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.INVALID_STATE,
"No valid context found.", null)); //$NON-NLS-1$
handleFailedUpdate(update);
return false;
}
return true;
}
/**
* A convenience method that checks whether a given service exists. If the service does not
* exist, the update is filled in with the appropriate error message.
* @param serviceClass Service class to find.
* @param filter Service filter to use in addition to the service class name.
* @param update Update object to fill in.
* @return true if service IS found, indicating that it's OK to proceed.
*/
protected boolean checkService(Class<? extends IDsfService> serviceClass, String filter, IViewerUpdate update) {
if (getServicesTracker().getService(serviceClass, filter) == null) {
update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.INVALID_STATE,
"Service " + serviceClass.getName() + " not available.", null)); //$NON-NLS-1$ //$NON-NLS-2$
handleFailedUpdate(update);
return false;
}
return true;
}
public void updateHasElements(final IHasChildrenUpdate[] updates) {
try {
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
updateHasElementsInSessionThread(updates);
}});
} catch (RejectedExecutionException e) {
for (IHasChildrenUpdate update : updates) {
handleFailedUpdate(update);
}
}
}
protected void updateHasElementsInSessionThread(IHasChildrenUpdate[] updates) {
for (final IHasChildrenUpdate update : updates) {
if (!checkUpdate(update)) continue;
updateElementsInSessionThread(
new ElementsUpdate(
new DataRequestMonitor<List<Object>>(getSession().getExecutor(), null) {
@Override
protected void handleCompleted() {
if (!checkUpdate(update)) return;
if (getStatus().isOK()) {
update.setHasChilren(getData().size() != 0);
} else {
update.setHasChilren(false);
}
update.done();
}
},
update.getElementPath())
);
}
}
public void updateElementCount(final IChildrenCountUpdate update) {
if (!checkUpdate(update)) return;
try {
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
// After every dispatch, must check if update still valid.
if (!checkUpdate(update)) return;
updateElementCountInSessionThread(update);
}});
} catch (RejectedExecutionException e) {
handleFailedUpdate(update);
}
}
protected void updateElementCountInSessionThread(final IChildrenCountUpdate update) {
updateElementsInSessionThread(
new ElementsUpdate(
new DataRequestMonitor<List<Object>>(getSession().getExecutor(), null) {
@Override
protected void handleCompleted() {
if (!checkUpdate(update)) return;
if (getStatus().isOK()) {
update.setChildCount(getData().size());
} else {
update.setChildCount(0);
}
update.done();
}
},
update.getElementPath())
);
}
public void updateElements(final IChildrenUpdate update) {
if (!checkUpdate(update)) return;
try {
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
// After every dispatch, must check if update still valid.
if (!checkUpdate(update)) return;
updateElementsInSessionThread(update);
}});
} catch (RejectedExecutionException e) {
handleFailedUpdate(update);
}
}
abstract protected void updateElementsInSessionThread(IChildrenUpdate update);
public void update(final ILabelUpdate[] updates) {
try {
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
// After every dispatch, must check if update still valid.
updateLabelInSessionThread(updates);
}});
} catch (RejectedExecutionException e) {
for (ILabelUpdate update : updates) {
handleFailedUpdate(update);
}
}
}
abstract protected void updateLabelInSessionThread(ILabelUpdate[] updates);
@Override
public int getDeltaFlags(Object e) {
int flags = 0;
if (e instanceof IDMEvent) {
flags = getNodeDeltaFlagsForDMEvent((IDMEvent<?>)e);
}
return flags | super.getDeltaFlags(e);
}
protected int getNodeDeltaFlagsForDMEvent(@SuppressWarnings("unused") IDMEvent<?> e) {
return IModelDelta.NO_CHANGE;
}
@Override
public void buildDelta(final Object e, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor requestMonitor) {
if (e instanceof IDMEvent) {
// Call handler for Data Model events. But check to make sure
// that session is still active.
if (DsfSession.isSessionActive(getSession().getId())) {
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
buildDeltaForDMEvent((IDMEvent<?>)e, parentDelta, nodeOffset, requestMonitor);
}
});
} else {
if (isDisposed()) return;
requestMonitor.done();
}
} else {
super.buildDelta(e, parentDelta, nodeOffset, requestMonitor);
}
}
/**
* Handle all Data Model events. If a DM context in the event contains
* a context of the type tracked by this node, then this base implementation
* will only create a delta node for this one element.
*/
protected void buildDeltaForDMEvent(final IDMEvent<?> event, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor requestMonitor) {
IDMContext dmc = DMContexts.getAncestorOfType(event.getDMContext(), fDMCClassType);
if (dmc != null) {
// Create the VM context based on the DM context from the DM event.
final IVMContext vmc = createVMContext(DMContexts.getAncestorOfType(event.getDMContext(), fDMCClassType));
final Map<IVMLayoutNode,Integer> childNodeDeltas = getChildNodesWithDeltaFlags(event);
if (childNodeDeltas.size() == 0) {
// There are no child nodes with deltas, just return to parent.
requestMonitor.done();
return;
}
// Check if any of the child nodes are will generate IModelDelta.SELECT or
// IModelDelta.EXPAND flags. If so, we must calcuate the index for this
// VMC.
boolean calculateIndex = false;
for (int childDelta : childNodeDeltas.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.
updateElements(new ElementsUpdate(
new DataRequestMonitor<List<Object>>(getExecutor(), null) {
@Override
protected void handleCompleted() {
if (isDisposed()) return;
// 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 (!getStatus().isOK() || getData().isEmpty()) {
requestMonitor.done();
return;
}
// Find the index.
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.
requestMonitor.done();
return;
}
VMDelta delta = parentDelta.addNode(vmc, nodeOffset + i, IModelDelta.NO_CHANGE);
callChildNodesToBuildDelta(childNodeDeltas, delta, event, requestMonitor);
}
},
parentDelta));
} else {
VMDelta delta = parentDelta.addNode(vmc, IModelDelta.NO_CHANGE);
callChildNodesToBuildDelta(childNodeDeltas, delta, event, requestMonitor);
}
} else {
// The DMC for this node was not found in the event. Call the
// super-class to resort to the default behavior which may add a
// delta for every element in this node.
super.buildDelta(event, parentDelta, nodeOffset, requestMonitor);
}
}
/**
* Utility method that takes an array of DMC object and creates a
* corresponding array of IVMContext elements base on that.
* @param parent The parent for generated IVMContext elements.
* @param dmcs Array of DMC objects to build return array on.
* @return Array of IVMContext objects.
*/
protected IVMContext[] dmcs2vmcs(IDMContext[] dmcs) {
IVMContext[] vmContexts = new IVMContext[dmcs.length];
for (int i = 0; i < dmcs.length; i++) {
vmContexts[i] = new DMVMContext(dmcs[i]);
}
return vmContexts;
}
protected void fillUpdateWithVMCs(IChildrenUpdate update, IDMContext[] dmcs) {
int startIdx = update.getOffset() != -1 ? update.getOffset() : 0;
int endIdx = update.getLength() != -1 ? startIdx + update.getLength() : dmcs.length;
// Ted: added bounds limitation of dmcs.length
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=202109
for (int i = startIdx; i < endIdx && i < dmcs.length; i++) {
update.setChild(createVMContext(dmcs[i]), i);
}
}
protected IVMContext createVMContext(IDMContext dmc) {
return new DMVMContext(dmc);
}
/**
* Searches for a DMC of given type in the tree patch contained in given
* VMC. Only a DMC in the same session will be returned.
* @param <V> Type of the DMC that will be returned.
* @param vmc VMC element to search.
* @param dmcType Class object for matching the type.
* @return DMC, or null if not found.
*/
@SuppressWarnings("unchecked")
public <T extends IDMContext> T findDmcInPath(TreePath path, Class<T> dmcType) {
T retVal = null;
for (int i = path.getSegmentCount() - 1; i >= 0; i--) {
if (path.getSegment(i) instanceof AbstractDMVMLayoutNode.DMVMContext) {
IDMContext dmc = ((DMVMContext)path.getSegment(i)).getDMC();
if ( dmc.getSessionId().equals(getSession().getId()) ) {
retVal = DMContexts.getAncestorOfType(dmc, dmcType);
if (retVal != null) break;
}
}
}
// Search the root object of the layout hierarchy.
if (retVal == null) {
Object inputObject = getVMProvider().getRootElement();
if (inputObject instanceof ITreeSelection) {
ITreeSelection inputSelection = (ITreeSelection)inputObject;
if (inputSelection.getPaths().length == 1) {
retVal = findDmcInPath(inputSelection.getPaths()[0], dmcType);
}
} else if (inputObject instanceof IStructuredSelection) {
Object rootElement = ((IStructuredSelection)inputObject).getFirstElement();
if (rootElement instanceof AbstractDMVMLayoutNode.DMVMContext) {
retVal = DMContexts.getAncestorOfType(((DMVMContext)rootElement).getDMC(), dmcType);
}
} else if (inputObject instanceof AbstractDMVMLayoutNode.DMVMContext) {
retVal = DMContexts.getAncestorOfType(((DMVMContext)inputObject).getDMC(), dmcType);
}
}
return retVal;
}
}

View file

@ -0,0 +1,334 @@
/*******************************************************************************
* Copyright (c) 2006 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel.dm;
import java.util.concurrent.RejectedExecutionException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.dd.dsf.concurrent.DsfRunnable;
import org.eclipse.dd.dsf.concurrent.Immutable;
import org.eclipse.dd.dsf.datamodel.DMContexts;
import org.eclipse.dd.dsf.datamodel.IDMContext;
import org.eclipse.dd.dsf.datamodel.IDMEvent;
import org.eclipse.dd.dsf.service.DsfServicesTracker;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.service.IDsfService;
import org.eclipse.dd.dsf.ui.DsfUIPlugin;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMContext;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.IVMContext;
import org.eclipse.dd.dsf.ui.viewmodel.IVMNode;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.jface.viewers.TreePath;
/**
* View model node based on a single Data Model Context type.
* The assumption in this implementation is that elements of this node have
* a single IDMContext associated with them, and all of these contexts
* are of the same class type.
*/
@SuppressWarnings("restriction")
abstract public class AbstractDMVMNode extends AbstractVMNode implements IVMNode {
/**
* IVMContext implementation used for this schema node.
*/
@Immutable
protected class DMVMContext extends AbstractVMContext implements IDMVMContext {
private final IDMContext fDmc;
public DMVMContext(IDMContext dmc) {
super(getVMProvider().getVMAdapter(), AbstractDMVMNode.this);
fDmc = dmc;
}
public IDMContext getDMContext() { return fDmc; }
/**
* The IAdaptable implementation. If the adapter is the DM context,
* return the context, otherwise delegate to IDMContext.getAdapter().
*/
@Override
@SuppressWarnings("unchecked")
public Object getAdapter(Class adapter) {
Object superAdapter = super.getAdapter(adapter);
if (superAdapter != null) {
return superAdapter;
} else if (adapter.isInstance(fDmc)) {
return fDmc;
} else {
return fDmc.getAdapter(adapter);
}
}
@Override
public boolean equals(Object other) {
if (!(other instanceof AbstractDMVMNode.DMVMContext)) return false;
DMVMContext otherVmc = (DMVMContext)other;
return AbstractDMVMNode.this.equals(otherVmc.getVMNode()) &&
fDmc.equals(otherVmc.fDmc);
}
@Override
public int hashCode() {
return AbstractDMVMNode.this.hashCode() + fDmc.hashCode();
}
@Override
public String toString() {
return fDmc.toString();
}
}
private DsfSession fSession;
private DsfServicesTracker fServicesTracker;
/**
* Concrete class type that the elements of this schema node are based on.
* Even though the data model type is a parameter the DMContextVMLayoutNode,
* this type is erased at runtime, so a concrete class typs of the DMC
* is needed for instanceof chacks.
*/
private Class<? extends IDMContext> fDMCClassType;
/**
* Constructor initializes instance data, except for the child nodes.
* Child nodes must be initialized by calling setChildNodes()
* @param session
* @param dmcClassType
* @see #setChildNodes(IVMNode[])
*/
public AbstractDMVMNode(AbstractDMVMProvider provider, DsfSession session, Class<? extends IDMContext> dmcClassType) {
super(provider);
fSession = session;
fServicesTracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), session.getId());
fDMCClassType = dmcClassType;
}
@Override
public void dispose() {
fServicesTracker.dispose();
super.dispose();
}
@Override
public IVMContext getContextFromEvent(Object event) {
if (event instanceof IDMEvent<?>) {
IDMEvent<?> dmEvent = (IDMEvent<?>)event;
IDMContext dmc = DMContexts.getAncestorOfType(dmEvent.getDMContext(), fDMCClassType);
if (dmc != null) {
return createVMContext(dmc);
}
}
return null;
}
protected AbstractDMVMProvider getDMVMProvider() {
return (AbstractDMVMProvider)getVMProvider();
}
protected DsfSession getSession() {
return fSession;
}
protected DsfServicesTracker getServicesTracker() {
return fServicesTracker;
}
@Override
protected boolean checkUpdate(IViewerUpdate update) {
if (!super.checkUpdate(update)) return false;
// Extract the VMC from the update (whatever the update sub-class.
Object element = update.getElement();
if (element instanceof IDMVMContext) {
// If update element is a DMC, check if session is still alive.
IDMContext dmc = ((IDMVMContext)element).getDMContext();
if (dmc.getSessionId() != getSession().getId() || !DsfSession.isSessionActive(dmc.getSessionId())) {
handleFailedUpdate(update);
return false;
}
}
return true;
}
/**
* Convenience method that checks whether the given dmc context is null. If it is null, an
* appropriate error message is set in the update.
* @param dmc Data Model Context (DMC) to check.
* @param update Update to handle in case the DMC is null.
* @return true if the DMC is NOT null, indicating that it's OK to proceed.
*/
protected boolean checkDmc(IDMContext dmc, IViewerUpdate update) {
if (dmc == null) {
update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.INVALID_STATE,
"No valid context found.", null)); //$NON-NLS-1$
handleFailedUpdate(update);
return false;
}
return true;
}
/**
* A convenience method that checks whether a given service exists. If the service does not
* exist, the update is filled in with the appropriate error message.
* @param serviceClass Service class to find.
* @param filter Service filter to use in addition to the service class name.
* @param update Update object to fill in.
* @return true if service IS found, indicating that it's OK to proceed.
*/
protected boolean checkService(Class<? extends IDsfService> serviceClass, String filter, IViewerUpdate update) {
if (getServicesTracker().getService(serviceClass, filter) == null) {
update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.INVALID_STATE,
"Service " + serviceClass.getName() + " not available.", null)); //$NON-NLS-1$ //$NON-NLS-2$
handleFailedUpdate(update);
return false;
}
return true;
}
public void update(final IHasChildrenUpdate[] updates) {
try {
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
for (IHasChildrenUpdate update : updates) {
if (!checkUpdate(update)) continue;
updateHasElementsInSessionThread(update);
}
}});
} catch (RejectedExecutionException e) {
for (IViewerUpdate update : updates) {
handleFailedUpdate(update);
}
}
}
protected void updateHasElementsInSessionThread(final IHasChildrenUpdate update) {
update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.NOT_SUPPORTED, "Not implemented, clients should call to update all children instead.", null)); //$NON-NLS-1$
update.done();
}
public void update(final IChildrenCountUpdate[] updates) {
try {
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
for (IChildrenCountUpdate update : updates) {
if (!checkUpdate(update)) continue;
updateElementCountInSessionThread(update);
}
}});
} catch (RejectedExecutionException e) {
for (IViewerUpdate update : updates) {
handleFailedUpdate(update);
}
}
}
protected void updateElementCountInSessionThread(final IChildrenCountUpdate update) {
update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.NOT_SUPPORTED, "Not implemented, clients should call to update all children instead.", null)); //$NON-NLS-1$
update.done();
}
public void update(final IChildrenUpdate[] updates) {
try {
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
// After every dispatch, must check if update still valid.
for (IChildrenUpdate update : updates) {
if (!checkUpdate(update)) continue;
updateElementsInSessionThread(update);
}
}});
} catch (RejectedExecutionException e) {
for (IViewerUpdate update : updates) {
handleFailedUpdate(update);
}
}
}
abstract protected void updateElementsInSessionThread(IChildrenUpdate update);
/**
* Utility method that takes an array of DMC object and creates a
* corresponding array of IVMContext elements base on that.
* @param parent The parent for generated IVMContext elements.
* @param dmcs Array of DMC objects to build return array on.
* @return Array of IVMContext objects.
*/
protected IVMContext[] dmcs2vmcs(IDMContext[] dmcs) {
IVMContext[] vmContexts = new IVMContext[dmcs.length];
for (int i = 0; i < dmcs.length; i++) {
vmContexts[i] = createVMContext(dmcs[i]);
}
return vmContexts;
}
protected void fillUpdateWithVMCs(IChildrenUpdate update, IDMContext[] dmcs) {
int startIdx = update.getOffset() != -1 ? update.getOffset() : 0;
int endIdx = update.getLength() != -1 ? startIdx + update.getLength() : dmcs.length;
// Ted: added bounds limitation of dmcs.length
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=202109
for (int i = startIdx; i < endIdx && i < dmcs.length; i++) {
update.setChild(createVMContext(dmcs[i]), i);
}
}
protected IDMVMContext createVMContext(IDMContext dmc) {
return new DMVMContext(dmc);
}
/**
* Searches for a DMC of given type in the tree patch contained in given
* VMC. Only a DMC in the same session will be returned.
* @param <V> Type of the DMC that will be returned.
* @param vmc VMC element to search.
* @param dmcType Class object for matching the type.
* @return DMC, or null if not found.
*/
public <T extends IDMContext> T findDmcInPath(Object inputObject, TreePath path, Class<T> dmcType) {
T retVal = null;
for (int i = path.getSegmentCount() - 1; i >= 0; i--) {
if (path.getSegment(i) instanceof IDMVMContext) {
IDMContext dmc = ((IDMVMContext)path.getSegment(i)).getDMContext();
if ( dmc.getSessionId().equals(getSession().getId()) ) {
retVal = DMContexts.getAncestorOfType(dmc, dmcType);
if (retVal != null) break;
}
}
}
// Search the root object of the layout hierarchy.
if (retVal == null) {
if (inputObject instanceof ITreeSelection) {
ITreeSelection inputSelection = (ITreeSelection)inputObject;
if (inputSelection.getPaths().length == 1) {
retVal = findDmcInPath(null, inputSelection.getPaths()[0], dmcType);
}
} else if (inputObject instanceof IStructuredSelection) {
Object rootElement = ((IStructuredSelection)inputObject).getFirstElement();
if (rootElement instanceof IDMVMContext) {
retVal = DMContexts.getAncestorOfType(((IDMVMContext)rootElement).getDMContext(), dmcType);
}
} else if (inputObject instanceof IDMVMContext) {
retVal = DMContexts.getAncestorOfType(((IDMVMContext)inputObject).getDMContext(), dmcType);
}
}
return retVal;
}
}

View file

@ -17,8 +17,8 @@ import org.eclipse.dd.dsf.datamodel.IDMEvent;
import org.eclipse.dd.dsf.service.DsfServiceEventHandler;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.IVMLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.IVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.update.AbstractCachingVMProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousContentAdapter;
@ -27,7 +27,7 @@ import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousLabelAdapt
/**
* View model provider implements the asynchronous view model functionality for
* a single view. This provider is just a holder which further delegates the
* model provider functionality to the view model layout nodes that need
* model provider functionality to the view model nodes that need
* to be configured with each provider.
* <p>
* The view model provider, often does not provide the model for the entire
@ -37,11 +37,11 @@ import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousLabelAdapt
* @see IAsynchronousContentAdapter
* @see IAsynchronousLabelAdapter
* @see IModelProxy
* @see IVMLayoutNode
* @see IVMNode
*/
@ConfinedToDsfExecutor("fSession#getExecutor")
@SuppressWarnings("restriction")
abstract public class AbstractDMVMProvider extends AbstractVMProvider
abstract public class AbstractDMVMProvider extends AbstractCachingVMProvider
{
private final DsfSession fSession;
@ -93,10 +93,8 @@ abstract public class AbstractDMVMProvider extends AbstractVMProvider
super.dispose();
}
protected DsfSession getSession() { return fSession; }
public DsfSession getSession() { return fSession; }
/**
* Handle "data model changed" event by generating a delta object for each
* view and passing it to the corresponding view model provider. The view
@ -106,8 +104,21 @@ abstract public class AbstractDMVMProvider extends AbstractVMProvider
*/
@DsfServiceEventHandler
public void eventDispatched(final IDMEvent<?> event) {
// We're in session's executor thread (session in which the event originated).
// Re-dispach to the view model provider executor thread and then call the
// model proxy strategy to handle the event.
if (isDisposed()) return;
handleEvent(event);
try {
getExecutor().execute(new Runnable() {
public void run() {
if (isDisposed()) return;
handleEvent(event);
}
});
} catch (RejectedExecutionException e) {
// Ignore. This exception could be thrown if the provider is being
// shut down.
}
}
}

View file

@ -1,74 +0,0 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Ted R Williams (Wind River Systems, Inc.) - initial implementation
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel.dm;
import org.eclipse.dd.dsf.datamodel.IDMEvent;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter;
import org.eclipse.dd.dsf.ui.viewmodel.update.VMCacheManager;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.dd.dsf.service.DsfServiceEventHandler;
@SuppressWarnings("restriction")
public abstract class AbstractDMVMProviderWithCache extends AbstractDMVMProvider
implements VMCacheManager.CacheListener
{
@DsfServiceEventHandler
@Override
public void eventDispatched(IDMEvent<?> event) {
VMCacheManager.getVMCacheManager().getCache(getPresentationContext()).handleEvent(event);
super.eventDispatched(event);
}
@SuppressWarnings("restriction")
public void cacheFlushed(Object context) {
if(getPresentationContext().equals(context))
getModelProxy().fireModelChanged(new ModelDelta(getRootElement(),IModelDelta.CONTENT));
}
public AbstractDMVMProviderWithCache(AbstractVMAdapter adapter, IPresentationContext presentationContext, DsfSession session) {
super(adapter, presentationContext, session);
VMCacheManager.getVMCacheManager().addCacheListener(getPresentationContext(), this);
}
public void flush() {
VMCacheManager.getVMCacheManager().flush(getPresentationContext());
}
@Override
public void update(IHasChildrenUpdate[] updates) {
super.update(VMCacheManager.getVMCacheManager().getCache(getPresentationContext()).update(updates));
}
@Override
public void update(IChildrenCountUpdate[] updates) {
super.update(VMCacheManager.getVMCacheManager().getCache(getPresentationContext()).update(updates));
}
@Override
public void update(final IChildrenUpdate[] updates) {
super.update(VMCacheManager.getVMCacheManager().getCache(getPresentationContext()).update(updates));
}
@Override
public void dispose()
{
VMCacheManager.getVMCacheManager().removeCacheListener(getPresentationContext(), this);
super.dispose();
}
}

View file

@ -13,9 +13,9 @@ package org.eclipse.dd.dsf.ui.viewmodel.dm;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.dd.dsf.datamodel.IDMContext;
import org.eclipse.dd.dsf.datamodel.CompositeDMContext;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode.DMVMContext;
import org.eclipse.dd.dsf.datamodel.IDMContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
import org.eclipse.jface.viewers.TreePath;
/**
@ -23,6 +23,7 @@ import org.eclipse.jface.viewers.TreePath;
* update. This object allows the view model to pass complete data model context
* information found in the view to the services.
*/
@SuppressWarnings("restriction")
public class CompositeDMVMContext extends CompositeDMContext {
/**
@ -37,19 +38,26 @@ public class CompositeDMVMContext extends CompositeDMContext {
*/
private IDMContext[] fParents;
/**
* Creates a composite context based in a viewer update.
*/
public CompositeDMVMContext(IViewerUpdate update) {
this(update.getViewerInput(), update.getElementPath());
}
/**
* Creates a composite context based on view model
* Creates a composite context based on a viewer input and a tree path.
*/
public CompositeDMVMContext(Object viewerInputObject, TreePath treePath) {
super(EMPTY_CONTEXTS_ARRAY);
List<IDMContext> parentsList = new ArrayList<IDMContext>(treePath.getSegmentCount() + 1);
for (int i = treePath.getSegmentCount() - 1; i >=0 ; i--) {
if (treePath.getSegment(i) instanceof DMVMContext) {
parentsList.add( ((DMVMContext)treePath.getSegment(i)).getDMC() );
if (treePath.getSegment(i) instanceof IDMVMContext) {
parentsList.add( ((IDMVMContext)treePath.getSegment(i)).getDMContext() );
}
}
if (viewerInputObject instanceof DMVMContext) {
parentsList.add( ((DMVMContext)viewerInputObject).getDMC() );
if (viewerInputObject instanceof IDMVMContext) {
parentsList.add( ((IDMVMContext)viewerInputObject).getDMContext() );
}
fParents = parentsList.toArray(new IDMContext[parentsList.size()]);

View file

@ -8,12 +8,20 @@
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.expression;
package org.eclipse.dd.dsf.ui.viewmodel.dm;
import org.eclipse.dd.dsf.datamodel.IDMContext;
import org.eclipse.dd.dsf.ui.viewmodel.IVMContext;
/**
*
* Interface for a view model context based on a DSF data model context.
*/
public interface IExpressionVMContext extends IVMContext {
public interface IDMVMContext extends IVMContext {
public static Object REFRESH_EVENT = new Object();
/**
* returns the data model context that this view model context wraps.
*/
public IDMContext getDMContext();
}

View file

@ -14,10 +14,8 @@ import org.eclipse.dd.dsf.datamodel.DMContexts;
import org.eclipse.dd.dsf.datamodel.IDMContext;
import org.eclipse.dd.dsf.datamodel.IDMEvent;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.VMRootLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.IVMRootLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode.DMVMContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.RootVMNode;
/**
* This is is a standard root node which listens to the selection in Debug View.
@ -30,11 +28,10 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
* node also has to use the first element as the root object instead of the
* whole selection.
*/
@SuppressWarnings("restriction")
public class DMVMRootLayoutNode extends VMRootLayoutNode
implements IVMRootLayoutNode
public class RootDMVMNode extends RootVMNode
implements IRootVMNode
{
public DMVMRootLayoutNode(AbstractVMProvider provider) {
public RootDMVMNode(AbstractVMProvider provider) {
super(provider);
}
@ -60,39 +57,30 @@ public class DMVMRootLayoutNode extends VMRootLayoutNode
* determine whether a delta is needed.
*/
@Override
public int getDeltaFlags(Object event) {
IDMContext inputDmc = getSelectedDMC();
if (event instanceof IDMEvent && inputDmc != null) {
boolean potentialMatchFound = false;
boolean matchFound = false;
IDMContext eventDmc = ((IDMEvent<?>)event).getDMContext();
for (IDMContext eventDmcAncestor : DMContexts.toList(eventDmc)) {
IDMContext inputDmcAncestor = DMContexts.getAncestorOfType(inputDmc, eventDmcAncestor.getClass());
if (inputDmcAncestor != null) {
potentialMatchFound = true;
if (inputDmcAncestor.equals(eventDmcAncestor)) {
return super.getDeltaFlags(event);
public boolean isDeltaEvent(Object rootObject, Object event) {
if (rootObject instanceof IDMVMContext) {
IDMContext inputDmc = ((IDMVMContext)rootObject).getDMContext();
if (event instanceof IDMEvent && inputDmc != null) {
boolean potentialMatchFound = false;
boolean matchFound = false;
IDMContext eventDmc = ((IDMEvent<?>)event).getDMContext();
for (IDMContext eventDmcAncestor : DMContexts.toList(eventDmc)) {
IDMContext inputDmcAncestor = DMContexts.getAncestorOfType(inputDmc, eventDmcAncestor.getClass());
if (inputDmcAncestor != null) {
potentialMatchFound = true;
if (inputDmcAncestor.equals(eventDmcAncestor)) {
return true;
}
}
}
}
if (potentialMatchFound && !matchFound) {
return IModelDelta.NO_CHANGE;
if (potentialMatchFound && !matchFound) {
return false;
}
}
}
return super.getDeltaFlags(event);
}
private IDMContext getSelectedDMC() {
Object rootObject = getVMProvider().getRootElement();
if (rootObject instanceof DMVMContext)
{
// Correct cast: (AbstractDMVMLayoutNode<?>.DMVMContext) breaks the javac compiler
@SuppressWarnings("unchecked")
DMVMContext vmc = (DMVMContext)rootObject;
return vmc.getDMC();
}
return null;
return true;
}
}

View file

@ -5,6 +5,7 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
/**
* Context sensitive properties update request for an element.
*/
@SuppressWarnings("restriction")
public interface IPropertiesUpdate extends IViewerUpdate {
/**
* Returns the list of element properties that the provider should set.

View file

@ -31,7 +31,7 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
@SuppressWarnings("restriction")
public class LabelText extends LabelAttribute {
public static final MessageFormat DEFAULT_MESSAGE = new MessageFormat("<unknown>");
public static final MessageFormat DEFAULT_MESSAGE = new MessageFormat(MessagesForProperties.DefaultLabelMessage_label);
/**
* Message format used to generate the label text.

View file

@ -0,0 +1,17 @@
package org.eclipse.dd.dsf.ui.viewmodel.properties;
import org.eclipse.osgi.util.NLS;
class MessagesForProperties extends NLS {
private static final String BUNDLE_NAME = "org.eclipse.dd.dsf.ui.viewmodel.properties.messages"; //$NON-NLS-1$
public static String DefaultLabelMessage_label;
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, MessagesForProperties.class);
}
private MessagesForProperties() {
}
}

View file

@ -77,7 +77,7 @@ public class PropertyBasedLabelProvider
@Override
public void done() {
@SuppressWarnings("unchecked")
DataRequestMonitor<Map<String,Object>> rm = (DataRequestMonitor<Map<String,Object>>)fRequestMonitor;
DataRequestMonitor<Map<String,Object>> rm = (DataRequestMonitor<Map<String,Object>>)getRequestMonitor();
if (fProperties == null || fValues.size() >= fProperties.length) {
rm.setData(fValues);
} else {

View file

@ -0,0 +1 @@
DefaultLabelMessage_label=<unknown>

View file

@ -0,0 +1,761 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel.update;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.datamodel.IDMContext;
import org.eclipse.dd.dsf.datamodel.IDMData;
import org.eclipse.dd.dsf.datamodel.IDMService;
import org.eclipse.dd.dsf.ui.concurrent.ViewerCountingRequestMonitor;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.IVMModelProxy;
import org.eclipse.dd.dsf.ui.viewmodel.IVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.VMChildrenCountUpdate;
import org.eclipse.dd.dsf.ui.viewmodel.VMChildrenUpdate;
import org.eclipse.dd.dsf.ui.viewmodel.VMHasChildrenUpdate;
import org.eclipse.dd.dsf.ui.viewmodel.properties.IElementPropertiesProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.jface.viewers.TreePath;
/**
* Base implementation of a caching view model provider.
*/
@SuppressWarnings("restriction")
public class AbstractCachingVMProvider extends AbstractVMProvider implements ICachingVMProvider {
private static final int MAX_CACHE_SIZE = 1000;
/**
* Class representing a key to an element's data in the cache. The main
* components of this key are the viewer input and the path, they uniquely
* identify an element. The root element is used to track when a given
* root element is no longer in the cache and can therefore be disposed.
* The node is needed because different nodes have different lists of
* children for the same parent element.
*/
private static class ElementDataKey {
ElementDataKey(Object rootElement, IVMNode node, Object viewerInput, TreePath path) {
fRootElement = rootElement;
fNode = node;
fViewerInput = viewerInput;
fPath = path;
}
final Object fRootElement;
final IVMNode fNode;
final Object fViewerInput;
final TreePath fPath;
@Override
public String toString() {
return fViewerInput + "." + fPath.toString() + "(" + fNode + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ElementDataKey)) return false;
ElementDataKey key = (ElementDataKey)obj;
return
(fNode == null && key.fNode == null || (fNode != null && fNode.equals(key.fNode))) &&
(fRootElement == null && key.fRootElement == null || (fRootElement != null && fRootElement.equals(key.fRootElement))) &&
(fViewerInput == null && key.fViewerInput == null || (fViewerInput != null && fViewerInput.equals(key.fViewerInput))) &&
(fPath == null && key.fPath == null || (fPath != null && fPath.equals(key.fPath)));
}
@Override
public int hashCode() {
return
(fRootElement != null ? fRootElement.hashCode() : 0) +
(fNode != null ? fNode.hashCode() : 0) +
(fViewerInput != null ? fViewerInput.hashCode() : 0) +
(fPath != null ? fPath.hashCode() : 0);
}
}
/**
* A base calss for the entry in the cache. Since the cache maintains
* a double-linked list through all the entries, the linked list references
* are maintained in this class.
*/
private static class Entry {
final Object fKey;
Entry fNext;
Entry fPrevious;
Entry(Object key) {
fKey = key;
}
void insert(Entry nextEntry) {
fNext = nextEntry;
fPrevious = nextEntry.fPrevious;
fPrevious.fNext = this;
fNext.fPrevious = this;
}
void remove() {
fPrevious.fNext = fNext;
fNext.fPrevious = fPrevious;
}
}
/**
* Entry with cached element data.
*/
static class ElementDataEntry extends Entry {
ElementDataEntry(ElementDataKey key) {
super(key);
}
Boolean fDirty = false;
Boolean fHasChildren = null;
Integer fChildrenCount = null;
boolean fAllChildrenKnown = false;
Map<Integer,Object> fChildren = null;
Map<IDMContext,Object> fDataOrStatus = new HashMap<IDMContext,Object>(1);
Map<IDMContext,IDMData> fArchiveData = new HashMap<IDMContext,IDMData>(1);;
@Override
public String toString() {
return fKey.toString() + " = " + //$NON-NLS-1$
"[hasChildren=" + fHasChildren + ", " +//$NON-NLS-1$ //$NON-NLS-2$
"childrenCount=" + fChildrenCount + //$NON-NLS-1$
", children=" + fChildren + //$NON-NLS-1$
", data/status=" + fDataOrStatus + //$NON-NLS-1$
", oldData=" + fArchiveData + "]"; //$NON-NLS-1$ //$NON-NLS-2$
}
}
/**
* A key for a special marker entry in the cache. This marker entry is used
* to optimize repeated flushing of the cache.
* @see AbstractCachingVMProvider#flush(List)
*/
private static class FlushMarkerKey {
private Object fRootElement;
private IElementUpdateTester fElementTester;
FlushMarkerKey(Object rootElement, IElementUpdateTester pathTester) {
fRootElement = rootElement;
fElementTester = pathTester;
}
boolean includes(FlushMarkerKey key) {
return fRootElement.equals(key.fRootElement) &&
fElementTester.includes(key.fElementTester);
}
int getUpdateFlags(ElementDataKey key) {
if (fRootElement.equals(key.fRootElement)) {
return fElementTester.getUpdateFlags(key.fViewerInput, key.fPath);
}
return 0;
}
}
/**
* Marker used to keep track of whether any entries with the given
* root element are present in the cache.
*/
private static class RootElementMarkerKey {
private Object fRootElement;
RootElementMarkerKey(Object rootElement) {
fRootElement = rootElement;
}
}
class RootElementMarkerEntry extends Entry {
RootElementMarkerEntry(RootElementMarkerKey key) {
super(key);
}
@Override
void remove() {
super.remove();
rootElementRemovedFromCache(((RootElementMarkerKey)fKey).fRootElement);
}
}
protected static String SELECTED_UPDATE_MODE = "org.eclipse.dd.dsf.ui.viewmodel.update.selectedUpdateMode"; //$NON-NLS-1$
private IVMUpdatePolicy fCurrentUpdatePolicy;
private IVMUpdatePolicy[] fAvailableUpdatePolicies;
public Map<Object, RootElementMarkerKey> fRootMarkers = new HashMap<Object, RootElementMarkerKey>();
/**
* Hash map holding cache data. To store the cache information, the cache uses a
* combination of this hash map and a double-linked list running through all
* the entries in the cache. The linked list is used to organize the cache entries
* in least recently used (LRU) order. This ordering is then used to delete least
* recently used entries in the cache and keep the cache from growing indefinitely.
* Also, the ordering is used to optimize the flushing of the cache data (see
* {@link FlushMarkerKey} for more details).
*/
private final Map<Object, Entry> fCacheData = new HashMap<Object, Entry>(200, 0.75f);
/**
* Pointer to the first cache entry in the double-linked list of cache entries.
*/
private final Entry fCacheListHead;
public AbstractCachingVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext) {
super(adapter, presentationContext);
fCacheListHead = new Entry(null);
fCacheListHead.fNext = fCacheListHead;
fCacheListHead.fPrevious = fCacheListHead;
String updateModeId = (String)presentationContext.getProperty(SELECTED_UPDATE_MODE);
if (updateModeId != null) {
for (IVMUpdatePolicy updateMode : getAvailableUpdatePolicies()) {
if (updateMode.getID().equals(updateModeId)) {
fCurrentUpdatePolicy = updateMode;
}
}
}
fAvailableUpdatePolicies = createUpdateModes();
fCurrentUpdatePolicy = fAvailableUpdatePolicies[0];
}
protected IVMUpdatePolicy[] createUpdateModes() {
return new IVMUpdatePolicy[] { new AutomaticUpdatePolicy() };
}
public IVMUpdatePolicy[] getAvailableUpdatePolicies() {
return fAvailableUpdatePolicies;
}
public IVMUpdatePolicy getActiveUpdatePolicy() {
return fCurrentUpdatePolicy;
}
public void setActiveUpdatePolicy(IVMUpdatePolicy updatePolicy) {
fCurrentUpdatePolicy = updatePolicy;
}
public void refresh() {
IElementUpdateTester elementTester = getActiveUpdatePolicy().getTesterTester(ManualUpdatePolicy.REFRESH_EVENT);
List<FlushMarkerKey> flushKeys = new LinkedList<FlushMarkerKey>();
for (final IVMModelProxy proxyStrategy : getActiveModelProxies()) {
flushKeys.add(new FlushMarkerKey(proxyStrategy.getRootElement(), elementTester));
}
flush(flushKeys);
for (final IVMModelProxy proxyStrategy : getActiveModelProxies()) {
if (!proxyStrategy.isDisposed()) {
proxyStrategy.fireModelChanged(new ModelDelta(proxyStrategy.getRootElement(), IModelDelta.CONTENT));
}
}
}
@Override
protected void updateNode(IVMNode node, IHasChildrenUpdate[] updates) {
LinkedList <IHasChildrenUpdate> missUpdates = new LinkedList<IHasChildrenUpdate>();
for(final IHasChildrenUpdate update : updates) {
ElementDataKey key = makeEntryKey(node, update);
final ElementDataEntry entry = getElementDataEntry(key);
if (entry.fHasChildren != null) {
update.setHasChilren(entry.fHasChildren.booleanValue());
update.done();
} else {
missUpdates.add(
new VMHasChildrenUpdate(update, new DataRequestMonitor<Boolean>(getExecutor(), null) {
@Override
protected void handleCompleted() {
if(getStatus().isOK()) {
entry.fHasChildren = this.getData();
update.setHasChilren(getData());
}
update.done();
}
}));
}
}
if (!missUpdates.isEmpty()) {
super.updateNode(node, missUpdates.toArray(new IHasChildrenUpdate[missUpdates.size()]));
}
}
@Override
protected void updateNode(IVMNode node, IChildrenCountUpdate[] updates) {
// Given our knowledge of DefaultVMContentProviderStragety, make an
// assumption about the updates argument: there should always be
// exactly one update in this array.
assert updates.length == 1;
final IChildrenCountUpdate update = updates[0];
ElementDataKey key = makeEntryKey(node, update);
final ElementDataEntry entry = getElementDataEntry(key);
if(entry.fChildrenCount != null) {
update.setChildCount(entry.fChildrenCount.intValue());
update.done();
} else {
updates[0] = new VMChildrenCountUpdate(update, new DataRequestMonitor<Integer>(getExecutor(), null) {
@Override
protected void handleCompleted() {
if(getStatus().isOK()) {
entry.fChildrenCount = this.getData();
update.setChildCount(getData());
}
update.done();
}
});
super.updateNode(node, updates);
}
}
@Override
protected void updateNode(IVMNode node, IChildrenUpdate[] updates) {
// Given our knowledge of DefaultVMContentProviderStragety, make an
// assumption about the updates argument: there should always be
// exactly one update in this array.
assert updates.length == 1;
final IChildrenUpdate update = updates[0];
ElementDataKey key = makeEntryKey(node, update);
final ElementDataEntry entry = getElementDataEntry(key);
if (entry.fChildren == null || (update.getOffset() < 0 && !entry.fAllChildrenKnown)) {
// We need to retrieve all the children if we don't have any children information.
// Or if the client requested all children (offset = -1, length -1) and we have not
// retrieved that before.
updates[0] = new VMChildrenUpdate(
update, update.getOffset(), update.getLength(),
new DataRequestMonitor<List<Object>>(getExecutor(), null)
{
@Override
protected void handleCompleted()
{
if(getData() != null) {
// Check if the udpate retrieved all children by specifying "offset = -1, length = -1"
int updateOffset = update.getOffset();
if (updateOffset < 0) {
updateOffset = 0;
entry.fAllChildrenKnown = true;
}
// Estimate size of children map.
Integer childrenCount = entry.fChildrenCount;
childrenCount = childrenCount != null ? childrenCount : 0;
int capacity = Math.max((childrenCount.intValue() * 4)/3, 32);
// Create a new map, but only if it hasn't been created yet by another update.
if (entry.fChildren == null) {
entry.fChildren = new HashMap<Integer,Object>(capacity);
}
// Set the children to map and update.
for(int j = 0; j < getData().size(); j++) {
int offset = updateOffset + j;
Object child = getData().get(j);
entry.fChildren.put(offset, child);
update.setChild(child, offset);
}
}
update.done();
}
});
super.updateNode(node, updates);
} else if (update.getOffset() < 0 ) {
// The udpate requested all children. Fill in all children assuming that
// the children array is complete.
// The following assert should never fail given the first if statement.
assert entry.fAllChildrenKnown;
// we have all of the children in cache; return from cache
for(int position = 0; position < entry.fChildren.size(); position++) {
update.setChild(entry.fChildren.get(position), position);
}
update.done();
} else {
// Make the list of missing children. If we've retrieved the
List<Integer> childrenMissingFromCache = new LinkedList<Integer>();
for (int i = update.getOffset(); i < update.getOffset() + update.getLength(); i++) {
childrenMissingFromCache.add(i);
}
childrenMissingFromCache.removeAll(entry.fChildren.keySet());
if (childrenMissingFromCache.size() > 0) {
// perform a partial update; we only have some of the children of the update request
List<IChildrenUpdate> partialUpdates = new ArrayList<IChildrenUpdate>(2);
final CountingRequestMonitor multiRm = new ViewerCountingRequestMonitor(getExecutor(), update);
while(childrenMissingFromCache.size() > 0)
{
final int offset = childrenMissingFromCache.get(0);
childrenMissingFromCache.remove(0);
int length = 1;
while(childrenMissingFromCache.size() > 0 && childrenMissingFromCache.get(0) == offset + length)
{
length++;
childrenMissingFromCache.remove(0);
}
partialUpdates.add(new VMChildrenUpdate(
update, offset, length,
new DataRequestMonitor<List<Object>>(getExecutor(), multiRm) {
@Override
protected void handleCompleted() {
if (getData() != null) {
for (int i = 0; i < getData().size(); i++) {
update.setChild(getData().get(i), offset + i);
}
}
multiRm.done();
}
}));
}
super.updateNode( node, partialUpdates.toArray(new IChildrenUpdate[partialUpdates.size()]) );
multiRm.setDoneCount(partialUpdates.size());
} else {
// we have all of the children in cache; return from cache
for(int position = update.getOffset(); position < update.getOffset() + update.getLength(); position++) {
update.setChild(entry.fChildren.get(position), position);
}
update.done();
}
}
}
/**
* Flushes the cache with given DMC as the root element.
* @param dmcToFlush DM Context which is the root of the flush operation. Entries
* for all DMCs that have this DMC as their ancestor will be flushed. If this
* parameter is null, then all entries are flushed.
* @param archive
*/
private void flush(List<FlushMarkerKey> flushKeys) {
// To flush the cache data for given context, we have to iterate through all the contexts
// in cache. For each entry that has the given context as a parent, perform the flush.
List<FlushMarkerKey> flushKeysCopy = new ArrayList<FlushMarkerKey>(flushKeys.size());
flushKeysCopy.addAll(flushKeys);
// Iterate through the cache entries backwards. This means that we will be
// iterating in order of most-recently-used to least-recently-used.
Entry entry = fCacheListHead.fPrevious;
while (entry != fCacheListHead && flushKeysCopy.size() != 0) {
for (Iterator<FlushMarkerKey> flushKeyItr = flushKeysCopy.iterator(); flushKeyItr.hasNext();) {
FlushMarkerKey flushKey = flushKeyItr.next();
if (entry.fKey instanceof FlushMarkerKey) {
FlushMarkerKey entryFlushKey = (FlushMarkerKey)entry.fKey;
// If the context currently being flushed includes the flush
// context in current entry, remove the current entry since it will
// be replaced with one at the end of the list.
// Use special handling for null contexts, which we treat like it's an
// ancestor of all other contexts.
if (flushKey.includes(entryFlushKey)) {
fCacheData.remove(entryFlushKey);
entry.remove();
}
// If the flush context in current entry includes the current context
// being flushed, we can stop iterating through the cache entries
// now.
if (entryFlushKey.includes(flushKey)) {
flushKeyItr.remove();
}
}
else if (entry instanceof ElementDataEntry) {
ElementDataEntry elementDataEntry = (ElementDataEntry)entry;
int updateFlags = flushKey.getUpdateFlags((ElementDataKey)elementDataEntry.fKey);
if ((updateFlags & IVMUpdatePolicy.FLUSH) != 0) {
if ((updateFlags & IVMUpdatePolicy.ARCHIVE) != 0) {
// We are saving current data for change history, check if the data is valid.
// If it valid, save it for archive, if it's not valid old archive data will be used
// if there is any. And if there is no old archive data, just remove the cache entry.
for (Iterator<Map.Entry<IDMContext, Object>> itr = elementDataEntry.fDataOrStatus.entrySet().iterator();
itr.hasNext();)
{
Map.Entry<IDMContext, Object> dataOrStatusEntry = itr.next();
if (dataOrStatusEntry.getValue() instanceof IDMData) {
elementDataEntry.fArchiveData.put(dataOrStatusEntry.getKey(), (IDMData)dataOrStatusEntry.getValue());
}
}
elementDataEntry.fDataOrStatus.clear();
if (elementDataEntry.fArchiveData.isEmpty()) {
fCacheData.remove(entry.fKey);
entry.remove();
}
} else {
// We are not changing the archived data. If archive data exists in the entry, leave it.
// Otherwise remove the whole entry.
if (!elementDataEntry.fArchiveData.isEmpty()) {
elementDataEntry.fDataOrStatus.clear();
} else {
fCacheData.remove(entry.fKey);
entry.remove();
}
}
elementDataEntry.fHasChildren = null;
elementDataEntry.fChildrenCount = null;
elementDataEntry.fChildren = null;
} else if ((updateFlags & IVMUpdatePolicy.DIRTY) != 0) {
elementDataEntry.fDirty = true;
}
}
}
entry = entry.fPrevious;
}
for (FlushMarkerKey flushKey : flushKeys) {
// Insert a marker for this flush operation.
Entry flushMarkerEntry = new Entry(flushKey);
fCacheData.put(flushKey, flushMarkerEntry);
flushMarkerEntry.insert(fCacheListHead);
}
}
@Override
public void handleEvent(final Object event) {
IElementUpdateTester elementTester = getActiveUpdatePolicy().getTesterTester(event);
List<FlushMarkerKey> flushKeys = new LinkedList<FlushMarkerKey>();
List<IVMModelProxy> proxies = new LinkedList<IVMModelProxy>();
for (final IVMModelProxy proxyStrategy : getActiveModelProxies()) {
if (proxyStrategy.isDeltaEvent(event)) {
flushKeys.add(new FlushMarkerKey(proxyStrategy.getRootElement(), elementTester));
proxies.add(proxyStrategy);
}
}
flush(flushKeys);
for (final IVMModelProxy proxyStrategy : proxies) {
if (!proxyStrategy.isDisposed() && proxyStrategy.isDeltaEvent(event)) {
proxyStrategy.createDelta(
event,
new DataRequestMonitor<IModelDelta>(getExecutor(), null) {
@Override
public void handleCompleted() {
if (getStatus().isOK()) {
proxyStrategy.fireModelChanged(getData());
}
}
@Override public String toString() {
return "Result of a delta for event: '" + event.toString() + "' in VMP: '" + this + "'" + "\n" + getData().toString(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
});
}
}
}
/**
* Override default implementation to avoid automatically removing disposed proxies from
* list of active proxies. The caching provider only removes a proxy after its root element
* is no longer in the cache.
*/
@Override
public IModelProxy createModelProxy(Object element, IPresentationContext context) {
assert getExecutor().isInExecutorThread();
// Iterate through the current active proxies to try to find a proxy with the same
// element and re-use it if found. At the same time purge proxies that are no longer
IVMModelProxy proxy = null;
for (Iterator<IVMModelProxy> itr = getActiveModelProxies().iterator(); itr.hasNext();) {
IVMModelProxy next = itr.next();
if (next == null && next.getRootElement().equals(element)) {
proxy = next;
}
}
if (proxy == null) {
proxy = createModelProxyStrategy(element);
getActiveModelProxies().add(proxy);
}
return proxy;
}
/**
* Called when a given all cache entries for the given root element have
* been removed from the cache. In order to property track changed elements,
* the caching VM provider does not immediately remove entries for a given root
* element, when the viewer root element changes. Instead it keeps this root
* element and keeps processing deltas for that root element until the
* cache entries for this element are gone.
*/
protected void rootElementRemovedFromCache(Object rootElement) {
fRootMarkers.remove(rootElement);
for (Iterator<IVMModelProxy> proxiesItr = getActiveModelProxies().iterator(); proxiesItr.hasNext();) {
IVMModelProxy proxy = proxiesItr.next();
if (proxy.isDisposed() && proxy.getRootElement().equals(rootElement) ) {
proxiesItr.remove();
}
}
}
/**
* Convenience class that searches for teh root element for the given
* update and creates an element cache entry key.
*/
private ElementDataKey makeEntryKey(IVMNode node, IViewerUpdate update) {
Object rootElement = update.getViewerInput(); // Default
outer: for (IVMModelProxy proxy : getActiveModelProxies()) {
Object proxyRoot = proxy.getRootElement();
if (proxyRoot.equals(update.getViewerInput())) {
rootElement = proxyRoot;
break;
}
TreePath path = update.getElementPath();
for (int i = 0; i < path.getSegmentCount(); i++) {
if (proxyRoot.equals(path.getSegment(i))) {
rootElement = proxyRoot;
break outer;
}
}
}
return new ElementDataKey(rootElement, node, update.getElement(), update.getElementPath());
}
/**
* This is the only method that should be used to access a cache entry.
* It creates a new entry if needed and it maintains the ordering in
* the least-recently-used linked list.
*/
private ElementDataEntry getElementDataEntry(ElementDataKey key) {
assert key != null;
ElementDataEntry entry = (ElementDataEntry)fCacheData.get(key);
if (entry == null) {
// Create a new entry and add it to the end of the list.
entry = new ElementDataEntry(key);
addEntry(key, entry);
} else {
// Entry exists, move it to the end of the list.
entry.remove();
entry.insert(fCacheListHead);
}
// Update they root element marker.
RootElementMarkerKey rootMarker = fRootMarkers.get(key.fRootElement);
if (rootMarker == null) {
rootMarker = new RootElementMarkerKey(key.fRootElement);
fRootMarkers.put(key.fRootElement, rootMarker);
}
Entry rootMarkerEntry = fCacheData.get(rootMarker);
if (rootMarkerEntry == null) {
rootMarkerEntry = new RootElementMarkerEntry(rootMarker);
addEntry(rootMarker, rootMarkerEntry);
} else {
rootMarkerEntry.remove();
rootMarkerEntry.insert(fCacheListHead);
}
return entry;
}
/**
* Convenience method used by {@link #getElementDataEntry(ElementDataKey)}
*/
private void addEntry(Object key, Entry entry) {
fCacheData.put(key, entry);
entry.insert(fCacheListHead);
// If we are at capacity in the cache, remove the entry from head.
if (fCacheData.size() > MAX_CACHE_SIZE) {
fCacheData.remove(fCacheListHead.fNext.fKey);
fCacheListHead.fNext.remove();
}
}
/**
* Retrieves the deprecated IDMData object for the given IDMContext. This
* method should be removed once the use of IDMData is replaced with
* {@link IElementPropertiesProvider}.
*/
@Deprecated
public void getModelData(IVMNode node, IViewerUpdate update, IDMService service, final IDMContext dmc,
final DataRequestMonitor rm, Executor executor)
{
ElementDataKey key = makeEntryKey(node, update);
final ElementDataEntry entry = getElementDataEntry(key);
Object dataOrStatus = entry.fDataOrStatus.get(dmc);
if(dataOrStatus != null) {
if (dataOrStatus instanceof IDMData) {
rm.setData( (IDMData)dataOrStatus );
} else {
rm.setStatus((IStatus)dataOrStatus );
}
rm.done();
} else {
service.getModelData(dmc,
new DataRequestMonitor<IDMData>(executor, rm) {
@Override
protected void handleCompleted() {
if (getStatus().isOK()) {
entry.fDataOrStatus.put(dmc, getData());
rm.setData(getData());
} else {
entry.fDataOrStatus.put(dmc, getStatus());
rm.setStatus(getStatus());
}
rm.done();
}
}
);
}
}
/**
* Retrieves the deprecated IDMData object for the given IDMContext. This
* method should be removed once the use of IDMData is replaced with
* {@link IElementPropertiesProvider}.
*/
@Deprecated
public IDMData getArchivedModelData(IVMNode node, IViewerUpdate update, IDMContext dmc) {
ElementDataKey key = makeEntryKey(node, update);
final ElementDataEntry entry = getElementDataEntry(key);
if ( entry.fArchiveData != null) {
return entry.fArchiveData.get(dmc);
}
return null;
}
}

View file

@ -0,0 +1,45 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel.update;
import org.eclipse.jface.viewers.TreePath;
/**
* An "automatic" update policy which causes the view model provider cache to
* be flushed whenever an event causes a delta to be generated in the given
* model.
*/
public class AutomaticUpdatePolicy implements IVMUpdatePolicy {
public static String AUTOMATIC_UPDATE_POLICY_ID = "org.eclipse.dd.dsf.ui.viewmodel.update.defaultUpdatePolicy"; //$NON-NLS-1$
public static IElementUpdateTester fgUpdateTester = new IElementUpdateTester() {
public int getUpdateFlags(Object viewerInput, TreePath path) {
return FLUSH | ARCHIVE;
}
public boolean includes(IElementUpdateTester tester) {
return tester.equals(this);
}
};
public String getID() {
return AUTOMATIC_UPDATE_POLICY_ID;
}
public String getName() {
return "Automatic";
}
public IElementUpdateTester getTesterTester(Object event) {
return fgUpdateTester;
}
}

View file

@ -0,0 +1,44 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel.update;
import org.eclipse.dd.dsf.ui.viewmodel.IVMProvider;
/**
* A view model provider which supports caching of data returned by view model
* nodes. The methods in this interface allow clients to configure how the
* cache should be updated in response to different events.
*/
public interface ICachingVMProvider extends IVMProvider {
/**
* Returns the update policies that the given provider supports.
*/
public IVMUpdatePolicy[] getAvailableUpdatePolicies();
/**
* Returns the active update policy.
*/
public IVMUpdatePolicy getActiveUpdatePolicy();
/**
* Sets the active update policy. This has to be one of the update
* policies supported by the provider.
*/
public void setActiveUpdatePolicy(IVMUpdatePolicy mode);
/**
* Forces the view to flush its cache and re-fetch data from the view
* model nodes.
*/
public void refresh();
}

View file

@ -0,0 +1,41 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel.update;
import org.eclipse.jface.viewers.TreePath;
/**
* Tester object used to determine how individual update cache
* entries should be updated during a flush operation.
*
* @see IVMUpdatePolicy
*/
public interface IElementUpdateTester {
/**
* Returns the flags indicating what updates should be performed on the
* cache entry of the given element.
*/
public int getUpdateFlags(Object viewerInput, TreePath path);
/**
* Returns whether update represented by this tester includes another
* update. For example if update A was created as a result of an element X,
* and update B was created for an element Y, and element X is a parent of
* element Y, then tester A should include tester B. Also a tester should
* always include itself.
* <p/>
* This method is used to optimize the repeated flushing of the cache as
* it allows the cache to avoid needlessly updating the same cache entries.
*/
public boolean includes(IElementUpdateTester tester);
}

View file

@ -0,0 +1,53 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel.update;
/**
* Interface for an update policy. The main function of an update policy is
* to create an element tester for each given event. The element tester
* is then used to update the viewer cache.
*/
public interface IVMUpdatePolicy {
/**
* Flag indicating that a given entry in the cache should be cleared.
*/
public static int FLUSH = 0x1;
/**
* Flag indicating that a given entry in the cache should be cleared
* and saved for purpose of change tracking.
*/
public static int ARCHIVE = FLUSH | 0x2; // Flush is required when archiving.
/**
* Flag indicating that the a given cache entry should be marked as dirty.
* A dirty cache entry is one that is known not to be consistent with
* target data.
*/
public static int DIRTY = 0x4;
/**
* Returns unique ID of this update policy.
*/
public String getID();
/**
* Returns the user-presentable name of this update policy.
*/
public String getName();
/**
* Creates an element tester for the given event.
*/
public IElementUpdateTester getTesterTester(Object event);
}

View file

@ -0,0 +1,89 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel.update;
import java.util.Set;
import org.eclipse.jface.viewers.TreePath;
/**
* An "manual" update policy which causes the view model provider cache to be
* flushed only as a result of an explicit user action.
*/
public class ManualUpdatePolicy implements IVMUpdatePolicy {
public static String MANUAL_UPDATE_POLICY_ID = "org.eclipse.dd.dsf.ui.viewmodel.update.manualUpdatePolicy"; //$NON-NLS-1$
public static Object REFRESH_EVENT = new Object();
private static class UserEditEventUpdateTester implements IElementUpdateTester {
private final Set<Object> fElements;
public UserEditEventUpdateTester(Set<Object> elements) {
fElements = elements;
}
public int getUpdateFlags(Object viewerInput, TreePath path) {
if (fElements.contains(viewerInput)) {
return FLUSH;
}
for (int i = 0; i < path.getSegmentCount(); i++) {
if (fElements.contains(path.getSegment(i))) {
return FLUSH;
}
}
return 0;
}
public boolean includes(IElementUpdateTester tester) {
return
tester instanceof UserEditEventUpdateTester &&
fElements.equals(((UserEditEventUpdateTester)tester).fElements);
}
}
private static IElementUpdateTester fgUpdateTester = new IElementUpdateTester() {
public int getUpdateFlags(Object viewerInput, TreePath path) {
return DIRTY;
}
public boolean includes(IElementUpdateTester tester) {
return tester.equals(this);
}
};
private static IElementUpdateTester fgRefreshUpdateTester = new IElementUpdateTester() {
public int getUpdateFlags(Object viewerInput, TreePath path) {
return FLUSH | ARCHIVE;
}
public boolean includes(IElementUpdateTester tester) {
return tester.equals(this) || tester.equals(fgUpdateTester) || tester instanceof UserEditEventUpdateTester;
}
};
public String getID() {
return MANUAL_UPDATE_POLICY_ID;
}
public String getName() {
return "Manual";
}
public IElementUpdateTester getTesterTester(Object event) {
if (event.equals(REFRESH_EVENT)) {
return fgRefreshUpdateTester;
}
return fgUpdateTester;
}
}

View file

@ -0,0 +1,37 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel.update;
import java.util.HashSet;
import java.util.Set;
/**
* An event representing a user editing of the data in the viewer. Typically, when
* a viewer is configured to be in a manual update mode, if user edits a value, the
* viewer should still update at least the value that the user editor. This event
* is used to accomplish that behavior.
*/
public class UserEditEvent {
private final Set<Object> fElements;
public UserEditEvent(Object element) {
fElements = new HashSet<Object>();
fElements.add(element);
}
public UserEditEvent(Set<Object> elements) {
fElements = elements;
}
public Set<Object> getElements() {
return fElements;
}
}

View file

@ -1,384 +0,0 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Ted R Williams (Wind River Systems, Inc.) - initial implementation
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel.update;
import java.util.HashMap;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.Executor;
import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.DefaultDsfExecutor;
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
import org.eclipse.dd.dsf.concurrent.MultiRequestMonitor;
import org.eclipse.dd.dsf.datamodel.IDMContext;
import org.eclipse.dd.dsf.datamodel.IDMData;
import org.eclipse.dd.dsf.datamodel.IDMEvent;
import org.eclipse.dd.dsf.datamodel.IDMService;
import org.eclipse.dd.dsf.ui.viewmodel.VMElementsCountUpdate;
import org.eclipse.dd.dsf.ui.viewmodel.VMElementsUpdate;
import org.eclipse.dd.dsf.ui.viewmodel.VMHasElementsUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
@SuppressWarnings("restriction")
public abstract class VMCache
{
protected Executor fExecutor = new DefaultDsfExecutor();
protected HashMap<Object, Integer> fChildrenCounts = new HashMap<Object, Integer>();
protected HashMap<Object, HashMap<Integer,Object>> fChildren = new HashMap<Object, HashMap<Integer,Object>>();
protected HashMap<Object, Boolean> fHasChildren = new HashMap<Object, Boolean>();
protected HashMap<IDMContext, IDMData> fData = new HashMap<IDMContext, IDMData>();
protected HashMap<IDMContext, IDMData> fDataArchive = fData;
public HashMap<?,?>[] getCacheData()
{
return new HashMap<?,?>[] { fHasChildren, fChildrenCounts, fChildren, fData, fDataArchive };
}
public VMCache()
{
}
// Suppress warnings related to the lost type information in getCacheData()
@SuppressWarnings("unchecked")
public VMCache(VMCache oldCache)
{
if(oldCache != null)
{
HashMap<?,?> oldCacheData[] = oldCache.getCacheData();
fHasChildren = (HashMap<Object, Boolean>)oldCacheData[0];
fChildrenCounts = (HashMap<Object, Integer>)oldCacheData[1];
fChildren = (HashMap<Object, HashMap<Integer,Object>>)oldCacheData[2];
fData = (HashMap<IDMContext, IDMData>)oldCacheData[3];
fDataArchive = (HashMap<IDMContext, IDMData>)oldCacheData[4];
}
}
protected void flush(boolean archive)
{
if(archive)
fDataArchive = fData;
fData = new HashMap<IDMContext, IDMData>();
fChildrenCounts.clear();
fChildren.clear();
fHasChildren.clear();
}
/**
* Returns whether the data in this cache should used when servicing
* view updates. If this method returns false all updates will be
* sent to the view model, although the retrieved data should still
* be stored in the cache if {@link #isCacheWriteEnabled()} returns true.
* @return
*/
protected boolean isCacheReadEnabled()
{
return true;
}
/**
* Returns true if data retrieved from the view model should be cached.
* If this returns false, then the state of the cache is frozen.
*/
protected boolean isCacheWriteEnabled()
{
return true;
}
@SuppressWarnings("restriction")
public IHasChildrenUpdate[] update(IHasChildrenUpdate[] updates) {
if(!isCacheReadEnabled())
return updates;
Vector<IHasChildrenUpdate> missVector = new Vector<IHasChildrenUpdate>();
for(IHasChildrenUpdate update : updates)
{
if(fHasChildren.containsKey(update.getElement()) && isCacheReadEnabled())
{
update.setHasChilren(fHasChildren.get(update.getElement()).booleanValue());
update.done();
}
else
{
missVector.addElement(update);
}
}
updates = new IHasChildrenUpdate[missVector.size()];
for(int i = 0; i < updates.length; i++)
{
final IHasChildrenUpdate update = missVector.elementAt(i);
updates[i] = new VMHasElementsUpdate(update, new DataRequestMonitor<Boolean>(fExecutor, null)
{
@Override
protected void handleCompleted()
{
if(getStatus().isOK())
{
if(isCacheWriteEnabled())
fHasChildren.put(update.getElement(), this.getData());
update.setHasChilren(getData());
}
update.done();
}
});
}
return updates;
}
@SuppressWarnings("restriction")
public IChildrenCountUpdate[] update(IChildrenCountUpdate[] updates)
{
if(!isCacheReadEnabled())
return updates;
Vector<IChildrenCountUpdate> missVector = new Vector<IChildrenCountUpdate>();
for(IChildrenCountUpdate update : updates)
{
if(fChildrenCounts.containsKey(update.getElement()) && isCacheReadEnabled())
{
update.setChildCount(fChildrenCounts.get(update.getElement()));
update.done();
}
else
{
missVector.addElement(update);
}
}
updates = new IChildrenCountUpdate[missVector.size()];
for(int i = 0; i < updates.length; i++)
{
final IChildrenCountUpdate update = missVector.elementAt(i);
updates[i] = new VMElementsCountUpdate(update, new DataRequestMonitor<Integer>(fExecutor, null)
{
@Override
protected void handleCompleted() {
if(getStatus().isOK())
{
if(isCacheWriteEnabled())
fChildrenCounts.put(update.getElement(), this.getData());
update.setChildCount(this.getData());
}
update.done();
}
});
}
return updates;
}
@SuppressWarnings("restriction")
public IChildrenUpdate[] update(IChildrenUpdate[] updates) {
if(!isCacheReadEnabled())
return updates;
Vector<IChildrenUpdate> updatesEntirelyMissingFromCache = new Vector<IChildrenUpdate>();
for(final IChildrenUpdate update : updates)
{
if(fChildren.containsKey(update.getElement()) && isCacheReadEnabled())
{
Vector<Integer> childrenMissingFromCache = new Vector<Integer>();
for(int i = update.getOffset(); i < update.getOffset() + update.getLength(); i++)
childrenMissingFromCache.addElement(i);
childrenMissingFromCache.removeAll(fChildren.get(update.getElement()).keySet());
if(childrenMissingFromCache.size() > 0)
{
// perform a partial update; we only have some of the children of the update request
final HashMap<DataRequestMonitor<List<Object>>,IChildrenUpdate> associationsRequestMonitorToChildUpdate
= new HashMap<DataRequestMonitor<List<Object>>,IChildrenUpdate>();
final MultiRequestMonitor<DataRequestMonitor<List<Object>>> childrenMultiRequestMon =
new MultiRequestMonitor<DataRequestMonitor<List<Object>>>(fExecutor, null) {
@Override
protected void handleCompleted() {
// Status is OK, only if all request monitors are OK.
if (getStatus().isOK())
{
for (DataRequestMonitor<List<Object>> monitor : getRequestMonitors())
{
int offset = associationsRequestMonitorToChildUpdate.get(monitor).getOffset();
for(Object child : monitor.getData())
update.setChild(child, offset++);
}
} else {
update.setStatus(getStatus());
}
update.done();
}
};
while(childrenMissingFromCache.size() > 0)
{
int offset = childrenMissingFromCache.elementAt(0);
childrenMissingFromCache.removeElementAt(0);
int length = 1;
while(childrenMissingFromCache.size() > 0 && childrenMissingFromCache.elementAt(0) == offset + length)
{
length++;
childrenMissingFromCache.removeElementAt(0);
}
DataRequestMonitor<List<Object>> partialUpdateMonitor = new DataRequestMonitor<List<Object>>(fExecutor, null)
{
@Override
protected void handleCompleted()
{
childrenMultiRequestMon.requestMonitorDone(this);
}
};
final IChildrenUpdate partialUpdate = new VMElementsUpdate(update, offset, length,
childrenMultiRequestMon.add(partialUpdateMonitor));
associationsRequestMonitorToChildUpdate.put(partialUpdateMonitor, partialUpdate);
updatesEntirelyMissingFromCache.add(partialUpdate);
}
}
else
{
// we have all of the children in cache; return from cache
for(int position = update.getOffset(); position < update.getOffset() + update.getLength(); position++)
update.setChild(fChildren.get(update.getElement()).get(position), position);
update.done();
}
}
else
{
updatesEntirelyMissingFromCache.addElement(update);
}
}
updates = new IChildrenUpdate[updatesEntirelyMissingFromCache.size()];
for(int i = 0; i < updates.length; i++)
{
final IChildrenUpdate update = updatesEntirelyMissingFromCache.elementAt(i);
updates[i] =
new VMElementsUpdate(
update, update.getOffset(), update.getLength(),
new DataRequestMonitor<List<Object>>(fExecutor, null)
{
@Override
protected void handleCompleted()
{
if(getData() != null)
{
for(int j = 0; j < getData().size(); j++)
{
if(isCacheWriteEnabled())
{
if(!fChildren.containsKey(update.getElement()))
fChildren.put(update.getElement(), new HashMap<Integer,Object>());
fChildren.get(update.getElement()).put(update.getOffset() + j, getData().get(j));
}
update.setChild(getData().get(j), update.getOffset() + j);
}
}
update.done();
}
})
{
/* See https://bugs.eclipse.org/bugs/show_bug.cgi?id=202109
*
* A flexible hierarchy bug/optimization causes query with incorrect
* IChildrenUpdate[] array length.
*
* We found this while deleting a register node. Example:
*
* the register view displays:
* PC
* EAX
* EBX
* ECX
* EDX
*
* we delete EBX and force a context refresh.
*
* flexible hierarchy queries for IChildrenUpdate[5] and IChildrenCountUpdate at
* the same time.
*
* VMElementsUpdate, used by VMCache to wrap the IChildrenUpdate, generates an
* IStatus.ERROR with message "Incomplete elements of updates" when fElements
* count (provided by service) does not match the length provided by the original
* update query.
*
* Workaround, respect getData() != null instead of IStatus.OK, override
* VMElementsUpdate.done() to set elements regardless of count
*/
@Override
public void done() {
@SuppressWarnings("unchecked")
DataRequestMonitor<List<Object>> rm = (DataRequestMonitor<List<Object>>)fRequestMonitor;
rm.setData(fElements);
super.done();
}
};
}
return updates;
}
@SuppressWarnings("unchecked")
@ConfinedToDsfExecutor("DsfSession.getSession(dmc.getSessionId()).getExecutor()")
public void getModelData(IDMService service, final IDMContext dmc, final DataRequestMonitor rm, DsfExecutor executor)
{
if(fData.containsKey(dmc) && isCacheReadEnabled())
{
rm.setData( fData.get(dmc));
rm.done();
}
else
{
service.getModelData(dmc,
new DataRequestMonitor<IDMData>(executor, rm) {
@Override
protected void handleOK() {
if(isCacheWriteEnabled())
fData.put(dmc, getData());
rm.setData(getData());
rm.done();
}
}
);
}
}
@SuppressWarnings("unchecked")
public IDMData getArchivedModelData(IDMContext dmc)
{
return fDataArchive.get(dmc);
}
@SuppressWarnings("unchecked")
public abstract void handleEvent(IDMEvent event);
}

View file

@ -1,112 +0,0 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Ted R Williams (Wind River Systems, Inc.) - initial implementation
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel.update;
import java.util.HashMap;
import java.util.Vector;
import org.eclipse.dd.dsf.datamodel.IDMEvent;
public class VMCacheManager
{
private static VMCacheManager fInstance = null;
private HashMap<Object, VMCache> fAssociations = new HashMap<Object, VMCache>();
public interface CacheListener
{
public void cacheFlushed(Object context);
}
private HashMap<Object, Vector<CacheListener>> fListeners = new HashMap<Object, Vector<CacheListener>>();
public VMCacheManager()
{
}
public static VMCacheManager getVMCacheManager()
{
if(fInstance == null)
fInstance = new VMCacheManager();
return fInstance;
}
public VMCache getCache(Object context)
{
if(!fAssociations.containsKey(context))
fAssociations.put(context, new VMCache()
{
@SuppressWarnings("unchecked")
@Override
public void handleEvent(IDMEvent event) {
}
@Override
public boolean isCacheReadEnabled()
{
return false;
}
@Override
public boolean isCacheWriteEnabled()
{
return false;
}
});
return fAssociations.get(context);
}
public void registerCache(Object context, VMCache cache)
{
fAssociations.put(context, cache);
}
public void addCacheListener(Object context, CacheListener listener)
{
if(!fListeners.containsKey(context))
fListeners.put(context, new Vector<CacheListener>());
fListeners.get(context).addElement(listener);
}
public void removeCacheListener(Object context, CacheListener listener)
{
if(!fListeners.containsKey(context))
{
fListeners.get(context).removeElement(listener);
if(fListeners.get(context).isEmpty())
fListeners.remove(context);
}
}
private void fireCacheFlushed(Object context)
{
if(fListeners.containsKey(context))
{
for(CacheListener listener : fListeners.get(context))
listener.cacheFlushed(context);
}
}
public void flush(Object context)
{
getCache(context).flush(false);
fireCacheFlushed(context);
}
}

View file

@ -1,40 +0,0 @@
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Ted R Williams (Wind River Systems, Inc.) - initial implementation
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel.update.actions;
import org.eclipse.dd.dsf.ui.viewmodel.update.VMCache;
import org.eclipse.dd.dsf.ui.viewmodel.update.VMCacheManager;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ui.IViewActionDelegate;
import org.eclipse.ui.IViewPart;
public abstract class AbstractRefreshActionDelegate implements IViewActionDelegate {
protected IViewPart fView;
public void init(IViewPart view) {
fView = view;
}
public void run(IAction action) {
VMCacheManager.getVMCacheManager().registerCache(getContext(), createCache());
}
public void selectionChanged(IAction action, ISelection selection) {
}
protected abstract Object getContext();
protected abstract VMCache createCache();
}

View file

@ -3,4 +3,5 @@ output.. = bin/
bin.includes = META-INF/,\
.,\
plugin.xml,\
plugin.properties,\
about.html

View file

@ -90,6 +90,10 @@ public class DefaultDsfExecutor extends ScheduledThreadPoolExecutor
return Thread.currentThread().equals( ((DsfThreadFactory)getThreadFactory()).fThread );
}
protected String getName() {
return fName;
}
static void logException(Throwable t) {
DsfPlugin plugin = DsfPlugin.getDefault();
if (plugin == null) return;
@ -114,14 +118,14 @@ public class DefaultDsfExecutor extends ScheduledThreadPoolExecutor
//
// Utilities used for tracing.
//
static boolean DEBUG_EXECUTOR = false;
static String DEBUG_EXECUTOR_NAME = "";
static boolean ASSERTIONS_ENABLED = false;
protected static boolean DEBUG_EXECUTOR = false;
protected static String DEBUG_EXECUTOR_NAME = ""; //$NON-NLS-1$
protected static boolean ASSERTIONS_ENABLED = false;
static {
DEBUG_EXECUTOR = DsfPlugin.DEBUG && "true".equals( //$NON-NLS-1$
Platform.getDebugOption("org.eclipse.dd.dsf/debug/executor")); //$NON-NLS-1$
DEBUG_EXECUTOR_NAME = DsfPlugin.DEBUG
? Platform.getDebugOption("org.eclipse.dd.dsf/debug/executorName") : ""; //$NON-NLS-1$
? Platform.getDebugOption("org.eclipse.dd.dsf/debug/executorName") : ""; //$NON-NLS-1$ //$NON-NLS-2$
assert (ASSERTIONS_ENABLED = true) == true;
}
@ -253,9 +257,7 @@ public class DefaultDsfExecutor extends ScheduledThreadPoolExecutor
fRunnable = runnable;
// Check if executable wasn't executed already.
if (fRunnable instanceof DsfExecutable &&
DEBUG_EXECUTOR && ("".equals(DEBUG_EXECUTOR_NAME) || fName.equals(DEBUG_EXECUTOR_NAME))) //$NON-NLS-1$
{
if (DEBUG_EXECUTOR && fRunnable instanceof DsfExecutable) {
assert !((DsfExecutable)fRunnable).getSubmitted() : "Executable was previously executed."; //$NON-NLS-1$
((DsfExecutable)fRunnable).setSubmitted();
}

View file

@ -61,7 +61,7 @@ public class DsfExecutable {
* Flag indicating whether this executable was ever executed by an
* executor. Used for tracing only.
*/
private boolean fSubmitted = false;
private volatile boolean fSubmitted = false;
@SuppressWarnings("unchecked")
public DsfExecutable() {
@ -96,7 +96,7 @@ public class DsfExecutable {
}
}
boolean getSubmitted() {
public boolean getSubmitted() {
return fSubmitted;
}
@ -104,7 +104,7 @@ public class DsfExecutable {
* Marks this executable to indicate that it has been executed by the
* executor. To be invoked only by DsfExecutor.
*/
void setSubmitted() {
public void setSubmitted() {
fSubmitted = true;
}

View file

@ -12,6 +12,9 @@ package org.eclipse.dd.dsf.concurrent;
import java.util.concurrent.Executor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.dd.dsf.DsfPlugin;
/**
* Executor that executes a runnable immediately as it is submitted. This
* executor is useful for clients that need to create <code>RequestMonitor</code>
@ -20,6 +23,16 @@ import java.util.concurrent.Executor;
*/
public class ImmediateExecutor implements Executor {
/**
* Debug flag used for tracking runnables that were never executed,
* or executed multiple times.
*/
protected static boolean DEBUG_EXECUTOR = false;
static {
DEBUG_EXECUTOR = DsfPlugin.DEBUG && "true".equals( //$NON-NLS-1$
Platform.getDebugOption("org.eclipse.dd.dsf/debug/executor")); //$NON-NLS-1$
}
private static ImmediateExecutor fInstance = new ImmediateExecutor();
/**
@ -36,6 +49,11 @@ public class ImmediateExecutor implements Executor {
}
public void execute(Runnable command) {
// Check if executable wasn't executed already.
if (DEBUG_EXECUTOR && command instanceof DsfExecutable) {
assert !((DsfExecutable)command).getSubmitted() : "Executable was previously executed."; //$NON-NLS-1$
((DsfExecutable)command).setSubmitted();
}
command.run();
}
}