mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
1. InterruptThread action available from the ThreadsPane (IDEA-23341)
2. ThreadsPane shows running threads and updates their state even if debug VM is not paused 3. tests fixed
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2000-2010 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.debugger.actions;
|
||||
|
||||
import com.intellij.debugger.DebuggerBundle;
|
||||
import com.intellij.debugger.engine.events.DebuggerCommandImpl;
|
||||
import com.intellij.debugger.impl.DebuggerContextImpl;
|
||||
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
|
||||
import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
|
||||
import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
|
||||
import com.intellij.debugger.ui.impl.watch.ThreadDescriptorImpl;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.Presentation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* User: lex
|
||||
* Date: Sep 26, 2003
|
||||
* Time: 7:35:09 PM
|
||||
*/
|
||||
public class InterruptThreadAction extends DebuggerAction{
|
||||
|
||||
public void actionPerformed(final AnActionEvent e) {
|
||||
final DebuggerTreeNodeImpl[] nodes = getSelectedNodes(e.getDataContext());
|
||||
if (nodes == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
//noinspection ConstantConditions
|
||||
final List<ThreadReferenceProxyImpl> threadsToInterrupt = new ArrayList<ThreadReferenceProxyImpl>();
|
||||
for (final DebuggerTreeNodeImpl debuggerTreeNode : nodes) {
|
||||
final NodeDescriptorImpl descriptor = debuggerTreeNode.getDescriptor();
|
||||
if (descriptor instanceof ThreadDescriptorImpl) {
|
||||
threadsToInterrupt.add(((ThreadDescriptorImpl)descriptor).getThreadReference());
|
||||
}
|
||||
}
|
||||
|
||||
if (!threadsToInterrupt.isEmpty()) {
|
||||
final DebuggerContextImpl debuggerContext = getDebuggerContext(e.getDataContext());
|
||||
debuggerContext.getDebugProcess().getManagerThread().schedule(new DebuggerCommandImpl() {
|
||||
protected void action() throws Exception {
|
||||
for (ThreadReferenceProxyImpl thread : threadsToInterrupt) {
|
||||
thread.getThreadReference().interrupt();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void update(AnActionEvent e) {
|
||||
final DebuggerTreeNodeImpl[] selectedNodes = getSelectedNodes(e.getDataContext());
|
||||
|
||||
boolean visible = false;
|
||||
boolean enabled = false;
|
||||
|
||||
if(selectedNodes != null && selectedNodes.length > 0){
|
||||
visible = true;
|
||||
enabled = true;
|
||||
for (DebuggerTreeNodeImpl selectedNode : selectedNodes) {
|
||||
final NodeDescriptorImpl threadDescriptor = selectedNode.getDescriptor();
|
||||
if (!(threadDescriptor instanceof ThreadDescriptorImpl)) {
|
||||
visible = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (visible) {
|
||||
for (DebuggerTreeNodeImpl selectedNode : selectedNodes) {
|
||||
final ThreadDescriptorImpl threadDescriptor = (ThreadDescriptorImpl)selectedNode.getDescriptor();
|
||||
if (threadDescriptor.isFrozen()) {
|
||||
enabled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
final Presentation presentation = e.getPresentation();
|
||||
presentation.setText(DebuggerBundle.message("action.interrupt.thread.text"));
|
||||
presentation.setVisible(visible);
|
||||
presentation.setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,9 @@ public class ContextUtil {
|
||||
|
||||
@Nullable
|
||||
public static SourcePosition getSourcePosition(final StackFrameContext context) {
|
||||
if (context == null) {
|
||||
return null;
|
||||
}
|
||||
DebugProcessImpl debugProcess = (DebugProcessImpl)context.getDebugProcess();
|
||||
if(debugProcess == null) {
|
||||
return null;
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.intellij.debugger.engine;
|
||||
import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.execution.configurations.RemoteConnection;
|
||||
import com.intellij.execution.configurations.RunProfileState;
|
||||
import com.sun.jdi.ThreadReference;
|
||||
|
||||
/**
|
||||
* @author lex
|
||||
@@ -66,6 +67,14 @@ public class DebugProcessAdapterImpl implements DebugProcessListener {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
//executed in manager thread
|
||||
public void threadStarted(DebugProcess proc, ThreadReference thread) {
|
||||
}
|
||||
|
||||
//executed in manager thread
|
||||
public void threadStopped(DebugProcess proc, ThreadReference thread) {
|
||||
}
|
||||
|
||||
public void attachException(RunProfileState state, ExecutionException exception, RemoteConnection remoteConnection) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,9 @@ import com.sun.jdi.VMDisconnectedException;
|
||||
import com.sun.jdi.VirtualMachine;
|
||||
import com.sun.jdi.event.*;
|
||||
import com.sun.jdi.request.EventRequest;
|
||||
import com.sun.jdi.request.EventRequestManager;
|
||||
import com.sun.jdi.request.ThreadDeathRequest;
|
||||
import com.sun.jdi.request.ThreadStartRequest;
|
||||
|
||||
/**
|
||||
* @author lex
|
||||
@@ -132,20 +135,43 @@ public class DebugProcessEvents extends DebugProcessImpl {
|
||||
while (!isStopped()) {
|
||||
try {
|
||||
final EventSet eventSet = eventQueue.remove();
|
||||
if (myReturnValueWatcher != null && myReturnValueWatcher.isEnabled()) {
|
||||
int processed = 0;
|
||||
for (EventIterator eventIterator = eventSet.eventIterator(); eventIterator.hasNext();) {
|
||||
final Event event = eventIterator.nextEvent();
|
||||
|
||||
final boolean methodWatcherActive = myReturnValueWatcher != null && myReturnValueWatcher.isEnabled();
|
||||
int processed = 0;
|
||||
for (EventIterator eventIterator = eventSet.eventIterator(); eventIterator.hasNext();) {
|
||||
final Event event = eventIterator.nextEvent();
|
||||
|
||||
if (methodWatcherActive) {
|
||||
if (event instanceof MethodExitEvent) {
|
||||
if (myReturnValueWatcher.processMethodExitEvent((MethodExitEvent)event)) {
|
||||
processed++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (processed == eventSet.size()) {
|
||||
eventSet.resume();
|
||||
continue;
|
||||
if (event instanceof ThreadStartEvent) {
|
||||
processed++;
|
||||
final ThreadReference thread = ((ThreadStartEvent)event).thread();
|
||||
getManagerThread().schedule(new DebuggerCommandImpl() {
|
||||
protected void action() throws Exception {
|
||||
myDebugProcessDispatcher.getMulticaster().threadStarted(DebugProcessEvents.this, thread);
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (event instanceof ThreadDeathEvent) {
|
||||
processed++;
|
||||
final ThreadReference thread = ((ThreadDeathEvent)event).thread();
|
||||
getManagerThread().schedule(new DebuggerCommandImpl() {
|
||||
protected void action() throws Exception {
|
||||
myDebugProcessDispatcher.getMulticaster().threadStopped(DebugProcessEvents.this, thread);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (processed == eventSet.size()) {
|
||||
eventSet.resume();
|
||||
continue;
|
||||
}
|
||||
|
||||
getManagerThread().invokeAndWait(new DebuggerCommandImpl() {
|
||||
@@ -262,10 +288,19 @@ public class DebugProcessEvents extends DebugProcessImpl {
|
||||
LOG.assertTrue(!isAttached());
|
||||
if(myState.compareAndSet(STATE_INITIAL, STATE_ATTACHED)) {
|
||||
final VirtualMachineProxyImpl machineProxy = getVirtualMachineProxy();
|
||||
final EventRequestManager requestManager = machineProxy.eventRequestManager();
|
||||
|
||||
if (machineProxy.canGetMethodReturnValues()) {
|
||||
myReturnValueWatcher = new MethodReturnValueWatcher(machineProxy.eventRequestManager());
|
||||
myReturnValueWatcher = new MethodReturnValueWatcher(requestManager);
|
||||
}
|
||||
|
||||
final ThreadStartRequest threadStartRequest = requestManager.createThreadStartRequest();
|
||||
threadStartRequest.setSuspendPolicy(EventRequest.SUSPEND_NONE);
|
||||
threadStartRequest.enable();
|
||||
final ThreadDeathRequest threadDeathRequest = requestManager.createThreadDeathRequest();
|
||||
threadDeathRequest.setSuspendPolicy(EventRequest.SUSPEND_NONE);
|
||||
threadDeathRequest.enable();
|
||||
|
||||
DebuggerManagerEx.getInstanceEx(getProject()).getBreakpointManager().setInitialBreakpointsState();
|
||||
myDebugProcessDispatcher.getMulticaster().processAttached(this);
|
||||
|
||||
|
||||
@@ -113,6 +113,9 @@ public class SuspendManagerUtil {
|
||||
}
|
||||
|
||||
public static SuspendContextImpl getSuspendContextForThread(SuspendContextImpl suspendContext, ThreadReferenceProxyImpl thread) {
|
||||
if (suspendContext == null) {
|
||||
return null;
|
||||
}
|
||||
SuspendContextImpl context = findContextByThread(suspendContext.getDebugProcess().getSuspendManager(), thread);
|
||||
return context != null && !context.myInProgress ? context : suspendContext;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
|
||||
import com.intellij.debugger.engine.requests.RequestManagerImpl;
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl;
|
||||
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
|
||||
import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
|
||||
import com.intellij.debugger.ui.breakpoints.Breakpoint;
|
||||
import com.intellij.debugger.ui.breakpoints.BreakpointWithHighlighter;
|
||||
import com.intellij.debugger.ui.breakpoints.LineBreakpoint;
|
||||
@@ -565,6 +566,26 @@ public class DebuggerSession implements AbstractDebuggerSession {
|
||||
});
|
||||
mySteppingThroughThreads.clear();
|
||||
}
|
||||
|
||||
public void threadStarted(DebugProcess proc, ThreadReference thread) {
|
||||
((VirtualMachineProxyImpl)proc.getVirtualMachineProxy()).threadStarted(thread);
|
||||
DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
|
||||
public void run() {
|
||||
final DebuggerStateManager contextManager = getContextManager();
|
||||
contextManager.fireStateChanged(contextManager.getContext(), EVENT_REFRESH_VIEWS_ONLY);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void threadStopped(DebugProcess proc, ThreadReference thread) {
|
||||
((VirtualMachineProxyImpl)proc.getVirtualMachineProxy()).threadStopped(thread);
|
||||
DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
|
||||
public void run() {
|
||||
final DebuggerStateManager contextManager = getContextManager();
|
||||
contextManager.fireStateChanged(contextManager.getContext(), EVENT_REFRESH_VIEWS_ONLY);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private class MyEvaluationListener implements EvaluationListener {
|
||||
|
||||
@@ -143,6 +143,22 @@ public class VirtualMachineProxyImpl implements JdiTimer, VirtualMachineProxy {
|
||||
return myAllThreads.values();
|
||||
}
|
||||
|
||||
public void threadStarted(ThreadReference thread) {
|
||||
DebuggerManagerThreadImpl.assertIsManagerThread();
|
||||
final Map<ThreadReference, ThreadReferenceProxyImpl> allThreads = myAllThreads;
|
||||
if (allThreads != null && !allThreads.containsKey(thread)) {
|
||||
allThreads.put(thread, new ThreadReferenceProxyImpl(this, thread));
|
||||
}
|
||||
}
|
||||
|
||||
public void threadStopped(ThreadReference thread) {
|
||||
DebuggerManagerThreadImpl.assertIsManagerThread();
|
||||
final Map<ThreadReference, ThreadReferenceProxyImpl> allThreads = myAllThreads;
|
||||
if (allThreads != null) {
|
||||
allThreads.remove(thread);
|
||||
}
|
||||
}
|
||||
|
||||
public void suspend() {
|
||||
DebuggerManagerThreadImpl.assertIsManagerThread();
|
||||
myPausePressedCount++;
|
||||
@@ -564,7 +580,7 @@ public class VirtualMachineProxyImpl implements JdiTimer, VirtualMachineProxy {
|
||||
if (!myNestedClassesCache.isEmpty()) {
|
||||
myNestedClassesCache = new HashMap<ReferenceType, List<ReferenceType>>(myNestedClassesCache.size());
|
||||
}
|
||||
myAllThreadsDirty = true;
|
||||
//myAllThreadsDirty = true;
|
||||
myTimeStamp++;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,6 @@ import com.intellij.execution.ui.layout.LayoutViewOptions;
|
||||
import com.intellij.execution.ui.layout.PlaceInGrid;
|
||||
import com.intellij.ide.CommonActionsManager;
|
||||
import com.intellij.ide.actions.ContextHelpAction;
|
||||
import com.intellij.ide.impl.ProjectUtil;
|
||||
import com.intellij.idea.ActionsBundle;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
@@ -55,7 +54,6 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.IconLoader;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.ui.content.AlertIcon;
|
||||
import com.intellij.ui.content.Content;
|
||||
import com.intellij.ui.content.ContentManagerAdapter;
|
||||
@@ -466,9 +464,7 @@ public class DebuggerSessionTab extends DebuggerSessionTabBase implements Dispos
|
||||
}
|
||||
}
|
||||
|
||||
public RunContentDescriptor attachToSession(final DebuggerSession session,
|
||||
final ProgramRunner runner,
|
||||
final ExecutionEnvironment env)
|
||||
public RunContentDescriptor attachToSession(final DebuggerSession session, final ProgramRunner runner, final ExecutionEnvironment env)
|
||||
throws ExecutionException {
|
||||
disposeSession();
|
||||
myDebuggerSession = session;
|
||||
@@ -487,7 +483,7 @@ public class DebuggerSessionTab extends DebuggerSessionTabBase implements Dispos
|
||||
myStateManager.fireStateChanged(newContext, event);
|
||||
}
|
||||
});
|
||||
return initUI(getDebugProcess().getExecutionResult());
|
||||
return initUI(session.getProcess().getExecutionResult());
|
||||
}
|
||||
|
||||
private void attractFramesOnPause(final int event) {
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.intellij.debugger.engine.evaluation.EvaluateException;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
|
||||
import com.intellij.debugger.engine.evaluation.TextWithImports;
|
||||
import com.intellij.debugger.engine.evaluation.TextWithImportsImpl;
|
||||
import com.intellij.debugger.engine.events.DebuggerCommandImpl;
|
||||
import com.intellij.debugger.impl.DebuggerContextImpl;
|
||||
import com.intellij.debugger.impl.DebuggerSession;
|
||||
import com.intellij.debugger.jdi.LocalVariableProxyImpl;
|
||||
@@ -104,7 +105,7 @@ public class FrameDebuggerTree extends DebuggerTree {
|
||||
}
|
||||
|
||||
|
||||
protected BuildNodeCommand getBuildNodeCommand(final DebuggerTreeNodeImpl node) {
|
||||
protected DebuggerCommandImpl getBuildNodeCommand(final DebuggerTreeNodeImpl node) {
|
||||
if (node.getDescriptor() instanceof StackFrameDescriptorImpl) {
|
||||
return new BuildFrameTreeVariablesCommand(node);
|
||||
}
|
||||
|
||||
@@ -17,14 +17,18 @@ package com.intellij.debugger.ui.impl;
|
||||
|
||||
import com.intellij.debugger.DebuggerInvocationUtil;
|
||||
import com.intellij.debugger.engine.DebugProcessImpl;
|
||||
import com.intellij.debugger.engine.SuspendContextImpl;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
|
||||
import com.intellij.debugger.engine.events.DebuggerCommandImpl;
|
||||
import com.intellij.debugger.impl.DebuggerContextImpl;
|
||||
import com.intellij.debugger.impl.DebuggerSession;
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl;
|
||||
import com.intellij.debugger.jdi.ThreadGroupReferenceProxyImpl;
|
||||
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
|
||||
import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
|
||||
import com.intellij.debugger.settings.ThreadsViewSettings;
|
||||
import com.intellij.debugger.ui.impl.watch.*;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.util.ui.tree.TreeModelAdapter;
|
||||
@@ -66,28 +70,43 @@ public class ThreadsDebuggerTree extends DebuggerTree {
|
||||
}
|
||||
|
||||
protected void build(DebuggerContextImpl context) {
|
||||
buildWhenPaused(context, new RefreshThreadsTreelCommand(context));
|
||||
DebuggerSession debuggerSession = context.getDebuggerSession();
|
||||
final RefreshThreadsTreeCommand command = new RefreshThreadsTreeCommand(debuggerSession);
|
||||
|
||||
final int state = debuggerSession.getState();
|
||||
if (ApplicationManager.getApplication().isUnitTestMode() || state == DebuggerSession.STATE_PAUSED || state == DebuggerSession.STATE_RUNNING) {
|
||||
showMessage(MessageDescriptor.EVALUATING);
|
||||
context.getDebugProcess().getManagerThread().schedule(command);
|
||||
}
|
||||
else {
|
||||
showMessage(debuggerSession.getStateDescription());
|
||||
}
|
||||
}
|
||||
|
||||
private class RefreshThreadsTreelCommand extends RefreshDebuggerTreeCommand{
|
||||
public RefreshThreadsTreelCommand(DebuggerContextImpl context) {
|
||||
super(context);
|
||||
private class RefreshThreadsTreeCommand extends DebuggerCommandImpl{
|
||||
private final DebuggerSession mySession;
|
||||
|
||||
public RefreshThreadsTreeCommand(DebuggerSession session) {
|
||||
mySession = session;
|
||||
}
|
||||
|
||||
public void contextAction() throws Exception {
|
||||
protected void action() throws Exception {
|
||||
final DebuggerTreeNodeImpl root = getNodeFactory().getDefaultNode();
|
||||
|
||||
final DebugProcessImpl debugProcess = mySession.getProcess();
|
||||
if(debugProcess == null || !debugProcess.isAttached()) {
|
||||
return;
|
||||
}
|
||||
final DebuggerContextImpl context = mySession.getContextManager().getContext();
|
||||
final SuspendContextImpl suspendContext = context.getSuspendContext();
|
||||
final ThreadReferenceProxyImpl suspendContextThread = suspendContext != null? suspendContext.getThread() : null;
|
||||
|
||||
final boolean showGroups = ThreadsViewSettings.getInstance().SHOW_THREAD_GROUPS;
|
||||
try {
|
||||
DebugProcessImpl debugProcess = getDebuggerContext().getDebugProcess();
|
||||
if(debugProcess == null || !debugProcess.isAttached()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ThreadReferenceProxyImpl currentThread = ThreadsViewSettings.getInstance().SHOW_CURRENT_THREAD ? getSuspendContext().getThread() : null;
|
||||
final ThreadReferenceProxyImpl currentThread = ThreadsViewSettings.getInstance().SHOW_CURRENT_THREAD ? suspendContextThread : null;
|
||||
final VirtualMachineProxyImpl vm = debugProcess.getVirtualMachineProxy();
|
||||
|
||||
final EvaluationContextImpl evaluationContext = getDebuggerContext().createEvaluationContext();
|
||||
final EvaluationContextImpl evaluationContext = suspendContext != null? getDebuggerContext().createEvaluationContext() : null;
|
||||
final NodeManagerImpl nodeManager = getNodeFactory();
|
||||
|
||||
if (showGroups) {
|
||||
@@ -139,12 +158,11 @@ public class ThreadsDebuggerTree extends DebuggerTree {
|
||||
}
|
||||
}
|
||||
|
||||
final ThreadReferenceProxyImpl thread = getSuspendContext().getThread();
|
||||
final boolean hasThreadToSelect = thread != null; // thread can be null if pause was pressed
|
||||
final boolean hasThreadToSelect = suspendContextThread != null; // thread can be null if pause was pressed
|
||||
final List<ThreadGroupReferenceProxyImpl> groups;
|
||||
if (hasThreadToSelect && showGroups) {
|
||||
groups = new ArrayList<ThreadGroupReferenceProxyImpl>();
|
||||
for(ThreadGroupReferenceProxyImpl group = thread.threadGroupProxy(); group != null; group = group.parent()) {
|
||||
for(ThreadGroupReferenceProxyImpl group = suspendContextThread.threadGroupProxy(); group != null; group = group.parent()) {
|
||||
groups.add(group);
|
||||
}
|
||||
Collections.reverse(groups);
|
||||
@@ -158,7 +176,7 @@ public class ThreadsDebuggerTree extends DebuggerTree {
|
||||
getMutableModel().setRoot(root);
|
||||
treeChanged();
|
||||
if (hasThreadToSelect) {
|
||||
selectThread(groups, thread, true);
|
||||
selectThread(groups, suspendContextThread, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -166,8 +184,6 @@ public class ThreadsDebuggerTree extends DebuggerTree {
|
||||
|
||||
private void selectThread(final List<ThreadGroupReferenceProxyImpl> pathToThread, final ThreadReferenceProxyImpl thread, final boolean expand) {
|
||||
LOG.assertTrue(SwingUtilities.isEventDispatchThread());
|
||||
|
||||
|
||||
class MyTreeModelAdapter extends TreeModelAdapter {
|
||||
private void structureChanged(DebuggerTreeNodeImpl node) {
|
||||
for(Enumeration enumeration = node.children(); enumeration.hasMoreElements(); ) {
|
||||
|
||||
@@ -17,20 +17,25 @@ package com.intellij.debugger.ui.impl;
|
||||
|
||||
import com.intellij.debugger.actions.DebuggerAction;
|
||||
import com.intellij.debugger.actions.DebuggerActions;
|
||||
import com.intellij.debugger.impl.DebuggerContextUtil;
|
||||
import com.intellij.debugger.impl.DebuggerStateManager;
|
||||
import com.intellij.debugger.engine.DebugProcessImpl;
|
||||
import com.intellij.debugger.engine.events.DebuggerCommandImpl;
|
||||
import com.intellij.debugger.impl.*;
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl;
|
||||
import com.intellij.debugger.ui.impl.watch.DebuggerTree;
|
||||
import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
|
||||
import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
|
||||
import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl;
|
||||
import com.intellij.debugger.ui.tree.render.DescriptorLabelListener;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.ActionManager;
|
||||
import com.intellij.openapi.actionSystem.ActionPopupMenu;
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.ui.ScrollPaneFactory;
|
||||
import com.intellij.util.Alarm;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
|
||||
import java.awt.*;
|
||||
@@ -39,8 +44,10 @@ import java.awt.event.KeyEvent;
|
||||
|
||||
public class ThreadsPanel extends DebuggerTreePanel{
|
||||
@NonNls private static final String HELP_ID = "debugging.debugThreads";
|
||||
private final Alarm myUpdateLabelsAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD);
|
||||
private static final int LABELS_UPDATE_DELAY_MS = 200;
|
||||
|
||||
public ThreadsPanel(Project project, DebuggerStateManager stateManager) {
|
||||
public ThreadsPanel(Project project, final DebuggerStateManager stateManager) {
|
||||
super(project, stateManager);
|
||||
|
||||
final Disposable disposable = DebuggerAction.installEditAction(getThreadsTree(), DebuggerActions.EDIT_FRAME_SOURCE);
|
||||
@@ -60,8 +67,88 @@ public class ThreadsPanel extends DebuggerTreePanel{
|
||||
}
|
||||
});
|
||||
add(ScrollPaneFactory.createScrollPane(getThreadsTree()), BorderLayout.CENTER);
|
||||
stateManager.addListener(new DebuggerContextListener() {
|
||||
public void changeEvent(DebuggerContextImpl newContext, int event) {
|
||||
if (DebuggerSession.EVENT_ATTACHED == event || DebuggerSession.EVENT_RESUME == event) {
|
||||
startLabelsUpdate();
|
||||
}
|
||||
else if (DebuggerSession.EVENT_PAUSE == event || DebuggerSession.EVENT_DETACHED == event || DebuggerSession.EVENT_DISPOSE == event) {
|
||||
myUpdateLabelsAlarm.cancelAllRequests();
|
||||
}
|
||||
if (DebuggerSession.EVENT_DETACHED == event || DebuggerSession.EVENT_DISPOSE == event) {
|
||||
stateManager.removeListener(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
startLabelsUpdate();
|
||||
}
|
||||
|
||||
private void startLabelsUpdate() {
|
||||
myUpdateLabelsAlarm.cancelAllRequests();
|
||||
myUpdateLabelsAlarm.addRequest(new Runnable() {
|
||||
public void run() {
|
||||
boolean updateScheduled = false;
|
||||
try {
|
||||
if (isUpdateEnabled()) {
|
||||
final ThreadsDebuggerTree tree = getThreadsTree();
|
||||
final DebuggerTreeNodeImpl root = (DebuggerTreeNodeImpl)tree.getModel().getRoot();
|
||||
if (root != null) {
|
||||
final DebugProcessImpl process = getContext().getDebugProcess();
|
||||
if (process != null) {
|
||||
process.getManagerThread().invoke(new DebuggerCommandImpl() {
|
||||
protected void action() throws Exception {
|
||||
try {
|
||||
updateNodeLabels(root);
|
||||
}
|
||||
finally {
|
||||
reschedule();
|
||||
}
|
||||
}
|
||||
protected void commandCancelled() {
|
||||
reschedule();
|
||||
}
|
||||
});
|
||||
updateScheduled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (!updateScheduled) {
|
||||
reschedule();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void reschedule() {
|
||||
final DebuggerSession session = getContext().getDebuggerSession();
|
||||
if (session.isAttached() && !session.isPaused()) {
|
||||
myUpdateLabelsAlarm.addRequest(this, LABELS_UPDATE_DELAY_MS, ModalityState.NON_MODAL);
|
||||
}
|
||||
}
|
||||
|
||||
}, LABELS_UPDATE_DELAY_MS, ModalityState.NON_MODAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
Disposer.dispose(myUpdateLabelsAlarm);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private static void updateNodeLabels(DebuggerTreeNodeImpl from) {
|
||||
final int childCount = from.getChildCount();
|
||||
for (int idx = 0; idx < childCount; idx++) {
|
||||
final DebuggerTreeNodeImpl child = (DebuggerTreeNodeImpl)from.getChildAt(idx);
|
||||
child.getDescriptor().updateRepresentation(null, new DescriptorLabelListener() {
|
||||
public void labelChanged() {
|
||||
child.labelChanged();
|
||||
}
|
||||
});
|
||||
updateNodeLabels(child);
|
||||
}
|
||||
}
|
||||
|
||||
protected DebuggerTree createTreeView() {
|
||||
return new ThreadsDebuggerTree(getProject());
|
||||
}
|
||||
|
||||
@@ -23,9 +23,9 @@ import com.intellij.debugger.ui.DebuggerView;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.ActionManager;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.CustomShortcutSet;
|
||||
import com.intellij.openapi.actionSystem.ShortcutSet;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.sun.jdi.VMDisconnectedException;
|
||||
|
||||
@@ -37,7 +37,7 @@ public abstract class UpdatableDebuggerView extends JPanel implements DebuggerVi
|
||||
private final Project myProject;
|
||||
private final DebuggerStateManager myStateManager;
|
||||
protected final Alarm myRebuildAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD);
|
||||
private volatile boolean myRefreshNeeded = true;
|
||||
protected volatile boolean myRefreshNeeded = true;
|
||||
protected final java.util.List<Disposable> myDisposables = new ArrayList<Disposable>();
|
||||
private boolean myUpdateEnabled;
|
||||
|
||||
@@ -118,9 +118,9 @@ public abstract class UpdatableDebuggerView extends JPanel implements DebuggerVi
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
myRebuildAlarm.dispose();
|
||||
Disposer.dispose(myRebuildAlarm);
|
||||
for (Disposable disposable : myDisposables) {
|
||||
disposable.dispose();
|
||||
Disposer.dispose(disposable);
|
||||
}
|
||||
myDisposables.clear();
|
||||
}
|
||||
|
||||
@@ -23,8 +23,10 @@ package com.intellij.debugger.ui.impl.watch;
|
||||
import com.intellij.debugger.DebuggerBundle;
|
||||
import com.intellij.debugger.DebuggerInvocationUtil;
|
||||
import com.intellij.debugger.engine.DebugProcessImpl;
|
||||
import com.intellij.debugger.engine.SuspendContextImpl;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
|
||||
import com.intellij.debugger.engine.events.DebuggerCommandImpl;
|
||||
import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
|
||||
import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
|
||||
import com.intellij.debugger.impl.DebuggerContextImpl;
|
||||
@@ -198,16 +200,16 @@ public abstract class DebuggerTree extends DebuggerTreeBase implements DataProvi
|
||||
}
|
||||
final DebugProcessImpl debugProcess = getDebuggerContext().getDebugProcess();
|
||||
if (debugProcess != null) {
|
||||
BuildNodeCommand command = getBuildNodeCommand(node);
|
||||
DebuggerCommandImpl command = getBuildNodeCommand(node);
|
||||
if (command != null) {
|
||||
command.getNode().add(myNodeManager.createMessageNode(MessageDescriptor.EVALUATING));
|
||||
node.add(myNodeManager.createMessageNode(MessageDescriptor.EVALUATING));
|
||||
debugProcess.getManagerThread().schedule(command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// todo: convert "if" into instance method call
|
||||
protected BuildNodeCommand getBuildNodeCommand(final DebuggerTreeNodeImpl node) {
|
||||
protected DebuggerCommandImpl getBuildNodeCommand(final DebuggerTreeNodeImpl node) {
|
||||
if (node.getDescriptor() instanceof StackFrameDescriptorImpl) {
|
||||
return new BuildStackFrameCommand(node);
|
||||
}
|
||||
@@ -668,19 +670,24 @@ public abstract class DebuggerTree extends DebuggerTreeBase implements DataProvi
|
||||
}
|
||||
}
|
||||
|
||||
private class BuildThreadGroupCommand extends BuildNodeCommand {
|
||||
private class BuildThreadGroupCommand extends DebuggerCommandImpl {
|
||||
private final DebuggerTreeNodeImpl myNode;
|
||||
protected final List<DebuggerTreeNode> myChildren = new LinkedList<DebuggerTreeNode>();
|
||||
|
||||
public BuildThreadGroupCommand(DebuggerTreeNodeImpl node) {
|
||||
super(node);
|
||||
myNode = node;
|
||||
}
|
||||
|
||||
public void threadAction() {
|
||||
ThreadGroupDescriptorImpl groupDescriptor = (ThreadGroupDescriptorImpl)getNode().getDescriptor();
|
||||
protected void action() throws Exception {
|
||||
ThreadGroupDescriptorImpl groupDescriptor = (ThreadGroupDescriptorImpl)myNode.getDescriptor();
|
||||
ThreadGroupReferenceProxyImpl threadGroup = groupDescriptor.getThreadGroupReference();
|
||||
|
||||
List<ThreadReferenceProxyImpl> threads = new ArrayList<ThreadReferenceProxyImpl>(threadGroup.threads());
|
||||
Collections.sort(threads, ThreadReferenceProxyImpl.ourComparator);
|
||||
|
||||
EvaluationContextImpl evaluationContext = getDebuggerContext().createEvaluationContext();
|
||||
final DebuggerContextImpl debuggerContext = getDebuggerContext();
|
||||
final SuspendContextImpl suspendContext = debuggerContext.getSuspendContext();
|
||||
final EvaluationContextImpl evaluationContext = suspendContext != null? debuggerContext.createEvaluationContext() : null;
|
||||
|
||||
boolean showCurrent = ThreadsViewSettings.getInstance().SHOW_CURRENT_THREAD;
|
||||
|
||||
@@ -702,8 +709,7 @@ public abstract class DebuggerTree extends DebuggerTreeBase implements DataProvi
|
||||
|
||||
for (ThreadReferenceProxyImpl thread : threads) {
|
||||
if (thread != null) {
|
||||
DebuggerTreeNodeImpl threadNode =
|
||||
myNodeManager.createNode(myNodeManager.getThreadDescriptor(groupDescriptor, thread), evaluationContext);
|
||||
final DebuggerTreeNodeImpl threadNode = myNodeManager.createNode(myNodeManager.getThreadDescriptor(groupDescriptor, thread), evaluationContext);
|
||||
if (showCurrent && ((ThreadDescriptorImpl)threadNode.getDescriptor()).isCurrent()) {
|
||||
threadNodes.add(0, threadNode);
|
||||
}
|
||||
@@ -717,6 +723,18 @@ public abstract class DebuggerTree extends DebuggerTreeBase implements DataProvi
|
||||
|
||||
updateUI(true);
|
||||
}
|
||||
|
||||
protected void updateUI(final boolean scrollToVisible) {
|
||||
DebuggerInvocationUtil.swingInvokeLater(getProject(), new Runnable() {
|
||||
public void run() {
|
||||
myNode.removeAllChildren();
|
||||
for (DebuggerTreeNode debuggerTreeNode : myChildren) {
|
||||
myNode.add(debuggerTreeNode);
|
||||
}
|
||||
myNode.childrenChanged(scrollToVisible);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void hideTooltip() {
|
||||
|
||||
@@ -37,7 +37,7 @@ public class ThisDescriptorImpl extends ValueDescriptorImpl{
|
||||
}
|
||||
|
||||
public Value calcValue(EvaluationContextImpl evaluationContext) throws EvaluateException {
|
||||
return evaluationContext.getThisObject();
|
||||
return evaluationContext != null? evaluationContext.getThisObject() : null;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
|
||||
+6
-7
@@ -70,7 +70,6 @@ public class ThreadDescriptorImpl extends NodeDescriptorImpl implements ThreadDe
|
||||
if (grname != null && !"SYSTEM".equalsIgnoreCase(grname)) {
|
||||
return DebuggerBundle.message("label.thread.node.in.group", myName, thread.uniqueID(), threadStatusText, grname);
|
||||
}
|
||||
|
||||
return DebuggerBundle.message("label.thread.node", myName, thread.uniqueID(), threadStatusText);
|
||||
}
|
||||
catch (ObjectCollectedException e) {
|
||||
@@ -96,20 +95,20 @@ public class ThreadDescriptorImpl extends NodeDescriptorImpl implements ThreadDe
|
||||
|
||||
public void setContext(EvaluationContextImpl context) {
|
||||
final ThreadReferenceProxyImpl thread = getThreadReference();
|
||||
final SuspendManager suspendManager = context.getDebugProcess().getSuspendManager();
|
||||
final SuspendContextImpl suspendContext = context.getSuspendContext();
|
||||
final SuspendManager suspendManager = context != null? context.getDebugProcess().getSuspendManager() : null;
|
||||
final SuspendContextImpl suspendContext = context != null? context.getSuspendContext() : null;
|
||||
|
||||
try {
|
||||
myIsSuspended = suspendManager.isSuspended(thread);
|
||||
myIsSuspended = suspendManager != null? suspendManager.isSuspended(thread) : thread.isSuspended();
|
||||
}
|
||||
catch (ObjectCollectedException e) {
|
||||
myIsSuspended = false;
|
||||
}
|
||||
myIsExpandable = calcExpandable(myIsSuspended);
|
||||
mySuspendContext = SuspendManagerUtil.getSuspendContextForThread(suspendContext, thread);
|
||||
myIsAtBreakpoint = SuspendManagerUtil.findContextByThread(suspendManager, thread) != null;
|
||||
myIsCurrent = suspendContext.getThread() == thread;
|
||||
myIsFrozen = suspendManager.isFrozen(thread);
|
||||
myIsAtBreakpoint = suspendManager != null? SuspendManagerUtil.findContextByThread(suspendManager, thread) != null : thread.getThreadReference().isAtBreakpoint();
|
||||
myIsCurrent = suspendContext != null? suspendContext.getThread() == thread : false;
|
||||
myIsFrozen = suspendManager != null? suspendManager.isFrozen(thread) : myIsSuspended;
|
||||
}
|
||||
|
||||
private boolean calcExpandable(final boolean isSuspended) {
|
||||
|
||||
+2
-2
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.debugger.ui.impl.watch;
|
||||
|
||||
import com.intellij.debugger.DebuggerBundle;
|
||||
import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
|
||||
@@ -22,7 +23,6 @@ import com.intellij.debugger.jdi.ThreadGroupReferenceProxyImpl;
|
||||
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
|
||||
import com.intellij.debugger.ui.tree.ThreadGroupDescriptor;
|
||||
import com.intellij.debugger.ui.tree.render.DescriptorLabelListener;
|
||||
import com.intellij.debugger.DebuggerBundle;
|
||||
import com.sun.jdi.ObjectCollectedException;
|
||||
|
||||
public class ThreadGroupDescriptorImpl extends NodeDescriptorImpl implements ThreadGroupDescriptor{
|
||||
@@ -64,7 +64,7 @@ public class ThreadGroupDescriptorImpl extends NodeDescriptorImpl implements Thr
|
||||
}
|
||||
|
||||
public void setContext(EvaluationContextImpl context) {
|
||||
ThreadReferenceProxyImpl threadProxy = context.getSuspendContext().getThread();
|
||||
ThreadReferenceProxyImpl threadProxy = context != null? context.getSuspendContext().getThread() : null;
|
||||
myIsCurrent = threadProxy != null && isDescendantGroup(threadProxy.threadGroupProxy());
|
||||
myIsExpandable = calcExpandable();
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ public abstract class ValueDescriptorImpl extends NodeDescriptorImpl implements
|
||||
@Nullable
|
||||
private static ObjectReference getTargetExceptionWithStackTraceFilled(final EvaluationContextImpl evaluationContext, EvaluateException ex){
|
||||
final ObjectReference exceptionObj = ex.getExceptionFromTargetVM();
|
||||
if (exceptionObj != null) {
|
||||
if (exceptionObj != null && evaluationContext != null) {
|
||||
try {
|
||||
final ReferenceType refType = exceptionObj.referenceType();
|
||||
final List<Method> methods = refType.methodsByName("getStackTrace", "()[Ljava/lang/StackTraceElement;");
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.intellij.debugger.engine;
|
||||
import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.execution.configurations.RemoteConnection;
|
||||
import com.intellij.execution.configurations.RunProfileState;
|
||||
import com.sun.jdi.ThreadReference;
|
||||
|
||||
public class DebugProcessAdapter implements DebugProcessListener{
|
||||
//executed in manager thread
|
||||
@@ -44,6 +45,14 @@ public class DebugProcessAdapter implements DebugProcessListener{
|
||||
|
||||
}
|
||||
|
||||
//executed in manager thread
|
||||
public void threadStarted(DebugProcess proc, ThreadReference thread) {
|
||||
}
|
||||
|
||||
//executed in manager thread
|
||||
public void threadStopped(DebugProcess proc, ThreadReference thread) {
|
||||
}
|
||||
|
||||
public void attachException(RunProfileState state, ExecutionException exception, RemoteConnection remoteConnection) {
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.intellij.debugger.engine;
|
||||
import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.execution.configurations.RemoteConnection;
|
||||
import com.intellij.execution.configurations.RunProfileState;
|
||||
import com.sun.jdi.ThreadReference;
|
||||
|
||||
import java.util.EventListener;
|
||||
|
||||
@@ -39,5 +40,9 @@ public interface DebugProcessListener extends EventListener{
|
||||
void processAttached(DebugProcess process);
|
||||
|
||||
void attachException(RunProfileState state, ExecutionException exception, RemoteConnection remoteConnection);
|
||||
|
||||
void threadStarted(DebugProcess proc, ThreadReference thread);
|
||||
|
||||
void threadStopped(DebugProcess proc, ThreadReference thread);
|
||||
}
|
||||
|
||||
|
||||
@@ -829,6 +829,7 @@ action.Debugger.SetValue.text=Set Value...
|
||||
action.Debugger.ShowFrame.text=Show Frame
|
||||
action.Debugger.ResumeThread.text=Resume
|
||||
action.Debugger.FreezeThread.text=Freeze
|
||||
action.Debugger.InterruptThread.text=Interrupt
|
||||
action.Debugger.MuteBreakpoints.text=Mute Breakpoints
|
||||
action.Debugger.MuteBreakpoints.description=Mute/unmute all breakpoints in a debug session.
|
||||
action.Debugger.MarkObject.text=Mark Object...
|
||||
|
||||
@@ -31,6 +31,7 @@ action.remove.watch.text={0,choice, 1#Remove Watch|2#Remove Watches}
|
||||
progress.evaluating=Evaluating {0}
|
||||
action.resume.thread.text.resume=Resume
|
||||
action.resume.thread.text.unfreeze=Unfreeze
|
||||
action.interrupt.thread.text=Interrupt
|
||||
title.set.value=Set Value
|
||||
warning.recalculate=The value will be recalculated
|
||||
progress.set.value=Setting value...
|
||||
|
||||
@@ -308,6 +308,7 @@
|
||||
<action id="Debugger.ShowFrame" class="com.intellij.debugger.actions.ShowFrameAction"/>
|
||||
<action id="Debugger.ResumeThread" class="com.intellij.debugger.actions.ResumeThreadAction"/>
|
||||
<action id="Debugger.FreezeThread" class="com.intellij.debugger.actions.FreezeThreadAction"/>
|
||||
<action id="Debugger.InterruptThread" class="com.intellij.debugger.actions.InterruptThreadAction"/>
|
||||
<action id="Debugger.FocusOnBreakpoint" class="com.intellij.debugger.ui.breakpoints.actions.FocusOnBreakpointAction"/>
|
||||
|
||||
</group>
|
||||
@@ -591,6 +592,7 @@
|
||||
<group id="Debugger.ThreadsPanelPopup">
|
||||
<!--<reference ref="Debugger.ResumeThread"/>-->
|
||||
<!--<reference ref="Debugger.FreezeThread"/>-->
|
||||
<reference ref="Debugger.InterruptThread"/>
|
||||
<!--<reference ref="Debugger.ShowFrame"/>-->
|
||||
<reference ref="Debugger.PopFrame"/>
|
||||
<!--<reference ref="Debugger.EditFrameSource"/>-->
|
||||
|
||||
Reference in New Issue
Block a user