mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-26 19:06:24 +07:00
445 lines
19 KiB
Java
445 lines
19 KiB
Java
/*
|
|
* Copyright 2000-2011 JetBrains s.r.o.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
package com.intellij.refactoring.introduceField;
|
|
|
|
import com.intellij.codeInsight.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.util.PropertiesComponent;
|
|
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.project.Project;
|
|
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
|
|
import com.intellij.openapi.util.Computable;
|
|
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.psi.util.PsiUtil;
|
|
import com.intellij.refactoring.JavaRefactoringSettings;
|
|
import com.intellij.refactoring.introduceParameter.AbstractInplaceIntroducer;
|
|
import com.intellij.refactoring.move.moveMembers.MoveMembersImpl;
|
|
import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer;
|
|
import com.intellij.refactoring.ui.JavaVisibilityPanel;
|
|
import com.intellij.refactoring.ui.TypeSelectorManagerImpl;
|
|
import com.intellij.refactoring.util.occurences.OccurenceManager;
|
|
import com.intellij.ui.StateRestoringCheckBox;
|
|
import com.intellij.ui.TitlePanel;
|
|
|
|
import javax.swing.*;
|
|
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/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 final TypeSelectorManagerImpl myTypeSelectorManager;
|
|
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 myLocalName;
|
|
private RangeMarker myExprMarker;
|
|
|
|
private boolean myInitListeners = false;
|
|
private JCheckBox myReplaceAllCb;
|
|
private JCheckBox myAnnotateNonNls;
|
|
private StateRestoringCheckBox myCbDeleteVariable;
|
|
|
|
private JCheckBox myMoveToAnotherClassCb;
|
|
|
|
private JavaVisibilityPanel myVisibilityPanel;
|
|
|
|
private JPanel myWholePanel;
|
|
|
|
public InplaceIntroduceConstantPopup(Project project,
|
|
Editor editor,
|
|
PsiClass parentClass,
|
|
PsiExpression expr,
|
|
PsiLocalVariable localVariable,
|
|
PsiExpression[] occurrences,
|
|
TypeSelectorManagerImpl typeSelectorManager,
|
|
PsiElement anchorElement,
|
|
PsiElement anchorElementIfAll, OccurenceManager occurenceManager) {
|
|
myProject = project;
|
|
myEditor = editor;
|
|
myParentClass = parentClass;
|
|
myExpr = expr;
|
|
myLocalVariable = localVariable;
|
|
myOccurrences = occurrences;
|
|
myTypeSelectorManager = typeSelectorManager;
|
|
myAnchorElement = anchorElement;
|
|
myAnchorElementIfAll = anchorElementIfAll;
|
|
for (int i = 0, occurrencesLength = occurrences.length; i < occurrencesLength; i++) {
|
|
PsiExpression occurrence = occurrences[i];
|
|
PsiElement parent = occurrence.getParent();
|
|
if (parent == myAnchorElement) {
|
|
myAnchorIdx = i;
|
|
}
|
|
if (parent == myAnchorElementIfAll) {
|
|
myAnchorIdxIfAll = i;
|
|
}
|
|
}
|
|
myOccurenceManager = occurenceManager;
|
|
|
|
myExprMarker = expr != null && expr.isPhysical() ? myEditor.getDocument().createRangeMarker(expr.getTextRange()) : null;
|
|
myExprText = expr != null ? expr.getText() : null;
|
|
myLocalName = localVariable != null ? localVariable.getName() : null;
|
|
|
|
myWholePanel = new JPanel(new GridBagLayout());
|
|
GridBagConstraints gc = new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0 , 0, 0), 0, 0);
|
|
|
|
final TitlePanel titlePanel = new TitlePanel();
|
|
titlePanel.setBorder(null);
|
|
titlePanel.setText(IntroduceConstantHandler.REFACTORING_NAME);
|
|
|
|
myWholePanel.add(titlePanel, gc);
|
|
|
|
gc.insets = new Insets(5, 5, 5, 5);
|
|
|
|
myVisibilityPanel = new JavaVisibilityPanel(false, false);
|
|
myVisibilityPanel.setVisibility(JavaRefactoringSettings.getInstance().INTRODUCE_CONSTANT_VISIBILITY);
|
|
myWholePanel.add(myVisibilityPanel, gc);
|
|
|
|
myReplaceAllCb = new JCheckBox("Replace all occurrences");
|
|
myReplaceAllCb.setMnemonic('a');
|
|
myReplaceAllCb.setFocusable(false);
|
|
myWholePanel.add(myReplaceAllCb, gc);
|
|
myReplaceAllCb.setVisible(myOccurrences.length > 1);
|
|
|
|
|
|
myCbDeleteVariable = new StateRestoringCheckBox("Delete variable declaration");
|
|
myCbDeleteVariable.setMnemonic('d');
|
|
myCbDeleteVariable.setFocusable(false);
|
|
myWholePanel.add(myCbDeleteVariable, gc);
|
|
if (myLocalVariable != null) {
|
|
if (myReplaceAllCb != null) {
|
|
myReplaceAllCb.setEnabled(false);
|
|
myReplaceAllCb.setSelected(true);
|
|
myCbDeleteVariable.setSelected(true);
|
|
myCbDeleteVariable.setEnabled(false);
|
|
}
|
|
} else {
|
|
myCbDeleteVariable.setVisible(false);
|
|
}
|
|
|
|
myAnnotateNonNls = new JCheckBox("Annotate field as @NonNls");
|
|
myAnnotateNonNls.setMnemonic('f');
|
|
myAnnotateNonNls.setFocusable(false);
|
|
myWholePanel.add(myAnnotateNonNls, gc);
|
|
final PsiManager psiManager = PsiManager.getInstance(myProject);
|
|
if ((myTypeSelectorManager.isSuggestedType("java.lang.String") || (myLocalVariable != null && AnnotationUtil.isAnnotated(myLocalVariable, AnnotationUtil.NON_NLS, false)))&&
|
|
LanguageLevelProjectExtension.getInstance(psiManager.getProject()).getLanguageLevel().hasEnumKeywordAndAutoboxing() &&
|
|
JavaPsiFacade.getInstance(psiManager.getProject()).findClass(AnnotationUtil.NON_NLS, myParentClass.getResolveScope()) != null) {
|
|
final PropertiesComponent component = PropertiesComponent.getInstance(myProject);
|
|
myAnnotateNonNls.setSelected(component.isTrueValue(IntroduceConstantDialog.NONNLS_SELECTED_PROPERTY));
|
|
myAnnotateNonNls.addItemListener(new ItemListener() {
|
|
public void itemStateChanged(ItemEvent e) {
|
|
component.setValue(IntroduceConstantDialog.NONNLS_SELECTED_PROPERTY, Boolean.toString(myAnnotateNonNls.isSelected()));
|
|
}
|
|
});
|
|
} else {
|
|
myAnnotateNonNls.setVisible(false);
|
|
}
|
|
|
|
myMoveToAnotherClassCb = new JCheckBox("Move to another class");
|
|
myMoveToAnotherClassCb.setMnemonic('m');
|
|
myMoveToAnotherClassCb.setFocusable(false);
|
|
myWholePanel.add(myMoveToAnotherClassCb, gc);
|
|
|
|
|
|
}
|
|
|
|
public void performInplaceIntroduce() {
|
|
startIntroduceTemplate(false);
|
|
}
|
|
|
|
private void startIntroduceTemplate(final boolean replaceAllOccurrences) {
|
|
CommandProcessor.getInstance().executeCommand(myProject, new Runnable() {
|
|
public void run() {
|
|
myTypeSelectorManager.setAllOccurences(replaceAllOccurrences);
|
|
final PsiType defaultType = myTypeSelectorManager.getTypeSelector().getSelectedType();
|
|
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);
|
|
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);
|
|
renamer.performInplaceRename(false, nameSuggestions);
|
|
}
|
|
}
|
|
}, IntroduceConstantHandler.REFACTORING_NAME, null);
|
|
}
|
|
|
|
private PsiField 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]) + " = " + myExprText + ";", myParentClass);
|
|
PsiUtil.setModifierProperty(field, PsiModifier.FINAL, true);
|
|
PsiUtil.setModifierProperty(field, PsiModifier.STATIC, true);
|
|
final String visibility = myVisibilityPanel.getVisibility();
|
|
if (visibility != null) {
|
|
PsiUtil.setModifierProperty(field, visibility, true);
|
|
}
|
|
field = BaseExpressionToFieldHandler.ConvertToFieldRunnable.appendField(myExpr, myParentClass, myParentClass, myAnchorElementIfAll, field);
|
|
return field;
|
|
}
|
|
});
|
|
}
|
|
|
|
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 void updateCbDeleteVariable() {
|
|
if (!myReplaceAllCb.isSelected()) {
|
|
myCbDeleteVariable.makeUnselectable(false);
|
|
}
|
|
else {
|
|
myCbDeleteVariable.makeSelectable();
|
|
}
|
|
}
|
|
|
|
private class FieldInplaceIntroducer extends AbstractInplaceIntroducer {
|
|
private RangeMarker myFieldRangeStart;
|
|
|
|
|
|
private SmartTypePointer myDefaultParameterTypePointer;
|
|
|
|
private SmartTypePointer myFieldTypePointer;
|
|
|
|
public FieldInplaceIntroducer(PsiField field) {
|
|
super(myProject, new TypeExpression(myProject, myTypeSelectorManager.getTypesForAll()),
|
|
myEditor, field, false,
|
|
myTypeSelectorManager.getTypesForAll().length > 1,
|
|
myExpr != null && myExpr.isPhysical() ? myEditor.getDocument().createRangeMarker(myExpr.getTextRange()) : null, InplaceIntroduceConstantPopup.this.getOccurrenceMarkers());
|
|
|
|
myDefaultParameterTypePointer =
|
|
SmartTypePointerManager.getInstance(myProject).createSmartTypePointer(myTypeSelectorManager.getDefaultType());
|
|
myFieldRangeStart = myEditor.getDocument().createRangeMarker(field.getTextRange());
|
|
}
|
|
|
|
@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 = myVisibilityPanel.getVisibility();
|
|
}
|
|
|
|
@Override
|
|
protected PsiVariable getVariable() {
|
|
PsiElement element = myParentClass.getContainingFile().findElementAt(myFieldRangeStart.getStartOffset());
|
|
if (element instanceof PsiWhiteSpace) {
|
|
element = PsiTreeUtil.skipSiblingsForward(element, PsiWhiteSpace.class);
|
|
}
|
|
return PsiTreeUtil.getParentOfType(element, PsiField.class, false);
|
|
}
|
|
|
|
@Override
|
|
protected void moveOffsetAfter(boolean success) {
|
|
if (success) {
|
|
final BaseExpressionToFieldHandler.Settings settings =
|
|
new BaseExpressionToFieldHandler.Settings(myConstantName,
|
|
isReplaceAllOccurrences(), true,
|
|
true,
|
|
BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION,
|
|
myVisibilityPanel.getVisibility(), 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 (myMoveToAnotherClassCb.isSelected()) {
|
|
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
MoveMembersImpl.doMove(myProject, new PsiElement[]{myParentClass.findFieldByName(myConstantName, false)}, null, null);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected JComponent getComponent() {
|
|
if (!myInitListeners) {
|
|
myInitListeners = true;
|
|
myVisibilityPanel.addListener(new VisibilityListener(myProject, myEditor){
|
|
@Override
|
|
protected String getVisibility() {
|
|
return myVisibilityPanel.getVisibility();
|
|
}
|
|
});
|
|
myReplaceAllCb.addItemListener(new ItemListener() {
|
|
@Override
|
|
public void itemStateChanged(ItemEvent e) {
|
|
final TemplateState templateState = TemplateManagerImpl.getTemplateState(myEditor);
|
|
if (templateState != null) {
|
|
templateState.gotoEnd(true);
|
|
startIntroduceTemplate(isReplaceAllOccurrences());
|
|
}
|
|
}
|
|
});
|
|
|
|
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;
|
|
}
|
|
|
|
@Override
|
|
public void finish() {
|
|
super.finish();
|
|
final PsiField psiField = (PsiField)getVariable();
|
|
LOG.assertTrue(psiField != null);
|
|
myFieldTypePointer = SmartTypePointerManager.getInstance(myProject).createSmartTypePointer(psiField.getType());
|
|
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
|
|
myConstantName = psiField.getName();
|
|
|
|
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
|
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();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
private boolean isAnnotateNonNls() {
|
|
return myAnnotateNonNls.isSelected();
|
|
}
|
|
|
|
private boolean isDeleteVariable() {
|
|
return myCbDeleteVariable.isSelected();
|
|
}
|
|
}
|