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
.extractMethodObject
;
18 import com
.intellij
.openapi
.editor
.event
.DocumentEvent
;
19 import com
.intellij
.openapi
.help
.HelpManager
;
20 import com
.intellij
.openapi
.project
.Project
;
21 import com
.intellij
.openapi
.util
.text
.StringUtil
;
22 import com
.intellij
.openapi
.wm
.IdeFocusManager
;
23 import com
.intellij
.psi
.*;
24 import com
.intellij
.psi
.util
.PsiFormatUtil
;
25 import com
.intellij
.refactoring
.HelpID
;
26 import com
.intellij
.refactoring
.extractMethod
.AbstractExtractDialog
;
27 import com
.intellij
.refactoring
.extractMethod
.InputVariables
;
28 import com
.intellij
.refactoring
.ui
.ConflictsDialog
;
29 import com
.intellij
.refactoring
.util
.ParameterTablePanel
;
30 import com
.intellij
.ui
.EditorTextField
;
31 import com
.intellij
.util
.Function
;
32 import com
.intellij
.util
.VisibilityUtil
;
33 import com
.intellij
.util
.containers
.MultiMap
;
34 import com
.intellij
.util
.ui
.UIUtil
;
35 import org
.jetbrains
.annotations
.NonNls
;
39 import java
.awt
.event
.ActionEvent
;
40 import java
.awt
.event
.ActionListener
;
41 import java
.util
.Enumeration
;
44 public class ExtractMethodObjectDialog
extends AbstractExtractDialog
{
45 private final Project myProject
;
46 private final PsiType myReturnType
;
47 private final PsiTypeParameterList myTypeParameterList
;
48 private final PsiType
[] myExceptions
;
49 private final boolean myStaticFlag
;
50 private final boolean myCanBeStatic
;
51 private final PsiElement
[] myElementsToExtract
;
52 private final boolean myMultipleExitPoints
;
54 private final InputVariables myVariableData
;
55 private final PsiClass myTargetClass
;
56 private boolean myWasStatic
;
59 private JRadioButton myCreateInnerClassRb
;
60 private JRadioButton myCreateAnonymousClassWrapperRb
;
61 private JTextArea mySignatureArea
;
62 private JCheckBox myCbMakeStatic
;
63 private JCheckBox myCbMakeVarargs
;
64 private JCheckBox myCbMakeVarargsAnonymous
;
66 private JPanel myWholePanel
;
67 private JPanel myParametersTableContainer
;
68 private JRadioButton myPrivateRadioButton
;
69 private JRadioButton myProtectedRadioButton
;
70 private JRadioButton myPackageLocalRadioButton
;
71 private JRadioButton myPublicRadioButton
;
73 private EditorTextField myInnerClassName
;
74 private EditorTextField myMethodName
;
76 private JPanel myInnerClassPanel
;
77 private JPanel myAnonymousClassPanel
;
78 private JCheckBox myFoldCb
;
79 private ButtonGroup myVisibilityGroup
;
80 private ParameterTablePanel
.VariableData
[] myInputVariables
;
83 public ExtractMethodObjectDialog(Project project
, PsiClass targetClass
, final InputVariables inputVariables
, PsiType returnType
,
84 PsiTypeParameterList typeParameterList
, PsiType
[] exceptions
, boolean isStatic
, boolean canBeStatic
,
85 final PsiElement
[] elementsToExtract
, final boolean multipleExitPoints
) {
88 myTargetClass
= targetClass
;
89 myReturnType
= returnType
;
90 myTypeParameterList
= typeParameterList
;
91 myExceptions
= exceptions
;
92 myStaticFlag
= isStatic
;
93 myCanBeStatic
= canBeStatic
;
94 myElementsToExtract
= elementsToExtract
;
95 myMultipleExitPoints
= multipleExitPoints
;
97 boolean canBeVarargs
= false;
98 for (ParameterTablePanel
.VariableData data
: inputVariables
.getInputVariables()) {
99 canBeVarargs
|= data
.type
instanceof PsiArrayType
;
101 canBeVarargs
|= inputVariables
.isFoldable() && inputVariables
.isFoldingSelectedByDefault();
102 myWasStatic
= canBeVarargs
;
104 myVariableData
= inputVariables
;
106 setTitle(ExtractMethodObjectProcessor
.REFACTORING_NAME
);
108 // Create UI components
111 myCbMakeVarargs
.setVisible(canBeVarargs
);
112 myCbMakeVarargsAnonymous
.setVisible(canBeVarargs
);
119 public boolean isMakeStatic() {
120 if (myStaticFlag
) return true;
121 if (!myCanBeStatic
) return false;
122 return myCbMakeStatic
.isSelected();
125 public boolean isChainedConstructor() {
129 protected Action
[] createActions() {
130 return new Action
[]{getOKAction(), getCancelAction(), getHelpAction()};
133 public String
getChosenMethodName() {
134 return myCreateInnerClassRb
.isSelected() ? myInnerClassName
.getText() : myMethodName
.getText();
137 public ParameterTablePanel
.VariableData
[] getChosenParameters() {
138 return myInputVariables
;
141 public JComponent
getPreferredFocusedComponent() {
142 return myInnerClassName
;
145 protected void doHelpAction() {
146 HelpManager
.getInstance().invokeHelp(HelpID
.EXTRACT_METHOD_OBJECT
);
149 protected void doOKAction() {
150 MultiMap
<PsiElement
, String
> conflicts
= new MultiMap
<PsiElement
, String
>();
151 if (myCreateInnerClassRb
.isSelected()) {
152 final PsiClass innerClass
= myTargetClass
.findInnerClassByName(myInnerClassName
.getText(), false);
153 if (innerClass
!= null) {
154 conflicts
.putValue(innerClass
, "Inner class " + myInnerClassName
.getText() + " already defined in class " + myTargetClass
.getName());
157 if (conflicts
.size() > 0) {
158 final ConflictsDialog conflictsDialog
= new ConflictsDialog(myProject
, conflicts
);
159 conflictsDialog
.show();
160 if (!conflictsDialog
.isOK()){
161 if (conflictsDialog
.isShowConflicts()) close(CANCEL_EXIT_CODE
);
166 final JCheckBox makeVarargsCb
= myCreateInnerClassRb
.isSelected() ? myCbMakeVarargs
: myCbMakeVarargsAnonymous
;
167 if (makeVarargsCb
!= null && makeVarargsCb
.isSelected()) {
168 final ParameterTablePanel
.VariableData data
= myInputVariables
[myInputVariables
.length
- 1];
169 if (data
.type
instanceof PsiArrayType
) {
170 data
.type
= new PsiEllipsisType(((PsiArrayType
)data
.type
).getComponentType());
176 private void updateVarargsEnabled() {
177 final boolean enabled
= myInputVariables
.length
> 0 && myInputVariables
[myInputVariables
.length
- 1].type
instanceof PsiArrayType
;
178 if (myCreateInnerClassRb
.isSelected()) {
179 myCbMakeVarargs
.setEnabled(enabled
);
181 myCbMakeVarargsAnonymous
.setEnabled(enabled
);
185 private void update() {
186 myCbMakeStatic
.setEnabled(myCanBeStatic
&& !myStaticFlag
);
188 final PsiNameHelper helper
= JavaPsiFacade
.getInstance(myProject
).getNameHelper();
189 setOKActionEnabled((myCreateInnerClassRb
.isSelected() && helper
.isIdentifier(myInnerClassName
.getText())) ||
190 (!myCreateInnerClassRb
.isSelected() && helper
.isIdentifier(myMethodName
.getText())));
193 public String
getVisibility() {
194 if (myPublicRadioButton
.isSelected()) {
195 return PsiModifier
.PUBLIC
;
197 if (myPackageLocalRadioButton
.isSelected()) {
198 return PsiModifier
.PACKAGE_LOCAL
;
200 if (myProtectedRadioButton
.isSelected()) {
201 return PsiModifier
.PROTECTED
;
203 if (myPrivateRadioButton
.isSelected()) {
204 return PsiModifier
.PRIVATE
;
210 protected JComponent
createCenterPanel() {
211 mySignatureArea
.setEditable(false);
212 myCreateInnerClassRb
.setSelected(true);
214 final ActionListener enableDisableListener
= new ActionListener() {
215 public void actionPerformed(final ActionEvent e
) {
216 enable(myCreateInnerClassRb
.isSelected());
219 myCreateInnerClassRb
.addActionListener(enableDisableListener
);
220 myCreateAnonymousClassWrapperRb
.addActionListener(enableDisableListener
);
221 myCreateAnonymousClassWrapperRb
.setEnabled(!myMultipleExitPoints
);
223 myFoldCb
.setSelected(myVariableData
.isFoldingSelectedByDefault());
224 myFoldCb
.setVisible(myVariableData
.isFoldable());
225 myVariableData
.setFoldingAvailable(myFoldCb
.isSelected());
226 myInputVariables
= myVariableData
.getInputVariables().toArray(new ParameterTablePanel
.VariableData
[myVariableData
.getInputVariables().size()]);
227 myFoldCb
.addActionListener(new ActionListener() {
228 public void actionPerformed(ActionEvent e
) {
229 myVariableData
.setFoldingAvailable(myFoldCb
.isSelected());
230 myInputVariables
= myVariableData
.getInputVariables().toArray(new ParameterTablePanel
.VariableData
[myVariableData
.getInputVariables().size()]);
231 myParametersTableContainer
.removeAll();
232 myParametersTableContainer
.add(createParametersPanel(), BorderLayout
.CENTER
);
234 updateVarargsEnabled();
237 myParametersTableContainer
.add(createParametersPanel(), BorderLayout
.CENTER
);
239 final ActionListener updateSugnatureListener
= new ActionListener() {
240 public void actionPerformed(final ActionEvent e
) {
242 IdeFocusManager
.getInstance(myProject
).requestFocus(myCreateInnerClassRb
.isSelected() ? myInnerClassName
: myMethodName
, false);
246 if (myStaticFlag
|| myCanBeStatic
) {
247 myCbMakeStatic
.setEnabled(!myStaticFlag
);
248 myCbMakeStatic
.setSelected(myStaticFlag
);
250 myCbMakeStatic
.addActionListener(updateSugnatureListener
);
252 myCbMakeStatic
.setSelected(false);
253 myCbMakeStatic
.setEnabled(false);
256 updateVarargsEnabled();
258 myCbMakeVarargs
.setSelected(myWasStatic
);
259 myCbMakeVarargs
.addActionListener(updateSugnatureListener
);
261 myCbMakeVarargsAnonymous
.setSelected(myWasStatic
);
262 myCbMakeVarargsAnonymous
.addActionListener(updateSugnatureListener
);
264 final com
.intellij
.openapi
.editor
.event
.DocumentAdapter nameListener
= new com
.intellij
.openapi
.editor
.event
.DocumentAdapter() {
266 public void documentChanged(final DocumentEvent e
) {
270 myInnerClassName
.getDocument().addDocumentListener(nameListener
);
271 myMethodName
.getDocument().addDocumentListener(nameListener
);
273 myPrivateRadioButton
.setSelected(true);
275 myCreateInnerClassRb
.addActionListener(updateSugnatureListener
);
276 myCreateAnonymousClassWrapperRb
.addActionListener(updateSugnatureListener
);
278 final Enumeration
<AbstractButton
> visibilities
= myVisibilityGroup
.getElements();
279 while(visibilities
.hasMoreElements()) {
280 visibilities
.nextElement().addActionListener(updateSugnatureListener
);
288 private void enable(boolean innerClassSelected
){
289 UIUtil
.setEnabled(myInnerClassPanel
, innerClassSelected
, true);
290 UIUtil
.setEnabled(myAnonymousClassPanel
, !innerClassSelected
, true);
293 private JComponent
createParametersPanel() {
294 return new ParameterTablePanel(myProject
, myInputVariables
, myElementsToExtract
) {
295 protected void updateSignature() {
296 updateVarargsEnabled();
297 ExtractMethodObjectDialog
.this.updateSignature();
300 protected void doEnterAction() {
301 clickDefaultButton();
304 protected void doCancelAction() {
305 ExtractMethodObjectDialog
.this.doCancelAction();
308 protected boolean areTypesDirected() {
314 protected void updateSignature() {
315 if (mySignatureArea
== null) return;
316 @NonNls StringBuffer buffer
= getSignature();
317 mySignatureArea
.setText(buffer
.toString());
320 protected StringBuffer
getSignature() {
321 final String INDENT
= " ";
322 @NonNls StringBuffer buffer
= new StringBuffer();
323 final String visibilityString
= VisibilityUtil
.getVisibilityString(getVisibility());
324 if (myCreateInnerClassRb
.isSelected()) {
325 buffer
.append(visibilityString
);
326 if (buffer
.length() > 0) {
329 if (isMakeStatic()) {
330 buffer
.append("static ");
332 buffer
.append("class ");
333 buffer
.append(myInnerClassName
.getText());
334 if (myTypeParameterList
!= null) {
335 buffer
.append(myTypeParameterList
.getText());
338 buffer
.append("{\n");
339 buffer
.append(INDENT
);
340 buffer
.append("public ");
341 buffer
.append(myInnerClassName
.getText());
342 methodSignature(INDENT
, buffer
);
343 buffer
.append("\n}");
345 buffer
.append("new Object(){\n");
346 buffer
.append(INDENT
);
347 buffer
.append("private ");
348 buffer
.append(PsiFormatUtil
.formatType(myReturnType
, 0, PsiSubstitutor
.EMPTY
));
350 buffer
.append(myMethodName
.getText());
351 methodSignature(INDENT
, buffer
);
352 buffer
.append("\n}.");
353 buffer
.append(myMethodName
.getText());
355 buffer
.append(StringUtil
.join(myInputVariables
, new Function
<ParameterTablePanel
.VariableData
, String
>() {
356 public String
fun(final ParameterTablePanel
.VariableData variableData
) {
357 return variableData
.name
;
366 private void methodSignature(final String INDENT
, final StringBuffer buffer
) {
369 final String indent
= " ";
370 for (int i
= 0; i
< myInputVariables
.length
; i
++) {
371 ParameterTablePanel
.VariableData data
= myInputVariables
[i
];
372 if (data
.passAsParameter
) {
373 //String typeAndModifiers = PsiFormatUtil.formatVariable(data.variable,
374 // PsiFormatUtil.SHOW_MODIFIERS | PsiFormatUtil.SHOW_TYPE);
375 PsiType type
= data
.type
;
376 if (i
== myInputVariables
.length
- 1 && type
instanceof PsiArrayType
&& ((myCreateInnerClassRb
.isSelected() && myCbMakeVarargs
.isSelected()) || (myCreateAnonymousClassWrapperRb
.isSelected() && myCbMakeVarargsAnonymous
.isSelected()))) {
377 type
= new PsiEllipsisType(((PsiArrayType
)type
).getComponentType());
380 String typeText
= type
.getPresentableText();
385 buffer
.append(indent
);
386 buffer
.append(typeText
);
388 buffer
.append(data
.name
);
393 if (myExceptions
.length
> 0) {
395 buffer
.append("throws\n");
396 for (PsiType exception
: myExceptions
) {
397 buffer
.append(INDENT
);
398 buffer
.append(PsiFormatUtil
.formatType(exception
, 0, PsiSubstitutor
.EMPTY
));
405 public boolean createInnerClass() {
406 return myCreateInnerClassRb
.isSelected();