deferred icons fix -- caches for different flags
[idea/community.git] / platform / platform-api / src / com / intellij / util / IconUtil.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.util;
17
18 import com.intellij.ide.FileIconPatcher;
19 import com.intellij.ide.FileIconProvider;
20 import com.intellij.openapi.extensions.Extensions;
21 import com.intellij.openapi.project.DumbAware;
22 import com.intellij.openapi.project.DumbService;
23 import com.intellij.openapi.project.Project;
24 import com.intellij.openapi.util.IconLoader;
25 import com.intellij.openapi.util.Iconable;
26 import com.intellij.openapi.vfs.VirtualFile;
27 import com.intellij.ui.IconDeferrer;
28 import com.intellij.ui.RowIcon;
29 import com.intellij.ui.LayeredIcon;
30 import com.intellij.util.ui.EmptyIcon;
31 import org.jetbrains.annotations.Nullable;
32
33 import javax.swing.*;
34
35
36 public class IconUtil {
37
38   private IconUtil() {
39   }
40
41   private static class FileIconKey {
42     private final VirtualFile myFile;
43     private final Project myProject;
44     private final int myFlags;
45
46     private FileIconKey(final VirtualFile file, final Project project, final int flags) {
47       myFile = file;
48       myProject = project;
49       myFlags = flags;
50     }
51
52     @Override
53     public boolean equals(final Object o) {
54       if (this == o) return true;
55       if (!(o instanceof FileIconKey)) return false;
56
57       final FileIconKey that = (FileIconKey)o;
58
59       if (myFlags != that.myFlags) return false;
60       if (!myFile.equals(that.myFile)) return false;
61       if (myProject != null ? !myProject.equals(that.myProject) : that.myProject != null) return false;
62
63       return true;
64     }
65
66     @Override
67     public int hashCode() {
68       int result = myFile.hashCode();
69       result = 31 * result + (myProject != null ? myProject.hashCode() : 0);
70       result = 31 * result + myFlags;
71       return result;
72     }
73
74     public VirtualFile getFile() {
75       return myFile;
76     }
77
78     public Project getProject() {
79       return myProject;
80     }
81
82     public int getFlags() {
83       return myFlags;
84     }
85   }
86
87   public static Icon getIcon(final VirtualFile file, final int flags, final Project project) {
88     Icon lastIcon = Iconable.LastComputedIcon.get(file, flags);
89
90     return IconDeferrer.getInstance().defer(lastIcon != null ? lastIcon : file.getIcon(), new FileIconKey(file, project, flags), new Function<FileIconKey, Icon>() {
91       public Icon fun(final FileIconKey key) {
92         VirtualFile file = key.getFile();
93         int flags = key.getFlags();
94         Project project = key.getProject();
95
96         if (!file.isValid() || project != null && project.isDisposed()) return null;
97
98         Icon providersIcon = getProvidersIcon(file, flags, project);
99         Icon icon = providersIcon == null ? file.getIcon() : providersIcon;
100
101         final boolean dumb = project != null && DumbService.getInstance(project).isDumb();
102         for (FileIconPatcher patcher : getPatchers()) {
103           if (dumb && !(patcher instanceof DumbAware)) {
104             continue;
105           }
106
107           icon = patcher.patchIcon(icon, file, flags, project);
108         }
109
110         if ((flags & Iconable.ICON_FLAG_READ_STATUS) != 0 && !file.isWritable()) {
111           icon = new LayeredIcon(icon, Icons.LOCKED_ICON);
112         }
113         
114         Iconable.LastComputedIcon.put(file, icon, flags);
115
116         return icon;
117       }
118     });
119   }
120
121   @Nullable
122   private static Icon getProvidersIcon(VirtualFile file, int flags, Project project) {
123     for (FileIconProvider provider : getProviders()) {
124       final Icon icon = provider.getIcon(file, flags, project);
125       if (icon != null) return icon;
126     }
127     return null;
128   }
129
130   public static Icon getEmptyIcon(boolean showVisibility) {
131     RowIcon baseIcon = new RowIcon(2);
132     baseIcon.setIcon(createEmptyIconLike(Icons.CLASS_ICON_PATH), 0);
133     if (showVisibility) {
134       baseIcon.setIcon(createEmptyIconLike(Icons.PUBLIC_ICON_PATH), 1);
135     }
136     return baseIcon;
137   }
138
139   @Nullable
140   private static Icon createEmptyIconLike(final String baseIconPath) {
141     Icon baseIcon = IconLoader.findIcon(baseIconPath);
142     if (baseIcon == null) {
143       return new EmptyIcon(16, 16);
144     }
145     return new EmptyIcon(baseIcon.getIconWidth(), baseIcon.getIconHeight());
146   }
147
148   private static class FileIconProviderHolder {
149     private static final FileIconProvider[] ourProviders = Extensions.getExtensions(FileIconProvider.EP_NAME);
150   }
151
152   private static FileIconProvider[] getProviders() {
153     return FileIconProviderHolder.ourProviders;
154   }
155
156   private static class FileIconPatcherHolder {
157     private static final FileIconPatcher[] ourPatchers = Extensions.getExtensions(FileIconPatcher.EP_NAME);
158   }
159
160   private static FileIconPatcher[] getPatchers() {
161     return FileIconPatcherHolder.ourPatchers;
162   }
163 }