JAL-3048 internalDialog with dialogRunner
[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    * centered on parent
486    * 
487    * @param parentComponent
488    * @param message
489    * @return
490    * @throws HeadlessException
491    */
492   public static String showInputDialog(Component parentComponent,
493           String message) throws HeadlessException
494   {
495     // test only
496
497     return isInteractiveMode()
498             ? JOptionPane.showInputDialog(parentComponent, message)
499             : getMockResponse().toString();
500   }
501
502   /**
503    * input with initial selection
504    * 
505    * @param parentComponent
506    * @param message
507    * @param initialSelectionValue
508    * @return
509    */
510   public static String showInputDialog(Component parentComponent,
511           String message, String initialSelectionValue)
512   {
513     
514     // AnnotationPanel
515     
516     return isInteractiveMode()
517             ? JOptionPane.showInputDialog(parentComponent, message,
518                     initialSelectionValue)
519             : getMockResponse().toString();
520   }
521
522   /**
523    * 
524    * @param parentComponent
525    * @param message
526    * @param title
527    * @param messageType
528    * @return
529    * @throws HeadlessException
530    */
531   public static String showInputDialog(Component parentComponent,
532           String message, String title, int messageType)
533           throws HeadlessException
534   {
535
536     // test only
537
538     return isInteractiveMode() ? JOptionPane
539             .showInputDialog(parentComponent, message, title, messageType)
540             : getMockResponse().toString();
541   }
542
543   /**
544    * Customized input option 
545    * 
546    * @param parentComponent
547    * @param message
548    * @param title
549    * @param messageType
550    * @param icon
551    * @param selectionValues
552    * @param initialSelectionValue
553    * @return
554    * @throws HeadlessException
555    */
556   public static Object showInputDialog(Component parentComponent,
557           Object message, String title, int messageType, Icon icon,
558           Object[] selectionValues, Object initialSelectionValue)
559           throws HeadlessException
560   {
561     
562     // test only
563     
564     return isInteractiveMode()
565             ? JOptionPane.showInputDialog(parentComponent, message, title,
566                     messageType, icon, selectionValues,
567                     initialSelectionValue)
568             : getMockResponse().toString();
569   }
570
571   
572   
573   /**
574    * internal version
575    * 
576    * @param parentComponent
577    * @param message
578    * @return
579    */
580   public static String showInternalInputDialog(Component parentComponent,
581           String message)
582   {
583     // test only
584     
585     return isInteractiveMode()
586             ? JOptionPane.showInternalInputDialog(parentComponent, message)
587             : getMockResponse().toString();
588   }
589
590   
591   /**
592    * internal with title and messageType
593    * 
594    * @param parentComponent
595    * @param message
596    * @param title
597    * @param messageType
598    * @return
599    */
600   public static String showInternalInputDialog(Component parentComponent,
601           String message, String title, int messageType)
602   {
603     
604     // AlignFrame tabbedPane_mousePressed
605     
606     return isInteractiveMode()
607             ? JOptionPane.showInternalInputDialog(parentComponent,
608                     getPrefix(messageType) + message, title, messageType)
609             : getMockResponse().toString();
610   }
611
612   /**
613    * customized internal
614    * 
615    * @param parentComponent
616    * @param message
617    * @param title
618    * @param messageType
619    * @param icon
620    * @param selectionValues
621    * @param initialSelectionValue
622    * @return
623    */
624   public static Object showInternalInputDialog(Component parentComponent,
625           String message, String title, int messageType, Icon icon,
626           Object[] selectionValues, Object initialSelectionValue)
627   {
628     // test only
629     
630     return isInteractiveMode()
631             ? JOptionPane.showInternalInputDialog(parentComponent, message,
632                     title, messageType, icon, selectionValues,
633                     initialSelectionValue)
634             : getMockResponse().toString();
635   }
636
637   
638   ///////////// end of options ///////////////
639   
640   
641   private static void outputMessage(Object message)
642   {
643     System.out.println(">>> JOption Message : " + message.toString());
644   }
645
646   public static Object getMockResponse()
647   {
648     return mockResponse;
649   }
650
651   public static void setMockResponse(Object mockOption)
652   {
653     JvOptionPane.mockResponse = mockOption;
654   }
655
656   public static void resetMock()
657   {
658     setMockResponse(JvOptionPane.CANCEL_OPTION);
659     setInteractiveMode(true);
660   }
661
662   public static boolean isInteractiveMode()
663   {
664     return interactiveMode;
665   }
666
667   public static void setInteractiveMode(boolean interactiveMode)
668   {
669     JvOptionPane.interactiveMode = interactiveMode;
670   }
671
672   @SuppressWarnings("unused")
673   private static String getPrefix(int messageType)
674   {
675     String prefix = ""; // JavaScript only
676
677     if (/** @j2sNative true || */
678     false)
679     {
680       switch (messageType)
681       {
682       default:
683       case JvOptionPane.INFORMATION_MESSAGE:
684         prefix = "Note: ";
685         break;
686       case JvOptionPane.WARNING_MESSAGE:
687         prefix = "WARNING! ";
688         break;
689       case JvOptionPane.ERROR_MESSAGE:
690         prefix = "ERRROR! ";
691         break;
692       }
693     }
694     return prefix;
695   }
696
697   DialogRunner<JvOptionPane> runner = new DialogRunner(this);
698
699   private List<Object> ourOptions;
700   /**
701    * create a new option dialog that can be used to register responses - along
702    * lines of showOptionDialog
703    * 
704    * @param desktop
705    * @param question
706    * @param string
707    * @param defaultOption
708    * @param plainMessage
709    * @param object
710    * @param options
711    * @param string2
712    * @return
713    */
714   public static JvOptionPane newOptionDialog(Component parentComponent)
715   {
716     return new JvOptionPane(parentComponent);
717   }
718
719   public void showDialog(
720           String message, String title, int optionType, int messageType,
721           Icon icon, Object[] options, Object initialValue)
722   {
723
724     if (!isInteractiveMode())
725     {
726       runner.firstRun((int) getMockResponse());
727     }
728     // two uses:
729     //
730     // TODO
731     //
732     // 1) AlignViewport for openLinkedAlignment
733     //
734     // Show a dialog with the option to open and link (cDNA <-> protein) as a
735     // new
736     // alignment, either as a standalone alignment or in a split frame. Returns
737     // true if the new alignment was opened, false if not, because the user
738     // declined the offer.
739     //
740     // 2) UserDefinedColors warning about saving over a name already defined
741     //
742     Component parent;
743     /**
744      * @j2sNative
745      * parent = this;
746      */
747     {
748       parent = parentComponent;
749     }
750     ;
751     ourOptions = Arrays.asList(options);
752     int response = JOptionPane.showOptionDialog(parent, message, title,
753             optionType, messageType, icon, options, initialValue);
754     /**
755      * @j2sNative
756      */
757     {
758       runner.firstRun(response);
759     }
760
761   }
762
763   public void showInternalDialog(JPanel mainPanel, String title,
764           int yesNoCancelOption, int questionMessage, Icon icon,
765           Object[] options, String initresponse)
766   {
767     if (!isInteractiveMode())
768     {
769       runner.firstRun((int) getMockResponse());
770     }
771     // two uses:
772     //
773     // TODO
774     //
775     // 1) AlignViewport for openLinkedAlignment
776     //
777     // Show a dialog with the option to open and link (cDNA <-> protein) as a
778     // new
779     // alignment, either as a standalone alignment or in a split frame. Returns
780     // true if the new alignment was opened, false if not, because the user
781     // declined the offer.
782     //
783     // 2) UserDefinedColors warning about saving over a name already defined
784     //
785     Component parent;
786     /**
787      * @j2sNative parent = this;
788      */
789     {
790       parent = parentComponent;
791     }
792     ;
793     ourOptions = Arrays.asList(options);
794     
795     int response;
796     if (parent!=this) {
797
798       response = JOptionPane.showInternalOptionDialog(parent, mainPanel,
799               title, yesNoCancelOption, questionMessage, icon, options,
800               initresponse);
801     }
802     else
803     {
804       response = JOptionPane.showOptionDialog(parent, mainPanel, title,
805               yesNoCancelOption, questionMessage, icon, options,
806               initresponse);
807     }
808     /**
809      * @j2sNative
810      */
811     {
812       runner.firstRun(response);
813     }
814     
815   }
816   @Override
817   public JvOptionPane response(RunResponse action)
818   {
819
820     runner.response(action);
821     return this;
822   }
823
824   public JvOptionPane defaultResponse(Runnable runnable)
825   {
826     runner.setDefaultResponse(runnable);
827     return this;
828   }
829
830   @Override
831   public void propertyChange(PropertyChangeEvent evt)
832   {
833     int ourOption = ourOptions.indexOf(evt.getNewValue());
834     if (ourOption == -1)
835     {
836       // try our luck..
837       runner.run(evt.getNewValue());
838     }
839     else
840     {
841       runner.run(ourOption);
842     }
843   }
844
845
846 }