blob: de2d8b3586dfc108cbc2bd428fe5894657fe34a3 [file] [log] [blame]
/*
* Copyright 2000-2009 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.ui.impl;
import com.intellij.debugger.actions.DebuggerAction;
import com.intellij.debugger.actions.DebuggerActions;
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.*;
import java.awt.event.KeyAdapter;
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, final DebuggerStateManager stateManager) {
super(project, stateManager);
final Disposable disposable = DebuggerAction.installEditAction(getThreadsTree(), DebuggerActions.EDIT_FRAME_SOURCE);
registerDisposable(disposable);
getThreadsTree().addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER && getThreadsTree().getSelectionCount() == 1) {
DebuggerTreeNodeImpl node = (DebuggerTreeNodeImpl)getThreadsTree().getLastSelectedPathComponent();
if (node != null) {
NodeDescriptorImpl descriptor = node.getDescriptor();
if (descriptor instanceof StackFrameDescriptorImpl) {
selectFrame(node);
}
}
}
}
});
add(ScrollPaneFactory.createScrollPane(getThreadsTree()), BorderLayout.CENTER);
stateManager.addListener(new DebuggerContextListener() {
@Override
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() {
@Override
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() {
@Override
protected void action() throws Exception {
try {
updateNodeLabels(root);
}
finally {
reschedule();
}
}
@Override
protected void commandCancelled() {
reschedule();
}
});
updateScheduled = true;
}
}
}
}
finally {
if (!updateScheduled) {
reschedule();
}
}
}
private void reschedule() {
final DebuggerSession session = getContext().getDebuggerSession();
if (session != null && 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() {
@Override
public void labelChanged() {
child.labelChanged();
}
});
updateNodeLabels(child);
}
}
@Override
protected DebuggerTree createTreeView() {
return new ThreadsDebuggerTree(getProject());
}
@Override
protected ActionPopupMenu createPopupMenu() {
DefaultActionGroup group = (DefaultActionGroup)ActionManager.getInstance().getAction(DebuggerActions.THREADS_PANEL_POPUP);
return ActionManager.getInstance().createActionPopupMenu(DebuggerActions.THREADS_PANEL_POPUP, group);
}
@Override
public Object getData(String dataId) {
if (PlatformDataKeys.HELP_ID.is(dataId)) {
return HELP_ID;
}
return super.getData(dataId);
}
private void selectFrame(DebuggerTreeNodeImpl node) {
StackFrameProxyImpl frame = ((StackFrameDescriptorImpl)node.getDescriptor()).getFrameProxy();
DebuggerContextUtil.setStackFrame(getContextManager(), frame);
}
public ThreadsDebuggerTree getThreadsTree() {
return (ThreadsDebuggerTree) getTree();
}
}