blob: efff2b7790cd44f5f593ff538fe206d6a772d165 [file] [log] [blame]
/*
* Copyright 2000-2013 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.inheritanceToDelegation;
import com.intellij.openapi.help.HelpManager;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.SuggestedNameInfo;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.refactoring.HelpID;
import com.intellij.refactoring.JavaRefactoringSettings;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.classMembers.MemberInfoChange;
import com.intellij.refactoring.classMembers.MemberInfoModel;
import com.intellij.refactoring.ui.ClassCellRenderer;
import com.intellij.refactoring.ui.MemberSelectionPanel;
import com.intellij.refactoring.ui.NameSuggestionsField;
import com.intellij.refactoring.ui.RefactoringDialog;
import com.intellij.refactoring.util.classMembers.InterfaceMemberDependencyGraph;
import com.intellij.refactoring.util.classMembers.MemberInfo;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
public class InheritanceToDelegationDialog extends RefactoringDialog {
private final PsiClass[] mySuperClasses;
private final PsiClass myClass;
private final HashMap<PsiClass, Collection<MemberInfo>> myBasesToMemberInfos;
private NameSuggestionsField myFieldNameField;
private NameSuggestionsField myInnerClassNameField;
private JCheckBox myCbGenerateGetter;
private MemberSelectionPanel myMemberSelectionPanel;
private JComboBox myClassCombo;
private final Project myProject;
private MyClassComboItemListener myClassComboItemListener;
private NameSuggestionsField.DataChanged myDataChangedListener;
public InheritanceToDelegationDialog(Project project,
PsiClass aClass,
PsiClass[] superClasses,
HashMap<PsiClass,Collection<MemberInfo>> basesToMemberInfos) {
super(project, true);
myProject = project;
myClass = aClass;
mySuperClasses = superClasses;
myBasesToMemberInfos = basesToMemberInfos;
setTitle(InheritanceToDelegationHandler.REFACTORING_NAME);
init();
}
@Override
public JComponent getPreferredFocusedComponent() {
return myFieldNameField;
}
protected void dispose() {
myInnerClassNameField.removeDataChangedListener(myDataChangedListener);
myFieldNameField.removeDataChangedListener(myDataChangedListener);
myClassCombo.removeItemListener(myClassComboItemListener);
super.dispose();
}
@NotNull
public String getFieldName() {
return myFieldNameField.getEnteredName();
}
@Nullable
public String getInnerClassName() {
if (myInnerClassNameField != null) {
return myInnerClassNameField.getEnteredName();
}
else {
return null;
}
}
public boolean isGenerateGetter() {
return myCbGenerateGetter.isSelected();
}
@Override
protected void canRun() throws ConfigurationException {
final String fieldName = getFieldName();
final PsiNameHelper helper = PsiNameHelper.getInstance(myProject);
if (!helper.isIdentifier(fieldName)){
throw new ConfigurationException("\'" + fieldName + "\' is invalid field name for delegation");
}
if (myInnerClassNameField != null) {
final String className = myInnerClassNameField.getEnteredName();
if (!helper.isIdentifier(className)) {
throw new ConfigurationException("\'" + className + "\' is invalid inner class name");
}
}
}
public Collection<MemberInfo> getSelectedMemberInfos() {
return myMemberSelectionPanel.getTable().getSelectedMemberInfos();
}
public PsiClass getSelectedTargetClass() {
return (PsiClass)myClassCombo.getSelectedItem();
}
protected void doHelpAction() {
HelpManager.getInstance().invokeHelp(HelpID.INHERITANCE_TO_DELEGATION);
}
protected void doAction() {
JavaRefactoringSettings.getInstance().INHERITANCE_TO_DELEGATION_DELEGATE_OTHER = myCbGenerateGetter.isSelected();
final Collection<MemberInfo> selectedMemberInfos = getSelectedMemberInfos();
final ArrayList<PsiClass> implementedInterfaces = new ArrayList<PsiClass>();
final ArrayList<PsiMethod> delegatedMethods = new ArrayList<PsiMethod>();
for (MemberInfo memberInfo : selectedMemberInfos) {
final PsiElement member = memberInfo.getMember();
if (member instanceof PsiClass && Boolean.FALSE.equals(memberInfo.getOverrides())) {
implementedInterfaces.add((PsiClass)member);
}
else if (member instanceof PsiMethod) {
delegatedMethods.add((PsiMethod)member);
}
}
invokeRefactoring(new InheritanceToDelegationProcessor(myProject, myClass,
getSelectedTargetClass(), getFieldName(),
getInnerClassName(),
implementedInterfaces.toArray(new PsiClass[implementedInterfaces.size()]),
delegatedMethods.toArray(new PsiMethod[delegatedMethods.size()]),
isGenerateGetter(), isGenerateGetter()));
}
protected JComponent createNorthPanel() {
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
gbc.anchor = GridBagConstraints.WEST;
gbc.gridy = 0;
gbc.gridx = 0;
gbc.insets = new Insets(4, 0, 0, 8);
myClassCombo = new JComboBox(mySuperClasses);
myClassCombo.setRenderer(new ClassCellRenderer(myClassCombo.getRenderer()));
gbc.gridwidth = 2;
final JLabel classComboLabel = new JLabel();
panel.add(classComboLabel, gbc);
gbc.gridy++;
panel.add(myClassCombo, gbc);
classComboLabel.setText(RefactoringBundle.message("replace.inheritance.from"));
myClassComboItemListener = new MyClassComboItemListener();
myClassCombo.addItemListener(myClassComboItemListener);
gbc.gridy++;
gbc.gridwidth = 1;
gbc.insets = new Insets(4, 0, 4, 0);
final JLabel fieldNameLabel = new JLabel();
panel.add(fieldNameLabel, gbc);
myFieldNameField = new NameSuggestionsField(myProject);
gbc.gridx++;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.insets = new Insets(4, 0, 4, 8);
gbc.weightx = 1.0;
panel.add(myFieldNameField.getComponent(), gbc);
fieldNameLabel.setText(RefactoringBundle.message("field.name"));
// if(InheritanceToDelegationUtil.isInnerClassNeeded(myClass, mySuperClass)) {
gbc.gridx = 0;
gbc.gridy++;
gbc.gridwidth = 1;
gbc.insets = new Insets(4, 0, 4, 0);
gbc.weightx = 0.0;
final JLabel innerClassNameLabel = new JLabel();
panel.add(innerClassNameLabel, gbc);
/*String[] suggestions = new String[mySuperClasses.length];
for (int i = 0; i < suggestions.length; i++) {
suggestions[i] = "My" + mySuperClasses[i].getName();
}*/
myInnerClassNameField = new NameSuggestionsField(myProject);
gbc.gridx++;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.insets = new Insets(4, 4, 4, 8);
gbc.weightx = 1.0;
panel.add(myInnerClassNameField.getComponent(), gbc);
innerClassNameLabel.setText(RefactoringBundle.message("inner.class.name"));
boolean innerClassNeeded = false;
for (PsiClass superClass : mySuperClasses) {
innerClassNeeded |= InheritanceToDelegationUtil.isInnerClassNeeded(myClass, superClass);
}
myInnerClassNameField.setVisible(innerClassNeeded);
innerClassNameLabel.setVisible(innerClassNeeded);
return panel;
}
protected JComponent createCenterPanel() {
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
gbc.anchor = GridBagConstraints.WEST;
gbc.gridy = 0;
gbc.gridx = 0;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.gridwidth = 1;
gbc.insets = new Insets(4, 0, 4, 4);
myMemberSelectionPanel = new MemberSelectionPanel(RefactoringBundle.message("delegate.members"), Collections.<MemberInfo>emptyList(), null);
panel.add(myMemberSelectionPanel, gbc);
MyMemberInfoModel memberInfoModel = new InheritanceToDelegationDialog.MyMemberInfoModel();
myMemberSelectionPanel.getTable().setMemberInfoModel(memberInfoModel);
myMemberSelectionPanel.getTable().addMemberInfoChangeListener(memberInfoModel);
gbc.gridy++;
gbc.insets = new Insets(4, 8, 0, 8);
gbc.weighty = 0.0;
myCbGenerateGetter = new JCheckBox(RefactoringBundle.message("generate.getter.for.delegated.component"));
myCbGenerateGetter.setFocusable(false);
panel.add(myCbGenerateGetter, gbc);
myCbGenerateGetter.setSelected(JavaRefactoringSettings.getInstance().INHERITANCE_TO_DELEGATION_DELEGATE_OTHER);
updateTargetClass();
return panel;
}
private void updateTargetClass() {
final PsiClass targetClass = getSelectedTargetClass();
PsiManager psiManager = myClass.getManager();
PsiType superType = JavaPsiFacade.getInstance(psiManager.getProject()).getElementFactory().createType(targetClass);
SuggestedNameInfo suggestedNameInfo =
JavaCodeStyleManager.getInstance(psiManager.getProject()).suggestVariableName(VariableKind.FIELD, null, null, superType);
myFieldNameField.setSuggestions(suggestedNameInfo.names);
myInnerClassNameField.getComponent().setEnabled(InheritanceToDelegationUtil.isInnerClassNeeded(myClass, targetClass));
@NonNls final String suggestion = "My" + targetClass.getName();
myInnerClassNameField.setSuggestions(new String[]{suggestion});
myDataChangedListener = new NameSuggestionsField.DataChanged() {
public void dataChanged() {
validateButtons();
}
};
myInnerClassNameField.addDataChangedListener(myDataChangedListener);
myFieldNameField.addDataChangedListener(myDataChangedListener);
myMemberSelectionPanel.getTable().setMemberInfos(myBasesToMemberInfos.get(targetClass));
myMemberSelectionPanel.getTable().fireExternalDataChange();
}
private class MyMemberInfoModel implements MemberInfoModel<PsiMember, MemberInfo> {
final HashMap<PsiClass,InterfaceMemberDependencyGraph<PsiMember, MemberInfo>> myGraphs;
public MyMemberInfoModel() {
myGraphs = new HashMap<PsiClass, InterfaceMemberDependencyGraph<PsiMember, MemberInfo>>();
for (PsiClass superClass : mySuperClasses) {
myGraphs.put(superClass, new InterfaceMemberDependencyGraph<PsiMember, MemberInfo>(superClass));
}
}
public boolean isMemberEnabled(MemberInfo memberInfo) {
if (getGraph().getDependent().contains(memberInfo.getMember())) {
return false;
}
else {
return true;
}
}
public boolean isCheckedWhenDisabled(MemberInfo member) {
return true;
}
public boolean isAbstractEnabled(MemberInfo member) {
return false;
}
public boolean isAbstractWhenDisabled(MemberInfo member) {
return false;
}
public Boolean isFixedAbstract(MemberInfo member) {
return null;
}
public int checkForProblems(@NotNull MemberInfo member) {
return OK;
}
public String getTooltipText(MemberInfo member) {
return null;
}
public void memberInfoChanged(MemberInfoChange<PsiMember, MemberInfo> event) {
final Collection<MemberInfo> changedMembers = event.getChangedMembers();
for (MemberInfo changedMember : changedMembers) {
getGraph().memberChanged(changedMember);
}
}
private InterfaceMemberDependencyGraph<PsiMember, MemberInfo> getGraph() {
return myGraphs.get(getSelectedTargetClass());
}
}
private class MyClassComboItemListener implements ItemListener {
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
updateTargetClass();
}
}
}
}