/*
* Copyright 2003-2011 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 jetbrains.mps.ide.findusages.caches;
import com.intellij.ide.startup.StartupManagerEx;
import com.intellij.openapi.components.AbstractProjectComponent;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.project.ProjectManagerAdapter;
import com.intellij.openapi.roots.ContentIterator;
import com.intellij.openapi.roots.ex.ProjectRootManagerEx;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.indexing.FileBasedIndex;
import com.intellij.util.indexing.IndexableFileSet;
import jetbrains.mps.ide.make.StartupModuleMaker;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
/**
* Provides project roots for idea indexing mechanism.
* IDEA asks whether the file needs to be indexed by calling {@link #isInSet(VirtualFile)} method.
*
* FIXME AP I don't like that we register out project roots via registering this IndexableFileSet as well
* as via MPSIndexableSetContributor. Is that right?
*/
public class MPSIndexableFileSet extends AbstractProjectComponent implements IndexableFileSet {
private static final Logger LOG = LogManager.getLogger(MPSIndexableFileSet.class);
private final ProjectRootManagerEx myRootManager;
private final ProjectManager myProjectManager;
private final FileBasedIndex myIndex;
private final IndexableRootCalculator myIndexableRootCalculator;
/**
* FIXME Why such an odd way to register/unregister some per-project-listener??
*/
private final ProjectManagerAdapter myProjectListener = new ProjectManagerAdapter() {
@Override
public void projectClosing(Project project) {
myIndex.removeIndexableSet(MPSIndexableFileSet.this);
}
};
public MPSIndexableFileSet(@NotNull final Project project,
final ProjectRootManagerEx rootManager,
ProjectManager projectManager,
FileBasedIndex index,
StartupModuleMaker maker) {
super(project);
myRootManager = rootManager;
myProjectManager = projectManager;
myIndex = index;
myIndexableRootCalculator = new IndexableRootCalculator(project);
final StartupManagerEx startupManager = (StartupManagerEx) StartupManager.getInstance(myProject);
if (startupManager != null) {
startupManager.registerPreStartupActivity(new Runnable() {
@Override
public void run() {
/**
* FIXME AP why to register like this if we could register just using MPSIndexableFileSetContributor???
*/
myIndex.registerIndexableSet(MPSIndexableFileSet.this, myProject);
LOG.debug("Queueing cache update");
}
});
}
}
@Override
public void initComponent() {
myProjectManager.addProjectManagerListener(myProject, myProjectListener);
myIndexableRootCalculator.register();
}
@Override
public void disposeComponent() {
myIndexableRootCalculator.unregister();
myProjectManager.removeProjectManagerListener(myProject, myProjectListener);
}
@Override
public boolean isInSet(@NotNull VirtualFile file) {
if (!isIgnored(file, myRootManager)) {
for (VirtualFile vf : getIndexableRoots()) {
if (VfsUtil.isAncestor(vf, file, true)) { // fixme why 'true' is passed??
return true;
}
}
}
return false;
}
@Override
public void iterateIndexableFilesIn(@NotNull VirtualFile file, @NotNull ContentIterator iterator) {
if (!isInSet(file)) return;
iterateIndexableFilesIn_internal(file, iterator);
}
private void iterateIndexableFilesIn_internal(VirtualFile file, ContentIterator iterator) {
if (!isIgnored(file, myRootManager)) {
if (file.isDirectory()) {
for (VirtualFile child : file.getChildren()) {
iterateIndexableFilesIn_internal(child, iterator);
}
} else {
iterator.processFile(file);
}
}
}
@NotNull
Set<VirtualFile> getIndexableRoots() {
return myIndexableRootCalculator.getIndexableRoots();
}
private static boolean isIgnored(VirtualFile file, ProjectRootManagerEx manager) {
return FileTypeManager.getInstance().isFileIgnored(file.getName()) || manager.getFileIndex().isExcluded(file);
}
}