1 package com
.intellij
.psi
.impl
;
3 import com
.intellij
.codeInsight
.CodeInsightBundle
;
4 import com
.intellij
.codeInsight
.TestUtil
;
5 import com
.intellij
.compiler
.CompilerConfiguration
;
6 import com
.intellij
.lang
.ant
.PsiAntElement
;
7 import com
.intellij
.navigation
.ItemPresentation
;
8 import com
.intellij
.openapi
.project
.Project
;
9 import com
.intellij
.openapi
.roots
.ProjectRootManager
;
10 import com
.intellij
.openapi
.util
.IconLoader
;
11 import com
.intellij
.openapi
.util
.Iconable
;
12 import com
.intellij
.openapi
.util
.Key
;
13 import com
.intellij
.openapi
.util
.UserDataHolderBase
;
14 import com
.intellij
.openapi
.util
.text
.StringUtil
;
15 import com
.intellij
.openapi
.vfs
.VirtualFile
;
16 import com
.intellij
.psi
.*;
17 import com
.intellij
.psi
.impl
.source
.jsp
.jspJava
.JspClass
;
18 import com
.intellij
.psi
.util
.*;
19 import com
.intellij
.psi
.xml
.XmlTag
;
20 import com
.intellij
.ui
.LayeredIcon
;
21 import com
.intellij
.ui
.RowIcon
;
22 import com
.intellij
.util
.IconUtil
;
23 import com
.intellij
.util
.Icons
;
24 import com
.intellij
.util
.SmartList
;
25 import gnu
.trove
.TIntObjectHashMap
;
26 import org
.jetbrains
.annotations
.Nullable
;
29 import java
.util
.List
;
31 public abstract class ElementBase
extends UserDataHolderBase
implements Iconable
{
32 private static final Icon STATIC_MARK_ICON
= IconLoader
.getIcon("/nodes/staticMark.png");
33 private static final Icon FINAL_MARK_ICON
= IconLoader
.getIcon("/nodes/finalMark.png");
34 private static final Icon JUNIT_TEST_MARK
= IconLoader
.getIcon("/nodes/junitTestMark.png");
35 private static final Icon RUNNABLE_MARK
= IconLoader
.getIcon("/nodes/runnableMark.png");
38 public Icon
getIcon(int flags
) {
39 if (!(this instanceof PsiElement
)) return null;
41 final PsiElement element
= (PsiElement
)this;
43 final Icon providersIcon
= IconUtil
.getProvidersIcon(element
, flags
);
44 if (providersIcon
!= null) {
45 final RowIcon rowIcon
= providersIcon
instanceof RowIcon ?
(RowIcon
)providersIcon
: createLayeredIcon(providersIcon
, flags
);
46 return addVisibilityIcon(element
, flags
, rowIcon
);
49 boolean visibilityAdded
= false;
51 final boolean isLocked
= (flags
& ICON_FLAG_READ_STATUS
) != 0 && !element
.isWritable();
52 int elementFlags
= isLocked ? FLAGS_LOCKED
: 0;
53 if (element
instanceof ItemPresentation
&& ((ItemPresentation
)element
).getIcon(false) != null) {
54 baseIcon
= createLayeredIcon(((ItemPresentation
)element
).getIcon(false), elementFlags
);
55 } else if (element
instanceof PsiDirectory
) {
57 final PsiDirectory psiDirectory
= (PsiDirectory
)element
;
58 if (psiDirectory
.getPackage() != null) {
59 symbolIcon
= Icons
.PACKAGE_ICON
;
62 symbolIcon
= Icons
.DIRECTORY_CLOSED_ICON
;
64 final VirtualFile vFile
= psiDirectory
.getVirtualFile();
65 final Project project
= psiDirectory
.getProject();
66 boolean isExcluded
= isExcluded(vFile
, project
);
67 baseIcon
= createLayeredIcon(symbolIcon
, elementFlags
| (isExcluded ? FLAGS_EXCLUDED
: 0));
69 else if (element
instanceof PsiPackage
) {
70 baseIcon
= createLayeredIcon(Icons
.PACKAGE_ICON
, elementFlags
);
72 else if (element
instanceof PsiFile
) {
73 PsiFile file
= (PsiFile
)element
;
75 VirtualFile virtualFile
= file
.getVirtualFile();
76 final Icon fileTypeIcon
;
77 if (virtualFile
== null) {
78 fileTypeIcon
= file
.getFileType().getIcon();
81 fileTypeIcon
= IconUtil
.getIcon(virtualFile
, flags
& ~ICON_FLAG_READ_STATUS
, file
.getProject());
82 if (fileTypeIcon
instanceof RowIcon
) {
83 visibilityAdded
= true;
86 baseIcon
= createLayeredIcon(fileTypeIcon
, elementFlags
);
88 else if (element
instanceof PsiClass
) {
89 final PsiClass aClass
= (PsiClass
)element
;
90 Icon symbolIcon
= getClassBaseIcon(aClass
);
91 baseIcon
= createLayeredIcon(symbolIcon
, getFlags(aClass
, isLocked
));
93 else if (element
instanceof PsiMethod
) {
94 final PsiMethod method
= (PsiMethod
)element
;
95 Icon methodIcon
= method
.hasModifierProperty(PsiModifier
.ABSTRACT
) ? Icons
.ABSTRACT_METHOD_ICON
: Icons
.METHOD_ICON
;
96 baseIcon
= createLayeredIcon(methodIcon
, getFlags(method
, false));
98 else if (element
instanceof PsiField
) {
99 baseIcon
= createLayeredIcon(Icons
.FIELD_ICON
, getFlags((PsiField
)element
, false));
101 else if (element
instanceof PsiParameter
) {
102 baseIcon
= createLayeredIcon(Icons
.PARAMETER_ICON
, 0);
104 else if (element
instanceof PsiVariable
) {
105 baseIcon
= createLayeredIcon(Icons
.VARIABLE_ICON
, getFlags((PsiVariable
)element
, false));
107 else if (element
instanceof XmlTag
) {
108 return Icons
.XML_TAG_ICON
;
110 else if (element
instanceof PsiAntElement
) {
111 return ((PsiAntElement
)element
).getRole().getIcon();
113 else if (element
instanceof PsiClassObjectAccessExpression
) {
114 final RowIcon rowIcon
= createLayeredIcon(Icons
.FIELD_ICON
, 0);
115 rowIcon
.setIcon(Icons
.PUBLIC_ICON
, 1);
118 else if (element
instanceof PsiClassInitializer
) {
119 return createLayeredIcon(Icons
.CLASS_INITIALIZER
, getFlags((PsiClassInitializer
)element
, false));
124 return visibilityAdded ? baseIcon
: addVisibilityIcon(element
, flags
, baseIcon
);
127 private static Icon
addVisibilityIcon(final PsiElement element
, final int flags
, final RowIcon baseIcon
) {
128 if ((flags
& ICON_FLAG_VISIBILITY
) != 0) {
129 PsiModifierList modifierList
= element
instanceof PsiModifierListOwner ?
((PsiModifierListOwner
)element
).getModifierList() : null;
130 IconUtil
.setVisibilityIcon(modifierList
, baseIcon
);
135 private static boolean isExcluded(final VirtualFile vFile
, final Project project
) {
137 && ProjectRootManager
.getInstance(project
).getFileIndex().isInSource(vFile
)
138 && CompilerConfiguration
.getInstance(project
).isExcludedFromCompilation(vFile
);
141 public static int getFlags(PsiModifierListOwner element
, final boolean isLocked
) {
142 final PsiFile containingFile
= element
.getContainingFile();
143 final VirtualFile vFile
= containingFile
== null ?
null : containingFile
.getVirtualFile();
144 final boolean isEnum
= element
instanceof PsiClass
&& ((PsiClass
)element
).isEnum();
145 int flags
= (element
.hasModifierProperty(PsiModifier
.FINAL
) && !isEnum ? FLAGS_FINAL
: 0)
146 | (element
.hasModifierProperty(PsiModifier
.STATIC
) && !isEnum ? FLAGS_STATIC
: 0)
147 | (isLocked ? FLAGS_LOCKED
: 0)
148 | (isExcluded(vFile
, element
.getProject()) ? FLAGS_EXCLUDED
: 0);
149 if (element
instanceof PsiClass
) {
150 final PsiClass aClass
= (PsiClass
)element
;
151 if (element
.hasModifierProperty(PsiModifier
.ABSTRACT
) && !((PsiClass
)element
).isInterface()) {
152 flags
|= FLAGS_ABSTRACT
;
154 int kind
= getClassKind(aClass
);
155 if (kind
== CLASS_KIND_JUNIT_TEST
) {
156 flags
|= FLAGS_JUNIT_TEST
;
158 else if (kind
== CLASS_KIND_RUNNABLE
) {
159 flags
|= FLAGS_RUNNABLE
;
165 private static final Icon ABSTRACT_EXCEPTION_CLASS_ICON
= IconLoader
.getIcon("/nodes/abstractException.png");
167 private static final int CLASS_KIND_INTERFACE
= 10;
168 private static final int CLASS_KIND_ANNOTATION
= 20;
169 public static final int CLASS_KIND_CLASS
= 30;
170 private static final int CLASS_KIND_ANONYMOUS
= 40;
171 private static final int CLASS_KIND_ENUM
= 50;
172 private static final int CLASS_KIND_ASPECT
= 60;
173 private static final int CLASS_KIND_JSP
= 70;
174 public static final int CLASS_KIND_EXCEPTION
= 80;
175 private static final int CLASS_KIND_JUNIT_TEST
= 90;
176 private static final int CLASS_KIND_RUNNABLE
= 100;
178 private static final int FLAGS_ABSTRACT
= 0x100;
179 private static final int FLAGS_STATIC
= 0x200;
180 private static final int FLAGS_FINAL
= 0x400;
181 private static final int FLAGS_LOCKED
= 0x800;
182 private static final int FLAGS_EXCLUDED
= 0x1000;
183 private static final int FLAGS_JUNIT_TEST
= 0x2000;
184 private static final int FLAGS_RUNNABLE
= 0x4000;
186 private static final Key
<CachedValue
<Integer
>> CLASS_KIND_KEY
= new Key
<CachedValue
<Integer
>>("CLASS_KIND_KEY");
188 public static int getClassKind(final PsiClass aClass
) {
189 if (!aClass
.isValid()) {
190 aClass
.putUserData(CLASS_KIND_KEY
, null);
191 return CLASS_KIND_CLASS
;
194 CachedValue
<Integer
> value
= aClass
.getUserData(CLASS_KIND_KEY
);
196 value
= aClass
.getManager().getCachedValuesManager().createCachedValue(new CachedValueProvider
<Integer
>() {
197 public Result
<Integer
> compute() {
198 return Result
.createSingleDependency(Integer
.valueOf(getClassKindImpl(aClass
)), aClass
);
201 aClass
.putUserData(CLASS_KIND_KEY
, value
);
203 return value
.getValue().intValue();
206 private static int getClassKindImpl(PsiClass aClass
) {
207 if (!aClass
.isValid()) return CLASS_KIND_CLASS
;
209 if (aClass
.isAnnotationType()) {
210 return CLASS_KIND_ANNOTATION
;
212 if (aClass
.isEnum()) {
213 return CLASS_KIND_ENUM
;
215 if (aClass
.isInterface()) {
216 return CLASS_KIND_INTERFACE
;
218 if (aClass
instanceof JspClass
) {
219 return CLASS_KIND_JSP
;
221 if (aClass
instanceof PsiAnonymousClass
) {
222 return CLASS_KIND_ANONYMOUS
;
225 final PsiManager manager
= aClass
.getManager();
226 final PsiClass javaLangTrowable
= manager
.findClass("java.lang.Throwable", aClass
.getResolveScope());
227 final boolean isException
= javaLangTrowable
!= null && InheritanceUtil
.isInheritorOrSelf(aClass
, javaLangTrowable
, true);
229 return CLASS_KIND_EXCEPTION
;
232 if (TestUtil
.isTestClass(aClass
)) {
233 return CLASS_KIND_JUNIT_TEST
;
235 if (PsiClassUtil
.isRunnableClass(aClass
, false) && PsiMethodUtil
.findMainMethod(aClass
) != null) {
236 return CLASS_KIND_RUNNABLE
;
238 return CLASS_KIND_CLASS
;
241 private static final TIntObjectHashMap
<Icon
> BASE_ICON
= new TIntObjectHashMap
<Icon
>(20);
243 BASE_ICON
.put(CLASS_KIND_CLASS
, Icons
.CLASS_ICON
);
244 BASE_ICON
.put(CLASS_KIND_CLASS
| FLAGS_ABSTRACT
, Icons
.ABSTRACT_CLASS_ICON
);
245 BASE_ICON
.put(CLASS_KIND_ANNOTATION
, Icons
.ANNOTATION_TYPE_ICON
);
246 BASE_ICON
.put(CLASS_KIND_ANNOTATION
| FLAGS_ABSTRACT
, Icons
.ANNOTATION_TYPE_ICON
);
247 BASE_ICON
.put(CLASS_KIND_ANONYMOUS
, Icons
.ANONYMOUS_CLASS_ICON
);
248 BASE_ICON
.put(CLASS_KIND_ANONYMOUS
| FLAGS_ABSTRACT
, Icons
.ANONYMOUS_CLASS_ICON
);
249 BASE_ICON
.put(CLASS_KIND_ASPECT
, Icons
.ASPECT_ICON
);
250 BASE_ICON
.put(CLASS_KIND_ASPECT
| FLAGS_ABSTRACT
, Icons
.ASPECT_ICON
);
251 BASE_ICON
.put(CLASS_KIND_ENUM
, Icons
.ENUM_ICON
);
252 BASE_ICON
.put(CLASS_KIND_ENUM
| FLAGS_ABSTRACT
, Icons
.ENUM_ICON
);
253 BASE_ICON
.put(CLASS_KIND_EXCEPTION
, Icons
.EXCEPTION_CLASS_ICON
);
254 BASE_ICON
.put(CLASS_KIND_EXCEPTION
| FLAGS_ABSTRACT
, ABSTRACT_EXCEPTION_CLASS_ICON
);
255 BASE_ICON
.put(CLASS_KIND_INTERFACE
, Icons
.INTERFACE_ICON
);
256 BASE_ICON
.put(CLASS_KIND_INTERFACE
| FLAGS_ABSTRACT
, Icons
.INTERFACE_ICON
);
257 BASE_ICON
.put(CLASS_KIND_JSP
, Icons
.JSP_ICON
);
258 BASE_ICON
.put(CLASS_KIND_JSP
| FLAGS_ABSTRACT
, Icons
.JSP_ICON
);
259 BASE_ICON
.put(CLASS_KIND_JUNIT_TEST
, Icons
.CLASS_ICON
);
260 BASE_ICON
.put(CLASS_KIND_JUNIT_TEST
| FLAGS_ABSTRACT
, Icons
.ABSTRACT_CLASS_ICON
);
261 BASE_ICON
.put(CLASS_KIND_RUNNABLE
, Icons
.CLASS_ICON
);
264 private static Icon
getClassBaseIcon(final PsiClass aClass
) {
265 final int classKind
= getClassKind(aClass
);
266 final boolean isAbstract
= aClass
.hasModifierProperty(PsiModifier
.ABSTRACT
);
267 return BASE_ICON
.get(classKind
| (isAbstract ? FLAGS_ABSTRACT
: 0));
270 public static String
getDescription(PsiModifierListOwner member
) {
272 if (member
instanceof PsiClass
) noun
= getClassNoun((PsiClass
)member
);
273 else if (member
instanceof PsiMethod
) noun
= CodeInsightBundle
.message("node.method.tooltip");
274 else if (member
instanceof PsiField
) noun
= CodeInsightBundle
.message("node.field.tooltip");
276 String adj
= getFlagsDescription(member
);
277 return (adj
+ " " + noun
).trim();
280 private static String
getClassNoun(final PsiClass aClass
) {
282 int kind
= getClassKind(aClass
);
284 case CLASS_KIND_ANNOTATION
: noun
= CodeInsightBundle
.message("node.annotation.tooltip"); break;
285 case CLASS_KIND_ANONYMOUS
: noun
= CodeInsightBundle
.message("node.anonymous.class.tooltip"); break;
286 case CLASS_KIND_ENUM
: noun
= CodeInsightBundle
.message("node.enum.tooltip"); break;
287 case CLASS_KIND_EXCEPTION
: noun
= CodeInsightBundle
.message("node.exception.tooltip"); break;
288 case CLASS_KIND_INTERFACE
: noun
= CodeInsightBundle
.message("node.interface.tooltip"); break;
289 case CLASS_KIND_JUNIT_TEST
: noun
= CodeInsightBundle
.message("node.junit.test.tooltip"); break;
290 case CLASS_KIND_RUNNABLE
: noun
= CodeInsightBundle
.message("node.runnable.class.tooltip"); break;
292 case CLASS_KIND_CLASS
: noun
= CodeInsightBundle
.message("node.class.tooltip"); break;
297 private static String
getFlagsDescription(final PsiModifierListOwner aClass
) {
298 int flags
= getFlags(aClass
, false);
300 if ((flags
& FLAGS_EXCLUDED
) != 0) adj
+= " " + CodeInsightBundle
.message("node.excluded.flag.tooltip");
301 if ((flags
& FLAGS_ABSTRACT
) != 0) adj
+= " " + CodeInsightBundle
.message("node.abstract.flag.tooltip");
302 if ((flags
& FLAGS_FINAL
) != 0) adj
+= " " + CodeInsightBundle
.message("node.final.flag.tooltip");
303 if ((flags
& FLAGS_STATIC
) != 0) adj
+= " " + CodeInsightBundle
.message("node.static.flag.tooltip");
304 PsiModifierList list
= aClass
.getModifierList();
306 int level
= PsiUtil
.getAccessLevel(list
);
307 if (level
!= PsiUtil
.ACCESS_LEVEL_PUBLIC
) {
308 adj
+= " " + StringUtil
.capitalize(PsiUtil
.getAccessModifier(level
));
314 public static RowIcon
createLayeredIcon(Icon icon
, int flags
) {
316 List
<Icon
> iconLayers
= new SmartList
<Icon
>();
317 if ((flags
& FLAGS_STATIC
) != 0) {
318 iconLayers
.add(STATIC_MARK_ICON
);
320 if ((flags
& FLAGS_LOCKED
) != 0) {
321 iconLayers
.add(Icons
.LOCKED_ICON
);
323 if ((flags
& FLAGS_EXCLUDED
) != 0) {
324 iconLayers
.add(Icons
.EXCLUDED_FROM_COMPILE_ICON
);
326 final boolean isFinal
= (flags
& FLAGS_FINAL
) != 0;
328 iconLayers
.add(FINAL_MARK_ICON
);
330 if ((flags
& FLAGS_JUNIT_TEST
) != 0) {
331 iconLayers
.add(JUNIT_TEST_MARK
);
333 if ((flags
& FLAGS_RUNNABLE
) != 0) {
334 iconLayers
.add(RUNNABLE_MARK
);
336 LayeredIcon layeredIcon
= new LayeredIcon(1 + iconLayers
.size());
337 layeredIcon
.setIcon(icon
, 0);
338 for (int i
= 0; i
< iconLayers
.size(); i
++) {
339 Icon icon1
= iconLayers
.get(i
);
340 layeredIcon
.setIcon(icon1
, i
+1);
344 RowIcon baseIcon
= new RowIcon(2);
345 baseIcon
.setIcon(icon
, 0);