run tests on module classpath: Inspection Gadgets
[idea/community.git] / platform / lang-api / src / com / intellij / psi / impl / ElementBase.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
17 package com.intellij.psi.impl;
18
19 import com.intellij.navigation.ItemPresentation;
20 import com.intellij.openapi.diagnostic.Logger;
21 import com.intellij.openapi.util.IconLoader;
22 import com.intellij.openapi.util.Iconable;
23 import com.intellij.openapi.util.Key;
24 import com.intellij.openapi.util.UserDataHolderBase;
25 import com.intellij.openapi.vfs.VirtualFile;
26 import com.intellij.openapi.progress.ProcessCanceledException;
27 import com.intellij.openapi.project.IndexNotReadyException;
28 import com.intellij.psi.PsiElement;
29 import com.intellij.psi.PsiFile;
30 import com.intellij.ui.IconDeferrer;
31 import com.intellij.ui.LayeredIcon;
32 import com.intellij.ui.RowIcon;
33 import com.intellij.util.*;
34 import com.intellij.util.ui.EmptyIcon;
35 import com.intellij.util.ui.update.ComparableObject;
36 import org.jetbrains.annotations.Nullable;
37
38 import javax.swing.*;
39 import java.util.ArrayList;
40 import java.util.List;
41
42 public abstract class ElementBase extends UserDataHolderBase implements Iconable {
43   private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.ElementBase");
44
45   public static final int FLAGS_LOCKED = 0x800;
46   private Icon myBaseIcon;
47
48   @Nullable
49   public Icon getIcon(int flags) {
50     if (!(this instanceof PsiElement)) return null;
51
52     try {
53       return computeIcon(flags);
54     }
55     catch (ProcessCanceledException e) {
56       throw e;
57     }
58     catch (IndexNotReadyException e) {
59       throw e;
60     }
61     catch(Exception e) {
62       LOG.error(e);
63         return null;
64       }
65     }
66
67   private Icon computeIcon(final int flags) {
68     PsiElement psiElement = (PsiElement)this;
69     Icon baseIcon = psiElement.getUserData(Iconable.LAST_COMPUTED_ICON);
70     if (baseIcon == null) {
71       if (myBaseIcon == null) {
72         myBaseIcon = computeBaseIcon();
73       }
74       baseIcon = myBaseIcon;
75     }
76
77     return IconDeferrer.getInstance().defer(baseIcon, new ElementIconRequest(psiElement,flags), new Function<ElementIconRequest, Icon>() {
78       public Icon fun(ElementIconRequest request) {
79         if (!request.getElement().isValid()) return null;
80
81         final Icon providersIcon = PsiIconUtil.getProvidersIcon(request.getElement(), request.getFlags());
82         if (providersIcon != null) {
83           return providersIcon instanceof RowIcon ? (RowIcon)providersIcon : createLayeredIcon(providersIcon, request.getFlags());
84         }
85         return getElementIcon(request.getFlags());
86       }
87     });
88   }
89
90   protected Icon computeBaseIcon() {
91     return new EmptyIcon(IconLoader.getIcon("/nodes/class.png"));
92   }
93
94   public static class ElementIconRequest extends ComparableObject.Impl {
95     public ElementIconRequest(PsiElement element, int flags) {
96       super(new Object[] {element, flags});
97     }
98
99     public PsiElement getElement() {
100       return (PsiElement)getEqualityObjects()[0];
101     }
102
103     public int getFlags() {
104       return (Integer)getEqualityObjects()[1];
105     }
106   }
107
108   protected Icon getElementIcon(final int flags) {
109     final PsiElement element = (PsiElement)this;
110     RowIcon baseIcon;
111     final boolean isLocked = (flags & ICON_FLAG_READ_STATUS) != 0 && !element.isWritable();
112     int elementFlags = isLocked ? FLAGS_LOCKED : 0;
113     if (element instanceof ItemPresentation && ((ItemPresentation)element).getIcon(false) != null) {
114         baseIcon = createLayeredIcon(((ItemPresentation)element).getIcon(false), elementFlags);
115     }
116     else if (element instanceof PsiFile) {
117       PsiFile file = (PsiFile)element;
118
119       VirtualFile virtualFile = file.getVirtualFile();
120       final Icon fileTypeIcon;
121       if (virtualFile == null) {
122         fileTypeIcon = file.getFileType().getIcon();
123       }
124       else {
125         fileTypeIcon = IconUtil.getIcon(virtualFile, flags & ~ICON_FLAG_READ_STATUS, file.getProject());
126       }
127       return createLayeredIcon(fileTypeIcon, elementFlags);
128     }
129     else {
130       return null;
131     }
132     return baseIcon;
133   }
134
135   public static RowIcon createLayeredIcon(Icon icon, int flags) {
136     if (flags != 0) {
137       List<Icon> iconLayers = new SmartList<Icon>();
138       for(IconLayer l: ourIconLayers) {
139         if ((flags & l.flagMask) != 0) {
140           iconLayers.add(l.icon);
141         }
142       }
143       LayeredIcon layeredIcon = new LayeredIcon(1 + iconLayers.size());
144       layeredIcon.setIcon(icon, 0);
145       for (int i = 0; i < iconLayers.size(); i++) {
146         Icon icon1 = iconLayers.get(i);
147         layeredIcon.setIcon(icon1, i+1);
148       }
149       icon = layeredIcon;
150     }
151     RowIcon baseIcon = new RowIcon(2);
152     baseIcon.setIcon(icon, 0);
153     return baseIcon;
154   }
155
156   public static int transformFlags(PsiElement element, int _flags) {
157     int flags = 0;
158     final boolean isLocked = (_flags & ICON_FLAG_READ_STATUS) != 0 && !element.isWritable();
159     if (isLocked) flags |= FLAGS_LOCKED;
160     return flags;
161   }
162
163   private static class IconLayer {
164     int flagMask;
165     Icon icon;
166
167     IconLayer(final int flagMask, final Icon icon) {
168       this.flagMask = flagMask;
169       this.icon = icon;
170     }
171   }
172
173   private static final List<IconLayer> ourIconLayers = new ArrayList<IconLayer>();
174
175   public static void registerIconLayer(int flagMask, Icon icon) {
176     for(IconLayer iconLayer: ourIconLayers) {
177       if (iconLayer.flagMask == flagMask) return;
178     }
179     ourIconLayers.add(new IconLayer(flagMask, icon));
180   }
181
182   static {
183     registerIconLayer(FLAGS_LOCKED, Icons.LOCKED_ICON);
184   }
185 }