memory index storage reworked:
[fedora-idea.git] / platform / lang-impl / src / com / intellij / util / LogicalRootsManagerImpl.java
blob825ee61fc84f6275508283ba444fdc270080cb47
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.intellij.util;
19 import com.intellij.ProjectTopics;
20 import com.intellij.openapi.fileTypes.FileType;
21 import com.intellij.openapi.module.Module;
22 import com.intellij.openapi.module.ModuleManager;
23 import com.intellij.openapi.module.ModuleUtil;
24 import com.intellij.openapi.project.Project;
25 import com.intellij.openapi.roots.ModuleRootEvent;
26 import com.intellij.openapi.roots.ModuleRootListener;
27 import com.intellij.openapi.roots.ModuleRootManager;
28 import com.intellij.openapi.util.MultiValuesMap;
29 import com.intellij.openapi.vfs.VfsUtil;
30 import com.intellij.openapi.vfs.VirtualFile;
31 import com.intellij.util.containers.ContainerUtil;
32 import com.intellij.util.messages.MessageBus;
33 import com.intellij.util.messages.MessageBusConnection;
34 import gnu.trove.THashMap;
35 import org.jetbrains.annotations.NotNull;
36 import org.jetbrains.annotations.Nullable;
38 import java.util.*;
40 /**
41 * @author spleaner
43 public class LogicalRootsManagerImpl extends LogicalRootsManager {
44 private Map<Module, MultiValuesMap<LogicalRootType, LogicalRoot>> myRoots = null;
45 private final MultiValuesMap<LogicalRootType, NotNullFunction> myProviders = new MultiValuesMap<LogicalRootType, NotNullFunction>();
46 private final MultiValuesMap<FileType, LogicalRootType> myFileTypes2RootTypes = new MultiValuesMap<FileType, LogicalRootType>();
47 private final ModuleManager myModuleManager;
48 private final Project myProject;
50 public LogicalRootsManagerImpl(final MessageBus bus, final ModuleManager moduleManager, final Project project) {
51 myModuleManager = moduleManager;
52 myProject = project;
54 final MessageBusConnection connection = bus.connect();
55 connection.subscribe(ProjectTopics.LOGICAL_ROOTS, new LogicalRootListener() {
56 public void logicalRootsChanged() {
57 clear();
58 //updateCache(moduleManager);
60 });
61 connection.subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootListener() {
62 public void beforeRootsChange(ModuleRootEvent event) {
65 public void rootsChanged(ModuleRootEvent event) {
66 bus.asyncPublisher(ProjectTopics.LOGICAL_ROOTS).logicalRootsChanged();
68 });
69 registerLogicalRootProvider(LogicalRootType.SOURCE_ROOT, new NotNullFunction<Module, List<VirtualFileLogicalRoot>>() {
70 @NotNull
71 public List<VirtualFileLogicalRoot> fun(final Module module) {
72 return ContainerUtil.map2List(ModuleRootManager.getInstance(module).getSourceRoots(), new Function<VirtualFile, VirtualFileLogicalRoot>() {
73 public VirtualFileLogicalRoot fun(final VirtualFile s) {
74 return new VirtualFileLogicalRoot(s);
76 });
78 });
81 private synchronized void clear() {
82 myRoots = null;
85 private synchronized Map<Module, MultiValuesMap<LogicalRootType, LogicalRoot>> getRoots(final ModuleManager moduleManager) {
86 if (myRoots == null) {
87 myRoots = new THashMap<Module, MultiValuesMap<LogicalRootType, LogicalRoot>>();
89 final Module[] modules = moduleManager.getModules();
90 for (Module module : modules) {
91 final MultiValuesMap<LogicalRootType, LogicalRoot> map = new MultiValuesMap<LogicalRootType, LogicalRoot>();
92 for (Map.Entry<LogicalRootType, Collection<NotNullFunction>> entry : myProviders.entrySet()) {
93 final Collection<NotNullFunction> functions = entry.getValue();
94 for (NotNullFunction function : functions) {
95 map.putAll(entry.getKey(), (List<LogicalRoot>) function.fun(module));
98 myRoots.put(module, map);
102 return myRoots;
105 @Nullable
106 public LogicalRoot findLogicalRoot(@NotNull final VirtualFile file) {
107 final Module module = ModuleUtil.findModuleForFile(file, myProject);
108 if (module == null) return null;
110 LogicalRoot result = null;
111 final List<LogicalRoot> list = getLogicalRoots(module);
112 for (final LogicalRoot root : list) {
113 final VirtualFile rootFile = root.getVirtualFile();
114 if (rootFile != null && VfsUtil.isAncestor(rootFile, file, false)) {
115 result = root;
116 break;
120 return result;
123 public List<LogicalRoot> getLogicalRoots() {
124 return ContainerUtil.concat(myModuleManager.getModules(), new Function<Module, Collection<? extends LogicalRoot>>() {
125 public Collection<? extends LogicalRoot> fun(final Module module) {
126 return getLogicalRoots(module);
131 public List<LogicalRoot> getLogicalRoots(@NotNull final Module module) {
132 final Map<Module, MultiValuesMap<LogicalRootType, LogicalRoot>> roots = getRoots(myModuleManager);
133 final MultiValuesMap<LogicalRootType, LogicalRoot> valuesMap = roots.get(module);
134 if (valuesMap == null) {
135 return Collections.emptyList();
137 return new ArrayList<LogicalRoot>(valuesMap.values());
140 public List<LogicalRoot> getLogicalRootsOfType(@NotNull final Module module, @NotNull final LogicalRootType... types) {
141 return ContainerUtil.concat(types, new Function<LogicalRootType, Collection<? extends LogicalRoot>>() {
142 public Collection<? extends LogicalRoot> fun(final LogicalRootType s) {
143 return getLogicalRootsOfType(module, s);
148 public <T extends LogicalRoot> List<T> getLogicalRootsOfType(@NotNull final Module module, @NotNull final LogicalRootType<T> type) {
149 final Map<Module, MultiValuesMap<LogicalRootType, LogicalRoot>> roots = getRoots(myModuleManager);
150 final MultiValuesMap<LogicalRootType, LogicalRoot> map = roots.get(module);
151 if (map == null) {
152 return Collections.emptyList();
155 Collection<LogicalRoot> collection = map.get(type);
156 if (collection == null) return Collections.emptyList();
157 return new ArrayList<T>((Collection<T>)collection);
160 @NotNull
161 public LogicalRootType[] getRootTypes(@NotNull final FileType type) {
162 final Collection<LogicalRootType> rootTypes = myFileTypes2RootTypes.get(type);
163 if (rootTypes == null) {
164 return new LogicalRootType[0];
167 return rootTypes.toArray(new LogicalRootType[rootTypes.size()]);
170 public void registerRootType(@NotNull final FileType fileType, @NotNull final LogicalRootType... rootTypes) {
171 myFileTypes2RootTypes.putAll(fileType, rootTypes);
174 public <T extends LogicalRoot> void registerLogicalRootProvider(@NotNull final LogicalRootType<T> rootType, @NotNull NotNullFunction<Module, List<T>> provider) {
175 myProviders.put(rootType, provider);
176 clear();