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:
parent
4a775182e0
commit
b191075ec4
31 changed files with 2619 additions and 1879 deletions
|
@ -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() {
|
||||
if (selection instanceof IStructuredSelection) {
|
||||
fRootVMC = new RootVMC<Object>( DebugViewSelectionRootLayoutNode.this,
|
||||
((IStructuredSelection)selection).getFirstElement() );
|
||||
} else {
|
||||
fRootVMC = new RootVMC<Object>( DebugViewSelectionRootLayoutNode.this, null );
|
||||
}
|
||||
fSelection = event.getContext();
|
||||
}
|
||||
|
||||
private IDMContext<?> getSelectedDMC() {
|
||||
Object selection = fSelection;
|
||||
if (selection instanceof IStructuredSelection) {
|
||||
IStructuredSelection structSelection = (IStructuredSelection)selection;
|
||||
if (structSelection.getFirstElement() instanceof DMVMContext)
|
||||
{
|
||||
return ((DMVMContext)structSelection.getFirstElement()).getDMC();
|
||||
}
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
return;
|
||||
}
|
||||
@Override
|
||||
protected void updateHasElementsInSessionThread(IHasChildrenUpdate[] updates) {
|
||||
|
||||
done.setData(getServicesTracker().getService(IStack.class).isStackAvailable(execDmc));
|
||||
getExecutor().execute(done);
|
||||
for (IHasChildrenUpdate update : updates) {
|
||||
if (!checkService(IStack.class, null, update)) return;
|
||||
|
||||
IExecutionDMContext execDmc = findDmcInPath(update.getElementPath(), IExecutionDMContext.class);
|
||||
if (execDmc == null) {
|
||||
handleFailedUpdate(update);
|
||||
return;
|
||||
}
|
||||
|
||||
update.setHasChilren(getServicesTracker().getService(IStack.class).isStackAvailable(execDmc));
|
||||
update.done();
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
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 (getServicesTracker().getService(IRunControl.class).isStepping(execDmc)) {
|
||||
getElementsTopStackFrameOnly(parentVmc, done);
|
||||
} else {
|
||||
propagateError(getExecutor(), done, "Failed retrieving stack frames"); //$NON-NLS-1$
|
||||
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(update);
|
||||
} else {
|
||||
update.done();
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
// Store the VMC element array, in case we need to use it when
|
||||
fCachedOldFrameVMCs = dmcs2vmcs(getData());
|
||||
for (int i = 0; i < fCachedOldFrameVMCs.length; i++) update.setChild(fCachedOldFrameVMCs[i], i);
|
||||
update.done();
|
||||
}
|
||||
// Store the VMC element array, in case we need to use it when
|
||||
fCachedOldFramesVMCs = dmcs2vmcs(parentVmc, getData());
|
||||
done.setData(fCachedOldFramesVMCs);
|
||||
getExecutor().execute(done);
|
||||
}});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -89,184 +102,197 @@ 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 (!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 (fCachedOldFramesVMCs != null && fCachedOldFramesVMCs.length >= 1) {
|
||||
fCachedOldFramesVMCs[0] = topFrameVmc;
|
||||
done.setData(fCachedOldFramesVMCs);
|
||||
if (fCachedOldFrameVMCs != null && fCachedOldFrameVMCs.length >= 1) {
|
||||
fCachedOldFrameVMCs[0] = topFrameVmc;
|
||||
for (int i = 0; i < fCachedOldFrameVMCs.length; i++) update.setChild(fCachedOldFrameVMCs[i], i);
|
||||
} else {
|
||||
done.setData(new IVMContext[] { topFrameVmc });
|
||||
update.setChild(topFrameVmc, 0);
|
||||
}
|
||||
getExecutor().execute(done);
|
||||
update.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();
|
||||
return;
|
||||
}
|
||||
|
||||
@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) });
|
||||
update.setImageDescriptor(DebugUITools.getImageDescriptor(imageKey), 0);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//
|
||||
// Finally, if all goes well, set the label.
|
||||
//
|
||||
StringBuilder label = new StringBuilder();
|
||||
|
||||
// Add frame number (if total number of frames in known)
|
||||
if (fCachedOldFramesVMCs != null) {
|
||||
label.append(fCachedOldFramesVMCs.length - getData().getLevel());
|
||||
}
|
||||
|
||||
// Add the function name
|
||||
if (getData().getFunction() != null && getData().getFunction().length() != 0) {
|
||||
label.append(" "); //$NON-NLS-1$
|
||||
label.append(getData().getFunction());
|
||||
label.append("()"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
// Add full file name
|
||||
if (getData().getFile() != null && getData().getFile().length() != 0) {
|
||||
label.append(" at "); //$NON-NLS-1$
|
||||
label.append(getData().getFile());
|
||||
}
|
||||
|
||||
// Add line number
|
||||
if (getData().getLine() >= 0) {
|
||||
label.append(":"); //$NON-NLS-1$
|
||||
label.append(getData().getLine());
|
||||
label.append(" "); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
// Add the address
|
||||
label.append(getData().getAddress());
|
||||
|
||||
// Set the label to the result listener
|
||||
result.setLabels(new String[] { label.toString() });
|
||||
result.done();
|
||||
}});
|
||||
//
|
||||
// Finally, if all goes well, set the label.
|
||||
//
|
||||
StringBuilder label = new StringBuilder();
|
||||
|
||||
// Add frame number (if total number of frames in known)
|
||||
if (fCachedOldFrameVMCs != null) {
|
||||
label.append(fCachedOldFrameVMCs.length - dmData.getLevel());
|
||||
}
|
||||
|
||||
// Add the function name
|
||||
if (dmData.getFunction() != null && dmData.getFunction().length() != 0) {
|
||||
label.append(" "); //$NON-NLS-1$
|
||||
label.append(dmData.getFunction());
|
||||
label.append("()"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
// Add full file name
|
||||
if (dmData.getFile() != null && dmData.getFile().length() != 0) {
|
||||
label.append(" at "); //$NON-NLS-1$
|
||||
label.append(dmData.getFile());
|
||||
}
|
||||
|
||||
// Add line number
|
||||
if (dmData.getLine() >= 0) {
|
||||
label.append(":"); //$NON-NLS-1$
|
||||
label.append(dmData.getLine());
|
||||
label.append(" "); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
// Add the address
|
||||
label.append(dmData.getAddress());
|
||||
|
||||
// Set the label to the result listener
|
||||
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())) {
|
||||
parent.addFlags(IModelDelta.CONTENT);
|
||||
}
|
||||
|
||||
// Always expand the thread node to show the stack frames.
|
||||
parent.addFlags(IModelDelta.EXPAND);
|
||||
|
||||
// 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);
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
// 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, done);
|
||||
}});
|
||||
StackFramesLayoutNode.super.buildDeltaForDMEvent(e, parent, done);
|
||||
} else {
|
||||
// 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);
|
||||
}
|
||||
} else if (e instanceof IStepQueueManager.ISteppingTimedOutEvent) {
|
||||
// Repaint the stack frame images to have the running symbol.
|
||||
// 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 (!runControlService.isStepping(e.getDMContext())) {
|
||||
parent.addFlags(IModelDelta.CONTENT);
|
||||
super.buildDeltaForDMEvent(e, parent, done);
|
||||
} else {
|
||||
// Call super-class to build sub-node delta's.
|
||||
super.buildDeltaForDMEvent(e, parent, done);
|
||||
}
|
||||
|
||||
// Always expand the thread node to show the stack frames.
|
||||
parent.addFlags(IModelDelta.EXPAND);
|
||||
|
||||
// Retrieve the list of stack frames, and mark the top frame to be selected.
|
||||
getElementsTopStackFrameOnly(
|
||||
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().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, nodeOffset, done);
|
||||
}
|
||||
},
|
||||
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);
|
||||
fCachedOldFrameVMCs = null;
|
||||
}
|
||||
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, nodeOffset, done);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()) {
|
||||
public void run() {
|
||||
if (propagateError(getExecutor(), done, "Failed to generate child deltas.")) return; //$NON-NLS-1$
|
||||
done.setData(delta);
|
||||
getExecutor().execute(done);
|
||||
}
|
||||
};
|
||||
for (final IVMLayoutNode childNode : childNodes) {
|
||||
childNode.buildDelta(event, rootDelta, doneCollector.addNoActionDone());
|
||||
}
|
||||
callChildNodesToBuildDelta(
|
||||
childNodeDeltas, rootDelta, event,
|
||||
new Done() {
|
||||
public void run() {
|
||||
if (propagateError(getExecutor(), done, "Failed to create delta.")); //$NON-NLS-1$
|
||||
done.setData(viewRootDelta);
|
||||
getExecutor().execute(done);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public IRootVMC getRootVMC() {
|
||||
return fRootVMC;
|
||||
public Object getRootObject() {
|
||||
return fLaunch;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
assert false;
|
||||
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 &&
|
||||
(de.getKind() == DebugEvent.CHANGE ||
|
||||
de.getKind() == DebugEvent.CREATE ||
|
||||
de.getKind() == DebugEvent.TERMINATE);
|
||||
if ( de.getSource() instanceof IProcess &&
|
||||
(de.getKind() == DebugEvent.CHANGE ||
|
||||
de.getKind() == DebugEvent.CREATE ||
|
||||
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) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 void hasElements( final IVMContext parentVmc , final GetDataDone<Boolean> done ) {
|
||||
final IExecutionDMContext execDmc = findDmcInVmc(parentVmc, IExecutionDMContext.class);
|
||||
|
||||
if (execDmc == null || getServicesTracker().getService(IRegisters.class) == null) {
|
||||
done.setData(Boolean.FALSE);
|
||||
getExecutor().execute(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(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 );
|
||||
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);
|
||||
}});
|
||||
public RegisterGroupLayoutNode(AbstractVMProvider provider, DsfSession session) {
|
||||
super(provider, session, IRegisters.IRegisterGroupDMContext.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fillColumnLabel(IDMContext<IRegisterGroupData> dmContext, IRegisterGroupData dmData,
|
||||
String columnId, int idx, String[] text, ImageDescriptor[] image,
|
||||
FontData[] fontData, RGB[] foreground, RGB[] background)
|
||||
{
|
||||
if (RegisterColumnPresentation.COL_NAME.equals(columnId)) {
|
||||
text[idx] = dmData.getName();
|
||||
} else if (RegisterColumnPresentation.COL_VALUE.equals(columnId)) {
|
||||
text[idx] = ""; //$NON-NLS-1$
|
||||
} else if (RegisterColumnPresentation.COL_DESCRIPTION.equals(columnId)) {
|
||||
text[idx] = dmData.getDescription();
|
||||
}
|
||||
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
|
||||
if (!checkService(IRegisters.class, null, update)) 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 (!getStatus().isOK()) {
|
||||
update.done();
|
||||
return;
|
||||
}
|
||||
fillUpdateWithVMCs(update, getData());
|
||||
update.done();
|
||||
}});
|
||||
} else {
|
||||
handleFailedUpdate(update);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
@Override
|
||||
protected void fillColumnLabel(IDMContext<IRegisterGroupData> dmContext, IRegisterGroupData 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("", idx); //$NON-NLS-1$
|
||||
} else if (RegisterColumnPresentation.COL_DESCRIPTION.equals(columnId)) {
|
||||
update.setLabel(dmData.getDescription(), idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,112 +20,86 @@ 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();
|
||||
if ("".equals(size)) { //$NON-NLS-1$
|
||||
if ( value.contains( "uint64" ) ) { //$NON-NLS-1$
|
||||
size = "64 bit register" ; //$NON-NLS-1$
|
||||
} else if ( value.contains( "v4_float" ) ) { //$NON-NLS-1$
|
||||
size = "128 bit register" ; //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
result.setLabels(new String[] { getData().getName(), getData().getHexValue(), size });
|
||||
}
|
||||
|
||||
result.done() ;
|
||||
return ;
|
||||
@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$
|
||||
} else if ( value.contains( "v4_float" ) ) { //$NON-NLS-1$
|
||||
size = "128 bit register" ; //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
) ;
|
||||
update.setLabel(size, idx);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasDeltaFlagsForDMEvent( IDMEvent<?> e ) {
|
||||
return (e instanceof IRunControl.ISuspendedDMEvent) || super.hasDeltaFlagsForDMEvent(e) ;
|
||||
@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 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
protected DsfSession getSession() { return fSession; }
|
||||
/**
|
||||
* Returns the executor that will be used to communicate with the providers
|
||||
* and the layout nodes.
|
||||
* @return
|
||||
*/
|
||||
public Executor getExecutor() {
|
||||
return fExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
// 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 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 {
|
||||
getExecutor().execute(new DsfRunnable() {
|
||||
public void run() {
|
||||
IPresentationContext context = null;
|
||||
int firstIdx = 0;
|
||||
int curIdx = 0;
|
||||
for (curIdx = 0; curIdx < updates.length; curIdx++) {
|
||||
if (!updates[curIdx].getPresentationContext().equals(context)) {
|
||||
if (context != null) {
|
||||
callProviderWithUpdate(updates, firstIdx, curIdx);
|
||||
}
|
||||
context = updates[curIdx].getPresentationContext();
|
||||
firstIdx = curIdx;
|
||||
}
|
||||
}
|
||||
callProviderWithUpdate(updates, firstIdx, curIdx);
|
||||
}
|
||||
});
|
||||
} catch(RejectedExecutionException e) {
|
||||
}
|
||||
}
|
||||
|
||||
private void callProviderWithUpdate(IViewerUpdate[] updates, int startIdx, int endIdx) {
|
||||
final IVMProvider provider = getViewModelProvider(updates[0].getPresentationContext());
|
||||
if (provider == null) {
|
||||
for (IViewerUpdate update : updates) {
|
||||
update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR,
|
||||
"No model provider for update " + update, null)); //$NON-NLS-1$
|
||||
update.done();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (startIdx == 0 && endIdx == updates.length) {
|
||||
if (updates instanceof IHasChildrenUpdate[]) provider.update((IHasChildrenUpdate[])updates);
|
||||
else if (updates instanceof IChildrenCountUpdate[]) provider.update((IChildrenCountUpdate[])updates);
|
||||
else if (updates instanceof IChildrenUpdate[]) provider.update((IChildrenUpdate[])updates);
|
||||
} else {
|
||||
if (updates instanceof IHasChildrenUpdate[]) {
|
||||
IHasChildrenUpdate[] providerUpdates = new IHasChildrenUpdate[endIdx - startIdx];
|
||||
System.arraycopy(updates, startIdx, providerUpdates, 0, endIdx - startIdx);
|
||||
provider.update(providerUpdates);
|
||||
}
|
||||
else if (updates instanceof IChildrenCountUpdate[]) {
|
||||
IChildrenCountUpdate[] providerUpdates = new IChildrenCountUpdate[endIdx - startIdx];
|
||||
System.arraycopy(updates, startIdx, providerUpdates, 0, endIdx - startIdx);
|
||||
provider.update(providerUpdates);
|
||||
}
|
||||
else if (updates instanceof IChildrenUpdate[]) {
|
||||
IChildrenUpdate[] providerUpdates = new IChildrenUpdate[endIdx - startIdx];
|
||||
System.arraycopy(updates, startIdx, providerUpdates, 0, endIdx - startIdx);
|
||||
provider.update(providerUpdates);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (VMProvider provider : fViewModelProviders.values()) {
|
||||
provider.dispose();
|
||||
}
|
||||
fViewModelProviders.clear();
|
||||
}
|
||||
|
||||
public void retrieveLabel(final Object object, final IPresentationContext context, final ILabelRequestMonitor 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: " + object.toString(), null)); //$NON-NLS-1$
|
||||
result.done();
|
||||
}
|
||||
provider.retrieveLabel(object, result, context.getColumns());
|
||||
}
|
||||
@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);
|
||||
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();
|
||||
}
|
||||
provider.isContainer(element, result);
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
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 (fDisposed) return;
|
||||
|
||||
// Check for an empty list of elements. If it's empty then we
|
||||
// don't have to call the children nodes, so return here.
|
||||
// No need to propagate error, there's no means or need to display it.
|
||||
if (!getStatus().isOK() || getData().size() == 0) {
|
||||
getExecutor().execute(done);
|
||||
return;
|
||||
}
|
||||
|
||||
final DoneCollector<Done> elementsDeltasDoneCollector = new DoneCollector<Done>() {
|
||||
public void run() {
|
||||
if (isDisposed()) return;
|
||||
getExecutor().execute(done);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* 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[]>() {
|
||||
public void run() {
|
||||
if (propagateError(getExecutor(), done, "Failed to retrieve elements in layout node " + AbstractVMLayoutNode.this)) return; //$NON-NLS-1$
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
getExecutor().execute(done);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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() {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
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#getColumnEditorId(IPresentationContext, Object)
|
||||
*/
|
||||
public String getColumnEditorId(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);
|
||||
}
|
||||
}
|
||||
|
||||
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()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method that returns a token value in case when the services
|
||||
* that the layout node depends on, are not available.
|
||||
*/
|
||||
protected void handleFailedRetrieveLabel(ILabelRequestMonitor result) {
|
||||
result.setLabels(new String[] { "..."} ); //$NON-NLS-1$
|
||||
result.done();
|
||||
return nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method that returns a token value in case when the services
|
||||
* that the layout node depends on, are not available.
|
||||
*/
|
||||
protected boolean checkUpdate(IViewerUpdate update) {
|
||||
if (update.isCanceled()) return false;
|
||||
if (fDisposed) {
|
||||
handleFailedUpdate(update);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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; }
|
||||
|
||||
/**
|
||||
* 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}.
|
||||
*/
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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,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 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 updateElementCount(IChildrenCountUpdate update) {
|
||||
update.setChildCount(1);
|
||||
update.done();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,9 +56,11 @@ 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 updateHasElements(IHasChildrenUpdate[] updates) {
|
||||
for (IHasChildrenUpdate update : updates) {
|
||||
update.setHasChilren(true);
|
||||
update.done();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -88,8 +68,8 @@ 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 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()) {
|
||||
public void run() {
|
||||
if (propagateError(getExecutor(), done, "Failed to generate child deltas.")) return; //$NON-NLS-1$
|
||||
done.setData(rootDelta);
|
||||
getExecutor().execute(done);
|
||||
}
|
||||
};
|
||||
for (final IVMLayoutNode childNode : childNodes) {
|
||||
childNode.buildDelta(event, rootDelta, doneCollector.addNoActionDone());
|
||||
}
|
||||
callChildNodesToBuildDelta(
|
||||
childNodeDeltas, rootDelta, event,
|
||||
new Done() {
|
||||
public void run() {
|
||||
if (isDisposed()) return;
|
||||
if (propagateError(getExecutor(), done, "Failed to create delta.")); //$NON-NLS-1$
|
||||
done.setData(rootDelta);
|
||||
getExecutor().execute(done);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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
|
||||
{
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -12,55 +12,67 @@ 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);
|
||||
|
||||
/**
|
||||
* Retrieves the list of elements.
|
||||
* @param parentVmc Parent node, for which to calculate elements at the
|
||||
* current level.
|
||||
* @param done The data return token.
|
||||
*/
|
||||
public void getElements(IVMContext parentVmc, GetDataDone<IVMContext[]> done);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public void retrieveLabel(IVMContext vmc, ILabelRequestMonitor result, String[] columns);
|
||||
public void updateHasElements(IHasChildrenUpdate[] updates);
|
||||
|
||||
/**
|
||||
* Retrieves the number of available elements in this node for the given
|
||||
* path in the viewer.
|
||||
*
|
||||
* @param updates The update object which needs to be filled in with result
|
||||
* calculated by this method.
|
||||
* Even though the "children" interface is reused, the updates refer to the
|
||||
* elements of this layout node, and not it's children.
|
||||
*/
|
||||
public void updateElementCount(IChildrenCountUpdate update);
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the element objects of this node for the given path in the
|
||||
* viewer, and for the given range of indexes. <br>
|
||||
* Note: the range of children, denoted by ILabelUpdate.getOffset()
|
||||
* and ILabelUpdate.getLength(), may not be specified, in which case these
|
||||
* methods may return -1. This means that all the elements should be
|
||||
* retrieved for this node.<br>
|
||||
*
|
||||
* @param updates The update object which needs to be filled in with result
|
||||
* calculated by this method.
|
||||
* Even though the "children" interface is reused, the updates refer to the
|
||||
* elements of this layout node, and not it's children.
|
||||
*/
|
||||
public void updateElements(IChildrenUpdate update);
|
||||
|
||||
|
||||
/**
|
||||
* Configures the child layout nodes for this node.
|
||||
* @param childNodes
|
||||
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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)}
|
||||
|
|
|
@ -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,21 +168,22 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the parent delta of this delta
|
||||
*
|
||||
|
@ -184,17 +192,19 @@ public class VMDelta extends ModelDelta {
|
|||
void setParent(VMDelta node) {
|
||||
fParent = node;
|
||||
}
|
||||
|
||||
|
||||
/* (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$
|
||||
|
@ -233,43 +246,78 @@ public class VMDelta extends ModelDelta {
|
|||
}
|
||||
|
||||
private void appendDetail(StringBuffer buf, VMDelta delta) {
|
||||
buf.append("\tElement: "); //$NON-NLS-1$
|
||||
buf.append(delta.getElement());
|
||||
buf.append('\n');
|
||||
buf.append("\t\tFlags: "); //$NON-NLS-1$
|
||||
int flags = delta.getFlags();
|
||||
if (flags == 0) {
|
||||
buf.append("NO_CHANGE"); //$NON-NLS-1$
|
||||
} else {
|
||||
if ((flags & IModelDelta.ADDED) > 0) {
|
||||
buf.append("ADDED | "); //$NON-NLS-1$
|
||||
}
|
||||
if ((flags & IModelDelta.CONTENT) > 0) {
|
||||
buf.append("CONTENT | "); //$NON-NLS-1$
|
||||
}
|
||||
if ((flags & IModelDelta.EXPAND) > 0) {
|
||||
buf.append("EXPAND | "); //$NON-NLS-1$
|
||||
}
|
||||
if ((flags & IModelDelta.INSERTED) > 0) {
|
||||
buf.append("INSERTED | "); //$NON-NLS-1$
|
||||
}
|
||||
if ((flags & IModelDelta.REMOVED) > 0) {
|
||||
buf.append("REMOVED | "); //$NON-NLS-1$
|
||||
}
|
||||
if ((flags & IModelDelta.REPLACED) > 0) {
|
||||
buf.append("REPLACED | "); //$NON-NLS-1$
|
||||
}
|
||||
if ((flags & IModelDelta.SELECT) > 0) {
|
||||
buf.append("SELECT | "); //$NON-NLS-1$
|
||||
}
|
||||
if ((flags & IModelDelta.STATE) > 0) {
|
||||
buf.append("STATE | "); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
buf.append('\n');
|
||||
VMDelta[] nodes = delta.getNodes();
|
||||
for (int i = 0; i < nodes.length; i++) {
|
||||
appendDetail(buf, nodes[i]);
|
||||
}
|
||||
buf.append("\tElement: "); //$NON-NLS-1$
|
||||
buf.append(delta.getElement());
|
||||
buf.append('\n');
|
||||
buf.append("\t\tFlags: "); //$NON-NLS-1$
|
||||
int flags = delta.getFlags();
|
||||
if (flags == 0) {
|
||||
buf.append("NO_CHANGE"); //$NON-NLS-1$
|
||||
} else {
|
||||
if ((flags & IModelDelta.ADDED) > 0) {
|
||||
buf.append("ADDED | "); //$NON-NLS-1$
|
||||
}
|
||||
if ((flags & IModelDelta.CONTENT) > 0) {
|
||||
buf.append("CONTENT | "); //$NON-NLS-1$
|
||||
}
|
||||
if ((flags & IModelDelta.EXPAND) > 0) {
|
||||
buf.append("EXPAND | "); //$NON-NLS-1$
|
||||
}
|
||||
if ((flags & IModelDelta.INSERTED) > 0) {
|
||||
buf.append("INSERTED | "); //$NON-NLS-1$
|
||||
}
|
||||
if ((flags & IModelDelta.REMOVED) > 0) {
|
||||
buf.append("REMOVED | "); //$NON-NLS-1$
|
||||
}
|
||||
if ((flags & IModelDelta.REPLACED) > 0) {
|
||||
buf.append("REPLACED | "); //$NON-NLS-1$
|
||||
}
|
||||
if ((flags & IModelDelta.SELECT) > 0) {
|
||||
buf.append("SELECT | "); //$NON-NLS-1$
|
||||
}
|
||||
if ((flags & IModelDelta.STATE) > 0) {
|
||||
buf.append("STATE | "); //$NON-NLS-1$
|
||||
}
|
||||
if ((flags & IModelDelta.INSTALL) > 0) {
|
||||
buf.append("INSTALL | "); //$NON-NLS-1$
|
||||
}
|
||||
if ((flags & IModelDelta.UNINSTALL) > 0) {
|
||||
buf.append("UNINSTALL | "); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
buf.append('\n');
|
||||
buf.append("\t\tIndex: "); //$NON-NLS-1$
|
||||
buf.append(delta.fIndex);
|
||||
buf.append(" Child Count: "); //$NON-NLS-1$
|
||||
buf.append(delta.fChildCount);
|
||||
buf.append('\n');
|
||||
IModelDelta[] nodes = delta.getChildDeltas();
|
||||
for (int i = 0; i < nodes.length; i++) {
|
||||
appendDetail(buf, (VMDelta)nodes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta#getChildCount()
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,12 +39,10 @@ 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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Should be used by the deriving class to compare the basic context object
|
||||
* information.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue