2 * Copyright 2000-2013 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.jetbrains.python.edu;
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.Extensions;
45 import com.intellij.openapi.extensions.ExtensionsArea;
46 import com.intellij.openapi.fileChooser.impl.FileChooserUtil;
47 import com.intellij.openapi.fileTypes.FileTypeManager;
48 import com.intellij.openapi.keymap.Keymap;
49 import com.intellij.openapi.keymap.ex.KeymapManagerEx;
50 import com.intellij.openapi.keymap.impl.KeymapImpl;
51 import com.intellij.openapi.keymap.impl.ui.Group;
52 import com.intellij.openapi.project.DumbAwareRunnable;
53 import com.intellij.openapi.project.Project;
54 import com.intellij.openapi.project.ProjectManager;
55 import com.intellij.openapi.project.ProjectManagerAdapter;
56 import com.intellij.openapi.project.ex.ProjectManagerEx;
57 import com.intellij.openapi.startup.StartupManager;
58 import com.intellij.openapi.util.Disposer;
59 import com.intellij.openapi.util.registry.Registry;
60 import com.intellij.openapi.vfs.VfsUtil;
61 import com.intellij.openapi.wm.*;
62 import com.intellij.platform.DirectoryProjectConfigurator;
63 import com.intellij.platform.PlatformProjectViewOpener;
64 import com.intellij.psi.codeStyle.CodeStyleSettings;
65 import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
66 import com.intellij.ui.treeStructure.Tree;
67 import com.intellij.util.containers.ContainerUtil;
68 import com.intellij.util.messages.MessageBus;
69 import com.intellij.util.ui.tree.TreeUtil;
70 import com.jetbrains.python.PythonLanguage;
71 import com.jetbrains.python.codeInsight.PyCodeInsightSettings;
72 import org.jetbrains.annotations.NonNls;
73 import org.jetbrains.annotations.NotNull;
74 import org.jetbrains.annotations.Nullable;
77 import javax.swing.tree.DefaultMutableTreeNode;
78 import javax.swing.tree.DefaultTreeModel;
79 import javax.swing.tree.TreeNode;
80 import javax.swing.tree.TreePath;
81 import java.util.HashSet;
87 @SuppressWarnings({"UtilityClassWithoutPrivateConstructor", "UtilityClassWithPublicConstructor"})
88 public class PyCharmEduInitialConfigurator {
89 @NonNls private static final String DISPLAYED_PROPERTY = "PyCharmEDU.initialConfigurationShown";
91 @NonNls private static final String CONFIGURED = "PyCharmEDU.InitialConfiguration";
92 @NonNls private static final String CONFIGURED_V1 = "PyCharmEDU.InitialConfiguration.V1";
94 private static final Set<String> UNRELATED_TIPS = Sets.newHashSet("LiveTemplatesDjango.html", "TerminalOpen.html",
95 "Terminal.html", "ConfiguringTerminal.html");
96 private static final Set<String> HIDDEN_ACTIONS = ContainerUtil.newHashSet("CopyAsPlainText", "CopyAsRichText", "EditorPasteSimple",
97 "Folding", "Generate", "CompareClipboardWithSelection",
98 "ChangeFileEncodingAction", "CloseAllUnmodifiedEditors",
99 "CloseAllUnpinnedEditors", "CloseAllEditorsButActive",
100 "CopyReference", "MoveTabRight", "MoveTabDown", "External Tools",
101 "MoveEditorToOppositeTabGroup", "OpenEditorInOppositeTabGroup",
102 "ChangeSplitOrientation", "PinActiveTab", "Tabs Placement",
103 "TabsAlphabeticalMode", "AddNewTabToTheEndMode", "NextTab",
104 "PreviousTab", "Add to Favorites", "Add All To Favorites",
105 "ValidateXml", "NewHtmlFile", "CleanPyc", "Images.ShowThumbnails",
106 "CompareFileWithEditor", "SynchronizeCurrentFile",
107 "Mark Directory As", "CompareTwoFiles", "ShowFilePath",
108 "ChangesView.ApplyPatch", "TemplateProjectProperties",
109 "ExportToHTML", "SaveAll", "Export/Import Actions",
110 "Synchronize", "Line Separators", "ToggleReadOnlyAttribute",
111 "Macros", "EditorToggleCase", "EditorJoinLines", "FillParagraph",
112 "Convert Indents", "TemplateParametersNavigation", "EscapeEntities",
113 "QuickDefinition", "ExpressionTypeInfo", "EditorContextInfo",
114 "ShowErrorDescription", "RecentChanges", "CompareActions",
115 "GotoCustomRegion", "JumpToLastChange", "JumpToNextChange",
116 "SelectIn", "GotoTypeDeclaration", "QuickChangeScheme",
117 "GotoTest", "GotoRelated", "Hierarchy Actions", "Bookmarks",
118 "Goto Error/Bookmark Actions", "GoToEditPointGroup",
119 "Change Navigation Actions", "Method Navigation Actions",
120 "EvaluateExpression", "Pause", "ViewBreakpoints",
121 "XDebugger.MuteBreakpoints");
123 public static class First {
126 patchRootAreaExtensions();
131 * @noinspection UnusedParameters
133 public PyCharmEduInitialConfigurator(MessageBus bus,
134 CodeInsightSettings codeInsightSettings,
135 final PropertiesComponent propertiesComponent,
136 FileTypeManager fileTypeManager,
137 final ProjectManagerEx projectManager) {
138 final UISettings uiSettings = UISettings.getInstance();
139 if (!propertiesComponent.getBoolean(CONFIGURED_V1, false)) {
141 uiSettings.SHOW_NAVIGATION_BAR = false;
142 propertiesComponent.setValue(CONFIGURED_V1, "true");
145 if (!propertiesComponent.getBoolean(CONFIGURED, false)) {
146 propertiesComponent.setValue(CONFIGURED, "true");
147 propertiesComponent.setValue("toolwindow.stripes.buttons.info.shown", "true");
149 uiSettings.HIDE_TOOL_STRIPES = false;
150 uiSettings.SHOW_MEMORY_INDICATOR = false;
151 uiSettings.SHOW_DIRECTORY_FOR_NON_UNIQUE_FILENAMES = true;
152 uiSettings.SHOW_MAIN_TOOLBAR = false;
154 codeInsightSettings.REFORMAT_ON_PASTE = CodeInsightSettings.NO_REFORMAT;
156 Registry.get("ide.new.settings.dialog").setValue(true);
158 GeneralSettings.getInstance().setShowTipsOnStartup(false);
160 EditorSettingsExternalizable.getInstance().setVirtualSpace(false);
161 EditorSettingsExternalizable.getInstance().getOptions().ARE_LINE_NUMBERS_SHOWN = true;
162 final CodeStyleSettings settings = CodeStyleSettingsManager.getInstance().getCurrentSettings();
163 settings.ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true;
164 settings.getCommonSettings(PythonLanguage.getInstance()).ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true;
165 uiSettings.SHOW_DIRECTORY_FOR_NON_UNIQUE_FILENAMES = true;
166 uiSettings.SHOW_MEMORY_INDICATOR = false;
167 final String ignoredFilesList = fileTypeManager.getIgnoredFilesList();
168 ApplicationManager.getApplication().invokeLater(new Runnable() {
171 ApplicationManager.getApplication().runWriteAction(new Runnable() {
174 FileTypeManager.getInstance().setIgnoredFilesList(ignoredFilesList + ";*$py.class");
179 PyCodeInsightSettings.getInstance().SHOW_IMPORT_POPUP = false;
181 final EditorColorsScheme editorColorsScheme = EditorColorsManager.getInstance().getScheme(EditorColorsScheme.DEFAULT_SCHEME_NAME);
182 editorColorsScheme.setEditorFontSize(14);
184 if (!propertiesComponent.isValueSet(DISPLAYED_PROPERTY)) {
186 bus.connect().subscribe(AppLifecycleListener.TOPIC, new AppLifecycleListener.Adapter() {
188 public void welcomeScreenDisplayed() {
190 ApplicationManager.getApplication().invokeLater(new Runnable() {
193 if (!propertiesComponent.isValueSet(DISPLAYED_PROPERTY)) {
194 GeneralSettings.getInstance().setShowTipsOnStartup(false);
195 propertiesComponent.setValue(DISPLAYED_PROPERTY, "true");
205 bus.connect().subscribe(ProjectManager.TOPIC, new ProjectManagerAdapter() {
207 public void projectOpened(final Project project) {
208 if (project.isDefault()) return;
209 if (FileChooserUtil.getLastOpenedFile(project) == null) {
210 FileChooserUtil.setLastOpenedFile(project, VfsUtil.getUserHomeDir());
213 patchProjectAreaExtensions(project);
215 StartupManager.getInstance(project).runWhenProjectIsInitialized(new DumbAwareRunnable() {
218 if (project.isDisposed()) return;
220 ToolWindowManager.getInstance(project).invokeLater(new Runnable() {
224 if (project.isDisposed()) return;
225 if (count++ < 3) { // we need to call this after ToolWindowManagerImpl.registerToolWindowsFromBeans
226 ToolWindowManager.getInstance(project).invokeLater(this);
229 ToolWindow toolWindow = ToolWindowManager.getInstance(project).getToolWindow("Project");
230 if (toolWindow.getType() != ToolWindowType.SLIDING) {
231 toolWindow.activate(null);
241 private static void patchMainMenu() {
242 final CustomActionsSchema schema = new CustomActionsSchema();
244 final JTree actionsTree = new Tree();
245 Group rootGroup = new Group("root", null, null);
246 final DefaultMutableTreeNode root = new DefaultMutableTreeNode(rootGroup);
247 DefaultTreeModel model = new DefaultTreeModel(root);
248 actionsTree.setModel(model);
250 schema.fillActionGroups(root);
251 for (int i = 0; i < root.getChildCount(); i++) {
252 final DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)root.getChildAt(i);
253 if ("Main menu".equals(getItemId(treeNode))) {
254 hideActionFromMainMenu(root, schema, treeNode);
256 hideActions(schema, root, treeNode, HIDDEN_ACTIONS);
258 CustomActionsSchema.getInstance().copyFrom(schema);
261 private static void hideActionFromMainMenu(@NotNull final DefaultMutableTreeNode root,
262 @NotNull final CustomActionsSchema schema, DefaultMutableTreeNode mainMenu){
263 final HashSet<String> menuItems = ContainerUtil.newHashSet("Tools", "VCS", "Refactor", "Code", "Window", "Run");
264 hideActions(schema, root, mainMenu, menuItems);
267 private static void hideActions(@NotNull CustomActionsSchema schema, @NotNull DefaultMutableTreeNode root,
268 @NotNull final TreeNode actionGroup, Set<String> items) {
269 for(int i = 0; i < actionGroup.getChildCount(); i++){
270 final DefaultMutableTreeNode child = (DefaultMutableTreeNode)actionGroup.getChildAt(i);
271 final int childCount = child.getChildCount();
272 final String childId = getItemId(child);
273 if (childId != null && items.contains(childId)){
274 final TreePath treePath = TreeUtil.getPath(root, child);
275 final ActionUrl url = CustomizationUtil.getActionUrl(treePath, ActionUrl.DELETED);
276 schema.addAction(url);
278 else if (childCount > 0) {
279 hideActions(schema, child, child, items);
285 private static String getItemId(@NotNull final DefaultMutableTreeNode child) {
286 final Object userObject = child.getUserObject();
287 if (userObject instanceof String) return (String)userObject;
288 return userObject instanceof Group ? ((Group)userObject).getName() : null;
291 private static void patchRootAreaExtensions() {
292 ExtensionsArea rootArea = Extensions.getArea(null);
294 for (ToolWindowEP ep : Extensions.getExtensions(ToolWindowEP.EP_NAME)) {
295 if (ToolWindowId.FAVORITES_VIEW.equals(ep.id) || ToolWindowId.TODO_VIEW.equals(ep.id) || EventLog.LOG_TOOL_WINDOW_ID.equals(ep.id)
296 || ToolWindowId.STRUCTURE_VIEW.equals(ep.id)) {
297 rootArea.getExtensionPoint(ToolWindowEP.EP_NAME).unregisterExtension(ep);
301 for (DirectoryProjectConfigurator ep : Extensions.getExtensions(DirectoryProjectConfigurator.EP_NAME)) {
302 if (ep instanceof PlatformProjectViewOpener) {
303 rootArea.getExtensionPoint(DirectoryProjectConfigurator.EP_NAME).unregisterExtension(ep);
307 // unregister unrelated tips
308 for (TipAndTrickBean tip : Extensions.getExtensions(TipAndTrickBean.EP_NAME)) {
309 if (UNRELATED_TIPS.contains(tip.fileName)) {
310 rootArea.getExtensionPoint(TipAndTrickBean.EP_NAME).unregisterExtension(tip);
314 for (IntentionActionBean ep : Extensions.getExtensions(IntentionManager.EP_INTENTION_ACTIONS)) {
315 if ("org.intellij.lang.regexp.intention.CheckRegExpIntentionAction".equals(ep.className)) {
316 rootArea.getExtensionPoint(IntentionManager.EP_INTENTION_ACTIONS).unregisterExtension(ep);
321 private static void patchProjectAreaExtensions(@NotNull final Project project) {
322 Executor debugExecutor = DefaultDebugExecutor.getDebugExecutorInstance();
323 unregisterAction(debugExecutor.getId(), ExecutorRegistryImpl.RUNNERS_GROUP);
324 unregisterAction(debugExecutor.getContextActionId(), ExecutorRegistryImpl.RUN_CONTEXT_GROUP);
326 ExtensionsArea projectArea = Extensions.getArea(project);
328 for (SelectInTarget target : Extensions.getExtensions(SelectInTarget.EP_NAME, project)) {
329 if (ToolWindowId.FAVORITES_VIEW.equals(target.getToolWindowId()) ||
330 ToolWindowId.STRUCTURE_VIEW.equals(target.getToolWindowId())) {
331 projectArea.getExtensionPoint(SelectInTarget.EP_NAME).unregisterExtension(target);
335 for (AbstractProjectViewPane pane : Extensions.getExtensions(AbstractProjectViewPane.EP_NAME, project)) {
336 if (pane.getId().equals(ScopeViewPane.ID)) {
337 Disposer.dispose(pane);
338 projectArea.getExtensionPoint(AbstractProjectViewPane.EP_NAME).unregisterExtension(pane);
343 private static void unregisterAction(String actionId, String groupId) {
344 ActionManager actionManager = ActionManager.getInstance();
345 AnAction action = actionManager.getAction(actionId);
346 if (action != null) {
347 AnAction actionGroup = actionManager.getAction(groupId);
348 if (actionGroup != null && actionGroup instanceof DefaultActionGroup) {
349 ((DefaultActionGroup)actionGroup).remove(action);
350 actionManager.unregisterAction(actionId);
355 private static void patchKeymap() {
356 Set<String> droppedActions = ContainerUtil.newHashSet(
357 "AddToFavoritesPopup",
358 "DatabaseView.ImportDataSources",
359 "CompileDirty", "Compile",
361 "AddNewFavoritesList", "EditFavorites", "RenameFavoritesList", "RemoveFavoritesList");
362 KeymapManagerEx keymapManager = KeymapManagerEx.getInstanceEx();
365 for (Keymap keymap : keymapManager.getAllKeymaps()) {
366 if (keymap.canModify()) continue;
368 KeymapImpl keymapImpl = (KeymapImpl)keymap;
370 for (String id : keymapImpl.getOwnActionIds()) {
371 if (droppedActions.contains(id)) keymapImpl.clearOwnActionsId(id);