81ac51d233379bd4db93f85e94a29f420a3ad692
[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   public JComponent getEditorComponent() {
147     return getComponent();
148   }
149
150   protected abstract void doSetText(XExpression text);
151
152   public void setExpression(@Nullable XExpression text) {
153     if (text == null) {
154       text = getMode() == EvaluationMode.EXPRESSION ? XExpressionImpl.EMPTY_EXPRESSION : XExpressionImpl.EMPTY_CODE_FRAGMENT;
155     }
156     Language language = text.getLanguage();
157     if (language == null) {
158       if (mySourcePosition != null) {
159         language = getFileTypeLanguage(mySourcePosition.getFile().getFileType());
160       }
161       if (language == null) {
162         language = getFileTypeLanguage(getEditorsProvider().getFileType());
163       }
164     }
165     text = new XExpressionImpl(text.getExpression(), language, text.getCustomInfo(), getMode());
166
167     Collection<Language> languages = getEditorsProvider().getSupportedLanguages(myProject, mySourcePosition);
168     boolean many = languages.size() > 1;
169
170     if (language != null) {
171       myChooseFactory.setVisible(many);
172     }
173     myChooseFactory.setVisible(myChooseFactory.isVisible() || many);
174     //myChooseFactory.setEnabled(many && languages.contains(language));
175
176     if (language != null && language.getAssociatedFileType() != null) {
177       Icon icon = language.getAssociatedFileType().getIcon();
178       myChooseFactory.setIcon(icon);
179       myChooseFactory.setDisabledIcon(IconLoader.getDisabledIcon(icon));
180     }
181
182     doSetText(text);
183   }
184
185   @Nullable
186   public static Language getFileTypeLanguage(@Nullable FileType fileType) {
187     if (fileType instanceof LanguageFileType) {
188       return ((LanguageFileType)fileType).getLanguage();
189     }
190     return null;
191   }
192
193   public abstract XExpression getExpression();
194
195   @Nullable
196   public abstract JComponent getPreferredFocusedComponent();
197
198   public void requestFocusInEditor() {
199     JComponent preferredFocusedComponent = getPreferredFocusedComponent();
200     if (preferredFocusedComponent != null) {
201       IdeFocusManager.getInstance(myProject).requestFocus(preferredFocusedComponent, true);
202     }
203   }
204
205   public abstract void selectAll();
206
207   protected void onHistoryChanged() {
208   }
209
210   public List<XExpression> getRecentExpressions() {
211     if (myHistoryId != null) {
212       return XDebuggerHistoryManager.getInstance(myProject).getRecentExpressions(myHistoryId);
213     }
214     return Collections.emptyList();
215   }
216
217   public void saveTextInHistory() {
218     saveTextInHistory(getExpression());
219   }
220
221   private void saveTextInHistory(final XExpression text) {
222     if (myHistoryId != null) {
223       boolean update = XDebuggerHistoryManager.getInstance(myProject).addRecentExpression(myHistoryId, text);
224       myHistoryIndex = -1; //meaning not from the history list
225       if (update) {
226         onHistoryChanged();
227       }
228     }
229   }
230
231   public XDebuggerEditorsProvider getEditorsProvider() {
232     return myDebuggerEditorsProvider;
233   }
234
235   public Project getProject() {
236     return myProject;
237   }
238
239   protected Document createDocument(final XExpression text) {
240     return getEditorsProvider().createDocument(getProject(), text, mySourcePosition, myMode);
241   }
242
243   public boolean canGoBackward() {
244     return myHistoryIndex < getRecentExpressions().size()-1;
245   }
246
247   public boolean canGoForward() {
248     return myHistoryIndex > 0;
249   }
250
251   public void goBackward() {
252     final List<XExpression> expressions = getRecentExpressions();
253     if (myHistoryIndex < expressions.size() - 1) {
254       myHistoryIndex++;
255       setExpression(expressions.get(myHistoryIndex));
256     }
257   }
258
259   public void goForward() {
260     final List<XExpression> expressions = getRecentExpressions();
261     if (myHistoryIndex > 0) {
262       myHistoryIndex--;
263       setExpression(expressions.get(myHistoryIndex));
264     }
265   }
266 }