X-Git-Url: http://source.jalview.org/gitweb/?p=jalview.git;a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FJvOptionPane.java;h=028e50b0d1e646efdc24cdc65aebeb12d5939180;hp=89899e2532bf50f5cbde66ae708b6aa216ff0637;hb=c5573e5957f2a470d17867857d80dc4de1e012a4;hpb=f6960fda4da039c82fa2fd520a38de207ddca12a diff --git a/src/jalview/gui/JvOptionPane.java b/src/jalview/gui/JvOptionPane.java index 89899e2..028e50b 100644 --- a/src/jalview/gui/JvOptionPane.java +++ b/src/jalview/gui/JvOptionPane.java @@ -21,26 +21,35 @@ package jalview.gui; -import jalview.util.dialogrunner.DialogRunner; -import jalview.util.dialogrunner.DialogRunnerI; -import jalview.util.dialogrunner.RunResponse; - 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; public class JvOptionPane extends JOptionPane implements DialogRunnerI, PropertyChangeListener { - // BH 2018 no changes needed here. - private static final long serialVersionUID = -3019167117756785229L; private static Object mockResponse = JvOptionPane.CANCEL_OPTION; @@ -49,10 +58,17 @@ public class JvOptionPane extends JOptionPane private Component parentComponent; - public JvOptionPane(final Component parentComponent) + private Map callbacks = new HashMap<>(); + + /* + * JalviewJS reports user choice in the dialog as the selected + * option (text); this list allows conversion to index (int) + */ + List ourOptions; + + public JvOptionPane(final Component parent) { - - this.parentComponent = parentComponent; + this.parentComponent = Platform.isJS() ? this : parent; } public static int showConfirmDialog(Component parentComponent, @@ -85,7 +101,7 @@ public class JvOptionPane extends JOptionPane switch (optionType) { case JvOptionPane.YES_NO_CANCEL_OPTION: - // FeatureRenderer amendFeatures ?? TODO ?? + // FeatureRenderer amendFeatures ?? TODO ?? // Chimera close // PromptUserConfig // $FALL-THROUGH$ @@ -158,8 +174,10 @@ public class JvOptionPane extends JOptionPane Object message) { // JvOptionPaneTest only; - return isInteractiveMode() ? JOptionPane.showInternalConfirmDialog( - parentComponent, message) : (int) getMockResponse(); + return isInteractiveMode() + ? JOptionPane.showInternalConfirmDialog(parentComponent, + message) + : (int) getMockResponse(); } /** @@ -393,7 +411,6 @@ public class JvOptionPane extends JOptionPane JOptionPane.showMessageDialog(parentComponent, message); } - /** * Adds title and messageType * @@ -482,6 +499,26 @@ public class JvOptionPane extends JOptionPane } /** + * adds inital selection value + * + * @param message + * @param initialSelectionValue + * @return + */ + public static String showInputDialog(Object message, + Object initialSelectionValue) + { + if (!isInteractiveMode()) + { + return getMockResponse().toString(); + } + + // AnnotationPanel character option + + return JOptionPane.showInputDialog(message, initialSelectionValue); + } + + /** * centered on parent * * @param parentComponent @@ -510,9 +547,29 @@ public class JvOptionPane extends JOptionPane public static String showInputDialog(Component parentComponent, String message, String initialSelectionValue) { - + // AnnotationPanel - + + return isInteractiveMode() + ? JOptionPane.showInputDialog(parentComponent, message, + initialSelectionValue) + : getMockResponse().toString(); + } + + /** + * input with initial selection + * + * @param parentComponent + * @param message + * @param initialSelectionValue + * @return + */ + public static String showInputDialog(Component parentComponent, + Object message, Object initialSelectionValue) + { + + // AnnotationPanel + return isInteractiveMode() ? JOptionPane.showInputDialog(parentComponent, message, initialSelectionValue) @@ -535,13 +592,14 @@ public class JvOptionPane extends JOptionPane // test only - return isInteractiveMode() ? JOptionPane - .showInputDialog(parentComponent, message, title, messageType) + return isInteractiveMode() + ? JOptionPane.showInputDialog(parentComponent, message, title, + messageType) : getMockResponse().toString(); } /** - * Customized input option + * Customized input option * * @param parentComponent * @param message @@ -558,9 +616,9 @@ public class JvOptionPane extends JOptionPane Object[] selectionValues, Object initialSelectionValue) throws HeadlessException { - + // test only - + return isInteractiveMode() ? JOptionPane.showInputDialog(parentComponent, message, title, messageType, icon, selectionValues, @@ -568,8 +626,6 @@ public class JvOptionPane extends JOptionPane : getMockResponse().toString(); } - - /** * internal version * @@ -581,13 +637,12 @@ public class JvOptionPane extends JOptionPane String message) { // test only - + return isInteractiveMode() ? JOptionPane.showInternalInputDialog(parentComponent, message) : getMockResponse().toString(); } - /** * internal with title and messageType * @@ -600,9 +655,9 @@ public class JvOptionPane extends JOptionPane public static String showInternalInputDialog(Component parentComponent, String message, String title, int messageType) { - + // AlignFrame tabbedPane_mousePressed - + return isInteractiveMode() ? JOptionPane.showInternalInputDialog(parentComponent, getPrefix(messageType) + message, title, messageType) @@ -626,7 +681,7 @@ public class JvOptionPane extends JOptionPane Object[] selectionValues, Object initialSelectionValue) { // test only - + return isInteractiveMode() ? JOptionPane.showInternalInputDialog(parentComponent, message, title, messageType, icon, selectionValues, @@ -634,10 +689,8 @@ public class JvOptionPane extends JOptionPane : getMockResponse().toString(); } - ///////////// end of options /////////////// - - + private static void outputMessage(Object message) { System.out.println(">>> JOption Message : " + message.toString()); @@ -664,39 +717,33 @@ public class JvOptionPane extends JOptionPane return interactiveMode; } - public static void setInteractiveMode(boolean interactiveMode) + public static void setInteractiveMode(boolean interactive) { - JvOptionPane.interactiveMode = interactiveMode; + JvOptionPane.interactiveMode = interactive; } - @SuppressWarnings("unused") private static String getPrefix(int messageType) { - String prefix = ""; // JavaScript only + String prefix = ""; - if (/** @j2sNative true || */ - false) + // JavaScript only + if (Platform.isJS()) { switch (messageType) { - default: - case JvOptionPane.INFORMATION_MESSAGE: - prefix = "Note: "; - break; case JvOptionPane.WARNING_MESSAGE: prefix = "WARNING! "; break; case JvOptionPane.ERROR_MESSAGE: - prefix = "ERRROR! "; + prefix = "ERROR! "; break; + default: + prefix = "Note: "; } } return prefix; } - DialogRunner runner = new DialogRunner(this); - - private List ourOptions; /** * create a new option dialog that can be used to register responses - along * lines of showOptionDialog @@ -716,14 +763,20 @@ public class JvOptionPane extends JOptionPane return new JvOptionPane(parentComponent); } - public void showDialog( - String message, String title, int optionType, int messageType, - Icon icon, Object[] options, Object initialValue) + 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()) { - runner.firstRun((int) getMockResponse()); + handleResponse(getMockResponse()); } // two uses: // @@ -739,25 +792,131 @@ public class JvOptionPane extends JOptionPane // // 2) UserDefinedColors warning about saving over a name already defined // - Component parent; - /** - * @j2sNative - * parent = this; - */ - { - parent = parentComponent; - } - ; + ourOptions = Arrays.asList(options); - int response = JOptionPane.showOptionDialog(parent, message, title, - optionType, messageType, icon, options, initialValue); - /** - * @j2sNative - */ + + if (modal) { - runner.firstRun(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); + } } public void showInternalDialog(JPanel mainPanel, String title, @@ -766,67 +925,79 @@ public class JvOptionPane extends JOptionPane { if (!isInteractiveMode()) { - runner.firstRun((int) getMockResponse()); - } - Component parent; - /** - * @j2sNative parent = this; - */ - { - parent = parentComponent; + handleResponse(getMockResponse()); } - ; + ourOptions = Arrays.asList(options); - int response; - if (parent!=this) { - - response = JOptionPane.showInternalOptionDialog(parent, mainPanel, - title, yesNoCancelOption, questionMessage, icon, options, - initresponse); + if (parentComponent != this) + { + response = JOptionPane.showInternalOptionDialog(parentComponent, + mainPanel, title, yesNoCancelOption, questionMessage, icon, + options, initresponse); } else { - response = JOptionPane.showOptionDialog(parent, mainPanel, title, - yesNoCancelOption, questionMessage, icon, options, + response = JOptionPane.showOptionDialog(parentComponent, mainPanel, + title, yesNoCancelOption, questionMessage, icon, options, initresponse); } + if (!Platform.isJS()) /** - * @j2sNative + * Java only + * + * @j2sIgnore */ { - runner.firstRun(response); + handleResponse(response); } - } - @Override - public JvOptionPane response(RunResponse action) - { - runner.response(action); - return this; - } - - public JvOptionPane defaultResponse(Runnable runnable) + @Override + public JvOptionPane setResponseHandler(Object response, Runnable action) { - runner.setDefaultResponse(runnable); + callbacks.put(response, action); return this; } + /** + * 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. + * + * @param evt + */ @Override public void propertyChange(PropertyChangeEvent evt) { - int ourOption = ourOptions.indexOf(evt.getNewValue()); - if (ourOption == -1) + Object newValue = evt.getNewValue(); + int ourOption = ourOptions.indexOf(newValue); + if (ourOption >= 0) { - // try our luck.. - runner.run(evt.getNewValue()); + handleResponse(ourOption); } else { - runner.run(ourOption); + // try our luck.. + handleResponse(newValue); } } - + @Override + public void handleResponse(Object response) + { + /* + * this test is for NaN in Chrome + */ + if (response != null && !response.equals(response)) + { + return; + } + Runnable action = callbacks.get(response); + if (action != null) + { + action.run(); + parentComponent.requestFocus(); + } + } }