| /* |
| * 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.scopeView; |
| |
| import com.intellij.icons.AllIcons; |
| import com.intellij.ide.IdeBundle; |
| import com.intellij.ide.SelectInTarget; |
| import com.intellij.ide.projectView.ProjectView; |
| import com.intellij.ide.projectView.impl.AbstractProjectViewPane; |
| import com.intellij.ide.projectView.impl.ShowModulesAction; |
| import com.intellij.ide.ui.customization.CustomizationUtil; |
| import com.intellij.openapi.actionSystem.ActionManager; |
| import com.intellij.openapi.actionSystem.ActionPlaces; |
| import com.intellij.openapi.actionSystem.DefaultActionGroup; |
| import com.intellij.openapi.actionSystem.IdeActions; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.util.ActionCallback; |
| import com.intellij.openapi.util.Comparing; |
| import com.intellij.openapi.util.Disposer; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.packageDependencies.DependencyValidationManager; |
| import com.intellij.packageDependencies.ui.PackageDependenciesNode; |
| import com.intellij.psi.PsiElement; |
| import com.intellij.psi.PsiFile; |
| import com.intellij.psi.PsiFileSystemItem; |
| import com.intellij.psi.PsiManager; |
| import com.intellij.psi.search.scope.NonProjectFilesScope; |
| import com.intellij.psi.search.scope.packageSet.*; |
| import com.intellij.util.Alarm; |
| import com.intellij.util.ArrayUtil; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| |
| import javax.swing.*; |
| import javax.swing.tree.DefaultMutableTreeNode; |
| |
| /** |
| * @author cdr |
| */ |
| public class ScopeViewPane extends AbstractProjectViewPane { |
| @NonNls public static final String ID = "Scope"; |
| private final ProjectView myProjectView; |
| private ScopeTreeViewPanel myViewPanel; |
| private final DependencyValidationManager myDependencyValidationManager; |
| private final NamedScopeManager myNamedScopeManager; |
| private final NamedScopesHolder.ScopeListener myScopeListener; |
| |
| public ScopeViewPane(final Project project, ProjectView projectView, DependencyValidationManager dependencyValidationManager, NamedScopeManager namedScopeManager) { |
| super(project); |
| myProjectView = projectView; |
| myDependencyValidationManager = dependencyValidationManager; |
| myNamedScopeManager = namedScopeManager; |
| myScopeListener = new NamedScopesHolder.ScopeListener() { |
| Alarm refreshProjectViewAlarm = new Alarm(); |
| @Override |
| public void scopesChanged() { |
| // amortize batch scope changes |
| refreshProjectViewAlarm.cancelAllRequests(); |
| refreshProjectViewAlarm.addRequest(new Runnable(){ |
| @Override |
| public void run() { |
| if (myProject.isDisposed()) return; |
| final String subId = getSubId(); |
| final String id = myProjectView.getCurrentViewId(); |
| myProjectView.removeProjectPane(ScopeViewPane.this); |
| myProjectView.addProjectPane(ScopeViewPane.this); |
| if (id != null) { |
| if (Comparing.strEqual(id, getId())) { |
| myProjectView.changeView(id, subId); |
| } else { |
| myProjectView.changeView(id); |
| } |
| } |
| } |
| },10); |
| } |
| }; |
| myDependencyValidationManager.addScopeListener(myScopeListener); |
| myNamedScopeManager.addScopeListener(myScopeListener); |
| } |
| |
| @Override |
| public String getTitle() { |
| return IdeBundle.message("scope.view.title"); |
| } |
| |
| @Override |
| public Icon getIcon() { |
| return AllIcons.Ide.LocalScope; |
| } |
| |
| @Override |
| @NotNull |
| public String getId() { |
| return ID; |
| } |
| |
| @Override |
| public JComponent createComponent() { |
| if (myViewPanel == null) { |
| myViewPanel = new ScopeTreeViewPanel(myProject); |
| Disposer.register(this, myViewPanel); |
| myViewPanel.initListeners(); |
| myTree = myViewPanel.getTree(); |
| CustomizationUtil.installPopupHandler(myTree, IdeActions.GROUP_SCOPE_VIEW_POPUP, ActionPlaces.SCOPE_VIEW_POPUP); |
| enableDnD(); |
| } |
| |
| myViewPanel.selectScope(NamedScopesHolder.getScope(myProject, getSubId())); |
| return myViewPanel.getPanel(); |
| } |
| |
| @Override |
| public void dispose() { |
| myViewPanel = null; |
| myDependencyValidationManager.removeScopeListener(myScopeListener); |
| myNamedScopeManager.removeScopeListener(myScopeListener); |
| super.dispose(); |
| } |
| |
| @Override |
| @NotNull |
| public String[] getSubIds() { |
| NamedScope[] scopes = getShownScopes(); |
| String[] ids = new String[scopes.length]; |
| for (int i = 0; i < scopes.length; i++) { |
| final NamedScope scope = scopes[i]; |
| ids[i] = scope.getName(); |
| } |
| return ids; |
| } |
| |
| private NamedScope[] getShownScopes() { |
| NamedScope[] scopes = myDependencyValidationManager.getScopes(); |
| scopes = ArrayUtil.mergeArrays(scopes, myNamedScopeManager.getScopes()); |
| scopes = NonProjectFilesScope.removeFromList(scopes); |
| scopes = ArrayUtil.remove(scopes, CustomScopesProviderEx.getAllScope()); |
| return scopes; |
| } |
| |
| @Override |
| @NotNull |
| public String getPresentableSubIdName(@NotNull final String subId) { |
| return subId; |
| } |
| |
| @Override |
| public void addToolbarActions(DefaultActionGroup actionGroup) { |
| actionGroup.add(ActionManager.getInstance().getAction("ScopeView.EditScopes")); |
| actionGroup.addAction(new ShowModulesAction(myProject){ |
| @NotNull |
| @Override |
| protected String getId() { |
| return ScopeViewPane.this.getId(); |
| } |
| }).setAsSecondary(true); |
| } |
| |
| @NotNull |
| @Override |
| public ActionCallback updateFromRoot(boolean restoreExpandedPaths) { |
| saveExpandedPaths(); |
| myViewPanel.selectScope(NamedScopesHolder.getScope(myProject, getSubId())); |
| restoreExpandedPaths(); |
| return new ActionCallback.Done(); |
| } |
| |
| @Override |
| public void select(Object element, VirtualFile file, boolean requestFocus) { |
| if (file == null) return; |
| PsiFileSystemItem psiFile = file.isDirectory() ? PsiManager.getInstance(myProject).findDirectory(file) |
| : PsiManager.getInstance(myProject).findFile(file); |
| if (psiFile == null) return; |
| if (!(element instanceof PsiElement)) return; |
| |
| NamedScope[] allScopes = getShownScopes(); |
| for (int i = 0; i < allScopes.length; i++) { |
| final NamedScope scope = allScopes[i]; |
| String name = scope.getName(); |
| if (name.equals(getSubId())) { |
| allScopes[i] = allScopes[0]; |
| allScopes[0] = scope; |
| break; |
| } |
| } |
| for (NamedScope scope : allScopes) { |
| String name = scope.getName(); |
| PackageSet packageSet = scope.getValue(); |
| if (packageSet == null) continue; |
| if (changeView(packageSet, ((PsiElement)element), psiFile, name, myNamedScopeManager, requestFocus)) break; |
| if (changeView(packageSet, ((PsiElement)element), psiFile, name, myDependencyValidationManager, requestFocus)) break; |
| } |
| } |
| |
| private boolean changeView(final PackageSet packageSet, final PsiElement element, final PsiFileSystemItem psiFileSystemItem, final String name, final NamedScopesHolder holder, |
| boolean requestFocus) { |
| if ((packageSet instanceof PackageSetBase && ((PackageSetBase)packageSet).contains(psiFileSystemItem.getVirtualFile(), myProject, holder)) || |
| (psiFileSystemItem instanceof PsiFile && packageSet.contains((PsiFile)psiFileSystemItem, holder))) { |
| if (!name.equals(getSubId())) { |
| if (!requestFocus) return true; |
| myProjectView.changeView(getId(), name); |
| } |
| myViewPanel.selectNode(element, psiFileSystemItem, requestFocus); |
| return true; |
| } |
| return false; |
| } |
| |
| |
| |
| @Override |
| public int getWeight() { |
| return 200; // was 3, changed to 200 in Android Studio so that has a lower weight than the Android view. |
| } |
| |
| @Override |
| public void installComparator() { |
| myViewPanel.setSortByType(); |
| } |
| |
| @Override |
| public SelectInTarget createSelectInTarget() { |
| return new ScopePaneSelectInTarget(myProject); |
| } |
| |
| @Override |
| protected Object exhumeElementFromNode(final DefaultMutableTreeNode node) { |
| if (node instanceof PackageDependenciesNode) { |
| return ((PackageDependenciesNode)node).getPsiElement(); |
| } |
| return super.exhumeElementFromNode(node); |
| } |
| |
| @Override |
| public Object getData(final String dataId) { |
| final Object data = super.getData(dataId); |
| if (data != null) { |
| return data; |
| } |
| return myViewPanel == null ? null : myViewPanel.getData(dataId); |
| } |
| |
| @NotNull |
| @Override |
| public ActionCallback getReady(@NotNull Object requestor) { |
| final ActionCallback callback = myViewPanel.getActionCallback(); |
| return callback == null ? new ActionCallback.Done() : callback; |
| } |
| } |