mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-26 17:10:44 +07:00
425 lines
18 KiB
Java
425 lines
18 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.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.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.ui.LabeledComponent;
|
|
import com.intellij.openapi.util.*;
|
|
import com.intellij.psi.*;
|
|
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
|
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
|
import com.intellij.psi.codeStyle.VariableKind;
|
|
import com.intellij.psi.util.PsiUtil;
|
|
import com.intellij.refactoring.IntroduceParameterRefactoring;
|
|
import com.intellij.refactoring.JavaRefactoringSettings;
|
|
import com.intellij.refactoring.RefactoringBundle;
|
|
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.TitlePanel;
|
|
import com.intellij.usageView.UsageInfo;
|
|
import com.intellij.util.ui.UIUtil;
|
|
import gnu.trove.TIntArrayList;
|
|
import gnu.trove.TIntProcedure;
|
|
|
|
import javax.swing.*;
|
|
import java.awt.*;
|
|
import java.util.*;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* User: anna
|
|
* Date: 2/25/11
|
|
*/
|
|
class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI {
|
|
|
|
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 JComboBox myReplaceFieldsCb;
|
|
private boolean myInitialized = false;
|
|
|
|
|
|
InplaceIntroduceParameterPopup(final Project project,
|
|
final Editor editor,
|
|
final List<UsageInfo> classMemberRefs,
|
|
final TypeSelectorManagerImpl typeSelectorManager,
|
|
final PsiExpression expr,
|
|
final PsiLocalVariable localVar,
|
|
final PsiMethod method,
|
|
final PsiMethod methodToSearchFor,
|
|
final PsiExpression[] occurrences,
|
|
final TIntArrayList parametersToRemove,
|
|
final boolean mustBeFinal) {
|
|
super(project, localVar, expr, method, parametersToRemove);
|
|
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);
|
|
|
|
final TitlePanel titlePanel = new TitlePanel();
|
|
titlePanel.setBorder(null);
|
|
titlePanel.setText(IntroduceParameterHandler.REFACTORING_NAME);
|
|
gc.gridwidth = 2;
|
|
myWholePanel.add(titlePanel, gc);
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
@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);
|
|
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;
|
|
}
|
|
|
|
void inplaceIntroduceParameter() {
|
|
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 = 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);
|
|
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);
|
|
renamer.performInplaceRename(false, nameSuggestions);
|
|
}
|
|
}
|
|
}, IntroduceParameterHandler.REFACTORING_NAME, IntroduceParameterHandler.REFACTORING_NAME);
|
|
}
|
|
|
|
@Override
|
|
protected TypeSelectorManager getTypeSelectionManager() {
|
|
return myTypeSelectorManager;
|
|
}
|
|
|
|
private PsiParameter getParameter() {
|
|
return myMethod.getParameterList().getParameters()[myParameterIndex];
|
|
}
|
|
|
|
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);
|
|
myDefaultParameterTypePointer = SmartTypePointerManager.getInstance(myProject).createSmartTypePointer(parameter.getType());
|
|
}
|
|
|
|
@Override
|
|
protected JComponent getComponent() {
|
|
if (!myInitialized) {
|
|
myInitialized = true;
|
|
myWholePanel.add(myCanBeFinal, new GridBagConstraints(0, myCbReplaceAllOccurences == null ? 2 : 3, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 5, 2, 5), 0, 0));
|
|
}
|
|
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);
|
|
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();
|
|
}
|
|
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);
|
|
} else {
|
|
super.moveOffsetAfter(success);
|
|
}
|
|
}
|
|
|
|
private void normalizeParameterIdxAccordingToRemovedParams(TIntArrayList parametersToRemove) {
|
|
parametersToRemove.forEach(new TIntProcedure() {
|
|
@Override
|
|
public boolean execute(int value) {
|
|
if (myParameterIndex > value) {
|
|
myParameterIndex--;
|
|
}
|
|
return true;
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
@Override
|
|
public void finish() {
|
|
super.finish();
|
|
final PsiParameter psiParameter = (PsiParameter)getVariable();
|
|
LOG.assertTrue(psiParameter != null);
|
|
myFinal = psiParameter.hasModifierProperty(PsiModifier.FINAL);
|
|
myParameterTypePointer = SmartTypePointerManager.getInstance(myProject).createSmartTypePointer(psiParameter.getType());
|
|
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
|
|
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();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
public boolean createFinals() {
|
|
return hasFinalModifier();
|
|
}
|
|
}
|
|
|
|
private boolean hasFinalModifier() {
|
|
final Boolean createFinals = JavaRefactoringSettings.getInstance().INTRODUCE_PARAMETER_CREATE_FINALS;
|
|
return createFinals == null ? CodeStyleSettingsManager.getSettings(myProject).GENERATE_FINAL_PARAMETERS : createFinals.booleanValue();
|
|
}
|
|
|
|
@Override
|
|
protected void updateControls(JCheckBox[] removeParamsCb) {
|
|
super.updateControls(removeParamsCb);
|
|
if (myParameterIndex < 0) return;
|
|
final TemplateState templateState = TemplateManagerImpl.getTemplateState(myEditor);
|
|
if (templateState != null) {
|
|
templateState.gotoEnd(true);
|
|
startIntroduceTemplate(isReplaceAllOccurences());
|
|
}
|
|
}
|
|
|
|
|
|
private PsiParameter createParameterToStartTemplateOn(final String[] names,
|
|
final PsiType defaultType) {
|
|
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myMethod.getProject());
|
|
return ApplicationManager.getApplication().runWriteAction(new Computable<PsiParameter>() {
|
|
@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;
|
|
}
|
|
});
|
|
}
|
|
|
|
}
|