package javajs.async; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.Icon; import javax.swing.JOptionPane; import javax.swing.plaf.UIResource; /** * A class to manage asynchronous input, option, and confirmation dialogs. * * @author Bob Hanson hansonr_at_stolaf.edu * */ public class AsyncDialog implements PropertyChangeListener { // see discussion in net.sf.j2s.core/doc/Differences.txt // // Confirmation dialog example. Note moving the parent component into the constructor. // Original: // // private void promptQuit() { // int sel = JOptionPane.showConfirmDialog(null, PROMPT_EXIT, NAME, JOptionPane.YES_NO_OPTION); // switch (sel) { // case JOptionPane.YES_OPTION: // resultsTab.clean(); // seqs.dispose(); // if (fromMain) { // System.exit(0); // } // break; // } // } // // revised: // // private void promptQuitAsync() { // new AsyncDialog().showConfirmDialog(null, PROMPT_EXIT, NAME, JOptionPane.YES_NO_OPTION, new ActionListener() { // // @Override // public void actionPerformed(ActionEvent e) { // int sel = ((AsyncDialog)e.getSource()).getOption(); // switch (sel) { // case JOptionPane.YES_OPTION: // resultsTab.clean(); // seqs.dispose(); // if (fromMain) { // System.exit(0); // } // break; // } // }})); // } public AsyncDialog() { } private ActionListener actionListener; private Object choice; private Object[] options; private Object value; private boolean wantsInput; // These options can be supplemented as desired. /** * Synchronous call; OK in JavaScript as long as we are using a JavaScript prompt() call * * @param frame * @param msg * @return */ @Deprecated public static String showInputDialog(Component frame, String msg) { return JOptionPane.showInputDialog(frame, msg); } public void showInputDialog(Component frame, Object message, ActionListener a) { setListener(a); wantsInput = true; process(JOptionPane.showInputDialog(frame, message)); unsetListener(); } public void showInputDialog(Component frame, Object message, String title, int messageType, Icon icon, Object[] selectionValues, Object initialSelectionValue, ActionListener a) { setListener(a); wantsInput = true; process(JOptionPane.showInputDialog(frame, message, title, messageType, icon, selectionValues, initialSelectionValue)); unsetListener(); } public void showMessageDialog(Component frame, Object message, ActionListener a) { setListener(a); JOptionPane.showMessageDialog(frame, message); unsetListener(); if (/** @j2sNative false || */true) process("" + message); } public void showOptionDialog(Component frame, Object message, String title, int optionType, int messageType, Icon icon, Object[] options, Object initialValue, ActionListener a) { actionListener = a; this.options = options; setListener(a); process(JOptionPane.showOptionDialog(frame, message, title, optionType, messageType, icon, options, initialValue)); unsetListener(); } public void showConfirmDialog(Component frame, Object message, String title, ActionListener a) { showConfirmDialog(frame, message, title, JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, a); } public void showConfirmDialog(Component frame, Object message, String title, int optionType, ActionListener a) { showConfirmDialog(frame, message, title, optionType, JOptionPane.QUESTION_MESSAGE, a); } public void showConfirmDialog(Component frame, Object message, String title, int optionType, int messageType, ActionListener a) { setListener(a); process(JOptionPane.showConfirmDialog(frame, message, title, optionType, messageType)); unsetListener(); } /** * retrieve selection from the ActionEvent, for which "this" is getSource() * * @return */ public Object getChoice() { return choice; } public int getOption() { if (!(choice instanceof Integer)) { throw new java.lang.IllegalArgumentException("AsyncDialog.getOption called for non-Integer choice"); } return ((Integer) choice).intValue(); } /** * A dialog option that allows for YES, NO, and CLOSE options via * ActionListener. ActionEvent.getID() contains the reply. * * @param parent The parent component for the dialog * @param message The text of the message to display * @param title Optional title defaults to "Question" * @param listener Handle options based on an ActionEvent */ public static void showYesNoAsync(Component parent, Object message, String title, ActionListener listener) { new AsyncDialog().showConfirmDialog(parent, message, (title == null ? "Question" : title), JOptionPane.YES_NO_OPTION, listener); } /** * A dialog option that involves just a YES follower. * @param parent * @param message * @param title TODO * @param yes */ public static void showYesAsync(Component parent, Object message, String title, Runnable yes) { AsyncDialog.showYesNoAsync(parent, message, title, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (e.getID() == JOptionPane.YES_OPTION) { yes.run(); } } }); } /** * A dialog option that involves just an OK follower. * @param parent * @param message * @param title * @param ok */ public static void showOKAsync(Component parent, Object message, String title, Runnable ok) { new AsyncDialog().showConfirmDialog(parent, message, title, JOptionPane.OK_CANCEL_OPTION, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (e.getID() == JOptionPane.OK_OPTION) { ok.run(); } } }); } private void setListener(ActionListener a) { actionListener = a; @SuppressWarnings("unused") Class c = JOptionPane.class; // loads the class /** @j2sNative c.$clazz$.listener = this */ } private void unsetListener() { /** @j2sNative javax.swing.JOptionPane.listener = null */ } /** * Switch from property change to action. * */ @Override public void propertyChange(PropertyChangeEvent evt) { value = evt.getNewValue(); switch (evt.getPropertyName()) { case "inputValue": process(value); break; case "value": if (value != null && options == null && !(value instanceof Integer)) { process(getOptionIndex(((JOptionPane) evt.getSource()).getOptions(), value)); return; } if (options != null) { int i = getOptionIndex(options, value); value = Integer.valueOf(i >= 0 ? i : JOptionPane.CLOSED_OPTION); } process(value); break; } } private int getOptionIndex(Object[] options, Object val) { if (options != null) for (int i = 0; i < options.length; i++) { if (options[i] == val) return i; } return -1; } public Object getValue() { if (wantsInput || options == null) return value; int val = ((Integer) value).intValue(); return (val < 0 ? null : options[val]); } private boolean processed; /** * Return for confirm dialog. * * @param ret may be JavaScript NaN, testable as ret != ret or ret != - -ret */ private void process(int ret) { if (ret != -(-ret) || processed) return; processed = true; choice = ret; actionListener.actionPerformed(new ActionEvent(this, ret, "SelectedOption")); } private void process(Object ret) { if (ret instanceof UIResource || processed) return; processed = true; choice = ret; actionListener.actionPerformed(new ActionEvent(this, ret == null ? JOptionPane.CANCEL_OPTION : JOptionPane.OK_OPTION, (ret == null ? null : ret.toString()))); } }