Use smart element pointer instead of weak reference to fix the IDEA-160333 Override...
[idea/community.git] / platform / lang-api / src / com / intellij / codeInsight / daemon / LineMarkerInfo.java
1 /*
2  * Copyright 2000-2015 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.codeInsight.daemon;
18
19 import com.intellij.openapi.actionSystem.AnAction;
20 import com.intellij.openapi.editor.markup.GutterIconRenderer;
21 import com.intellij.openapi.editor.markup.RangeHighlighter;
22 import com.intellij.openapi.editor.markup.SeparatorPlacement;
23 import com.intellij.openapi.project.IndexNotReadyException;
24 import com.intellij.openapi.util.Comparing;
25 import com.intellij.openapi.util.TextRange;
26 import com.intellij.psi.PsiElement;
27 import com.intellij.psi.SmartPointerManager;
28 import com.intellij.psi.SmartPsiElementPointer;
29 import com.intellij.util.Function;
30 import org.jetbrains.annotations.NotNull;
31 import org.jetbrains.annotations.Nullable;
32
33 import javax.swing.*;
34 import java.awt.*;
35
36 public class LineMarkerInfo<T extends PsiElement> {
37   protected final Icon myIcon;
38   private final SmartPsiElementPointer<T> elementRef;
39   public final int startOffset;
40   public final int endOffset;
41   public Color separatorColor;
42   public SeparatorPlacement separatorPlacement;
43   public RangeHighlighter highlighter;
44
45   public final int updatePass;
46   @Nullable private final Function<? super T, String> myTooltipProvider;
47   private AnAction myNavigateAction = new NavigateAction<>(this);
48   @NotNull private final GutterIconRenderer.Alignment myIconAlignment;
49   @Nullable private final GutterIconNavigationHandler<T> myNavigationHandler;
50
51   /**
52    * Creates a line marker info for the element.
53    * @param element         the element for which the line marker is created.
54    * @param range     the range (relative to beginning of file) with which the marker is associated
55    * @param icon            the icon to show in the gutter for the line marker
56    * @param updatePass      the ID of the daemon pass during which the marker should be recalculated
57    * @param tooltipProvider the callback to calculate the tooltip for the gutter icon
58    * @param navHandler      the handler executed when the gutter icon is clicked
59    */
60   public LineMarkerInfo(@NotNull T element,
61                         @NotNull TextRange range,
62                         Icon icon,
63                         int updatePass,
64                         @Nullable Function<? super T, String> tooltipProvider,
65                         @Nullable GutterIconNavigationHandler<T> navHandler,
66                         @NotNull GutterIconRenderer.Alignment alignment) {
67     myIcon = icon;
68     myTooltipProvider = tooltipProvider;
69     myIconAlignment = alignment;
70     elementRef = SmartPointerManager.getInstance(element.getProject()).createSmartPsiElementPointer(element);
71     myNavigationHandler = navHandler;
72     startOffset = range.getStartOffset();
73     endOffset = range.getEndOffset();
74     this.updatePass = 11; //Pass.LINE_MARKERS;
75   }
76
77   /**
78    * @deprecated use {@link LineMarkerInfo#LineMarkerInfo(PsiElement, TextRange, Icon, int, Function, GutterIconNavigationHandler, GutterIconRenderer.Alignment)} instead
79    */
80   public LineMarkerInfo(@NotNull T element,
81                         int startOffset,
82                         Icon icon,
83                         int updatePass,
84                         @Nullable Function<? super T, String> tooltipProvider,
85                         @Nullable GutterIconNavigationHandler<T> navHandler,
86                         @NotNull GutterIconRenderer.Alignment alignment) {
87     this(element, new TextRange(startOffset, startOffset), icon, updatePass, tooltipProvider, navHandler, alignment);
88   }
89
90   /**
91    * @deprecated use {@link LineMarkerInfo#LineMarkerInfo(PsiElement, TextRange, Icon, int, Function, GutterIconNavigationHandler, GutterIconRenderer.Alignment)} instead
92    */
93   public LineMarkerInfo(@NotNull T element,
94                         int startOffset,
95                         Icon icon,
96                         int updatePass,
97                         @Nullable Function<? super T, String> tooltipProvider,
98                         @Nullable GutterIconNavigationHandler<T> navHandler) {
99     this(element, startOffset, icon, updatePass, tooltipProvider, navHandler, GutterIconRenderer.Alignment.RIGHT);
100   }
101
102   @Nullable
103   public GutterIconRenderer createGutterRenderer() {
104     if (myIcon == null) return null;
105     return new LineMarkerGutterIconRenderer<>(this);
106   }
107
108   @Nullable
109   public String getLineMarkerTooltip() {
110     if (myTooltipProvider == null) return null;
111     T element = getElement();
112     return element == null || !element.isValid() ? null : myTooltipProvider.fun(element);
113   }
114
115   @Nullable
116   public T getElement() {
117     return elementRef.getElement();
118   }
119
120   void setNavigateAction(@NotNull  AnAction navigateAction) {
121     myNavigateAction = navigateAction;
122   }
123
124   @Nullable
125   public GutterIconNavigationHandler<T> getNavigationHandler() {
126     return myNavigationHandler;
127   }
128
129   public static class LineMarkerGutterIconRenderer<T extends PsiElement> extends GutterIconRenderer {
130     private final LineMarkerInfo<T> myInfo;
131
132     public LineMarkerGutterIconRenderer(@NotNull LineMarkerInfo<T> info) {
133       myInfo = info;
134     }
135
136     public LineMarkerInfo<T> getLineMarkerInfo() {
137       return myInfo;
138     }
139
140     @Override
141     @NotNull
142     public Icon getIcon() {
143       return myInfo.myIcon;
144     }
145
146     @Override
147     public AnAction getClickAction() {
148       return myInfo.myNavigateAction;
149     }
150
151     @Override
152     public boolean isNavigateAction() {
153       return myInfo.myNavigationHandler != null;
154     }
155
156     @Override
157     public String getTooltipText() {
158       try {
159         return myInfo.getLineMarkerTooltip();
160       }
161       catch (IndexNotReadyException ignored) {
162         return null;
163       }
164     }
165
166     @NotNull
167     @Override
168     public Alignment getAlignment() {
169       return myInfo.myIconAlignment;
170     }
171
172     protected boolean looksTheSameAs(@NotNull LineMarkerGutterIconRenderer renderer) {
173       return
174         myInfo.getElement() != null &&
175         renderer.myInfo.getElement() != null &&
176         myInfo.getElement() == renderer.myInfo.getElement() &&
177         Comparing.equal(myInfo.myTooltipProvider, renderer.myInfo.myTooltipProvider) &&
178         Comparing.equal(myInfo.myIcon, renderer.myInfo.myIcon);
179     }
180
181     @Override
182     public boolean equals(Object obj) {
183       return obj instanceof LineMarkerGutterIconRenderer && looksTheSameAs((LineMarkerGutterIconRenderer)obj);
184     }
185
186     @Override
187     public int hashCode() {
188       T element = myInfo.getElement();
189       return element == null ? 0 : element.hashCode();
190     }
191   }
192
193   @Override
194   public String toString() {
195     return "("+startOffset+","+endOffset+") -> "+elementRef;
196   }
197 }