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.
20 package com
.intellij
.codeInsight
.daemon
.impl
;
22 import com
.intellij
.codeInsight
.daemon
.GutterIconNavigationHandler
;
23 import com
.intellij
.codeInsight
.daemon
.DaemonBundle
;
24 import com
.intellij
.codeInsight
.CodeInsightBundle
;
25 import com
.intellij
.psi
.*;
26 import com
.intellij
.psi
.util
.PsiUtil
;
27 import com
.intellij
.psi
.search
.PsiElementProcessor
;
28 import com
.intellij
.psi
.search
.PsiElementProcessorAdapter
;
29 import com
.intellij
.psi
.search
.searches
.OverridingMethodsSearch
;
30 import com
.intellij
.psi
.search
.searches
.ClassInheritorsSearch
;
31 import com
.intellij
.util
.Function
;
32 import com
.intellij
.util
.NullableFunction
;
33 import com
.intellij
.util
.CommonProcessors
;
34 import com
.intellij
.ide
.util
.MethodCellRenderer
;
35 import com
.intellij
.ide
.util
.PsiClassListCellRenderer
;
36 import com
.intellij
.openapi
.progress
.ProgressManager
;
37 import org
.jetbrains
.annotations
.NonNls
;
40 import java
.util
.Comparator
;
41 import java
.util
.Arrays
;
42 import java
.awt
.event
.MouseEvent
;
44 public enum MarkerType
{
45 OVERRIDING_METHOD(new NullableFunction
<PsiElement
, String
>() {
46 public String
fun(PsiElement element
) {
47 PsiElement parent
= element
.getParent();
48 if (!(parent
instanceof PsiMethod
)) return null;
49 PsiMethod method
= (PsiMethod
)parent
;
51 PsiMethod
[] superMethods
= method
.findSuperMethods(false);
52 if (superMethods
.length
== 0) return null;
54 PsiMethod superMethod
= superMethods
[0];
55 boolean isAbstract
= method
.hasModifierProperty(PsiModifier
.ABSTRACT
);
56 boolean isSuperAbstract
= superMethod
.hasModifierProperty(PsiModifier
.ABSTRACT
);
58 final boolean sameSignature
= superMethod
.getSignature(PsiSubstitutor
.EMPTY
).equals(method
.getSignature(PsiSubstitutor
.EMPTY
));
59 @NonNls final String key
;
60 if (isSuperAbstract
&& !isAbstract
){
61 key
= sameSignature ?
"method.implements" : "method.implements.in";
64 key
= sameSignature ?
"method.overrides" : "method.overrides.in";
66 return GutterIconTooltipHelper
.composeText(superMethods
, "", DaemonBundle
.message(key
));
68 }, new LineMarkerNavigator(){
69 public void browse(MouseEvent e
, PsiElement element
) {
70 PsiElement parent
= element
.getParent();
71 if (!(parent
instanceof PsiMethod
)) return;
72 PsiMethod method
= (PsiMethod
)parent
;
73 PsiMethod
[] superMethods
= method
.findSuperMethods(false);
74 if (superMethods
.length
== 0) return;
75 boolean showMethodNames
= !PsiUtil
.allMethodsHaveSameSignature(superMethods
);
76 PsiElementListNavigator
.openTargets(e
, superMethods
,
77 DaemonBundle
.message("navigation.title.super.method", method
.getName()),
78 new MethodCellRenderer(showMethodNames
));
82 OVERRIDEN_METHOD(new NullableFunction
<PsiElement
, String
>() {
83 public String
fun(PsiElement element
) {
84 PsiElement parent
= element
.getParent();
85 if (!(parent
instanceof PsiMethod
)) return null;
86 PsiMethod method
= (PsiMethod
)parent
;
88 PsiElementProcessor
.CollectElementsWithLimit
<PsiMethod
> processor
= new PsiElementProcessor
.CollectElementsWithLimit
<PsiMethod
>(5);
89 OverridingMethodsSearch
.search(method
, method
.getUseScope(), true).forEach(new PsiElementProcessorAdapter
<PsiMethod
>(processor
));
91 boolean isAbstract
= method
.hasModifierProperty(PsiModifier
.ABSTRACT
);
93 if (processor
.isOverflow()){
94 return isAbstract ? DaemonBundle
.message("method.is.implemented.too.many") : DaemonBundle
.message("method.is.overridden.too.many");
97 PsiMethod
[] overridings
= processor
.toArray(new PsiMethod
[processor
.getCollection().size()]);
98 if (overridings
.length
== 0) return null;
100 Comparator
<PsiMethod
> comparator
= new MethodCellRenderer(false).getComparator();
101 Arrays
.sort(overridings
, comparator
);
103 String start
= isAbstract ? DaemonBundle
.message("method.is.implemented.header") : DaemonBundle
.message("method.is.overriden.header");
104 @NonNls String pattern
= " {1}";
105 return GutterIconTooltipHelper
.composeText(overridings
, start
, pattern
);
107 }, new LineMarkerNavigator(){
108 public void browse(MouseEvent e
, PsiElement element
) {
109 PsiElement parent
= element
.getParent();
110 if (!(parent
instanceof PsiMethod
)) return;
112 final PsiMethod method
= (PsiMethod
)parent
;
113 final CommonProcessors
.CollectProcessor
<PsiMethod
> collectProcessor
= new CommonProcessors
.CollectProcessor
<PsiMethod
>();
114 if (!ProgressManager
.getInstance().runProcessWithProgressSynchronously(new Runnable() {
116 OverridingMethodsSearch
.search(method
, method
.getUseScope(), true).forEach(collectProcessor
);
118 }, "Searching for overridding methods", true, method
.getProject(), (JComponent
)e
.getComponent())) {
122 PsiMethod
[] overridings
= collectProcessor
.toArray(PsiMethod
.EMPTY_ARRAY
);
123 if (overridings
.length
== 0) return;
124 String title
= method
.hasModifierProperty(PsiModifier
.ABSTRACT
) ?
125 DaemonBundle
.message("navigation.title.implementation.method", method
.getName(), overridings
.length
) :
126 DaemonBundle
.message("navigation.title.overrider.method", method
.getName(), overridings
.length
);
127 boolean showMethodNames
= !PsiUtil
.allMethodsHaveSameSignature(overridings
);
128 MethodCellRenderer renderer
= new MethodCellRenderer(showMethodNames
);
129 Arrays
.sort(overridings
, renderer
.getComparator());
130 PsiElementListNavigator
.openTargets(e
, overridings
, title
, renderer
);
134 SUBCLASSED_CLASS(new NullableFunction
<PsiElement
, String
>() {
135 public String
fun(PsiElement element
) {
136 PsiElement parent
= element
.getParent();
137 if (!(parent
instanceof PsiClass
)) return null;
138 PsiClass aClass
= (PsiClass
)parent
;
139 PsiElementProcessor
.CollectElementsWithLimit
<PsiClass
> processor
= new PsiElementProcessor
.CollectElementsWithLimit
<PsiClass
>(5);
140 ClassInheritorsSearch
.search(aClass
, aClass
.getUseScope(), true).forEach(new PsiElementProcessorAdapter
<PsiClass
>(processor
));
142 if (processor
.isOverflow()) {
143 return aClass
.isInterface()
144 ? DaemonBundle
.message("interface.is.implemented.too.many")
145 : DaemonBundle
.message("class.is.subclassed.too.many");
148 PsiClass
[] subclasses
= processor
.toArray(new PsiClass
[processor
.getCollection().size()]);
149 if (subclasses
.length
== 0) return null;
151 Comparator
<PsiClass
> comparator
= new PsiClassListCellRenderer().getComparator();
152 Arrays
.sort(subclasses
, comparator
);
154 String start
= aClass
.isInterface()
155 ? DaemonBundle
.message("interface.is.implemented.by.header")
156 : DaemonBundle
.message("class.is.subclassed.by.header");
157 @NonNls String pattern
= " {0}";
158 return GutterIconTooltipHelper
.composeText(subclasses
, start
, pattern
);
160 }, new LineMarkerNavigator(){
161 public void browse(MouseEvent e
, PsiElement element
) {
162 PsiElement parent
= element
.getParent();
163 if (!(parent
instanceof PsiClass
)) return;
165 final PsiClass aClass
= (PsiClass
)parent
;
166 final CommonProcessors
.CollectProcessor
<PsiClass
> collectProcessor
= new CommonProcessors
.CollectProcessor
<PsiClass
>();
167 if (!ProgressManager
.getInstance().runProcessWithProgressSynchronously(new Runnable() {
169 ClassInheritorsSearch
.search(aClass
, aClass
.getUseScope(), true).forEach(collectProcessor
);
171 }, "Searching for overridden methods", true, aClass
.getProject(), (JComponent
)e
.getComponent())) {
175 PsiClass
[] inheritors
= collectProcessor
.toArray(PsiClass
.EMPTY_ARRAY
);
176 if (inheritors
.length
== 0) return;
177 String title
= aClass
.isInterface()
178 ? CodeInsightBundle
.message("goto.implementation.chooser.title", aClass
.getName(), inheritors
.length
)
179 : DaemonBundle
.message("navigation.title.subclass", aClass
.getName(), inheritors
.length
);
180 PsiClassListCellRenderer renderer
= new PsiClassListCellRenderer();
181 Arrays
.sort(inheritors
, renderer
.getComparator());
182 PsiElementListNavigator
.openTargets(e
, inheritors
, title
, renderer
);
186 private final GutterIconNavigationHandler handler
;
187 private final Function
<?
super PsiElement
, String
> myTooltip
;
189 MarkerType(Function
<?
super PsiElement
, String
> tooltip
, final LineMarkerNavigator navigator
) {
191 handler
= new GutterIconNavigationHandler() {
192 public void navigate(MouseEvent e
, PsiElement elt
) {
193 navigator
.browse(e
, elt
);
198 public <T
extends PsiElement
> GutterIconNavigationHandler
<T
> getNavigationHandler() {
202 public <T
extends PsiElement
> Function
<T
, String
> getTooltip() {
203 return (Function
<T
, String
>)myTooltip
;