2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import java.awt.AWTEvent;
24 import java.awt.ActiveEvent;
25 import java.awt.Component;
26 import java.awt.Container;
27 import java.awt.Dialog.ModalityType;
28 import java.awt.EventQueue;
29 import java.awt.HeadlessException;
30 import java.awt.MenuComponent;
31 import java.awt.Toolkit;
32 import java.awt.Window;
33 import java.awt.event.ActionEvent;
34 import java.awt.event.ActionListener;
35 import java.awt.event.MouseAdapter;
36 import java.awt.event.MouseMotionAdapter;
37 import java.beans.PropertyChangeEvent;
38 import java.beans.PropertyChangeListener;
39 import java.util.ArrayList;
40 import java.util.Arrays;
41 import java.util.HashMap;
42 import java.util.List;
44 import java.util.concurrent.Callable;
45 import java.util.concurrent.ExecutorService;
46 import java.util.concurrent.Executors;
48 import javax.swing.Icon;
49 import javax.swing.JButton;
50 import javax.swing.JDialog;
51 import javax.swing.JFrame;
52 import javax.swing.JInternalFrame;
53 import javax.swing.JLayeredPane;
54 import javax.swing.JOptionPane;
55 import javax.swing.JPanel;
56 import javax.swing.SwingUtilities;
57 import javax.swing.UIManager;
58 import javax.swing.event.InternalFrameEvent;
59 import javax.swing.event.InternalFrameListener;
61 import jalview.bin.Console;
62 import jalview.util.ChannelProperties;
63 import jalview.util.Platform;
64 import jalview.util.dialogrunner.DialogRunnerI;
66 public class JvOptionPane extends JOptionPane
67 implements DialogRunnerI, PropertyChangeListener
69 private static final long serialVersionUID = -3019167117756785229L;
71 private static Object mockResponse = JvOptionPane.CANCEL_OPTION;
73 private static boolean interactiveMode = true;
75 private Component parentComponent;
77 private ExecutorService executor = Executors.newCachedThreadPool();
79 private JDialog dialog = null;
81 private Map<Object, Callable<Void>> callbacks = new HashMap<>();
84 * JalviewJS reports user choice in the dialog as the selected option (text);
85 * this list allows conversion to index (int)
87 List<Object> ourOptions;
89 public JvOptionPane(final Component parent)
91 this.parentComponent = Platform.isJS() ? this : parent;
95 public static int showConfirmDialog(Component parentComponent,
96 Object message) throws HeadlessException
98 // only called by test
99 return isInteractiveMode()
100 ? JOptionPane.showConfirmDialog(parentComponent, message)
101 : (int) getMockResponse();
105 * Message, title, optionType
107 * @param parentComponent
112 * @throws HeadlessException
114 public static int showConfirmDialog(Component parentComponent,
115 Object message, String title, int optionType)
116 throws HeadlessException
118 if (!isInteractiveMode())
120 return (int) getMockResponse();
124 case JvOptionPane.YES_NO_CANCEL_OPTION:
125 // FeatureRenderer amendFeatures ?? TODO ??
130 case JvOptionPane.YES_NO_OPTION:
131 // PromptUserConfig usage stats
132 // for now treated as "OK CANCEL"
134 case JvOptionPane.OK_CANCEL_OPTION:
135 // will fall back to simple HTML
136 return JOptionPane.showConfirmDialog(parentComponent, message, title,
142 * Adds a message type. Fallback is to just add it in the beginning.
144 * @param parentComponent
150 * @throws HeadlessException
152 public static int showConfirmDialog(Component parentComponent,
153 Object message, String title, int optionType, int messageType)
154 throws HeadlessException
156 // JalviewServicesChanged
157 // PromptUserConfig raiseDialog
158 return isInteractiveMode()
159 ? JOptionPane.showConfirmDialog(parentComponent, message, title,
160 optionType, messageType)
161 : (int) getMockResponse();
167 * @param parentComponent
174 * @throws HeadlessException
176 public static int showConfirmDialog(Component parentComponent,
177 Object message, String title, int optionType, int messageType,
178 Icon icon) throws HeadlessException
180 // JvOptionPaneTest only
181 return isInteractiveMode()
182 ? JOptionPane.showConfirmDialog(parentComponent, message, title,
183 optionType, messageType, icon)
184 : (int) getMockResponse();
188 * Internal version "OK"
190 * @param parentComponent
194 public static int showInternalConfirmDialog(Component parentComponent,
197 // JvOptionPaneTest only;
198 return isInteractiveMode()
199 ? JOptionPane.showInternalConfirmDialog(parentComponent,
201 : (int) getMockResponse();
205 * Internal version -- changed to standard version for now
207 * @param parentComponent
213 public static int showInternalConfirmDialog(Component parentComponent,
214 String message, String title, int optionType)
216 if (!isInteractiveMode())
218 return (int) getMockResponse();
222 case JvOptionPane.YES_NO_CANCEL_OPTION:
223 // ColourMenuHelper.addMenuItmers.offerRemoval TODO
224 case JvOptionPane.YES_NO_OPTION:
225 // UserDefinedColoursSave -- relevant? TODO
228 case JvOptionPane.OK_CANCEL_OPTION:
230 // EditNameDialog --- uses panel for messsage TODO
232 // Desktop.inputURLMenuItem
234 return JOptionPane.showConfirmDialog(parentComponent, message, title,
241 * @param parentComponent
248 public static int showInternalConfirmDialog(Component parentComponent,
249 Object message, String title, int optionType, int messageType)
251 if (!isInteractiveMode())
253 return (int) getMockResponse();
257 case JvOptionPane.YES_NO_CANCEL_OPTION:
258 case JvOptionPane.YES_NO_OPTION:
259 // UserQuestionanaireCheck
263 case JvOptionPane.OK_CANCEL_OPTION:
264 // will fall back to simple HTML
265 return JOptionPane.showConfirmDialog(parentComponent, message, title,
266 optionType, messageType);
271 * adds icon; no longer internal
273 * @param parentComponent
281 public static int showInternalConfirmDialog(Component parentComponent,
282 Object message, String title, int optionType, int messageType,
285 if (!isInteractiveMode())
287 return (int) getMockResponse();
291 case JvOptionPane.YES_NO_CANCEL_OPTION:
292 case JvOptionPane.YES_NO_OPTION:
295 case JvOptionPane.OK_CANCEL_OPTION:
296 // Preferences editLink/newLink
297 return JOptionPane.showConfirmDialog(parentComponent, message, title,
298 optionType, messageType, icon);
304 * custom options full-featured
306 * @param parentComponent
313 * @param initialValue
315 * @throws HeadlessException
317 public static int showOptionDialog(Component parentComponent,
318 String message, String title, int optionType, int messageType,
319 Icon icon, Object[] options, Object initialValue)
320 throws HeadlessException
322 if (!isInteractiveMode())
324 return (int) getMockResponse();
330 // 1) AlignViewport for openLinkedAlignment
332 // Show a dialog with the option to open and link (cDNA <-> protein) as a
334 // alignment, either as a standalone alignment or in a split frame. Returns
335 // true if the new alignment was opened, false if not, because the user
336 // declined the offer.
338 // 2) UserDefinedColors warning about saving over a name already defined
340 return JOptionPane.showOptionDialog(parentComponent, message, title,
341 optionType, messageType, icon, options, initialValue);
348 * @throws HeadlessException
350 public static void showMessageDialog(Component parentComponent,
351 String message) throws HeadlessException
353 if (!isInteractiveMode())
355 outputMessage(message);
361 JOptionPane.showMessageDialog(parentComponent, message);
365 * OK with message, title, and type
367 * @param parentComponent
371 * @throws HeadlessException
373 public static void showMessageDialog(Component parentComponent,
374 String message, String title, int messageType)
375 throws HeadlessException
377 // 30 implementations -- all just fine.
379 if (!isInteractiveMode())
381 outputMessage(message);
385 JOptionPane.showMessageDialog(parentComponent,
386 getPrefix(messageType) + message, title, messageType);
390 * adds title and icon
392 * @param parentComponent
397 * @throws HeadlessException
399 public static void showMessageDialog(Component parentComponent,
400 String message, String title, int messageType, Icon icon)
401 throws HeadlessException
406 if (!isInteractiveMode())
408 outputMessage(message);
412 JOptionPane.showMessageDialog(parentComponent, message, title,
420 public static void showInternalMessageDialog(Component parentComponent,
424 // WsPreferences only
426 if (!isInteractiveMode())
428 outputMessage(message);
432 JOptionPane.showMessageDialog(parentComponent, message);
436 * Adds title and messageType
438 * @param parentComponent
443 public static void showInternalMessageDialog(Component parentComponent,
444 String message, String title, int messageType)
449 if (!isInteractiveMode())
451 outputMessage(message);
455 JOptionPane.showMessageDialog(parentComponent,
456 getPrefix(messageType) + message, title, messageType);
461 * @param parentComponent
467 public static void showInternalMessageDialog(Component parentComponent,
468 Object message, String title, int messageType, Icon icon)
473 if (!isInteractiveMode())
475 outputMessage(message);
479 JOptionPane.showMessageDialog(parentComponent, message, title,
487 * @throws HeadlessException
489 public static String showInputDialog(Object message)
490 throws HeadlessException
494 if (!isInteractiveMode())
496 return getMockResponse().toString();
499 return JOptionPane.showInputDialog(message);
503 * adds inital selection value
506 * @param initialSelectionValue
509 public static String showInputDialog(String message,
510 String initialSelectionValue)
512 if (!isInteractiveMode())
514 return getMockResponse().toString();
517 // AnnotationPanel character option
519 return JOptionPane.showInputDialog(message, initialSelectionValue);
523 * adds inital selection value
526 * @param initialSelectionValue
529 public static String showInputDialog(Object message,
530 Object initialSelectionValue)
532 if (!isInteractiveMode())
534 return getMockResponse().toString();
537 // AnnotationPanel character option
539 return JOptionPane.showInputDialog(message, initialSelectionValue);
545 * @param parentComponent
548 * @throws HeadlessException
550 public static String showInputDialog(Component parentComponent,
551 String message) throws HeadlessException
555 return isInteractiveMode()
556 ? JOptionPane.showInputDialog(parentComponent, message)
557 : getMockResponse().toString();
561 * input with initial selection
563 * @param parentComponent
565 * @param initialSelectionValue
568 public static String showInputDialog(Component parentComponent,
569 String message, String initialSelectionValue)
574 return isInteractiveMode()
575 ? JOptionPane.showInputDialog(parentComponent, message,
576 initialSelectionValue)
577 : getMockResponse().toString();
581 * input with initial selection
583 * @param parentComponent
585 * @param initialSelectionValue
588 public static String showInputDialog(Component parentComponent,
589 Object message, Object initialSelectionValue)
594 return isInteractiveMode()
595 ? JOptionPane.showInputDialog(parentComponent, message,
596 initialSelectionValue)
597 : getMockResponse().toString();
602 * @param parentComponent
607 * @throws HeadlessException
609 public static String showInputDialog(Component parentComponent,
610 String message, String title, int messageType)
611 throws HeadlessException
616 return isInteractiveMode()
617 ? JOptionPane.showInputDialog(parentComponent, message, title,
619 : getMockResponse().toString();
623 * Customized input option
625 * @param parentComponent
630 * @param selectionValues
631 * @param initialSelectionValue
633 * @throws HeadlessException
635 public static Object showInputDialog(Component parentComponent,
636 Object message, String title, int messageType, Icon icon,
637 Object[] selectionValues, Object initialSelectionValue)
638 throws HeadlessException
643 return isInteractiveMode()
644 ? JOptionPane.showInputDialog(parentComponent, message, title,
645 messageType, icon, selectionValues,
646 initialSelectionValue)
647 : getMockResponse().toString();
653 * @param parentComponent
657 public static String showInternalInputDialog(Component parentComponent,
662 return isInteractiveMode()
663 ? JOptionPane.showInternalInputDialog(parentComponent, message)
664 : getMockResponse().toString();
668 * internal with title and messageType
670 * @param parentComponent
676 public static String showInternalInputDialog(Component parentComponent,
677 String message, String title, int messageType)
680 // AlignFrame tabbedPane_mousePressed
682 return isInteractiveMode()
683 ? JOptionPane.showInternalInputDialog(parentComponent,
684 getPrefix(messageType) + message, title, messageType)
685 : getMockResponse().toString();
689 * customized internal
691 * @param parentComponent
696 * @param selectionValues
697 * @param initialSelectionValue
700 public static Object showInternalInputDialog(Component parentComponent,
701 String message, String title, int messageType, Icon icon,
702 Object[] selectionValues, Object initialSelectionValue)
706 return isInteractiveMode()
707 ? JOptionPane.showInternalInputDialog(parentComponent, message,
708 title, messageType, icon, selectionValues,
709 initialSelectionValue)
710 : getMockResponse().toString();
713 ///////////// end of options ///////////////
715 private static void outputMessage(Object message)
717 System.out.println(">>> JOption Message : " + message.toString());
720 public static Object getMockResponse()
725 public static void setMockResponse(Object mockOption)
727 JvOptionPane.mockResponse = mockOption;
730 public static void resetMock()
732 setMockResponse(JvOptionPane.CANCEL_OPTION);
733 setInteractiveMode(true);
736 public static boolean isInteractiveMode()
738 return interactiveMode;
741 public static void setInteractiveMode(boolean interactive)
743 JvOptionPane.interactiveMode = interactive;
746 private static String getPrefix(int messageType)
755 case JvOptionPane.WARNING_MESSAGE:
756 prefix = "WARNING! ";
758 case JvOptionPane.ERROR_MESSAGE:
769 * create a new option dialog that can be used to register responses - along
770 * lines of showOptionDialog
775 * @param defaultOption
776 * @param plainMessage
782 public static JvOptionPane newOptionDialog()
784 return new JvOptionPane(null);
787 public static JvOptionPane newOptionDialog(Component parentComponent)
789 return new JvOptionPane(parentComponent);
792 public void showDialog(String message, String title, int optionType,
793 int messageType, Icon icon, Object[] options, Object initialValue)
795 showDialog(message, title, optionType, messageType, icon, options,
799 public void showDialog(Object message, String title, int optionType,
800 int messageType, Icon icon, Object[] options, Object initialValue,
803 showDialog(message, title, optionType, messageType, icon, options,
804 initialValue, modal, null);
807 public void showDialog(Object message, String title, int optionType,
808 int messageType, Icon icon, Object[] options, Object initialValue,
809 boolean modal, JButton[] buttons)
811 if (!isInteractiveMode())
813 handleResponse(getMockResponse());
820 // 1) AlignViewport for openLinkedAlignment
822 // Show a dialog with the option to open and link (cDNA <-> protein) as a
824 // alignment, either as a standalone alignment or in a split frame. Returns
825 // true if the new alignment was opened, false if not, because the user
826 // declined the offer.
828 // 2) UserDefinedColors warning about saving over a name already defined
831 ourOptions = Arrays.asList(options);
835 boolean useButtons = false;
836 Object initialValueButton = null;
837 NOTNULL: if (buttons != null)
839 if (buttons.length != options.length)
841 jalview.bin.Console.error(
842 "Supplied buttons array not the same length as supplied options array.");
845 int[] buttonActions = { JOptionPane.YES_OPTION,
846 JOptionPane.NO_OPTION, JOptionPane.CANCEL_OPTION };
847 for (int i = 0; i < options.length; i++)
849 Object o = options[i];
850 jalview.bin.Console.debug(
851 "Setting button " + i + " to '" + o.toString() + "'");
852 JButton jb = buttons[i];
854 if (o.equals(initialValue))
855 initialValueButton = jb;
857 int buttonAction = buttonActions[i];
858 Callable<Void> action = callbacks.get(buttonAction);
859 jb.setText((String) o);
860 jb.addActionListener(new ActionListener()
863 public void actionPerformed(ActionEvent e)
866 Object obj = e.getSource();
867 if (obj == null || !(obj instanceof Component))
869 jalview.bin.Console.debug(
870 "Could not find Component source of event object "
874 Object joptionpaneObject = SwingUtilities.getAncestorOfClass(
875 JOptionPane.class, (Component) obj);
876 if (joptionpaneObject == null
877 || !(joptionpaneObject instanceof JOptionPane))
879 jalview.bin.Console.debug(
880 "Could not find JOptionPane ancestor of event object "
884 JOptionPane joptionpane = (JOptionPane) joptionpaneObject;
885 joptionpane.setValue(buttonAction);
887 getExecutor().submit(action);
888 joptionpane.transferFocusBackward();
889 joptionpane.setVisible(false);
890 // put focus and raise parent window if possible, unless cancel or
892 boolean raiseParent = (parentComponent != null);
893 if (buttonAction == JOptionPane.CANCEL_OPTION)
895 if (optionType == JOptionPane.YES_NO_OPTION
896 && buttonAction == JOptionPane.NO_OPTION)
900 parentComponent.requestFocus();
901 if (parentComponent instanceof JInternalFrame)
903 JInternalFrame jif = (JInternalFrame) parentComponent;
908 else if (parentComponent instanceof Window)
910 Window w = (Window) parentComponent;
915 joptionpane.setVisible(false);
922 // use a JOptionPane as usual
923 int response = JOptionPane.showOptionDialog(parentComponent, message,
924 title, optionType, messageType, icon,
925 useButtons ? buttons : options,
926 useButtons ? initialValueButton : initialValue);
929 * In Java, the response is returned to this thread and handled here; (for
930 * Javascript, see propertyChange)
932 if (!Platform.isJS())
939 handleResponse(response);
945 * This is java similar to the swingjs handling, with the callbacks attached to
946 * the button press of the dialog. This means we can use a non-modal JDialog for
947 * the confirmation without blocking the GUI.
949 JOptionPane joptionpane = new JOptionPane();
950 // Make button options
951 int[] buttonActions = { JvOptionPane.YES_OPTION,
952 JvOptionPane.NO_OPTION, JvOptionPane.CANCEL_OPTION };
954 // we need the strings to make the buttons with actionEventListener
957 ArrayList<String> options_default = new ArrayList<>();
959 .add(UIManager.getString("OptionPane.yesButtonText"));
960 if (optionType == JvOptionPane.YES_NO_OPTION
961 || optionType == JvOptionPane.YES_NO_CANCEL_OPTION)
964 .add(UIManager.getString("OptionPane.noButtonText"));
966 if (optionType == JvOptionPane.YES_NO_CANCEL_OPTION)
969 .add(UIManager.getString("OptionPane.cancelButtonText"));
971 options = options_default.toArray();
974 ArrayList<JButton> options_btns = new ArrayList<>();
975 Object initialValue_btn = null;
976 if (!Platform.isJS()) // JalviewJS already uses callback, don't need to
979 for (int i = 0; i < options.length && i < 3; i++)
981 Object o = options[i];
982 int buttonAction = buttonActions[i];
983 Callable<Void> action = callbacks.get(buttonAction);
984 JButton jb = new JButton();
985 jb.setText((String) o);
986 jb.addActionListener(new ActionListener()
990 public void actionPerformed(ActionEvent e)
992 joptionpane.setValue(buttonAction);
994 getExecutor().submit(action);
995 // joptionpane.transferFocusBackward();
996 joptionpane.transferFocusBackward();
997 joptionpane.setVisible(false);
998 // put focus and raise parent window if possible, unless cancel
1000 boolean raiseParent = (parentComponent != null);
1001 if (buttonAction == JvOptionPane.CANCEL_OPTION)
1002 raiseParent = false;
1003 if (optionType == JvOptionPane.YES_NO_OPTION
1004 && buttonAction == JvOptionPane.NO_OPTION)
1005 raiseParent = false;
1008 parentComponent.requestFocus();
1009 if (parentComponent instanceof JInternalFrame)
1011 JInternalFrame jif = (JInternalFrame) parentComponent;
1016 else if (parentComponent instanceof Window)
1018 Window w = (Window) parentComponent;
1023 joptionpane.setVisible(false);
1026 options_btns.add(jb);
1027 if (o.equals(initialValue))
1028 initialValue_btn = jb;
1031 joptionpane.setMessage(message);
1032 joptionpane.setMessageType(messageType);
1033 joptionpane.setOptionType(optionType);
1034 joptionpane.setIcon(icon);
1035 joptionpane.setOptions(
1036 Platform.isJS() ? options : options_btns.toArray());
1037 joptionpane.setInitialValue(
1038 Platform.isJS() ? initialValue : initialValue_btn);
1040 JDialog dialog = joptionpane.createDialog(parentComponent, title);
1041 dialog.setIconImages(ChannelProperties.getIconList());
1042 dialog.setModalityType(modal ? ModalityType.APPLICATION_MODAL
1043 : ModalityType.MODELESS);
1044 dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
1045 dialog.setVisible(true);
1050 public void showInternalDialog(JPanel mainPanel, String title,
1051 int yesNoCancelOption, int questionMessage, Icon icon,
1052 Object[] options, String initresponse)
1054 if (!isInteractiveMode())
1056 handleResponse(getMockResponse());
1059 // need to set these separately so we can set the title bar icon later
1060 this.setOptionType(yesNoCancelOption);
1061 this.setMessageType(questionMessage);
1063 this.setInitialValue(initresponse);
1064 this.setOptions(options);
1065 this.setMessage(mainPanel);
1067 ourOptions = Arrays.asList(options);
1069 if (parentComponent != this
1070 && !(parentComponent == null && Desktop.instance == null))
1072 JInternalFrame jif = this.createInternalFrame(
1073 parentComponent != null ? parentComponent : Desktop.instance,
1075 jif.setFrameIcon(null);
1076 jif.addInternalFrameListener(new InternalFrameListener()
1079 public void internalFrameActivated(InternalFrameEvent arg0)
1084 public void internalFrameClosed(InternalFrameEvent arg0)
1086 JvOptionPane.this.internalDialogHandleResponse();
1090 public void internalFrameClosing(InternalFrameEvent arg0)
1095 public void internalFrameDeactivated(InternalFrameEvent arg0)
1100 public void internalFrameDeiconified(InternalFrameEvent arg0)
1105 public void internalFrameIconified(InternalFrameEvent arg0)
1110 public void internalFrameOpened(InternalFrameEvent arg0)
1114 jif.setVisible(true);
1120 JDialog dialog = this.createDialog(parentComponent, title);
1121 dialog.setIconImages(ChannelProperties.getIconList());
1122 dialog.setVisible(true); // blocking
1123 this.internalDialogHandleResponse();
1128 private void internalDialogHandleResponse()
1130 String responseString = (String) this.getValue();
1131 int response = ourOptions.indexOf(responseString);
1133 if (!Platform.isJS())
1140 handleResponse(response);
1145 * @Override public JvOptionPane setResponseHandler(Object response, Runnable
1146 * action) { callbacks.put(response, new Callable<Void>() {
1148 * @Override public Void call() { action.run(); return null; } }); return this;
1152 public JvOptionPane setResponseHandler(Object response,
1153 Callable<Void> action)
1155 callbacks.put(response, action);
1159 public ExecutorService getExecutor()
1161 if (executor == null)
1162 executor = Executors.newSingleThreadExecutor();
1166 public void setExecutor(ExecutorService es)
1171 public void setDialog(JDialog d)
1176 public JDialog getDialog()
1182 * showDialogOnTop will create a dialog that (attempts to) come to top of OS
1185 public static int showDialogOnTop(String label, String actionString,
1186 int JOPTIONPANE_OPTION, int JOPTIONPANE_MESSAGETYPE)
1188 return showDialogOnTop(null, label, actionString, JOPTIONPANE_OPTION,
1189 JOPTIONPANE_MESSAGETYPE);
1192 public static int showDialogOnTop(Component dialogParentComponent,
1193 String label, String actionString, int JOPTIONPANE_OPTION,
1194 int JOPTIONPANE_MESSAGETYPE)
1196 if (!isInteractiveMode())
1198 return (int) getMockResponse();
1200 // Ensure Jalview window is brought to front (primarily for Quit
1201 // confirmation window to be visible)
1203 // This method of raising the Jalview window is broken in java
1204 // jalviewDesktop.setVisible(true);
1205 // jalviewDesktop.toFront();
1207 // A better hack which works is to create a new JFrame parent with
1208 // setAlwaysOnTop(true)
1209 JFrame dialogParent = new JFrame();
1210 if (dialogParentComponent == null)
1212 dialogParent.setIconImages(ChannelProperties.getIconList());
1213 dialogParent.setAlwaysOnTop(true);
1216 int answer = JOptionPane.showConfirmDialog(
1217 dialogParentComponent == null ? dialogParent
1218 : dialogParentComponent,
1219 label, actionString, JOPTIONPANE_OPTION,
1220 JOPTIONPANE_MESSAGETYPE);
1222 if (dialogParentComponent == null)
1224 dialogParent.setAlwaysOnTop(false);
1225 dialogParent.dispose();
1231 public void showDialogOnTopAsync(String label, String actionString,
1232 int JOPTIONPANE_OPTION, int JOPTIONPANE_MESSAGETYPE, Icon icon,
1233 Object[] options, Object initialValue, boolean modal)
1235 JFrame frame = new JFrame();
1236 frame.setIconImages(ChannelProperties.getIconList());
1237 showDialogOnTopAsync(frame, label, actionString, JOPTIONPANE_OPTION,
1238 JOPTIONPANE_MESSAGETYPE, icon, options, initialValue, modal);
1241 public void showDialogOnTopAsync(JFrame dialogParent, Object label,
1242 String actionString, int JOPTIONPANE_OPTION,
1243 int JOPTIONPANE_MESSAGETYPE, Icon icon, Object[] options,
1244 Object initialValue, boolean modal)
1246 showDialogOnTopAsync(dialogParent, label, actionString,
1247 JOPTIONPANE_OPTION, JOPTIONPANE_MESSAGETYPE, icon, options,
1248 initialValue, modal, null);
1251 public void showDialogOnTopAsync(JFrame dialogParent, Object label,
1252 String actionString, int JOPTIONPANE_OPTION,
1253 int JOPTIONPANE_MESSAGETYPE, Icon icon, Object[] options,
1254 Object initialValue, boolean modal, JButton[] buttons)
1256 if (!isInteractiveMode())
1258 handleResponse(getMockResponse());
1261 // Ensure Jalview window is brought to front (primarily for Quit
1262 // confirmation window to be visible)
1264 // This method of raising the Jalview window is broken in java
1265 // jalviewDesktop.setVisible(true);
1266 // jalviewDesktop.toFront();
1268 // A better hack which works is to create a new JFrame parent with
1269 // setAlwaysOnTop(true)
1270 dialogParent.setAlwaysOnTop(true);
1271 parentComponent = dialogParent;
1273 showDialog(label, actionString, JOPTIONPANE_OPTION,
1274 JOPTIONPANE_MESSAGETYPE, icon, options, initialValue, modal,
1277 dialogParent.setAlwaysOnTop(false);
1278 dialogParent.dispose();
1282 * JalviewJS signals option selection by a property change event for the
1283 * option e.g. "OK". This methods responds to that by running the response
1284 * action that corresponds to that option.
1289 public void propertyChange(PropertyChangeEvent evt)
1291 Object newValue = evt.getNewValue();
1292 int ourOption = ourOptions.indexOf(newValue);
1295 handleResponse(ourOption);
1300 handleResponse(newValue);
1305 public void handleResponse(Object response)
1308 * this test is for NaN in Chrome
1310 if (response != null && !response.equals(response))
1314 Callable<Void> action = callbacks.get(response);
1319 getExecutor().submit(action).get();
1321 } catch (Exception e)
1323 e.printStackTrace();
1325 if (parentComponent != null)
1326 parentComponent.requestFocus();
1331 * Create a non-modal confirm dialog
1333 public JDialog createDialog(Component parentComponent, Object message,
1334 String title, int optionType, int messageType, Icon icon,
1335 Object[] options, Object initialValue, boolean modal)
1337 return createDialog(parentComponent, message, title, optionType,
1338 messageType, icon, options, initialValue, modal, null);
1341 public JDialog createDialog(Component parentComponent, Object message,
1342 String title, int optionType, int messageType, Icon icon,
1343 Object[] options, Object initialValue, boolean modal,
1346 if (!isInteractiveMode())
1348 handleResponse(getMockResponse());
1351 JButton[] optionsButtons = null;
1352 Object initialValueButton = null;
1353 JOptionPane joptionpane = new JOptionPane();
1354 // Make button options
1355 int[] buttonActions = { JOptionPane.YES_OPTION, JOptionPane.NO_OPTION,
1356 JOptionPane.CANCEL_OPTION };
1358 // we need the strings to make the buttons with actionEventListener
1359 if (options == null)
1361 ArrayList<String> options_default = new ArrayList<>();
1362 options_default.add(UIManager.getString("OptionPane.yesButtonText"));
1363 if (optionType == JOptionPane.YES_NO_OPTION
1364 || optionType == JOptionPane.YES_NO_CANCEL_OPTION)
1366 options_default.add(UIManager.getString("OptionPane.noButtonText"));
1368 if (optionType == JOptionPane.YES_NO_CANCEL_OPTION)
1371 .add(UIManager.getString("OptionPane.cancelButtonText"));
1373 options = options_default.toArray();
1375 if (!Platform.isJS()) // JalviewJS already uses callback, don't need to
1378 if (((optionType == JOptionPane.YES_OPTION
1379 || optionType == JOptionPane.NO_OPTION
1380 || optionType == JOptionPane.CANCEL_OPTION
1381 || optionType == JOptionPane.OK_OPTION
1382 || optionType == JOptionPane.DEFAULT_OPTION)
1383 && options.length < 1)
1384 || ((optionType == JOptionPane.YES_NO_OPTION
1385 || optionType == JOptionPane.OK_CANCEL_OPTION)
1386 && options.length < 2)
1387 || (optionType == JOptionPane.YES_NO_CANCEL_OPTION
1388 && options.length < 3))
1391 .debug("JvOptionPane: not enough options for dialog type");
1393 optionsButtons = new JButton[options.length];
1394 for (int i = 0; i < options.length && i < 3; i++)
1396 Object o = options[i];
1397 int buttonAction = buttonActions[i];
1398 Callable<Void> action = callbacks.get(buttonAction);
1400 if (buttons != null && buttons.length > i && buttons[i] != null)
1408 jb.setText((String) o);
1409 jb.addActionListener(new ActionListener()
1412 public void actionPerformed(ActionEvent e)
1414 joptionpane.setValue(buttonAction);
1416 getExecutor().submit(action);
1417 // joptionpane.transferFocusBackward();
1418 joptionpane.transferFocusBackward();
1419 joptionpane.setVisible(false);
1420 // put focus and raise parent window if possible, unless cancel
1422 boolean raiseParent = (parentComponent != null);
1423 if (buttonAction == JOptionPane.CANCEL_OPTION)
1424 raiseParent = false;
1425 if (optionType == JOptionPane.YES_NO_OPTION
1426 && buttonAction == JOptionPane.NO_OPTION)
1427 raiseParent = false;
1430 parentComponent.requestFocus();
1431 if (parentComponent instanceof JInternalFrame)
1433 JInternalFrame jif = (JInternalFrame) parentComponent;
1438 else if (parentComponent instanceof Window)
1440 Window w = (Window) parentComponent;
1445 joptionpane.setVisible(false);
1448 optionsButtons[i] = jb;
1449 if (o.equals(initialValue))
1450 initialValueButton = jb;
1453 joptionpane.setMessage(message);
1454 joptionpane.setMessageType(messageType);
1455 joptionpane.setOptionType(optionType);
1456 joptionpane.setIcon(icon);
1457 joptionpane.setOptions(Platform.isJS() ? options : optionsButtons);
1458 joptionpane.setInitialValue(
1459 Platform.isJS() ? initialValue : initialValueButton);
1461 JDialog dialog = joptionpane.createDialog(parentComponent, title);
1462 dialog.setIconImages(ChannelProperties.getIconList());
1463 dialog.setModalityType(
1464 modal ? ModalityType.APPLICATION_MODAL : ModalityType.MODELESS);
1465 dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
1471 * Utility to programmatically click a button on a JOptionPane (as a JFrame)
1473 * returns true if button was found
1475 public static boolean clickButton(JFrame frame, int buttonType)
1482 * This helper method makes the JInternalFrame wait until it is notified by an
1483 * InternalFrameClosing event. This method also adds the given JOptionPane to
1484 * the JInternalFrame and sizes it according to the JInternalFrame's preferred
1488 * The JInternalFrame to make modal.
1490 private static void startModal(JInternalFrame f)
1492 // We need to add an additional glasspane-like component directly
1493 // below the frame, which intercepts all mouse events that are not
1494 // directed at the frame itself.
1495 JPanel modalInterceptor = new JPanel();
1496 modalInterceptor.setOpaque(false);
1497 JLayeredPane lp = JLayeredPane.getLayeredPaneAbove(f);
1498 lp.setLayer(modalInterceptor, JLayeredPane.MODAL_LAYER.intValue());
1499 modalInterceptor.setBounds(0, 0, lp.getWidth(), lp.getHeight());
1500 modalInterceptor.addMouseListener(new MouseAdapter()
1503 modalInterceptor.addMouseMotionListener(new MouseMotionAdapter()
1506 lp.add(modalInterceptor);
1509 // We need to explicitly dispatch events when we are blocking the event
1511 EventQueue queue = Toolkit.getDefaultToolkit().getSystemEventQueue();
1514 while (!f.isClosed())
1516 if (EventQueue.isDispatchThread())
1518 // The getNextEventMethod() issues wait() when no
1519 // event is available, so we don't need do explicitly wait().
1520 AWTEvent ev = queue.getNextEvent();
1521 // This mimics EventQueue.dispatchEvent(). We can't use
1522 // EventQueue.dispatchEvent() directly, because it is
1523 // protected, unfortunately.
1524 if (ev instanceof ActiveEvent)
1525 ((ActiveEvent) ev).dispatch();
1526 else if (ev.getSource() instanceof Component)
1527 ((Component) ev.getSource()).dispatchEvent(ev);
1528 else if (ev.getSource() instanceof MenuComponent)
1529 ((MenuComponent) ev.getSource()).dispatchEvent(ev);
1530 // Other events are ignored as per spec in
1531 // EventQueue.dispatchEvent
1535 // Give other threads a chance to become active.
1539 } catch (InterruptedException ex)
1541 // If we get interrupted, then leave the modal state.
1544 // Clean up the modal interceptor.
1545 lp.remove(modalInterceptor);
1547 // Remove the internal frame from its parent, so it is no longer
1548 // lurking around and clogging memory.
1549 Container parent = f.getParent();
1555 public static JvOptionPane frameDialog(String message, String title,
1556 int messageType, String[] buttonsText, String defaultButton,
1557 Callable<Void>[] handlers, boolean modal)
1559 JFrame parent = new JFrame();
1560 JvOptionPane jvop = JvOptionPane.newOptionDialog();
1561 JButton[] buttons = new JButton[buttonsText.length];
1562 for (int i = 0; i < buttonsText.length; i++)
1564 buttons[i] = new JButton();
1565 buttons[i].setText(buttonsText[i]);
1566 Console.debug("DISABLING BUTTON " + buttons[i].getText());
1567 buttons[i].setEnabled(false);
1568 buttons[i].setVisible(false);
1571 int dialogType = -1;
1572 if (buttonsText.length == 1)
1574 dialogType = JOptionPane.OK_OPTION;
1576 else if (buttonsText.length == 2)
1578 dialogType = JOptionPane.YES_NO_OPTION;
1582 dialogType = JOptionPane.YES_NO_CANCEL_OPTION;
1584 jvop.setResponseHandler(JOptionPane.YES_OPTION, handlers[0]);
1585 if (dialogType == JOptionPane.YES_NO_OPTION
1586 || dialogType == JOptionPane.YES_NO_CANCEL_OPTION)
1588 jvop.setResponseHandler(JOptionPane.NO_OPTION, handlers[1]);
1590 if (dialogType == JOptionPane.YES_NO_CANCEL_OPTION)
1592 jvop.setResponseHandler(JOptionPane.CANCEL_OPTION, handlers[2]);
1595 final int dt = dialogType;
1596 jvop.getExecutor().execute(() -> {
1597 jvop.showDialog(message, title, dt, messageType, null, buttonsText,
1598 defaultButton, modal, buttons);