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;
|
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.DMContexts;
|
||||||
import org.eclipse.dd.dsf.datamodel.IDMContext;
|
import org.eclipse.dd.dsf.datamodel.IDMContext;
|
||||||
import org.eclipse.dd.dsf.datamodel.IDMEvent;
|
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.AbstractVMRootLayoutNode;
|
||||||
import org.eclipse.dd.dsf.ui.viewmodel.IVMRootLayoutNode;
|
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.DebugUITools;
|
||||||
import org.eclipse.debug.ui.contexts.DebugContextEvent;
|
import org.eclipse.debug.ui.contexts.DebugContextEvent;
|
||||||
import org.eclipse.debug.ui.contexts.IDebugContextListener;
|
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.
|
* 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.
|
* 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
|
public class DebugViewSelectionRootLayoutNode extends AbstractVMRootLayoutNode
|
||||||
implements IVMRootLayoutNode, IDebugContextListener
|
implements IVMRootLayoutNode, IDebugContextListener
|
||||||
{
|
{
|
||||||
private RootVMC<Object> fRootVMC;
|
private ISelection fSelection;
|
||||||
|
|
||||||
public DebugViewSelectionRootLayoutNode(DsfExecutor executor, IWorkbenchWindow window) {
|
public DebugViewSelectionRootLayoutNode(AbstractVMProvider provider) {
|
||||||
super(executor);
|
super(provider);
|
||||||
ISelection selection = DebugUITools.getDebugContextManager().getContextService(window).getActiveContext();
|
IWorkbenchWindow activeWindow = DsfDebugUIPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow();
|
||||||
if (selection instanceof IStructuredSelection) {
|
if (activeWindow != null) {
|
||||||
fRootVMC = new RootVMC<Object>( this, ((IStructuredSelection)selection).getFirstElement() );
|
fSelection = DebugUITools.getDebugContextManager().getContextService(activeWindow).getActiveContext();
|
||||||
} else {
|
|
||||||
fRootVMC = new RootVMC<Object>( this, null );
|
|
||||||
}
|
}
|
||||||
DebugUITools.getDebugContextManager().addDebugContextListener(this);
|
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
|
* Then we can filter the event to make sure that the view does not
|
||||||
* react to events that relate to objects outside this view.
|
* 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.
|
* determine whether a delta is needed.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean hasDeltaFlags(Object event) {
|
public int getDeltaFlags(Object event) {
|
||||||
if (event instanceof IDMEvent && fRootVMC.getInputObject() instanceof DMContextVMContext) {
|
IDMContext<?> inputDmc = getSelectedDMC();
|
||||||
|
if (event instanceof IDMEvent && inputDmc != null) {
|
||||||
boolean potentialMatchFound = false;
|
boolean potentialMatchFound = false;
|
||||||
boolean matchFound = false;
|
boolean matchFound = false;
|
||||||
|
|
||||||
IDMContext<?> eventDmc = ((IDMEvent)event).getDMContext();
|
IDMContext<?> eventDmc = ((IDMEvent)event).getDMContext();
|
||||||
IDMContext<?> inputDmc = ((DMContextVMContext)fRootVMC.getInputObject()).getDMC();
|
|
||||||
for (IDMContext<?> eventDmcAncestor : DMContexts.toList(eventDmc)) {
|
for (IDMContext<?> eventDmcAncestor : DMContexts.toList(eventDmc)) {
|
||||||
IDMContext<?> inputDmcAncestor = DMContexts.getAncestorOfType(inputDmc, eventDmcAncestor.getClass());
|
IDMContext<?> inputDmcAncestor = DMContexts.getAncestorOfType(inputDmc, eventDmcAncestor.getClass());
|
||||||
if (inputDmcAncestor != null) {
|
if (inputDmcAncestor != null) {
|
||||||
potentialMatchFound = true;
|
potentialMatchFound = true;
|
||||||
if (inputDmcAncestor.equals(eventDmcAncestor)) {
|
if (inputDmcAncestor.equals(eventDmcAncestor)) {
|
||||||
matchFound = true;
|
return super.getDeltaFlags(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (potentialMatchFound && !matchFound) {
|
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) {
|
public void debugContextChanged(DebugContextEvent event) {
|
||||||
final ISelection selection = event.getContext();
|
fSelection = event.getContext();
|
||||||
getExecutor().execute(new DsfRunnable() {
|
}
|
||||||
public void run() {
|
|
||||||
|
private IDMContext<?> getSelectedDMC() {
|
||||||
|
Object selection = fSelection;
|
||||||
if (selection instanceof IStructuredSelection) {
|
if (selection instanceof IStructuredSelection) {
|
||||||
fRootVMC = new RootVMC<Object>( DebugViewSelectionRootLayoutNode.this,
|
IStructuredSelection structSelection = (IStructuredSelection)selection;
|
||||||
((IStructuredSelection)selection).getFirstElement() );
|
if (structSelection.getFirstElement() instanceof DMVMContext)
|
||||||
} else {
|
{
|
||||||
fRootVMC = new RootVMC<Object>( DebugViewSelectionRootLayoutNode.this, null );
|
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;
|
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.Done;
|
||||||
import org.eclipse.dd.dsf.concurrent.GetDataDone;
|
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.datamodel.IDMEvent;
|
||||||
import org.eclipse.dd.dsf.debug.service.IRunControl;
|
import org.eclipse.dd.dsf.debug.service.IRunControl;
|
||||||
import org.eclipse.dd.dsf.debug.service.IStack;
|
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.IRunControl.StateChangeReason;
|
||||||
import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext;
|
import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext;
|
||||||
import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMData;
|
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.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.IVMContext;
|
||||||
import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
|
import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.ILabelRequestMonitor;
|
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta;
|
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.DebugUITools;
|
||||||
import org.eclipse.debug.ui.IDebugUIConstants;
|
import org.eclipse.debug.ui.IDebugUIConstants;
|
||||||
import org.eclipse.jface.resource.ImageDescriptor;
|
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("restriction")
|
@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) {
|
public StackFramesLayoutNode(AbstractVMProvider provider, DsfSession session) {
|
||||||
super(session, IStack.IFrameDMContext.class);
|
super(provider, session, IStack.IFrameDMContext.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void hasElements(IVMContext parentVmc, final GetDataDone<Boolean> done) {
|
@Override
|
||||||
IExecutionDMContext execDmc = findDmcInVmc(parentVmc, IExecutionDMContext.class);
|
protected void updateHasElementsInSessionThread(IHasChildrenUpdate[] updates) {
|
||||||
if (execDmc == null || getServicesTracker().getService(IStack.class) == null || getServicesTracker().getService(IRunControl.class) == null) {
|
|
||||||
done.setData(false);
|
for (IHasChildrenUpdate update : updates) {
|
||||||
getExecutor().execute(done);
|
if (!checkService(IStack.class, null, update)) return;
|
||||||
|
|
||||||
|
IExecutionDMContext execDmc = findDmcInPath(update.getElementPath(), IExecutionDMContext.class);
|
||||||
|
if (execDmc == null) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
done.setData(getServicesTracker().getService(IStack.class).isStackAvailable(execDmc));
|
update.setHasChilren(getServicesTracker().getService(IStack.class).isStackAvailable(execDmc));
|
||||||
getExecutor().execute(done);
|
update.done();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void getElements(final IVMContext parentVmc, final GetDataDone<IVMContext[]> done) {
|
@Override
|
||||||
final IExecutionDMContext execDmc = findDmcInVmc(parentVmc, IExecutionDMContext.class);
|
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
|
||||||
if (execDmc == null || getServicesTracker().getService(IStack.class) == null || getServicesTracker().getService(IRunControl.class) == null) {
|
if (!checkService(IStack.class, null, update)) return;
|
||||||
done.setData(new IVMContext[0]);
|
|
||||||
getExecutor().execute(done);
|
final IExecutionDMContext execDmc = findDmcInPath(update.getElementPath(), IExecutionDMContext.class);
|
||||||
|
if (execDmc == null) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
getServicesTracker().getService(IStack.class).getFrames(
|
getServicesTracker().getService(IStack.class).getFrames(
|
||||||
execDmc,
|
execDmc,
|
||||||
new GetDataDone<IFrameDMContext[]>() { public void run() {
|
new GetDataDone<IFrameDMContext[]>() {
|
||||||
|
public void run() {
|
||||||
if (!getStatus().isOK()) {
|
if (!getStatus().isOK()) {
|
||||||
// Failed to retrieve frames. If we are stepping, we
|
// Failed to retrieve frames. If we are stepping, we
|
||||||
// might still be able to retrieve just the top stack
|
// might still be able to retrieve just the top stack
|
||||||
// frame, which would still be useful in Debug View.
|
// frame, which would still be useful in Debug View.
|
||||||
|
if (!checkService(IRunControl.class, null, update)) return;
|
||||||
if (getServicesTracker().getService(IRunControl.class).isStepping(execDmc)) {
|
if (getServicesTracker().getService(IRunControl.class).isStepping(execDmc)) {
|
||||||
getElementsTopStackFrameOnly(parentVmc, done);
|
getElementsTopStackFrameOnly(update);
|
||||||
} else {
|
} else {
|
||||||
propagateError(getExecutor(), done, "Failed retrieving stack frames"); //$NON-NLS-1$
|
update.done();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Store the VMC element array, in case we need to use it when
|
// Store the VMC element array, in case we need to use it when
|
||||||
fCachedOldFramesVMCs = dmcs2vmcs(parentVmc, getData());
|
fCachedOldFrameVMCs = dmcs2vmcs(getData());
|
||||||
done.setData(fCachedOldFramesVMCs);
|
for (int i = 0; i < fCachedOldFrameVMCs.length; i++) update.setChild(fCachedOldFrameVMCs[i], i);
|
||||||
getExecutor().execute(done);
|
update.done();
|
||||||
}});
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -89,68 +102,56 @@ public class StackFramesLayoutNode extends DMContextVMLayoutNode<IStack.IFrameDM
|
||||||
* frames are retrieved from the cache or omitted.
|
* frames are retrieved from the cache or omitted.
|
||||||
* @see #getElements(IVMContext, GetDataDone)
|
* @see #getElements(IVMContext, GetDataDone)
|
||||||
*/
|
*/
|
||||||
private void getElementsTopStackFrameOnly(final IVMContext parentVmc, final GetDataDone<IVMContext[]> done) {
|
private void getElementsTopStackFrameOnly(final IChildrenUpdate update) {
|
||||||
final IExecutionDMContext execDmc = findDmcInVmc(parentVmc, IExecutionDMContext.class);
|
final IExecutionDMContext execDmc = findDmcInPath(update.getElementPath(), IExecutionDMContext.class);
|
||||||
|
if (execDmc == null) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
getServicesTracker().getService(IStack.class).getTopFrame(
|
getServicesTracker().getService(IStack.class).getTopFrame(
|
||||||
execDmc,
|
execDmc,
|
||||||
new GetDataDone<IFrameDMContext>() { public void run() {
|
new GetDataDone<IFrameDMContext>() { public void run() {
|
||||||
if (propagateError(getExecutor(), done, "Failed retrieving top stack frame")) return; //$NON-NLS-1$
|
if (!getStatus().isOK()) {
|
||||||
IVMContext topFrameVmc = new DMContextVMContext(parentVmc, getData());
|
handleFailedUpdate(update);
|
||||||
|
|
||||||
// If there are old frames cached, use them and only substitute the top frame object. Otherwise, create
|
|
||||||
// an array of VMCs with just the top frame.
|
|
||||||
if (fCachedOldFramesVMCs != null && fCachedOldFramesVMCs.length >= 1) {
|
|
||||||
fCachedOldFramesVMCs[0] = topFrameVmc;
|
|
||||||
done.setData(fCachedOldFramesVMCs);
|
|
||||||
} else {
|
|
||||||
done.setData(new IVMContext[] { topFrameVmc });
|
|
||||||
}
|
|
||||||
getExecutor().execute(done);
|
|
||||||
}});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void retrieveLabel(IVMContext vmc, final ILabelRequestMonitor result, String[] columns) {
|
|
||||||
final IExecutionDMContext execDmc = findDmcInVmc(vmc, IExecutionDMContext.class);
|
|
||||||
if (execDmc == null || getServicesTracker().getService(IStack.class) == null || getServicesTracker().getService(IRunControl.class) == null) {
|
|
||||||
result.done();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IVMContext topFrameVmc = new DMVMContext(getData());
|
||||||
|
|
||||||
|
update.setChild(topFrameVmc, 0);
|
||||||
|
// If there are old frames cached, use them and only substitute the top frame object. Otherwise, create
|
||||||
|
// an array of VMCs with just the top frame.
|
||||||
|
if (fCachedOldFrameVMCs != null && fCachedOldFrameVMCs.length >= 1) {
|
||||||
|
fCachedOldFrameVMCs[0] = topFrameVmc;
|
||||||
|
for (int i = 0; i < fCachedOldFrameVMCs.length; i++) update.setChild(fCachedOldFrameVMCs[i], i);
|
||||||
|
} else {
|
||||||
|
update.setChild(topFrameVmc, 0);
|
||||||
|
}
|
||||||
|
update.done();
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void fillColumnLabel(IDMContext<IFrameDMData> dmContext, IFrameDMData dmData, String columnId, int idx,
|
||||||
|
ILabelUpdate update)
|
||||||
|
{
|
||||||
|
if (idx != 0) return;
|
||||||
|
|
||||||
|
final IExecutionDMContext execDmc = findDmcInPath(update.getElementPath(), IExecutionDMContext.class);
|
||||||
|
IRunControl runControlService = getServicesTracker().getService(IRunControl.class);
|
||||||
|
IStepQueueManager stepQueueMgrService = getServicesTracker().getService(IStepQueueManager.class);
|
||||||
|
if (execDmc == null || runControlService == null || stepQueueMgrService == null) return;
|
||||||
|
|
||||||
String imageKey = null;
|
String imageKey = null;
|
||||||
IRunControl rc = getServicesTracker().getService(IRunControl.class);
|
if (runControlService.isSuspended(execDmc) ||
|
||||||
if (rc.isSuspended(execDmc) ||
|
(runControlService.isStepping(execDmc) && !stepQueueMgrService.isSteppingTimedOut(execDmc)))
|
||||||
(rc.isStepping(execDmc) && !getServicesTracker().getService(IStepQueueManager.class).isSteppingTimedOut(execDmc)))
|
|
||||||
{
|
{
|
||||||
imageKey = IDebugUIConstants.IMG_OBJS_STACKFRAME;
|
imageKey = IDebugUIConstants.IMG_OBJS_STACKFRAME;
|
||||||
} else {
|
} else {
|
||||||
imageKey = IDebugUIConstants.IMG_OBJS_STACKFRAME_RUNNING;
|
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.
|
// Finally, if all goes well, set the label.
|
||||||
|
@ -158,62 +159,92 @@ public class StackFramesLayoutNode extends DMContextVMLayoutNode<IStack.IFrameDM
|
||||||
StringBuilder label = new StringBuilder();
|
StringBuilder label = new StringBuilder();
|
||||||
|
|
||||||
// Add frame number (if total number of frames in known)
|
// Add frame number (if total number of frames in known)
|
||||||
if (fCachedOldFramesVMCs != null) {
|
if (fCachedOldFrameVMCs != null) {
|
||||||
label.append(fCachedOldFramesVMCs.length - getData().getLevel());
|
label.append(fCachedOldFrameVMCs.length - dmData.getLevel());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the function name
|
// Add the function name
|
||||||
if (getData().getFunction() != null && getData().getFunction().length() != 0) {
|
if (dmData.getFunction() != null && dmData.getFunction().length() != 0) {
|
||||||
label.append(" "); //$NON-NLS-1$
|
label.append(" "); //$NON-NLS-1$
|
||||||
label.append(getData().getFunction());
|
label.append(dmData.getFunction());
|
||||||
label.append("()"); //$NON-NLS-1$
|
label.append("()"); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add full file name
|
// Add full file name
|
||||||
if (getData().getFile() != null && getData().getFile().length() != 0) {
|
if (dmData.getFile() != null && dmData.getFile().length() != 0) {
|
||||||
label.append(" at "); //$NON-NLS-1$
|
label.append(" at "); //$NON-NLS-1$
|
||||||
label.append(getData().getFile());
|
label.append(dmData.getFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add line number
|
// Add line number
|
||||||
if (getData().getLine() >= 0) {
|
if (dmData.getLine() >= 0) {
|
||||||
label.append(":"); //$NON-NLS-1$
|
label.append(":"); //$NON-NLS-1$
|
||||||
label.append(getData().getLine());
|
label.append(dmData.getLine());
|
||||||
label.append(" "); //$NON-NLS-1$
|
label.append(" "); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the address
|
// Add the address
|
||||||
label.append(getData().getAddress());
|
label.append(dmData.getAddress());
|
||||||
|
|
||||||
// Set the label to the result listener
|
// Set the label to the result listener
|
||||||
result.setLabels(new String[] { label.toString() });
|
update.setLabel(label.toString(), 0);
|
||||||
result.done();
|
|
||||||
}});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// This node generates delta if the timers have changed, or if the
|
||||||
// label has changed.
|
// label has changed.
|
||||||
return e instanceof IRunControl.ISuspendedDMEvent ||
|
if (e instanceof IRunControl.ISuspendedDMEvent) {
|
||||||
e instanceof IRunControl.IResumedDMEvent ||
|
return IModelDelta.CONTENT | IModelDelta.EXPAND | IModelDelta.SELECT;
|
||||||
e instanceof IStepQueueManager.ISteppingTimedOutEvent ||
|
} else if (e instanceof IRunControl.IResumedDMEvent) {
|
||||||
super.hasDeltaFlagsForDMEvent(e);
|
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) {
|
@Override
|
||||||
if (getServicesTracker().getService(IStack.class) == null || getServicesTracker().getService(IRunControl.class) == null) {
|
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.
|
// Required services have not initialized yet. Ignore the event.
|
||||||
super.buildDeltaForDMEvent(e, parent, done);
|
super.buildDeltaForDMEvent(e, parent, nodeOffset, done);
|
||||||
return;
|
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
|
// 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
|
// 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.
|
// refresh the whole stack trace with every step would slow down stepping too much.
|
||||||
if (!getServicesTracker().getService(IRunControl.class).isStepping(suspendedEvent.getDMContext())) {
|
if (!runControlService.isStepping(e.getDMContext())) {
|
||||||
parent.addFlags(IModelDelta.CONTENT);
|
parent.addFlags(IModelDelta.CONTENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,51 +253,46 @@ public class StackFramesLayoutNode extends DMContextVMLayoutNode<IStack.IFrameDM
|
||||||
|
|
||||||
// Retrieve the list of stack frames, and mark the top frame to be selected.
|
// Retrieve the list of stack frames, and mark the top frame to be selected.
|
||||||
getElementsTopStackFrameOnly(
|
getElementsTopStackFrameOnly(
|
||||||
parent.getVMC(),
|
new ElementsUpdate(
|
||||||
new GetDataDone<IVMContext[]>() { public void run() {
|
new GetDataDone<List<Object>>() {
|
||||||
if (getStatus().isOK() && getData().length != 0) {
|
public void run() {
|
||||||
parent.addNode( getData()[0], IModelDelta.SELECT | IModelDelta.STATE);
|
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
|
// If second frame is available repaint it, so that a "..." appears. This gives a better
|
||||||
// impression that the frames are not up-to date.
|
// impression that the frames are not up-to date.
|
||||||
if (getData().length >= 2) {
|
if (getData().size() >= 2) {
|
||||||
parent.addNode( getData()[1], IModelDelta.STATE);
|
parent.addNode( getData().get(1), IModelDelta.STATE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Even in case of errors, call super-class to complete building of the delta.
|
// Even in case of errors, call super-class to complete building of the delta.
|
||||||
StackFramesLayoutNode.super.buildDeltaForDMEvent(e, parent, done);
|
StackFramesLayoutNode.super.buildDeltaForDMEvent(e, parent, nodeOffset, 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);
|
},
|
||||||
}});
|
parent)
|
||||||
StackFramesLayoutNode.super.buildDeltaForDMEvent(e, parent, done);
|
);
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
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
|
// Refresh the list of stack frames only if the run operation is not a step. Also, clear the list
|
||||||
// of cached frames.
|
// of cached frames.
|
||||||
parent.addFlags(IModelDelta.CONTENT);
|
parent.addFlags(IModelDelta.CONTENT);
|
||||||
fCachedOldFramesVMCs = null;
|
fCachedOldFrameVMCs = null;
|
||||||
// Call super-class to build sub-node delta's.
|
|
||||||
super.buildDeltaForDMEvent(e, parent, done);
|
|
||||||
}
|
}
|
||||||
} else if (e instanceof IStepQueueManager.ISteppingTimedOutEvent) {
|
super.buildDeltaForDMEvent(e, parent, nodeOffset, done);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildDeltaForSteppingTimedOutEvent(final IStepQueueManager.ISteppingTimedOutEvent e, final VMDelta parent, final int nodeOffset, final Done done) {
|
||||||
// Repaint the stack frame images to have the running symbol.
|
// Repaint the stack frame images to have the running symbol.
|
||||||
parent.addFlags(IModelDelta.CONTENT);
|
parent.addFlags(IModelDelta.CONTENT);
|
||||||
super.buildDeltaForDMEvent(e, parent, done);
|
super.buildDeltaForDMEvent(e, parent, nodeOffset, done);
|
||||||
} else {
|
|
||||||
// Call super-class to build sub-node delta's.
|
|
||||||
super.buildDeltaForDMEvent(e, parent, done);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,20 +10,24 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.dd.dsf.debug.ui.viewmodel.launch;
|
package org.eclipse.dd.dsf.debug.ui.viewmodel.launch;
|
||||||
|
|
||||||
import org.eclipse.dd.dsf.concurrent.DoneCollector;
|
import java.util.Arrays;
|
||||||
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
|
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.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.AbstractVMRootLayoutNode;
|
||||||
import org.eclipse.dd.dsf.ui.viewmodel.IVMContext;
|
|
||||||
import org.eclipse.dd.dsf.ui.viewmodel.IVMLayoutNode;
|
import org.eclipse.dd.dsf.ui.viewmodel.IVMLayoutNode;
|
||||||
import org.eclipse.dd.dsf.ui.viewmodel.IVMRootLayoutNode;
|
import org.eclipse.dd.dsf.ui.viewmodel.IVMRootLayoutNode;
|
||||||
import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
|
import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
|
||||||
import org.eclipse.debug.core.DebugEvent;
|
import org.eclipse.debug.core.DebugEvent;
|
||||||
import org.eclipse.debug.core.DebugPlugin;
|
import org.eclipse.debug.core.DebugPlugin;
|
||||||
import org.eclipse.debug.core.ILaunch;
|
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.IDebugElement;
|
||||||
import org.eclipse.debug.core.model.IProcess;
|
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
|
* 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
|
public class StandardLaunchRootLayoutNode extends AbstractVMRootLayoutNode
|
||||||
implements IVMRootLayoutNode
|
implements IVMRootLayoutNode
|
||||||
{
|
{
|
||||||
final private RootVMC<ILaunch> fRootVMC;
|
final private ILaunch fLaunch;
|
||||||
final IVMContext[] fElements;
|
|
||||||
|
|
||||||
public StandardLaunchRootLayoutNode(DsfExecutor executor, ILaunch launch) {
|
public StandardLaunchRootLayoutNode(AbstractVMProvider provider, ILaunch launch) {
|
||||||
super(executor);
|
super(provider);
|
||||||
fRootVMC = new RootVMC<ILaunch>(this, launch);
|
fLaunch = launch;
|
||||||
fElements = new IVMContext[] { fRootVMC };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasDeltaFlags(Object e) {
|
public int getDeltaFlags(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.
|
|
||||||
*/
|
|
||||||
if (e instanceof DebugEvent) {
|
if (e instanceof DebugEvent) {
|
||||||
DebugEvent de = (DebugEvent)e;
|
DebugEvent de = (DebugEvent)e;
|
||||||
if (de.getSource() instanceof IProcess) {
|
if (de.getSource() instanceof IProcess &&
|
||||||
return ((IProcess)de.getSource()).getLaunch().equals(getRootVMC().getInputObject()) && super.hasDeltaFlags(e);
|
!((IProcess)de.getSource()).getLaunch().equals(fLaunch) )
|
||||||
} else if (de.getSource() instanceof IDebugElement) {
|
{
|
||||||
return ((IDebugElement)de.getSource()).getLaunch().equals(getRootVMC().getInputObject()) && super.hasDeltaFlags(e);
|
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) {
|
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
|
* root of the view, create the delta with the path to the launch, then
|
||||||
* pass that to the child layout nodes.
|
* pass that to the child layout nodes.
|
||||||
*/
|
*/
|
||||||
final VMDelta delta = new VMDelta(DebugPlugin.getDefault().getLaunchManager(), null);
|
ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager();
|
||||||
done.setData(delta);
|
List<ILaunch> launchList = Arrays.asList(manager.getLaunches());
|
||||||
final VMDelta rootDelta = delta.addNode(getRootVMC().getInputObject(), getRootVMC());
|
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);
|
final Map<IVMLayoutNode,Integer> childNodeDeltas = getChildNodesWithDeltas(event);
|
||||||
if (childNodes.length == 0) {
|
assert childNodeDeltas.size() != 0 : "Caller should make sure that there are deltas for given event."; //$NON-NLS-1$
|
||||||
done.setData(delta);
|
|
||||||
getExecutor().execute(done);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
callChildNodesToBuildDelta(
|
||||||
* The execution for this node is not done until all the child nodes
|
childNodeDeltas, rootDelta, event,
|
||||||
* are done. Use the tracker to wait for all children to complete.
|
new Done() {
|
||||||
*/
|
|
||||||
final DoneCollector doneCollector = new DoneCollector(getExecutor()) {
|
|
||||||
public void run() {
|
public void run() {
|
||||||
if (propagateError(getExecutor(), done, "Failed to generate child deltas.")) return; //$NON-NLS-1$
|
if (propagateError(getExecutor(), done, "Failed to create delta.")); //$NON-NLS-1$
|
||||||
done.setData(delta);
|
done.setData(viewRootDelta);
|
||||||
getExecutor().execute(done);
|
getExecutor().execute(done);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
for (final IVMLayoutNode childNode : childNodes) {
|
|
||||||
childNode.buildDelta(event, rootDelta, doneCollector.addNoActionDone());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IRootVMC getRootVMC() {
|
public Object getRootObject() {
|
||||||
return fRootVMC;
|
return fLaunch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,25 +10,23 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.dd.dsf.debug.ui.viewmodel.launch;
|
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.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.AbstractVMLayoutNode;
|
||||||
|
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMProvider;
|
||||||
import org.eclipse.dd.dsf.ui.viewmodel.IVMContext;
|
import org.eclipse.dd.dsf.ui.viewmodel.IVMContext;
|
||||||
import org.eclipse.dd.dsf.ui.viewmodel.IVMLayoutNode;
|
import org.eclipse.dd.dsf.ui.viewmodel.IVMLayoutNode;
|
||||||
import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
|
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.DebugEvent;
|
||||||
import org.eclipse.debug.core.DebugException;
|
import org.eclipse.debug.core.DebugException;
|
||||||
import org.eclipse.debug.core.ILaunch;
|
import org.eclipse.debug.core.ILaunch;
|
||||||
import org.eclipse.debug.core.model.IProcess;
|
import org.eclipse.debug.core.model.IProcess;
|
||||||
import org.eclipse.debug.core.model.IStreamsProxy;
|
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.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
|
* 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
|
* VMC element implementation, it is a proxy for the IProcess class, to
|
||||||
* allow the standard label adapter to be used with this object.
|
* 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;
|
private final IProcess fProcess;
|
||||||
|
|
||||||
VMC(IVMContext parentVmc, IProcess process) {
|
VMC(IProcess process) {
|
||||||
fParentVmc = parentVmc;
|
super(getVMProvider().getVMAdapter(), StandardProcessLayoutNode.this);
|
||||||
fProcess = process;
|
fProcess = process;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IVMContext getParent() { return fParentVmc; }
|
|
||||||
public IVMLayoutNode getLayoutNode() { return StandardProcessLayoutNode.this; }
|
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 toString() { return "IProcess " + fProcess.toString(); } //$NON-NLS-1$
|
||||||
|
|
||||||
public String getAttribute(String key) { return fProcess.getAttribute(key); }
|
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 int hashCode() { return fProcess.hashCode(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public StandardProcessLayoutNode(DsfExecutor executor) {
|
public StandardProcessLayoutNode(AbstractVMProvider provider) {
|
||||||
super(executor);
|
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 updateElements(IChildrenUpdate update) {
|
||||||
public void getElements(IVMContext parentVmc, GetDataDone<IVMContext[]> done) {
|
ILaunch launch = findLaunch(update.getElementPath());
|
||||||
ILaunch launch = findLaunch(parentVmc);
|
|
||||||
if (launch == null) {
|
if (launch == null) {
|
||||||
/*
|
// There is no launch in the parent of this node. This means that the
|
||||||
* There is no launch in the parent of this node. This means that the
|
// layout is misconfigured.
|
||||||
* layout is misconfigured.
|
|
||||||
*/
|
|
||||||
assert false;
|
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$
|
update.done();
|
||||||
getExecutor().execute(done);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,30 +90,43 @@ public class StandardProcessLayoutNode extends AbstractVMLayoutNode {
|
||||||
* retrieve them on dispatch thread.
|
* retrieve them on dispatch thread.
|
||||||
*/
|
*/
|
||||||
IProcess[] processes = launch.getProcesses();
|
IProcess[] processes = launch.getProcesses();
|
||||||
IVMContext[] processVmcs = new IVMContext[processes.length];
|
|
||||||
for (int i = 0; i < processes.length; i++) {
|
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);
|
update.done();
|
||||||
getExecutor().execute(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 updateElementCount(IChildrenCountUpdate update) {
|
||||||
public void hasElements(IVMContext parentVmc, GetDataDone<Boolean> done) {
|
ILaunch launch = findLaunch(update.getElementPath());
|
||||||
ILaunch launch = findLaunch(parentVmc);
|
|
||||||
if (launch == null) {
|
if (launch == null) {
|
||||||
assert false;
|
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$
|
update.setChildCount(0);
|
||||||
getExecutor().execute(done);
|
update.done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
done.setData(launch.getProcesses().length != 0);
|
update.setChildCount(launch.getProcesses().length);
|
||||||
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 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)
|
// @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
|
* 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.
|
* Recursively searches the VMC for Launch VMC, and returns its ILaunch.
|
||||||
* Returns null if an ILaunch is not found.
|
* Returns null if an ILaunch is not found.
|
||||||
*/
|
*/
|
||||||
private ILaunch findLaunch(IVMContext vmc) {
|
private ILaunch findLaunch(TreePath path) {
|
||||||
if (vmc == null) {
|
for (int i = path.getSegmentCount() - 1; i >= 0; i--) {
|
||||||
return null;
|
if (path.getSegment(i) instanceof ILaunch) {
|
||||||
} else if (vmc instanceof IRootVMC || ((IRootVMC)vmc).getInputObject() instanceof ILaunch) {
|
return (ILaunch)path.getSegment(i);
|
||||||
return (ILaunch)(((IRootVMC)vmc)).getInputObject();
|
|
||||||
} else {
|
|
||||||
return findLaunch(vmc.getParent());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasDeltaFlags(Object e) {
|
public int getDeltaFlags(Object e) {
|
||||||
|
int myFlags = 0;
|
||||||
if (e instanceof DebugEvent) {
|
if (e instanceof DebugEvent) {
|
||||||
DebugEvent de = (DebugEvent)e;
|
DebugEvent de = (DebugEvent)e;
|
||||||
return de.getSource() instanceof IProcess &&
|
if ( de.getSource() instanceof IProcess &&
|
||||||
(de.getKind() == DebugEvent.CHANGE ||
|
(de.getKind() == DebugEvent.CHANGE ||
|
||||||
de.getKind() == DebugEvent.CREATE ||
|
de.getKind() == DebugEvent.CREATE ||
|
||||||
de.getKind() == DebugEvent.TERMINATE);
|
de.getKind() == DebugEvent.TERMINATE) )
|
||||||
|
{
|
||||||
|
myFlags = IModelDelta.STATE;
|
||||||
}
|
}
|
||||||
return super.hasDeltaFlags(e);
|
}
|
||||||
|
return myFlags | super.getDeltaFlags(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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) {
|
if (e instanceof DebugEvent && ((DebugEvent)e).getSource() instanceof IProcess) {
|
||||||
DebugEvent de = (DebugEvent)e;
|
DebugEvent de = (DebugEvent)e;
|
||||||
if (de.getKind() == DebugEvent.CHANGE) {
|
if (de.getKind() == DebugEvent.CHANGE) {
|
||||||
|
@ -173,12 +184,12 @@ public class StandardProcessLayoutNode extends AbstractVMLayoutNode {
|
||||||
*/
|
*/
|
||||||
getExecutor().execute(done);
|
getExecutor().execute(done);
|
||||||
} else {
|
} else {
|
||||||
super.buildDelta(e, parent, done);
|
super.buildDelta(e, parent, nodeOffset, done);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void handleChange(DebugEvent event, VMDelta parent) {
|
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) {
|
protected void handleCreate(DebugEvent event, VMDelta parent) {
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
package org.eclipse.dd.dsf.debug.ui.viewmodel.register;
|
package org.eclipse.dd.dsf.debug.ui.viewmodel.register;
|
||||||
|
|
||||||
import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin;
|
import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
|
||||||
import org.eclipse.jface.resource.ImageDescriptor;
|
import org.eclipse.jface.resource.ImageDescriptor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -10,84 +10,58 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.dd.dsf.debug.ui.viewmodel.register;
|
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.concurrent.GetDataDone;
|
||||||
import org.eclipse.dd.dsf.datamodel.IDMContext;
|
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;
|
||||||
import org.eclipse.dd.dsf.debug.service.IRegisters.IRegisterGroupDMContext;
|
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.IRegisters.IRegisterGroupData;
|
||||||
import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext;
|
import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext;
|
||||||
import org.eclipse.dd.dsf.service.DsfSession;
|
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.dm.AbstractDMVMLayoutNode;
|
||||||
import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
|
||||||
import org.eclipse.jface.resource.ImageDescriptor;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
|
||||||
import org.eclipse.swt.graphics.FontData;
|
|
||||||
import org.eclipse.swt.graphics.RGB;
|
|
||||||
|
|
||||||
@SuppressWarnings("restriction")
|
@SuppressWarnings("restriction")
|
||||||
public class RegisterGroupLayoutNode extends DMContextVMLayoutNode<IRegisterGroupData> {
|
public class RegisterGroupLayoutNode extends AbstractDMVMLayoutNode<IRegisterGroupData> {
|
||||||
|
|
||||||
public RegisterGroupLayoutNode(DsfSession session) {
|
public RegisterGroupLayoutNode(AbstractVMProvider provider, DsfSession session) {
|
||||||
super(session, IRegisters.IRegisterGroupDMContext.class);
|
super(provider, session, IRegisters.IRegisterGroupDMContext.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void hasElements( final IVMContext parentVmc , final GetDataDone<Boolean> done ) {
|
@Override
|
||||||
final IExecutionDMContext execDmc = findDmcInVmc(parentVmc, IExecutionDMContext.class);
|
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
|
||||||
|
if (!checkService(IRegisters.class, null, update)) return;
|
||||||
|
|
||||||
if (execDmc == null || getServicesTracker().getService(IRegisters.class) == null) {
|
final IExecutionDMContext execDmc = findDmcInPath(update.getElementPath(), IExecutionDMContext.class) ;
|
||||||
done.setData(Boolean.FALSE);
|
|
||||||
getExecutor().execute(done);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (execDmc != null) {
|
||||||
getServicesTracker().getService(IRegisters.class).getRegisterGroups(
|
getServicesTracker().getService(IRegisters.class).getRegisterGroups(
|
||||||
execDmc, null,
|
execDmc, null,
|
||||||
new GetDataDone<IRegisterGroupDMContext[]>() { public void run() {
|
new GetDataDone<IRegisterGroupDMContext[]>() { public void run() {
|
||||||
if (propagateError(getExecutor(), done, "Failed to retrieve register groups")) return; //$NON-NLS-1$
|
if (!getStatus().isOK()) {
|
||||||
done.setData(getData().length != 0);
|
update.done();
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
|
fillUpdateWithVMCs(update, getData());
|
||||||
getServicesTracker().getService(IRegisters.class).getRegisterGroups(
|
update.done();
|
||||||
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);
|
|
||||||
}});
|
}});
|
||||||
|
} else {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void fillColumnLabel(IDMContext<IRegisterGroupData> dmContext, IRegisterGroupData dmData,
|
protected void fillColumnLabel(IDMContext<IRegisterGroupData> dmContext, IRegisterGroupData dmData,
|
||||||
String columnId, int idx, String[] text, ImageDescriptor[] image,
|
String columnId, int idx, ILabelUpdate update)
|
||||||
FontData[] fontData, RGB[] foreground, RGB[] background)
|
|
||||||
{
|
{
|
||||||
if (RegisterColumnPresentation.COL_NAME.equals(columnId)) {
|
if (RegisterColumnPresentation.COL_NAME.equals(columnId)) {
|
||||||
text[idx] = dmData.getName();
|
update.setLabel(dmData.getName(), idx);
|
||||||
} else if (RegisterColumnPresentation.COL_VALUE.equals(columnId)) {
|
} else if (RegisterColumnPresentation.COL_VALUE.equals(columnId)) {
|
||||||
text[idx] = ""; //$NON-NLS-1$
|
update.setLabel("", idx); //$NON-NLS-1$
|
||||||
} else if (RegisterColumnPresentation.COL_DESCRIPTION.equals(columnId)) {
|
} else if (RegisterColumnPresentation.COL_DESCRIPTION.equals(columnId)) {
|
||||||
text[idx] = dmData.getDescription();
|
update.setLabel(dmData.getDescription(), idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasDeltaFlagsForDMEvent(IDMEvent<?> e) {
|
|
||||||
return super.hasDeltaFlagsForDMEvent(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void buildDeltaForDMEvent(final IDMEvent<?> e, final VMDelta parent, final Done done) {
|
|
||||||
super.buildDeltaForDMEvent(e, parent, done);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.Done;
|
||||||
import org.eclipse.dd.dsf.concurrent.GetDataDone;
|
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.datamodel.IDMEvent;
|
||||||
import org.eclipse.dd.dsf.debug.service.IRegisters;
|
import org.eclipse.dd.dsf.debug.service.IRegisters;
|
||||||
import org.eclipse.dd.dsf.debug.service.IRunControl;
|
import org.eclipse.dd.dsf.debug.service.IRunControl;
|
||||||
|
@ -19,79 +20,56 @@ import org.eclipse.dd.dsf.debug.service.IRegisters.IRegisterDMContext;
|
||||||
import org.eclipse.dd.dsf.debug.service.IRegisters.IRegisterDMData;
|
import org.eclipse.dd.dsf.debug.service.IRegisters.IRegisterDMData;
|
||||||
import org.eclipse.dd.dsf.debug.service.IRegisters.IRegisterGroupDMContext;
|
import org.eclipse.dd.dsf.debug.service.IRegisters.IRegisterGroupDMContext;
|
||||||
import org.eclipse.dd.dsf.service.DsfSession;
|
import org.eclipse.dd.dsf.service.DsfSession;
|
||||||
import org.eclipse.dd.dsf.service.IDsfService;
|
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMProvider;
|
||||||
import org.eclipse.dd.dsf.ui.viewmodel.DMContextVMLayoutNode;
|
|
||||||
import org.eclipse.dd.dsf.ui.viewmodel.IVMContext;
|
import org.eclipse.dd.dsf.ui.viewmodel.IVMContext;
|
||||||
import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
|
import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.ILabelRequestMonitor;
|
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta;
|
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")
|
@SuppressWarnings("restriction")
|
||||||
public class RegisterLayoutNode extends DMContextVMLayoutNode<IRegisterDMData> {
|
public class RegisterLayoutNode extends AbstractDMVMLayoutNode<IRegisterDMData> {
|
||||||
|
|
||||||
public IVMContext[] fCachedRegisterVMCs;
|
public IVMContext[] fCachedRegisterVMCs;
|
||||||
|
|
||||||
public RegisterLayoutNode(DsfSession session) {
|
public RegisterLayoutNode(AbstractVMProvider provider, DsfSession session) {
|
||||||
super(session, IRegisters.IRegisterDMContext.class);
|
super(provider, session, IRegisters.IRegisterDMContext.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void hasElements( final IVMContext parentVmc , final GetDataDone<Boolean> done ) {
|
@Override
|
||||||
final IRegisterGroupDMContext registerGroupDmc = findDmcInVmc(parentVmc, IRegisterGroupDMContext.class);
|
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
|
||||||
|
final IRegisterGroupDMContext execDmc = findDmcInPath(update.getElementPath(), IRegisterGroupDMContext.class);
|
||||||
|
|
||||||
if (registerGroupDmc == null || getServicesTracker().getService(IRegisters.class) == null) {
|
if (execDmc == null) {
|
||||||
done.setData(Boolean.FALSE);
|
handleFailedUpdate(update);
|
||||||
getExecutor().execute(done);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
getServicesTracker().getService( IRegisters.class ).getRegisters(
|
getServicesTracker().getService(IRegisters.class).getRegisters(
|
||||||
registerGroupDmc,
|
execDmc,
|
||||||
new GetDataDone<IRegisterDMContext[]>() {
|
new GetDataDone<IRegisterDMContext[]>() {
|
||||||
public void run() {
|
public void run() {
|
||||||
if (propagateError(getExecutor(), done, "Failed to retrieve registers")) return; //$NON-NLS-1$
|
if (!getStatus().isOK()) {
|
||||||
done.setData(getData().length != 0);
|
handleFailedUpdate(update);
|
||||||
getExecutor().execute(done);
|
}
|
||||||
|
fillUpdateWithVMCs(update, getData());
|
||||||
|
update.done();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void getElements( final IVMContext parentVmc , final GetDataDone<IVMContext[]> done ) {
|
@Override
|
||||||
final IRegisterGroupDMContext execDmc = findDmcInVmc(parentVmc, IRegisterGroupDMContext.class);
|
protected void fillColumnLabel(IDMContext<IRegisterDMData> dmContext, IRegisterDMData dmData, String columnId,
|
||||||
|
int idx, ILabelUpdate update)
|
||||||
if (execDmc == null || getServicesTracker().getService(IRegisters.class) == null) {
|
{
|
||||||
getExecutor().execute(done);
|
if (RegisterColumnPresentation.COL_NAME.equals(columnId)) {
|
||||||
return;
|
update.setLabel(dmData.getName(), idx);
|
||||||
}
|
} else if (RegisterColumnPresentation.COL_VALUE.equals(columnId)) {
|
||||||
|
update.setLabel(dmData.getHexValue(), idx);
|
||||||
getServicesTracker().getService( IRegisters.class ).getRegisters(
|
} else if (RegisterColumnPresentation.COL_DESCRIPTION.equals(columnId)) {
|
||||||
execDmc,
|
String size = dmData.getDescription();
|
||||||
new GetDataDone<IRegisterDMContext[]>() { public void run() {
|
String value = dmData.getHexValue();
|
||||||
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 ("".equals(size)) { //$NON-NLS-1$
|
||||||
if ( value.contains( "uint64" ) ) { //$NON-NLS-1$
|
if ( value.contains( "uint64" ) ) { //$NON-NLS-1$
|
||||||
size = "64 bit register" ; //$NON-NLS-1$
|
size = "64 bit register" ; //$NON-NLS-1$
|
||||||
|
@ -99,32 +77,29 @@ public class RegisterLayoutNode extends DMContextVMLayoutNode<IRegisterDMData> {
|
||||||
size = "128 bit register" ; //$NON-NLS-1$
|
size = "128 bit register" ; //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
update.setLabel(size, idx);
|
||||||
result.setLabels(new String[] { getData().getName(), getData().getHexValue(), size });
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.done() ;
|
@Override
|
||||||
return ;
|
protected int getNodeDeltaFlagsForDMEvent(IDMEvent<?> e) {
|
||||||
|
if (e instanceof IRunControl.ISuspendedDMEvent) {
|
||||||
|
return IModelDelta.CONTENT;
|
||||||
|
} else if (e instanceof IRegisters.IRegisterChangedDMEvent) {
|
||||||
|
return IModelDelta.STATE;
|
||||||
}
|
}
|
||||||
}
|
return IModelDelta.NO_CHANGE;
|
||||||
) ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasDeltaFlagsForDMEvent( IDMEvent<?> e ) {
|
@Override
|
||||||
return (e instanceof IRunControl.ISuspendedDMEvent) || super.hasDeltaFlagsForDMEvent(e) ;
|
protected void buildDeltaForDMEvent(IDMEvent<?> e, VMDelta parent, int nodeOffset, Done done) {
|
||||||
}
|
|
||||||
|
|
||||||
public void buildDeltaForDMEvent( final IDMEvent<?> e, final VMDelta parent, final Done done ) {
|
|
||||||
if (e instanceof IRunControl.ISuspendedDMEvent) {
|
if (e instanceof IRunControl.ISuspendedDMEvent) {
|
||||||
// Create a delta that the whole register group has changed.
|
// Create a delta that the whole register group has changed.
|
||||||
parent.addFlags(IModelDelta.CONTENT);
|
parent.addFlags(IModelDelta.CONTENT);
|
||||||
}
|
}
|
||||||
if (e instanceof IRegisters.IRegisterChangedDMEvent) {
|
if (e instanceof IRegisters.IRegisterChangedDMEvent) {
|
||||||
parent.addNode(
|
parent.addNode( new DMVMContext(((IRegisters.IRegisterChangedDMEvent)e).getDMContext()), IModelDelta.STATE );
|
||||||
new DMContextVMContext(parent.getVMC(), ((IRegisters.IRegisterChangedDMEvent)e).getDMContext()),
|
|
||||||
IModelDelta.STATE);
|
|
||||||
}
|
}
|
||||||
|
super.buildDeltaForDMEvent(e, parent, nodeOffset, done);
|
||||||
super.buildDeltaForDMEvent(e, parent, 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.debug.ui.viewmodel.DebugViewSelectionRootLayoutNode;
|
||||||
import org.eclipse.dd.dsf.service.DsfSession;
|
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.IVMLayoutNode;
|
||||||
import org.eclipse.dd.dsf.ui.viewmodel.IVMRootLayoutNode;
|
import org.eclipse.dd.dsf.ui.viewmodel.IVMRootLayoutNode;
|
||||||
import org.eclipse.dd.dsf.ui.viewmodel.VMProvider;
|
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMProvider;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("restriction")
|
@SuppressWarnings("restriction")
|
||||||
public class RegisterVMProvider extends VMProvider {
|
public class RegisterVMProvider extends AbstractDMVMProvider {
|
||||||
public RegisterVMProvider(DsfSession session, IPresentationContext context) {
|
public RegisterVMProvider(AbstractVMAdapter adapter, IPresentationContext context, DsfSession session) {
|
||||||
super(session, null);
|
super(adapter, context, session);
|
||||||
IVMRootLayoutNode debugViewSelection = new DebugViewSelectionRootLayoutNode(
|
IVMRootLayoutNode debugViewSelection = new DebugViewSelectionRootLayoutNode(this);
|
||||||
getSession().getExecutor(), context.getPart().getSite().getWorkbenchWindow() );
|
IVMLayoutNode registerGroupNode = new RegisterGroupLayoutNode(this, getSession());
|
||||||
IVMLayoutNode registerGroupNode = new RegisterGroupLayoutNode(getSession());
|
|
||||||
debugViewSelection.setChildNodes(new IVMLayoutNode[] { registerGroupNode });
|
debugViewSelection.setChildNodes(new IVMLayoutNode[] { registerGroupNode });
|
||||||
IVMLayoutNode registerNode = new RegisterLayoutNode(getSession());
|
IVMLayoutNode registerNode = new RegisterLayoutNode(this, getSession());
|
||||||
registerGroupNode.setChildNodes(new IVMLayoutNode[] { registerNode });
|
registerGroupNode.setChildNodes(new IVMLayoutNode[] { registerNode });
|
||||||
setRootLayoutNode(debugViewSelection);
|
setRootLayoutNode(debugViewSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IColumnPresentation createColumnPresentation(Object element) {
|
public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) {
|
||||||
return new RegisterColumnPresentation();
|
return new RegisterColumnPresentation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getColumnPresentationId(Object element) {
|
public String getColumnPresentationId(IPresentationContext context, Object element) {
|
||||||
return RegisterColumnPresentation.ID;
|
return RegisterColumnPresentation.ID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,5 +11,6 @@ Require-Bundle: org.eclipse.ui,
|
||||||
org.eclipse.dd.dsf,
|
org.eclipse.dd.dsf,
|
||||||
org.eclipse.debug.ui
|
org.eclipse.debug.ui
|
||||||
Eclipse-LazyStart: true
|
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
|
Bundle-RequiredExecutionEnvironment: J2SE-1.5
|
||||||
|
|
|
@ -13,46 +13,39 @@ package org.eclipse.dd.dsf.ui.viewmodel;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.RejectedExecutionException;
|
import java.util.concurrent.RejectedExecutionException;
|
||||||
|
|
||||||
import org.eclipse.core.runtime.IStatus;
|
import org.eclipse.core.runtime.IStatus;
|
||||||
import org.eclipse.core.runtime.Status;
|
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.DsfRunnable;
|
||||||
import org.eclipse.dd.dsf.concurrent.ThreadSafe;
|
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.service.IDsfService;
|
||||||
import org.eclipse.dd.dsf.ui.DsfUIPlugin;
|
import org.eclipse.dd.dsf.ui.DsfUIPlugin;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousContentAdapter;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousLabelAdapter;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.IChildrenRequestMonitor;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditor;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditorFactoryAdapter;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentationFactoryAdapter;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
@ThreadSafe
|
||||||
@SuppressWarnings("restriction")
|
@SuppressWarnings("restriction")
|
||||||
abstract public class AbstractVMAdapter
|
abstract public class AbstractVMAdapter implements IVMAdapter
|
||||||
implements IAsynchronousLabelAdapter,
|
|
||||||
IAsynchronousContentAdapter,
|
|
||||||
IModelProxyFactoryAdapter,
|
|
||||||
IColumnPresentationFactoryAdapter,
|
|
||||||
IColumnEditorFactoryAdapter
|
|
||||||
{
|
{
|
||||||
private final DsfSession fSession;
|
private final ExecutorService fExecutor;
|
||||||
|
private boolean fDisposed;
|
||||||
|
|
||||||
@ConfinedToDsfExecutor("getSession().getExecutor()")
|
private final Map<IPresentationContext, IVMProvider> fViewModelProviders =
|
||||||
private final Map<IPresentationContext, VMProvider> fViewModelProviders =
|
Collections.synchronizedMap( new HashMap<IPresentationContext, IVMProvider>() );
|
||||||
Collections.synchronizedMap( new HashMap<IPresentationContext, VMProvider>() );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for the View Model session. It is tempting to have the
|
* 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.
|
* to have the owner of this object register it with the session.
|
||||||
* @param session
|
* @param session
|
||||||
*/
|
*/
|
||||||
public AbstractVMAdapter(DsfSession session) {
|
public AbstractVMAdapter() {
|
||||||
fSession = session;
|
fExecutor = new DefaultDsfExecutor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ThreadSafe
|
/**
|
||||||
abstract protected VMProvider createViewModelProvider(IPresentationContext context);
|
* Returns the executor that will be used to communicate with the providers
|
||||||
|
* and the layout nodes.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Executor getExecutor() {
|
||||||
|
return fExecutor;
|
||||||
|
}
|
||||||
|
|
||||||
protected DsfSession getSession() { return fSession; }
|
/**
|
||||||
|
* Creates a new View Model Provider for given presentation context. Returns null
|
||||||
|
* if the presentation context is not supported.
|
||||||
|
*/
|
||||||
|
@ThreadSafe
|
||||||
|
abstract protected IVMProvider createViewModelProvider(IPresentationContext context);
|
||||||
|
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
private VMProvider getViewModelProvider(IPresentationContext context) {
|
private IVMProvider getViewModelProvider(IPresentationContext context) {
|
||||||
assert DsfSession.isSessionActive(getSession().getId());
|
|
||||||
|
|
||||||
synchronized(fViewModelProviders) {
|
synchronized(fViewModelProviders) {
|
||||||
VMProvider provider = fViewModelProviders.get(context);
|
if (fDisposed) return null;
|
||||||
|
|
||||||
|
IVMProvider provider = fViewModelProviders.get(context);
|
||||||
if (provider == null) {
|
if (provider == null) {
|
||||||
provider = createViewModelProvider(context);
|
provider = createViewModelProvider(context);
|
||||||
if (provider != null) {
|
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() {
|
public void dispose() {
|
||||||
assert getSession().getExecutor().isInExecutorThread();
|
// Execute the shutdown in adapter's dispatch thread.
|
||||||
|
getExecutor().execute(new DsfRunnable() {
|
||||||
for (VMProvider provider : fViewModelProviders.values()) {
|
public void run() {
|
||||||
|
synchronized(fViewModelProviders) {
|
||||||
|
fDisposed = true;
|
||||||
|
for (IVMProvider provider : fViewModelProviders.values()) {
|
||||||
provider.dispose();
|
provider.dispose();
|
||||||
}
|
}
|
||||||
fViewModelProviders.clear();
|
fViewModelProviders.clear();
|
||||||
}
|
}
|
||||||
|
fExecutor.shutdown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public void retrieveLabel(final Object object, final IPresentationContext context, final ILabelRequestMonitor result) {
|
public void update(IHasChildrenUpdate[] updates) {
|
||||||
|
handleUpdates(updates);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(IChildrenCountUpdate[] updates) {
|
||||||
|
handleUpdates(updates);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(final IChildrenUpdate[] updates) {
|
||||||
|
handleUpdates(updates);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleUpdates(final IViewerUpdate[] updates) {
|
||||||
try {
|
try {
|
||||||
getSession().getExecutor().execute(new DsfRunnable() {
|
getExecutor().execute(new DsfRunnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
if (result.isCanceled()) return;
|
IPresentationContext context = null;
|
||||||
|
int firstIdx = 0;
|
||||||
VMProvider provider = getViewModelProvider(context);
|
int curIdx = 0;
|
||||||
if (provider == null) {
|
for (curIdx = 0; curIdx < updates.length; curIdx++) {
|
||||||
result.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, "No model provider for object: " + object.toString(), null)); //$NON-NLS-1$
|
if (!updates[curIdx].getPresentationContext().equals(context)) {
|
||||||
result.done();
|
if (context != null) {
|
||||||
|
callProviderWithUpdate(updates, firstIdx, curIdx);
|
||||||
}
|
}
|
||||||
provider.retrieveLabel(object, result, context.getColumns());
|
context = updates[curIdx].getPresentationContext();
|
||||||
|
firstIdx = curIdx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callProviderWithUpdate(updates, firstIdx, curIdx);
|
||||||
}
|
}
|
||||||
@Override
|
|
||||||
public String toString() { return "Switch to dispatch thread to execute retrieveLabel()"; } //$NON-NLS-1$
|
|
||||||
});
|
});
|
||||||
} catch(RejectedExecutionException e) {
|
} 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) {
|
private void callProviderWithUpdate(IViewerUpdate[] updates, int startIdx, int endIdx) {
|
||||||
try {
|
final IVMProvider provider = getViewModelProvider(updates[0].getPresentationContext());
|
||||||
getSession().getExecutor().execute(new DsfRunnable() {
|
|
||||||
public void run() {
|
|
||||||
if (result.isCanceled()) return;
|
|
||||||
|
|
||||||
VMProvider provider = getViewModelProvider(context);
|
|
||||||
if (provider == null) {
|
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$
|
for (IViewerUpdate update : updates) {
|
||||||
result.done();
|
update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR,
|
||||||
|
"No model provider for update " + update, null)); //$NON-NLS-1$
|
||||||
|
update.done();
|
||||||
}
|
}
|
||||||
provider.isContainer(element, result);
|
return;
|
||||||
}
|
}
|
||||||
public String toString() { return "Switch to dispatch thread to execute isContainer()"; } //$NON-NLS-1$
|
if (startIdx == 0 && endIdx == updates.length) {
|
||||||
});
|
if (updates instanceof IHasChildrenUpdate[]) provider.update((IHasChildrenUpdate[])updates);
|
||||||
} catch(RejectedExecutionException e) {
|
else if (updates instanceof IChildrenCountUpdate[]) provider.update((IChildrenCountUpdate[])updates);
|
||||||
// This can happen if session is being shut down.
|
else if (updates instanceof IChildrenUpdate[]) provider.update((IChildrenUpdate[])updates);
|
||||||
result.done();
|
} 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[]) {
|
||||||
public void retrieveChildren(final Object element, final IPresentationContext context, final IChildrenRequestMonitor result) {
|
IChildrenUpdate[] providerUpdates = new IChildrenUpdate[endIdx - startIdx];
|
||||||
try {
|
System.arraycopy(updates, startIdx, providerUpdates, 0, endIdx - startIdx);
|
||||||
getSession().getExecutor().execute(new DsfRunnable() {
|
provider.update(providerUpdates);
|
||||||
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) {
|
public IModelProxy createModelProxy(Object element, IPresentationContext context) {
|
||||||
/*
|
IVMProvider provider = getViewModelProvider(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);
|
|
||||||
if (provider != null) {
|
if (provider != null) {
|
||||||
return provider.getColumnPresentationId(element);
|
return provider.createModelProxy(element, context);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) {
|
public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) {
|
||||||
VMProvider provider = getViewModelProvider(context);
|
final IVMProvider provider = getViewModelProvider(context);
|
||||||
if (provider != null) {
|
if (provider != null) {
|
||||||
return provider.createColumnPresentation(element);
|
return provider.createColumnPresentation(context, element);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IColumnEditor createColumnEditor(IPresentationContext context, Object element) {
|
public String getColumnPresentationId(IPresentationContext context, Object element) {
|
||||||
VMProvider provider = getViewModelProvider(context);
|
final IVMProvider provider = getViewModelProvider(context);
|
||||||
if (provider != null) {
|
if (provider != null) {
|
||||||
return provider.createColumnEditor(element);
|
return provider.getColumnPresentationId(context, element);
|
||||||
}
|
}
|
||||||
return null;
|
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;
|
package org.eclipse.dd.dsf.ui.viewmodel;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
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.Done;
|
||||||
import org.eclipse.dd.dsf.concurrent.DoneCollector;
|
import org.eclipse.dd.dsf.concurrent.DoneCollector;
|
||||||
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
|
|
||||||
import org.eclipse.dd.dsf.concurrent.GetDataDone;
|
import org.eclipse.dd.dsf.concurrent.GetDataDone;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditor;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditorFactoryAdapter;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.ILabelRequestMonitor;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactoryAdapter;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
|
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")
|
@SuppressWarnings("restriction")
|
||||||
abstract public class AbstractVMLayoutNode implements IVMLayoutNode {
|
abstract public class AbstractVMLayoutNode implements IVMLayoutNode {
|
||||||
|
|
||||||
private final DsfExecutor fExecutor;
|
private final AbstractVMProvider fProvider;
|
||||||
|
private boolean fDisposed = false;
|
||||||
|
|
||||||
/** Child schema nodes of this node. */
|
/** Child schema nodes of this node. */
|
||||||
private IVMLayoutNode[] fChildNodes = new IVMLayoutNode[0];
|
private IVMLayoutNode[] fChildNodes = new IVMLayoutNode[0];
|
||||||
|
|
||||||
|
|
||||||
public AbstractVMLayoutNode(DsfExecutor executor) {
|
public AbstractVMLayoutNode(AbstractVMProvider provider) {
|
||||||
fExecutor = executor;
|
fProvider = provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accessor method for sub-classes.
|
* Accessor method for sub-classes.
|
||||||
*/
|
*/
|
||||||
protected DsfExecutor getExecutor() {
|
protected Executor getExecutor() {
|
||||||
return fExecutor;
|
return fProvider.getExecutor();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IVMProvider getVMProvider() {
|
||||||
|
return fProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setChildNodes(IVMLayoutNode[] childNodes) {
|
public void setChildNodes(IVMLayoutNode[] childNodes) {
|
||||||
|
@ -55,6 +73,7 @@ abstract public class AbstractVMLayoutNode implements IVMLayoutNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
|
fDisposed = true;
|
||||||
for (IVMLayoutNode childNode : getChildLayoutNodes()) {
|
for (IVMLayoutNode childNode : getChildLayoutNodes()) {
|
||||||
childNode.dispose();
|
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
|
* If any of the children nodes have delta flags, that means that this
|
||||||
* node has to generate a delta as well.
|
* 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()) {
|
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
|
* schema nodes have deltas, this schema node has to provide the
|
||||||
* IModelDelta objects that the child shema node can build on.
|
* IModelDelta objects that the child shema node can build on.
|
||||||
*/
|
*/
|
||||||
public void buildDelta(final Object e, final VMDelta parent, final Done done) {
|
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.
|
||||||
* Find the child nodes that have deltas for the given event. If no
|
final Map<IVMLayoutNode,Integer> childNodeDeltas = getChildNodesWithDeltas(event);
|
||||||
* child layout nodes have deltas, just invoke the done.
|
|
||||||
*/
|
// If no child layout nodes have deltas we can stop here.
|
||||||
final IVMLayoutNode[] childNodes = getChildNodesWithDeltas(e);
|
if (childNodeDeltas.size() == 0) {
|
||||||
if (childNodes.length == 0) {
|
|
||||||
getExecutor().execute(done);
|
getExecutor().execute(done);
|
||||||
return;
|
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) {
|
||||||
* The given child layout nodes have deltas potentially for all elements
|
callChildNodesToBuildDelta(childNodeDeltas, parentDelta, event, done);
|
||||||
* from this node. Retrieve all elements and call the child nodes with
|
} else {
|
||||||
* each element as the parent of their delta.
|
// The given child layout nodes have deltas potentially for all elements
|
||||||
*/
|
// from this node. Retrieve all elements and call the child nodes with
|
||||||
getElements(
|
// each element as the parent of their delta.
|
||||||
parent.getVMC(),
|
updateElements(new ElementsUpdate(
|
||||||
new GetDataDone<IVMContext[]>() {
|
new GetDataDone<List<Object>>() {
|
||||||
public void run() {
|
public void run() {
|
||||||
if (propagateError(getExecutor(), done, "Failed to retrieve elements in layout node " + AbstractVMLayoutNode.this)) return; //$NON-NLS-1$
|
if (fDisposed) return;
|
||||||
|
|
||||||
/*
|
// Check for an empty list of elements. If it's empty then we
|
||||||
* Check for an empty list of elements. If it's empty then we
|
// don't have to call the children nodes, so return here.
|
||||||
* 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) {
|
||||||
if (getData().length == 0) {
|
|
||||||
getExecutor().execute(done);
|
getExecutor().execute(done);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
final DoneCollector<Done> elementsDeltasDoneCollector = new DoneCollector<Done>() {
|
||||||
* The execution for this node is not done until all the child nodes
|
public void run() {
|
||||||
* are done. Use the tracker to wait for all children to complete.
|
if (isDisposed()) return;
|
||||||
*/
|
|
||||||
final DoneCollector doneCollector = new DoneCollector(getExecutor()) { public void run() {
|
|
||||||
getExecutor().execute(done);
|
getExecutor().execute(done);
|
||||||
}};
|
|
||||||
for (IVMContext element : getData()) {
|
|
||||||
for (final IVMLayoutNode childNode : childNodes) {
|
|
||||||
childNode.buildDelta(
|
|
||||||
e,
|
|
||||||
parent.addNode(element, IModelDelta.NO_CHANGE),
|
|
||||||
doneCollector.addNoActionDone());
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// For each element from this node, create a new delta,
|
||||||
|
// and then call all the child nodes to build their delta.
|
||||||
|
for (int i = 0; i < getData().size(); i++) {
|
||||||
|
VMDelta delta = parentDelta.addNode((IVMContext)getData().get(i), nodeOffset + i, IModelDelta.NO_CHANGE);
|
||||||
|
callChildNodesToBuildDelta(
|
||||||
|
childNodeDeltas, delta, event,
|
||||||
|
elementsDeltasDoneCollector.add(new Done() {
|
||||||
|
public void run() {
|
||||||
|
elementsDeltasDoneCollector.doneDone(this);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
parentDelta));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void callChildNodesToBuildDelta(final Map<IVMLayoutNode,Integer> nodes, final VMDelta delta, final Object event, final Done done) {
|
||||||
|
assert nodes.size() != 0;
|
||||||
|
|
||||||
|
// Check if any of the child nodes are will generate IModelDelta.SELECT or
|
||||||
|
// IModelDelta.EXPAND flags. If so, we must calcuate the index for this
|
||||||
|
// VMC.
|
||||||
|
boolean calculateOffsets = false;
|
||||||
|
for (int childDelta : nodes.values()) {
|
||||||
|
if ( (childDelta & (IModelDelta.SELECT | IModelDelta.EXPAND)) != 0 ) {
|
||||||
|
calculateOffsets = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getChildNodesElementOffsets(delta, !calculateOffsets, new GetDataDone<Map<IVMLayoutNode, Integer>>() {
|
||||||
|
public void run() {
|
||||||
|
final DoneCollector<Done> childrenBuildDeltaDoneCollector = new DoneCollector<Done>() {
|
||||||
|
public void run() {
|
||||||
|
if (isDisposed()) return;
|
||||||
|
getExecutor().execute(done);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set the total count of number of children in the parent delta.
|
||||||
|
delta.setChildCount(getData().get(null));
|
||||||
|
|
||||||
|
for (IVMLayoutNode node : nodes.keySet()) {
|
||||||
|
node.buildDelta(
|
||||||
|
event, delta, getData().get(node),
|
||||||
|
childrenBuildDeltaDoneCollector.add(new Done() {
|
||||||
|
public void run() {
|
||||||
|
childrenBuildDeltaDoneCollector.doneDone(this);
|
||||||
|
}})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void getChildNodesElementOffsets(IModelDelta delta, boolean fakeIt, final GetDataDone<Map<IVMLayoutNode, Integer>> done) {
|
||||||
* Default implementation of the IColumnEditorFactoryAdapter delegate. It
|
assert getChildLayoutNodes().length != 0;
|
||||||
* returns null, which means that no cell editor is configured.
|
|
||||||
* @see IColumnEditorFactoryAdapter#createColumnEditor(IPresentationContext, Object)
|
if (!fakeIt) {
|
||||||
*/
|
final Integer[] counts = new Integer[getChildLayoutNodes().length];
|
||||||
public IColumnEditor createColumnEditor(IVMContext vmc) {
|
final DoneCollector<Done> childrenCountDoneCollector = new DoneCollector<Done>() {
|
||||||
return null;
|
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() {
|
||||||
* Default implementation of the IColumnEditorFactoryAdapter delegate. It
|
return fDisposed;
|
||||||
* returns null, which means that no cell editor is configured.
|
|
||||||
* @see IColumnEditorFactoryAdapter#getColumnEditorId(IPresentationContext, Object)
|
|
||||||
*/
|
|
||||||
public String getColumnEditorId(IVMContext vmc) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -149,41 +256,173 @@ abstract public class AbstractVMLayoutNode implements IVMLayoutNode {
|
||||||
* <code>true</code> to the <code>hasDeltaFlags()</code> test for the given
|
* <code>true</code> to the <code>hasDeltaFlags()</code> test for the given
|
||||||
* event.
|
* event.
|
||||||
*/
|
*/
|
||||||
protected IVMLayoutNode[] getChildNodesWithDeltas(Object e) {
|
protected Map<IVMLayoutNode, Integer> getChildNodesWithDeltas(Object e) {
|
||||||
List<IVMLayoutNode> nodes = new ArrayList<IVMLayoutNode>();
|
Map<IVMLayoutNode, Integer> nodes = new HashMap<IVMLayoutNode, Integer>();
|
||||||
for (final IVMLayoutNode childNode : getChildLayoutNodes()) {
|
for (final IVMLayoutNode childNode : getChildLayoutNodes()) {
|
||||||
if (childNode.hasDeltaFlags(e)) {
|
int delta = childNode.getDeltaFlags(e);
|
||||||
nodes.add(childNode);
|
if (delta != IModelDelta.NO_CHANGE) {
|
||||||
|
nodes.put(childNode, delta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nodes.toArray(new IVMLayoutNode[nodes.size()]);
|
return nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience method that returns a token value in case when the services
|
* Convenience method that returns a token value in case when the services
|
||||||
* that the layout node depends on, are not available.
|
* that the layout node depends on, are not available.
|
||||||
*/
|
*/
|
||||||
protected void handleFailedHasElements(GetDataDone<Boolean> done) {
|
protected boolean checkUpdate(IViewerUpdate update) {
|
||||||
done.setData(false);
|
if (update.isCanceled()) return false;
|
||||||
getExecutor().execute(done);
|
if (fDisposed) {
|
||||||
|
handleFailedUpdate(update);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected void handleFailedUpdate(IViewerUpdate update) {
|
||||||
* Convenience method that returns a token value in case when the services
|
if (update instanceof IHasChildrenUpdate) {
|
||||||
* that the layout node depends on, are not available.
|
((IHasChildrenUpdate)update).setHasChilren(false);
|
||||||
*/
|
} else if (update instanceof IChildrenCountUpdate) {
|
||||||
protected void handleFailedGetElements(GetDataDone<IVMContext[]> done) {
|
((IChildrenCountUpdate)update).setChildCount(0);
|
||||||
done.setData(new IVMContext[0]);
|
} else if (update instanceof ILabelUpdate) {
|
||||||
getExecutor().execute(done);
|
ILabelUpdate labelUpdate = (ILabelUpdate)update;
|
||||||
|
String[] columns = labelUpdate.getPresentationContext().getColumns();
|
||||||
|
for (int i = 0; i < (columns != null ? columns.length : 1); i++) {
|
||||||
|
labelUpdate.setLabel("...", i); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
update.done();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class AbstractVMContext implements IVMContext {
|
||||||
|
protected final IVMAdapter fVMAdapter;
|
||||||
|
protected final IVMLayoutNode fLayoutNode;
|
||||||
|
|
||||||
|
public AbstractVMContext(IVMAdapter adapter, IVMLayoutNode node) {
|
||||||
|
fVMAdapter = adapter;
|
||||||
|
fLayoutNode = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IVMLayoutNode getLayoutNode() { return fLayoutNode; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience method that returns a token value in case when the services
|
* IAdapter implementation returns the IVMAdapter instance for the
|
||||||
* that the layout node depends on, are not available.
|
* interfaces that are actually implemented by the VM Adapter. These
|
||||||
|
* should at least include {@link IElementContentProvider},
|
||||||
|
* {@link IModelProxyFactoryAdapter}, and
|
||||||
|
* {@link IColumnPresentationFactoryAdapter}.
|
||||||
*/
|
*/
|
||||||
protected void handleFailedRetrieveLabel(ILabelRequestMonitor result) {
|
@SuppressWarnings("unchecked")
|
||||||
result.setLabels(new String[] { "..."} ); //$NON-NLS-1$
|
public Object getAdapter(Class adapter) {
|
||||||
result.done();
|
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;
|
package org.eclipse.dd.dsf.ui.viewmodel;
|
||||||
|
|
||||||
import org.eclipse.core.runtime.IAdaptable;
|
import java.util.Map;
|
||||||
import org.eclipse.dd.dsf.concurrent.DoneCollector;
|
|
||||||
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
|
import org.eclipse.dd.dsf.concurrent.Done;
|
||||||
import org.eclipse.dd.dsf.concurrent.GetDataDone;
|
import org.eclipse.dd.dsf.concurrent.GetDataDone;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.ILabelRequestMonitor;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta;
|
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")
|
@SuppressWarnings("restriction")
|
||||||
abstract public class AbstractVMRootLayoutNode extends AbstractVMLayoutNode implements IVMRootLayoutNode {
|
abstract public class AbstractVMRootLayoutNode extends AbstractVMLayoutNode implements IVMRootLayoutNode {
|
||||||
|
|
||||||
protected static class RootVMC<V> implements IRootVMC {
|
public AbstractVMRootLayoutNode(AbstractVMProvider provider) {
|
||||||
private final V fInputObject;
|
super(provider);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -68,9 +35,10 @@ abstract public class AbstractVMRootLayoutNode extends AbstractVMLayoutNode impl
|
||||||
* There is no use case for a root node implementing this method, but its
|
* 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.
|
* easier to just impelemnt it for sake of uniformity of model.
|
||||||
*/
|
*/
|
||||||
public void getElements(IVMContext parentVmc, GetDataDone<IVMContext[]> done) {
|
public void updateElements(IChildrenUpdate update) {
|
||||||
done.setData(new IVMContext[] { getRootVMC() });
|
// Ignore startIdx, endIdx, since there's only one element to be had.
|
||||||
getExecutor().execute(done);
|
update.setChild(getRootObject(), 0);
|
||||||
|
update.done();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,9 +46,9 @@ abstract public class AbstractVMRootLayoutNode extends AbstractVMLayoutNode impl
|
||||||
* There is no use case for a root node implementing this method, but its
|
* 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.
|
* easier to just impelemnt it for sake of uniformity of model.
|
||||||
*/
|
*/
|
||||||
public void hasElements(IVMContext parentVmc, GetDataDone<Boolean> done) {
|
public void updateElementCount(IChildrenCountUpdate update) {
|
||||||
done.setData(true);
|
update.setChildCount(1);
|
||||||
getExecutor().execute(done);
|
update.done();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -88,8 +56,20 @@ abstract public class AbstractVMRootLayoutNode extends AbstractVMLayoutNode impl
|
||||||
* There is no use case for a root node implementing this method, but its
|
* 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.
|
* easier to just impelemnt it for sake of uniformity of model.
|
||||||
*/
|
*/
|
||||||
public void retrieveLabel(IVMContext vmc, ILabelRequestMonitor result, String[] columns) {
|
public void updateHasElements(IHasChildrenUpdate[] updates) {
|
||||||
result.done();
|
for (IHasChildrenUpdate update : updates) {
|
||||||
|
update.setHasChilren(true);
|
||||||
|
update.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This implementation only fulfils the requirements of the super-interface.
|
||||||
|
* There is no use case for a root node implementing this method, but its
|
||||||
|
* easier to just impelemnt it for sake of uniformity of model.
|
||||||
|
*/
|
||||||
|
public void updateLabel(IVMContext vmc, ILabelUpdate update) {
|
||||||
|
update.done();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -97,28 +77,21 @@ abstract public class AbstractVMRootLayoutNode extends AbstractVMLayoutNode impl
|
||||||
* is the input object into the view.
|
* is the input object into the view.
|
||||||
*/
|
*/
|
||||||
public void createDelta(Object event, final GetDataDone<IModelDelta> done) {
|
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);
|
// Always create the rootDelta, no matter what delta flags the child nodes have.
|
||||||
if (childNodes.length == 0) {
|
final VMDelta rootDelta = new VMDelta(getRootObject(), IModelDelta.NO_CHANGE);
|
||||||
done.setData(rootDelta);
|
|
||||||
getExecutor().execute(done);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
callChildNodesToBuildDelta(
|
||||||
* The execution for this node is not done until all the child nodes
|
childNodeDeltas, rootDelta, event,
|
||||||
* are done. Use the tracker to wait for all children to complete.
|
new Done() {
|
||||||
*/
|
|
||||||
final DoneCollector doneCollector = new DoneCollector(getExecutor()) {
|
|
||||||
public void run() {
|
public void run() {
|
||||||
if (propagateError(getExecutor(), done, "Failed to generate child deltas.")) return; //$NON-NLS-1$
|
if (isDisposed()) return;
|
||||||
|
if (propagateError(getExecutor(), done, "Failed to create delta.")); //$NON-NLS-1$
|
||||||
done.setData(rootDelta);
|
done.setData(rootDelta);
|
||||||
getExecutor().execute(done);
|
getExecutor().execute(done);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
for (final IVMLayoutNode childNode : childNodes) {
|
|
||||||
childNode.buildDelta(event, rootDelta, doneCollector.addNoActionDone());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
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
|
@Immutable
|
||||||
public interface IVMContext extends IAdaptable {
|
public interface IVMContext extends IAdaptable {
|
||||||
|
@ -23,10 +23,4 @@ public interface IVMContext extends IAdaptable {
|
||||||
* Returns the layout node that originated this element.
|
* Returns the layout node that originated this element.
|
||||||
*/
|
*/
|
||||||
public IVMLayoutNode getLayoutNode();
|
public IVMLayoutNode getLayoutNode();
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the parent of this element in the viewer layout.
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public IVMContext getParent();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,54 +12,66 @@ package org.eclipse.dd.dsf.ui.viewmodel;
|
||||||
|
|
||||||
import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
|
import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
|
||||||
import org.eclipse.dd.dsf.concurrent.Done;
|
import org.eclipse.dd.dsf.concurrent.Done;
|
||||||
import org.eclipse.dd.dsf.concurrent.GetDataDone;
|
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMProvider;
|
||||||
import org.eclipse.dd.dsf.concurrent.ThreadSafeAndProhibitedFromDsfExecutor;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditor;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditorFactoryAdapter;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.ILabelRequestMonitor;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta;
|
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View model layout nodes are combined together into a tree, to collectively
|
* 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
|
* define the layout of a view. Each layout node generates elements of type
|
||||||
* IVMContext, and provide label information about these elements.
|
* IVMContext which are then stored in the viewer.
|
||||||
* <p>
|
* <p>
|
||||||
* Besides the standard Data Model Context based implementation, this
|
* Besides the standard Data Model Context based implementation, this
|
||||||
* node could be implemented to present data from any source, not necessarily
|
* 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
|
* DSF services. It could also define a static node which operates on basis
|
||||||
* of other data in the view tree.
|
* of other data in the view tree.
|
||||||
* @see VMProvider
|
* @see AbstractDMVMProvider
|
||||||
*/
|
*/
|
||||||
@ConfinedToDsfExecutor("")
|
@ConfinedToDsfExecutor("")
|
||||||
@SuppressWarnings("restriction")
|
@SuppressWarnings("restriction")
|
||||||
public interface IVMLayoutNode {
|
public interface IVMLayoutNode
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves information whether for the given parent node, there are any elements
|
* Retrieves information whether for a given path in the viewer,
|
||||||
* available.
|
* there are any elements available in this node.
|
||||||
* @param parentVmc Parent node, for which to calculate elements at the
|
*
|
||||||
* current level.
|
* @param updates The update objects which need to be filled in with results
|
||||||
* @param done The data return token.
|
* calculated by this method.
|
||||||
|
* Even though the "children" interface is reused, the updates refer to the
|
||||||
|
* elements of this layout node, and not it's children.
|
||||||
*/
|
*/
|
||||||
public void hasElements(IVMContext parentVmc, GetDataDone<Boolean> done);
|
public void updateHasElements(IHasChildrenUpdate[] updates);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the list of elements.
|
* Retrieves the number of available elements in this node for the given
|
||||||
* @param parentVmc Parent node, for which to calculate elements at the
|
* path in the viewer.
|
||||||
* current level.
|
*
|
||||||
* @param done The data return token.
|
* @param updates The update object which needs to be filled in with result
|
||||||
|
* calculated by this method.
|
||||||
|
* Even though the "children" interface is reused, the updates refer to the
|
||||||
|
* elements of this layout node, and not it's children.
|
||||||
*/
|
*/
|
||||||
public void getElements(IVMContext parentVmc, GetDataDone<IVMContext[]> done);
|
public void updateElementCount(IChildrenCountUpdate update);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the label for the given element.
|
* Retrieves the element objects of this node for the given path in the
|
||||||
* @param vmc Element for which to retrieve label information.
|
* viewer, and for the given range of indexes. <br>
|
||||||
* @param result Monitor which accepts the data.
|
* Note: the range of children, denoted by ILabelUpdate.getOffset()
|
||||||
* @param columns Currently configured columns in view.
|
* and ILabelUpdate.getLength(), may not be specified, in which case these
|
||||||
* @see IPresentationContext
|
* methods may return -1. This means that all the elements should be
|
||||||
|
* retrieved for this node.<br>
|
||||||
|
*
|
||||||
|
* @param updates The update object which needs to be filled in with result
|
||||||
|
* calculated by this method.
|
||||||
|
* Even though the "children" interface is reused, the updates refer to the
|
||||||
|
* elements of this layout node, and not it's children.
|
||||||
*/
|
*/
|
||||||
public void retrieveLabel(IVMContext vmc, ILabelRequestMonitor result, String[] columns);
|
public void updateElements(IChildrenUpdate update);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the child layout nodes for this node.
|
* Configures the child layout nodes for this node.
|
||||||
|
@ -73,51 +85,28 @@ public interface IVMLayoutNode {
|
||||||
public IVMLayoutNode[] getChildLayoutNodes();
|
public IVMLayoutNode[] getChildLayoutNodes();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true/false indicating whether the given even will cause this
|
* Returns the potential delta flags that would be generated by this node
|
||||||
* schema node to generate a model delta.
|
* for the given event.
|
||||||
* @param event Event to process.
|
* @param event Event to process.
|
||||||
* @return True if this node (or its children) would generate delta data
|
* @return IModelDelta flags
|
||||||
* due to this event.
|
|
||||||
* @see IModelDelta
|
* @see IModelDelta
|
||||||
*/
|
*/
|
||||||
public boolean hasDeltaFlags(Object event);
|
public int getDeltaFlags(Object event);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds model delta information based on the given event.
|
* Builds model delta information based on the given event.
|
||||||
* @param event Event to process.
|
* @param event Event to process.
|
||||||
* @param parent Parent model delta node that this object should add delta
|
* @param parent Parent model delta node that this object should add delta
|
||||||
* data to.
|
* 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
|
* @param done Return token, which notifies the caller that the calculation is
|
||||||
* complete.
|
* 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
|
* Releases the resources held by this node.
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
public void dispose();
|
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;
|
package org.eclipse.dd.dsf.ui.viewmodel;
|
||||||
|
|
||||||
import org.eclipse.dd.dsf.concurrent.GetDataDone;
|
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
|
* 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")
|
@SuppressWarnings("restriction")
|
||||||
public interface IVMRootLayoutNode extends IVMLayoutNode{
|
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
|
* 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.
|
* one element, and this is a convenience method to access this element.
|
||||||
* Alternatively getElements() could be used.
|
* Alternatively getElements() could be used.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public IRootVMC getRootVMC();
|
public Object getRootObject();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Version of the {@link IVMLayoutNode#buildDelta(Object, ViewModelDelta, org.eclipse.dd.dsf.concurrent.Done)}
|
* 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;
|
package org.eclipse.dd.dsf.ui.viewmodel;
|
||||||
|
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
|
||||||
import org.eclipse.debug.internal.ui.viewers.provisional.ModelDelta;
|
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
|
* 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 {
|
public class VMDelta extends ModelDelta {
|
||||||
|
|
||||||
private VMDelta fParent;
|
private VMDelta fParent;
|
||||||
private IVMContext fVmcElement;
|
|
||||||
private Object fElement;
|
private Object fElement;
|
||||||
private int fFlags;
|
private int fFlags;
|
||||||
private VMDelta[] fNodes = EMPTY_NODES;
|
private VMDelta[] fNodes = EMPTY_NODES;
|
||||||
private Object fReplacement;
|
private Object fReplacement;
|
||||||
private int fIndex;
|
private int fIndex;
|
||||||
private static final VMDelta[] EMPTY_NODES = new VMDelta[0];
|
private static final VMDelta[] EMPTY_NODES = new VMDelta[0];
|
||||||
|
private int fChildCount = -1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new delta for the given element.
|
* Constructs a new delta for the given element.
|
||||||
|
@ -39,9 +40,9 @@ public class VMDelta extends ModelDelta {
|
||||||
* @param vmcElement model element
|
* @param vmcElement model element
|
||||||
* @param flags change flags
|
* @param flags change flags
|
||||||
*/
|
*/
|
||||||
public VMDelta(IVMContext vmcElement, int flags) {
|
public VMDelta(Object element, int flags) {
|
||||||
super(vmcElement, flags);
|
super(element, flags);
|
||||||
fVmcElement = vmcElement;
|
fElement = element;
|
||||||
fFlags = flags;
|
fFlags = flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,9 +54,9 @@ public class VMDelta extends ModelDelta {
|
||||||
* @param replacement replacement element
|
* @param replacement replacement element
|
||||||
* @param flags change flags
|
* @param flags change flags
|
||||||
*/
|
*/
|
||||||
public VMDelta(IVMContext vmcElement, Object replacement, int flags) {
|
public VMDelta(Object element, Object replacement, int flags) {
|
||||||
super(vmcElement, replacement, flags);
|
super(element, replacement, flags);
|
||||||
fVmcElement = vmcElement;
|
fElement = element;
|
||||||
fReplacement = replacement;
|
fReplacement = replacement;
|
||||||
fFlags = flags;
|
fFlags = flags;
|
||||||
}
|
}
|
||||||
|
@ -68,40 +69,44 @@ public class VMDelta extends ModelDelta {
|
||||||
* @param index insertion position
|
* @param index insertion position
|
||||||
* @param flags change flags
|
* @param flags change flags
|
||||||
*/
|
*/
|
||||||
public VMDelta(IVMContext vmcElement, int index, int flags) {
|
public VMDelta(Object element, int index, int flags) {
|
||||||
super(vmcElement, index, flags);
|
super(element, index, flags);
|
||||||
fVmcElement = vmcElement;
|
fElement = element;
|
||||||
fIndex = index;
|
fIndex = index;
|
||||||
fFlags = flags;
|
fFlags = flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for model delta based on non-VMC element. This delta is
|
* Constructs a new delta for the given element at the specified index
|
||||||
* only needed for creating delta nodes for parent elements in the tree
|
* relative to its parent with the given number of children.
|
||||||
* if the VMC elements are not at the root of the tree.
|
*
|
||||||
* @param element Element to create the delta for.
|
* @param element model element
|
||||||
* @param vmcElement Optional VMC element for this node, it can be used
|
* @param index insertion position
|
||||||
* by other nodes in the delta to set their VMC parent element correctly.
|
* @param flags change flags
|
||||||
|
* @param childCount number of children this node has
|
||||||
*/
|
*/
|
||||||
public VMDelta(Object element, IVMContext vmcElement) {
|
public VMDelta(Object element, int index, int flags, int childCount) {
|
||||||
super(element, IModelDelta.NO_CHANGE);
|
super(element, index, flags, childCount);
|
||||||
fElement = element;
|
fElement = element;
|
||||||
fVmcElement = vmcElement;
|
fIndex = index;
|
||||||
|
fFlags = flags;
|
||||||
|
fChildCount = childCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the non-VMC element if one is set, otherwise returns the VMC
|
* Returns the non-VMC element if one is set, otherwise returns the VMC
|
||||||
* element of this delta node.
|
* element of this delta node.
|
||||||
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getElement()
|
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getElement()
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public Object getElement() {
|
public Object getElement() {
|
||||||
return fElement != null ? fElement : fVmcElement;
|
return fElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getFlags()
|
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getFlags()
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public int getFlags() {
|
public int getFlags() {
|
||||||
return fFlags;
|
return fFlags;
|
||||||
}
|
}
|
||||||
|
@ -110,7 +115,9 @@ public class VMDelta extends ModelDelta {
|
||||||
fFlags |= flags;
|
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,
|
* 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
|
* @param flags change flags for child
|
||||||
* @return newly created child delta
|
* @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);
|
VMDelta node = new VMDelta(element, flags);
|
||||||
node.setParent(this);
|
node.setParent(this);
|
||||||
addDelta(node);
|
addDelta(node);
|
||||||
|
@ -137,7 +144,7 @@ public class VMDelta extends ModelDelta {
|
||||||
* @param flags change flags
|
* @param flags change flags
|
||||||
* @return newly created child delta
|
* @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);
|
VMDelta node = new VMDelta(element, replacement, flags);
|
||||||
node.setParent(this);
|
node.setParent(this);
|
||||||
addDelta(node);
|
addDelta(node);
|
||||||
|
@ -153,7 +160,7 @@ public class VMDelta extends ModelDelta {
|
||||||
* @param flags change flags
|
* @param flags change flags
|
||||||
* @return newly created child delta
|
* @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);
|
VMDelta node = new VMDelta(element, index, flags);
|
||||||
node.setParent(this);
|
node.setParent(this);
|
||||||
addDelta(node);
|
addDelta(node);
|
||||||
|
@ -161,16 +168,17 @@ public class VMDelta extends ModelDelta {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a node to the delta for a non-VMC element. This is used to
|
* Adds a child delta to this delta at the specified index with the
|
||||||
* construct the root branch of the delta before it is handed off to
|
* given number of children, and returns the newly created child delta.
|
||||||
* ViewModelProvider.handleDataModelEvent()
|
*
|
||||||
* @param element Element in the asynchronous view to create the new node for.
|
* @param element child element in insert
|
||||||
* @param vmcElement Optional VMC element for this node, it can be used
|
* @param index index of the element relative to parent
|
||||||
* by other nodes in the delta to set their VMC parent element correctly.
|
* @param flags change flags
|
||||||
* @return Returns the added delta node.
|
* @param numChildren the number of children the element has
|
||||||
|
* @return newly created child delta
|
||||||
*/
|
*/
|
||||||
public VMDelta addNode(Object element, IVMContext vmcElement) {
|
public ModelDelta addNode(Object element, int index, int flags, int numChildren) {
|
||||||
VMDelta node = new VMDelta(element, vmcElement);
|
VMDelta node = new VMDelta(element, index, flags, numChildren);
|
||||||
node.setParent(this);
|
node.setParent(this);
|
||||||
addDelta(node);
|
addDelta(node);
|
||||||
return node;
|
return node;
|
||||||
|
@ -188,13 +196,15 @@ public class VMDelta extends ModelDelta {
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getParent()
|
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getParent()
|
||||||
*/
|
*/
|
||||||
public IModelDelta getParent() {
|
@Override
|
||||||
|
public IModelDelta getParentDelta() {
|
||||||
return fParent;
|
return fParent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getReplacementElement()
|
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getReplacementElement()
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public Object getReplacementElement() {
|
public Object getReplacementElement() {
|
||||||
return fReplacement;
|
return fReplacement;
|
||||||
}
|
}
|
||||||
|
@ -202,6 +212,7 @@ public class VMDelta extends ModelDelta {
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getIndex()
|
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getIndex()
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public int getIndex() {
|
public int getIndex() {
|
||||||
return fIndex;
|
return fIndex;
|
||||||
}
|
}
|
||||||
|
@ -209,7 +220,8 @@ public class VMDelta extends ModelDelta {
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getNodes()
|
* @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getNodes()
|
||||||
*/
|
*/
|
||||||
public VMDelta[] getNodes() {
|
@Override
|
||||||
|
public VMDelta[] getChildDeltas() {
|
||||||
return fNodes;
|
return fNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,6 +236,7 @@ public class VMDelta extends ModelDelta {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuffer buf = new StringBuffer();
|
StringBuffer buf = new StringBuffer();
|
||||||
buf.append("Model Delta Start\n"); //$NON-NLS-1$
|
buf.append("Model Delta Start\n"); //$NON-NLS-1$
|
||||||
|
@ -265,11 +278,46 @@ public class VMDelta extends ModelDelta {
|
||||||
if ((flags & IModelDelta.STATE) > 0) {
|
if ((flags & IModelDelta.STATE) > 0) {
|
||||||
buf.append("STATE | "); //$NON-NLS-1$
|
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('\n');
|
||||||
VMDelta[] nodes = delta.getNodes();
|
buf.append("\t\tIndex: "); //$NON-NLS-1$
|
||||||
|
buf.append(delta.fIndex);
|
||||||
|
buf.append(" Child Count: "); //$NON-NLS-1$
|
||||||
|
buf.append(delta.fChildCount);
|
||||||
|
buf.append('\n');
|
||||||
|
IModelDelta[] nodes = delta.getChildDeltas();
|
||||||
for (int i = 0; i < nodes.length; i++) {
|
for (int i = 0; i < nodes.length; i++) {
|
||||||
appendDetail(buf, nodes[i]);
|
appendDetail(buf, (VMDelta)nodes[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta#getChildCount()
|
||||||
|
*/
|
||||||
|
public int getChildCount() {
|
||||||
|
return fChildCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta#accept(org.eclipse.debug.internal.ui.viewers.provisional.IModelDeltaVisitor)
|
||||||
|
*/
|
||||||
|
public void accept(IModelDeltaVisitor visitor) {
|
||||||
|
doAccept(visitor, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void doAccept(IModelDeltaVisitor visitor, int depth) {
|
||||||
|
if (visitor.visit(this, depth)) {
|
||||||
|
ModelDelta[] childDeltas = getChildDeltas();
|
||||||
|
for (int i = 0; i < childDeltas.length; i++) {
|
||||||
|
((VMDelta)childDeltas[i]).doAccept(visitor, depth+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
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) {
|
if (log != null) {
|
||||||
log.log(new Status(
|
log.log(new Status(
|
||||||
IStatus.ERROR, DsfPlugin.PLUGIN_ID, -1, "Uncaught exception in DSF executor thread", t)); //$NON-NLS-1$
|
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) {
|
public TracingWrapperRunnable(Runnable runnable, int offset) {
|
||||||
super(offset);
|
super(offset);
|
||||||
fRunnable = runnable;
|
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; }
|
protected Object getExecutable() { return fRunnable; }
|
||||||
|
@ -229,11 +238,6 @@ public class DefaultDsfExecutor extends ScheduledThreadPoolExecutor
|
||||||
public void run() {
|
public void run() {
|
||||||
traceExecution();
|
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.
|
// Finally invoke the runnable code.
|
||||||
fRunnable.run();
|
fRunnable.run();
|
||||||
}
|
}
|
||||||
|
@ -251,11 +255,6 @@ public class DefaultDsfExecutor extends ScheduledThreadPoolExecutor
|
||||||
public T call() throws Exception {
|
public T call() throws Exception {
|
||||||
traceExecution();
|
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.
|
// Finally invoke the runnable code.
|
||||||
return fCallable.call();
|
return fCallable.call();
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,9 +35,8 @@ import org.eclipse.dd.dsf.DsfPlugin;
|
||||||
* }
|
* }
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public abstract class DoneCollector extends Done {
|
public abstract class DoneCollector<V extends Done> extends Done {
|
||||||
private final DsfExecutor fExecutor;
|
private Map<V,Boolean> fDones = new HashMap<V,Boolean>();
|
||||||
private Map<Done,Boolean> fDones = new HashMap<Done,Boolean>();
|
|
||||||
private int fDoneCounter;
|
private int fDoneCounter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,39 +46,25 @@ public abstract class DoneCollector extends Done {
|
||||||
* execution of the last done, and in the same dispatch loop.
|
* 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$
|
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.
|
* Adds a new Done callback to this tracker's list.
|
||||||
* @param <V> Service-specific class of the Done callback, to avoid an
|
* @param <T> Client-specific class of the Done callback, it's used here to avoid an
|
||||||
* unnecessary cast.
|
* unnecessary cast by the client.
|
||||||
* @param done callback object to add to the tracker
|
* @param done callback object to add to the tracker
|
||||||
* @return the done that was just added, it allows this method to be used
|
* @return the done that was just added, it allows this method to be used
|
||||||
* inlined in service method calls
|
* 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);
|
assert !fDones.containsKey(done);
|
||||||
fDones.put(done, false);
|
fDones.put(done, false);
|
||||||
fDoneCounter++;
|
fDoneCounter++;
|
||||||
return done;
|
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
|
* Marks the given Done callback as completed. Client implementations of
|
||||||
* the Done callback have to call this method in order for the tracker
|
* 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!
|
* Note: funniest method signature ever!
|
||||||
* @param done
|
* @param done
|
||||||
*/
|
*/
|
||||||
public void doneDone(Done done) {
|
public void doneDone(V done) {
|
||||||
((MultiStatus)getStatus()).merge(done.getStatus());
|
((MultiStatus)getStatus()).merge(done.getStatus());
|
||||||
|
assert fDones.containsKey(done);
|
||||||
fDones.put(done, true);
|
fDones.put(done, true);
|
||||||
|
assert fDoneCounter > 0;
|
||||||
fDoneCounter--;
|
fDoneCounter--;
|
||||||
if (fDoneCounter == 0) {
|
if (fDoneCounter == 0) {
|
||||||
assert !fDones.containsValue(false);
|
assert !fDones.containsValue(false);
|
||||||
fExecutor.execute(this);
|
run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,10 +91,15 @@ public abstract class DoneCollector extends Done {
|
||||||
* done callbacks.
|
* done callbacks.
|
||||||
* @return map of the done callbacks.
|
* @return map of the done callbacks.
|
||||||
*/
|
*/
|
||||||
public Map<Done,Boolean> getDones() { return fDones; }
|
public Map<V,Boolean> getDones() { return fDones; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Done Collector: " + getStatus().toString(); //$NON-NLS-1$
|
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
|
* Flag indicating whether this executable was ever executed by an
|
||||||
* executor. Used for tracing only.
|
* executor. Used for tracing only.
|
||||||
*/
|
*/
|
||||||
private boolean fExecuted = false;
|
private boolean fSubmitted = false;
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public DsfExecutable() {
|
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
|
* Marks this executable to indicate that it has been executed by the
|
||||||
* executor. To be invoked only by DsfExecutor.
|
* executor. To be invoked only by DsfExecutor.
|
||||||
*/
|
*/
|
||||||
void setExecuted() {
|
void setSubmitted() {
|
||||||
fExecuted = true;
|
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
|
@Override
|
||||||
protected void finalize() {
|
protected void finalize() {
|
||||||
if (DEBUG_EXECUTOR && !fExecuted) {
|
if (DEBUG_EXECUTOR && !fSubmitted && isExecutionRequired()) {
|
||||||
StringBuilder traceBuilder = new StringBuilder();
|
StringBuilder traceBuilder = new StringBuilder();
|
||||||
|
|
||||||
// Record the time
|
// Record the time
|
||||||
|
|
|
@ -12,7 +12,6 @@ package org.eclipse.dd.dsf.datamodel;
|
||||||
|
|
||||||
import org.eclipse.core.runtime.PlatformObject;
|
import org.eclipse.core.runtime.PlatformObject;
|
||||||
import org.eclipse.dd.dsf.concurrent.Immutable;
|
import org.eclipse.dd.dsf.concurrent.Immutable;
|
||||||
import org.eclipse.dd.dsf.service.AbstractDsfService;
|
|
||||||
import org.eclipse.dd.dsf.service.DsfSession;
|
import org.eclipse.dd.dsf.service.DsfSession;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,10 +39,8 @@ abstract public class AbstractDMContext<V extends IDMData> extends PlatformObjec
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Convenience constructor */
|
/** Convenience constructor */
|
||||||
public AbstractDMContext(AbstractDsfService service, IDMContext<?> parent) {
|
public AbstractDMContext(IDMService service, IDMContext<?>[] parents) {
|
||||||
this(service.getSession().getId(),
|
this(service.getSession().getId(), service.getServiceFilter(), parents);
|
||||||
service.getServiceFilter(),
|
|
||||||
parent == null ? new IDMContext[] {} : new IDMContext[] { parent });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.dd.dsf.datamodel;
|
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
|
* 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> {
|
public class ServiceDMContext<V extends IDMService> extends AbstractDMContext<V> {
|
||||||
String fServiceDMID;
|
String fServiceDMID;
|
||||||
|
|
||||||
public ServiceDMContext(AbstractDsfService service, String serviceDMID) {
|
public ServiceDMContext(IDMService service, String serviceDMID) {
|
||||||
super(service, null);
|
super(service, new IDMContext<?>[0]);
|
||||||
fServiceDMID = serviceDMID;
|
fServiceDMID = serviceDMID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,10 +74,14 @@ public interface IDsfService {
|
||||||
*/
|
*/
|
||||||
final static int INTERNAL_ERROR = 10005;
|
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.
|
* Returns the executor that should be used to call methods of this service.
|
||||||
* @return
|
* This method is equivalent to calling getSession().getExecutor()
|
||||||
*/
|
*/
|
||||||
DsfExecutor getExecutor();
|
DsfExecutor getExecutor();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue