From 83e5cfc9f6f11ef063bbc0586b3bba1b1a635c20 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Tue, 29 Apr 2025 18:29:11 +0200 Subject: [PATCH] [kotlin] reuse java safe delete dialog instead of copying it (IDEA-350217) GitOrigin-RevId: 48a0d2985f8955ff3de4fb67e5fa1c81172b94f1 --- .../safeDelete/OverridingMethodsDialog.java | 60 +++-- .../messages/KotlinBundle.properties | 3 +- .../safeDelete/KotlinOverridingDialog.java | 242 ++---------------- 3 files changed, 63 insertions(+), 242 deletions(-) diff --git a/java/java-impl-refactorings/src/com/intellij/refactoring/safeDelete/OverridingMethodsDialog.java b/java/java-impl-refactorings/src/com/intellij/refactoring/safeDelete/OverridingMethodsDialog.java index 11b5dc89af6d..65c2fdbbb908 100644 --- a/java/java-impl-refactorings/src/com/intellij/refactoring/safeDelete/OverridingMethodsDialog.java +++ b/java/java-impl-refactorings/src/com/intellij/refactoring/safeDelete/OverridingMethodsDialog.java @@ -7,6 +7,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Splitter; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.NlsContexts; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiSubstitutor; @@ -23,9 +24,11 @@ import com.intellij.ui.table.JBTable; import com.intellij.usageView.UsageInfo; import com.intellij.usages.UsageViewPresentation; import com.intellij.usages.impl.UsagePreviewPanel; +import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.ListSelectionEvent; @@ -42,7 +45,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; -class OverridingMethodsDialog extends DialogWrapper { +public class OverridingMethodsDialog extends DialogWrapper { private final Project myProject; private final List myOverridingMethods; private final String[] myMethodText; @@ -52,7 +55,7 @@ class OverridingMethodsDialog extends DialogWrapper { private JBTable myTable; private final UsagePreviewPanel myUsagePreviewPanel; - OverridingMethodsDialog(Project project, List overridingMethods) { + public OverridingMethodsDialog(Project project, List overridingMethods) { super(project, true); myProject = project; myOverridingMethods = overridingMethods; @@ -60,29 +63,48 @@ class OverridingMethodsDialog extends DialogWrapper { Arrays.fill(myChecked, true); myMethodText = new String[myOverridingMethods.size()]; - for (int i = 0; i < myMethodText.length; i++) { - PsiElement overridingMethod = ((SafeDeleteOverridingMethodUsageInfo)myOverridingMethods.get(i)).getOverridingMethod(); - if (overridingMethod instanceof PsiMethod method) { - int options = PsiFormatUtilBase.SHOW_CONTAINING_CLASS | - PsiFormatUtilBase.SHOW_NAME | - PsiFormatUtilBase.SHOW_PARAMETERS | - PsiFormatUtilBase.SHOW_TYPE; - myMethodText[i] = PsiFormatUtil.formatMethod(method, PsiSubstitutor.EMPTY, options, PsiFormatUtilBase.SHOW_TYPE); - } - else { - myMethodText[i] = SymbolPresentationUtil.getSymbolPresentableText(overridingMethod); - } - } + Arrays.setAll(myMethodText, i -> getElementDescription(myOverridingMethods.get(i))); myUsagePreviewPanel = new UsagePreviewPanel(project, new UsageViewPresentation()); - setTitle(JavaRefactoringBundle.message("unused.overriding.methods.title")); + setTitle(getTitleText()); init(); } + protected @NlsContexts.DialogTitle @NotNull String getTitleText() { + return JavaRefactoringBundle.message("unused.overriding.methods.title"); + } + + protected @NlsContexts.DialogMessage @NotNull String getDescriptionText() { + return JavaRefactoringBundle.message("there.are.unused.methods.that.override.methods.you.delete"); + } + + protected @NlsContexts.ColumnName @NotNull String getColumnName() { + return JavaRefactoringBundle.message("method.column"); + } + + protected String getElementDescription(UsageInfo info) { + PsiElement overridingMethod = ((SafeDeleteOverridingMethodUsageInfo)info).getOverridingMethod(); + if (overridingMethod instanceof PsiMethod method) { + int options = PsiFormatUtilBase.SHOW_CONTAINING_CLASS | + PsiFormatUtilBase.SHOW_NAME | + PsiFormatUtilBase.SHOW_PARAMETERS | + PsiFormatUtilBase.SHOW_TYPE; + return PsiFormatUtil.formatMethod(method, PsiSubstitutor.EMPTY, options, PsiFormatUtilBase.SHOW_TYPE); + } + else { + return SymbolPresentationUtil.getSymbolPresentableText(overridingMethod); + } + } + @Override protected String getDimensionServiceKey() { return "#com.intellij.refactoring.safeDelete.OverridingMethodsDialog"; } + @Override + public @Nullable Dimension getInitialSize() { + return JBUI.DialogSizes.large(); + } + public ArrayList getSelected() { ArrayList result = new ArrayList<>(); for (int i = 0; i < myChecked.length; i++) { @@ -112,7 +134,7 @@ class OverridingMethodsDialog extends DialogWrapper { @Override protected JComponent createCenterPanel() { JPanel panel = new JPanel(new BorderLayout(0, UIUtil.DEFAULT_VGAP)); - panel.add(new JLabel(JavaRefactoringBundle.message("there.are.unused.methods.that.override.methods.you.delete")), BorderLayout.NORTH); + panel.add(new JLabel(getDescriptionText()), BorderLayout.NORTH); final MyTableModel tableModel = new MyTableModel(); myTable = new JBTable(tableModel); myTable.setShowGrid(false); @@ -153,7 +175,7 @@ class OverridingMethodsDialog extends DialogWrapper { JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(myTable); ListSelectionListener selectionListener = new ListSelectionListener() { @Override - public void valueChanged(final ListSelectionEvent e) { + public void valueChanged(ListSelectionEvent e) { int index = myTable.getSelectionModel().getLeadSelectionIndex(); if (index != -1) { UsageInfo usageInfo = myOverridingMethods.get(index); @@ -191,7 +213,7 @@ class OverridingMethodsDialog extends DialogWrapper { @Override public String getColumnName(int column) { - return column == CHECK_COLUMN ? " " : JavaRefactoringBundle.message("method.column"); + return column == CHECK_COLUMN ? " " : OverridingMethodsDialog.this.getColumnName(); } @Override diff --git a/plugins/kotlin/base/resources/resources-en/messages/KotlinBundle.properties b/plugins/kotlin/base/resources/resources-en/messages/KotlinBundle.properties index 65a0375f28d0..e79efb349f69 100644 --- a/plugins/kotlin/base/resources/resources-en/messages/KotlinBundle.properties +++ b/plugins/kotlin/base/resources/resources-en/messages/KotlinBundle.properties @@ -293,8 +293,7 @@ override.declaration.x.implements.y={0} implements {1}. override.declaration.x.overrides.y.in.class.list={0} overrides declarations in the following classes/interfaces: {1} Do you want to {2} the base declarations? override.declaration.unused.overriding.methods.title=Unused Overriding Members -override.declaration.unused.overriding.methods.description=There are unused members that override methods you delete. -override.declaration.choose.to.delete=Choose the ones you want to be deleted. +override.declaration.choose.to.delete=There are unused members that override methods that are going to be deleted. Choose the ones you want to delete as well: override.declaration.member=Member override.declaration.delete.multiple.parameters={0} is a part of method hierarchy. Do you want to delete multiple parameters? diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/KotlinOverridingDialog.java b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/KotlinOverridingDialog.java index 99cab72bbecb..463eb0da9dd0 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/KotlinOverridingDialog.java +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/KotlinOverridingDialog.java @@ -1,247 +1,47 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. - +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.kotlin.idea.refactoring.safeDelete; -import com.intellij.openapi.Disposable; -import com.intellij.openapi.help.HelpManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.ui.Splitter; -import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.NlsContexts; import com.intellij.openapi.util.text.HtmlChunk; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.ElementDescriptionUtil; -import com.intellij.refactoring.HelpID; +import com.intellij.psi.PsiElement; +import com.intellij.refactoring.safeDelete.OverridingMethodsDialog; import com.intellij.refactoring.util.RefactoringDescriptionLocation; -import com.intellij.ui.BooleanTableCellRenderer; -import com.intellij.ui.ScrollPaneFactory; -import com.intellij.ui.table.JBTable; import com.intellij.usageView.UsageInfo; -import com.intellij.usages.UsageViewPresentation; -import com.intellij.usages.impl.UsagePreviewPanel; +import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.idea.base.resources.KotlinBundle; -import javax.swing.*; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; -import javax.swing.table.AbstractTableModel; -import javax.swing.table.TableColumnModel; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; import java.util.List; -/* -* Mostly copied from com.intellij.refactoring.safeDelete.OverridingMethodsDialog -* Revision: 14aa2e2 -* (replace PsiMethod formatting) -*/ -class KotlinOverridingDialog extends DialogWrapper { - private final Project myProject; - private final List myOverridingMethods; - private final String[] myMethodText; - private final boolean[] myChecked; - - private static final int CHECK_COLUMN = 0; - private JBTable myTable; - private final UsagePreviewPanel myUsagePreviewPanel; - - KotlinOverridingDialog(Project project, List overridingMethods) { - super(project, true); - myProject = project; - myOverridingMethods = overridingMethods; - myChecked = new boolean[myOverridingMethods.size()]; - Arrays.fill(myChecked, true); - - myMethodText = new String[myOverridingMethods.size()]; - for (int i = 0; i < myMethodText.length; i++) { - myMethodText[i] = HtmlChunk.html() - .addRaw(ElementDescriptionUtil.getElementDescription(((KotlinSafeDeleteOverridingUsageInfo) myOverridingMethods.get(i)).getOverridingElement(), - RefactoringDescriptionLocation.WITH_PARENT)) - .toString(); - } - myUsagePreviewPanel = new UsagePreviewPanel(project, new UsageViewPresentation()); - setTitle(KotlinBundle.message("override.declaration.unused.overriding.methods.title")); - init(); +class KotlinOverridingDialog extends OverridingMethodsDialog { + KotlinOverridingDialog(Project project, List overridingMethods) { + super(project, overridingMethods); } @Override - protected String getDimensionServiceKey() { - return "#org.jetbrains.kotlin.idea.refactoring.safeDelete.KotlinOverridingDialog"; + protected @NlsContexts.DialogTitle @NotNull String getTitleText() { + return KotlinBundle.message("override.declaration.unused.overriding.methods.title"); } - public @NotNull List getSelected() { - List result = new ArrayList<>(); - for (int i = 0; i < myChecked.length; i++) { - if (myChecked[i]) { - result.add(myOverridingMethods.get(i)); - } - } - return result; + @Nls + @Override + protected @NotNull String getDescriptionText() { + return KotlinBundle.message("override.declaration.choose.to.delete"); } @Override - protected @NotNull Action[] createActions() { - return new Action[] {getOKAction(), getCancelAction()}; + protected @NotNull String getColumnName() { + return KotlinBundle.message("override.declaration.member"); } @Override - protected void doHelpAction() { - HelpManager.getInstance().invokeHelp(HelpID.SAFE_DELETE_OVERRIDING); - } - - @Override - protected JComponent createNorthPanel() { - JPanel panel = new JPanel(); - panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); - panel.add(new JLabel(KotlinBundle.message("override.declaration.unused.overriding.methods.description"))); - panel.add(new JLabel(KotlinBundle.message("override.declaration.choose.to.delete"))); - return panel; - } - - @Override - public JComponent getPreferredFocusedComponent() { - return myTable; - } - - @Override - protected void dispose() { - Disposer.dispose(myUsagePreviewPanel); - super.dispose(); - } - - @Override - protected JComponent createCenterPanel() { - JPanel panel = new JPanel(new BorderLayout()); - panel.setBorder(BorderFactory.createEmptyBorder(8, 0, 4, 0)); - final MyTableModel tableModel = new MyTableModel(); - myTable = new JBTable(tableModel); - myTable.setShowGrid(false); - - TableColumnModel columnModel = myTable.getColumnModel(); - int checkBoxWidth = new JCheckBox().getPreferredSize().width; - columnModel.getColumn(CHECK_COLUMN).setCellRenderer(new BooleanTableCellRenderer()); - columnModel.getColumn(CHECK_COLUMN).setMaxWidth(checkBoxWidth); - columnModel.getColumn(CHECK_COLUMN).setMinWidth(checkBoxWidth); - - - // make SPACE check/uncheck selected rows - InputMap inputMap = myTable.getInputMap(); - inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "enable_disable"); - ActionMap actionMap = myTable.getActionMap(); - actionMap.put("enable_disable", new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - if (myTable.isEditing()) return; - int[] rows = myTable.getSelectedRows(); - if (rows.length > 0) { - boolean valueToBeSet = false; - for (int row : rows) { - if (!myChecked[row]) { - valueToBeSet = true; - break; - } - } - for (int row : rows) { - myChecked[row] = valueToBeSet; - } - - tableModel.updateData(); - } - } - }); - - panel.setLayout(new BorderLayout()); - - JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(myTable); - - panel.add(scrollPane, BorderLayout.CENTER); - ListSelectionListener selectionListener = new ListSelectionListener() { - @Override - public void valueChanged(ListSelectionEvent e) { - int index = myTable.getSelectionModel().getLeadSelectionIndex(); - if (index != -1) { - UsageInfo usageInfo = myOverridingMethods.get(index); - myUsagePreviewPanel.updateLayout(usageInfo.getProject(), Collections.singletonList(usageInfo)); - } - else { - myUsagePreviewPanel.updateLayout(myProject, null); - } - } - }; - myTable.getSelectionModel().addListSelectionListener(selectionListener); - - final Splitter splitter = new Splitter(true, 0.3f); - splitter.setFirstComponent(panel); - splitter.setSecondComponent(myUsagePreviewPanel); - myUsagePreviewPanel.updateLayout(myProject, null); - - Disposer.register(myDisposable, new Disposable() { - @Override - public void dispose() { - splitter.dispose(); - } - }); - - if (tableModel.getRowCount() != 0) { - myTable.getSelectionModel().addSelectionInterval(0, 0); - } - return splitter; - } - - class MyTableModel extends AbstractTableModel { - @Override - public int getRowCount() { - return myChecked.length; - } - - @Override - public String getColumnName(int column) { - if (column == CHECK_COLUMN) { - return " "; - } - return KotlinBundle.message("override.declaration.member"); - } - - @Override - public Class getColumnClass(int columnIndex) { - return columnIndex == CHECK_COLUMN ? Boolean.class : String.class; - } - - - @Override - public int getColumnCount() { - return 2; - } - - @Override - public Object getValueAt(int rowIndex, int columnIndex) { - if (columnIndex == CHECK_COLUMN) { - return Boolean.valueOf(myChecked[rowIndex]); - } - else { - return myMethodText[rowIndex]; - } - } - - @Override - public void setValueAt(Object aValue, int rowIndex, int columnIndex) { - if (columnIndex == CHECK_COLUMN) { - myChecked[rowIndex] = ((Boolean) aValue).booleanValue(); - } - } - - @Override - public boolean isCellEditable(int rowIndex, int columnIndex) { - return columnIndex == CHECK_COLUMN; - } - - void updateData() { - fireTableDataChanged(); - } + protected String getElementDescription(UsageInfo info) { + PsiElement overridingElement = ((KotlinSafeDeleteOverridingUsageInfo) info).getOverridingElement(); + String description = ElementDescriptionUtil.getElementDescription(overridingElement, RefactoringDescriptionLocation.WITH_PARENT); + return HtmlChunk.html().addRaw(StringUtil.capitalize(description)).toString(); } }