| /* |
| * Copyright 2000-2013 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.intellij.ide.hierarchy.call; |
| |
| import com.intellij.codeInsight.highlighting.HighlightManager; |
| import com.intellij.icons.AllIcons; |
| import com.intellij.ide.IdeBundle; |
| import com.intellij.ide.hierarchy.HierarchyNodeDescriptor; |
| import com.intellij.ide.hierarchy.JavaHierarchyUtil; |
| import com.intellij.openapi.editor.Editor; |
| import com.intellij.openapi.editor.colors.EditorColors; |
| import com.intellij.openapi.editor.colors.EditorColorsManager; |
| import com.intellij.openapi.editor.markup.RangeHighlighter; |
| import com.intellij.openapi.editor.markup.TextAttributes; |
| import com.intellij.openapi.fileEditor.FileEditorManager; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.roots.ui.util.CompositeAppearance; |
| import com.intellij.openapi.util.Comparing; |
| import com.intellij.openapi.util.Iconable; |
| import com.intellij.openapi.util.TextRange; |
| import com.intellij.pom.Navigatable; |
| import com.intellij.psi.*; |
| import com.intellij.psi.presentation.java.ClassPresentationUtil; |
| import com.intellij.psi.util.*; |
| import com.intellij.ui.LayeredIcon; |
| import org.jetbrains.annotations.NotNull; |
| |
| import javax.swing.*; |
| import java.awt.*; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| public final class CallHierarchyNodeDescriptor extends HierarchyNodeDescriptor implements Navigatable { |
| private int myUsageCount = 1; |
| private final List<PsiReference> myReferences = new ArrayList<PsiReference>(); |
| private final boolean myNavigateToReference; |
| |
| public CallHierarchyNodeDescriptor(@NotNull Project project, |
| final HierarchyNodeDescriptor parentDescriptor, |
| @NotNull PsiElement element, |
| final boolean isBase, |
| final boolean navigateToReference) { |
| super(project, parentDescriptor, element, isBase); |
| myNavigateToReference = navigateToReference; |
| } |
| |
| /** |
| * @return PsiMethod or PsiClass or JspFile |
| */ |
| public final PsiMember getEnclosingElement(){ |
| return myElement == null ? null : getEnclosingElement(myElement); |
| } |
| |
| public static PsiMember getEnclosingElement(final PsiElement element){ |
| return PsiTreeUtil.getNonStrictParentOfType(element, PsiMethod.class, PsiClass.class); |
| } |
| |
| public final void incrementUsageCount(){ |
| myUsageCount++; |
| } |
| |
| /** |
| * Element for OpenFileDescriptor |
| */ |
| public final PsiElement getTargetElement(){ |
| return myElement; |
| } |
| |
| public final boolean isValid(){ |
| final PsiElement element = getEnclosingElement(); |
| return element != null && element.isValid(); |
| } |
| |
| public final boolean update(){ |
| final CompositeAppearance oldText = myHighlightedText; |
| final Icon oldIcon = getIcon(); |
| |
| int flags = Iconable.ICON_FLAG_VISIBILITY; |
| if (isMarkReadOnly()) { |
| flags |= Iconable.ICON_FLAG_READ_STATUS; |
| } |
| |
| boolean changes = super.update(); |
| |
| final PsiElement enclosingElement = getEnclosingElement(); |
| |
| if (enclosingElement == null) { |
| final String invalidPrefix = IdeBundle.message("node.hierarchy.invalid"); |
| if (!myHighlightedText.getText().startsWith(invalidPrefix)) { |
| myHighlightedText.getBeginning().addText(invalidPrefix, HierarchyNodeDescriptor.getInvalidPrefixAttributes()); |
| } |
| return true; |
| } |
| |
| Icon newIcon = enclosingElement.getIcon(flags); |
| if (changes && myIsBase) { |
| final LayeredIcon icon = new LayeredIcon(2); |
| icon.setIcon(newIcon, 0); |
| icon.setIcon(AllIcons.Hierarchy.Base, 1, -AllIcons.Hierarchy.Base.getIconWidth() / 2, 0); |
| newIcon = icon; |
| } |
| setIcon(newIcon); |
| |
| myHighlightedText = new CompositeAppearance(); |
| TextAttributes mainTextAttributes = null; |
| if (myColor != null) { |
| mainTextAttributes = new TextAttributes(myColor, null, null, null, Font.PLAIN); |
| } |
| if (enclosingElement instanceof PsiMethod) { |
| if (enclosingElement instanceof SyntheticElement) { |
| PsiFile file = enclosingElement.getContainingFile(); |
| myHighlightedText.getEnding().addText(file != null ? file.getName() : IdeBundle.message("node.call.hierarchy.unknown.jsp"), mainTextAttributes); |
| } |
| else { |
| final PsiMethod method = (PsiMethod)enclosingElement; |
| final StringBuilder buffer = new StringBuilder(128); |
| final PsiClass containingClass = method.getContainingClass(); |
| if (containingClass != null) { |
| buffer.append(ClassPresentationUtil.getNameForClass(containingClass, false)); |
| buffer.append('.'); |
| } |
| final String methodText = PsiFormatUtil.formatMethod( |
| method, |
| PsiSubstitutor.EMPTY, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS, |
| PsiFormatUtilBase.SHOW_TYPE |
| ); |
| buffer.append(methodText); |
| |
| myHighlightedText.getEnding().addText(buffer.toString(), mainTextAttributes); |
| } |
| } |
| else if (FileTypeUtils.isInServerPageFile(enclosingElement) && enclosingElement instanceof PsiFile) { |
| final PsiFile file = PsiUtilCore.getTemplateLanguageFile(enclosingElement); |
| myHighlightedText.getEnding().addText(file.getName(), mainTextAttributes); |
| } |
| else { |
| myHighlightedText.getEnding().addText(ClassPresentationUtil.getNameForClass((PsiClass)enclosingElement, false), mainTextAttributes); |
| } |
| if (myUsageCount > 1) { |
| myHighlightedText.getEnding().addText(IdeBundle.message("node.call.hierarchy.N.usages", myUsageCount), HierarchyNodeDescriptor.getUsageCountPrefixAttributes()); |
| } |
| if (!(FileTypeUtils.isInServerPageFile(enclosingElement) && enclosingElement instanceof PsiFile)) { |
| final PsiClass containingClass = enclosingElement instanceof PsiMethod |
| ? ((PsiMethod)enclosingElement).getContainingClass() |
| : (PsiClass)enclosingElement; |
| if (containingClass != null) { |
| final String packageName = JavaHierarchyUtil.getPackageName(containingClass); |
| myHighlightedText.getEnding().addText(" (" + packageName + ")", HierarchyNodeDescriptor.getPackageNameAttributes()); |
| } |
| } |
| myName = myHighlightedText.getText(); |
| |
| if ( |
| !Comparing.equal(myHighlightedText, oldText) || |
| !Comparing.equal(getIcon(), oldIcon) |
| ){ |
| changes = true; |
| } |
| return changes; |
| } |
| |
| public void addReference(final PsiReference reference) { |
| myReferences.add(reference); |
| } |
| |
| public boolean hasReference(PsiReference reference) { |
| return myReferences.contains(reference); |
| } |
| |
| public void navigate(boolean requestFocus) { |
| if (!myNavigateToReference) { |
| if (myElement instanceof Navigatable && ((Navigatable)myElement).canNavigate()) { |
| ((Navigatable)myElement).navigate(requestFocus); |
| } |
| return; |
| } |
| |
| final PsiReference firstReference = myReferences.get(0); |
| final PsiElement element = firstReference.getElement(); |
| if (element == null) return; |
| final PsiElement callElement = element.getParent(); |
| if (callElement instanceof Navigatable && ((Navigatable)callElement).canNavigate()) { |
| ((Navigatable)callElement).navigate(requestFocus); |
| } else { |
| final PsiFile psiFile = callElement.getContainingFile(); |
| if (psiFile == null || psiFile.getVirtualFile() == null) return; |
| FileEditorManager.getInstance(myProject).openFile(psiFile.getVirtualFile(), requestFocus); |
| } |
| |
| Editor editor = PsiUtilBase.findEditor(callElement); |
| |
| if (editor != null) { |
| |
| HighlightManager highlightManager = HighlightManager.getInstance(myProject); |
| EditorColorsManager colorManager = EditorColorsManager.getInstance(); |
| TextAttributes attributes = colorManager.getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES); |
| ArrayList<RangeHighlighter> highlighters = new ArrayList<RangeHighlighter>(); |
| for (PsiReference psiReference : myReferences) { |
| final PsiElement eachElement = psiReference.getElement(); |
| if (eachElement != null) { |
| final PsiElement eachMethodCall = eachElement.getParent(); |
| if (eachMethodCall != null) { |
| final TextRange textRange = eachMethodCall.getTextRange(); |
| highlightManager.addRangeHighlight(editor, textRange.getStartOffset(), textRange.getEndOffset(), attributes, false, highlighters); |
| } |
| } |
| } |
| } |
| } |
| |
| public boolean canNavigate() { |
| if (!myNavigateToReference) { |
| return myElement instanceof Navigatable && ((Navigatable) myElement).canNavigate(); |
| } |
| if (myReferences.isEmpty()) return false; |
| final PsiReference firstReference = myReferences.get(0); |
| final PsiElement callElement = firstReference.getElement().getParent(); |
| if (callElement == null || !callElement.isValid()) return false; |
| if (!(callElement instanceof Navigatable) || !((Navigatable)callElement).canNavigate()) { |
| final PsiFile psiFile = callElement.getContainingFile(); |
| if (psiFile == null) return false; |
| } |
| return true; |
| } |
| |
| public boolean canNavigateToSource() { |
| return canNavigate(); |
| } |
| } |