| /* |
| * Copyright 2000-2009 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. |
| */ |
| |
| /* |
| * User: anna |
| * Date: 23-Jan-2008 |
| */ |
| package com.intellij.ide.projectView.impl.nodes; |
| |
| import com.intellij.ide.projectView.ProjectViewNode; |
| import com.intellij.ide.projectView.ProjectViewSettings; |
| import com.intellij.ide.projectView.ViewSettings; |
| import com.intellij.ide.util.treeView.AbstractTreeNode; |
| import com.intellij.openapi.components.ServiceManager; |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.fileTypes.FileTypeRegistry; |
| import com.intellij.openapi.module.Module; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.roots.ModuleFileIndex; |
| import com.intellij.openapi.roots.ModuleRootManager; |
| import com.intellij.openapi.roots.ProjectFileIndex; |
| import com.intellij.openapi.roots.ProjectRootManager; |
| import com.intellij.openapi.roots.impl.DirectoryIndex; |
| import com.intellij.openapi.roots.impl.DirectoryInfo; |
| import com.intellij.openapi.util.Comparing; |
| import com.intellij.openapi.util.registry.Registry; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.psi.*; |
| import com.intellij.psi.search.PsiElementProcessor; |
| import com.intellij.psi.util.PsiUtilCore; |
| import gnu.trove.THashSet; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.List; |
| import java.util.Set; |
| |
| public class ProjectViewDirectoryHelper { |
| protected static final Logger LOG = Logger.getInstance("#" + ProjectViewDirectoryHelper.class.getName()); |
| |
| private final Project myProject; |
| private final DirectoryIndex myIndex; |
| |
| public static ProjectViewDirectoryHelper getInstance(Project project) { |
| return ServiceManager.getService(project, ProjectViewDirectoryHelper.class); |
| } |
| |
| public ProjectViewDirectoryHelper(Project project, DirectoryIndex index) { |
| myProject = project; |
| myIndex = index; |
| } |
| |
| public Project getProject() { |
| return myProject; |
| } |
| |
| @Nullable |
| public String getLocationString(@NotNull PsiDirectory psiDirectory) { |
| final VirtualFile directory = psiDirectory.getVirtualFile(); |
| final VirtualFile contentRootForFile = ProjectRootManager.getInstance(myProject) |
| .getFileIndex().getContentRootForFile(directory); |
| if (Comparing.equal(contentRootForFile, psiDirectory)) { |
| return directory.getPresentableUrl(); |
| } |
| return null; |
| } |
| |
| |
| |
| public boolean isShowFQName(ViewSettings settings, Object parentValue, PsiDirectory value) { |
| return false; |
| } |
| |
| |
| @Nullable |
| public String getNodeName(ViewSettings settings, Object parentValue, PsiDirectory directory) { |
| return directory.getName(); |
| } |
| |
| public boolean skipDirectory(PsiDirectory directory) { |
| return true; |
| } |
| |
| public boolean isEmptyMiddleDirectory(PsiDirectory directory, final boolean strictlyEmpty) { |
| return false; |
| } |
| |
| public boolean supportsFlattenPackages() { |
| return false; |
| } |
| |
| public boolean supportsHideEmptyMiddlePackages() { |
| return false; |
| } |
| |
| public boolean canRepresent(Object element, PsiDirectory directory) { |
| if (element instanceof VirtualFile) { |
| VirtualFile vFile = (VirtualFile) element; |
| return Comparing.equal(directory.getVirtualFile(), vFile); |
| } |
| return false; |
| } |
| |
| public Collection<AbstractTreeNode> getDirectoryChildren(final PsiDirectory psiDirectory, |
| final ViewSettings settings, |
| final boolean withSubDirectories) { |
| final List<AbstractTreeNode> children = new ArrayList<AbstractTreeNode>(); |
| final Project project = psiDirectory.getProject(); |
| final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex(); |
| final Module module = fileIndex.getModuleForFile(psiDirectory.getVirtualFile()); |
| final ModuleFileIndex moduleFileIndex = module == null ? null : ModuleRootManager.getInstance(module).getFileIndex(); |
| if (!settings.isFlattenPackages() || skipDirectory(psiDirectory)) { |
| processPsiDirectoryChildren(psiDirectory, directoryChildrenInProject(psiDirectory, settings), |
| children, fileIndex, null, settings, withSubDirectories); |
| } |
| else { // source directory in "flatten packages" mode |
| final PsiDirectory parentDir = psiDirectory.getParentDirectory(); |
| if (parentDir == null || skipDirectory(parentDir) /*|| !rootDirectoryFound(parentDir)*/ && withSubDirectories) { |
| addAllSubpackages(children, psiDirectory, moduleFileIndex, settings); |
| } |
| PsiDirectory[] subdirs = psiDirectory.getSubdirectories(); |
| for (PsiDirectory subdir : subdirs) { |
| if (!skipDirectory(subdir)) { |
| continue; |
| } |
| VirtualFile directoryFile = subdir.getVirtualFile(); |
| |
| if (Registry.is("ide.hide.excluded.files")) { |
| if (fileIndex.isExcluded(directoryFile)) continue; |
| } |
| else { |
| if (FileTypeRegistry.getInstance().isFileIgnored(directoryFile)) continue; |
| } |
| |
| if (withSubDirectories) { |
| children.add(new PsiDirectoryNode(project, subdir, settings)); |
| } |
| } |
| processPsiDirectoryChildren(psiDirectory, psiDirectory.getFiles(), children, fileIndex, moduleFileIndex, settings, |
| withSubDirectories); |
| } |
| return children; |
| } |
| |
| public List<VirtualFile> getTopLevelRoots() { |
| List<VirtualFile> topLevelContentRoots = new ArrayList<VirtualFile>(); |
| ProjectRootManager prm = ProjectRootManager.getInstance(myProject); |
| ProjectFileIndex index = prm.getFileIndex(); |
| |
| for (VirtualFile root : prm.getContentRoots()) { |
| VirtualFile parent = root.getParent(); |
| if (parent == null || !index.isInContent(parent)) { |
| topLevelContentRoots.add(root); |
| } |
| } |
| return topLevelContentRoots; |
| } |
| |
| private PsiElement[] directoryChildrenInProject(PsiDirectory psiDirectory, final ViewSettings settings) { |
| final VirtualFile dir = psiDirectory.getVirtualFile(); |
| if (shouldBeShown(dir, settings)) { |
| final List<PsiElement> children = new ArrayList<PsiElement>(); |
| psiDirectory.processChildren(new PsiElementProcessor<PsiFileSystemItem>() { |
| @Override |
| public boolean execute(@NotNull PsiFileSystemItem element) { |
| if (shouldBeShown(element.getVirtualFile(), settings)) { |
| children.add(element); |
| } |
| return true; |
| } |
| }); |
| return PsiUtilCore.toPsiElementArray(children); |
| } |
| |
| PsiManager manager = psiDirectory.getManager(); |
| Set<PsiElement> directoriesOnTheWayToContentRoots = new THashSet<PsiElement>(); |
| for (VirtualFile root : getTopLevelRoots()) { |
| VirtualFile current = root; |
| while (current != null) { |
| VirtualFile parent = current.getParent(); |
| |
| if (Comparing.equal(parent, dir)) { |
| final PsiDirectory psi = manager.findDirectory(current); |
| if (psi != null) { |
| directoriesOnTheWayToContentRoots.add(psi); |
| } |
| } |
| current = parent; |
| } |
| } |
| |
| return PsiUtilCore.toPsiElementArray(directoriesOnTheWayToContentRoots); |
| } |
| |
| private boolean shouldBeShown(VirtualFile dir, ViewSettings settings) { |
| DirectoryInfo directoryInfo = myIndex.getInfoForFile(dir); |
| if (directoryInfo.isInProject()) return true; |
| |
| if (!Registry.is("ide.hide.excluded.files") && settings instanceof ProjectViewSettings && ((ProjectViewSettings)settings).isShowExcludedFiles()) { |
| return directoryInfo.isExcluded(); |
| } |
| return false; |
| } |
| |
| // used only for non-flatten packages mode |
| public void processPsiDirectoryChildren(final PsiDirectory psiDir, |
| PsiElement[] children, |
| List<AbstractTreeNode> container, |
| ProjectFileIndex projectFileIndex, |
| ModuleFileIndex moduleFileIndex, |
| ViewSettings viewSettings, |
| boolean withSubDirectories) { |
| for (PsiElement child : children) { |
| LOG.assertTrue(child.isValid()); |
| |
| final VirtualFile vFile; |
| if (child instanceof PsiFile) { |
| vFile = ((PsiFile)child).getVirtualFile(); |
| addNode(moduleFileIndex, projectFileIndex, psiDir, vFile, container, PsiFileNode.class, child, viewSettings); |
| } |
| else if (child instanceof PsiDirectory) { |
| if (withSubDirectories) { |
| PsiDirectory dir = (PsiDirectory)child; |
| vFile = dir.getVirtualFile(); |
| if (!vFile.equals(projectFileIndex.getSourceRootForFile(vFile))) { // if is not a source root |
| if (viewSettings.isHideEmptyMiddlePackages() && !skipDirectory(psiDir) && isEmptyMiddleDirectory(dir, true)) { |
| processPsiDirectoryChildren(dir, directoryChildrenInProject(dir, viewSettings), |
| container, projectFileIndex, moduleFileIndex, viewSettings, withSubDirectories); // expand it recursively |
| continue; |
| } |
| } |
| addNode(moduleFileIndex, projectFileIndex, psiDir, vFile, container, PsiDirectoryNode.class, child, viewSettings); |
| } |
| } |
| else { |
| LOG.error("Either PsiFile or PsiDirectory expected as a child of " + child.getParent() + ", but was " + child); |
| } |
| } |
| } |
| |
| public void addNode(ModuleFileIndex moduleFileIndex, |
| ProjectFileIndex projectFileIndex, |
| PsiDirectory psiDir, |
| VirtualFile vFile, |
| List<AbstractTreeNode> container, |
| Class<? extends AbstractTreeNode> nodeClass, |
| PsiElement element, |
| final ViewSettings settings) { |
| if (vFile == null) { |
| return; |
| } |
| // this check makes sense for classes not in library content only |
| if (moduleFileIndex != null && !moduleFileIndex.isInContent(vFile)) { |
| return; |
| } |
| /* |
| final boolean childInLibraryClasses = projectFileIndex.isInLibraryClasses(vFile); |
| if (!projectFileIndex.isInSourceContent(vFile)) { |
| if (childInLibraryClasses) { |
| final VirtualFile psiDirVFile = psiDir.getVirtualFile(); |
| final boolean parentInLibraryContent = |
| projectFileIndex.isInLibraryClasses(psiDirVFile) || projectFileIndex.isInLibrarySource(psiDirVFile); |
| if (!parentInLibraryContent) { |
| return; |
| } |
| } |
| } |
| if (childInLibraryClasses && !projectFileIndex.isInContent(vFile) && !showFileInLibClasses(vFile)) { |
| return; // skip java sources in classpath |
| } |
| */ |
| |
| try { |
| container.add(ProjectViewNode.createTreeNode(nodeClass, element.getProject(), element, settings)); |
| } |
| catch (Exception e) { |
| LOG.error(e); |
| } |
| } |
| |
| // used only in flatten packages mode |
| public void addAllSubpackages(List<AbstractTreeNode> container, |
| PsiDirectory dir, |
| ModuleFileIndex moduleFileIndex, |
| ViewSettings viewSettings) { |
| final Project project = dir.getProject(); |
| PsiDirectory[] subdirs = dir.getSubdirectories(); |
| for (PsiDirectory subdir : subdirs) { |
| if (skipDirectory(subdir)) { |
| continue; |
| } |
| if (moduleFileIndex != null) { |
| if (!moduleFileIndex.isInContent(subdir.getVirtualFile())) { |
| container.add(new PsiDirectoryNode(project, subdir, viewSettings)); |
| continue; |
| } |
| } |
| if (viewSettings.isHideEmptyMiddlePackages()) { |
| if (!isEmptyMiddleDirectory(subdir, false)) { |
| |
| container.add(new PsiDirectoryNode(project, subdir, viewSettings)); |
| } |
| } |
| else { |
| container.add(new PsiDirectoryNode(project, subdir, viewSettings)); |
| } |
| addAllSubpackages(container, subdir, moduleFileIndex, viewSettings); |
| } |
| } |
| } |