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
.refactoring
.changeSignature
.inCallers
;
18 import com
.intellij
.codeInsight
.highlighting
.HighlightManager
;
19 import com
.intellij
.ide
.highlighter
.HighlighterFactory
;
20 import com
.intellij
.openapi
.application
.ApplicationManager
;
21 import com
.intellij
.openapi
.editor
.Document
;
22 import com
.intellij
.openapi
.editor
.Editor
;
23 import com
.intellij
.openapi
.editor
.EditorFactory
;
24 import com
.intellij
.openapi
.editor
.colors
.EditorColors
;
25 import com
.intellij
.openapi
.editor
.colors
.EditorColorsManager
;
26 import com
.intellij
.openapi
.editor
.ex
.EditorEx
;
27 import com
.intellij
.openapi
.editor
.markup
.TextAttributes
;
28 import com
.intellij
.openapi
.fileTypes
.StdFileTypes
;
29 import com
.intellij
.openapi
.project
.Project
;
30 import com
.intellij
.openapi
.ui
.DialogWrapper
;
31 import com
.intellij
.openapi
.ui
.Splitter
;
32 import com
.intellij
.psi
.*;
33 import com
.intellij
.psi
.search
.LocalSearchScope
;
34 import com
.intellij
.psi
.search
.searches
.ReferencesSearch
;
35 import com
.intellij
.refactoring
.RefactoringBundle
;
36 import com
.intellij
.ui
.CheckboxTree
;
37 import com
.intellij
.ui
.CheckedTreeNode
;
38 import com
.intellij
.ui
.IdeBorderFactory
;
39 import com
.intellij
.ui
.treeStructure
.Tree
;
40 import com
.intellij
.util
.Alarm
;
41 import com
.intellij
.util
.containers
.HashSet
;
42 import org
.jetbrains
.annotations
.NotNull
;
45 import javax
.swing
.event
.TreeSelectionEvent
;
46 import javax
.swing
.event
.TreeSelectionListener
;
47 import javax
.swing
.tree
.TreePath
;
48 import javax
.swing
.tree
.TreeSelectionModel
;
50 import java
.util
.Enumeration
;
56 public abstract class CallerChooser
extends DialogWrapper
{
58 private final Alarm myAlarm
= new Alarm();
59 private MethodNode myRoot
;
60 private final Project myProject
;
62 private TreeSelectionListener myTreeSelectionListener
;
63 private Editor myCallerEditor
;
64 private Editor myCalleeEditor
;
66 public Tree
getTree() {
70 public CallerChooser(final PsiMethod method
, String title
, Tree previousTree
) {
73 myProject
= myMethod
.getProject();
74 myTree
= previousTree
;
79 protected JComponent
createCenterPanel() {
80 Splitter splitter
= new Splitter(false, (float)0.6);
81 JPanel result
= new JPanel(new BorderLayout());
83 myTree
= createTree();
86 final CheckedTreeNode root
= (CheckedTreeNode
)myTree
.getModel().getRoot();
87 myRoot
= (MethodNode
)root
.getFirstChild();
89 myTreeSelectionListener
= new TreeSelectionListener() {
90 public void valueChanged(TreeSelectionEvent e
) {
91 final TreePath path
= e
.getPath();
93 final MethodNode node
= (MethodNode
)path
.getLastPathComponent();
94 myAlarm
.cancelAllRequests();
95 myAlarm
.addRequest(new Runnable() {
97 updateEditorTexts(node
);
103 myTree
.getSelectionModel().addTreeSelectionListener(myTreeSelectionListener
);
105 JScrollPane scrollPane
= new JScrollPane(myTree
);
106 splitter
.setFirstComponent(scrollPane
);
107 final JComponent callSitesViewer
= createCallSitesViewer();
108 TreePath selectionPath
= myTree
.getSelectionPath();
109 if (selectionPath
== null) {
110 selectionPath
= new TreePath(myRoot
.getPath());
111 myTree
.getSelectionModel().addSelectionPath(selectionPath
);
114 final MethodNode node
= (MethodNode
)selectionPath
.getLastPathComponent();
115 updateEditorTexts(node
);
117 splitter
.setSecondComponent(callSitesViewer
);
118 result
.add(splitter
);
122 private void updateEditorTexts(final MethodNode node
) {
123 final MethodNode parentNode
= (MethodNode
)node
.getParent();
124 final String callerText
= node
!= myRoot ?
getText(node
.getMethod()) : "";
125 final Document callerDocument
= myCallerEditor
.getDocument();
126 final String calleeText
= node
!= myRoot ?
getText(parentNode
.getMethod()) : "";
127 final Document calleeDocument
= myCalleeEditor
.getDocument();
129 ApplicationManager
.getApplication().runWriteAction(new Runnable() {
131 callerDocument
.setText(callerText
);
132 calleeDocument
.setText(calleeText
);
136 final PsiMethod caller
= node
.getMethod();
137 final PsiMethod callee
= parentNode
!= null ? parentNode
.getMethod() : null;
138 if (caller
!= null && callee
!= null) {
139 HighlightManager highlighter
= HighlightManager
.getInstance(myProject
);
140 EditorColorsManager colorManager
= EditorColorsManager
.getInstance();
141 TextAttributes attributes
= colorManager
.getGlobalScheme().getAttributes(EditorColors
.TEXT_SEARCH_RESULT_ATTRIBUTES
);
142 int start
= getStartOffset(caller
);
143 for (PsiReference ref
: ReferencesSearch
.search(callee
, new LocalSearchScope(caller
), false)) {
144 final PsiElement element
= ref
.getElement();
145 if (element
!= null) {
146 highlighter
.addRangeHighlight(myCallerEditor
, element
.getTextRange().getStartOffset() - start
,
147 element
.getTextRange().getEndOffset() - start
, attributes
, false, null);
153 public void dispose() {
154 myTree
.removeTreeSelectionListener(myTreeSelectionListener
);
155 EditorFactory
.getInstance().releaseEditor(myCallerEditor
);
156 EditorFactory
.getInstance().releaseEditor(myCalleeEditor
);
160 private String
getText(final PsiMethod method
) {
161 if (method
== null) return "";
162 final PsiFile file
= method
.getContainingFile();
163 Document document
= PsiDocumentManager
.getInstance(myProject
).getDocument(file
);
164 final int start
= document
.getLineStartOffset(document
.getLineNumber(method
.getTextRange().getStartOffset()));
165 final int end
= document
.getLineEndOffset(document
.getLineNumber(method
.getTextRange().getEndOffset()));
166 return document
.getText().substring(start
, end
);
169 private int getStartOffset (@NotNull final PsiMethod method
) {
170 final PsiFile file
= method
.getContainingFile();
171 Document document
= PsiDocumentManager
.getInstance(myProject
).getDocument(file
);
172 return document
.getLineStartOffset(document
.getLineNumber(method
.getTextRange().getStartOffset()));
175 private JComponent
createCallSitesViewer() {
176 Splitter splitter
= new Splitter(true);
177 myCallerEditor
= createEditor();
178 myCalleeEditor
= createEditor();
179 final JComponent callerComponent
= myCallerEditor
.getComponent();
180 callerComponent
.setBorder(IdeBorderFactory
.createTitledBorder(RefactoringBundle
.message("caller.chooser.caller.method")));
181 splitter
.setFirstComponent(callerComponent
);
182 final JComponent calleeComponent
= myCalleeEditor
.getComponent();
183 calleeComponent
.setBorder(IdeBorderFactory
.createTitledBorder(RefactoringBundle
.message("caller.chooser.callee.method")));
184 splitter
.setSecondComponent(calleeComponent
);
185 splitter
.setBorder(IdeBorderFactory
.createBorder());
189 private Editor
createEditor() {
190 final EditorFactory editorFactory
= EditorFactory
.getInstance();
191 final Document document
= editorFactory
.createDocument("");
192 final Editor editor
= editorFactory
.createViewer(document
, myProject
);
193 ((EditorEx
)editor
).setHighlighter(HighlighterFactory
.createHighlighter(myProject
, StdFileTypes
.JAVA
));
197 private Tree
createTree() {
198 final CheckedTreeNode root
= new MethodNode(null, new HashSet
<PsiMethod
>());
199 myRoot
= new MethodNode(myMethod
, new HashSet
<PsiMethod
>());
201 final CheckboxTree
.CheckboxTreeCellRenderer cellRenderer
= new CheckboxTree
.CheckboxTreeCellRenderer() {
202 public void customizeCellRenderer(JTree tree
,
209 if (value
instanceof MethodNode
) {
210 ((MethodNode
)value
).customizeRenderer(getTextRenderer());
214 Tree tree
= new CheckboxTree(cellRenderer
, root
);
215 tree
.getSelectionModel().setSelectionMode(TreeSelectionModel
.SINGLE_TREE_SELECTION
);
216 tree
.getSelectionModel().setSelectionPath(new TreePath(myRoot
.getPath()));
221 private void getSelectedMethods(Set
<PsiMethod
> methods
) {
222 MethodNode node
= myRoot
;
223 getSelectedMethodsInner(node
, methods
);
224 methods
.remove(node
.getMethod());
227 private static void getSelectedMethodsInner(final MethodNode node
, final Set
<PsiMethod
> allMethods
) {
228 if (node
.isChecked()) {
229 PsiMethod method
= node
.getMethod();
230 final PsiMethod
[] superMethods
= method
.findDeepestSuperMethods();
231 if (superMethods
.length
== 0) {
232 allMethods
.add(method
);
234 for (PsiMethod superMethod
: superMethods
) {
235 allMethods
.add(superMethod
);
239 final Enumeration children
= node
.children();
240 while (children
.hasMoreElements()) {
241 getSelectedMethodsInner((MethodNode
)children
.nextElement(), allMethods
);
246 protected void doOKAction() {
247 final Set
<PsiMethod
> selectedMethods
= new HashSet
<PsiMethod
>();
248 getSelectedMethods(selectedMethods
);
249 callersChosen(selectedMethods
);
253 abstract protected void callersChosen(Set
<PsiMethod
> callers
);