2 * Copyright (c) 2000-2007 JetBrains s.r.o. All Rights Reserved.
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
;
31 import java
.text
.MessageFormat
;
37 public class NavigationGutterIconBuilder
<T
> {
38 @NonNls private static final String PATTERN
= " {0}";
39 private static final NotNullFunction
<PsiElement
,Collection
<?
extends PsiElement
>> DEFAULT_PSI_CONVERTOR
= new NotNullFunction
<PsiElement
, Collection
<?
extends PsiElement
>>() {
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
>>() {
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
) {
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
) {
92 public NavigationGutterIconBuilder
<T
> setTargets(@NotNull final Collection
<?
extends T
> targets
) {
93 myTargets
= new NotNullLazyValue
<Collection
<?
extends T
>>() {
95 public Collection
<?
extends T
> compute() {
102 public NavigationGutterIconBuilder
<T
> setTooltipText(@NotNull String tooltipText
) {
103 myTooltipText
= tooltipText
;
107 public NavigationGutterIconBuilder
<T
> setAlignment(@NotNull final GutterIconRenderer
.Alignment alignment
) {
108 myAlignment
= alignment
;
112 public NavigationGutterIconBuilder
<T
> setPopupTitle(@NotNull String popupTitle
) {
113 myPopupTitle
= popupTitle
;
117 public NavigationGutterIconBuilder
<T
> setEmptyPopupText(@NotNull String emptyText
) {
118 myEmptyText
= emptyText
;
122 public NavigationGutterIconBuilder
<T
> setTooltipTitle(@NotNull final String tooltipTitle
) {
123 myTooltipTitle
= tooltipTitle
;
127 public NavigationGutterIconBuilder
<T
> setNamer(@NotNull NullableFunction
<T
,String
> namer
) {
132 public NavigationGutterIconBuilder
<T
> setCellRenderer(@NotNull final PsiElementListCellRenderer cellRenderer
) {
133 myCellRenderer
= cellRenderer
;
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());
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);
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
>>() {
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
));
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
);
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
);
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
;
224 myTooltipText
= tooltipText
;
228 public Icon
getIcon() {
233 public String
getTooltipText() {
234 return myTooltipText
;
237 public Alignment
getAlignment() {
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;
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);