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

Ported to new flexible hierarchy APIs (bug 164341).

This commit is contained in:
Pawel Piech 2006-11-30 22:47:43 +00:00
parent 4a775182e0
commit b191075ec4
31 changed files with 2619 additions and 1879 deletions

View file

@ -10,14 +10,15 @@
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel;
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
import org.eclipse.dd.dsf.concurrent.DsfRunnable;
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.ui.DsfDebugUIPlugin;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMRootLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.IVMRootLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.DMContextVMLayoutNode.DMContextVMContext;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode.DMVMContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.contexts.DebugContextEvent;
import org.eclipse.debug.ui.contexts.IDebugContextListener;
@ -27,21 +28,26 @@ import org.eclipse.ui.IWorkbenchWindow;
/**
* This is is a standard root node which listens to the selection in Debug View.
* Views such as variables and registers base their content based on the
* Views such as variables and registers base their content on the
* selection in Debug view, and this node provides tracking of that selection.
* <p>
* Note: The variables/registers views track the selection using the same
* IDebugContextListener interface, but they only use the first element of the
* selection, as in IStructuredSelection.getFirstElement(). Therefore the root
* node also has to use the first element as the root object instead of the
* whole selection.
*/
@SuppressWarnings("restriction")
public class DebugViewSelectionRootLayoutNode extends AbstractVMRootLayoutNode
implements IVMRootLayoutNode, IDebugContextListener
{
private RootVMC<Object> fRootVMC;
private ISelection fSelection;
public DebugViewSelectionRootLayoutNode(DsfExecutor executor, IWorkbenchWindow window) {
super(executor);
ISelection selection = DebugUITools.getDebugContextManager().getContextService(window).getActiveContext();
if (selection instanceof IStructuredSelection) {
fRootVMC = new RootVMC<Object>( this, ((IStructuredSelection)selection).getFirstElement() );
} else {
fRootVMC = new RootVMC<Object>( this, null );
public DebugViewSelectionRootLayoutNode(AbstractVMProvider provider) {
super(provider);
IWorkbenchWindow activeWindow = DsfDebugUIPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow();
if (activeWindow != null) {
fSelection = DebugUITools.getDebugContextManager().getContextService(activeWindow).getActiveContext();
}
DebugUITools.getDebugContextManager().addDebugContextListener(this);
}
@ -53,7 +59,7 @@ public class DebugViewSelectionRootLayoutNode extends AbstractVMRootLayoutNode
}
/**
* If the input object is a DMC-VMC, and the event is a DMC event.
* If the input object is a Data Model context, and the event is a DMC event.
* Then we can filter the event to make sure that the view does not
* react to events that relate to objects outside this view.
*
@ -74,45 +80,58 @@ public class DebugViewSelectionRootLayoutNode extends AbstractVMRootLayoutNode
* determine whether a delta is needed.
*/
@Override
public boolean hasDeltaFlags(Object event) {
if (event instanceof IDMEvent && fRootVMC.getInputObject() instanceof DMContextVMContext) {
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();
IDMContext<?> inputDmc = ((DMContextVMContext)fRootVMC.getInputObject()).getDMC();
for (IDMContext<?> eventDmcAncestor : DMContexts.toList(eventDmc)) {
IDMContext<?> inputDmcAncestor = DMContexts.getAncestorOfType(inputDmc, eventDmcAncestor.getClass());
if (inputDmcAncestor != null) {
potentialMatchFound = true;
if (inputDmcAncestor.equals(eventDmcAncestor)) {
matchFound = true;
return super.getDeltaFlags(event);
}
}
}
if (potentialMatchFound && !matchFound) {
return false;
return IModelDelta.NO_CHANGE;
}
}
return super.hasDeltaFlags(event);
return super.getDeltaFlags(event);
}
public IRootVMC getRootVMC() {
return fRootVMC;
/**
* Returns the full selection as it came from the DebugContextManager.
* @return
*/
public ISelection getSelection() {
return fSelection;
}
public Object getRootObject() {
if (fSelection instanceof IStructuredSelection) {
return ((IStructuredSelection)fSelection).getFirstElement();
}
return null;
}
public void debugContextChanged(DebugContextEvent event) {
final ISelection selection = event.getContext();
getExecutor().execute(new DsfRunnable() {
public void run() {
fSelection = event.getContext();
}
private IDMContext<?> getSelectedDMC() {
Object selection = fSelection;
if (selection instanceof IStructuredSelection) {
fRootVMC = new RootVMC<Object>( DebugViewSelectionRootLayoutNode.this,
((IStructuredSelection)selection).getFirstElement() );
} else {
fRootVMC = new RootVMC<Object>( DebugViewSelectionRootLayoutNode.this, null );
IStructuredSelection structSelection = (IStructuredSelection)selection;
if (structSelection.getFirstElement() instanceof DMVMContext)
{
return ((DMVMContext)structSelection.getFirstElement()).getDMC();
}
}
});
return null;
}
}

View file

@ -1,70 +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.debug.ui.viewmodel.launch;
import org.eclipse.dd.dsf.concurrent.DsfRunnable;
import org.eclipse.dd.dsf.concurrent.GetDataDone;
import org.eclipse.dd.dsf.concurrent.ThreadSafe;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.ui.viewmodel.IVMRootLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.VMProvider;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IDebugEventSetListener;
import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta;
/**
*
*/
@SuppressWarnings("restriction")
public class LaunchViewModelProvider extends VMProvider
implements IDebugEventSetListener
{
@ThreadSafe
public LaunchViewModelProvider(DsfSession session, IVMRootLayoutNode rootLayoutNode) {
super(session, rootLayoutNode);
DebugPlugin.getDefault().addDebugEventListener(this);
}
public void handleDebugEvents(final DebugEvent[] events) {
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
for (DebugEvent event : events) {
handleDebugEvent(event);
}
}
});
}
private void handleDebugEvent(DebugEvent event) {
/*
* Just like with DMC events, go through all the layout nodes and
* collect delta information for the received event.
*/
if (getRootLayoutNode() != null && getRootLayoutNode().hasDeltaFlags(event)) {
getRootLayoutNode().createDelta(event, new GetDataDone<IModelDelta>() {
public void run() {
if (getStatus().isOK()) {
getModelProxy().fireModelChangedNonDispatch(getData());
}
}
});
}
}
@Override
public void dispose() {
DebugPlugin.getDefault().removeDebugEventListener(this);
super.dispose();
}
}

View file

@ -10,9 +10,11 @@
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.launch;
import org.eclipse.core.runtime.MultiStatus;
import java.util.List;
import org.eclipse.dd.dsf.concurrent.Done;
import org.eclipse.dd.dsf.concurrent.GetDataDone;
import org.eclipse.dd.dsf.datamodel.IDMContext;
import org.eclipse.dd.dsf.datamodel.IDMEvent;
import org.eclipse.dd.dsf.debug.service.IRunControl;
import org.eclipse.dd.dsf.debug.service.IStack;
@ -21,66 +23,77 @@ import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext;
import org.eclipse.dd.dsf.debug.service.IRunControl.StateChangeReason;
import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext;
import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMData;
import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.ui.viewmodel.DMContextVMLayoutNode;
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.debug.internal.ui.viewers.provisional.ILabelRequestMonitor;
import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode;
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;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.jface.resource.ImageDescriptor;
@SuppressWarnings("restriction")
public class StackFramesLayoutNode extends DMContextVMLayoutNode<IStack.IFrameDMData> {
public class StackFramesLayoutNode extends AbstractDMVMLayoutNode<IStack.IFrameDMData> {
public IVMContext[] fCachedOldFramesVMCs;
public IVMContext[] fCachedOldFrameVMCs;
public StackFramesLayoutNode(DsfSession session) {
super(session, IStack.IFrameDMContext.class);
public StackFramesLayoutNode(AbstractVMProvider provider, DsfSession session) {
super(provider, session, IStack.IFrameDMContext.class);
}
public void hasElements(IVMContext parentVmc, final GetDataDone<Boolean> done) {
IExecutionDMContext execDmc = findDmcInVmc(parentVmc, IExecutionDMContext.class);
if (execDmc == null || getServicesTracker().getService(IStack.class) == null || getServicesTracker().getService(IRunControl.class) == null) {
done.setData(false);
getExecutor().execute(done);
@Override
protected void updateHasElementsInSessionThread(IHasChildrenUpdate[] updates) {
for (IHasChildrenUpdate update : updates) {
if (!checkService(IStack.class, null, update)) return;
IExecutionDMContext execDmc = findDmcInPath(update.getElementPath(), IExecutionDMContext.class);
if (execDmc == null) {
handleFailedUpdate(update);
return;
}
done.setData(getServicesTracker().getService(IStack.class).isStackAvailable(execDmc));
getExecutor().execute(done);
update.setHasChilren(getServicesTracker().getService(IStack.class).isStackAvailable(execDmc));
update.done();
}
}
public void getElements(final IVMContext parentVmc, final GetDataDone<IVMContext[]> done) {
final IExecutionDMContext execDmc = findDmcInVmc(parentVmc, IExecutionDMContext.class);
if (execDmc == null || getServicesTracker().getService(IStack.class) == null || getServicesTracker().getService(IRunControl.class) == null) {
done.setData(new IVMContext[0]);
getExecutor().execute(done);
@Override
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
if (!checkService(IStack.class, null, update)) return;
final IExecutionDMContext execDmc = findDmcInPath(update.getElementPath(), IExecutionDMContext.class);
if (execDmc == null) {
handleFailedUpdate(update);
return;
}
getServicesTracker().getService(IStack.class).getFrames(
execDmc,
new GetDataDone<IFrameDMContext[]>() { public void run() {
new GetDataDone<IFrameDMContext[]>() {
public void run() {
if (!getStatus().isOK()) {
// Failed to retrieve frames. If we are stepping, we
// might still be able to retrieve just the top stack
// frame, which would still be useful in Debug View.
if (!checkService(IRunControl.class, null, update)) return;
if (getServicesTracker().getService(IRunControl.class).isStepping(execDmc)) {
getElementsTopStackFrameOnly(parentVmc, done);
getElementsTopStackFrameOnly(update);
} else {
propagateError(getExecutor(), done, "Failed retrieving stack frames"); //$NON-NLS-1$
update.done();
}
return;
}
// Store the VMC element array, in case we need to use it when
fCachedOldFramesVMCs = dmcs2vmcs(parentVmc, getData());
done.setData(fCachedOldFramesVMCs);
getExecutor().execute(done);
}});
fCachedOldFrameVMCs = dmcs2vmcs(getData());
for (int i = 0; i < fCachedOldFrameVMCs.length; i++) update.setChild(fCachedOldFrameVMCs[i], i);
update.done();
}
});
}
/**
@ -89,68 +102,56 @@ public class StackFramesLayoutNode extends DMContextVMLayoutNode<IStack.IFrameDM
* frames are retrieved from the cache or omitted.
* @see #getElements(IVMContext, GetDataDone)
*/
private void getElementsTopStackFrameOnly(final IVMContext parentVmc, final GetDataDone<IVMContext[]> done) {
final IExecutionDMContext execDmc = findDmcInVmc(parentVmc, IExecutionDMContext.class);
private void getElementsTopStackFrameOnly(final IChildrenUpdate update) {
final IExecutionDMContext execDmc = findDmcInPath(update.getElementPath(), IExecutionDMContext.class);
if (execDmc == null) {
handleFailedUpdate(update);
return;
}
getServicesTracker().getService(IStack.class).getTopFrame(
execDmc,
new GetDataDone<IFrameDMContext>() { public void run() {
if (propagateError(getExecutor(), done, "Failed retrieving top stack frame")) return; //$NON-NLS-1$
IVMContext topFrameVmc = new DMContextVMContext(parentVmc, getData());
// If there are old frames cached, use them and only substitute the top frame object. Otherwise, create
// an array of VMCs with just the top frame.
if (fCachedOldFramesVMCs != null && fCachedOldFramesVMCs.length >= 1) {
fCachedOldFramesVMCs[0] = topFrameVmc;
done.setData(fCachedOldFramesVMCs);
} else {
done.setData(new IVMContext[] { topFrameVmc });
}
getExecutor().execute(done);
}});
}
public void retrieveLabel(IVMContext vmc, final ILabelRequestMonitor result, String[] columns) {
final IExecutionDMContext execDmc = findDmcInVmc(vmc, IExecutionDMContext.class);
if (execDmc == null || getServicesTracker().getService(IStack.class) == null || getServicesTracker().getService(IRunControl.class) == null) {
result.done();
if (!getStatus().isOK()) {
handleFailedUpdate(update);
return;
}
IVMContext topFrameVmc = new DMVMContext(getData());
update.setChild(topFrameVmc, 0);
// If there are old frames cached, use them and only substitute the top frame object. Otherwise, create
// an array of VMCs with just the top frame.
if (fCachedOldFrameVMCs != null && fCachedOldFrameVMCs.length >= 1) {
fCachedOldFrameVMCs[0] = topFrameVmc;
for (int i = 0; i < fCachedOldFrameVMCs.length; i++) update.setChild(fCachedOldFrameVMCs[i], i);
} else {
update.setChild(topFrameVmc, 0);
}
update.done();
}});
}
@Override
protected void fillColumnLabel(IDMContext<IFrameDMData> dmContext, IFrameDMData dmData, String columnId, int idx,
ILabelUpdate update)
{
if (idx != 0) return;
final IExecutionDMContext execDmc = findDmcInPath(update.getElementPath(), IExecutionDMContext.class);
IRunControl runControlService = getServicesTracker().getService(IRunControl.class);
IStepQueueManager stepQueueMgrService = getServicesTracker().getService(IStepQueueManager.class);
if (execDmc == null || runControlService == null || stepQueueMgrService == null) return;
String imageKey = null;
IRunControl rc = getServicesTracker().getService(IRunControl.class);
if (rc.isSuspended(execDmc) ||
(rc.isStepping(execDmc) && !getServicesTracker().getService(IStepQueueManager.class).isSteppingTimedOut(execDmc)))
if (runControlService.isSuspended(execDmc) ||
(runControlService.isStepping(execDmc) && !stepQueueMgrService.isSteppingTimedOut(execDmc)))
{
imageKey = IDebugUIConstants.IMG_OBJS_STACKFRAME;
} else {
imageKey = IDebugUIConstants.IMG_OBJS_STACKFRAME_RUNNING;
}
result.setImageDescriptors(new ImageDescriptor[] { DebugUITools.getImageDescriptor(imageKey) });
IFrameDMContext frameDmc = (IFrameDMContext)((DMContextVMContext)vmc).getDMC();
getServicesTracker().getService(IStack.class).getModelData(
frameDmc,
new GetDataDone<IFrameDMData>() { public void run() {
// Check if services are still available.
if (getServicesTracker().getService(IRunControl.class) == null) {
result.done();
return;
}
if (!getStatus().isOK()) {
// If failed set a dummy label, and only propagate the
// error if we are not stepping, since that would be a
// common cause of failure.
result.setLabels(new String[] { "..." }); //$NON-NLS-1$
if (!getServicesTracker().getService(IRunControl.class).isStepping(execDmc)) {
MultiStatus status = new MultiStatus(DsfDebugUIPlugin.PLUGIN_ID, 0, "Failed to retrieve stack frame label", null); //$NON-NLS-1$
status.add(getStatus());
result.setStatus(status);
}
result.done();
return;
}
update.setImageDescriptor(DebugUITools.getImageDescriptor(imageKey), 0);
//
// Finally, if all goes well, set the label.
@ -158,62 +159,92 @@ public class StackFramesLayoutNode extends DMContextVMLayoutNode<IStack.IFrameDM
StringBuilder label = new StringBuilder();
// Add frame number (if total number of frames in known)
if (fCachedOldFramesVMCs != null) {
label.append(fCachedOldFramesVMCs.length - getData().getLevel());
if (fCachedOldFrameVMCs != null) {
label.append(fCachedOldFrameVMCs.length - dmData.getLevel());
}
// Add the function name
if (getData().getFunction() != null && getData().getFunction().length() != 0) {
if (dmData.getFunction() != null && dmData.getFunction().length() != 0) {
label.append(" "); //$NON-NLS-1$
label.append(getData().getFunction());
label.append(dmData.getFunction());
label.append("()"); //$NON-NLS-1$
}
// Add full file name
if (getData().getFile() != null && getData().getFile().length() != 0) {
if (dmData.getFile() != null && dmData.getFile().length() != 0) {
label.append(" at "); //$NON-NLS-1$
label.append(getData().getFile());
label.append(dmData.getFile());
}
// Add line number
if (getData().getLine() >= 0) {
if (dmData.getLine() >= 0) {
label.append(":"); //$NON-NLS-1$
label.append(getData().getLine());
label.append(dmData.getLine());
label.append(" "); //$NON-NLS-1$
}
// Add the address
label.append(getData().getAddress());
label.append(dmData.getAddress());
// Set the label to the result listener
result.setLabels(new String[] { label.toString() });
result.done();
}});
update.setLabel(label.toString(), 0);
}
public boolean hasDeltaFlagsForDMEvent(IDMEvent<?> e) {
protected void handleFailedUpdate(IViewerUpdate update) {
if (update instanceof ILabelUpdate) {
// Avoid repainting the label if it's not available. This only slows
// down the display.
} else {
super.handleFailedUpdate(update);
}
}
@Override
protected int getNodeDeltaFlagsForDMEvent(org.eclipse.dd.dsf.datamodel.IDMEvent<?> e) {
// This node generates delta if the timers have changed, or if the
// label has changed.
return e instanceof IRunControl.ISuspendedDMEvent ||
e instanceof IRunControl.IResumedDMEvent ||
e instanceof IStepQueueManager.ISteppingTimedOutEvent ||
super.hasDeltaFlagsForDMEvent(e);
if (e instanceof IRunControl.ISuspendedDMEvent) {
return IModelDelta.CONTENT | IModelDelta.EXPAND | IModelDelta.SELECT;
} else if (e instanceof IRunControl.IResumedDMEvent) {
if (((IRunControl.IResumedDMEvent)e).getReason() == StateChangeReason.STEP) {
return IModelDelta.STATE;
} else {
return IModelDelta.CONTENT;
}
} else if (e instanceof IStepQueueManager.ISteppingTimedOutEvent) {
return IModelDelta.CONTENT;
}
return 0;
}
public void buildDeltaForDMEvent(final IDMEvent<?> e, final VMDelta parent, final Done done) {
if (getServicesTracker().getService(IStack.class) == null || getServicesTracker().getService(IRunControl.class) == null) {
@Override
protected void buildDeltaForDMEvent(final IDMEvent<?> e, final VMDelta parent, final int nodeOffset, final Done done) {
if (e instanceof IRunControl.ISuspendedDMEvent) {
buildDeltaForSuspendedEvent((IRunControl.ISuspendedDMEvent)e, parent, nodeOffset, done);
} else if (e instanceof IRunControl.IResumedDMEvent) {
buildDeltaForResumedEvent((IRunControl.IResumedDMEvent)e, parent, nodeOffset, done);
} else if (e instanceof IStepQueueManager.ISteppingTimedOutEvent) {
buildDeltaForSteppingTimedOutEvent((IStepQueueManager.ISteppingTimedOutEvent)e, parent, nodeOffset, done);
} else {
// Call super-class to build sub-node delta's.
super.buildDeltaForDMEvent(e, parent, nodeOffset, done);
}
}
private void buildDeltaForSuspendedEvent(final IRunControl.ISuspendedDMEvent e, final VMDelta parent, final int nodeOffset, final Done done) {
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, done);
super.buildDeltaForDMEvent(e, parent, nodeOffset, done);
return;
}
if (e instanceof IRunControl.ISuspendedDMEvent) {
IRunControl.ISuspendedDMEvent suspendedEvent = (IRunControl.ISuspendedDMEvent)e;
// Refresh the whole list of stack frames unless the target is already stepping the next command. In
// 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 (!getServicesTracker().getService(IRunControl.class).isStepping(suspendedEvent.getDMContext())) {
if (!runControlService.isStepping(e.getDMContext())) {
parent.addFlags(IModelDelta.CONTENT);
}
@ -222,51 +253,46 @@ public class StackFramesLayoutNode extends DMContextVMLayoutNode<IStack.IFrameDM
// Retrieve the list of stack frames, and mark the top frame to be selected.
getElementsTopStackFrameOnly(
parent.getVMC(),
new GetDataDone<IVMContext[]>() { public void run() {
if (getStatus().isOK() && getData().length != 0) {
parent.addNode( getData()[0], IModelDelta.SELECT | IModelDelta.STATE);
new ElementsUpdate(
new GetDataDone<List<Object>>() {
public void run() {
if (getStatus().isOK() && getData().size() != 0) {
parent.addNode( getData().get(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().length >= 2) {
parent.addNode( getData()[1], IModelDelta.STATE);
if (getData().size() >= 2) {
parent.addNode( getData().get(1), IModelDelta.STATE);
}
}
// Even in case of errors, call super-class to complete building of the delta.
StackFramesLayoutNode.super.buildDeltaForDMEvent(e, parent, done);
}});
} else if (e instanceof IRunControl.IResumedDMEvent) {
IRunControl.IResumedDMEvent resumedEvent = (IRunControl.IResumedDMEvent)e;
getExecutor().execute(done);
if (resumedEvent.getReason() == StateChangeReason.STEP) {
// TODO: Refreshing the state of the top stack frame is only necessary to re-enable the step button.
// This is because platform disables the step action every time after it is invoked. Need to file
// a bug on this.
getServicesTracker().getService(IStack.class).getTopFrame(
resumedEvent.getDMContext(),
new GetDataDone<IFrameDMContext>() { public void run() {
if (getStatus().isOK()) {
parent.addNode(new DMContextVMContext(parent.getVMC(), getData()), IModelDelta.STATE);
StackFramesLayoutNode.super.buildDeltaForDMEvent(e, parent, nodeOffset, done);
}
StackFramesLayoutNode.super.buildDeltaForDMEvent(e, parent, done);
}});
StackFramesLayoutNode.super.buildDeltaForDMEvent(e, parent, done);
} else {
},
parent)
);
}
private void buildDeltaForResumedEvent(final IRunControl.IResumedDMEvent e, final VMDelta parent, final int nodeOffset, final Done done) {
IStack stackService = getServicesTracker().getService(IStack.class);
if (stackService == null) {
// Required services have not initialized yet. Ignore the event.
super.buildDeltaForDMEvent(e, parent, nodeOffset, done);
return;
}
IRunControl.IResumedDMEvent resumedEvent = (IRunControl.IResumedDMEvent)e;
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);
fCachedOldFramesVMCs = null;
// Call super-class to build sub-node delta's.
super.buildDeltaForDMEvent(e, parent, done);
fCachedOldFrameVMCs = null;
}
} else if (e instanceof IStepQueueManager.ISteppingTimedOutEvent) {
super.buildDeltaForDMEvent(e, parent, nodeOffset, done);
}
private void buildDeltaForSteppingTimedOutEvent(final IStepQueueManager.ISteppingTimedOutEvent e, final VMDelta parent, final int nodeOffset, final Done done) {
// Repaint the stack frame images to have the running symbol.
parent.addFlags(IModelDelta.CONTENT);
super.buildDeltaForDMEvent(e, parent, done);
} else {
// Call super-class to build sub-node delta's.
super.buildDeltaForDMEvent(e, parent, done);
}
super.buildDeltaForDMEvent(e, parent, nodeOffset, done);
}
}

View file

@ -10,20 +10,24 @@
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.launch;
import org.eclipse.dd.dsf.concurrent.DoneCollector;
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.eclipse.dd.dsf.concurrent.Done;
import org.eclipse.dd.dsf.concurrent.GetDataDone;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMRootLayoutNode;
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.VMDelta;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
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.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
/**
* Layout node for the standard ILaunch object. This node can only be used at
@ -34,34 +38,29 @@ import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta;
public class StandardLaunchRootLayoutNode extends AbstractVMRootLayoutNode
implements IVMRootLayoutNode
{
final private RootVMC<ILaunch> fRootVMC;
final IVMContext[] fElements;
final private ILaunch fLaunch;
public StandardLaunchRootLayoutNode(DsfExecutor executor, ILaunch launch) {
super(executor);
fRootVMC = new RootVMC<ILaunch>(this, launch);
fElements = new IVMContext[] { fRootVMC };
public StandardLaunchRootLayoutNode(AbstractVMProvider provider, ILaunch launch) {
super(provider);
fLaunch = launch;
}
@Override
public boolean hasDeltaFlags(Object e) {
/*
* Launch deltas for standard platform DebugEvent events are handled by
* org.eclipse.debug.internal.ui.viewers.update.LaunchManagerProxy.
* Here only control the deltas of child nodes. This is necessary to avoid
* IProcess layout node from processing events that are intended for a
* different launch. This is not a problem with DMC events, because the
* full path of the DMC object is built into the DMC itself.
*/
public int getDeltaFlags(Object e) {
if (e instanceof DebugEvent) {
DebugEvent de = (DebugEvent)e;
if (de.getSource() instanceof IProcess) {
return ((IProcess)de.getSource()).getLaunch().equals(getRootVMC().getInputObject()) && super.hasDeltaFlags(e);
} else if (de.getSource() instanceof IDebugElement) {
return ((IDebugElement)de.getSource()).getLaunch().equals(getRootVMC().getInputObject()) && super.hasDeltaFlags(e);
if (de.getSource() instanceof IProcess &&
!((IProcess)de.getSource()).getLaunch().equals(fLaunch) )
{
return IModelDelta.NO_CHANGE;
}
else if (de.getSource() instanceof IDebugElement &&
!((IDebugElement)de.getSource()).getLaunch().equals(fLaunch) )
{
return IModelDelta.NO_CHANGE;
}
}
return super.hasDeltaFlags(e);
return super.getDeltaFlags(e);
}
public void createDelta(Object event, final GetDataDone<IModelDelta> done) {
@ -70,34 +69,26 @@ public class StandardLaunchRootLayoutNode extends AbstractVMRootLayoutNode
* root of the view, create the delta with the path to the launch, then
* pass that to the child layout nodes.
*/
final VMDelta delta = new VMDelta(DebugPlugin.getDefault().getLaunchManager(), null);
done.setData(delta);
final VMDelta rootDelta = delta.addNode(getRootVMC().getInputObject(), getRootVMC());
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 IVMLayoutNode[] childNodes = getChildNodesWithDeltas(event);
if (childNodes.length == 0) {
done.setData(delta);
getExecutor().execute(done);
return;
}
final Map<IVMLayoutNode,Integer> childNodeDeltas = getChildNodesWithDeltas(event);
assert childNodeDeltas.size() != 0 : "Caller should make sure that there are deltas for given event."; //$NON-NLS-1$
/*
* The execution for this node is not done until all the child nodes
* are done. Use the tracker to wait for all children to complete.
*/
final DoneCollector doneCollector = new DoneCollector(getExecutor()) {
callChildNodesToBuildDelta(
childNodeDeltas, rootDelta, event,
new Done() {
public void run() {
if (propagateError(getExecutor(), done, "Failed to generate child deltas.")) return; //$NON-NLS-1$
done.setData(delta);
if (propagateError(getExecutor(), done, "Failed to create delta.")); //$NON-NLS-1$
done.setData(viewRootDelta);
getExecutor().execute(done);
}
};
for (final IVMLayoutNode childNode : childNodes) {
childNode.buildDelta(event, rootDelta, doneCollector.addNoActionDone());
}
});
}
public IRootVMC getRootVMC() {
return fRootVMC;
public Object getRootObject() {
return fLaunch;
}
}

View file

@ -10,25 +10,23 @@
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.launch;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.dd.dsf.concurrent.Done;
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
import org.eclipse.dd.dsf.concurrent.GetDataDone;
import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin;
import org.eclipse.dd.dsf.service.IDsfService;
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.dd.dsf.ui.viewmodel.IVMRootLayoutNode.IRootVMC;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.debug.core.model.IStreamsProxy;
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.provisional.ILabelRequestMonitor;
import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta;
import org.eclipse.jface.viewers.TreePath;
/**
* Layout node for the standard platform debug model IProcess object. This
@ -43,19 +41,20 @@ public class StandardProcessLayoutNode extends AbstractVMLayoutNode {
* VMC element implementation, it is a proxy for the IProcess class, to
* allow the standard label adapter to be used with this object.
*/
private class VMC implements IVMContext, IProcess
private class VMC extends AbstractVMContext
implements IProcess
{
private final IVMContext fParentVmc;
private final IProcess fProcess;
VMC(IVMContext parentVmc, IProcess process) {
fParentVmc = parentVmc;
VMC(IProcess process) {
super(getVMProvider().getVMAdapter(), StandardProcessLayoutNode.this);
fProcess = process;
}
public IVMContext getParent() { return fParentVmc; }
public IVMLayoutNode getLayoutNode() { return StandardProcessLayoutNode.this; }
@SuppressWarnings("unchecked") public Object getAdapter(Class adapter) { return fProcess.getAdapter(adapter); }
@SuppressWarnings("unchecked") public Object getAdapter(Class adapter) {
return fProcess.getAdapter(adapter);
}
public String toString() { return "IProcess " + fProcess.toString(); } //$NON-NLS-1$
public String getAttribute(String key) { return fProcess.getAttribute(key); }
@ -72,21 +71,17 @@ public class StandardProcessLayoutNode extends AbstractVMLayoutNode {
public int hashCode() { return fProcess.hashCode(); }
}
public StandardProcessLayoutNode(DsfExecutor executor) {
super(executor);
public StandardProcessLayoutNode(AbstractVMProvider provider) {
super(provider);
}
// @see org.eclipse.dd.dsf.ui.viewmodel.IViewModelLayoutNode#getElements(org.eclipse.dd.dsf.ui.viewmodel.IVMContext, org.eclipse.dd.dsf.concurrent.GetDataDone)
public void getElements(IVMContext parentVmc, GetDataDone<IVMContext[]> done) {
ILaunch launch = findLaunch(parentVmc);
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.
*/
// There is no launch in the parent of this node. This means that the
// layout is misconfigured.
assert false;
done.setStatus(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, "Can't get list of processes, because there is no launch.", null)); //$NON-NLS-1$
getExecutor().execute(done);
update.done();
return;
}
@ -95,30 +90,43 @@ public class StandardProcessLayoutNode extends AbstractVMLayoutNode {
* retrieve them on dispatch thread.
*/
IProcess[] processes = launch.getProcesses();
IVMContext[] processVmcs = new IVMContext[processes.length];
for (int i = 0; i < processes.length; i++) {
processVmcs[i] = new VMC(parentVmc, processes[i]);
update.setChild(new VMC(processes[i]), i);
}
done.setData(processVmcs);
getExecutor().execute(done);
update.done();
}
// @see org.eclipse.dd.dsf.ui.viewmodel.IViewModelLayoutNode#hasElements(org.eclipse.dd.dsf.ui.viewmodel.IVMContext, org.eclipse.dd.dsf.concurrent.GetDataDone)
public void hasElements(IVMContext parentVmc, GetDataDone<Boolean> done) {
ILaunch launch = findLaunch(parentVmc);
public void updateElementCount(IChildrenCountUpdate update) {
ILaunch launch = findLaunch(update.getElementPath());
if (launch == null) {
assert false;
done.setStatus(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, "Can't get list of processes, because there is no launch.", null)); //$NON-NLS-1$
getExecutor().execute(done);
update.setChildCount(0);
update.done();
return;
}
done.setData(launch.getProcesses().length != 0);
getExecutor().execute(done);
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.GetDataDone)
public void updateHasElements(IHasChildrenUpdate[] updates) {
for (IHasChildrenUpdate update : updates) {
ILaunch launch = findLaunch(update.getElementPath());
if (launch == null) {
assert false;
update.setHasChilren(false);
update.done();
return;
}
update.setHasChilren(launch.getProcesses().length != 0);
update.done();
}
}
// @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 retrieveLabel(IVMContext vmc, ILabelRequestMonitor result, String[] columns) {
public void updateLabel(IVMContext vmc, ILabelRequestMonitor result, String[] columns) {
/*
* The implementation of IAdapterFactory that uses this node should not
@ -134,30 +142,33 @@ public class StandardProcessLayoutNode extends AbstractVMLayoutNode {
* Recursively searches the VMC for Launch VMC, and returns its ILaunch.
* Returns null if an ILaunch is not found.
*/
private ILaunch findLaunch(IVMContext vmc) {
if (vmc == null) {
return null;
} else if (vmc instanceof IRootVMC || ((IRootVMC)vmc).getInputObject() instanceof ILaunch) {
return (ILaunch)(((IRootVMC)vmc)).getInputObject();
} else {
return findLaunch(vmc.getParent());
private ILaunch findLaunch(TreePath path) {
for (int i = path.getSegmentCount() - 1; i >= 0; i--) {
if (path.getSegment(i) instanceof ILaunch) {
return (ILaunch)path.getSegment(i);
}
}
return null;
}
@Override
public boolean hasDeltaFlags(Object e) {
public int getDeltaFlags(Object e) {
int myFlags = 0;
if (e instanceof DebugEvent) {
DebugEvent de = (DebugEvent)e;
return de.getSource() instanceof IProcess &&
if ( de.getSource() instanceof IProcess &&
(de.getKind() == DebugEvent.CHANGE ||
de.getKind() == DebugEvent.CREATE ||
de.getKind() == DebugEvent.TERMINATE);
de.getKind() == DebugEvent.TERMINATE) )
{
myFlags = IModelDelta.STATE;
}
return super.hasDeltaFlags(e);
}
return myFlags | super.getDeltaFlags(e);
}
@Override
public void buildDelta(Object e, VMDelta parent, Done done) {
public void buildDelta(Object e, VMDelta parent, int nodeOffset, Done done) {
if (e instanceof DebugEvent && ((DebugEvent)e).getSource() instanceof IProcess) {
DebugEvent de = (DebugEvent)e;
if (de.getKind() == DebugEvent.CHANGE) {
@ -173,12 +184,12 @@ public class StandardProcessLayoutNode extends AbstractVMLayoutNode {
*/
getExecutor().execute(done);
} else {
super.buildDelta(e, parent, done);
super.buildDelta(e, parent, nodeOffset, done);
}
}
protected void handleChange(DebugEvent event, VMDelta parent) {
parent.addNode(new VMC(parent.getVMC(), (IProcess)event.getSource()), IModelDelta.STATE);
parent.addNode(new VMC((IProcess)event.getSource()), IModelDelta.STATE);
}
protected void handleCreate(DebugEvent event, VMDelta parent) {

View file

@ -11,8 +11,8 @@
package org.eclipse.dd.dsf.debug.ui.viewmodel.register;
import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin;
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation;
import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.jface.resource.ImageDescriptor;
/**

View file

@ -10,84 +10,58 @@
*******************************************************************************/
package org.eclipse.dd.dsf.debug.ui.viewmodel.register;
import org.eclipse.dd.dsf.concurrent.Done;
import org.eclipse.dd.dsf.concurrent.GetDataDone;
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.IRegisters.IRegisterGroupDMContext;
import org.eclipse.dd.dsf.debug.service.IRegisters.IRegisterGroupData;
import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.ui.viewmodel.DMContextVMLayoutNode;
import org.eclipse.dd.dsf.ui.viewmodel.IVMContext;
import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
@SuppressWarnings("restriction")
public class RegisterGroupLayoutNode extends DMContextVMLayoutNode<IRegisterGroupData> {
public class RegisterGroupLayoutNode extends AbstractDMVMLayoutNode<IRegisterGroupData> {
public RegisterGroupLayoutNode(DsfSession session) {
super(session, IRegisters.IRegisterGroupDMContext.class);
public RegisterGroupLayoutNode(AbstractVMProvider provider, DsfSession session) {
super(provider, session, IRegisters.IRegisterGroupDMContext.class);
}
public void hasElements( final IVMContext parentVmc , final GetDataDone<Boolean> done ) {
final IExecutionDMContext execDmc = findDmcInVmc(parentVmc, IExecutionDMContext.class);
@Override
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
if (!checkService(IRegisters.class, null, update)) return;
if (execDmc == null || getServicesTracker().getService(IRegisters.class) == null) {
done.setData(Boolean.FALSE);
getExecutor().execute(done);
return;
}
final IExecutionDMContext execDmc = findDmcInPath(update.getElementPath(), IExecutionDMContext.class) ;
if (execDmc != null) {
getServicesTracker().getService(IRegisters.class).getRegisterGroups(
execDmc, null,
new GetDataDone<IRegisterGroupDMContext[]>() { public void run() {
if (propagateError(getExecutor(), done, "Failed to retrieve register groups")) return; //$NON-NLS-1$
done.setData(getData().length != 0);
getExecutor().execute(done);
}});
}
public void getElements( final IVMContext parentVmc, final GetDataDone<IVMContext[]> done ) {
final IExecutionDMContext execDmc = findDmcInVmc(parentVmc, IExecutionDMContext.class) ;
if ( execDmc == null || getServicesTracker().getService( IRegisters.class ) == null ) {
done.setData(new IVMContext[0]);
getExecutor().execute( done );
if (!getStatus().isOK()) {
update.done();
return;
}
getServicesTracker().getService(IRegisters.class).getRegisterGroups(
execDmc, null,
new GetDataDone<IRegisterGroupDMContext[]>() { public void run() {
if (propagateError(getExecutor(), done, "Failed to retrieve register groups")) return; //$NON-NLS-1$
done.setData(dmcs2vmcs(parentVmc, getData()));
getExecutor().execute(done);
fillUpdateWithVMCs(update, getData());
update.done();
}});
} else {
handleFailedUpdate(update);
}
}
@Override
protected void fillColumnLabel(IDMContext<IRegisterGroupData> dmContext, IRegisterGroupData dmData,
String columnId, int idx, String[] text, ImageDescriptor[] image,
FontData[] fontData, RGB[] foreground, RGB[] background)
String columnId, int idx, ILabelUpdate update)
{
if (RegisterColumnPresentation.COL_NAME.equals(columnId)) {
text[idx] = dmData.getName();
update.setLabel(dmData.getName(), idx);
} else if (RegisterColumnPresentation.COL_VALUE.equals(columnId)) {
text[idx] = ""; //$NON-NLS-1$
update.setLabel("", idx); //$NON-NLS-1$
} else if (RegisterColumnPresentation.COL_DESCRIPTION.equals(columnId)) {
text[idx] = dmData.getDescription();
update.setLabel(dmData.getDescription(), idx);
}
}
public boolean hasDeltaFlagsForDMEvent(IDMEvent<?> e) {
return super.hasDeltaFlagsForDMEvent(e);
}
public void buildDeltaForDMEvent(final IDMEvent<?> e, final VMDelta parent, final Done done) {
super.buildDeltaForDMEvent(e, parent, done);
}
}

View file

@ -12,6 +12,7 @@ package org.eclipse.dd.dsf.debug.ui.viewmodel.register;
import org.eclipse.dd.dsf.concurrent.Done;
import org.eclipse.dd.dsf.concurrent.GetDataDone;
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;
@ -19,79 +20,56 @@ import org.eclipse.dd.dsf.debug.service.IRegisters.IRegisterDMContext;
import org.eclipse.dd.dsf.debug.service.IRegisters.IRegisterDMData;
import org.eclipse.dd.dsf.debug.service.IRegisters.IRegisterGroupDMContext;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.service.IDsfService;
import org.eclipse.dd.dsf.ui.viewmodel.DMContextVMLayoutNode;
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.debug.internal.ui.viewers.provisional.ILabelRequestMonitor;
import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
@SuppressWarnings("restriction")
public class RegisterLayoutNode extends DMContextVMLayoutNode<IRegisterDMData> {
public class RegisterLayoutNode extends AbstractDMVMLayoutNode<IRegisterDMData> {
public IVMContext[] fCachedRegisterVMCs;
public RegisterLayoutNode(DsfSession session) {
super(session, IRegisters.IRegisterDMContext.class);
public RegisterLayoutNode(AbstractVMProvider provider, DsfSession session) {
super(provider, session, IRegisters.IRegisterDMContext.class);
}
public void hasElements( final IVMContext parentVmc , final GetDataDone<Boolean> done ) {
final IRegisterGroupDMContext registerGroupDmc = findDmcInVmc(parentVmc, IRegisterGroupDMContext.class);
@Override
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
final IRegisterGroupDMContext execDmc = findDmcInPath(update.getElementPath(), IRegisterGroupDMContext.class);
if (registerGroupDmc == null || getServicesTracker().getService(IRegisters.class) == null) {
done.setData(Boolean.FALSE);
getExecutor().execute(done);
if (execDmc == null) {
handleFailedUpdate(update);
return;
}
getServicesTracker().getService( IRegisters.class ).getRegisters(
registerGroupDmc,
getServicesTracker().getService(IRegisters.class).getRegisters(
execDmc,
new GetDataDone<IRegisterDMContext[]>() {
public void run() {
if (propagateError(getExecutor(), done, "Failed to retrieve registers")) return; //$NON-NLS-1$
done.setData(getData().length != 0);
getExecutor().execute(done);
if (!getStatus().isOK()) {
handleFailedUpdate(update);
}
fillUpdateWithVMCs(update, getData());
update.done();
}
});
}
public void getElements( final IVMContext parentVmc , final GetDataDone<IVMContext[]> done ) {
final IRegisterGroupDMContext execDmc = findDmcInVmc(parentVmc, IRegisterGroupDMContext.class);
if (execDmc == null || getServicesTracker().getService(IRegisters.class) == null) {
getExecutor().execute(done);
return;
}
getServicesTracker().getService( IRegisters.class ).getRegisters(
execDmc,
new GetDataDone<IRegisterDMContext[]>() { public void run() {
if (propagateError(getExecutor(), done, "Failed to retrieve registers")) return; //$NON-NLS-1$
done.setData( dmcs2vmcs( parentVmc, getData()) );
getExecutor().execute(done);
}});
}
public void retrieveLabel(final IVMContext vmc , final ILabelRequestMonitor result, String[] columns) {
if ( getServicesTracker().getService( IRegisters.class ) == null ) {
result.done();
return;
}
final IRegisterDMContext registerDmc = (IRegisterDMContext) ( (DMContextVMContext) vmc ).getDMC() ;
getServicesTracker().getService( IRegisters.class ).getModelData(
registerDmc ,
new GetDataDone<IRegisterDMData>() {
public void run() {
if ( !getStatus().isOK() ) {
assert getStatus().getCode() == IDsfService.INVALID_STATE || getStatus().getCode() == IDsfService.INVALID_HANDLE : getStatus().toString();
// Some error conditions are expected.
result.setLabels( new String[] { "...", "...", "..." } ) ; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
} else {
String size = getData().getDescription();
String value = getData().getHexValue();
@Override
protected void fillColumnLabel(IDMContext<IRegisterDMData> dmContext, IRegisterDMData dmData, String columnId,
int idx, ILabelUpdate update)
{
if (RegisterColumnPresentation.COL_NAME.equals(columnId)) {
update.setLabel(dmData.getName(), idx);
} else if (RegisterColumnPresentation.COL_VALUE.equals(columnId)) {
update.setLabel(dmData.getHexValue(), idx);
} else if (RegisterColumnPresentation.COL_DESCRIPTION.equals(columnId)) {
String size = dmData.getDescription();
String value = dmData.getHexValue();
if ("".equals(size)) { //$NON-NLS-1$
if ( value.contains( "uint64" ) ) { //$NON-NLS-1$
size = "64 bit register" ; //$NON-NLS-1$
@ -99,32 +77,29 @@ public class RegisterLayoutNode extends DMContextVMLayoutNode<IRegisterDMData> {
size = "128 bit register" ; //$NON-NLS-1$
}
}
result.setLabels(new String[] { getData().getName(), getData().getHexValue(), size });
update.setLabel(size, idx);
}
}
result.done() ;
return ;
@Override
protected int getNodeDeltaFlagsForDMEvent(IDMEvent<?> e) {
if (e instanceof IRunControl.ISuspendedDMEvent) {
return IModelDelta.CONTENT;
} else if (e instanceof IRegisters.IRegisterChangedDMEvent) {
return IModelDelta.STATE;
}
}
) ;
return IModelDelta.NO_CHANGE;
}
public boolean hasDeltaFlagsForDMEvent( IDMEvent<?> e ) {
return (e instanceof IRunControl.ISuspendedDMEvent) || super.hasDeltaFlagsForDMEvent(e) ;
}
public void buildDeltaForDMEvent( final IDMEvent<?> e, final VMDelta parent, final Done done ) {
@Override
protected void buildDeltaForDMEvent(IDMEvent<?> e, VMDelta parent, int nodeOffset, Done done) {
if (e instanceof IRunControl.ISuspendedDMEvent) {
// Create a delta that the whole register group has changed.
parent.addFlags(IModelDelta.CONTENT);
}
if (e instanceof IRegisters.IRegisterChangedDMEvent) {
parent.addNode(
new DMContextVMContext(parent.getVMC(), ((IRegisters.IRegisterChangedDMEvent)e).getDMContext()),
IModelDelta.STATE);
parent.addNode( new DMVMContext(((IRegisters.IRegisterChangedDMEvent)e).getDMContext()), IModelDelta.STATE );
}
super.buildDeltaForDMEvent(e, parent, done);
super.buildDeltaForDMEvent(e, parent, nodeOffset, done);
}
}

View file

@ -12,35 +12,35 @@ package org.eclipse.dd.dsf.debug.ui.viewmodel.register;
import org.eclipse.dd.dsf.debug.ui.viewmodel.DebugViewSelectionRootLayoutNode;
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.VMProvider;
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation;
import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
/**
*
*/
@SuppressWarnings("restriction")
public class RegisterVMProvider extends VMProvider {
public RegisterVMProvider(DsfSession session, IPresentationContext context) {
super(session, null);
IVMRootLayoutNode debugViewSelection = new DebugViewSelectionRootLayoutNode(
getSession().getExecutor(), context.getPart().getSite().getWorkbenchWindow() );
IVMLayoutNode registerGroupNode = new RegisterGroupLayoutNode(getSession());
public class RegisterVMProvider extends AbstractDMVMProvider {
public RegisterVMProvider(AbstractVMAdapter adapter, IPresentationContext context, DsfSession session) {
super(adapter, context, session);
IVMRootLayoutNode debugViewSelection = new DebugViewSelectionRootLayoutNode(this);
IVMLayoutNode registerGroupNode = new RegisterGroupLayoutNode(this, getSession());
debugViewSelection.setChildNodes(new IVMLayoutNode[] { registerGroupNode });
IVMLayoutNode registerNode = new RegisterLayoutNode(getSession());
IVMLayoutNode registerNode = new RegisterLayoutNode(this, getSession());
registerGroupNode.setChildNodes(new IVMLayoutNode[] { registerNode });
setRootLayoutNode(debugViewSelection);
}
@Override
public IColumnPresentation createColumnPresentation(Object element) {
public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) {
return new RegisterColumnPresentation();
}
@Override
public String getColumnPresentationId(Object element) {
public String getColumnPresentationId(IPresentationContext context, Object element) {
return RegisterColumnPresentation.ID;
}
}

View file

@ -11,5 +11,6 @@ Require-Bundle: org.eclipse.ui,
org.eclipse.dd.dsf,
org.eclipse.debug.ui
Eclipse-LazyStart: true
Export-Package: org.eclipse.dd.dsf.ui.viewmodel
Export-Package: org.eclipse.dd.dsf.ui.viewmodel,
org.eclipse.dd.dsf.ui.viewmodel.dm
Bundle-RequiredExecutionEnvironment: J2SE-1.5

View file

@ -13,46 +13,39 @@ package org.eclipse.dd.dsf.ui.viewmodel;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionException;
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.DefaultDsfExecutor;
import org.eclipse.dd.dsf.concurrent.DsfRunnable;
import org.eclipse.dd.dsf.concurrent.ThreadSafe;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.service.IDsfService;
import org.eclipse.dd.dsf.ui.DsfUIPlugin;
import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousContentAdapter;
import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousLabelAdapter;
import org.eclipse.debug.internal.ui.viewers.provisional.IChildrenRequestMonitor;
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditor;
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditorFactoryAdapter;
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation;
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentationFactoryAdapter;
import org.eclipse.debug.internal.ui.viewers.provisional.IContainerRequestMonitor;
import org.eclipse.debug.internal.ui.viewers.provisional.ILabelRequestMonitor;
import org.eclipse.debug.internal.ui.viewers.provisional.IModelProxy;
import org.eclipse.debug.internal.ui.viewers.provisional.IModelProxyFactoryAdapter;
import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
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.IHasChildrenUpdate;
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;
/**
* Base implementation for DSF-based view model adapters.
* Base implementation for View Model Adapters. The implementation uses
* its own single-thread executor for communicating with providers and
* layout nodes.
*/
@ThreadSafe
@SuppressWarnings("restriction")
abstract public class AbstractVMAdapter
implements IAsynchronousLabelAdapter,
IAsynchronousContentAdapter,
IModelProxyFactoryAdapter,
IColumnPresentationFactoryAdapter,
IColumnEditorFactoryAdapter
abstract public class AbstractVMAdapter implements IVMAdapter
{
private final DsfSession fSession;
private final ExecutorService fExecutor;
private boolean fDisposed;
@ConfinedToDsfExecutor("getSession().getExecutor()")
private final Map<IPresentationContext, VMProvider> fViewModelProviders =
Collections.synchronizedMap( new HashMap<IPresentationContext, VMProvider>() );
private final Map<IPresentationContext, IVMProvider> fViewModelProviders =
Collections.synchronizedMap( new HashMap<IPresentationContext, IVMProvider>() );
/**
* Constructor for the View Model session. It is tempting to have the
@ -62,21 +55,32 @@ abstract public class AbstractVMAdapter
* to have the owner of this object register it with the session.
* @param session
*/
public AbstractVMAdapter(DsfSession session) {
fSession = session;
public AbstractVMAdapter() {
fExecutor = new DefaultDsfExecutor();
}
@ThreadSafe
abstract protected VMProvider createViewModelProvider(IPresentationContext context);
/**
* Returns the executor that will be used to communicate with the providers
* and the layout nodes.
* @return
*/
public Executor getExecutor() {
return fExecutor;
}
protected DsfSession getSession() { return fSession; }
/**
* Creates a new View Model Provider for given presentation context. Returns null
* if the presentation context is not supported.
*/
@ThreadSafe
abstract protected IVMProvider createViewModelProvider(IPresentationContext context);
@ThreadSafe
private VMProvider getViewModelProvider(IPresentationContext context) {
assert DsfSession.isSessionActive(getSession().getId());
private IVMProvider getViewModelProvider(IPresentationContext context) {
synchronized(fViewModelProviders) {
VMProvider provider = fViewModelProviders.get(context);
if (fDisposed) return null;
IVMProvider provider = fViewModelProviders.get(context);
if (provider == null) {
provider = createViewModelProvider(context);
if (provider != null) {
@ -87,129 +91,113 @@ abstract public class AbstractVMAdapter
}
}
@ConfinedToDsfExecutor("getSession().getExecutor()")
public void install(IPresentationContext context) {
}
@ConfinedToDsfExecutor("getSession().getExecutor()")
public void dispose() {
assert getSession().getExecutor().isInExecutorThread();
for (VMProvider provider : fViewModelProviders.values()) {
// Execute the shutdown in adapter's dispatch thread.
getExecutor().execute(new DsfRunnable() {
public void run() {
synchronized(fViewModelProviders) {
fDisposed = true;
for (IVMProvider provider : fViewModelProviders.values()) {
provider.dispose();
}
fViewModelProviders.clear();
}
fExecutor.shutdown();
}
});
}
public void retrieveLabel(final Object object, final IPresentationContext context, final ILabelRequestMonitor result) {
public void update(IHasChildrenUpdate[] updates) {
handleUpdates(updates);
}
public void update(IChildrenCountUpdate[] updates) {
handleUpdates(updates);
}
public void update(final IChildrenUpdate[] updates) {
handleUpdates(updates);
}
private void handleUpdates(final IViewerUpdate[] updates) {
try {
getSession().getExecutor().execute(new DsfRunnable() {
getExecutor().execute(new DsfRunnable() {
public void run() {
if (result.isCanceled()) return;
VMProvider provider = getViewModelProvider(context);
if (provider == null) {
result.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, "No model provider for object: " + object.toString(), null)); //$NON-NLS-1$
result.done();
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);
}
provider.retrieveLabel(object, result, context.getColumns());
context = updates[curIdx].getPresentationContext();
firstIdx = curIdx;
}
}
callProviderWithUpdate(updates, firstIdx, curIdx);
}
@Override
public String toString() { return "Switch to dispatch thread to execute retrieveLabel()"; } //$NON-NLS-1$
});
} catch(RejectedExecutionException e) {
// This can happen if session is being shut down.
result.done();
}
}
public void isContainer(final Object element, final IPresentationContext context, final IContainerRequestMonitor result) {
try {
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
if (result.isCanceled()) return;
VMProvider provider = getViewModelProvider(context);
private void callProviderWithUpdate(IViewerUpdate[] updates, int startIdx, int endIdx) {
final IVMProvider provider = getViewModelProvider(updates[0].getPresentationContext());
if (provider == null) {
result.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, "No model provider for object: " + element.toString(), null)); //$NON-NLS-1$
result.done();
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();
}
provider.isContainer(element, result);
return;
}
public String toString() { return "Switch to dispatch thread to execute isContainer()"; } //$NON-NLS-1$
});
} catch(RejectedExecutionException e) {
// This can happen if session is being shut down.
result.done();
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);
}
public void retrieveChildren(final Object element, final IPresentationContext context, final IChildrenRequestMonitor result) {
try {
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
if (result.isCanceled()) return;
VMProvider provider = getViewModelProvider(context);
if (provider == null) {
result.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, "No model provider for object: " + element.toString(), null)); //$NON-NLS-1$
result.done();
else if (updates instanceof IChildrenUpdate[]) {
IChildrenUpdate[] providerUpdates = new IChildrenUpdate[endIdx - startIdx];
System.arraycopy(updates, startIdx, providerUpdates, 0, endIdx - startIdx);
provider.update(providerUpdates);
}
provider.retrieveChildren(element, result);
}
public String toString() { return "Switch to dispatch thread to execute retrieveChildren()"; } //$NON-NLS-1$
});
} catch(RejectedExecutionException e) {
// This can happen if session is being shut down.
result.done();
}
}
public IModelProxy 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. We only need to
* create a proxy for the root element of the tree.
*/
VMProvider provider = getViewModelProvider(context);
if (provider != null &&
provider.getRootLayoutNode() != null &&
element.equals(provider.getRootLayoutNode().getRootVMC().getInputObject()))
{
return provider.getModelProxy();
}
return null;
}
public String getColumnPresentationId(IPresentationContext context, Object element) {
VMProvider provider = getViewModelProvider(context);
IVMProvider provider = getViewModelProvider(context);
if (provider != null) {
return provider.getColumnPresentationId(element);
return provider.createModelProxy(element, context);
}
return null;
}
public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) {
VMProvider provider = getViewModelProvider(context);
final IVMProvider provider = getViewModelProvider(context);
if (provider != null) {
return provider.createColumnPresentation(element);
return provider.createColumnPresentation(context, element);
}
return null;
}
public IColumnEditor createColumnEditor(IPresentationContext context, Object element) {
VMProvider provider = getViewModelProvider(context);
public String getColumnPresentationId(IPresentationContext context, Object element) {
final IVMProvider provider = getViewModelProvider(context);
if (provider != null) {
return provider.createColumnEditor(element);
return provider.getColumnPresentationId(context, element);
}
return null;
}
public String getColumnEditorId(IPresentationContext context, Object element) {
VMProvider provider = getViewModelProvider(context);
if (provider != null) {
return provider.getColumnEditorId(element);
}
return null;
}
}

View file

@ -11,39 +11,57 @@
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.Executor;
import java.util.concurrent.RejectedExecutionException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.dd.dsf.concurrent.Done;
import org.eclipse.dd.dsf.concurrent.DoneCollector;
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
import org.eclipse.dd.dsf.concurrent.GetDataDone;
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditor;
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditorFactoryAdapter;
import org.eclipse.debug.internal.ui.viewers.provisional.ILabelRequestMonitor;
import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
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.IColumnPresentationFactoryAdapter;
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.IModelProxyFactoryAdapter;
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 DsfExecutor fExecutor;
private final AbstractVMProvider fProvider;
private boolean fDisposed = false;
/** Child schema nodes of this node. */
private IVMLayoutNode[] fChildNodes = new IVMLayoutNode[0];
public AbstractVMLayoutNode(DsfExecutor executor) {
fExecutor = executor;
public AbstractVMLayoutNode(AbstractVMProvider provider) {
fProvider = provider;
}
/**
* Accessor method for sub-classes.
*/
protected DsfExecutor getExecutor() {
return fExecutor;
protected Executor getExecutor() {
return fProvider.getExecutor();
}
protected IVMProvider getVMProvider() {
return fProvider;
}
public void setChildNodes(IVMLayoutNode[] childNodes) {
@ -55,6 +73,7 @@ abstract public class AbstractVMLayoutNode implements IVMLayoutNode {
}
public void dispose() {
fDisposed = true;
for (IVMLayoutNode childNode : getChildLayoutNodes()) {
childNode.dispose();
}
@ -64,11 +83,12 @@ abstract public class AbstractVMLayoutNode implements IVMLayoutNode {
* If any of the children nodes have delta flags, that means that this
* node has to generate a delta as well.
*/
public boolean hasDeltaFlags(Object e) {
public int getDeltaFlags(Object e) {
int retVal = 0;
for (IVMLayoutNode childNode : getChildLayoutNodes()) {
if (childNode.hasDeltaFlags(e)) return true;
retVal |= childNode.getDeltaFlags(e);
}
return false;
return retVal;
}
/**
@ -76,72 +96,159 @@ abstract public class AbstractVMLayoutNode implements IVMLayoutNode {
* schema nodes have deltas, this schema node has to provide the
* IModelDelta objects that the child shema node can build on.
*/
public void buildDelta(final Object e, final VMDelta parent, final Done done) {
/*
* Find the child nodes that have deltas for the given event. If no
* child layout nodes have deltas, just invoke the done.
*/
final IVMLayoutNode[] childNodes = getChildNodesWithDeltas(e);
if (childNodes.length == 0) {
public void buildDelta(final Object event, final VMDelta parentDelta, final int nodeOffset, final Done done) {
// Find the child nodes that have deltas for the given event.
final Map<IVMLayoutNode,Integer> childNodeDeltas = getChildNodesWithDeltas(event);
// If no child layout nodes have deltas we can stop here.
if (childNodeDeltas.size() == 0) {
getExecutor().execute(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 : childNodeDeltas.values()) {
if ((childDelta & ~IModelDelta.CONTENT & ~IModelDelta.STATE) != 0) {
mustGetElements = true;
}
}
/*
* 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.
*/
getElements(
parent.getVMC(),
new GetDataDone<IVMContext[]>() {
if (!mustGetElements) {
callChildNodesToBuildDelta(childNodeDeltas, parentDelta, event, done);
} 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 GetDataDone<List<Object>>() {
public void run() {
if (propagateError(getExecutor(), done, "Failed to retrieve elements in layout node " + AbstractVMLayoutNode.this)) return; //$NON-NLS-1$
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.
*/
if (getData().length == 0) {
// 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) {
getExecutor().execute(done);
return;
}
/*
* The execution for this node is not done until all the child nodes
* are done. Use the tracker to wait for all children to complete.
*/
final DoneCollector doneCollector = new DoneCollector(getExecutor()) { public void run() {
final DoneCollector<Done> elementsDeltasDoneCollector = new DoneCollector<Done>() {
public void run() {
if (isDisposed()) return;
getExecutor().execute(done);
}};
for (IVMContext element : getData()) {
for (final IVMLayoutNode childNode : childNodes) {
childNode.buildDelta(
e,
parent.addNode(element, IModelDelta.NO_CHANGE),
doneCollector.addNoActionDone());
}
};
// 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((IVMContext)getData().get(i), nodeOffset + i, IModelDelta.NO_CHANGE);
callChildNodesToBuildDelta(
childNodeDeltas, delta, event,
elementsDeltasDoneCollector.add(new Done() {
public void run() {
elementsDeltasDoneCollector.doneDone(this);
}
}));
}
}
},
parentDelta));
}
}
protected void callChildNodesToBuildDelta(final Map<IVMLayoutNode,Integer> nodes, final VMDelta delta, final Object event, final Done done) {
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 GetDataDone<Map<IVMLayoutNode, Integer>>() {
public void run() {
final DoneCollector<Done> childrenBuildDeltaDoneCollector = new DoneCollector<Done>() {
public void run() {
if (isDisposed()) return;
getExecutor().execute(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 Done() {
public void run() {
childrenBuildDeltaDoneCollector.doneDone(this);
}})
);
}
}
});
}
/**
* Default implementation of the IColumnEditorFactoryAdapter delegate. It
* returns null, which means that no cell editor is configured.
* @see IColumnEditorFactoryAdapter#createColumnEditor(IPresentationContext, Object)
*/
public IColumnEditor createColumnEditor(IVMContext vmc) {
return null;
private void getChildNodesElementOffsets(IModelDelta delta, boolean fakeIt, final GetDataDone<Map<IVMLayoutNode, Integer>> done) {
assert getChildLayoutNodes().length != 0;
if (!fakeIt) {
final Integer[] counts = new Integer[getChildLayoutNodes().length];
final DoneCollector<Done> childrenCountDoneCollector = new DoneCollector<Done>() {
public void run() {
if (isDisposed()) return;
if (propagateError(getExecutor(), done, "")) return; //$NON-NLS-1$
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);
done.setData(data);
getExecutor().execute(done);
}
};
for (int i = 0; i < getChildLayoutNodes().length; i++) {
final int nodeIndex = i;
getChildLayoutNodes()[i].updateElementCount(
new ElementsCountUpdate(
childrenCountDoneCollector.add(new GetDataDone<Integer>() {
public void run() {
counts[nodeIndex] = getData();
childrenCountDoneCollector.doneDone(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);
done.setData(data);
getExecutor().execute(done);
}
}
/**
* Default implementation of the IColumnEditorFactoryAdapter delegate. It
* returns null, which means that no cell editor is configured.
* @see IColumnEditorFactoryAdapter#getColumnEditorId(IPresentationContext, Object)
*/
public String getColumnEditorId(IVMContext vmc) {
return null;
protected boolean isDisposed() {
return fDisposed;
}
/**
@ -149,41 +256,173 @@ abstract public class AbstractVMLayoutNode implements IVMLayoutNode {
* <code>true</code> to the <code>hasDeltaFlags()</code> test for the given
* event.
*/
protected IVMLayoutNode[] getChildNodesWithDeltas(Object e) {
List<IVMLayoutNode> nodes = new ArrayList<IVMLayoutNode>();
protected Map<IVMLayoutNode, Integer> getChildNodesWithDeltas(Object e) {
Map<IVMLayoutNode, Integer> nodes = new HashMap<IVMLayoutNode, Integer>();
for (final IVMLayoutNode childNode : getChildLayoutNodes()) {
if (childNode.hasDeltaFlags(e)) {
nodes.add(childNode);
int delta = childNode.getDeltaFlags(e);
if (delta != IModelDelta.NO_CHANGE) {
nodes.put(childNode, delta);
}
}
return nodes.toArray(new IVMLayoutNode[nodes.size()]);
return nodes;
}
/**
* Convenience method that returns a token value in case when the services
* that the layout node depends on, are not available.
*/
protected void handleFailedHasElements(GetDataDone<Boolean> done) {
done.setData(false);
getExecutor().execute(done);
protected boolean checkUpdate(IViewerUpdate update) {
if (update.isCanceled()) return false;
if (fDisposed) {
handleFailedUpdate(update);
return false;
}
return true;
}
/**
* Convenience method that returns a token value in case when the services
* that the layout node depends on, are not available.
*/
protected void handleFailedGetElements(GetDataDone<IVMContext[]> done) {
done.setData(new IVMContext[0]);
getExecutor().execute(done);
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();
}
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; }
/**
* Convenience method that returns a token value in case when the services
* that the layout node depends on, are not available.
* 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 IModelProxyFactoryAdapter}, and
* {@link IColumnPresentationFactoryAdapter}.
*/
protected void handleFailedRetrieveLabel(ILabelRequestMonitor result) {
result.setLabels(new String[] { "..."} ); //$NON-NLS-1$
result.done();
@SuppressWarnings("unchecked")
public Object getAdapter(Class adapter) {
if (adapter.isInstance(fVMAdapter)) {
return fVMAdapter;
} else if (adapter.isInstance(fLayoutNode)) {
return fLayoutNode;
}
return null;
}
}
protected class ViewerUpdate implements IViewerUpdate {
final private Done fDone;
private boolean fDoneInvoked = false;
final private TreePath fTreePath;
private IStatus fStatus;
private boolean fCancelled = false;
public ViewerUpdate(Done done, IModelDelta delta) {
fDone = done;
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(Done done, TreePath path) {
fDone = done;
fTreePath = path;
}
public Object getElement(TreePath path) {
// If not asking for root, just return the last segment in path.
if (path.getSegmentCount() > 0) {
return path.getLastSegment();
}
// Calculate the root of the viewer.
return getVMProvider().getRootLayoutNode().getRootObject();
}
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 void beginTask(String name, int totalWork) {}
public void internalWorked(double work) {}
public boolean isCanceled() { return fCancelled; }
public void setCanceled(boolean value) { fCancelled = value; }
public void setTaskName(String name) {}
public void subTask(String name) {}
public void worked(int work) {}
public void done() {
assert !fDoneInvoked;
fDoneInvoked = true;
try {
getExecutor().execute(fDone);
} catch (RejectedExecutionException e) {
}
}
}
protected class ElementsCountUpdate extends ViewerUpdate implements IChildrenCountUpdate {
private final GetDataDone<Integer> fDone;
public ElementsCountUpdate(GetDataDone<Integer> done, IModelDelta delta) {
super(done, delta);
fDone = done;
}
public void setChildCount(int numChildren) {
fDone.setData(numChildren);
}
}
protected class ElementsUpdate extends ViewerUpdate implements IChildrenUpdate {
private final List<Object> fChildren = new ArrayList<Object>();
private GetDataDone<List<Object>> fDone;
public ElementsUpdate(GetDataDone<List<Object>> done, IModelDelta delta) {
super(done, delta);
fDone = done;
fDone.setData(fChildren);
}
public ElementsUpdate(GetDataDone<List<Object>> done, TreePath path) {
super(done, path);
fDone = done;
fDone.setData(fChildren);
}
public int getOffset() {
return -1;
}
public int getLength() {
return -1;
}
public void setChild(Object child, int offset) {
fChildren.add(offset, child);
}
}
}

View file

@ -0,0 +1,648 @@
/*******************************************************************************
* 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.List;
import java.util.Map;
import java.util.concurrent.Executor;
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.Done;
import org.eclipse.dd.dsf.concurrent.DoneCollector;
import org.eclipse.dd.dsf.concurrent.GetDataDone;
import org.eclipse.dd.dsf.concurrent.ThreadSafe;
import org.eclipse.dd.dsf.datamodel.IDMEvent;
import org.eclipse.dd.dsf.service.DsfServiceEventHandler;
import org.eclipse.dd.dsf.service.IDsfService;
import org.eclipse.dd.dsf.ui.DsfUIPlugin;
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.IColumnPresentationFactoryAdapter;
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.provisional.AbstractModelProxy;
import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousContentAdapter;
import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousLabelAdapter;
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditorFactoryAdapter;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.Viewer;
/**
* 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
* to be configured with each provider.
* <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.
*
* @see IAsynchronousContentAdapter
* @see IAsynchronousLabelAdapter
* @see IModelProxy
* @see IVMLayoutNode
*/
@ConfinedToDsfExecutor("getVMAdapter#getExecutor")
@SuppressWarnings("restriction")
abstract public class AbstractVMProvider implements IVMProvider
{
private final AbstractVMAdapter fVMAdapter;
private final IPresentationContext fPresentationContext;
private final ModelProxy fModelProxy = new ModelProxy();
private boolean fDisposed = false;
/**
* The root node for this model provider. The root layout node could be
* 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>();
/**
* Constructs the view model provider for given DSF session. The
* constructor is thread-safe to allow VM provider to be constructed
* synchronously when a call to getAdapter() is made on an element
* in a view.
*/
public AbstractVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext) {
fVMAdapter = adapter;
fPresentationContext = presentationContext;
}
public IVMAdapter getVMAdapter() {
return fVMAdapter;
}
public IPresentationContext getPresentationContext() {
return fPresentationContext;
}
/**
* Sets the root node for this provider.
*/
@ThreadSafe
protected void setRootLayoutNode(IVMRootLayoutNode rootLayoutNode) {
final IVMRootLayoutNode oldRootLayoutNode = fRootLayoutNodeRef.getAndSet(rootLayoutNode);
if (oldRootLayoutNode != null) {
oldRootLayoutNode.dispose();
}
}
protected ModelProxy getModelProxy() {
return fModelProxy;
}
@ThreadSafe
public IVMRootLayoutNode getRootLayoutNode() {
return fRootLayoutNodeRef.get();
}
/** Called to dispose the provider. */
public void dispose() {
fDisposed = true;
if (fRootLayoutNodeRef.get() != null) {
fRootLayoutNodeRef.get().dispose();
}
}
protected boolean isDisposed() {
return fDisposed;
}
/**
* Convenience method to access the View Model's executor.
*/
public Executor 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 = getLayoutNodeObject(update.getElement());
if (layoutNode == null) {
// Stale update, most likely as a result of the layout nodes being
// changed. Just ignore it.
if (!update.isCanceled()) 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);
}
return;
}
HasElementsUpdate[][] elementsUpdates =
new HasElementsUpdate[node.getChildLayoutNodes().length][updates.length];
for (int i = 0; i < updates.length; i ++)
{
final IHasChildrenUpdate update = updates[i];
for (int j = 0; j < node.getChildLayoutNodes().length; j++)
{
final DoneCollector<GetDataDone<Boolean>> hasChildrenDoneCollector =
new DoneCollector<GetDataDone<Boolean>>() {
public void run() {
// Status is OK, only if all dones are OK.
if (getStatus().isOK()) {
boolean isContainer = false;
for (GetDataDone<Boolean> hasElementsDone : getDones().keySet()) {
isContainer |= hasElementsDone.getStatus().isOK() &&
hasElementsDone.getData().booleanValue();
}
update.setHasChilren(isContainer);
update.done();
}
}
};
elementsUpdates[j][i] = new HasElementsUpdate(
update,
hasChildrenDoneCollector.add(new GetDataDone<Boolean>() {
public void run() {
hasChildrenDoneCollector.doneDone(this);
}
}));
}
}
for (int j = 0; j < node.getChildLayoutNodes().length; j++) {
node.getChildLayoutNodes()[j].updateHasElements(elementsUpdates[j]);
}
}
public void update(final IChildrenCountUpdate[] updates) {
for (final IChildrenCountUpdate update : updates) {
if (update.isCanceled()) continue;
getChildrenCountsForNode(
update, update.getElementPath(),
new GetDataDone<Integer[]>() {
public void run() {
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, update.getElementPath(),
new GetDataDone<Integer[]>() {
public void run() {
if (!getStatus().isOK()) {
update.done();
return;
}
updateChildrenWithCounts(update, getData());
}
});
}
}
private void getChildrenCountsForNode(IViewerUpdate update, TreePath elementPath, final GetDataDone<Integer[]> done) {
if (isDisposed()) return;
// Get the VM Context for last element in path.
final IVMLayoutNode layoutNode = getLayoutNodeObject(update.getElement());
if (layoutNode == null) {
// Stale update. Just ignore.
done.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.INVALID_HANDLE,
"Stale update.", null)); //$NON-NLS-1$
getExecutor().execute(done);
return;
}
IVMLayoutNode[] childNodes = layoutNode.getChildLayoutNodes();
// If parent element's layout node has no children, just mark done and
// return.
if (childNodes.length == 0) {
done.setData(new Integer[0]);
getExecutor().execute(done);
return;
}
// Get the mapping of all the counts.
final Integer[] counts = new Integer[childNodes.length];
final DoneCollector<Done> childrenCountDoneCollector =
new DoneCollector<Done>() {
public void run() {
if (fDisposed) return;
if (propagateError(getExecutor(), done, "")) return; //$NON-NLS-1$
done.setData(counts);
getExecutor().execute(done);
}
};
for (int i = 0; i < childNodes.length; i++) {
final int nodeIndex = i;
childNodes[i].updateElementCount(
new ElementsCountUpdate(
update,
childrenCountDoneCollector.add(new GetDataDone<Integer>() {
public void run() {
if (getStatus().isOK()) {
assert getData() != null;
counts[nodeIndex] = getData();
}
childrenCountDoneCollector.doneDone(this);
}
}),
elementPath)
);
}
}
private void updateChildrenWithCounts(final IChildrenUpdate update, Integer[] nodeElementCounts) {
final IVMLayoutNode layoutNode = getLayoutNodeObject(update.getElement());
if (layoutNode == null) {
// Stale update. Just ignore.
if (!update.isCanceled()) update.done();
}
// Create the done collector to mark update when querying all children nodes is finished.
final DoneCollector<Done> elementsDoneCollector =
new DoneCollector<Done>() {
public void run() {
if (!update.isCanceled()) 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]);
layoutNodes[i].updateElements(
new ElementsUpdate(
update,
elementsDoneCollector.add(new Done() {
public void run() {
elementsDoneCollector.doneDone(this);
}
}),
nodeStartIdx, elementsStartIdx, elementsEndIdx - elementsStartIdx)
);
}
}
// Guard against invalid queries.
if (elementsDoneCollector.getDones().isEmpty()) {
update.done();
}
}
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. We only need to
* create a proxy for the root element of the tree.
*/
if (getRootLayoutNode() != null &&
element.equals(getRootLayoutNode().getRootObject()))
{
return fModelProxy;
}
return null;
}
/**
* Creates the column presentation for the given object. This method is meant
* to be overriden by deriving class to provide view-specific functionality.
* The default is to return null, meaning no columns.
* <p>
* The viewer only reads the column presentation for the root/input element of
* the tree/table, so the VMProvider must be configured to own the root element
* in the view in order for this setting to be effective.
* <p>
* Note: since the IColumnEditorFactoryAdapter interface is synchronous, and since
* column info is fairly static, this method is thread-safe, and it will
* not be called on the executor thread.
*
* @see IColumnPresentationFactoryAdapter#createColumnPresentation(IPresentationContext, Object)
*/
public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) {
return null;
}
/**
* Returns the ID of the column presentation for the given object. This method
* is meant to be overriden by deriving class to provide view-specific
* functionality. The default is to return null, meaning no columns.
* <p>
* The viewer only reads the column presentation for the root/input element of
* the tree/table, so the VMProvider must be configured to own the root element
* in the view in order for this setting to be effective.
* <p>
* Note: since the IColumnEditorFactoryAdapter interface is synchronous, and since
* column info is fairly static, this method is thread-safe, and it will
* not be called on the executor thread.
*
* @see IColumnEditorFactoryAdapter#getColumnEditorId(IPresentationContext, Object)
*/
public String getColumnPresentationId(IPresentationContext context, Object element) {
return null;
}
/**
* 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.
*/
private IVMLayoutNode getLayoutNodeObject(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(rootLayoutNode.getRootObject())) {
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;
}
/**
* Handle "data model changed" event by generating a delta object for each
* view and passing it to the corresponding view model provider. The view
* model provider is then responsible for filling-in and sending the delta
* to the viewer.
* @param e
*/
@DsfServiceEventHandler
public void eventDispatched(final IDMEvent<?> event) {
IVMRootLayoutNode rootLayoutNode = getRootLayoutNode();
if (rootLayoutNode != null && rootLayoutNode.getDeltaFlags(event) != 0) {
rootLayoutNode.createDelta(event, new GetDataDone<IModelDelta>() {
public void run() {
if (getStatus().isOK()) {
fModelProxy.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$
}
});
}
}
@ThreadSafe
protected class ModelProxy extends AbstractModelProxy {
/**
* Counter for whether the model proxy is currently installed in the viewer.
* Data model events are processed only if the model proxy is active.
*/
private int fProxyActive = 0;
/**
* 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; }
};
public void installed(Viewer viewer) {
fProxyActive++;
}
public void dispose() {
fProxyActive--;
super.dispose();
}
/**
* 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) {
if (fProxyActive <= 0) return;
Job job = new Job("Processing view model delta.") { //$NON-NLS-1$
protected IStatus run(IProgressMonitor monitor) {
fireModelChanged(delta);
return Status.OK_STATUS;
}
};
job.setPriority(Job.INTERACTIVE);
job.setRule(fModelChangeRule);
job.schedule();
}
}
class ViewerUpdate implements IViewerUpdate {
private IStatus fStatus;
private boolean fDoneInvoked = false;
final private Done fDone;
final protected IViewerUpdate fClientUpdate;
public ViewerUpdate(IViewerUpdate clientUpdate, Done done) {
fDone = done;
fClientUpdate = clientUpdate;
}
public Object getElement() { return fClientUpdate.getElement(); }
public TreePath getElementPath() { return fClientUpdate.getElementPath(); }
public IPresentationContext getPresentationContext() { return fClientUpdate.getPresentationContext(); }
public IStatus getStatus() { return fStatus; }
public void setStatus(IStatus status) { fStatus = status; }
public void beginTask(String name, int totalWork) {}
public void internalWorked(double work) {}
public boolean isCanceled() { return fClientUpdate.isCanceled(); }
public void setCanceled(boolean value) { fClientUpdate.setCanceled(value); }
public void setTaskName(String name) {}
public void subTask(String name) {}
public void worked(int work) {}
public void done() {
assert !fDoneInvoked;
fDoneInvoked = true;
try {
getExecutor().execute(fDone);
} catch (RejectedExecutionException e) { // Ignore
}
}
}
class HasElementsUpdate extends ViewerUpdate implements IHasChildrenUpdate {
final private GetDataDone<Boolean> fDone;
HasElementsUpdate(IHasChildrenUpdate clientUpdate, GetDataDone<Boolean> done) {
super(clientUpdate, done);
fDone = done;
}
public TreePath getElementPath() {
return ((IHasChildrenUpdate)fClientUpdate).getElementPath();
}
public void setHasChilren(boolean hasChildren) {
fDone.setData(hasChildren);
}
public void done() {
assert fDone.getData() != null || !fDone.getStatus().isOK();
super.done();
}
}
class ElementsCountUpdate extends ViewerUpdate implements IChildrenCountUpdate {
final private GetDataDone<Integer> fDone;
final private TreePath fElementPath;
ElementsCountUpdate(IViewerUpdate clientUpdate, GetDataDone<Integer> done, TreePath elementPath) {
super(clientUpdate, done);
fElementPath = elementPath;
fDone = done;
}
public TreePath getElementPath() {
return fElementPath;
}
public void setChildCount(int count) {
fDone.setData(count);
}
public void done() {
assert fDone.getData() != null || !fDone.getStatus().isOK();
super.done();
}
}
class ElementsUpdate extends ViewerUpdate implements IChildrenUpdate {
private final int fClientOffset;
private final int fOffset;
private final int fLength;
ElementsUpdate(IChildrenUpdate clientUpdate, Done done, int clientOffset, int offset, int length) {
super(clientUpdate, done);
fClientOffset = clientOffset;
fOffset = offset;
fLength = length;
}
public int getOffset() {
return fOffset;
}
public int getLength() {
return fLength;
}
public TreePath getElementPath() {
return ((IChildrenUpdate)fClientUpdate).getElementPath();
}
public void setChild(Object child, int offset) {
if (offset >= fOffset && offset < (fOffset + fLength)) {
((IChildrenUpdate)fClientUpdate).setChild(child, fClientOffset + offset);
}
}
}
}

View file

@ -10,12 +10,15 @@
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.dd.dsf.concurrent.DoneCollector;
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
import java.util.Map;
import org.eclipse.dd.dsf.concurrent.Done;
import org.eclipse.dd.dsf.concurrent.GetDataDone;
import org.eclipse.debug.internal.ui.viewers.provisional.ILabelRequestMonitor;
import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta;
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;
/**
*
@ -23,44 +26,8 @@ import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta;
@SuppressWarnings("restriction")
abstract public class AbstractVMRootLayoutNode extends AbstractVMLayoutNode implements IVMRootLayoutNode {
protected static class RootVMC<V> implements IRootVMC {
private final V fInputObject;
private final IVMRootLayoutNode fVMRootLayoutNode;
public RootVMC(IVMRootLayoutNode vmRootLayoutNode, V inputObject) {
fVMRootLayoutNode = vmRootLayoutNode;
fInputObject = inputObject;
}
/** Returns the ILaunch object belonging to this launch VMC. */
public V getInputObject() { return fInputObject; }
public IVMContext getParent() { return null; }
public IVMLayoutNode getLayoutNode() { return fVMRootLayoutNode; }
@SuppressWarnings("unchecked")
public Object getAdapter(Class adapter) {
if (fInputObject instanceof IAdaptable) {
return ((IAdaptable)fInputObject).getAdapter(adapter);
}
return null;
}
public boolean equals(Object other) {
return getClass().equals( other.getClass() ) &&
fInputObject.equals( ((RootVMC)other).getInputObject() );
}
public int hashCode() {
return fInputObject.hashCode();
}
public String toString() { return "Root VMC for " + fInputObject.toString(); } //$NON-NLS-1$
}
public AbstractVMRootLayoutNode(DsfExecutor executor) {
super(executor);
public AbstractVMRootLayoutNode(AbstractVMProvider provider) {
super(provider);
}
/**
@ -68,9 +35,10 @@ abstract public class AbstractVMRootLayoutNode extends AbstractVMLayoutNode impl
* 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 getElements(IVMContext parentVmc, GetDataDone<IVMContext[]> done) {
done.setData(new IVMContext[] { getRootVMC() });
getExecutor().execute(done);
public void updateElements(IChildrenUpdate update) {
// Ignore startIdx, endIdx, since there's only one element to be had.
update.setChild(getRootObject(), 0);
update.done();
}
/**
@ -78,9 +46,9 @@ abstract public class AbstractVMRootLayoutNode extends AbstractVMLayoutNode impl
* 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 hasElements(IVMContext parentVmc, GetDataDone<Boolean> done) {
done.setData(true);
getExecutor().execute(done);
public void updateElementCount(IChildrenCountUpdate update) {
update.setChildCount(1);
update.done();
}
/**
@ -88,8 +56,20 @@ abstract public class AbstractVMRootLayoutNode extends AbstractVMLayoutNode impl
* 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 retrieveLabel(IVMContext vmc, ILabelRequestMonitor result, String[] columns) {
result.done();
public void updateHasElements(IHasChildrenUpdate[] updates) {
for (IHasChildrenUpdate update : updates) {
update.setHasChilren(true);
update.done();
}
}
/**
* This implementation only fulfils 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 updateLabel(IVMContext vmc, ILabelUpdate update) {
update.done();
}
/**
@ -97,28 +77,21 @@ abstract public class AbstractVMRootLayoutNode extends AbstractVMLayoutNode impl
* is the input object into the view.
*/
public void createDelta(Object event, final GetDataDone<IModelDelta> done) {
final VMDelta rootDelta = new VMDelta(getRootVMC().getInputObject(), getRootVMC());
final Map<IVMLayoutNode,Integer> childNodeDeltas = getChildNodesWithDeltas(event);
assert childNodeDeltas.size() != 0 : "Caller should make sure that there are deltas for given event."; //$NON-NLS-1$
final IVMLayoutNode[] childNodes = getChildNodesWithDeltas(event);
if (childNodes.length == 0) {
done.setData(rootDelta);
getExecutor().execute(done);
return;
}
// Always create the rootDelta, no matter what delta flags the child nodes have.
final VMDelta rootDelta = new VMDelta(getRootObject(), IModelDelta.NO_CHANGE);
/*
* The execution for this node is not done until all the child nodes
* are done. Use the tracker to wait for all children to complete.
*/
final DoneCollector doneCollector = new DoneCollector(getExecutor()) {
callChildNodesToBuildDelta(
childNodeDeltas, rootDelta, event,
new Done() {
public void run() {
if (propagateError(getExecutor(), done, "Failed to generate child deltas.")) return; //$NON-NLS-1$
if (isDisposed()) return;
if (propagateError(getExecutor(), done, "Failed to create delta.")); //$NON-NLS-1$
done.setData(rootDelta);
getExecutor().execute(done);
}
};
for (final IVMLayoutNode childNode : childNodes) {
childNode.buildDelta(event, rootDelta, doneCollector.addNoActionDone());
}
});
}
}

View file

@ -1,360 +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.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.dd.dsf.concurrent.Done;
import org.eclipse.dd.dsf.concurrent.DoneCollector;
import org.eclipse.dd.dsf.concurrent.GetDataDone;
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.IDMData;
import org.eclipse.dd.dsf.datamodel.IDMEvent;
import org.eclipse.dd.dsf.datamodel.IDMService;
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.IVMRootLayoutNode.IRootVMC;
import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousLabelAdapter;
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentationFactoryAdapter;
import org.eclipse.debug.internal.ui.viewers.provisional.ILabelRequestMonitor;
import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.RGB;
/**
* 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 DMContextVMLayoutNode<V extends IDMData> extends AbstractVMLayoutNode {
/**
* IVMContext implementation used for this schema node.
*/
@Immutable
public class DMContextVMContext implements IVMContext {
private final IVMContext fParent;
private final IDMContext<V> fDmc;
public DMContextVMContext(IVMContext parent, IDMContext<V> dmc) {
fParent = parent;
fDmc = dmc;
}
public IDMContext<V> getDMC() { return fDmc; }
public IVMContext getParent() { return fParent; }
public IVMLayoutNode getLayoutNode() { return DMContextVMLayoutNode.this; }
/**
* The IAdaptable implementation. If the adapter is the DM context,
* return the context, otherwise delegate to IDMContext.getAdapter().
*/
@SuppressWarnings("unchecked")
public Object getAdapter(Class adapter) {
if (adapter.isInstance(fDmc)) {
return fDmc;
} else {
return fDmc.getAdapter(adapter);
}
}
public boolean equals(Object other) {
if (!(other instanceof DMContextVMLayoutNode.DMContextVMContext)) return false;
DMContextVMLayoutNode.DMContextVMContext otherVmc = (DMContextVMLayoutNode.DMContextVMContext)other;
return DMContextVMLayoutNode.this.equals(otherVmc.getLayoutNode()) &&
fParent.equals(otherVmc.fParent) &&
fDmc.equals(otherVmc.fDmc);
}
public int hashCode() {
return DMContextVMLayoutNode.this.hashCode() + fParent.hashCode() + fDmc.hashCode();
}
public String toString() {
return fParent.toString() + "->" + fDmc.toString(); //$NON-NLS-1$
}
}
/** Service tracker to be used by sub-classes */
private DsfServicesTracker fServices;
private DsfSession fSession;
/**
* 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<V>> 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 DMContextVMLayoutNode(DsfSession session, Class<? extends IDMContext<V>> dmcClassType) {
super(session.getExecutor());
fSession = session;
fServices = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), session.getId());
fDMCClassType = dmcClassType;
}
/**
* Returns the session for use by sub-classes.
*/
protected DsfSession getSession() {
return fSession;
}
/**
* Returns the services tracker for sub-class use.
*/
protected DsfServicesTracker getServicesTracker() {
return fServices;
}
/**
* The default implementation of the retrieve label method. It acquires
* the service, using parameters in the DMC, then it fetches the model
* data from the service, and then it calls the protected method
* fillColumnLabel() for each column. The deriving classes should override
* this method if a different method of computing the label is needed.
*
* @see #fillColumnLabel(IDMData, String, int, String[], ImageDescriptor[], FontData[], RGB[], RGB[])
*/
@SuppressWarnings("unchecked")
public void retrieveLabel(IVMContext vmc, final ILabelRequestMonitor result, final String[] columns) {
/*
* Extract the DMContext from the VMContext, see DMContextVMContext.getAdapter().
* Since the VMContext is supplied by this node, the DMContext should never be null.
* Note: had to suppress type cast warnings here, because getAdapter() does not support
* generics, and even if it did, I'm not sure it would help.
*/
final IDMContext<V> dmc = (IDMContext<V>)(vmc).getAdapter(IDMContext.class);
if (dmc == null) {
assert false;
result.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, "Invalid VMC type", null)); //$NON-NLS-1$
result.done();
return;
}
/*
* Get the instance of the service using the service filter in the DMContext
* If null it could mean that the service already shut down, and the view
* is holding stale elements which will be cleaned up shortly.
*/
IDMService dmService = (IDMService)getServicesTracker().getService(null, dmc.getServiceFilter());
if (dmService == null) {
handleFailedRetrieveLabel(result);
return;
}
dmService.getModelData(
dmc,
new GetDataDone<V>() {
public void run() {
/*
* 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() || !getData().isValid()) {
assert getStatus().isOK() ||
getStatus().getCode() != IDsfService.INTERNAL_ERROR ||
getStatus().getCode() != IDsfService.NOT_SUPPORTED;
handleFailedRetrieveLabel(result);
return;
}
/*
* If columns are configured, call the protected methods to
* fill in column values.
*/
String[] localColumns = columns;
if (localColumns == null) localColumns = new String[] { null };
String[] text = new String[localColumns.length];
ImageDescriptor[] image = new ImageDescriptor[localColumns.length];
FontData[] fontData = new FontData[localColumns.length];
RGB[] foreground = new RGB[localColumns.length];
RGB[] background = new RGB[localColumns.length];
for (int i = 0; i < localColumns.length; i++) {
fillColumnLabel(dmc, getData(), localColumns[i], i, text, image, fontData, foreground, background);
}
result.setLabels(text);
result.setImageDescriptors(image);
result.setFontDatas(fontData);
result.setBackgrounds(background);
result.setForegrounds(foreground);
result.done();
}
});
}
/**
* Fills in label information for given column. This method is intended to
* be overriden by deriving classes, to supply label information specific
* to the node. <br>
* The implementation should fill in the correct value in each array at the
* given index.
* @param dmContext Data Model Context object for which the label is generated.
* @param dmData Data Model Data object retrieved from the model service.
* for the DM Context supplied to the retrieveLabel() call.
* @param columnId Name of the column to fill in, null if no columns specified.
* @param idx Index to fill in in the label arrays.
* @param text
* @param image
* @param fontData
* @param foreground
* @param background
*
* @see IAsynchronousLabelAdapter
* @see IColumnPresentationFactoryAdapter
*/
protected void fillColumnLabel(IDMContext<V> dmContext, V dmData, String columnId, int idx, String[] text,
ImageDescriptor[] image, FontData[] fontData, RGB[] foreground, RGB[] background )
{
text[idx] = ""; //$NON-NLS-1$
}
@Override
public boolean hasDeltaFlags(Object e) {
if (e instanceof IDMEvent) {
return hasDeltaFlagsForDMEvent((IDMEvent)e);
} else {
return super.hasDeltaFlags(e);
}
}
/**
* DMC-specific version of {@link IVMLayoutNode#hasDeltaFlags(Object)}.
* By default, it falls back on the super-class implementation.
*/
protected boolean hasDeltaFlagsForDMEvent(IDMEvent<?> e) {
return super.hasDeltaFlags(e);
}
@Override
public void buildDelta(Object e, VMDelta parent, Done done) {
if (e instanceof IDMEvent) {
buildDeltaForDMEvent((IDMEvent)e, parent, done);
} else {
super.buildDelta(e, parent, done);
}
}
/**
* Adds an optimization (over the AbstractViewModelLayoutNode) which
* narrows down the list of children based on the DMC within the event.
*/
public void buildDeltaForDMEvent(final IDMEvent<?> e, final VMDelta parent, final Done done) {
/*
* Take the IDMContext (DMC) that the event is based on, and
* search its ancestors. Look for the DMC class typs that this schema
* node is based on. If its found, then only one IModelDelta needs to
* be generated for this schema node. Otherwise, resort to the default
* behavior and generate a IModelDelta for every element in this schema
* node.
*/
IDMContext<V> dmc = DMContexts.getAncestorOfType(e.getDMContext(), fDMCClassType);
if (dmc != null) {
IVMLayoutNode[] childNodes = getChildNodesWithDeltas(e);
if (childNodes.length == 0) {
// There are no child nodes with deltas, just return to parent.
getExecutor().execute(done);
return;
}
/*
* This execution for this node is not done until all the child nodes
* are done. Use the tracker to wait for all children to complete.
*/
DoneCollector childDoneTracker = new DoneCollector(getExecutor()) {
public void run() {
getExecutor().execute(done);
}
};
for (final IVMLayoutNode childNode : getChildLayoutNodes()) {
/*
* Create a delta corresponding to the DMC from the event and pass
* it as parent VMC to the child node. The child node will build
* its delta on top of this delta.
*/
childNode.buildDelta(
e,
parent.addNode(new DMContextVMContext(parent.getVMC(), dmc), IModelDelta.NO_CHANGE),
childDoneTracker.addNoActionDone());
}
} else {
super.buildDelta(e, parent, done);
}
}
/**
* 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(IVMContext parent, IDMContext<V>[] dmcs) {
IVMContext[] vmContexts = new IVMContext[dmcs.length];
for (int i = 0; i < dmcs.length; i++) {
vmContexts[i] = new DMContextVMContext(parent, dmcs[i]);
}
return vmContexts;
}
/**
* Searches for a DMC of given type in the tree patch contained in given
* VMC. VMCs keep a reference to the parent node that contain them in the
* tree. This method recursively looks compares the parent until root is
* reached, or the DMC is found. If the root is reached, and the root's
* input is also a VMC (which comes from another view), then the hierarchy
* of the input object will be searched as well.
* @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 static <V extends IDMContext> V findDmcInVmc(IVMContext vmc, Class<V> dmcType) {
if (vmc instanceof IRootVMC && ((IRootVMC)vmc).getInputObject() instanceof IVMContext) {
vmc = (IVMContext)((IRootVMC)vmc).getInputObject();
}
if (vmc instanceof DMContextVMLayoutNode.DMContextVMContext &&
dmcType.isAssignableFrom( ((DMContextVMLayoutNode.DMContextVMContext)vmc).getDMC().getClass() ))
{
return (V)((DMContextVMLayoutNode.DMContextVMContext)vmc).getDMC();
} else if (vmc.getParent() != null) {
return findDmcInVmc(vmc.getParent(), dmcType);
}
return null;
}
public void dispose() {
fServices.dispose();
super.dispose();
}
}

View file

@ -0,0 +1,19 @@
package org.eclipse.dd.dsf.ui.viewmodel;
import org.eclipse.dd.dsf.concurrent.ThreadSafe;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactoryAdapter;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactoryAdapter;
/**
* The View Model adapter handles the layout of a given data model within a
* set of viewers. This adapter should be returned by an adapter factory for
* the input object of the viewer, and this adapter implementation will then
* populate the view contents.
*/
@ThreadSafe
@SuppressWarnings("restriction")
public interface IVMAdapter
extends IElementContentProvider, IModelProxyFactoryAdapter, IColumnPresentationFactoryAdapter
{
}

View file

@ -14,7 +14,7 @@ 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.
*/
@Immutable
public interface IVMContext extends IAdaptable {
@ -23,10 +23,4 @@ public interface IVMContext extends IAdaptable {
* Returns the layout node that originated this element.
*/
public IVMLayoutNode getLayoutNode();
/**
* Returns the parent of this element in the viewer layout.
* @return
*/
public IVMContext getParent();
}

View file

@ -12,54 +12,66 @@ package org.eclipse.dd.dsf.ui.viewmodel;
import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.dd.dsf.concurrent.Done;
import org.eclipse.dd.dsf.concurrent.GetDataDone;
import org.eclipse.dd.dsf.concurrent.ThreadSafeAndProhibitedFromDsfExecutor;
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditor;
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditorFactoryAdapter;
import org.eclipse.debug.internal.ui.viewers.provisional.ILabelRequestMonitor;
import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
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.IHasChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
/**
* View model layout nodes are combined together into a tree, to collectively
* define the layout of a view. Each schema node generates elements of type
* IVMContext, and provide label information about these elements.
* 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.
* @see VMProvider
* @see AbstractDMVMProvider
*/
@ConfinedToDsfExecutor("")
@SuppressWarnings("restriction")
public interface IVMLayoutNode {
public interface IVMLayoutNode
{
/**
* Retrieves information whether for the given parent node, there are any elements
* available.
* @param parentVmc Parent node, for which to calculate elements at the
* current level.
* @param done The data return token.
* 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 hasElements(IVMContext parentVmc, GetDataDone<Boolean> done);
public void updateHasElements(IHasChildrenUpdate[] updates);
/**
* Retrieves the list of elements.
* @param parentVmc Parent node, for which to calculate elements at the
* current level.
* @param done The data return token.
* 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 getElements(IVMContext parentVmc, GetDataDone<IVMContext[]> done);
public void updateElementCount(IChildrenCountUpdate update);
/**
* Retrieves the label for the given element.
* @param vmc Element for which to retrieve label information.
* @param result Monitor which accepts the data.
* @param columns Currently configured columns in view.
* @see IPresentationContext
* Retrieves the element objects of this node for the given path in the
* viewer, and for the given range of indexes. <br>
* Note: 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 retrieveLabel(IVMContext vmc, ILabelRequestMonitor result, String[] columns);
public void updateElements(IChildrenUpdate update);
/**
* Configures the child layout nodes for this node.
@ -73,51 +85,28 @@ public interface IVMLayoutNode {
public IVMLayoutNode[] getChildLayoutNodes();
/**
* Returns true/false indicating whether the given even will cause this
* schema node to generate a model delta.
* Returns the potential delta flags that would be generated by this node
* for the given event.
* @param event Event to process.
* @return True if this node (or its children) would generate delta data
* due to this event.
* @return IModelDelta flags
* @see IModelDelta
*/
public boolean hasDeltaFlags(Object event);
public int getDeltaFlags(Object event);
/**
* Builds model delta information based on the given event.
* @param event Event to process.
* @param parent Parent model delta node that this object should add delta
* data to.
* @param nodeOffset The offset of the first element in this node. This offset
* depends on the elements returned by the siblings of this layout node.
* @param done Return token, which notifies the caller that the calculation is
* complete.
*/
public void buildDelta(Object event, VMDelta parent, Done done);
public void buildDelta(Object event, VMDelta parent, int nodeOffset, Done done);
/**
* Creates a column editor for the given element. The interface that this
* method is delegated to is synchronous, therefore it also needs to be thread
* safe.
*
* @see IColumnEditorFactoryAdapter#createColumnEditor(IPresentationContext, Object)
* @param vmc VM Context to return the editor for
* @return
*/
@ThreadSafeAndProhibitedFromDsfExecutor("")
public IColumnEditor createColumnEditor(IVMContext vmc);
/**
* Returns the ID of the editor for the given element. The interface that this
* method is delegated to is synchronous, therefore it also needs to be thread
* safe.
*
* @see IColumnEditorFactoryAdapter#getColumnEditorId(IPresentationContext, Object)
* @param vmc VM Context to return the editor ID for
* @return
*/
@ThreadSafeAndProhibitedFromDsfExecutor("")
public String getColumnEditorId(IVMContext vmc);
/**
* Disposes the resources held by this node.
* Releases the resources held by this node.
*/
public void dispose();
}

View file

@ -0,0 +1,40 @@
package org.eclipse.dd.dsf.ui.viewmodel;
import org.eclipse.dd.dsf.concurrent.ThreadSafe;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactoryAdapter;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactoryAdapter;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
/**
* 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.
*/
@ThreadSafe
@SuppressWarnings("restriction")
public interface IVMProvider
extends IElementContentProvider, IModelProxyFactoryAdapter, IColumnPresentationFactoryAdapter
{
/**
* Returns the View Model Adapter that this provider belongs to.
*/
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.
*/
public IVMRootLayoutNode getRootLayoutNode();
/**
* Returns the presentation context of the viewer that this provider
* is configured for.
*/
public IPresentationContext getPresentationContext();
/**
* Cleans up the resources associated with this provider.
*/
public void dispose();
}

View file

@ -11,7 +11,7 @@
package org.eclipse.dd.dsf.ui.viewmodel;
import org.eclipse.dd.dsf.concurrent.GetDataDone;
import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta;
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
@ -21,28 +21,13 @@ import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta;
@SuppressWarnings("restriction")
public interface IVMRootLayoutNode extends IVMLayoutNode{
/**
* The root VMC object of this root layout node. There can be only element
* in the root node at a time, and this element must implement this
* interface.
*/
public interface IRootVMC extends IVMContext {
/**
* Returns the view's "input" object. This could be the actual input
* object for the whole view, if this view model hierarchy fills the
* whole view. Or this could an element in the tree from which this
* hierarchy starts. This is the case
*/
Object getInputObject();
}
/**
* Returns the single element of this node. Root layout node can only have
* one element, and this is a convenience method to access this element.
* Alternatively getElements() could be used.
* @return
*/
public IRootVMC getRootVMC();
public Object getRootObject();
/**
* Version of the {@link IVMLayoutNode#buildDelta(Object, ViewModelDelta, org.eclipse.dd.dsf.concurrent.Done)}

View file

@ -11,8 +11,9 @@
*******************************************************************************/
package org.eclipse.dd.dsf.ui.viewmodel;
import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.provisional.ModelDelta;
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
@ -25,13 +26,13 @@ import org.eclipse.debug.internal.ui.viewers.provisional.ModelDelta;
public class VMDelta extends ModelDelta {
private VMDelta fParent;
private IVMContext fVmcElement;
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.
@ -39,9 +40,9 @@ public class VMDelta extends ModelDelta {
* @param vmcElement model element
* @param flags change flags
*/
public VMDelta(IVMContext vmcElement, int flags) {
super(vmcElement, flags);
fVmcElement = vmcElement;
public VMDelta(Object element, int flags) {
super(element, flags);
fElement = element;
fFlags = flags;
}
@ -53,9 +54,9 @@ public class VMDelta extends ModelDelta {
* @param replacement replacement element
* @param flags change flags
*/
public VMDelta(IVMContext vmcElement, Object replacement, int flags) {
super(vmcElement, replacement, flags);
fVmcElement = vmcElement;
public VMDelta(Object element, Object replacement, int flags) {
super(element, replacement, flags);
fElement = element;
fReplacement = replacement;
fFlags = flags;
}
@ -68,40 +69,44 @@ public class VMDelta extends ModelDelta {
* @param index insertion position
* @param flags change flags
*/
public VMDelta(IVMContext vmcElement, int index, int flags) {
super(vmcElement, index, flags);
fVmcElement = vmcElement;
public VMDelta(Object element, int index, int flags) {
super(element, index, flags);
fElement = element;
fIndex = index;
fFlags = flags;
}
/**
* Constructor for model delta based on non-VMC element. This delta is
* only needed for creating delta nodes for parent elements in the tree
* if the VMC elements are not at the root of the tree.
* @param element Element to create the delta for.
* @param vmcElement Optional VMC element for this node, it can be used
* by other nodes in the delta to set their VMC parent element correctly.
* 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, IVMContext vmcElement) {
super(element, IModelDelta.NO_CHANGE);
public VMDelta(Object element, int index, int flags, int childCount) {
super(element, index, flags, childCount);
fElement = element;
fVmcElement = vmcElement;
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 != null ? fElement : fVmcElement;
return fElement;
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getFlags()
*/
@Override
public int getFlags() {
return fFlags;
}
@ -110,7 +115,9 @@ public class VMDelta extends ModelDelta {
fFlags |= flags;
}
public IVMContext getVMC() { return fVmcElement; }
public void setChildCount(int count) {
fChildCount = count;
}
/**
* Adds a child node to this delta with the given element and change flags,
@ -120,7 +127,7 @@ public class VMDelta extends ModelDelta {
* @param flags change flags for child
* @return newly created child delta
*/
public VMDelta addNode(IVMContext element, int flags) {
public VMDelta addNode(Object element, int flags) {
VMDelta node = new VMDelta(element, flags);
node.setParent(this);
addDelta(node);
@ -137,7 +144,7 @@ public class VMDelta extends ModelDelta {
* @param flags change flags
* @return newly created child delta
*/
public VMDelta addNode(IVMContext element, Object replacement, int flags) {
public VMDelta addNode(Object element, Object replacement, int flags) {
VMDelta node = new VMDelta(element, replacement, flags);
node.setParent(this);
addDelta(node);
@ -153,7 +160,7 @@ public class VMDelta extends ModelDelta {
* @param flags change flags
* @return newly created child delta
*/
public VMDelta addNode(IVMContext element, int index, int flags) {
public VMDelta addNode(Object element, int index, int flags) {
VMDelta node = new VMDelta(element, index, flags);
node.setParent(this);
addDelta(node);
@ -161,16 +168,17 @@ public class VMDelta extends ModelDelta {
}
/**
* Adds a node to the delta for a non-VMC element. This is used to
* construct the root branch of the delta before it is handed off to
* ViewModelProvider.handleDataModelEvent()
* @param element Element in the asynchronous view to create the new node for.
* @param vmcElement Optional VMC element for this node, it can be used
* by other nodes in the delta to set their VMC parent element correctly.
* @return Returns the added delta 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
*/
public VMDelta addNode(Object element, IVMContext vmcElement) {
VMDelta node = new VMDelta(element, vmcElement);
public ModelDelta addNode(Object element, int index, int flags, int numChildren) {
VMDelta node = new VMDelta(element, index, flags, numChildren);
node.setParent(this);
addDelta(node);
return node;
@ -188,13 +196,15 @@ public class VMDelta extends ModelDelta {
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getParent()
*/
public IModelDelta getParent() {
@Override
public IModelDelta getParentDelta() {
return fParent;
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getReplacementElement()
*/
@Override
public Object getReplacementElement() {
return fReplacement;
}
@ -202,6 +212,7 @@ public class VMDelta extends ModelDelta {
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getIndex()
*/
@Override
public int getIndex() {
return fIndex;
}
@ -209,7 +220,8 @@ public class VMDelta extends ModelDelta {
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getNodes()
*/
public VMDelta[] getNodes() {
@Override
public VMDelta[] getChildDeltas() {
return fNodes;
}
@ -224,6 +236,7 @@ public class VMDelta extends ModelDelta {
}
}
@Override
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("Model Delta Start\n"); //$NON-NLS-1$
@ -265,11 +278,46 @@ public class VMDelta extends ModelDelta {
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');
VMDelta[] nodes = delta.getNodes();
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, nodes[i]);
appendDetail(buf, (VMDelta)nodes[i]);
}
}
/* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta#getChildCount()
*/
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)
*/
public void accept(IModelDeltaVisitor visitor) {
doAccept(visitor, 0);
}
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

@ -1,439 +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.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.Done;
import org.eclipse.dd.dsf.concurrent.DoneCollector;
import org.eclipse.dd.dsf.concurrent.GetDataDone;
import org.eclipse.dd.dsf.concurrent.ThreadSafe;
import org.eclipse.dd.dsf.datamodel.IDMEvent;
import org.eclipse.dd.dsf.service.DsfServiceEventHandler;
import org.eclipse.dd.dsf.service.DsfSession;
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.debug.internal.ui.viewers.provisional.IChildrenRequestMonitor;
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditor;
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditorFactoryAdapter;
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation;
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentationFactoryAdapter;
import org.eclipse.debug.internal.ui.viewers.provisional.IContainerRequestMonitor;
import org.eclipse.debug.internal.ui.viewers.provisional.ILabelRequestMonitor;
import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.provisional.IModelProxy;
import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
/**
* 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
* to be configured with each provider.
* <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.
*
* @see IAsynchronousContentAdapter
* @see IAsynchronousLabelAdapter
* @see IModelProxy
* @see IVMLayoutNode
*/
@ConfinedToDsfExecutor("fSession#getExecutor")
@SuppressWarnings("restriction")
public class VMProvider
{
private final DsfSession fSession;
private final ModelProxy fModelProxy = new ModelProxy();
/**
* It is theoretically possible for a VMProvider to be disposed before it
* has a chance to register itself as event listener. This flag is used
* to avoid removing itself as listener in such situation.
*/
private boolean fRegisteredAsEventListener = false;
/**
* The root node for this model provider. The root layout node could be
* 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>();
/**
* Constructs the view model provider for given DSF session. The
* constructor is thread-safe to allow VM provider to be constructed
* synchronously when a call to getAdapter() is made on an element
* in a view.
*/
@ThreadSafe
public VMProvider(DsfSession session, IVMRootLayoutNode rootLayoutNode) {
fSession = session;
fRootLayoutNodeRef.set(rootLayoutNode);
// Add ourselves as listener for DM events events.
session.getExecutor().execute(new Runnable() {
public void run() {
if (DsfSession.isSessionActive(getSession().getId())) {
getSession().addServiceEventListener(VMProvider.this, null);
fRegisteredAsEventListener = true;
}
}
});
}
/**
* Sets the layout nodes. This method is thread-safe, because it might
* be called fromthe constructor, which itself is thread-safe.
*/
@ThreadSafe
public void setRootLayoutNode(IVMRootLayoutNode rootLayoutNode) {
final IVMRootLayoutNode oldRootLayoutNode = fRootLayoutNodeRef.getAndSet(rootLayoutNode);
if (oldRootLayoutNode != null) {
// IVMLayoutNode has to be called on dispatch thread... for now at least.
getSession().getExecutor().execute( new Runnable() {
public void run() {
oldRootLayoutNode.dispose();
}
});
}
}
public IVMRootLayoutNode getRootLayoutNode() {
return fRootLayoutNodeRef.get();
}
/** Called to dispose the provider. */
public void dispose() {
if (fRegisteredAsEventListener) {
fSession.removeServiceEventListener(this);
}
if (fRootLayoutNodeRef != null) {
fRootLayoutNodeRef.get().dispose();
}
}
protected DsfSession getSession() { return fSession; }
/**
* Performs the query to determine if given VNC is a container.
* Note: this method must be called on the provider's dispatch thread.
* @see IAsynchronousContentAdapter#isContainer(Object, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext, IContainerRequestMonitor)
*/
@SuppressWarnings("unchecked")
public void isContainer(Object parent, final IContainerRequestMonitor monitor)
{
assert fSession.getExecutor().isInExecutorThread();
IVMContext parentVmc = getVmcForObject(parent);
if (parentVmc == null) {
monitor.done();
return;
}
/*
* If the element's model node has no child layout nodes, it's not a
* container.
*/
if (parentVmc.getLayoutNode().getChildLayoutNodes().length == 0) {
monitor.setIsContainer(false);
monitor.done();
return;
}
/*
* For each child layout node, retrieve the list of elements. When
* all are done, If any of the child nodes have elements, notify the
* monitor that there are children.
*/
final DoneCollector doneCollector = new DoneCollector(fSession.getExecutor()) {
public void run() {
if (monitor.isCanceled()) return;
boolean isContainer = false;
for (Done hasElementsDone : getDones().keySet()) {
isContainer |= hasElementsDone.getStatus().isOK() &&
((GetDataDone<Boolean>)hasElementsDone).getData().booleanValue();
}
monitor.setIsContainer(isContainer);
monitor.done();
}
};
for (IVMLayoutNode childNode : parentVmc.getLayoutNode().getChildLayoutNodes()) {
childNode.hasElements(
parentVmc,
doneCollector.add( new GetDataDone<Boolean>() { public void run() {
doneCollector.doneDone(this);
}}));
}
}
/**
* Performs the query to retrieve children for the given VMC.
* Note: this method must be called on the provider's dispatch thread.
* @see IAsynchronousContentAdapter#retrieveChildren(Object, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext, IChildrenRequestMonitor)
*/
@SuppressWarnings("unchecked")
public void retrieveChildren(final Object parent, final IChildrenRequestMonitor monitor)
{
assert fSession.getExecutor().isInExecutorThread();
IVMContext parentVmc = getVmcForObject(parent);
if (parentVmc == null) {
monitor.done();
return;
}
/*
* If the element's model node has no child layout nodes. There is
* nothing to do, just mark the monitor done.
*/
if (parentVmc.getLayoutNode().getChildLayoutNodes().length == 0) {
assert false : "We should never get here, because isContainer() should have returned false"; //$NON-NLS-1$
monitor.done();
return;
}
/*
* Iterate through the child layout nodes, and request their elements.
* Requests are async, so use a tracker for the results.
*/
final DoneCollector doneCollector = new DoneCollector(fSession.getExecutor()) {
public void run() {
if (monitor.isCanceled()) return;
monitor.done();
}
};
for (IVMLayoutNode childNode : parentVmc.getLayoutNode().getChildLayoutNodes()) {
childNode.getElements(
parentVmc,
doneCollector.add( new GetDataDone<IVMContext[]>() {
public void run() {
if (getStatus().isOK()) {
monitor.addChildren(getData());
}
doneCollector.doneDone(this);
}
}));
}
}
/**
* Retrieves the label information for given object.
* The implementation converts the object into a VM-Context, then delegates
* to the context's layout node.
* Note: this method must be called on the provider's dispatch thread.
* @see IAsynchronousLabelAdapter#retrieveLabel(Object, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext, ILabelRequestMonitor)
*/
public void retrieveLabel(Object object, ILabelRequestMonitor result, String[] columns)
{
IVMContext vmc = getVmcForObject(object);
if (vmc == null) {
result.done();
return;
}
vmc.getLayoutNode().retrieveLabel(vmc, result, columns);
}
public ModelProxy getModelProxy() {
return fModelProxy;
}
/**
* Creates the column presentation for the given object. This method is meant
* to be overriden by deriving class to provide view-specific functionality.
* The default is to return null, meaning no columns.
* <p>
* The viewer only reads the column presentation for the root/input element of
* the tree/table, so the VMProvider must be configured to own the root element
* in the view in order for this setting to be effective.
* <p>
* Note: since the IColumnEditorFactoryAdapter interface is synchronous, and since
* column info is fairly static, this method is thread-safe, and it will
* not be called on the executor thread.
*
* @see IColumnPresentationFactoryAdapter#createColumnPresentation(IPresentationContext, Object)
*/
@ThreadSafe
public IColumnPresentation createColumnPresentation(Object element) {
return null;
}
/**
* Returns the ID of the column presentation for the given object. This method
* is meant to be overriden by deriving class to provide view-specific
* functionality. The default is to return null, meaning no columns.
* <p>
* The viewer only reads the column presentation for the root/input element of
* the tree/table, so the VMProvider must be configured to own the root element
* in the view in order for this setting to be effective.
* <p>
* Note: since the IColumnEditorFactoryAdapter interface is synchronous, and since
* column info is fairly static, this method is thread-safe, and it will
* not be called on the executor thread.
*
* @see IColumnEditorFactoryAdapter#getColumnEditorId(IPresentationContext, Object)
*/
@ThreadSafe
public String getColumnPresentationId(Object element) {
return null;
}
public IColumnEditor createColumnEditor(Object element) {
IVMContext vmc = getVmcForObject(element);
if (vmc == null) {
return null;
}
return vmc.getLayoutNode().createColumnEditor(vmc);
}
public String getColumnEditorId(Object element) {
IVMContext vmc = getVmcForObject(element);
if (vmc == null) {
return null;
}
return vmc.getLayoutNode().getColumnEditorId(vmc);
}
/**
* 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.
*/
private IVMContext getVmcForObject(Object parent) {
/*
* 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 (parent.equals(rootLayoutNode.getRootVMC().getInputObject())) {
return rootLayoutNode.getRootVMC();
}
else if (parent 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)parent).getLayoutNode(),
new IVMLayoutNode[] { rootLayoutNode } ))
{
return (IVMContext)parent;
}
}
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;
}
/**
* Handle "data model changed" event by generating a delta object for each
* view and passing it to the corresponding view model provider. The view
* model provider is then responsible for filling-in and sending the delta
* to the viewer.
* @param e
*/
@DsfServiceEventHandler
public void eventDispatched(final IDMEvent<?> event) {
IVMRootLayoutNode rootLayoutNode = getRootLayoutNode();
if (rootLayoutNode != null && rootLayoutNode.hasDeltaFlags(event)) {
rootLayoutNode.createDelta(event, new GetDataDone<IModelDelta>() {
public void run() {
if (getStatus().isOK()) {
fModelProxy.fireModelChangedNonDispatch(getData());
}
}
@Override public String toString() {
return "Result of a delta for event: '" + event.toString() + "' in VMP: '" + VMProvider.this + "'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
});
}
}
@ThreadSafe
public class ModelProxy extends AbstractModelProxy {
/**
* Counter for whether the model proxy is currently installed in the viewer.
* Data model events are processed only if the model proxy is active.
*/
private int fProxyActive = 0;
/**
* 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; }
};
public void installed() {
fProxyActive++;
}
public void dispose() {
fProxyActive--;
super.dispose();
}
/**
* 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) {
if (fProxyActive <= 0) return;
Job job = new Job("Processing view model delta.") { //$NON-NLS-1$
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,44 @@
/*******************************************************************************
* 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 org.eclipse.dd.dsf.concurrent.ThreadSafe;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter;
/**
* Base implementation for DSF-based view model adapters.
*/
@ThreadSafe
abstract public class AbstractDMVMAdapter extends AbstractVMAdapter
{
private final DsfSession fSession;
/**
* Constructor for the View Model session. It is tempting to have the
* adapter register itself here with the session as the model adapter, but
* that would mean that the adapter might get accessed on another thread
* even before the deriving class is fully constructed. So it it better
* to have the owner of this object register it with the session.
* @param session
*/
public AbstractDMVMAdapter(DsfSession session) {
super();
fSession = session;
}
/**
* Returns the DSF session that this adapter is associated with.
* @return
*/
protected DsfSession getSession() { return fSession; }
}

View file

@ -0,0 +1,501 @@
/*******************************************************************************
* 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.Done;
import org.eclipse.dd.dsf.concurrent.DsfRunnable;
import org.eclipse.dd.dsf.concurrent.GetDataDone;
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.IDMData;
import org.eclipse.dd.dsf.datamodel.IDMEvent;
import org.eclipse.dd.dsf.datamodel.IDMService;
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.IColumnPresentationFactoryAdapter;
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.resource.ImageDescriptor;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.RGB;
/**
* 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<V extends IDMData> 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().
*/
@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);
}
}
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);
}
public int hashCode() {
return AbstractDMVMLayoutNode.this.hashCode() + fDmc.hashCode();
}
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<V>> 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<V>> dmcClassType) {
super(provider);
fSession = session;
fServicesTracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), session.getId());
fDMCClassType = dmcClassType;
}
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;
}
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) {
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
updateHasElementsInSessionThread(updates);
}});
}
protected void updateHasElementsInSessionThread(IHasChildrenUpdate[] updates) {
for (final IHasChildrenUpdate update : updates) {
if (!checkUpdate(update)) return;
updateElementsInSessionThread(
new ElementsUpdate(
new GetDataDone<List<Object>>() {
public void run() {
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;
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
// After every dispatch, must check if update still valid.
if (!checkUpdate(update)) return;
updateElementCountInSessionThread(update);
}});
}
protected void updateElementCountInSessionThread(final IChildrenCountUpdate update) {
updateElementsInSessionThread(
new ElementsUpdate(
new GetDataDone<List<Object>>() {
public void run() {
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;
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
// After every dispatch, must check if update still valid.
if (!checkUpdate(update)) return;
updateElementsInSessionThread(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);
}
}
}
/**
* The default implementation of the retrieve label method. It acquires
* the service, using parameters in the DMC, then it fetches the model
* data from the service, and then it calls the protected method
* fillColumnLabel() for each column. The deriving classes should override
* this method if a different method of computing the label is needed.
*
* @see #fillColumnLabel(IDMData, String, int, String[], ImageDescriptor[], FontData[], RGB[], RGB[])
*/
protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
for (final ILabelUpdate update : updates) {
final DMVMContext vmc = (DMVMContext)update.getElement();
if (!checkService(null, vmc.getDMC().getServiceFilter(), update)) return;
final IDMContext<V> dmc = findDmcInPath(update.getElementPath(), fDMCClassType);
((IDMService)getServicesTracker().getService(null, vmc.getDMC().getServiceFilter())).getModelData(
dmc,
new GetDataDone<V>() {
public void run() {
/*
* 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() || !getData().isValid()) {
assert getStatus().isOK() ||
getStatus().getCode() != IDsfService.INTERNAL_ERROR ||
getStatus().getCode() != IDsfService.NOT_SUPPORTED;
handleFailedUpdate(update);
return;
}
/*
* If columns are configured, call the protected methods to
* fill in column values.
*/
String[] localColumns = update.getPresentationContext().getColumns();
if (localColumns == null) localColumns = new String[] { null };
for (int i = 0; i < localColumns.length; i++) {
fillColumnLabel(dmc, getData(), localColumns[i], i, update);
}
update.done();
}
});
}
}
/**
* Fills in label information for given column. This method is intended to
* be overriden by deriving classes, to supply label information specific
* to the node. <br>
* The implementation should fill in the correct value in each array at the
* given index.
* @param dmContext Data Model Context object for which the label is generated.
* @param dmData Data Model Data object retrieved from the model service.
* for the DM Context supplied to the retrieveLabel() call.
* @param columnId Name of the column to fill in, null if no columns specified.
* @param idx Index to fill in in the label arrays.
* @param update Update object to fill information to
*
* @see IElementLabelProvider
* @see IColumnPresentationFactoryAdapter
*/
protected void fillColumnLabel(IDMContext<V> dmContext, V dmData, String columnId, int idx, ILabelUpdate update) {
update.setLabel("", idx); //$NON-NLS-1$
}
@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(IDMEvent<?> e) {
return IModelDelta.NO_CHANGE;
}
@Override
public void buildDelta(final Object e, final VMDelta parentDelta, final int nodeOffset, final Done done) {
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, done);
}
});
} else {
if (isDisposed()) return;
getExecutor().execute(done);
}
} else {
super.buildDelta(e, parentDelta, nodeOffset, done);
}
}
/**
* 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 Done done) {
IDMContext<V> 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 = new DMVMContext(DMContexts.getAncestorOfType(event.getDMContext(), fDMCClassType));
final Map<IVMLayoutNode,Integer> childNodeDeltas = getChildNodesWithDeltas(event);
if (childNodeDeltas.size() == 0) {
// There are no child nodes with deltas, just return to parent.
getExecutor().execute(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 GetDataDone<List<Object>>() {
public void run() {
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()) {
getExecutor().execute(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.
getExecutor().execute(done);
}
VMDelta delta = parentDelta.addNode(vmc, nodeOffset + i, IModelDelta.NO_CHANGE);
callChildNodesToBuildDelta(childNodeDeltas, delta, event, done);
}
},
parentDelta));
} else {
VMDelta delta = parentDelta.addNode(vmc, IModelDelta.NO_CHANGE);
callChildNodesToBuildDelta(childNodeDeltas, delta, event, done);
}
} else {
// The for this node was not found in the event. Call the
// super-class to resort to the default behavior which may add a
// delta node for every element in this node.
super.buildDelta(event, parentDelta, nodeOffset, done);
}
}
/**
* 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<V>[] 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<V>[] dmcs) {
int startIdx = update.getOffset() != -1 ? update.getOffset() : 0;
int endIdx = update.getLength() != -1 ? startIdx + update.getLength() : dmcs.length;
for (int i = startIdx; i < endIdx; i++) {
update.setChild(new DMVMContext(dmcs[i]), i);
}
}
/**
* 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().getRootLayoutNode().getRootObject();
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,139 @@
/*******************************************************************************
* 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.dd.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.dd.dsf.concurrent.GetDataDone;
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.IVMRootLayoutNode;
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.provisional.IAsynchronousContentAdapter;
import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousLabelAdapter;
/**
* 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
* to be configured with each provider.
* <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.
*
* @see IAsynchronousContentAdapter
* @see IAsynchronousLabelAdapter
* @see IModelProxy
* @see IVMLayoutNode
*/
@ConfinedToDsfExecutor("fSession#getExecutor")
@SuppressWarnings("restriction")
abstract public class AbstractDMVMProvider extends AbstractVMProvider
{
private final DsfSession fSession;
/**
* It is theoretically possible for a VMProvider to be disposed before it
* has a chance to register itself as event listener. This flag is used
* to avoid removing itself as listener in such situation.
*/
private boolean fRegisteredAsEventListener = false;
/**
* Constructs the view model provider for given DSF session. The
* constructor is thread-safe to allow VM provider to be constructed
* synchronously when a call to getAdapter() is made on an element
* in a view.
*/
public AbstractDMVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext, DsfSession session) {
super(adapter, presentationContext);
fSession = session;
// Add ourselves as listener for DM events events.
try {
session.getExecutor().execute(new Runnable() {
public void run() {
if (DsfSession.isSessionActive(getSession().getId())) {
getSession().addServiceEventListener(AbstractDMVMProvider.this, null);
fRegisteredAsEventListener = true;
}
}
});
} catch (RejectedExecutionException e) {
// Session shut down, not much we can do but wait to be disposed.
}
}
/** Called to dispose the provider. */
public void dispose() {
try {
getSession().getExecutor().execute(new Runnable() {
public void run() {
if (DsfSession.isSessionActive(getSession().getId()) && fRegisteredAsEventListener ) {
fSession.removeServiceEventListener(AbstractDMVMProvider.this);
}
}
});
} catch (RejectedExecutionException e) {
// Session shut down.
}
super.dispose();
}
protected 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
* model provider is then responsible for filling-in and sending the delta
* to the viewer.
* @param e
*/
@DsfServiceEventHandler
public void eventDispatched(final IDMEvent<?> event) {
if (isDisposed()) return;
// 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 GetDataDone<IModelDelta>() {
public void run() {
if (getStatus().isOK()) {
getModelProxy().fireModelChangedNonDispatch(getData());
}
}
@Override public String toString() {
return "Result of a delta for event: '" + event.toString() + "' in VMP: '" + AbstractDMVMProvider.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.
}
}
}

View file

@ -86,7 +86,10 @@ public class DefaultDsfExecutor extends ScheduledThreadPoolExecutor
}
static void logException(Throwable t) {
ILog log = DsfPlugin.getDefault().getLog();
DsfPlugin plugin = DsfPlugin.getDefault();
if (plugin == null) return;
ILog log = plugin.getLog();
if (log != null) {
log.log(new Status(
IStatus.ERROR, DsfPlugin.PLUGIN_ID, -1, "Uncaught exception in DSF executor thread", t)); //$NON-NLS-1$
@ -222,6 +225,12 @@ public class DefaultDsfExecutor extends ScheduledThreadPoolExecutor
public TracingWrapperRunnable(Runnable runnable, int offset) {
super(offset);
fRunnable = runnable;
// Check if executable wasn't executed already.
if (DEBUG_EXECUTOR && fRunnable instanceof DsfExecutable) {
assert !((DsfExecutable)fRunnable).getSubmitted() : "Executable was previously executed."; //$NON-NLS-1$
((DsfExecutable)fRunnable).setSubmitted();
}
}
protected Object getExecutable() { return fRunnable; }
@ -229,11 +238,6 @@ public class DefaultDsfExecutor extends ScheduledThreadPoolExecutor
public void run() {
traceExecution();
// If debugging a DSF exeutable, mark that it was executed.
if (DEBUG_EXECUTOR && fRunnable instanceof DsfExecutable) {
((DsfExecutable)fRunnable).setExecuted();
}
// Finally invoke the runnable code.
fRunnable.run();
}
@ -251,11 +255,6 @@ public class DefaultDsfExecutor extends ScheduledThreadPoolExecutor
public T call() throws Exception {
traceExecution();
// If debugging a DSF exeutable, mark that it was executed.
if (DEBUG_EXECUTOR && fCallable instanceof DsfExecutable) {
((DsfExecutable)fCallable).setExecuted();
}
// Finally invoke the runnable code.
return fCallable.call();
}

View file

@ -35,9 +35,8 @@ import org.eclipse.dd.dsf.DsfPlugin;
* }
* </pre>
*/
public abstract class DoneCollector extends Done {
private final DsfExecutor fExecutor;
private Map<Done,Boolean> fDones = new HashMap<Done,Boolean>();
public abstract class DoneCollector<V extends Done> extends Done {
private Map<V,Boolean> fDones = new HashMap<V,Boolean>();
private int fDoneCounter;
/**
@ -47,39 +46,25 @@ public abstract class DoneCollector extends Done {
* execution of the last done, and in the same dispatch loop.
*
*/
public DoneCollector(DsfExecutor executor) {
public DoneCollector() {
setStatus(new MultiStatus(DsfPlugin.PLUGIN_ID, 0, "Collective status for set of sub-operations.", null)); //$NON-NLS-1$
fExecutor = executor;
}
/**
* Adds a new Done callback to this tracker's list.
* @param <V> Service-specific class of the Done callback, to avoid an
* unnecessary cast.
* @param <T> Client-specific class of the Done callback, it's used here to avoid an
* unnecessary cast by the client.
* @param done callback object to add to the tracker
* @return the done that was just added, it allows this method to be used
* inlined in service method calls
*/
public <V extends Done> V add(V done) {
public <T extends V> T add(T done) {
assert !fDones.containsKey(done);
fDones.put(done, false);
fDoneCounter++;
return done;
}
/**
* Adds a Done which performs no actions. This is useful if all work
* is performed inside DoneCollector.run().
* @return Done which is to be passed as an argument to a service method.
*/
public Done addNoActionDone() {
return add(new Done() {
public void run() {
doneDone(this);
}
});
}
/**
* Marks the given Done callback as completed. Client implementations of
* the Done callback have to call this method in order for the tracker
@ -88,13 +73,15 @@ public abstract class DoneCollector extends Done {
* Note: funniest method signature ever!
* @param done
*/
public void doneDone(Done done) {
public void doneDone(V done) {
((MultiStatus)getStatus()).merge(done.getStatus());
assert fDones.containsKey(done);
fDones.put(done, true);
assert fDoneCounter > 0;
fDoneCounter--;
if (fDoneCounter == 0) {
assert !fDones.containsValue(false);
fExecutor.execute(this);
run();
}
}
@ -104,10 +91,15 @@ public abstract class DoneCollector extends Done {
* done callbacks.
* @return map of the done callbacks.
*/
public Map<Done,Boolean> getDones() { return fDones; }
public Map<V,Boolean> getDones() { return fDones; }
@Override
public String toString() {
return "Done Collector: " + getStatus().toString(); //$NON-NLS-1$
}
@Override
protected boolean isExecutionRequired() {
return false;
}
}

View file

@ -62,7 +62,7 @@ public class DsfExecutable {
* Flag indicating whether this executable was ever executed by an
* executor. Used for tracing only.
*/
private boolean fExecuted = false;
private boolean fSubmitted = false;
@SuppressWarnings("unchecked")
public DsfExecutable() {
@ -97,17 +97,31 @@ public class DsfExecutable {
}
}
boolean getSubmitted() {
return fSubmitted;
}
/**
* Marks this executable to indicate that it has been executed by the
* executor. To be invoked only by DsfExecutor.
*/
void setExecuted() {
fExecuted = true;
void setSubmitted() {
fSubmitted = true;
}
/**
* Returns whether the runnable/callable is expected to be always executed.
* Overriding classes can implement this method and return false, to avoid
* unnecessary trace output.
* @return true if this runnable is expected to run.
*/
protected boolean isExecutionRequired() {
return true;
}
@Override
protected void finalize() {
if (DEBUG_EXECUTOR && !fExecuted) {
if (DEBUG_EXECUTOR && !fSubmitted && isExecutionRequired()) {
StringBuilder traceBuilder = new StringBuilder();
// Record the time

View file

@ -12,7 +12,6 @@ package org.eclipse.dd.dsf.datamodel;
import org.eclipse.core.runtime.PlatformObject;
import org.eclipse.dd.dsf.concurrent.Immutable;
import org.eclipse.dd.dsf.service.AbstractDsfService;
import org.eclipse.dd.dsf.service.DsfSession;
/**
@ -40,10 +39,8 @@ abstract public class AbstractDMContext<V extends IDMData> extends PlatformObjec
}
/** Convenience constructor */
public AbstractDMContext(AbstractDsfService service, IDMContext<?> parent) {
this(service.getSession().getId(),
service.getServiceFilter(),
parent == null ? new IDMContext[] {} : new IDMContext[] { parent });
public AbstractDMContext(IDMService service, IDMContext<?>[] parents) {
this(service.getSession().getId(), service.getServiceFilter(), parents);
}
/**

View file

@ -10,7 +10,6 @@
*******************************************************************************/
package org.eclipse.dd.dsf.datamodel;
import org.eclipse.dd.dsf.service.AbstractDsfService;
/**
* The Data Model Context representing the owner service. The service DM Context
@ -22,8 +21,8 @@ import org.eclipse.dd.dsf.service.AbstractDsfService;
public class ServiceDMContext<V extends IDMService> extends AbstractDMContext<V> {
String fServiceDMID;
public ServiceDMContext(AbstractDsfService service, String serviceDMID) {
super(service, null);
public ServiceDMContext(IDMService service, String serviceDMID) {
super(service, new IDMContext<?>[0]);
fServiceDMID = serviceDMID;
}

View file

@ -74,10 +74,14 @@ public interface IDsfService {
*/
final static int INTERNAL_ERROR = 10005;
/**
* Returns the DSF Session that this service belongs to.
*/
DsfSession getSession();
/**
* Returns the executor that should be used to call methods of this service.
* @return
* This method is equivalent to calling getSession().getExecutor()
*/
DsfExecutor getExecutor();