// Copyright 2014 Pants project contributors (see CONTRIBUTORS.md). // Licensed under the Apache License, Version 2.0 (see LICENSE). package com.twitter.intellij.pants.projectview; import com.intellij.icons.AllIcons; import com.intellij.ide.projectView.PresentationData; import com.intellij.ide.projectView.ProjectView; import com.intellij.ide.projectView.ProjectViewNode; import com.intellij.ide.projectView.ViewSettings; import com.intellij.ide.projectView.impl.ProjectViewImpl; import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode; import com.intellij.ide.projectView.impl.nodes.PsiFileNode; import com.intellij.ide.util.treeView.AbstractTreeNode; import com.intellij.openapi.module.ModuleUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.twitter.intellij.pants.components.PantsProjectCache; import com.twitter.intellij.pants.components.impl.PantsProjectCacheImpl; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; public class VirtualFileTreeNode extends ProjectViewNode<VirtualFile> { public VirtualFileTreeNode( @NotNull Project project, @NotNull VirtualFile virtualFile, @NotNull ViewSettings viewSettings ) { super(project, virtualFile, viewSettings); } @Nullable @Override public VirtualFile getVirtualFile() { return getValue(); } @Override public int getWeight() { final ProjectView projectView = ProjectView.getInstance(myProject); final boolean foldersOnTop = projectView instanceof ProjectViewImpl && !((ProjectViewImpl)projectView).isFoldersAlwaysOnTop(); return foldersOnTop && getValue().isDirectory() ? 20 : 0; // see PsiDirectoryNode.getWeight() } @Override public boolean contains(@NotNull VirtualFile file) { final VirtualFile myFile = getValue(); return myFile.isDirectory() && VfsUtil.isAncestor(myFile, file, true); } @Override protected void update(PresentationData presentation) { final PsiManager psiManager = PsiManager.getInstance(myProject); final VirtualFile virtualFile = getValue(); final PsiFile psiElement = virtualFile.isValid() ? psiManager.findFile(virtualFile) : null; if (psiElement instanceof PsiDirectory) { new PsiDirectoryNode(myProject, (PsiDirectory)psiElement, getSettings()).update(presentation); } else if (psiElement != null) { new PsiFileNode(myProject, psiElement, getSettings()).update(presentation); } else { presentation.setPresentableText(virtualFile.getName()); presentation.setIcon(virtualFile.isDirectory() ? AllIcons.Nodes.Folder : virtualFile.getFileType().getIcon()); } } @NotNull @Override public Collection<? extends AbstractTreeNode> getChildren() { final PsiManager psiManager = PsiManager.getInstance(myProject); final VirtualFile virtualFile = getValue(); return ContainerUtil.mapNotNull( virtualFile.isValid() && virtualFile.isDirectory() ? virtualFile.getChildren() : VirtualFile.EMPTY_ARRAY, new Function<VirtualFile, AbstractTreeNode>() { @Override public AbstractTreeNode fun(VirtualFile file) { final PsiElement psiElement = file.isDirectory() ? psiManager.findDirectory(file) : psiManager.findFile(file); if (psiElement instanceof PsiDirectory && ModuleUtil.findModuleForPsiElement(psiElement) != null) { // PsiDirectoryNode doesn't render files outside of a project // let's use PsiDirectoryNode only for folders in a modules return new PsiDirectoryNode(myProject, (PsiDirectory)psiElement, getSettings()); } else if (psiElement instanceof PsiFile) { return new PsiFileNode(myProject, (PsiFile)psiElement, getSettings()); } else { return shouldShow(file) ? new VirtualFileTreeNode(myProject, file, getSettings()) : null; } } } ); } private boolean shouldShow(@NotNull VirtualFile file) { if (!file.isValid()) { return false; } if (file.isDirectory()) { return shouldIncludeDirectory(file); } return !file.getName().startsWith("."); } private boolean shouldIncludeDirectory(VirtualFile dir) { final ViewSettings viewSettings = getSettings(); if (viewSettings instanceof PantsViewSettings && ((PantsViewSettings)viewSettings).isShowOnlyLoadedFiles()) { final PantsProjectCache projectCache = PantsProjectCacheImpl.getInstance(getProject()); return projectCache.folderContainsSourceRoot(dir); } return true; } }