use LanguageUtil
[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.lang.LanguageUtil;
21 import com.intellij.openapi.actionSystem.AnAction;
22 import com.intellij.openapi.actionSystem.AnActionEvent;
23 import com.intellij.openapi.actionSystem.DataContext;
24 import com.intellij.openapi.actionSystem.DefaultActionGroup;
25 import com.intellij.openapi.editor.Document;
26 import com.intellij.openapi.editor.Editor;
27 import com.intellij.openapi.project.Project;
28 import com.intellij.openapi.ui.popup.JBPopupFactory;
29 import com.intellij.openapi.ui.popup.ListPopup;
30 import com.intellij.openapi.util.IconLoader;
31 import com.intellij.openapi.wm.IdeFocusManager;
32 import com.intellij.reference.SoftReference;
33 import com.intellij.ui.ClickListener;
34 import com.intellij.util.ui.JBUI;
35 import com.intellij.xdebugger.XDebuggerBundle;
36 import com.intellij.xdebugger.XExpression;
37 import com.intellij.xdebugger.XSourcePosition;
38 import com.intellij.xdebugger.evaluation.EvaluationMode;
39 import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider;
40 import com.intellij.xdebugger.impl.XDebuggerHistoryManager;
41 import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl;
42 import org.jetbrains.annotations.NonNls;
43 import org.jetbrains.annotations.NotNull;
44 import org.jetbrains.annotations.Nullable;
45
46 import javax.swing.*;
47 import java.awt.*;
48 import java.awt.event.MouseEvent;
49 import java.lang.ref.WeakReference;
50 import java.util.Collection;
51 import java.util.Collections;
52 import java.util.List;
53
54 /**
55  * @author nik
56  */
57 public abstract class XDebuggerEditorBase {
58   private final Project myProject;
59   private final XDebuggerEditorsProvider myDebuggerEditorsProvider;
60   @NotNull private final EvaluationMode myMode;
61   @Nullable private final String myHistoryId;
62   @Nullable private XSourcePosition mySourcePosition;
63   private int myHistoryIndex = -1;
64
65   private final JLabel myChooseFactory = new JLabel();
66   private WeakReference<ListPopup> myPopup;
67
68   protected XDebuggerEditorBase(final Project project,
69                                 @NotNull XDebuggerEditorsProvider debuggerEditorsProvider,
70                                 @NotNull EvaluationMode mode,
71                                 @Nullable @NonNls String historyId,
72                                 final @Nullable XSourcePosition sourcePosition) {
73     myProject = project;
74     myDebuggerEditorsProvider = debuggerEditorsProvider;
75     myMode = mode;
76     myHistoryId = historyId;
77     mySourcePosition = sourcePosition;
78
79     myChooseFactory.setToolTipText(XDebuggerBundle.message("xdebugger.evaluate.language.hint"));
80     myChooseFactory.setBorder(JBUI.Borders.empty(0, 3, 0, 3));
81     new ClickListener() {
82       @Override
83       public boolean onClick(@NotNull MouseEvent e, int clickCount) {
84         ListPopup oldPopup = SoftReference.dereference(myPopup);
85         if (oldPopup != null && !oldPopup.isDisposed()) {
86           oldPopup.cancel();
87           myPopup = null;
88           return true;
89         }
90         ListPopup popup = createLanguagePopup();
91         popup.showUnderneathOf(myChooseFactory);
92         myPopup = new WeakReference<ListPopup>(popup);
93         return true;
94       }
95     }.installOn(myChooseFactory);
96   }
97
98   private ListPopup createLanguagePopup() {
99     DefaultActionGroup actions = new DefaultActionGroup();
100     for (final Language language : getEditorsProvider().getSupportedLanguages(myProject, mySourcePosition)) {
101       //noinspection ConstantConditions
102       actions.add(new AnAction(language.getDisplayName(), null, language.getAssociatedFileType().getIcon()) {
103         @Override
104         public void actionPerformed(@NotNull AnActionEvent e) {
105           XExpression currentExpression = getExpression();
106           setExpression(new XExpressionImpl(currentExpression.getExpression(), language, currentExpression.getCustomInfo()));
107           requestFocusInEditor();
108         }
109       });
110     }
111
112     DataContext dataContext = DataManager.getInstance().getDataContext(getComponent());
113     return JBPopupFactory.getInstance().createActionGroupPopup("Choose language", actions, dataContext,
114                                                                JBPopupFactory.ActionSelectionAid.SPEEDSEARCH,
115                                                                false);
116   }
117
118   protected JPanel addChooseFactoryLabel(JComponent component, boolean top) {
119     JPanel panel = new JPanel(new BorderLayout());
120     panel.add(component, BorderLayout.CENTER);
121
122     JPanel factoryPanel = new JPanel(new BorderLayout());
123     factoryPanel.add(myChooseFactory, top ? BorderLayout.NORTH : BorderLayout.CENTER);
124     panel.add(factoryPanel, BorderLayout.WEST);
125     return panel;
126   }
127
128   public void setSourcePosition(@Nullable XSourcePosition sourcePosition) {
129     if (mySourcePosition != sourcePosition) {
130       mySourcePosition = sourcePosition;
131       setExpression(getExpression());
132     }
133   }
134
135   @NotNull
136   public EvaluationMode getMode() {
137     return myMode;
138   }
139
140   @Nullable
141   public abstract Editor getEditor();
142
143   public abstract JComponent getComponent();
144
145   public JComponent getEditorComponent() {
146     return getComponent();
147   }
148
149   protected abstract void doSetText(XExpression text);
150
151   public void setExpression(@Nullable XExpression text) {
152     if (text == null) {
153       text = getMode() == EvaluationMode.EXPRESSION ? XExpressionImpl.EMPTY_EXPRESSION : XExpressionImpl.EMPTY_CODE_FRAGMENT;
154     }
155     Language language = text.getLanguage();
156     if (language == null) {
157       if (mySourcePosition != null) {
158         language = LanguageUtil.getFileLanguage(mySourcePosition.getFile());
159       }
160       if (language == null) {
161         language = LanguageUtil.getFileTypeLanguage(getEditorsProvider().getFileType());
162       }
163     }
164     text = new XExpressionImpl(text.getExpression(), language, text.getCustomInfo(), getMode());
165
166     Collection<Language> languages = getEditorsProvider().getSupportedLanguages(myProject, mySourcePosition);
167     boolean many = languages.size() > 1;
168
169     if (language != null) {
170       myChooseFactory.setVisible(many);
171     }
172     myChooseFactory.setVisible(myChooseFactory.isVisible() || many);
173     //myChooseFactory.setEnabled(many && languages.contains(language));
174
175     if (language != null && language.getAssociatedFileType() != null) {
176       Icon icon = language.getAssociatedFileType().getIcon();
177       myChooseFactory.setIcon(icon);
178       myChooseFactory.setDisabledIcon(IconLoader.getDisabledIcon(icon));
179     }
180
181     doSetText(text);
182   }
183
184   public abstract XExpression getExpression();
185
186   @Nullable
187   public abstract JComponent getPreferredFocusedComponent();
188
189   public void requestFocusInEditor() {
190     JComponent preferredFocusedComponent = getPreferredFocusedComponent();
191     if (preferredFocusedComponent != null) {
192       IdeFocusManager.getInstance(myProject).requestFocus(preferredFocusedComponent, true);
193     }
194   }
195
196   public abstract void selectAll();
197
198   protected void onHistoryChanged() {
199   }
200
201   public List<XExpression> getRecentExpressions() {
202     if (myHistoryId != null) {
203       return XDebuggerHistoryManager.getInstance(myProject).getRecentExpressions(myHistoryId);
204     }
205     return Collections.emptyList();
206   }
207
208   public void saveTextInHistory() {
209     saveTextInHistory(getExpression());
210   }
211
212   private void saveTextInHistory(final XExpression text) {
213     if (myHistoryId != null) {
214       boolean update = XDebuggerHistoryManager.getInstance(myProject).addRecentExpression(myHistoryId, text);
215       myHistoryIndex = -1; //meaning not from the history list
216       if (update) {
217         onHistoryChanged();
218       }
219     }
220   }
221
222   public XDebuggerEditorsProvider getEditorsProvider() {
223     return myDebuggerEditorsProvider;
224   }
225
226   public Project getProject() {
227     return myProject;
228   }
229
230   protected Document createDocument(final XExpression text) {
231     return getEditorsProvider().createDocument(getProject(), text, mySourcePosition, myMode);
232   }
233
234   public boolean canGoBackward() {
235     return myHistoryIndex < getRecentExpressions().size()-1;
236   }
237
238   public boolean canGoForward() {
239     return myHistoryIndex > 0;
240   }
241
242   public void goBackward() {
243     final List<XExpression> expressions = getRecentExpressions();
244     if (myHistoryIndex < expressions.size() - 1) {
245       myHistoryIndex++;
246       setExpression(expressions.get(myHistoryIndex));
247     }
248   }
249
250   public void goForward() {
251     final List<XExpression> expressions = getRecentExpressions();
252     if (myHistoryIndex > 0) {
253       myHistoryIndex--;
254       setExpression(expressions.get(myHistoryIndex));
255     }
256   }
257 }