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