NavigationGutterIconBuilder
[fedora-idea.git] / xml / dom-openapi / src / com / intellij / codeInsight / navigation / NavigationGutterIconBuilder.java
blob5066558334ce716da75add36cadf4892517c5e42
1 /*
2 * Copyright (c) 2000-2007 JetBrains s.r.o. All Rights Reserved.
3 */
4 package com.intellij.codeInsight.navigation;
6 import com.intellij.codeHighlighting.Pass;
7 import com.intellij.codeInsight.daemon.LineMarkerInfo;
8 import com.intellij.ide.util.DefaultPsiElementCellRenderer;
9 import com.intellij.ide.util.PsiElementListCellRenderer;
10 import com.intellij.lang.annotation.Annotation;
11 import com.intellij.lang.annotation.AnnotationHolder;
12 import com.intellij.lang.annotation.HighlightSeverity;
13 import com.intellij.openapi.editor.markup.GutterIconRenderer;
14 import com.intellij.openapi.project.Project;
15 import com.intellij.openapi.util.NotNullLazyValue;
16 import com.intellij.psi.PsiElement;
17 import com.intellij.psi.SmartPointerManager;
18 import com.intellij.psi.SmartPsiElementPointer;
19 import com.intellij.util.NotNullFunction;
20 import com.intellij.util.NullableFunction;
21 import com.intellij.util.containers.ContainerUtil;
22 import com.intellij.util.xml.DomElement;
23 import com.intellij.util.xml.ElementPresentationManager;
24 import com.intellij.util.xml.highlighting.DomElementAnnotationHolder;
25 import gnu.trove.THashSet;
26 import org.jetbrains.annotations.NonNls;
27 import org.jetbrains.annotations.NotNull;
28 import org.jetbrains.annotations.Nullable;
30 import javax.swing.*;
31 import java.text.MessageFormat;
32 import java.util.*;
34 /**
35 * @author peter
37 public class NavigationGutterIconBuilder<T> {
38 @NonNls private static final String PATTERN = "&nbsp;&nbsp;&nbsp;&nbsp;{0}";
39 private static final NotNullFunction<PsiElement,Collection<? extends PsiElement>> DEFAULT_PSI_CONVERTOR = new NotNullFunction<PsiElement, Collection<? extends PsiElement>>() {
40 @NotNull
41 public Collection<? extends PsiElement> fun(final PsiElement element) {
42 return ContainerUtil.createMaybeSingletonList(element);
46 private final Icon myIcon;
47 private final NotNullFunction<T,Collection<? extends PsiElement>> myConvertor;
49 private NotNullLazyValue<Collection<? extends T>> myTargets;
50 private boolean myLazy;
51 private String myTooltipText;
52 private String myPopupTitle;
53 private String myEmptyText;
54 private String myTooltipTitle;
55 private GutterIconRenderer.Alignment myAlignment = GutterIconRenderer.Alignment.CENTER;
56 private PsiElementListCellRenderer myCellRenderer;
57 private NullableFunction<T,String> myNamer = (NullableFunction<T, String>)ElementPresentationManager.NAMER;
58 public static final NotNullFunction<DomElement,Collection<? extends PsiElement>> DEFAULT_DOM_CONVERTOR = new NotNullFunction<DomElement, Collection<? extends PsiElement>>() {
59 @NotNull
60 public Collection<? extends PsiElement> fun(final DomElement o) {
61 return ContainerUtil.createMaybeSingletonList(o.getXmlElement());
65 protected NavigationGutterIconBuilder(@NotNull final Icon icon, NotNullFunction<T,Collection<? extends PsiElement>> convertor) {
66 myIcon = icon;
67 myConvertor = convertor;
70 public static NavigationGutterIconBuilder<PsiElement> create(@NotNull final Icon icon) {
71 return create(icon, DEFAULT_PSI_CONVERTOR);
74 public static <T> NavigationGutterIconBuilder<T> create(@NotNull final Icon icon, NotNullFunction<T, Collection<? extends PsiElement>> convertor) {
75 return new NavigationGutterIconBuilder<T>(icon, convertor);
78 public NavigationGutterIconBuilder<T> setTarget(@Nullable T target) {
79 return setTargets(ContainerUtil.createMaybeSingletonList(target));
82 public NavigationGutterIconBuilder<T> setTargets(@NotNull T... targets) {
83 return setTargets(Arrays.asList(targets));
86 public NavigationGutterIconBuilder<T> setTargets(@NotNull final NotNullLazyValue<Collection<? extends T>> targets) {
87 myTargets = targets;
88 myLazy = true;
89 return this;
92 public NavigationGutterIconBuilder<T> setTargets(@NotNull final Collection<? extends T> targets) {
93 myTargets = new NotNullLazyValue<Collection<? extends T>>() {
94 @NotNull
95 public Collection<? extends T> compute() {
96 return targets;
99 return this;
102 public NavigationGutterIconBuilder<T> setTooltipText(@NotNull String tooltipText) {
103 myTooltipText = tooltipText;
104 return this;
107 public NavigationGutterIconBuilder<T> setAlignment(@NotNull final GutterIconRenderer.Alignment alignment) {
108 myAlignment = alignment;
109 return this;
112 public NavigationGutterIconBuilder<T> setPopupTitle(@NotNull String popupTitle) {
113 myPopupTitle = popupTitle;
114 return this;
117 public NavigationGutterIconBuilder<T> setEmptyPopupText(@NotNull String emptyText) {
118 myEmptyText = emptyText;
119 return this;
122 public NavigationGutterIconBuilder<T> setTooltipTitle(@NotNull final String tooltipTitle) {
123 myTooltipTitle = tooltipTitle;
124 return this;
127 public NavigationGutterIconBuilder<T> setNamer(@NotNull NullableFunction<T,String> namer) {
128 myNamer = namer;
129 return this;
132 public NavigationGutterIconBuilder<T> setCellRenderer(@NotNull final PsiElementListCellRenderer cellRenderer) {
133 myCellRenderer = cellRenderer;
134 return this;
137 @Nullable
138 public Annotation install(@NotNull DomElementAnnotationHolder holder, @Nullable DomElement element) {
139 if (!myLazy && myTargets.getValue().isEmpty() || element == null) return null;
140 return doInstall(holder.createAnnotation(element, HighlightSeverity.INFORMATION, null), element.getManager().getProject());
143 @Nullable
144 public Annotation install(@NotNull AnnotationHolder holder, @Nullable PsiElement element) {
145 if (!myLazy && myTargets.getValue().isEmpty() || element == null) return null;
146 return doInstall(holder.createInfoAnnotation(element, null), element.getProject());
149 private Annotation doInstall(final Annotation annotation, final Project project) {
150 final MyNavigationGutterIconRenderer renderer = createGutterIconRenderer(project);
151 annotation.setGutterIconRenderer(renderer);
152 annotation.setNeedsUpdateOnTyping(false);
153 return annotation;
156 public LineMarkerInfo createLineMarkerInfo(PsiElement element) {
157 final MyNavigationGutterIconRenderer renderer = createGutterIconRenderer(element.getProject());
158 return new LineMarkerInfo<PsiElement>(element, element.getTextRange(), renderer.getIcon(), Pass.UPDATE_OVERRIDEN_MARKERS, new NullableFunction<PsiElement, String>() {
159 public String fun(final PsiElement element) {
160 return renderer.getTooltipText();
162 }, renderer, renderer.getAlignment());
165 private MyNavigationGutterIconRenderer createGutterIconRenderer(final Project project) {
166 final SmartPointerManager manager = SmartPointerManager.getInstance(project);
168 NotNullLazyValue<List<SmartPsiElementPointer>> pointers = new NotNullLazyValue<List<SmartPsiElementPointer>>() {
169 @NotNull
170 public List<SmartPsiElementPointer> compute() {
171 Set<PsiElement> elements = new THashSet<PsiElement>();
172 final ArrayList<SmartPsiElementPointer> list = new ArrayList<SmartPsiElementPointer>();
173 for (final T target : myTargets.getValue()) {
174 for (final PsiElement psiElement : myConvertor.fun(target)) {
175 if (elements.add(psiElement)) {
176 list.add(manager.createSmartPsiElementPointer(psiElement));
180 return list;
184 if (!myLazy) {
185 pointers.getValue();
188 if (myTooltipText == null && !myLazy) {
189 final SortedSet<String> names = new TreeSet<String>();
190 for (T t : myTargets.getValue()) {
191 final String text = myNamer.fun(t);
192 if (text != null) {
193 names.add(MessageFormat.format(PATTERN, text));
196 @NonNls StringBuilder sb = new StringBuilder("<html><body>");
197 if (myTooltipTitle != null) {
198 sb.append(myTooltipTitle).append("<br>");
200 for (String name : names) {
201 sb.append(name).append("<br>");
203 sb.append("</body></html>");
204 myTooltipText = sb.toString();
207 if (myCellRenderer == null) {
208 myCellRenderer = new DefaultPsiElementCellRenderer();
211 final MyNavigationGutterIconRenderer renderer = new MyNavigationGutterIconRenderer(this, myAlignment, myIcon, myTooltipText, pointers);
212 return renderer;
215 private static class MyNavigationGutterIconRenderer extends NavigationGutterIconRenderer {
216 private final Alignment myAlignment;
217 private final Icon myIcon;
218 private final String myTooltipText;
220 public MyNavigationGutterIconRenderer(final NavigationGutterIconBuilder builder, final Alignment alignment, final Icon icon, final String tooltipText, final NotNullLazyValue<List<SmartPsiElementPointer>> pointers) {
221 super(builder.myPopupTitle, builder.myEmptyText, builder.myCellRenderer, pointers);
222 myAlignment = alignment;
223 myIcon = icon;
224 myTooltipText = tooltipText;
227 @NotNull
228 public Icon getIcon() {
229 return myIcon;
232 @Nullable
233 public String getTooltipText() {
234 return myTooltipText;
237 public Alignment getAlignment() {
238 return myAlignment;
241 public boolean equals(final Object o) {
242 if (this == o) return true;
243 if (o == null || getClass() != o.getClass()) return false;
244 if (!super.equals(o)) return false;
246 final MyNavigationGutterIconRenderer that = (MyNavigationGutterIconRenderer)o;
248 if (myAlignment != that.myAlignment) return false;
249 if (myIcon != null ? !myIcon.equals(that.myIcon) : that.myIcon != null) return false;
250 if (myTooltipText != null ? !myTooltipText.equals(that.myTooltipText) : that.myTooltipText != null) return false;
252 return true;
255 public int hashCode() {
256 int result = super.hashCode();
257 result = 31 * result + (myAlignment != null ? myAlignment.hashCode() : 0);
258 result = 31 * result + (myIcon != null ? myIcon.hashCode() : 0);
259 result = 31 * result + (myTooltipText != null ? myTooltipText.hashCode() : 0);
260 return result;