/* * 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 getDirectoryChildren(final PsiDirectory psiDirectory, final ViewSettings settings, final boolean withSubDirectories) { final List children = new ArrayList(); 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 getTopLevelRoots() { List topLevelContentRoots = new ArrayList(); 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 children = new ArrayList(); psiDirectory.processChildren(new PsiElementProcessor() { @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 directoriesOnTheWayToContentRoots = new THashSet(); 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 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 container, Class 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 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); } } }