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 16fdaad1eab6..dcc54be00a2c 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java @@ -54,6 +54,8 @@ import com.sun.jdi.ArrayType; import com.sun.jdi.Value; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.concurrency.AsyncPromise; +import org.jetbrains.concurrency.Promise; import javax.swing.*; import java.util.ArrayList; @@ -457,14 +459,17 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV return myValueDescriptor.canSetValue() ? new JavaValueModifier(this) : null; } - private volatile String evaluationExpression = null; - @Nullable + + @NotNull @Override - public String getEvaluationExpression() { - if (evaluationExpression == null) { - // TODO: change API to allow to calculate it asynchronously - myEvaluationContext.getManagerThread().invokeAndWait(new SuspendContextCommandImpl(myEvaluationContext.getSuspendContext()) { + public Promise calculateEvaluationExpression() { + if (evaluationExpression != null) { + return Promise.resolve(evaluationExpression); + } + else { + final AsyncPromise res = new AsyncPromise(); + myEvaluationContext.getManagerThread().schedule(new SuspendContextCommandImpl(myEvaluationContext.getSuspendContext()) { @Override public Priority getPriority() { return Priority.HIGH; @@ -487,10 +492,11 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV return null; } }); + res.setResult(evaluationExpression); } }); + return res; } - return evaluationExpression; } @Override diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XValue.java b/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XValue.java index 64c0d900b29d..82539889ed86 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XValue.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XValue.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -19,6 +19,7 @@ import com.intellij.util.ThreeState; import com.intellij.xdebugger.evaluation.XInstanceEvaluator; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.concurrency.Promise; /** * Represents a value in debugger tree. @@ -44,6 +45,14 @@ public abstract class XValue extends XValueContainer { return null; } + /** + * Asynchronously calculates expression which evaluates to the current value + */ + @NotNull + public Promise calculateEvaluationExpression() { + return Promise.resolve(getEvaluationExpression()); + } + /** * @return evaluator to calculate value of the current object instance */ diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerEvaluateActionHandler.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerEvaluateActionHandler.java index b6875bec0664..fc274d686245 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerEvaluateActionHandler.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerEvaluateActionHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -23,6 +23,8 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ui.AppUIUtil; +import com.intellij.util.Consumer; import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XExpression; import com.intellij.xdebugger.XSourcePosition; @@ -45,8 +47,8 @@ import org.jetbrains.annotations.Nullable; public class XDebuggerEvaluateActionHandler extends XDebuggerActionHandler { @Override protected void perform(@NotNull final XDebugSession session, final DataContext dataContext) { - XDebuggerEditorsProvider editorsProvider = session.getDebugProcess().getEditorsProvider(); - XStackFrame stackFrame = session.getCurrentStackFrame(); + final XDebuggerEditorsProvider editorsProvider = session.getDebugProcess().getEditorsProvider(); + final XStackFrame stackFrame = session.getCurrentStackFrame(); final XDebuggerEvaluator evaluator = session.getDebugProcess().getEvaluator(); if (evaluator == null) { return; @@ -72,10 +74,29 @@ public class XDebuggerEvaluateActionHandler extends XDebuggerActionHandler { if (text == null) { XValue value = XDebuggerTreeActionBase.getSelectedValue(dataContext); if (value != null) { - text = value.getEvaluationExpression(); + final EvaluationMode evalMode = mode; + value.calculateEvaluationExpression().done(new Consumer() { + @Override + public void consume(final String text) { + AppUIUtil.invokeOnEdt(new Runnable() { + @Override + public void run() { + showDialog(session, dataContext, editorsProvider, stackFrame, evaluator, evalMode, text); + } + }); + } + }); + return; } } + showDialog(session, dataContext, editorsProvider, stackFrame, evaluator, mode, text); + } + + private static void showDialog(@NotNull XDebugSession session, + DataContext dataContext, + XDebuggerEditorsProvider editorsProvider, + XStackFrame stackFrame, XDebuggerEvaluator evaluator, EvaluationMode mode, String text) { Language language = null; if (stackFrame != null) { XSourcePosition position = stackFrame.getSourcePosition(); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java index 533cae3e07d3..8c2e7d0aed82 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -32,6 +32,7 @@ import com.intellij.openapi.util.SystemInfo; import com.intellij.ui.*; import com.intellij.ui.border.CustomLineBorder; import com.intellij.util.Alarm; +import com.intellij.util.Consumer; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.tree.TreeUtil; import com.intellij.xdebugger.XDebugSession; @@ -432,11 +433,15 @@ public class XWatchesViewImpl extends XDebugView implements DnDNativeTarget, XWa if (object instanceof XValueNodeImpl[]) { final XValueNodeImpl[] nodes = (XValueNodeImpl[])object; for (XValueNodeImpl node : nodes) { - String expression = node.getValueContainer().getEvaluationExpression(); - if (expression != null) { - //noinspection ConstantConditions - addWatchExpression(XExpressionImpl.fromText(expression), -1, false); - } + node.getValueContainer().calculateEvaluationExpression().done(new Consumer() { + @Override + public void consume(String expression) { + if (expression != null) { + //noinspection ConstantConditions + addWatchExpression(XExpressionImpl.fromText(expression), -1, false); + } + } + }); } } else if (object instanceof EventInfo) { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java index 063226f82f76..c0110780674c 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java @@ -25,6 +25,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.*; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.DimensionService; +import com.intellij.openapi.util.Getter; import com.intellij.openapi.util.Ref; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.openapi.wm.WindowManager; @@ -38,6 +39,7 @@ import com.intellij.xdebugger.breakpoints.XBreakpointAdapter; import com.intellij.xdebugger.breakpoints.XBreakpointListener; import com.intellij.xdebugger.breakpoints.XBreakpointManager; import com.intellij.xdebugger.frame.XFullValueEvaluator; +import com.intellij.xdebugger.frame.XValue; import com.intellij.xdebugger.impl.breakpoints.XBreakpointBase; import com.intellij.xdebugger.impl.breakpoints.ui.BreakpointsDialogFactory; import com.intellij.xdebugger.impl.breakpoints.ui.XLightBreakpointPropertiesPanel; @@ -45,6 +47,7 @@ import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.concurrency.Promise; import javax.swing.*; import java.awt.*; @@ -346,4 +349,16 @@ public class DebuggerUIUtil { return valueNode.getRawValue(); } } + + /** + * Checks if value has evaluation expression ready, or calculation is pending + */ + public static boolean hasEvaluationExpression(@NotNull XValue value) { + Promise promise = value.calculateEvaluationExpression(); + if (promise.getState() == Promise.State.PENDING) return true; + if (promise instanceof Getter) { + return ((Getter)promise).get() != null; + } + return true; + } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/XDebuggerTreePanel.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/XDebuggerTreePanel.java index 1a4c5604ed18..0cc1cf7b285d 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/XDebuggerTreePanel.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/XDebuggerTreePanel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -29,6 +29,7 @@ import com.intellij.xdebugger.XDebuggerBundle; import com.intellij.xdebugger.XSourcePosition; import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider; import com.intellij.xdebugger.impl.frame.XValueMarkers; +import com.intellij.xdebugger.impl.ui.DebuggerUIUtil; import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -70,7 +71,7 @@ public class XDebuggerTreePanel implements DnDSource { return myTree.getSelectedNodes(XValueNodeImpl.class, new Tree.NodeFilter() { @Override public boolean accept(final XValueNodeImpl node) { - return node.getValueContainer().getEvaluationExpression() != null; + return DebuggerUIUtil.hasEvaluationExpression(node.getValueContainer()); } }); } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/EvaluateInConsoleFromTreeAction.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/EvaluateInConsoleFromTreeAction.java index 8f515ee5907e..29cd6b9d6133 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/EvaluateInConsoleFromTreeAction.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/EvaluateInConsoleFromTreeAction.java @@ -1,8 +1,24 @@ +/* + * Copyright 2000-2015 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.actions; import com.intellij.execution.console.ConsoleExecuteAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.LangDataKeys; +import com.intellij.util.Consumer; import com.intellij.xdebugger.impl.actions.handlers.XEvaluateInConsoleFromEditorActionHandler; import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl; import org.jetbrains.annotations.NotNull; @@ -32,12 +48,16 @@ class EvaluateInConsoleFromTreeAction extends XAddToWatchesAction { @Override protected void perform(XValueNodeImpl node, @NotNull String nodeName, AnActionEvent e) { - ConsoleExecuteAction action = getConsoleExecuteAction(e); + final ConsoleExecuteAction action = getConsoleExecuteAction(e); if (action != null) { - String expression = node.getValueContainer().getEvaluationExpression(); - if (expression != null) { - action.execute(null, expression, null); - } + node.getValueContainer().calculateEvaluationExpression().done(new Consumer() { + @Override + public void consume(String expression) { + if (expression != null) { + action.execute(null, expression, null); + } + } + }); } } } \ No newline at end of file diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XAddToWatchesAction.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XAddToWatchesAction.java index 211fddae40ea..3cf3114d430f 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XAddToWatchesAction.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XAddToWatchesAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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,11 +18,13 @@ package com.intellij.xdebugger.impl.ui.tree.actions; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.Consumer; import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XDebuggerManager; import com.intellij.xdebugger.impl.XDebugSessionImpl; import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl; import com.intellij.xdebugger.impl.frame.XWatchesView; +import com.intellij.xdebugger.impl.ui.DebuggerUIUtil; import com.intellij.xdebugger.impl.ui.XDebugSessionTab; import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl; import org.jetbrains.annotations.NotNull; @@ -33,17 +35,21 @@ import org.jetbrains.annotations.NotNull; class XAddToWatchesAction extends XDebuggerTreeActionBase { @Override protected boolean isEnabled(@NotNull final XValueNodeImpl node, @NotNull AnActionEvent e) { - return super.isEnabled(node, e) && node.getValueContainer().getEvaluationExpression() != null && getWatchesView(e) != null; + return super.isEnabled(node, e) && DebuggerUIUtil.hasEvaluationExpression(node.getValueContainer()) && getWatchesView(e) != null; } @Override protected void perform(final XValueNodeImpl node, @NotNull final String nodeName, final AnActionEvent e) { - XWatchesView watchesView = getWatchesView(e); + final XWatchesView watchesView = getWatchesView(e); if (watchesView != null) { - String expression = node.getValueContainer().getEvaluationExpression(); - if (!StringUtil.isEmpty(expression)) { - watchesView.addWatchExpression(XExpressionImpl.fromText(expression), -1, true); - } + node.getValueContainer().calculateEvaluationExpression().done(new Consumer() { + @Override + public void consume(String expression) { + if (!StringUtil.isEmpty(expression)) { + watchesView.addWatchExpression(XExpressionImpl.fromText(expression), -1, true); + } + } + }); } }