d669a2b870f99e27fbb3ff62459bf907a7832e5e
[idea/community.git] / platform / projectModel-impl / src / com / intellij / openapi / roots / impl / ProjectFileIndexImpl.java
1 /*
2  * Copyright 2000-2012 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
17 package com.intellij.openapi.roots.impl;
18
19 import com.intellij.injected.editor.VirtualFileWindow;
20 import com.intellij.openapi.application.ApplicationManager;
21 import com.intellij.openapi.diagnostic.Logger;
22 import com.intellij.openapi.fileTypes.FileTypeRegistry;
23 import com.intellij.openapi.module.Module;
24 import com.intellij.openapi.module.ModuleManager;
25 import com.intellij.openapi.project.Project;
26 import com.intellij.openapi.roots.ContentIterator;
27 import com.intellij.openapi.roots.ModuleRootManager;
28 import com.intellij.openapi.roots.OrderEntry;
29 import com.intellij.openapi.roots.ProjectFileIndex;
30 import com.intellij.openapi.util.Computable;
31 import com.intellij.openapi.vfs.VfsUtilCore;
32 import com.intellij.openapi.vfs.VirtualFile;
33 import com.intellij.openapi.vfs.VirtualFileFilter;
34 import com.intellij.util.containers.ContainerUtil;
35 import org.jetbrains.annotations.NotNull;
36 import org.jetbrains.annotations.Nullable;
37 import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes;
38 import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
39
40 import java.util.Collections;
41 import java.util.List;
42 import java.util.Set;
43
44 public class ProjectFileIndexImpl extends FileIndexBase implements ProjectFileIndex {
45   private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.roots.impl.ProjectFileIndexImpl");
46   private final Project myProject;
47   private final ContentFilter myContentFilter;
48
49   public ProjectFileIndexImpl(@NotNull Project project, @NotNull DirectoryIndex directoryIndex, @NotNull FileTypeRegistry fileTypeManager) {
50     super(directoryIndex, fileTypeManager, project);
51     myProject = project;
52     myContentFilter = new ContentFilter();
53   }
54
55   @Override
56   public boolean iterateContent(@NotNull ContentIterator iterator) {
57     Module[] modules = ApplicationManager.getApplication().runReadAction(new Computable<Module[]>() {
58       @Override
59       public Module[] compute() {
60         return ModuleManager.getInstance(myProject).getModules();
61       }
62     });
63     for (final Module module : modules) {
64       for (VirtualFile contentRoot : getRootsToIterate(module)) {
65         boolean finished = VfsUtilCore.iterateChildrenRecursively(contentRoot, myContentFilter, iterator);
66         if (!finished) return false;
67       }
68     }
69
70     return true;
71   }
72
73   private List<VirtualFile> getRootsToIterate(final Module module) {
74     return ApplicationManager.getApplication().runReadAction(new Computable<List<VirtualFile>>() {
75       @Override
76       public List<VirtualFile> compute() {
77         if (module.isDisposed()) return Collections.emptyList();
78
79         List<VirtualFile> result = ContainerUtil.newArrayList();
80         for (VirtualFile contentRoot : ModuleRootManager.getInstance(module).getContentRoots()) {
81           DirectoryInfo info = getInfoForFileOrDirectory(contentRoot);
82           if (!info.isInProject()) continue; // is excluded or ignored
83           if (!module.equals(info.getModule())) continue; // maybe 2 modules have the same content root?
84
85           VirtualFile parent = contentRoot.getParent();
86           if (parent != null) {
87             DirectoryInfo parentInfo = getInfoForFileOrDirectory(parent);
88             if (parentInfo.isInProject() && parentInfo.getModule() != null) continue;
89           }
90           result.add(contentRoot);
91         }
92
93         return result;
94       }
95     });
96   }
97
98   @Override
99   public boolean iterateContentUnderDirectory(@NotNull VirtualFile dir, @NotNull ContentIterator iterator) {
100     return VfsUtilCore.iterateChildrenRecursively(dir, myContentFilter, iterator);
101   }
102
103   @Override
104   public boolean isExcluded(@NotNull VirtualFile file) {
105     DirectoryInfo info = getInfoForFileOrDirectory(file);
106     return info.isIgnored() || info.isExcluded();
107   }
108
109   @Override
110   public boolean isUnderIgnored(@NotNull VirtualFile file) {
111     return getInfoForFileOrDirectory(file).isIgnored();
112   }
113
114   @Override
115   public Module getModuleForFile(@NotNull VirtualFile file) {
116     return getModuleForFile(file, true);
117   }
118
119   @Nullable
120   @Override
121   public Module getModuleForFile(@NotNull VirtualFile file, boolean honorExclusion) {
122     if (file instanceof VirtualFileWindow) file = ((VirtualFileWindow)file).getDelegate();
123     DirectoryInfo info = getInfoForFileOrDirectory(file);
124     if (info.isInProject() || !honorExclusion && info.isExcluded()) {
125       return info.getModule();
126     }
127     return null;
128   }
129
130   @Override
131   @NotNull
132   public List<OrderEntry> getOrderEntriesForFile(@NotNull VirtualFile file) {
133     return myDirectoryIndex.getOrderEntries(getInfoForFileOrDirectory(file));
134   }
135
136   @Override
137   public VirtualFile getClassRootForFile(@NotNull VirtualFile file) {
138     final DirectoryInfo info = getInfoForFileOrDirectory(file);
139     if (!info.isInProject()) return null;
140     return info.getLibraryClassRoot();
141   }
142
143   @Override
144   public VirtualFile getSourceRootForFile(@NotNull VirtualFile file) {
145     final DirectoryInfo info = getInfoForFileOrDirectory(file);
146     if (!info.isInProject()) return null;
147     return info.getSourceRoot();
148   }
149
150   @Override
151   public VirtualFile getContentRootForFile(@NotNull VirtualFile file) {
152     return getContentRootForFile(file, true);
153   }
154
155   @Override
156   public VirtualFile getContentRootForFile(@NotNull VirtualFile file, final boolean honorExclusion) {
157     final DirectoryInfo info = getInfoForFileOrDirectory(file);
158     if (info.isInProject() || !honorExclusion && info.isExcluded()) {
159       return info.getContentRoot();
160     }
161     return null;
162   }
163
164   @Override
165   public String getPackageNameByDirectory(@NotNull VirtualFile dir) {
166     if (!dir.isDirectory()) LOG.error(dir.getPresentableUrl());
167     return myDirectoryIndex.getPackageName(dir);
168   }
169
170   @Override
171   public boolean isLibraryClassFile(@NotNull VirtualFile file) {
172     if (file.isDirectory()) return false;
173     DirectoryInfo parentInfo = getInfoForFileOrDirectory(file);
174     return parentInfo.isInProject() && parentInfo.hasLibraryClassRoot();
175   }
176
177   @Override
178   public boolean isInSource(@NotNull VirtualFile fileOrDir) {
179     DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
180     return info.isInModuleSource() || info.isInLibrarySource();
181   }
182
183   @Override
184   public boolean isInLibraryClasses(@NotNull VirtualFile fileOrDir) {
185     DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
186     return info.isInProject() && info.hasLibraryClassRoot();
187   }
188
189   @Override
190   public boolean isInLibrarySource(@NotNull VirtualFile fileOrDir) {
191     return getInfoForFileOrDirectory(fileOrDir).isInLibrarySource();
192   }
193
194   @Override
195   public boolean isIgnored(@NotNull VirtualFile file) {
196     return isExcluded(file);
197   }
198
199   @Override
200   public boolean isInContent(@NotNull VirtualFile fileOrDir) {
201     DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
202     return info.isInProject() && info.getModule() != null;
203   }
204
205   @Override
206   public boolean isInSourceContent(@NotNull VirtualFile fileOrDir) {
207     return getInfoForFileOrDirectory(fileOrDir).isInModuleSource();
208   }
209
210   @Override
211   public boolean isInTestSourceContent(@NotNull VirtualFile fileOrDir) {
212     DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
213     return info.isInModuleSource() && JavaModuleSourceRootTypes.isTestSourceOrResource(myDirectoryIndex.getSourceRootType(info));
214   }
215
216   @Override
217   public boolean isUnderSourceRootOfType(@NotNull VirtualFile fileOrDir, @NotNull Set<? extends JpsModuleSourceRootType<?>> rootTypes) {
218     DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
219     return info.isInModuleSource() && rootTypes.contains(myDirectoryIndex.getSourceRootType(info));
220   }
221
222   private class ContentFilter implements VirtualFileFilter {
223     @Override
224     public boolean accept(@NotNull final VirtualFile file) {
225       return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
226         @Override
227         public Boolean compute() {
228           DirectoryInfo info = getInfoForFileOrDirectory(file);
229           if (!info.isInProject() || info.getModule() == null) return false;
230
231           if (file.isDirectory()) {
232             return true;
233           }
234           else {
235             return !myFileTypeRegistry.isFileIgnored(file);
236           }
237         }
238       });
239     }
240   }
241 }