Fixed exception when LayeredLexer and tokens with 0 length
[idea/community.git] / python / edu / src / com / jetbrains / python / edu / PyCharmEduInitialConfigurator.java
1 /*
2  * Copyright 2000-2013 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.jetbrains.python.edu;
17
18 import com.google.common.collect.Sets;
19 import com.intellij.codeInsight.CodeInsightSettings;
20 import com.intellij.codeInsight.intention.IntentionActionBean;
21 import com.intellij.codeInsight.intention.IntentionManager;
22 import com.intellij.ide.AppLifecycleListener;
23 import com.intellij.ide.GeneralSettings;
24 import com.intellij.ide.SelectInTarget;
25 import com.intellij.ide.projectView.impl.AbstractProjectViewPane;
26 import com.intellij.ide.scopeView.ScopeViewPane;
27 import com.intellij.ide.ui.UISettings;
28 import com.intellij.ide.ui.customization.ActionUrl;
29 import com.intellij.ide.ui.customization.CustomActionsSchema;
30 import com.intellij.ide.ui.customization.CustomizationUtil;
31 import com.intellij.ide.util.PropertiesComponent;
32 import com.intellij.ide.util.TipAndTrickBean;
33 import com.intellij.notification.EventLog;
34 import com.intellij.openapi.application.ApplicationManager;
35 import com.intellij.openapi.editor.colors.EditorColorsManager;
36 import com.intellij.openapi.editor.colors.EditorColorsScheme;
37 import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
38 import com.intellij.openapi.extensions.Extensions;
39 import com.intellij.openapi.extensions.ExtensionsArea;
40 import com.intellij.openapi.fileChooser.impl.FileChooserUtil;
41 import com.intellij.openapi.fileTypes.FileTypeManager;
42 import com.intellij.openapi.keymap.Keymap;
43 import com.intellij.openapi.keymap.ex.KeymapManagerEx;
44 import com.intellij.openapi.keymap.impl.KeymapImpl;
45 import com.intellij.openapi.keymap.impl.ui.Group;
46 import com.intellij.openapi.project.DumbAwareRunnable;
47 import com.intellij.openapi.project.Project;
48 import com.intellij.openapi.project.ProjectManager;
49 import com.intellij.openapi.project.ProjectManagerAdapter;
50 import com.intellij.openapi.project.ex.ProjectManagerEx;
51 import com.intellij.openapi.startup.StartupManager;
52 import com.intellij.openapi.util.Disposer;
53 import com.intellij.openapi.util.registry.Registry;
54 import com.intellij.openapi.vfs.VfsUtil;
55 import com.intellij.openapi.wm.*;
56 import com.intellij.platform.DirectoryProjectConfigurator;
57 import com.intellij.platform.PlatformProjectViewOpener;
58 import com.intellij.psi.codeStyle.CodeStyleSettings;
59 import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
60 import com.intellij.ui.treeStructure.Tree;
61 import com.intellij.util.containers.ContainerUtil;
62 import com.intellij.util.messages.MessageBus;
63 import com.intellij.util.ui.tree.TreeUtil;
64 import com.jetbrains.python.PythonLanguage;
65 import com.jetbrains.python.codeInsight.PyCodeInsightSettings;
66 import org.jetbrains.annotations.NonNls;
67 import org.jetbrains.annotations.NotNull;
68 import org.jetbrains.annotations.Nullable;
69
70 import javax.swing.*;
71 import javax.swing.tree.DefaultMutableTreeNode;
72 import javax.swing.tree.DefaultTreeModel;
73 import javax.swing.tree.TreeNode;
74 import javax.swing.tree.TreePath;
75 import java.util.HashSet;
76 import java.util.Set;
77
78 /**
79  * @author traff
80  */
81 @SuppressWarnings({"UtilityClassWithoutPrivateConstructor", "UtilityClassWithPublicConstructor"})
82 public class PyCharmEduInitialConfigurator {
83   @NonNls private static final String DISPLAYED_PROPERTY = "PyCharmEDU.initialConfigurationShown";
84
85   @NonNls private static final String CONFIGURED = "PyCharmEDU.InitialConfiguration";
86   @NonNls private static final String CONFIGURED_V1 = "PyCharmEDU.InitialConfiguration.V1";
87
88   private static final Set<String> UNRELATED_TIPS = Sets.newHashSet("LiveTemplatesDjango.html", "TerminalOpen.html",
89                                                                     "Terminal.html", "ConfiguringTerminal.html");
90   private static final Set<String> HIDDEN_ACTIONS = ContainerUtil.newHashSet("CopyAsPlainText", "CopyAsRichText", "EditorPasteSimple",
91                                                                              "Folding", "Generate", "CompareClipboardWithSelection",
92                                                                              "ChangeFileEncodingAction", "CloseAllUnmodifiedEditors",
93                                                                              "CloseAllUnpinnedEditors", "CloseAllEditorsButActive",
94                                                                              "CopyReference", "MoveTabRight", "MoveTabDown", "External Tools",
95                                                                              "MoveEditorToOppositeTabGroup", "OpenEditorInOppositeTabGroup",
96                                                                              "ChangeSplitOrientation", "PinActiveTab", "Tabs Placement",
97                                                                              "TabsAlphabeticalMode", "AddNewTabToTheEndMode", "NextTab",
98                                                                              "PreviousTab", "Add to Favorites", "Add All To Favorites",
99                                                                              "ValidateXml", "NewHtmlFile", "CleanPyc", "Images.ShowThumbnails",
100                                                                              "CompareFileWithEditor", "SynchronizeCurrentFile",
101                                                                              "Mark Directory As", "CompareTwoFiles", "ShowFilePath",
102                                                                              "ChangesView.ApplyPatch", "TemplateProjectProperties",
103                                                                              "ExportToHTML", "SaveAll", "Export/Import Actions",
104                                                                              "Synchronize", "Line Separators", "ToggleReadOnlyAttribute",
105                                                                              "Macros", "EditorToggleCase", "EditorJoinLines", "FillParagraph",
106                                                                              "Convert Indents", "TemplateParametersNavigation", "EscapeEntities",
107                                                                              "QuickDefinition", "ExpressionTypeInfo", "EditorContextInfo",
108                                                                              "ShowErrorDescription", "RecentChanges", "CompareActions",
109                                                                              "GotoCustomRegion", "JumpToLastChange", "JumpToNextChange",
110                                                                              "SelectIn", "GotoTypeDeclaration", "QuickChangeScheme",
111                                                                              "GotoTest", "GotoRelated", "Hierarchy Actions", "Bookmarks",
112                                                                              "Goto Error/Bookmark Actions", "GoToEditPointGroup",
113                                                                              "Change Navigation Actions", "Method Navigation Actions",
114                                                                              "EvaluateExpression", "Pause", "ViewBreakpoints",
115                                                                              "XDebugger.MuteBreakpoints");
116
117   public static class First {
118
119     public First() {
120       patchRootAreaExtensions();
121     }
122   }
123
124   /**
125    * @noinspection UnusedParameters
126    */
127   public PyCharmEduInitialConfigurator(MessageBus bus,
128                                        CodeInsightSettings codeInsightSettings,
129                                        final PropertiesComponent propertiesComponent,
130                                        FileTypeManager fileTypeManager,
131                                        final ProjectManagerEx projectManager) {
132     final UISettings uiSettings = UISettings.getInstance();
133     if (!propertiesComponent.getBoolean(CONFIGURED_V1, false)) {
134       patchMainMenu();
135       uiSettings.SHOW_NAVIGATION_BAR = false;
136       propertiesComponent.setValue(CONFIGURED_V1, "true");
137     }
138
139     if (!propertiesComponent.getBoolean(CONFIGURED, false)) {
140       propertiesComponent.setValue(CONFIGURED, "true");
141       propertiesComponent.setValue("toolwindow.stripes.buttons.info.shown", "true");
142
143       uiSettings.HIDE_TOOL_STRIPES = false;
144       uiSettings.SHOW_MEMORY_INDICATOR = false;
145       uiSettings.SHOW_DIRECTORY_FOR_NON_UNIQUE_FILENAMES = true;
146       uiSettings.SHOW_MAIN_TOOLBAR = false;
147
148       codeInsightSettings.REFORMAT_ON_PASTE = CodeInsightSettings.NO_REFORMAT;
149
150       Registry.get("ide.new.settings.dialog").setValue(true);
151
152       GeneralSettings.getInstance().setShowTipsOnStartup(false);
153
154       EditorSettingsExternalizable.getInstance().setVirtualSpace(false);
155       EditorSettingsExternalizable.getInstance().getOptions().ARE_LINE_NUMBERS_SHOWN = true;
156       final CodeStyleSettings settings = CodeStyleSettingsManager.getInstance().getCurrentSettings();
157       settings.ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true;
158       settings.getCommonSettings(PythonLanguage.getInstance()).ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true;
159       uiSettings.SHOW_DIRECTORY_FOR_NON_UNIQUE_FILENAMES = true;
160       uiSettings.SHOW_MEMORY_INDICATOR = false;
161       final String ignoredFilesList = fileTypeManager.getIgnoredFilesList();
162       ApplicationManager.getApplication().invokeLater(new Runnable() {
163         @Override
164         public void run() {
165           ApplicationManager.getApplication().runWriteAction(new Runnable() {
166             @Override
167             public void run() {
168               FileTypeManager.getInstance().setIgnoredFilesList(ignoredFilesList + ";*$py.class");
169             }
170           });
171         }
172       });
173       PyCodeInsightSettings.getInstance().SHOW_IMPORT_POPUP = false;
174     }
175     final EditorColorsScheme editorColorsScheme = EditorColorsManager.getInstance().getScheme(EditorColorsScheme.DEFAULT_SCHEME_NAME);
176     editorColorsScheme.setEditorFontSize(14);
177
178     if (!propertiesComponent.isValueSet(DISPLAYED_PROPERTY)) {
179
180       bus.connect().subscribe(AppLifecycleListener.TOPIC, new AppLifecycleListener.Adapter() {
181         @Override
182         public void welcomeScreenDisplayed() {
183
184           ApplicationManager.getApplication().invokeLater(new Runnable() {
185             @Override
186             public void run() {
187               if (!propertiesComponent.isValueSet(DISPLAYED_PROPERTY)) {
188                 GeneralSettings.getInstance().setShowTipsOnStartup(false);
189                 propertiesComponent.setValue(DISPLAYED_PROPERTY, "true");
190
191                 patchKeymap();
192               }
193             }
194           });
195         }
196       });
197     }
198
199     bus.connect().subscribe(ProjectManager.TOPIC, new ProjectManagerAdapter() {
200       @Override
201       public void projectOpened(final Project project) {
202         if (project.isDefault()) return;
203         if (FileChooserUtil.getLastOpenedFile(project) == null) {
204           FileChooserUtil.setLastOpenedFile(project, VfsUtil.getUserHomeDir());
205         }
206
207         patchProjectAreaExtensions(project);
208
209         StartupManager.getInstance(project).runWhenProjectIsInitialized(new DumbAwareRunnable() {
210           @Override
211           public void run() {
212             if (project.isDisposed()) return;
213
214             ToolWindowManager.getInstance(project).invokeLater(new Runnable() {
215               int count = 0;
216
217               public void run() {
218                 if (project.isDisposed()) return;
219                 if (count++ < 3) { // we need to call this after ToolWindowManagerImpl.registerToolWindowsFromBeans
220                   ToolWindowManager.getInstance(project).invokeLater(this);
221                   return;
222                 }
223                 ToolWindow toolWindow = ToolWindowManager.getInstance(project).getToolWindow("Project");
224                 if (toolWindow.getType() != ToolWindowType.SLIDING) {
225                   toolWindow.activate(null);
226                 }
227               }
228             });
229           }
230         });
231       }
232     });
233   }
234
235   private static void patchMainMenu() {
236     final CustomActionsSchema schema = new CustomActionsSchema();
237
238     final JTree actionsTree = new Tree();
239     Group rootGroup = new Group("root", null, null);
240     final DefaultMutableTreeNode root = new DefaultMutableTreeNode(rootGroup);
241     DefaultTreeModel model = new DefaultTreeModel(root);
242     actionsTree.setModel(model);
243
244     schema.fillActionGroups(root);
245     for (int i = 0; i < root.getChildCount(); i++) {
246       final DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)root.getChildAt(i);
247       if ("Main menu".equals(getItemId(treeNode))) {
248         hideActionFromMainMenu(root, schema, treeNode);
249       }
250       hideActions(schema, root, treeNode, HIDDEN_ACTIONS);
251     }
252     CustomActionsSchema.getInstance().copyFrom(schema);
253   }
254
255   private static void hideActionFromMainMenu(@NotNull final DefaultMutableTreeNode root,
256                                              @NotNull final CustomActionsSchema schema, DefaultMutableTreeNode mainMenu){
257     final HashSet<String> menuItems = ContainerUtil.newHashSet("Tools", "VCS", "Refactor", "Code", "Window", "Run");
258     hideActions(schema, root, mainMenu, menuItems);
259   }
260
261   private static void hideActions(@NotNull CustomActionsSchema schema, @NotNull DefaultMutableTreeNode root,
262                                   @NotNull final TreeNode actionGroup, Set<String> items) {
263     for(int i = 0; i < actionGroup.getChildCount(); i++){
264       final DefaultMutableTreeNode child = (DefaultMutableTreeNode)actionGroup.getChildAt(i);
265       final int childCount = child.getChildCount();
266       final String childId = getItemId(child);
267       if (childId != null && items.contains(childId)){
268         final TreePath treePath = TreeUtil.getPath(root, child);
269         final ActionUrl url = CustomizationUtil.getActionUrl(treePath, ActionUrl.DELETED);
270         schema.addAction(url);
271       }
272       else if (childCount > 0) {
273         hideActions(schema, child, child, items);
274       }
275     }
276   }
277
278   @Nullable
279   private static String getItemId(@NotNull final DefaultMutableTreeNode child) {
280     final Object userObject = child.getUserObject();
281     if (userObject instanceof String) return (String)userObject;
282     return userObject instanceof Group ? ((Group)userObject).getName() : null;
283   }
284
285   private static void patchRootAreaExtensions() {
286     ExtensionsArea rootArea = Extensions.getArea(null);
287
288     for (ToolWindowEP ep : Extensions.getExtensions(ToolWindowEP.EP_NAME)) {
289       if (ToolWindowId.FAVORITES_VIEW.equals(ep.id) || ToolWindowId.TODO_VIEW.equals(ep.id) || EventLog.LOG_TOOL_WINDOW_ID.equals(ep.id)
290           || ToolWindowId.STRUCTURE_VIEW.equals(ep.id)) {
291         rootArea.getExtensionPoint(ToolWindowEP.EP_NAME).unregisterExtension(ep);
292       }
293     }
294
295     for (DirectoryProjectConfigurator ep : Extensions.getExtensions(DirectoryProjectConfigurator.EP_NAME)) {
296       if (ep instanceof PlatformProjectViewOpener) {
297         rootArea.getExtensionPoint(DirectoryProjectConfigurator.EP_NAME).unregisterExtension(ep);
298       }
299     }
300
301     // unregister unrelated tips
302     for (TipAndTrickBean tip : Extensions.getExtensions(TipAndTrickBean.EP_NAME)) {
303       if (UNRELATED_TIPS.contains(tip.fileName)) {
304         rootArea.getExtensionPoint(TipAndTrickBean.EP_NAME).unregisterExtension(tip);
305       }
306     }
307
308     for (IntentionActionBean ep : Extensions.getExtensions(IntentionManager.EP_INTENTION_ACTIONS)) {
309       if ("org.intellij.lang.regexp.intention.CheckRegExpIntentionAction".equals(ep.className)) {
310         rootArea.getExtensionPoint(IntentionManager.EP_INTENTION_ACTIONS).unregisterExtension(ep);
311       }
312     }
313   }
314
315   private static void patchProjectAreaExtensions(@NotNull final Project project) {
316     ExtensionsArea projectArea = Extensions.getArea(project);
317
318     for (SelectInTarget target : Extensions.getExtensions(SelectInTarget.EP_NAME, project)) {
319       if (ToolWindowId.FAVORITES_VIEW.equals(target.getToolWindowId()) ||
320           ToolWindowId.STRUCTURE_VIEW.equals(target.getToolWindowId())) {
321         projectArea.getExtensionPoint(SelectInTarget.EP_NAME).unregisterExtension(target);
322       }
323     }
324
325     for (AbstractProjectViewPane pane : Extensions.getExtensions(AbstractProjectViewPane.EP_NAME, project)) {
326       if (pane.getId().equals(ScopeViewPane.ID)) {
327         Disposer.dispose(pane);
328         projectArea.getExtensionPoint(AbstractProjectViewPane.EP_NAME).unregisterExtension(pane);
329       }
330     }
331   }
332
333   private static void patchKeymap() {
334     Set<String> droppedActions = ContainerUtil.newHashSet(
335       "AddToFavoritesPopup",
336       "DatabaseView.ImportDataSources",
337       "CompileDirty", "Compile",
338       // hidden
339       "AddNewFavoritesList", "EditFavorites", "RenameFavoritesList", "RemoveFavoritesList");
340     KeymapManagerEx keymapManager = KeymapManagerEx.getInstanceEx();
341
342
343     for (Keymap keymap : keymapManager.getAllKeymaps()) {
344       if (keymap.canModify()) continue;
345
346       KeymapImpl keymapImpl = (KeymapImpl)keymap;
347
348       for (String id : keymapImpl.getOwnActionIds()) {
349         if (droppedActions.contains(id)) keymapImpl.clearOwnActionsId(id);
350       }
351     }
352   }
353
354 }