From c5573e5957f2a470d17867857d80dc4de1e012a4 Mon Sep 17 00:00:00 2001 From: Ben Soares Date: Fri, 15 Jul 2022 18:37:04 +0100 Subject: [PATCH] JAL-4034 Allow request for non-modal JDialog, which puts the Runnable action into the button click listener (similar to JalviewJS) --- src/jalview/gui/JvOptionPane.java | 151 +++++++++++++++++++++++++++++++++---- 1 file changed, 137 insertions(+), 14 deletions(-) diff --git a/src/jalview/gui/JvOptionPane.java b/src/jalview/gui/JvOptionPane.java index 733223d..028e50b 100644 --- a/src/jalview/gui/JvOptionPane.java +++ b/src/jalview/gui/JvOptionPane.java @@ -22,17 +22,27 @@ package jalview.gui; import java.awt.Component; +import java.awt.Dialog.ModalityType; import java.awt.HeadlessException; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.Executors; import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JInternalFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; +import javax.swing.UIManager; import jalview.util.Platform; import jalview.util.dialogrunner.DialogRunnerI; @@ -756,7 +766,14 @@ public class JvOptionPane extends JOptionPane public void showDialog(String message, String title, int optionType, int messageType, Icon icon, Object[] options, Object initialValue) { + showDialog(message, title, optionType, messageType, icon, options, + initialValue, true); + } + public void showDialog(String message, String title, int optionType, + int messageType, Icon icon, Object[] options, Object initialValue, + boolean modal) + { if (!isInteractiveMode()) { handleResponse(getMockResponse()); @@ -778,21 +795,127 @@ public class JvOptionPane extends JOptionPane ourOptions = Arrays.asList(options); - int response = JOptionPane.showOptionDialog(parentComponent, message, - title, optionType, messageType, icon, options, initialValue); - - /* - * In Java, the response is returned to this thread and handled here; - * (for Javascript, see propertyChange) - */ - if (!Platform.isJS()) - /** - * Java only - * - * @j2sIgnore - */ + if (modal) { - handleResponse(response); + // use a JOptionPane as usual + int response = JOptionPane.showOptionDialog(parentComponent, message, + title, optionType, messageType, icon, options, initialValue); + + /* + * In Java, the response is returned to this thread and handled here; + * (for Javascript, see propertyChange) + */ + if (!Platform.isJS()) + /** + * Java only + * + * @j2sIgnore + */ + { + handleResponse(response); + } + } + else + { + /* + * This is java similar to the swingjs handling, with the callbacks + * attached to the button press of the dialog. This means we can use + * a non-modal JDialog for the confirmation without blocking the GUI. + */ + JOptionPane joptionpane = new JOptionPane(); + // Make button options + int[] buttonActions = { JvOptionPane.YES_OPTION, + JvOptionPane.NO_OPTION, JvOptionPane.CANCEL_OPTION }; + + // we need the strings to make the buttons with actionEventListener + if (options == null) + { + ArrayList options_default = new ArrayList<>(); + options_default + .add(UIManager.getString("OptionPane.yesButtonText")); + if (optionType == JvOptionPane.YES_NO_OPTION + || optionType == JvOptionPane.YES_NO_CANCEL_OPTION) + { + options_default + .add(UIManager.getString("OptionPane.noButtonText")); + } + if (optionType == JvOptionPane.YES_NO_CANCEL_OPTION) + { + options_default + .add(UIManager.getString("OptionPane.cancelButtonText")); + } + options = options_default.toArray(); + } + + ArrayList options_btns = new ArrayList<>(); + Object initialValue_btn = null; + if (!Platform.isJS()) // JalviewJS already uses callback, don't need to add them here + { + for (int i = 0; i < options.length && i < 3; i++) + { + Object o = options[i]; + int buttonAction = buttonActions[i]; + Runnable action = callbacks.get(buttonAction); + JButton jb = new JButton(); + jb.setText((String) o); + jb.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + joptionpane.setValue(buttonAction); + if (action != null) + Executors.defaultThreadFactory().newThread(action).start(); + // joptionpane.transferFocusBackward(); + joptionpane.transferFocusBackward(); + joptionpane.setVisible(false); + // put focus and raise parent window if possible, unless cancel + // button pressed + boolean raiseParent = (parentComponent != null); + if (buttonAction == JvOptionPane.CANCEL_OPTION) + raiseParent = false; + if (optionType == JvOptionPane.YES_NO_OPTION + && buttonAction == JvOptionPane.NO_OPTION) + raiseParent = false; + if (raiseParent) + { + parentComponent.requestFocus(); + if (parentComponent instanceof JInternalFrame) + { + JInternalFrame jif = (JInternalFrame) parentComponent; + jif.show(); + jif.moveToFront(); + jif.grabFocus(); + } + else if (parentComponent instanceof Window) + { + Window w = (Window) parentComponent; + w.toFront(); + w.requestFocus(); + } + } + joptionpane.setVisible(false); + } + }); + options_btns.add(jb); + if (o.equals(initialValue)) + initialValue_btn = jb; + } + } + joptionpane.setMessage(message); + joptionpane.setMessageType(messageType); + joptionpane.setOptionType(optionType); + joptionpane.setIcon(icon); + joptionpane.setOptions( + Platform.isJS() ? options : options_btns.toArray()); + joptionpane.setInitialValue( + Platform.isJS() ? initialValue : initialValue_btn); + + JDialog dialog = joptionpane.createDialog(parentComponent, title); + dialog.setModalityType(modal ? ModalityType.APPLICATION_MODAL + : ModalityType.MODELESS); + dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + dialog.setVisible(true); } } -- 1.7.10.2