inplace introduce api extracted

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