2 * Copyright 2000-2015 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
21 package com.intellij.debugger.ui.impl.watch;
23 import com.intellij.debugger.DebuggerBundle;
24 import com.intellij.debugger.DebuggerInvocationUtil;
25 import com.intellij.debugger.engine.*;
26 import com.intellij.debugger.engine.evaluation.EvaluateException;
27 import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
28 import com.intellij.debugger.engine.events.DebuggerCommandImpl;
29 import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
30 import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
31 import com.intellij.debugger.impl.DebuggerContextImpl;
32 import com.intellij.debugger.impl.DebuggerSession;
33 import com.intellij.debugger.impl.DebuggerUtilsEx;
34 import com.intellij.debugger.jdi.*;
35 import com.intellij.debugger.settings.NodeRendererSettings;
36 import com.intellij.debugger.settings.ThreadsViewSettings;
37 import com.intellij.debugger.ui.breakpoints.Breakpoint;
38 import com.intellij.debugger.ui.impl.DebuggerTreeBase;
39 import com.intellij.debugger.ui.impl.tree.TreeBuilder;
40 import com.intellij.debugger.ui.impl.tree.TreeBuilderNode;
41 import com.intellij.debugger.ui.tree.DebuggerTreeNode;
42 import com.intellij.debugger.ui.tree.NodeDescriptor;
43 import com.intellij.debugger.ui.tree.render.ArrayRenderer;
44 import com.intellij.debugger.ui.tree.render.ChildrenBuilder;
45 import com.intellij.debugger.ui.tree.render.ClassRenderer;
46 import com.intellij.debugger.ui.tree.render.NodeRenderer;
47 import com.intellij.openapi.actionSystem.DataKey;
48 import com.intellij.openapi.actionSystem.DataProvider;
49 import com.intellij.openapi.application.ApplicationManager;
50 import com.intellij.openapi.diagnostic.Logger;
51 import com.intellij.openapi.project.Project;
52 import com.intellij.openapi.util.Key;
53 import com.intellij.openapi.util.Pair;
54 import com.intellij.openapi.util.text.StringUtil;
55 import com.intellij.ui.SpeedSearchComparator;
56 import com.intellij.ui.TreeSpeedSearch;
57 import com.intellij.xdebugger.settings.XDebuggerSettingsManager;
59 import com.sun.jdi.event.Event;
60 import com.sun.jdi.event.ExceptionEvent;
63 import javax.swing.event.TreeModelEvent;
64 import javax.swing.event.TreeModelListener;
65 import javax.swing.tree.TreePath;
67 import java.awt.event.MouseEvent;
69 import java.util.List;
71 public abstract class DebuggerTree extends DebuggerTreeBase implements DataProvider {
72 private static final Logger LOG = Logger.getInstance(DebuggerTree.class);
73 protected static final Key<Rectangle> VISIBLE_RECT = Key.create("VISIBLE_RECT");
75 public static final DataKey<DebuggerTree> DATA_KEY = DataKey.create("DebuggerTree");
77 protected final NodeManagerImpl myNodeManager;
79 private DebuggerContextImpl myDebuggerContext = DebuggerContextImpl.EMPTY_CONTEXT;
81 private DebuggerTreeNodeImpl myEditedNode;
83 public DebuggerTree(Project project) {
85 setScrollsOnExpand(false);
86 myNodeManager = createNodeManager(project);
88 final TreeBuilder model = new TreeBuilder(this) {
90 public void buildChildren(TreeBuilderNode node) {
91 final DebuggerTreeNodeImpl debuggerTreeNode = (DebuggerTreeNodeImpl)node;
92 if (debuggerTreeNode.getDescriptor() instanceof DefaultNodeDescriptor) {
95 buildNode(debuggerTreeNode);
99 public boolean isExpandable(TreeBuilderNode builderNode) {
100 return DebuggerTree.this.isExpandable((DebuggerTreeNodeImpl)builderNode);
103 model.setRoot(getNodeFactory().getDefaultNode());
104 model.addTreeModelListener(new TreeModelListener() {
106 public void treeNodesChanged(TreeModelEvent event) {
111 public void treeNodesInserted(TreeModelEvent event) {
116 public void treeNodesRemoved(TreeModelEvent event) {
121 public void treeStructureChanged(TreeModelEvent event) {
128 final TreeSpeedSearch search = new TreeSpeedSearch(this);
129 search.setComparator(new SpeedSearchComparator(false));
132 protected NodeManagerImpl createNodeManager(Project project) {
133 return new NodeManagerImpl(project, this);
137 public void dispose() {
138 myNodeManager.dispose();
139 myDebuggerContext = DebuggerContextImpl.EMPTY_CONTEXT;
143 protected boolean isExpandable(DebuggerTreeNodeImpl node) {
144 NodeDescriptorImpl descriptor = node.getDescriptor();
145 return descriptor.isExpandable();
149 public Object getData(String dataId) {
150 if (DATA_KEY.is(dataId)) {
157 private void buildNode(final DebuggerTreeNodeImpl node) {
158 if (node == null || node.getDescriptor() == null) {
161 final DebugProcessImpl debugProcess = getDebuggerContext().getDebugProcess();
162 if (debugProcess != null) {
163 DebuggerCommandImpl command = getBuildNodeCommand(node);
164 if (command != null) {
165 node.add(myNodeManager.createMessageNode(MessageDescriptor.EVALUATING));
166 debugProcess.getManagerThread().schedule(command);
171 // todo: convert "if" into instance method call
172 protected DebuggerCommandImpl getBuildNodeCommand(final DebuggerTreeNodeImpl node) {
173 if (node.getDescriptor() instanceof StackFrameDescriptorImpl) {
174 return new BuildStackFrameCommand(node);
176 else if (node.getDescriptor() instanceof ValueDescriptorImpl) {
177 return new BuildValueNodeCommand(node);
179 else if (node.getDescriptor() instanceof StaticDescriptorImpl) {
180 return new BuildStaticNodeCommand(node);
182 else if (node.getDescriptor() instanceof ThreadDescriptorImpl) {
183 return new BuildThreadCommand(node);
185 else if (node.getDescriptor() instanceof ThreadGroupDescriptorImpl) {
186 return new BuildThreadGroupCommand(node);
188 LOG.assertTrue(false);
192 public void saveState(DebuggerTreeNodeImpl node) {
193 if (node.getDescriptor() != null) {
194 TreePath path = new TreePath(node.getPath());
195 node.getDescriptor().myIsExpanded = isExpanded(path);
196 node.getDescriptor().myIsSelected = getSelectionModel().isPathSelected(path);
197 Rectangle rowBounds = getRowBounds(getRowForPath(path));
198 if (rowBounds != null && getVisibleRect().contains(rowBounds)) {
199 node.getDescriptor().putUserData(VISIBLE_RECT, getVisibleRect());
200 node.getDescriptor().myIsVisible = true;
203 node.getDescriptor().putUserData(VISIBLE_RECT, null);
204 node.getDescriptor().myIsVisible = false;
208 for (Enumeration e = node.rawChildren(); e.hasMoreElements();) {
209 DebuggerTreeNodeImpl child = (DebuggerTreeNodeImpl)e.nextElement();
214 public void restoreState(DebuggerTreeNodeImpl node) {
215 restoreStateImpl(node);
216 scrollToVisible(node);
219 protected final void scrollToVisible(DebuggerTreeNodeImpl scopeNode) {
220 final TreePath rootPath = new TreePath(scopeNode.getPath());
221 final int rowCount = getRowCount();
222 for (int idx = rowCount - 1; idx >= 0; idx--) {
223 final TreePath treePath = getPathForRow(idx);
224 if (treePath != null) {
225 if (!rootPath.isDescendant(treePath)) {
228 final DebuggerTreeNodeImpl pathNode = (DebuggerTreeNodeImpl)treePath.getLastPathComponent();
229 final NodeDescriptorImpl descriptor = pathNode.getDescriptor();
231 if (descriptor != null && descriptor.myIsVisible) {
232 final Rectangle visibleRect = descriptor.getUserData(VISIBLE_RECT);
233 if (visibleRect != null) {
234 // prefer visible rect
235 scrollRectToVisible(visibleRect);
238 scrollPathToVisible(treePath);
247 public void scrollRectToVisible(Rectangle aRect) {
249 aRect.width += aRect.x;
251 super.scrollRectToVisible(aRect);
254 private void restoreStateImpl(DebuggerTreeNodeImpl node) {
255 restoreNodeState(node);
256 if (node.getDescriptor().myIsExpanded) {
257 for (Enumeration e = node.rawChildren(); e.hasMoreElements();) {
258 DebuggerTreeNodeImpl child = (DebuggerTreeNodeImpl)e.nextElement();
259 restoreStateImpl(child);
264 public void restoreState() {
266 DebuggerTreeNodeImpl root = (DebuggerTreeNodeImpl)getModel().getRoot();
272 protected void restoreNodeState(DebuggerTreeNodeImpl node) {
273 final NodeDescriptorImpl descriptor = node.getDescriptor();
274 if (descriptor != null) {
275 if (node.getParent() == null) {
276 descriptor.myIsExpanded = true;
279 TreePath path = new TreePath(node.getPath());
280 if (descriptor.myIsExpanded) {
283 if (descriptor.myIsSelected) {
284 addSelectionPath(path);
289 public NodeManagerImpl getNodeFactory() {
290 return myNodeManager;
293 public TreeBuilder getMutableModel() {
294 return (TreeBuilder)getModel();
297 public void removeAllChildren() {
298 DebuggerTreeNodeImpl root = (DebuggerTreeNodeImpl)getModel().getRoot();
299 root.removeAllChildren();
303 public void showMessage(MessageDescriptor messageDesc) {
304 DebuggerTreeNodeImpl root = getNodeFactory().getDefaultNode();
305 getMutableModel().setRoot(root);
306 DebuggerTreeNodeImpl message = root.add(messageDesc);
308 expandPath(new TreePath(message.getPath()));
311 public void showMessage(String messageText) {
312 showMessage(new MessageDescriptor(messageText));
315 public final void treeChanged() {
316 DebuggerTreeNodeImpl node = (DebuggerTreeNodeImpl)getModel().getRoot();
318 getMutableModel().nodeStructureChanged(node);
323 protected abstract void build(DebuggerContextImpl context);
325 protected final void buildWhenPaused(DebuggerContextImpl context, RefreshDebuggerTreeCommand command) {
326 DebuggerSession session = context.getDebuggerSession();
328 if (ApplicationManager.getApplication().isUnitTestMode() || (session != null && session.getState() == DebuggerSession.STATE_PAUSED)) {
329 showMessage(MessageDescriptor.EVALUATING);
330 context.getDebugProcess().getManagerThread().schedule(command);
333 showMessage(session != null? session.getStateDescription() : DebuggerBundle.message("status.debug.stopped"));
334 if (session == null || session.isStopped()) {
335 getNodeFactory().clearHistory(); // save memory by clearing references on JDI objects
340 public void rebuild(final DebuggerContextImpl context) {
341 ApplicationManager.getApplication().assertIsDispatchThread();
342 final DebugProcessImpl process = context.getDebugProcess();
343 if (process == null) {
344 return; // empty context, no process available yet
346 myDebuggerContext = context;
348 process.getManagerThread().schedule(new DebuggerCommandImpl() {
350 protected void action() throws Exception {
351 getNodeFactory().setHistoryByContext(context);
354 public Priority getPriority() {
355 return Priority.NORMAL;
362 public void saveState() {
363 saveState((DebuggerTreeNodeImpl)getModel().getRoot());
366 public void onEditorShown(DebuggerTreeNodeImpl node) {
371 public void onEditorHidden(DebuggerTreeNodeImpl node) {
372 if (myEditedNode != null) {
373 assert myEditedNode == node;
379 public JComponent createToolTip(MouseEvent e) {
380 return myEditedNode != null ? null : super.createToolTip(e);
383 protected abstract static class RefreshDebuggerTreeCommand extends SuspendContextCommandImpl {
384 private final DebuggerContextImpl myDebuggerContext;
387 public Priority getPriority() {
388 return Priority.NORMAL;
391 public RefreshDebuggerTreeCommand(DebuggerContextImpl context) {
392 super(context.getSuspendContext());
393 myDebuggerContext = context;
396 public final DebuggerContextImpl getDebuggerContext() {
397 return myDebuggerContext;
401 public DebuggerContextImpl getDebuggerContext() {
402 return myDebuggerContext;
405 public abstract class BuildNodeCommand extends DebuggerContextCommandImpl {
406 private final DebuggerTreeNodeImpl myNode;
408 protected final List<DebuggerTreeNodeImpl> myChildren = new LinkedList<DebuggerTreeNodeImpl>();
410 protected BuildNodeCommand(DebuggerTreeNodeImpl node) {
411 super(DebuggerTree.this.getDebuggerContext());
416 public Priority getPriority() {
417 return Priority.NORMAL;
420 public DebuggerTreeNodeImpl getNode() {
424 protected void updateUI(final boolean scrollToVisible) {
425 DebuggerInvocationUtil.swingInvokeLater(getProject(), new Runnable() {
428 myNode.removeAllChildren();
429 for (DebuggerTreeNodeImpl debuggerTreeNode : myChildren) {
430 myNode.add(debuggerTreeNode);
432 myNode.childrenChanged(scrollToVisible);
438 protected class BuildStackFrameCommand extends BuildNodeCommand {
439 public BuildStackFrameCommand(DebuggerTreeNodeImpl stackNode) {
444 public void threadAction() {
446 final StackFrameDescriptorImpl stackDescriptor = (StackFrameDescriptorImpl)getNode().getDescriptor();
447 final StackFrameProxyImpl frame = stackDescriptor.getFrameProxy();
449 final DebuggerContextImpl debuggerContext = getDebuggerContext();
450 final EvaluationContextImpl evaluationContext = debuggerContext.createEvaluationContext();
451 if (!debuggerContext.isEvaluationPossible()) {
452 myChildren.add(myNodeManager.createNode(MessageDescriptor.EVALUATION_NOT_POSSIBLE, evaluationContext));
455 final Location location = frame.location();
456 LOG.assertTrue(location != null);
458 final ObjectReference thisObjectReference = frame.thisObject();
459 final NodeDescriptor descriptor;
460 if (thisObjectReference != null) {
461 descriptor = myNodeManager.getThisDescriptor(stackDescriptor, thisObjectReference);
464 descriptor = myNodeManager.getStaticDescriptor(stackDescriptor, location.method().declaringType());
466 myChildren.add(myNodeManager.createNode(descriptor, evaluationContext));
468 final ClassRenderer classRenderer = NodeRendererSettings.getInstance().getClassRenderer();
469 if (classRenderer.SHOW_VAL_FIELDS_AS_LOCAL_VARIABLES) {
470 if (thisObjectReference != null && evaluationContext.getDebugProcess().getVirtualMachineProxy().canGetSyntheticAttribute()) {
471 final ReferenceType thisRefType = thisObjectReference.referenceType();
472 if (thisRefType instanceof ClassType && thisRefType.equals(location.declaringType()) && thisRefType.name().contains("$")) { // makes sense for nested classes only
473 final ClassType clsType = (ClassType)thisRefType;
474 for (Field field : clsType.fields()) {
475 if (DebuggerUtils.isSynthetic(field) && StringUtil.startsWith(field.name(), FieldDescriptorImpl.OUTER_LOCAL_VAR_FIELD_PREFIX)) {
476 final FieldDescriptorImpl fieldDescriptor = myNodeManager.getFieldDescriptor(stackDescriptor, thisObjectReference, field);
477 myChildren.add(myNodeManager.createNode(fieldDescriptor, evaluationContext));
485 buildVariables(stackDescriptor, evaluationContext);
486 if (XDebuggerSettingsManager.getInstance().getDataViewSettings().isSortValues()) {
487 Collections.sort(myChildren, NodeManagerImpl.getNodeComparator());
490 catch (EvaluateException e) {
491 myChildren.add(myNodeManager.createMessageNode(new MessageDescriptor(e.getMessage())));
493 // add last method return value if any
494 final Pair<Method, Value> methodValuePair = debuggerContext.getDebugProcess().getLastExecutedMethod();
495 if (methodValuePair != null) {
496 ValueDescriptorImpl returnValueDescriptor = myNodeManager.getMethodReturnValueDescriptor(stackDescriptor, methodValuePair.getFirst(), methodValuePair.getSecond());
497 myChildren.add(1, myNodeManager.createNode(returnValueDescriptor, evaluationContext));
499 // add context exceptions
500 for (Pair<Breakpoint, Event> pair : DebuggerUtilsEx.getEventDescriptors(getSuspendContext())) {
501 final Event debugEvent = pair.getSecond();
502 if (debugEvent instanceof ExceptionEvent) {
503 final ObjectReference exception = ((ExceptionEvent)debugEvent).exception();
504 if (exception != null) {
505 final ValueDescriptorImpl exceptionDescriptor = myNodeManager.getThrownExceptionObjectDescriptor(stackDescriptor, exception);
506 final DebuggerTreeNodeImpl exceptionNode = myNodeManager.createNode(exceptionDescriptor, evaluationContext);
507 myChildren.add(1, exceptionNode);
513 catch (EvaluateException e) {
515 myChildren.add(myNodeManager.createMessageNode(new MessageDescriptor(e.getMessage())));
517 catch (InvalidStackFrameException e) {
522 catch (InternalException e) {
523 if (e.errorCode() == 35) {
525 myNodeManager.createMessageNode(new MessageDescriptor(DebuggerBundle.message("error.corrupt.debug.info", e.getMessage()))));
535 protected void buildVariables(final StackFrameDescriptorImpl stackDescriptor, final EvaluationContextImpl evaluationContext) throws EvaluateException {
536 final StackFrameProxyImpl frame = stackDescriptor.getFrameProxy();
537 for (final LocalVariableProxyImpl local : frame.visibleVariables()) {
538 final LocalVariableDescriptorImpl localVariableDescriptor = myNodeManager.getLocalVariableDescriptor(stackDescriptor, local);
539 final DebuggerTreeNodeImpl variableNode = myNodeManager.createNode(localVariableDescriptor, evaluationContext);
540 myChildren.add(variableNode);
545 private class BuildValueNodeCommand extends BuildNodeCommand implements ChildrenBuilder {
546 public BuildValueNodeCommand(DebuggerTreeNodeImpl node) {
551 public void threadAction() {
552 final DebuggerTreeNodeImpl node = getNode();
553 ValueDescriptorImpl descriptor = (ValueDescriptorImpl)node.getDescriptor();
555 final NodeRenderer renderer = descriptor.getRenderer(getSuspendContext().getDebugProcess());
556 renderer.buildChildren(descriptor.getValue(), this, getDebuggerContext().createEvaluationContext());
558 catch (ObjectCollectedException e) {
559 final String message = e.getMessage();
560 DebuggerInvocationUtil.swingInvokeLater(getProject(), new Runnable() {
563 node.removeAllChildren();
564 node.add(getNodeFactory().createMessageNode(
565 new MessageDescriptor(DebuggerBundle.message("error.cannot.build.node.children.object.collected", message)))
567 node.childrenChanged(false);
574 public NodeManagerImpl getNodeManager() {
576 return myNodeManager;
580 public NodeManagerImpl getDescriptorManager() {
581 return myNodeManager;
585 public ValueDescriptorImpl getParentDescriptor() {
586 return (ValueDescriptorImpl)getNode().getDescriptor();
590 public void setRemaining(int remaining) {}
593 public void initChildrenArrayRenderer(ArrayRenderer renderer) {}
596 public void setChildren(final List<DebuggerTreeNode> children) {
597 for (DebuggerTreeNode child : children) {
598 if (child instanceof DebuggerTreeNodeImpl) {
599 myChildren.add(((DebuggerTreeNodeImpl)child));
606 private class BuildStaticNodeCommand extends BuildNodeCommand {
607 public BuildStaticNodeCommand(DebuggerTreeNodeImpl node) {
612 public void threadAction() {
613 final StaticDescriptorImpl sd = (StaticDescriptorImpl)getNode().getDescriptor();
614 final ReferenceType refType = sd.getType();
615 List<Field> fields = refType.allFields();
616 for (Field field : fields) {
617 if (field.isStatic()) {
618 final FieldDescriptorImpl fieldDescriptor = myNodeManager.getFieldDescriptor(sd, null, field);
619 final EvaluationContextImpl evaluationContext = getDebuggerContext().createEvaluationContext();
620 final DebuggerTreeNodeImpl node = myNodeManager.createNode(fieldDescriptor, evaluationContext);
621 myChildren.add(node);
629 private class BuildThreadCommand extends BuildNodeCommand {
630 public BuildThreadCommand(DebuggerTreeNodeImpl threadNode) {
635 public void threadAction() {
636 ThreadDescriptorImpl threadDescriptor = ((ThreadDescriptorImpl)getNode().getDescriptor());
637 ThreadReferenceProxyImpl threadProxy = threadDescriptor.getThreadReference();
638 if (!threadProxy.isCollected() && getDebuggerContext().getDebugProcess().getSuspendManager().isSuspended(threadProxy)) {
639 int status = threadProxy.status();
640 if (!(status == ThreadReference.THREAD_STATUS_UNKNOWN) &&
641 !(status == ThreadReference.THREAD_STATUS_NOT_STARTED) &&
642 !(status == ThreadReference.THREAD_STATUS_ZOMBIE)) {
644 for (StackFrameProxyImpl stackFrame : threadProxy.frames()) {
645 //Method method = stackFrame.location().method();
646 //ToDo :check whether is synthetic if (shouldDisplay(method)) {
647 myChildren.add(myNodeManager.createNode(myNodeManager.getStackFrameDescriptor(threadDescriptor, stackFrame),
648 getDebuggerContext().createEvaluationContext()));
651 catch (EvaluateException e) {
653 myChildren.add(myNodeManager.createMessageNode(e.getMessage()));
655 //LOG.assertTrue(false);
656 // if we pause during evaluation of this method the exception is thrown
657 // private static void longMethod(){
659 // Thread.sleep(100000);
660 // } catch (InterruptedException e) {
661 // e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
671 private class BuildThreadGroupCommand extends DebuggerCommandImpl {
672 private final DebuggerTreeNodeImpl myNode;
673 protected final List<DebuggerTreeNodeImpl> myChildren = new LinkedList<DebuggerTreeNodeImpl>();
675 public BuildThreadGroupCommand(DebuggerTreeNodeImpl node) {
680 protected void action() throws Exception {
681 ThreadGroupDescriptorImpl groupDescriptor = (ThreadGroupDescriptorImpl)myNode.getDescriptor();
682 ThreadGroupReferenceProxyImpl threadGroup = groupDescriptor.getThreadGroupReference();
684 List<ThreadReferenceProxyImpl> threads = new ArrayList<ThreadReferenceProxyImpl>(threadGroup.threads());
685 Collections.sort(threads, ThreadReferenceProxyImpl.ourComparator);
687 final DebuggerContextImpl debuggerContext = getDebuggerContext();
688 final SuspendContextImpl suspendContext = debuggerContext.getSuspendContext();
689 final EvaluationContextImpl evaluationContext = suspendContext != null && !suspendContext.isResumed()? debuggerContext.createEvaluationContext() : null;
691 boolean showCurrent = ThreadsViewSettings.getInstance().SHOW_CURRENT_THREAD;
693 for (final ThreadGroupReferenceProxyImpl group : threadGroup.threadGroups()) {
695 DebuggerTreeNodeImpl threadNode =
696 myNodeManager.createNode(myNodeManager.getThreadGroupDescriptor(groupDescriptor, group), evaluationContext);
698 if (showCurrent && ((ThreadGroupDescriptorImpl)threadNode.getDescriptor()).isCurrent()) {
699 myChildren.add(0, threadNode);
702 myChildren.add(threadNode);
707 ArrayList<DebuggerTreeNodeImpl> threadNodes = new ArrayList<DebuggerTreeNodeImpl>();
709 for (ThreadReferenceProxyImpl thread : threads) {
710 if (thread != null) {
711 final DebuggerTreeNodeImpl threadNode = myNodeManager.createNode(myNodeManager.getThreadDescriptor(groupDescriptor, thread), evaluationContext);
712 if (showCurrent && ((ThreadDescriptorImpl)threadNode.getDescriptor()).isCurrent()) {
713 threadNodes.add(0, threadNode);
716 threadNodes.add(threadNode);
721 myChildren.addAll(threadNodes);
726 protected void updateUI(final boolean scrollToVisible) {
727 DebuggerInvocationUtil.swingInvokeLater(getProject(), new Runnable() {
730 myNode.removeAllChildren();
731 for (DebuggerTreeNodeImpl debuggerTreeNode : myChildren) {
732 myNode.add(debuggerTreeNode);
734 myNode.childrenChanged(scrollToVisible);
740 public void hideTooltip() {
741 myTipManager.hideTooltip();