Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch')
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/AbstractContainerVMNode.java191
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/AbstractLaunchVMProvider.java294
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/AbstractThreadVMNode.java328
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/DefaultDsfModelSelectionPolicyFactory.java44
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/DefaultDsfSelectionPolicy.java154
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/DelayedStackRefreshUpdatePolicy.java175
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/ExpandStackEvent.java27
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/FullStackRefreshEvent.java28
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/LaunchRootVMNode.java130
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/LaunchVMUpdateMessages.java29
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/StackFramesVMNode.java724
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/StandardProcessVMNode.java223
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/actions/ExpandStackAction.java87
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);
+ }
+ }
+}

Back to the top