blob: 4c42e86f5f58d46d8b2d7f2fbb88ca8406e92d5d [file] [log] [blame]
/*
* Copyright 2006 Sascha Weinreuter
*
* 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 org.intellij.plugins.xpathView.search;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ContentIterator;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.OrderEnumerator;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.*;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileVisitor;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiSearchScopeUtil;
import com.intellij.util.Processor;
import gnu.trove.THashSet;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
public class SearchScope implements JDOMExternalizable {
public enum ScopeType {
PROJECT,MODULE,DIRECTORY,CUSTOM
}
private ScopeType myScopeType;
private String myModuleName;
private String myPath;
private boolean myRecursive;
private String myScopeName;
private com.intellij.psi.search.SearchScope myCustomScope;
public SearchScope() {
myScopeType = ScopeType.PROJECT;
myRecursive = true;
}
public SearchScope(SearchScope scope) {
myScopeType = scope.getScopeType();
myModuleName = scope.getModuleName();
myPath = scope.getPath();
myRecursive = scope.isRecursive();
myScopeName = scope.getScopeName();
}
public SearchScope(ScopeType scopeType, String directoryName, boolean recursive, String moduleName, String scopeName) {
myScopeType = scopeType;
myPath = directoryName;
myRecursive = recursive;
myModuleName = moduleName;
myScopeName = scopeName;
}
public void setCustomScope(com.intellij.psi.search.SearchScope customScope) {
myCustomScope = customScope;
}
@NotNull
public String getName() {
switch (getScopeType()) {
case PROJECT:
return "Project";
case MODULE:
return "Module '" + getModuleName() + "'";
case DIRECTORY:
return "Directory '" + getPath() + "'";
case CUSTOM:
return "Scope '" + getScopeName() + "'";
}
assert false;
return null;
}
@NotNull
public ScopeType getScopeType() {
return myScopeType;
}
public String getModuleName() {
return myModuleName;
}
@Nullable
public String getScopeName() {
return myScopeName;
}
@Nullable
public String getPath() {
return myPath;
}
public boolean isRecursive() {
return myRecursive;
}
public void readExternal(Element element) throws InvalidDataException {
myScopeType = ScopeType.valueOf(element.getAttributeValue("type"));
if (myScopeType == ScopeType.MODULE) {
final Element m = element.getChild("module");
if (m != null) {
myModuleName = m.getTextTrim();
}
} else if (myScopeType == ScopeType.DIRECTORY) {
final Element path = element.getChild("path");
if (path != null) {
myPath = path.getTextTrim();
myRecursive = "true".equals(path.getAttributeValue("recursive"));
}
} else if (myScopeType == ScopeType.CUSTOM) {
myScopeName = element.getAttributeValue("scope-name");
}
}
public void writeExternal(Element element) throws WriteExternalException {
final ScopeType scopeType = getScopeType();
element.setAttribute("type", scopeType.toString());
if (scopeType == ScopeType.MODULE) {
if (myModuleName != null) {
final Element m = new Element("module");
element.addContent(m);
m.setText(myModuleName);
}
} else if (scopeType == ScopeType.DIRECTORY) {
final Element p = new Element("path");
element.addContent(p);
p.setAttribute("recursive", Boolean.toString(myRecursive));
if (myPath != null) {
p.setText(myPath);
}
} else if (scopeType == ScopeType.CUSTOM) {
if (myScopeName != null) {
element.setAttribute("scope-name", myScopeName);
}
}
}
public boolean isValid() {
final String dirName = getPath();
final String moduleName = getModuleName();
switch (getScopeType()) {
case MODULE:
return moduleName != null && moduleName.length() > 0;
case DIRECTORY:
return dirName != null && dirName.length() > 0 && findFile(dirName) != null;
case CUSTOM:
return myCustomScope != null;
case PROJECT:
return true;
}
return false;
}
public void iterateContent(@NotNull final Project project, final Processor<VirtualFile> processor) {
switch (getScopeType()) {
case PROJECT:
//noinspection unchecked
ProjectRootManager.getInstance(project).getFileIndex().iterateContent(new MyFileIterator(processor, Conditions.<VirtualFile>alwaysTrue()));
break;
case MODULE:
final Module module = ModuleManager.getInstance(project).findModuleByName(getModuleName());
//noinspection unchecked
ModuleRootManager.getInstance(module).getFileIndex().iterateContent(new MyFileIterator(processor, Conditions.<VirtualFile>alwaysTrue()));
break;
case DIRECTORY:
final String dirName = getPath();
assert dirName != null;
final VirtualFile virtualFile = findFile(dirName);
if (virtualFile != null) {
iterateRecursively(virtualFile, processor, isRecursive());
}
break;
case CUSTOM:
assert myCustomScope != null;
final ContentIterator iterator;
if (myCustomScope instanceof GlobalSearchScope) {
final GlobalSearchScope searchScope = (GlobalSearchScope)myCustomScope;
iterator = new MyFileIterator(processor, new Condition<VirtualFile>() {
public boolean value(VirtualFile virtualFile) {
return searchScope.contains(virtualFile);
}
});
if (searchScope.isSearchInLibraries()) {
final OrderEnumerator enumerator = OrderEnumerator.orderEntries(project).withoutModuleSourceEntries().withoutDepModules();
final Collection<VirtualFile> libraryFiles = new THashSet<VirtualFile>();
Collections.addAll(libraryFiles, enumerator.getClassesRoots());
Collections.addAll(libraryFiles, enumerator.getSourceRoots());
final Processor<VirtualFile> adapter = new Processor<VirtualFile>() {
public boolean process(VirtualFile virtualFile) {
return iterator.processFile(virtualFile);
}
};
for (final VirtualFile file : libraryFiles) {
iterateRecursively(file, adapter, true);
}
}
} else {
final PsiManager manager = PsiManager.getInstance(project);
iterator = new MyFileIterator(processor, new Condition<VirtualFile>() {
public boolean value(VirtualFile virtualFile) {
final PsiFile element = manager.findFile(virtualFile);
return element != null && PsiSearchScopeUtil.isInScope(myCustomScope, element);
}
});
}
ProjectRootManager.getInstance(project).getFileIndex().iterateContent(iterator);
}
}
@Nullable
private static VirtualFile findFile(String dirName) {
return LocalFileSystem.getInstance().findFileByPath(dirName.replace('\\', '/'));
}
private static void iterateRecursively(VirtualFile virtualFile, final Processor<VirtualFile> processor, boolean recursive) {
VfsUtilCore.visitChildrenRecursively(virtualFile, new VirtualFileVisitor(recursive ? null : VirtualFileVisitor.ONE_LEVEL_DEEP) {
@Override
public boolean visitFile(@NotNull VirtualFile file) {
if (!file.isDirectory()) {
processor.process(file);
}
return true;
}
});
}
private static class MyFileIterator implements ContentIterator {
private final Processor<VirtualFile> myProcessor;
private final Condition<VirtualFile> myCondition;
public MyFileIterator(Processor<VirtualFile> processor, Condition<VirtualFile> condition) {
myCondition = condition;
myProcessor = processor;
}
public boolean processFile(VirtualFile fileOrDir) {
if (!fileOrDir.isDirectory() && myCondition.value(fileOrDir)) {
myProcessor.process(fileOrDir);
}
return true;
}
}
}