change signature: do not expand params/exceptions tree on node check
[fedora-idea.git] / java / java-impl / src / com / intellij / refactoring / changeSignature / inCallers / CallerChooser.java
bloba7a04e18564a36b82e1e4261d377a83c9624945a
1 /*
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;
45 import javax.swing.*;
46 import javax.swing.event.TreeSelectionEvent;
47 import javax.swing.event.TreeSelectionListener;
48 import javax.swing.tree.TreePath;
49 import javax.swing.tree.TreeSelectionModel;
50 import java.awt.*;
51 import java.util.Enumeration;
52 import java.util.Set;
54 /**
55 * @author ven
57 public abstract class CallerChooser extends DialogWrapper {
58 PsiMethod myMethod;
59 private final Alarm myAlarm = new Alarm();
60 private MethodNode myRoot;
61 private final Project myProject;
62 private Tree myTree;
63 private TreeSelectionListener myTreeSelectionListener;
64 private Editor myCallerEditor;
65 private Editor myCalleeEditor;
67 public Tree getTree() {
68 return myTree;
71 public CallerChooser(final PsiMethod method, String title, Tree previousTree) {
72 super(true);
73 myMethod = method;
74 myProject = myMethod.getProject();
75 myTree = previousTree;
76 setTitle(title);
77 init();
80 protected JComponent createCenterPanel() {
81 Splitter splitter = new Splitter(false, (float)0.6);
82 JPanel result = new JPanel(new BorderLayout());
83 if (myTree == null) {
84 myTree = createTree();
86 else {
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();
93 if (path != null) {
94 final MethodNode node = (MethodNode)path.getLastPathComponent();
95 myAlarm.cancelAllRequests();
96 myAlarm.addRequest(new Runnable() {
97 public void run() {
98 updateEditorTexts(node);
100 }, 300);
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);
120 return result;
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() {
131 public void run() {
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);
158 super.dispose();
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());
187 return splitter;
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));
195 return editor;
198 private Tree createTree() {
199 final CheckedTreeNode root = new MethodNode(null, new HashSet<PsiMethod>());
200 myRoot = new MethodNode(myMethod, new HashSet<PsiMethod>());
201 root.add(myRoot);
202 final CheckboxTree.CheckboxTreeCellRenderer cellRenderer = new CheckboxTree.CheckboxTreeCellRenderer(true, false) {
203 public void customizeCellRenderer(JTree tree,
204 Object value,
205 boolean selected,
206 boolean expanded,
207 boolean leaf,
208 int row,
209 boolean hasFocus) {
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()));
219 return tree;
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);
234 } else {
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);
251 super.doOKAction();
254 abstract protected void callersChosen(Set<PsiMethod> callers);