X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fjalview%2Fgui%2FJvOptionPane.java;fp=src%2Fjalview%2Fgui%2FJvOptionPane.java;h=c5427cb1c224075b4dd8d90ed067e6ec074321fb;hb=b364e1e6d199002069dab615d1007799b5bb71e1;hp=028e50b0d1e646efdc24cdc65aebeb12d5939180;hpb=0980e87380e2922790d01bde3f616115f1916a43;p=jalview.git diff --git a/src/jalview/gui/JvOptionPane.java b/src/jalview/gui/JvOptionPane.java index 028e50b..c5427cb 100644 --- a/src/jalview/gui/JvOptionPane.java +++ b/src/jalview/gui/JvOptionPane.java @@ -34,11 +34,13 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.Callable; import java.util.concurrent.Executors; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JDialog; +import javax.swing.JFrame; import javax.swing.JInternalFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; @@ -52,13 +54,13 @@ public class JvOptionPane extends JOptionPane { private static final long serialVersionUID = -3019167117756785229L; - private static Object mockResponse = JvOptionPane.CANCEL_OPTION; + private static Object mockResponse = JOptionPane.CANCEL_OPTION; private static boolean interactiveMode = true; private Component parentComponent; - private Map callbacks = new HashMap<>(); + private Map callbacks = new HashMap<>(); /* * JalviewJS reports user choice in the dialog as the selected @@ -100,17 +102,17 @@ public class JvOptionPane extends JOptionPane } switch (optionType) { - case JvOptionPane.YES_NO_CANCEL_OPTION: + case JOptionPane.YES_NO_CANCEL_OPTION: // FeatureRenderer amendFeatures ?? TODO ?? // Chimera close // PromptUserConfig // $FALL-THROUGH$ default: - case JvOptionPane.YES_NO_OPTION: + case JOptionPane.YES_NO_OPTION: // PromptUserConfig usage stats // for now treated as "OK CANCEL" // $FALL-THROUGH$ - case JvOptionPane.OK_CANCEL_OPTION: + case JOptionPane.OK_CANCEL_OPTION: // will fall back to simple HTML return JOptionPane.showConfirmDialog(parentComponent, message, title, optionType); @@ -198,13 +200,13 @@ public class JvOptionPane extends JOptionPane } switch (optionType) { - case JvOptionPane.YES_NO_CANCEL_OPTION: + case JOptionPane.YES_NO_CANCEL_OPTION: // ColourMenuHelper.addMenuItmers.offerRemoval TODO - case JvOptionPane.YES_NO_OPTION: + case JOptionPane.YES_NO_OPTION: // UserDefinedColoursSave -- relevant? TODO // $FALL-THROUGH$ default: - case JvOptionPane.OK_CANCEL_OPTION: + case JOptionPane.OK_CANCEL_OPTION: // EditNameDialog --- uses panel for messsage TODO @@ -233,13 +235,13 @@ public class JvOptionPane extends JOptionPane } switch (optionType) { - case JvOptionPane.YES_NO_CANCEL_OPTION: - case JvOptionPane.YES_NO_OPTION: + case JOptionPane.YES_NO_CANCEL_OPTION: + case JOptionPane.YES_NO_OPTION: // UserQuestionanaireCheck // VamsasApplication // $FALL-THROUGH$ default: - case JvOptionPane.OK_CANCEL_OPTION: + case JOptionPane.OK_CANCEL_OPTION: // will fall back to simple HTML return JOptionPane.showConfirmDialog(parentComponent, message, title, optionType, messageType); @@ -267,11 +269,11 @@ public class JvOptionPane extends JOptionPane } switch (optionType) { - case JvOptionPane.YES_NO_CANCEL_OPTION: - case JvOptionPane.YES_NO_OPTION: + case JOptionPane.YES_NO_CANCEL_OPTION: + case JOptionPane.YES_NO_OPTION: //$FALL-THROUGH$ default: - case JvOptionPane.OK_CANCEL_OPTION: + case JOptionPane.OK_CANCEL_OPTION: // Preferences editLink/newLink return JOptionPane.showConfirmDialog(parentComponent, message, title, optionType, messageType, icon); @@ -708,7 +710,7 @@ public class JvOptionPane extends JOptionPane public static void resetMock() { - setMockResponse(JvOptionPane.CANCEL_OPTION); + setMockResponse(JOptionPane.CANCEL_OPTION); setInteractiveMode(true); } @@ -731,10 +733,10 @@ public class JvOptionPane extends JOptionPane { switch (messageType) { - case JvOptionPane.WARNING_MESSAGE: + case JOptionPane.WARNING_MESSAGE: prefix = "WARNING! "; break; - case JvOptionPane.ERROR_MESSAGE: + case JOptionPane.ERROR_MESSAGE: prefix = "ERROR! "; break; default: @@ -758,6 +760,11 @@ public class JvOptionPane extends JOptionPane * @param string2 * @return */ + public static JvOptionPane newOptionDialog() + { + return new JvOptionPane(null); + } + public static JvOptionPane newOptionDialog(Component parentComponent) { return new JvOptionPane(parentComponent); @@ -822,100 +829,12 @@ public class JvOptionPane extends JOptionPane * 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); + JDialog dialog = this.createDialog(parentComponent, message, title, + optionType, messageType, icon, options, initialValue, modal); + jalview.bin.Console.debug("About to setVisible(true)"); dialog.setVisible(true); + jalview.bin.Console.debug("Just setVisible(true)"); } } @@ -953,14 +872,84 @@ public class JvOptionPane extends JOptionPane } } + /* @Override public JvOptionPane setResponseHandler(Object response, Runnable action) { + callbacks.put(response, new Callable() + { + @Override + public Void call() + { + action.run(); + return null; + } + }); + return this; + } + */ + @Override + public JvOptionPane setResponseHandler(Object response, Callable action) + { callbacks.put(response, action); return this; } /** + * showDialogOnTop will create a dialog that (attempts to) come to top of OS + * desktop windows + */ + public static int showDialogOnTop(String label, String actionString, + int JOPTIONPANE_OPTION, int JOPTIONPANE_MESSAGETYPE) + { + // Ensure Jalview window is brought to front (primarily for Quit + // confirmation window to be visible) + + // This method of raising the Jalview window is broken in java + // jalviewDesktop.setVisible(true); + // jalviewDesktop.toFront(); + + // A better hack which works is to create a new JFrame parent with + // setAlwaysOnTop(true) + JFrame dialogParent = new JFrame(); + dialogParent.setAlwaysOnTop(true); + + int answer = JOptionPane.showConfirmDialog(dialogParent, label, + actionString, JOPTIONPANE_OPTION, JOPTIONPANE_MESSAGETYPE); + + dialogParent.setAlwaysOnTop(false); + jalview.bin.Console.debug("*********** BEFORE dialogParent.dispose()"); + dialogParent.dispose(); + jalview.bin.Console.debug("*********** BEFORE dialogParent.dispose()"); + + return answer; + } + + public void showDialogOnTopAsync(String label, String actionString, + int JOPTIONPANE_OPTION, int JOPTIONPANE_MESSAGETYPE, Icon icon, + Object[] options, Object initialValue, boolean modal) + { + // Ensure Jalview window is brought to front (primarily for Quit + // confirmation window to be visible) + + // This method of raising the Jalview window is broken in java + // jalviewDesktop.setVisible(true); + // jalviewDesktop.toFront(); + + // A better hack which works is to create a new JFrame parent with + // setAlwaysOnTop(true) + JFrame dialogParent = new JFrame(); + dialogParent.setAlwaysOnTop(true); + parentComponent = dialogParent; + + showDialog(label, actionString, JOPTIONPANE_OPTION, + JOPTIONPANE_MESSAGETYPE, icon, options, initialValue, modal); + + dialogParent.setAlwaysOnTop(false); + dialogParent.dispose(); + } + + /** * JalviewJS signals option selection by a property change event for the * option e.g. "OK". This methods responds to that by running the response * action that corresponds to that option. @@ -993,11 +982,139 @@ public class JvOptionPane extends JOptionPane { return; } - Runnable action = callbacks.get(response); + Callable action = callbacks.get(response); if (action != null) { - action.run(); - parentComponent.requestFocus(); + try + { + action.call(); + } catch (Exception e) + { + e.printStackTrace(); + } + if (parentComponent != null) + parentComponent.requestFocus(); + } + } + + /** + * Create a non-modal confirm dialog + */ + public JDialog createDialog(Component parentComponent, String message, + String title, int optionType, int messageType, Icon icon, + Object[] options, Object initialValue, boolean modal) + { + JOptionPane joptionpane = new JOptionPane(); + // Make button options + int[] buttonActions = { JOptionPane.YES_OPTION, JOptionPane.NO_OPTION, + JOptionPane.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 == JOptionPane.YES_NO_OPTION + || optionType == JOptionPane.YES_NO_CANCEL_OPTION) + { + options_default.add(UIManager.getString("OptionPane.noButtonText")); + } + if (optionType == JOptionPane.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 + { + if (((optionType == JOptionPane.YES_NO_OPTION + || optionType == JOptionPane.OK_CANCEL_OPTION) + && options.length < 2) + || (optionType == JOptionPane.YES_NO_CANCEL_OPTION + && options.length < 3)) + { + jalview.bin.Console + .debug("JvOptionPane: not enough options for dialog type"); + } + for (int i = 0; i < options.length && i < 3; i++) + { + Object o = options[i]; + int buttonAction = buttonActions[i]; + Callable 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.newSingleThreadExecutor().submit(action); + // 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 == JOptionPane.CANCEL_OPTION) + raiseParent = false; + if (optionType == JOptionPane.YES_NO_OPTION + && buttonAction == JOptionPane.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); + return dialog; + } + + /** + * Utility to programmatically click a button on a JOptionPane (as a JFrame) + * + * returns true if button was found + */ + public static boolean clickButton(JFrame frame, int buttonType) + { + + return false; } }