mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-26 19:06:24 +07:00
IDEA-58049 Provide add type parameter quick-fix intention implemented
This commit is contained in:
+29
-104
@@ -15,14 +15,13 @@
|
||||
*/
|
||||
package com.intellij.codeInsight.daemon.impl.quickfix;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightUtilBase;
|
||||
import com.intellij.codeInsight.daemon.QuickFixBundle;
|
||||
import com.intellij.codeInsight.intention.impl.BaseIntentionAction;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.ScrollType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiUtilBase;
|
||||
import com.intellij.refactoring.changeClassSignature.ChangeClassSignatureDialog;
|
||||
import com.intellij.refactoring.changeClassSignature.TypeParameterInfo;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -62,119 +61,50 @@ public class ChangeClassSignatureFromUsageFix extends BaseIntentionAction {
|
||||
return false;
|
||||
}
|
||||
|
||||
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
|
||||
Map<PsiTypeParameter, Boolean> typeParameterBooleanMap = createTypeParameters(
|
||||
factory,
|
||||
classTypeParameterList.getTypeParameters(),
|
||||
myParameterList.getTypeParameterElements()
|
||||
);
|
||||
|
||||
if (isAddOneTypeParameter(typeParameterBooleanMap)) {
|
||||
setText(QuickFixBundle.message("add.type.parameter.text", myClass.getName()));
|
||||
}
|
||||
else {
|
||||
setText(QuickFixBundle.message("change.class.signature.text", myClass.getName(), parametersToSignatureText(typeParameterBooleanMap)));
|
||||
}
|
||||
setText(QuickFixBundle.message("change.class.signature.text", myClass.getName(), myParameterList.getText()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isAddOneTypeParameter(@NotNull Map<PsiTypeParameter, Boolean> map) {
|
||||
boolean oneParameter = false;
|
||||
for (Boolean b : map.values()) {
|
||||
if (b == Boolean.TRUE) {
|
||||
if (oneParameter) {
|
||||
return false;
|
||||
}
|
||||
oneParameter = true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String parametersToSignatureText(@NotNull Map<PsiTypeParameter, Boolean> map) {
|
||||
final StringBuilder result = new StringBuilder("<");
|
||||
for (Map.Entry<PsiTypeParameter, Boolean> e : map.entrySet()) {
|
||||
final String text = e.getKey().getText();
|
||||
if (e.getValue() == Boolean.TRUE) {
|
||||
result.append("<b>").append(text).append("</b>");
|
||||
}
|
||||
else {
|
||||
result.append(text);
|
||||
}
|
||||
result.append(", ");
|
||||
}
|
||||
|
||||
final int lng = result.length();
|
||||
result.delete(lng - 2, lng);
|
||||
|
||||
return result.append(">").toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
|
||||
if (!CodeInsightUtilBase.prepareFileForWrite(file)) return;
|
||||
|
||||
final PsiTypeParameterList classTypeParameterList = myClass.getTypeParameterList();
|
||||
if (classTypeParameterList == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
|
||||
|
||||
final PsiElement newTypeParameterList = classTypeParameterList.replace(
|
||||
createTypeParameterList(
|
||||
factory,
|
||||
classTypeParameterList.getTypeParameters(),
|
||||
myParameterList.getTypeParameterElements()
|
||||
)
|
||||
ChangeClassSignatureDialog dialog = new ChangeClassSignatureDialog(
|
||||
myClass,
|
||||
createTypeParameters(
|
||||
JavaCodeFragmentFactory.getInstance(project),
|
||||
Arrays.asList(classTypeParameterList.getTypeParameters()),
|
||||
Arrays.asList(myParameterList.getTypeParameterElements())
|
||||
),
|
||||
false
|
||||
);
|
||||
|
||||
navigateTo(newTypeParameterList);
|
||||
}
|
||||
|
||||
private static void navigateTo(@NotNull PsiElement element) {
|
||||
element.getContainingFile().navigate(false);
|
||||
final Editor editor = PsiUtilBase.findEditor(element);
|
||||
if (editor == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
editor.getCaretModel().moveToOffset(element.getTextRange().getStartOffset());
|
||||
editor.getScrollingModel().scrollToCaret(ScrollType.CENTER);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PsiTypeParameterList createTypeParameterList(@NotNull PsiElementFactory factory,
|
||||
@NotNull PsiTypeParameter[] classTypeParameters,
|
||||
@NotNull PsiTypeElement[] typeElements) {
|
||||
final PsiTypeParameterList result = factory.createTypeParameterList();
|
||||
for (PsiTypeParameter p : createTypeParameters(factory, classTypeParameters, typeElements).keySet()) {
|
||||
result.add(p);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Map<PsiTypeParameter, Boolean> createTypeParameters(@NotNull PsiElementFactory factory,
|
||||
@NotNull PsiTypeParameter[] classTypeParameters,
|
||||
@NotNull PsiTypeElement[] typeElements) {
|
||||
final LinkedHashMap<PsiTypeParameter, Boolean> result = new LinkedHashMap<PsiTypeParameter, Boolean>();
|
||||
private static Map<TypeParameterInfo, PsiTypeCodeFragment> createTypeParameters(@NotNull JavaCodeFragmentFactory factory,
|
||||
@NotNull List<PsiTypeParameter> classTypeParameters,
|
||||
@NotNull List<PsiTypeElement> typeElements) {
|
||||
final LinkedHashMap<TypeParameterInfo, PsiTypeCodeFragment> result = new LinkedHashMap<TypeParameterInfo, PsiTypeCodeFragment>();
|
||||
final TypeParameterNameSuggester suggester = new TypeParameterNameSuggester(classTypeParameters);
|
||||
|
||||
final Queue<PsiTypeParameter> classTypeParametersQueue = new LinkedList<PsiTypeParameter>(Arrays.asList(classTypeParameters));
|
||||
int listIndex = 0;
|
||||
for (PsiTypeElement typeElement : typeElements) {
|
||||
if (!classTypeParametersQueue.isEmpty()) {
|
||||
final PsiTypeParameter typeParameter = classTypeParametersQueue.peek();
|
||||
if (listIndex < classTypeParameters.size()) {
|
||||
final PsiTypeParameter typeParameter = classTypeParameters.get(listIndex);
|
||||
|
||||
if (isAssignable(typeParameter, typeElement.getType())) {
|
||||
result.put(typeParameter, false);
|
||||
classTypeParametersQueue.poll();
|
||||
result.put(new TypeParameterInfo(listIndex++), null);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
result.put(toTypeParameter(factory, suggester, typeElement), true);
|
||||
|
||||
final PsiClassType type = (PsiClassType)typeElement.getType();
|
||||
result.put(new TypeParameterInfo(suggester.suggest(type), type), factory.createTypeCodeFragment(type.getClassName(), typeElement, true));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -189,25 +119,20 @@ public class ChangeClassSignatureFromUsageFix extends BaseIntentionAction {
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PsiTypeParameter toTypeParameter(@NotNull PsiElementFactory factory,
|
||||
@NotNull TypeParameterNameSuggester suggester,
|
||||
@NotNull PsiTypeElement typeElement) {
|
||||
final PsiType type = typeElement.getType();
|
||||
|
||||
return factory.createTypeParameter(suggester.suggest((PsiClassType)type), PsiClassType.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startInWriteAction() {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static class TypeParameterNameSuggester {
|
||||
private final Set<String> usedNames = new HashSet<String>();
|
||||
|
||||
public TypeParameterNameSuggester(@NotNull PsiTypeParameter[] typeParameters) {
|
||||
public TypeParameterNameSuggester(@NotNull PsiTypeParameter... typeParameters) {
|
||||
this(Arrays.asList(typeParameters));
|
||||
}
|
||||
|
||||
public TypeParameterNameSuggester(@NotNull Collection<PsiTypeParameter> typeParameters) {
|
||||
for (PsiTypeParameter p : typeParameters) {
|
||||
usedNames.add(p.getName());
|
||||
}
|
||||
|
||||
+77
-39
@@ -25,12 +25,12 @@ import com.intellij.refactoring.ui.JavaCodeFragmentTableCellEditor;
|
||||
import com.intellij.refactoring.ui.RefactoringDialog;
|
||||
import com.intellij.refactoring.ui.StringTableCellEditor;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import com.intellij.refactoring.util.RefactoringUIUtil;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.table.JBTable;
|
||||
import com.intellij.usageView.UsageViewUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ui.EditableModel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -39,17 +39,15 @@ import javax.swing.event.TableModelListener;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import javax.swing.table.TableColumn;
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author dsl
|
||||
* @author Konstantin Bulenkov
|
||||
*/
|
||||
public class ChangeClassSignatureDialog extends RefactoringDialog {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.changeClassSignature.ChangeClassSignatureDialog");
|
||||
private static final Logger LOG = Logger.getInstance(ChangeClassSignatureDialog.class);
|
||||
private static final int NAME_COLUMN = 0;
|
||||
private static final int VALUE_COLUMN = 1;
|
||||
|
||||
@@ -61,19 +59,53 @@ public class ChangeClassSignatureDialog extends RefactoringDialog {
|
||||
private final MyTableModel myTableModel;
|
||||
private JBTable myTable;
|
||||
static final String REFACTORING_NAME = RefactoringBundle.message("changeClassSignature.refactoring.name");
|
||||
private boolean myHideDefaultValueColumn;
|
||||
|
||||
public ChangeClassSignatureDialog(PsiClass aClass) {
|
||||
public ChangeClassSignatureDialog(@NotNull PsiClass aClass, boolean hideDefaultValueColumn) {
|
||||
this(
|
||||
aClass,
|
||||
initTypeParameterInfos(aClass.getTypeParameters().length),
|
||||
initTypeCodeFragment(aClass.getTypeParameters().length),
|
||||
hideDefaultValueColumn
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<TypeParameterInfo> initTypeParameterInfos(int length) {
|
||||
final List<TypeParameterInfo> result = new ArrayList<TypeParameterInfo>();
|
||||
for (int i = 0; i < length; i++) {
|
||||
result.add(new TypeParameterInfo(i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<PsiTypeCodeFragment> initTypeCodeFragment(int length) {
|
||||
final List<PsiTypeCodeFragment> result = new ArrayList<PsiTypeCodeFragment>();
|
||||
for (int i = 0; i < length; i++) {
|
||||
result.add(null);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public ChangeClassSignatureDialog(@NotNull PsiClass aClass,
|
||||
@NotNull Map<TypeParameterInfo, PsiTypeCodeFragment> parameters,
|
||||
boolean hideDefaultValueColumn) {
|
||||
this(aClass, parameters.keySet(), parameters.values(), hideDefaultValueColumn);
|
||||
}
|
||||
|
||||
public ChangeClassSignatureDialog(@NotNull PsiClass aClass,
|
||||
@NotNull Collection<TypeParameterInfo> typeParameterInfos,
|
||||
@NotNull Collection<PsiTypeCodeFragment> typeCodeFragments,
|
||||
boolean hideDefaultValueColumn) {
|
||||
super(aClass.getProject(), true);
|
||||
myHideDefaultValueColumn = hideDefaultValueColumn;
|
||||
setTitle(REFACTORING_NAME);
|
||||
myClass = aClass;
|
||||
myProject = myClass.getProject();
|
||||
myTypeParameterInfos = new ArrayList<TypeParameterInfo>();
|
||||
myTypeCodeFragments = new ArrayList<PsiTypeCodeFragment>();
|
||||
myOriginalParameters = myClass.getTypeParameters();
|
||||
for (int i = 0; i < myOriginalParameters.length; i++) {
|
||||
myTypeParameterInfos.add(new TypeParameterInfo(i));
|
||||
myTypeCodeFragments.add(null);
|
||||
}
|
||||
myTypeParameterInfos = new ArrayList<TypeParameterInfo>(typeParameterInfos);
|
||||
myTypeCodeFragments = new ArrayList<PsiTypeCodeFragment>(typeCodeFragments);
|
||||
myTableModel = new MyTableModel();
|
||||
init();
|
||||
}
|
||||
@@ -115,26 +147,28 @@ public class ChangeClassSignatureDialog extends RefactoringDialog {
|
||||
myTable.setCellSelectionEnabled(true);
|
||||
myTable.setFocusCycleRoot(true);
|
||||
|
||||
final TableColumn defaultValue = myTable.getColumnModel().getColumn(1);
|
||||
myTable.removeColumn(defaultValue);
|
||||
myTable.getModel().addTableModelListener(new TableModelListener() {
|
||||
@Override
|
||||
public void tableChanged(TableModelEvent e) {
|
||||
if (e.getType() == TableModelEvent.INSERT) {
|
||||
myTable.getModel().removeTableModelListener(this);
|
||||
final TableColumnAnimator animator = new TableColumnAnimator(myTable);
|
||||
animator.setStep(20);
|
||||
animator.addColumn(defaultValue, myTable.getWidth() / 2);
|
||||
animator.startAndDoWhenDone(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
myTable.editCellAt(myTable.getRowCount() - 1, 0);
|
||||
}
|
||||
});
|
||||
animator.start();
|
||||
if (myHideDefaultValueColumn) {
|
||||
final TableColumn defaultValue = myTable.getColumnModel().getColumn(VALUE_COLUMN);
|
||||
myTable.removeColumn(defaultValue);
|
||||
myTable.getModel().addTableModelListener(new TableModelListener() {
|
||||
@Override
|
||||
public void tableChanged(TableModelEvent e) {
|
||||
if (e.getType() == TableModelEvent.INSERT) {
|
||||
myTable.getModel().removeTableModelListener(this);
|
||||
final TableColumnAnimator animator = new TableColumnAnimator(myTable);
|
||||
animator.setStep(20);
|
||||
animator.addColumn(defaultValue, myTable.getWidth() / 2);
|
||||
animator.startAndDoWhenDone(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
myTable.editCellAt(myTable.getRowCount() - 1, 0);
|
||||
}
|
||||
});
|
||||
animator.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
final JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.add(SeparatorFactory.createSeparator(RefactoringBundle.message("changeClassSignature.parameters.panel.border.title"), myTable), BorderLayout.NORTH);
|
||||
@@ -208,12 +242,13 @@ public class ChangeClassSignatureDialog extends RefactoringDialog {
|
||||
}
|
||||
|
||||
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||
switch(columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case NAME_COLUMN:
|
||||
TypeParameterInfo info = myTypeParameterInfos.get(rowIndex);
|
||||
if (info.isForExistingParameter()) {
|
||||
return myOriginalParameters[info.getOldParameterIndex()].getName();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return info.getNewName();
|
||||
}
|
||||
case VALUE_COLUMN:
|
||||
@@ -228,18 +263,21 @@ public class ChangeClassSignatureDialog extends RefactoringDialog {
|
||||
}
|
||||
|
||||
public String getColumnName(int column) {
|
||||
switch(column) {
|
||||
case NAME_COLUMN: return RefactoringBundle.message("column.name.name");
|
||||
case VALUE_COLUMN: return RefactoringBundle.message("changeSignature.default.value.column");
|
||||
default: LOG.assertTrue(false);
|
||||
switch (column) {
|
||||
case NAME_COLUMN:
|
||||
return RefactoringBundle.message("column.name.name");
|
||||
case VALUE_COLUMN:
|
||||
return RefactoringBundle.message("changeSignature.default.value.column");
|
||||
default:
|
||||
LOG.assertTrue(false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
|
||||
switch(columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case NAME_COLUMN:
|
||||
myTypeParameterInfos.get(rowIndex).setNewName((String) aValue);
|
||||
myTypeParameterInfos.get(rowIndex).setNewName((String)aValue);
|
||||
break;
|
||||
case VALUE_COLUMN:
|
||||
break;
|
||||
|
||||
+3
-3
@@ -25,17 +25,17 @@ import org.jetbrains.annotations.NonNls;
|
||||
/**
|
||||
* @author dsl
|
||||
*/
|
||||
class TypeParameterInfo {
|
||||
public class TypeParameterInfo {
|
||||
private final int myOldParameterIndex;
|
||||
private String myNewName;
|
||||
private CanonicalTypes.Type myDefaultValue;
|
||||
|
||||
TypeParameterInfo(int oldIndex) {
|
||||
public TypeParameterInfo(int oldIndex) {
|
||||
myOldParameterIndex = oldIndex;
|
||||
myDefaultValue = null;
|
||||
}
|
||||
|
||||
TypeParameterInfo(String name, PsiType aType) {
|
||||
public TypeParameterInfo(String name, PsiType aType) {
|
||||
myOldParameterIndex = -1;
|
||||
myNewName = name;
|
||||
if (aType != null) {
|
||||
|
||||
+7
-1
@@ -20,6 +20,8 @@ import com.intellij.ide.util.SuperMethodWarningUtil;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.actionSystem.LangDataKeys;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.ScrollType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -99,8 +101,12 @@ public class JavaChangeSignatureHandler implements ChangeSignatureHandler {
|
||||
}
|
||||
if (!CommonRefactoringUtil.checkReadOnlyStatus(project, aClass)) return;
|
||||
|
||||
ChangeClassSignatureDialog dialog = new ChangeClassSignatureDialog(aClass);
|
||||
ChangeClassSignatureDialog dialog = new ChangeClassSignatureDialog(aClass, true);
|
||||
//if (!ApplicationManager.getApplication().isUnitTestMode()){
|
||||
dialog.show();
|
||||
//}else {
|
||||
// dialog.showAndGetOk()
|
||||
//}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
Reference in New Issue
Block a user