xdebugger: watches tree reworked

This commit is contained in:
nik
2009-11-23 10:57:05 +03:00
parent 0ca0a0f01f
commit f9e1224ebc
7 changed files with 128 additions and 111 deletions
@@ -37,7 +37,6 @@ import java.awt.*;
public class DebuggerTreeRenderer extends ColoredTreeCellRenderer {
private static final Icon myThreadGroupIcon = IconLoader.getIcon("/debugger/threadGroup.png");
private static final Icon myCurrentThreadGroupIcon = IconLoader.getIcon("/debugger/threadGroupCurrent.png");
private static final Icon myWatchedValueIcon = IconLoader.getIcon("/debugger/watch.png");
private static final Icon myStaticFieldIcon = Icons.FIELD_ICON;
private static final Icon myStaticIcon = IconLoader.getIcon("/nodes/static.png");
@@ -83,7 +82,7 @@ public class DebuggerTreeRenderer extends ColoredTreeCellRenderer {
}
else {
if (valueDescriptor instanceof WatchItemDescriptor) {
nodeIcon = myWatchedValueIcon;
nodeIcon = DebuggerIcons.WATCHED_VALUE_ICON;
} else {
nodeIcon = DebuggerIcons.VALUE_ICON;
}
@@ -34,6 +34,7 @@ public interface DebuggerIcons {
Icon VALUE_ICON = IconLoader.getIcon("/debugger/value.png");
Icon ARRAY_VALUE_ICON = IconLoader.getIcon("/debugger/db_array.png");
Icon PRIMITIVE_VALUE_ICON = IconLoader.getIcon("/debugger/db_primitive.png");
Icon WATCHED_VALUE_ICON = IconLoader.getIcon("/debugger/watch.png");
Icon STACK_FRAME_ICON = IconLoader.getIcon("/debugger/stackFrame.png");
Icon SUSPENDED_THREAD_ICON = IconLoader.getIcon("/debugger/threadSuspended.png");
@@ -34,8 +34,8 @@ public class WatchInplaceEditor extends XDebuggerTreeInplaceEditor {
private final WatchesRootNode myRootNode;
@Nullable private final WatchNode myOldNode;
public WatchInplaceEditor(WatchesRootNode rootNode, final XDebuggerTreeNode node, @NonNls final String historyId, final @Nullable WatchNode oldNode) {
super(node, historyId);
public WatchInplaceEditor(WatchesRootNode rootNode, final WatchNode node, @NonNls final String historyId, final @Nullable WatchNode oldNode) {
super((XDebuggerTreeNode)node, historyId);
myRootNode = rootNode;
myOldNode = oldNode;
myExpressionEditor.setText(oldNode != null ? oldNode.getExpression() : "");
@@ -21,7 +21,6 @@ import com.intellij.ide.dnd.DnDNativeTarget;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.CustomShortcutSet;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ui.tree.TreeUtil;
import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.XDebuggerBundle;
@@ -33,7 +32,10 @@ import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree;
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTreePanel;
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTreeRestorer;
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTreeState;
import com.intellij.xdebugger.impl.ui.tree.nodes.*;
import com.intellij.xdebugger.impl.ui.tree.nodes.WatchNode;
import com.intellij.xdebugger.impl.ui.tree.nodes.WatchesRootNode;
import com.intellij.xdebugger.impl.ui.tree.nodes.XDebuggerTreeNode;
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
@@ -41,7 +43,6 @@ import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
@@ -49,9 +50,9 @@ import java.util.List;
*/
public class XWatchesView extends XDebugViewBase implements DnDNativeTarget {
private final XDebuggerTreePanel myTreePanel;
private final List<String> myWatchExpressions = new ArrayList<String>();
private XDebuggerTreeState myTreeState;
private XDebuggerTreeRestorer myTreeRestorer;
private WatchesRootNode myRootNode;
public XWatchesView(final XDebugSession session, final Disposable parentDisposable, final XDebugSessionData sessionData) {
super(session, parentDisposable);
@@ -69,23 +70,17 @@ public class XWatchesView extends XDebugViewBase implements DnDNativeTarget {
CustomShortcutSet f2Shortcut = new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0));
actionManager.getAction(XDebuggerActions.XEDIT_WATCH).registerCustomShortcutSet(f2Shortcut, tree);
myWatchExpressions.addAll(Arrays.asList(sessionData.getWatchExpressions()));
DnDManager.getInstance().registerTarget(this, tree);
myRootNode = new WatchesRootNode(tree, sessionData.getWatchExpressions());
tree.setRoot(myRootNode, false);
}
public void addWatchExpression(@NotNull String expression, int index) {
if (index == -1) {
myWatchExpressions.add(expression);
}
else {
myWatchExpressions.add(index, expression);
}
XStackFrame stackFrame = mySession.getCurrentStackFrame();
if (stackFrame != null) {
XDebuggerEvaluator evaluator = stackFrame.getEvaluator();
XDebuggerTreeNode root = myTreePanel.getTree().getRoot();
if (evaluator != null && root instanceof WatchesRootNode) {
((WatchesRootNode)root).addWatchExpression(evaluator, expression, index);
if (evaluator != null) {
myRootNode.addWatchExpression(evaluator, expression, index);
}
}
}
@@ -106,14 +101,14 @@ public class XWatchesView extends XDebugViewBase implements DnDNativeTarget {
if (stackFrame != null) {
tree.setSourcePosition(stackFrame.getSourcePosition());
tree.setRoot(new WatchesRootNode(tree, stackFrame.getEvaluator()), false);
myRootNode.updateWatches(stackFrame.getEvaluator());
if (myTreeState != null) {
myTreeRestorer = myTreeState.restoreState(tree);
}
}
else {
tree.setSourcePosition(null);
tree.setRoot(MessageTreeNode.createInfoMessage(tree, null, mySession.getDebugProcess().getCurrentStateMessage()), true);
myRootNode.updateWatches(null);
}
}
@@ -132,36 +127,34 @@ public class XWatchesView extends XDebugViewBase implements DnDNativeTarget {
}
public void removeWatches(final List<? extends XDebuggerTreeNode> nodes) {
XDebuggerTreeNode root = getTree().getRoot();
if (!(root instanceof WatchesRootNode)) return;
final WatchesRootNode watchesRoot = (WatchesRootNode)root;
List<? extends XDebuggerTreeNode> children = watchesRoot.getAllChildren();
List<? extends WatchNode> children = myRootNode.getAllChildren();
int minIndex = Integer.MAX_VALUE;
if (children != null) {
for (XDebuggerTreeNode node : nodes) {
int index = children.indexOf(node);
if (index != -1) {
minIndex = Math.min(minIndex, index);
myWatchExpressions.remove(index);
}
}
}
watchesRoot.removeChildren(nodes);
myRootNode.removeChildren(nodes);
List<? extends XDebuggerTreeNode> newChildren = watchesRoot.getAllChildren();
List<? extends WatchNode> newChildren = myRootNode.getAllChildren();
if (newChildren != null && newChildren.size() > 0) {
XDebuggerTreeNode node = minIndex < newChildren.size() ? newChildren.get(minIndex) : newChildren.get(newChildren.size() - 1);
WatchNode node = minIndex < newChildren.size() ? newChildren.get(minIndex) : newChildren.get(newChildren.size() - 1);
TreeUtil.selectNode(myTreePanel.getTree(), node);
}
}
public String[] getWatchExpressions() {
return ArrayUtil.toStringArray(myWatchExpressions);
}
public void removeWatchExpression(final int index) {
myWatchExpressions.remove(index);
public List<String> getWatchExpressions() {
List<String> watchExpressions = new ArrayList<String>();
final List<? extends WatchNode> children = myRootNode.getAllChildren();
if (children != null) {
for (WatchNode child : children) {
watchExpressions.add(child.getExpression());
}
}
return watchExpressions;
}
public boolean update(final DnDEvent aEvent) {
@@ -1,41 +0,0 @@
/*
* 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.xdebugger.impl.ui.tree.nodes;
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree;
import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants;
import com.intellij.ui.SimpleTextAttributes;
import org.jetbrains.annotations.NotNull;
/**
* @author nik
*/
public class WatchErrorNode extends MessageTreeNode implements WatchNode {
private final String myExpression;
public WatchErrorNode(XDebuggerTree tree, XDebuggerTreeNode parent, @NotNull String expression, @NotNull String errorMessage) {
super(tree, parent, true);
myExpression = expression;
setIcon(XDebuggerUIConstants.ERROR_MESSAGE_ICON);
myText.append(expression + " = ", SimpleTextAttributes.REGULAR_ATTRIBUTES);
myText.append(errorMessage, SimpleTextAttributes.ERROR_ATTRIBUTES);
}
@NotNull
public String getExpression() {
return myExpression;
}
}
@@ -0,0 +1,61 @@
/*
* 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.xdebugger.impl.ui.tree.nodes;
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree;
import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.xdebugger.ui.DebuggerIcons;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
/**
* @author nik
*/
public class WatchMessageNode extends MessageTreeNode implements WatchNode {
private final String myExpression;
private WatchMessageNode(XDebuggerTree tree, XDebuggerTreeNode parent, @NotNull String expression, final Icon icon) {
super(tree, parent, true);
myExpression = expression;
setIcon(icon);
}
@NotNull
public String getExpression() {
return myExpression;
}
public static WatchMessageNode createMessageNode(XDebuggerTree tree, XDebuggerTreeNode parent, String expression) {
final WatchMessageNode node = new WatchMessageNode(tree, parent, expression, DebuggerIcons.WATCHED_VALUE_ICON);
node.myText.append(expression, SimpleTextAttributes.REGULAR_ATTRIBUTES);
return node;
}
public static WatchMessageNode createEvaluatingNode(XDebuggerTree tree, XDebuggerTreeNode parent, String expression) {
final WatchMessageNode node = new WatchMessageNode(tree, parent, expression, DebuggerIcons.WATCHED_VALUE_ICON);
node.myText.append(expression + " = ...", XDebuggerUIConstants.EVALUATING_EXPRESSION_HIGHLIGHT_ATTRIBUTES);
return node;
}
public static WatchMessageNode createErrorNode(XDebuggerTree tree, XDebuggerTreeNode parent, @NotNull String expression, @NotNull String errorMessage) {
final WatchMessageNode node = new WatchMessageNode(tree, parent, expression, XDebuggerUIConstants.ERROR_MESSAGE_ICON);
node.myText.append(expression + " = ", SimpleTextAttributes.REGULAR_ATTRIBUTES);
node.myText.append(errorMessage, SimpleTextAttributes.ERROR_ATTRIBUTES);
return node;
}
}
@@ -17,10 +17,9 @@ package com.intellij.xdebugger.impl.ui.tree.nodes;
import com.intellij.xdebugger.evaluation.XDebuggerEvaluator;
import com.intellij.xdebugger.frame.XValue;
import com.intellij.xdebugger.impl.frame.WatchInplaceEditor;
import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree;
import com.intellij.xdebugger.impl.frame.WatchInplaceEditor;
import com.intellij.xdebugger.impl.XDebugSessionImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -34,47 +33,55 @@ import java.util.List;
* @author nik
*/
public class WatchesRootNode extends XDebuggerTreeNode {
private List<XDebuggerTreeNode> myChildren;
private List<WatchNode> myChildren;
private List<XDebuggerTreeNode> myLoadedChildren;
private final XDebuggerEvaluator myEvaluator;
private XDebuggerEvaluator myCurrentEvaluator;
public WatchesRootNode(final XDebuggerTree tree, XDebuggerEvaluator evaluator) {
public WatchesRootNode(final XDebuggerTree tree, String[] watchExpressions) {
super(tree, null, false);
myEvaluator = evaluator;
loadChildren();
myChildren = new ArrayList<WatchNode>();
for (String watchExpression : watchExpressions) {
myChildren.add(WatchMessageNode.createMessageNode(tree, this, watchExpression));
}
}
private void loadChildren() {
String[] expressions = ((XDebugSessionImpl)myTree.getSession()).getSessionTab().getWatchesView().getWatchExpressions();
myChildren = new ArrayList<XDebuggerTreeNode>();
for (String expression : expressions) {
myChildren.add(MessageTreeNode.createEvaluatingMessage(myTree, this, expression + " = ..."));
public void updateWatches(@Nullable XDebuggerEvaluator evaluator) {
myCurrentEvaluator = evaluator;
List<WatchNode> newChildren = new ArrayList<WatchNode>();
if (evaluator != null) {
for (WatchNode child : myChildren) {
final String expression = child.getExpression();
final WatchMessageNode evaluatingNode = WatchMessageNode.createEvaluatingNode(myTree, this, expression);
newChildren.add(evaluatingNode);
evaluator.evaluate(expression, new MyEvaluationCallback(evaluatingNode));
}
}
for (int i = 0; i < expressions.length; i++) {
myEvaluator.evaluate(expressions[i], new MyEvaluationCallback(expressions[i], myChildren.get(i)));
else {
for (WatchNode child : myChildren) {
final String expression = child.getExpression();
newChildren.add(WatchMessageNode.createMessageNode(myTree, this, expression));
}
}
myChildren = newChildren;
myLoadedChildren = null;
fireNodeChildrenChanged();
}
protected List<? extends TreeNode> getChildren() {
if (myChildren == null) {
loadChildren();
}
return myChildren;
}
@Nullable
public List<? extends XDebuggerTreeNode> getAllChildren() {
public List<? extends WatchNode> getAllChildren() {
return myChildren;
}
public List<? extends XDebuggerTreeNode> getLoadedChildren() {
if (myLoadedChildren == null) {
myLoadedChildren = new ArrayList<XDebuggerTreeNode>();
for (XDebuggerTreeNode child : myChildren) {
for (WatchNode child : myChildren) {
if (child instanceof WatchNodeImpl) {
myLoadedChildren.add(child);
myLoadedChildren.add((WatchNodeImpl)child);
}
}
}
@@ -83,12 +90,12 @@ public class WatchesRootNode extends XDebuggerTreeNode {
@Override
public void clearChildren() {
myChildren = null;
updateWatches(myCurrentEvaluator);
}
private void replaceNode(final XDebuggerTreeNode oldNode, final XDebuggerTreeNode newNode) {
private void replaceNode(final WatchNode oldNode, final WatchNode newNode) {
for (int i = 0; i < myChildren.size(); i++) {
XDebuggerTreeNode child = myChildren.get(i);
WatchNode child = myChildren.get(i);
if (child == oldNode) {
myChildren.set(i, newNode);
if (newNode instanceof XValueContainerNode<?>) {
@@ -105,14 +112,14 @@ public class WatchesRootNode extends XDebuggerTreeNode {
}
public void addWatchExpression(final @NotNull XDebuggerEvaluator evaluator, final @NotNull String expression, int index) {
MessageTreeNode message = MessageTreeNode.createEvaluatingMessage(myTree, this, expression + "...");
WatchNode message = WatchMessageNode.createEvaluatingNode(myTree, this, expression);
if (index == -1) {
myChildren.add(message);
}
else {
myChildren.add(index, message);
}
evaluator.evaluate(expression, new MyEvaluationCallback(expression, message));
evaluator.evaluate(expression, new MyEvaluationCallback(message));
fireNodeChildrenChanged();
}
@@ -135,14 +142,13 @@ public class WatchesRootNode extends XDebuggerTreeNode {
}
public void editWatch(@Nullable WatchNode node) {
MessageTreeNode messageNode = MessageTreeNode.createMessageNode(myTree, this, "", null);
WatchNode messageNode = WatchMessageNode.createMessageNode(myTree, this, "");
int index = node != null ? myChildren.indexOf(node) : -1;
if (index == -1) {
myChildren.add(messageNode);
}
else {
myChildren.set(index, messageNode);
((XDebugSessionImpl)myTree.getSession()).getSessionTab().getWatchesView().removeWatchExpression(index);
}
fireNodeChildrenChanged();
WatchInplaceEditor editor = new WatchInplaceEditor(this, messageNode, "watch", node);
@@ -150,18 +156,16 @@ public class WatchesRootNode extends XDebuggerTreeNode {
}
private class MyEvaluationCallback extends XEvaluationCallbackBase {
private final String myExpression;
private final XDebuggerTreeNode myResultPlace;
private final WatchNode myResultPlace;
public MyEvaluationCallback(final @NotNull String expression, final @NotNull XDebuggerTreeNode resultPlace) {
myExpression = expression;
public MyEvaluationCallback(final @NotNull WatchNode resultPlace) {
myResultPlace = resultPlace;
}
public void evaluated(@NotNull final XValue result) {
DebuggerUIUtil.invokeLater(new Runnable() {
public void run() {
replaceNode(myResultPlace, new WatchNodeImpl(myTree, WatchesRootNode.this, result, myExpression));
replaceNode(myResultPlace, new WatchNodeImpl(myTree, WatchesRootNode.this, result, myResultPlace.getExpression()));
}
});
}
@@ -169,7 +173,7 @@ public class WatchesRootNode extends XDebuggerTreeNode {
public void errorOccurred(@NotNull final String errorMessage) {
DebuggerUIUtil.invokeLater(new Runnable() {
public void run() {
replaceNode(myResultPlace, new WatchErrorNode(myTree, WatchesRootNode.this, myExpression, errorMessage));
replaceNode(myResultPlace, WatchMessageNode.createErrorNode(myTree, WatchesRootNode.this, myResultPlace.getExpression(), errorMessage));
}
});
}