add ProjectFileIndex#getSourceFolder to simplify clients (IDEA-CR-57371)
[idea/community.git] / platform / lang-impl / src / com / intellij / psi / impl / file / SourceRootIconProvider.java
1 // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2
3 package com.intellij.psi.impl.file;
4
5 import com.intellij.icons.AllIcons;
6 import com.intellij.ide.IconLayerProvider;
7 import com.intellij.ide.IconProvider;
8 import com.intellij.ide.projectView.impl.ProjectRootsUtil;
9 import com.intellij.openapi.project.DumbAware;
10 import com.intellij.openapi.project.Project;
11 import com.intellij.openapi.roots.ProjectFileIndex;
12 import com.intellij.openapi.roots.ProjectRootManager;
13 import com.intellij.openapi.roots.SourceFolder;
14 import com.intellij.openapi.roots.impl.ProjectFileIndexImpl;
15 import com.intellij.openapi.roots.ui.configuration.SourceRootPresentation;
16 import com.intellij.openapi.util.Iconable;
17 import com.intellij.openapi.util.registry.Registry;
18 import com.intellij.openapi.vfs.VirtualFile;
19 import com.intellij.psi.PsiDirectory;
20 import com.intellij.psi.PsiElement;
21 import com.intellij.psi.PsiFile;
22 import com.intellij.psi.util.CachedValueProvider;
23 import com.intellij.psi.util.CachedValuesManager;
24 import com.intellij.util.ObjectUtils;
25 import com.intellij.util.PlatformIcons;
26 import org.jetbrains.annotations.NotNull;
27 import org.jetbrains.annotations.Nullable;
28
29 import javax.swing.*;
30
31 public class SourceRootIconProvider {
32   @NotNull
33   public static Icon getDirectoryIcon(VirtualFile vFile, Project project) {
34     SourceFolder sourceFolder = ProjectRootsUtil.getModuleSourceRoot(vFile, project);
35     if (sourceFolder != null) {
36       return SourceRootPresentation.getSourceRootIcon(sourceFolder);
37     }
38     else {
39       Icon excludedIcon = getIconIfExcluded(project, vFile);
40       return excludedIcon != null ? excludedIcon : PlatformIcons.FOLDER_ICON;
41     }
42   }
43   
44   @Nullable
45   public static Icon getIconIfExcluded(@NotNull Project project, @NotNull VirtualFile vFile) {
46     if (!Registry.is("ide.hide.excluded.files")) {
47       boolean ignored = ProjectRootManager.getInstance(project).getFileIndex().isExcluded(vFile);
48       if (ignored) {
49         return AllIcons.Modules.ExcludeRoot;
50       }
51     }
52     return null;
53   }
54
55   @Nullable
56   private static Icon calcFileLayerIcon(VirtualFile vFile, Project project) {
57     ProjectFileIndex index = ProjectFileIndex.getInstance(project);
58     if (vFile != null) {
59       VirtualFile parent = vFile.getParent();
60       
61       if (index.isExcluded(vFile)) {
62         //If the parent directory is also excluded it'll have a special icon (see DirectoryIconProvider), so it makes no sense to add
63         // additional marks for all files under it.
64         if (parent == null || !index.isExcluded(parent)) {
65           return AllIcons.Nodes.ExcludedFromCompile;
66         }
67       }
68       else {
69         SourceFolder sourceFolder = index.getSourceFolder(vFile);
70         if (sourceFolder != null && vFile.equals(sourceFolder.getFile())) {
71           SourceFolder parentSourceFolder = parent == null ? null : index.getSourceFolder(parent);
72
73           // do not mark files under folder of the same root type (e.g. test root file under test root dir)
74           // but mark file if they are under different root type (e.g. test root file under source root dir)
75           if (parentSourceFolder == null || !sourceFolder.equals(parentSourceFolder)) {
76             return SourceRootPresentation.getSourceRootFileLayerIcon(sourceFolder);
77           }
78         }
79       }
80     }
81     return null;
82   }
83
84   public static class DirectoryProvider extends IconProvider implements DumbAware {
85     @Override
86     public Icon getIcon(@NotNull final PsiElement element, final int flags) {
87       if (element instanceof PsiDirectory) {
88         final PsiDirectory psiDirectory = (PsiDirectory)element;
89         return getDirectoryIcon(psiDirectory.getVirtualFile(), psiDirectory.getProject());
90       }
91       return null;
92     }
93   }
94   
95   public static class FileLayerProvider implements IconLayerProvider, DumbAware {
96     @Nullable
97     @Override
98     public Icon getLayerIcon(@NotNull Iconable element, boolean isLocked) {
99       if (element instanceof PsiFile) {
100         Project project = ((PsiFile)element).getProject();
101         VirtualFile virtualFile = ((PsiFile)element).getVirtualFile();
102         return CachedValuesManager.getCachedValue((PsiElement)element,
103                                                   () -> CachedValueProvider.Result.create(calcFileLayerIcon(virtualFile, project),
104                                                                                           ProjectRootManager.getInstance(project)));
105       }
106       return null;
107     }
108   
109     @NotNull
110     @Override
111     public String getLayerDescription() {
112       return "Source root files";
113     }
114   }
115 }