| /* |
| * 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); |
| } |
| } |
| } |
| } |