diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java index 7e976589905f..50d336c79d6d 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java @@ -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() { diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/CompoundRendererConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/settings/CompoundRendererConfigurable.java index d36f8718ef09..0600bff905b1 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/CompoundRendererConfigurable.java +++ b/java/debugger/impl/src/com/intellij/debugger/settings/CompoundRendererConfigurable.java @@ -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 myData = new ArrayList<>(); + private final List myData = new ArrayList<>(); public MyTableModel() { } - public void init(List> data) { + public void init(List data) { myData.clear(); - for (final Pair 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> getExpressions() { - final ArrayList> pairs = new ArrayList<>(myData.size()); - for (final Row row : myData) { - pairs.add(Pair.create(row.name, row.value)); - } - return pairs; + public List getExpressions() { + return myData; } private static final class Row { diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/NodeRendererSettings.java b/java/debugger/impl/src/com/intellij/debugger/settings/NodeRendererSettings.java index c372c0ee7944..37fecaf50636 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/NodeRendererSettings.java +++ b/java/debugger/impl/src/com/intellij/debugger/settings/NodeRendererSettings.java @@ -359,12 +359,12 @@ public class NodeRendererSettings implements PersistentStateComponent { } public static EnumerationChildrenRenderer createEnumerationChildrenRenderer(@NonNls String[][] expressions) { - final EnumerationChildrenRenderer childrenRenderer = new EnumerationChildrenRenderer(); + EnumerationChildrenRenderer childrenRenderer = new EnumerationChildrenRenderer(); if (expressions != null && expressions.length > 0) { - final ArrayList> 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 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); } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/CustomFieldInplaceEditor.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/CustomFieldInplaceEditor.java index 50eb9b3da296..15819daf1221 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/CustomFieldInplaceEditor.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/CustomFieldInplaceEditor.java @@ -78,7 +78,7 @@ public class CustomFieldInplaceEditor extends XDebuggerTreeInplaceEditor { } @Override - protected List> getRendererChildren() { + protected List getRendererChildren() { if (myRenderer != null) { return myRenderer.getChildren(); } @@ -110,20 +110,21 @@ public class CustomFieldInplaceEditor extends XDebuggerTreeInplaceEditor { return type != null ? type.name() : null; } - protected List> getRendererChildren() { + protected List getRendererChildren() { return myRenderer.getChildren(); } @Override public void doOKAction() { - List> children = getRendererChildren(); + List 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, diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/EnumerationChildrenRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/EnumerationChildrenRenderer.java index 875a1ede6851..e3c0b0081c2d 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/EnumerationChildrenRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/EnumerationChildrenRenderer.java @@ -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> myChildren; + private List 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> children) { + public EnumerationChildrenRenderer(List 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 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 children = new ArrayList<>(); int idx = 0; - for (Pair 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> getChildren() { + public List getChildren() { return myChildren; } - public void setChildren(List> children) { + public void setChildren(List 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; + } + } } diff --git a/resources-en/src/messages/DebuggerBundle.properties b/resources-en/src/messages/DebuggerBundle.properties index fb866dbcfb51..291e8d4c578a 100644 --- a/resources-en/src/messages/DebuggerBundle.properties +++ b/resources-en/src/messages/DebuggerBundle.properties @@ -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}