| /* |
| * Copyright 2000-2014 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.intellij.ide.projectView.impl; |
| |
| import com.intellij.ProjectTopics; |
| import com.intellij.history.LocalHistory; |
| import com.intellij.history.LocalHistoryAction; |
| import com.intellij.icons.AllIcons; |
| import com.intellij.ide.*; |
| import com.intellij.ide.actions.CollapseAllToolbarAction; |
| import com.intellij.ide.impl.ProjectViewSelectInTarget; |
| import com.intellij.ide.projectView.HelpID; |
| import com.intellij.ide.projectView.ProjectView; |
| import com.intellij.ide.projectView.ProjectViewNode; |
| import com.intellij.ide.projectView.impl.nodes.*; |
| import com.intellij.ide.scopeView.ScopeViewPane; |
| import com.intellij.ide.ui.SplitterProportionsDataImpl; |
| import com.intellij.ide.ui.UISettings; |
| import com.intellij.ide.util.DeleteHandler; |
| import com.intellij.ide.util.DirectoryChooserUtil; |
| import com.intellij.ide.util.EditorHelper; |
| import com.intellij.ide.util.treeView.AbstractTreeBuilder; |
| import com.intellij.ide.util.treeView.AbstractTreeNode; |
| import com.intellij.ide.util.treeView.NodeDescriptor; |
| import com.intellij.openapi.Disposable; |
| import com.intellij.openapi.actionSystem.*; |
| import com.intellij.openapi.application.ApplicationManager; |
| import com.intellij.openapi.command.CommandProcessor; |
| import com.intellij.openapi.components.PersistentStateComponent; |
| import com.intellij.openapi.components.State; |
| import com.intellij.openapi.components.Storage; |
| import com.intellij.openapi.components.StoragePathMacros; |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.editor.Editor; |
| import com.intellij.openapi.extensions.Extensions; |
| import com.intellij.openapi.fileEditor.FileEditor; |
| import com.intellij.openapi.fileEditor.FileEditorManager; |
| import com.intellij.openapi.fileEditor.TextEditor; |
| import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; |
| import com.intellij.openapi.module.Module; |
| import com.intellij.openapi.module.ModuleUtilCore; |
| import com.intellij.openapi.project.DumbAware; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.roots.*; |
| import com.intellij.openapi.roots.ui.configuration.actions.ModuleDeleteProvider; |
| import com.intellij.openapi.ui.Messages; |
| import com.intellij.openapi.ui.SimpleToolWindowPanel; |
| import com.intellij.openapi.ui.SplitterProportionsData; |
| import com.intellij.openapi.ui.popup.PopupChooserBuilder; |
| import com.intellij.openapi.util.*; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.openapi.vfs.JarFileSystem; |
| import com.intellij.openapi.vfs.LocalFileSystem; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.openapi.wm.*; |
| import com.intellij.openapi.wm.ex.ToolWindowEx; |
| import com.intellij.openapi.wm.ex.ToolWindowManagerAdapter; |
| import com.intellij.openapi.wm.ex.ToolWindowManagerEx; |
| import com.intellij.openapi.wm.impl.content.ToolWindowContentUi; |
| import com.intellij.psi.*; |
| import com.intellij.psi.impl.file.PsiDirectoryFactory; |
| import com.intellij.psi.util.PsiUtilCore; |
| import com.intellij.ui.AutoScrollFromSourceHandler; |
| import com.intellij.ui.AutoScrollToSourceHandler; |
| import com.intellij.ui.GuiUtils; |
| import com.intellij.ui.components.JBList; |
| import com.intellij.ui.content.Content; |
| import com.intellij.ui.content.ContentManager; |
| import com.intellij.ui.content.ContentManagerAdapter; |
| import com.intellij.ui.content.ContentManagerEvent; |
| import com.intellij.ui.switcher.QuickActionProvider; |
| import com.intellij.util.ArrayUtil; |
| import com.intellij.util.IJSwingUtilities; |
| import com.intellij.util.PlatformIcons; |
| import com.intellij.util.messages.MessageBusConnection; |
| import com.intellij.util.ui.UIUtil; |
| import com.intellij.util.ui.tree.TreeUtil; |
| import gnu.trove.THashMap; |
| import gnu.trove.THashSet; |
| import org.jdom.Attribute; |
| import org.jdom.Element; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import javax.swing.*; |
| import javax.swing.tree.DefaultMutableTreeNode; |
| import javax.swing.tree.DefaultTreeModel; |
| import javax.swing.tree.TreePath; |
| import java.awt.*; |
| import java.util.*; |
| import java.util.List; |
| |
| @State( |
| name="ProjectView", |
| storages= { |
| @Storage( |
| file = StoragePathMacros.WORKSPACE_FILE |
| )} |
| ) |
| public class ProjectViewImpl extends ProjectView implements PersistentStateComponent<Element>, Disposable, QuickActionProvider, BusyObject { |
| private static final Logger LOG = Logger.getInstance("#com.intellij.ide.projectView.impl.ProjectViewImpl"); |
| private static final Key<String> ID_KEY = Key.create("pane-id"); |
| private static final Key<String> SUB_ID_KEY = Key.create("pane-sub-id"); |
| private final CopyPasteDelegator myCopyPasteDelegator; |
| private boolean isInitialized; |
| private boolean myExtensionsLoaded = false; |
| @NotNull private final Project myProject; |
| |
| // + options |
| private final Map<String, Boolean> myFlattenPackages = new THashMap<String, Boolean>(); |
| private static final boolean ourFlattenPackagesDefaults = false; |
| private final Map<String, Boolean> myShowMembers = new THashMap<String, Boolean>(); |
| private static final boolean ourShowMembersDefaults = false; |
| private final Map<String, Boolean> mySortByType = new THashMap<String, Boolean>(); |
| private static final boolean ourSortByTypeDefaults = false; |
| private final Map<String, Boolean> myShowModules = new THashMap<String, Boolean>(); |
| private static final boolean ourShowModulesDefaults = true; |
| private final Map<String, Boolean> myShowLibraryContents = new THashMap<String, Boolean>(); |
| private static final boolean ourShowLibraryContentsDefaults = true; |
| private final Map<String, Boolean> myHideEmptyPackages = new THashMap<String, Boolean>(); |
| private static final boolean ourHideEmptyPackagesDefaults = true; |
| private final Map<String, Boolean> myAbbreviatePackageNames = new THashMap<String, Boolean>(); |
| private static final boolean ourAbbreviatePackagesDefaults = false; |
| private final Map<String, Boolean> myAutoscrollToSource = new THashMap<String, Boolean>(); |
| private final Map<String, Boolean> myAutoscrollFromSource = new THashMap<String, Boolean>(); |
| private static final boolean ourAutoscrollFromSourceDefaults = false; |
| |
| private String myCurrentViewId; |
| private String myCurrentViewSubId; |
| // - options |
| |
| private final AutoScrollToSourceHandler myAutoScrollToSourceHandler; |
| private final MyAutoScrollFromSourceHandler myAutoScrollFromSourceHandler; |
| |
| private final IdeView myIdeView = new MyIdeView(); |
| private final MyDeletePSIElementProvider myDeletePSIElementProvider = new MyDeletePSIElementProvider(); |
| private final ModuleDeleteProvider myDeleteModuleProvider = new ModuleDeleteProvider(); |
| |
| private SimpleToolWindowPanel myPanel; |
| private final Map<String, AbstractProjectViewPane> myId2Pane = new LinkedHashMap<String, AbstractProjectViewPane>(); |
| private final Collection<AbstractProjectViewPane> myUninitializedPanes = new THashSet<AbstractProjectViewPane>(); |
| |
| static final DataKey<ProjectViewImpl> DATA_KEY = DataKey.create("com.intellij.ide.projectView.impl.ProjectViewImpl"); |
| |
| private DefaultActionGroup myActionGroup; |
| private String mySavedPaneId = ProjectViewPane.ID; |
| private String mySavedPaneSubId; |
| //private static final Icon COMPACT_EMPTY_MIDDLE_PACKAGES_ICON = IconLoader.getIcon("/objectBrowser/compactEmptyPackages.png"); |
| //private static final Icon HIDE_EMPTY_MIDDLE_PACKAGES_ICON = IconLoader.getIcon("/objectBrowser/hideEmptyPackages.png"); |
| @NonNls private static final String ELEMENT_NAVIGATOR = "navigator"; |
| @NonNls private static final String ELEMENT_PANES = "panes"; |
| @NonNls private static final String ELEMENT_PANE = "pane"; |
| @NonNls private static final String ATTRIBUTE_CURRENT_VIEW = "currentView"; |
| @NonNls private static final String ATTRIBUTE_CURRENT_SUBVIEW = "currentSubView"; |
| @NonNls private static final String ELEMENT_FLATTEN_PACKAGES = "flattenPackages"; |
| @NonNls private static final String ELEMENT_SHOW_MEMBERS = "showMembers"; |
| @NonNls private static final String ELEMENT_SHOW_MODULES = "showModules"; |
| @NonNls private static final String ELEMENT_SHOW_LIBRARY_CONTENTS = "showLibraryContents"; |
| @NonNls private static final String ELEMENT_HIDE_EMPTY_PACKAGES = "hideEmptyPackages"; |
| @NonNls private static final String ELEMENT_ABBREVIATE_PACKAGE_NAMES = "abbreviatePackageNames"; |
| @NonNls private static final String ELEMENT_AUTOSCROLL_TO_SOURCE = "autoscrollToSource"; |
| @NonNls private static final String ELEMENT_AUTOSCROLL_FROM_SOURCE = "autoscrollFromSource"; |
| @NonNls private static final String ELEMENT_SORT_BY_TYPE = "sortByType"; |
| |
| private static final String ATTRIBUTE_ID = "id"; |
| private JPanel myViewContentPanel; |
| private static final Comparator<AbstractProjectViewPane> PANE_WEIGHT_COMPARATOR = new Comparator<AbstractProjectViewPane>() { |
| @Override |
| public int compare(final AbstractProjectViewPane o1, final AbstractProjectViewPane o2) { |
| return o1.getWeight() - o2.getWeight(); |
| } |
| }; |
| private final FileEditorManager myFileEditorManager; |
| private final MyPanel myDataProvider; |
| private final SplitterProportionsData splitterProportions = new SplitterProportionsDataImpl(); |
| private final MessageBusConnection myConnection; |
| private final Map<String, Element> myUninitializedPaneState = new HashMap<String, Element>(); |
| private final Map<String, SelectInTarget> mySelectInTargets = new LinkedHashMap<String, SelectInTarget>(); |
| private ContentManager myContentManager; |
| private boolean myFoldersAlwaysOnTop = true; |
| |
| public ProjectViewImpl(@NotNull Project project, final FileEditorManager fileEditorManager, final ToolWindowManagerEx toolWindowManager) { |
| myProject = project; |
| |
| constructUi(); |
| |
| |
| Disposer.register(myProject, this); |
| myFileEditorManager = fileEditorManager; |
| |
| myConnection = project.getMessageBus().connect(); |
| myConnection.subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootAdapter() { |
| @Override |
| public void rootsChanged(ModuleRootEvent event) { |
| refresh(); |
| } |
| }); |
| |
| myAutoScrollFromSourceHandler = new MyAutoScrollFromSourceHandler(); |
| |
| myDataProvider = new MyPanel(); |
| myDataProvider.add(myPanel, BorderLayout.CENTER); |
| myCopyPasteDelegator = new CopyPasteDelegator(myProject, myPanel) { |
| @Override |
| @NotNull |
| protected PsiElement[] getSelectedElements() { |
| final AbstractProjectViewPane viewPane = getCurrentProjectViewPane(); |
| return viewPane == null ? PsiElement.EMPTY_ARRAY : viewPane.getSelectedPSIElements(); |
| } |
| }; |
| myAutoScrollToSourceHandler = new AutoScrollToSourceHandler() { |
| @Override |
| protected boolean isAutoScrollMode() { |
| return isAutoscrollToSource(myCurrentViewId); |
| } |
| |
| @Override |
| protected void setAutoScrollMode(boolean state) { |
| setAutoscrollToSource(state, myCurrentViewId); |
| } |
| }; |
| toolWindowManager.addToolWindowManagerListener(new ToolWindowManagerAdapter(){ |
| private boolean toolWindowVisible; |
| |
| @Override |
| public void stateChanged() { |
| ToolWindow window = toolWindowManager.getToolWindow(ToolWindowId.PROJECT_VIEW); |
| if (window == null) return; |
| if (window.isVisible() && !toolWindowVisible) { |
| String id = getCurrentViewId(); |
| if (isAutoscrollToSource(id)) { |
| AbstractProjectViewPane currentProjectViewPane = getCurrentProjectViewPane(); |
| |
| if (currentProjectViewPane != null) { |
| myAutoScrollToSourceHandler.onMouseClicked(currentProjectViewPane.getTree()); |
| } |
| } |
| if (isAutoscrollFromSource(id)) { |
| myAutoScrollFromSourceHandler.setAutoScrollEnabled(true); |
| } |
| } |
| toolWindowVisible = window.isVisible(); |
| } |
| }); |
| } |
| |
| private void constructUi() { |
| myViewContentPanel = new JPanel(); |
| myPanel = new SimpleToolWindowPanel(true).setProvideQuickActions(false); |
| myPanel.setContent(myViewContentPanel); |
| } |
| |
| @Override |
| public String getName() { |
| return "Project"; |
| } |
| |
| @Override |
| @NotNull |
| public List<AnAction> getActions(boolean originalProvider) { |
| ArrayList<AnAction> result = new ArrayList<AnAction>(); |
| |
| DefaultActionGroup views = new DefaultActionGroup("Change View", true); |
| boolean lastHeaderHadKids = false; |
| for (int i = 0; i < myContentManager.getContentCount(); i++) { |
| Content each = myContentManager.getContent(i); |
| if (each != null) { |
| if (each.getUserData(SUB_ID_KEY) == null) { |
| if (lastHeaderHadKids) { |
| views.add(new Separator()); |
| } else { |
| if (i + 1 < myContentManager.getContentCount()) { |
| Content next = myContentManager.getContent(i + 1); |
| if (next != null) { |
| if (next.getUserData(SUB_ID_KEY) != null) { |
| views.add(new Separator()); |
| } |
| } |
| } |
| } |
| } |
| else { |
| lastHeaderHadKids = true; |
| } |
| |
| views.add(new ChangeViewAction(each.getUserData(ID_KEY), each.getUserData(SUB_ID_KEY))); |
| } |
| } |
| result.add(views); |
| result.add(new Separator()); |
| |
| |
| List<AnAction> secondary = new ArrayList<AnAction>(); |
| if (myActionGroup != null) { |
| AnAction[] kids = myActionGroup.getChildren(null); |
| for (AnAction each : kids) { |
| if (myActionGroup.isPrimary(each)) { |
| result.add(each); |
| } |
| else { |
| secondary.add(each); |
| } |
| } |
| } |
| result.add(new Separator()); |
| result.addAll(secondary); |
| |
| return result; |
| } |
| |
| private class ChangeViewAction extends AnAction { |
| private final String myId; |
| private final String mySubId; |
| |
| private ChangeViewAction(@NotNull String id, String subId) { |
| myId = id; |
| mySubId = subId; |
| } |
| |
| @Override |
| public void update(AnActionEvent e) { |
| AbstractProjectViewPane pane = getProjectViewPaneById(myId); |
| e.getPresentation().setText(pane.getTitle() + (mySubId != null ? (" - " + pane.getPresentableSubIdName(mySubId)) : "")); |
| } |
| |
| @Override |
| public void actionPerformed(AnActionEvent e) { |
| changeView(myId, mySubId); |
| } |
| } |
| |
| @Override |
| public boolean isCycleRoot() { |
| return false; |
| } |
| |
| @Override |
| public synchronized void addProjectPane(@NotNull final AbstractProjectViewPane pane) { |
| myUninitializedPanes.add(pane); |
| SelectInTarget selectInTarget = pane.createSelectInTarget(); |
| if (selectInTarget != null) { |
| mySelectInTargets.put(pane.getId(), selectInTarget); |
| } |
| if (isInitialized) { |
| doAddUninitializedPanes(); |
| } |
| } |
| |
| @Override |
| public synchronized void removeProjectPane(@NotNull AbstractProjectViewPane pane) { |
| ApplicationManager.getApplication().assertIsDispatchThread(); |
| myUninitializedPanes.remove(pane); |
| //assume we are completely initialized here |
| String idToRemove = pane.getId(); |
| |
| if (!myId2Pane.containsKey(idToRemove)) return; |
| pane.removeTreeChangeListener(); |
| for (int i = myContentManager.getContentCount() - 1; i >= 0; i--) { |
| Content content = myContentManager.getContent(i); |
| String id = content != null ? content.getUserData(ID_KEY) : null; |
| if (id != null && id.equals(idToRemove)) { |
| myContentManager.removeContent(content, true); |
| } |
| } |
| myId2Pane.remove(idToRemove); |
| mySelectInTargets.remove(idToRemove); |
| viewSelectionChanged(); |
| } |
| |
| private synchronized void doAddUninitializedPanes() { |
| for (AbstractProjectViewPane pane : myUninitializedPanes) { |
| doAddPane(pane); |
| } |
| final Content[] contents = myContentManager.getContents(); |
| for (int i = 1; i < contents.length; i++) { |
| Content content = contents[i]; |
| Content prev = contents[i - 1]; |
| if (!StringUtil.equals(content.getUserData(ID_KEY), prev.getUserData(ID_KEY)) && |
| prev.getUserData(SUB_ID_KEY) != null && content.getSeparator() == null) { |
| content.setSeparator(""); |
| } |
| } |
| |
| String selectID = null; |
| String selectSubID = null; |
| |
| // try to find saved selected view... |
| for (Content content : contents) { |
| final String id = content.getUserData(ID_KEY); |
| final String subId = content.getUserData(SUB_ID_KEY); |
| if (id != null && |
| id.equals(mySavedPaneId) && |
| StringUtil.equals(subId, mySavedPaneSubId)) { |
| selectID = id; |
| selectSubID = subId; |
| break; |
| } |
| } |
| |
| // saved view not found (plugin disabled, ID changed etc.) - select first available view... |
| if (selectID == null && contents.length > 0) { |
| Content content = contents[0]; |
| selectID = content.getUserData(ID_KEY); |
| selectSubID = content.getUserData(SUB_ID_KEY); |
| } |
| |
| if (selectID != null) { |
| changeView(selectID, selectSubID); |
| mySavedPaneId = null; |
| mySavedPaneSubId = null; |
| } |
| |
| myUninitializedPanes.clear(); |
| } |
| |
| private void doAddPane(@NotNull final AbstractProjectViewPane newPane) { |
| ApplicationManager.getApplication().assertIsDispatchThread(); |
| int index; |
| final ContentManager manager = myContentManager; |
| for (index = 0; index < manager.getContentCount(); index++) { |
| Content content = manager.getContent(index); |
| String id = content.getUserData(ID_KEY); |
| AbstractProjectViewPane pane = myId2Pane.get(id); |
| |
| int comp = PANE_WEIGHT_COMPARATOR.compare(pane, newPane); |
| if (comp == 0) { |
| System.out.println("here"); |
| } |
| LOG.assertTrue(comp != 0); |
| if (comp > 0) { |
| break; |
| } |
| } |
| final String id = newPane.getId(); |
| myId2Pane.put(id, newPane); |
| String[] subIds = newPane.getSubIds(); |
| subIds = subIds.length == 0 ? new String[]{null} : subIds; |
| boolean first = true; |
| for (String subId : subIds) { |
| final String title = subId != null ? newPane.getPresentableSubIdName(subId) : newPane.getTitle(); |
| final Content content = myContentManager.getFactory().createContent(getComponent(), title, false); |
| content.setTabName(title); |
| content.putUserData(ID_KEY, id); |
| content.putUserData(SUB_ID_KEY, subId); |
| content.putUserData(ToolWindow.SHOW_CONTENT_ICON, Boolean.TRUE); |
| content.setIcon(newPane.getIcon()); |
| content.setPopupIcon(subId != null ? AllIcons.General.Bullet : newPane.getIcon()); |
| content.setPreferredFocusedComponent(new Computable<JComponent>() { |
| @Override |
| public JComponent compute() { |
| final AbstractProjectViewPane current = getCurrentProjectViewPane(); |
| return current != null ? current.getComponentToFocus() : null; |
| } |
| }); |
| content.setBusyObject(this); |
| if (first && subId != null) { |
| content.setSeparator(newPane.getTitle()); |
| } |
| manager.addContent(content, index++); |
| first = false; |
| } |
| Disposer.register(this, newPane); |
| } |
| |
| private void showPane(@NotNull AbstractProjectViewPane newPane) { |
| AbstractProjectViewPane currentPane = getCurrentProjectViewPane(); |
| PsiElement selectedPsiElement = null; |
| if (currentPane != null) { |
| if (currentPane != newPane) { |
| currentPane.saveExpandedPaths(); |
| } |
| final PsiElement[] elements = currentPane.getSelectedPSIElements(); |
| if (elements.length > 0) { |
| selectedPsiElement = elements[0]; |
| } |
| } |
| myViewContentPanel.removeAll(); |
| JComponent component = newPane.createComponent(); |
| UIUtil.removeScrollBorder(component); |
| myViewContentPanel.setLayout(new BorderLayout()); |
| myViewContentPanel.add(component, BorderLayout.CENTER); |
| myCurrentViewId = newPane.getId(); |
| String newSubId = myCurrentViewSubId = newPane.getSubId(); |
| myViewContentPanel.revalidate(); |
| myViewContentPanel.repaint(); |
| createToolbarActions(); |
| updateTitleActions(); |
| |
| myAutoScrollToSourceHandler.install(newPane.myTree); |
| |
| IdeFocusManager.getInstance(myProject).requestFocus(newPane.getComponentToFocus(), false); |
| |
| newPane.restoreExpandedPaths(); |
| if (selectedPsiElement != null) { |
| final VirtualFile virtualFile = PsiUtilCore.getVirtualFile(selectedPsiElement); |
| if (virtualFile != null && ((ProjectViewSelectInTarget)newPane.createSelectInTarget()).isSubIdSelectable(newSubId, new SelectInContext() { |
| @Override |
| @NotNull |
| public Project getProject() { |
| return myProject; |
| } |
| |
| @Override |
| @NotNull |
| public VirtualFile getVirtualFile() { |
| return virtualFile; |
| } |
| |
| @Override |
| public Object getSelectorInFile() { |
| return null; |
| } |
| |
| @Override |
| public FileEditorProvider getFileEditorProvider() { |
| return null; |
| } |
| })) { |
| newPane.select(selectedPsiElement, virtualFile, true); |
| } |
| } |
| myAutoScrollToSourceHandler.onMouseClicked(newPane.myTree); |
| } |
| |
| private void updateTitleActions() { |
| final ToolWindow window = ToolWindowManager.getInstance(myProject).getToolWindow("Project"); |
| if (!(window instanceof ToolWindowEx)) return; |
| ScrollFromSourceAction scrollAction = null; |
| CollapseAllToolbarAction collapseAction = null; |
| for (AnAction action : myActionGroup.getChildren(null)) { |
| if (action instanceof ScrollFromSourceAction) { |
| scrollAction = (ScrollFromSourceAction)action; |
| myActionGroup.remove(scrollAction); |
| } |
| if (action instanceof CollapseAllToolbarAction) { |
| collapseAction = (CollapseAllToolbarAction)action; |
| collapseAction.getTemplatePresentation().setIcon(AllIcons.General.CollapseAll); |
| collapseAction.getTemplatePresentation().setHoveredIcon(AllIcons.General.CollapseAllHover); |
| myActionGroup.remove(collapseAction); |
| } |
| } |
| ((ToolWindowEx)window).setTitleActions(scrollAction, collapseAction); |
| } |
| |
| // public for tests |
| public synchronized void setupImpl(@NotNull ToolWindow toolWindow) { |
| setupImpl(toolWindow, true); |
| } |
| |
| // public for tests |
| public synchronized void setupImpl(@NotNull ToolWindow toolWindow, final boolean loadPaneExtensions) { |
| ApplicationManager.getApplication().assertIsDispatchThread(); |
| myActionGroup = new DefaultActionGroup(); |
| |
| myAutoScrollFromSourceHandler.install(); |
| |
| myContentManager = toolWindow.getContentManager(); |
| if (!ApplicationManager.getApplication().isUnitTestMode()) { |
| toolWindow.setContentUiType(ToolWindowContentUiType.COMBO, null); |
| ((ToolWindowEx)toolWindow).setAdditionalGearActions(myActionGroup); |
| toolWindow.getComponent().putClientProperty(ToolWindowContentUi.HIDE_ID_LABEL, "true"); |
| } |
| |
| GuiUtils.replaceJSplitPaneWithIDEASplitter(myPanel); |
| SwingUtilities.invokeLater(new Runnable() { |
| @Override |
| public void run() { |
| splitterProportions.restoreSplitterProportions(myPanel); |
| } |
| }); |
| |
| if (loadPaneExtensions) { |
| ensurePanesLoaded(); |
| } |
| isInitialized = true; |
| doAddUninitializedPanes(); |
| |
| myContentManager.addContentManagerListener(new ContentManagerAdapter() { |
| @Override |
| public void selectionChanged(ContentManagerEvent event) { |
| if (event.getOperation() == ContentManagerEvent.ContentOperation.add) { |
| viewSelectionChanged(); |
| } |
| } |
| }); |
| } |
| |
| private void ensurePanesLoaded() { |
| if (myExtensionsLoaded) return; |
| myExtensionsLoaded = true; |
| for(AbstractProjectViewPane pane: Extensions.getExtensions(AbstractProjectViewPane.EP_NAME, myProject)) { |
| if (myUninitializedPaneState.containsKey(pane.getId())) { |
| try { |
| pane.readExternal(myUninitializedPaneState.get(pane.getId())); |
| } |
| catch (InvalidDataException e) { |
| // ignore |
| } |
| myUninitializedPaneState.remove(pane.getId()); |
| } |
| if (pane.isInitiallyVisible() && !myId2Pane.containsKey(pane.getId())) { |
| addProjectPane(pane); |
| } |
| Disposer.register(this, pane); |
| } |
| } |
| |
| private boolean viewSelectionChanged() { |
| Content content = myContentManager.getSelectedContent(); |
| if (content == null) return false; |
| final String id = content.getUserData(ID_KEY); |
| String subId = content.getUserData(SUB_ID_KEY); |
| if (content.equals(Pair.create(myCurrentViewId, myCurrentViewSubId))) return false; |
| final AbstractProjectViewPane newPane = getProjectViewPaneById(id); |
| if (newPane == null) return false; |
| newPane.setSubId(subId); |
| showPane(newPane); |
| if (isAutoscrollFromSource(id)) { |
| myAutoScrollFromSourceHandler.scrollFromSource(); |
| } |
| return true; |
| } |
| |
| private void createToolbarActions() { |
| myActionGroup.removeAll(); |
| if (ProjectViewDirectoryHelper.getInstance(myProject).supportsFlattenPackages()) { |
| myActionGroup.addAction(new PaneOptionAction(myFlattenPackages, IdeBundle.message("action.flatten.packages"), |
| IdeBundle.message("action.flatten.packages"), PlatformIcons.FLATTEN_PACKAGES_ICON, |
| ourFlattenPackagesDefaults) { |
| @Override |
| public void setSelected(AnActionEvent event, boolean flag) { |
| final AbstractProjectViewPane viewPane = getCurrentProjectViewPane(); |
| final SelectionInfo selectionInfo = SelectionInfo.create(viewPane); |
| |
| super.setSelected(event, flag); |
| |
| selectionInfo.apply(viewPane); |
| } |
| }).setAsSecondary(true); |
| } |
| |
| class FlattenPackagesDependableAction extends PaneOptionAction { |
| FlattenPackagesDependableAction(@NotNull Map<String, Boolean> optionsMap, |
| @NotNull String text, |
| @NotNull String description, |
| @NotNull Icon icon, |
| boolean optionDefaultValue) { |
| super(optionsMap, text, description, icon, optionDefaultValue); |
| } |
| |
| @Override |
| public void update(AnActionEvent e) { |
| super.update(e); |
| final Presentation presentation = e.getPresentation(); |
| presentation.setVisible(isFlattenPackages(myCurrentViewId)); |
| } |
| } |
| if (ProjectViewDirectoryHelper.getInstance(myProject).supportsHideEmptyMiddlePackages()) { |
| myActionGroup.addAction(new HideEmptyMiddlePackagesAction()).setAsSecondary(true); |
| } |
| if (ProjectViewDirectoryHelper.getInstance(myProject).supportsFlattenPackages()) { |
| myActionGroup.addAction(new FlattenPackagesDependableAction(myAbbreviatePackageNames, |
| IdeBundle.message("action.abbreviate.qualified.package.names"), |
| IdeBundle.message("action.abbreviate.qualified.package.names"), |
| AllIcons.ObjectBrowser.AbbreviatePackageNames, |
| ourAbbreviatePackagesDefaults) { |
| @Override |
| public boolean isSelected(AnActionEvent event) { |
| return super.isSelected(event) && isAbbreviatePackageNames(myCurrentViewId); |
| } |
| |
| |
| @Override |
| public void update(AnActionEvent e) { |
| super.update(e); |
| if (ScopeViewPane.ID.equals(myCurrentViewId)) { |
| e.getPresentation().setEnabled(false); |
| } |
| } |
| }).setAsSecondary(true); |
| } |
| |
| if (isShowMembersOptionSupported()) { |
| myActionGroup.addAction(new PaneOptionAction(myShowMembers, IdeBundle.message("action.show.members"), |
| IdeBundle.message("action.show.hide.members"), |
| AllIcons.ObjectBrowser.ShowMembers, ourShowMembersDefaults)) |
| .setAsSecondary(true); |
| } |
| myActionGroup.addAction(myAutoScrollToSourceHandler.createToggleAction()).setAsSecondary(true); |
| myActionGroup.addAction(myAutoScrollFromSourceHandler.createToggleAction()).setAsSecondary(true); |
| myActionGroup.addAction(new SortByTypeAction()).setAsSecondary(true); |
| myActionGroup.addAction(new FoldersAlwaysOnTopAction()).setAsSecondary(true); |
| |
| if (!myAutoScrollFromSourceHandler.isAutoScrollEnabled()) { |
| myActionGroup.addAction(new ScrollFromSourceAction()); |
| } |
| AnAction collapseAllAction = CommonActionsManager.getInstance().createCollapseAllAction(new TreeExpander() { |
| @Override |
| public void expandAll() { |
| |
| } |
| |
| @Override |
| public boolean canExpand() { |
| return false; |
| } |
| |
| @Override |
| public void collapseAll() { |
| AbstractProjectViewPane pane = getCurrentProjectViewPane(); |
| JTree tree = pane.myTree; |
| if (tree != null) { |
| TreeUtil.collapseAll(tree, 0); |
| } |
| } |
| |
| @Override |
| public boolean canCollapse() { |
| return true; |
| } |
| }, getComponent()); |
| myActionGroup.add(collapseAllAction); |
| getCurrentProjectViewPane().addToolbarActions(myActionGroup); |
| } |
| |
| protected boolean isShowMembersOptionSupported() { |
| return true; |
| } |
| |
| @Override |
| public AbstractProjectViewPane getProjectViewPaneById(String id) { |
| if (!ApplicationManager.getApplication().isUnitTestMode()) { // most tests don't need all panes to be loaded |
| ensurePanesLoaded(); |
| } |
| |
| final AbstractProjectViewPane pane = myId2Pane.get(id); |
| if (pane != null) { |
| return pane; |
| } |
| for (AbstractProjectViewPane viewPane : myUninitializedPanes) { |
| if (viewPane.getId().equals(id)) { |
| return viewPane; |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public AbstractProjectViewPane getCurrentProjectViewPane() { |
| return getProjectViewPaneById(myCurrentViewId); |
| } |
| |
| @Override |
| public void refresh() { |
| AbstractProjectViewPane currentProjectViewPane = getCurrentProjectViewPane(); |
| if (currentProjectViewPane != null) { |
| // may be null for e.g. default project |
| currentProjectViewPane.updateFromRoot(false); |
| } |
| } |
| |
| @Override |
| public void select(final Object element, VirtualFile file, boolean requestFocus) { |
| final AbstractProjectViewPane viewPane = getCurrentProjectViewPane(); |
| if (viewPane != null) { |
| viewPane.select(element, file, requestFocus); |
| } |
| } |
| |
| @NotNull |
| @Override |
| public ActionCallback selectCB(Object element, VirtualFile file, boolean requestFocus) { |
| final AbstractProjectViewPane viewPane = getCurrentProjectViewPane(); |
| if (viewPane != null && viewPane instanceof AbstractProjectViewPSIPane) { |
| return ((AbstractProjectViewPSIPane)viewPane).selectCB(element, file, requestFocus); |
| } |
| select(element, file, requestFocus); |
| return new ActionCallback.Done(); |
| } |
| |
| @Override |
| public void dispose() { |
| myConnection.disconnect(); |
| } |
| |
| @Override |
| public JComponent getComponent() { |
| return myDataProvider; |
| } |
| |
| @Override |
| public String getCurrentViewId() { |
| return myCurrentViewId; |
| } |
| |
| @Override |
| public PsiElement getParentOfCurrentSelection() { |
| final AbstractProjectViewPane viewPane = getCurrentProjectViewPane(); |
| if (viewPane == null) { |
| return null; |
| } |
| TreePath path = viewPane.getSelectedPath(); |
| if (path == null) { |
| return null; |
| } |
| path = path.getParentPath(); |
| if (path == null) { |
| return null; |
| } |
| DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent(); |
| Object userObject = node.getUserObject(); |
| if (userObject instanceof ProjectViewNode) { |
| ProjectViewNode descriptor = (ProjectViewNode)userObject; |
| Object element = descriptor.getValue(); |
| if (element instanceof PsiElement) { |
| PsiElement psiElement = (PsiElement)element; |
| if (!psiElement.isValid()) return null; |
| return psiElement; |
| } |
| else { |
| return null; |
| } |
| } |
| return null; |
| } |
| |
| |
| private class PaneOptionAction extends ToggleAction implements DumbAware { |
| private final Map<String, Boolean> myOptionsMap; |
| private final boolean myOptionDefaultValue; |
| |
| PaneOptionAction(@NotNull Map<String, Boolean> optionsMap, |
| @NotNull String text, |
| @NotNull String description, |
| Icon icon, |
| boolean optionDefaultValue) { |
| super(text, description, icon); |
| myOptionsMap = optionsMap; |
| myOptionDefaultValue = optionDefaultValue; |
| } |
| |
| @Override |
| public boolean isSelected(AnActionEvent event) { |
| return getPaneOptionValue(myOptionsMap, myCurrentViewId, myOptionDefaultValue); |
| } |
| |
| @Override |
| public void setSelected(AnActionEvent event, boolean flag) { |
| setPaneOption(myOptionsMap, flag, myCurrentViewId, true); |
| } |
| } |
| |
| @Override |
| public void changeView() { |
| final List<AbstractProjectViewPane> views = new ArrayList<AbstractProjectViewPane>(myId2Pane.values()); |
| views.remove(getCurrentProjectViewPane()); |
| Collections.sort(views, PANE_WEIGHT_COMPARATOR); |
| |
| final JList list = new JBList(ArrayUtil.toObjectArray(views)); |
| list.setCellRenderer(new DefaultListCellRenderer() { |
| @Override |
| public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { |
| super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); |
| AbstractProjectViewPane pane = (AbstractProjectViewPane)value; |
| setText(pane.getTitle()); |
| return this; |
| } |
| }); |
| |
| if (!views.isEmpty()) { |
| list.setSelectedValue(views.get(0), true); |
| } |
| Runnable runnable = new Runnable() { |
| @Override |
| public void run() { |
| if (list.getSelectedIndex() < 0) return; |
| AbstractProjectViewPane pane = (AbstractProjectViewPane)list.getSelectedValue(); |
| changeView(pane.getId()); |
| } |
| }; |
| |
| new PopupChooserBuilder(list). |
| setTitle(IdeBundle.message("title.popup.views")). |
| setItemChoosenCallback(runnable). |
| createPopup().showInCenterOf(getComponent()); |
| } |
| |
| @Override |
| public void changeView(@NotNull String viewId) { |
| changeView(viewId, null); |
| } |
| |
| @Override |
| public void changeView(@NotNull String viewId, @Nullable String subId) { |
| AbstractProjectViewPane pane = getProjectViewPaneById(viewId); |
| LOG.assertTrue(pane != null, "Project view pane not found: " + viewId + "; subId:" + subId); |
| if (!viewId.equals(getCurrentViewId()) |
| || subId != null && !subId.equals(pane.getSubId())) { |
| for (Content content : myContentManager.getContents()) { |
| if (viewId.equals(content.getUserData(ID_KEY)) && StringUtil.equals(subId, content.getUserData(SUB_ID_KEY))) { |
| myContentManager.setSelectedContent(content); |
| break; |
| } |
| } |
| viewSelectionChanged(); |
| } |
| } |
| |
| private final class MyDeletePSIElementProvider implements DeleteProvider { |
| @Override |
| public boolean canDeleteElement(@NotNull DataContext dataContext) { |
| final PsiElement[] elements = getElementsToDelete(); |
| return DeleteHandler.shouldEnableDeleteAction(elements); |
| } |
| |
| @Override |
| public void deleteElement(@NotNull DataContext dataContext) { |
| List<PsiElement> allElements = Arrays.asList(getElementsToDelete()); |
| List<PsiElement> validElements = new ArrayList<PsiElement>(); |
| for (PsiElement psiElement : allElements) { |
| if (psiElement != null && psiElement.isValid()) validElements.add(psiElement); |
| } |
| final PsiElement[] elements = PsiUtilCore.toPsiElementArray(validElements); |
| |
| LocalHistoryAction a = LocalHistory.getInstance().startAction(IdeBundle.message("progress.deleting")); |
| try { |
| DeleteHandler.deletePsiElement(elements, myProject); |
| } |
| finally { |
| a.finish(); |
| } |
| } |
| |
| @NotNull |
| private PsiElement[] getElementsToDelete() { |
| final AbstractProjectViewPane viewPane = getCurrentProjectViewPane(); |
| PsiElement[] elements = viewPane.getSelectedPSIElements(); |
| for (int idx = 0; idx < elements.length; idx++) { |
| final PsiElement element = elements[idx]; |
| if (element instanceof PsiDirectory) { |
| PsiDirectory directory = (PsiDirectory)element; |
| final ProjectViewDirectoryHelper directoryHelper = ProjectViewDirectoryHelper.getInstance(myProject); |
| if (isHideEmptyMiddlePackages(viewPane.getId()) && directory.getChildren().length == 0 && !directoryHelper.skipDirectory(directory)) { |
| while (true) { |
| PsiDirectory parent = directory.getParentDirectory(); |
| if (parent == null) break; |
| if (directoryHelper.skipDirectory(parent) || PsiDirectoryFactory.getInstance(myProject).getQualifiedName(parent, false).length() == 0) break; |
| PsiElement[] children = parent.getChildren(); |
| if (children.length == 0 || children.length == 1 && children[0] == directory) { |
| directory = parent; |
| } |
| else { |
| break; |
| } |
| } |
| elements[idx] = directory; |
| } |
| final VirtualFile virtualFile = directory.getVirtualFile(); |
| final String path = virtualFile.getPath(); |
| if (path.endsWith(JarFileSystem.JAR_SEPARATOR)) { // if is jar-file root |
| final VirtualFile vFile = |
| LocalFileSystem.getInstance().findFileByPath(path.substring(0, path.length() - JarFileSystem.JAR_SEPARATOR.length())); |
| if (vFile != null) { |
| final PsiFile psiFile = PsiManager.getInstance(myProject).findFile(vFile); |
| if (psiFile != null) { |
| elements[idx] = psiFile; |
| } |
| } |
| } |
| } |
| } |
| return elements; |
| } |
| |
| } |
| |
| private final class MyPanel extends JPanel implements DataProvider { |
| MyPanel() { |
| super(new BorderLayout()); |
| } |
| |
| @Nullable |
| private Object getSelectedNodeElement() { |
| final AbstractProjectViewPane currentProjectViewPane = getCurrentProjectViewPane(); |
| if (currentProjectViewPane == null) { // can happen if not initialized yet |
| return null; |
| } |
| DefaultMutableTreeNode node = currentProjectViewPane.getSelectedNode(); |
| if (node == null) { |
| return null; |
| } |
| Object userObject = node.getUserObject(); |
| if (userObject instanceof AbstractTreeNode) { |
| return ((AbstractTreeNode)userObject).getValue(); |
| } |
| if (!(userObject instanceof NodeDescriptor)) { |
| return null; |
| } |
| return ((NodeDescriptor)userObject).getElement(); |
| } |
| |
| @Override |
| public Object getData(String dataId) { |
| final AbstractProjectViewPane currentProjectViewPane = getCurrentProjectViewPane(); |
| if (currentProjectViewPane != null) { |
| final Object paneSpecificData = currentProjectViewPane.getData(dataId); |
| if (paneSpecificData != null) return paneSpecificData; |
| } |
| |
| if (CommonDataKeys.PSI_ELEMENT.is(dataId)) { |
| if (currentProjectViewPane == null) return null; |
| final PsiElement[] elements = currentProjectViewPane.getSelectedPSIElements(); |
| return elements.length == 1 ? elements[0] : null; |
| } |
| if (LangDataKeys.PSI_ELEMENT_ARRAY.is(dataId)) { |
| if (currentProjectViewPane == null) { |
| return null; |
| } |
| PsiElement[] elements = currentProjectViewPane.getSelectedPSIElements(); |
| return elements.length == 0 ? null : elements; |
| } |
| if (LangDataKeys.MODULE.is(dataId)) { |
| VirtualFile[] virtualFiles = (VirtualFile[])getData(CommonDataKeys.VIRTUAL_FILE_ARRAY.getName()); |
| if (virtualFiles == null || virtualFiles.length <= 1) return null; |
| final Set<Module> modules = new HashSet<Module>(); |
| for (VirtualFile virtualFile : virtualFiles) { |
| modules.add(ModuleUtilCore.findModuleForFile(virtualFile, myProject)); |
| } |
| return modules.size() == 1 ? modules.iterator().next() : null; |
| } |
| if (LangDataKeys.TARGET_PSI_ELEMENT.is(dataId)) { |
| return null; |
| } |
| if (PlatformDataKeys.CUT_PROVIDER.is(dataId)) { |
| return myCopyPasteDelegator.getCutProvider(); |
| } |
| if (PlatformDataKeys.COPY_PROVIDER.is(dataId)) { |
| return myCopyPasteDelegator.getCopyProvider(); |
| } |
| if (PlatformDataKeys.PASTE_PROVIDER.is(dataId)) { |
| return myCopyPasteDelegator.getPasteProvider(); |
| } |
| if (LangDataKeys.IDE_VIEW.is(dataId)) { |
| return myIdeView; |
| } |
| if (PlatformDataKeys.DELETE_ELEMENT_PROVIDER.is(dataId)) { |
| final Module[] modules = getSelectedModules(); |
| if (modules != null) { |
| return myDeleteModuleProvider; |
| } |
| final LibraryOrderEntry orderEntry = getSelectedLibrary(); |
| if (orderEntry != null) { |
| return new DeleteProvider() { |
| @Override |
| public void deleteElement(@NotNull DataContext dataContext) { |
| detachLibrary(orderEntry, myProject); |
| } |
| |
| @Override |
| public boolean canDeleteElement(@NotNull DataContext dataContext) { |
| return true; |
| } |
| }; |
| } |
| return myDeletePSIElementProvider; |
| } |
| if (PlatformDataKeys.HELP_ID.is(dataId)) { |
| return HelpID.PROJECT_VIEWS; |
| } |
| if (ProjectViewImpl.DATA_KEY.is(dataId)) { |
| return ProjectViewImpl.this; |
| } |
| if (PlatformDataKeys.PROJECT_CONTEXT.is(dataId)) { |
| Object selected = getSelectedNodeElement(); |
| return selected instanceof Project ? selected : null; |
| } |
| if (LangDataKeys.MODULE_CONTEXT.is(dataId)) { |
| Object selected = getSelectedNodeElement(); |
| if (selected instanceof Module) { |
| return !((Module)selected).isDisposed() ? selected : null; |
| } |
| else if (selected instanceof PsiDirectory) { |
| return moduleBySingleContentRoot(((PsiDirectory)selected).getVirtualFile()); |
| } |
| else if (selected instanceof VirtualFile) { |
| return moduleBySingleContentRoot((VirtualFile)selected); |
| } |
| else { |
| return null; |
| } |
| } |
| |
| if (LangDataKeys.MODULE_CONTEXT_ARRAY.is(dataId)) { |
| return getSelectedModules(); |
| } |
| if (ModuleGroup.ARRAY_DATA_KEY.is(dataId)) { |
| final List<ModuleGroup> selectedElements = getSelectedElements(ModuleGroup.class); |
| return selectedElements.isEmpty() ? null : selectedElements.toArray(new ModuleGroup[selectedElements.size()]); |
| } |
| if (LibraryGroupElement.ARRAY_DATA_KEY.is(dataId)) { |
| final List<LibraryGroupElement> selectedElements = getSelectedElements(LibraryGroupElement.class); |
| return selectedElements.isEmpty() ? null : selectedElements.toArray(new LibraryGroupElement[selectedElements.size()]); |
| } |
| if (NamedLibraryElement.ARRAY_DATA_KEY.is(dataId)) { |
| final List<NamedLibraryElement> selectedElements = getSelectedElements(NamedLibraryElement.class); |
| return selectedElements.isEmpty() ? null : selectedElements.toArray(new NamedLibraryElement[selectedElements.size()]); |
| } |
| |
| if (QuickActionProvider.KEY.is(dataId)) { |
| return ProjectViewImpl.this; |
| } |
| |
| return null; |
| } |
| |
| @Nullable |
| private LibraryOrderEntry getSelectedLibrary() { |
| final AbstractProjectViewPane viewPane = getCurrentProjectViewPane(); |
| DefaultMutableTreeNode node = viewPane != null ? viewPane.getSelectedNode() : null; |
| if (node == null) return null; |
| DefaultMutableTreeNode parent = (DefaultMutableTreeNode)node.getParent(); |
| if (parent == null) return null; |
| Object userObject = parent.getUserObject(); |
| if (userObject instanceof LibraryGroupNode) { |
| userObject = node.getUserObject(); |
| if (userObject instanceof NamedLibraryElementNode) { |
| NamedLibraryElement element = ((NamedLibraryElementNode)userObject).getValue(); |
| OrderEntry orderEntry = element.getOrderEntry(); |
| return orderEntry instanceof LibraryOrderEntry ? (LibraryOrderEntry)orderEntry : null; |
| } |
| PsiDirectory directory = ((PsiDirectoryNode)userObject).getValue(); |
| VirtualFile virtualFile = directory.getVirtualFile(); |
| Module module = (Module)((AbstractTreeNode)((DefaultMutableTreeNode)parent.getParent()).getUserObject()).getValue(); |
| |
| if (module == null) return null; |
| ModuleFileIndex index = ModuleRootManager.getInstance(module).getFileIndex(); |
| OrderEntry entry = index.getOrderEntryForFile(virtualFile); |
| if (entry instanceof LibraryOrderEntry) { |
| return (LibraryOrderEntry)entry; |
| } |
| } |
| |
| return null; |
| } |
| |
| private void detachLibrary(@NotNull final LibraryOrderEntry orderEntry, @NotNull Project project) { |
| final Module module = orderEntry.getOwnerModule(); |
| String message = IdeBundle.message("detach.library.from.module", orderEntry.getPresentableName(), module.getName()); |
| String title = IdeBundle.message("detach.library"); |
| int ret = Messages.showOkCancelDialog(project, message, title, Messages.getQuestionIcon()); |
| if (ret != Messages.OK) return; |
| CommandProcessor.getInstance().executeCommand(module.getProject(), new Runnable() { |
| @Override |
| public void run() { |
| final Runnable action = new Runnable() { |
| @Override |
| public void run() { |
| ModuleRootManager rootManager = ModuleRootManager.getInstance(module); |
| OrderEntry[] orderEntries = rootManager.getOrderEntries(); |
| ModifiableRootModel model = rootManager.getModifiableModel(); |
| OrderEntry[] modifiableEntries = model.getOrderEntries(); |
| for (int i = 0; i < orderEntries.length; i++) { |
| OrderEntry entry = orderEntries[i]; |
| if (entry instanceof LibraryOrderEntry && ((LibraryOrderEntry)entry).getLibrary() == orderEntry.getLibrary()) { |
| model.removeOrderEntry(modifiableEntries[i]); |
| } |
| } |
| model.commit(); |
| } |
| }; |
| ApplicationManager.getApplication().runWriteAction(action); |
| } |
| }, title, null); |
| } |
| |
| @Nullable |
| private Module[] getSelectedModules() { |
| final AbstractProjectViewPane viewPane = getCurrentProjectViewPane(); |
| if (viewPane == null) return null; |
| final Object[] elements = viewPane.getSelectedElements(); |
| ArrayList<Module> result = new ArrayList<Module>(); |
| for (Object element : elements) { |
| if (element instanceof Module) { |
| final Module module = (Module)element; |
| if (!module.isDisposed()) { |
| result.add(module); |
| } |
| } |
| else if (element instanceof ModuleGroup) { |
| Collection<Module> modules = ((ModuleGroup)element).modulesInGroup(myProject, true); |
| result.addAll(modules); |
| } |
| else if (element instanceof PsiDirectory) { |
| Module module = moduleBySingleContentRoot(((PsiDirectory)element).getVirtualFile()); |
| if (module != null) result.add(module); |
| } |
| else if (element instanceof VirtualFile) { |
| Module module = moduleBySingleContentRoot((VirtualFile)element); |
| if (module != null) result.add(module); |
| } |
| } |
| |
| if (result.isEmpty()) { |
| return null; |
| } |
| else { |
| return result.toArray(new Module[result.size()]); |
| } |
| } |
| } |
| |
| /** Project view has the same node for module and its single content root |
| * => MODULE_CONTEXT data key should return the module when its content root is selected |
| * When there are multiple content roots, they have different nodes under the module node |
| * => MODULE_CONTEXT should be only available for the module node |
| * otherwise VirtualFileArrayRule will return all module's content roots when just one of them is selected |
| */ |
| @Nullable |
| private Module moduleBySingleContentRoot(@NotNull VirtualFile file) { |
| if (ProjectRootsUtil.isModuleContentRoot(file, myProject)) { |
| Module module = ProjectRootManager.getInstance(myProject).getFileIndex().getModuleForFile(file); |
| if (module != null && !module.isDisposed() && ModuleRootManager.getInstance(module).getContentRoots().length == 1) { |
| return module; |
| } |
| } |
| |
| return null; |
| } |
| |
| @NotNull |
| private <T> List<T> getSelectedElements(@NotNull Class<T> klass) { |
| List<T> result = new ArrayList<T>(); |
| final AbstractProjectViewPane viewPane = getCurrentProjectViewPane(); |
| if (viewPane == null) return result; |
| final Object[] elements = viewPane.getSelectedElements(); |
| for (Object element : elements) { |
| //element still valid |
| if (element != null && klass.isAssignableFrom(element.getClass())) { |
| result.add((T)element); |
| } |
| } |
| return result; |
| } |
| |
| private final class MyIdeView implements IdeView { |
| @Override |
| public void selectElement(PsiElement element) { |
| selectPsiElement(element, false); |
| boolean requestFocus = true; |
| if (element != null) { |
| final boolean isDirectory = element instanceof PsiDirectory; |
| if (!isDirectory) { |
| FileEditor editor = EditorHelper.openInEditor(element, false); |
| if (editor != null) { |
| ToolWindowManager.getInstance(myProject).activateEditorComponent(); |
| requestFocus = false; |
| } |
| } |
| } |
| |
| if (requestFocus) { |
| selectPsiElement(element, true); |
| } |
| } |
| |
| @NotNull |
| @Override |
| public PsiDirectory[] getDirectories() { |
| final AbstractProjectViewPane viewPane = getCurrentProjectViewPane(); |
| if (viewPane != null) { |
| return viewPane.getSelectedDirectories(); |
| } |
| |
| return PsiDirectory.EMPTY_ARRAY; |
| } |
| |
| @Override |
| public PsiDirectory getOrChooseDirectory() { |
| return DirectoryChooserUtil.getOrChooseDirectory(this); |
| } |
| } |
| |
| @Override |
| public void selectPsiElement(PsiElement element, boolean requestFocus) { |
| if (element == null) return; |
| VirtualFile virtualFile = PsiUtilCore.getVirtualFile(element); |
| select(element, virtualFile, requestFocus); |
| } |
| |
| |
| private static void readOption(Element node, @NotNull Map<String, Boolean> options) { |
| if (node == null) return; |
| List attributes = node.getAttributes(); |
| for (final Object attribute1 : attributes) { |
| Attribute attribute = (Attribute)attribute1; |
| options.put(attribute.getName(), Boolean.TRUE.toString().equals(attribute.getValue()) ? Boolean.TRUE : Boolean.FALSE); |
| } |
| } |
| |
| private static void writeOption(@NotNull Element parentNode, @NotNull Map<String, Boolean> optionsForPanes, @NotNull String optionName) { |
| Element e = new Element(optionName); |
| for (Map.Entry<String, Boolean> entry : optionsForPanes.entrySet()) { |
| final String key = entry.getKey(); |
| if (key != null) { //SCR48267 |
| e.setAttribute(key, Boolean.toString(entry.getValue().booleanValue())); |
| } |
| } |
| |
| parentNode.addContent(e); |
| } |
| |
| @Override |
| public void loadState(Element parentNode) { |
| Element navigatorElement = parentNode.getChild(ELEMENT_NAVIGATOR); |
| if (navigatorElement != null) { |
| mySavedPaneId = navigatorElement.getAttributeValue(ATTRIBUTE_CURRENT_VIEW); |
| mySavedPaneSubId = navigatorElement.getAttributeValue(ATTRIBUTE_CURRENT_SUBVIEW); |
| if (mySavedPaneId == null) { |
| mySavedPaneId = ProjectViewPane.ID; |
| mySavedPaneSubId = null; |
| } |
| readOption(navigatorElement.getChild(ELEMENT_FLATTEN_PACKAGES), myFlattenPackages); |
| readOption(navigatorElement.getChild(ELEMENT_SHOW_MEMBERS), myShowMembers); |
| readOption(navigatorElement.getChild(ELEMENT_SHOW_MODULES), myShowModules); |
| readOption(navigatorElement.getChild(ELEMENT_SHOW_LIBRARY_CONTENTS), myShowLibraryContents); |
| readOption(navigatorElement.getChild(ELEMENT_HIDE_EMPTY_PACKAGES), myHideEmptyPackages); |
| readOption(navigatorElement.getChild(ELEMENT_ABBREVIATE_PACKAGE_NAMES), myAbbreviatePackageNames); |
| readOption(navigatorElement.getChild(ELEMENT_AUTOSCROLL_TO_SOURCE), myAutoscrollToSource); |
| readOption(navigatorElement.getChild(ELEMENT_AUTOSCROLL_FROM_SOURCE), myAutoscrollFromSource); |
| readOption(navigatorElement.getChild(ELEMENT_SORT_BY_TYPE), mySortByType); |
| |
| try { |
| splitterProportions.readExternal(navigatorElement); |
| } |
| catch (InvalidDataException e) { |
| // ignore |
| } |
| } |
| Element panesElement = parentNode.getChild(ELEMENT_PANES); |
| if (panesElement != null) { |
| readPaneState(panesElement); |
| } |
| } |
| |
| private void readPaneState(@NotNull Element panesElement) { |
| @SuppressWarnings({"unchecked"}) |
| final List<Element> paneElements = panesElement.getChildren(ELEMENT_PANE); |
| |
| for (Element paneElement : paneElements) { |
| String paneId = paneElement.getAttributeValue(ATTRIBUTE_ID); |
| final AbstractProjectViewPane pane = myId2Pane.get(paneId); |
| if (pane != null) { |
| try { |
| pane.readExternal(paneElement); |
| } |
| catch (InvalidDataException e) { |
| // ignore |
| } |
| } |
| else { |
| myUninitializedPaneState.put(paneId, paneElement); |
| } |
| } |
| } |
| |
| @Override |
| public Element getState() { |
| Element parentNode = new Element("projectView"); |
| Element navigatorElement = new Element(ELEMENT_NAVIGATOR); |
| AbstractProjectViewPane currentPane = getCurrentProjectViewPane(); |
| if (currentPane != null) { |
| navigatorElement.setAttribute(ATTRIBUTE_CURRENT_VIEW, currentPane.getId()); |
| String subId = currentPane.getSubId(); |
| if (subId != null) { |
| navigatorElement.setAttribute(ATTRIBUTE_CURRENT_SUBVIEW, subId); |
| } |
| } |
| writeOption(navigatorElement, myFlattenPackages, ELEMENT_FLATTEN_PACKAGES); |
| writeOption(navigatorElement, myShowMembers, ELEMENT_SHOW_MEMBERS); |
| writeOption(navigatorElement, myShowModules, ELEMENT_SHOW_MODULES); |
| writeOption(navigatorElement, myShowLibraryContents, ELEMENT_SHOW_LIBRARY_CONTENTS); |
| writeOption(navigatorElement, myHideEmptyPackages, ELEMENT_HIDE_EMPTY_PACKAGES); |
| writeOption(navigatorElement, myAbbreviatePackageNames, ELEMENT_ABBREVIATE_PACKAGE_NAMES); |
| writeOption(navigatorElement, myAutoscrollToSource, ELEMENT_AUTOSCROLL_TO_SOURCE); |
| writeOption(navigatorElement, myAutoscrollFromSource, ELEMENT_AUTOSCROLL_FROM_SOURCE); |
| writeOption(navigatorElement, mySortByType, ELEMENT_SORT_BY_TYPE); |
| |
| splitterProportions.saveSplitterProportions(myPanel); |
| try { |
| splitterProportions.writeExternal(navigatorElement); |
| } |
| catch (WriteExternalException e) { |
| // ignore |
| } |
| parentNode.addContent(navigatorElement); |
| |
| Element panesElement = new Element(ELEMENT_PANES); |
| writePaneState(panesElement); |
| parentNode.addContent(panesElement); |
| return parentNode; |
| } |
| |
| private void writePaneState(@NotNull Element panesElement) { |
| for (AbstractProjectViewPane pane : myId2Pane.values()) { |
| Element paneElement = new Element(ELEMENT_PANE); |
| paneElement.setAttribute(ATTRIBUTE_ID, pane.getId()); |
| try { |
| pane.writeExternal(paneElement); |
| } |
| catch (WriteExternalException e) { |
| continue; |
| } |
| panesElement.addContent(paneElement); |
| } |
| for (Element element : myUninitializedPaneState.values()) { |
| panesElement.addContent(element.clone()); |
| } |
| } |
| |
| @Override |
| public boolean isAutoscrollToSource(String paneId) { |
| return getPaneOptionValue(myAutoscrollToSource, paneId, UISettings.getInstance().DEFAULT_AUTOSCROLL_TO_SOURCE); |
| } |
| |
| public void setAutoscrollToSource(boolean autoscrollMode, String paneId) { |
| myAutoscrollToSource.put(paneId, autoscrollMode ? Boolean.TRUE : Boolean.FALSE); |
| } |
| |
| @Override |
| public boolean isAutoscrollFromSource(String paneId) { |
| return getPaneOptionValue(myAutoscrollFromSource, paneId, ourAutoscrollFromSourceDefaults); |
| } |
| |
| public void setAutoscrollFromSource(boolean autoscrollMode, String paneId) { |
| setPaneOption(myAutoscrollFromSource, autoscrollMode, paneId, false); |
| } |
| |
| @Override |
| public boolean isFlattenPackages(String paneId) { |
| return getPaneOptionValue(myFlattenPackages, paneId, ourFlattenPackagesDefaults); |
| } |
| |
| public void setFlattenPackages(boolean flattenPackages, String paneId) { |
| setPaneOption(myFlattenPackages, flattenPackages, paneId, true); |
| } |
| |
| public boolean isFoldersAlwaysOnTop() { |
| return myFoldersAlwaysOnTop; |
| } |
| |
| public void setFoldersAlwaysOnTop(boolean foldersAlwaysOnTop) { |
| if (myFoldersAlwaysOnTop != foldersAlwaysOnTop) { |
| myFoldersAlwaysOnTop = foldersAlwaysOnTop; |
| for (AbstractProjectViewPane pane : myId2Pane.values()) { |
| if (pane.getTree() != null) { |
| pane.updateFromRoot(false); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public boolean isShowMembers(String paneId) { |
| return getPaneOptionValue(myShowMembers, paneId, ourShowMembersDefaults); |
| } |
| |
| public void setShowMembers(boolean showMembers, String paneId) { |
| setPaneOption(myShowMembers, showMembers, paneId, true); |
| } |
| |
| @Override |
| public boolean isHideEmptyMiddlePackages(String paneId) { |
| return getPaneOptionValue(myHideEmptyPackages, paneId, ourHideEmptyPackagesDefaults); |
| } |
| |
| @Override |
| public boolean isAbbreviatePackageNames(String paneId) { |
| return getPaneOptionValue(myAbbreviatePackageNames, paneId, ourAbbreviatePackagesDefaults); |
| } |
| |
| @Override |
| public boolean isShowLibraryContents(String paneId) { |
| return getPaneOptionValue(myShowLibraryContents, paneId, ourShowLibraryContentsDefaults); |
| } |
| |
| @Override |
| public void setShowLibraryContents(boolean showLibraryContents, @NotNull String paneId) { |
| setPaneOption(myShowLibraryContents, showLibraryContents, paneId, true); |
| } |
| |
| @NotNull |
| public ActionCallback setShowLibraryContentsCB(boolean showLibraryContents, String paneId) { |
| return setPaneOption(myShowLibraryContents, showLibraryContents, paneId, true); |
| } |
| |
| @Override |
| public boolean isShowModules(String paneId) { |
| return getPaneOptionValue(myShowModules, paneId, ourShowModulesDefaults); |
| } |
| |
| @Override |
| public void setShowModules(boolean showModules, @NotNull String paneId) { |
| setPaneOption(myShowModules, showModules, paneId, true); |
| } |
| |
| @Override |
| public void setHideEmptyPackages(boolean hideEmptyPackages, @NotNull String paneId) { |
| setPaneOption(myHideEmptyPackages, hideEmptyPackages, paneId, true); |
| } |
| |
| @Override |
| public void setAbbreviatePackageNames(boolean abbreviatePackageNames, @NotNull String paneId) { |
| setPaneOption(myAbbreviatePackageNames, abbreviatePackageNames, paneId, true); |
| } |
| |
| @NotNull |
| private ActionCallback setPaneOption(@NotNull Map<String, Boolean> optionsMap, boolean value, String paneId, final boolean updatePane) { |
| optionsMap.put(paneId, value ? Boolean.TRUE : Boolean.FALSE); |
| if (updatePane) { |
| final AbstractProjectViewPane pane = getProjectViewPaneById(paneId); |
| if (pane != null) { |
| return pane.updateFromRoot(false); |
| } |
| } |
| return new ActionCallback.Done(); |
| } |
| |
| private static boolean getPaneOptionValue(@NotNull Map<String, Boolean> optionsMap, String paneId, boolean defaultValue) { |
| final Boolean value = optionsMap.get(paneId); |
| return value == null ? defaultValue : value.booleanValue(); |
| } |
| |
| private class HideEmptyMiddlePackagesAction extends PaneOptionAction { |
| private HideEmptyMiddlePackagesAction() { |
| super(myHideEmptyPackages, "", "", null, ourHideEmptyPackagesDefaults); |
| } |
| |
| @Override |
| public void setSelected(AnActionEvent event, boolean flag) { |
| final AbstractProjectViewPane viewPane = getCurrentProjectViewPane(); |
| final SelectionInfo selectionInfo = SelectionInfo.create(viewPane); |
| |
| super.setSelected(event, flag); |
| |
| selectionInfo.apply(viewPane); |
| } |
| |
| @Override |
| public void update(AnActionEvent e) { |
| super.update(e); |
| final Presentation presentation = e.getPresentation(); |
| if (isFlattenPackages(myCurrentViewId)) { |
| presentation.setText(IdeBundle.message("action.hide.empty.middle.packages")); |
| presentation.setDescription(IdeBundle.message("action.show.hide.empty.middle.packages")); |
| } |
| else { |
| presentation.setText(IdeBundle.message("action.compact.empty.middle.packages")); |
| presentation.setDescription(IdeBundle.message("action.show.compact.empty.middle.packages")); |
| } |
| } |
| } |
| |
| private static class SelectionInfo { |
| private final Object[] myElements; |
| |
| private SelectionInfo(@NotNull Object[] elements) { |
| myElements = elements; |
| } |
| |
| public void apply(final AbstractProjectViewPane viewPane) { |
| if (viewPane == null) { |
| return; |
| } |
| AbstractTreeBuilder treeBuilder = viewPane.getTreeBuilder(); |
| JTree tree = viewPane.myTree; |
| DefaultTreeModel treeModel = (DefaultTreeModel)tree.getModel(); |
| List<TreePath> paths = new ArrayList<TreePath>(myElements.length); |
| for (final Object element : myElements) { |
| DefaultMutableTreeNode node = treeBuilder.getNodeForElement(element); |
| if (node == null) { |
| treeBuilder.buildNodeForElement(element); |
| node = treeBuilder.getNodeForElement(element); |
| } |
| if (node != null) { |
| paths.add(new TreePath(treeModel.getPathToRoot(node))); |
| } |
| } |
| if (!paths.isEmpty()) { |
| tree.setSelectionPaths(paths.toArray(new TreePath[paths.size()])); |
| } |
| } |
| |
| @NotNull |
| public static SelectionInfo create(final AbstractProjectViewPane viewPane) { |
| List<Object> selectedElements = Collections.emptyList(); |
| if (viewPane != null) { |
| final TreePath[] selectionPaths = viewPane.getSelectionPaths(); |
| if (selectionPaths != null) { |
| selectedElements = new ArrayList<Object>(); |
| for (TreePath path : selectionPaths) { |
| final DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent(); |
| final Object userObject = node.getUserObject(); |
| if (userObject instanceof NodeDescriptor) { |
| selectedElements.add(((NodeDescriptor)userObject).getElement()); |
| } |
| } |
| } |
| } |
| return new SelectionInfo(selectedElements.toArray()); |
| } |
| } |
| |
| private class MyAutoScrollFromSourceHandler extends AutoScrollFromSourceHandler { |
| private MyAutoScrollFromSourceHandler() { |
| super(ProjectViewImpl.this.myProject, myViewContentPanel, ProjectViewImpl.this); |
| } |
| |
| @Override |
| protected void selectElementFromEditor(@NotNull FileEditor fileEditor) { |
| if (myProject.isDisposed() || !myViewContentPanel.isShowing()) return; |
| if (isAutoscrollFromSource(getCurrentViewId())) { |
| if (fileEditor instanceof TextEditor) { |
| Editor editor = ((TextEditor)fileEditor).getEditor(); |
| selectElementAtCaretNotLosingFocus(editor); |
| } |
| else { |
| final VirtualFile file = FileEditorManagerEx.getInstanceEx(myProject).getFile(fileEditor); |
| if (file != null) { |
| final PsiFile psiFile = PsiManager.getInstance(myProject).findFile(file); |
| if (psiFile != null) { |
| final SelectInTarget target = mySelectInTargets.get(getCurrentViewId()); |
| if (target != null) { |
| final MySelectInContext selectInContext = new MySelectInContext(psiFile, null) { |
| @Override |
| public Object getSelectorInFile() { |
| return psiFile; |
| } |
| }; |
| |
| if (target.canSelect(selectInContext)) { |
| target.selectIn(selectInContext, false); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| public void scrollFromSource() { |
| final FileEditorManager fileEditorManager = FileEditorManager.getInstance(myProject); |
| final Editor selectedTextEditor = fileEditorManager.getSelectedTextEditor(); |
| if (selectedTextEditor != null) { |
| selectElementAtCaret(selectedTextEditor); |
| return; |
| } |
| final FileEditor[] editors = fileEditorManager.getSelectedEditors(); |
| for (FileEditor fileEditor : editors) { |
| if (fileEditor instanceof TextEditor) { |
| Editor editor = ((TextEditor)fileEditor).getEditor(); |
| selectElementAtCaret(editor); |
| return; |
| } |
| } |
| final VirtualFile[] selectedFiles = fileEditorManager.getSelectedFiles(); |
| if (selectedFiles.length > 0) { |
| final PsiFile file = PsiManager.getInstance(myProject).findFile(selectedFiles[0]); |
| if (file != null) { |
| scrollFromFile(file, null); |
| } |
| } |
| } |
| |
| private void selectElementAtCaretNotLosingFocus(@NotNull Editor editor) { |
| if (IJSwingUtilities.hasFocus(getCurrentProjectViewPane().getComponentToFocus())) return; |
| selectElementAtCaret(editor); |
| } |
| |
| private void selectElementAtCaret(@NotNull Editor editor) { |
| final PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(editor.getDocument()); |
| if (file == null) return; |
| |
| scrollFromFile(file, editor); |
| } |
| |
| private void scrollFromFile(@NotNull PsiFile file, @Nullable Editor editor) { |
| final MySelectInContext selectInContext = new MySelectInContext(file, editor); |
| |
| final SelectInTarget target = mySelectInTargets.get(getCurrentViewId()); |
| if (target != null && target.canSelect(selectInContext)) { |
| target.selectIn(selectInContext, false); |
| } |
| } |
| |
| @Override |
| protected boolean isAutoScrollEnabled() { |
| return isAutoscrollFromSource(myCurrentViewId); |
| } |
| |
| @Override |
| protected void setAutoScrollEnabled(boolean state) { |
| setAutoscrollFromSource(state, myCurrentViewId); |
| if (state) { |
| final Editor editor = myFileEditorManager.getSelectedTextEditor(); |
| if (editor != null) { |
| selectElementAtCaretNotLosingFocus(editor); |
| } |
| } |
| createToolbarActions(); |
| updateTitleActions(); |
| } |
| |
| private class MySelectInContext implements SelectInContext { |
| @NotNull private final PsiFile myPsiFile; |
| @Nullable private final Editor myEditor; |
| |
| private MySelectInContext(@NotNull PsiFile psiFile, @Nullable Editor editor) { |
| myPsiFile = psiFile; |
| myEditor = editor; |
| } |
| |
| @Override |
| @NotNull |
| public Project getProject() { |
| return myProject; |
| } |
| |
| @NotNull |
| private PsiFile getPsiFile() { |
| return myPsiFile; |
| } |
| |
| @Override |
| @NotNull |
| public FileEditorProvider getFileEditorProvider() { |
| return new FileEditorProvider() { |
| @Override |
| public FileEditor openFileEditor() { |
| return myFileEditorManager.openFile(myPsiFile.getContainingFile().getVirtualFile(), false)[0]; |
| } |
| }; |
| } |
| |
| @NotNull |
| private PsiElement getPsiElement() { |
| PsiElement e = null; |
| if (myEditor != null) { |
| final int offset = myEditor.getCaretModel().getOffset(); |
| PsiDocumentManager.getInstance(myProject).commitAllDocuments(); |
| e = getPsiFile().findElementAt(offset); |
| } |
| if (e == null) { |
| e = getPsiFile(); |
| } |
| return e; |
| } |
| |
| @Override |
| @NotNull |
| public VirtualFile getVirtualFile() { |
| return getPsiFile().getVirtualFile(); |
| } |
| |
| @Override |
| public Object getSelectorInFile() { |
| return getPsiElement(); |
| } |
| } |
| } |
| |
| @Override |
| public boolean isSortByType(String paneId) { |
| return getPaneOptionValue(mySortByType, paneId, ourSortByTypeDefaults); |
| } |
| |
| @Override |
| public void setSortByType(@NotNull String paneId, final boolean sortByType) { |
| setPaneOption(mySortByType, sortByType, paneId, false); |
| final AbstractProjectViewPane pane = getProjectViewPaneById(paneId); |
| pane.installComparator(); |
| } |
| |
| private class SortByTypeAction extends ToggleAction { |
| private SortByTypeAction() { |
| super(IdeBundle.message("action.sort.by.type"), IdeBundle.message("action.sort.by.type"), AllIcons.ObjectBrowser.SortByType); |
| } |
| |
| @Override |
| public boolean isSelected(AnActionEvent event) { |
| return isSortByType(getCurrentViewId()); |
| } |
| |
| @Override |
| public void setSelected(AnActionEvent event, boolean flag) { |
| setSortByType(getCurrentViewId(), flag); |
| } |
| |
| @Override |
| public void update(final AnActionEvent e) { |
| super.update(e); |
| final Presentation presentation = e.getPresentation(); |
| presentation.setVisible(getCurrentProjectViewPane() != null); |
| } |
| } |
| |
| private class FoldersAlwaysOnTopAction extends ToggleAction { |
| private FoldersAlwaysOnTopAction() { |
| super("Folders Always on Top"); |
| } |
| |
| @Override |
| public boolean isSelected(AnActionEvent event) { |
| return isFoldersAlwaysOnTop(); |
| } |
| |
| @Override |
| public void setSelected(AnActionEvent event, boolean flag) { |
| setFoldersAlwaysOnTop(flag); |
| } |
| |
| @Override |
| public void update(final AnActionEvent e) { |
| super.update(e); |
| final Presentation presentation = e.getPresentation(); |
| presentation.setVisible(getCurrentProjectViewPane() != null); |
| } |
| } |
| |
| private class ScrollFromSourceAction extends AnAction implements DumbAware { |
| private ScrollFromSourceAction() { |
| super("Scroll from Source", "Select the file open in the active editor", AllIcons.General.Locate); |
| getTemplatePresentation().setHoveredIcon(AllIcons.General.LocateHover); |
| } |
| |
| @Override |
| public void actionPerformed(AnActionEvent e) { |
| myAutoScrollFromSourceHandler.scrollFromSource(); |
| } |
| } |
| |
| @NotNull |
| @Override |
| public Collection<String> getPaneIds() { |
| return myId2Pane.keySet(); |
| } |
| |
| @NotNull |
| @Override |
| public Collection<SelectInTarget> getSelectInTargets() { |
| ensurePanesLoaded(); |
| return mySelectInTargets.values(); |
| } |
| |
| @NotNull |
| @Override |
| public ActionCallback getReady(@NotNull Object requestor) { |
| AbstractProjectViewPane pane = myId2Pane.get(myCurrentViewSubId); |
| if (pane == null) { |
| pane = myId2Pane.get(myCurrentViewId); |
| } |
| return pane != null ? pane.getReady(requestor) : new ActionCallback.Done(); |
| } |
| } |