diff options
Diffstat (limited to 'dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch')
13 files changed, 2434 insertions, 0 deletions
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/AbstractContainerVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/AbstractContainerVMNode.java new file mode 100644 index 00000000000..26cfc2d5468 --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/AbstractContainerVMNode.java @@ -0,0 +1,191 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. 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: + * Anton Leherbauer (Wind River Systems) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.debug.ui.viewmodel.launch; + +import java.util.concurrent.RejectedExecutionException; + +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.DsfRunnable; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.datamodel.DMContexts; +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.datamodel.IDMEvent; +import org.eclipse.cdt.dsf.debug.service.IRunControl; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerResumedDMEvent; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerSuspendedDMEvent; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IStartedDMEvent; +import org.eclipse.cdt.dsf.debug.service.StepQueueManager.ISteppingTimedOutEvent; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.SteppingController.SteppingTimedOutEvent; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext; +import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta; +import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode; +import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; + +/** + * Abstract implementation of a container view model node. + * Clients need to implement {@link #updateLabelInSessionThread(ILabelUpdate[])}. + * + * @since 1.1 + */ +@SuppressWarnings("restriction") +public abstract class AbstractContainerVMNode extends AbstractDMVMNode implements IElementLabelProvider { + + public AbstractContainerVMNode(AbstractDMVMProvider provider, DsfSession session) { + super(provider, session, IRunControl.IContainerDMContext.class); + } + + public void update(final ILabelUpdate[] updates) { + try { + getSession().getExecutor().execute(new DsfRunnable() { + public void run() { + for (final ILabelUpdate update : updates) { + updateLabelInSessionThread(update); + } + }}); + } catch (RejectedExecutionException e) { + for (ILabelUpdate update : updates) { + handleFailedUpdate(update); + } + } + } + + /** + * Perform the given label updates in the session executor thread. + * + * @param updates the pending label updates + * @see {@link #update(ILabelUpdate[]) + */ + protected abstract void updateLabelInSessionThread(ILabelUpdate update); + + @Override + public void getContextsForEvent(VMDelta parentDelta, Object e, final DataRequestMonitor<IVMContext[]> rm) { + super.getContextsForEvent(parentDelta, e, rm); + } + + public int getDeltaFlags(Object e) { + IDMContext dmc = e instanceof IDMEvent<?> ? ((IDMEvent<?>)e).getDMContext() : null; + + if (e instanceof IContainerResumedDMEvent) { + if (((IContainerResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP) + { + return IModelDelta.CONTENT; + } + } else if (e instanceof IContainerSuspendedDMEvent) { + return IModelDelta.NO_CHANGE; + } else if (e instanceof FullStackRefreshEvent) { + if (dmc instanceof IContainerDMContext) { + return IModelDelta.CONTENT; + } + } else if (e instanceof SteppingTimedOutEvent) { + if (dmc instanceof IContainerDMContext) + { + return IModelDelta.CONTENT; + } + } else if (e instanceof ISteppingTimedOutEvent) { + if (dmc instanceof IContainerDMContext) + { + return IModelDelta.CONTENT; + } + } else if (e instanceof IExitedDMEvent) { + return IModelDelta.CONTENT; + } else if (e instanceof IStartedDMEvent) { + if (dmc instanceof IContainerDMContext) { + return IModelDelta.EXPAND | IModelDelta.SELECT; + } else { + return IModelDelta.CONTENT; + } + } + return IModelDelta.NO_CHANGE; + } + + public void buildDelta(Object e, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor requestMonitor) { + IDMContext dmc = e instanceof IDMEvent<?> ? ((IDMEvent<?>)e).getDMContext() : null; + + if(e instanceof IContainerResumedDMEvent) { + // Container resumed: + // - If not stepping, update the container and the execution + // contexts under it. + // - If stepping, do nothing to avoid too many updates. If a + // time-out is reached before the step completes, the + // ISteppingTimedOutEvent will trigger a full refresh. + if (((IContainerResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP) + { + parentDelta.addNode(createVMContext(((IDMEvent<?>)e).getDMContext()), IModelDelta.CONTENT); + } + } else if (e instanceof IContainerSuspendedDMEvent) { + // Container suspended. Do nothing here to give the stack the + // priority in updating. The container and threads will update as + // a result of FullStackRefreshEvent. + } else if (e instanceof FullStackRefreshEvent) { + // Full-stack refresh event is generated following a suspended event + // and a fixed delay. If the suspended event was generated for the + // container refresh the whole container. + if (dmc instanceof IContainerDMContext) { + parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT); + } + } else if (e instanceof SteppingTimedOutEvent) { + // Stepping time-out indicates that a step operation is taking + // a long time, and the view needs to be refreshed to show + // the user that the program is running. + // If the step was issued for the whole container refresh + // the whole container. + if (dmc instanceof IContainerDMContext) { + parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT); + } + } else if (e instanceof ISteppingTimedOutEvent) { + // Stepping time-out indicates that a step operation is taking + // a long time, and the view needs to be refreshed to show + // the user that the program is running. + // If the step was issued for the whole container refresh + // the whole container. + if (dmc instanceof IContainerDMContext) { + parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT); + } + } else if (e instanceof IExitedDMEvent) { + // An exited event could either be for a thread within a container + // or for the container itself. + // If a container exited, refresh the parent element so that the + // container may be removed. + // If a thread exited within a container, refresh that container. + if (dmc instanceof IContainerDMContext) { + parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT); + } else { + IContainerDMContext containerCtx = DMContexts.getAncestorOfType(dmc, IContainerDMContext.class); + if (containerCtx != null) { + parentDelta.addNode(createVMContext(containerCtx), IModelDelta.CONTENT); + } + } + } else if (e instanceof IStartedDMEvent) { + // A started event could either be for a thread within a container + // or for the container itself. + // If a container started, issue an expand and select event to + // show the threads in the new container. + // Note: the EXPAND flag implies refreshing the parent element. + if (dmc instanceof IContainerDMContext) { + parentDelta.addNode(createVMContext(dmc), IModelDelta.EXPAND | IModelDelta.SELECT); + } else { + IContainerDMContext containerCtx = DMContexts.getAncestorOfType(dmc, IContainerDMContext.class); + if (containerCtx != null) { + parentDelta.addNode(createVMContext(containerCtx), IModelDelta.CONTENT); + } + } + } + + requestMonitor.done(); + } + +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/AbstractLaunchVMProvider.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/AbstractLaunchVMProvider.java new file mode 100644 index 00000000000..28de36ba1d8 --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/AbstractLaunchVMProvider.java @@ -0,0 +1,294 @@ +/******************************************************************************* + * Copyright (c) 2006, 2008 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 + * Ericsson - Modified for new functionality + *******************************************************************************/ +package org.eclipse.cdt.dsf.debug.ui.viewmodel.launch; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import org.eclipse.cdt.dsf.concurrent.DsfRunnable; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.concurrent.ThreadSafe; +import org.eclipse.cdt.dsf.datamodel.DMContexts; +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.datamodel.IDMEvent; +import org.eclipse.cdt.dsf.debug.service.IRunControl; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IStartedDMEvent; +import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent; +import org.eclipse.cdt.dsf.debug.ui.IDsfDebugUIConstants; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.LaunchRootVMNode.LaunchesEvent; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.StackFramesVMNode.IncompleteStackVMContext; +import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter; +import org.eclipse.cdt.dsf.ui.viewmodel.IRootVMNode; +import org.eclipse.cdt.dsf.ui.viewmodel.IVMModelProxy; +import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode; +import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; +import org.eclipse.cdt.dsf.ui.viewmodel.update.AutomaticUpdatePolicy; +import org.eclipse.cdt.dsf.ui.viewmodel.update.IVMUpdatePolicy; +import org.eclipse.cdt.dsf.ui.viewmodel.update.ManualUpdatePolicy; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.IDebugEventSetListener; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchesListener2; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.jface.viewers.DoubleClickEvent; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; + + +/** + * @since 1.1 + */ +@SuppressWarnings("restriction") +public class AbstractLaunchVMProvider extends AbstractDMVMProvider + implements IDebugEventSetListener, ILaunchesListener2 +{ + /** + * Delay (in milliseconds) before a full stack trace will be requested. + */ + private static final int FRAME_UPDATE_DELAY= 200; + + private final Map<IExecutionDMContext,ScheduledFuture<?>> fRefreshStackFramesFutures = new HashMap<IExecutionDMContext,ScheduledFuture<?>>(); + + private IPropertyChangeListener fPreferencesListener; + + @ThreadSafe + public AbstractLaunchVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext, DsfSession session) + { + super(adapter, presentationContext, session); + + final IPreferenceStore store= DsfUIPlugin.getDefault().getPreferenceStore(); + if (store.getBoolean(IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT_ENABLE)) { + getPresentationContext().setProperty(IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT, store.getInt(IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT)); + } + + fPreferencesListener = new IPropertyChangeListener() { + public void propertyChange(final PropertyChangeEvent event) { + handlePropertyChanged(store, event); + }}; + store.addPropertyChangeListener(fPreferencesListener); + } + + @Override + protected IVMUpdatePolicy[] createUpdateModes() { + return new IVMUpdatePolicy[] { + new DelayedStackRefreshUpdatePolicy(new AutomaticUpdatePolicy()), + new DelayedStackRefreshUpdatePolicy(new ManualUpdatePolicy()) + }; + } + + public void handleDebugEvents(final DebugEvent[] events) { + 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; + + for (final DebugEvent event : events) { + handleEvent(event); + } + }}); + } catch (RejectedExecutionException e) { + // Ignore. This exception could be thrown if the provider is being + // shut down. + } + } + + @Override + public void handleEvent(Object event, final RequestMonitor rm) { + if (event instanceof DoubleClickEvent && !isDisposed()) { + final ISelection selection= ((DoubleClickEvent) event).getSelection(); + if (selection instanceof IStructuredSelection) { + Object element= ((IStructuredSelection) selection).getFirstElement(); + if (element instanceof IncompleteStackVMContext) { + IncompleteStackVMContext incStackVmc = ((IncompleteStackVMContext) element); + IVMNode node = incStackVmc.getVMNode(); + if (node instanceof StackFramesVMNode && node.getVMProvider() == this) { + IExecutionDMContext exeCtx= incStackVmc.getExecutionDMContext(); + ((StackFramesVMNode) node).incrementStackFrameLimit(exeCtx); + // replace double click event with expand stack event + final ExpandStackEvent expandStackEvent = new ExpandStackEvent(exeCtx); + getExecutor().execute(new DsfRunnable() { + public void run() { + handleEvent(expandStackEvent, null); + } + }); + } + } + } + if (rm != null) { + rm.done(); + } + return; + } + super.handleEvent(event, rm); + } + + @Override + protected void handleEvent(IVMModelProxy proxyStrategy, final Object event, RequestMonitor rm) { + super.handleEvent(proxyStrategy, event, rm); + + if (event instanceof IRunControl.ISuspendedDMEvent) { + final IExecutionDMContext exeContext= ((IRunControl.ISuspendedDMEvent) event).getDMContext(); + ScheduledFuture<?> refreshStackFramesFuture = getRefreshFuture(exeContext); + // trigger delayed full stack frame update + if (refreshStackFramesFuture != null) { + // cancel previously scheduled frame update + refreshStackFramesFuture.cancel(false); + } + + refreshStackFramesFuture = getSession().getExecutor().schedule( + new DsfRunnable() { + public void run() { + if (getSession().isActive()) { + getExecutor().execute(new Runnable() { + public void run() { + // trigger full stack frame update + ScheduledFuture<?> future= fRefreshStackFramesFutures.get(exeContext); + if (future != null && !isDisposed()) { + fRefreshStackFramesFutures.remove(exeContext); + handleEvent(new FullStackRefreshEvent(exeContext), null); + } + }}); + } + } + }, + FRAME_UPDATE_DELAY, TimeUnit.MILLISECONDS); + fRefreshStackFramesFutures.put(exeContext, refreshStackFramesFuture); + } else if (event instanceof IRunControl.IResumedDMEvent) { + IExecutionDMContext exeContext= ((IRunControl.IResumedDMEvent) event).getDMContext(); + ScheduledFuture<?> refreshStackFramesFuture= fRefreshStackFramesFutures.get(exeContext); + if (refreshStackFramesFuture != null) { + // cancel previously scheduled frame update + refreshStackFramesFuture.cancel(false); + fRefreshStackFramesFutures.remove(exeContext); + } + } + + } + + /** + * Returns the future for the given execution context or for any child of the + * given execution context. + */ + private ScheduledFuture<?> getRefreshFuture(IExecutionDMContext execCtx) { + for (IExecutionDMContext refreshCtx : fRefreshStackFramesFutures.keySet()) { + if (refreshCtx.equals(execCtx) || DMContexts.isAncestorOf(refreshCtx, execCtx)) { + return fRefreshStackFramesFutures.remove(refreshCtx); + } + } + return null; + } + + @Override + public void dispose() { + DebugPlugin.getDefault().removeDebugEventListener(this); + DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(this); + + final IPreferenceStore store= DsfUIPlugin.getDefault().getPreferenceStore(); + store.removePropertyChangeListener(fPreferencesListener); + + super.dispose(); + } + + public void launchesAdded(ILaunch[] launches) { + handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.ADDED)); + } + + public void launchesRemoved(ILaunch[] launches) { + handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.REMOVED)); + } + + public void launchesChanged(ILaunch[] launches) { + handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.CHANGED)); + } + + public void launchesTerminated(ILaunch[] launches) { + handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.TERMINATED)); + } + + private void handleLaunchesEvent(final LaunchesEvent 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; + + IRootVMNode rootLayoutNode = getRootVMNode(); + if (rootLayoutNode != null && rootLayoutNode.getDeltaFlags(event) != 0) { + handleEvent(event); + } + }}); + } catch (RejectedExecutionException e) { + // Ignore. This exception could be thrown if the provider is being + // shut down. + } + } + + @Override + protected boolean canSkipHandlingEvent(Object newEvent, Object eventToSkip) { + // To optimize view performance when stepping rapidly, skip events that came + // before the last suspended events. However, the debug view can get suspended + // events for different threads, so make sure to skip only the events if they + // were in the same hierarchy as the last suspended event. + // Note: Avoid skipping thread started/exited events which require a larger + // scope refresh than some suspended events. + if (newEvent instanceof IStartedDMEvent || newEvent instanceof IExitedDMEvent) { + return false; + } + + if (newEvent instanceof ISuspendedDMEvent && eventToSkip instanceof IDMEvent<?>) { + IDMContext newEventDmc = ((IDMEvent<?>)newEvent).getDMContext(); + IDMContext eventToSkipDmc = ((IDMEvent<?>)eventToSkip).getDMContext(); + + if (newEventDmc.equals(eventToSkipDmc) || DMContexts.isAncestorOf(eventToSkipDmc, newEventDmc)) { + return true; + } + } + + return false; + } + + protected void handlePropertyChanged(final IPreferenceStore store, final PropertyChangeEvent event) { + String property = event.getProperty(); + if (IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT_ENABLE.equals(property) + || IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT.equals(property)) { + if (store.getBoolean(IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT_ENABLE)) { + getPresentationContext().setProperty(IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT, store.getInt(IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT)); + } else { + getPresentationContext().setProperty(IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT, null); + } + getExecutor().execute(new DsfRunnable() { + public void run() { + handleEvent(event); + } + }); + } + } + +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/AbstractThreadVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/AbstractThreadVMNode.java new file mode 100644 index 00000000000..51f28dc57f9 --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/AbstractThreadVMNode.java @@ -0,0 +1,328 @@ +/******************************************************************************* + * Copyright (c) 2006, 2008 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 + * Ericsson - Modified for multi threaded functionality + *******************************************************************************/ +package org.eclipse.cdt.dsf.debug.ui.viewmodel.launch; + +import java.util.List; +import java.util.concurrent.RejectedExecutionException; + +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.DsfRunnable; +import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.datamodel.DMContexts; +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.datamodel.IDMEvent; +import org.eclipse.cdt.dsf.debug.service.IRunControl; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerResumedDMEvent; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerSuspendedDMEvent; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IResumedDMEvent; +import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent; +import org.eclipse.cdt.dsf.debug.service.StepQueueManager.ISteppingTimedOutEvent; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.SteppingController.SteppingTimedOutEvent; +import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.cdt.dsf.ui.concurrent.ViewerDataRequestMonitor; +import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext; +import org.eclipse.cdt.dsf.ui.viewmodel.ModelProxyInstalledEvent; +import org.eclipse.cdt.dsf.ui.viewmodel.VMChildrenUpdate; +import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta; +import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode; +import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; +import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; + + +/** + * Abstract implementation of a thread view model node. + * Clients need to implement {@link #updateLabelInSessionThread(ILabelUpdate[])}. + * + * @since 1.1 + */ +@SuppressWarnings("restriction") +public abstract class AbstractThreadVMNode extends AbstractDMVMNode + implements IElementLabelProvider +{ + public AbstractThreadVMNode(AbstractDMVMProvider provider, DsfSession session) { + super(provider, session, IExecutionDMContext.class); + } + + @Override + protected void updateElementsInSessionThread(final IChildrenUpdate update) { + IRunControl runControl = getServicesTracker().getService(IRunControl.class); + final IContainerDMContext contDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IContainerDMContext.class); + if (runControl == null || contDmc == null) { + handleFailedUpdate(update); + return; + } + + runControl.getExecutionContexts(contDmc, + new ViewerDataRequestMonitor<IExecutionDMContext[]>(getSession().getExecutor(), update){ + @Override + public void handleCompleted() { + if (!isSuccess()) { + handleFailedUpdate(update); + return; + } + fillUpdateWithVMCs(update, getData()); + update.done(); + } + }); + } + + + public void update(final ILabelUpdate[] updates) { + try { + getSession().getExecutor().execute(new DsfRunnable() { + public void run() { + updateLabelInSessionThread(updates); + }}); + } catch (RejectedExecutionException e) { + for (ILabelUpdate update : updates) { + handleFailedUpdate(update); + } + } + } + + @Override + public void getContextsForEvent(VMDelta parentDelta, Object e, final DataRequestMonitor<IVMContext[]> rm) { + if(e instanceof IContainerResumedDMEvent) { + IExecutionDMContext[] triggerContexts = ((IContainerResumedDMEvent)e).getTriggeringContexts(); + if (triggerContexts.length != 0) { + rm.setData(new IVMContext[] { createVMContext(triggerContexts[0]) }); + rm.done(); + return; + } + } else if(e instanceof IContainerSuspendedDMEvent) { + IExecutionDMContext[] triggerContexts = ((IContainerSuspendedDMEvent)e).getTriggeringContexts(); + if (triggerContexts.length != 0) { + rm.setData(new IVMContext[] { createVMContext(triggerContexts[0]) }); + rm.done(); + return; + } + } else if (e instanceof SteppingTimedOutEvent && + ((SteppingTimedOutEvent)e).getDMContext() instanceof IContainerDMContext) + { + // The timed out event occured on a container and not on a thread. Do not + // return a context for this event, which will force the view model to generate + // a delta for all the threads. + rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, "", null)); //$NON-NLS-1$ + rm.done(); + return; + } else if (e instanceof ISteppingTimedOutEvent && + ((ISteppingTimedOutEvent)e).getDMContext() instanceof IContainerDMContext) + { + // The timed out event occured on a container and not on a thread. Do not + // return a context for this event, which will force the view model to generate + // a delta for all the threads. + rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, "", null)); //$NON-NLS-1$ + rm.done(); + return; + } else if (e instanceof FullStackRefreshEvent && + ((FullStackRefreshEvent)e).getDMContext() instanceof IContainerDMContext) + { + // The step sequence end event occured on a container and not on a thread. Do not + // return a context for this event, which will force the view model to generate + // a delta for all the threads. + rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, "", null)); //$NON-NLS-1$ + rm.done(); + return; + } else if (e instanceof ModelProxyInstalledEvent) { + getThreadVMCForModelProxyInstallEvent( + parentDelta, + new DataRequestMonitor<VMContextInfo>(getExecutor(), rm) { + @Override + protected void handleCompleted() { + if (isSuccess()) { + rm.setData(new IVMContext[] { getData().fVMContext }); + } else { + rm.setData(new IVMContext[0]); + } + rm.done(); + } + }); + return; + } + super.getContextsForEvent(parentDelta, e, rm); + } + + private static class VMContextInfo { + final IVMContext fVMContext; + final int fIndex; + final boolean fIsSuspended; + VMContextInfo(IVMContext vmContext, int index, boolean isSuspended) { + fVMContext = vmContext; + fIndex = index; + fIsSuspended = isSuspended; + } + } + + private void getThreadVMCForModelProxyInstallEvent(VMDelta parentDelta, final DataRequestMonitor<VMContextInfo> rm) { + getVMProvider().updateNode(this, new VMChildrenUpdate( + parentDelta, getVMProvider().getPresentationContext(), -1, -1, + new DataRequestMonitor<List<Object>>(getExecutor(), rm) { + @Override + protected void handleSuccess() { + try { + getSession().getExecutor().execute(new DsfRunnable() { + public void run() { + final IRunControl runControl = getServicesTracker().getService(IRunControl.class); + if (runControl != null) { + int vmcIdx = -1; + int suspendedVmcIdx = -1; + + for (int i = 0; i < getData().size(); i++) { + if (getData().get(i) instanceof IDMVMContext) { + IDMVMContext vmc = (IDMVMContext)getData().get(i); + IExecutionDMContext execDmc = DMContexts.getAncestorOfType( + vmc.getDMContext(), IExecutionDMContext.class); + if (execDmc != null) { + vmcIdx = vmcIdx < 0 ? i : vmcIdx; + if (runControl.isSuspended(execDmc)) { + suspendedVmcIdx = suspendedVmcIdx < 0 ? i : suspendedVmcIdx; + } + } + } + } + if (suspendedVmcIdx >= 0) { + rm.setData(new VMContextInfo( + (IVMContext)getData().get(suspendedVmcIdx), suspendedVmcIdx, true)); + } else if (vmcIdx >= 0) { + rm.setData(new VMContextInfo((IVMContext)getData().get(vmcIdx), vmcIdx, false)); + } else { + rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "No threads available", null)); //$NON-NLS-1$ + } + rm.done(); + } else { + rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "No threads available", null)); //$NON-NLS-1$ + rm.done(); + } + } + }); + } catch (RejectedExecutionException e) { + rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, "", null)); //$NON-NLS-1$ + rm.done(); + } + } + })); + } + + /** + * Perform the given label updates in the session executor thread. + * + * @param updates the pending label updates + * @see {@link #update(ILabelUpdate[]) + */ + protected abstract void updateLabelInSessionThread(ILabelUpdate[] updates); + + + public int getDeltaFlags(Object e) { + IDMContext dmc = e instanceof IDMEvent<?> ? ((IDMEvent<?>)e).getDMContext() : null; + + if (dmc instanceof IContainerDMContext) { + return IModelDelta.NO_CHANGE; + } else if (e instanceof IResumedDMEvent && + ((IResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP) + { + return IModelDelta.CONTENT; + } else if (e instanceof ISuspendedDMEvent) { + return IModelDelta.NO_CHANGE; + } else if (e instanceof FullStackRefreshEvent) { + return IModelDelta.CONTENT; + } else if (e instanceof SteppingTimedOutEvent) { + return IModelDelta.CONTENT; + } else if (e instanceof ISteppingTimedOutEvent) { + return IModelDelta.CONTENT; + } else if (e instanceof ModelProxyInstalledEvent) { + return IModelDelta.SELECT | IModelDelta.EXPAND; + } + return IModelDelta.NO_CHANGE; + } + + public void buildDelta(Object e, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor rm) { + IDMContext dmc = e instanceof IDMEvent<?> ? ((IDMEvent<?>)e).getDMContext() : null; + + if(dmc instanceof IContainerDMContext) { + // The IContainerDMContext sub-classes IExecutionDMContext. + // Also IContainerResumedDMEvent sub-classes IResumedDMEvent and + // IContainerSuspendedDMEvnet sub-classes ISuspendedEvent. + // Because of this relationship, the thread VM node can be called + // with data-model evnets for the containers. This statement + // filters out those event. + rm.done(); + } else if(e instanceof IResumedDMEvent) { + // Resumed: + // - If not stepping, update the thread and its content (its stack). + // - If stepping, do nothing to avoid too many updates. If a + // time-out is reached before the step completes, the + // ISteppingTimedOutEvent will trigger a refresh. + if (((IResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP) { + parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT); + } + rm.done(); + } else if (e instanceof ISuspendedDMEvent) { + // Container suspended. Do nothing here to give the stack the + // priority in updating. The thread will update as a result of + // FullStackRefreshEvent. + rm.done(); + } else if (e instanceof FullStackRefreshEvent) { + // Full-stack refresh event is generated following a suspended event + // and a fixed delay. Refresh the whole thread upon this event. + parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT); + rm.done(); + } else if (e instanceof SteppingTimedOutEvent) { + // Stepping time-out indicates that a step operation is taking + // a long time, and the view needs to be refreshed to show + // the user that the program is running. + parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT); + rm.done(); + } else if (e instanceof ISteppingTimedOutEvent) { + // Stepping time-out indicates that a step operation is taking + // a long time, and the view needs to be refreshed to show + // the user that the program is running. + parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT); + rm.done(); + } else if (e instanceof ModelProxyInstalledEvent) { + // Model Proxy install event is generated when the model is first + // populated into the view. This happens when a new debug session + // is started or when the view is first opened. + // In both cases, if there are already threads in the debug model, + // the desired user behavior is to show the threads and to select + // the first thread. + // If the thread is suspended, do not select the thread, instead, + // its top stack frame will be selected. + getThreadVMCForModelProxyInstallEvent( + parentDelta, + new DataRequestMonitor<VMContextInfo>(getExecutor(), rm) { + @Override + protected void handleCompleted() { + if (isSuccess()) { + parentDelta.addNode( + getData().fVMContext, nodeOffset + getData().fIndex, + IModelDelta.EXPAND | (getData().fIsSuspended ? 0 : IModelDelta.SELECT)); + } + rm.done(); + } + }); + } else { + + rm.done(); + } + } + +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/DefaultDsfModelSelectionPolicyFactory.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/DefaultDsfModelSelectionPolicyFactory.java new file mode 100644 index 00000000000..7a05904d4a4 --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/DefaultDsfModelSelectionPolicyFactory.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. 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: + * Anton Leherbauer (Wind River Systems) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.dsf.debug.ui.viewmodel.launch; + +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicyFactory; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; +import org.eclipse.debug.ui.IDebugUIConstants; + +/** + * Default model selection policy factory for DSF. + * @since 1.1 + */ +@SuppressWarnings("restriction") +public class DefaultDsfModelSelectionPolicyFactory implements IModelSelectionPolicyFactory { + + /* + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicyFactory#createModelSelectionPolicyAdapter(java.lang.Object, org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext) + */ + public IModelSelectionPolicy createModelSelectionPolicyAdapter(Object element, IPresentationContext context) { + if (IDebugUIConstants.ID_DEBUG_VIEW.equals(context.getId())) { + if (element instanceof IDMVMContext) { + IDMVMContext dmvmContext= (IDMVMContext) element; + IDMContext dmContext= dmvmContext.getDMContext(); + if (dmContext != null) { + return new DefaultDsfSelectionPolicy(dmContext); + } + } + } + return null; + } + +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/DefaultDsfSelectionPolicy.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/DefaultDsfSelectionPolicy.java new file mode 100644 index 00000000000..cb1e8faffbc --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/DefaultDsfSelectionPolicy.java @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. 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: + * Anton Leherbauer (Wind River Systems) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.debug.ui.viewmodel.launch; + +import org.eclipse.cdt.dsf.datamodel.DMContexts; +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext; +import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin; +import org.eclipse.cdt.dsf.service.DsfServicesTracker; +import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; +import org.eclipse.debug.ui.IDebugUIConstants; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.ITreeSelection; +import org.eclipse.jface.viewers.TreePath; +import org.eclipse.jface.viewers.TreeSelection; + +/** + * Default DSF selection policy implementation modelled after platform version + * (<code>DefaultSelectionPolicy</code>). + * @since 1.1 + */ +@SuppressWarnings("restriction") +public class DefaultDsfSelectionPolicy implements IModelSelectionPolicy { + + private IDMContext fDMContext; + + /** + * Create selection policy instance for the given data model context. + * + * @param dmContext + */ + public DefaultDsfSelectionPolicy(IDMContext dmContext) { + fDMContext= dmContext; + } + + /* + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy#contains(org.eclipse.jface.viewers.ISelection, org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext) + */ + public boolean contains(ISelection selection, IPresentationContext context) { + if (IDebugUIConstants.ID_DEBUG_VIEW.equals(context.getId())) { + if (selection instanceof IStructuredSelection) { + IStructuredSelection ss= (IStructuredSelection) selection; + Object element= ss.getFirstElement(); + if (element instanceof IDMVMContext) { + IDMVMContext dmvmContext= (IDMVMContext) element; + IDMContext dmContext= dmvmContext.getDMContext(); + if (dmContext != null) { + return fDMContext.getSessionId().equals(dmContext.getSessionId()); + } + } + } + } + return false; + } + + /* + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy#isSticky(org.eclipse.jface.viewers.ISelection, org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext) + */ + public boolean isSticky(ISelection selection, IPresentationContext context) { + if (IDebugUIConstants.ID_DEBUG_VIEW.equals(context.getId())) { + if (selection instanceof IStructuredSelection) { + IStructuredSelection ss= (IStructuredSelection) selection; + Object element= ss.getFirstElement(); + return isSticky(element); + } + } + return false; + } + + protected boolean isSticky(Object element) { + if (element instanceof IDMVMContext) { + IDMVMContext dmvmContext= (IDMVMContext) element; + IDMContext dmContext= dmvmContext.getDMContext(); + if (dmContext instanceof IFrameDMContext) { + IExecutionDMContext execContext= DMContexts.getAncestorOfType(dmContext, IExecutionDMContext.class); + if (execContext != null) { + DsfServicesTracker servicesTracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), dmContext.getSessionId()); + try { + IRunControl runControl= servicesTracker.getService(IRunControl.class); + if (runControl != null) { + if (runControl.isSuspended(execContext)) { + return true; + } + } + } finally { + servicesTracker.dispose(); + } + } + } + } + return false; + } + + /* + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy#overrides(org.eclipse.jface.viewers.ISelection, org.eclipse.jface.viewers.ISelection, org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext) + */ + public boolean overrides(ISelection existing, ISelection candidate, IPresentationContext context) { + if (IDebugUIConstants.ID_DEBUG_VIEW.equals(context.getId())) { + if (existing instanceof IStructuredSelection && candidate instanceof IStructuredSelection) { + IStructuredSelection ssExisting = (IStructuredSelection) existing; + IStructuredSelection ssCandidate = (IStructuredSelection) candidate; + return overrides(ssExisting.getFirstElement(), ssCandidate.getFirstElement()); + } + } + return true; + } + + + protected boolean overrides(Object existing, Object candidate) { + if (existing == null || existing.equals(candidate)) { + return true; + } + if (existing instanceof IDMVMContext && candidate instanceof IDMVMContext) { + IDMContext curr = ((IDMVMContext) existing).getDMContext(); + IDMContext cand = ((IDMVMContext) candidate).getDMContext(); + if (curr instanceof IFrameDMContext && cand instanceof IFrameDMContext) { + IExecutionDMContext currExecContext= DMContexts.getAncestorOfType(curr, IExecutionDMContext.class); + if (currExecContext != null) { + IExecutionDMContext candExecContext= DMContexts.getAncestorOfType(cand, IExecutionDMContext.class); + return currExecContext.equals(candExecContext) || !isSticky(existing); + } + } + } + return !isSticky(existing); + } + + /* + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy#replaceInvalidSelection(org.eclipse.jface.viewers.ISelection, org.eclipse.jface.viewers.ISelection) + */ + public ISelection replaceInvalidSelection(ISelection invalidSelection, ISelection newSelection) { + if (invalidSelection instanceof ITreeSelection) { + ITreeSelection treeSelection = (ITreeSelection)invalidSelection; + if (treeSelection.getPaths().length == 1) { + TreePath path = treeSelection.getPaths()[0]; + return new TreeSelection(path.getParentPath()); + } + } + return newSelection; + } + +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/DelayedStackRefreshUpdatePolicy.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/DelayedStackRefreshUpdatePolicy.java new file mode 100644 index 00000000000..8cdfc04d8d7 --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/DelayedStackRefreshUpdatePolicy.java @@ -0,0 +1,175 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. 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.cdt.dsf.debug.ui.viewmodel.launch; + +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent; +import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent; +import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext; +import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext; +import org.eclipse.cdt.dsf.ui.viewmodel.update.IElementUpdateTester; +import org.eclipse.cdt.dsf.ui.viewmodel.update.IVMUpdatePolicy; +import org.eclipse.cdt.dsf.ui.viewmodel.update.UpdatePolicyDecorator; +import org.eclipse.jface.viewers.TreePath; + +/** + * An update strategy decorator specialized for delayed stack frame refresh. The + * strategy flushes only the cached top stack frame in case of an normal {@link ISuspendedDMEvent}, + * while in in case of a special {@link FullStackRefreshEvent} everything is invalidated. + * + * <p> + * The underlying base update policy is considered for container contexts only. + * In other cases the cache data is always flushed. + * </p> + * + * @since 1.1 + */ +public class DelayedStackRefreshUpdatePolicy extends UpdatePolicyDecorator { + + private static final class DelayedStackRefreshUpdateTester implements IElementUpdateTester { + + private final IElementUpdateTester fBaseTester; + + /** Indicates whether only the top stack frame should be updated */ + private final boolean fLazyStackFrameMode; + + DelayedStackRefreshUpdateTester(IElementUpdateTester baseTester, boolean lazyStackFrameMode) { + fBaseTester = baseTester; + fLazyStackFrameMode = lazyStackFrameMode; + } + public int getUpdateFlags(Object viewerInput, TreePath path) { + Object element = path.getSegmentCount() != 0 ? path.getLastSegment() : viewerInput; + if (element instanceof IDMVMContext) { + IDMContext dmc = ((IDMVMContext) element).getDMContext(); + if (fLazyStackFrameMode) { + if (dmc instanceof IFrameDMContext) { + if (((IFrameDMContext) dmc).getLevel() == 0) { + return FLUSH; + } + } else if (dmc instanceof IExecutionDMContext) { + return fBaseTester.getUpdateFlags(viewerInput, path); + } + return DIRTY; + } else if (dmc instanceof IContainerDMContext) { + return fBaseTester.getUpdateFlags(viewerInput, path); + } + } + return FLUSH; + } + + public boolean includes(IElementUpdateTester tester) { + // A non-lazy tester includes a lazy tester, but not vice versa. + // This allows entries that were marked as dirty by a flush with + // the lazy mode to be superseded by a non-lazy update which + // actually clears the entries that were marked as dirty. + if (tester instanceof DelayedStackRefreshUpdateTester) { + DelayedStackRefreshUpdateTester sfTester = (DelayedStackRefreshUpdateTester)tester; + if (fLazyStackFrameMode) { + if (sfTester.fLazyStackFrameMode) { + return fBaseTester.includes(sfTester.fBaseTester); + } + } else { + if (!sfTester.fLazyStackFrameMode) { + return fBaseTester.includes(sfTester.fBaseTester); + } + // non-lazy includes lazy + return true; + } + } + return false; + } + + @Override + public String toString() { + return "Delayed stack refresh (lazy = " + fLazyStackFrameMode + ", base = " + fBaseTester + ") update tester"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + } + + private static final class ThreadsUpdateTester implements IElementUpdateTester { + + private final IElementUpdateTester fBaseTester; + + private final boolean fRefreshAll; + + ThreadsUpdateTester(IElementUpdateTester baseTester, boolean refreshAll) { + fBaseTester = baseTester; + fRefreshAll = refreshAll; + } + + public int getUpdateFlags(Object viewerInput, TreePath path) { + Object element = path.getSegmentCount() != 0 ? path.getLastSegment() : viewerInput; + + if (!fRefreshAll && element instanceof IDMVMContext) { + IDMContext dmc = ((IDMVMContext) element).getDMContext(); + if (dmc instanceof IContainerDMContext) { + return fBaseTester.getUpdateFlags(viewerInput, path); + } + } + + // If the element is not a container or if the flush all flag is set, + // always flush it. + return FLUSH; + } + + public boolean includes(IElementUpdateTester tester) { + // A refresh-all tester includes a non-refresh-all tester, but not + // vice versa. This allows entries that were marked as dirty by + // a flush with + // the non-refresh-all to be superseded by a refresh-all update which + // actually clears the entries that were marked as dirty. + if (tester instanceof ThreadsUpdateTester) { + ThreadsUpdateTester threadsTester = (ThreadsUpdateTester)tester; + if (fRefreshAll) { + if (threadsTester.fRefreshAll) { + return fBaseTester.includes(threadsTester.fBaseTester); + } + // refresh-all includes the non-refresh-all + return true; + } else { + if (!threadsTester.fRefreshAll) { + return fBaseTester.includes(threadsTester.fBaseTester); + } + } + } + return false; + } + + @Override + public String toString() { + return "Threads update tester (base = " + fBaseTester + ") update tester"; //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + + public DelayedStackRefreshUpdatePolicy(IVMUpdatePolicy base) { + super(base); + } + + @Override + public IElementUpdateTester getElementUpdateTester(Object event) { + if (event instanceof ISuspendedDMEvent) { + return new DelayedStackRefreshUpdateTester(getBaseUpdatePolicy().getElementUpdateTester(event), true); + } else if (event instanceof FullStackRefreshEvent) { + return new DelayedStackRefreshUpdateTester(getBaseUpdatePolicy().getElementUpdateTester(event), false); + } else if (event instanceof IExitedDMEvent && + ((IExitedDMEvent)event).getDMContext() instanceof IContainerDMContext) + { + // container exit should always trigger a refresh + return new ThreadsUpdateTester(super.getElementUpdateTester(event), true); + } else { + return new ThreadsUpdateTester(super.getElementUpdateTester(event), false); + } + } + +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/ExpandStackEvent.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/ExpandStackEvent.java new file mode 100644 index 00000000000..bed23000bb8 --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/ExpandStackEvent.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. 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.cdt.dsf.debug.ui.viewmodel.launch; + +import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext; + +/** + * Event to increase the stack frame limit for an execution context. + * + * @since 1.1 + */ +public class ExpandStackEvent extends AbstractDMEvent<IExecutionDMContext> { + + public ExpandStackEvent(IExecutionDMContext execCtx) { + super(execCtx); + } + +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/FullStackRefreshEvent.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/FullStackRefreshEvent.java new file mode 100644 index 00000000000..ecca6de8eb6 --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/FullStackRefreshEvent.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. 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.cdt.dsf.debug.ui.viewmodel.launch; + +import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext; + +/** + * Indicates the end of a sequence of steps. Should be handled like a suspended + * event to trigger a full refresh of stack frames. + * + * @since 1.1 + */ +public class FullStackRefreshEvent extends AbstractDMEvent<IExecutionDMContext> { + + public FullStackRefreshEvent(IExecutionDMContext execCtx) { + super(execCtx); + } + +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/LaunchRootVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/LaunchRootVMNode.java new file mode 100644 index 00000000000..faed099a305 --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/LaunchRootVMNode.java @@ -0,0 +1,130 @@ +/******************************************************************************* + * Copyright (c) 2006, 2008 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.cdt.dsf.debug.ui.viewmodel.launch; + +import java.util.Arrays; +import java.util.List; + +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; +import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin; +import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMProvider; +import org.eclipse.cdt.dsf.ui.viewmodel.IRootVMNode; +import org.eclipse.cdt.dsf.ui.viewmodel.RootVMNode; +import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchManager; +import org.eclipse.debug.core.model.IDebugElement; +import org.eclipse.debug.core.model.IProcess; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; + +/** + * Layout node for the standard ILaunch object. This node can only be used at + * the root of a hierarchy. It does not implement the label provider + * functionality, so the default adapters should be used to retrieve the label. + */ +@SuppressWarnings("restriction") +public class LaunchRootVMNode extends RootVMNode + implements IRootVMNode +{ + public static class LaunchesEvent { + public enum Type { ADDED, REMOVED, CHANGED, TERMINATED } + public final ILaunch[] fLaunches; + public final Type fType; + + public LaunchesEvent(ILaunch[] launches, Type type) { + fLaunches = launches; + fType = type; + } + } + + + public LaunchRootVMNode(AbstractVMProvider provider) { + super(provider); + } + + @Override + public String toString() { + return "LaunchRootVMNode"; //$NON-NLS-1$ + } + + @Override + public boolean isDeltaEvent(Object rootObject, Object e) { + if (e instanceof DebugEvent) { + DebugEvent de = (DebugEvent)e; + if (de.getSource() instanceof IProcess && + !((IProcess)de.getSource()).getLaunch().equals(rootObject) ) + { + return false; + } + else if (de.getSource() instanceof IDebugElement && + !rootObject.equals(((IDebugElement)de.getSource()).getLaunch())) + { + return false; + } + } + return super.isDeltaEvent(rootObject, e); + } + + @Override + public int getDeltaFlags(Object e) { + int flags = 0; + if (e instanceof LaunchesEvent) { + LaunchesEvent le = (LaunchesEvent)e; + if (le.fType == LaunchesEvent.Type.CHANGED || le.fType == LaunchesEvent.Type.TERMINATED) { + flags = IModelDelta.STATE | IModelDelta.CONTENT; + } + } + + return flags; + } + + @Override + public void createRootDelta(Object rootObject, Object event, final DataRequestMonitor<VMDelta> rm) { + if (!(rootObject instanceof ILaunch)) { + rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Invalid root element configured with launch root node.", null)); //$NON-NLS-1$ + return; + } + + ILaunch rootLaunch = (ILaunch)rootObject; + + /* + * Create the root of the delta. Since the launch object is not at the + * root of the view, create the delta with the path to the launch. + */ + ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager(); + List<ILaunch> launchList = Arrays.asList(manager.getLaunches()); + final VMDelta viewRootDelta = new VMDelta(manager, 0, IModelDelta.NO_CHANGE, launchList.size()); + final VMDelta rootDelta = viewRootDelta.addNode(rootLaunch, launchList.indexOf(rootLaunch), IModelDelta.NO_CHANGE); + + // Generate delta for launch node. + if (event instanceof LaunchesEvent) { + LaunchesEvent le = (LaunchesEvent)event; + for (ILaunch launch : le.fLaunches) { + if (rootLaunch == launch) { + if (le.fType == LaunchesEvent.Type.CHANGED) { + rootDelta.setFlags(rootDelta.getFlags() | IModelDelta.STATE | IModelDelta.CONTENT); + } else if (le.fType == LaunchesEvent.Type.TERMINATED) { + rootDelta.setFlags(rootDelta.getFlags() | IModelDelta.STATE | IModelDelta.CONTENT); + } + } + } + } + + rm.setData(rootDelta); + rm.done(); + } + +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/LaunchVMUpdateMessages.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/LaunchVMUpdateMessages.java new file mode 100644 index 00000000000..0a5db99385e --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/LaunchVMUpdateMessages.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2008 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.cdt.dsf.debug.ui.viewmodel.launch; + +import org.eclipse.osgi.util.NLS; + +/** + * @since 1.1 + */ +public class LaunchVMUpdateMessages extends NLS { + + private static final String BUNDLE_NAME = "org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.LaunchVMUpdateMessages";//$NON-NLS-1$ + + public static String ThreadsAutomaticUpdatePolicy_name; + public static String ThreadsManualUpdatePolicy_name; + + static { + // load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, LaunchVMUpdateMessages.class); + } +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/StackFramesVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/StackFramesVMNode.java new file mode 100644 index 00000000000..957f25598f1 --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/StackFramesVMNode.java @@ -0,0 +1,724 @@ +/******************************************************************************* + * Copyright (c) 2006, 2008 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.cdt.dsf.debug.ui.viewmodel.launch; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.RejectedExecutionException; + +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.DsfRunnable; +import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.datamodel.DMContexts; +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl; +import org.eclipse.cdt.dsf.debug.service.IStack; +import org.eclipse.cdt.dsf.debug.service.IStack2; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerSuspendedDMEvent; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent; +import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent; +import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext; +import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMData; +import org.eclipse.cdt.dsf.debug.service.StepQueueManager.ISteppingTimedOutEvent; +import org.eclipse.cdt.dsf.debug.ui.IDsfDebugUIConstants; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.SteppingController; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.SteppingController.SteppingTimedOutEvent; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.cdt.dsf.ui.concurrent.ViewerDataRequestMonitor; +import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMContext; +import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext; +import org.eclipse.cdt.dsf.ui.viewmodel.ModelProxyInstalledEvent; +import org.eclipse.cdt.dsf.ui.viewmodel.VMChildrenUpdate; +import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta; +import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode; +import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; +import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext; +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.IElementCompareRequest; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest; +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.ui.DebugUITools; +import org.eclipse.debug.ui.IDebugUIConstants; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.ui.IMemento; + +@SuppressWarnings("restriction") +public class StackFramesVMNode extends AbstractDMVMNode + implements IElementLabelProvider, IElementMementoProvider +{ + + /** + * View model context representing the end of an incomplete stack. + * + * @since 1.1 + */ + public class IncompleteStackVMContext extends AbstractVMContext { + private final int fLevel; + private final IExecutionDMContext fDmc; + + public IncompleteStackVMContext(IExecutionDMContext dmc, int level) { + super(StackFramesVMNode.this); + fDmc = dmc; + fLevel = level; + } + public int getLevel() { + return fLevel; + } + public IExecutionDMContext getExecutionDMContext() { + return fDmc; + } + @Override + public boolean equals(Object obj) { + return obj instanceof IncompleteStackVMContext && + ((IncompleteStackVMContext)obj).fDmc.equals(fDmc); + } + + @Override + public int hashCode() { + return fDmc.hashCode(); + } + } + + /** + * Temporary stack frame limit to allow incremental stack updates. + */ + private Map<IExecutionDMContext, Integer> fTemporaryLimits = new HashMap<IExecutionDMContext, Integer>(); + + public StackFramesVMNode(AbstractDMVMProvider provider, DsfSession session) { + super(provider, session, IStack.IFrameDMContext.class); + } + + @Override + public String toString() { + return "StackFramesVMNode(" + getSession().getId() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + /* + * (non-Javadoc) + * @see org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#updateHasElementsInSessionThread(org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate) + */ + @Override + protected void updateHasElementsInSessionThread(IHasChildrenUpdate update) { + IRunControl runControl = getServicesTracker().getService(IRunControl.class); + IExecutionDMContext execCtx = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExecutionDMContext.class); + if (runControl == null || execCtx == null) { + handleFailedUpdate(update); + return; + } + + update.setHasChilren(runControl.isSuspended(execCtx) || runControl.isStepping(execCtx)); + update.done(); + } + + @Override + protected void updateElementCountInSessionThread(final IChildrenCountUpdate update) { + IStack stackService = getServicesTracker().getService(IStack.class); + final IExecutionDMContext execDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExecutionDMContext.class); + if (stackService == null || execDmc == null) { + handleFailedUpdate(update); + return; + } + + final int stackFrameLimit= getStackFrameLimit(execDmc); + stackService.getStackDepth( + execDmc, stackFrameLimit == Integer.MAX_VALUE ? 0 : stackFrameLimit + 1, + new ViewerDataRequestMonitor<Integer>(getSession().getExecutor(), update) { + @Override + public void handleCompleted() { + if (!isSuccess()) { + handleFailedUpdate(update); + return; + } + int stackDepth= getData(); + if (stackFrameLimit < stackDepth) { + stackDepth = stackFrameLimit + 1; + } + update.setChildCount(stackDepth); + update.done(); + } + }); + } + + /* + * (non-Javadoc) + * @see org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#updateElementsInSessionThread(org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate) + */ + @Override + protected void updateElementsInSessionThread(final IChildrenUpdate update) { + IStack stackService = getServicesTracker().getService(IStack.class); + final IExecutionDMContext execDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExecutionDMContext.class); + if (stackService == null || execDmc == null) { + handleFailedUpdate(update); + return; + } + + final int stackFrameLimit= getStackFrameLimit(execDmc); + final int startIndex= update.getOffset(); + + if (startIndex == 0 && update.getLength() == 1) { + // Requesting top stack frame only + stackService.getTopFrame( + execDmc, + new ViewerDataRequestMonitor<IFrameDMContext>(getSession().getExecutor(), update) { + @Override + public void handleCompleted() { + if (!isSuccess()) { + handleFailedUpdate(update); + return; + } + update.setChild(createVMContext(getData()), 0); + update.done(); + } + }); + + } else { + if (startIndex >= 0 && update.getLength() > 0 && stackService instanceof IStack2) { + // partial stack dump + IStack2 stackService2= (IStack2) stackService; + int endIndex= startIndex + update.getLength() - 1; + if (startIndex < stackFrameLimit && endIndex >= stackFrameLimit) { + endIndex = stackFrameLimit - 1; + } + stackService2.getFrames( + execDmc, + startIndex, + endIndex, + new ViewerDataRequestMonitor<IFrameDMContext[]>(getSession().getExecutor(), update) { + @Override + public void handleCompleted() { + if (!isSuccess()) { + handleFailedUpdate(update); + return; + } + IFrameDMContext[] frames = getData(); + fillUpdateWithVMCs(update, frames, startIndex); + if (startIndex + update.getLength() > stackFrameLimit) { + update.setChild(new IncompleteStackVMContext(execDmc, stackFrameLimit), stackFrameLimit); + } + update.done(); + } + }); + } else { + // full stack dump + stackService.getFrames( + execDmc, + new ViewerDataRequestMonitor<IFrameDMContext[]>(getSession().getExecutor(), update) { + @Override + public void handleCompleted() { + if (!isSuccess()) { + handleFailedUpdate(update); + return; + } + IFrameDMContext[] frames = getData(); + if (frames.length > stackFrameLimit) { + IFrameDMContext[] tmpFrames = new IFrameDMContext[stackFrameLimit]; + System.arraycopy(frames, 0, tmpFrames, 0, stackFrameLimit); + frames = tmpFrames; + update.setChild(new IncompleteStackVMContext(execDmc, stackFrameLimit), stackFrameLimit); + } + fillUpdateWithVMCs(update, frames); + update.done(); + } + }); + } + } + } + + /* + * (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider#update(org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate[]) + */ + public void update(final ILabelUpdate[] updates) { + try { + getSession().getExecutor().execute(new DsfRunnable() { + public void run() { + updateLabelInSessionThread(updates); + }}); + } catch (RejectedExecutionException e) { + for (ILabelUpdate update : updates) { + handleFailedUpdate(update); + } + } + } + + protected void updateLabelInSessionThread(ILabelUpdate[] updates) { + for (final ILabelUpdate update : updates) { + IStack stackService = getServicesTracker().getService(IStack.class); + + if (stackService == null) { + handleFailedUpdate(update); + continue; + } + + if (update.getElement() instanceof IncompleteStackVMContext) { + update.setLabel("<...more frames...>", 0); //$NON-NLS-1$ + update.setImageDescriptor(DebugUITools.getImageDescriptor(IDebugUIConstants.IMG_OBJS_STACKFRAME), 0); + update.done(); + continue; + } + + final IFrameDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IFrameDMContext.class); + if (dmc == null) { + handleFailedUpdate(update); + continue; + } + + getDMVMProvider().getModelData( + this, update, + getServicesTracker().getService(IStack.class, null), + dmc, + new ViewerDataRequestMonitor<IFrameDMData>(getSession().getExecutor(), update) { + @Override + protected void handleCompleted() { + /* + * Check that the request was evaluated and data is still + * valid. The request could fail if the state of the + * service changed during the request, but the view model + * has not been updated yet. + */ + if (!isSuccess()) { + assert getStatus().isOK() || + getStatus().getCode() != IDsfStatusConstants.INTERNAL_ERROR || + getStatus().getCode() != IDsfStatusConstants.NOT_SUPPORTED; + handleFailedUpdate(update); + return; + } + + /* + * If columns are configured, call the protected methods to + * fill in column values. + */ + String[] localColumns = update.getColumnIds(); + if (localColumns == null) localColumns = new String[] { null }; + + for (int i = 0; i < localColumns.length; i++) { + fillColumnLabel(dmc, getData(), localColumns[i], i, update); + } + update.done(); + } + }, + getExecutor()); + } + } + + protected void fillColumnLabel(IFrameDMContext dmContext, IFrameDMData dmData, String columnId, int idx, ILabelUpdate update) + { + if (idx != 0) return; + + final IExecutionDMContext execDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExecutionDMContext.class); + if (execDmc == null) { + return; + } + IRunControl runControlService = getServicesTracker().getService(IRunControl.class); + SteppingController stepQueueMgr = (SteppingController) execDmc.getAdapter(SteppingController.class); + if (runControlService == null || stepQueueMgr == null) return; + + String imageKey = null; + if (runControlService.isSuspended(execDmc) || + (runControlService.isStepping(execDmc) && !stepQueueMgr.isSteppingTimedOut(execDmc))) + { + imageKey = IDebugUIConstants.IMG_OBJS_STACKFRAME; + } else { + imageKey = IDebugUIConstants.IMG_OBJS_STACKFRAME_RUNNING; + } + update.setImageDescriptor(DebugUITools.getImageDescriptor(imageKey), 0); + + // + // Finally, if all goes well, set the label. + // + StringBuilder label = new StringBuilder(); + + // Add the function name + if (dmData.getFunction() != null && dmData.getFunction().length() != 0) { + label.append(" "); //$NON-NLS-1$ + label.append(dmData.getFunction()); + label.append("()"); //$NON-NLS-1$ + } + + // Add full file name + if (dmData.getFile() != null && dmData.getFile().length() != 0) { + label.append(" at "); //$NON-NLS-1$ + label.append(dmData.getFile()); + } + + // Add line number + if (dmData.getLine() >= 0) { + label.append(":"); //$NON-NLS-1$ + label.append(dmData.getLine()); + label.append(" "); //$NON-NLS-1$ + } + + // Add the address + if (dmData.getAddress() != null) { + label.append("- 0x" + dmData.getAddress().toString(16)); //$NON-NLS-1$ + } + + // Set the label to the result listener + update.setLabel(label.toString(), 0); + } + + /* + * (non-Javadoc) + * @see org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#getContextsForEvent(org.eclipse.cdt.dsf.ui.viewmodel.VMDelta, java.lang.Object, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor) + */ + @Override + public void getContextsForEvent(final VMDelta parentDelta, Object e, final DataRequestMonitor<IVMContext[]> rm) { + if (e instanceof ModelProxyInstalledEvent) { + // Retrieve the list of stack frames, and mark the top frame to be selected. + getVMProvider().updateNode( + this, + new VMChildrenUpdate( + parentDelta, getVMProvider().getPresentationContext(), 0, 1, + new DataRequestMonitor<List<Object>>(getExecutor(), rm) { + @Override + public void handleCompleted() { + if (isSuccess() && getData().size() != 0) { + rm.setData(new IVMContext[] { (IVMContext)getData().get(0) }); + } else { + // In case of errors, return an empty set of frames. + rm.setData(new IVMContext[0]); + } + rm.done(); + } + }) + ); + return; + } + super.getContextsForEvent(parentDelta, e, rm); + } + + /* + * (non-Javadoc) + * @see org.eclipse.cdt.dsf.ui.viewmodel.IVMNode#getDeltaFlags(java.lang.Object) + */ + public int getDeltaFlags(Object e) { + // This node generates delta if the timers have changed, or if the + // label has changed. + if (e instanceof ISuspendedDMEvent) { + return IModelDelta.CONTENT | IModelDelta.EXPAND | IModelDelta.SELECT; + } else if (e instanceof FullStackRefreshEvent) { + return IModelDelta.CONTENT | IModelDelta.EXPAND; + } else if (e instanceof SteppingTimedOutEvent) { + return IModelDelta.CONTENT; + } else if (e instanceof ISteppingTimedOutEvent) { + return IModelDelta.CONTENT; + } else if (e instanceof ModelProxyInstalledEvent) { + return IModelDelta.SELECT | IModelDelta.EXPAND; + } else if (e instanceof ExpandStackEvent) { + return IModelDelta.CONTENT; + } else if (e instanceof IExitedDMEvent) { + // Do not generate a delta for this event, but do clear the + // internal stack frame limit to avoid a memory leak. + clearStackFrameLimit( ((IExitedDMEvent)e).getDMContext() ); + return IModelDelta.NO_CHANGE; + } else if (e instanceof PropertyChangeEvent) { + String property = ((PropertyChangeEvent)e).getProperty(); + if (IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT_ENABLE.equals(property) + || IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT.equals(property)) + { + return IModelDelta.CONTENT; + } + } else { + } + + return IModelDelta.NO_CHANGE; + } + + /* + * (non-Javadoc) + * @see org.eclipse.cdt.dsf.ui.viewmodel.IVMNode#buildDelta(java.lang.Object, org.eclipse.cdt.dsf.ui.viewmodel.VMDelta, int, org.eclipse.cdt.dsf.concurrent.RequestMonitor) + */ + public void buildDelta(final Object e, final VMDelta parent, final int nodeOffset, final RequestMonitor rm) { + if (e instanceof IContainerSuspendedDMEvent) { + // Clear the limit on the stack frames for all stack frames under a given container. + clearStackFrameLimit( ((IContainerSuspendedDMEvent)e).getDMContext() ); + + IContainerSuspendedDMEvent csEvent = (IContainerSuspendedDMEvent)e; + + IExecutionDMContext triggeringCtx = csEvent.getTriggeringContexts().length != 0 + ? csEvent.getTriggeringContexts()[0] : null; + + if (parent.getElement() instanceof IDMVMContext) { + IExecutionDMContext threadDmc = null; + threadDmc = DMContexts.getAncestorOfType( ((IDMVMContext)parent.getElement()).getDMContext(), IExecutionDMContext.class); + buildDeltaForSuspendedEvent(threadDmc, triggeringCtx, parent, nodeOffset, rm); + } else { + rm.done(); + } + } else if (e instanceof FullStackRefreshEvent) { + IExecutionDMContext execDmc = ((FullStackRefreshEvent)e).getDMContext(); + buildDeltaForFullStackRefreshEvent(execDmc, execDmc, parent, nodeOffset, rm); + } else if (e instanceof ISuspendedDMEvent) { + clearStackFrameLimit( ((ISuspendedDMEvent)e).getDMContext() ); + IExecutionDMContext execDmc = ((ISuspendedDMEvent)e).getDMContext(); + buildDeltaForSuspendedEvent(execDmc, execDmc, parent, nodeOffset, rm); + } else if (e instanceof SteppingTimedOutEvent) { + buildDeltaForSteppingTimedOutEvent((SteppingTimedOutEvent)e, parent, nodeOffset, rm); + } else if (e instanceof ISteppingTimedOutEvent) { + buildDeltaForSteppingTimedOutEvent((ISteppingTimedOutEvent)e, parent, nodeOffset, rm); + } else if (e instanceof ModelProxyInstalledEvent) { + buildDeltaForModelProxyInstalledEvent(parent, nodeOffset, rm); + } else if (e instanceof ExpandStackEvent) { + IExecutionDMContext execDmc = ((ExpandStackEvent)e).getDMContext(); + buildDeltaForExpandStackEvent(execDmc, parent, rm); + } else if (e instanceof PropertyChangeEvent) { + String property = ((PropertyChangeEvent)e).getProperty(); + if (IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT_ENABLE.equals(property) + || IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT.equals(property)) + { + buildDeltaForStackFrameLimitPreferenceChangedEvent(parent, rm); + } else { + rm.done(); + } + } else { + rm.done(); + } + } + + private void buildDeltaForSuspendedEvent(final IExecutionDMContext executionCtx, final IExecutionDMContext triggeringCtx, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor rm) { + IRunControl runControlService = getServicesTracker().getService(IRunControl.class); + IStack stackService = getServicesTracker().getService(IStack.class); + if (stackService == null || runControlService == null) { + // Required services have not initialized yet. Ignore the event. + rm.done(); + return; + } + + // Check if we are building a delta for the thread that triggered the event. + // Only then expand the stack frames and select the top one. + if (executionCtx.equals(triggeringCtx)) { + // Always expand the thread node to show the stack frames. + parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.EXPAND); + + // Retrieve the list of stack frames, and mark the top frame to be selected. + getVMProvider().updateNode( + this, + new VMChildrenUpdate( + parentDelta, getVMProvider().getPresentationContext(), 0, 2, + new DataRequestMonitor<List<Object>>(getExecutor(), rm) { + @Override + public void handleCompleted() { + final List<Object> data= getData(); + if (data != null && data.size() != 0) { + parentDelta.addNode(data.get(0), 0, IModelDelta.SELECT | IModelDelta.STATE); + + // Refresh the whole list of stack frames unless the target is already stepping the next command. In + // which case, the refresh will occur when the stepping sequence slows down or stops. Trying to + // refresh the whole stack trace with every step would slow down stepping too much. + IRunControl runControlService = getServicesTracker().getService(IRunControl.class); + if (runControlService != null && + triggeringCtx != null && runControlService.isStepping(triggeringCtx) && + data.size() >= 2) + { + parentDelta.addNode( data.get(1), 1, IModelDelta.STATE); + } + } + // Even in case of errors, complete the request monitor. + rm.done(); + } + }) + ); + } else { + rm.done(); + } + } + + private void buildDeltaForFullStackRefreshEvent(final IExecutionDMContext executionCtx, final IExecutionDMContext triggeringCtx, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor rm) { + IRunControl runControlService = getServicesTracker().getService(IRunControl.class); + IStack stackService = getServicesTracker().getService(IStack.class); + if (stackService == null || runControlService == null) { + // Required services have not initialized yet. Ignore the event. + rm.done(); + return; + } + + // Refresh the whole list of stack frames unless the target is already stepping the next command. In + // which case, the refresh will occur when the stepping sequence slows down or stops. Trying to + // refresh the whole stack trace with every step would slow down stepping too much. + if (triggeringCtx == null || !runControlService.isStepping(triggeringCtx)) { + parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT); + } + + rm.done(); + } + + private void buildDeltaForSteppingTimedOutEvent(final SteppingTimedOutEvent e, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor rm) { + // Repaint the stack frame images to have the running symbol. + //parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT); + rm.done(); + } + + private void buildDeltaForSteppingTimedOutEvent(final ISteppingTimedOutEvent e, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor rm) { + // Repaint the stack frame images to have the running symbol. + //parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT); + rm.done(); + } + + private void buildDeltaForModelProxyInstalledEvent(final VMDelta parentDelta, final int nodeOffset, final RequestMonitor rm) { + // Retrieve the list of stack frames, and mark the top frame to be selected. + getVMProvider().updateNode( + this, + new VMChildrenUpdate( + parentDelta, getVMProvider().getPresentationContext(), -1, -1, + new DataRequestMonitor<List<Object>>(getExecutor(), rm) { + @Override + public void handleCompleted() { + if (isSuccess() && getData().size() != 0) { + parentDelta.addNode( getData().get(0), 0, IModelDelta.SELECT | IModelDelta.EXPAND); + } + rm.done(); + } + }) + ); + } + + private void buildDeltaForExpandStackEvent(IExecutionDMContext execDmc, final VMDelta parentDelta, final RequestMonitor rm) { + parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT); + rm.done(); + } + + + private void buildDeltaForStackFrameLimitPreferenceChangedEvent(final VMDelta parentDelta, final RequestMonitor rm) { + parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT); + rm.done(); + } + + private String produceFrameElementName( String viewName , IFrameDMContext frame ) { + /* + * We are addressing Bugzilla 211490 which wants the Register View to keep the same expanded + * state for registers for stack frames within the same thread. Different threads could have + * different register sets ( e.g. one thread may have floating point & another may not ). But + * within a thread we are enforcing the assumption that the register sets will be the same. + * So we make a more convenient work flow by keeping the same expansion when selecting amount + * stack frames within the same thread. We accomplish this by only differentiating by adding + * the level for the Expression/Variables view. Otherwise we do not delineate based on which + * view and this captures the Register View in its filter. + */ + if ( viewName.startsWith(IDebugUIConstants.ID_VARIABLE_VIEW) || + viewName.startsWith(IDebugUIConstants.ID_EXPRESSION_VIEW) ) + { + return "Frame." + frame.getLevel() + "." + frame.getSessionId(); //$NON-NLS-1$ //$NON-NLS-2$ + } + else { + return "Frame" + frame.getSessionId(); //$NON-NLS-1$ + } + } + + /* + * (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#compareElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest[]) + */ + public void compareElements(IElementCompareRequest[] requests) { + + for ( IElementCompareRequest request : requests ) { + + Object element = request.getElement(); + IMemento memento = request.getMemento(); + String mementoName = memento.getString("STACK_FRAME_MEMENTO_NAME"); //$NON-NLS-1$ + + if (mementoName != null) { + if (element instanceof IDMVMContext) { + + IDMContext dmc = ((IDMVMContext)element).getDMContext(); + + if ( dmc instanceof IFrameDMContext) { + + String elementName = produceFrameElementName( request.getPresentationContext().getId(), (IFrameDMContext) dmc ); + request.setEqual( elementName.equals( mementoName ) ); + } + } + } + request.done(); + } + } + + /* + * (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#encodeElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest[]) + */ + public void encodeElements(IElementMementoRequest[] requests) { + + for ( IElementMementoRequest request : requests ) { + + Object element = request.getElement(); + IMemento memento = request.getMemento(); + + if (element instanceof IDMVMContext) { + + IDMContext dmc = ((IDMVMContext)element).getDMContext(); + + if ( dmc instanceof IFrameDMContext) { + + String elementName = produceFrameElementName( request.getPresentationContext().getId(), (IFrameDMContext) dmc ); + memento.putString("STACK_FRAME_MEMENTO_NAME", elementName); //$NON-NLS-1$ + } + } + request.done(); + } + } + + /** + * Get the current active stack frame limit. If no limit is applicable {@link Integer.MAX_VALUE} is returned. + * + * @return the current stack frame limit + * + * @since 1.1 + */ + public int getStackFrameLimit(IExecutionDMContext execCtx) { + if (fTemporaryLimits.containsKey(execCtx)) { + return fTemporaryLimits.get(execCtx); + } + Object stackDepthLimit= getVMProvider().getPresentationContext().getProperty(IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT); + if (stackDepthLimit instanceof Integer) { + return (Integer)stackDepthLimit; + } + return Integer.MAX_VALUE; + } + + private void clearStackFrameLimit(IExecutionDMContext execCtx) { + if (execCtx instanceof IContainerDMContext) { + for (Iterator<IExecutionDMContext> itr = fTemporaryLimits.keySet().iterator(); itr.hasNext();) { + IExecutionDMContext limitCtx = itr.next(); + if (limitCtx.equals(execCtx) || DMContexts.isAncestorOf(limitCtx, execCtx)) { + itr.remove(); + } + } + } else { + fTemporaryLimits.remove(execCtx); + } + } + + + /** + * Increment the stack frame limit by the default increment. + * This implementation doubles the current limit. + * + * @since 1.1 + */ + public void incrementStackFrameLimit(IExecutionDMContext execCtx) { + final int stackFrameLimit= getStackFrameLimit(execCtx); + if (stackFrameLimit < Integer.MAX_VALUE / 2) { + fTemporaryLimits.put(execCtx, stackFrameLimit * 2); + } else { + fTemporaryLimits.put(execCtx, Integer.MAX_VALUE); + } + } +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/StandardProcessVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/StandardProcessVMNode.java new file mode 100644 index 00000000000..5e0e7212e23 --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/StandardProcessVMNode.java @@ -0,0 +1,223 @@ +/******************************************************************************* + * Copyright (c) 2006, 2008 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.cdt.dsf.debug.ui.viewmodel.launch; + +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMContext; +import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMNode; +import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMProvider; +import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext; +import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode; +import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.model.IProcess; +import org.eclipse.debug.core.model.IStreamsProxy; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; +import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta; +import org.eclipse.debug.internal.ui.viewers.provisional.ILabelRequestMonitor; +import org.eclipse.jface.viewers.TreePath; + +/** + * Layout node for the standard platform debug model IProcess object. This + * node requires that an ILaunch object be found as an ancestor of this node. + * It does not implement the label provider functionality, so the default + * adapters should be used to retrieve the label. + */ +@SuppressWarnings("restriction") +public class StandardProcessVMNode extends AbstractVMNode { + + /** + * VMC element implementation, it is a proxy for the IProcess class, to + * allow the standard label adapter to be used with this object. + */ + private class VMC extends AbstractVMContext + implements IProcess + { + private final IProcess fProcess; + + VMC(IProcess process) { + super(StandardProcessVMNode.this); + fProcess = process; + } + + @Override + public IVMNode getVMNode() { return StandardProcessVMNode.this; } + @Override + @SuppressWarnings("unchecked") + public Object getAdapter(Class adapter) { + Object vmcAdapter = super.getAdapter(adapter); + if (vmcAdapter != null) { + return vmcAdapter; + } + return fProcess.getAdapter(adapter); + } + @Override + public String toString() { return "IProcess " + fProcess.toString(); } //$NON-NLS-1$ + + public String getAttribute(String key) { return fProcess.getAttribute(key); } + public int getExitValue() throws DebugException { return fProcess.getExitValue(); } + public String getLabel() { return fProcess.getLabel(); } + public ILaunch getLaunch() { return fProcess.getLaunch(); } + public IStreamsProxy getStreamsProxy() { return fProcess.getStreamsProxy(); } + public void setAttribute(String key, String value) { fProcess.setAttribute(key, value); } + public boolean canTerminate() { return fProcess.canTerminate(); } + public boolean isTerminated() { return fProcess.isTerminated(); } + public void terminate() throws DebugException { fProcess.terminate(); } + + @Override + public boolean equals(Object other) { + return other instanceof VMC && fProcess.equals(((VMC)other).fProcess); + } + @Override + public int hashCode() { return fProcess.hashCode(); } + } + + public StandardProcessVMNode(AbstractVMProvider provider) { + super(provider); + } + + @Override + public String toString() { + return "StandardProcessVMNode"; //$NON-NLS-1$ + } + + public void update(IChildrenUpdate[] updates) { + for (IChildrenUpdate update : updates) { + ILaunch launch = findLaunch(update.getElementPath()); + if (launch == null) { + // There is no launch in the parent of this node. This means that the + // layout is misconfigured. + assert false; + update.done(); + continue; + } + + /* + * Assume that the process objects are stored within the launch, and + * retrieve them on dispatch thread. + */ + IProcess[] processes = launch.getProcesses(); + for (int i = 0; i < processes.length; i++) { + update.setChild(new VMC(processes[i]), i); + } + update.done(); + } + } + + public void update(final IChildrenCountUpdate[] updates) { + for (IChildrenCountUpdate update : updates) { + if (!checkUpdate(update)) continue; + ILaunch launch = findLaunch(update.getElementPath()); + if (launch == null) { + assert false; + update.setChildCount(0); + update.done(); + return; + } + + update.setChildCount(launch.getProcesses().length); + update.done(); + } + } + + // @see org.eclipse.cdt.dsf.ui.viewmodel.IViewModelLayoutNode#hasElements(org.eclipse.cdt.dsf.ui.viewmodel.IVMContext, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor) + public void update(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.cdt.dsf.ui.viewmodel.IViewModelLayoutNode#retrieveLabel(org.eclipse.cdt.dsf.ui.viewmodel.IVMContext, org.eclipse.debug.internal.ui.viewers.provisional.ILabelRequestMonitor) + public void updateLabel(IVMContext vmc, ILabelRequestMonitor result, String[] columns) { + + /* + * The implementation of IAdapterFactory that uses this node should not + * register a label adapter for IProcess. This will cause the default + * label provider to be used instead, and this method should then never + * be called. + */ + assert false; + result.done(); + } + + /** + * Recursively searches the VMC for Launch VMC, and returns its ILaunch. + * Returns null if an ILaunch is not found. + */ + private ILaunch findLaunch(TreePath path) { + for (int i = path.getSegmentCount() - 1; i >= 0; i--) { + if (path.getSegment(i) instanceof ILaunch) { + return (ILaunch)path.getSegment(i); + } + } + return null; + } + + public int getDeltaFlags(Object e) { + int myFlags = 0; + if (e instanceof DebugEvent) { + DebugEvent de = (DebugEvent)e; + if ( de.getSource() instanceof IProcess && + (de.getKind() == DebugEvent.CHANGE || + de.getKind() == DebugEvent.CREATE || + de.getKind() == DebugEvent.TERMINATE) ) + { + myFlags = IModelDelta.STATE; + } + } + return myFlags; + } + + public void buildDelta(Object e, VMDelta parent, int nodeOffset, RequestMonitor requestMonitor) { + if (e instanceof DebugEvent && ((DebugEvent)e).getSource() instanceof IProcess) { + DebugEvent de = (DebugEvent)e; + if (de.getKind() == DebugEvent.CHANGE) { + handleChange(de, parent); + } else if (de.getKind() == DebugEvent.CREATE) { + handleCreate(de, parent); + } else if (de.getKind() == DebugEvent.TERMINATE) { + handleTerminate(de, parent); + } + /* + * No other node should need to process events related to process. + * Therefore, just invoke the request monitor without calling super.buildDelta(). + */ + } + requestMonitor.done(); + } + + protected void handleChange(DebugEvent event, ModelDelta parent) { + parent.addNode(new VMC((IProcess)event.getSource()), IModelDelta.STATE); + } + + protected void handleCreate(DebugEvent event, ModelDelta parent) { + parent.setFlags(parent.getFlags() | IModelDelta.CONTENT); + } + + protected void handleTerminate(DebugEvent event, ModelDelta parent) { + handleChange(event, parent); + } + +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/actions/ExpandStackAction.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/actions/ExpandStackAction.java new file mode 100644 index 00000000000..665d6e9f109 --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/actions/ExpandStackAction.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. 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.cdt.dsf.debug.ui.viewmodel.launch.actions; + +import org.eclipse.cdt.dsf.concurrent.DsfRunnable; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.actions.AbstractVMProviderActionDelegate; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.AbstractLaunchVMProvider; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.ExpandStackEvent; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.StackFramesVMNode; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.StackFramesVMNode.IncompleteStackVMContext; +import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode; +import org.eclipse.debug.ui.contexts.DebugContextEvent; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.ui.IObjectActionDelegate; +import org.eclipse.ui.IViewPart; +import org.eclipse.ui.IWorkbenchPart; + +/** + * Increment the (temporary) stack limit for the selected stack. + */ +public class ExpandStackAction extends AbstractVMProviderActionDelegate implements IObjectActionDelegate { + + /* + * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction) + */ + public void run(IAction action) { + Object element = getViewerInput(); + if (element instanceof IncompleteStackVMContext) { + IncompleteStackVMContext incStackVmc = ((IncompleteStackVMContext) element); + IVMNode node = incStackVmc.getVMNode(); + if (incStackVmc.getVMNode() instanceof StackFramesVMNode) { + final IExecutionDMContext exeCtx= incStackVmc.getExecutionDMContext(); + ((StackFramesVMNode) node).incrementStackFrameLimit(exeCtx); + final ExpandStackEvent event = new ExpandStackEvent(exeCtx); + final AbstractLaunchVMProvider vmProvider = (AbstractLaunchVMProvider) getVMProvider(); + vmProvider.getExecutor().execute(new DsfRunnable() { + public void run() { + vmProvider.handleEvent(event); + } + }); + } + } + } + + @Override + public void init(IViewPart view) { + super.init(view); + updateEnablement(); + } + + @Override + public void debugContextChanged(DebugContextEvent event) { + super.debugContextChanged(event); + updateEnablement(); + } + + @Override + public void selectionChanged(IAction action, ISelection selection) { + super.selectionChanged(action, selection); + updateEnablement(); + } + + private void updateEnablement() { + boolean enabled = false; + if (getVMProvider() instanceof AbstractLaunchVMProvider) { + Object element = getViewerInput(); + enabled = element instanceof IncompleteStackVMContext; + } + getAction().setEnabled(enabled); + } + + public void setActivePart(IAction action, IWorkbenchPart targetPart) { + if (targetPart instanceof IViewPart) { + init((IViewPart) targetPart); + } + } +} |