2 * Copyright 2000-2009 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.intellij.psi.impl;
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;
39 import java.util.ArrayList;
40 import java.util.List;
42 public abstract class ElementBase extends UserDataHolderBase implements Iconable {
43 private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.ElementBase");
45 public static final int FLAGS_LOCKED = 0x800;
46 private Icon myBaseIcon;
49 public Icon getIcon(int flags) {
50 if (!(this instanceof PsiElement)) return null;
53 return computeIcon(flags);
55 catch (ProcessCanceledException e) {
58 catch (IndexNotReadyException e) {
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();
74 baseIcon = myBaseIcon;
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;
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());
85 return getElementIcon(request.getFlags());
90 protected Icon computeBaseIcon() {
91 return new EmptyIcon(IconLoader.getIcon("/nodes/class.png"));
94 public static class ElementIconRequest extends ComparableObject.Impl {
95 public ElementIconRequest(PsiElement element, int flags) {
96 super(new Object[] {element, flags});
99 public PsiElement getElement() {
100 return (PsiElement)getEqualityObjects()[0];
103 public int getFlags() {
104 return (Integer)getEqualityObjects()[1];
108 protected Icon getElementIcon(final int flags) {
109 final PsiElement element = (PsiElement)this;
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);
116 else if (element instanceof PsiFile) {
117 PsiFile file = (PsiFile)element;
119 VirtualFile virtualFile = file.getVirtualFile();
120 final Icon fileTypeIcon;
121 if (virtualFile == null) {
122 fileTypeIcon = file.getFileType().getIcon();
125 fileTypeIcon = IconUtil.getIcon(virtualFile, flags & ~ICON_FLAG_READ_STATUS, file.getProject());
127 return createLayeredIcon(fileTypeIcon, elementFlags);
135 public static RowIcon createLayeredIcon(Icon icon, int flags) {
137 List<Icon> iconLayers = new SmartList<Icon>();
138 for(IconLayer l: ourIconLayers) {
139 if ((flags & l.flagMask) != 0) {
140 iconLayers.add(l.icon);
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);
151 RowIcon baseIcon = new RowIcon(2);
152 baseIcon.setIcon(icon, 0);
156 public static int transformFlags(PsiElement element, int _flags) {
158 final boolean isLocked = (_flags & ICON_FLAG_READ_STATUS) != 0 && !element.isWritable();
159 if (isLocked) flags |= FLAGS_LOCKED;
163 private static class IconLayer {
167 IconLayer(final int flagMask, final Icon icon) {
168 this.flagMask = flagMask;
173 private static final List<IconLayer> ourIconLayers = new ArrayList<IconLayer>();
175 public static void registerIconLayer(int flagMask, Icon icon) {
176 for(IconLayer iconLayer: ourIconLayers) {
177 if (iconLayer.flagMask == flagMask) return;
179 ourIconLayers.add(new IconLayer(flagMask, icon));
183 registerIconLayer(FLAGS_LOCKED, Icons.LOCKED_ICON);