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 java.awt.Component;
25 import java.awt.HeadlessException;
26 import java.beans.PropertyChangeEvent;
27 import java.beans.PropertyChangeListener;
28 import java.util.Arrays;
29 import java.util.HashMap;
30 import java.util.List;
33 import javax.swing.Icon;
34 import javax.swing.JOptionPane;
35 import javax.swing.JPanel;
37 import jalview.util.Platform;
38 import jalview.util.dialogrunner.DialogRunnerI;
40 public class JvOptionPane extends JOptionPane
41 implements DialogRunnerI, 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()
168 ? JOptionPane.showInternalConfirmDialog(parentComponent,
170 : (int) getMockResponse();
174 * Internal version -- changed to standard version for now
176 * @param parentComponent
182 public static int showInternalConfirmDialog(Component parentComponent,
183 String message, String title, int optionType)
185 if (!isInteractiveMode())
187 return (int) getMockResponse();
191 case JvOptionPane.YES_NO_CANCEL_OPTION:
192 // ColourMenuHelper.addMenuItmers.offerRemoval TODO
193 case JvOptionPane.YES_NO_OPTION:
194 // UserDefinedColoursSave -- relevant? TODO
197 case JvOptionPane.OK_CANCEL_OPTION:
199 // EditNameDialog --- uses panel for messsage TODO
201 // Desktop.inputURLMenuItem
203 return JOptionPane.showConfirmDialog(parentComponent, message, title,
210 * @param parentComponent
217 public static int showInternalConfirmDialog(Component parentComponent,
218 Object message, String title, int optionType, int messageType)
220 if (!isInteractiveMode())
222 return (int) getMockResponse();
226 case JvOptionPane.YES_NO_CANCEL_OPTION:
227 case JvOptionPane.YES_NO_OPTION:
228 // UserQuestionanaireCheck
232 case JvOptionPane.OK_CANCEL_OPTION:
233 // will fall back to simple HTML
234 return JOptionPane.showConfirmDialog(parentComponent, message, title,
235 optionType, messageType);
240 * adds icon; no longer internal
242 * @param parentComponent
250 public static int showInternalConfirmDialog(Component parentComponent,
251 Object message, String title, int optionType, int messageType,
254 if (!isInteractiveMode())
256 return (int) getMockResponse();
260 case JvOptionPane.YES_NO_CANCEL_OPTION:
261 case JvOptionPane.YES_NO_OPTION:
264 case JvOptionPane.OK_CANCEL_OPTION:
265 // Preferences editLink/newLink
266 return JOptionPane.showConfirmDialog(parentComponent, message, title,
267 optionType, messageType, icon);
273 * custom options full-featured
275 * @param parentComponent
282 * @param initialValue
284 * @throws HeadlessException
286 public static int showOptionDialog(Component parentComponent,
287 String message, String title, int optionType, int messageType,
288 Icon icon, Object[] options, Object initialValue)
289 throws HeadlessException
291 if (!isInteractiveMode())
293 return (int) getMockResponse();
299 // 1) AlignViewport for openLinkedAlignment
301 // Show a dialog with the option to open and link (cDNA <-> protein) as a
303 // alignment, either as a standalone alignment or in a split frame. Returns
304 // true if the new alignment was opened, false if not, because the user
305 // declined the offer.
307 // 2) UserDefinedColors warning about saving over a name already defined
309 return JOptionPane.showOptionDialog(parentComponent, message, title,
310 optionType, messageType, icon, options, initialValue);
317 * @throws HeadlessException
319 public static void showMessageDialog(Component parentComponent,
320 String message) throws HeadlessException
322 if (!isInteractiveMode())
324 outputMessage(message);
330 JOptionPane.showMessageDialog(parentComponent, message);
334 * OK with message, title, and type
336 * @param parentComponent
340 * @throws HeadlessException
342 public static void showMessageDialog(Component parentComponent,
343 String message, String title, int messageType)
344 throws HeadlessException
346 // 30 implementations -- all just fine.
348 if (!isInteractiveMode())
350 outputMessage(message);
354 JOptionPane.showMessageDialog(parentComponent,
355 getPrefix(messageType) + message, title, messageType);
359 * adds title and icon
361 * @param parentComponent
366 * @throws HeadlessException
368 public static void showMessageDialog(Component parentComponent,
369 String message, String title, int messageType, Icon icon)
370 throws HeadlessException
375 if (!isInteractiveMode())
377 outputMessage(message);
381 JOptionPane.showMessageDialog(parentComponent, message, title,
389 public static void showInternalMessageDialog(Component parentComponent,
393 // WsPreferences only
395 if (!isInteractiveMode())
397 outputMessage(message);
401 JOptionPane.showMessageDialog(parentComponent, message);
405 * Adds title and messageType
407 * @param parentComponent
412 public static void showInternalMessageDialog(Component parentComponent,
413 String message, String title, int messageType)
418 if (!isInteractiveMode())
420 outputMessage(message);
424 JOptionPane.showMessageDialog(parentComponent,
425 getPrefix(messageType) + message, title, messageType);
430 * @param parentComponent
436 public static void showInternalMessageDialog(Component parentComponent,
437 Object message, String title, int messageType, Icon icon)
442 if (!isInteractiveMode())
444 outputMessage(message);
448 JOptionPane.showMessageDialog(parentComponent, message, title,
456 * @throws HeadlessException
458 public static String showInputDialog(Object message)
459 throws HeadlessException
463 if (!isInteractiveMode())
465 return getMockResponse().toString();
468 return JOptionPane.showInputDialog(message);
472 * adds inital selection value
475 * @param initialSelectionValue
478 public static String showInputDialog(String message,
479 String initialSelectionValue)
481 if (!isInteractiveMode())
483 return getMockResponse().toString();
486 // AnnotationPanel character option
488 return JOptionPane.showInputDialog(message, initialSelectionValue);
492 * adds inital selection value
495 * @param initialSelectionValue
498 public static String showInputDialog(Object message,
499 Object initialSelectionValue)
501 if (!isInteractiveMode())
503 return getMockResponse().toString();
506 // AnnotationPanel character option
508 return JOptionPane.showInputDialog(message, initialSelectionValue);
514 * @param parentComponent
517 * @throws HeadlessException
519 public static String showInputDialog(Component parentComponent,
520 String message) throws HeadlessException
524 return isInteractiveMode()
525 ? JOptionPane.showInputDialog(parentComponent, message)
526 : getMockResponse().toString();
530 * input with initial selection
532 * @param parentComponent
534 * @param initialSelectionValue
537 public static String showInputDialog(Component parentComponent,
538 String message, String initialSelectionValue)
543 return isInteractiveMode()
544 ? JOptionPane.showInputDialog(parentComponent, message,
545 initialSelectionValue)
546 : getMockResponse().toString();
550 * input with initial selection
552 * @param parentComponent
554 * @param initialSelectionValue
557 public static String showInputDialog(Component parentComponent,
558 Object message, Object initialSelectionValue)
563 return isInteractiveMode()
564 ? JOptionPane.showInputDialog(parentComponent, message,
565 initialSelectionValue)
566 : getMockResponse().toString();
571 * @param parentComponent
576 * @throws HeadlessException
578 public static String showInputDialog(Component parentComponent,
579 String message, String title, int messageType)
580 throws HeadlessException
585 return isInteractiveMode()
586 ? JOptionPane.showInputDialog(parentComponent, message, title,
588 : getMockResponse().toString();
592 * Customized input option
594 * @param parentComponent
599 * @param selectionValues
600 * @param initialSelectionValue
602 * @throws HeadlessException
604 public static Object showInputDialog(Component parentComponent,
605 Object message, String title, int messageType, Icon icon,
606 Object[] selectionValues, Object initialSelectionValue)
607 throws HeadlessException
612 return isInteractiveMode()
613 ? JOptionPane.showInputDialog(parentComponent, message, title,
614 messageType, icon, selectionValues,
615 initialSelectionValue)
616 : getMockResponse().toString();
622 * @param parentComponent
626 public static String showInternalInputDialog(Component parentComponent,
631 return isInteractiveMode()
632 ? JOptionPane.showInternalInputDialog(parentComponent, message)
633 : getMockResponse().toString();
637 * internal with title and messageType
639 * @param parentComponent
645 public static String showInternalInputDialog(Component parentComponent,
646 String message, String title, int messageType)
649 // AlignFrame tabbedPane_mousePressed
651 return isInteractiveMode()
652 ? JOptionPane.showInternalInputDialog(parentComponent,
653 getPrefix(messageType) + message, title, messageType)
654 : getMockResponse().toString();
658 * customized internal
660 * @param parentComponent
665 * @param selectionValues
666 * @param initialSelectionValue
669 public static Object showInternalInputDialog(Component parentComponent,
670 String message, String title, int messageType, Icon icon,
671 Object[] selectionValues, Object initialSelectionValue)
675 return isInteractiveMode()
676 ? JOptionPane.showInternalInputDialog(parentComponent, message,
677 title, messageType, icon, selectionValues,
678 initialSelectionValue)
679 : getMockResponse().toString();
682 ///////////// end of options ///////////////
684 private static void outputMessage(Object message)
686 System.out.println(">>> JOption Message : " + message.toString());
689 public static Object getMockResponse()
694 public static void setMockResponse(Object mockOption)
696 JvOptionPane.mockResponse = mockOption;
699 public static void resetMock()
701 setMockResponse(JvOptionPane.CANCEL_OPTION);
702 setInteractiveMode(true);
705 public static boolean isInteractiveMode()
707 return interactiveMode;
710 public static void setInteractiveMode(boolean interactive)
712 JvOptionPane.interactiveMode = interactive;
715 private static String getPrefix(int messageType)
724 case JvOptionPane.WARNING_MESSAGE:
725 prefix = "WARNING! ";
727 case JvOptionPane.ERROR_MESSAGE:
738 * create a new option dialog that can be used to register responses - along
739 * lines of showOptionDialog
744 * @param defaultOption
745 * @param plainMessage
751 public static JvOptionPane newOptionDialog(Component parentComponent)
753 return new JvOptionPane(parentComponent);
756 public void showDialog(String message, String title, int optionType,
757 int messageType, Icon icon, Object[] options, Object initialValue)
760 if (!isInteractiveMode())
762 handleResponse(getMockResponse());
768 // 1) AlignViewport for openLinkedAlignment
770 // Show a dialog with the option to open and link (cDNA <-> protein) as a
772 // alignment, either as a standalone alignment or in a split frame. Returns
773 // true if the new alignment was opened, false if not, because the user
774 // declined the offer.
776 // 2) UserDefinedColors warning about saving over a name already defined
779 ourOptions = Arrays.asList(options);
781 int response = JOptionPane.showOptionDialog(parentComponent, message,
782 title, optionType, messageType, icon, options, initialValue);
785 * In Java, the response is returned to this thread and handled here;
786 * (for Javascript, see propertyChange)
788 if (!Platform.isJS())
795 handleResponse(response);
799 public void showInternalDialog(JPanel mainPanel, String title,
800 int yesNoCancelOption, int questionMessage, Icon icon,
801 Object[] options, String initresponse)
803 if (!isInteractiveMode())
805 handleResponse(getMockResponse());
808 ourOptions = Arrays.asList(options);
810 if (parentComponent != this)
812 response = JOptionPane.showInternalOptionDialog(parentComponent,
813 mainPanel, title, yesNoCancelOption, questionMessage, icon,
814 options, initresponse);
818 response = JOptionPane.showOptionDialog(parentComponent, mainPanel,
819 title, yesNoCancelOption, questionMessage, icon, options,
822 if (!Platform.isJS())
829 handleResponse(response);
834 public JvOptionPane setResponseHandler(Object response, Runnable action)
836 callbacks.put(response, action);
841 * JalviewJS signals option selection by a property change event for the
842 * option e.g. "OK". This methods responds to that by running the response
843 * action that corresponds to that option.
848 public void propertyChange(PropertyChangeEvent evt)
850 Object newValue = evt.getNewValue();
851 int ourOption = ourOptions.indexOf(newValue);
854 handleResponse(ourOption);
859 handleResponse(newValue);
864 public void handleResponse(Object response)
867 * this test is for NaN in Chrome
869 if (response != null && !response.equals(response))
873 Runnable action = callbacks.get(response);
877 parentComponent.requestFocus();