blob: 2ece1842ecac115f7ec1d951df06e9246b25e8f3 [file] [log] [blame]
/*
* 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.
*/
/*
* @author max
*/
package com.intellij.util.indexing;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.caches.FileContent;
import com.intellij.ide.startup.StartupManagerEx;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.AbstractProjectComponent;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.*;
import com.intellij.openapi.roots.ContentIterator;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ex.ProjectRootManagerEx;
import com.intellij.openapi.roots.impl.ProjectRootManagerComponent;
import com.intellij.openapi.roots.impl.PushedFilePropertiesUpdater;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileVisitor;
import com.intellij.util.Consumer;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public class FileBasedIndexProjectHandler extends AbstractProjectComponent implements IndexableFileSet {
private static final Logger LOG = Logger.getInstance("#com.intellij.util.indexing.FileBasedIndexProjectHandler");
private final FileBasedIndexImpl myIndex;
private final ProjectRootManagerEx myRootManager;
private final FileTypeManager myFileTypeManager;
public FileBasedIndexProjectHandler(final FileBasedIndexImpl index, final Project project, final ProjectRootManagerComponent rootManager, FileTypeManager ftManager, final ProjectManager projectManager) {
super(project);
myIndex = index;
myRootManager = rootManager;
myFileTypeManager = ftManager;
if (ApplicationManager.getApplication().isInternal()) {
project.getMessageBus().connect().subscribe(DumbService.DUMB_MODE, new DumbService.DumbModeListener() {
public void enteredDumbMode() {
}
public void exitDumbMode() {
LOG.info("Has changed files: " + (createChangedFilesIndexingTask(project) != null) + "; project=" + project);
}
});
}
final StartupManagerEx startupManager = (StartupManagerEx)StartupManager.getInstance(project);
if (startupManager != null) {
startupManager.registerPreStartupActivity(new Runnable() {
@Override
public void run() {
PushedFilePropertiesUpdater.getInstance(project).initializeProperties();
// dumb mode should start before post-startup activities
// only when queueTask is called from UI thread, we can guarantee that
// when the method returns, the application has entered dumb mode
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
if (!project.isDisposed()) {
DumbService.getInstance(project).queueTask(new UnindexedFilesUpdater(project, true));
}
}
});
myIndex.registerIndexableSet(FileBasedIndexProjectHandler.this, project);
projectManager.addProjectManagerListener(project, new ProjectManagerAdapter() {
private boolean removed = false;
@Override
public void projectClosing(Project project) {
if (!removed) {
removed = true;
myIndex.removeIndexableSet(FileBasedIndexProjectHandler.this);
}
}
});
}
});
}
}
@Override
public boolean isInSet(@NotNull final VirtualFile file) {
final ProjectFileIndex index = myRootManager.getFileIndex();
if (index.isInContent(file) || index.isInLibraryClasses(file) || index.isInLibrarySource(file)) {
return !myFileTypeManager.isFileIgnored(file);
}
return false;
}
@Override
public void iterateIndexableFilesIn(@NotNull final VirtualFile file, @NotNull final ContentIterator iterator) {
VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor() {
@Override
public boolean visitFile(@NotNull VirtualFile file) {
if (!isInSet(file)) return false;
iterator.processFile(file);
return true;
}
});
}
@Override
public void disposeComponent() {
// done mostly for tests. In real life this is noop, because the set was removed on project closing
myIndex.removeIndexableSet(this);
}
@Nullable
public static DumbModeTask createChangedFilesIndexingTask(final Project project) {
final FileBasedIndexImpl index = (FileBasedIndexImpl)FileBasedIndex.getInstance();
if (index.getChangedFileCount() + index.getNumberOfPendingInvalidations() < 20) {
return null;
}
return new DumbModeTask() {
@Override
public void performInDumbMode(@NotNull ProgressIndicator indicator) {
final Collection<VirtualFile> files = index.getFilesToUpdate(project);
indicator.setIndeterminate(false);
indicator.setText(IdeBundle.message("progress.indexing.updating"));
reindexRefreshedFiles(indicator, files, project, index);
}
};
}
private static void reindexRefreshedFiles(ProgressIndicator indicator,
Collection<VirtualFile> files,
final Project project,
final FileBasedIndexImpl index) {
CacheUpdateRunner.processFiles(indicator, true, files, project, new Consumer<FileContent>() {
@Override
public void consume(FileContent content) {
index.processRefreshedFile(project, content);
}
});
}
}