| /* |
| * 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.changeSignature; |
| |
| import com.intellij.codeInsight.completion.CompletionResultSet; |
| import com.intellij.codeInsight.lookup.LookupElementBuilder; |
| import com.intellij.openapi.actionSystem.AnActionEvent; |
| import com.intellij.openapi.actionSystem.CustomShortcutSet; |
| import com.intellij.openapi.command.WriteCommandAction; |
| import com.intellij.openapi.editor.Document; |
| import com.intellij.openapi.editor.colors.EditorColorsManager; |
| import com.intellij.openapi.editor.colors.EditorFontType; |
| import com.intellij.openapi.editor.event.DocumentAdapter; |
| import com.intellij.openapi.editor.event.DocumentEvent; |
| import com.intellij.openapi.fileTypes.LanguageFileType; |
| import com.intellij.openapi.fileTypes.StdFileTypes; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.ui.Messages; |
| import com.intellij.openapi.ui.ValidationInfo; |
| import com.intellij.openapi.util.Comparing; |
| import com.intellij.openapi.util.Computable; |
| import com.intellij.openapi.util.Pair; |
| import com.intellij.openapi.util.Ref; |
| import com.intellij.openapi.util.text.StringUtil; |
| 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.BaseRefactoringProcessor; |
| import com.intellij.refactoring.RefactoringBundle; |
| import com.intellij.refactoring.changeSignature.inCallers.JavaCallerChooser; |
| import com.intellij.refactoring.ui.CodeFragmentTableCellRenderer; |
| import com.intellij.refactoring.ui.JavaCodeFragmentTableCellEditor; |
| import com.intellij.refactoring.ui.JavaComboBoxVisibilityPanel; |
| import com.intellij.refactoring.ui.VisibilityPanelBase; |
| import com.intellij.refactoring.util.CanonicalTypes; |
| import com.intellij.refactoring.util.RefactoringMessageUtil; |
| import com.intellij.refactoring.util.RefactoringUtil; |
| import com.intellij.ui.*; |
| import com.intellij.ui.table.JBTable; |
| import com.intellij.ui.table.TableView; |
| import com.intellij.ui.treeStructure.Tree; |
| import com.intellij.util.*; |
| import com.intellij.util.ui.DialogUtil; |
| import com.intellij.util.ui.UIUtil; |
| import com.intellij.util.ui.table.JBListTable; |
| import com.intellij.util.ui.table.JBTableRow; |
| import com.intellij.util.ui.table.JBTableRowEditor; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import javax.swing.*; |
| import javax.swing.event.TableModelEvent; |
| import javax.swing.event.TableModelListener; |
| import javax.swing.table.TableColumn; |
| import java.awt.*; |
| import java.awt.event.ActionEvent; |
| import java.awt.event.ActionListener; |
| import java.awt.event.MouseEvent; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Set; |
| |
| import static com.intellij.refactoring.changeSignature.ChangeSignatureHandler.REFACTORING_NAME; |
| |
| /** |
| * @author Konstantin Bulenkov |
| */ |
| public class JavaChangeSignatureDialog extends ChangeSignatureDialogBase<ParameterInfoImpl, PsiMethod, String, JavaMethodDescriptor, ParameterTableModelItemBase<ParameterInfoImpl>, JavaParameterTableModel> { |
| private ExceptionsTableModel myExceptionsModel; |
| protected Set<PsiMethod> myMethodsToPropagateExceptions; |
| private AnActionButton myPropExceptionsButton; |
| private Tree myExceptionPropagationTree; |
| |
| public JavaChangeSignatureDialog(Project project, PsiMethod method, boolean allowDelegation, PsiElement context) { |
| this(project, new JavaMethodDescriptor(method), allowDelegation, context); |
| } |
| |
| protected JavaChangeSignatureDialog(Project project, JavaMethodDescriptor descriptor, boolean allowDelegation, PsiElement context) { |
| super(project, descriptor, allowDelegation, context); |
| } |
| |
| public static JavaChangeSignatureDialog createAndPreselectNew(final Project project, |
| final PsiMethod method, |
| final List<ParameterInfoImpl> parameterInfos, |
| final boolean allowDelegation, final PsiReferenceExpression refExpr) { |
| return new JavaChangeSignatureDialog(project, method, allowDelegation, refExpr) { |
| @Override |
| protected int getSelectedIdx() { |
| for (int i = 0; i < parameterInfos.size(); i++) { |
| ParameterInfoImpl info = parameterInfos.get(i); |
| if (info.oldParameterIndex < 0) { |
| return i; |
| } |
| } |
| return super.getSelectedIdx(); |
| } |
| }; |
| } |
| |
| @Override |
| protected VisibilityPanelBase<String> createVisibilityControl() { |
| return new JavaComboBoxVisibilityPanel(); |
| } |
| |
| @Override |
| protected JComponent createCenterPanel() { |
| final JComponent centerPanel = super.createCenterPanel(); |
| myPropagateParamChangesButton.setVisible(true); |
| return centerPanel; |
| } |
| |
| @Override |
| protected void updatePropagateButtons() { |
| super.updatePropagateButtons(); |
| myPropExceptionsButton.setEnabled(!isGenerateDelegate() && mayPropagateExceptions()); |
| } |
| |
| protected boolean mayPropagateExceptions() { |
| final ThrownExceptionInfo[] exceptions = myExceptionsModel.getThrownExceptions(); |
| final PsiClassType[] types = myMethod.getMethod().getThrowsList().getReferencedTypes(); |
| |
| if (exceptions.length <= types.length) { |
| return false; |
| } |
| |
| for (int i = 0; i < types.length; i++) { |
| if (exceptions[i].getOldIndex() != i) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| @NotNull |
| protected List<Pair<String,JPanel>> createAdditionalPanels() { |
| // this method is invoked before constructor body |
| myExceptionsModel = new ExceptionsTableModel(myMethod.getMethod().getThrowsList()); |
| myExceptionsModel.setTypeInfos(myMethod.getMethod()); |
| |
| final JBTable table = new JBTable(myExceptionsModel); |
| table.setStriped(true); |
| table.setRowHeight(20); |
| table.getColumnModel().getColumn(0).setCellRenderer(new CodeFragmentTableCellRenderer(myProject)); |
| final JavaCodeFragmentTableCellEditor cellEditor = new JavaCodeFragmentTableCellEditor(myProject); |
| cellEditor.addDocumentListener(new DocumentAdapter() { |
| @Override |
| public void documentChanged(DocumentEvent e) { |
| final int row = table.getSelectedRow(); |
| final int col = table.getSelectedColumn(); |
| myExceptionsModel.setValueAt(cellEditor.getCellEditorValue(), row, col); |
| updateSignature(); |
| } |
| }); |
| table.getColumnModel().getColumn(0).setCellEditor(cellEditor); |
| table.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); |
| table.getSelectionModel().setSelectionInterval(0, 0); |
| table.setSurrendersFocusOnKeystroke(true); |
| |
| myPropExceptionsButton = new AnActionButton(RefactoringBundle.message("changeSignature.propagate.exceptions.title"), null, PlatformIcons.NEW_EXCEPTION) { |
| @Override |
| public void actionPerformed(AnActionEvent e) { |
| final Ref<JavaCallerChooser> chooser = new Ref<JavaCallerChooser>(); |
| Consumer<Set<PsiMethod>> callback = new Consumer<Set<PsiMethod>>() { |
| @Override |
| public void consume(Set<PsiMethod> psiMethods) { |
| myMethodsToPropagateExceptions = psiMethods; |
| myExceptionPropagationTree = chooser.get().getTree(); |
| } |
| }; |
| chooser.set(new JavaCallerChooser(myMethod.getMethod(), |
| myProject, |
| RefactoringBundle.message("changeSignature.exception.caller.chooser"), |
| myExceptionPropagationTree, |
| callback)); |
| chooser.get().show(); |
| } |
| }; |
| myPropExceptionsButton.setShortcut(CustomShortcutSet.fromString("alt X")); |
| |
| final JPanel panel = ToolbarDecorator.createDecorator(table).addExtraAction(myPropExceptionsButton).createPanel(); |
| panel.setBorder(IdeBorderFactory.createEmptyBorder()); |
| |
| myExceptionsModel.addTableModelListener(mySignatureUpdater); |
| |
| final ArrayList<Pair<String, JPanel>> result = new ArrayList<Pair<String, JPanel>>(); |
| final String message = RefactoringBundle.message("changeSignature.exceptions.panel.border.title"); |
| result.add(Pair.create(message, panel)); |
| return result; |
| } |
| |
| @Override |
| protected LanguageFileType getFileType() { |
| return StdFileTypes.JAVA; |
| } |
| |
| @Override |
| protected JavaParameterTableModel createParametersInfoModel(JavaMethodDescriptor descriptor) { |
| final PsiParameterList parameterList = descriptor.getMethod().getParameterList(); |
| return new JavaParameterTableModel(parameterList, myDefaultValueContext, this); |
| } |
| |
| @Override |
| protected boolean isListTableViewSupported() { |
| return true; |
| } |
| |
| @Override |
| protected boolean isEmptyRow(ParameterTableModelItemBase<ParameterInfoImpl> row) { |
| if (!StringUtil.isEmpty(row.parameter.getName())) return false; |
| if (!StringUtil.isEmpty(row.parameter.getTypeText())) return false; |
| return true; |
| } |
| |
| @Override |
| protected JComponent getRowPresentation(ParameterTableModelItemBase<ParameterInfoImpl> item, boolean selected, final boolean focused) { |
| final String typeText = item.typeCodeFragment.getText(); |
| final String separator = StringUtil.repeatSymbol(' ', getTypesMaxLength() - typeText.length() + 1); |
| String text = typeText + separator + item.parameter.getName(); |
| final String defaultValue = item.defaultValueCodeFragment.getText(); |
| String tail = ""; |
| if (StringUtil.isNotEmpty(defaultValue)) { |
| tail += " default value = " + defaultValue; |
| } |
| if (item.parameter.isUseAnySingleVariable()) { |
| if (StringUtil.isNotEmpty(defaultValue)) { |
| tail += ";"; |
| } |
| tail += " Use any var."; |
| } |
| if (!StringUtil.isEmpty(tail)) { |
| text += " //" + tail; |
| } |
| return JBListTable.createEditorTextFieldPresentation(getProject(), getFileType(), " " + text, selected, focused); |
| } |
| |
| private int getTypesMaxLength() { |
| int len = 0; |
| for (ParameterTableModelItemBase<ParameterInfoImpl> item : myParametersTableModel.getItems()) { |
| final String text = item.typeCodeFragment == null ? null : item.typeCodeFragment.getText(); |
| len = Math.max(len, text == null ? 0 : text.length()); |
| } |
| return len; |
| } |
| |
| private int getNamesMaxLength() { |
| int len = 0; |
| for (ParameterTableModelItemBase<ParameterInfoImpl> item : myParametersTableModel.getItems()) { |
| final String text = item.parameter.getName(); |
| len = Math.max(len, text == null ? 0 : text.length()); |
| } |
| return len; |
| } |
| |
| private int getColumnWidth(int index) { |
| int letters = getTypesMaxLength() + (index == 0 ? 1 : getNamesMaxLength() + 2); |
| Font font = EditorColorsManager.getInstance().getGlobalScheme().getFont(EditorFontType.PLAIN); |
| font = new Font(font.getFontName(), font.getStyle(), 12); |
| return letters * Toolkit.getDefaultToolkit().getFontMetrics(font).stringWidth("W"); |
| } |
| |
| private int getTypesColumnWidth() { |
| return getColumnWidth(0); |
| } |
| |
| private int getNamesColumnWidth() { |
| return getColumnWidth(1); |
| } |
| |
| @Override |
| protected JBTableRowEditor getTableEditor(final JTable t, final ParameterTableModelItemBase<ParameterInfoImpl> item) { |
| return new JBTableRowEditor() { |
| private EditorTextField myTypeEditor; |
| private EditorTextField myNameEditor; |
| private EditorTextField myDefaultValueEditor; |
| private JCheckBox myAnyVar; |
| |
| @Override |
| public void prepareEditor(JTable table, int row) { |
| setLayout(new BorderLayout()); |
| final Document document = PsiDocumentManager.getInstance(getProject()).getDocument(item.typeCodeFragment); |
| myTypeEditor = new EditorTextField(document, getProject(), getFileType()); |
| myTypeEditor.addDocumentListener(mySignatureUpdater); |
| myTypeEditor.setPreferredWidth(t.getWidth() / 2); |
| myTypeEditor.addDocumentListener(new RowEditorChangeListener(0)); |
| add(createLabeledPanel("Type:", myTypeEditor), BorderLayout.WEST); |
| |
| myNameEditor = new EditorTextField(item.parameter.getName(), getProject(), getFileType()); |
| myNameEditor.addDocumentListener(mySignatureUpdater); |
| myNameEditor.addDocumentListener(new RowEditorChangeListener(1)); |
| add(createLabeledPanel("Name:", myNameEditor), BorderLayout.CENTER); |
| new TextFieldCompletionProvider() { |
| |
| @Override |
| protected void addCompletionVariants(@NotNull String text, |
| int offset, |
| @NotNull String prefix, |
| @NotNull CompletionResultSet result) { |
| final PsiCodeFragment fragment = item.typeCodeFragment; |
| if (fragment instanceof PsiTypeCodeFragment) { |
| final PsiType type; |
| try { |
| type = ((PsiTypeCodeFragment)fragment).getType(); |
| } |
| catch (Exception e) { |
| return; |
| } |
| final SuggestedNameInfo info = JavaCodeStyleManager.getInstance(myProject) |
| .suggestVariableName(VariableKind.PARAMETER, null, null, type); |
| |
| for (String completionVariant : info.names) { |
| final LookupElementBuilder element = LookupElementBuilder.create(completionVariant); |
| result.addElement(element.withLookupString(completionVariant.toLowerCase())); |
| } |
| } |
| } |
| }.apply(myNameEditor, item.parameter.getName()); |
| |
| if (!item.isEllipsisType() && item.parameter.getOldIndex() == -1) { |
| final JPanel additionalPanel = new JPanel(new BorderLayout()); |
| final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(item.defaultValueCodeFragment); |
| myDefaultValueEditor = new EditorTextField(doc, getProject(), getFileType()); |
| ((PsiExpressionCodeFragment)item.defaultValueCodeFragment).setExpectedType(getRowType(item)); |
| myDefaultValueEditor.setPreferredWidth(t.getWidth() / 2); |
| myDefaultValueEditor.addDocumentListener(new RowEditorChangeListener(2)); |
| additionalPanel.add(createLabeledPanel("Default value:", myDefaultValueEditor), BorderLayout.WEST); |
| |
| if (!isGenerateDelegate()) { |
| myAnyVar = new JCheckBox("&Use Any Var"); |
| UIUtil.applyStyle(UIUtil.ComponentStyle.SMALL, myAnyVar); |
| DialogUtil.registerMnemonic(myAnyVar, '&'); |
| myAnyVar.addActionListener(new ActionListener() { |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| item.parameter.setUseAnySingleVariable(myAnyVar.isSelected()); |
| } |
| }); |
| final JPanel anyVarPanel = new JPanel(new BorderLayout()); |
| anyVarPanel.add(myAnyVar, BorderLayout.SOUTH); |
| UIUtil.addInsets(anyVarPanel, new Insets(0,0,8,0)); |
| additionalPanel.add(anyVarPanel, BorderLayout.CENTER); |
| //additionalPanel.setPreferredSize(new Dimension(t.getWidth() / 3, -1)); |
| } |
| add(additionalPanel, BorderLayout.SOUTH); |
| } |
| } |
| |
| @Override |
| public JBTableRow getValue() { |
| return new JBTableRow() { |
| @Override |
| public Object getValueAt(int column) { |
| switch (column) { |
| case 0: return item.typeCodeFragment; |
| case 1: return myNameEditor.getText().trim(); |
| case 2: return item.defaultValueCodeFragment; |
| case 3: return myAnyVar != null && myAnyVar.isSelected(); |
| } |
| return null; |
| } |
| }; |
| } |
| |
| @Override |
| public JComponent getPreferredFocusedComponent() { |
| final MouseEvent me = getMouseEvent(); |
| if (me == null) { |
| return myTypeEditor.getFocusTarget(); |
| } |
| final double x = me.getPoint().getX(); |
| return x <= getTypesColumnWidth() |
| ? myTypeEditor.getFocusTarget() |
| : myDefaultValueEditor == null || x <= getNamesColumnWidth() |
| ? myNameEditor.getFocusTarget() |
| : myDefaultValueEditor.getFocusTarget(); |
| } |
| |
| @Override |
| public JComponent[] getFocusableComponents() { |
| final List<JComponent> focusable = new ArrayList<JComponent>(); |
| focusable.add(myTypeEditor.getFocusTarget()); |
| focusable.add(myNameEditor.getFocusTarget()); |
| if (myDefaultValueEditor != null) { |
| focusable.add(myDefaultValueEditor.getFocusTarget()); |
| } |
| if (myAnyVar != null) { |
| focusable.add(myAnyVar); |
| } |
| return focusable.toArray(new JComponent[focusable.size()]); |
| } |
| }; |
| } |
| |
| @Nullable |
| private static PsiType getRowType(ParameterTableModelItemBase<ParameterInfoImpl> item) { |
| try { |
| return ((PsiTypeCodeFragment)item.typeCodeFragment).getType(); |
| } |
| catch (PsiTypeCodeFragment.TypeSyntaxException e) { |
| return null; |
| } |
| catch (PsiTypeCodeFragment.NoTypeException e) { |
| return null; |
| } |
| } |
| |
| @Override |
| protected void customizeParametersTable(TableView<ParameterTableModelItemBase<ParameterInfoImpl>> table) { |
| final JTable t = table.getComponent(); |
| final TableColumn defaultValue = t.getColumnModel().getColumn(2); |
| final TableColumn varArg = t.getColumnModel().getColumn(3); |
| t.removeColumn(defaultValue); |
| t.removeColumn(varArg); |
| t.getModel().addTableModelListener(new TableModelListener() { |
| @Override |
| public void tableChanged(TableModelEvent e) { |
| if (e.getType() == TableModelEvent.INSERT) { |
| t.getModel().removeTableModelListener(this); |
| final TableColumnAnimator animator = new TableColumnAnimator(t); |
| animator.setStep(48); |
| animator.addColumn(defaultValue, (t.getWidth() - 48) / 3); |
| animator.addColumn(varArg, 48); |
| animator.startAndDoWhenDone(new Runnable() { |
| @Override |
| public void run() { |
| t.editCellAt(t.getRowCount() - 1, 0); |
| } |
| }); |
| animator.start(); |
| } |
| } |
| }); |
| } |
| |
| @Override |
| protected void invokeRefactoring(final BaseRefactoringProcessor processor) { |
| if (myMethodsToPropagateExceptions != null && !mayPropagateExceptions()) { |
| Messages.showWarningDialog(myProject, RefactoringBundle.message("changeSignature.exceptions.wont.propagate"), REFACTORING_NAME); |
| myMethodsToPropagateExceptions = null; |
| } |
| super.invokeRefactoring(processor); |
| } |
| |
| @Override |
| protected BaseRefactoringProcessor createRefactoringProcessor() { |
| final List<ParameterInfoImpl> parameters = getParameters(); |
| return new ChangeSignatureProcessor(myProject, |
| myMethod.getMethod(), |
| isGenerateDelegate(), |
| getVisibility(), |
| getMethodName(), |
| getReturnType(), |
| parameters.toArray(new ParameterInfoImpl[parameters.size()]), |
| getExceptions(), |
| myMethodsToPropagateParameters, |
| myMethodsToPropagateExceptions); |
| } |
| |
| @Nullable |
| protected CanonicalTypes.Type getReturnType() { |
| if (myReturnTypeField != null) { |
| try { |
| final PsiType type = ((PsiTypeCodeFragment)myReturnTypeCodeFragment).getType(); |
| return CanonicalTypes.createTypeWrapper(type); |
| } |
| catch (PsiTypeCodeFragment.TypeSyntaxException e) { |
| return null; |
| } |
| catch (PsiTypeCodeFragment.NoTypeException e) { |
| return null; |
| } |
| } |
| |
| return null; |
| } |
| |
| protected ThrownExceptionInfo[] getExceptions() { |
| return myExceptionsModel.getThrownExceptions(); |
| } |
| |
| @Override |
| protected PsiCodeFragment createReturnTypeCodeFragment() { |
| final String returnTypeText = StringUtil.notNullize(myMethod.getReturnTypeText()); |
| final JavaCodeFragmentFactory factory = JavaCodeFragmentFactory.getInstance(myProject); |
| return factory.createTypeCodeFragment(returnTypeText, myMethod.getMethod(), true, JavaCodeFragmentFactory.ALLOW_VOID); |
| } |
| |
| @Override |
| protected CallerChooserBase<PsiMethod> createCallerChooser(String title, Tree treeToReuse, Consumer<Set<PsiMethod>> callback) { |
| return new JavaCallerChooser(myMethod.getMethod(), myProject, title, treeToReuse, callback); |
| } |
| |
| @Override |
| protected String validateAndCommitData() { |
| PsiManager manager = PsiManager.getInstance(myProject); |
| PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); |
| |
| String name = getMethodName(); |
| if (!PsiNameHelper.getInstance(manager.getProject()).isIdentifier(name)) { |
| return RefactoringMessageUtil.getIncorrectIdentifierMessage(name); |
| } |
| |
| if (myMethod.canChangeReturnType() == MethodDescriptor.ReadWriteOption.ReadWrite) { |
| try { |
| ((PsiTypeCodeFragment)myReturnTypeCodeFragment).getType(); |
| } |
| catch (PsiTypeCodeFragment.TypeSyntaxException e) { |
| myReturnTypeField.requestFocus(); |
| return RefactoringBundle.message("changeSignature.wrong.return.type", myReturnTypeCodeFragment.getText()); |
| } |
| catch (PsiTypeCodeFragment.NoTypeException e) { |
| myReturnTypeField.requestFocus(); |
| return RefactoringBundle.message("changeSignature.no.return.type"); |
| } |
| } |
| |
| List<ParameterTableModelItemBase<ParameterInfoImpl>> parameterInfos = myParametersTableModel.getItems(); |
| final int newParametersNumber = parameterInfos.size(); |
| |
| for (int i = 0; i < newParametersNumber; i++) { |
| final ParameterTableModelItemBase<ParameterInfoImpl> item = parameterInfos.get(i); |
| |
| if (!PsiNameHelper.getInstance(manager.getProject()).isIdentifier(item.parameter.getName())) { |
| return RefactoringMessageUtil.getIncorrectIdentifierMessage(item.parameter.getName()); |
| } |
| |
| final PsiType type; |
| try { |
| type = ((PsiTypeCodeFragment)parameterInfos.get(i).typeCodeFragment).getType(); |
| } catch (PsiTypeCodeFragment.TypeSyntaxException e) { |
| return RefactoringBundle.message("changeSignature.wrong.type.for.parameter", |
| item.typeCodeFragment.getText(), |
| item.parameter.getName()); |
| } catch (PsiTypeCodeFragment.NoTypeException e) { |
| return RefactoringBundle.message("changeSignature.no.type.for.parameter", item.parameter.getName()); |
| } |
| |
| item.parameter.setType(type); |
| |
| if (type instanceof PsiEllipsisType && i != newParametersNumber - 1) { |
| return RefactoringBundle.message("changeSignature.vararg.not.last"); |
| } |
| |
| if (item.parameter.oldParameterIndex < 0) { |
| item.parameter.defaultValue = WriteCommandAction.runWriteCommandAction(myProject, new Computable<String>() { |
| @Override |
| public String compute() { |
| return JavaCodeStyleManager.getInstance(myProject).qualifyClassReferences(item.defaultValueCodeFragment).getText(); |
| } |
| }); |
| String def = item.parameter.defaultValue; |
| def = def.trim(); |
| if (!(type instanceof PsiEllipsisType)) { |
| try { |
| if (!StringUtil.isEmpty(def)) { |
| factory.createExpressionFromText(def, null); |
| } |
| } |
| catch (IncorrectOperationException e) { |
| return e.getMessage(); |
| } |
| } |
| } |
| } |
| |
| ThrownExceptionInfo[] exceptionInfos = myExceptionsModel.getThrownExceptions(); |
| PsiTypeCodeFragment[] typeCodeFragments = myExceptionsModel.getTypeCodeFragments(); |
| for (int i = 0; i < exceptionInfos.length; i++) { |
| ThrownExceptionInfo exceptionInfo = exceptionInfos[i]; |
| PsiTypeCodeFragment typeCodeFragment = typeCodeFragments[i]; |
| try { |
| PsiType type = typeCodeFragment.getType(); |
| if (!(type instanceof PsiClassType)) { |
| return RefactoringBundle.message("changeSignature.wrong.type.for.exception", typeCodeFragment.getText()); |
| } |
| |
| PsiClassType throwable = JavaPsiFacade.getInstance(myProject).getElementFactory() |
| .createTypeByFQClassName("java.lang.Throwable", type.getResolveScope()); |
| if (!throwable.isAssignableFrom(type)) { |
| return RefactoringBundle.message("changeSignature.not.throwable.type", typeCodeFragment.getText()); |
| } |
| exceptionInfo.setType((PsiClassType)type); |
| } |
| catch (PsiTypeCodeFragment.TypeSyntaxException e) { |
| return RefactoringBundle.message("changeSignature.wrong.type.for.exception", typeCodeFragment.getText()); |
| } |
| catch (PsiTypeCodeFragment.NoTypeException e) { |
| return RefactoringBundle.message("changeSignature.no.type.for.exception"); |
| } |
| } |
| |
| // warnings |
| try { |
| if (myMethod.canChangeReturnType() == MethodDescriptor.ReadWriteOption.ReadWrite) { |
| if (!RefactoringUtil.isResolvableType(((PsiTypeCodeFragment)myReturnTypeCodeFragment).getType())) { |
| if (Messages.showOkCancelDialog(myProject, RefactoringBundle |
| .message("changeSignature.cannot.resolve.return.type", myReturnTypeCodeFragment.getText()), |
| RefactoringBundle.message("changeSignature.refactoring.name"), Messages.getWarningIcon()) != Messages.OK) { |
| return EXIT_SILENTLY; |
| } |
| } |
| } |
| for (ParameterTableModelItemBase<ParameterInfoImpl> item : parameterInfos) { |
| |
| if (!RefactoringUtil.isResolvableType(((PsiTypeCodeFragment)item.typeCodeFragment).getType())) { |
| if (Messages.showOkCancelDialog(myProject, RefactoringBundle |
| .message("changeSignature.cannot.resolve.parameter.type", item.typeCodeFragment.getText(), item.parameter.getName()), |
| RefactoringBundle.message("changeSignature.refactoring.name"), Messages.getWarningIcon()) != |
| Messages.OK) { |
| return EXIT_SILENTLY; |
| } |
| } |
| } |
| } |
| catch (PsiTypeCodeFragment.IncorrectTypeException ignored) { |
| } |
| return null; |
| } |
| |
| @Override |
| protected ValidationInfo doValidate() { |
| if (!getTableComponent().isEditing()) { |
| for (final ParameterTableModelItemBase<ParameterInfoImpl> item : myParametersTableModel.getItems()) { |
| if (item.parameter.oldParameterIndex < 0) { |
| if (StringUtil.isEmpty(item.defaultValueCodeFragment.getText())) |
| return new ValidationInfo("Default value is missing. Method calls will contain blanks instead of the new parameter value."); |
| } |
| } |
| } |
| return super.doValidate(); |
| } |
| |
| @Override |
| protected boolean postponeValidation() { |
| return false; |
| } |
| |
| @Override |
| protected String calculateSignature() { |
| return doCalculateSignature(myMethod.getMethod()); |
| } |
| |
| protected String doCalculateSignature(PsiMethod method) { |
| final StringBuilder buffer = new StringBuilder(); |
| final PsiModifierList modifierList = method.getModifierList(); |
| String modifiers = modifierList.getText(); |
| final String oldModifier = VisibilityUtil.getVisibilityModifier(modifierList); |
| final String newModifier = getVisibility(); |
| String newModifierStr = VisibilityUtil.getVisibilityString(newModifier); |
| if (!Comparing.equal(newModifier, oldModifier)) { |
| int index = modifiers.indexOf(oldModifier); |
| if (index >= 0) { |
| final StringBuilder buf = new StringBuilder(modifiers); |
| buf.replace(index, |
| index + oldModifier.length() + (StringUtil.isEmpty(newModifierStr) ? 1 : 0), |
| newModifierStr); |
| modifiers = buf.toString(); |
| } else { |
| if (!StringUtil.isEmpty(newModifierStr)) { |
| newModifierStr += " "; |
| } |
| modifiers = newModifierStr + modifiers; |
| } |
| } |
| |
| buffer.append(modifiers); |
| if (modifiers.length() > 0 && |
| !StringUtil.endsWithChar(modifiers, '\n') && |
| !StringUtil.endsWithChar(modifiers, '\r') && |
| !StringUtil.endsWithChar(modifiers, ' ')) { |
| buffer.append(" "); |
| } |
| |
| if (!method.isConstructor()) { |
| final CanonicalTypes.Type type = getReturnType(); |
| if (type != null) { |
| buffer.append(type.getTypeText()); |
| } |
| buffer.append(" "); |
| } |
| buffer.append(getMethodName()); |
| buffer.append("("); |
| |
| final int lineBreakIdx = buffer.lastIndexOf("\n"); |
| String indent = StringUtil.repeatSymbol(' ', lineBreakIdx >= 0 ? buffer.length() - lineBreakIdx - 1 : buffer.length()); |
| List<ParameterTableModelItemBase<ParameterInfoImpl>> items = myParametersTableModel.getItems(); |
| int curIndent = indent.length(); |
| for (int i = 0; i < items.size(); i++) { |
| final ParameterTableModelItemBase<ParameterInfoImpl> item = items.get(i); |
| if (i > 0) { |
| buffer.append(","); |
| buffer.append("\n"); |
| buffer.append(indent); |
| } |
| final String text = item.typeCodeFragment.getText(); |
| buffer.append(text).append(" "); |
| final String name = item.parameter.getName(); |
| buffer.append(name); |
| curIndent = indent.length() + text.length() + 1 + name.length(); |
| } |
| //if (!items.isEmpty()) { |
| // buffer.append("\n"); |
| //} |
| buffer.append(")"); |
| PsiTypeCodeFragment[] thrownExceptionsFragments = myExceptionsModel.getTypeCodeFragments(); |
| if (thrownExceptionsFragments.length > 0) { |
| //buffer.append("\n"); |
| buffer.append(" throws "); |
| curIndent += 9; // ") throws ".length() |
| indent = StringUtil.repeatSymbol(' ', curIndent); |
| for (int i = 0; i < thrownExceptionsFragments.length; i++) { |
| String text = thrownExceptionsFragments[i].getText(); |
| if (i != 0) buffer.append(indent); |
| buffer.append(text); |
| if (i < thrownExceptionsFragments.length - 1) { |
| buffer.append(","); |
| } |
| buffer.append("\n"); |
| } |
| } |
| |
| return buffer.toString(); |
| } |
| } |