From 34cecc05ca598ee8e51296a5d9da3b8906fe449b Mon Sep 17 00:00:00 2001 From: anna Date: Tue, 24 May 2011 21:25:40 +0400 Subject: [PATCH] inplace introduce api extracted --- .../intention/impl/TypeExpression.java | 4 + .../introduceField/InplaceCombosUtil.java | 103 ++++ .../InplaceIntroduceConstantPopup.java | 545 +++++------------- .../InplaceIntroduceFieldPopup.java | 349 ++++------- .../IntroduceConstantHandler.java | 3 +- .../introduceField/IntroduceFieldHandler.java | 7 +- .../IntroduceFieldPopupPanel.java | 6 +- .../AbstractInplaceIntroducer.java | 269 +++++---- .../AbstractInplaceVariableIntroducer.java | 190 ++++++ .../AbstractJavaInplaceIntroducer.java | 156 +++++ .../InplaceIntroduceParameterPopup.java | 495 ++++------------ .../InplaceIntroduceParameterUI.java | 202 +++++++ .../IntroduceParameterHandler.java | 3 +- .../VisibilityListener.java | 85 +++ .../introduceVariable/FinalListener.java | 55 ++ .../IntroduceVariableBase.java | 4 +- .../VariableInplaceIntroducer.java | 334 +++-------- .../inplaceIntroduceField/escapePosition.java | 6 + .../escapePositionOnLocal.java | 5 + .../escapePositionOnLocal_after.java | 6 + .../escapePosition_after.java | 7 + .../InplaceIntroduceFieldTest.java | 41 +- .../inplace/VariableInplaceRenamer.java | 20 +- 23 files changed, 1488 insertions(+), 1407 deletions(-) create mode 100644 java/java-impl/src/com/intellij/refactoring/introduceField/InplaceCombosUtil.java create mode 100644 java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractInplaceVariableIntroducer.java create mode 100644 java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractJavaInplaceIntroducer.java create mode 100644 java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterUI.java create mode 100644 java/java-impl/src/com/intellij/refactoring/introduceParameter/VisibilityListener.java create mode 100644 java/java-impl/src/com/intellij/refactoring/introduceVariable/FinalListener.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceField/escapePosition.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceField/escapePositionOnLocal.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceField/escapePositionOnLocal_after.java create mode 100644 java/java-tests/testData/refactoring/inplaceIntroduceField/escapePosition_after.java diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/TypeExpression.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/TypeExpression.java index d5d396b9b733..a7814b6a718c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/TypeExpression.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/TypeExpression.java @@ -73,4 +73,8 @@ public class TypeExpression extends Expression { return result.toArray(new LookupElement[result.size()]); } + public boolean hasSuggestions() { + return myItems.size() > 1; + } + } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceCombosUtil.java b/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceCombosUtil.java new file mode 100644 index 000000000000..7fe38f3f34dc --- /dev/null +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceCombosUtil.java @@ -0,0 +1,103 @@ +package com.intellij.refactoring.introduceField; + +import com.intellij.ide.ui.ListCellRendererWrapper; +import com.intellij.ide.ui.UISettings; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.wm.ToolWindowManager; +import com.intellij.psi.PsiBundle; +import com.intellij.psi.PsiModifier; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; + +/** + * User: anna + */ +public class InplaceCombosUtil { + public static JComboBox createVisibilityCombo(final JPanel left, + final GridBagConstraints lgc, + final Project project, + @NotNull final String initialVisibility) { + + final JLabel label = new JLabel("Visibility:"); + label.setDisplayedMnemonic('V'); + left.add(label, lgc); + final JComboBox visibilityCombo = new JComboBox(new String[]{PsiModifier.PUBLIC, PsiModifier.PACKAGE_LOCAL, PsiModifier.PROTECTED, PsiModifier.PRIVATE}); + visibilityCombo.setRenderer(new ListCellRendererWrapper(visibilityCombo.getRenderer()) { + @Override + public void customize(JList list, String value, int index, boolean selected, boolean hasFocus) { + if (value == null) return; + setText(PsiBundle.visibilityPresentation(value)); + } + }); + label.setLabelFor(visibilityCombo); + visibilityCombo.setSelectedItem(initialVisibility); + + appendActions(visibilityCombo, project); + lgc.gridx++; + lgc.insets.top = 2; + lgc.insets.left = 2; + left.add(visibilityCombo, lgc); + return visibilityCombo; + } + + public static void appendActions(final JComboBox comboBox, final Project project) { + final boolean toggleStrategy = !UIUtil.isUnderAquaLookAndFeel(); + final boolean[] moveFocusBack = new boolean[] {true}; + comboBox.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + if (!moveFocusBack[0]) { + moveFocusBack[0] = true; + return; + } + + if (toggleStrategy) { + final int size = comboBox.getModel().getSize(); + int next = comboBox.getSelectedIndex() + 1; + if (next < 0 || next >= size) { + if (!UISettings.getInstance().CYCLE_SCROLLING) { + return; + } + next = (next + size) % size; + } + comboBox.setSelectedIndex(next); + ToolWindowManager.getInstance(project).activateEditorComponent(); + } + else { + JBPopupFactory popupFactory = JBPopupFactory.getInstance(); + boolean fromTheSameBalloon = popupFactory.getParentBalloonFor(e.getComponent()) == popupFactory.getParentBalloonFor(e.getOppositeComponent()); + if (!fromTheSameBalloon) { + comboBox.showPopup(); + } + } + } + }); + comboBox.addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + moveFocusBack[0] = false; + } + }); + comboBox.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + moveFocusBack[0] = true; + if (!toggleStrategy && e.getKeyCode() == KeyEvent.VK_ESCAPE && e.getModifiers() == 0) { + ToolWindowManager.getInstance(project).activateEditorComponent(); + } + } + }); + comboBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + moveFocusBack[0] = true; + ToolWindowManager.getInstance(project).activateEditorComponent(); + } + }); + } +} diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceConstantPopup.java b/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceConstantPopup.java index 00297ce6e6db..7a2a9a1ddd4b 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceConstantPopup.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceConstantPopup.java @@ -16,77 +16,49 @@ package com.intellij.refactoring.introduceField; import com.intellij.codeInsight.AnnotationUtil; -import com.intellij.codeInsight.intention.impl.TypeExpression; -import com.intellij.codeInsight.template.impl.TemplateManagerImpl; -import com.intellij.codeInsight.template.impl.TemplateState; -import com.intellij.ide.ui.ListCellRendererWrapper; -import com.intellij.ide.ui.UISettings; import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.application.Result; +import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; -import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.LanguageLevelProjectExtension; -import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.Computable; -import com.intellij.openapi.util.Ref; -import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.codeStyle.VariableKind; -import com.intellij.psi.impl.source.PostprocessReformattingAspect; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.refactoring.JavaRefactoringSettings; -import com.intellij.refactoring.introduceParameter.AbstractInplaceIntroducer; +import com.intellij.refactoring.introduceParameter.AbstractJavaInplaceIntroducer; +import com.intellij.refactoring.introduceParameter.VisibilityListener; import com.intellij.refactoring.move.moveMembers.MoveMembersImpl; -import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer; import com.intellij.refactoring.ui.TypeSelectorManagerImpl; import com.intellij.refactoring.util.occurences.OccurenceManager; import com.intellij.ui.StateRestoringCheckBox; -import com.intellij.ui.TitlePanel; -import com.intellij.util.ArrayUtil; -import com.intellij.util.ui.UIUtil; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; -import java.awt.event.*; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedHashSet; -import java.util.List; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; /** * User: anna * Date: 3/18/11 */ -public class InplaceIntroduceConstantPopup { - private final Project myProject; - private final PsiClass myParentClass; - private PsiExpression myExpr; - private final PsiLocalVariable myLocalVariable; - private final PsiExpression[] myOccurrences; - private TypeSelectorManagerImpl myTypeSelectorManager; +public class InplaceIntroduceConstantPopup extends AbstractJavaInplaceIntroducer { private PsiElement myAnchorElement; private int myAnchorIdx = -1; private PsiElement myAnchorElementIfAll; private int myAnchorIdxIfAll = -1; private final OccurenceManager myOccurenceManager; - private Editor myEditor; - private String myConstantName; - private List myOccurrenceMarkers; - private final String myExprText; private final String myInitializerText; - private final String myLocalName; - private RangeMarker myExprMarker; - private boolean myInitListeners = false; + private JCheckBox myReplaceAllCb; private JCheckBox myAnnotateNonNls; private StateRestoringCheckBox myCbDeleteVariable; @@ -96,6 +68,7 @@ public class InplaceIntroduceConstantPopup { private JComboBox myVisibilityCombo; private JPanel myWholePanel; + private final PsiClass myParentClass; public InplaceIntroduceConstantPopup(Project project, Editor editor, @@ -106,12 +79,8 @@ public class InplaceIntroduceConstantPopup { TypeSelectorManagerImpl typeSelectorManager, PsiElement anchorElement, PsiElement anchorElementIfAll, OccurenceManager occurenceManager) { - myProject = project; - myEditor = editor; + super(project, editor, expr, localVariable, occurrences, typeSelectorManager.getDefaultType(), typeSelectorManager, IntroduceConstantHandler.REFACTORING_NAME); myParentClass = parentClass; - myExpr = expr; - myLocalVariable = localVariable; - myOccurrences = occurrences; myTypeSelectorManager = typeSelectorManager; myAnchorElement = anchorElement; myAnchorElementIfAll = anchorElementIfAll; @@ -127,13 +96,12 @@ public class InplaceIntroduceConstantPopup { } myOccurenceManager = occurenceManager; - myExprMarker = expr != null && expr.isPhysical() ? myEditor.getDocument().createRangeMarker(expr.getTextRange()) : null; - myExprText = expr != null ? expr.getText() : null; myInitializerText = getExprText(expr, localVariable); - myLocalName = localVariable != null ? localVariable.getName() : null; + myWholePanel = new JPanel(new GridBagLayout()); - GridBagConstraints gc = new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0 , 0, 0), 0, 0); + GridBagConstraints gc = + new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0); gc.gridwidth = 1; gc.gridy = 1; @@ -142,7 +110,6 @@ public class InplaceIntroduceConstantPopup { gc.gridx = 1; gc.insets.left = 6; myWholePanel.add(createRightPanel(), gc); - } @Nullable @@ -159,7 +126,9 @@ public class InplaceIntroduceConstantPopup { private JPanel createRightPanel() { final JPanel right = new JPanel(new GridBagLayout()); - final GridBagConstraints rgc = new GridBagConstraints(0, GridBagConstraints.RELATIVE,1,1,0,0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(1,0,0,0), 0, 0); + final GridBagConstraints rgc = + new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, + new Insets(1, 0, 0, 0), 0, 0); myReplaceAllCb = new JCheckBox("Replace all occurrences"); myReplaceAllCb.setMnemonic('a'); myReplaceAllCb.setFocusable(false); @@ -176,7 +145,8 @@ public class InplaceIntroduceConstantPopup { myCbDeleteVariable.setSelected(true); myCbDeleteVariable.setEnabled(false); } - } else { + } + else { myCbDeleteVariable.setVisible(false); } right.add(myCbDeleteVariable, rgc); @@ -185,7 +155,7 @@ public class InplaceIntroduceConstantPopup { myAnnotateNonNls.setMnemonic('f'); myAnnotateNonNls.setFocusable(false); if ((myTypeSelectorManager.isSuggestedType("java.lang.String") || (myLocalVariable != null && AnnotationUtil - .isAnnotated(myLocalVariable, AnnotationUtil.NON_NLS, false)))&& + .isAnnotated(myLocalVariable, AnnotationUtil.NON_NLS, false))) && LanguageLevelProjectExtension.getInstance(myProject).getLanguageLevel().hasEnumKeywordAndAutoboxing() && JavaPsiFacade.getInstance(myProject).findClass(AnnotationUtil.NON_NLS, myParentClass.getResolveScope()) != null) { final PropertiesComponent component = PropertiesComponent.getInstance(myProject); @@ -195,7 +165,8 @@ public class InplaceIntroduceConstantPopup { component.setValue(IntroduceConstantDialog.NONNLS_SELECTED_PROPERTY, Boolean.toString(myAnnotateNonNls.isSelected())); } }); - } else { + } + else { myAnnotateNonNls.setVisible(false); } right.add(myAnnotateNonNls, rgc); @@ -208,156 +179,38 @@ public class InplaceIntroduceConstantPopup { if (initialVisibility == null) { initialVisibility = PsiModifier.PUBLIC; } - myVisibilityCombo = createVisibilityCombo(left, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0, 0, GridBagConstraints.NORTHEAST, GridBagConstraints.NONE, new Insets(6,5,0,0), 0, 0), - myProject, initialVisibility); + myVisibilityCombo = InplaceCombosUtil.createVisibilityCombo(left, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0, 0, + GridBagConstraints.NORTHEAST, + GridBagConstraints.NONE, + new Insets(6, 5, 0, 0), 0, 0), + myProject, initialVisibility); myMoveToAnotherClassCb = new JCheckBox("Move to another class"); myMoveToAnotherClassCb.setMnemonic('m'); myMoveToAnotherClassCb.setFocusable(false); - left.add(myMoveToAnotherClassCb, new GridBagConstraints(0, 1, 2, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); + left.add(myMoveToAnotherClassCb, + new GridBagConstraints(0, 1, 2, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), + 0, 0)); return left; } - public static JComboBox createVisibilityCombo(final JPanel left, - final GridBagConstraints lgc, - final Project project, - @NotNull final String initialVisibility) { - final JLabel label = new JLabel("Visibility:"); - label.setDisplayedMnemonic('V'); - left.add(label, lgc); - final JComboBox visibilityCombo = new JComboBox(new String[]{PsiModifier.PUBLIC, PsiModifier.PACKAGE_LOCAL, PsiModifier.PROTECTED, PsiModifier.PRIVATE}); - visibilityCombo.setRenderer(new ListCellRendererWrapper(visibilityCombo.getRenderer()) { - @Override - public void customize(JList list, String value, int index, boolean selected, boolean hasFocus) { - if (value == null) return; - setText(PsiBundle.visibilityPresentation(value)); - } - }); - label.setLabelFor(visibilityCombo); - visibilityCombo.setSelectedItem(initialVisibility); - - appendActions(visibilityCombo, project); - lgc.gridx++; - lgc.insets.top = 2; - lgc.insets.left = 2; - left.add(visibilityCombo, lgc); - return visibilityCombo; + private String getSelectedVisibility() { + return (String)myVisibilityCombo.getSelectedItem(); } - public static void appendActions(final JComboBox comboBox, final Project project) { - final boolean toggleStrategy = !UIUtil.isUnderAquaLookAndFeel(); - final boolean[] moveFocusBack = new boolean[] {true}; - comboBox.addFocusListener(new FocusAdapter() { - @Override - public void focusGained(FocusEvent e) { - if (!moveFocusBack[0]) { - moveFocusBack[0] = true; - return; - } - if (toggleStrategy) { - final int size = comboBox.getModel().getSize(); - int next = comboBox.getSelectedIndex() + 1; - if (next < 0 || next >= size) { - if (!UISettings.getInstance().CYCLE_SCROLLING) { - return; - } - next = (next + size) % size; - } - comboBox.setSelectedIndex(next); - ToolWindowManager.getInstance(project).activateEditorComponent(); - } - else { - JBPopupFactory popupFactory = JBPopupFactory.getInstance(); - boolean fromTheSameBalloon = popupFactory.getParentBalloonFor(e.getComponent()) == popupFactory.getParentBalloonFor(e.getOppositeComponent()); - if (!fromTheSameBalloon) { - comboBox.showPopup(); - } - } - } - }); - comboBox.addMouseListener(new MouseAdapter() { - @Override - public void mouseEntered(MouseEvent e) { - moveFocusBack[0] = false; - } - }); - comboBox.addKeyListener(new KeyAdapter() { - @Override - public void keyPressed(KeyEvent e) { - moveFocusBack[0] = true; - if (!toggleStrategy && e.getKeyCode() == KeyEvent.VK_ESCAPE && e.getModifiers() == 0) { - ToolWindowManager.getInstance(project).activateEditorComponent(); - } - } - }); - comboBox.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - moveFocusBack[0] = true; - ToolWindowManager.getInstance(project).activateEditorComponent(); - } - }); - } + private RangeMarker myFieldRangeStart; - public boolean performInplaceIntroduce() { - return startIntroduceTemplate(false, null); - } - private boolean startIntroduceTemplate(final boolean replaceAllOccurrences, @Nullable final PsiType fieldDefaultType) { - final Ref result = new Ref(); - CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { - public void run() { - myTypeSelectorManager.setAllOccurences(replaceAllOccurrences); - PsiType defaultType = myTypeSelectorManager.getTypeSelector().getSelectedType(); - if (fieldDefaultType != null) { - if (replaceAllOccurrences) { - if (ArrayUtil.find(myTypeSelectorManager.getTypesForAll(), fieldDefaultType) != -1) { - defaultType = fieldDefaultType; - } - } - else if (ArrayUtil.find(myTypeSelectorManager.getTypesForOne(), fieldDefaultType) != -1) { - defaultType = fieldDefaultType; - } - } - final String propName = myLocalVariable != null ? JavaCodeStyleManager - .getInstance(myProject).variableNameToPropertyName(myLocalVariable.getName(), VariableKind.LOCAL_VARIABLE) : null; - final String[] names = - IntroduceConstantDialog.createNameSuggestionGenerator(propName, myExpr, JavaCodeStyleManager.getInstance(myProject)) - .getSuggestedNameInfo(defaultType).names; - final PsiField field = createFieldToStartTemplateOn(names, defaultType); - boolean started = false; - if (field != null) { - myEditor.getCaretModel().moveToOffset(field.getTextOffset()); - myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); - final LinkedHashSet nameSuggestions = new LinkedHashSet(); - nameSuggestions.add(field.getName()); - nameSuggestions.addAll(Arrays.asList(names)); - final VariableInplaceRenamer renamer = new FieldInplaceIntroducer(field); - started = renamer.performInplaceRename(false, nameSuggestions); - } - result.set(started); - if (!started && field != null) { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - field.delete(); - } - }); - } - } - }, IntroduceConstantHandler.REFACTORING_NAME, IntroduceConstantHandler.REFACTORING_NAME); - return result.get(); - } - - private PsiField createFieldToStartTemplateOn(final String[] names, final PsiType psiType) { + @Override + protected PsiVariable createFieldToStartTemplateOn(final String[] names, final PsiType psiType) { final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); return ApplicationManager.getApplication().runWriteAction(new Computable() { @Override public PsiField compute() { PsiField field = elementFactory.createFieldFromText( - psiType.getCanonicalText() + " " + (myConstantName != null ? myConstantName : names[0]) + " = " + myInitializerText + ";", + psiType.getCanonicalText() + " " + (getInputName() != null ? getInputName() : names[0]) + " = " + myInitializerText + ";", myParentClass); PsiUtil.setModifierProperty(field, PsiModifier.FINAL, true); PsiUtil.setModifierProperty(field, PsiModifier.STATIC, true); @@ -365,243 +218,137 @@ public class InplaceIntroduceConstantPopup { if (visibility != null) { PsiUtil.setModifierProperty(field, visibility, true); } - return BaseExpressionToFieldHandler.ConvertToFieldRunnable + field = BaseExpressionToFieldHandler.ConvertToFieldRunnable .appendField(myExpr, BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION, myParentClass, myParentClass, myAnchorElementIfAll, field); + myFieldRangeStart = myEditor.getDocument().createRangeMarker(field.getTextRange()); + return field; } }); } - private String getSelectedVisibility() { - return (String)myVisibilityCombo.getSelectedItem(); + @Override + protected String[] suggestNames(PsiType defaultType, String propName) { + return IntroduceConstantDialog.createNameSuggestionGenerator(propName, myExpr, JavaCodeStyleManager.getInstance(myProject)) + .getSuggestedNameInfo(defaultType).names; } - public List getOccurrenceMarkers() { - if (myOccurrenceMarkers == null) { - myOccurrenceMarkers = new ArrayList(); - for (PsiExpression occurrence : myOccurrences) { - myOccurrenceMarkers.add(myEditor.getDocument().createRangeMarker(occurrence.getTextRange())); - } - } - return myOccurrenceMarkers; + @Override + protected boolean isReplaceAllOccurrences() { + return myReplaceAllCb.isSelected(); } - private void updateCbDeleteVariable() { - if (!myReplaceAllCb.isSelected()) { - myCbDeleteVariable.makeUnselectable(false); - } - else { - myCbDeleteVariable.makeSelectable(); - } + @Override + protected PsiElement checkLocalScope() { + return myParentClass; } - private class FieldInplaceIntroducer extends AbstractInplaceIntroducer { - private RangeMarker myFieldRangeStart; + @Override + protected void saveSettings(PsiVariable psiVariable) { + super.saveSettings(psiVariable); + JavaRefactoringSettings.getInstance().INTRODUCE_CONSTANT_VISIBILITY = getSelectedVisibility(); + } - - private SmartTypePointer myDefaultParameterTypePointer; - - private SmartTypePointer myFieldTypePointer; - - public FieldInplaceIntroducer(PsiField field) { - super(myProject, new TypeExpression(myProject, myReplaceAllCb.isSelected() ? myTypeSelectorManager.getTypesForAll() : myTypeSelectorManager.getTypesForOne()), - myEditor, field, false, - myTypeSelectorManager.getTypesForAll().length > 1, - myExpr != null && myExpr.isPhysical() ? myEditor.getDocument().createRangeMarker(myExpr.getTextRange()) : null, InplaceIntroduceConstantPopup.this.getOccurrenceMarkers(), - IntroduceConstantHandler.REFACTORING_NAME, IntroduceConstantHandler.REFACTORING_NAME); - - myDefaultParameterTypePointer = - SmartTypePointerManager.getInstance(myProject).createSmartTypePointer(myTypeSelectorManager.getDefaultType()); - myFieldRangeStart = myEditor.getDocument().createRangeMarker(field.getTextRange()); + @Override + protected PsiVariable getVariable() { + PsiElement element = myParentClass.getContainingFile().findElementAt(myFieldRangeStart.getStartOffset()); + if (element instanceof PsiWhiteSpace) { + element = PsiTreeUtil.skipSiblingsForward(element, PsiWhiteSpace.class); } + return PsiTreeUtil.getParentOfType(element, PsiField.class, false); + } - @Override - protected boolean isReplaceAllOccurrences() { - return myReplaceAllCb.isSelected(); - } - - @Override - protected PsiExpression getExpr() { - return myExpr != null && myExpr.isValid() && myExpr.isPhysical() ? myExpr : null; - } - - @Override - protected PsiExpression[] getOccurrences() { - return myOccurrences; - } - - @Override - protected List getOccurrenceMarkers() { - return InplaceIntroduceConstantPopup.this.getOccurrenceMarkers(); - } - - @Override - protected PsiElement checkLocalScope() { - return myParentClass; - } - - @Override - public RangeMarker getExprMarker() { - return myExprMarker; - } - - @Override - protected void saveSettings(PsiVariable psiVariable) { - TypeSelectorManagerImpl.typeSelected(psiVariable.getType(), myDefaultParameterTypePointer.getType()); - JavaRefactoringSettings.getInstance().INTRODUCE_CONSTANT_VISIBILITY = getSelectedVisibility(); - } - - @Override - protected PsiVariable getVariable() { - PsiElement element = myParentClass.getContainingFile().findElementAt(myFieldRangeStart.getStartOffset()); - if (element instanceof PsiWhiteSpace) { - element = PsiTreeUtil.skipSiblingsForward(element, PsiWhiteSpace.class); - } - return PsiTreeUtil.getParentOfType(element, PsiField.class, false); - } - - @Override - protected void moveOffsetAfter(boolean success) { - if (success) { - if (myLocalVariable == null && myExpr == null || myConstantName == null) { - super.moveOffsetAfter(false); - return; - } - final BaseExpressionToFieldHandler.Settings settings = - new BaseExpressionToFieldHandler.Settings(myConstantName, - isReplaceAllOccurrences(), true, - true, - BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION, - getSelectedVisibility(), myLocalVariable, - myFieldTypePointer.getType(), - isDeleteVariable(), - myParentClass, isAnnotateNonNls(), false); - final Runnable runnable = new Runnable() { - public void run() { - if (myLocalVariable != null) { - final LocalToFieldHandler.IntroduceFieldRunnable fieldRunnable = - new LocalToFieldHandler.IntroduceFieldRunnable(false, myLocalVariable, myParentClass, settings, true, myOccurrences); - fieldRunnable.run(); - } - else { - final BaseExpressionToFieldHandler.ConvertToFieldRunnable convertToFieldRunnable = - new BaseExpressionToFieldHandler.ConvertToFieldRunnable(myExpr, settings, settings.getForcedType(), - myOccurrences, myOccurenceManager, - myAnchorElementIfAll, myAnchorElement, myEditor, myParentClass); - convertToFieldRunnable.run(); - } - } - }; - ApplicationManager.getApplication().runWriteAction(runnable); - } - super.moveOffsetAfter(success); - if (myLocalVariable != null && myLocalVariable.isValid()) { - myEditor.getCaretModel().moveToOffset(myLocalVariable.getTextOffset()); - myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); - } - if (myMoveToAnotherClassCb.isSelected()) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - MoveMembersImpl.doMove(myProject, new PsiElement[]{myParentClass.findFieldByName(myConstantName, false)}, null, null); - } - }); - } - } - - @Override - public void finish() { - super.finish(); - final PsiField psiField = (PsiField)getVariable(); - if (psiField == null) { - return; - } - myFieldTypePointer = SmartTypePointerManager.getInstance(myProject).createSmartTypePointer(psiField.getType()); - PsiDocumentManager.getInstance(myProject).commitAllDocuments(); - myConstantName = psiField.getName(); - - ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + protected void performPostIntroduceTasks() { + if (myMoveToAnotherClassCb.isSelected()) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override public void run() { - final PsiFile containingFile = myParentClass.getContainingFile(); - final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); - final RangeMarker exprMarker = getExprMarker(); - if (exprMarker != null) { - myExpr = restoreExpression(containingFile, psiField, elementFactory, exprMarker, myExprText); - if (myExpr != null && myExpr.isPhysical()) { - myExprMarker = myEditor.getDocument().createRangeMarker(myExpr.getTextRange()); - } - } - final List occurrenceMarkers = getOccurrenceMarkers(); - for (int i = 0, occurrenceMarkersSize = occurrenceMarkers.size(); i < occurrenceMarkersSize; i++) { - RangeMarker marker = occurrenceMarkers.get(i); - if (getExprMarker() != null && marker.getStartOffset() == getExprMarker().getStartOffset()) { - myOccurrences[i] = myExpr; - continue; - } - final PsiExpression psiExpression = - restoreExpression(containingFile, psiField, elementFactory, marker, myLocalVariable != null ? myLocalName : myExprText); - if (psiExpression != null) { - myOccurrences[i] = psiExpression; - } - } - - if (myAnchorIdxIfAll != -1 && myOccurrences[myAnchorIdxIfAll] != null) { - myAnchorElementIfAll = myOccurrences[myAnchorIdxIfAll].getParent(); - } - - if (myAnchorIdx != -1 && myOccurrences[myAnchorIdx] != null) { - myAnchorElement = myOccurrences[myAnchorIdx].getParent(); - } - myOccurrenceMarkers = null; - if (psiField.isValid()) { - psiField.delete(); - } + MoveMembersImpl.doMove(myProject, new PsiElement[]{myParentClass.findFieldByName(getInputName(), false)}, null, null); } }); } + } - @Override - protected JComponent getComponent() { - if (!myInitListeners) { - myInitListeners = true; - final VisibilityListener visibilityListener = new VisibilityListener(myProject, IntroduceConstantHandler.REFACTORING_NAME, myEditor) { - @Override - protected String getVisibility() { - return getSelectedVisibility(); - } - }; - myVisibilityCombo.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - visibilityListener.stateChanged(null); - } - }); - myReplaceAllCb.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - Runnable restartTemplateRunnable = new Runnable() { - public void run() { - final TemplateState templateState = TemplateManagerImpl.getTemplateState(myEditor); - if (templateState != null) { - templateState.gotoEnd(true); - myTypeSelectorManager = new TypeSelectorManagerImpl(myProject, myDefaultParameterTypePointer.getType(), null, myExpr, myOccurrences); - startIntroduceTemplate(isReplaceAllOccurrences(), myFieldTypePointer.getType()); - } - } - }; - CommandProcessor.getInstance().executeCommand(myProject, restartTemplateRunnable, IntroduceConstantHandler.REFACTORING_NAME, IntroduceConstantHandler.REFACTORING_NAME); - } - }); - - myAnnotateNonNls.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - //todo it is unresolved; import here is not a good idea new FinalListener(myProject).perform(myAnnotateNonNls.isSelected(), "@NonNls"); - } - }); + @Override + protected void performIntroduce() { + final BaseExpressionToFieldHandler.Settings settings = + new BaseExpressionToFieldHandler.Settings(getInputName(), + isReplaceAllOccurrences(), true, + true, + BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION, + getSelectedVisibility(), (PsiLocalVariable)myLocalVariable, + myTypePointer.getType(), + isDeleteVariable(), + myParentClass, isAnnotateNonNls(), false); + new WriteCommandAction(myProject, getCommandName(), getCommandName()) { + @Override + protected void run(Result result) throws Throwable { + if (myLocalVariable != null) { + final LocalToFieldHandler.IntroduceFieldRunnable fieldRunnable = + new LocalToFieldHandler.IntroduceFieldRunnable(false, (PsiLocalVariable)myLocalVariable, myParentClass, settings, true, myOccurrences); + fieldRunnable.run(); + } + else { + final BaseExpressionToFieldHandler.ConvertToFieldRunnable convertToFieldRunnable = + new BaseExpressionToFieldHandler.ConvertToFieldRunnable(myExpr, settings, settings.getForcedType(), + myOccurrences, myOccurenceManager, + myAnchorElementIfAll, myAnchorElement, myEditor, myParentClass); + convertToFieldRunnable.run(); + } } - return myWholePanel; + }.execute(); + } + + @Override + protected void restoreAnchors() { + if (myAnchorIdxIfAll != -1 && myOccurrences[myAnchorIdxIfAll] != null) { + myAnchorElementIfAll = myOccurrences[myAnchorIdxIfAll].getParent(); } + + if (myAnchorIdx != -1 && myOccurrences[myAnchorIdx] != null) { + myAnchorElement = myOccurrences[myAnchorIdx].getParent(); + } + } + + @Override + protected JComponent getComponent() { + final VisibilityListener visibilityListener = new VisibilityListener(myEditor) { + @Override + protected String getVisibility() { + return getSelectedVisibility(); + } + }; + myVisibilityCombo.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + new WriteCommandAction(myProject, IntroduceConstantHandler.REFACTORING_NAME, IntroduceConstantHandler.REFACTORING_NAME) { + @Override + protected void run(Result result) throws Throwable { + PsiDocumentManager.getInstance(myProject).commitDocument(myEditor.getDocument()); + visibilityListener.perform(getVariable()); + } + }.execute(); + } + }); + myReplaceAllCb.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + restartTemplate(); + } + }); + + myAnnotateNonNls.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + //todo it is unresolved; import here is not a good idea new FinalListener(myProject).perform(myAnnotateNonNls.isSelected(), "@NonNls"); + } + }); + return myWholePanel; + } + + public String getCommandName() { + return IntroduceConstantHandler.REFACTORING_NAME; } private boolean isAnnotateNonNls() { diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceFieldPopup.java b/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceFieldPopup.java index 77b1c27dca0a..4e97763826dd 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceFieldPopup.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceFieldPopup.java @@ -15,73 +15,52 @@ */ package com.intellij.refactoring.introduceField; -import com.intellij.codeInsight.CodeInsightBundle; -import com.intellij.codeInsight.intention.impl.TypeExpression; -import com.intellij.codeInsight.template.impl.TemplateManagerImpl; -import com.intellij.codeInsight.template.impl.TemplateState; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.Result; -import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; -import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; -import com.intellij.openapi.util.Ref; import com.intellij.psi.*; -import com.intellij.psi.codeStyle.SuggestedNameInfo; -import com.intellij.psi.impl.source.PostprocessReformattingAspect; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.refactoring.JavaRefactoringSettings; -import com.intellij.refactoring.introduceParameter.AbstractInplaceIntroducer; -import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer; +import com.intellij.refactoring.introduceParameter.AbstractJavaInplaceIntroducer; +import com.intellij.refactoring.introduceParameter.VisibilityListener; +import com.intellij.refactoring.introduceVariable.FinalListener; import com.intellij.refactoring.ui.TypeSelectorManagerImpl; import com.intellij.refactoring.util.occurences.OccurenceManager; -import com.intellij.util.ArrayUtil; -import org.jetbrains.annotations.Nullable; import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; import java.awt.*; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedHashSet; -import java.util.List; /** * User: anna * Date: 3/15/11 */ -public class InplaceIntroduceFieldPopup { +public class InplaceIntroduceFieldPopup extends AbstractJavaInplaceIntroducer { private PsiLocalVariable myLocalVariable; private PsiClass myParentClass; private boolean myStatic; - private PsiExpression[] myOccurrences; - private PsiExpression myInitializerExpression; private final Editor myEditor; private Project myProject; - private TypeSelectorManagerImpl myTypeSelectorManager; - private final PsiElement myAnchorElement; + private PsiElement myAnchorElement; private int myAnchorIdx = -1; - private final PsiElement myAnchorElementIfAll; + private PsiElement myAnchorElementIfAll; private int myAnchorIdxIfAll = -1; private final OccurenceManager myOccurenceManager; - private List myOccurrenceMarkers; private final IntroduceFieldCentralPanel myIntroduceFieldPanel; private JPanel myWholePanel; - private String myExprText; - private String myLocalName; - private RangeMarker myExprMarker; - private String myFieldName; - private boolean myInitListeners = false; static BaseExpressionToFieldHandler.InitializationPlace ourLastInitializerPlace; public InplaceIntroduceFieldPopup(PsiLocalVariable localVariable, @@ -94,16 +73,13 @@ public class InplaceIntroduceFieldPopup { final boolean allowInitInMethod, boolean allowInitInMethodIfAll, final PsiElement anchorElement, final PsiElement anchorElementIfAll, - final OccurenceManager occurenceManager) { + final OccurenceManager occurenceManager, Project project) { + super(project, editor, initializerExpression, localVariable, occurrences, typeSelectorManager.getDefaultType(), typeSelectorManager, + IntroduceFieldHandler.REFACTORING_NAME); myLocalVariable = localVariable; myParentClass = parentClass; myStatic = aStatic; myOccurrences = occurrences; - myInitializerExpression = initializerExpression; - myExprText = myInitializerExpression != null ? myInitializerExpression.getText() : null; - myLocalName = localVariable != null ? localVariable.getName() : null; - myExprMarker = myInitializerExpression != null && myInitializerExpression.isPhysical() ? editor.getDocument().createRangeMarker(myInitializerExpression.getTextRange()) : null; - myTypeSelectorManager = typeSelectorManager; myAnchorElement = anchorElement; myAnchorElementIfAll = anchorElementIfAll; for (int i = 0, occurrencesLength = occurrences.length; i < occurrencesLength; i++) { @@ -117,7 +93,7 @@ public class InplaceIntroduceFieldPopup { } } myOccurenceManager = occurenceManager; - myProject = myLocalVariable != null ? myLocalVariable.getProject() : myInitializerExpression.getProject(); + myProject = myLocalVariable != null ? myLocalVariable.getProject() : initializerExpression.getProject(); myEditor = editor; myIntroduceFieldPanel = @@ -141,85 +117,31 @@ public class InplaceIntroduceFieldPopup { } - public List getOccurrenceMarkers() { - if (myOccurrenceMarkers == null) { - myOccurrenceMarkers = new ArrayList(); - for (PsiExpression occurrence : myOccurrences) { - myOccurrenceMarkers.add(myEditor.getDocument().createRangeMarker(occurrence.getTextRange())); - } - } - return myOccurrenceMarkers; - } - - public boolean startTemplate() { - return startTemplate(false, null); - } - - public boolean startTemplate(final boolean replaceAllOccurrences, @Nullable final PsiType fieldDefaultType) { - final Ref result = new Ref(); - CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { - public void run() { - myTypeSelectorManager.setAllOccurences(replaceAllOccurrences); - - PsiType defaultType = myTypeSelectorManager.getTypeSelector().getSelectedType(); - if (fieldDefaultType != null) { - if (replaceAllOccurrences) { - if (ArrayUtil.find(myTypeSelectorManager.getTypesForAll(), fieldDefaultType) != -1) { - defaultType = fieldDefaultType; - } - } - else if (ArrayUtil.find(myTypeSelectorManager.getTypesForOne(), fieldDefaultType) != -1) { - defaultType = fieldDefaultType; - } - } - - final SuggestedNameInfo suggestedNameInfo = - IntroduceFieldDialog.createGenerator(myStatic, myLocalVariable, myInitializerExpression, myLocalVariable != null) - .getSuggestedNameInfo(defaultType); - - boolean started = false; - final PsiField field = createFieldToStartTemplateOn(suggestedNameInfo.names, defaultType); - if (field != null) { - myEditor.getCaretModel().moveToOffset(field.getTextOffset()); - myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); - final LinkedHashSet nameSuggestions = new LinkedHashSet(); - nameSuggestions.add(field.getName()); - nameSuggestions.addAll(Arrays.asList(suggestedNameInfo.names)); - final VariableInplaceRenamer renamer = new FieldInplaceIntroducer(field); - started = renamer.performInplaceRename(false, nameSuggestions); - } - result.set(started); - if (!started && field != null) { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - field.delete(); - } - }); - } - } - }, IntroduceFieldHandler.REFACTORING_NAME, IntroduceFieldHandler.REFACTORING_NAME); - return result.get(); - } - - private PsiField createFieldToStartTemplateOn(final String[] names, + protected PsiField createFieldToStartTemplateOn(final String[] names, final PsiType defaultType) { final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); return ApplicationManager.getApplication().runWriteAction(new Computable() { @Override public PsiField compute() { - PsiField field = elementFactory.createField(myFieldName != null ? myFieldName : names[0], defaultType); + PsiField field = elementFactory.createField(getInputName() != null ? getInputName() : names[0], defaultType); field = (PsiField)myParentClass.add(field); PsiUtil.setModifierProperty(field, PsiModifier.FINAL, myIntroduceFieldPanel.isDeclareFinal()); final String visibility = myIntroduceFieldPanel.getFieldVisibility(); if (visibility != null) { PsiUtil.setModifierProperty(field, visibility, true); } + myFieldRangeStart = myEditor.getDocument().createRangeMarker(field.getTextRange()); return field; } }); } + @Override + protected String[] suggestNames(PsiType defaultType, String propName) { + return IntroduceFieldDialog.createGenerator(myStatic, myLocalVariable, myExpr, myLocalVariable != null) + .getSuggestedNameInfo(defaultType).names; + } + public void setReplaceAllOccurrences(boolean replaceAllOccurrences) { myIntroduceFieldPanel.setReplaceAllOccurrences(replaceAllOccurrences); } @@ -240,54 +162,17 @@ public class InplaceIntroduceFieldPopup { ourLastInitializerPlace = place; } - class FieldInplaceIntroducer extends AbstractInplaceIntroducer { - private RangeMarker myFieldRangeStart; - private SmartTypePointer myDefaultParameterTypePointer; - - private SmartTypePointer myFieldTypePointer; - - public FieldInplaceIntroducer(PsiVariable psiVariable) { - super(myProject, new TypeExpression(myProject, myIntroduceFieldPanel.isReplaceAllOccurrences() ? myTypeSelectorManager.getTypesForAll() : myTypeSelectorManager.getTypesForOne()), - myEditor, psiVariable, false, - myTypeSelectorManager.getTypesForAll().length > 1, - myInitializerExpression != null && myInitializerExpression.isPhysical() ? myEditor.getDocument().createRangeMarker(myInitializerExpression.getTextRange()) : null, InplaceIntroduceFieldPopup.this.getOccurrenceMarkers(), - IntroduceFieldHandler.REFACTORING_NAME, IntroduceFieldHandler.REFACTORING_NAME); - myDefaultParameterTypePointer = - SmartTypePointerManager.getInstance(myProject).createSmartTypePointer(myTypeSelectorManager.getDefaultType()); - myFieldRangeStart = myEditor.getDocument().createRangeMarker(psiVariable.getTextRange()); - } - @Override protected boolean isReplaceAllOccurrences() { return myIntroduceFieldPanel.isReplaceAllOccurrences(); } - @Override - protected PsiExpression getExpr() { - return myInitializerExpression != null && myInitializerExpression.isValid() && myInitializerExpression.isPhysical() ? myInitializerExpression : null; - } - - @Override - protected PsiExpression[] getOccurrences() { - return myOccurrences; - } - - @Override - protected List getOccurrenceMarkers() { - return InplaceIntroduceFieldPopup.this.getOccurrenceMarkers(); - } - - @Override - public RangeMarker getExprMarker() { - return myExprMarker; - } - @Override protected void saveSettings(PsiVariable psiVariable) { - TypeSelectorManagerImpl.typeSelected(psiVariable.getType(), myDefaultParameterTypePointer.getType()); + super.saveSettings(psiVariable); JavaRefactoringSettings.getInstance().INTRODUCE_FIELD_VISIBILITY = myIntroduceFieldPanel.getFieldVisibility(); } @@ -298,46 +183,52 @@ public class InplaceIntroduceFieldPopup { @Override protected JComponent getComponent() { - if (!myInitListeners) { - myInitListeners = true; - myIntroduceFieldPanel.addVisibilityListener(new VisibilityListener(myProject, IntroduceFieldHandler.REFACTORING_NAME, myEditor){ - @Override - protected String getVisibility() { - return myIntroduceFieldPanel.getFieldVisibility(); - } - }); - final FinalListener finalListener = new FinalListener(myProject, IntroduceFieldHandler.REFACTORING_NAME); - myIntroduceFieldPanel.addFinalListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - finalListener.perform(myIntroduceFieldPanel.isDeclareFinal()); - } - }); - myIntroduceFieldPanel.addOccurrenceListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - final Runnable restartTemplate = new Runnable() { - @Override - public void run() { - final TemplateState templateState = - TemplateManagerImpl.getTemplateState(myEditor); - if (templateState != null) { - templateState.gotoEnd(true); - myTypeSelectorManager = new TypeSelectorManagerImpl(myProject, myDefaultParameterTypePointer.getType(), null, myInitializerExpression, myOccurrences); - startTemplate(myIntroduceFieldPanel.isReplaceAllOccurrences(), myFieldTypePointer.getType()); - } - } - }; - CommandProcessor.getInstance().executeCommand(myProject, restartTemplate, - IntroduceFieldHandler.REFACTORING_NAME, - IntroduceFieldHandler.REFACTORING_NAME); - } - }); - } + final VisibilityListener visibilityListener = new VisibilityListener(myEditor) { + @Override + protected String getVisibility() { + return myIntroduceFieldPanel.getFieldVisibility(); + } + }; + myIntroduceFieldPanel.addVisibilityListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + new WriteCommandAction(myProject, getCommandName(), getCommandName()) { + @Override + protected void run(Result result) throws Throwable { + PsiDocumentManager.getInstance(myProject).commitDocument(myEditor.getDocument()); + visibilityListener.perform(getVariable()); + } + }.execute(); + } + }); + final FinalListener finalListener = new FinalListener(myEditor); + myIntroduceFieldPanel.addFinalListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + new WriteCommandAction(myProject, getCommandName(), getCommandName()){ + @Override + protected void run(Result result) throws Throwable { + PsiDocumentManager.getInstance(myProject).commitDocument(myEditor.getDocument()); + finalListener.perform(myIntroduceFieldPanel.isDeclareFinal(), getVariable()); + } + }.execute(); + } + }); + myIntroduceFieldPanel.addOccurrenceListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + restartTemplate(); + } + }); return myWholePanel; } + @Override + protected String getCommandName() { + return IntroduceFieldHandler.REFACTORING_NAME; + } + @Override protected PsiVariable getVariable() { PsiElement element = myParentClass.getContainingFile().findElementAt(myFieldRangeStart.getStartOffset()); @@ -352,89 +243,47 @@ public class InplaceIntroduceFieldPopup { } @Override - protected void moveOffsetAfter(boolean success) { - if (success) { - if (myLocalVariable == null && myInitializerExpression == null || myFieldName == null) { - super.moveOffsetAfter(false); - return; - } - ourLastInitializerPlace = myIntroduceFieldPanel.getInitializerPlace(); - myIntroduceFieldPanel.saveFinalState(); - final BaseExpressionToFieldHandler.Settings settings = - new BaseExpressionToFieldHandler.Settings(myFieldName, myIntroduceFieldPanel.isReplaceAllOccurrences(), myStatic, - myIntroduceFieldPanel.isDeclareFinal(), - myIntroduceFieldPanel.getInitializerPlace(), - myIntroduceFieldPanel.getFieldVisibility(), myLocalVariable, - myFieldTypePointer.getType(), - myIntroduceFieldPanel.isDeleteVariable(), - myParentClass, false, false); - final Runnable runnable = new Runnable() { - public void run() { - if (myLocalVariable != null) { - final LocalToFieldHandler.IntroduceFieldRunnable fieldRunnable = - new LocalToFieldHandler.IntroduceFieldRunnable(false, myLocalVariable, myParentClass, settings, myStatic, myOccurrences); - fieldRunnable.run(); - } - else { - final BaseExpressionToFieldHandler.ConvertToFieldRunnable convertToFieldRunnable = - new BaseExpressionToFieldHandler.ConvertToFieldRunnable(myInitializerExpression, settings, settings.getForcedType(), - myOccurrences, myOccurenceManager, - myAnchorIdxIfAll != -1 && myOccurrences[myAnchorIdxIfAll] != null ? myOccurrences[myAnchorIdxIfAll].getParent() : myAnchorElementIfAll, - myAnchorIdx != -1 && myOccurrences[myAnchorIdx] != null ? myOccurrences[myAnchorIdx].getParent() : myAnchorElement, myEditor, - myParentClass); - convertToFieldRunnable.run(); - } - } - }; - ApplicationManager.getApplication().runWriteAction(runnable); + protected void restoreAnchors() { + if (myAnchorIdxIfAll != -1 && myOccurrences[myAnchorIdxIfAll] != null) { + myAnchorElementIfAll = myOccurrences[myAnchorIdxIfAll].getParent(); } - super.moveOffsetAfter(success); - if (myLocalVariable != null && myLocalVariable.isValid()) { - myEditor.getCaretModel().moveToOffset(myLocalVariable.getTextOffset()); - myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); + + if (myAnchorIdx != -1 && myOccurrences[myAnchorIdx] != null) { + myAnchorElement = myOccurrences[myAnchorIdx].getParent(); } } - @Override - public void finish() { - super.finish(); - final PsiField psiField = (PsiField)getVariable(); - if (psiField == null) { - return; - } - myFieldTypePointer = SmartTypePointerManager.getInstance(myProject).createSmartTypePointer(psiField.getType()); - PsiDocumentManager.getInstance(myProject).commitAllDocuments(); - myFieldName = psiField.getName(); - - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - final PsiFile containingFile = myParentClass.getContainingFile(); - final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); - if (getExprMarker() != null) { - myInitializerExpression = restoreExpression(containingFile, psiField, elementFactory, getExprMarker(), myExprText); - if (myInitializerExpression != null) { - myExprMarker = myEditor.getDocument().createRangeMarker(myInitializerExpression.getTextRange()); - } + protected void performIntroduce() { + ourLastInitializerPlace = myIntroduceFieldPanel.getInitializerPlace(); + myIntroduceFieldPanel.saveFinalState(); + final BaseExpressionToFieldHandler.Settings settings = + new BaseExpressionToFieldHandler.Settings(getInputName(), myIntroduceFieldPanel.isReplaceAllOccurrences(), myStatic, + myIntroduceFieldPanel.isDeclareFinal(), + myIntroduceFieldPanel.getInitializerPlace(), + myIntroduceFieldPanel.getFieldVisibility(), myLocalVariable, + myTypePointer.getType(), + myIntroduceFieldPanel.isDeleteVariable(), + myParentClass, false, false); + new WriteCommandAction(myProject, getCommandName(), getCommandName()){ + @Override + protected void run(Result result) throws Throwable { + if (myLocalVariable != null) { + final LocalToFieldHandler.IntroduceFieldRunnable fieldRunnable = + new LocalToFieldHandler.IntroduceFieldRunnable(false, myLocalVariable, myParentClass, settings, myStatic, myOccurrences); + fieldRunnable.run(); } - final List occurrenceMarkers = getOccurrenceMarkers(); - for (int i = 0, occurrenceMarkersSize = occurrenceMarkers.size(); i < occurrenceMarkersSize; i++) { - RangeMarker marker = occurrenceMarkers.get(i); - if (getExprMarker() != null && marker.getStartOffset() == getExprMarker().getStartOffset()) { - myOccurrences[i] = myInitializerExpression; - continue; - } - final PsiExpression psiExpression = - restoreExpression(containingFile, psiField, elementFactory, marker, myLocalVariable != null ? myLocalName : myExprText); - if (psiExpression != null) { - myOccurrences[i] = psiExpression; - } - } - myOccurrenceMarkers = null; - if (psiField.isValid()) { - psiField.delete(); + else { + final BaseExpressionToFieldHandler.ConvertToFieldRunnable convertToFieldRunnable = + new BaseExpressionToFieldHandler.ConvertToFieldRunnable(myExpr, settings, settings.getForcedType(), + myOccurrences, myOccurenceManager, + myAnchorIdxIfAll != -1 && myOccurrences[myAnchorIdxIfAll] != null ? myOccurrences[myAnchorIdxIfAll].getParent() : myAnchorElementIfAll, + myAnchorIdx != -1 && myOccurrences[myAnchorIdx] != null ? myOccurrences[myAnchorIdx].getParent() : myAnchorElement, myEditor, + myParentClass); + convertToFieldRunnable.run(); } } - }); + }.execute(); } - } + + } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceConstantHandler.java b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceConstantHandler.java index cf86a545362b..f0d8e74bdd1c 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceConstantHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceConstantHandler.java @@ -17,7 +17,6 @@ package com.intellij.refactoring.introduceField; import com.intellij.codeInsight.highlighting.HighlightManager; import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.colors.EditorColors; import com.intellij.openapi.editor.colors.EditorColorsManager; @@ -149,7 +148,7 @@ public class IntroduceConstantHandler extends BaseExpressionToFieldHandler { if (editor != null && editor.getSettings().isVariableInplaceRenameEnabled()) { if (new InplaceIntroduceConstantPopup(project, editor, parentClass, expr, localVariable, occurences, typeSelectorManager, anchorElement, anchorElementIfAll, - expr != null ? createOccurenceManager(expr, parentClass) : null).performInplaceIntroduce() ){ + expr != null ? createOccurenceManager(expr, parentClass) : null).startInplaceIntroduceTemplate() ){ return null; } } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldHandler.java b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldHandler.java index d617bb670d7b..78ed5c6bd24e 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldHandler.java @@ -16,8 +16,6 @@ package com.intellij.refactoring.introduceField; import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.wm.WindowManager; @@ -108,8 +106,9 @@ public class IntroduceFieldHandler extends BaseExpressionToFieldHandler { if (editor != null && editor.getSettings().isVariableInplaceRenameEnabled()) { myInplaceIntroduceFieldPopup = new InplaceIntroduceFieldPopup(localVariable, parentClass, declareStatic, currentMethodConstructor, occurences, expr, typeSelectorManager, editor, - allowInitInMethod, allowInitInMethodIfAll, anchorElement, anchorElementIfAll, expr != null ? createOccurenceManager(expr, parentClass) : null); - if (myInplaceIntroduceFieldPopup.startTemplate()) { + allowInitInMethod, allowInitInMethodIfAll, anchorElement, anchorElementIfAll, expr != null ? createOccurenceManager(expr, parentClass) : null, + project); + if (myInplaceIntroduceFieldPopup.startInplaceIntroduceTemplate()) { return null; } } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldPopupPanel.java b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldPopupPanel.java index 5aa768e45b33..8450e6490d51 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldPopupPanel.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldPopupPanel.java @@ -134,7 +134,7 @@ public class IntroduceFieldPopupPanel extends IntroduceFieldCentralPanel { initLabel.setDisplayedMnemonic('i'); groupPanel.add(initLabel, gridBagConstraints); JComboBox initializersCombo = new JComboBox(myInitialisersPlaceModel); - InplaceIntroduceConstantPopup.appendActions(initializersCombo, myParentClass.getProject()); + InplaceCombosUtil.appendActions(initializersCombo, myParentClass.getProject()); initLabel.setLabelFor(initializersCombo); initializersCombo.setRenderer(new ListCellRendererWrapper(initializersCombo) { @Override @@ -176,8 +176,8 @@ public class IntroduceFieldPopupPanel extends IntroduceFieldCentralPanel { if (visibility == null) { visibility = PsiModifier.PRIVATE; } - myVisibilityCombo = InplaceIntroduceConstantPopup.createVisibilityCombo(groupPanel, gridBagConstraints, myParentClass.getProject(), - visibility); + myVisibilityCombo = InplaceCombosUtil.createVisibilityCombo(groupPanel, gridBagConstraints, myParentClass.getProject(), + visibility); mainPanel.add(groupPanel, BorderLayout.CENTER); diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractInplaceIntroducer.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractInplaceIntroducer.java index ff6e0b9b56f6..80d6b409fd3a 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractInplaceIntroducer.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractInplaceIntroducer.java @@ -16,64 +16,129 @@ package com.intellij.refactoring.introduceParameter; import com.intellij.codeInsight.highlighting.HighlightManager; -import com.intellij.codeInsight.intention.impl.TypeExpression; -import com.intellij.codeInsight.lookup.LookupManager; -import com.intellij.codeInsight.lookup.impl.LookupImpl; -import com.intellij.openapi.application.Result; -import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.editor.Document; +import com.intellij.codeInsight.template.impl.TemplateManagerImpl; +import com.intellij.codeInsight.template.impl.TemplateState; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; +import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.editor.colors.EditorColors; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.markup.RangeHighlighter; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.search.searches.ReferencesSearch; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.refactoring.introduceVariable.VariableInplaceIntroducer; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import java.util.Collection; -import java.util.List; -import java.util.Map; +import javax.swing.*; +import java.util.*; /** * User: anna * Date: 3/15/11 */ -public abstract class AbstractInplaceIntroducer extends VariableInplaceIntroducer { +public abstract class AbstractInplaceIntroducer extends AbstractInplaceVariableIntroducer { + protected final V myLocalVariable; + + private final String myExprText; + private final String myLocalName; + + protected String myConstantName; + public AbstractInplaceIntroducer(Project project, - TypeExpression expression, Editor editor, - PsiVariable elementToRename, - boolean cantChangeFinalModifier, - boolean hasTypeSuggestion, - RangeMarker exprMarker, - List occurrenceMarkers, String commandName, String title) { - super(project, expression, editor, elementToRename, cantChangeFinalModifier, hasTypeSuggestion, exprMarker, occurrenceMarkers, commandName, title); + E expr, + V localVariable, + E[] occurrences, + String title) { + super(null, editor, project, title, occurrences, expr); + myLocalVariable = localVariable; + myExprText = expr != null ? expr.getText() : null; + myLocalName = localVariable != null ? localVariable.getName() : null; } + protected abstract String getCommandName(); + + protected abstract V createFieldToStartTemplateOn(boolean replaceAll, String[] names); + protected abstract String[] suggestNames(boolean replaceAll, V variable); + + protected abstract void performIntroduce(); + protected void performPostIntroduceTasks() {} + + public abstract E restoreExpression(PsiFile containingFile, V variable, RangeMarker marker, String exprText); + protected abstract boolean isReplaceAllOccurrences(); - - protected abstract PsiExpression getExpr(); - - protected abstract PsiExpression[] getOccurrences(); + protected abstract JComponent getComponent(); + protected void restoreAnchors() {} - protected abstract List getOccurrenceMarkers(); + protected abstract void saveSettings(V variable); + protected abstract V getVariable(); + + public boolean startInplaceIntroduceTemplate() { + final boolean replaceAllOccurrences = isReplaceAllOccurrences(); + final Ref result = new Ref(); + CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { + public void run() { + final String[] names = suggestNames(replaceAllOccurrences, myLocalVariable); + final V variable = createFieldToStartTemplateOn(replaceAllOccurrences, names); + boolean started = false; + if (variable != null) { + myEditor.getCaretModel().moveToOffset(variable.getTextOffset()); + myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); + + final LinkedHashSet nameSuggestions = new LinkedHashSet(); + nameSuggestions.add(variable.getName()); + nameSuggestions.addAll(Arrays.asList(names)); + initOccurrencesMarkers(); + setElementToRename(variable); + started = AbstractInplaceIntroducer.super.performInplaceRename(false, nameSuggestions); + } + result.set(started); + if (!started && variable != null) { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + variable.delete(); + } + }); + } + } + + }, getCommandName(), getCommandName()); + return result.get(); + } + + protected String getInputName() { + return myConstantName; + } + + @Override + protected boolean performAutomaticRename() { + return false; + } + + + @Override + public void finish() { + super.finish(); + PsiDocumentManager.getInstance(myProject).commitAllDocuments(); + final V variable = getVariable(); + if (variable == null) { + return; + } + restoreState(variable); + } @Override protected void addReferenceAtCaret(Collection refs) { - final PsiVariable variable = getVariable(); + final V variable = getVariable(); if (variable != null) { for (PsiReference reference : ReferencesSearch.search(variable)) { refs.remove(reference); @@ -89,7 +154,7 @@ public abstract class AbstractInplaceIntroducer extends VariableInplaceIntroduce @Override protected void collectAdditionalElementsToRename(boolean processTextOccurrences, List> stringUsages) { if (isReplaceAllOccurrences()) { - for (PsiExpression expression : getOccurrences()) { + for (E expression : getOccurrences()) { stringUsages.add(Pair.create(expression, new TextRange(0, expression.getTextLength()))); } } @@ -125,80 +190,84 @@ public abstract class AbstractInplaceIntroducer extends VariableInplaceIntroduce super.addHighlights(ranges, editor, highlighters, highlightManager); } - protected abstract class VisibilityListener implements ChangeListener { - private Project myProject; - private final String myCommandName; - private Editor myEditor; - - protected VisibilityListener(Project project, String commandName, Editor editor) { - myProject = project; - myCommandName = commandName; - myEditor = editor; - } - - @Override - public void stateChanged(ChangeEvent e) { - new WriteCommandAction(myProject, myCommandName, myCommandName) { - @Override - protected void run(Result result) throws Throwable { - final Document document = myEditor.getDocument(); - PsiDocumentManager.getInstance(getProject()).commitDocument(document); - final PsiVariable variable = getVariable(); - LOG.assertTrue(variable != null); - final PsiModifierList modifierList = variable.getModifierList(); - LOG.assertTrue(modifierList != null); - int textOffset = modifierList.getTextOffset(); - final String modifierListText = modifierList.getText(); - - int length = PsiModifier.PUBLIC.length(); - int idx = modifierListText.indexOf(PsiModifier.PUBLIC); - - if (idx == -1) { - idx = modifierListText.indexOf(PsiModifier.PROTECTED); - length = PsiModifier.PROTECTED.length(); + protected void restoreState(final V psiField) { + myConstantName = psiField.getName(); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + final PsiFile containingFile = psiField.getContainingFile(); + final RangeMarker exprMarker = getExprMarker(); + if (exprMarker != null) { + myExpr = restoreExpression(containingFile, psiField, exprMarker, myExprText); + if (myExpr != null && myExpr.isPhysical()) { + myExprMarker = myEditor.getDocument().createRangeMarker(myExpr.getTextRange()); } - - if (idx == -1) { - idx = modifierListText.indexOf(PsiModifier.PRIVATE); - length = PsiModifier.PRIVATE.length(); + } + final List occurrenceMarkers = getOccurrenceMarkers(); + for (int i = 0, occurrenceMarkersSize = occurrenceMarkers.size(); i < occurrenceMarkersSize; i++) { + RangeMarker marker = occurrenceMarkers.get(i); + if (getExprMarker() != null && marker.getStartOffset() == getExprMarker().getStartOffset()) { + myOccurrences[i] = myExpr; + continue; } - - String visibility = getVisibility(); - if (visibility == PsiModifier.PACKAGE_LOCAL) { - visibility = ""; - } - - final boolean wasPackageLocal = idx == -1; - final boolean isPackageLocal = visibility.isEmpty(); - - final int startOffset = textOffset + (wasPackageLocal ? 0 : idx); - final int endOffset; - if (wasPackageLocal) { - endOffset = startOffset; - } - else { - endOffset = textOffset + length + (isPackageLocal ? 1 : 0); - } - - final String finalVisibility = visibility + (wasPackageLocal ? " " : ""); - - Runnable runnable = new Runnable() { - @Override - public void run() { - document.replaceString(startOffset, endOffset, finalVisibility); - } - }; - - final LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(myEditor); - if (lookup != null) { - lookup.performGuardedChange(runnable); - } else { - runnable.run(); + final E psiExpression = + restoreExpression(containingFile, psiField, marker, myLocalVariable != null ? myLocalName : myExprText); + if (psiExpression != null) { + myOccurrences[i] = psiExpression; } } - }.execute(); - } - protected abstract String getVisibility(); + restoreAnchors(); + myOccurrenceMarkers = null; + if (psiField.isValid()) { + psiField.delete(); + } + } + }); + } + + @Override + protected void moveOffsetAfter(boolean success) { + if (success) { + if (myLocalVariable == null && myExpr == null || + getInputName() == null || + myLocalVariable != null && !myLocalVariable.isValid() || + myExpr != null && !myExpr.isValid()) { + super.moveOffsetAfter(false); + return; + } + performIntroduce(); + saveSettings(getVariable()); + } + if (myLocalVariable != null && myLocalVariable.isValid()) { + myEditor.getCaretModel().moveToOffset(myLocalVariable.getTextOffset()); + myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); + } + else if (getExprMarker() != null) { + myEditor.getCaretModel().moveToOffset(getExprMarker().getStartOffset()); + myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); + } + super.moveOffsetAfter(success); + if (success) { + performPostIntroduceTasks(); + } + } + + protected void restartTemplate() { + Runnable restartTemplateRunnable = new Runnable() { + public void run() { + final TemplateState templateState = TemplateManagerImpl.getTemplateState(myEditor); + if (templateState != null) { + myEditor.putUserData(INTRODUCE_RESTART, true); + try { + templateState.gotoEnd(true); + startInplaceIntroduceTemplate(); + } + finally { + myEditor.putUserData(INTRODUCE_RESTART, false); + } + } + } + }; + CommandProcessor.getInstance().executeCommand(myProject, restartTemplateRunnable, getCommandName(), getCommandName()); } } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractInplaceVariableIntroducer.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractInplaceVariableIntroducer.java new file mode 100644 index 000000000000..1e8247cf58ec --- /dev/null +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractInplaceVariableIntroducer.java @@ -0,0 +1,190 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.refactoring.introduceParameter; + +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementBuilder; +import com.intellij.codeInsight.template.TextResult; +import com.intellij.codeInsight.template.impl.TemplateManagerImpl; +import com.intellij.codeInsight.template.impl.TemplateState; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.RangeMarker; +import com.intellij.openapi.editor.SelectionModel; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.popup.Balloon; +import com.intellij.openapi.ui.popup.BalloonBuilder; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiNamedElement; +import com.intellij.refactoring.rename.NameSuggestionProvider; +import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer; +import com.intellij.ui.awt.RelativePoint; + +import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; + +/** + * User: anna + * Date: 3/15/11 + */ +public abstract class AbstractInplaceVariableIntroducer extends VariableInplaceRenamer { + public static final Key INTRODUCE_RESTART = Key.create("INTRODUCE_RESTART"); + + protected List myOccurrenceMarkers; + protected RangeMarker myExprMarker; + protected E myExpr; + protected E[] myOccurrences; + protected Balloon myBalloon; + protected String myTitle; + + public AbstractInplaceVariableIntroducer(PsiNamedElement elementToRename, + Editor editor, + Project project, + String title, E[] occurrences, E expr) { + super(elementToRename, editor, project); + myTitle = title; + myOccurrences = occurrences; + myExpr = expr; + myExprMarker = myExpr != null && myExpr.isPhysical() ? myEditor.getDocument().createRangeMarker(myExpr.getTextRange()) : null; + initOccurrencesMarkers(); + } + + protected abstract JComponent getComponent(); + protected abstract String getCommandName(); + + public void setOccurrenceMarkers(List occurrenceMarkers) { + myOccurrenceMarkers = occurrenceMarkers; + } + + public void setExprMarker(RangeMarker exprMarker) { + myExprMarker = exprMarker; + } + + protected E getExpr() { + return myExpr != null && myExpr.isValid() && myExpr.isPhysical() ? myExpr : null; + } + + protected E[] getOccurrences() { + return myOccurrences; + } + + public List getOccurrenceMarkers() { + if (myOccurrenceMarkers == null) { + initOccurrencesMarkers(); + } + return myOccurrenceMarkers; + } + + protected void initOccurrencesMarkers() { + if (myOccurrenceMarkers != null) return; + myOccurrenceMarkers = new ArrayList(); + for (E occurrence : myOccurrences) { + myOccurrenceMarkers.add(myEditor.getDocument().createRangeMarker(occurrence.getTextRange())); + } + } + + + public RangeMarker getExprMarker() { + return myExprMarker; + } + + @Override + public boolean performInplaceRename(boolean processTextOccurrences, LinkedHashSet nameSuggestions) { + final boolean result = super.performInplaceRename(processTextOccurrences, nameSuggestions); + if (result) { + if (myBalloon == null) { + showBalloon(); + } + } + return result; + } + + private void showBalloon() { + final JComponent component = getComponent(); + if (component == null) return; + if (ApplicationManager.getApplication().isHeadlessEnvironment()) return; + final BalloonBuilder balloonBuilder = JBPopupFactory.getInstance().createBalloonBuilder(component); + balloonBuilder.setFadeoutTime(0) + .setFillColor(UIManager.getColor("Panel.background")) + .setAnimationCycle(100) + .setHideOnClickOutside(false) + .setHideOnKeyOutside(false) + .setHideOnAction(false) + .setCloseButtonEnabled(true) + .setTitle(myTitle); + + final RelativePoint target = JBPopupFactory.getInstance().guessBestPopupLocation(myEditor); + final Point screenPoint = target.getScreenPoint(); + myBalloon = balloonBuilder.createBalloon(); + int y = screenPoint.y; + if (target.getPoint().getY() > myEditor.getLineHeight() + myBalloon.getPreferredSize().getHeight()) { + y -= myEditor.getLineHeight(); + } + myBalloon.show(new RelativePoint(new Point(screenPoint.x, y)), Balloon.Position.above); + } + + @Override + public void finish() { + super.finish(); + if (myBalloon != null) { + final Boolean isRestart = myEditor.getUserData(INTRODUCE_RESTART); + if (isRestart == null || !isRestart.booleanValue()) { + myBalloon.hide(); + } + } + } + + @Override + protected LookupElement[] createLookupItems(LookupElement[] lookupItems, String name) { + TemplateState templateState = TemplateManagerImpl.getTemplateState(myEditor); + final PsiNamedElement psiVariable = getVariable(); + if (psiVariable != null) { + final TextResult insertedValue = + templateState != null ? templateState.getVariableValue(PRIMARY_VARIABLE_NAME) : null; + if (insertedValue != null) { + final String text = insertedValue.getText(); + if (!text.isEmpty() && !Comparing.strEqual(text, name)) { + final LinkedHashSet names = new LinkedHashSet(); + names.add(text); + for (NameSuggestionProvider provider : Extensions.getExtensions(NameSuggestionProvider.EP_NAME)) { + provider.getSuggestedNames(psiVariable, psiVariable, names); + } + final LookupElement[] items = new LookupElement[names.size()]; + final Iterator iterator = names.iterator(); + for (int i = 0; i < items.length; i++) { + items[i] = LookupElementBuilder.create(iterator.next()); + } + return items; + } + } + } + return super.createLookupItems(lookupItems, name); + } + + @Override + protected TextRange preserveSelectedRange(SelectionModel selectionModel) { + return null; + } +} diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractJavaInplaceIntroducer.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractJavaInplaceIntroducer.java new file mode 100644 index 000000000000..99a2f27e3154 --- /dev/null +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractJavaInplaceIntroducer.java @@ -0,0 +1,156 @@ +package com.intellij.refactoring.introduceParameter; + +import com.intellij.codeInsight.intention.impl.TypeExpression; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.template.*; +import com.intellij.openapi.actionSystem.Shortcut; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.RangeMarker; +import com.intellij.openapi.keymap.Keymap; +import com.intellij.openapi.keymap.KeymapManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.VariableKind; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.ui.TypeSelectorManagerImpl; +import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.Nullable; + +/** + * User: anna + */ +public abstract class AbstractJavaInplaceIntroducer extends AbstractInplaceIntroducer { + protected SmartTypePointer myTypePointer; + protected TypeSelectorManagerImpl myTypeSelectorManager; + protected final SmartTypePointer myDefaultType; + protected final TypeExpression myExpression; + + + public AbstractJavaInplaceIntroducer(Project project, + Editor editor, + PsiExpression expr, + PsiVariable localVariable, + PsiExpression[] occurrences, + PsiType defaultType, TypeSelectorManagerImpl typeSelectorManager, String title) { + super(project, editor, expr, localVariable, occurrences, title); + myTypeSelectorManager = typeSelectorManager; + myExpression = new TypeExpression(project, typeSelectorManager.getTypesForOne()); + myDefaultType = SmartTypePointerManager.getInstance(project).createSmartTypePointer(defaultType); + setAdvertisementText(getAdvertisementText(myExpression.hasSuggestions())); + } + + protected abstract PsiVariable createFieldToStartTemplateOn(String[] names, PsiType psiType); + protected abstract String[] suggestNames(PsiType defaultType, String propName); + + + @Override + protected String[] suggestNames(boolean replaceAll, PsiVariable variable) { + myTypeSelectorManager.setAllOccurences(replaceAll); + final PsiType defaultType = myTypeSelectorManager.getTypeSelector().getSelectedType(); + final String propertyName = variable != null + ? JavaCodeStyleManager.getInstance(myProject).variableNameToPropertyName(variable.getName(), VariableKind.LOCAL_VARIABLE) + : null; + return suggestNames(defaultType, propertyName); + } + + + @Override + protected PsiVariable createFieldToStartTemplateOn(boolean replaceAll, String[] names) { + final PsiType fieldDefaultType = myTypePointer != null ? myTypePointer.getType() : null; + + myTypeSelectorManager.setAllOccurences(replaceAll); + PsiType defaultType = myTypeSelectorManager.getTypeSelector().getSelectedType(); + if (fieldDefaultType != null) { + if (replaceAll) { + if (ArrayUtil.find(myTypeSelectorManager.getTypesForAll(), fieldDefaultType) != -1) { + defaultType = fieldDefaultType; + } + } + else if (ArrayUtil.find(myTypeSelectorManager.getTypesForOne(), fieldDefaultType) != -1) { + defaultType = fieldDefaultType; + } + } + return createFieldToStartTemplateOn(names, defaultType); + } + + @Override + public PsiExpression restoreExpression(PsiFile containingFile, PsiVariable psiVariable, RangeMarker marker, String exprText) { + return restoreExpression(containingFile, psiVariable, JavaPsiFacade.getElementFactory(myProject), marker, exprText); + } + + @Override + protected void restoreState(PsiVariable psiField) { + myTypePointer = SmartTypePointerManager.getInstance(myProject).createSmartTypePointer(psiField.getType()); + super.restoreState(psiField); + myTypeSelectorManager = new TypeSelectorManagerImpl(myProject, myDefaultType.getType(), null, myExpr, myOccurrences); + } + + @Override + protected void saveSettings(PsiVariable psiVariable) { + TypeSelectorManagerImpl.typeSelected(psiVariable.getType(), myDefaultType.getType()); + } + + protected void addAdditionalVariables(TemplateBuilderImpl builder) { + final PsiTypeElement typeElement = getVariable().getTypeElement(); + builder.replaceElement(typeElement, "Variable_Type", createExpression(myExpression, typeElement.getText()), true, true); + } + + @Nullable + public static PsiExpression restoreExpression(PsiFile containingFile, + PsiVariable psiVariable, + PsiElementFactory elementFactory, + RangeMarker marker, String exprText) { + if (exprText == null) return null; + if (psiVariable == null || !psiVariable.isValid()) return null; + final PsiElement refVariableElement = containingFile.findElementAt(marker.getStartOffset()); + PsiExpression expression = PsiTreeUtil.getParentOfType(refVariableElement, PsiReferenceExpression.class); + if (expression instanceof PsiReferenceExpression && (((PsiReferenceExpression)expression).resolve() == psiVariable || + Comparing.strEqual(psiVariable.getName(), + ((PsiReferenceExpression)expression).getReferenceName()))) { + return (PsiExpression)expression.replace(elementFactory.createExpressionFromText(exprText, psiVariable)); + } + if (expression == null) { + expression = PsiTreeUtil.getParentOfType(refVariableElement, PsiExpression.class); + } + return expression != null && expression.isValid() && expression.getText().equals(exprText) ? expression : null; + } + + @Nullable + private static String getAdvertisementText(final boolean hasTypeSuggestion) { + final Keymap keymap = KeymapManager.getInstance().getActiveKeymap(); + if (hasTypeSuggestion) { + final Shortcut[] shortcuts = keymap.getShortcuts("PreviousTemplateVariable"); + if (shortcuts.length > 0) { + return "Press " + shortcuts[0] + " to change type"; + } + } + return null; + } + + public static Expression createExpression(final TypeExpression expression, final String defaultType) { + return new Expression() { + @Override + public Result calculateResult(ExpressionContext context) { + return new TextResult(defaultType); + } + + @Override + public Result calculateQuickResult(ExpressionContext context) { + return new TextResult(defaultType); + } + + @Override + public LookupElement[] calculateLookupItems(ExpressionContext context) { + return expression.calculateLookupItems(context); + } + + @Override + public String getAdvertisingText() { + return null; + } + }; + } + +} diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java index 7578f7b67c53..b154a6b42833 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java @@ -15,76 +15,43 @@ */ package com.intellij.refactoring.introduceParameter; -import com.intellij.codeInsight.intention.impl.TypeExpression; -import com.intellij.codeInsight.template.impl.TemplateManagerImpl; -import com.intellij.codeInsight.template.impl.TemplateState; -import com.intellij.ide.ui.ListCellRendererWrapper; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.RangeMarker; -import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.LabeledComponent; -import com.intellij.openapi.util.*; +import com.intellij.openapi.util.Computable; import com.intellij.psi.*; -import com.intellij.psi.codeStyle.CodeStyleSettingsManager; -import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.util.PsiUtil; -import com.intellij.refactoring.IntroduceParameterRefactoring; import com.intellij.refactoring.JavaRefactoringSettings; -import com.intellij.refactoring.RefactoringBundle; -import com.intellij.refactoring.inline.InlineParameterHandler; -import com.intellij.refactoring.introduceField.InplaceIntroduceConstantPopup; -import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer; -import com.intellij.refactoring.ui.TypeSelectorManager; import com.intellij.refactoring.ui.TypeSelectorManagerImpl; -import com.intellij.ui.IdeBorderFactory; -import com.intellij.ui.NonFocusableCheckBox; import com.intellij.usageView.UsageInfo; -import com.intellij.util.ui.UIUtil; import gnu.trove.TIntArrayList; import gnu.trove.TIntProcedure; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.*; import java.util.List; /** * User: anna * Date: 2/25/11 */ -class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { +class InplaceIntroduceParameterPopup extends AbstractJavaInplaceIntroducer { + private static final Logger LOG = Logger.getInstance("#" + InplaceIntroduceParameterPopup.class.getName()); private final Project myProject; private final Editor myEditor; - private final TypeSelectorManagerImpl myTypeSelectorManager; - private PsiExpression myExpr; private final PsiLocalVariable myLocalVar; private final PsiMethod myMethod; private final PsiMethod myMethodToSearchFor; - private final PsiExpression[] myOccurrences; private final boolean myMustBeFinal; - private RangeMarker myExprMarker; - private List myOccurrenceMarkers; private final JPanel myWholePanel; private int myParameterIndex = -1; - private String myParameterName; - private final String myExprText; + private InplaceIntroduceParameterUI myPanel; - private JComboBox myReplaceFieldsCb; - private boolean myInitialized = false; - private static final Logger LOG = Logger.getInstance("#" + InplaceIntroduceParameterPopup.class.getName()); - - private JCheckBox myFinalCb; - private boolean myHasWriteAccess = false; InplaceIntroduceParameterPopup(final Project project, final Editor editor, @@ -97,152 +64,58 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { final PsiExpression[] occurrences, final TIntArrayList parametersToRemove, final boolean mustBeFinal) { - super(project, localVar, expr, method, parametersToRemove); + super(project, editor, expr, localVar, occurrences, typeSelectorManager.getDefaultType(), typeSelectorManager, IntroduceParameterHandler.REFACTORING_NAME + ); myProject = project; myEditor = editor; - myTypeSelectorManager = typeSelectorManager; - myExpr = expr; myLocalVar = localVar; myMethod = method; myMethodToSearchFor = methodToSearchFor; - myOccurrences = occurrences; myMustBeFinal = mustBeFinal; - myExprMarker = expr != null && expr.isPhysical() ? myEditor.getDocument().createRangeMarker(expr.getTextRange()) : null; - myExprText = myExpr != null ? myExpr.getText() : null; myWholePanel = new JPanel(new GridBagLayout()); myWholePanel.setBorder(null); - final GridBagConstraints gc = - new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0); - gc.insets = new Insets(0, 5, 0, 0); - gc.gridwidth = 1; - gc.fill = GridBagConstraints.NONE; - if (myOccurrences.length > 1 && !myIsInvokedOnDeclaration) { - gc.gridy++; - createOccurrencesCb(gc, myWholePanel, myOccurrences.length); - } - gc.gridy++; - gc.insets.left = 5; - createDelegateCb(gc, myWholePanel); - - - final JavaRefactoringSettings settings = JavaRefactoringSettings.getInstance(); - final JPanel rightPanel = new JPanel(new GridBagLayout()); - final GridBagConstraints rgc = new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0,0,0,5), 0, 0); - createLocalVariablePanel(rgc, rightPanel, settings); - createRemoveParamsPanel(rgc, rightPanel); - if (Util.anyFieldsWithGettersPresent(classMemberRefs)) { - rgc.gridy++; - rightPanel.add(createReplaceFieldsWithGettersPanel(), rgc); - } - - gc.gridx = 1; - gc.gridheight = myCbReplaceAllOccurences != null ? 3 : 2; - gc.gridy = 1; - myWholePanel.add(rightPanel, gc); - - for (PsiExpression occurrence : occurrences) { - if (PsiUtil.isAccessedForWriting(occurrence)) { - myHasWriteAccess = true; - break; + myPanel = new InplaceIntroduceParameterUI(project, localVar, expr, method, parametersToRemove, typeSelectorManager, + myEditor, myOccurrences, classMemberRefs, myMustBeFinal) { + @Override + protected PsiParameter getParameter() { + return InplaceIntroduceParameterPopup.this.getParameter(); } - } - if (!myMustBeFinal) { - myFinalCb = new NonFocusableCheckBox("Declare final"); - myFinalCb.setMnemonic('f'); - myWholePanel.add(myFinalCb, - new GridBagConstraints(0, myCbReplaceAllOccurences == null ? 2 : 3, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, - GridBagConstraints.NONE, new Insets(0, 5, 2, 5), 0, 0)); - } + @Override + protected void updateControls(JCheckBox[] removeParamsCb) { + super.updateControls(removeParamsCb); + if (myParameterIndex < 0) return; + restartTemplate(); + } + }; + myPanel.append2MainPanel(myWholePanel); } - @Override - protected JPanel createReplaceFieldsWithGettersPanel() { - final LabeledComponent component = new LabeledComponent(); - myReplaceFieldsCb = new JComboBox(new Integer[] {IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_ALL, - IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_INACCESSIBLE, IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_NONE}); - myReplaceFieldsCb.setRenderer(new ListCellRendererWrapper(myReplaceFieldsCb) { + protected PsiVariable createFieldToStartTemplateOn(final String[] names, final PsiType defaultType) { + final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myMethod.getProject()); + return ApplicationManager.getApplication().runWriteAction(new Computable() { @Override - public void customize(JList list, Integer value, int index, boolean selected, boolean hasFocus) { - switch (value) { - case IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_NONE: - setText(UIUtil.removeMnemonic(RefactoringBundle.message("do.not.replace"))); - break; - case IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_INACCESSIBLE: - setText(UIUtil.removeMnemonic(RefactoringBundle.message("replace.fields.inaccessible.in.usage.context"))); - break; - default: - setText(UIUtil.removeMnemonic(RefactoringBundle.message("replace.all.fields"))); - } + public PsiParameter compute() { + final String name = getInputName() != null ? getInputName() : names[0]; + final PsiParameter anchor = JavaIntroduceParameterMethodUsagesProcessor.getAnchorParameter(myMethod); + final PsiParameter psiParameter = (PsiParameter)myMethod.getParameterList() + .addAfter(elementFactory.createParameter(name, defaultType), anchor); + PsiUtil.setModifierProperty(psiParameter, PsiModifier.FINAL, myPanel.hasFinalModifier()); + myParameterIndex = myMethod.getParameterList().getParameterIndex(psiParameter); + return psiParameter; } }); - myReplaceFieldsCb.setSelectedItem(JavaRefactoringSettings.getInstance().INTRODUCE_PARAMETER_REPLACE_FIELDS_WITH_GETTERS); - InplaceIntroduceConstantPopup.appendActions(myReplaceFieldsCb, myProject); - component.setComponent(myReplaceFieldsCb); - component.setText(RefactoringBundle.message("replace.fields.used.in.expressions.with.their.getters")); - component.getLabel().setDisplayedMnemonic('u'); - component.setLabelLocation(BorderLayout.NORTH); - component.setBorder(IdeBorderFactory.createEmptyBorder(3, 3, 2, 2)); - return component; } @Override - protected int getReplaceFieldsWithGetters() { - return myReplaceFieldsCb!= null ? (Integer)myReplaceFieldsCb.getSelectedItem() : IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_INACCESSIBLE; + protected String[] suggestNames(PsiType defaultType, String propName) { + return IntroduceParameterHandler.createNameSuggestionGenerator(myExpr, propName, myProject) + .getSuggestedNameInfo(defaultType).names; } - boolean inplaceIntroduceParameter() { - return startIntroduceTemplate(false); - } - - private boolean startIntroduceTemplate(final boolean replaceAllOccurrences) { - return startIntroduceTemplate(replaceAllOccurrences, hasFinalModifier()); - } - - private boolean startIntroduceTemplate(final boolean replaceAllOccurrences, - final boolean hasFinalModifier) { - final Ref result = new Ref(); - CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { - public void run() { - myTypeSelectorManager.setAllOccurences(replaceAllOccurrences); - final PsiType defaultType = myTypeSelectorManager.getTypeSelector().getSelectedType(); - final String propName = myLocalVar != null ? JavaCodeStyleManager - .getInstance(myProject).variableNameToPropertyName(myLocalVar.getName(), VariableKind.LOCAL_VARIABLE) : null; - final String[] names = IntroduceParameterHandler.createNameSuggestionGenerator(myExpr, propName, myProject) - .getSuggestedNameInfo(defaultType).names; - final PsiParameter parameter = createParameterToStartTemplateOn(names, defaultType, hasFinalModifier); - boolean started = false; - if (parameter != null) { - myParameterIndex = myMethod.getParameterList().getParameterIndex(parameter); - myEditor.getCaretModel().moveToOffset(parameter.getTextOffset()); - myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); - final LinkedHashSet nameSuggestions = new LinkedHashSet(); - nameSuggestions.add(parameter.getName()); - nameSuggestions.addAll(Arrays.asList(names)); - final VariableInplaceRenamer renamer = new ParameterInplaceIntroducer(parameter); - LOG.assertTrue(parameter.isPhysical()); - started = renamer.performInplaceRename(false, nameSuggestions); - } - result.set(started); - if (!started && parameter != null) { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - parameter.delete(); - } - }); - } - } - }, IntroduceParameterHandler.REFACTORING_NAME, IntroduceParameterHandler.REFACTORING_NAME); - return result.get(); - } - - @Override - protected TypeSelectorManager getTypeSelectionManager() { - return myTypeSelectorManager; - } @Nullable private PsiParameter getParameter() { @@ -251,247 +124,85 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { return parameters.length > myParameterIndex ? parameters[myParameterIndex] : null; } - public List getOccurrenceMarkers() { - if (myOccurrenceMarkers == null) { - myOccurrenceMarkers = new ArrayList(); - for (PsiExpression occurrence : myOccurrences) { - myOccurrenceMarkers.add(myEditor.getDocument().createRangeMarker(occurrence.getTextRange())); - } - } - return myOccurrenceMarkers; - } - private class ParameterInplaceIntroducer extends AbstractInplaceIntroducer { - - private SmartTypePointer myParameterTypePointer; - private SmartTypePointer myDefaultParameterTypePointer; - - private boolean myFinal; - - public ParameterInplaceIntroducer(PsiParameter parameter) { - super(myProject, new TypeExpression(myProject, myTypeSelectorManager.getTypesForAll()), - myEditor, parameter, myMustBeFinal, - myTypeSelectorManager.getTypesForAll().length > 1, myExprMarker, InplaceIntroduceParameterPopup.this.getOccurrenceMarkers(), - IntroduceParameterHandler.REFACTORING_NAME, IntroduceParameterHandler.REFACTORING_NAME); - myDefaultParameterTypePointer = SmartTypePointerManager.getInstance(myProject).createSmartTypePointer(parameter.getType()); - } - - @Override - protected JComponent getComponent() { - if (!myInitialized) { - myInitialized = true; - if (myFinalCb != null) { - myFinalCb.setSelected(createFinals()); - final FinalListener finalListener = new FinalListener(myProject, InlineParameterHandler.REFACTORING_NAME); - myFinalCb.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - finalListener.perform(myFinalCb.isSelected()); - } - }); - } - } - return myWholePanel; - } - - @Override - protected boolean isReplaceAllOccurrences() { - return InplaceIntroduceParameterPopup.this.isReplaceAllOccurences(); - } - - @Override - protected PsiExpression getExpr() { - return myExpr != null && myExpr.isValid() && myExpr.isPhysical() ? myExpr : null; - } - - @Override - protected PsiExpression[] getOccurrences() { - return myOccurrences; - } - - @Override - protected List getOccurrenceMarkers() { - return InplaceIntroduceParameterPopup.this.getOccurrenceMarkers(); - } - - @Override - protected PsiVariable getVariable() { - return getParameter(); - } - - - @Override - protected void saveSettings(PsiVariable psiVariable) { - final JavaRefactoringSettings settings = JavaRefactoringSettings.getInstance(); - InplaceIntroduceParameterPopup.super.saveSettings(settings); - if (myFinalCb != null && myFinalCb.isEnabled()) { - settings.INTRODUCE_PARAMETER_CREATE_FINALS = psiVariable.hasModifierProperty(PsiModifier.FINAL); - } - TypeSelectorManagerImpl.typeSelected(psiVariable.getType(), myDefaultParameterTypePointer.getType()); - } - - @Override - protected void moveOffsetAfter(boolean success) { - if (success) { - boolean isDeleteLocalVariable = false; - - PsiExpression parameterInitializer = myExpr; - if (myLocalVar != null) { - if (isUseInitializer()) { - parameterInitializer = myLocalVar.getInitializer(); - } - isDeleteLocalVariable = isDeleteLocalVariable(); - } - - if (!myMethod.isValid() || myParameterName == null || myLocalVar == null && myExpr == null) { - super.moveOffsetAfter(false); - return; - } - - final TIntArrayList parametersToRemove = getParametersToRemove(); - - final IntroduceParameterProcessor processor = - new IntroduceParameterProcessor(myProject, myMethod, - myMethodToSearchFor, parameterInitializer, myExpr, - myLocalVar, isDeleteLocalVariable, myParameterName, - isReplaceAllOccurences(), - getReplaceFieldsWithGetters(), myMustBeFinal || myFinal, isGenerateDelegate(), - myParameterTypePointer.getType(), - parametersToRemove); - final Runnable runnable = new Runnable() { - public void run() { - ApplicationManager.getApplication().invokeLater(new Runnable() { - public void run() { - final boolean [] conflictsFound = new boolean[] {true}; - processor.setPrepareSuccessfulSwingThreadCallback(new Runnable() { - @Override - public void run() { - conflictsFound[0] = processor.hasConflicts(); - } - }); - processor.run(); - normalizeParameterIdxAccordingToRemovedParams(parametersToRemove); - ParameterInplaceIntroducer.super.moveOffsetAfter(!conflictsFound[0]); - } - }); - } - }; - CommandProcessor.getInstance().executeCommand(myProject, runnable, IntroduceParameterHandler.REFACTORING_NAME, null); - } - super.moveOffsetAfter(false); - if (myLocalVar != null && myLocalVar.isValid()) { - myEditor.getCaretModel().moveToOffset(myLocalVar.getTextOffset()); - myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); - } - } - - @Override - public void finish() { - super.finish(); - PsiDocumentManager.getInstance(myProject).commitAllDocuments(); - final PsiParameter psiParameter = (PsiParameter)getVariable(); - if (psiParameter == null) { - return; - } - myFinal = psiParameter.hasModifierProperty(PsiModifier.FINAL); - myParameterTypePointer = SmartTypePointerManager.getInstance(myProject).createSmartTypePointer(psiParameter.getType()); - - myParameterName = psiParameter.getName(); - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - final PsiFile containingFile = myMethod.getContainingFile(); - final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); - if (myExprMarker != null) { - myExpr = restoreExpression(containingFile, psiParameter, elementFactory, myExprMarker, myExprText); - if (myExpr != null) { - myExprMarker = myEditor.getDocument().createRangeMarker(myExpr.getTextRange()); - } - } - final List occurrenceMarkers = getOccurrenceMarkers(); - for (int i = 0, occurrenceMarkersSize = occurrenceMarkers.size(); i < occurrenceMarkersSize; i++) { - RangeMarker marker = occurrenceMarkers.get(i); - if (myExprMarker != null && marker.getStartOffset() == myExprMarker.getStartOffset()) { - myOccurrences[i] = myExpr; - continue; - } - final PsiExpression psiExpression = restoreExpression(containingFile, psiParameter, elementFactory, marker, myExprText); - if (psiExpression != null) { - myOccurrences[i] = psiExpression; - } - } - myOccurrenceMarkers = null; - if (psiParameter.isValid()) { - psiParameter.delete(); - } - } - }); - } - - private void normalizeParameterIdxAccordingToRemovedParams(TIntArrayList parametersToRemove) { - parametersToRemove.forEach(new TIntProcedure() { - @Override - public boolean execute(int value) { - if (myParameterIndex >= value) { - myParameterIndex--; - } - return true; - } - }); - } - - public boolean createFinals() { - return hasFinalModifier(); - } - } - - private boolean hasFinalModifier() { - if (myHasWriteAccess) return false; - final Boolean createFinals = JavaRefactoringSettings.getInstance().INTRODUCE_PARAMETER_CREATE_FINALS; - return createFinals == null ? CodeStyleSettingsManager.getSettings(myProject).GENERATE_FINAL_PARAMETERS : createFinals.booleanValue(); + @Override + protected JComponent getComponent() { + return myWholePanel; } @Override - protected void updateControls(JCheckBox[] removeParamsCb) { - super.updateControls(removeParamsCb); - if (myParameterIndex < 0) return; - final boolean writeUsageWouldBeReplaced = myHasWriteAccess && isReplaceAllOccurences(); - Runnable restartTemplateRunnable = new Runnable() { - public void run() { - final TemplateState templateState = TemplateManagerImpl.getTemplateState(myEditor); - if (templateState != null) { - PsiDocumentManager.getInstance(myProject).commitDocument(myEditor.getDocument()); - final PsiParameter parameter = getParameter(); - boolean hasFinalModifier = parameter.hasModifierProperty(PsiModifier.FINAL) && !writeUsageWouldBeReplaced; - templateState.gotoEnd(true); - startIntroduceTemplate(isReplaceAllOccurences(), hasFinalModifier); - } - } - }; - CommandProcessor.getInstance().executeCommand(myProject, restartTemplateRunnable, IntroduceParameterHandler.REFACTORING_NAME, - IntroduceParameterHandler.REFACTORING_NAME); - if (myFinalCb != null) { - if (writeUsageWouldBeReplaced) { - myFinalCb.setSelected(false); - } - myFinalCb.setEnabled(!writeUsageWouldBeReplaced); - } + protected boolean isReplaceAllOccurrences() { + return myPanel.isReplaceAllOccurences(); + } + + @Override + protected PsiVariable getVariable() { + return getParameter(); } - private PsiParameter createParameterToStartTemplateOn(final String[] names, - final PsiType defaultType, final boolean hasFinalModifier) { - final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myMethod.getProject()); - return ApplicationManager.getApplication().runWriteAction(new Computable() { + @Override + protected void saveSettings(PsiVariable psiVariable) { + myPanel.saveSettings(JavaRefactoringSettings.getInstance()); + } + + protected void performIntroduce() { + boolean isDeleteLocalVariable = false; + + PsiExpression parameterInitializer = myExpr; + if (myLocalVar != null) { + if (myPanel.isUseInitializer()) { + parameterInitializer = myLocalVar.getInitializer(); + } + isDeleteLocalVariable = myPanel.isDeleteLocalVariable(); + } + + final TIntArrayList parametersToRemove = myPanel.getParametersToRemove(); + + final IntroduceParameterProcessor processor = + new IntroduceParameterProcessor(myProject, myMethod, + myMethodToSearchFor, parameterInitializer, myExpr, + myLocalVar, isDeleteLocalVariable, getInputName(), + myPanel.isReplaceAllOccurences(), + myPanel.getReplaceFieldsWithGetters(), myMustBeFinal || myPanel.isGenerateFinal(), + myPanel.isGenerateDelegate(), + myTypePointer.getType(), + parametersToRemove); + final Runnable runnable = new Runnable() { + public void run() { + ApplicationManager.getApplication().invokeLater(new Runnable() { + public void run() { + final boolean[] conflictsFound = new boolean[]{true}; + processor.setPrepareSuccessfulSwingThreadCallback(new Runnable() { + @Override + public void run() { + conflictsFound[0] = processor.hasConflicts(); + } + }); + processor.run(); + normalizeParameterIdxAccordingToRemovedParams(parametersToRemove); + InplaceIntroduceParameterPopup.super.moveOffsetAfter(!conflictsFound[0]); + InplaceIntroduceParameterPopup.super.saveSettings(getParameter()); + } + }); + } + }; + CommandProcessor.getInstance().executeCommand(myProject, runnable, getCommandName(), null); + } + + public String getCommandName() { + return IntroduceParameterHandler.REFACTORING_NAME; + } + + private void normalizeParameterIdxAccordingToRemovedParams(TIntArrayList parametersToRemove) { + parametersToRemove.forEach(new TIntProcedure() { @Override - public PsiParameter compute() { - final String name = myParameterName != null ? myParameterName : names[0]; - final PsiParameter anchor = JavaIntroduceParameterMethodUsagesProcessor.getAnchorParameter(myMethod); - final PsiParameter psiParameter = (PsiParameter)myMethod.getParameterList() - .addAfter(elementFactory.createParameter(name, defaultType), anchor); - PsiUtil.setModifierProperty(psiParameter, PsiModifier.FINAL, hasFinalModifier); - return psiParameter; + public boolean execute(int value) { + if (myParameterIndex >= value) { + myParameterIndex--; + } + return true; } }); } - } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterUI.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterUI.java new file mode 100644 index 000000000000..27bf5707b015 --- /dev/null +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterUI.java @@ -0,0 +1,202 @@ +package com.intellij.refactoring.introduceParameter; + +import com.intellij.ide.ui.ListCellRendererWrapper; +import com.intellij.openapi.application.Result; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.LabeledComponent; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleSettingsManager; +import com.intellij.psi.util.PsiUtil; +import com.intellij.refactoring.IntroduceParameterRefactoring; +import com.intellij.refactoring.JavaRefactoringSettings; +import com.intellij.refactoring.RefactoringBundle; +import com.intellij.refactoring.introduceField.InplaceCombosUtil; +import com.intellij.refactoring.introduceVariable.FinalListener; +import com.intellij.refactoring.ui.TypeSelectorManager; +import com.intellij.ui.IdeBorderFactory; +import com.intellij.ui.NonFocusableCheckBox; +import com.intellij.usageView.UsageInfo; +import com.intellij.util.ui.UIUtil; +import gnu.trove.TIntArrayList; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.List; + +/** + * User: anna + */ +public abstract class InplaceIntroduceParameterUI extends IntroduceParameterSettingsUI { + private JComboBox myReplaceFieldsCb; + private JCheckBox myFinalCb; + private boolean myHasWriteAccess = false; + private Project myProject; + private TypeSelectorManager myTypeSelectorManager; + private Editor myEditor; + private PsiExpression[] myOccurrences; + private List myClassMemberRefs; + private boolean myMustBeFinal; + + public InplaceIntroduceParameterUI(Project project, + PsiLocalVariable onLocalVariable, + PsiExpression onExpression, + PsiMethod methodToReplaceIn, + TIntArrayList parametersToRemove, + TypeSelectorManager typeSelectorManager, + Editor editor, + PsiExpression[] occurrences, List classMemberRefs, boolean mustBeFinal) { + super(project, onLocalVariable, onExpression, methodToReplaceIn, parametersToRemove); + myProject = project; + myTypeSelectorManager = typeSelectorManager; + myEditor = editor; + myOccurrences = occurrences; + myClassMemberRefs = classMemberRefs; + myMustBeFinal = mustBeFinal; + + for (PsiExpression occurrence : myOccurrences) { + if (PsiUtil.isAccessedForWriting(occurrence)) { + myHasWriteAccess = true; + break; + } + } + } + + protected abstract PsiParameter getParameter(); + + @Override + protected JPanel createReplaceFieldsWithGettersPanel() { + final LabeledComponent component = new LabeledComponent(); + myReplaceFieldsCb = new JComboBox(new Integer[]{IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_ALL, + IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_INACCESSIBLE, + IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_NONE}); + myReplaceFieldsCb.setRenderer(new ListCellRendererWrapper(myReplaceFieldsCb) { + @Override + public void customize(JList list, Integer value, int index, boolean selected, boolean hasFocus) { + switch (value) { + case IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_NONE: + setText(UIUtil.removeMnemonic(RefactoringBundle.message("do.not.replace"))); + break; + case IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_INACCESSIBLE: + setText(UIUtil.removeMnemonic(RefactoringBundle.message("replace.fields.inaccessible.in.usage.context"))); + break; + default: + setText(UIUtil.removeMnemonic(RefactoringBundle.message("replace.all.fields"))); + } + } + }); + myReplaceFieldsCb.setSelectedItem(JavaRefactoringSettings.getInstance().INTRODUCE_PARAMETER_REPLACE_FIELDS_WITH_GETTERS); + InplaceCombosUtil.appendActions(myReplaceFieldsCb, myProject); + component.setComponent(myReplaceFieldsCb); + component.setText(RefactoringBundle.message("replace.fields.used.in.expressions.with.their.getters")); + component.getLabel().setDisplayedMnemonic('u'); + component.setLabelLocation(BorderLayout.NORTH); + component.setBorder(IdeBorderFactory.createEmptyBorder(3, 3, 2, 2)); + return component; + } + + @Override + protected int getReplaceFieldsWithGetters() { + return myReplaceFieldsCb != null + ? (Integer)myReplaceFieldsCb.getSelectedItem() + : IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_INACCESSIBLE; + } + + @Override + protected TypeSelectorManager getTypeSelectionManager() { + return myTypeSelectorManager; + } + + public boolean isGenerateFinal() { + return myFinalCb == null || myFinalCb.isSelected(); + } + + @Override + protected void updateControls(JCheckBox[] removeParamsCb) { + super.updateControls(removeParamsCb); + final boolean writeUsageWouldBeReplaced = writeUsageWouldBeReplaced(); + if (myFinalCb != null) { + if (writeUsageWouldBeReplaced) { + myFinalCb.setSelected(false); + } + myFinalCb.setEnabled(!writeUsageWouldBeReplaced); + } + } + + protected boolean writeUsageWouldBeReplaced() { + return myHasWriteAccess && isReplaceAllOccurences(); + } + + public void append2MainPanel(JPanel myWholePanel) { + final GridBagConstraints gc = + new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0); + + gc.insets = new Insets(0, 5, 0, 0); + gc.gridwidth = 1; + gc.fill = GridBagConstraints.NONE; + if (myOccurrences.length > 1 && !myIsInvokedOnDeclaration) { + gc.gridy++; + createOccurrencesCb(gc, myWholePanel, myOccurrences.length); + } + gc.gridy++; + gc.insets.left = 5; + createDelegateCb(gc, myWholePanel); + + + final JavaRefactoringSettings settings = JavaRefactoringSettings.getInstance(); + final JPanel rightPanel = new JPanel(new GridBagLayout()); + final GridBagConstraints rgc = + new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, + new Insets(0, 0, 0, 5), 0, 0); + createLocalVariablePanel(rgc, rightPanel, settings); + createRemoveParamsPanel(rgc, rightPanel); + if (Util.anyFieldsWithGettersPresent(myClassMemberRefs)) { + rgc.gridy++; + rightPanel.add(createReplaceFieldsWithGettersPanel(), rgc); + } + + gc.gridx = 1; + gc.gridheight = myCbReplaceAllOccurences != null ? 3 : 2; + gc.gridy = 1; + myWholePanel.add(rightPanel, gc); + + if (!myMustBeFinal) { + myFinalCb = new NonFocusableCheckBox("Declare final"); + myFinalCb.setMnemonic('f'); + myFinalCb.setSelected(hasFinalModifier()); + final FinalListener finalListener = new FinalListener(myEditor); + myFinalCb.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + new WriteCommandAction(myProject, IntroduceParameterHandler.REFACTORING_NAME, IntroduceParameterHandler.REFACTORING_NAME) { + @Override + protected void run(Result result) throws Throwable { + PsiDocumentManager.getInstance(myProject).commitDocument(myEditor.getDocument()); + finalListener.perform(myFinalCb.isSelected(), getParameter()); + } + }.execute(); + } + }); + myWholePanel.add(myFinalCb, + new GridBagConstraints(0, myCbReplaceAllOccurences == null ? 2 : 3, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, + GridBagConstraints.NONE, new Insets(0, 5, 2, 5), 0, 0)); + } + } + + @Override + protected void saveSettings(JavaRefactoringSettings settings) { + super.saveSettings(settings); + if (myFinalCb != null && myFinalCb.isEnabled()) { + settings.INTRODUCE_PARAMETER_CREATE_FINALS = myFinalCb.isSelected(); + } + } + + public boolean hasFinalModifier() { + if (myHasWriteAccess) return false; + final Boolean createFinals = JavaRefactoringSettings.getInstance().INTRODUCE_PARAMETER_CREATE_FINALS; + return createFinals == null ? CodeStyleSettingsManager.getSettings(myProject).GENERATE_FINAL_PARAMETERS : createFinals.booleanValue(); + } +} diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java index 215534815684..860ece8c1a5a 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java @@ -53,7 +53,6 @@ import com.intellij.refactoring.ui.TypeSelectorManagerImpl; import com.intellij.refactoring.util.CommonRefactoringUtil; import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.refactoring.util.occurences.ExpressionOccurenceManager; -import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.components.JBList; import com.intellij.usageView.UsageInfo; @@ -423,7 +422,7 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase implements R typeSelectorManager, myExpr, myLocalVar, method, methodToSearchFor, occurences, parametersToRemove, - mustBeFinal).inplaceIntroduceParameter()) { + mustBeFinal).startInplaceIntroduceTemplate()) { return; } if (myEditor != null) { diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/VisibilityListener.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/VisibilityListener.java new file mode 100644 index 000000000000..84c38022a5a9 --- /dev/null +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/VisibilityListener.java @@ -0,0 +1,85 @@ +package com.intellij.refactoring.introduceParameter; + +import com.intellij.codeInsight.lookup.LookupManager; +import com.intellij.codeInsight.lookup.impl.LookupImpl; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.psi.PsiModifier; +import com.intellij.psi.PsiModifierList; +import com.intellij.psi.PsiVariable; + +/** +* User: anna +*/ +public abstract class VisibilityListener { + private Editor myEditor; + private static final Logger LOG = Logger.getInstance("#" + VisibilityListener.class.getName()); + + protected VisibilityListener(Editor editor) { + myEditor = editor; + } + + /** + * to be performed in write action + */ + public void perform(final PsiVariable variable) { + ApplicationManager.getApplication().assertWriteAccessAllowed(); + + final Document document = myEditor.getDocument(); + LOG.assertTrue(variable != null); + final PsiModifierList modifierList = variable.getModifierList(); + LOG.assertTrue(modifierList != null); + int textOffset = modifierList.getTextOffset(); + final String modifierListText = modifierList.getText(); + + int length = PsiModifier.PUBLIC.length(); + int idx = modifierListText.indexOf(PsiModifier.PUBLIC); + + if (idx == -1) { + idx = modifierListText.indexOf(PsiModifier.PROTECTED); + length = PsiModifier.PROTECTED.length(); + } + + if (idx == -1) { + idx = modifierListText.indexOf(PsiModifier.PRIVATE); + length = PsiModifier.PRIVATE.length(); + } + + String visibility = getVisibility(); + if (visibility == PsiModifier.PACKAGE_LOCAL) { + visibility = ""; + } + + final boolean wasPackageLocal = idx == -1; + final boolean isPackageLocal = visibility.isEmpty(); + + final int startOffset = textOffset + (wasPackageLocal ? 0 : idx); + final int endOffset; + if (wasPackageLocal) { + endOffset = startOffset; + } + else { + endOffset = textOffset + length + (isPackageLocal ? 1 : 0); + } + + final String finalVisibility = visibility + (wasPackageLocal ? " " : ""); + + Runnable runnable = new Runnable() { + @Override + public void run() { + document.replaceString(startOffset, endOffset, finalVisibility); + } + }; + + final LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(myEditor); + if (lookup != null) { + lookup.performGuardedChange(runnable); + } else { + runnable.run(); + } + } + + protected abstract String getVisibility(); +} diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/FinalListener.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/FinalListener.java new file mode 100644 index 000000000000..00ebbc94cc37 --- /dev/null +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/FinalListener.java @@ -0,0 +1,55 @@ +package com.intellij.refactoring.introduceVariable; + +import com.intellij.codeInsight.lookup.LookupManager; +import com.intellij.codeInsight.lookup.impl.LookupImpl; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.psi.PsiModifier; +import com.intellij.psi.PsiModifierList; +import com.intellij.psi.PsiTypeElement; +import com.intellij.psi.PsiVariable; + +/** +* User: anna +*/ +public class FinalListener { + private final Editor myEditor; + private static final Logger LOG = Logger.getInstance("#" + FinalListener.class.getName()); + + public FinalListener(Editor editor) { + myEditor = editor; + } + + public void perform(final boolean generateFinal, PsiVariable variable) { + perform(generateFinal, PsiModifier.FINAL, variable); + } + + public void perform(final boolean generateFinal, final String modifier, final PsiVariable variable) { + final Document document = myEditor.getDocument(); + LOG.assertTrue(variable != null); + final PsiModifierList modifierList = variable.getModifierList(); + LOG.assertTrue(modifierList != null); + final int textOffset = modifierList.getTextOffset(); + + final Runnable runnable = new Runnable() { + public void run() { + if (generateFinal) { + final PsiTypeElement typeElement = variable.getTypeElement(); + final int typeOffset = typeElement != null ? typeElement.getTextOffset() : textOffset; + document.insertString(typeOffset, modifier + " "); + } + else { + final int idx = modifierList.getText().indexOf(modifier); + document.deleteString(textOffset + idx, textOffset + idx + modifier.length() + 1); + } + } + }; + final LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(myEditor); + if (lookup != null) { + lookup.performGuardedChange(runnable); + } else { + runnable.run(); + } + } +} diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java index acabd1c64a51..b150d39d4a7a 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java @@ -49,7 +49,6 @@ import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.PsiUtilBase; import com.intellij.refactoring.*; import com.intellij.refactoring.introduceField.ElementToWorkOn; -import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer; import com.intellij.refactoring.ui.TypeSelectorManagerImpl; import com.intellij.refactoring.util.CommonRefactoringUtil; import com.intellij.refactoring.util.FieldConflictsResolver; @@ -531,7 +530,8 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme final boolean cantChangeFinalModifier = (hasWriteAccess || inFinalContext) && choice == OccurrencesChooser.ReplaceChoice.ALL; final VariableInplaceIntroducer renamer = new VariableInplaceIntroducer(project, expression, editor, elementToRename, cantChangeFinalModifier, - typeSelectorManager.getTypesForAll().length > 1, exprMarker, occurrenceMarkers, IntroduceVariableBase.REFACTORING_NAME, IntroduceVariableBase.REFACTORING_NAME); + typeSelectorManager.getTypesForAll().length > 1, exprMarker, occurrenceMarkers, + IntroduceVariableBase.REFACTORING_NAME); renamer.initInitialText(expressionText); PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument()); renamer.performInplaceRename(false, new LinkedHashSet(Arrays.asList(suggestedName.names))); diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/VariableInplaceIntroducer.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/VariableInplaceIntroducer.java index c5951cf994a2..f2c15c86380b 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/VariableInplaceIntroducer.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/VariableInplaceIntroducer.java @@ -16,27 +16,17 @@ package com.intellij.refactoring.introduceVariable; import com.intellij.codeInsight.intention.impl.TypeExpression; -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.codeInsight.lookup.LookupElementBuilder; -import com.intellij.codeInsight.lookup.LookupManager; -import com.intellij.codeInsight.lookup.impl.LookupImpl; -import com.intellij.codeInsight.template.*; -import com.intellij.codeInsight.template.impl.TemplateManagerImpl; -import com.intellij.codeInsight.template.impl.TemplateState; -import com.intellij.ide.IdeTooltipManager; +import com.intellij.codeInsight.template.TemplateBuilderImpl; import com.intellij.openapi.actionSystem.Shortcut; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.editor.*; -import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.RangeMarker; +import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.keymap.Keymap; import com.intellij.openapi.keymap.KeymapManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.popup.Balloon; -import com.intellij.openapi.ui.popup.BalloonBuilder; -import com.intellij.openapi.ui.popup.JBPopupFactory; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; @@ -44,73 +34,63 @@ import com.intellij.psi.scope.processor.VariablesProcessor; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.JavaRefactoringSettings; -import com.intellij.refactoring.rename.NameSuggestionProvider; -import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer; +import com.intellij.refactoring.introduceParameter.AbstractInplaceVariableIntroducer; +import com.intellij.refactoring.introduceParameter.AbstractJavaInplaceIntroducer; import com.intellij.refactoring.ui.TypeSelectorManagerImpl; import com.intellij.ui.NonFocusableCheckBox; -import com.intellij.ui.TitlePanel; -import com.intellij.ui.awt.RelativePoint; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.Iterator; -import java.util.LinkedHashSet; import java.util.List; /** * User: anna * Date: 12/8/10 */ -public class VariableInplaceIntroducer extends VariableInplaceRenamer { - private final PsiVariable myElementToRename; - private final Editor myEditor; - private final TypeExpression myExpression; - private final Project myProject; +public class VariableInplaceIntroducer extends AbstractInplaceVariableIntroducer { + protected final Editor myEditor; + + protected final Project myProject; private final SmartPsiElementPointer myPointer; - private final RangeMarker myExprMarker; - private final List myOccurrenceMarkers; - private final SmartTypePointer myDefaultType; private JCheckBox myCanBeFinalCb; - private Balloon myBalloon; + private boolean myCantChangeFinalModifier; - private String myCommandName; private String myTitle; private String myExpressionText; + protected final SmartTypePointer myDefaultType; + protected final TypeExpression myExpression; public VariableInplaceIntroducer(final Project project, final TypeExpression expression, final Editor editor, - final PsiVariable elementToRename, + final @NotNull PsiVariable elementToRename, final boolean cantChangeFinalModifier, final boolean hasTypeSuggestion, final RangeMarker exprMarker, final List occurrenceMarkers, - final String commandName, final String title) { - super(elementToRename, editor); + super(elementToRename, editor, project, title, new PsiExpression[0], null); myProject = project; myEditor = editor; - myElementToRename = elementToRename; - myExpression = expression; myCantChangeFinalModifier = cantChangeFinalModifier; - myCommandName = commandName; myTitle = title; - - myExprMarker = exprMarker; - myOccurrenceMarkers = occurrenceMarkers; - - final PsiType defaultType = elementToRename.getType(); - myDefaultType = SmartTypePointerManager.getInstance(project).createSmartTypePointer(defaultType); - + setExprMarker(exprMarker); + setOccurrenceMarkers(occurrenceMarkers); final PsiDeclarationStatement declarationStatement = PsiTreeUtil.getParentOfType(elementToRename, PsiDeclarationStatement.class); myPointer = declarationStatement != null ? SmartPointerManager.getInstance(project).createSmartPsiElementPointer(declarationStatement) : null; editor.putUserData(ReassignVariableUtil.DECLARATION_KEY, myPointer); - editor.putUserData(ReassignVariableUtil.OCCURRENCES_KEY, - occurrenceMarkers.toArray(new RangeMarker[occurrenceMarkers.size()])); + if (occurrenceMarkers != null) { + editor.putUserData(ReassignVariableUtil.OCCURRENCES_KEY, + occurrenceMarkers.toArray(new RangeMarker[occurrenceMarkers.size()])); + } + myExpression = expression; + final PsiType defaultType = elementToRename.getType(); + myDefaultType = SmartTypePointerManager.getInstance(project).createSmartTypePointer(defaultType); setAdvertisementText(getAdvertisementText(declarationStatement, defaultType, hasTypeSuggestion)); } @@ -118,39 +98,6 @@ public class VariableInplaceIntroducer extends VariableInplaceRenamer { myExpressionText = text; } - @Override - protected void addAdditionalVariables(TemplateBuilderImpl builder) { - final PsiTypeElement typeElement = myElementToRename.getTypeElement(); - builder.replaceElement(typeElement, "Variable_Type", createExpression(myExpression, typeElement.getText()), true, true); - } - - @Override - protected LookupElement[] createLookupItems(LookupElement[] lookupItems, String name) { - TemplateState templateState = TemplateManagerImpl.getTemplateState(myEditor); - final PsiVariable psiVariable = getVariable(); - if (psiVariable != null) { - final TextResult insertedValue = - templateState != null ? templateState.getVariableValue(PRIMARY_VARIABLE_NAME) : null; - if (insertedValue != null) { - final String text = insertedValue.getText(); - if (!text.isEmpty() && !Comparing.strEqual(text, name)) { - final LinkedHashSet names = new LinkedHashSet(); - names.add(text); - for (NameSuggestionProvider provider : Extensions.getExtensions(NameSuggestionProvider.EP_NAME)) { - provider.getSuggestedNames(psiVariable, psiVariable, names); - } - final LookupElement[] items = new LookupElement[names.size()]; - final Iterator iterator = names.iterator(); - for (int i = 0; i < items.length; i++) { - items[i] = LookupElementBuilder.create(iterator.next()); - } - return items; - } - } - } - return super.createLookupItems(lookupItems, name); - } - @Nullable protected PsiVariable getVariable() { final PsiDeclarationStatement declarationStatement = myPointer.getElement(); @@ -161,29 +108,6 @@ public class VariableInplaceIntroducer extends VariableInplaceRenamer { return null; } - @Override - protected TextRange preserveSelectedRange(SelectionModel selectionModel) { - return null; - } - - @Override - public boolean performInplaceRename(boolean processTextOccurrences, LinkedHashSet nameSuggestions) { - final boolean result = super.performInplaceRename(processTextOccurrences, nameSuggestions); - if (result) { - showBalloon(); - } - return result; - } - - public RangeMarker getExprMarker() { - return myExprMarker; - } - - @Override - protected boolean performAutomaticRename() { - return false; - } - @Override protected void moveOffsetAfter(boolean success) { try { @@ -196,7 +120,8 @@ public class VariableInplaceIntroducer extends VariableInplaceRenamer { LOG.assertTrue(psiVariable.isValid()); saveSettings(psiVariable); adjustLine(psiVariable, document); - int startOffset = myExprMarker != null && myExprMarker.isValid() ? myExprMarker.getStartOffset() : psiVariable.getTextOffset(); + + int startOffset = getExprMarker() != null && getExprMarker().isValid() ? getExprMarker().getStartOffset() : psiVariable.getTextOffset(); final PsiFile file = psiVariable.getContainingFile(); final PsiReference referenceAt = file.findReferenceAt(startOffset); if (referenceAt != null && referenceAt.resolve() instanceof PsiVariable) { @@ -213,13 +138,13 @@ public class VariableInplaceIntroducer extends VariableInplaceRenamer { if (psiVariable.getInitializer() != null) { ApplicationManager.getApplication().runWriteAction(new Runnable() { public void run() { - appendTypeCasts(myOccurrenceMarkers, file, myProject, psiVariable); + appendTypeCasts(getOccurrenceMarkers(), file, myProject, psiVariable); } }); } } else { - if (myExprMarker != null) { - myEditor.getCaretModel().moveToOffset(myExprMarker.getStartOffset()); + if (getExprMarker() != null) { + myEditor.getCaretModel().moveToOffset(getExprMarker().getStartOffset()); myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); } if (myExpressionText != null) { @@ -231,8 +156,9 @@ public class VariableInplaceIntroducer extends VariableInplaceRenamer { if (vars.length > 0 && vars[0] instanceof PsiVariable) { final PsiFile containingFile = element.getContainingFile(); final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); - for (RangeMarker occurrenceMarker : myOccurrenceMarkers) { - if (restoreExpression(containingFile, (PsiVariable)vars[0], elementFactory, occurrenceMarker, myExpressionText) == null) return; + for (RangeMarker occurrenceMarker : getOccurrenceMarkers()) { + if (AbstractJavaInplaceIntroducer + .restoreExpression(containingFile, (PsiVariable)vars[0], elementFactory, occurrenceMarker, myExpressionText) == null) return; } element.delete(); } @@ -244,23 +170,17 @@ public class VariableInplaceIntroducer extends VariableInplaceRenamer { } finally { myEditor.putUserData(ReassignVariableUtil.DECLARATION_KEY, null); - for (RangeMarker occurrenceMarker : myOccurrenceMarkers) { + for (RangeMarker occurrenceMarker : getOccurrenceMarkers()) { occurrenceMarker.dispose(); } myEditor.putUserData(ReassignVariableUtil.OCCURRENCES_KEY, null); - if (myExprMarker != null) myExprMarker.dispose(); + if (getExprMarker() != null) getExprMarker().dispose(); } } - @Override - public void finish() { - super.finish(); - if (myBalloon != null) myBalloon.hide(); - } - protected void saveSettings(PsiVariable psiVariable) { - JavaRefactoringSettings.getInstance().INTRODUCE_LOCAL_CREATE_FINALS = psiVariable.hasModifierProperty(PsiModifier.FINAL); TypeSelectorManagerImpl.typeSelected(psiVariable.getType(), myDefaultType.getType()); + JavaRefactoringSettings.getInstance().INTRODUCE_LOCAL_CREATE_FINALS = psiVariable.hasModifierProperty(PsiModifier.FINAL); } @@ -270,7 +190,19 @@ public class VariableInplaceIntroducer extends VariableInplaceRenamer { myCanBeFinalCb = new NonFocusableCheckBox("Declare final"); myCanBeFinalCb.setSelected(createFinals()); myCanBeFinalCb.setMnemonic('f'); - myCanBeFinalCb.addActionListener(new FinalListener(myProject, myCommandName)); + final FinalListener finalListener = new FinalListener(myEditor); + myCanBeFinalCb.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + new WriteCommandAction(myProject, IntroduceVariableBase.REFACTORING_NAME, IntroduceVariableBase.REFACTORING_NAME) { + @Override + protected void run(com.intellij.openapi.application.Result result) throws Throwable { + PsiDocumentManager.getInstance(myProject).commitDocument(myEditor.getDocument()); + finalListener.perform(myCanBeFinalCb.isSelected(), getVariable()); + } + }.execute(); + } + }); } else { return null; } @@ -286,27 +218,39 @@ public class VariableInplaceIntroducer extends VariableInplaceRenamer { return panel; } + protected void addAdditionalVariables(TemplateBuilderImpl builder) { + final PsiTypeElement typeElement = getVariable().getTypeElement(); + builder.replaceElement(typeElement, "Variable_Type", AbstractJavaInplaceIntroducer.createExpression(myExpression, typeElement.getText()), true, true); + } + + @Override + protected String getCommandName() { + return IntroduceVariableBase.REFACTORING_NAME; + } + private static void appendTypeCasts(List occurrenceMarkers, PsiFile file, Project project, @Nullable PsiVariable psiVariable) { - for (RangeMarker occurrenceMarker : occurrenceMarkers) { - final PsiElement refVariableElement = file.findElementAt(occurrenceMarker.getStartOffset()); - final PsiReferenceExpression referenceExpression = PsiTreeUtil.getParentOfType(refVariableElement, PsiReferenceExpression.class); - if (referenceExpression != null) { - final PsiElement parent = referenceExpression.getParent(); - if (parent instanceof PsiVariable) { - createCastInVariableDeclaration(project, (PsiVariable)parent); - } - else if (parent instanceof PsiReferenceExpression && psiVariable != null) { - final PsiExpression initializer = psiVariable.getInitializer(); - LOG.assertTrue(initializer != null); - final PsiType type = initializer.getType(); - if (((PsiReferenceExpression)parent).resolve() == null && type != null) { - final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project); - final PsiExpression castedExpr = - elementFactory.createExpressionFromText("((" + type.getCanonicalText() + ")" + referenceExpression.getText() + ")", parent); - JavaCodeStyleManager.getInstance(project).shortenClassReferences(referenceExpression.replace(castedExpr)); + if (occurrenceMarkers != null) { + for (RangeMarker occurrenceMarker : occurrenceMarkers) { + final PsiElement refVariableElement = file.findElementAt(occurrenceMarker.getStartOffset()); + final PsiReferenceExpression referenceExpression = PsiTreeUtil.getParentOfType(refVariableElement, PsiReferenceExpression.class); + if (referenceExpression != null) { + final PsiElement parent = referenceExpression.getParent(); + if (parent instanceof PsiVariable) { + createCastInVariableDeclaration(project, (PsiVariable)parent); + } + else if (parent instanceof PsiReferenceExpression && psiVariable != null) { + final PsiExpression initializer = psiVariable.getInitializer(); + LOG.assertTrue(initializer != null); + final PsiType type = initializer.getType(); + if (((PsiReferenceExpression)parent).resolve() == null && type != null) { + final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project); + final PsiExpression castedExpr = + elementFactory.createExpressionFromText("((" + type.getCanonicalText() + ")" + referenceExpression.getText() + ")", parent); + JavaCodeStyleManager.getInstance(project).shortenClassReferences(referenceExpression.replace(castedExpr)); + } } } } @@ -350,29 +294,6 @@ public class VariableInplaceIntroducer extends VariableInplaceRenamer { return null; } - private static Expression createExpression(final TypeExpression expression, final String defaultType) { - return new Expression() { - @Override - public Result calculateResult(ExpressionContext context) { - return new TextResult(defaultType); - } - - @Override - public Result calculateQuickResult(ExpressionContext context) { - return new TextResult(defaultType); - } - - @Override - public LookupElement[] calculateLookupItems(ExpressionContext context) { - return expression.calculateLookupItems(context); - } - - @Override - public String getAdvertisingText() { - return null; - } - }; - } protected boolean createFinals() { return IntroduceVariableBase.createFinals(myProject); @@ -396,97 +317,16 @@ public class VariableInplaceIntroducer extends VariableInplaceRenamer { return myTitle; } - private void showBalloon() { - final JComponent component = getComponent(); - if (component == null) return; - if (ApplicationManager.getApplication().isHeadlessEnvironment()) return; - final BalloonBuilder balloonBuilder = JBPopupFactory.getInstance().createBalloonBuilder(component); - balloonBuilder.setFadeoutTime(0) - .setFillColor(UIManager.getColor("Panel.background")) - .setAnimationCycle(100) - .setHideOnClickOutside(false) - .setHideOnKeyOutside(false) - .setHideOnAction(false) - .setCloseButtonEnabled(true) - .setTitle(getTitle()); - - final RelativePoint target = JBPopupFactory.getInstance().guessBestPopupLocation(myEditor); - final Point screenPoint = target.getScreenPoint(); - myBalloon = balloonBuilder.createBalloon(); - int y = screenPoint.y; - if (target.getPoint().getY() > myEditor.getLineHeight() + myBalloon.getPreferredSize().getHeight()) { - y -= myEditor.getLineHeight(); - } - myBalloon.show(new RelativePoint(new Point(screenPoint.x, y)), Balloon.Position.above); - } @Nullable - protected static PsiExpression restoreExpression(PsiFile containingFile, - PsiVariable psiVariable, - PsiElementFactory elementFactory, - RangeMarker marker, String exprText) { - if (exprText == null) return null; - if (psiVariable == null || !psiVariable.isValid()) return null; - final PsiElement refVariableElement = containingFile.findElementAt(marker.getStartOffset()); - final PsiExpression expression = PsiTreeUtil.getParentOfType(refVariableElement, PsiReferenceExpression.class); - if (expression instanceof PsiReferenceExpression && (((PsiReferenceExpression)expression).resolve() == psiVariable || - Comparing.strEqual(psiVariable.getName(), ((PsiReferenceExpression)expression).getReferenceName()))) { - return (PsiExpression)expression.replace(elementFactory.createExpressionFromText(exprText, psiVariable)); - } - return expression != null && expression.isValid() && expression.getText().equals(exprText) ? expression : null; - } - - public class FinalListener implements ActionListener { - private final Project myProject; - private final String myCommandName; - - public FinalListener(Project project, String commandName) { - myProject = project; - myCommandName = commandName; - } - - @Override - public void actionPerformed(ActionEvent e) { - perform(myCanBeFinalCb.isSelected()); - } - - public void perform(final boolean generateFinal) { - perform(generateFinal, PsiModifier.FINAL); - } - - public void perform(final boolean generateFinal, final String modifier) { - new WriteCommandAction(myProject, myCommandName, myCommandName){ - @Override - protected void run(com.intellij.openapi.application.Result result) throws Throwable { - final Document document = myEditor.getDocument(); - PsiDocumentManager.getInstance(getProject()).commitDocument(document); - final PsiVariable variable = getVariable(); - LOG.assertTrue(variable != null); - final PsiModifierList modifierList = variable.getModifierList(); - LOG.assertTrue(modifierList != null); - final int textOffset = modifierList.getTextOffset(); - - final Runnable runnable = new Runnable() { - public void run() { - if (generateFinal) { - final PsiTypeElement typeElement = variable.getTypeElement(); - final int typeOffset = typeElement != null ? typeElement.getTextOffset() : textOffset; - document.insertString(typeOffset, modifier + " "); - } - else { - final int idx = modifierList.getText().indexOf(modifier); - document.deleteString(textOffset + idx, textOffset + idx + modifier.length() + 1); - } - } - }; - final LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(myEditor); - if (lookup != null) { - lookup.performGuardedChange(runnable); - } else { - runnable.run(); - } - } - }.execute(); + private static String getAdvertisementText(final boolean hasTypeSuggestion) { + final Keymap keymap = KeymapManager.getInstance().getActiveKeymap(); + if (hasTypeSuggestion) { + final Shortcut[] shortcuts = keymap.getShortcuts("PreviousTemplateVariable"); + if (shortcuts.length > 0) { + return "Press " + shortcuts[0] + " to change type"; + } } + return null; } } diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceField/escapePosition.java b/java/java-tests/testData/refactoring/inplaceIntroduceField/escapePosition.java new file mode 100644 index 000000000000..b1a33a400fb4 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceField/escapePosition.java @@ -0,0 +1,6 @@ +class Test { + void simpleMethod() { + System.out.println(""); + System.out.println(""); + } +} diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceField/escapePositionOnLocal.java b/java/java-tests/testData/refactoring/inplaceIntroduceField/escapePositionOnLocal.java new file mode 100644 index 000000000000..429535e3ac38 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceField/escapePositionOnLocal.java @@ -0,0 +1,5 @@ +class Test { + void simpleMethod() { + boolean bb; + } +} diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceField/escapePositionOnLocal_after.java b/java/java-tests/testData/refactoring/inplaceIntroduceField/escapePositionOnLocal_after.java new file mode 100644 index 000000000000..c66315130dae --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceField/escapePositionOnLocal_after.java @@ -0,0 +1,6 @@ +class Test { + + void simpleMethod() { + boolean bb; + } +} diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceField/escapePosition_after.java b/java/java-tests/testData/refactoring/inplaceIntroduceField/escapePosition_after.java new file mode 100644 index 000000000000..a639e2c83588 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceField/escapePosition_after.java @@ -0,0 +1,7 @@ +class Test { + + void simpleMethod() { + System.out.println(""); + System.out.println(""); + } +} diff --git a/java/java-tests/testSrc/com/intellij/refactoring/InplaceIntroduceFieldTest.java b/java/java-tests/testSrc/com/intellij/refactoring/InplaceIntroduceFieldTest.java index 6d5bdc4bfd79..c875062f789c 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/InplaceIntroduceFieldTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/InplaceIntroduceFieldTest.java @@ -20,7 +20,6 @@ import com.intellij.codeInsight.template.impl.TemplateManagerImpl; import com.intellij.codeInsight.template.impl.TemplateState; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; - import com.intellij.openapi.util.Pass; import com.intellij.psi.PsiExpression; import com.intellij.psi.PsiLocalVariable; @@ -92,6 +91,46 @@ public class InplaceIntroduceFieldTest extends LightCodeInsightTestCase { }); } + public void testEscapePosition() throws Exception { + doTestEscape(); + } + + public void testEscapePositionOnLocal() throws Exception { + doTestEscape(); + } + + private void doTestEscape() throws Exception { + String name = getTestName(true); + configureByFile(BASE_PATH + name + ".java"); + final boolean enabled = getEditor().getSettings().isVariableInplaceRenameEnabled(); + TemplateManagerImpl templateManager = (TemplateManagerImpl)TemplateManager.getInstance(getProject()); + try { + templateManager.setTemplateTesting(true); + getEditor().getSettings().setVariableInplaceRenameEnabled(true); + + final MyIntroduceFieldHandler introduceFieldHandler = new MyIntroduceFieldHandler(); + final PsiExpression expression = + PsiTreeUtil.getParentOfType(getFile().findElementAt(getEditor().getCaretModel().getOffset()), PsiExpression.class); + if (expression != null) { + introduceFieldHandler.invokeImpl(getProject(), expression, getEditor()); + } else { + final PsiLocalVariable localVariable = + PsiTreeUtil.getParentOfType(getFile().findElementAt(getEditor().getCaretModel().getOffset()), PsiLocalVariable.class); + assertNotNull(localVariable); + introduceFieldHandler.invokeImpl(getProject(), localVariable, getEditor()); + } + TemplateState state = TemplateManagerImpl.getTemplateState(getEditor()); + assert state != null; + state.gotoEnd(true); + checkResultByFile(BASE_PATH + name + "_after.java"); + } + finally { + myEditor.getSettings().setVariableInplaceRenameEnabled(enabled); + templateManager.setTemplateTesting(false); + InplaceIntroduceFieldPopup.setInitializationPlace(null); + } + } + private void doTest(final Pass pass) throws Exception { String name = getTestName(true); diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java index c8b122194853..3abbbdd44b99 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java @@ -90,12 +90,12 @@ public class VariableInplaceRenamer { "com.intellij.rename.inplace.resolveSnapshotProvider" ); - private final PsiNamedElement myElementToRename; + private PsiNamedElement myElementToRename; @NonNls protected static final String PRIMARY_VARIABLE_NAME = "PrimaryVariable"; @NonNls private static final String OTHER_VARIABLE_NAME = "OtherVariable"; private ArrayList myHighlighters; - private final Editor myEditor; - private final Project myProject; + protected final Editor myEditor; + protected final Project myProject; private RangeMarker myRenameOffset; public void setAdvertisementText(String advertisementText) { @@ -107,10 +107,16 @@ public class VariableInplaceRenamer { private static final Stack ourRenamersStack = new Stack(); public VariableInplaceRenamer(@NotNull PsiNamedElement elementToRename, Editor editor) { + this(elementToRename, editor, elementToRename.getProject()); + } + + public VariableInplaceRenamer(PsiNamedElement elementToRename, + Editor editor, + Project project) { myElementToRename = elementToRename; myEditor = /*(editor instanceof EditorWindow)? ((EditorWindow)editor).getDelegate() : */editor; - myProject = myElementToRename.getProject(); - myRenameOffset = myEditor.getDocument().createRangeMarker(myElementToRename.getTextRange()); + myProject = project; + myRenameOffset = myElementToRename != null ? myEditor.getDocument().createRangeMarker(myElementToRename.getTextRange()) : null; } public boolean performInplaceRename() { @@ -393,6 +399,10 @@ public class VariableInplaceRenamer { } } + public void setElementToRename(PsiNamedElement elementToRename) { + myElementToRename = elementToRename; + } + private static VirtualFile getTopLevelVirtualFile(final FileViewProvider fileViewProvider) { VirtualFile file = fileViewProvider.getVirtualFile(); if (file instanceof VirtualFileWindow) file = ((VirtualFileWindow)file).getDelegate();