diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/PopFrameAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/PopFrameAction.java index 347f55087a0a..d15c3b5994d2 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/PopFrameAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/PopFrameAction.java @@ -23,7 +23,6 @@ import com.intellij.CommonBundle; import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.SourcePosition; import com.intellij.debugger.engine.DebugProcessImpl; -import com.intellij.debugger.engine.JavaDebugProcess; import com.intellij.debugger.engine.JavaStackFrame; import com.intellij.debugger.engine.SuspendContextImpl; import com.intellij.debugger.impl.DebuggerContextImpl; @@ -79,85 +78,73 @@ public class PopFrameAction extends DebuggerAction { if(debugProcess == null) { return; } - if (DebuggerSettings.getInstance().CHECK_FINALLY_ON_POP_FRAME) { + + if (!DebuggerSettings.EVALUATE_FINALLY_NEVER.equals(DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME)) { List statements = getFinallyStatements(debuggerContext.getSourcePosition()); if (!statements.isEmpty()) { StringBuilder sb = new StringBuilder(); for (PsiStatement statement : statements) { sb.append("\n").append(statement.getText()); } - int res = MessageDialogBuilder - .yesNoCancel(UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)), - DebuggerBundle.message("warning.finally.block.detected") + sb) - .project(project) - .icon(Messages.getWarningIcon()) - .yesText(DebuggerBundle.message("button.drop.anyway")) - .noText(DebuggerBundle.message("button.execute.finally")) - .cancelText(CommonBundle.message("button.cancel")) - .doNotAsk( - new DialogWrapper.DoNotAskOption() { - @Override - public boolean isToBeShown() { - return DebuggerSettings.getInstance().CHECK_FINALLY_ON_POP_FRAME; - } - - @Override - public void setToBeShown(boolean value, int exitCode) { - DebuggerSettings.getInstance().CHECK_FINALLY_ON_POP_FRAME = value; - } - - @Override - public boolean canBeHidden() { - return true; - } - - @Override - public boolean shouldSaveOptionsOnCancel() { - return false; - } - - @NotNull - @Override - public String getDoNotShowMessage() { - return CommonBundle.message("dialog.options.do.not.show"); - } - }) - .show(); - - switch (res) { - case Messages.CANCEL : return; - case Messages.OK : break; // drop frame - case Messages.NO : // evaluate - JavaDebugProcess process = debugProcess.getXdebugProcess(); - XExpressionImpl expression = XExpressionImpl.fromText(sb.toString()); - expression = XExpressionImpl.changeMode(expression, EvaluationMode.CODE_FRAGMENT); - XDebuggerEvaluator evaluator = stackFrame.getEvaluator(); - if (evaluator != null) { - evaluator.evaluate(expression, new XDebuggerEvaluator.XEvaluationCallback() { + if (DebuggerSettings.EVALUATE_FINALLY_ALWAYS.equals(DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME)) { + evaluateAndPop(project, stackFrame, debuggerContext, debugProcess, sb); + return; + } + else { + int res = MessageDialogBuilder + .yesNoCancel(UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)), + DebuggerBundle.message("warning.finally.block.detected") + sb) + .project(project) + .icon(Messages.getWarningIcon()) + .yesText(DebuggerBundle.message("button.execute.finally")) + .noText(DebuggerBundle.message("button.drop.anyway")) + .cancelText(CommonBundle.message("button.cancel")) + .doNotAsk( + new DialogWrapper.DoNotAskOption() { @Override - public void evaluated(@NotNull XValue result) { - debugProcess.getManagerThread().schedule(debugProcess.createPopFrameCommand(debuggerContext, stackFrame.getStackFrameProxy())); + public boolean isToBeShown() { + return !DebuggerSettings.EVALUATE_FINALLY_ALWAYS.equals(DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME) && + !DebuggerSettings.EVALUATE_FINALLY_NEVER.equals(DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME); } @Override - public void errorOccurred(@NotNull final String errorMessage) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - Messages - .showMessageDialog(project, DebuggerBundle.message("error.executing.finally", errorMessage), - UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)), Messages.getErrorIcon()); - } - }); + public void setToBeShown(boolean value, int exitCode) { + if (!value) { + DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME = + exitCode == Messages.YES ? DebuggerSettings.EVALUATE_FINALLY_ALWAYS : DebuggerSettings.EVALUATE_FINALLY_NEVER; + } + else { + DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME = DebuggerSettings.EVALUATE_FINALLY_ASK; + } } - }, stackFrame.getSourcePosition()); + + @Override + public boolean canBeHidden() { + return true; + } + + @Override + public boolean shouldSaveOptionsOnCancel() { + return false; + } + + @NotNull + @Override + public String getDoNotShowMessage() { + return CommonBundle.message("dialog.options.do.not.show"); + } + }) + .show(); + + switch (res) { + case Messages.CANCEL: return; - } - else { - Messages.showMessageDialog(project, XDebuggerBundle.message("xdebugger.evaluate.stack.frame.has.not.evaluator"), - UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)), - Messages.getErrorIcon()); - } + case Messages.NO: + break; + case Messages.YES: // evaluate finally + evaluateAndPop(project, stackFrame, debuggerContext, debugProcess, sb); + return; + } } } } @@ -173,6 +160,40 @@ public class PopFrameAction extends DebuggerAction { } } + private static void evaluateAndPop(final Project project, + final JavaStackFrame stackFrame, + final DebuggerContextImpl debuggerContext, + final DebugProcessImpl debugProcess, StringBuilder sb) { + XExpressionImpl expression = XExpressionImpl.fromText(sb.toString()); + expression = XExpressionImpl.changeMode(expression, EvaluationMode.CODE_FRAGMENT); + XDebuggerEvaluator evaluator = stackFrame.getEvaluator(); + if (evaluator != null) { + evaluator.evaluate(expression, new XDebuggerEvaluator.XEvaluationCallback() { + @Override + public void evaluated(@NotNull XValue result) { + debugProcess.getManagerThread().schedule(debugProcess.createPopFrameCommand(debuggerContext, stackFrame.getStackFrameProxy())); + } + + @Override + public void errorOccurred(@NotNull final String errorMessage) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + Messages + .showMessageDialog(project, DebuggerBundle.message("error.executing.finally", errorMessage), + UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)), Messages.getErrorIcon()); + } + }); + } + }, stackFrame.getSourcePosition()); + } + else { + Messages.showMessageDialog(project, XDebuggerBundle.message("xdebugger.evaluate.stack.frame.has.not.evaluator"), + UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)), + Messages.getErrorIcon()); + } + } + private static List getFinallyStatements(SourcePosition position) { List res = new ArrayList(); PsiElement element = position.getFile().findElementAt(position.getOffset()); diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSettings.java b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSettings.java index d18b0eb15fca..2855ab4dfc1f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSettings.java +++ b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSettings.java @@ -20,6 +20,7 @@ import com.intellij.openapi.components.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.classFilter.ClassFilter; import com.intellij.util.containers.hash.LinkedHashMap; import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters; @@ -55,6 +56,10 @@ public class DebuggerSettings implements Cloneable, PersistentStateComponent { private JCheckBox myCbSkipClassLoaders; private ClassFilterEditor mySteppingFilterEditor; private JCheckBox myCbSkipSimpleGetters; - private JCheckBox myCbCheckFinallyOnPopFrame; + private JRadioButton myRbEvaluateFinallyAlways; + private JRadioButton myRbEvaluateFinallyNever; + private JRadioButton myRbEvaluateFinallyAsk; @Override public void reset(@NotNull DebuggerSettings settings) { @@ -47,7 +50,15 @@ class DebuggerSteppingConfigurable implements ConfigurableUi { mySteppingFilterEditor.setFilters(settings.getSteppingFilters()); mySteppingFilterEditor.setEnabled(settings.TRACING_FILTERS_ENABLED); - myCbCheckFinallyOnPopFrame.setSelected(settings.CHECK_FINALLY_ON_POP_FRAME); + if (DebuggerSettings.EVALUATE_FINALLY_ALWAYS.equals(settings.EVALUATE_FINALLY_ON_POP_FRAME)) { + myRbEvaluateFinallyAlways.setSelected(true); + } + else if (DebuggerSettings.EVALUATE_FINALLY_NEVER.equals(settings.EVALUATE_FINALLY_ON_POP_FRAME)) { + myRbEvaluateFinallyNever.setSelected(true); + } + else { + myRbEvaluateFinallyAsk.setSelected(true); + } } @Override @@ -62,7 +73,15 @@ class DebuggerSteppingConfigurable implements ConfigurableUi { settings.SKIP_CLASSLOADERS = myCbSkipClassLoaders.isSelected(); settings.TRACING_FILTERS_ENABLED = myCbStepInfoFiltersEnabled.isSelected(); - settings.CHECK_FINALLY_ON_POP_FRAME = myCbCheckFinallyOnPopFrame.isSelected(); + if (myRbEvaluateFinallyAlways.isSelected()) { + settings.EVALUATE_FINALLY_ON_POP_FRAME = DebuggerSettings.EVALUATE_FINALLY_ALWAYS; + } + else if (myRbEvaluateFinallyNever.isSelected()) { + settings.EVALUATE_FINALLY_ON_POP_FRAME = DebuggerSettings.EVALUATE_FINALLY_NEVER; + } + else { + settings.EVALUATE_FINALLY_ON_POP_FRAME = DebuggerSettings.EVALUATE_FINALLY_ASK; + } mySteppingFilterEditor.stopEditing(); settings.setSteppingFilters(mySteppingFilterEditor.getFilters()); @@ -83,13 +102,11 @@ class DebuggerSteppingConfigurable implements ConfigurableUi { myCbSkipConstructors = new JCheckBox(DebuggerBundle.message("label.debugger.general.configurable.skip.constructors")); myCbSkipClassLoaders = new JCheckBox(DebuggerBundle.message("label.debugger.general.configurable.skip.classLoaders")); myCbSkipSimpleGetters = new JCheckBox(DebuggerBundle.message("label.debugger.general.configurable.skip.simple.getters")); - myCbCheckFinallyOnPopFrame = new JCheckBox(DebuggerBundle.message("label.debugger.general.configurable.check.finally.on.pop")); myCbStepInfoFiltersEnabled = new JCheckBox(DebuggerBundle.message("label.debugger.general.configurable.step.filters.list.header")); panel.add(myCbSkipSyntheticMethods, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0),0, 0)); panel.add(myCbSkipConstructors, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0),0, 0)); panel.add(myCbSkipClassLoaders, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0),0, 0)); panel.add(myCbSkipSimpleGetters, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0),0, 0)); - panel.add(myCbCheckFinallyOnPopFrame, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0),0, 0)); panel.add(myCbStepInfoFiltersEnabled, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(8, 0, 0, 0),0, 0)); mySteppingFilterEditor = new ClassFilterEditor(JavaDebuggerSupport.getContextProjectForEditorFieldsInDebuggerConfigurables(), null, "reference.viewBreakpoints.classFilters.newPattern"); @@ -101,6 +118,33 @@ class DebuggerSteppingConfigurable implements ConfigurableUi { mySteppingFilterEditor.setEnabled(myCbStepInfoFiltersEnabled.isSelected()); } }); + + myRbEvaluateFinallyAlways = new JRadioButton(DebuggerBundle.message("label.debugger.general.configurable.evaluate.finally.always")); + myRbEvaluateFinallyNever = new JRadioButton(DebuggerBundle.message("label.debugger.general.configurable.evaluate.finally.never")); + myRbEvaluateFinallyAsk = new JRadioButton(DebuggerBundle.message("label.debugger.general.configurable.evaluate.finally.ask")); + + int cbLeftOffset = 0; + final Border border = myCbSkipSimpleGetters.getBorder(); + if (border != null) { + final Insets insets = border.getBorderInsets(myCbSkipSimpleGetters); + if (insets != null) { + cbLeftOffset = insets.left; + } + } + + final ButtonGroup group = new ButtonGroup(); + group.add(myRbEvaluateFinallyAlways); + group.add(myRbEvaluateFinallyNever); + group.add(myRbEvaluateFinallyAsk); + final Box box = Box.createHorizontalBox(); + box.add(myRbEvaluateFinallyAlways); + box.add(myRbEvaluateFinallyNever); + box.add(myRbEvaluateFinallyAsk); + final JPanel evalFinallyPanel = new JPanel(new BorderLayout()); + evalFinallyPanel.add(box, BorderLayout.CENTER); + evalFinallyPanel.add(new JLabel(DebuggerBundle.message("label.debugger.general.configurable.evaluate.finally.on.pop")), BorderLayout.WEST); + panel.add(evalFinallyPanel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(4, cbLeftOffset, 0, 0), 0, 0)); + return panel; } } \ No newline at end of file diff --git a/resources-en/src/messages/DebuggerBundle.properties b/resources-en/src/messages/DebuggerBundle.properties index 5a51808e9929..18a0df9dcc8d 100644 --- a/resources-en/src/messages/DebuggerBundle.properties +++ b/resources-en/src/messages/DebuggerBundle.properties @@ -225,7 +225,10 @@ label.debugger.general.configurable.skip.constructors=Skip &constructors label.debugger.general.configurable.skip.classLoaders=Skip class l&oaders label.debugger.general.configurable.skip.simple.getters=Skip simple &getters label.debugger.general.configurable.step.filters.list.header=Do not step &into the classes -label.debugger.general.configurable.check.finally.on.pop=Ask if in finally block on pop frame +label.debugger.general.configurable.evaluate.finally.on.pop=Evaluate finally blocks on pop frame: +label.debugger.general.configurable.evaluate.finally.always=&Always +label.debugger.general.configurable.evaluate.finally.never=N&ever +label.debugger.general.configurable.evaluate.finally.ask=As&k label.threads.view.configurable.show.source.file.name=Show source file name label.threads.view.configurable.show.class.name=Show class name label.threads.view.configurable.show.line.number=Show &line number