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.FileEditorManager;
28 import com.intellij.openapi.project.Project;
29 import com.intellij.openapi.roots.ui.util.CompositeAppearance;
30 import com.intellij.openapi.util.Comparing;
31 import com.intellij.openapi.util.Iconable;
32 import com.intellij.openapi.util.TextRange;
33 import com.intellij.pom.Navigatable;
34 import com.intellij.psi.*;
35 import com.intellij.psi.impl.source.jsp.jspJava.JspHolderMethod;
36 import com.intellij.psi.jsp.JspFile;
37 import com.intellij.psi.presentation.java.ClassPresentationUtil;
38 import com.intellij.psi.util.PsiFormatUtil;
39 import com.intellij.psi.util.PsiTreeUtil;
40 import com.intellij.psi.util.PsiUtilBase;
41 import com.intellij.ui.LayeredIcon;
45 import java.util.ArrayList;
46 import java.util.List;
48 public final class CallHierarchyNodeDescriptor extends HierarchyNodeDescriptor implements Navigatable {
49 private int myUsageCount = 1;
50 private final List<PsiReference> myReferences = new ArrayList<PsiReference>();
51 private final boolean myNavigateToReference;
53 public CallHierarchyNodeDescriptor(
54 final Project project,
55 final HierarchyNodeDescriptor parentDescriptor,
56 final PsiElement element,
58 final boolean navigateToReference){
59 super(project, parentDescriptor, element, isBase);
60 myNavigateToReference = navigateToReference;
64 * @return PsiMethod or PsiClass or JspFile
66 public final PsiMember getEnclosingElement(){
67 return myElement == null ? null : getEnclosingElement(myElement);
70 static PsiMember getEnclosingElement(final PsiElement element){
71 return PsiTreeUtil.getNonStrictParentOfType(element, PsiMethod.class, PsiClass.class);
74 public final void incrementUsageCount(){
79 * Element for OpenFileDescriptor
81 public final PsiElement getTargetElement(){
85 public final boolean isValid(){
86 final PsiElement element = getEnclosingElement();
87 return element != null && element.isValid();
90 public final boolean update(){
91 final CompositeAppearance oldText = myHighlightedText;
92 final Icon oldOpenIcon = myOpenIcon;
94 int flags = Iconable.ICON_FLAG_VISIBILITY;
95 if (isMarkReadOnly()) {
96 flags |= Iconable.ICON_FLAG_READ_STATUS;
99 boolean changes = super.update();
101 final PsiElement enclosingElement = getEnclosingElement();
103 if (enclosingElement == null) {
104 final String invalidPrefix = IdeBundle.message("node.hierarchy.invalid");
105 if (!myHighlightedText.getText().startsWith(invalidPrefix)) {
106 myHighlightedText.getBeginning().addText(invalidPrefix, HierarchyNodeDescriptor.getInvalidPrefixAttributes());
111 myOpenIcon = enclosingElement.getIcon(flags);
112 if (changes && myIsBase) {
113 final LayeredIcon icon = new LayeredIcon(2);
114 icon.setIcon(myOpenIcon, 0);
115 icon.setIcon(BASE_POINTER_ICON, 1, -BASE_POINTER_ICON.getIconWidth() / 2, 0);
118 myClosedIcon = myOpenIcon;
120 myHighlightedText = new CompositeAppearance();
121 TextAttributes mainTextAttributes = null;
122 if (myColor != null) {
123 mainTextAttributes = new TextAttributes(myColor, null, null, null, Font.PLAIN);
125 if (enclosingElement instanceof PsiMethod) {
126 if (enclosingElement instanceof JspHolderMethod) {
127 PsiFile file = enclosingElement.getContainingFile();
128 myHighlightedText.getEnding().addText(file != null ? file.getName() : IdeBundle.message("node.call.hierarchy.unknown.jsp"), mainTextAttributes);
131 final PsiMethod method = (PsiMethod)enclosingElement;
132 final StringBuilder buffer = new StringBuilder(128);
133 final PsiClass containingClass = method.getContainingClass();
134 if (containingClass != null) {
135 buffer.append(ClassPresentationUtil.getNameForClass(containingClass, false));
138 final String methodText = PsiFormatUtil.formatMethod(
140 PsiSubstitutor.EMPTY, PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_PARAMETERS,
141 PsiFormatUtil.SHOW_TYPE
143 buffer.append(methodText);
145 myHighlightedText.getEnding().addText(buffer.toString(), mainTextAttributes);
148 else if (JspPsiUtil.isInJspFile(enclosingElement) && enclosingElement instanceof PsiFile) {
149 final JspFile file = JspPsiUtil.getJspFile(enclosingElement);
150 myHighlightedText.getEnding().addText(file.getName(), mainTextAttributes);
153 myHighlightedText.getEnding().addText(ClassPresentationUtil.getNameForClass((PsiClass)enclosingElement, false), mainTextAttributes);
155 if (myUsageCount > 1) {
156 myHighlightedText.getEnding().addText(IdeBundle.message("node.call.hierarchy.N.usages", myUsageCount), HierarchyNodeDescriptor.getUsageCountPrefixAttributes());
158 if (!(JspPsiUtil.isInJspFile(enclosingElement) && enclosingElement instanceof PsiFile)) {
159 final PsiClass containingClass = enclosingElement instanceof PsiMethod
160 ? ((PsiMethod)enclosingElement).getContainingClass()
161 : (PsiClass)enclosingElement;
162 if (containingClass != null) {
163 final String packageName = JavaHierarchyUtil.getPackageName(containingClass);
164 myHighlightedText.getEnding().addText(" (" + packageName + ")", HierarchyNodeDescriptor.getPackageNameAttributes());
167 myName = myHighlightedText.getText();
170 !Comparing.equal(myHighlightedText, oldText) ||
171 !Comparing.equal(myOpenIcon, oldOpenIcon)
178 public void addReference(final PsiReference reference) {
179 myReferences.add(reference);
182 public boolean hasReference(PsiReference reference) {
183 return myReferences.contains(reference);
186 public void navigate(boolean requestFocus) {
187 if (!myNavigateToReference) {
188 if (myElement instanceof Navigatable && ((Navigatable)myElement).canNavigate()) {
189 ((Navigatable)myElement).navigate(requestFocus);
194 final PsiReference firstReference = myReferences.get(0);
195 final PsiElement element = firstReference.getElement();
196 if (element == null) return;
197 final PsiElement callElement = element.getParent();
198 if (callElement instanceof Navigatable && ((Navigatable)callElement).canNavigate()) {
199 ((Navigatable)callElement).navigate(requestFocus);
201 final PsiFile psiFile = callElement.getContainingFile();
202 if (psiFile == null || psiFile.getVirtualFile() == null) return;
203 FileEditorManager.getInstance(myProject).openFile(psiFile.getVirtualFile(), requestFocus);
206 Editor editor = PsiUtilBase.findEditor(callElement);
208 if (editor != null) {
210 HighlightManager highlightManager = HighlightManager.getInstance(myProject);
211 EditorColorsManager colorManager = EditorColorsManager.getInstance();
212 TextAttributes attributes = colorManager.getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES);
213 ArrayList<RangeHighlighter> highlighters = new ArrayList<RangeHighlighter>();
214 for (PsiReference psiReference : myReferences) {
215 final PsiElement eachElement = psiReference.getElement();
216 if (eachElement != null) {
217 final PsiElement eachMethodCall = eachElement.getParent();
218 if (eachMethodCall != null) {
219 final TextRange textRange = eachMethodCall.getTextRange();
220 highlightManager.addRangeHighlight(editor, textRange.getStartOffset(), textRange.getEndOffset(), attributes, false, highlighters);
227 public boolean canNavigate() {
228 if (!myNavigateToReference) {
229 return myElement instanceof Navigatable && ((Navigatable) myElement).canNavigate();
231 if (myReferences.isEmpty()) return false;
232 final PsiReference firstReference = myReferences.get(0);
233 final PsiElement callElement = firstReference.getElement().getParent();
234 if (callElement == null || !callElement.isValid()) return false;
235 if (!(callElement instanceof Navigatable) || !((Navigatable)callElement).canNavigate()) {
236 final PsiFile psiFile = callElement.getContainingFile();
237 if (psiFile == null) return false;
242 public boolean canNavigateToSource() {
243 return canNavigate();