4652052bc886ab532afdb1a3f71a4cd64463f300
[idea/community.git] / platform / lang-impl / src / com / intellij / application / options / codeStyle / MultilanguageCodeStyleAbstractPanel.java
1 /*
2  * Copyright 2010 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.application.options.codeStyle;
17
18 import com.intellij.application.options.CodeStyleAbstractPanel;
19 import com.intellij.ide.DataManager;
20 import com.intellij.lang.Language;
21 import com.intellij.openapi.actionSystem.PlatformDataKeys;
22 import com.intellij.openapi.application.ApplicationManager;
23 import com.intellij.openapi.command.CommandProcessor;
24 import com.intellij.openapi.diagnostic.Logger;
25 import com.intellij.openapi.editor.Document;
26 import com.intellij.openapi.editor.colors.EditorColorsScheme;
27 import com.intellij.openapi.editor.highlighter.EditorHighlighter;
28 import com.intellij.openapi.fileTypes.FileType;
29 import com.intellij.openapi.fileTypes.LanguageFileType;
30 import com.intellij.openapi.fileTypes.StdFileTypes;
31 import com.intellij.openapi.project.Project;
32 import com.intellij.openapi.project.ProjectManager;
33 import com.intellij.openapi.project.ex.ProjectManagerEx;
34 import com.intellij.openapi.util.Disposer;
35 import com.intellij.psi.PsiDocumentManager;
36 import com.intellij.psi.PsiFile;
37 import com.intellij.psi.PsiFileFactory;
38 import com.intellij.psi.codeStyle.CodeStyleManager;
39 import com.intellij.psi.codeStyle.CodeStyleSettings;
40 import com.intellij.ui.IdeBorderFactory;
41 import com.intellij.util.IncorrectOperationException;
42 import com.intellij.util.LocalTimeCounter;
43 import org.jetbrains.annotations.NotNull;
44
45 import javax.swing.*;
46 import javax.swing.event.AncestorEvent;
47 import javax.swing.event.AncestorListener;
48 import javax.swing.event.ChangeEvent;
49 import javax.swing.event.ChangeListener;
50 import java.awt.*;
51 import java.io.File;
52
53 /**
54  * Base class for code style settings panels supporting multiple programming languages.
55  *
56  * @author rvishnyakov
57  */
58 public abstract class MultilanguageCodeStyleAbstractPanel extends CodeStyleAbstractPanel {
59
60   private static Language myLanguage;
61   private static final Logger LOG = Logger.getInstance("#com.intellij.application.options.codeStyle.MultilanguageCodeStyleAbstractPanel");
62   private static Project mySettingsProject;
63   private static int myInstanceCount;
64   private int myLangSelectionIndex;
65   private JTabbedPane tabbedPane;
66
67   protected MultilanguageCodeStyleAbstractPanel(CodeStyleSettings settings) {
68     super(settings);
69     initProject();
70   }
71
72   private synchronized static void initProject() {
73     createSettingsProject();
74     myInstanceCount++;
75   }
76
77   /**
78    * @return Always true for multilanguage panel.
79    */
80   @Override
81   protected final boolean isMultilanguage() {
82     return true;
83   }
84
85   public void setLanguage(Language language) {
86     myLanguage = language;
87     updatePreviewEditor();
88   }
89
90   protected abstract LanguageCodeStyleSettingsProvider.SettingsType getSettingsType();
91
92   @Override
93   protected String getPreviewText() {
94     if (myLanguage == null) return "";
95     return LanguageCodeStyleSettingsProvider.getCodeSample(myLanguage, getSettingsType());
96   }
97
98   @NotNull
99   @Override
100   protected final FileType getFileType() {
101     if (myLanguage != null) {
102       return myLanguage.getAssociatedFileType();
103     }
104     Language langs[] = LanguageCodeStyleSettingsProvider.getLanguagesWithCodeStyleSettings();
105     if (langs.length > 0) {
106       myLanguage = langs[0];
107       FileType type = langs[0].getAssociatedFileType();
108       if (type != null) return type;
109     }
110     return StdFileTypes.JAVA;
111   }
112
113   protected EditorHighlighter createHighlighter(final EditorColorsScheme scheme) {
114     Project project = PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext());
115     if (project == null) {
116       project = ProjectManager.getInstance().getDefaultProject();
117     }
118     if (getFileType() instanceof LanguageFileType) {
119       return ((LanguageFileType)getFileType()).getEditorHighlighter(project, null, scheme);
120     }
121     return null;
122   }
123
124
125   protected PsiFile createFileFromText(Project project, String text) {
126     final PsiFile psiFile =
127       PsiFileFactory.getInstance(project).createFileFromText("a", getFileType(), text, LocalTimeCounter.currentTime(), true);
128     return psiFile;
129   }
130
131   @Override
132   protected PsiFile doReformat(final Project project, final PsiFile psiFile) {
133     final String text = psiFile.getText();
134     final PsiDocumentManager manager = PsiDocumentManager.getInstance(project);
135     final Document doc = manager.getDocument(psiFile);
136     CommandProcessor.getInstance().executeCommand(project, new Runnable() {
137       public void run() {
138         ApplicationManager.getApplication().runWriteAction(new Runnable() {
139           public void run() {
140             doc.replaceString(0, doc.getTextLength(), text);
141             manager.commitDocument(doc);
142             try {
143               CodeStyleManager.getInstance(project).reformat(psiFile);
144             }
145             catch (IncorrectOperationException e) {
146               LOG.error(e);
147             }
148           }
149         });
150       }
151     }, "", "");
152     manager.commitDocument(doc);
153     return psiFile;
154   }
155
156   @Override
157   protected final synchronized Project getCurrentProject() {
158     return mySettingsProject;
159   }
160
161   @Override
162   public void dispose() {
163     myInstanceCount--;
164     if (myInstanceCount == 0) {
165       disposeSettingsProject();
166     }
167     super.dispose();
168   }
169
170   /**
171    * A physical settings project is created to ensure that all formatters in preview panels work correctly.
172    */
173   private synchronized static void createSettingsProject() {
174     if (mySettingsProject != null) return;
175     try {
176       File tempFile = File.createTempFile("idea-", "-settings.tmp");
177       tempFile.deleteOnExit();
178       mySettingsProject = ProjectManagerEx.getInstanceEx().newProject("settings.tmp", tempFile.getPath(), true, false);
179     }
180     catch (Exception e) {
181       LOG.error(e);
182     }
183   }
184
185   private synchronized static void disposeSettingsProject() {
186     if (mySettingsProject == null) return;
187     Disposer.dispose(mySettingsProject);
188     mySettingsProject = null;
189   }
190
191   protected static JPanel createPreviewPanel() {
192     JPanel panel = new JPanel(new BorderLayout());
193     panel.setBorder(IdeBorderFactory.createTitledBorder("Preview"));
194     panel.setPreferredSize(new Dimension(200, 0));
195     return panel;
196   }
197
198
199   @Override
200   protected void installPreviewPanel(final JPanel previewPanel) {
201     tabbedPane = new JTabbedPane();
202     tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
203     Language[] langs = LanguageCodeStyleSettingsProvider.getLanguagesWithCodeStyleSettings();
204     if (langs.length == 0) return;
205     for (Language lang : langs) {
206       tabbedPane.addTab(lang.getDisplayName(), createDummy());
207     }
208     tabbedPane.setComponentAt(0, getEditor().getComponent());
209     myLangSelectionIndex = 0;
210     if (myLanguage == null) {
211       setLanguage(langs[0]);
212     }
213     else {
214       updatePreviewEditor();
215     }
216     tabbedPane.addChangeListener(new ChangeListener() {
217       public void stateChanged(ChangeEvent e) {
218         onTabSelection((JTabbedPane)e.getSource());        
219       }
220     });
221     previewPanel.add(tabbedPane, BorderLayout.CENTER);
222     previewPanel.addAncestorListener(new AncestorListener(){
223       public void ancestorAdded(AncestorEvent event) {
224         selectCurrentLanguageTab();
225       }
226
227       public void ancestorRemoved(AncestorEvent event) {
228         // Do nothing
229       }
230
231       public void ancestorMoved(AncestorEvent event) {
232         // Do nothing
233       }
234     });
235   }
236
237   private void selectCurrentLanguageTab() {
238     for(int i = 0; i < tabbedPane.getTabCount(); i ++) {
239       if (myLanguage.getDisplayName().equals(tabbedPane.getTitleAt(i))) {
240         tabbedPane.setSelectedIndex(i);
241         return;
242       }
243     }
244   }
245
246
247   private void onTabSelection(JTabbedPane tabs) {
248     int i = tabs.getSelectedIndex();
249     tabs.setComponentAt(myLangSelectionIndex, createDummy());
250     tabs.setComponentAt(i, getEditor().getComponent());
251     myLangSelectionIndex = i;
252     String selectionTitle = tabs.getTitleAt(i);
253     Language lang = LanguageCodeStyleSettingsProvider.getLanguage(selectionTitle);
254     if (lang != null) {
255       setLanguage(lang);
256     }
257   }
258
259
260   private JComponent createDummy() {
261     return new JLabel("");
262   }
263
264
265 }