do not switch view during package navigation
[idea/community.git] / java / java-impl / src / com / intellij / psi / impl / file / PsiPackageImplementationHelperImpl.java
1 /*
2  * Copyright 2000-2011 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.psi.impl.file;
17
18 import com.intellij.ide.projectView.ProjectView;
19 import com.intellij.openapi.application.ApplicationManager;
20 import com.intellij.openapi.command.undo.GlobalUndoableAction;
21 import com.intellij.openapi.command.undo.UndoManager;
22 import com.intellij.openapi.editor.Document;
23 import com.intellij.openapi.editor.Editor;
24 import com.intellij.openapi.fileEditor.FileEditorManager;
25 import com.intellij.openapi.module.Module;
26 import com.intellij.openapi.module.ModuleManager;
27 import com.intellij.openapi.module.ModuleUtil;
28 import com.intellij.openapi.project.Project;
29 import com.intellij.openapi.roots.*;
30 import com.intellij.openapi.vfs.VfsUtil;
31 import com.intellij.openapi.vfs.VirtualFile;
32 import com.intellij.openapi.wm.ToolWindow;
33 import com.intellij.openapi.wm.ToolWindowId;
34 import com.intellij.openapi.wm.ToolWindowManager;
35 import com.intellij.psi.*;
36 import com.intellij.psi.impl.PackagePrefixElementFinder;
37 import com.intellij.psi.search.GlobalSearchScope;
38 import com.intellij.psi.util.PsiModificationTracker;
39
40 import java.util.ArrayList;
41 import java.util.List;
42
43 /**
44  * @author yole
45  */
46 public class PsiPackageImplementationHelperImpl extends PsiPackageImplementationHelper {
47   @Override
48   public GlobalSearchScope adjustAllScope(PsiPackage psiPackage, GlobalSearchScope globalSearchScope) {
49     return NonClasspathClassFinder.addNonClasspathScope(psiPackage.getProject(), globalSearchScope);
50   }
51
52   @Override
53   public VirtualFile[] occursInPackagePrefixes(PsiPackage psiPackage) {
54     List<VirtualFile> result = new ArrayList<VirtualFile>();
55     final Module[] modules = ModuleManager.getInstance(psiPackage.getProject()).getModules();
56
57     for (final Module module : modules) {
58       final ContentEntry[] contentEntries = ModuleRootManager.getInstance(module).getContentEntries();
59       for (final ContentEntry contentEntry : contentEntries) {
60         final SourceFolder[] sourceFolders = contentEntry.getSourceFolders();
61         for (final SourceFolder sourceFolder : sourceFolders) {
62           final String packagePrefix = sourceFolder.getPackagePrefix();
63           if (packagePrefix.startsWith(psiPackage.getQualifiedName())) {
64             final VirtualFile file = sourceFolder.getFile();
65             if (file != null) {
66               result.add(file);
67             }
68           }
69         }
70       }
71     }
72
73     return VfsUtil.toVirtualFileArray(result);
74   }
75
76   @Override
77   public void handleQualifiedNameChange(final PsiPackage psiPackage, final String newQualifiedName) {
78     ApplicationManager.getApplication().assertWriteAccessAllowed();
79     final String oldQualifedName = psiPackage.getQualifiedName();
80     final boolean anyChanged = changePackagePrefixes(psiPackage, oldQualifedName, newQualifiedName);
81     if (anyChanged) {
82       UndoManager.getInstance(psiPackage.getProject()).undoableActionPerformed(new GlobalUndoableAction() {
83         @Override
84         public void undo() {
85           changePackagePrefixes(psiPackage, newQualifiedName, oldQualifedName);
86         }
87
88         @Override
89         public void redo() {
90           changePackagePrefixes(psiPackage, oldQualifedName, newQualifiedName);
91         }
92       });
93     }
94   }
95
96   private static boolean changePackagePrefixes(PsiPackage psiPackage, final String oldQualifiedName, final String newQualifiedName) {
97     final Module[] modules = ModuleManager.getInstance(psiPackage.getProject()).getModules();
98     List<ModifiableRootModel> modelsToCommit = new ArrayList<ModifiableRootModel>();
99     for (final Module module : modules) {
100       boolean anyChange = false;
101       final ModifiableRootModel rootModel = ModuleRootManager.getInstance(module).getModifiableModel();
102       final ContentEntry[] contentEntries = rootModel.getContentEntries();
103       for (final ContentEntry contentEntry : contentEntries) {
104         final SourceFolder[] sourceFolders = contentEntry.getSourceFolders();
105         for (final SourceFolder sourceFolder : sourceFolders) {
106           final String packagePrefix = sourceFolder.getPackagePrefix();
107           if (packagePrefix.startsWith(oldQualifiedName)) {
108             sourceFolder.setPackagePrefix(newQualifiedName + packagePrefix.substring(oldQualifiedName.length()));
109             anyChange = true;
110           }
111         }
112       }
113       if (anyChange) {
114         modelsToCommit.add(rootModel);
115       } else {
116         rootModel.dispose();
117       }
118     }
119
120     if (!modelsToCommit.isEmpty()) {
121       ProjectRootManager.getInstance(psiPackage.getProject()).multiCommit(
122         modelsToCommit.toArray(new ModifiableRootModel[modelsToCommit.size()])
123       );
124       return true;
125     } else {
126       return false;
127     }
128   }
129
130   @Override
131   public void navigate(final PsiPackage psiPackage, final boolean requestFocus) {
132     final Project project = psiPackage.getProject();
133     ToolWindow window = ToolWindowManager.getInstance(project).getToolWindow(ToolWindowId.PROJECT_VIEW);
134     window.activate(null);
135     window.getActivation().doWhenDone(new Runnable() {
136       @Override
137       public void run() {
138         final ProjectView projectView = ProjectView.getInstance(project);
139         PsiDirectory[] directories = suggestMostAppropriateDirectories(psiPackage);
140         if (directories.length == 0) return;
141         projectView.select(directories[0], directories[0].getVirtualFile(), requestFocus);
142       }
143     });
144   }
145
146   private static PsiDirectory[] suggestMostAppropriateDirectories(PsiPackage psiPackage) {
147     final Project project = psiPackage.getProject();
148     PsiDirectory[] directories = null;
149     final Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor();
150     if (editor != null) {
151       final Document document = editor.getDocument();
152       final PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document);
153       if (psiFile != null) {
154         final Module module = ModuleUtil.findModuleForPsiElement(psiFile);
155         if (module != null) {
156           directories = psiPackage.getDirectories(GlobalSearchScope.moduleWithDependenciesScope(module));
157         } else {
158           directories = psiPackage.getDirectories(GlobalSearchScope.notScope(GlobalSearchScope.projectScope(project)));
159         }
160       }
161     }
162
163     if (directories == null || directories.length == 0) {
164       directories = psiPackage.getDirectories();
165     }
166     return directories;
167   }
168
169   @Override
170   public boolean packagePrefixExists(PsiPackage psiPackage) {
171     return PackagePrefixElementFinder.getInstance(psiPackage.getProject()).packagePrefixExists(psiPackage.getQualifiedName());
172   }
173
174   @Override
175   public Object[] getDirectoryCachedValueDependencies(PsiPackage psiPackage) {
176     return new Object[] { PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT, ProjectRootManager.getInstance(psiPackage.getProject()) };
177   }
178 }