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
.CheckboxTreeBase
;
38 import com
.intellij
.ui
.CheckedTreeNode
;
39 import com
.intellij
.ui
.IdeBorderFactory
;
40 import com
.intellij
.ui
.treeStructure
.Tree
;
41 import com
.intellij
.util
.Alarm
;
42 import com
.intellij
.util
.containers
.HashSet
;
43 import org
.jetbrains
.annotations
.NotNull
;
46 import javax
.swing
.event
.TreeSelectionEvent
;
47 import javax
.swing
.event
.TreeSelectionListener
;
48 import javax
.swing
.tree
.TreePath
;
49 import javax
.swing
.tree
.TreeSelectionModel
;
51 import java
.util
.Enumeration
;
57 public abstract class CallerChooser
extends DialogWrapper
{
59 private final Alarm myAlarm
= new Alarm();
60 private MethodNode myRoot
;
61 private final Project myProject
;
63 private TreeSelectionListener myTreeSelectionListener
;
64 private Editor myCallerEditor
;
65 private Editor myCalleeEditor
;
67 public Tree
getTree() {
71 public CallerChooser(final PsiMethod method
, String title
, Tree previousTree
) {
74 myProject
= myMethod
.getProject();
75 myTree
= previousTree
;
80 protected JComponent
createCenterPanel() {
81 Splitter splitter
= new Splitter(false, (float)0.6);
82 JPanel result
= new JPanel(new BorderLayout());
84 myTree
= createTree();
87 final CheckedTreeNode root
= (CheckedTreeNode
)myTree
.getModel().getRoot();
88 myRoot
= (MethodNode
)root
.getFirstChild();
90 myTreeSelectionListener
= new TreeSelectionListener() {
91 public void valueChanged(TreeSelectionEvent e
) {
92 final TreePath path
= e
.getPath();
94 final MethodNode node
= (MethodNode
)path
.getLastPathComponent();
95 myAlarm
.cancelAllRequests();
96 myAlarm
.addRequest(new Runnable() {
98 updateEditorTexts(node
);
104 myTree
.getSelectionModel().addTreeSelectionListener(myTreeSelectionListener
);
106 JScrollPane scrollPane
= new JScrollPane(myTree
);
107 splitter
.setFirstComponent(scrollPane
);
108 final JComponent callSitesViewer
= createCallSitesViewer();
109 TreePath selectionPath
= myTree
.getSelectionPath();
110 if (selectionPath
== null) {
111 selectionPath
= new TreePath(myRoot
.getPath());
112 myTree
.getSelectionModel().addSelectionPath(selectionPath
);
115 final MethodNode node
= (MethodNode
)selectionPath
.getLastPathComponent();
116 updateEditorTexts(node
);
118 splitter
.setSecondComponent(callSitesViewer
);
119 result
.add(splitter
);
123 private void updateEditorTexts(final MethodNode node
) {
124 final MethodNode parentNode
= (MethodNode
)node
.getParent();
125 final String callerText
= node
!= myRoot ?
getText(node
.getMethod()) : "";
126 final Document callerDocument
= myCallerEditor
.getDocument();
127 final String calleeText
= node
!= myRoot ?
getText(parentNode
.getMethod()) : "";
128 final Document calleeDocument
= myCalleeEditor
.getDocument();
130 ApplicationManager
.getApplication().runWriteAction(new Runnable() {
132 callerDocument
.setText(callerText
);
133 calleeDocument
.setText(calleeText
);
137 final PsiMethod caller
= node
.getMethod();
138 final PsiMethod callee
= parentNode
!= null ? parentNode
.getMethod() : null;
139 if (caller
!= null && callee
!= null) {
140 HighlightManager highlighter
= HighlightManager
.getInstance(myProject
);
141 EditorColorsManager colorManager
= EditorColorsManager
.getInstance();
142 TextAttributes attributes
= colorManager
.getGlobalScheme().getAttributes(EditorColors
.TEXT_SEARCH_RESULT_ATTRIBUTES
);
143 int start
= getStartOffset(caller
);
144 for (PsiReference ref
: ReferencesSearch
.search(callee
, new LocalSearchScope(caller
), false)) {
145 final PsiElement element
= ref
.getElement();
146 if (element
!= null) {
147 highlighter
.addRangeHighlight(myCallerEditor
, element
.getTextRange().getStartOffset() - start
,
148 element
.getTextRange().getEndOffset() - start
, attributes
, false, null);
154 public void dispose() {
155 myTree
.removeTreeSelectionListener(myTreeSelectionListener
);
156 EditorFactory
.getInstance().releaseEditor(myCallerEditor
);
157 EditorFactory
.getInstance().releaseEditor(myCalleeEditor
);
161 private String
getText(final PsiMethod method
) {
162 if (method
== null) return "";
163 final PsiFile file
= method
.getContainingFile();
164 Document document
= PsiDocumentManager
.getInstance(myProject
).getDocument(file
);
165 final int start
= document
.getLineStartOffset(document
.getLineNumber(method
.getTextRange().getStartOffset()));
166 final int end
= document
.getLineEndOffset(document
.getLineNumber(method
.getTextRange().getEndOffset()));
167 return document
.getText().substring(start
, end
);
170 private int getStartOffset (@NotNull final PsiMethod method
) {
171 final PsiFile file
= method
.getContainingFile();
172 Document document
= PsiDocumentManager
.getInstance(myProject
).getDocument(file
);
173 return document
.getLineStartOffset(document
.getLineNumber(method
.getTextRange().getStartOffset()));
176 private JComponent
createCallSitesViewer() {
177 Splitter splitter
= new Splitter(true);
178 myCallerEditor
= createEditor();
179 myCalleeEditor
= createEditor();
180 final JComponent callerComponent
= myCallerEditor
.getComponent();
181 callerComponent
.setBorder(IdeBorderFactory
.createTitledBorder(RefactoringBundle
.message("caller.chooser.caller.method")));
182 splitter
.setFirstComponent(callerComponent
);
183 final JComponent calleeComponent
= myCalleeEditor
.getComponent();
184 calleeComponent
.setBorder(IdeBorderFactory
.createTitledBorder(RefactoringBundle
.message("caller.chooser.callee.method")));
185 splitter
.setSecondComponent(calleeComponent
);
186 splitter
.setBorder(IdeBorderFactory
.createBorder());
190 private Editor
createEditor() {
191 final EditorFactory editorFactory
= EditorFactory
.getInstance();
192 final Document document
= editorFactory
.createDocument("");
193 final Editor editor
= editorFactory
.createViewer(document
, myProject
);
194 ((EditorEx
)editor
).setHighlighter(HighlighterFactory
.createHighlighter(myProject
, StdFileTypes
.JAVA
));
198 private Tree
createTree() {
199 final CheckedTreeNode root
= new MethodNode(null, new HashSet
<PsiMethod
>());
200 myRoot
= new MethodNode(myMethod
, new HashSet
<PsiMethod
>());
202 final CheckboxTree
.CheckboxTreeCellRenderer cellRenderer
= new CheckboxTree
.CheckboxTreeCellRenderer(true, false) {
203 public void customizeCellRenderer(JTree tree
,
210 if (value
instanceof MethodNode
) {
211 ((MethodNode
)value
).customizeRenderer(getTextRenderer());
215 Tree tree
= new CheckboxTree(cellRenderer
, root
, new CheckboxTreeBase
.CheckPolicy(false, false, true, false));
216 tree
.getSelectionModel().setSelectionMode(TreeSelectionModel
.SINGLE_TREE_SELECTION
);
217 tree
.getSelectionModel().setSelectionPath(new TreePath(myRoot
.getPath()));
222 private void getSelectedMethods(Set
<PsiMethod
> methods
) {
223 MethodNode node
= myRoot
;
224 getSelectedMethodsInner(node
, methods
);
225 methods
.remove(node
.getMethod());
228 private static void getSelectedMethodsInner(final MethodNode node
, final Set
<PsiMethod
> allMethods
) {
229 if (node
.isChecked()) {
230 PsiMethod method
= node
.getMethod();
231 final PsiMethod
[] superMethods
= method
.findDeepestSuperMethods();
232 if (superMethods
.length
== 0) {
233 allMethods
.add(method
);
235 for (PsiMethod superMethod
: superMethods
) {
236 allMethods
.add(superMethod
);
240 final Enumeration children
= node
.children();
241 while (children
.hasMoreElements()) {
242 getSelectedMethodsInner((MethodNode
)children
.nextElement(), allMethods
);
247 protected void doOKAction() {
248 final Set
<PsiMethod
> selectedMethods
= new HashSet
<PsiMethod
>();
249 getSelectedMethods(selectedMethods
);
250 callersChosen(selectedMethods
);
254 abstract protected void callersChosen(Set
<PsiMethod
> callers
);