update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / refactoring / introduceField / IntroduceConstantDialog.java
blob0f2de7af75612f7ceaedc85fc4fde888efafc990
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.introduceField;
18 import com.intellij.codeInsight.AnnotationUtil;
19 import com.intellij.codeInsight.completion.JavaCompletionUtil;
20 import com.intellij.ide.util.PropertiesComponent;
21 import com.intellij.ide.util.TreeClassChooser;
22 import com.intellij.ide.util.TreeClassChooserFactory;
23 import com.intellij.openapi.diagnostic.Logger;
24 import com.intellij.openapi.editor.event.DocumentAdapter;
25 import com.intellij.openapi.editor.event.DocumentEvent;
26 import com.intellij.openapi.help.HelpManager;
27 import com.intellij.openapi.project.Project;
28 import com.intellij.openapi.roots.LanguageLevelProjectExtension;
29 import com.intellij.openapi.ui.DialogWrapper;
30 import com.intellij.openapi.ui.Messages;
31 import com.intellij.openapi.util.Comparing;
32 import com.intellij.psi.*;
33 import com.intellij.psi.codeStyle.JavaCodeStyleManager;
34 import com.intellij.psi.codeStyle.SuggestedNameInfo;
35 import com.intellij.psi.codeStyle.VariableKind;
36 import com.intellij.psi.impl.source.resolve.JavaResolveUtil;
37 import com.intellij.psi.search.GlobalSearchScope;
38 import com.intellij.refactoring.HelpID;
39 import com.intellij.refactoring.JavaRefactoringSettings;
40 import com.intellij.refactoring.RefactoringBundle;
41 import com.intellij.refactoring.ui.*;
42 import com.intellij.refactoring.util.CommonRefactoringUtil;
43 import com.intellij.refactoring.util.EnumConstantsUtil;
44 import com.intellij.refactoring.util.RefactoringMessageUtil;
45 import com.intellij.ui.RecentsManager;
46 import com.intellij.ui.ReferenceEditorComboWithBrowseButton;
47 import com.intellij.ui.StateRestoringCheckBox;
48 import com.intellij.util.IncorrectOperationException;
49 import gnu.trove.THashSet;
50 import org.jetbrains.annotations.NonNls;
52 import javax.swing.*;
53 import java.awt.*;
54 import java.awt.event.ActionEvent;
55 import java.awt.event.ActionListener;
56 import java.awt.event.ItemEvent;
57 import java.awt.event.ItemListener;
58 import java.util.Iterator;
59 import java.util.LinkedHashSet;
60 import java.util.Set;
62 class IntroduceConstantDialog extends DialogWrapper {
63 private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.introduceField.IntroduceConstantDialog");
64 @NonNls private static final String RECENTS_KEY = "IntroduceConstantDialog.RECENTS_KEY";
65 @NonNls private static final String NONNLS_SELECTED_PROPERTY = "INTRODUCE_CONSTANT_NONNLS";
67 private final Project myProject;
68 private final PsiClass myParentClass;
69 private final PsiExpression myInitializerExpression;
70 private final PsiLocalVariable myLocalVariable;
71 private final boolean myInvokedOnDeclaration;
72 private final PsiExpression[] myOccurrences;
73 private final int myOccurrencesCount;
74 private PsiClass myTargetClass;
75 private final TypeSelectorManager myTypeSelectorManager;
77 private NameSuggestionsField myNameField;
78 private JCheckBox myCbReplaceAll;
80 private JRadioButton myRbPrivate;
81 private JRadioButton myRbProtected;
82 private JRadioButton myRbpackageLocal;
83 private JRadioButton myRbPublic;
85 private TypeSelector myTypeSelector;
86 private StateRestoringCheckBox myCbDeleteVariable;
87 private final JavaCodeStyleManager myCodeStyleManager;
88 private ReferenceEditorComboWithBrowseButton myTfTargetClassName;
89 private BaseExpressionToFieldHandler.TargetDestination myDestinationClass;
90 private JPanel myTypePanel;
91 private JPanel myTargetClassNamePanel;
92 private JPanel myPanel;
93 private JLabel myTypeLabel;
94 private JPanel myNameSuggestionPanel;
95 private JLabel myNameSuggestionLabel;
96 private JLabel myTargetClassNameLabel;
97 private JCheckBox myCbNonNls;
98 private final JCheckBox myIntroduceEnumConstantCb = new JCheckBox(RefactoringBundle.message("introduce.constant.enum.cb"), true);
100 IntroduceConstantDialog(Project project,
101 PsiClass parentClass,
102 PsiExpression initializerExpression,
103 PsiLocalVariable localVariable,
104 boolean isInvokedOnDeclaration,
105 PsiExpression[] occurrences,
106 PsiClass targetClass,
107 TypeSelectorManager typeSelectorManager) {
108 super(project, true);
109 myProject = project;
110 myParentClass = parentClass;
111 myInitializerExpression = initializerExpression;
112 myLocalVariable = localVariable;
113 myInvokedOnDeclaration = isInvokedOnDeclaration;
114 myOccurrences = occurrences;
115 myOccurrencesCount = occurrences.length;
116 myTargetClass = targetClass;
117 myTypeSelectorManager = typeSelectorManager;
118 myDestinationClass = null;
120 setTitle(IntroduceConstantHandler.REFACTORING_NAME);
121 myCodeStyleManager = JavaCodeStyleManager.getInstance(myProject);
122 init();
124 final String ourLastVisibility = JavaRefactoringSettings.getInstance().INTRODUCE_CONSTANT_VISIBILITY;
125 if (PsiModifier.PUBLIC.equals(ourLastVisibility)) {
126 myRbPublic.setSelected(true);
127 } else if (PsiModifier.PROTECTED.equals(ourLastVisibility)) {
128 myRbProtected.setSelected(true);
129 } else if (PsiModifier.PACKAGE_LOCAL.equals(ourLastVisibility)) {
130 myRbpackageLocal.setSelected(true);
131 } else if (PsiModifier.PRIVATE.equals(ourLastVisibility)) {
132 myRbPrivate.setSelected(true);
133 } else {
134 myRbPrivate.setSelected(true);
136 myIntroduceEnumConstantCb.setEnabled(EnumConstantsUtil.isSuitableForEnumConstant(getSelectedType(), myTargetClass));
137 updateVisibilityPanel();
140 public String getEnteredName() {
141 return myNameField.getEnteredName();
144 private String getTargetClassName() {
145 return myTfTargetClassName.getText().trim();
148 public BaseExpressionToFieldHandler.TargetDestination getDestinationClass () {
149 return myDestinationClass;
152 public boolean introduceEnumConstant() {
153 return myIntroduceEnumConstantCb.isEnabled() && myIntroduceEnumConstantCb.isSelected();
156 @Modifier
157 public String getFieldVisibility() {
158 if (myRbPublic.isSelected()) {
159 return PsiModifier.PUBLIC;
161 if (myRbpackageLocal.isSelected()) {
162 return PsiModifier.PACKAGE_LOCAL;
164 if (myRbProtected.isSelected()) {
165 return PsiModifier.PROTECTED;
167 if (myRbPrivate.isSelected()) {
168 return PsiModifier.PRIVATE;
170 LOG.assertTrue(false);
171 return null;
174 public boolean isReplaceAllOccurrences() {
175 return myOccurrencesCount > 1 && myCbReplaceAll.isSelected();
178 public PsiType getSelectedType() {
179 return myTypeSelector.getSelectedType();
182 protected Action[] createActions() {
183 return new Action[]{getOKAction(), getCancelAction(), getHelpAction()};
186 protected void doHelpAction() {
187 HelpManager.getInstance().invokeHelp(HelpID.INTRODUCE_CONSTANT);
190 protected JComponent createNorthPanel() {
191 myTypeSelector = myTypeSelectorManager.getTypeSelector();
192 myTypePanel.setLayout(new BorderLayout());
193 myTypePanel.add(myTypeSelector.getComponent(), BorderLayout.CENTER);
194 if (myTypeSelector.getFocusableComponent() != null) {
195 myTypeLabel.setLabelFor(myTypeSelector.getFocusableComponent());
198 myNameField = new NameSuggestionsField(myProject);
199 myNameSuggestionPanel.setLayout(new BorderLayout());
201 myNameSuggestionPanel.add(myNameField.getComponent(), BorderLayout.CENTER);
202 myNameSuggestionLabel.setLabelFor(myNameField.getFocusableComponent());
204 Set<String> possibleClassNames = new LinkedHashSet<String>();
205 for (final PsiExpression occurrence : myOccurrences) {
206 final PsiClass parentClass = new IntroduceConstantHandler().getParentClass(occurrence);
207 if (parentClass != null && parentClass.getQualifiedName() != null) {
208 possibleClassNames.add(parentClass.getQualifiedName());
211 myTfTargetClassName =
212 new ReferenceEditorComboWithBrowseButton(new ChooseClassAction(), "", PsiManager.getInstance(myProject), true, RECENTS_KEY);
213 myTargetClassNamePanel.setLayout(new BorderLayout());
214 myTargetClassNamePanel.add(myTfTargetClassName, BorderLayout.CENTER);
215 myTargetClassNameLabel.setLabelFor(myTfTargetClassName);
216 for (String possibleClassName : possibleClassNames) {
217 myTfTargetClassName.prependItem(possibleClassName);
219 myTfTargetClassName.getChildComponent().addDocumentListener(new DocumentAdapter() {
220 public void documentChanged(DocumentEvent e) {
221 targetClassChanged();
224 myIntroduceEnumConstantCb.addActionListener(new ActionListener() {
225 public void actionPerformed(final ActionEvent e) {
226 enableEnumDependant(introduceEnumConstant());
229 enableEnumDependant(introduceEnumConstant());
230 final JPanel enumPanel = new JPanel(new BorderLayout());
231 enumPanel.add(myIntroduceEnumConstantCb, BorderLayout.EAST);
232 myTargetClassNamePanel.add(enumPanel, BorderLayout.SOUTH);
234 final String propertyName;
235 if (myLocalVariable != null) {
236 propertyName = myCodeStyleManager.variableNameToPropertyName(myLocalVariable.getName(), VariableKind.LOCAL_VARIABLE);
238 else {
239 propertyName = null;
241 final NameSuggestionsManager nameSuggestionsManager =
242 new NameSuggestionsManager(myTypeSelector, myNameField, new NameSuggestionsGenerator() {
243 public SuggestedNameInfo getSuggestedNameInfo(PsiType type) {
244 final SuggestedNameInfo nameInfo =
245 myCodeStyleManager.suggestVariableName(VariableKind.STATIC_FINAL_FIELD, propertyName, myInitializerExpression, type);
246 final String[] strings = JavaCompletionUtil.completeVariableNameForRefactoring(myCodeStyleManager, type, VariableKind.LOCAL_VARIABLE, nameInfo);
247 return new SuggestedNameInfo.Delegate(strings, nameInfo);
252 nameSuggestionsManager.setLabelsFor(myTypeLabel, myNameSuggestionLabel);
253 //////////
254 if (myOccurrencesCount > 1) {
255 myCbReplaceAll.addItemListener(new ItemListener() {
256 public void itemStateChanged(ItemEvent e) {
257 updateTypeSelector();
259 myNameField.requestFocusInWindow();
262 myCbReplaceAll.setText(RefactoringBundle.message("replace.all.occurences", myOccurrencesCount));
264 else {
265 myCbReplaceAll.setVisible(false);
268 if (myLocalVariable != null) {
269 if (myInvokedOnDeclaration) {
270 myCbDeleteVariable.setEnabled(false);
271 myCbDeleteVariable.setSelected(true);
273 else if (myCbReplaceAll != null) {
274 updateCbDeleteVariable();
275 myCbReplaceAll.addItemListener(
276 new ItemListener() {
277 public void itemStateChanged(ItemEvent e) {
278 updateCbDeleteVariable();
283 else {
284 myCbDeleteVariable.setVisible(false);
287 final PsiManager psiManager = PsiManager.getInstance(myProject);
288 if (myTypeSelectorManager.isSuggestedType("java.lang.String") &&
289 LanguageLevelProjectExtension.getInstance(psiManager.getProject()).getLanguageLevel().hasEnumKeywordAndAutoboxing() &&
290 JavaPsiFacade.getInstance(psiManager.getProject()).findClass(AnnotationUtil.NON_NLS, myParentClass.getResolveScope()) != null) {
291 final PropertiesComponent component = PropertiesComponent.getInstance(myProject);
292 myCbNonNls.setSelected(component.isTrueValue(NONNLS_SELECTED_PROPERTY));
293 myCbNonNls.addItemListener(new ItemListener() {
294 public void itemStateChanged(ItemEvent e) {
295 component.setValue(NONNLS_SELECTED_PROPERTY, Boolean.toString(myCbNonNls.isSelected()));
298 } else {
299 myCbNonNls.setVisible(false);
302 updateTypeSelector();
304 ButtonGroup bg = new ButtonGroup();
305 bg.add(myRbPrivate);
306 bg.add(myRbpackageLocal);
307 bg.add(myRbProtected);
308 bg.add(myRbPublic);
310 return myPanel;
313 private void targetClassChanged() {
314 final String targetClassName = getTargetClassName();
315 myTargetClass = JavaPsiFacade.getInstance(myProject).findClass(targetClassName, GlobalSearchScope.projectScope(myProject));
316 updateVisibilityPanel();
317 myIntroduceEnumConstantCb.setEnabled(EnumConstantsUtil.isSuitableForEnumConstant(getSelectedType(), myTargetClass));
320 private void enableEnumDependant(boolean enable) {
321 if (enable) {
322 myRbPrivate.setEnabled(false);
323 myRbProtected.setEnabled(false);
324 myRbpackageLocal.setEnabled(false);
325 myRbPublic.setEnabled(true);
326 myRbPublic.setSelected(true);
327 } else {
328 updateVisibilityPanel();
330 myCbNonNls.setEnabled(!enable);
333 protected JComponent createCenterPanel() {
334 return new JPanel();
337 public boolean isDeleteVariable() {
338 return myInvokedOnDeclaration || myCbDeleteVariable != null && myCbDeleteVariable.isSelected();
341 public boolean isAnnotateAsNonNls() {
342 return myCbNonNls != null && myCbNonNls.isSelected();
345 private void updateCbDeleteVariable() {
346 if (!myCbReplaceAll.isSelected()) {
347 myCbDeleteVariable.makeUnselectable(false);
349 else {
350 myCbDeleteVariable.makeSelectable();
354 private void updateTypeSelector() {
355 if (myCbReplaceAll != null) {
356 myTypeSelectorManager.setAllOccurences(myCbReplaceAll.isSelected());
358 else {
359 myTypeSelectorManager.setAllOccurences(false);
363 private void updateVisibilityPanel() {
364 if (myTargetClass == null) return;
365 if (myTargetClass.isInterface()) {
366 myRbPrivate.setEnabled(false);
367 myRbProtected.setEnabled(false);
368 myRbpackageLocal.setEnabled(false);
369 myRbPublic.setEnabled(true);
370 myRbPublic.setSelected(true);
372 else {
373 myRbPrivate.setEnabled(true);
374 myRbProtected.setEnabled(true);
375 myRbpackageLocal.setEnabled(true);
376 myRbPublic.setEnabled(true);
377 // exclude all modifiers not visible from all occurences
378 final Set<String> visible = new THashSet<String>();
379 visible.add(PsiModifier.PRIVATE);
380 visible.add(PsiModifier.PROTECTED);
381 visible.add(PsiModifier.PACKAGE_LOCAL);
382 visible.add(PsiModifier.PUBLIC);
383 for (PsiExpression occurrence : myOccurrences) {
384 final PsiManager psiManager = PsiManager.getInstance(myProject);
385 for (Iterator<String> iterator = visible.iterator(); iterator.hasNext();) {
386 String modifier = iterator.next();
388 try {
389 final String modifierText = PsiModifier.PACKAGE_LOCAL.equals(modifier) ? "" : modifier;
390 final PsiField field = JavaPsiFacade.getInstance(psiManager.getProject()).getElementFactory().createFieldFromText(modifierText + " int xxx;", myTargetClass);
391 if (!JavaResolveUtil.isAccessible(field, myTargetClass, field.getModifierList(), occurrence, myTargetClass, null)) {
392 iterator.remove();
395 catch (IncorrectOperationException e) {
396 LOG.error(e);
400 if (visible.contains(PsiModifier.PUBLIC)) myRbPublic.setSelected(true);
401 if (visible.contains(PsiModifier.PACKAGE_LOCAL)) myRbpackageLocal.setSelected(true);
402 if (visible.contains(PsiModifier.PROTECTED)) myRbProtected.setSelected(true);
403 if (visible.contains(PsiModifier.PRIVATE)) myRbPrivate.setSelected(true);
407 protected void doOKAction() {
408 final String targetClassName = getTargetClassName();
409 PsiClass newClass = myParentClass;
411 if (!"".equals (targetClassName) && !Comparing.strEqual(targetClassName, myParentClass.getQualifiedName())) {
412 newClass = JavaPsiFacade.getInstance(myProject).findClass(targetClassName, GlobalSearchScope.projectScope(myProject));
413 if (newClass == null) {
414 if (Messages.showOkCancelDialog(myProject, RefactoringBundle.message("class.does.not.exist.in.the.project"), IntroduceConstantHandler.REFACTORING_NAME, Messages.getErrorIcon()) != OK_EXIT_CODE) {
415 return;
417 myDestinationClass = new BaseExpressionToFieldHandler.TargetDestination(targetClassName, myParentClass);
418 } else {
419 myDestinationClass = new BaseExpressionToFieldHandler.TargetDestination(newClass);
423 String fieldName = getEnteredName();
424 String errorString = null;
425 if ("".equals(fieldName)) {
426 errorString = RefactoringBundle.message("no.field.name.specified");
427 } else if (!JavaPsiFacade.getInstance(myProject).getNameHelper().isIdentifier(fieldName)) {
428 errorString = RefactoringMessageUtil.getIncorrectIdentifierMessage(fieldName);
430 if (errorString != null) {
431 CommonRefactoringUtil.showErrorMessage(
432 IntroduceFieldHandler.REFACTORING_NAME,
433 errorString,
434 HelpID.INTRODUCE_FIELD,
435 myProject);
436 return;
438 if (newClass != null) {
439 PsiField oldField = newClass.findFieldByName(fieldName, true);
441 if (oldField != null) {
442 int answer = Messages.showYesNoDialog(
443 myProject,
444 RefactoringBundle.message("field.exists", fieldName, oldField.getContainingClass().getQualifiedName()),
445 IntroduceFieldHandler.REFACTORING_NAME,
446 Messages.getWarningIcon()
448 if (answer != 0) {
449 return;
454 JavaRefactoringSettings.getInstance().INTRODUCE_CONSTANT_VISIBILITY = getFieldVisibility();
456 RecentsManager.getInstance(myProject).registerRecentEntry(RECENTS_KEY, targetClassName);
457 super.doOKAction();
460 public JComponent getPreferredFocusedComponent() {
461 return myNameField.getFocusableComponent();
464 private class ChooseClassAction implements ActionListener {
465 public void actionPerformed(ActionEvent e) {
466 TreeClassChooser chooser = TreeClassChooserFactory.getInstance(myProject).createWithInnerClassesScopeChooser(RefactoringBundle.message("choose.destination.class"), GlobalSearchScope.projectScope(myProject), new TreeClassChooser.ClassFilter() {
467 public boolean isAccepted(PsiClass aClass) {
468 return aClass.getParent() instanceof PsiJavaFile || aClass.hasModifierProperty(PsiModifier.STATIC);
470 }, null);
471 if (myTargetClass != null) {
472 chooser.selectDirectory(myTargetClass.getContainingFile().getContainingDirectory());
474 chooser.showDialog();
475 PsiClass aClass = chooser.getSelectedClass();
476 if (aClass != null) {
477 myTfTargetClassName.setText(aClass.getQualifiedName());