JAL-3048 add additional wrapper methods for JOptionPane to ensure JvOptionPane tests...
[jalview.git] / src / jalview / gui / JvOptionPane.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
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.
11  *  
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.
16  * 
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.
20  */
21
22 package jalview.gui;
23
24 import jalview.util.dialogrunner.DialogRunner;
25 import jalview.util.dialogrunner.DialogRunnerI;
26 import jalview.util.dialogrunner.RunResponse;
27
28 import java.awt.Component;
29 import java.awt.HeadlessException;
30 import java.beans.PropertyChangeEvent;
31 import java.beans.PropertyChangeListener;
32 import java.util.Arrays;
33 import java.util.List;
34
35 import javax.swing.Icon;
36 import javax.swing.JOptionPane;
37 import javax.swing.JPanel;
38
39 public class JvOptionPane extends JOptionPane
40         implements DialogRunnerI, PropertyChangeListener
41 {
42   // BH 2018 no changes needed here.
43
44   private static final long serialVersionUID = -3019167117756785229L;
45
46   private static Object mockResponse = JvOptionPane.CANCEL_OPTION;
47
48   private static boolean interactiveMode = true;
49
50   private Component parentComponent;
51
52   public JvOptionPane(final Component parentComponent)
53   {
54     
55     this.parentComponent = parentComponent;
56   }
57
58   public static int showConfirmDialog(Component parentComponent,
59           Object message) throws HeadlessException
60   {
61     // only called by test
62     return isInteractiveMode()
63             ? JOptionPane.showConfirmDialog(parentComponent, message)
64             : (int) getMockResponse();
65   }
66
67   /**
68    * Message, title, optionType
69    * 
70    * @param parentComponent
71    * @param message
72    * @param title
73    * @param optionType
74    * @return
75    * @throws HeadlessException
76    */
77   public static int showConfirmDialog(Component parentComponent,
78           Object message, String title, int optionType)
79           throws HeadlessException
80   {
81     if (!isInteractiveMode())
82     {
83       return (int) getMockResponse();
84     }
85     switch (optionType)
86     {
87     case JvOptionPane.YES_NO_CANCEL_OPTION:
88       // FeatureRenderer amendFeatures  ?? TODO ??
89       // Chimera close
90       // PromptUserConfig
91       // $FALL-THROUGH$
92     default:
93     case JvOptionPane.YES_NO_OPTION:
94       // PromptUserConfig usage stats
95       // for now treated as "OK CANCEL"
96       // $FALL-THROUGH$
97     case JvOptionPane.OK_CANCEL_OPTION:
98       // will fall back to simple HTML
99       return JOptionPane.showConfirmDialog(parentComponent, message, title,
100               optionType);
101     }
102   }
103
104   /**
105    * Adds a message type. Fallback is to just add it in the beginning.
106    * 
107    * @param parentComponent
108    * @param message
109    * @param title
110    * @param optionType
111    * @param messageType
112    * @return
113    * @throws HeadlessException
114    */
115   public static int showConfirmDialog(Component parentComponent,
116           Object message, String title, int optionType, int messageType)
117           throws HeadlessException
118   {
119     // JalviewServicesChanged
120     // PromptUserConfig raiseDialog
121     return isInteractiveMode()
122             ? JOptionPane.showConfirmDialog(parentComponent, message, title,
123                     optionType, messageType)
124             : (int) getMockResponse();
125   }
126
127   /**
128    * Adds an icon
129    * 
130    * @param parentComponent
131    * @param message
132    * @param title
133    * @param optionType
134    * @param messageType
135    * @param icon
136    * @return
137    * @throws HeadlessException
138    */
139   public static int showConfirmDialog(Component parentComponent,
140           Object message, String title, int optionType, int messageType,
141           Icon icon) throws HeadlessException
142   {
143     // JvOptionPaneTest only
144     return isInteractiveMode()
145             ? JOptionPane.showConfirmDialog(parentComponent, message, title,
146                     optionType, messageType, icon)
147             : (int) getMockResponse();
148   }
149
150   /**
151    * Internal version "OK"
152    * 
153    * @param parentComponent
154    * @param message
155    * @return
156    */
157   public static int showInternalConfirmDialog(Component parentComponent,
158           Object message)
159   {
160     // JvOptionPaneTest only;
161     return isInteractiveMode() ? JOptionPane.showInternalConfirmDialog(
162             parentComponent, message) : (int) getMockResponse();
163   }
164
165   /**
166    * Internal version -- changed to standard version for now
167    * 
168    * @param parentComponent
169    * @param message
170    * @param title
171    * @param optionType
172    * @return
173    */
174   public static int showInternalConfirmDialog(Component parentComponent,
175           String message, String title, int optionType)
176   {
177     if (!isInteractiveMode())
178     {
179       return (int) getMockResponse();
180     }
181     switch (optionType)
182     {
183     case JvOptionPane.YES_NO_CANCEL_OPTION:
184       // ColourMenuHelper.addMenuItmers.offerRemoval TODO
185     case JvOptionPane.YES_NO_OPTION:
186       // UserDefinedColoursSave -- relevant? TODO
187       // $FALL-THROUGH$
188     default:
189     case JvOptionPane.OK_CANCEL_OPTION:
190
191       // EditNameDialog --- uses panel for messsage TODO
192
193       // Desktop.inputURLMenuItem
194       // WsPreferenses
195       return JOptionPane.showConfirmDialog(parentComponent, message, title,
196               optionType);
197     }
198   }
199
200   /**
201    * 
202    * @param parentComponent
203    * @param message
204    * @param title
205    * @param optionType
206    * @param messageType
207    * @return
208    */
209   public static int showInternalConfirmDialog(Component parentComponent,
210           Object message, String title, int optionType, int messageType)
211   {
212     if (!isInteractiveMode())
213     {
214       return (int) getMockResponse();
215     }
216     switch (optionType)
217     {
218     case JvOptionPane.YES_NO_CANCEL_OPTION:
219     case JvOptionPane.YES_NO_OPTION:
220       // UserQuestionanaireCheck
221       // VamsasApplication
222       // $FALL-THROUGH$
223     default:
224     case JvOptionPane.OK_CANCEL_OPTION:
225       // will fall back to simple HTML
226       return JOptionPane.showConfirmDialog(parentComponent, message, title,
227               optionType, messageType);
228     }
229   }
230
231   /**
232    * adds icon; no longer internal
233    * 
234    * @param parentComponent
235    * @param message
236    * @param title
237    * @param optionType
238    * @param messageType
239    * @param icon
240    * @return
241    */
242   public static int showInternalConfirmDialog(Component parentComponent,
243           Object message, String title, int optionType, int messageType,
244           Icon icon)
245   {
246     if (!isInteractiveMode())
247     {
248       return (int) getMockResponse();
249     }
250     switch (optionType)
251     {
252     case JvOptionPane.YES_NO_CANCEL_OPTION:
253     case JvOptionPane.YES_NO_OPTION:
254       //$FALL-THROUGH$
255     default:
256     case JvOptionPane.OK_CANCEL_OPTION:
257       // Preferences editLink/newLink
258       return JOptionPane.showConfirmDialog(parentComponent, message, title,
259               optionType, messageType, icon);
260     }
261
262   }
263
264   /**
265    * custom options full-featured
266    * 
267    * @param parentComponent
268    * @param message
269    * @param title
270    * @param optionType
271    * @param messageType
272    * @param icon
273    * @param options
274    * @param initialValue
275    * @return
276    * @throws HeadlessException
277    */
278   public static int showOptionDialog(Component parentComponent,
279           String message, String title, int optionType, int messageType,
280           Icon icon, Object[] options, Object initialValue)
281           throws HeadlessException
282   {
283     if (!isInteractiveMode())
284     {
285       return (int) getMockResponse();
286     }
287     // two uses:
288     //
289     // TODO
290     //
291     // 1) AlignViewport for openLinkedAlignment
292     //
293     // Show a dialog with the option to open and link (cDNA <-> protein) as a
294     // new
295     // alignment, either as a standalone alignment or in a split frame. Returns
296     // true if the new alignment was opened, false if not, because the user
297     // declined the offer.
298     //
299     // 2) UserDefinedColors warning about saving over a name already defined
300     //
301     return JOptionPane.showOptionDialog(parentComponent, message, title,
302             optionType, messageType, icon, options, initialValue);
303   }
304
305   /**
306    * Just an OK message
307    * 
308    * @param message
309    * @throws HeadlessException
310    */
311   public static void showMessageDialog(Component parentComponent,
312           String message) throws HeadlessException
313   {
314     if (!isInteractiveMode())
315     {
316       outputMessage(message);
317       return;
318     }
319
320     // test class only
321
322     JOptionPane.showMessageDialog(parentComponent, message);
323   }
324
325   /**
326    * OK with message, title, and type
327    * 
328    * @param parentComponent
329    * @param message
330    * @param title
331    * @param messageType
332    * @throws HeadlessException
333    */
334   public static void showMessageDialog(Component parentComponent,
335           String message, String title, int messageType)
336           throws HeadlessException
337   {
338     // 30 implementations -- all just fine.
339
340     if (!isInteractiveMode())
341     {
342       outputMessage(message);
343       return;
344     }
345
346     JOptionPane.showMessageDialog(parentComponent,
347             getPrefix(messageType) + message, title, messageType);
348   }
349
350   /**
351    * adds title and icon
352    * 
353    * @param parentComponent
354    * @param message
355    * @param title
356    * @param messageType
357    * @param icon
358    * @throws HeadlessException
359    */
360   public static void showMessageDialog(Component parentComponent,
361           String message, String title, int messageType, Icon icon)
362           throws HeadlessException
363   {
364
365     // test only
366
367     if (!isInteractiveMode())
368     {
369       outputMessage(message);
370       return;
371     }
372
373     JOptionPane.showMessageDialog(parentComponent, message, title,
374             messageType, icon);
375   }
376
377   /**
378    * was internal
379    * 
380    */
381   public static void showInternalMessageDialog(Component parentComponent,
382           Object message)
383   {
384
385     // WsPreferences only
386
387     if (!isInteractiveMode())
388     {
389       outputMessage(message);
390       return;
391     }
392
393     JOptionPane.showMessageDialog(parentComponent, message);
394   }
395
396
397   /**
398    * Adds title and messageType
399    * 
400    * @param parentComponent
401    * @param message
402    * @param title
403    * @param messageType
404    */
405   public static void showInternalMessageDialog(Component parentComponent,
406           String message, String title, int messageType)
407   {
408
409     // 41 references
410
411     if (!isInteractiveMode())
412     {
413       outputMessage(message);
414       return;
415     }
416
417     JOptionPane.showMessageDialog(parentComponent,
418             getPrefix(messageType) + message, title, messageType);
419   }
420
421   /**
422    * 
423    * @param parentComponent
424    * @param message
425    * @param title
426    * @param messageType
427    * @param icon
428    */
429   public static void showInternalMessageDialog(Component parentComponent,
430           Object message, String title, int messageType, Icon icon)
431   {
432
433     // test only
434
435     if (!isInteractiveMode())
436     {
437       outputMessage(message);
438       return;
439     }
440
441     JOptionPane.showMessageDialog(parentComponent, message, title,
442             messageType, icon);
443   }
444
445   /**
446    * 
447    * @param message
448    * @return
449    * @throws HeadlessException
450    */
451   public static String showInputDialog(Object message)
452           throws HeadlessException
453   {
454     // test only
455
456     if (!isInteractiveMode())
457     {
458       return getMockResponse().toString();
459     }
460
461     return JOptionPane.showInputDialog(message);
462   }
463
464   /**
465    * adds inital selection value
466    * 
467    * @param message
468    * @param initialSelectionValue
469    * @return
470    */
471   public static String showInputDialog(String message,
472           String initialSelectionValue)
473   {
474     if (!isInteractiveMode())
475     {
476       return getMockResponse().toString();
477     }
478
479     // AnnotationPanel character option
480
481     return JOptionPane.showInputDialog(message, initialSelectionValue);
482   }
483
484   /**
485    * adds inital selection value
486    * 
487    * @param message
488    * @param initialSelectionValue
489    * @return
490    */
491   public static String showInputDialog(Object message,
492           Object initialSelectionValue)
493   {
494     if (!isInteractiveMode())
495     {
496       return getMockResponse().toString();
497     }
498
499     // AnnotationPanel character option
500
501     return JOptionPane.showInputDialog(message, initialSelectionValue);
502   }
503   /**
504    * centered on parent
505    * 
506    * @param parentComponent
507    * @param message
508    * @return
509    * @throws HeadlessException
510    */
511   public static String showInputDialog(Component parentComponent,
512           String message) throws HeadlessException
513   {
514     // test only
515
516     return isInteractiveMode()
517             ? JOptionPane.showInputDialog(parentComponent, message)
518             : getMockResponse().toString();
519   }
520
521   /**
522    * input with initial selection
523    * 
524    * @param parentComponent
525    * @param message
526    * @param initialSelectionValue
527    * @return
528    */
529   public static String showInputDialog(Component parentComponent,
530           String message, String initialSelectionValue)
531   {
532     
533     // AnnotationPanel
534     
535     return isInteractiveMode()
536             ? JOptionPane.showInputDialog(parentComponent, message,
537                     initialSelectionValue)
538             : getMockResponse().toString();
539   }
540   
541
542   /**
543    * input with initial selection
544    * 
545    * @param parentComponent
546    * @param message
547    * @param initialSelectionValue
548    * @return
549    */
550   public static String showInputDialog(Component parentComponent,
551           Object message, Object initialSelectionValue)
552   {
553     
554     // AnnotationPanel
555     
556     return isInteractiveMode()
557             ? JOptionPane.showInputDialog(parentComponent, message,
558                     initialSelectionValue)
559             : getMockResponse().toString();
560   }
561
562   /**
563    * 
564    * @param parentComponent
565    * @param message
566    * @param title
567    * @param messageType
568    * @return
569    * @throws HeadlessException
570    */
571   public static String showInputDialog(Component parentComponent,
572           String message, String title, int messageType)
573           throws HeadlessException
574   {
575
576     // test only
577
578     return isInteractiveMode() ? JOptionPane
579             .showInputDialog(parentComponent, message, title, messageType)
580             : getMockResponse().toString();
581   }
582
583   /**
584    * Customized input option 
585    * 
586    * @param parentComponent
587    * @param message
588    * @param title
589    * @param messageType
590    * @param icon
591    * @param selectionValues
592    * @param initialSelectionValue
593    * @return
594    * @throws HeadlessException
595    */
596   public static Object showInputDialog(Component parentComponent,
597           Object message, String title, int messageType, Icon icon,
598           Object[] selectionValues, Object initialSelectionValue)
599           throws HeadlessException
600   {
601     
602     // test only
603     
604     return isInteractiveMode()
605             ? JOptionPane.showInputDialog(parentComponent, message, title,
606                     messageType, icon, selectionValues,
607                     initialSelectionValue)
608             : getMockResponse().toString();
609   }
610
611   
612   
613   /**
614    * internal version
615    * 
616    * @param parentComponent
617    * @param message
618    * @return
619    */
620   public static String showInternalInputDialog(Component parentComponent,
621           String message)
622   {
623     // test only
624     
625     return isInteractiveMode()
626             ? JOptionPane.showInternalInputDialog(parentComponent, message)
627             : getMockResponse().toString();
628   }
629
630   
631   /**
632    * internal with title and messageType
633    * 
634    * @param parentComponent
635    * @param message
636    * @param title
637    * @param messageType
638    * @return
639    */
640   public static String showInternalInputDialog(Component parentComponent,
641           String message, String title, int messageType)
642   {
643     
644     // AlignFrame tabbedPane_mousePressed
645     
646     return isInteractiveMode()
647             ? JOptionPane.showInternalInputDialog(parentComponent,
648                     getPrefix(messageType) + message, title, messageType)
649             : getMockResponse().toString();
650   }
651
652   /**
653    * customized internal
654    * 
655    * @param parentComponent
656    * @param message
657    * @param title
658    * @param messageType
659    * @param icon
660    * @param selectionValues
661    * @param initialSelectionValue
662    * @return
663    */
664   public static Object showInternalInputDialog(Component parentComponent,
665           String message, String title, int messageType, Icon icon,
666           Object[] selectionValues, Object initialSelectionValue)
667   {
668     // test only
669     
670     return isInteractiveMode()
671             ? JOptionPane.showInternalInputDialog(parentComponent, message,
672                     title, messageType, icon, selectionValues,
673                     initialSelectionValue)
674             : getMockResponse().toString();
675   }
676
677   
678   ///////////// end of options ///////////////
679   
680   
681   private static void outputMessage(Object message)
682   {
683     System.out.println(">>> JOption Message : " + message.toString());
684   }
685
686   public static Object getMockResponse()
687   {
688     return mockResponse;
689   }
690
691   public static void setMockResponse(Object mockOption)
692   {
693     JvOptionPane.mockResponse = mockOption;
694   }
695
696   public static void resetMock()
697   {
698     setMockResponse(JvOptionPane.CANCEL_OPTION);
699     setInteractiveMode(true);
700   }
701
702   public static boolean isInteractiveMode()
703   {
704     return interactiveMode;
705   }
706
707   public static void setInteractiveMode(boolean interactiveMode)
708   {
709     JvOptionPane.interactiveMode = interactiveMode;
710   }
711
712   @SuppressWarnings("unused")
713   private static String getPrefix(int messageType)
714   {
715     String prefix = ""; // JavaScript only
716
717     if (/** @j2sNative true || */
718     false)
719     {
720       switch (messageType)
721       {
722       default:
723       case JvOptionPane.INFORMATION_MESSAGE:
724         prefix = "Note: ";
725         break;
726       case JvOptionPane.WARNING_MESSAGE:
727         prefix = "WARNING! ";
728         break;
729       case JvOptionPane.ERROR_MESSAGE:
730         prefix = "ERRROR! ";
731         break;
732       }
733     }
734     return prefix;
735   }
736
737   DialogRunner<JvOptionPane> runner = new DialogRunner(this);
738
739   private List<Object> ourOptions;
740   /**
741    * create a new option dialog that can be used to register responses - along
742    * lines of showOptionDialog
743    * 
744    * @param desktop
745    * @param question
746    * @param string
747    * @param defaultOption
748    * @param plainMessage
749    * @param object
750    * @param options
751    * @param string2
752    * @return
753    */
754   public static JvOptionPane newOptionDialog(Component parentComponent)
755   {
756     return new JvOptionPane(parentComponent);
757   }
758
759   public void showDialog(
760           String message, String title, int optionType, int messageType,
761           Icon icon, Object[] options, Object initialValue)
762   {
763
764     if (!isInteractiveMode())
765     {
766       runner.firstRun((int) getMockResponse());
767     }
768     // two uses:
769     //
770     // TODO
771     //
772     // 1) AlignViewport for openLinkedAlignment
773     //
774     // Show a dialog with the option to open and link (cDNA <-> protein) as a
775     // new
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.
779     //
780     // 2) UserDefinedColors warning about saving over a name already defined
781     //
782     Component parent;
783     /**
784      * @j2sNative
785      * parent = this;
786      */
787     {
788       parent = parentComponent;
789     }
790     ;
791     ourOptions = Arrays.asList(options);
792     int response = JOptionPane.showOptionDialog(parent, message, title,
793             optionType, messageType, icon, options, initialValue);
794     /**
795      * @j2sNative
796      */
797     {
798       runner.firstRun(response);
799     }
800
801   }
802
803   public void showInternalDialog(JPanel mainPanel, String title,
804           int yesNoCancelOption, int questionMessage, Icon icon,
805           Object[] options, String initresponse)
806   {
807     if (!isInteractiveMode())
808     {
809       runner.firstRun((int) getMockResponse());
810     }
811     Component parent;
812     /**
813      * @j2sNative parent = this;
814      */
815     {
816       parent = parentComponent;
817     }
818     ;
819     ourOptions = Arrays.asList(options);
820     
821     int response;
822     if (parent!=this) {
823
824       response = JOptionPane.showInternalOptionDialog(parent, mainPanel,
825               title, yesNoCancelOption, questionMessage, icon, options,
826               initresponse);
827     }
828     else
829     {
830       response = JOptionPane.showOptionDialog(parent, mainPanel, title,
831               yesNoCancelOption, questionMessage, icon, options,
832               initresponse);
833     }
834     /**
835      * @j2sNative
836      */
837     {
838       runner.firstRun(response);
839     }
840     
841   }
842   @Override
843   public JvOptionPane response(RunResponse action)
844   {
845
846     runner.response(action);
847     return this;
848   }
849
850   public JvOptionPane defaultResponse(Runnable runnable)
851   {
852     runner.setDefaultResponse(runnable);
853     return this;
854   }
855
856   @Override
857   public void propertyChange(PropertyChangeEvent evt)
858   {
859     int ourOption = ourOptions.indexOf(evt.getNewValue());
860     if (ourOption == -1)
861     {
862       // try our luck..
863       runner.run(evt.getNewValue());
864     }
865     else
866     {
867       runner.run(ourOption);
868     }
869   }
870
871
872 }