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 d2af8760cf9f..ac222be24052 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java @@ -157,8 +157,13 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV XValuePresentation presentation = new JavaValuePresentation( value, myValueDescriptor.getIdLabel(), exception != null ? exception.getMessage() : null, myValueDescriptor); - if (myValueDescriptor.getLastRenderer() instanceof FullValueEvaluatorProvider) { - XFullValueEvaluator evaluator = ((FullValueEvaluatorProvider)myValueDescriptor.getLastRenderer()) + // TODO move inside JavaValuePresentation + Renderer lastRenderer = myValueDescriptor.getLastRenderer(); + if (lastRenderer instanceof CompoundNodeRenderer) { + lastRenderer = ((CompoundNodeRenderer)lastRenderer).getLabelRenderer(); + } + if (lastRenderer instanceof FullValueEvaluatorProvider) { + XFullValueEvaluator evaluator = ((FullValueEvaluatorProvider)lastRenderer) .getFullValueEvaluator(myEvaluationContext, myValueDescriptor); if (evaluator != null) { node.setFullValueEvaluator(evaluator); @@ -302,13 +307,20 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV String value = truncateToMaxLength(myValue); Renderer lastRenderer = myValueDescriptor.getLastRenderer(); + if (lastRenderer instanceof OnDemandRenderer) { + OnDemandRenderer onDemandRenderer = (OnDemandRenderer)lastRenderer; + if (OnDemandRenderer.isCalculated(myValueDescriptor)) { + lastRenderer = onDemandRenderer.getRenderer(); + } + else { + return; + } + } + if (lastRenderer instanceof CompoundTypeRenderer) { lastRenderer = ((CompoundTypeRenderer)lastRenderer).getLabelRenderer(); } if (lastRenderer instanceof ToStringRenderer) { - if (lastRenderer instanceof LazyToStringRenderer && !((LazyToStringRenderer)lastRenderer).isCalculated(myValueDescriptor)) { - return; - } value = StringUtil.wrapWithDoubleQuote(value); } renderer.renderValue(value); 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 f8b7afa03a57..d36f8718ef09 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/CompoundRendererConfigurable.java +++ b/java/debugger/impl/src/com/intellij/debugger/settings/CompoundRendererConfigurable.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -59,6 +59,7 @@ class CompoundRendererConfigurable extends JPanel { private final JRadioButton myRbDefaultLabel; private final JRadioButton myRbExpressionLabel; private final JBCheckBox myShowTypeCheckBox; + private final JBCheckBox myOnDemandCheckBox; private final JRadioButton myRbDefaultChildrenRenderer; private final JRadioButton myRbExpressionChildrenRenderer; private final JRadioButton myRbListChildrenRenderer; @@ -88,6 +89,7 @@ class CompoundRendererConfigurable extends JPanel { labelButtonsGroup.add(myRbExpressionLabel); myShowTypeCheckBox = new JBCheckBox(DebuggerBundle.message("label.compound.renderer.configurable.show.type")); + myOnDemandCheckBox = new JBCheckBox(DebuggerBundle.message("label.compound.renderer.configurable.ondemand")); myRbDefaultChildrenRenderer = new JRadioButton(DebuggerBundle.message("label.compound.renderer.configurable.use.default.renderer")); myRbExpressionChildrenRenderer = new JRadioButton(DebuggerBundle.message("label.compound.renderer.configurable.use.expression")); @@ -156,6 +158,8 @@ class CompoundRendererConfigurable extends JPanel { JBUI.insetsLeft(10), 0, 0)); panel.add(myLabelEditor.getComponent(), new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, JBUI.insetsLeft(30), 0, 0)); + panel.add(myOnDemandCheckBox, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, + GridBagConstraints.HORIZONTAL, JBUI.insetsLeft(30), 0, 0)); panel.add(new JLabel(DebuggerBundle.message("label.compound.renderer.configurable.when.expanding")), new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, @@ -218,7 +222,9 @@ class CompoundRendererConfigurable extends JPanel { } private void updateEnabledState() { - myLabelEditor.setEnabled(myRbExpressionLabel.isSelected()); + boolean isLabelRenderer = myRbExpressionLabel.isSelected(); + myLabelEditor.setEnabled(isLabelRenderer); + myOnDemandCheckBox.setEnabled(isLabelRenderer); final boolean isChildrenExpression = myRbExpressionChildrenRenderer.isSelected(); myChildrenExpandedEditor.setEnabled(isChildrenExpression); @@ -321,6 +327,7 @@ class CompoundRendererConfigurable extends JPanel { if (myRbExpressionLabel.isSelected()) { labelRenderer = new LabelRenderer(); labelRenderer.setLabelExpression(TextWithImportsImpl.fromXExpression(myLabelEditor.getExpression())); + labelRenderer.setOnDemand(myOnDemandCheckBox.isSelected()); } renderer.setLabelRenderer(labelRenderer); // children @@ -362,7 +369,9 @@ class CompoundRendererConfigurable extends JPanel { } else { myRbExpressionLabel.setSelected(true); - myLabelEditor.setExpression(TextWithImportsImpl.toXExpression(((LabelRenderer)labelRenderer).getLabelExpression())); + LabelRenderer lr = (LabelRenderer)labelRenderer; + myLabelEditor.setExpression(TextWithImportsImpl.toXExpression(lr.getLabelExpression())); + myOnDemandCheckBox.setSelected(lr.isOnDemand()); } getTableModel().clear(); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorImpl.java index 6a57152614ae..3182f211bbb6 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorImpl.java @@ -22,7 +22,7 @@ import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.debugger.ui.tree.NodeDescriptor; import com.intellij.debugger.ui.tree.render.DescriptorLabelListener; -import com.intellij.debugger.ui.tree.render.LazyToStringRenderer; +import com.intellij.debugger.ui.tree.render.OnDemandRenderer; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Key; import com.intellij.util.containers.HashMap; @@ -119,7 +119,7 @@ public abstract class NodeDescriptorImpl implements NodeDescriptor { // TODO introduce unified way to handle this if (myUserData != null) { - myUserData.remove(LazyToStringRenderer.LAZY_CALCULATED); // lazy flag should not be inherited + myUserData.remove(OnDemandRenderer.ON_DEMAND_CALCULATED); // calculated flag should not be inherited } } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/LabelRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/LabelRenderer.java index 176803a04837..665d2dfbfdea 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/LabelRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/LabelRenderer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -18,25 +18,25 @@ package com.intellij.debugger.ui.tree.render; import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.engine.DebugProcess; import com.intellij.debugger.engine.DebuggerUtils; -import com.intellij.debugger.engine.evaluation.EvaluateException; -import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil; -import com.intellij.debugger.engine.evaluation.EvaluationContext; -import com.intellij.debugger.engine.evaluation.TextWithImports; +import com.intellij.debugger.engine.FullValueEvaluatorProvider; +import com.intellij.debugger.engine.evaluation.*; import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator; +import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl; import com.intellij.debugger.ui.tree.ValueDescriptor; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.DefaultJDOMExternalizer; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; +import com.intellij.xdebugger.frame.XFullValueEvaluator; import com.sun.jdi.Value; import org.jdom.Element; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.Nullable; import javax.swing.*; -public class LabelRenderer extends TypeRenderer implements ValueLabelRenderer{ +public class LabelRenderer extends TypeRenderer implements ValueLabelRenderer, FullValueEvaluatorProvider { public static final @NonNls String UNIQUE_ID = "LabelRenderer"; - private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.impl.watch.render.ClassLabelRenderer"); + public boolean myOnDemand; private CachedEvaluator myLabelExpression = createCachedEvaluator(); @@ -62,6 +62,10 @@ public class LabelRenderer extends TypeRenderer implements ValueLabelRenderer{ public String calcLabel(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener labelListener) throws EvaluateException { + if (myOnDemand && !OnDemandRenderer.isCalculated(descriptor)) { + return ""; + } + final Value value = descriptor.getValue(); String result; @@ -88,6 +92,15 @@ public class LabelRenderer extends TypeRenderer implements ValueLabelRenderer{ return result; } + @Nullable + @Override + public XFullValueEvaluator getFullValueEvaluator(EvaluationContextImpl evaluationContext, ValueDescriptorImpl valueDescriptor) { + if (myOnDemand && !OnDemandRenderer.isCalculated(valueDescriptor)) { + return OnDemandRenderer.createFullValueEvaluator("… " + getLabelExpression().getText()); + } + return null; + } + public void readExternal(Element element) throws InvalidDataException { super.readExternal(element); DefaultJDOMExternalizer.readExternal(this, element); @@ -111,4 +124,11 @@ public class LabelRenderer extends TypeRenderer implements ValueLabelRenderer{ myLabelExpression.setReferenceExpression(expression); } + public boolean isOnDemand() { + return myOnDemand; + } + + public void setOnDemand(boolean value) { + myOnDemand = value; + } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/LazyToStringRenderer.kt b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/OnDemandRenderer.kt similarity index 52% rename from java/debugger/impl/src/com/intellij/debugger/ui/tree/render/LazyToStringRenderer.kt rename to java/debugger/impl/src/com/intellij/debugger/ui/tree/render/OnDemandRenderer.kt index 00298030d235..41fcf05e600f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/LazyToStringRenderer.kt +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/OnDemandRenderer.kt @@ -16,64 +16,105 @@ package com.intellij.debugger.ui.tree.render import com.intellij.debugger.DebuggerBundle +import com.intellij.debugger.DebuggerContext import com.intellij.debugger.engine.FullValueEvaluatorProvider +import com.intellij.debugger.engine.JavaValue import com.intellij.debugger.engine.evaluation.EvaluateException import com.intellij.debugger.engine.evaluation.EvaluationContext import com.intellij.debugger.engine.evaluation.EvaluationContextImpl import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl +import com.intellij.debugger.ui.tree.DebuggerTreeNode +import com.intellij.debugger.ui.tree.NodeDescriptor import com.intellij.debugger.ui.tree.ValueDescriptor import com.intellij.openapi.util.Key +import com.intellij.psi.PsiElement import com.intellij.xdebugger.frame.XFullValueEvaluator import com.intellij.xdebugger.frame.XValuePlace import com.intellij.xdebugger.impl.ui.tree.nodes.HeadlessValueEvaluationCallback +import com.sun.jdi.Type +import com.sun.jdi.Value +import javax.swing.Icon /** * @author egor */ -class LazyToStringRenderer : ToStringRenderer(), FullValueEvaluatorProvider { +class OnDemandRenderer(val renderer: NodeRendererImpl) : NodeRendererImpl(), FullValueEvaluatorProvider { init { isEnabled = true } - override fun getFullValueEvaluator(evaluationContext: EvaluationContextImpl?, valueDescriptor: ValueDescriptorImpl): XFullValueEvaluator? { - if (!isCalculated(valueDescriptor)) { - return object : XFullValueEvaluator(DebuggerBundle.message("message.node.toString")) { - override fun startEvaluation(callback: XFullValueEvaluator.XFullValueEvaluationCallback) { - if (callback is HeadlessValueEvaluationCallback) { - val node = callback.node - node.clearFullValueEvaluator() - valueDescriptor.putUserData(LAZY_CALCULATED, true) - node.valueContainer.computePresentation(node, XValuePlace.TREE) - } - callback.evaluated("") - } - }.setShowValuePopup(false) - } - return null - } - @Throws(EvaluateException::class) override fun calcLabel(descriptor: ValueDescriptor, evaluationContext: EvaluationContext, listener: DescriptorLabelListener): String? { if (!isCalculated(descriptor)) { return "" } - return super.calcLabel(descriptor, evaluationContext, listener) + return renderer.calcLabel(descriptor, evaluationContext, listener) } - fun isCalculated(descriptor: ValueDescriptor): Boolean { - return LAZY_CALCULATED.get(descriptor, false) + override fun getFullValueEvaluator(evaluationContext: EvaluationContextImpl?, valueDescriptor: ValueDescriptorImpl): XFullValueEvaluator? { + if (!isCalculated(valueDescriptor)) { + return createFullValueEvaluator(DebuggerBundle.message("message.node.toString")) + } + return null + } + + override fun buildChildren(value: Value?, builder: ChildrenBuilder?, evaluationContext: EvaluationContext?) { + renderer.buildChildren(value, builder, evaluationContext) + } + + override fun getChildValueExpression(node: DebuggerTreeNode?, context: DebuggerContext?): PsiElement { + return renderer.getChildValueExpression(node, context) + } + + override fun isExpandable(value: Value?, evaluationContext: EvaluationContext?, parentDescriptor: NodeDescriptor?): Boolean { + return renderer.isExpandable(value, evaluationContext, parentDescriptor) + } + + override fun calcValueIcon(descriptor: ValueDescriptor?, + evaluationContext: EvaluationContext?, + listener: DescriptorLabelListener?): Icon? { + return renderer.calcValueIcon(descriptor, evaluationContext, listener) + } + + override fun isApplicable(type: Type?): Boolean { + return renderer.isApplicable(type) } override fun getName(): String { - return "Lazy" + super.getName() + return "OnDemand" + renderer.getName() } override fun getUniqueId(): String { - return "Lazy" + super.getUniqueId() + return "OnDemand" + renderer.getUniqueId() } companion object { + @JvmStatic + fun createFullValueEvaluator(text: String): XFullValueEvaluator { + return object : XFullValueEvaluator(text) { + override fun startEvaluation(callback: XFullValueEvaluator.XFullValueEvaluationCallback) { + if (callback is HeadlessValueEvaluationCallback) { + val node = callback.node + node.clearFullValueEvaluator() + setCalculated((node.valueContainer as JavaValue).descriptor) + node.valueContainer.computePresentation(node, XValuePlace.TREE) + } + callback.evaluated("") + } + }.setShowValuePopup(false) + } + @JvmField - val LAZY_CALCULATED = Key.create("LAZY_CALCULATED") + val ON_DEMAND_CALCULATED = Key.create("ON_DEMAND_CALCULATED") + + @JvmStatic + fun isCalculated(descriptor: ValueDescriptor): Boolean { + return ON_DEMAND_CALCULATED.get(descriptor, false) + } + + @JvmStatic + fun setCalculated(descriptor: ValueDescriptor) { + ON_DEMAND_CALCULATED.set(descriptor, true) + } } -} +} \ No newline at end of file diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XFullValueEvaluator.java b/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XFullValueEvaluator.java index 6c4f6c9c17fe..d1753cadf620 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XFullValueEvaluator.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XFullValueEvaluator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -52,6 +52,7 @@ public abstract class XFullValueEvaluator { return myShowValuePopup; } + @NotNull public XFullValueEvaluator setShowValuePopup(boolean value) { myShowValuePopup = value; return this; diff --git a/resources-en/src/messages/DebuggerBundle.properties b/resources-en/src/messages/DebuggerBundle.properties index 634c20b0bc64..a7dcafea0328 100644 --- a/resources-en/src/messages/DebuggerBundle.properties +++ b/resources-en/src/messages/DebuggerBundle.properties @@ -208,6 +208,7 @@ label.base.renderer.configurable.enable.toString=Enable 't&oString()' object vie label.base.renderer.configurable.all.overriding=For all classes that override 'toString()' method label.base.renderer.configurable.classes.from.list=For classes from the list: label.compound.renderer.configurable.show.type=Show type and object id +label.compound.renderer.configurable.ondemand=On-demand label.compound.renderer.configurable.use.default.renderer=Use default renderer label.compound.renderer.configurable.use.expression=Use following expression: label.compound.renderer.configurable.use.expression.list=Use list of expressions: