blob: da5be799dacedc23dfb4e7c45d2b3d1bed71f7a8 [file] [log] [blame]
/*
* 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.TestFrameworks;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.*;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.ui.TypeSelectorManager;
import com.intellij.ui.NonFocusableCheckBox;
import com.intellij.ui.StateRestoringCheckBox;
import com.intellij.util.Processor;
import org.jetbrains.annotations.TestOnly;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
/**
* User: anna
* Date: 3/16/11
*/
public abstract class IntroduceFieldCentralPanel {
protected static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.introduceField.IntroduceFieldDialog");
private static final String INTRODUCE_FIELD_FINAL_CHECKBOX = "introduce.final.checkbox";
public static boolean ourLastCbFinalState = PropertiesComponent.getInstance().getBoolean(INTRODUCE_FIELD_FINAL_CHECKBOX, true);
protected final PsiClass myParentClass;
protected final PsiExpression myInitializerExpression;
protected final PsiLocalVariable myLocalVariable;
protected final boolean myIsCurrentMethodConstructor;
protected final boolean myIsInvokedOnDeclaration;
protected final boolean myWillBeDeclaredStatic;
protected final int myOccurrencesCount;
protected final boolean myAllowInitInMethod;
protected final boolean myAllowInitInMethodIfAll;
protected final TypeSelectorManager myTypeSelectorManager;
private JCheckBox myCbReplaceAll;
private StateRestoringCheckBox myCbDeleteVariable;
private StateRestoringCheckBox myCbFinal;
private boolean myHasWriteAccess;
public IntroduceFieldCentralPanel(PsiClass parentClass,
PsiExpression initializerExpression,
PsiLocalVariable localVariable,
boolean isCurrentMethodConstructor, boolean isInvokedOnDeclaration, boolean willBeDeclaredStatic,
PsiExpression[] occurrences, boolean allowInitInMethod, boolean allowInitInMethodIfAll,
TypeSelectorManager typeSelectorManager) {
myParentClass = parentClass;
myInitializerExpression = initializerExpression;
myLocalVariable = localVariable;
myIsCurrentMethodConstructor = isCurrentMethodConstructor;
myIsInvokedOnDeclaration = isInvokedOnDeclaration;
myWillBeDeclaredStatic = willBeDeclaredStatic;
myOccurrencesCount = occurrences.length;
myHasWriteAccess = false;
for (PsiExpression occurrence : occurrences) {
if (PsiUtil.isAccessedForWriting(occurrence)) {
myHasWriteAccess = true;
break;
}
}
myAllowInitInMethod = allowInitInMethod;
myAllowInitInMethodIfAll = allowInitInMethodIfAll;
myTypeSelectorManager = typeSelectorManager;
}
protected boolean setEnabledInitializationPlaces(PsiElement initializerPart, PsiElement initializer) {
if (initializerPart instanceof PsiReferenceExpression) {
PsiReferenceExpression refExpr = (PsiReferenceExpression)initializerPart;
if (refExpr.getQualifierExpression() == null) {
PsiElement refElement = refExpr.resolve();
if (refElement == null ||
(refElement instanceof PsiLocalVariable ||
refElement instanceof PsiParameter ||
(refElement instanceof PsiField && !((PsiField)refElement).hasInitializer())) &&
!PsiTreeUtil.isAncestor(initializer, refElement, true)) {
return updateInitializationPlaceModel(initializedInSetUp(refElement));
}
}
}
PsiElement[] children = initializerPart.getChildren();
for (PsiElement child : children) {
if (!setEnabledInitializationPlaces(child, initializer)) return false;
}
return true;
}
private boolean initializedInSetUp(PsiElement refElement) {
if (refElement instanceof PsiField && hasSetUpChoice()) {
final PsiMethod setUpMethod = TestFrameworks.getInstance().findSetUpMethod(((PsiField)refElement).getContainingClass());
if (setUpMethod != null) {
final Processor<PsiReference> initializerSearcher = new Processor<PsiReference>() {
@Override
public boolean process(PsiReference reference) {
final PsiElement referenceElement = reference.getElement();
if (referenceElement instanceof PsiExpression) {
return !PsiUtil.isAccessedForWriting((PsiExpression)referenceElement);
}
return true;
}
};
if (!ReferencesSearch.search(refElement, new LocalSearchScope(setUpMethod)).forEach(initializerSearcher)) {
return true;
}
}
}
return false;
}
public abstract BaseExpressionToFieldHandler.InitializationPlace getInitializerPlace();
protected abstract void initializeInitializerPlace(PsiExpression initializerExpression,
BaseExpressionToFieldHandler.InitializationPlace ourLastInitializerPlace);
protected abstract JComponent createInitializerPlacePanel(ItemListener itemListener, ItemListener finalUpdater);
public abstract void setInitializeInFieldDeclaration();
public abstract void setVisibility(String visibility);
public abstract String getFieldVisibility();
protected void initializeControls(PsiExpression initializerExpression,
BaseExpressionToFieldHandler.InitializationPlace ourLastInitializerPlace) {
myCbFinal.setSelected(myCbFinal.isEnabled() && ourLastCbFinalState);
}
public boolean isReplaceAllOccurrences() {
if (myIsInvokedOnDeclaration) return true;
if (myOccurrencesCount <= 1) return false;
return myCbReplaceAll.isSelected();
}
public boolean isDeleteVariable() {
if (myIsInvokedOnDeclaration) return true;
if (myCbDeleteVariable == null) return false;
return myCbDeleteVariable.isSelected();
}
public boolean isDeclareFinal() {
return myCbFinal.isSelected();
}
protected JComponent createCenterPanel() {
ItemListener itemListener = new ItemListener() {
public void itemStateChanged(ItemEvent e) {
if (myCbReplaceAll != null && myAllowInitInMethod) {
updateInitializerSelection();
}
if (shouldUpdateTypeSelector()) {
updateTypeSelector();
}
}
};
ItemListener finalUpdater = new ItemListener() {
public void itemStateChanged(ItemEvent e) {
updateCbFinal();
}
};
final JComponent initializerPlacePanel = createInitializerPlacePanel(itemListener, finalUpdater);
final JPanel checkboxes = appendCheckboxes(itemListener);
JPanel panel = composeWholePanel(initializerPlacePanel, checkboxes);
updateTypeSelector();
updateCbFinal();
return panel;
}
protected abstract JPanel composeWholePanel(JComponent initializerPlacePanel, JPanel checkboxPanel);
protected void updateInitializerSelection() {
}
protected boolean shouldUpdateTypeSelector() {
return true;
}
protected JPanel appendCheckboxes(ItemListener itemListener) {
GridBagConstraints gbConstraints = new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1,1,0,0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0,0,0,0), 0,0);
JPanel panel = new JPanel(new GridBagLayout());
myCbFinal = new StateRestoringCheckBox();
myCbFinal.setFocusable(false);
myCbFinal.setText(RefactoringBundle.message("declare.final"));
myCbFinal.addItemListener(itemListener);
gbConstraints.gridy++;
panel.add(myCbFinal, gbConstraints);
appendOccurrences(itemListener, gbConstraints, panel);
if (myLocalVariable != null) {
gbConstraints.gridy++;
if (myCbReplaceAll != null) {
gbConstraints.insets = new Insets(0, 8, 0, 0);
}
myCbDeleteVariable = new StateRestoringCheckBox();
myCbDeleteVariable.setText(RefactoringBundle.message("delete.variable.declaration"));
panel.add(myCbDeleteVariable, gbConstraints);
if (myIsInvokedOnDeclaration) {
myCbDeleteVariable.setEnabled(false);
myCbDeleteVariable.setSelected(true);
} else if (myCbReplaceAll != null) {
updateCbDeleteVariable();
myCbReplaceAll.addItemListener(
new ItemListener() {
public void itemStateChanged(ItemEvent e) {
updateCbDeleteVariable();
}
}
);
}
}
return panel;
}
public void appendOccurrences(ItemListener itemListener, GridBagConstraints gbConstraints, JPanel panel) {
if (myOccurrencesCount > 1) {
myCbReplaceAll = new NonFocusableCheckBox();
myCbReplaceAll.setText(RefactoringBundle.message("replace.all.occurrences.of.expression.0.occurrences", myOccurrencesCount));
gbConstraints.gridy++;
panel.add(myCbReplaceAll, gbConstraints);
myCbReplaceAll.addItemListener(itemListener);
if (myIsInvokedOnDeclaration) {
myCbReplaceAll.setEnabled(false);
myCbReplaceAll.setSelected(true);
}
}
}
private void updateTypeSelector() {
if (myCbReplaceAll != null) {
myTypeSelectorManager.setAllOccurrences(myCbReplaceAll.isSelected());
} else {
myTypeSelectorManager.setAllOccurrences(false);
}
}
private void updateCbDeleteVariable() {
if (!myCbReplaceAll.isSelected()) {
myCbDeleteVariable.makeUnselectable(false);
} else {
myCbDeleteVariable.makeSelectable();
}
}
protected void updateCbFinal() {
if (!allowFinal()) {
myCbFinal.makeUnselectable(false);
} else {
myCbFinal.makeSelectable();
}
}
protected boolean allowFinal() {
if (myHasWriteAccess && isReplaceAllOccurrences()) return false;
return true;
}
public void addOccurrenceListener(ItemListener itemListener) {
if (myCbReplaceAll != null) {
myCbReplaceAll.addItemListener(itemListener);
}
}
public void setReplaceAllOccurrences(boolean replaceAllOccurrences) {
if (myCbReplaceAll != null) {
myCbReplaceAll.setSelected(replaceAllOccurrences);
}
}
@TestOnly
public void setCreateFinal(boolean createFinal) {
myCbFinal.setSelected(createFinal);
myCbFinal.setEnabled(true);
}
protected void enableFinal(boolean enable){
myCbFinal.setEnabled(enable);
}
public void saveFinalState() {
if (myCbFinal != null && myCbFinal.isEnabled()) {
ourLastCbFinalState = myCbFinal.isSelected();
PropertiesComponent.getInstance().setValue(INTRODUCE_FIELD_FINAL_CHECKBOX, String.valueOf(ourLastCbFinalState));
}
}
protected abstract boolean updateInitializationPlaceModel(boolean initializedInsetup);
protected abstract boolean hasSetUpChoice();
}