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.
24 import jalview.util.Platform;
25 import jalview.util.dialogrunner.DialogRunnerI;
27 import java.awt.Component;
28 import java.awt.HeadlessException;
29 import java.beans.PropertyChangeEvent;
30 import java.beans.PropertyChangeListener;
31 import java.util.Arrays;
32 import java.util.HashMap;
33 import java.util.List;
36 import javax.swing.Icon;
37 import javax.swing.JOptionPane;
38 import javax.swing.JPanel;
40 public class JvOptionPane extends JOptionPane implements DialogRunnerI,
41 PropertyChangeListener
43 private static final long serialVersionUID = -3019167117756785229L;
45 private static Object mockResponse = JvOptionPane.CANCEL_OPTION;
47 private static boolean interactiveMode = true;
49 private Component parentComponent;
51 private Map<Object, Runnable> callbacks = new HashMap<>();
54 * JalviewJS reports user choice in the dialog as the selected
55 * option (text); this list allows conversion to index (int)
57 List<Object> ourOptions;
59 public JvOptionPane(final Component parent)
61 this.parentComponent = Platform.isJS() ? this : parent;
64 public static int showConfirmDialog(Component parentComponent,
65 Object message) throws HeadlessException
67 // only called by test
68 return isInteractiveMode()
69 ? JOptionPane.showConfirmDialog(parentComponent, message)
70 : (int) getMockResponse();
74 * Message, title, optionType
76 * @param parentComponent
81 * @throws HeadlessException
83 public static int showConfirmDialog(Component parentComponent,
84 Object message, String title, int optionType)
85 throws HeadlessException
87 if (!isInteractiveMode())
89 return (int) getMockResponse();
93 case JvOptionPane.YES_NO_CANCEL_OPTION:
94 // FeatureRenderer amendFeatures ?? TODO ??
99 case JvOptionPane.YES_NO_OPTION:
100 // PromptUserConfig usage stats
101 // for now treated as "OK CANCEL"
103 case JvOptionPane.OK_CANCEL_OPTION:
104 // will fall back to simple HTML
105 return JOptionPane.showConfirmDialog(parentComponent, message, title,
111 * Adds a message type. Fallback is to just add it in the beginning.
113 * @param parentComponent
119 * @throws HeadlessException
121 public static int showConfirmDialog(Component parentComponent,
122 Object message, String title, int optionType, int messageType)
123 throws HeadlessException
125 // JalviewServicesChanged
126 // PromptUserConfig raiseDialog
127 return isInteractiveMode()
128 ? JOptionPane.showConfirmDialog(parentComponent, message, title,
129 optionType, messageType)
130 : (int) getMockResponse();
136 * @param parentComponent
143 * @throws HeadlessException
145 public static int showConfirmDialog(Component parentComponent,
146 Object message, String title, int optionType, int messageType,
147 Icon icon) throws HeadlessException
149 // JvOptionPaneTest only
150 return isInteractiveMode()
151 ? JOptionPane.showConfirmDialog(parentComponent, message, title,
152 optionType, messageType, icon)
153 : (int) getMockResponse();
157 * Internal version "OK"
159 * @param parentComponent
163 public static int showInternalConfirmDialog(Component parentComponent,
166 // JvOptionPaneTest only;
167 return isInteractiveMode() ? JOptionPane.showInternalConfirmDialog(
168 parentComponent, message) : (int) getMockResponse();
172 * Internal version -- changed to standard version for now
174 * @param parentComponent
180 public static int showInternalConfirmDialog(Component parentComponent,
181 String message, String title, int optionType)
183 if (!isInteractiveMode())
185 return (int) getMockResponse();
189 case JvOptionPane.YES_NO_CANCEL_OPTION:
190 // ColourMenuHelper.addMenuItmers.offerRemoval TODO
191 case JvOptionPane.YES_NO_OPTION:
192 // UserDefinedColoursSave -- relevant? TODO
195 case JvOptionPane.OK_CANCEL_OPTION:
197 // EditNameDialog --- uses panel for messsage TODO
199 // Desktop.inputURLMenuItem
201 return JOptionPane.showConfirmDialog(parentComponent, message, title,
208 * @param parentComponent
215 public static int showInternalConfirmDialog(Component parentComponent,
216 Object message, String title, int optionType, int messageType)
218 if (!isInteractiveMode())
220 return (int) getMockResponse();
224 case JvOptionPane.YES_NO_CANCEL_OPTION:
225 case JvOptionPane.YES_NO_OPTION:
226 // UserQuestionanaireCheck
230 case JvOptionPane.OK_CANCEL_OPTION:
231 // will fall back to simple HTML
232 return JOptionPane.showConfirmDialog(parentComponent, message, title,
233 optionType, messageType);
238 * adds icon; no longer internal
240 * @param parentComponent
248 public static int showInternalConfirmDialog(Component parentComponent,
249 Object message, String title, int optionType, int messageType,
252 if (!isInteractiveMode())
254 return (int) getMockResponse();
258 case JvOptionPane.YES_NO_CANCEL_OPTION:
259 case JvOptionPane.YES_NO_OPTION:
262 case JvOptionPane.OK_CANCEL_OPTION:
263 // Preferences editLink/newLink
264 return JOptionPane.showConfirmDialog(parentComponent, message, title,
265 optionType, messageType, icon);
271 * custom options full-featured
273 * @param parentComponent
280 * @param initialValue
282 * @throws HeadlessException
284 public static int showOptionDialog(Component parentComponent,
285 String message, String title, int optionType, int messageType,
286 Icon icon, Object[] options, Object initialValue)
287 throws HeadlessException
289 if (!isInteractiveMode())
291 return (int) getMockResponse();
297 // 1) AlignViewport for openLinkedAlignment
299 // Show a dialog with the option to open and link (cDNA <-> protein) as a
301 // alignment, either as a standalone alignment or in a split frame. Returns
302 // true if the new alignment was opened, false if not, because the user
303 // declined the offer.
305 // 2) UserDefinedColors warning about saving over a name already defined
307 return JOptionPane.showOptionDialog(parentComponent, message, title,
308 optionType, messageType, icon, options, initialValue);
315 * @throws HeadlessException
317 public static void showMessageDialog(Component parentComponent,
318 String message) throws HeadlessException
320 if (!isInteractiveMode())
322 outputMessage(message);
328 JOptionPane.showMessageDialog(parentComponent, message);
332 * OK with message, title, and type
334 * @param parentComponent
338 * @throws HeadlessException
340 public static void showMessageDialog(Component parentComponent,
341 String message, String title, int messageType)
342 throws HeadlessException
344 // 30 implementations -- all just fine.
346 if (!isInteractiveMode())
348 outputMessage(message);
352 JOptionPane.showMessageDialog(parentComponent,
353 getPrefix(messageType) + message, title, messageType);
357 * adds title and icon
359 * @param parentComponent
364 * @throws HeadlessException
366 public static void showMessageDialog(Component parentComponent,
367 String message, String title, int messageType, Icon icon)
368 throws HeadlessException
373 if (!isInteractiveMode())
375 outputMessage(message);
379 JOptionPane.showMessageDialog(parentComponent, message, title,
387 public static void showInternalMessageDialog(Component parentComponent,
391 // WsPreferences only
393 if (!isInteractiveMode())
395 outputMessage(message);
399 JOptionPane.showMessageDialog(parentComponent, message);
404 * Adds title and messageType
406 * @param parentComponent
411 public static void showInternalMessageDialog(Component parentComponent,
412 String message, String title, int messageType)
417 if (!isInteractiveMode())
419 outputMessage(message);
423 JOptionPane.showMessageDialog(parentComponent,
424 getPrefix(messageType) + message, title, messageType);
429 * @param parentComponent
435 public static void showInternalMessageDialog(Component parentComponent,
436 Object message, String title, int messageType, Icon icon)
441 if (!isInteractiveMode())
443 outputMessage(message);
447 JOptionPane.showMessageDialog(parentComponent, message, title,
455 * @throws HeadlessException
457 public static String showInputDialog(Object message)
458 throws HeadlessException
462 if (!isInteractiveMode())
464 return getMockResponse().toString();
467 return JOptionPane.showInputDialog(message);
471 * adds inital selection value
474 * @param initialSelectionValue
477 public static String showInputDialog(String message,
478 String initialSelectionValue)
480 if (!isInteractiveMode())
482 return getMockResponse().toString();
485 // AnnotationPanel character option
487 return JOptionPane.showInputDialog(message, initialSelectionValue);
491 * adds inital selection value
494 * @param initialSelectionValue
497 public static String showInputDialog(Object message,
498 Object initialSelectionValue)
500 if (!isInteractiveMode())
502 return getMockResponse().toString();
505 // AnnotationPanel character option
507 return JOptionPane.showInputDialog(message, initialSelectionValue);
512 * @param parentComponent
515 * @throws HeadlessException
517 public static String showInputDialog(Component parentComponent,
518 String message) throws HeadlessException
522 return isInteractiveMode()
523 ? JOptionPane.showInputDialog(parentComponent, message)
524 : getMockResponse().toString();
528 * input with initial selection
530 * @param parentComponent
532 * @param initialSelectionValue
535 public static String showInputDialog(Component parentComponent,
536 String message, String initialSelectionValue)
541 return isInteractiveMode()
542 ? JOptionPane.showInputDialog(parentComponent, message,
543 initialSelectionValue)
544 : getMockResponse().toString();
549 * input with initial selection
551 * @param parentComponent
553 * @param initialSelectionValue
556 public static String showInputDialog(Component parentComponent,
557 Object message, Object initialSelectionValue)
562 return isInteractiveMode()
563 ? JOptionPane.showInputDialog(parentComponent, message,
564 initialSelectionValue)
565 : getMockResponse().toString();
570 * @param parentComponent
575 * @throws HeadlessException
577 public static String showInputDialog(Component parentComponent,
578 String message, String title, int messageType)
579 throws HeadlessException
584 return isInteractiveMode() ? JOptionPane
585 .showInputDialog(parentComponent, message, title, messageType)
586 : getMockResponse().toString();
590 * Customized input option
592 * @param parentComponent
597 * @param selectionValues
598 * @param initialSelectionValue
600 * @throws HeadlessException
602 public static Object showInputDialog(Component parentComponent,
603 Object message, String title, int messageType, Icon icon,
604 Object[] selectionValues, Object initialSelectionValue)
605 throws HeadlessException
610 return isInteractiveMode()
611 ? JOptionPane.showInputDialog(parentComponent, message, title,
612 messageType, icon, selectionValues,
613 initialSelectionValue)
614 : getMockResponse().toString();
622 * @param parentComponent
626 public static String showInternalInputDialog(Component parentComponent,
631 return isInteractiveMode()
632 ? JOptionPane.showInternalInputDialog(parentComponent, message)
633 : getMockResponse().toString();
638 * internal with title and messageType
640 * @param parentComponent
646 public static String showInternalInputDialog(Component parentComponent,
647 String message, String title, int messageType)
650 // AlignFrame tabbedPane_mousePressed
652 return isInteractiveMode()
653 ? JOptionPane.showInternalInputDialog(parentComponent,
654 getPrefix(messageType) + message, title, messageType)
655 : getMockResponse().toString();
659 * customized internal
661 * @param parentComponent
666 * @param selectionValues
667 * @param initialSelectionValue
670 public static Object showInternalInputDialog(Component parentComponent,
671 String message, String title, int messageType, Icon icon,
672 Object[] selectionValues, Object initialSelectionValue)
676 return isInteractiveMode()
677 ? JOptionPane.showInternalInputDialog(parentComponent, message,
678 title, messageType, icon, selectionValues,
679 initialSelectionValue)
680 : getMockResponse().toString();
684 ///////////// end of options ///////////////
687 private static void outputMessage(Object message)
689 System.out.println(">>> JOption Message : " + message.toString());
692 public static Object getMockResponse()
697 public static void setMockResponse(Object mockOption)
699 JvOptionPane.mockResponse = mockOption;
702 public static void resetMock()
704 setMockResponse(JvOptionPane.CANCEL_OPTION);
705 setInteractiveMode(true);
708 public static boolean isInteractiveMode()
710 return interactiveMode;
713 public static void setInteractiveMode(boolean interactive)
715 JvOptionPane.interactiveMode = interactive;
718 private static String getPrefix(int messageType)
727 case JvOptionPane.WARNING_MESSAGE:
728 prefix = "WARNING! ";
730 case JvOptionPane.ERROR_MESSAGE:
741 * create a new option dialog that can be used to register responses - along
742 * lines of showOptionDialog
747 * @param defaultOption
748 * @param plainMessage
754 public static JvOptionPane newOptionDialog(Component parentComponent)
756 return new JvOptionPane(parentComponent);
759 public void showDialog(
760 String message, String title, int optionType, int messageType,
761 Icon icon, Object[] options, Object initialValue)
764 if (!isInteractiveMode())
766 handleResponse(getMockResponse());
772 // 1) AlignViewport for openLinkedAlignment
774 // Show a dialog with the option to open and link (cDNA <-> protein) as a
776 // alignment, either as a standalone alignment or in a split frame. Returns
777 // true if the new alignment was opened, false if not, because the user
778 // declined the offer.
780 // 2) UserDefinedColors warning about saving over a name already defined
783 ourOptions = Arrays.asList(options);
785 int response = JOptionPane.showOptionDialog(parentComponent, message, title,
786 optionType, messageType, icon, options, initialValue);
789 * In Java, the response is returned to this thread and handled here;
790 * (for Javascript, see propertyChange)
792 if (!Platform.isJS())
799 handleResponse(response);
803 public void showInternalDialog(JPanel mainPanel, String title,
804 int yesNoCancelOption, int questionMessage, Icon icon,
805 Object[] options, String initresponse)
807 if (!isInteractiveMode())
809 handleResponse(getMockResponse());
812 ourOptions = Arrays.asList(options);
814 if (parentComponent != this)
816 response = JOptionPane.showInternalOptionDialog(parentComponent, mainPanel,
817 title, yesNoCancelOption, questionMessage, icon, options,
822 response = JOptionPane.showOptionDialog(parentComponent, mainPanel, title,
823 yesNoCancelOption, questionMessage, icon, options,
826 if (!Platform.isJS())
833 handleResponse(response);
838 public JvOptionPane setResponseHandler(Object response, Runnable action)
840 callbacks.put(response, action);
845 * JalviewJS signals option selection by a property change event
846 * for the option e.g. "OK". This methods responds to that by
847 * running the response action that corresponds to that option.
852 public void propertyChange(PropertyChangeEvent evt)
854 Object newValue = evt.getNewValue();
855 int ourOption = ourOptions.indexOf(newValue);
858 handleResponse(ourOption);
863 handleResponse(newValue);
868 public void handleResponse(Object response)
871 * this test is for NaN in Chrome
873 if (response != null && !response.equals(response))
877 Runnable action = callbacks.get(response);