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.
16 package com
.intellij
.ide
.hierarchy
.call
;
18 import com
.intellij
.codeInsight
.highlighting
.HighlightManager
;
19 import com
.intellij
.ide
.IdeBundle
;
20 import com
.intellij
.ide
.hierarchy
.HierarchyNodeDescriptor
;
21 import com
.intellij
.ide
.hierarchy
.JavaHierarchyUtil
;
22 import com
.intellij
.openapi
.editor
.Editor
;
23 import com
.intellij
.openapi
.editor
.colors
.EditorColors
;
24 import com
.intellij
.openapi
.editor
.colors
.EditorColorsManager
;
25 import com
.intellij
.openapi
.editor
.markup
.RangeHighlighter
;
26 import com
.intellij
.openapi
.editor
.markup
.TextAttributes
;
27 import com
.intellij
.openapi
.fileEditor
.FileEditor
;
28 import com
.intellij
.openapi
.fileEditor
.FileEditorManager
;
29 import com
.intellij
.openapi
.fileEditor
.TextEditor
;
30 import com
.intellij
.openapi
.project
.Project
;
31 import com
.intellij
.openapi
.roots
.ui
.util
.CompositeAppearance
;
32 import com
.intellij
.openapi
.util
.Comparing
;
33 import com
.intellij
.openapi
.util
.Iconable
;
34 import com
.intellij
.openapi
.util
.TextRange
;
35 import com
.intellij
.pom
.Navigatable
;
36 import com
.intellij
.psi
.*;
37 import com
.intellij
.psi
.impl
.source
.jsp
.jspJava
.JspHolderMethod
;
38 import com
.intellij
.psi
.jsp
.JspFile
;
39 import com
.intellij
.psi
.presentation
.java
.ClassPresentationUtil
;
40 import com
.intellij
.psi
.util
.PsiFormatUtil
;
41 import com
.intellij
.psi
.util
.PsiTreeUtil
;
42 import com
.intellij
.ui
.LayeredIcon
;
43 import org
.jetbrains
.annotations
.Nullable
;
47 import java
.util
.ArrayList
;
48 import java
.util
.List
;
50 public final class CallHierarchyNodeDescriptor
extends HierarchyNodeDescriptor
implements Navigatable
{
51 private int myUsageCount
= 1;
52 private final List
<PsiReference
> myReferences
= new ArrayList
<PsiReference
>();
53 private final boolean myNavigateToReference
;
55 public CallHierarchyNodeDescriptor(
56 final Project project
,
57 final HierarchyNodeDescriptor parentDescriptor
,
58 final PsiElement element
,
60 final boolean navigateToReference
){
61 super(project
, parentDescriptor
, element
, isBase
);
62 myNavigateToReference
= navigateToReference
;
66 * @return PsiMethod or PsiClass or JspFile
68 public final PsiMember
getEnclosingElement(){
69 return myElement
== null ?
null : getEnclosingElement(myElement
);
72 static PsiMember
getEnclosingElement(final PsiElement element
){
73 return PsiTreeUtil
.getNonStrictParentOfType(element
, PsiMethod
.class, PsiClass
.class);
76 public final void incrementUsageCount(){
81 * Element for OpenFileDescriptor
83 public final PsiElement
getTargetElement(){
87 public final boolean isValid(){
88 final PsiElement element
= getEnclosingElement();
89 return element
!= null && element
.isValid();
92 public final boolean update(){
93 final CompositeAppearance oldText
= myHighlightedText
;
94 final Icon oldOpenIcon
= myOpenIcon
;
96 int flags
= Iconable
.ICON_FLAG_VISIBILITY
;
97 if (isMarkReadOnly()) {
98 flags
|= Iconable
.ICON_FLAG_READ_STATUS
;
101 boolean changes
= super.update();
103 final PsiElement enclosingElement
= getEnclosingElement();
105 if (enclosingElement
== null) {
106 final String invalidPrefix
= IdeBundle
.message("node.hierarchy.invalid");
107 if (!myHighlightedText
.getText().startsWith(invalidPrefix
)) {
108 myHighlightedText
.getBeginning().addText(invalidPrefix
, HierarchyNodeDescriptor
.getInvalidPrefixAttributes());
113 myOpenIcon
= enclosingElement
.getIcon(flags
);
114 if (changes
&& myIsBase
) {
115 final LayeredIcon icon
= new LayeredIcon(2);
116 icon
.setIcon(myOpenIcon
, 0);
117 icon
.setIcon(BASE_POINTER_ICON
, 1, -BASE_POINTER_ICON
.getIconWidth() / 2, 0);
120 myClosedIcon
= myOpenIcon
;
122 myHighlightedText
= new CompositeAppearance();
123 TextAttributes mainTextAttributes
= null;
124 if (myColor
!= null) {
125 mainTextAttributes
= new TextAttributes(myColor
, null, null, null, Font
.PLAIN
);
127 if (enclosingElement
instanceof PsiMethod
) {
128 if (enclosingElement
instanceof JspHolderMethod
) {
129 PsiFile file
= enclosingElement
.getContainingFile();
130 myHighlightedText
.getEnding().addText(file
!= null ? file
.getName() : IdeBundle
.message("node.call.hierarchy.unknown.jsp"), mainTextAttributes
);
133 final PsiMethod method
= (PsiMethod
)enclosingElement
;
134 final StringBuilder buffer
= new StringBuilder(128);
135 final PsiClass containingClass
= method
.getContainingClass();
136 if (containingClass
!= null) {
137 buffer
.append(ClassPresentationUtil
.getNameForClass(containingClass
, false));
140 final String methodText
= PsiFormatUtil
.formatMethod(
142 PsiSubstitutor
.EMPTY
, PsiFormatUtil
.SHOW_NAME
| PsiFormatUtil
.SHOW_PARAMETERS
,
143 PsiFormatUtil
.SHOW_TYPE
145 buffer
.append(methodText
);
147 myHighlightedText
.getEnding().addText(buffer
.toString(), mainTextAttributes
);
150 else if (JspPsiUtil
.isInJspFile(enclosingElement
) && enclosingElement
instanceof PsiFile
) {
151 final JspFile file
= JspPsiUtil
.getJspFile(enclosingElement
);
152 myHighlightedText
.getEnding().addText(file
.getName(), mainTextAttributes
);
155 myHighlightedText
.getEnding().addText(ClassPresentationUtil
.getNameForClass((PsiClass
)enclosingElement
, false), mainTextAttributes
);
157 if (myUsageCount
> 1) {
158 myHighlightedText
.getEnding().addText(IdeBundle
.message("node.call.hierarchy.N.usages", myUsageCount
), HierarchyNodeDescriptor
.getUsageCountPrefixAttributes());
160 if (!(JspPsiUtil
.isInJspFile(enclosingElement
) && enclosingElement
instanceof PsiFile
)) {
161 final String packageName
= JavaHierarchyUtil
.getPackageName(enclosingElement
instanceof PsiMethod ?
((PsiMethod
)enclosingElement
).getContainingClass() : (PsiClass
)enclosingElement
);
162 myHighlightedText
.getEnding().addText(" (" + packageName
+ ")", HierarchyNodeDescriptor
.getPackageNameAttributes());
164 myName
= myHighlightedText
.getText();
167 !Comparing
.equal(myHighlightedText
, oldText
) ||
168 !Comparing
.equal(myOpenIcon
, oldOpenIcon
)
175 public void addReference(final PsiReference reference
) {
176 myReferences
.add(reference
);
179 public void navigate(boolean requestFocus
) {
180 if (!myNavigateToReference
) {
181 if (myElement
instanceof Navigatable
&& ((Navigatable
)myElement
).canNavigate()) {
182 ((Navigatable
)myElement
).navigate(requestFocus
);
187 final PsiReference firstReference
= myReferences
.get(0);
188 final PsiElement element
= firstReference
.getElement();
189 if (element
== null) return;
190 final PsiElement callElement
= element
.getParent();
191 if (callElement
instanceof Navigatable
&& ((Navigatable
)callElement
).canNavigate()) {
192 ((Navigatable
)callElement
).navigate(requestFocus
);
194 final PsiFile psiFile
= callElement
.getContainingFile();
195 if (psiFile
== null || psiFile
.getVirtualFile() == null) return;
196 FileEditorManager
.getInstance(myProject
).openFile(psiFile
.getVirtualFile(), requestFocus
);
199 Editor editor
= getEditor(callElement
);
201 if (editor
!= null) {
203 HighlightManager highlightManager
= HighlightManager
.getInstance(myProject
);
204 EditorColorsManager colorManager
= EditorColorsManager
.getInstance();
205 TextAttributes attributes
= colorManager
.getGlobalScheme().getAttributes(EditorColors
.SEARCH_RESULT_ATTRIBUTES
);
206 ArrayList
<RangeHighlighter
> highlighters
= new ArrayList
<RangeHighlighter
>();
207 for (PsiReference psiReference
: myReferences
) {
208 final PsiElement eachElement
= psiReference
.getElement();
209 if (eachElement
!= null) {
210 final PsiElement eachMethodCall
= eachElement
.getParent();
211 if (eachMethodCall
!= null) {
212 final TextRange textRange
= eachMethodCall
.getTextRange();
213 highlightManager
.addRangeHighlight(editor
, textRange
.getStartOffset(), textRange
.getEndOffset(), attributes
, false, highlighters
);
221 private Editor
getEditor(final PsiElement callElement
) {
222 final FileEditor editor
= FileEditorManager
.getInstance(myProject
).getSelectedEditor(callElement
.getContainingFile().getVirtualFile());
223 if (editor
instanceof TextEditor
) {
224 return ((TextEditor
)editor
).getEditor();
230 public boolean canNavigate() {
231 if (!myNavigateToReference
) {
232 return myElement
instanceof Navigatable
&& ((Navigatable
) myElement
).canNavigate();
234 if (myReferences
.isEmpty()) return false;
235 final PsiReference firstReference
= myReferences
.get(0);
236 final PsiElement callElement
= firstReference
.getElement().getParent();
237 if (callElement
== null || !callElement
.isValid()) return false;
238 if (!(callElement
instanceof Navigatable
) || !((Navigatable
)callElement
).canNavigate()) {
239 final PsiFile psiFile
= callElement
.getContainingFile();
240 if (psiFile
== null) return false;
245 public boolean canNavigateToSource() {
246 return canNavigate();