IDEA-139797 Default Theme doesn't allow to apply font size to evaluate expression...
[idea/community.git] / platform / xdebugger-impl / src / com / intellij / xdebugger / impl / ui / XDebuggerEditorBase.java
1 /*
2  * Copyright 2000-2015 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.xdebugger.impl.ui;
17
18 import com.intellij.ide.DataManager;
19 import com.intellij.lang.Language;
20 import com.intellij.openapi.actionSystem.AnAction;
21 import com.intellij.openapi.actionSystem.AnActionEvent;
22 import com.intellij.openapi.actionSystem.DataContext;
23 import com.intellij.openapi.actionSystem.DefaultActionGroup;
24 import com.intellij.openapi.editor.Document;
25 import com.intellij.openapi.editor.Editor;
26 import com.intellij.openapi.fileTypes.FileType;
27 import com.intellij.openapi.fileTypes.LanguageFileType;
28 import com.intellij.openapi.project.Project;
29 import com.intellij.openapi.ui.popup.JBPopupFactory;
30 import com.intellij.openapi.ui.popup.ListPopup;
31 import com.intellij.openapi.util.IconLoader;
32 import com.intellij.openapi.wm.IdeFocusManager;
33 import com.intellij.reference.SoftReference;
34 import com.intellij.ui.ClickListener;
35 import com.intellij.util.ui.JBUI;
36 import com.intellij.xdebugger.XDebuggerBundle;
37 import com.intellij.xdebugger.XExpression;
38 import com.intellij.xdebugger.XSourcePosition;
39 import com.intellij.xdebugger.evaluation.EvaluationMode;
40 import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider;
41 import com.intellij.xdebugger.impl.XDebuggerHistoryManager;
42 import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl;
43 import org.jetbrains.annotations.NonNls;
44 import org.jetbrains.annotations.NotNull;
45 import org.jetbrains.annotations.Nullable;
46
47 import javax.swing.*;
48 import java.awt.*;
49 import java.awt.event.MouseEvent;
50 import java.lang.ref.WeakReference;
51 import java.util.Collection;
52 import java.util.Collections;
53 import java.util.List;
54
55 /**
56  * @author nik
57  */
58 public abstract class XDebuggerEditorBase {
59   private final Project myProject;
60   private final XDebuggerEditorsProvider myDebuggerEditorsProvider;
61   @NotNull private final EvaluationMode myMode;
62   @Nullable private final String myHistoryId;
63   @Nullable private XSourcePosition mySourcePosition;
64   private int myHistoryIndex = -1;
65
66   private final JLabel myChooseFactory = new JLabel();
67   private WeakReference<ListPopup> myPopup;
68
69   protected XDebuggerEditorBase(final Project project,
70                                 @NotNull XDebuggerEditorsProvider debuggerEditorsProvider,
71                                 @NotNull EvaluationMode mode,
72                                 @Nullable @NonNls String historyId,
73                                 final @Nullable XSourcePosition sourcePosition) {
74     myProject = project;
75     myDebuggerEditorsProvider = debuggerEditorsProvider;
76     myMode = mode;
77     myHistoryId = historyId;
78     mySourcePosition = sourcePosition;
79
80     myChooseFactory.setToolTipText(XDebuggerBundle.message("xdebugger.evaluate.language.hint"));
81     myChooseFactory.setBorder(JBUI.Borders.empty(0, 3, 0, 3));
82     new ClickListener() {
83       @Override
84       public boolean onClick(@NotNull MouseEvent e, int clickCount) {
85         ListPopup oldPopup = SoftReference.dereference(myPopup);
86         if (oldPopup != null && !oldPopup.isDisposed()) {
87           oldPopup.cancel();
88           myPopup = null;
89           return true;
90         }
91         ListPopup popup = createLanguagePopup();
92         popup.showUnderneathOf(myChooseFactory);
93         myPopup = new WeakReference<ListPopup>(popup);
94         return true;
95       }
96     }.installOn(myChooseFactory);
97   }
98
99   private ListPopup createLanguagePopup() {
100     DefaultActionGroup actions = new DefaultActionGroup();
101     for (final Language language : getEditorsProvider().getSupportedLanguages(myProject, mySourcePosition)) {
102       //noinspection ConstantConditions
103       actions.add(new AnAction(language.getDisplayName(), null, language.getAssociatedFileType().getIcon()) {
104         @Override
105         public void actionPerformed(@NotNull AnActionEvent e) {
106           XExpression currentExpression = getExpression();
107           setExpression(new XExpressionImpl(currentExpression.getExpression(), language, currentExpression.getCustomInfo()));
108           requestFocusInEditor();
109         }
110       });
111     }
112
113     DataContext dataContext = DataManager.getInstance().getDataContext(getComponent());
114     return JBPopupFactory.getInstance().createActionGroupPopup("Choose language", actions, dataContext,
115                                                                JBPopupFactory.ActionSelectionAid.SPEEDSEARCH,
116                                                                false);
117   }
118
119   protected JPanel addChooseFactoryLabel(JComponent component, boolean top) {
120     JPanel panel = new JPanel(new BorderLayout());
121     panel.add(component, BorderLayout.CENTER);
122
123     JPanel factoryPanel = new JPanel(new BorderLayout());
124     factoryPanel.add(myChooseFactory, top ? BorderLayout.NORTH : BorderLayout.CENTER);
125     panel.add(factoryPanel, BorderLayout.WEST);
126     return panel;
127   }
128
129   public void setSourcePosition(@Nullable XSourcePosition sourcePosition) {
130     if (mySourcePosition != sourcePosition) {
131       mySourcePosition = sourcePosition;
132       setExpression(getExpression());
133     }
134   }
135
136   @NotNull
137   public EvaluationMode getMode() {
138     return myMode;
139   }
140
141   @Nullable
142   public abstract Editor getEditor();
143
144   public abstract JComponent getComponent();
145
146   protected abstract void doSetText(XExpression text);
147
148   public void setExpression(@Nullable XExpression text) {
149     if (text == null) {
150       text = getMode() == EvaluationMode.EXPRESSION ? XExpressionImpl.EMPTY_EXPRESSION : XExpressionImpl.EMPTY_CODE_FRAGMENT;
151     }
152     Language language = text.getLanguage();
153     if (language == null) {
154       if (mySourcePosition != null) {
155         language = getFileTypeLanguage(mySourcePosition.getFile().getFileType());
156       }
157       if (language == null) {
158         language = getFileTypeLanguage(getEditorsProvider().getFileType());
159       }
160     }
161     text = new XExpressionImpl(text.getExpression(), language, text.getCustomInfo(), getMode());
162
163     Collection<Language> languages = getEditorsProvider().getSupportedLanguages(myProject, mySourcePosition);
164     boolean many = languages.size() > 1;
165
166     if (language != null) {
167       myChooseFactory.setVisible(many);
168     }
169     myChooseFactory.setVisible(myChooseFactory.isVisible() || many);
170     //myChooseFactory.setEnabled(many && languages.contains(language));
171
172     if (language != null && language.getAssociatedFileType() != null) {
173       Icon icon = language.getAssociatedFileType().getIcon();
174       myChooseFactory.setIcon(icon);
175       myChooseFactory.setDisabledIcon(IconLoader.getDisabledIcon(icon));
176     }
177
178     doSetText(text);
179   }
180
181   @Nullable
182   public static Language getFileTypeLanguage(@Nullable FileType fileType) {
183     if (fileType instanceof LanguageFileType) {
184       return ((LanguageFileType)fileType).getLanguage();
185     }
186     return null;
187   }
188
189   public abstract XExpression getExpression();
190
191   @Nullable
192   public abstract JComponent getPreferredFocusedComponent();
193
194   public void requestFocusInEditor() {
195     JComponent preferredFocusedComponent = getPreferredFocusedComponent();
196     if (preferredFocusedComponent != null) {
197       IdeFocusManager.getInstance(myProject).requestFocus(preferredFocusedComponent, true);
198     }
199   }
200
201   public abstract void selectAll();
202
203   protected void onHistoryChanged() {
204   }
205
206   public List<XExpression> getRecentExpressions() {
207     if (myHistoryId != null) {
208       return XDebuggerHistoryManager.getInstance(myProject).getRecentExpressions(myHistoryId);
209     }
210     return Collections.emptyList();
211   }
212
213   public void saveTextInHistory() {
214     saveTextInHistory(getExpression());
215   }
216
217   private void saveTextInHistory(final XExpression text) {
218     if (myHistoryId != null) {
219       boolean update = XDebuggerHistoryManager.getInstance(myProject).addRecentExpression(myHistoryId, text);
220       myHistoryIndex = -1; //meaning not from the history list
221       if (update) {
222         onHistoryChanged();
223       }
224     }
225   }
226
227   public XDebuggerEditorsProvider getEditorsProvider() {
228     return myDebuggerEditorsProvider;
229   }
230
231   public Project getProject() {
232     return myProject;
233   }
234
235   protected Document createDocument(final XExpression text) {
236     return getEditorsProvider().createDocument(getProject(), text, mySourcePosition, myMode);
237   }
238
239   public boolean canGoBackward() {
240     return myHistoryIndex < getRecentExpressions().size()-1;
241   }
242
243   public boolean canGoForward() {
244     return myHistoryIndex > 0;
245   }
246
247   public void goBackward() {
248     final List<XExpression> expressions = getRecentExpressions();
249     if (myHistoryIndex < expressions.size() - 1) {
250       myHistoryIndex++;
251       setExpression(expressions.get(myHistoryIndex));
252     }
253   }
254
255   public void goForward() {
256     final List<XExpression> expressions = getRecentExpressions();
257     if (myHistoryIndex > 0) {
258       myHistoryIndex--;
259       setExpression(expressions.get(myHistoryIndex));
260     }
261   }
262 }