diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/BaseExpressionToFieldHandler.java b/java/java-impl/src/com/intellij/refactoring/introduceField/BaseExpressionToFieldHandler.java index 2447df011396..c8367bb08d6c 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/BaseExpressionToFieldHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/BaseExpressionToFieldHandler.java @@ -32,7 +32,9 @@ import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.ide.util.DirectoryChooserUtil; import com.intellij.ide.util.PackageUtil; 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.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.colors.EditorColors; @@ -70,7 +72,6 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.Set; public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase implements RefactoringActionHandler { private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.introduceField.BaseExpressionToFieldHandler"); @@ -152,15 +153,6 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase } final PsiType type = tempType; - final String fieldName = settings.getFieldName(); - final PsiElement anchorElementIfOne = tempAnchorElement; - final boolean replaceAll = settings.isReplaceAll(); - if (replaceAll) { - tempAnchorElement = anchorStatementIfAll; - } - final PsiElement anchorElement = tempAnchorElement; - - if (editor != null) { HighlightManager highlightManager = HighlightManager.getInstance(project); for (RangeHighlighter highlighter : highlighters) { @@ -168,194 +160,18 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase } } - PsiElement anchor = getNormalizedAnchor(anchorElement); - final Boolean outOfCodeBlockExtraction = selectedExpr.getUserData(ElementToWorkOn.OUT_OF_CODE_BLOCK); - boolean tempDeleteSelf = outOfCodeBlockExtraction != null; - if (element.getParent() instanceof PsiExpressionStatement && anchor.equals(anchorElement)) { - PsiStatement statement = (PsiStatement)element.getParent(); - if (statement.getParent() instanceof PsiCodeBlock) { - tempDeleteSelf = true; + final Runnable runnable = + new ConvertToFieldRunnable(selectedExpr, settings, type, occurrences, occurenceManager, + anchorStatementIfAll, tempAnchorElement, editor, + myParentClass); + + new WriteCommandAction(project, getRefactoringName()){ + @Override + protected void run(Result result) throws Throwable { + runnable.run(); } - } - final boolean deleteSelf = tempDeleteSelf; - - final Runnable runnable = new Runnable() { - public void run() { - try { - PsiExpression expr = selectedExpr; - InitializationPlace initializerPlace = settings.getInitializerPlace(); - final PsiLocalVariable localVariable = settings.getLocalVariable(); - final boolean deleteLocalVariable = settings.isDeleteLocalVariable(); - @Nullable PsiExpression initializer; - if (localVariable != null) { - initializer = localVariable.getInitializer(); - } - else { - initializer = expr; - } - - final PsiMethod enclosingConstructor = getEnclosingConstructor(myParentClass, anchorElement); - final PsiClass destClass = settings.getDestinationClass() == null ? myParentClass : settings.getDestinationClass(); - - if (!CommonRefactoringUtil.checkReadOnlyStatus(project, destClass.getContainingFile())) return; - - if (initializer != null) { - ChangeContextUtil.encodeContextInfo(initializer, true); - } - PsiField field = settings.isIntroduceEnumConstant() ? EnumConstantsUtil.createEnumConstant(destClass, fieldName, initializer) : createField(fieldName, type, initializer, initializerPlace == InitializationPlace.IN_FIELD_DECLARATION && initializer != null); - - PsiElement finalAnchorElement = null; - if (destClass == myParentClass) { - for (finalAnchorElement = anchorElement; - finalAnchorElement != null && finalAnchorElement.getParent() != destClass; - finalAnchorElement = finalAnchorElement.getParent()) { - - } - } - PsiMember anchorMember = finalAnchorElement instanceof PsiMember ? (PsiMember)finalAnchorElement : null; - setModifiers(field, settings, settings.isDeclareStatic()); - if ((anchorMember instanceof PsiField) && - anchorMember.hasModifierProperty(PsiModifier.STATIC) == field.hasModifierProperty(PsiModifier.STATIC)) { - field = (PsiField)destClass.addBefore(field, anchorMember); - } - else if (anchorMember instanceof PsiClassInitializer) { - field = (PsiField)destClass.addBefore(field, anchorMember); - destClass.addBefore(CodeEditUtil.createLineFeed(field.getManager()), anchorMember); - } - else { - final PsiField forwardReference = checkForwardRefs(initializer); - if (forwardReference != null) { - field = (PsiField)destClass.addAfter(field, forwardReference); - } else { - field = (PsiField)destClass.add(field); - } - } - if (!settings.isIntroduceEnumConstant()) { - VisibilityUtil.fixVisibility(occurrences, field, settings.getFieldVisibility()); - } - PsiStatement assignStatement = null; - PsiElement anchorElementHere = null; - if (initializerPlace == InitializationPlace.IN_CURRENT_METHOD && initializer != null || - initializerPlace == InitializationPlace.IN_CONSTRUCTOR && enclosingConstructor != null && initializer != null) { - if (replaceAll) { - if (enclosingConstructor != null) { - final PsiElement anchorInConstructor = occurenceManager.getAnchorStatementForAllInScope(enclosingConstructor); - anchorElementHere = anchorInConstructor != null ? anchorInConstructor : anchorStatementIfAll; - } - else { - anchorElementHere = anchorStatementIfAll; - } - } - else { - anchorElementHere = anchorElementIfOne; - } - assignStatement = createAssignment(field, initializer, anchorElementHere); - if (!IntroduceVariableBase.isLoopOrIf(anchorElementHere.getParent())) { - anchorElementHere.getParent().addBefore(assignStatement, getNormalizedAnchor(anchorElementHere)); - } - } - if (initializerPlace == InitializationPlace.IN_CONSTRUCTOR && initializer != null) { - addInitializationToConstructors(initializer, field, enclosingConstructor); - } - if (initializerPlace == InitializationPlace.IN_SETUP_METHOD && initializer != null) { - addInitializationToSetUp(initializer, field, occurenceManager, replaceAll); - } - if (expr.getParent() instanceof PsiParenthesizedExpression) { - expr = (PsiExpression)expr.getParent(); - } - if (outOfCodeBlockExtraction != null) { - final int endOffset = selectedExpr.getUserData(ElementToWorkOn.TEXT_RANGE).getEndOffset(); - PsiElement endElement = element.getContainingFile().findElementAt(endOffset); - while (true) { - final PsiElement parent = endElement.getParent(); - if (parent instanceof PsiClass) break; - endElement = parent; - } - element.getParent().deleteChildRange(element, PsiTreeUtil.skipSiblingsBackward(endElement, PsiWhiteSpace.class)); - } else if (deleteSelf) { - element.getParent().delete(); - } - - if (replaceAll) { - List array = new ArrayList(); - for (PsiExpression occurrence : occurrences) { - if (occurrence instanceof PsiExpression) { - occurrence = RefactoringUtil.outermostParenthesizedExpression(occurrence); - } - if (deleteSelf && occurrence.equals(expr)) continue; - final PsiElement replaced = RefactoringUtil.replaceOccurenceWithFieldRef(occurrence, field, destClass); - if (replaced != null) { - array.add(replaced); - } - } - - if (editor != null) { - if (!ApplicationManager.getApplication().isUnitTestMode()) { - PsiElement[] exprsToHighlight = PsiUtilBase.toPsiElementArray(array); - HighlightManager highlightManager = HighlightManager.getInstance(project); - highlightManager.addOccurrenceHighlights(editor, exprsToHighlight, highlightAttributes(), true, null); - WindowManager.getInstance().getStatusBar(project).setInfo(RefactoringBundle.message("press.escape.to.remove.the.highlighting")); - } - } - } - else { - if (!deleteSelf) { - expr = RefactoringUtil.outermostParenthesizedExpression(expr); - RefactoringUtil.replaceOccurenceWithFieldRef(expr, field, destClass); - } - } - - if (anchorElementHere != null && IntroduceVariableBase.isLoopOrIf(anchorElementHere.getParent())) { - IntroduceVariableBase.putStatementInLoopBody(assignStatement, anchorElementHere.getParent(), anchorElementHere); - } - - - if (localVariable != null) { - if (deleteLocalVariable) { - localVariable.normalizeDeclaration(); - localVariable.getParent().delete(); - } - } - - if (initializer != null) { - ChangeContextUtil.clearContextInfo(initializer); - } - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - } - - private PsiField checkForwardRefs(PsiExpression initializer) { - final PsiField[] refConstantFields = new PsiField[1]; - initializer.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitReferenceExpression(PsiReferenceExpression expression) { - super.visitReferenceExpression(expression); - final PsiElement resolve = expression.resolve(); - if (resolve instanceof PsiField && - ((PsiField)resolve).hasModifierProperty(PsiModifier.FINAL) && - PsiTreeUtil.isAncestor(myParentClass, resolve, false) && ((PsiField)resolve).hasInitializer()) { - if (refConstantFields[0] == null || refConstantFields[0].getTextOffset() < resolve.getTextOffset()) { - refConstantFields[0] = (PsiField)resolve; - } - } - } - }); - return refConstantFields[0]; - } - }; - - CommandProcessor.getInstance().executeCommand( - project, - new Runnable() { - public void run() { - ApplicationManager.getApplication().runWriteAction(runnable); - } - }, - getRefactoringName(), null - ); + }.execute(); return true; } @@ -452,10 +268,12 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase return null; } - private void addInitializationToSetUp(final PsiExpression initializer, - final PsiField field, - final OccurenceManager occurenceManager, final boolean replaceAll) throws IncorrectOperationException { - final PsiMethod setupMethod = TestUtil.findOrCreateSetUpMethod(myParentClass); + private static void addInitializationToSetUp(final PsiExpression initializer, + final PsiField field, + final OccurenceManager occurenceManager, + final boolean replaceAll, + final PsiClass parentClass) throws IncorrectOperationException { + final PsiMethod setupMethod = TestUtil.findOrCreateSetUpMethod(parentClass); assert setupMethod != null; @@ -467,7 +285,7 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase } final PsiExpressionStatement expressionStatement = - (PsiExpressionStatement)JavaPsiFacade.getInstance(myParentClass.getProject()).getElementFactory() + (PsiExpressionStatement)JavaPsiFacade.getInstance(parentClass.getProject()).getElementFactory() .createStatementFromText(field.getName() + "= expr;", null); PsiAssignmentExpression expr = (PsiAssignmentExpression)expressionStatement.getExpression(); final PsiExpression rExpression = expr.getRExpression(); @@ -479,7 +297,9 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase body.addBefore(expressionStatement, anchor); } - private void addInitializationToConstructors(PsiExpression initializerExpression, PsiField field, PsiMethod enclosingConstructor) { + private static void addInitializationToConstructors(PsiExpression initializerExpression, + PsiField field, + PsiMethod enclosingConstructor, final PsiClass parentClass) { try { PsiClass aClass = field.getContainingClass(); PsiMethod[] constructors = aClass.getConstructors(); @@ -502,7 +322,7 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase } } } - PsiStatement assignment = createAssignment(field, initializerExpression, body.getLastChild()); + PsiStatement assignment = createAssignment(field, initializerExpression, body.getLastChild(), parentClass); assignment = (PsiStatement) body.add(assignment); ChangeContextUtil.decodeContextInfo(assignment, field.getContainingClass(), RefactoringUtil.createThisExpression(field.getManager(), null)); @@ -512,7 +332,7 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase PsiElementFactory factory = JavaPsiFacade.getInstance(field.getProject()).getElementFactory(); PsiMethod constructor = (PsiMethod)aClass.add(factory.createConstructor()); final PsiCodeBlock body = constructor.getBody(); - PsiStatement assignment = createAssignment(field, initializerExpression, body.getLastChild()); + PsiStatement assignment = createAssignment(field, initializerExpression, body.getLastChild(), parentClass); assignment = (PsiStatement) body.add(assignment); ChangeContextUtil.decodeContextInfo(assignment, field.getContainingClass(), RefactoringUtil.createThisExpression(field.getManager(), null)); @@ -523,7 +343,10 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase } } - private PsiField createField(String fieldName, PsiType type, PsiExpression initializerExpr, boolean includeInitializer) { + private static PsiField createField(String fieldName, + PsiType type, + PsiExpression initializerExpr, + boolean includeInitializer, final PsiClass parentClass) { @NonNls StringBuilder pattern = new StringBuilder(); pattern.append("private int "); pattern.append(fieldName); @@ -531,7 +354,7 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase pattern.append("=0"); } pattern.append(";"); - PsiManager psiManager = myParentClass.getManager(); + PsiManager psiManager = parentClass.getManager(); PsiElementFactory factory = JavaPsiFacade.getInstance(psiManager.getProject()).getElementFactory(); try { PsiField field = factory.createFieldFromText(pattern.toString(), null); @@ -548,10 +371,13 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase } } - private PsiStatement createAssignment(PsiField field, PsiExpression initializerExpr, PsiElement context) { + private static PsiStatement createAssignment(PsiField field, + PsiExpression initializerExpr, + PsiElement context, + final PsiClass parentClass) { try { @NonNls String pattern = "x=0;"; - PsiManager psiManager = myParentClass.getManager(); + PsiManager psiManager = parentClass.getManager(); PsiElementFactory factory = JavaPsiFacade.getInstance(psiManager.getProject()).getElementFactory(); PsiExpressionStatement statement = (PsiExpressionStatement)factory.createStatementFromText(pattern, null); statement = (PsiExpressionStatement)CodeStyleManager.getInstance(psiManager.getProject()).reformat(statement); @@ -733,4 +559,230 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase return myTargetClass; } } + + public static class ConvertToFieldRunnable implements Runnable { + private PsiExpression mySelectedExpr; + private final Settings mySettings; + private final PsiElement myAnchorElement; + private final Project myProject; + private final String myFieldName; + private final PsiType myType; + private final PsiExpression[] myOccurrences; + private final boolean myReplaceAll; + private final OccurenceManager myOccurenceManager; + private final PsiElement myAnchorStatementIfAll; + private final PsiElement myAnchorElementIfOne; + private final Boolean myOutOfCodeBlockExtraction; + private final PsiElement myElement; + private boolean myDeleteSelf; + private final Editor myEditor; + private final PsiClass myParentClass; + + private PsiField myField; + + public ConvertToFieldRunnable(PsiExpression selectedExpr, + Settings settings, + PsiType type, + PsiExpression[] occurrences, + OccurenceManager occurenceManager, + PsiElement anchorStatementIfAll, + PsiElement anchorElementIfOne, + Editor editor, + PsiClass parentClass) { + mySelectedExpr = selectedExpr; + mySettings = settings; + myAnchorElement = settings.isReplaceAll() ? anchorStatementIfAll : anchorElementIfOne; + myProject = selectedExpr.getProject(); + myFieldName = settings.getFieldName(); + myType = type; + myOccurrences = occurrences; + myReplaceAll = settings.isReplaceAll(); + myOccurenceManager = occurenceManager; + myAnchorStatementIfAll = anchorStatementIfAll; + myAnchorElementIfOne = anchorElementIfOne; + myOutOfCodeBlockExtraction = selectedExpr.getUserData(ElementToWorkOn.OUT_OF_CODE_BLOCK); + myDeleteSelf = myOutOfCodeBlockExtraction != null; + myElement = getPhysicalElement(selectedExpr); + if (myElement.getParent() instanceof PsiExpressionStatement && getNormalizedAnchor(myAnchorElement).equals(myAnchorElement)) { + PsiStatement statement = (PsiStatement)myElement.getParent(); + if (statement.getParent() instanceof PsiCodeBlock) { + myDeleteSelf = true; + } + } + + myEditor = editor; + myParentClass = parentClass; + } + + public void run() { + try { + InitializationPlace initializerPlace = mySettings.getInitializerPlace(); + final PsiLocalVariable localVariable = mySettings.getLocalVariable(); + final boolean deleteLocalVariable = mySettings.isDeleteLocalVariable(); + @Nullable PsiExpression initializer; + if (localVariable != null) { + initializer = localVariable.getInitializer(); + } + else { + initializer = mySelectedExpr; + } + + final PsiMethod enclosingConstructor = getEnclosingConstructor(myParentClass, myAnchorElement); + final PsiClass destClass = mySettings.getDestinationClass() == null ? myParentClass : mySettings.getDestinationClass(); + + if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, destClass.getContainingFile())) return; + + if (initializer != null) { + ChangeContextUtil.encodeContextInfo(initializer, true); + } + myField = mySettings.isIntroduceEnumConstant() ? EnumConstantsUtil.createEnumConstant(destClass, myFieldName, initializer) : + createField(myFieldName, myType, initializer, initializerPlace == InitializationPlace.IN_FIELD_DECLARATION && initializer != null, + myParentClass); + + PsiElement finalAnchorElement = null; + if (destClass == myParentClass) { + for (finalAnchorElement = myAnchorElement; + finalAnchorElement != null && finalAnchorElement.getParent() != destClass; + finalAnchorElement = finalAnchorElement.getParent()) { + + } + } + PsiMember anchorMember = finalAnchorElement instanceof PsiMember ? (PsiMember)finalAnchorElement : null; + setModifiers(myField, mySettings, mySettings.isDeclareStatic()); + if ((anchorMember instanceof PsiField) && + anchorMember.hasModifierProperty(PsiModifier.STATIC) == myField.hasModifierProperty(PsiModifier.STATIC)) { + myField = (PsiField)destClass.addBefore(myField, anchorMember); + } + else if (anchorMember instanceof PsiClassInitializer) { + myField = (PsiField)destClass.addBefore(myField, anchorMember); + destClass.addBefore(CodeEditUtil.createLineFeed(myField.getManager()), anchorMember); + } + else { + final PsiField forwardReference = checkForwardRefs(initializer); + if (forwardReference != null) { + myField = (PsiField)destClass.addAfter(myField, forwardReference); + } else { + myField = (PsiField)destClass.add(myField); + } + } + if (!mySettings.isIntroduceEnumConstant()) { + VisibilityUtil.fixVisibility(myOccurrences, myField, mySettings.getFieldVisibility()); + } + PsiStatement assignStatement = null; + PsiElement anchorElementHere = null; + if (initializerPlace == InitializationPlace.IN_CURRENT_METHOD && initializer != null || + initializerPlace == InitializationPlace.IN_CONSTRUCTOR && enclosingConstructor != null && initializer != null) { + if (myReplaceAll) { + if (enclosingConstructor != null) { + final PsiElement anchorInConstructor = myOccurenceManager.getAnchorStatementForAllInScope(enclosingConstructor); + anchorElementHere = anchorInConstructor != null ? anchorInConstructor : myAnchorStatementIfAll; + } + else { + anchorElementHere = myAnchorStatementIfAll; + } + } + else { + anchorElementHere = myAnchorElementIfOne; + } + assignStatement = createAssignment(myField, initializer, anchorElementHere, myParentClass); + if (!IntroduceVariableBase.isLoopOrIf(anchorElementHere.getParent())) { + anchorElementHere.getParent().addBefore(assignStatement, getNormalizedAnchor(anchorElementHere)); + } + } + if (initializerPlace == InitializationPlace.IN_CONSTRUCTOR && initializer != null) { + addInitializationToConstructors(initializer, myField, enclosingConstructor, myParentClass); + } + if (initializerPlace == InitializationPlace.IN_SETUP_METHOD && initializer != null) { + addInitializationToSetUp(initializer, myField, myOccurenceManager, myReplaceAll, myParentClass); + } + if (mySelectedExpr.getParent() instanceof PsiParenthesizedExpression) { + mySelectedExpr = (PsiExpression)mySelectedExpr.getParent(); + } + if (myOutOfCodeBlockExtraction != null) { + final int endOffset = mySelectedExpr.getUserData(ElementToWorkOn.TEXT_RANGE).getEndOffset(); + PsiElement endElement = myElement.getContainingFile().findElementAt(endOffset); + while (true) { + final PsiElement parent = endElement.getParent(); + if (parent instanceof PsiClass) break; + endElement = parent; + } + myElement.getParent().deleteChildRange(myElement, PsiTreeUtil.skipSiblingsBackward(endElement, PsiWhiteSpace.class)); + } else if (myDeleteSelf) { + myElement.getParent().delete(); + } + + if (myReplaceAll) { + List array = new ArrayList(); + for (PsiExpression occurrence : myOccurrences) { + if (occurrence instanceof PsiExpression) { + occurrence = RefactoringUtil.outermostParenthesizedExpression(occurrence); + } + if (myDeleteSelf && occurrence.equals(mySelectedExpr)) continue; + final PsiElement replaced = RefactoringUtil.replaceOccurenceWithFieldRef(occurrence, myField, destClass); + if (replaced != null) { + array.add(replaced); + } + } + + if (myEditor != null) { + if (!ApplicationManager.getApplication().isUnitTestMode()) { + PsiElement[] exprsToHighlight = PsiUtilBase.toPsiElementArray(array); + HighlightManager highlightManager = HighlightManager.getInstance(myProject); + highlightManager.addOccurrenceHighlights(myEditor, exprsToHighlight, highlightAttributes(), true, null); + WindowManager + .getInstance().getStatusBar(myProject).setInfo(RefactoringBundle.message("press.escape.to.remove.the.highlighting")); + } + } + } + else { + if (!myDeleteSelf) { + mySelectedExpr = RefactoringUtil.outermostParenthesizedExpression(mySelectedExpr); + RefactoringUtil.replaceOccurenceWithFieldRef(mySelectedExpr, myField, destClass); + } + } + + if (anchorElementHere != null && IntroduceVariableBase.isLoopOrIf(anchorElementHere.getParent())) { + IntroduceVariableBase.putStatementInLoopBody(assignStatement, anchorElementHere.getParent(), anchorElementHere); + } + + + if (localVariable != null) { + if (deleteLocalVariable) { + localVariable.normalizeDeclaration(); + localVariable.getParent().delete(); + } + } + + if (initializer != null) { + ChangeContextUtil.clearContextInfo(initializer); + } + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + + private PsiField checkForwardRefs(PsiExpression initializer) { + final PsiField[] refConstantFields = new PsiField[1]; + initializer.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + final PsiElement resolve = expression.resolve(); + if (resolve instanceof PsiField && + ((PsiField)resolve).hasModifierProperty(PsiModifier.FINAL) && + PsiTreeUtil.isAncestor(myParentClass, resolve, false) && ((PsiField)resolve).hasInitializer()) { + if (refConstantFields[0] == null || refConstantFields[0].getTextOffset() < resolve.getTextOffset()) { + refConstantFields[0] = (PsiField)resolve; + } + } + } + }); + return refConstantFields[0]; + } + + public PsiField getField() { + return myField; + } + } } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/InitializerPlaceChooser.java b/java/java-impl/src/com/intellij/refactoring/introduceField/InitializerPlaceChooser.java deleted file mode 100644 index d8f7a95c1fd6..000000000000 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/InitializerPlaceChooser.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * 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.introduceField; - -import com.intellij.codeInsight.TestUtil; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.psi.*; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.refactoring.RefactoringBundle; -import com.intellij.ui.IdeBorderFactory; - -import javax.swing.*; -import java.awt.event.ItemListener; - -public class InitializerPlaceChooser { - private static final Logger LOG = Logger.getInstance("#" + InitializerPlaceChooser.class.getName()); - static BaseExpressionToFieldHandler.InitializationPlace ourLastInitializerPlace; - - PsiClass myParentClass; - - PsiExpression myInitializerExpression; - - boolean myAllowInitInMethod; - boolean myAllowInitInMethodIfAll; - - JRadioButton myRbInConstructor; - JRadioButton myRbInCurrentMethod; - JRadioButton myRbInFieldDeclaration; - JRadioButton myRbInSetUp; - - public InitializerPlaceChooser(PsiClass parentClass, - PsiExpression initializerExpression, - boolean allowInitInMethod, boolean allowInitInMethodIfAll) { - myParentClass = parentClass; - myInitializerExpression = initializerExpression; - myAllowInitInMethod = allowInitInMethod; - myAllowInitInMethodIfAll = allowInitInMethodIfAll; - } - - void updateInitializerPlace(boolean replaceAll) { - if (myAllowInitInMethod) { - myRbInCurrentMethod.setEnabled(myAllowInitInMethodIfAll || !replaceAll); - if (!myRbInCurrentMethod.isEnabled() && myRbInCurrentMethod.isSelected()) { - myRbInCurrentMethod.setSelected(false); - myRbInFieldDeclaration.setSelected(true); - } - } - } - - void initializeControls(PsiExpression initializerExpression) { - if (initializerExpression != null) { - if (!setEnabledInitializationPlaces(initializerExpression, initializerExpression)) { - myRbInFieldDeclaration.setEnabled(false); - myRbInConstructor.setEnabled(false); - if (myRbInSetUp != null) myRbInSetUp.setEnabled(false); - } - if (!myAllowInitInMethod) { - myRbInCurrentMethod.setEnabled(false); - } - } - else { - myRbInConstructor.setEnabled(false); - myRbInCurrentMethod.setEnabled(false); - myRbInFieldDeclaration.setEnabled(false); - if (myRbInSetUp != null) myRbInSetUp.setEnabled(false); - } - - final PsiMethod setUpMethod = TestUtil.findSetUpMethod(myParentClass); - if (myInitializerExpression != null && PsiTreeUtil.isAncestor(setUpMethod, myInitializerExpression, false) && myRbInSetUp.isEnabled() || - ourLastInitializerPlace == BaseExpressionToFieldHandler.InitializationPlace.IN_SETUP_METHOD && - TestUtil.isTestClass(myParentClass) && - myRbInSetUp.isEnabled()) { - myRbInSetUp.setSelected(true); - } - else if (ourLastInitializerPlace == BaseExpressionToFieldHandler.InitializationPlace.IN_CONSTRUCTOR) { - if (myRbInConstructor.isEnabled()) { - myRbInConstructor.setSelected(true); - } - else { - selectInCurrentMethod(); - } - } - else if (ourLastInitializerPlace == BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION) { - if (myRbInFieldDeclaration.isEnabled()) { - myRbInFieldDeclaration.setSelected(true); - } - else { - selectInCurrentMethod(); - } - } - else { - selectInCurrentMethod(); - } - } - - void selectInCurrentMethod() { - if (myRbInCurrentMethod.isEnabled()) { - myRbInCurrentMethod.setSelected(true); - } - else if (myRbInFieldDeclaration.isEnabled()) { - myRbInFieldDeclaration.setSelected(true); - } - else { - myRbInCurrentMethod.setSelected(true); - } - } - - public BaseExpressionToFieldHandler.InitializationPlace getInitializerPlace() { - if (myRbInConstructor.isSelected()) { - return BaseExpressionToFieldHandler.InitializationPlace.IN_CONSTRUCTOR; - } - if (myRbInCurrentMethod.isSelected()) { - return BaseExpressionToFieldHandler.InitializationPlace.IN_CURRENT_METHOD; - } - if (myRbInFieldDeclaration.isSelected()) { - return BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION; - } - if (myRbInSetUp != null && myRbInSetUp.isSelected()) { - return BaseExpressionToFieldHandler.InitializationPlace.IN_SETUP_METHOD; - } - - LOG.assertTrue(false); - return BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION; - } - - JComponent createInitializerPlacePanel() { - - final JPanel initializationPanel = new JPanel(); - initializationPanel.setBorder(IdeBorderFactory.createTitledBorder(RefactoringBundle.message("initialize.in.border.title"))); - initializationPanel.setLayout(new BoxLayout(initializationPanel, BoxLayout.Y_AXIS)); - - myRbInCurrentMethod = new JRadioButton(); - myRbInCurrentMethod.setFocusable(false); - myRbInCurrentMethod.setText(RefactoringBundle.message("current.method.radio")); - myRbInCurrentMethod.setEnabled(myAllowInitInMethod); - myRbInFieldDeclaration = new JRadioButton(); - myRbInFieldDeclaration.setFocusable(false); - myRbInFieldDeclaration.setText(RefactoringBundle.message("field.declaration.radio")); - myRbInConstructor = new JRadioButton(); - myRbInConstructor.setFocusable(false); - myRbInConstructor.setText(RefactoringBundle.message("class.constructors.radio")); - - initializationPanel.add(myRbInCurrentMethod); - initializationPanel.add(myRbInFieldDeclaration); - initializationPanel.add(myRbInConstructor); - - if (TestUtil.isTestClass(myParentClass)) { - myRbInSetUp = new JRadioButton(); - myRbInSetUp.setFocusable(false); - myRbInSetUp.setText(RefactoringBundle.message("setup.method.radio")); - initializationPanel.add(myRbInSetUp); - } - - ButtonGroup bg = new ButtonGroup(); - bg.add(myRbInCurrentMethod); - bg.add(myRbInFieldDeclaration); - bg.add(myRbInConstructor); - if (myRbInSetUp != null) bg.add(myRbInSetUp); - - return initializationPanel; - } - - static boolean setEnabledInitializationPlaces(PsiElement initializerPart, PsiElement initializer) { - if (initializerPart instanceof PsiReferenceExpression) { - PsiReferenceExpression refExpr = (PsiReferenceExpression)initializerPart; - if (refExpr.getQualifierExpression() == null) { - PsiElement refElement = refExpr.resolve(); - if (refElement == null || - (refElement instanceof PsiLocalVariable || refElement instanceof PsiParameter) && - !PsiTreeUtil.isAncestor(initializer, refElement, true)) { - return false; - } - } - } - PsiElement[] children = initializerPart.getChildren(); - for (PsiElement child : children) { - if (!setEnabledInitializationPlaces(child, initializer)) return false; - } - return true; - } - - boolean allowFinal(boolean willBeDeclaredStatic, boolean isCurrentMethodConstructor) { - boolean allowFinal = myRbInFieldDeclaration.isSelected() || (myRbInConstructor.isSelected() && !willBeDeclaredStatic); - if (myRbInCurrentMethod.isSelected() && isCurrentMethodConstructor) { - final PsiMethod[] constructors = myParentClass.getConstructors(); - allowFinal = constructors.length <= 1; - } - return allowFinal; - } - - void addItemListener(ItemListener listener) { - myRbInConstructor.addItemListener(listener); - myRbInCurrentMethod.addItemListener(listener); - myRbInFieldDeclaration.addItemListener(listener); - if (myRbInSetUp != null) myRbInSetUp.addItemListener(listener); - } -} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceFieldPopup.java b/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceFieldPopup.java new file mode 100644 index 000000000000..a6eac2f69237 --- /dev/null +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceFieldPopup.java @@ -0,0 +1,381 @@ +/* + * 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.introduceField; + +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.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.RangeMarker; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.SuggestedNameInfo; +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.ui.TypeSelectorManagerImpl; +import com.intellij.refactoring.util.occurences.OccurenceManager; +import com.intellij.ui.TitlePanel; + +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 { + + private PsiLocalVariable myLocalVariable; + private PsiClass myParentClass; + private boolean myStatic; + private PsiExpression[] myOccurrences; + private PsiExpression myInitializerExpression; + private final Editor myEditor; + private Project myProject; + + private final TypeSelectorManagerImpl myTypeSelectorManager; + private final PsiElement myAnchorElement; + private final PsiElement myAnchorElementIfAll; + private final OccurenceManager myOccurenceManager; + private List myOccurrenceMarkers; + + private final IntroduceFieldCentralPanel myIntroduceFieldPanel; + + private JPanel myWholePanel; + private String myExprText; + private RangeMarker myExprMarker; + private String myFieldName; + + private boolean myInitListeners = false; + + public InplaceIntroduceFieldPopup(PsiLocalVariable localVariable, + PsiClass parentClass, + boolean aStatic, + boolean currentMethodConstructor, PsiExpression[] occurrences, + PsiExpression initializerExpression, + TypeSelectorManagerImpl typeSelectorManager, + Editor editor, + final boolean allowInitInMethod, + boolean allowInitInMethodIfAll, final PsiElement anchorElement, + final PsiElement anchorElementIfAll, + final OccurenceManager occurenceManager) { + myLocalVariable = localVariable; + myParentClass = parentClass; + myStatic = aStatic; + myOccurrences = occurrences; + myInitializerExpression = initializerExpression; + myExprText = myInitializerExpression != null ? myInitializerExpression.getText() : null; + myExprMarker = myInitializerExpression != null ? editor.getDocument().createRangeMarker(myInitializerExpression.getTextRange()) : null; + myTypeSelectorManager = typeSelectorManager; + myAnchorElement = anchorElement; + myAnchorElementIfAll = anchorElementIfAll; + myOccurenceManager = occurenceManager; + myProject = myLocalVariable != null ? myLocalVariable.getProject() : myInitializerExpression.getProject(); + myEditor = editor; + + myIntroduceFieldPanel = + new IntroduceFieldCentralPanel(parentClass, initializerExpression, localVariable, currentMethodConstructor, localVariable != null, aStatic, + myOccurrences.length, allowInitInMethod, allowInitInMethodIfAll, typeSelectorManager); + + myWholePanel = new JPanel(new GridBagLayout()); + myWholePanel.setBorder(null); + + final TitlePanel titlePanel = new TitlePanel(); + titlePanel.setBorder(null); + titlePanel.setText(IntroduceFieldHandler.REFACTORING_NAME); + + GridBagConstraints gc = + new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, + new Insets(0,0,0,0), 0, 0); + + myWholePanel.add(titlePanel, gc); + + gc.gridy++; + gc.insets.top = 5; + + myWholePanel.add(myIntroduceFieldPanel.createCenterPanel(), gc); + myIntroduceFieldPanel.initializeControls(initializerExpression); + myIntroduceFieldPanel.addOccurrenceListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + final TemplateState templateState = TemplateManagerImpl.getTemplateState(myEditor); + if (templateState != null) { + templateState.gotoEnd(true); + startTemplate(myIntroduceFieldPanel.isReplaceAllOccurrences()); + } + } + }); + + } + + public List getOccurrenceMarkers() { + if (myOccurrenceMarkers == null) { + myOccurrenceMarkers = new ArrayList(); + for (PsiExpression occurrence : myOccurrences) { + myOccurrenceMarkers.add(myEditor.getDocument().createRangeMarker(occurrence.getTextRange())); + } + } + return myOccurrenceMarkers; + } + + public void startTemplate() { + startTemplate(false); + } + + public void startTemplate(final boolean replaceAllOccurrences) { + CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { + public void run() { + myTypeSelectorManager.setAllOccurences(replaceAllOccurrences); + + final PsiType defaultType = myTypeSelectorManager.getTypeSelector().getSelectedType(); + + final SuggestedNameInfo suggestedNameInfo = + IntroduceFieldDialog.createGenerator(myStatic, myLocalVariable, myInitializerExpression, myLocalVariable != null) + .getSuggestedNameInfo(defaultType); + + final PsiField field = createFieldToStartTemplateOn(suggestedNameInfo.names, defaultType, null); + if (field != null) { + myEditor.getCaretModel().moveToOffset(field.getTextOffset()); + final LinkedHashSet nameSuggestions = new LinkedHashSet(); + nameSuggestions.add(field.getName()); + nameSuggestions.addAll(Arrays.asList(suggestedNameInfo.names)); + final VariableInplaceRenamer renamer = new FieldInplaceIntroducer(field); + renamer.performInplaceRename(false, nameSuggestions); + } + } + }, IntroduceFieldHandler.REFACTORING_NAME, null); + } + + private PsiField createFieldToStartTemplateOn(final String[] names, + final PsiType defaultType, + final PsiElement anchor) { + 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); + field = anchor != null ? (PsiField)myParentClass.addBefore(field, anchor) : (PsiField)myParentClass.add(field); + PsiUtil.setModifierProperty(field, PsiModifier.FINAL, myIntroduceFieldPanel.isDeclareFinal()); + return field; + } + }); + } + + class FieldInplaceIntroducer extends AbstractInplaceIntroducer { + + private RangeMarker myFieldRangeStart; + + + private SmartTypePointer myDefaultParameterTypePointer; + + private SmartTypePointer myFieldTypePointer; + + public FieldInplaceIntroducer(PsiVariable psiVariable) { + super(myProject, new TypeExpression(myProject, myTypeSelectorManager.getTypesForAll()), + myEditor, psiVariable, false, + myTypeSelectorManager.getTypesForAll().length > 1, + myInitializerExpression != null ? myEditor.getDocument().createRangeMarker(myInitializerExpression.getTextRange()) : null, InplaceIntroduceFieldPopup.this.getOccurrenceMarkers()); + 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; + } + + @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()); + JavaRefactoringSettings.getInstance().INTRODUCE_FIELD_VISIBILITY = myIntroduceFieldPanel.getFieldVisibility(); + } + + @Override + protected PsiElement checkLocalScope() { + return myParentClass; + } + + @Override + protected JComponent getComponent() { + if (!myInitListeners) { + myInitListeners = true; + myIntroduceFieldPanel.addVisibilityListener(new VisibilityListener()); + final FinalListener finalListener = new FinalListener(myProject); + myIntroduceFieldPanel.addFinalListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + finalListener.perform(myIntroduceFieldPanel.isDeclareFinal()); + } + }); + } + + return myWholePanel; + } + + @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) { + 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); + 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, + myAnchorElementIfAll, myAnchorElement, myEditor, + myParentClass); + convertToFieldRunnable.run(); + } + } + super.moveOffsetAfter(success); + } + + @Override + public void finish() { + super.finish(); + final PsiField psiField = (PsiField)getVariable(); + LOG.assertTrue(psiField != null); + 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); + myInitializerExpression = restoreExpression(containingFile, psiField, elementFactory, getExprMarker(), myExprText); + if (myInitializerExpression != null) { + myExprMarker = myEditor.getDocument().createRangeMarker(myInitializerExpression.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] = myInitializerExpression; + continue; + } + final PsiExpression psiExpression = restoreExpression(containingFile, psiField, elementFactory, marker, myExprText); + if (psiExpression != null) { + myOccurrences[i] = psiExpression; + } + } + myOccurrenceMarkers = null; + if (psiField.isValid()) { + psiField.delete(); + } + } + }); + } + + private class VisibilityListener implements ChangeListener { + @Override + public void stateChanged(ChangeEvent e) { + new WriteCommandAction(myProject) { + @Override + protected void run(Result result) throws Throwable { + final PsiVariable variable = getVariable(); + LOG.assertTrue(variable != null); + final PsiModifierList modifierList = variable.getModifierList(); + LOG.assertTrue(modifierList != null); + int textOffset = modifierList.getTextOffset(); + + final Document document = myEditor.getDocument(); + String visibility = myIntroduceFieldPanel.getFieldVisibility(); + if (visibility == PsiModifier.PACKAGE_LOCAL) { + visibility = ""; + } + 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(); + } + + final int startOffset = textOffset + Math.max(idx, 0); + final int endOffset = textOffset + (idx > -1 ? length : 0); + + document.replaceString(startOffset, endOffset, visibility + (startOffset == endOffset ? " " : "")); + } + }.execute(); + } + } + } +} diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldCentralPanel.java b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldCentralPanel.java new file mode 100644 index 000000000000..823168cc32d7 --- /dev/null +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldCentralPanel.java @@ -0,0 +1,394 @@ +/* + * 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.introduceField; + +import com.intellij.codeInsight.TestUtil; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.JavaRefactoringSettings; +import com.intellij.refactoring.RefactoringBundle; +import com.intellij.refactoring.ui.JavaVisibilityPanel; +import com.intellij.refactoring.ui.TypeSelectorManager; +import com.intellij.ui.IdeBorderFactory; +import com.intellij.ui.NonFocusableCheckBox; +import com.intellij.ui.StateRestoringCheckBox; + +import javax.swing.*; +import javax.swing.event.ChangeListener; +import java.awt.*; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +/** + * User: anna + * Date: 3/16/11 + */ +public class IntroduceFieldCentralPanel { + private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.introduceField.IntroduceFieldDialog"); + + private static boolean ourLastCbFinalState = false; + private static BaseExpressionToFieldHandler.InitializationPlace ourLastInitializerPlace; + + private final PsiClass myParentClass; + private final PsiExpression myInitializerExpression; + private final PsiLocalVariable myLocalVariable; + private final boolean myIsCurrentMethodConstructor; + private final boolean myIsInvokedOnDeclaration; + private final boolean myWillBeDeclaredStatic; + private final int myOccurrencesCount; + private final boolean myAllowInitInMethod; + private final boolean myAllowInitInMethodIfAll; + private final TypeSelectorManager myTypeSelectorManager; + + + private JCheckBox myCbReplaceAll; + private StateRestoringCheckBox myCbDeleteVariable; + private StateRestoringCheckBox myCbFinal; + + private JRadioButton myRbInConstructor; + private JRadioButton myRbInCurrentMethod; + private JRadioButton myRbInFieldDeclaration; + private JRadioButton myRbInSetUp; + + private JavaVisibilityPanel myVisibilityPanel; + + public IntroduceFieldCentralPanel(PsiClass parentClass, + PsiExpression initializerExpression, + PsiLocalVariable localVariable, + boolean isCurrentMethodConstructor, boolean isInvokedOnDeclaration, boolean willBeDeclaredStatic, + int occurrencesCount, boolean allowInitInMethod, boolean allowInitInMethodIfAll, + TypeSelectorManager typeSelectorManager) { + myParentClass = parentClass; + myInitializerExpression = initializerExpression; + myLocalVariable = localVariable; + myIsCurrentMethodConstructor = isCurrentMethodConstructor; + myIsInvokedOnDeclaration = isInvokedOnDeclaration; + myWillBeDeclaredStatic = willBeDeclaredStatic; + myOccurrencesCount = occurrencesCount; + myAllowInitInMethod = allowInitInMethod; + myAllowInitInMethodIfAll = allowInitInMethodIfAll; + myTypeSelectorManager = typeSelectorManager; + } + + void initializeControls(PsiExpression initializerExpression) { + if (initializerExpression != null) { + setEnabledInitializationPlaces(initializerExpression, initializerExpression); + if (!myAllowInitInMethod) { + myRbInCurrentMethod.setEnabled(false); + } + } else { + myRbInConstructor.setEnabled(false); + myRbInCurrentMethod.setEnabled(false); + myRbInFieldDeclaration.setEnabled(false); + if (myRbInSetUp != null) myRbInSetUp.setEnabled(false); + } + + final PsiMethod setUpMethod = TestUtil.findSetUpMethod(myParentClass); + if (myInitializerExpression != null && PsiTreeUtil.isAncestor(setUpMethod, myInitializerExpression, false) && myRbInSetUp.isEnabled() || + ourLastInitializerPlace == BaseExpressionToFieldHandler.InitializationPlace.IN_SETUP_METHOD && TestUtil.isTestClass(myParentClass) && myRbInSetUp.isEnabled()) { + myRbInSetUp.setSelected(true); + } + else if (ourLastInitializerPlace == BaseExpressionToFieldHandler.InitializationPlace.IN_CONSTRUCTOR) { + if (myRbInConstructor.isEnabled()) { + myRbInConstructor.setSelected(true); + } else { + selectInCurrentMethod(); + } + } else if (ourLastInitializerPlace == BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION) { + if (myRbInFieldDeclaration.isEnabled()) { + myRbInFieldDeclaration.setSelected(true); + } else { + selectInCurrentMethod(); + } + } else { + selectInCurrentMethod(); + } + String ourLastVisibility = JavaRefactoringSettings.getInstance().INTRODUCE_FIELD_VISIBILITY; + myVisibilityPanel.setVisibility(ourLastVisibility); + myCbFinal.setSelected(myCbFinal.isEnabled() && ourLastCbFinalState); + } + + private void selectInCurrentMethod() { + if (myRbInCurrentMethod.isEnabled()) { + myRbInCurrentMethod.setSelected(true); + } + else if (myRbInFieldDeclaration.isEnabled()) { + myRbInFieldDeclaration.setSelected(true); + } + else { + myRbInCurrentMethod.setSelected(true); + } + } + + + public BaseExpressionToFieldHandler.InitializationPlace getInitializerPlace() { + if (myRbInConstructor.isSelected()) { + return BaseExpressionToFieldHandler.InitializationPlace.IN_CONSTRUCTOR; + } + if (myRbInCurrentMethod.isSelected()) { + return BaseExpressionToFieldHandler.InitializationPlace.IN_CURRENT_METHOD; + } + if (myRbInFieldDeclaration.isSelected()) { + return BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION; + } + if (myRbInSetUp != null && myRbInSetUp.isSelected()) { + return BaseExpressionToFieldHandler.InitializationPlace.IN_SETUP_METHOD; + } + + LOG.assertTrue(false); + return BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION; + } + + + public String getFieldVisibility() { + return myVisibilityPanel.getVisibility(); + } + + public boolean isReplaceAllOccurrences() { + if (myIsInvokedOnDeclaration) return true; + if (myOccurrencesCount <= 1) return false; + return myCbReplaceAll.isSelected(); + } + + public boolean isDeleteVariable() { + if (myIsInvokedOnDeclaration) return true; + if (myCbDeleteVariable == null) return false; + return myCbDeleteVariable.isSelected(); + } + + public boolean isDeclareFinal() { + return myCbFinal.isSelected(); + } + + + + protected JComponent createCenterPanel() { + JPanel panel = new JPanel(new GridBagLayout()); + GridBagConstraints gbConstraints = new GridBagConstraints(); + gbConstraints.fill = GridBagConstraints.HORIZONTAL; + gbConstraints.weightx = 1; + gbConstraints.weighty = 0; + gbConstraints.gridwidth = 1; + gbConstraints.gridx = 0; + gbConstraints.gridy = 0; + final Insets standardInsets = new Insets(0, 0, 0, 0); + gbConstraints.insets = standardInsets; + + panel.add(createInitializerPlacePanel(), gbConstraints); + ItemListener itemListener = new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if (myCbReplaceAll != null && myAllowInitInMethod) { + myRbInCurrentMethod.setEnabled(myAllowInitInMethodIfAll || !myCbReplaceAll.isSelected()); + if (!myRbInCurrentMethod.isEnabled() && myRbInCurrentMethod.isSelected()) { + myRbInCurrentMethod.setSelected(false); + myRbInFieldDeclaration.setSelected(true); + } + } + updateTypeSelector(); + } + }; + ItemListener finalUpdater = new ItemListener() { + public void itemStateChanged(ItemEvent e) { + updateCbFinal(); + } + }; + myRbInConstructor.addItemListener(itemListener); + myRbInCurrentMethod.addItemListener(itemListener); + myRbInFieldDeclaration.addItemListener(itemListener); + myRbInConstructor.addItemListener(finalUpdater); + myRbInCurrentMethod.addItemListener(finalUpdater); + myRbInFieldDeclaration.addItemListener(finalUpdater); + if (myRbInSetUp != null) myRbInSetUp.addItemListener(finalUpdater); + if (myOccurrencesCount > 1) { + myCbReplaceAll = new NonFocusableCheckBox(); + myCbReplaceAll.setText(RefactoringBundle.message("replace.all.occurrences.of.expression.0.occurrences", myOccurrencesCount)); + gbConstraints.gridy++; + panel.add(myCbReplaceAll, gbConstraints); + myCbReplaceAll.addItemListener(itemListener); + if (myIsInvokedOnDeclaration) { + myCbReplaceAll.setEnabled(false); + myCbReplaceAll.setSelected(true); + } + } + + if (myLocalVariable != null) { + gbConstraints.gridy++; + if (myCbReplaceAll != null) { + gbConstraints.insets = new Insets(0, 8, 0, 0); + } + myCbDeleteVariable = new StateRestoringCheckBox(); + myCbDeleteVariable.setText(RefactoringBundle.message("delete.variable.declaration")); + panel.add(myCbDeleteVariable, gbConstraints); + if (myIsInvokedOnDeclaration) { + myCbDeleteVariable.setEnabled(false); + myCbDeleteVariable.setSelected(true); + } else if (myCbReplaceAll != null) { + updateCbDeleteVariable(); + myCbReplaceAll.addItemListener( + new ItemListener() { + public void itemStateChanged(ItemEvent e) { + updateCbDeleteVariable(); + } + } + ); + } + gbConstraints.insets = standardInsets; + } + myCbFinal.addItemListener(itemListener); +// myCbStatic.addItemListener(itemListener); +// myCbStatic.addItemListener(finalUpdater); +// myCbStatic.addItemListener( +// new ItemListener() { +// public void itemStateChanged(ItemEvent e) { +// updateNameList(); +// } +// } +// ); + + updateTypeSelector(); + return panel; + } + + private void updateTypeSelector() { + if (myCbReplaceAll != null) { + myTypeSelectorManager.setAllOccurences(myCbReplaceAll.isSelected()); + } else { + myTypeSelectorManager.setAllOccurences(false); + } + } + + private void updateCbDeleteVariable() { + if (!myCbReplaceAll.isSelected()) { + myCbDeleteVariable.makeUnselectable(false); + } else { + myCbDeleteVariable.makeSelectable(); + } + } + + private JComponent createInitializerPlacePanel() { + JPanel mainPanel = new JPanel(); + mainPanel.setLayout(new BorderLayout()); + + JPanel initializationPanel = new JPanel(); + initializationPanel.setBorder(IdeBorderFactory.createTitledBorder(RefactoringBundle.message("initialize.in.border.title"))); + initializationPanel.setLayout(new BoxLayout(initializationPanel, BoxLayout.Y_AXIS)); + + + myRbInCurrentMethod = new JRadioButton(); + myRbInCurrentMethod.setFocusable(false); + myRbInCurrentMethod.setText(RefactoringBundle.message("current.method.radio")); + myRbInCurrentMethod.setEnabled(myAllowInitInMethod); + + myRbInFieldDeclaration = new JRadioButton(); + myRbInFieldDeclaration.setFocusable(false); + myRbInFieldDeclaration.setText(RefactoringBundle.message("field.declaration.radio")); + + myRbInConstructor = new JRadioButton(); + myRbInConstructor.setFocusable(false); + myRbInConstructor.setText(RefactoringBundle.message("class.constructors.radio")); + + myVisibilityPanel = new JavaVisibilityPanel(false, false); + + myCbFinal = new StateRestoringCheckBox(); + myCbFinal.setFocusable(false); + myCbFinal.setText(RefactoringBundle.message("declare.final")); + + initializationPanel.add(myRbInCurrentMethod); + initializationPanel.add(myRbInFieldDeclaration); + initializationPanel.add(myRbInConstructor); + + if (TestUtil.isTestClass(myParentClass)) { + myRbInSetUp = new JRadioButton(); + myRbInSetUp.setFocusable(false); + myRbInSetUp.setText(RefactoringBundle.message("setup.method.radio")); + initializationPanel.add(myRbInSetUp); + } + + ButtonGroup bg = new ButtonGroup(); + bg.add(myRbInCurrentMethod); + bg.add(myRbInFieldDeclaration); + bg.add(myRbInConstructor); + if (myRbInSetUp != null) bg.add(myRbInSetUp); + + + +// modifiersPanel.add(myCbFinal); +// modifiersPanel.add(myCbStatic); + + JPanel groupPanel = new JPanel(new GridLayout(1, 2)); + groupPanel.add(initializationPanel); + groupPanel.add(myVisibilityPanel); + mainPanel.add(groupPanel, BorderLayout.CENTER); + mainPanel.add(myCbFinal, BorderLayout.SOUTH); + + return mainPanel; + } + + private void updateCbFinal() { + boolean allowFinal = myRbInFieldDeclaration.isSelected() || (myRbInConstructor.isSelected() && !myWillBeDeclaredStatic); + if (myRbInCurrentMethod.isSelected() && myIsCurrentMethodConstructor) { + final PsiMethod[] constructors = myParentClass.getConstructors(); + allowFinal = constructors.length <= 1; + } + if (!allowFinal) { + myCbFinal.makeUnselectable(false); + } else { + myCbFinal.makeSelectable(); + } + } + + + + + private boolean setEnabledInitializationPlaces(PsiElement initializerPart, PsiElement initializer) { + if (initializerPart instanceof PsiReferenceExpression) { + PsiReferenceExpression refExpr = (PsiReferenceExpression) initializerPart; + if (refExpr.getQualifierExpression() == null) { + PsiElement refElement = refExpr.resolve(); + if (refElement == null || + (refElement instanceof PsiLocalVariable || refElement instanceof PsiParameter) && + !PsiTreeUtil.isAncestor(initializer, refElement, true)) { + myRbInFieldDeclaration.setEnabled(false); + myRbInConstructor.setEnabled(false); + if (myRbInSetUp != null) myRbInSetUp.setEnabled(false); + myCbFinal.setEnabled(false); + return false; + } + } + } + PsiElement[] children = initializerPart.getChildren(); + for (PsiElement child : children) { + if (!setEnabledInitializationPlaces(child, initializer)) return false; + } + return true; + } + + public void addOccurrenceListener(ItemListener itemListener) { + if (myCbReplaceAll != null) { + myCbReplaceAll.addItemListener(itemListener); + } + } + + public void addVisibilityListener(ChangeListener changeListener) { + myVisibilityPanel.addListener(changeListener); + } + + public void addFinalListener(ItemListener itemListener) { + myCbFinal.addItemListener(itemListener); + } +} diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldDialog.java b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldDialog.java index 6ad435b31e3e..bb2a6dca1672 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldDialog.java @@ -33,30 +33,28 @@ import com.intellij.refactoring.util.RefactoringMessageUtil; import javax.swing.*; import java.awt.*; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; class IntroduceFieldDialog extends DialogWrapper { + static BaseExpressionToFieldHandler.InitializationPlace ourLastInitializerPlace; + static boolean ourLastCbFinalState = false; + private final Project myProject; private final PsiClass myParentClass; private final PsiExpression myInitializerExpression; private final PsiLocalVariable myLocalVariable; - private final boolean myIsCurrentMethodConstructor; private final boolean myIsInvokedOnDeclaration; private final boolean myWillBeDeclaredStatic; private final TypeSelectorManager myTypeSelectorManager; private NameSuggestionsField myNameField; + private IntroduceFieldCentralPanel myCentralPanel; private TypeSelector myTypeSelector; private NameSuggestionsManager myNameSuggestionsManager; private static final String REFACTORING_NAME = RefactoringBundle.message("introduce.field.title"); - private final InitializerPlaceChooser myInitializerPlaceChooser; - private JavaVisibilityPanel myVisibilityPanel; - private IntroduceFieldPanel myIntroduceFieldPanel; public IntroduceFieldDialog(Project project, PsiClass parentClass, @@ -69,10 +67,11 @@ class IntroduceFieldDialog extends DialogWrapper { myProject = project; myParentClass = parentClass; myInitializerExpression = initializerExpression; - myInitializerPlaceChooser = new InitializerPlaceChooser(parentClass, initializerExpression, allowInitInMethod, allowInitInMethodIfAll); - myIntroduceFieldPanel = new IntroduceFieldPanel(isInvokedOnDeclaration, occurrencesCount, localVariable); + myCentralPanel = + new IntroduceFieldCentralPanel(parentClass, initializerExpression, localVariable, isCurrentMethodConstructor, isInvokedOnDeclaration, + willBeDeclaredStatic, occurrencesCount, allowInitInMethod, allowInitInMethodIfAll, + typeSelectorManager); myLocalVariable = localVariable; - myIsCurrentMethodConstructor = isCurrentMethodConstructor; myIsInvokedOnDeclaration = isInvokedOnDeclaration; myWillBeDeclaredStatic = willBeDeclaredStatic; @@ -81,44 +80,36 @@ class IntroduceFieldDialog extends DialogWrapper { setTitle(REFACTORING_NAME); init(); - initializeControls(initializerExpression); + myCentralPanel.initializeControls(initializerExpression); updateButtons(); } - private void initializeControls(PsiExpression initializerExpression) { - myInitializerPlaceChooser.initializeControls(initializerExpression); - myIntroduceFieldPanel.initializeControls(initializerExpression); - - String ourLastVisibility = JavaRefactoringSettings.getInstance().INTRODUCE_FIELD_VISIBILITY; - myVisibilityPanel.setVisibility(ourLastVisibility); - } - public String getEnteredName() { return myNameField.getEnteredName(); } public BaseExpressionToFieldHandler.InitializationPlace getInitializerPlace() { - return myInitializerPlaceChooser.getInitializerPlace(); + return myCentralPanel.getInitializerPlace(); } @Modifier public String getFieldVisibility() { - return myVisibilityPanel.getVisibility(); + return myCentralPanel.getFieldVisibility(); } public boolean isReplaceAllOccurrences() { - return myIntroduceFieldPanel.isReplaceAllOccurrences(); + return myCentralPanel.isReplaceAllOccurrences(); } public boolean isDeleteVariable() { - return myIntroduceFieldPanel.isDeleteVariable(); + return myCentralPanel.isDeleteVariable(); } public boolean isDeclareFinal() { - return myIntroduceFieldPanel.isDeclareFinal(); + return myCentralPanel.isDeclareFinal(); } public PsiType getFieldType() { @@ -179,7 +170,8 @@ class IntroduceFieldDialog extends DialogWrapper { }); namePrompt.setLabelFor(myNameField.getFocusableComponent()); - myNameSuggestionsManager = new NameSuggestionsManager(myTypeSelector, myNameField, createGenerator()); + myNameSuggestionsManager = new NameSuggestionsManager(myTypeSelector, myNameField, + createGenerator(myWillBeDeclaredStatic, myLocalVariable, myInitializerExpression, myIsInvokedOnDeclaration)); myNameSuggestionsManager.setLabelsFor(type, namePrompt); return panel; @@ -196,66 +188,27 @@ class IntroduceFieldDialog extends DialogWrapper { } protected JComponent createCenterPanel() { - final JPanel panel = new JPanel(new GridBagLayout()); - final GridBagConstraints gbConstraints = new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0,0,0,0), 0, 0); - - final JPanel mainPanel = new JPanel(); - mainPanel.setLayout(new BorderLayout()); - - JPanel groupPanel = new JPanel(new GridLayout(1, 2)); - - final JComponent initializerPlacePanel = myInitializerPlaceChooser.createInitializerPlacePanel(); - myInitializerPlaceChooser.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - myIntroduceFieldPanel.updateTypeSelector(myTypeSelectorManager); - myIntroduceFieldPanel.updateCbFinal(myInitializerPlaceChooser.allowFinal(myWillBeDeclaredStatic, myIsCurrentMethodConstructor)); - } - }); - groupPanel.add(initializerPlacePanel); - - myVisibilityPanel = new JavaVisibilityPanel(false, false); - groupPanel.add(myVisibilityPanel); - - mainPanel.add(groupPanel, BorderLayout.CENTER); - - final ItemListener itemListener = new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - if (myIntroduceFieldPanel.hasOccurrences()) { - myInitializerPlaceChooser.updateInitializerPlace(myIntroduceFieldPanel.isReplaceAllOccurrences()); - } - myIntroduceFieldPanel.updateTypeSelector(myTypeSelectorManager); - myNameField.requestFocusInWindow(); - } - }; - panel.add(mainPanel, gbConstraints); - myIntroduceFieldPanel.appendFinalCb(panel, gbConstraints, itemListener); - myIntroduceFieldPanel.appendOccurrencesCb(panel, gbConstraints, itemListener); - myIntroduceFieldPanel.appendDeleteVariableDeclarationCb(panel, gbConstraints); - - myIntroduceFieldPanel.updateTypeSelector(myTypeSelectorManager); - return panel; + return myCentralPanel.createCenterPanel(); } - - private NameSuggestionsGenerator createGenerator() { + static NameSuggestionsGenerator createGenerator(final boolean willBeDeclaredStatic, + final PsiLocalVariable localVariable, + final PsiExpression initializerExpression, + final boolean isInvokedOnDeclaration) { return new NameSuggestionsGenerator() { - private final JavaCodeStyleManager myCodeStyleManager = JavaCodeStyleManager.getInstance(myProject); + private final JavaCodeStyleManager myCodeStyleManager = JavaCodeStyleManager.getInstance(localVariable != null ? localVariable.getProject() + : initializerExpression.getProject()); public SuggestedNameInfo getSuggestedNameInfo(PsiType type) { - VariableKind variableKind = myWillBeDeclaredStatic ? VariableKind.STATIC_FIELD : VariableKind.FIELD; + VariableKind variableKind = willBeDeclaredStatic ? VariableKind.STATIC_FIELD : VariableKind.FIELD; String propertyName = null; - if (myIsInvokedOnDeclaration) { - propertyName = myCodeStyleManager.variableNameToPropertyName(myLocalVariable.getName(), - VariableKind.LOCAL_VARIABLE - ); + if (isInvokedOnDeclaration) { + propertyName = myCodeStyleManager.variableNameToPropertyName(localVariable.getName(), VariableKind.LOCAL_VARIABLE); } - final SuggestedNameInfo nameInfo = myCodeStyleManager.suggestVariableName(variableKind, propertyName, myInitializerExpression, type); + final SuggestedNameInfo nameInfo = myCodeStyleManager.suggestVariableName(variableKind, propertyName, initializerExpression, type); final String[] strings = JavaCompletionUtil.completeVariableNameForRefactoring(myCodeStyleManager, type, VariableKind.LOCAL_VARIABLE, nameInfo); - return new SuggestedNameInfo.Delegate(strings, nameInfo); + return new SuggestedNameInfo.Delegate(strings, nameInfo); } - }; } @@ -293,8 +246,8 @@ class IntroduceFieldDialog extends DialogWrapper { } } - IntroduceFieldPanel.ourLastCbFinalState = myIntroduceFieldPanel.isFinal(); - InitializerPlaceChooser.ourLastInitializerPlace = myInitializerPlaceChooser.getInitializerPlace(); + ourLastCbFinalState = myCentralPanel.isDeclareFinal(); + ourLastInitializerPlace = myCentralPanel.getInitializerPlace(); JavaRefactoringSettings.getInstance().INTRODUCE_FIELD_VISIBILITY = getFieldVisibility(); myNameSuggestionsManager.nameSelected(); 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 2351b4a6c8cd..65cee01e33c3 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldHandler.java @@ -16,6 +16,8 @@ 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; @@ -96,12 +98,21 @@ public class IntroduceFieldHandler extends BaseExpressionToFieldHandler { final boolean currentMethodConstructor = containingMethod != null && containingMethod.isConstructor(); final boolean allowInitInMethod = (!currentMethodConstructor || !isInSuperOrThis) && (anchorElement instanceof PsiLocalVariable || anchorElement instanceof PsiStatement); final boolean allowInitInMethodIfAll = (!currentMethodConstructor || !isInSuperOrThis) && anchorElementIfAll instanceof PsiStatement; + final TypeSelectorManagerImpl typeSelectorManager = new TypeSelectorManagerImpl(project, type, containingMethod, expr, occurences); + + if (editor != null && editor.getSettings().isVariableInplaceRenameEnabled() && ApplicationManagerEx.getApplicationEx().isInternal()) { + new InplaceIntroduceFieldPopup(localVariable, parentClass, declareStatic, currentMethodConstructor, occurences, expr, typeSelectorManager, editor, + allowInitInMethod, allowInitInMethodIfAll, anchorElement, anchorElementIfAll, createOccurenceManager(expr, parentClass)) + .startTemplate(); + return null; + } + IntroduceFieldDialog dialog = new IntroduceFieldDialog( project, parentClass, expr, localVariable, currentMethodConstructor, localVariable != null, declareStatic, occurencesNumber, allowInitInMethod, allowInitInMethodIfAll, - new TypeSelectorManagerImpl(project, type, containingMethod, expr, occurences) + typeSelectorManager ); dialog.show(); diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldPanel.java b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldPanel.java deleted file mode 100644 index cd4d13594431..000000000000 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldPanel.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * 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.introduceField; - -import com.intellij.psi.PsiExpression; -import com.intellij.psi.PsiLocalVariable; -import com.intellij.refactoring.RefactoringBundle; -import com.intellij.refactoring.ui.TypeSelectorManager; -import com.intellij.ui.NonFocusableCheckBox; -import com.intellij.ui.StateRestoringCheckBox; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; - -/** - * User: anna - * Date: 3/15/11 - */ -public class IntroduceFieldPanel { - static boolean ourLastCbFinalState = false; - - private JCheckBox myCbReplaceAll; - private StateRestoringCheckBox myCbDeleteVariable; - private StateRestoringCheckBox myCbFinal; - private boolean myIsInvokedOnDeclaration; - private int myOccurrencesCount; - private PsiLocalVariable myLocalVariable; - - public IntroduceFieldPanel(boolean isInvokedOnDeclaration, int occurrencesCount, PsiLocalVariable localVariable) { - myIsInvokedOnDeclaration = isInvokedOnDeclaration; - myOccurrencesCount = occurrencesCount; - myLocalVariable = localVariable; - } - - public void initializeControls(PsiExpression initializerExpression) { - if (initializerExpression != null && !InitializerPlaceChooser.setEnabledInitializationPlaces(initializerExpression, initializerExpression)) { - myCbFinal.setEnabled(false); - } - myCbFinal.setSelected(myCbFinal.isEnabled() && ourLastCbFinalState); - } - - public boolean isReplaceAllOccurrences() { - if (myIsInvokedOnDeclaration) return true; - if (myOccurrencesCount <= 1) return false; - return myCbReplaceAll.isSelected(); - } - - public boolean isDeclareFinal() { - return myCbFinal.isSelected(); - } - - public boolean isDeleteVariable() { - if (myIsInvokedOnDeclaration) return true; - if (myCbDeleteVariable == null) return false; - return myCbDeleteVariable.isSelected(); - } - - void appendFinalCb(JPanel mainPanel, GridBagConstraints gbConstraints, ItemListener itemListener) { - myCbFinal = new StateRestoringCheckBox(); - myCbFinal.setText(RefactoringBundle.message("declare.final")); - myCbFinal.addItemListener(itemListener); - gbConstraints.gridy++; - mainPanel.add(myCbFinal, gbConstraints); - } - - void appendOccurrencesCb(JPanel panel, GridBagConstraints gbConstraints, ItemListener itemListener) { - if (myOccurrencesCount > 1) { - myCbReplaceAll = new NonFocusableCheckBox(); - myCbReplaceAll.setText(RefactoringBundle.message("replace.all.occurrences.of.expression.0.occurrences", myOccurrencesCount)); - gbConstraints.gridy++; - panel.add(myCbReplaceAll, gbConstraints); - myCbReplaceAll.addItemListener(itemListener); - if (myIsInvokedOnDeclaration) { - myCbReplaceAll.setEnabled(false); - myCbReplaceAll.setSelected(true); - } - } - } - - void appendDeleteVariableDeclarationCb(JPanel panel, GridBagConstraints gbConstraints) { - if (myLocalVariable != null) { - gbConstraints.gridy++; - if (myCbReplaceAll != null) { - gbConstraints.insets = new Insets(0, 8, 0, 0); - } - myCbDeleteVariable = new StateRestoringCheckBox(); - myCbDeleteVariable.setText(RefactoringBundle.message("delete.variable.declaration")); - panel.add(myCbDeleteVariable, gbConstraints); - if (myIsInvokedOnDeclaration) { - myCbDeleteVariable.setEnabled(false); - myCbDeleteVariable.setSelected(true); - } else if (myCbReplaceAll != null) { - updateCbDeleteVariable(); - myCbReplaceAll.addItemListener( - new ItemListener() { - public void itemStateChanged(ItemEvent e) { - updateCbDeleteVariable(); - } - } - ); - } - gbConstraints.insets = new Insets(0, 0, 0, 0); - } - } - - private void updateCbDeleteVariable() { - if (!myCbReplaceAll.isSelected()) { - myCbDeleteVariable.makeUnselectable(false); - } else { - myCbDeleteVariable.makeSelectable(); - } - } - - void updateCbFinal(boolean allowFinal) { - if (!allowFinal) { - myCbFinal.makeUnselectable(false); - } else { - myCbFinal.makeSelectable(); - } - } - - public boolean isFinal() { - return myCbFinal.isSelected(); - } - - void updateTypeSelector(TypeSelectorManager typeSelectorManager) { - if (myCbReplaceAll != null) { - typeSelectorManager.setAllOccurences(myCbReplaceAll.isSelected()); - } else { - typeSelectorManager.setAllOccurences(false); - } - } - - public boolean hasOccurrences() { - return myCbReplaceAll != null; - } -} diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/LocalToFieldHandler.java b/java/java-impl/src/com/intellij/refactoring/introduceField/LocalToFieldHandler.java index 32b1f57d5293..bdb26a8e9b45 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/LocalToFieldHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/LocalToFieldHandler.java @@ -45,11 +45,9 @@ public abstract class LocalToFieldHandler { private static final String REFACTORING_NAME = RefactoringBundle.message("convert.local.to.field.title"); private final Project myProject; private final boolean myIsConstant; - private final PsiManager myManager; public LocalToFieldHandler(Project project, boolean isConstant) { myProject = project; - myManager = PsiManager.getInstance(myProject); myIsConstant = isConstant; } @@ -86,9 +84,6 @@ public abstract class LocalToFieldHandler { final BaseExpressionToFieldHandler.Settings settings = showRefactoringDialog(aClass, local, occurences, isStatic); if (settings == null) return false; //LocalToFieldDialog dialog = new LocalToFieldDialog(project, aClass, local, isStatic); - final String variableName = local.getName(); - final String fieldName = settings.getFieldName(); - final BaseExpressionToFieldHandler.InitializationPlace initializerPlace = settings.getInitializerPlace(); final PsiClass destinationClass = settings.getDestinationClass(); boolean rebindNeeded = false; if (destinationClass != null) { @@ -98,76 +93,8 @@ public abstract class LocalToFieldHandler { final PsiClass aaClass = aClass; final boolean rebindNeeded1 = rebindNeeded; - final Runnable runnable = new Runnable() { - public void run() { - try { - final boolean rebindNeeded2 = !variableName.equals(fieldName) || rebindNeeded1; - final PsiReference[] refs; - if (rebindNeeded2) { - refs = ReferencesSearch.search(local, GlobalSearchScope.projectScope(myProject), false).toArray(new PsiReference[0]); - } - else { - refs = null; - } - - final PsiMethod enclosingConstructor = BaseExpressionToFieldHandler.getEnclosingConstructor(aaClass, local); - PsiField field = settings.isIntroduceEnumConstant() ? EnumConstantsUtil.createEnumConstant(aaClass, local, fieldName) - : createField(local, settings.getForcedType(), fieldName, initializerPlace == IN_FIELD_DECLARATION); - field = (PsiField)aaClass.add(field); - BaseExpressionToFieldHandler.setModifiers(field, settings, isStatic); - if (!settings.isIntroduceEnumConstant()) { - VisibilityUtil.fixVisibility(occurences, field, settings.getFieldVisibility()); - } - - local.normalizeDeclaration(); - PsiDeclarationStatement declarationStatement = (PsiDeclarationStatement)local.getParent(); - final BaseExpressionToFieldHandler.InitializationPlace finalInitializerPlace; - if (local.getInitializer() == null) { - finalInitializerPlace = IN_FIELD_DECLARATION; - } - else { - finalInitializerPlace = initializerPlace; - } - final PsiElementFactory factory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory(); - - switch (finalInitializerPlace) { - case IN_FIELD_DECLARATION: - declarationStatement.delete(); - break; - - case IN_CURRENT_METHOD: - PsiStatement statement = createAssignment(local, fieldName, factory); - declarationStatement.replace(statement); - break; - - case IN_CONSTRUCTOR: - addInitializationToConstructors(local, field, enclosingConstructor, factory); - break; - case IN_SETUP_METHOD: - addInitializationToSetUp(local, field, factory); - } - - if (enclosingConstructor != null && initializerPlace == IN_CONSTRUCTOR) { - PsiStatement statement = createAssignment(local, fieldName, factory); - declarationStatement.replace(statement); - } - - if (rebindNeeded2) { - for (final PsiReference reference : refs) { - if (reference != null) { - //expr = RefactoringUtil.outermostParenthesizedExpression(expr); - RefactoringUtil.replaceOccurenceWithFieldRef((PsiExpression)reference, field, aaClass); - //replaceOccurenceWithFieldRef((PsiExpression)reference, field, aaClass); - } - } - //RefactoringUtil.renameVariableReferences(local, pPrefix + fieldName, GlobalSearchScope.projectScope(myProject)); - } - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - } - }; + final Runnable runnable = + new IntroduceFieldRunnable(rebindNeeded1, local, aaClass, settings, isStatic, occurences); CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { public void run() { ApplicationManager.getApplication().runWriteAction(runnable); @@ -176,7 +103,7 @@ public abstract class LocalToFieldHandler { return true; } - private PsiField createField(PsiLocalVariable local, PsiType forcedType, String fieldName, boolean includeInitializer) { + private static PsiField createField(PsiLocalVariable local, PsiType forcedType, String fieldName, boolean includeInitializer) { @NonNls StringBuilder pattern = new StringBuilder(); pattern.append("private int "); pattern.append(fieldName); @@ -187,10 +114,11 @@ public abstract class LocalToFieldHandler { pattern.append("=0"); } pattern.append(";"); - PsiElementFactory factory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory(); + final Project project = local.getProject(); + PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory(); try { PsiField field = factory.createFieldFromText(pattern.toString(), null); - field = (PsiField)CodeStyleManager.getInstance(myProject).reformat(field); + field = (PsiField)CodeStyleManager.getInstance(project).reformat(field); field.getTypeElement().replace(factory.createTypeElement(forcedType)); if (includeInitializer) { @@ -207,11 +135,11 @@ public abstract class LocalToFieldHandler { } } - private PsiStatement createAssignment(PsiLocalVariable local, String fieldname, PsiElementFactory factory) { + private static PsiStatement createAssignment(PsiLocalVariable local, String fieldname, PsiElementFactory factory) { try { String pattern = fieldname + "=0;"; PsiExpressionStatement statement = (PsiExpressionStatement)factory.createStatementFromText(pattern, null); - statement = (PsiExpressionStatement)CodeStyleManager.getInstance(myProject).reformat(statement); + statement = (PsiExpressionStatement)CodeStyleManager.getInstance(local.getProject()).reformat(statement); PsiAssignmentExpression expr = (PsiAssignmentExpression)statement.getExpression(); final PsiExpression initializer = RefactoringUtil.convertInitializerToNormalExpression(local.getInitializer(), local.getType()); @@ -225,7 +153,7 @@ public abstract class LocalToFieldHandler { } } - private void addInitializationToSetUp(final PsiLocalVariable local, final PsiField field, final PsiElementFactory factory) + private static PsiStatement addInitializationToSetUp(final PsiLocalVariable local, final PsiField field, final PsiElementFactory factory) throws IncorrectOperationException { PsiMethod inClass = TestUtil.findOrCreateSetUpMethod(field.getContainingClass()); assert inClass != null; @@ -233,15 +161,16 @@ public abstract class LocalToFieldHandler { final PsiCodeBlock body = inClass.getBody(); assert body != null; if (PsiTreeUtil.isAncestor(body, local, false)) { - body.addBefore(assignment, PsiTreeUtil.getParentOfType(local, PsiStatement.class)); + assignment = (PsiStatement)body.addBefore(assignment, PsiTreeUtil.getParentOfType(local, PsiStatement.class)); } else { - body.add(assignment); + assignment = (PsiStatement)body.add(assignment); } local.delete(); + return assignment; } - private void addInitializationToConstructors(PsiLocalVariable local, PsiField field, PsiMethod enclosingConstructor, - PsiElementFactory factory) throws IncorrectOperationException { + private static PsiStatement addInitializationToConstructors(PsiLocalVariable local, PsiField field, PsiMethod enclosingConstructor, + PsiElementFactory factory) throws IncorrectOperationException { PsiClass aClass = field.getContainingClass(); PsiMethod[] constructors = aClass.getConstructors(); PsiStatement assignment = createAssignment(local, field.getName(), factory); @@ -263,15 +192,125 @@ public abstract class LocalToFieldHandler { } } } - body.add(assignment); + assignment = (PsiStatement)body.add(assignment); added = true; } if (!added && enclosingConstructor == null) { - PsiMethod constructor = factory.createConstructor(); - constructor.getBody().add(assignment); - aClass.add(constructor); + PsiMethod constructor = (PsiMethod)aClass.add(factory.createConstructor()); + assignment = (PsiStatement)constructor.getBody().add(assignment); } if (enclosingConstructor == null) local.delete(); + return assignment; + } + + static class IntroduceFieldRunnable implements Runnable { + private final String myVariableName; + private final String myFieldName; + private final boolean myRebindNeeded; + private final PsiLocalVariable myLocal; + private final Project myProject; + private final PsiClass myDestinationClass; + private final BaseExpressionToFieldHandler.Settings mySettings; + private final BaseExpressionToFieldHandler.InitializationPlace myInitializerPlace; + private final boolean myStatic; + private final PsiExpression[] myOccurences; + private PsiField myField; + private PsiStatement myAssignmentStatement; + + public IntroduceFieldRunnable(boolean rebindNeeded, + PsiLocalVariable local, + PsiClass aClass, + BaseExpressionToFieldHandler.Settings settings, + boolean isStatic, + PsiExpression[] occurrences) { + myVariableName = local.getName(); + myFieldName = settings.getFieldName(); + myRebindNeeded = rebindNeeded; + myLocal = local; + myProject = local.getProject(); + myDestinationClass = aClass; + mySettings = settings; + myInitializerPlace = settings.getInitializerPlace(); + myStatic = isStatic; + myOccurences = occurrences; + } + + public void run() { + try { + final boolean rebindNeeded2 = !myVariableName.equals(myFieldName) || myRebindNeeded; + final PsiReference[] refs; + if (rebindNeeded2) { + refs = ReferencesSearch.search(myLocal, GlobalSearchScope.projectScope(myProject), false).toArray(new PsiReference[0]); + } + else { + refs = null; + } + + final PsiMethod enclosingConstructor = BaseExpressionToFieldHandler.getEnclosingConstructor(myDestinationClass, myLocal); + myField = mySettings.isIntroduceEnumConstant() ? EnumConstantsUtil.createEnumConstant(myDestinationClass, myLocal, myFieldName) + : createField(myLocal, mySettings.getForcedType(), myFieldName, myInitializerPlace == IN_FIELD_DECLARATION); + myField = (PsiField)myDestinationClass.add(myField); + BaseExpressionToFieldHandler.setModifiers(myField, mySettings, myStatic); + if (!mySettings.isIntroduceEnumConstant()) { + VisibilityUtil.fixVisibility(myOccurences, myField, mySettings.getFieldVisibility()); + } + + myLocal.normalizeDeclaration(); + PsiDeclarationStatement declarationStatement = (PsiDeclarationStatement)myLocal.getParent(); + final BaseExpressionToFieldHandler.InitializationPlace finalInitializerPlace; + if (myLocal.getInitializer() == null) { + finalInitializerPlace = IN_FIELD_DECLARATION; + } + else { + finalInitializerPlace = myInitializerPlace; + } + final PsiElementFactory factory = JavaPsiFacade.getInstance(myProject).getElementFactory(); + + switch (finalInitializerPlace) { + case IN_FIELD_DECLARATION: + declarationStatement.delete(); + break; + + case IN_CURRENT_METHOD: + PsiStatement statement = createAssignment(myLocal, myFieldName, factory); + myAssignmentStatement = (PsiStatement)declarationStatement.replace(statement); + break; + + case IN_CONSTRUCTOR: + myAssignmentStatement = addInitializationToConstructors(myLocal, myField, enclosingConstructor, factory); + break; + case IN_SETUP_METHOD: + myAssignmentStatement = addInitializationToSetUp(myLocal, myField, factory); + } + + if (enclosingConstructor != null && myInitializerPlace == IN_CONSTRUCTOR) { + PsiStatement statement = createAssignment(myLocal, myFieldName, factory); + myAssignmentStatement = (PsiStatement)declarationStatement.replace(statement); + } + + if (rebindNeeded2) { + for (final PsiReference reference : refs) { + if (reference != null) { + //expr = RefactoringUtil.outermostParenthesizedExpression(expr); + RefactoringUtil.replaceOccurenceWithFieldRef((PsiExpression)reference, myField, myDestinationClass); + //replaceOccurenceWithFieldRef((PsiExpression)reference, field, aaClass); + } + } + //RefactoringUtil.renameVariableReferences(local, pPrefix + fieldName, GlobalSearchScope.projectScope(myProject)); + } + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + + public PsiField getField() { + return myField; + } + + public PsiStatement getAssignmentStatement() { + return myAssignmentStatement; + } } } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractInplaceIntroducer.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractInplaceIntroducer.java new file mode 100644 index 000000000000..724a1ec316fa --- /dev/null +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractInplaceIntroducer.java @@ -0,0 +1,134 @@ +/* + * 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.highlighting.HighlightManager; +import com.intellij.codeInsight.intention.impl.TypeExpression; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.RangeMarker; +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.Pair; +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 java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * User: anna + * Date: 3/15/11 + */ +public abstract class AbstractInplaceIntroducer extends VariableInplaceIntroducer { + public AbstractInplaceIntroducer(Project project, + TypeExpression expression, + Editor editor, + PsiVariable elementToRename, + boolean cantChangeFinalModifier, + boolean hasTypeSuggestion, + RangeMarker exprMarker, + List occurrenceMarkers) { + super(project, expression, editor, elementToRename, cantChangeFinalModifier, hasTypeSuggestion, exprMarker, occurrenceMarkers); + } + + protected abstract boolean isReplaceAllOccurrences(); + + protected abstract PsiExpression getExpr(); + + protected abstract PsiExpression[] getOccurrences(); + + + + protected abstract List getOccurrenceMarkers(); + + @Override + protected void addReferenceAtCaret(Collection refs) { + final PsiVariable variable = getVariable(); + if (variable != null) { + for (PsiReference reference : ReferencesSearch.search(variable)) { + refs.remove(reference); + } + } + } + + @Override + protected boolean appendAdditionalElement(List> stringUsages) { + return true; + } + + @Override + protected void collectAdditionalElementsToRename(boolean processTextOccurrences, List> stringUsages) { + if (isReplaceAllOccurrences()) { + for (PsiExpression expression : getOccurrences()) { + stringUsages.add(Pair.create(expression, new TextRange(0, expression.getTextLength()))); + } + } + else if (getExpr() != null) { + stringUsages.add(Pair.create(getExpr(), new TextRange(0, getExpr().getTextLength()))); + } + } + + @Override + protected void collectAdditionalRangesToHighlight(Map rangesToHighlight, + Collection> stringUsages, + EditorColorsManager colorsManager) { + } + + @Override + protected void addHighlights(@NotNull Map ranges, + @NotNull Editor editor, + @NotNull Collection highlighters, + @NotNull HighlightManager highlightManager) { + final TextAttributes attributes = + EditorColorsManager.getInstance().getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES); + final int variableNameLength = getVariable().getName().length(); + if (isReplaceAllOccurrences()) { + for (RangeMarker marker : getOccurrenceMarkers()) { + final int startOffset = marker.getStartOffset(); + highlightManager.addOccurrenceHighlight(editor, startOffset, startOffset + variableNameLength, attributes, 0, highlighters, null); + } + } + else if (getExpr() != null) { + final int startOffset = getExprMarker().getStartOffset(); + highlightManager.addOccurrenceHighlight(editor, startOffset, startOffset + variableNameLength, attributes, 0, highlighters, null); + } + super.addHighlights(ranges, editor, highlighters, highlightManager); + } + + @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) { + return (PsiExpression)expression.replace(elementFactory.createExpressionFromText(exprText, psiVariable)); + } + 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 9d3759ada12e..4aa71d3722b4 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java @@ -15,43 +15,28 @@ */ package com.intellij.refactoring.introduceParameter; -import com.intellij.codeInsight.highlighting.HighlightManager; 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.IdeTooltipManager; 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.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.ui.popup.Balloon; -import com.intellij.openapi.ui.popup.BalloonBuilder; -import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.*; 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.search.searches.ReferencesSearch; -import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.refactoring.JavaRefactoringSettings; -import com.intellij.refactoring.introduceVariable.VariableInplaceIntroducer; import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer; import com.intellij.refactoring.ui.TypeSelectorManager; import com.intellij.refactoring.ui.TypeSelectorManagerImpl; import com.intellij.ui.TitlePanel; -import com.intellij.ui.awt.RelativePoint; import com.intellij.usageView.UsageInfo; import gnu.trove.TIntArrayList; import gnu.trove.TIntProcedure; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; @@ -64,7 +49,6 @@ import java.util.List; */ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { - private Balloon myBalloon; private final Project myProject; private final Editor myEditor; private final TypeSelectorManagerImpl myTypeSelectorManager; @@ -104,7 +88,7 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { myMethodToSearchFor = methodToSearchFor; myOccurrences = occurrences; myMustBeFinal = mustBeFinal; - myExprMarker = expr != null ? myEditor.getDocument().createRangeMarker(myExpr.getTextRange()) : null; + myExprMarker = expr != null ? myEditor.getDocument().createRangeMarker(expr.getTextRange()) : null; myExprText = myExpr != null ? myExpr.getText() : null; myWholePanel = new JPanel(new GridBagLayout()); @@ -180,7 +164,7 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { return myOccurrenceMarkers; } - private class ParameterInplaceIntroducer extends VariableInplaceIntroducer { + private class ParameterInplaceIntroducer extends AbstractInplaceIntroducer { private SmartTypePointer myParameterTypePointer; private SmartTypePointer myDefaultParameterTypePointer; @@ -190,7 +174,7 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { public ParameterInplaceIntroducer(PsiParameter parameter) { super(myProject, new TypeExpression(myProject, myTypeSelectorManager.getTypesForAll()), myEditor, parameter, myMustBeFinal, - myTypeSelectorManager.getTypesForAll().length > 1, myExprMarker, getOccurrenceMarkers()); + myTypeSelectorManager.getTypesForAll().length > 1, myExprMarker, InplaceIntroduceParameterPopup.this.getOccurrenceMarkers()); myDefaultParameterTypePointer = SmartTypePointerManager.getInstance(myProject).createSmartTypePointer(parameter.getType()); } @@ -207,64 +191,31 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { return panel; } + @Override + protected boolean isReplaceAllOccurrences() { + return InplaceIntroduceParameterPopup.this.isReplaceAllOccurences(); + } + + @Override + protected PsiExpression getExpr() { + return myExpr; + } + + @Override + protected PsiExpression[] getOccurrences() { + return myOccurrences; + } + + @Override + protected List getOccurrenceMarkers() { + return InplaceIntroduceParameterPopup.this.getOccurrenceMarkers(); + } + @Override protected PsiVariable getVariable() { return getParameter(); } - @Override - protected void addReferenceAtCaret(Collection refs) { - final PsiVariable variable = getVariable(); - if (variable != null) { - for (PsiReference reference : ReferencesSearch.search(variable)) { - refs.remove(reference); - } - } - } - - @Override - protected boolean appendAdditionalElement(List> stringUsages) { - return true; - } - - @Override - protected void collectAdditionalElementsToRename(boolean processTextOccurrences, List> stringUsages) { - if (isReplaceAllOccurences()) { - for (PsiExpression expression : myOccurrences) { - stringUsages.add(Pair.create(expression, new TextRange(0, expression.getTextLength()))); - } - } - else if (myExpr != null) { - stringUsages.add(Pair.create(myExpr, new TextRange(0, myExpr.getTextLength()))); - } - } - - @Override - protected void collectAdditionalRangesToHighlight(Map rangesToHighlight, - Collection> stringUsages, - EditorColorsManager colorsManager) { - } - - @Override - protected void addHighlights(@NotNull Map ranges, - @NotNull Editor editor, - @NotNull Collection highlighters, - @NotNull HighlightManager highlightManager) { - final TextAttributes attributes = - EditorColorsManager.getInstance().getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES); - final int variableNameLength = getVariable().getName().length(); - if (isReplaceAllOccurences()) { - for (RangeMarker marker : getOccurrenceMarkers()) { - final int startOffset = marker.getStartOffset(); - highlightManager.addOccurrenceHighlight(editor, startOffset, startOffset + variableNameLength, attributes, 0, highlighters, null); - } - } - else if (myExpr != null) { - final int startOffset = myExprMarker.getStartOffset(); - highlightManager.addOccurrenceHighlight(editor, startOffset, startOffset + variableNameLength, attributes, 0, highlighters, null); - } - super.addHighlights(ranges, editor, highlighters, highlightManager); - } @Override protected void saveSettings(PsiVariable psiVariable) { @@ -336,7 +287,7 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { public void run() { final PsiFile containingFile = myMethod.getContainingFile(); final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); - myExpr = restoreExpression(containingFile, psiParameter, elementFactory, myExprMarker); + myExpr = restoreExpression(containingFile, psiParameter, elementFactory, myExprMarker, myExprText); if (myExpr != null) { myExprMarker = myEditor.getDocument().createRangeMarker(myExpr.getTextRange()); } @@ -347,7 +298,7 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { myOccurrences[i] = myExpr; continue; } - final PsiExpression psiExpression = restoreExpression(containingFile, psiParameter, elementFactory, marker); + final PsiExpression psiExpression = restoreExpression(containingFile, psiParameter, elementFactory, marker, myExprText); if (psiExpression != null) { myOccurrences[i] = psiExpression; } @@ -360,21 +311,6 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { }); } - @Nullable - private PsiExpression restoreExpression(PsiFile containingFile, - PsiParameter psiParameter, - PsiElementFactory elementFactory, - RangeMarker marker) { - if (myExprText == null) return null; - if (psiParameter == null || !psiParameter.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() == psiParameter) { - return (PsiExpression)expression.replace(elementFactory.createExpressionFromText(myExprText, myMethod)); - } - return null; - } - public boolean createFinals() { return hasFinalModifier(); 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 7ce2d61d33fc..2cd413c43a30 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/VariableInplaceIntroducer.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/VariableInplaceIntroducer.java @@ -109,30 +109,7 @@ public class VariableInplaceIntroducer extends VariableInplaceRenamer { myCanBeFinal = new NonFocusableCheckBox("Declare final"); myCanBeFinal.setSelected(createFinals()); myCanBeFinal.setMnemonic('f'); - myCanBeFinal.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - new WriteCommandAction(project){ - @Override - protected void run(com.intellij.openapi.application.Result result) throws Throwable { - final PsiModifierList modifierList = getVariable().getModifierList(); - LOG.assertTrue(modifierList != null); - final Document document = myEditor.getDocument(); - final int textOffset = modifierList.getTextOffset(); - if (myCanBeFinal.isSelected()) { - if (StringUtil.isEmptyOrSpaces(document.getText(new TextRange(textOffset - 1, textOffset)))) { - document.insertString(textOffset - 1, "final"); - } else { - document.insertString(textOffset, "final "); - } - } - else { - document.deleteString(textOffset, textOffset + modifierList.getTextLength()); - } - } - }.execute(); - } - }); + myCanBeFinal.addActionListener(new FinalListener(project)); } } @@ -186,6 +163,10 @@ public class VariableInplaceIntroducer extends VariableInplaceRenamer { return super.performInplaceRename(processTextOccurrences, nameSuggestions); } + public RangeMarker getExprMarker() { + return myExprMarker; + } + @Override protected void moveOffsetAfter(boolean success) { try { @@ -382,4 +363,41 @@ public class VariableInplaceIntroducer extends VariableInplaceRenamer { myBalloon .show(new RelativePoint(new Point(screenPoint.x, screenPoint.y - myEditor.getLineHeight())), Balloon.Position.above); } + + public class FinalListener implements ActionListener { + private final Project myProject; + + public FinalListener(Project project) { + myProject = project; + } + + @Override + public void actionPerformed(ActionEvent e) { + perform(myCanBeFinal.isSelected()); + } + + public void perform(final boolean generateFinal) { + new WriteCommandAction(myProject){ + @Override + protected void run(com.intellij.openapi.application.Result result) throws Throwable { + final PsiVariable variable = getVariable(); + LOG.assertTrue(variable != null); + final PsiModifierList modifierList = variable.getModifierList(); + LOG.assertTrue(modifierList != null); + final int textOffset = modifierList.getTextOffset(); + + final Document document = myEditor.getDocument(); + if (generateFinal) { + final PsiTypeElement typeElement = variable.getTypeElement(); + final int typeOffset = typeElement != null ? typeElement.getTextOffset() : textOffset; + document.insertString(typeOffset, PsiModifier.FINAL + " "); + } + else { + final int idx = modifierList.getText().indexOf(PsiModifier.FINAL); + document.deleteString(textOffset + idx, textOffset + idx + PsiModifier.FINAL.length() + 1); + } + } + }.execute(); + } + } } 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 87f7d7cbaed0..5b0e601e695c 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 @@ -144,12 +144,7 @@ public class VariableInplaceRenamer { ourRenamersStack.push(this); - PsiElement scope = null; - final SearchScope searchScope = myElementToRename.getManager().getSearchHelper().getUseScope(myElementToRename); - if (searchScope instanceof LocalSearchScope) { - final PsiElement[] elements = ((LocalSearchScope)searchScope).getScope(); - scope = PsiTreeUtil.findCommonParent(elements); - } + PsiElement scope = checkLocalScope(); if (scope == null) { return false; // Should have valid local search scope for inplace rename @@ -173,6 +168,17 @@ public class VariableInplaceRenamer { return true; } + @Nullable + protected PsiElement checkLocalScope() { + final SearchScope searchScope = myElementToRename.getManager().getSearchHelper().getUseScope(myElementToRename); + if (searchScope instanceof LocalSearchScope) { + final PsiElement[] elements = ((LocalSearchScope)searchScope).getScope(); + return PsiTreeUtil.findCommonParent(elements); + } + + return null; + } + protected boolean appendAdditionalElement(List> stringUsages) { return stringUsages.isEmpty(); }