IDEA-175489 On-demand children expressions in user-renderers

This commit is contained in:
Egor.Ushakov
2017-07-07 12:48:18 +03:00
parent e5b56114c1
commit 6c438ddc44
6 changed files with 87 additions and 42 deletions
@@ -32,6 +32,7 @@ import com.intellij.debugger.ui.impl.watch.*;
import com.intellij.debugger.ui.tree.*;
import com.intellij.debugger.ui.tree.render.*;
import com.intellij.debugger.ui.tree.render.Renderer;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.diagnostic.Logger;
@@ -47,6 +48,7 @@ import com.intellij.xdebugger.evaluation.XDebuggerEvaluator;
import com.intellij.xdebugger.evaluation.XInstanceEvaluator;
import com.intellij.xdebugger.frame.*;
import com.intellij.xdebugger.frame.presentation.XErrorValuePresentation;
import com.intellij.xdebugger.frame.presentation.XRegularValuePresentation;
import com.intellij.xdebugger.frame.presentation.XValuePresentation;
import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl;
import com.intellij.xdebugger.impl.evaluate.XValueCompactPresentation;
@@ -126,8 +128,21 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV
return myNodeManager;
}
private boolean isOnDemand() {
return OnDemandRenderer.ON_DEMAND_CALCULATED.isIn(myValueDescriptor);
}
private boolean isCalculated() {
return OnDemandRenderer.isCalculated(myValueDescriptor);
}
@Override
public void computePresentation(@NotNull final XValueNode node, @NotNull XValuePlace place) {
if (isOnDemand() && !isCalculated()) {
node.setFullValueEvaluator(OnDemandRenderer.createFullValueEvaluator(DebuggerBundle.message("message.node.evaluate")));
node.setPresentation(AllIcons.Debugger.Watch, new XRegularValuePresentation("", null, ""), false);
return;
}
myEvaluationContext.getManagerThread().schedule(new SuspendContextCommandImpl(myEvaluationContext.getSuspendContext()) {
@Override
public Priority getPriority() {
@@ -74,6 +74,7 @@ class CompoundRendererConfigurable extends JPanel {
@NonNls private static final String DATA_PANEL_ID = "DATA";
private static final int NAME_TABLE_COLUMN = 0;
private static final int EXPRESSION_TABLE_COLUMN = 1;
private static final int ONDEMAND_TABLE_COLUMN = 2;
public CompoundRendererConfigurable(@NotNull Disposable parentDisposable) {
super(new CardLayout());
@@ -407,22 +408,22 @@ class CompoundRendererConfigurable extends JPanel {
}
private static final class MyTableModel extends AbstractTableModel {
private final List<Row> myData = new ArrayList<>();
private final List<EnumerationChildrenRenderer.ChildInfo> myData = new ArrayList<>();
public MyTableModel() {
}
public void init(List<Pair<String, TextWithImports>> data) {
public void init(List<EnumerationChildrenRenderer.ChildInfo> data) {
myData.clear();
for (final Pair<String, TextWithImports> pair : data) {
myData.add(new Row(pair.getFirst(), pair.getSecond()));
for (EnumerationChildrenRenderer.ChildInfo childInfo : data) {
myData.add(new EnumerationChildrenRenderer.ChildInfo(childInfo.myName, childInfo.myExpression, childInfo.myOnDemand));
}
fireTableDataChanged();
}
@Override
public int getColumnCount() {
return 2;
return 3;
}
@Override
@@ -443,6 +444,8 @@ class CompoundRendererConfigurable extends JPanel {
return String.class;
case EXPRESSION_TABLE_COLUMN:
return TextWithImports.class;
case ONDEMAND_TABLE_COLUMN:
return Boolean.class;
default:
return super.getColumnClass(columnIndex);
}
@@ -453,12 +456,14 @@ class CompoundRendererConfigurable extends JPanel {
if (rowIndex >= getRowCount()) {
return null;
}
final Row row = myData.get(rowIndex);
final EnumerationChildrenRenderer.ChildInfo row = myData.get(rowIndex);
switch (columnIndex) {
case NAME_TABLE_COLUMN:
return row.name;
return row.myName;
case EXPRESSION_TABLE_COLUMN:
return row.value;
return row.myExpression;
case ONDEMAND_TABLE_COLUMN:
return row.myOnDemand;
default:
return null;
}
@@ -469,13 +474,16 @@ class CompoundRendererConfigurable extends JPanel {
if (rowIndex >= getRowCount()) {
return;
}
final Row row = myData.get(rowIndex);
final EnumerationChildrenRenderer.ChildInfo row = myData.get(rowIndex);
switch (columnIndex) {
case NAME_TABLE_COLUMN:
row.name = (String)aValue;
row.myName = (String)aValue;
break;
case EXPRESSION_TABLE_COLUMN:
row.value = (TextWithImports)aValue;
row.myExpression = (TextWithImports)aValue;
break;
case ONDEMAND_TABLE_COLUMN:
row.myOnDemand = (Boolean)aValue;
break;
}
}
@@ -488,13 +496,15 @@ class CompoundRendererConfigurable extends JPanel {
return DebuggerBundle.message("label.compound.renderer.configurable.table.header.name");
case EXPRESSION_TABLE_COLUMN:
return DebuggerBundle.message("label.compound.renderer.configurable.table.header.expression");
case ONDEMAND_TABLE_COLUMN:
return DebuggerBundle.message("label.compound.renderer.configurable.table.header.ondemand");
default:
return "";
}
}
public void addRow(final String name, final TextWithImports expressionWithImports) {
myData.add(new Row(name, expressionWithImports));
myData.add(new EnumerationChildrenRenderer.ChildInfo(name, expressionWithImports, false));
final int lastRow = myData.size() - 1;
fireTableRowsInserted(lastRow, lastRow);
}
@@ -511,12 +521,8 @@ class CompoundRendererConfigurable extends JPanel {
fireTableDataChanged();
}
public List<Pair<String, TextWithImports>> getExpressions() {
final ArrayList<Pair<String, TextWithImports>> pairs = new ArrayList<>(myData.size());
for (final Row row : myData) {
pairs.add(Pair.create(row.name, row.value));
}
return pairs;
public List<EnumerationChildrenRenderer.ChildInfo> getExpressions() {
return myData;
}
private static final class Row {
@@ -359,12 +359,12 @@ public class NodeRendererSettings implements PersistentStateComponent<Element> {
}
public static EnumerationChildrenRenderer createEnumerationChildrenRenderer(@NonNls String[][] expressions) {
final EnumerationChildrenRenderer childrenRenderer = new EnumerationChildrenRenderer();
EnumerationChildrenRenderer childrenRenderer = new EnumerationChildrenRenderer();
if (expressions != null && expressions.length > 0) {
final ArrayList<Pair<String, TextWithImports>> childrenList = new ArrayList<>(expressions.length);
for (final String[] expression : expressions) {
childrenList.add(
new Pair<>(expression[0], new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, expression[1], "", StdFileTypes.JAVA)));
ArrayList<EnumerationChildrenRenderer.ChildInfo> childrenList = new ArrayList<>(expressions.length);
for (String[] expression : expressions) {
childrenList.add(new EnumerationChildrenRenderer.ChildInfo(
expression[0], new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, expression[1], "", StdFileTypes.JAVA), false));
}
childrenRenderer.setChildren(childrenList);
}
@@ -78,7 +78,7 @@ public class CustomFieldInplaceEditor extends XDebuggerTreeInplaceEditor {
}
@Override
protected List<Pair<String, TextWithImports>> getRendererChildren() {
protected List<EnumerationChildrenRenderer.ChildInfo> getRendererChildren() {
if (myRenderer != null) {
return myRenderer.getChildren();
}
@@ -110,20 +110,21 @@ public class CustomFieldInplaceEditor extends XDebuggerTreeInplaceEditor {
return type != null ? type.name() : null;
}
protected List<Pair<String, TextWithImports>> getRendererChildren() {
protected List<EnumerationChildrenRenderer.ChildInfo> getRendererChildren() {
return myRenderer.getChildren();
}
@Override
public void doOKAction() {
List<Pair<String, TextWithImports>> children = getRendererChildren();
List<EnumerationChildrenRenderer.ChildInfo> children = getRendererChildren();
TextWithImports newText = TextWithImportsImpl.fromXExpression(myExpressionEditor.getExpression());
if (myDescriptor == null) {
children.add(0, Pair.create("", newText));
children.add(0, new EnumerationChildrenRenderer.ChildInfo("", newText, false));
}
else {
int index = myDescriptor.getEnumerationIndex();
children.set(index, Pair.create(children.get(index).first, newText));
EnumerationChildrenRenderer.ChildInfo old = children.get(index);
children.set(index, new EnumerationChildrenRenderer.ChildInfo(old.myName, newText, old.myOnDemand));
}
myTree.putClientProperty(XDebuggerTreeRestorer.SELECTION_PATH_PROPERTY,
@@ -27,7 +27,6 @@ import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
import com.intellij.debugger.ui.tree.*;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizerUtil;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.psi.PsiElement;
import com.sun.jdi.Value;
@@ -42,17 +41,18 @@ public final class EnumerationChildrenRenderer extends TypeRenderer implements C
public static final @NonNls String UNIQUE_ID = "EnumerationChildrenRenderer";
private boolean myAppendDefaultChildren;
private List<Pair<String, TextWithImports>> myChildren;
private List<ChildInfo> myChildren;
public static final @NonNls String APPEND_DEFAULT_NAME = "AppendDefault";
public static final @NonNls String CHILDREN_EXPRESSION = "ChildrenExpression";
public static final @NonNls String CHILD_NAME = "Name";
public static final @NonNls String CHILD_ONDEMAND = "OnDemand";
public EnumerationChildrenRenderer() {
this(new ArrayList<>());
}
public EnumerationChildrenRenderer(List<Pair<String, TextWithImports>> children) {
public EnumerationChildrenRenderer(List<ChildInfo> children) {
super();
myChildren = children;
}
@@ -84,8 +84,9 @@ public final class EnumerationChildrenRenderer extends TypeRenderer implements C
for (Element item : children) {
String name = item.getAttributeValue(CHILD_NAME);
TextWithImports text = DebuggerUtils.getInstance().readTextWithImports(item.getChildren().get(0));
boolean onDemand = Boolean.parseBoolean(item.getAttributeValue(CHILD_ONDEMAND));
myChildren.add(Pair.create(name, text));
myChildren.add(new ChildInfo(name, text, onDemand));
}
}
@@ -96,10 +97,13 @@ public final class EnumerationChildrenRenderer extends TypeRenderer implements C
JDOMExternalizerUtil.writeField(element, APPEND_DEFAULT_NAME, "true");
}
for (Pair<String, TextWithImports> pair : myChildren) {
for (ChildInfo childInfo : myChildren) {
Element child = new Element(CHILDREN_EXPRESSION);
child.setAttribute(CHILD_NAME, pair.getFirst());
child.addContent(DebuggerUtils.getInstance().writeTextWithImports(pair.getSecond()));
child.setAttribute(CHILD_NAME, childInfo.myName);
if (childInfo.myOnDemand) {
child.setAttribute(CHILD_ONDEMAND, "true");
}
child.addContent(DebuggerUtils.getInstance().writeTextWithImports(childInfo.myExpression));
element.addContent(child);
}
@@ -111,12 +115,17 @@ public final class EnumerationChildrenRenderer extends TypeRenderer implements C
List<DebuggerTreeNode> children = new ArrayList<>();
int idx = 0;
for (Pair<String, TextWithImports> pair : myChildren) {
UserExpressionData data =
new UserExpressionData((ValueDescriptorImpl)builder.getParentDescriptor(), getClassName(), pair.getFirst(), pair.getSecond());
for (ChildInfo childInfo : myChildren) {
UserExpressionData data = new UserExpressionData((ValueDescriptorImpl)builder.getParentDescriptor(),
getClassName(),
childInfo.myName,
childInfo.myExpression);
data.setEnumerationIndex(idx++);
children.add(nodeManager.createNode(
descriptorFactory.getUserExpressionDescriptor(builder.getParentDescriptor(), data), evaluationContext));
UserExpressionDescriptor descriptor = descriptorFactory.getUserExpressionDescriptor(builder.getParentDescriptor(), data);
if (childInfo.myOnDemand) {
descriptor.putUserData(OnDemandRenderer.ON_DEMAND_CALCULATED, false);
}
children.add(nodeManager.createNode(descriptor, evaluationContext));
}
builder.addChildren(children, !myAppendDefaultChildren);
@@ -134,11 +143,11 @@ public final class EnumerationChildrenRenderer extends TypeRenderer implements C
(myAppendDefaultChildren && DebugProcessImpl.getDefaultRenderer(value).isExpandable(value, evaluationContext, parentDescriptor));
}
public List<Pair<String, TextWithImports>> getChildren() {
public List<ChildInfo> getChildren() {
return myChildren;
}
public void setChildren(List<Pair<String, TextWithImports>> children) {
public void setChildren(List<ChildInfo> children) {
myChildren = children;
}
@@ -154,4 +163,16 @@ public final class EnumerationChildrenRenderer extends TypeRenderer implements C
}
return null;
}
public static class ChildInfo implements Cloneable {
public String myName;
public TextWithImports myExpression;
public boolean myOnDemand;
public ChildInfo(String name, TextWithImports expression, boolean onDemand) {
myName = name;
myExpression = expression;
myOnDemand = onDemand;
}
}
}
@@ -225,6 +225,7 @@ button.move.up=Move &Up
button.move.down=Move &Down
label.compound.renderer.configurable.table.header.name=Name
label.compound.renderer.configurable.table.header.expression=Expression
label.compound.renderer.configurable.table.header.ondemand=On-demand
label.debugger.hotswap.configurable.hotswap.background=Reload classes in &background
label.debugger.hotswap.configurable.compile.before.hotswap=Build project before reloading classes
label.debugger.hotswap.configurable.enable.vm.hang.warning=Enable 'JVM will hang' warning
@@ -432,6 +433,7 @@ message.node.show.image=\u2026 Show image
message.node.show.icon=\u2026 Show icon
message.node.navigate=\u2026 Navigate
message.node.toString=\u2026 toString()
message.node.evaluate=\u2026 Evaluate
label.thread.node.thread.collected=Thread ''{0}'' has been garbage-collected
label.thread.node=\"{0}\"@{1}: {2}
label.thread.node.in.group=\"{0}\"@{1} in group \"{3}\": {2}