From 190db1ad4b254c270fe7e5f99932b834b37ed376 Mon Sep 17 00:00:00 2001 From: tangcent Date: Wed, 1 Jan 2025 10:58:32 +0800 Subject: [PATCH] chore: remove AskWithApplyAllDialog form file --- .../plugin/dialog/AskWithApplyAllDialog.form | 83 --------- .../plugin/dialog/AskWithApplyAllDialog.kt | 173 ++++++++++++------ .../idea/plugin/dialog/SuvApiExportDialog.kt | 3 +- .../idea/swing/DefaultMessagesHelper.kt | 13 +- .../itangcent/idea/swing/MessagesHelper.kt | 16 +- .../com/itangcent/idea/utils/SwingUtils.kt | 39 ++-- .../idea/swing/MessagesHelperTest.kt | 18 +- .../com/itangcent/mock/EmptyMessagesHelper.kt | 3 +- 8 files changed, 182 insertions(+), 166 deletions(-) delete mode 100644 idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/dialog/AskWithApplyAllDialog.form diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/dialog/AskWithApplyAllDialog.form b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/dialog/AskWithApplyAllDialog.form deleted file mode 100644 index 8127ff48..00000000 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/dialog/AskWithApplyAllDialog.form +++ /dev/null @@ -1,83 +0,0 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/dialog/AskWithApplyAllDialog.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/dialog/AskWithApplyAllDialog.kt index a4ba1131..6c9baf96 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/dialog/AskWithApplyAllDialog.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/dialog/AskWithApplyAllDialog.kt @@ -1,92 +1,163 @@ package com.itangcent.idea.plugin.dialog +import com.intellij.openapi.ui.Messages +import com.intellij.util.ui.JBUI import com.itangcent.common.logger.Log import com.itangcent.idea.utils.SwingUtils import java.awt.EventQueue +import java.awt.GridBagConstraints +import java.awt.GridBagLayout import java.awt.Window import java.awt.event.KeyEvent import java.awt.event.WindowAdapter import java.awt.event.WindowEvent import javax.swing.* -class AskWithApplyAllDialog(owner: Window? = null) : JDialog(owner) { - private var contentPane: JPanel? = null - private var buttonOK: JButton? = null - private var buttonCancel: JButton? = null - private var buttonNO: JButton? = null - private var applyToAllCheckBox: JCheckBox? = null - private var messageLabel: JLabel? = null - private var callBack: ((Int, Boolean) -> Unit)? = null +/** + * Represents the labels for the three buttons in a confirmation dialog + */ +data class ConfirmationDialogLabels( + val okText: String = "OK", + val noText: String = "No", + val cancelText: String = "Cancel" +) - fun updateMessage( - message: String, - ) { - EventQueue.invokeLater { - messageLabel!!.text = message - } +class AskWithApplyAllDialog(owner: Window? = null) : JDialog(owner) { + private val contentPane = JPanel(GridBagLayout()).apply { + border = BorderFactory.createEmptyBorder(10, 10, 10, 10) } - /** - * @param buttonNames [YES,NO,CANCEL] - */ - fun updateButtons(buttonNames: Array) { - EventQueue.invokeLater { - try { - buttonOK!!.text = buttonNames[0] - buttonNO!!.text = buttonNames[1] - buttonCancel!!.text = buttonNames[2] - } catch (e: Exception) { - LOG.error("failed set button name: $buttonNames") - } - } + private val messageLabel = JLabel().apply { + border = BorderFactory.createEmptyBorder(0, 0, 10, 0) } - fun setCallBack( - callBack: (Int, Boolean) -> Unit, - ) { - this.callBack = callBack + private val applyToAllCheckBox = JCheckBox("Apply to all").apply { + border = BorderFactory.createEmptyBorder(10, 0, 10, 0) } - private fun onOK() { - dispose() - callBack?.invoke(com.intellij.openapi.ui.Messages.OK, applyToAllCheckBox!!.isSelected) + private val buttonPanel = JPanel().apply { + layout = BoxLayout(this, BoxLayout.X_AXIS) + border = BorderFactory.createEmptyBorder(10, 0, 0, 0) } - private fun onNO() { - dispose() - callBack?.invoke(com.intellij.openapi.ui.Messages.NO, applyToAllCheckBox!!.isSelected) - } + private val defaultLabels = ConfirmationDialogLabels() + private val buttonOK = JButton(defaultLabels.okText) + private val buttonNO = JButton(defaultLabels.noText) + private val buttonCancel = JButton(defaultLabels.cancelText) - private fun onCancel() { - dispose() - callBack?.invoke(com.intellij.openapi.ui.Messages.CANCEL, applyToAllCheckBox!!.isSelected) - } + private var callBack: ((Int, Boolean) -> Unit)? = null init { - setContentPane(contentPane) + title = "Confirm" isModal = true - getRootPane().defaultButton = buttonOK + initComponents() + initLayout() + initListeners() SwingUtils.centerWindow(this) + } - buttonOK!!.addActionListener { onOK() } - buttonNO!!.addActionListener { onNO() } - buttonCancel!!.addActionListener { onCancel() } - - // call onCancel() when cross is clicked + private fun initComponents() { defaultCloseOperation = DO_NOTHING_ON_CLOSE + rootPane.defaultButton = buttonOK + + buttonPanel.add(Box.createHorizontalGlue()) + buttonPanel.add(buttonOK) + buttonPanel.add(Box.createHorizontalStrut(5)) + buttonPanel.add(buttonNO) + buttonPanel.add(Box.createHorizontalStrut(5)) + buttonPanel.add(buttonCancel) + } + + private fun initLayout() { + setContentPane(contentPane) + + contentPane.add(messageLabel, GridBagConstraints().apply { + gridx = 0 + gridy = 0 + weightx = 1.0 + fill = GridBagConstraints.HORIZONTAL + anchor = GridBagConstraints.WEST + insets = JBUI.insets(0) + }) + + contentPane.add(applyToAllCheckBox, GridBagConstraints().apply { + gridx = 0 + gridy = 1 + weightx = 1.0 + fill = GridBagConstraints.HORIZONTAL + anchor = GridBagConstraints.WEST + insets = JBUI.insets(0) + }) + + contentPane.add(buttonPanel, GridBagConstraints().apply { + gridx = 0 + gridy = 2 + weightx = 1.0 + fill = GridBagConstraints.HORIZONTAL + anchor = GridBagConstraints.EAST + insets = JBUI.insets(0) + }) + + pack() + } + + private fun initListeners() { + buttonOK.addActionListener { onOK() } + buttonNO.addActionListener { onNO() } + buttonCancel.addActionListener { onCancel() } + addWindowListener(object : WindowAdapter() { override fun windowClosing(e: WindowEvent) { onCancel() } }) - // call onCancel() on ESCAPE - contentPane!!.registerKeyboardAction( + contentPane.registerKeyboardAction( { onCancel() }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ) } + fun updateMessage(message: String) { + EventQueue.invokeLater { + messageLabel.text = message + pack() + } + } + + /** + * Updates the text of all three buttons. + * + * @param labels The labels for all three buttons + */ + fun updateButtonLabels(labels: ConfirmationDialogLabels) { + EventQueue.invokeLater { + buttonOK.text = labels.okText + buttonNO.text = labels.noText + buttonCancel.text = labels.cancelText + pack() + } + } + + fun setCallBack(callBack: (Int, Boolean) -> Unit) { + this.callBack = callBack + } + + private fun onOK() { + dispose() + callBack?.invoke(Messages.OK, applyToAllCheckBox.isSelected) + } + + private fun onNO() { + dispose() + callBack?.invoke(Messages.NO, applyToAllCheckBox.isSelected) + } + + private fun onCancel() { + dispose() + callBack?.invoke(Messages.CANCEL, applyToAllCheckBox.isSelected) + } + companion object : Log() } \ No newline at end of file diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/dialog/SuvApiExportDialog.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/dialog/SuvApiExportDialog.kt index a24feb35..8092835a 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/dialog/SuvApiExportDialog.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/dialog/SuvApiExportDialog.kt @@ -89,7 +89,6 @@ class SuvApiExportDialog : ContextDialog() { contentPane = suvApiExportPanel getRootPane().defaultButton = buttonOK - SwingUtils.centerWindow(this) buttonOK.addActionListener { onOK() } @@ -139,6 +138,8 @@ class SuvApiExportDialog : ContextDialog() { selectAllCheckBox.isSelected = apiList.model.size == apiList.selectionModel.selectedItemsCount } } + + SwingUtils.centerWindow(this) } private fun onSelectedAll() = this.trigger.withTrigger("onSelectAll") { diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/swing/DefaultMessagesHelper.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/swing/DefaultMessagesHelper.kt index 232d49e7..e5916c0e 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/swing/DefaultMessagesHelper.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/swing/DefaultMessagesHelper.kt @@ -7,6 +7,7 @@ import com.intellij.openapi.ui.Messages import com.intellij.openapi.ui.Messages.YesNoResult import com.itangcent.idea.plugin.dialog.AskWithApplyAllDialog import com.itangcent.idea.plugin.dialog.ChooseWithTipDialog +import com.itangcent.idea.plugin.dialog.ConfirmationDialogLabels import com.itangcent.idea.utils.SwingUtils import com.itangcent.intellij.context.ActionContext import com.itangcent.intellij.util.UIUtils @@ -142,15 +143,15 @@ class DefaultMessagesHelper : MessagesHelper { override fun showAskWithApplyAllDialog( message: String?, - buttonNames: Array?, + buttonLabels: ConfirmationDialogLabels, callBack: (Int, Boolean) -> Unit, ) { actionContext.runInSwingUI { - val chooseWithTipDialog = AskWithApplyAllDialog(SwingUtils.preferableWindow()) - buttonNames?.let { chooseWithTipDialog.updateButtons(buttonNames) } - chooseWithTipDialog.updateMessage(message ?: "Yes or No?") - UIUtils.show(chooseWithTipDialog) - chooseWithTipDialog.setCallBack(callBack) + val dialog = AskWithApplyAllDialog(SwingUtils.preferableWindow()) + dialog.updateButtonLabels(buttonLabels) + dialog.updateMessage(message ?: "Yes or No?") + UIUtils.show(dialog) + dialog.setCallBack(callBack) } } } \ No newline at end of file diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/swing/MessagesHelper.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/swing/MessagesHelper.kt index 471c9f24..89ce5be0 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/swing/MessagesHelper.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/swing/MessagesHelper.kt @@ -3,6 +3,7 @@ package com.itangcent.idea.swing import com.google.inject.ImplementedBy import com.intellij.openapi.ui.Messages import com.itangcent.common.concurrent.ValueHolder +import com.itangcent.idea.plugin.dialog.ConfirmationDialogLabels import com.itangcent.intellij.context.ActionContext import org.jetbrains.annotations.Nls import javax.swing.Icon @@ -61,13 +62,16 @@ interface MessagesHelper { ) /** - * @param message tip at the top - * @param buttonNames [YES,NO,CANCEL] - * @param callBack callback when button be clicked + * Shows a dialog with a message and three buttons, plus an "Apply to all" checkbox. + * + * @param message The message to display at the top of the dialog + * @param buttonLabels The labels for the three buttons (OK/YES, NO, CANCEL) + * @param callBack Callback invoked when a button is clicked, with the button type ([Messages.OK], [Messages.NO], [Messages.CANCEL]) + * and the state of the "Apply to all" checkbox */ fun showAskWithApplyAllDialog( message: String?, - buttonNames: Array?, + buttonLabels: ConfirmationDialogLabels = ConfirmationDialogLabels(), callBack: (Int, Boolean) -> Unit, ) } @@ -88,7 +92,7 @@ fun MessagesHelper.showChooseWithTipDialog( fun MessagesHelper.showAskWithApplyAllDialog( message: String?, - buttonNames: Array?, + buttonLabels: ConfirmationDialogLabels = ConfirmationDialogLabels(), key: String, callBack: (Int) -> Unit, ) { @@ -99,7 +103,7 @@ fun MessagesHelper.showAskWithApplyAllDialog( return } - this.showAskWithApplyAllDialog(message, buttonNames) { ret, applyAll -> + this.showAskWithApplyAllDialog(message, buttonLabels) { ret, applyAll -> if (applyAll) { actionContext?.cache(key, ret) } diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/utils/SwingUtils.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/utils/SwingUtils.kt index 62a133cb..4428372c 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/utils/SwingUtils.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/utils/SwingUtils.kt @@ -61,17 +61,34 @@ object SwingUtils : Log() { component.background = component.parent.background } - // Centers a Component on the screen. - fun centerWindow(component: Component) { - val toolkit = Toolkit.getDefaultToolkit() - val scmSize = toolkit.screenSize - val width = component.width - val height = component.height - - component.setLocation( - scmSize.width / 2 - width / 2, - scmSize.height / 2 - height / 2 - ) + // Centers a Component on the screen or relative to its parent window. + fun centerWindow(window: Window) { + EventQueue.invokeLater { + window.pack() + + val parentWindow = when { + window.owner != null && window.owner.isVisible && window.owner.width > 0 && window.owner.height > 0 -> window.owner + window.parent != null -> SwingUtilities.getWindowAncestor(window.parent)?.takeIf { it.isVisible && it.width > 0 && it.height > 0 } + else -> null + }?.takeIf { !it.javaClass.name.contains("SharedOwnerFrame") } + + if (parentWindow != null) { + // Center relative to parent window + val parentBounds = parentWindow.bounds + window.setLocation( + parentBounds.x + (parentBounds.width - window.width) / 2, + parentBounds.y + (parentBounds.height - window.height) / 2 + ) + } else { + // Center on screen + val toolkit = Toolkit.getDefaultToolkit() + val scmSize = toolkit.screenSize + window.setLocation( + scmSize.width / 2 - window.width / 2, + scmSize.height / 2 - window.height / 2 + ) + } + } } // Returns the active window of the current project in the IntelliJ IDEA IDE. diff --git a/idea-plugin/src/test/kotlin/com/itangcent/idea/swing/MessagesHelperTest.kt b/idea-plugin/src/test/kotlin/com/itangcent/idea/swing/MessagesHelperTest.kt index 8bb433bc..e653942e 100644 --- a/idea-plugin/src/test/kotlin/com/itangcent/idea/swing/MessagesHelperTest.kt +++ b/idea-plugin/src/test/kotlin/com/itangcent/idea/swing/MessagesHelperTest.kt @@ -1,6 +1,7 @@ package com.itangcent.idea.swing import com.intellij.openapi.ui.Messages +import com.itangcent.idea.plugin.dialog.ConfirmationDialogLabels import com.itangcent.mock.BaseContextTest import org.junit.jupiter.api.Test import org.mockito.Mockito @@ -38,11 +39,14 @@ internal class MessagesHelperTest : BaseContextTest() { val callBack: (Int, Boolean) -> Unit = it.getArgument(2)!! callBack(Messages.YES, applyAll) }.`when`(messagesHelper) - .showAskWithApplyAllDialog(Mockito.any(), Mockito.any(), com.itangcent.mock.any { _, _ -> }) + .showAskWithApplyAllDialog( + Mockito.any(), + com.itangcent.mock.any(ConfirmationDialogLabels()), + com.itangcent.mock.any { _, _ -> }) var ret: Int? = null messagesHelper.showAskWithApplyAllDialog( "msg", - null, + ConfirmationDialogLabels(), "test-showAskWithApplyAllDialogWithApplyAll" ) { @@ -54,12 +58,12 @@ internal class MessagesHelperTest : BaseContextTest() { ) verify(messagesHelper, times(1)).showAskWithApplyAllDialog( Mockito.any(), - Mockito.any(), + com.itangcent.mock.any(ConfirmationDialogLabels()), com.itangcent.mock.any { _, _ -> }) applyAll = true messagesHelper.showAskWithApplyAllDialog( "msg", - null, + ConfirmationDialogLabels(), "test-showAskWithApplyAllDialogWithApplyAll" ) { @@ -71,11 +75,11 @@ internal class MessagesHelperTest : BaseContextTest() { ) verify(messagesHelper, times(2)).showAskWithApplyAllDialog( Mockito.any(), - Mockito.any(), + com.itangcent.mock.any(ConfirmationDialogLabels()), com.itangcent.mock.any { _, _ -> }) messagesHelper.showAskWithApplyAllDialog( "msg", - null, + ConfirmationDialogLabels(), "test-showAskWithApplyAllDialogWithApplyAll" ) { @@ -87,7 +91,7 @@ internal class MessagesHelperTest : BaseContextTest() { ) verify(messagesHelper, times(2)).showAskWithApplyAllDialog( Mockito.any(), - Mockito.any(), + com.itangcent.mock.any(ConfirmationDialogLabels()), com.itangcent.mock.any { _, _ -> }) } } \ No newline at end of file diff --git a/idea-plugin/src/test/kotlin/com/itangcent/mock/EmptyMessagesHelper.kt b/idea-plugin/src/test/kotlin/com/itangcent/mock/EmptyMessagesHelper.kt index 64219e5b..1f82c039 100644 --- a/idea-plugin/src/test/kotlin/com/itangcent/mock/EmptyMessagesHelper.kt +++ b/idea-plugin/src/test/kotlin/com/itangcent/mock/EmptyMessagesHelper.kt @@ -1,6 +1,7 @@ package com.itangcent.mock import com.intellij.openapi.ui.Messages +import com.itangcent.idea.plugin.dialog.ConfirmationDialogLabels import com.itangcent.idea.swing.MessagesHelper import javax.swing.Icon @@ -49,7 +50,7 @@ class EmptyMessagesHelper : MessagesHelper { override fun showAskWithApplyAllDialog( message: String?, - buttonNames: Array?, + buttonLabels: ConfirmationDialogLabels, callBack: (Int, Boolean) -> Unit, ) { callBack(Messages.YES, true)