blob: 5a6d19de32349c7d664d513c1c4c6c6421a882e4 [file] [log] [blame]
/*
* Copyright 2000-2014 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.evaluate;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CustomShortcutSet;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.xdebugger.*;
import com.intellij.xdebugger.evaluation.EvaluationMode;
import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider;
import com.intellij.xdebugger.evaluation.XDebuggerEvaluator;
import com.intellij.xdebugger.impl.XDebugSessionImpl;
import com.intellij.xdebugger.impl.XDebuggerUtilImpl;
import com.intellij.xdebugger.impl.actions.XDebuggerActions;
import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl;
import com.intellij.xdebugger.impl.settings.XDebuggerSettingsManager;
import com.intellij.xdebugger.impl.ui.XDebugSessionTab;
import com.intellij.xdebugger.impl.ui.XDebuggerEditorBase;
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree;
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTreePanel;
import com.intellij.xdebugger.impl.ui.tree.nodes.EvaluatingExpressionRootNode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.tree.TreeNode;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
/**
* @author nik
*/
public class XDebuggerEvaluationDialog extends DialogWrapper {
private final JPanel myMainPanel;
private final JPanel myResultPanel;
private final XDebuggerTreePanel myTreePanel;
private EvaluationInputComponent myInputComponent;
private final XDebugSession mySession;
private final XDebuggerEditorsProvider myEditorsProvider;
private EvaluationMode myMode;
private final XSourcePosition mySourcePosition;
private final SwitchModeAction mySwitchModeAction;
private final boolean myIsCodeFragmentEvaluationSupported;
public XDebuggerEvaluationDialog(@NotNull XDebugSession session,
@NotNull XDebuggerEditorsProvider editorsProvider,
@NotNull XDebuggerEvaluator evaluator,
@NotNull XExpression text,
@Nullable XSourcePosition sourcePosition) {
super(session.getProject(), true);
mySession = session;
myEditorsProvider = editorsProvider;
mySourcePosition = sourcePosition;
setModal(false);
setOKButtonText(XDebuggerBundle.message("xdebugger.button.evaluate"));
setCancelButtonText(XDebuggerBundle.message("xdebugger.evaluate.dialog.close"));
mySession.addSessionListener(new XDebugSessionAdapter() {
@Override
public void sessionStopped() {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
close(CANCEL_EXIT_CODE);
}
});
}
@Override
public void stackFrameChanged() {
updateSourcePosition();
}
@Override
public void sessionPaused() {
updateSourcePosition();
}
}, myDisposable);
myTreePanel = new XDebuggerTreePanel(session.getProject(), editorsProvider, myDisposable, sourcePosition, XDebuggerActions.EVALUATE_DIALOG_TREE_POPUP_GROUP,
((XDebugSessionImpl)session).getValueMarkers());
myResultPanel = new JPanel(new BorderLayout());
myResultPanel.add(new JLabel(XDebuggerBundle.message("xdebugger.evaluate.label.result")), BorderLayout.NORTH);
myResultPanel.add(myTreePanel.getMainPanel(), BorderLayout.CENTER);
myMainPanel = new JPanel(new BorderLayout());
mySwitchModeAction = new SwitchModeAction();
new AnAction() {
@Override
public void actionPerformed(AnActionEvent e) {
IdeFocusManager.getInstance(mySession.getProject()).requestFocus(myTreePanel.getTree(), true);
}
}.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.ALT_DOWN_MASK)), getRootPane(),
myDisposable);
myTreePanel.getTree().expandNodesOnLoad(new Condition<TreeNode>() {
@Override
public boolean value(TreeNode node) {
return node.getParent() instanceof EvaluatingExpressionRootNode;
}
});
EvaluationMode mode = XDebuggerSettingsManager.getInstanceImpl().getGeneralSettings().getEvaluationDialogMode();
myIsCodeFragmentEvaluationSupported = evaluator.isCodeFragmentEvaluationSupported();
if (mode == EvaluationMode.CODE_FRAGMENT && !myIsCodeFragmentEvaluationSupported) {
mode = EvaluationMode.EXPRESSION;
}
if (mode == EvaluationMode.EXPRESSION) {
text = new XExpressionImpl(StringUtil.replace(text.getExpression(), "\n", " "), text.getLanguage(), text.getCustomInfo());
}
switchToMode(mode, text);
init();
}
private void updateSourcePosition() {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
getInputEditor().setSourcePosition(mySession.getCurrentPosition());
}
});
}
@Override
protected void doOKAction() {
evaluate();
}
@Override
protected void createDefaultActions() {
super.createDefaultActions();
myOKAction = new OkAction(){
@Override
public void actionPerformed(ActionEvent e) {
super.actionPerformed(e);
if (myMode == EvaluationMode.EXPRESSION && ((e.getModifiers() & InputEvent.CTRL_MASK) != 0)) {
// add to watches
XExpression expression = getInputEditor().getExpression();
if (!XDebuggerUtilImpl.isEmptyExpression(expression)) {
XDebugSessionTab tab = ((XDebugSessionImpl)mySession).getSessionTab();
if (tab != null) {
tab.getWatchesView().addWatchExpression(expression, -1, true);
requestFocusInEditor();
}
}
}
}
};
}
@NotNull
@Override
protected Action[] createActions() {
if (myIsCodeFragmentEvaluationSupported) {
return new Action[]{getOKAction(), mySwitchModeAction, getCancelAction()};
}
return super.createActions();
}
@Override
protected String getHelpId() {
return "debugging.debugMenu.evaluate";
}
@Override
protected JButton createJButtonForAction(Action action) {
final JButton button = super.createJButtonForAction(action);
if (action == mySwitchModeAction) {
int width1 = new JButton(getSwitchButtonText(EvaluationMode.EXPRESSION)).getPreferredSize().width;
int width2 = new JButton(getSwitchButtonText(EvaluationMode.CODE_FRAGMENT)).getPreferredSize().width;
final Dimension size = new Dimension(Math.max(width1, width2), button.getPreferredSize().height);
button.setMinimumSize(size);
button.setPreferredSize(size);
}
return button;
}
public XExpression getExpression() {
return getInputEditor().getExpression();
}
private static String getSwitchButtonText(EvaluationMode mode) {
return mode != EvaluationMode.EXPRESSION
? XDebuggerBundle.message("button.text.expression.mode")
: XDebuggerBundle.message("button.text.code.fragment.mode");
}
private void switchToMode(EvaluationMode mode, XExpression text) {
if (myMode == mode) return;
XDebuggerSettingsManager.getInstanceImpl().getGeneralSettings().setEvaluationDialogMode(mode);
myMode = mode;
myInputComponent = createInputComponent(mode, text);
myMainPanel.removeAll();
myInputComponent.addComponent(myMainPanel, myResultPanel);
setTitle(myInputComponent.getTitle());
mySwitchModeAction.putValue(Action.NAME, getSwitchButtonText(mode));
requestFocusInEditor();
}
private void requestFocusInEditor() {
JComponent preferredFocusedComponent = getInputEditor().getPreferredFocusedComponent();
if (preferredFocusedComponent != null) {
IdeFocusManager.getInstance(mySession.getProject()).requestFocus(preferredFocusedComponent, true);
}
}
private XDebuggerEditorBase getInputEditor() {
return myInputComponent.getInputEditor();
}
private EvaluationInputComponent createInputComponent(EvaluationMode mode, XExpression text) {
final Project project = mySession.getProject();
text = XExpressionImpl.changeMode(text, mode);
if (mode == EvaluationMode.EXPRESSION) {
return new ExpressionInputComponent(project, myEditorsProvider, mySourcePosition, text);
}
else {
return new CodeFragmentInputComponent(project, myEditorsProvider, mySourcePosition, text, myDisposable);
}
}
private void evaluate() {
final XDebuggerEditorBase inputEditor = getInputEditor();
int offset = -1;
//try to save caret position
Editor editor = inputEditor.getEditor();
if (editor != null) {
offset = editor.getCaretModel().getOffset();
}
final XDebuggerTree tree = myTreePanel.getTree();
tree.markNodesObsolete();
tree.setRoot(new EvaluatingExpressionRootNode(this, tree), false);
myResultPanel.invalidate();
//editor is already changed
editor = inputEditor.getEditor();
//selectAll puts focus back
inputEditor.selectAll();
//try to restore caret position and clear selection
if (offset >= 0 && editor != null) {
offset = Math.min(editor.getDocument().getTextLength(), offset);
editor.getCaretModel().moveToOffset(offset);
editor.getSelectionModel().setSelection(offset, offset);
}
}
@Override
protected String getDimensionServiceKey() {
return "#xdebugger.evaluate";
}
@Override
protected JComponent createCenterPanel() {
return myMainPanel;
}
public void startEvaluation(@NotNull XDebuggerEvaluator.XEvaluationCallback evaluationCallback) {
final XDebuggerEditorBase inputEditor = getInputEditor();
inputEditor.saveTextInHistory();
XExpression expression = inputEditor.getExpression();
XDebuggerEvaluator evaluator = mySession.getDebugProcess().getEvaluator();
if (evaluator == null) {
evaluationCallback.errorOccurred(XDebuggerBundle.message("xdebugger.evaluate.stack.frame.has.not.evaluator"));
}
else {
evaluator.evaluate(expression, evaluationCallback, null);
}
}
@Override
public JComponent getPreferredFocusedComponent() {
return getInputEditor().getPreferredFocusedComponent();
}
private class SwitchModeAction extends AbstractAction {
@Override
public void actionPerformed(ActionEvent e) {
XExpression text = getInputEditor().getExpression();
if (myMode == EvaluationMode.EXPRESSION) {
switchToMode(EvaluationMode.CODE_FRAGMENT, text);
}
else {
if (text.getExpression().indexOf('\n') != -1) text = XExpressionImpl.EMPTY_EXPRESSION;
switchToMode(EvaluationMode.EXPRESSION, text);
}
}
}
}