Clover icon

Coverage Report

  1. Project Clover database Wed Nov 13 2024 16:12:26 GMT
  2. Package jalview.gui

File JvOptionPane.java

 

Coverage histogram

../../img/srcFileCovDistChart3.png
52% of files have more coverage

Code metrics

240
466
71
1
1,779
1,166
244
0.52
6.56
71
3.44

Classes

Class Line # Actions
JvOptionPane 72 466 244
0.2483912624.8%
 

Contributing tests

This file is covered by 38 tests. .

Source view

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    package jalview.gui;
22   
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.KeyEvent;
36    import java.awt.event.MouseAdapter;
37    import java.awt.event.MouseMotionAdapter;
38    import java.beans.PropertyChangeEvent;
39    import java.beans.PropertyChangeListener;
40    import java.beans.PropertyVetoException;
41    import java.util.ArrayList;
42    import java.util.Arrays;
43    import java.util.HashMap;
44    import java.util.List;
45    import java.util.Map;
46    import java.util.concurrent.ExecutorService;
47    import java.util.concurrent.Executors;
48    import java.util.concurrent.TimeUnit;
49   
50    import javax.swing.Icon;
51    import javax.swing.JButton;
52    import javax.swing.JDialog;
53    import javax.swing.JFrame;
54    import javax.swing.JInternalFrame;
55    import javax.swing.JLayeredPane;
56    import javax.swing.JMenu;
57    import javax.swing.JMenuBar;
58    import javax.swing.JOptionPane;
59    import javax.swing.JPanel;
60    import javax.swing.JRootPane;
61    import javax.swing.SwingUtilities;
62    import javax.swing.UIManager;
63    import javax.swing.event.InternalFrameEvent;
64    import javax.swing.event.InternalFrameListener;
65   
66    import jalview.bin.Console;
67    import jalview.util.ChannelProperties;
68    import jalview.util.MessageManager;
69    import jalview.util.Platform;
70    import jalview.util.dialogrunner.DialogRunnerI;
71   
 
72    public class JvOptionPane extends JOptionPane
73    implements DialogRunnerI, PropertyChangeListener
74    {
75    private static final long serialVersionUID = -3019167117756785229L;
76   
77    private static Object mockResponse = JvOptionPane.CANCEL_OPTION;
78   
79    private static boolean interactiveMode = true;
80   
81    public static final Runnable NULLCALLABLE = () -> {
82    };
83   
84    private Component parentComponent;
85   
86    private ExecutorService executor = Executors.newCachedThreadPool();
87   
88    private JDialog dialog = null;
89   
90    private Map<Object, Runnable> callbacks = new HashMap<>();
91   
92    private int timeout = -1;
93   
 
94  1 toggle public void setTimeout(int i)
95    {
96  1 timeout = i;
97    }
98   
99    /*
100    * JalviewJS reports user choice in the dialog as the selected option (text);
101    * this list allows conversion to index (int)
102    */
103    List<Object> ourOptions;
104   
 
105  5 toggle public JvOptionPane(final Component parent)
106    {
107  5 this.parentComponent = Platform.isJS() ? this : parent;
108  5 this.setIcon(null);
109    }
110   
 
111  1 toggle public static int showConfirmDialog(Component parentComponent,
112    Object message) throws HeadlessException
113    {
114    // only called by test
115  1 return isInteractiveMode()
116    ? JOptionPane.showConfirmDialog(parentComponent, message)
117    : (int) getMockResponse();
118    }
119   
120    /**
121    * Message, title, optionType
122    *
123    * @param parentComponent
124    * @param message
125    * @param title
126    * @param optionType
127    * @return
128    * @throws HeadlessException
129    */
 
130  1 toggle public static int showConfirmDialog(Component parentComponent,
131    Object message, String title, int optionType)
132    throws HeadlessException
133    {
134  1 if (!isInteractiveMode())
135    {
136  1 return (int) getMockResponse();
137    }
138  0 switch (optionType)
139    {
140  0 case JvOptionPane.YES_NO_CANCEL_OPTION:
141    // FeatureRenderer amendFeatures ?? TODO ??
142    // Chimera close
143    // PromptUserConfig
144    // $FALL-THROUGH$
145  0 default:
146  0 case JvOptionPane.YES_NO_OPTION:
147    // PromptUserConfig usage stats
148    // for now treated as "OK CANCEL"
149    // $FALL-THROUGH$
150  0 case JvOptionPane.OK_CANCEL_OPTION:
151    // will fall back to simple HTML
152  0 return JOptionPane.showConfirmDialog(parentComponent, message, title,
153    optionType);
154    }
155    }
156   
157    /**
158    * Adds a message type. Fallback is to just add it in the beginning.
159    *
160    * @param parentComponent
161    * @param message
162    * @param title
163    * @param optionType
164    * @param messageType
165    * @return
166    * @throws HeadlessException
167    */
 
168  37 toggle public static int showConfirmDialog(Component parentComponent,
169    Object message, String title, int optionType, int messageType)
170    throws HeadlessException
171    {
172    // JalviewServicesChanged
173    // PromptUserConfig raiseDialog
174  37 return isInteractiveMode()
175    ? JOptionPane.showConfirmDialog(parentComponent, message, title,
176    optionType, messageType)
177    : (int) getMockResponse();
178    }
179   
180    /**
181    * Adds an icon
182    *
183    * @param parentComponent
184    * @param message
185    * @param title
186    * @param optionType
187    * @param messageType
188    * @param icon
189    * @return
190    * @throws HeadlessException
191    */
 
192  1 toggle public static int showConfirmDialog(Component parentComponent,
193    Object message, String title, int optionType, int messageType,
194    Icon icon) throws HeadlessException
195    {
196    // JvOptionPaneTest only
197  1 return isInteractiveMode()
198    ? JOptionPane.showConfirmDialog(parentComponent, message, title,
199    optionType, messageType, icon)
200    : (int) getMockResponse();
201    }
202   
203    /**
204    * Internal version "OK"
205    *
206    * @param parentComponent
207    * @param message
208    * @return
209    */
 
210  1 toggle public static int showInternalConfirmDialog(Component parentComponent,
211    Object message)
212    {
213    // JvOptionPaneTest only;
214  1 return isInteractiveMode()
215    ? JOptionPane.showInternalConfirmDialog(parentComponent,
216    message)
217    : (int) getMockResponse();
218    }
219   
220    /**
221    * Internal version -- changed to standard version for now
222    *
223    * @param parentComponent
224    * @param message
225    * @param title
226    * @param optionType
227    * @return
228    */
 
229  1 toggle public static int showInternalConfirmDialog(Component parentComponent,
230    String message, String title, int optionType)
231    {
232  1 if (!isInteractiveMode())
233    {
234  1 return (int) getMockResponse();
235    }
236  0 switch (optionType)
237    {
238  0 case JvOptionPane.YES_NO_CANCEL_OPTION:
239    // ColourMenuHelper.addMenuItmers.offerRemoval TODO
240  0 case JvOptionPane.YES_NO_OPTION:
241    // UserDefinedColoursSave -- relevant? TODO
242    // $FALL-THROUGH$
243  0 default:
244  0 case JvOptionPane.OK_CANCEL_OPTION:
245   
246    // EditNameDialog --- uses panel for messsage TODO
247   
248    // Desktop.inputURLMenuItem
249    // WsPreferenses
250  0 return JOptionPane.showConfirmDialog(parentComponent, message, title,
251    optionType);
252    }
253    }
254   
255    /**
256    *
257    * @param parentComponent
258    * @param message
259    * @param title
260    * @param optionType
261    * @param messageType
262    * @return
263    */
 
264  1 toggle public static int showInternalConfirmDialog(Component parentComponent,
265    Object message, String title, int optionType, int messageType)
266    {
267  1 if (!isInteractiveMode())
268    {
269  1 return (int) getMockResponse();
270    }
271  0 switch (optionType)
272    {
273  0 case JvOptionPane.YES_NO_CANCEL_OPTION:
274  0 case JvOptionPane.YES_NO_OPTION:
275    // UserQuestionanaireCheck
276    // VamsasApplication
277    // $FALL-THROUGH$
278  0 default:
279  0 case JvOptionPane.OK_CANCEL_OPTION:
280    // will fall back to simple HTML
281  0 return JOptionPane.showConfirmDialog(parentComponent, message, title,
282    optionType, messageType);
283    }
284    }
285   
286    /**
287    * adds icon; no longer internal
288    *
289    * @param parentComponent
290    * @param message
291    * @param title
292    * @param optionType
293    * @param messageType
294    * @param icon
295    * @return
296    */
 
297  1 toggle public static int showInternalConfirmDialog(Component parentComponent,
298    Object message, String title, int optionType, int messageType,
299    Icon icon)
300    {
301  1 if (!isInteractiveMode())
302    {
303  1 return (int) getMockResponse();
304    }
305  0 switch (optionType)
306    {
307  0 case JvOptionPane.YES_NO_CANCEL_OPTION:
308  0 case JvOptionPane.YES_NO_OPTION:
309    //$FALL-THROUGH$
310  0 default:
311  0 case JvOptionPane.OK_CANCEL_OPTION:
312    // Preferences editLink/newLink
313  0 return JOptionPane.showConfirmDialog(parentComponent, message, title,
314    optionType, messageType, icon);
315    }
316   
317    }
318   
319    /**
320    * custom options full-featured
321    *
322    * @param parentComponent
323    * @param message
324    * @param title
325    * @param optionType
326    * @param messageType
327    * @param icon
328    * @param options
329    * @param initialValue
330    * @return
331    * @throws HeadlessException
332    */
 
333  0 toggle public static int showOptionDialog(Component parentComponent,
334    String message, String title, int optionType, int messageType,
335    Icon icon, Object[] options, Object initialValue)
336    throws HeadlessException
337    {
338  0 if (!isInteractiveMode())
339    {
340  0 return (int) getMockResponse();
341    }
342    // two uses:
343    //
344    // TODO
345    //
346    // 1) AlignViewport for openLinkedAlignment
347    //
348    // Show a dialog with the option to open and link (cDNA <-> protein) as a
349    // new
350    // alignment, either as a standalone alignment or in a split frame. Returns
351    // true if the new alignment was opened, false if not, because the user
352    // declined the offer.
353    //
354    // 2) UserDefinedColors warning about saving over a name already defined
355    //
356  0 return JOptionPane.showOptionDialog(parentComponent, message, title,
357    optionType, messageType, icon, options, initialValue);
358    }
359   
360    /**
361    * Just an OK message
362    *
363    * @param message
364    * @throws HeadlessException
365    */
 
366  1 toggle public static void showMessageDialog(Component parentComponent,
367    String message) throws HeadlessException
368    {
369  1 if (!isInteractiveMode())
370    {
371  1 outputMessage(message);
372  1 return;
373    }
374   
375    // test class only
376   
377  0 JOptionPane.showMessageDialog(parentComponent, message);
378    }
379   
380    /**
381    * OK with message, title, and type
382    *
383    * @param parentComponent
384    * @param message
385    * @param title
386    * @param messageType
387    * @throws HeadlessException
388    */
 
389  3 toggle public static void showMessageDialog(Component parentComponent,
390    String message, String title, int messageType)
391    throws HeadlessException
392    {
393    // 30 implementations -- all just fine.
394   
395  3 if (!isInteractiveMode())
396    {
397  3 outputMessage(message);
398  3 return;
399    }
400   
401  0 JOptionPane.showMessageDialog(parentComponent,
402    getPrefix(messageType) + message, title, messageType);
403    }
404   
405    /**
406    * adds title and icon
407    *
408    * @param parentComponent
409    * @param message
410    * @param title
411    * @param messageType
412    * @param icon
413    * @throws HeadlessException
414    */
 
415  1 toggle public static void showMessageDialog(Component parentComponent,
416    String message, String title, int messageType, Icon icon)
417    throws HeadlessException
418    {
419   
420    // test only
421   
422  1 if (!isInteractiveMode())
423    {
424  1 outputMessage(message);
425  1 return;
426    }
427   
428  0 JOptionPane.showMessageDialog(parentComponent, message, title,
429    messageType, icon);
430    }
431   
432    /**
433    * was internal
434    *
435    */
 
436  1 toggle public static void showInternalMessageDialog(Component parentComponent,
437    Object message)
438    {
439   
440    // WsPreferences only
441   
442  1 if (!isInteractiveMode())
443    {
444  1 outputMessage(message);
445  1 return;
446    }
447   
448  0 JOptionPane.showMessageDialog(parentComponent, message);
449    }
450   
451    /**
452    * Adds title and messageType
453    *
454    * @param parentComponent
455    * @param message
456    * @param title
457    * @param messageType
458    */
 
459  2 toggle public static void showInternalMessageDialog(Component parentComponent,
460    String message, String title, int messageType)
461    {
462   
463    // 41 references
464   
465  2 if (!isInteractiveMode())
466    {
467  2 outputMessage(message);
468  2 return;
469    }
470   
471  0 JOptionPane.showMessageDialog(parentComponent,
472    getPrefix(messageType) + message, title, messageType);
473    }
474   
475    /**
476    *
477    * @param parentComponent
478    * @param message
479    * @param title
480    * @param messageType
481    * @param icon
482    */
 
483  1 toggle public static void showInternalMessageDialog(Component parentComponent,
484    Object message, String title, int messageType, Icon icon)
485    {
486   
487    // test only
488   
489  1 if (!isInteractiveMode())
490    {
491  1 outputMessage(message);
492  1 return;
493    }
494   
495  0 JOptionPane.showMessageDialog(parentComponent, message, title,
496    messageType, icon);
497    }
498   
499    /**
500    *
501    * @param message
502    * @return
503    * @throws HeadlessException
504    */
 
505  1 toggle public static String showInputDialog(Object message)
506    throws HeadlessException
507    {
508    // test only
509   
510  1 if (!isInteractiveMode())
511    {
512  1 return getMockResponse().toString();
513    }
514   
515  0 return JOptionPane.showInputDialog(message);
516    }
517   
518    /**
519    * adds inital selection value
520    *
521    * @param message
522    * @param initialSelectionValue
523    * @return
524    */
 
525  0 toggle public static String showInputDialog(String message,
526    String initialSelectionValue)
527    {
528  0 if (!isInteractiveMode())
529    {
530  0 return getMockResponse().toString();
531    }
532   
533    // AnnotationPanel character option
534   
535  0 return JOptionPane.showInputDialog(message, initialSelectionValue);
536    }
537   
538    /**
539    * adds inital selection value
540    *
541    * @param message
542    * @param initialSelectionValue
543    * @return
544    */
 
545  1 toggle public static String showInputDialog(Object message,
546    Object initialSelectionValue)
547    {
548  1 if (!isInteractiveMode())
549    {
550  1 return getMockResponse().toString();
551    }
552   
553    // AnnotationPanel character option
554   
555  0 return JOptionPane.showInputDialog(message, initialSelectionValue);
556    }
557   
558    /**
559    * centered on parent
560    *
561    * @param parentComponent
562    * @param message
563    * @return
564    * @throws HeadlessException
565    */
 
566  1 toggle public static String showInputDialog(Component parentComponent,
567    String message) throws HeadlessException
568    {
569    // test only
570   
571  1 return isInteractiveMode()
572    ? JOptionPane.showInputDialog(parentComponent, message)
573    : getMockResponse().toString();
574    }
575   
576    /**
577    * input with initial selection
578    *
579    * @param parentComponent
580    * @param message
581    * @param initialSelectionValue
582    * @return
583    */
 
584  0 toggle public static String showInputDialog(Component parentComponent,
585    String message, String initialSelectionValue)
586    {
587   
588    // AnnotationPanel
589   
590  0 return isInteractiveMode()
591    ? JOptionPane.showInputDialog(parentComponent, message,
592    initialSelectionValue)
593    : getMockResponse().toString();
594    }
595   
596    /**
597    * input with initial selection
598    *
599    * @param parentComponent
600    * @param message
601    * @param initialSelectionValue
602    * @return
603    */
 
604  1 toggle public static String showInputDialog(Component parentComponent,
605    Object message, Object initialSelectionValue)
606    {
607   
608    // AnnotationPanel
609   
610  1 return isInteractiveMode()
611    ? JOptionPane.showInputDialog(parentComponent, message,
612    initialSelectionValue)
613    : getMockResponse().toString();
614    }
615   
616    /**
617    *
618    * @param parentComponent
619    * @param message
620    * @param title
621    * @param messageType
622    * @return
623    * @throws HeadlessException
624    */
 
625  1 toggle public static String showInputDialog(Component parentComponent,
626    String message, String title, int messageType)
627    throws HeadlessException
628    {
629   
630    // test only
631   
632  1 return isInteractiveMode()
633    ? JOptionPane.showInputDialog(parentComponent, message, title,
634    messageType)
635    : getMockResponse().toString();
636    }
637   
638    /**
639    * Customized input option
640    *
641    * @param parentComponent
642    * @param message
643    * @param title
644    * @param messageType
645    * @param icon
646    * @param selectionValues
647    * @param initialSelectionValue
648    * @return
649    * @throws HeadlessException
650    */
 
651  1 toggle public static Object showInputDialog(Component parentComponent,
652    Object message, String title, int messageType, Icon icon,
653    Object[] selectionValues, Object initialSelectionValue)
654    throws HeadlessException
655    {
656   
657    // test only
658   
659  1 return isInteractiveMode()
660    ? JOptionPane.showInputDialog(parentComponent, message, title,
661    messageType, icon, selectionValues,
662    initialSelectionValue)
663    : getMockResponse().toString();
664    }
665   
666    /**
667    * internal version
668    *
669    * @param parentComponent
670    * @param message
671    * @return
672    */
 
673  1 toggle public static String showInternalInputDialog(Component parentComponent,
674    String message)
675    {
676    // test only
677   
678  1 return isInteractiveMode()
679    ? JOptionPane.showInternalInputDialog(parentComponent, message)
680    : getMockResponse().toString();
681    }
682   
683    /**
684    * internal with title and messageType
685    *
686    * @param parentComponent
687    * @param message
688    * @param title
689    * @param messageType
690    * @return
691    */
 
692  1 toggle public static String showInternalInputDialog(Component parentComponent,
693    String message, String title, int messageType)
694    {
695   
696    // AlignFrame tabbedPane_mousePressed
697   
698  1 return isInteractiveMode()
699    ? JOptionPane.showInternalInputDialog(parentComponent,
700    getPrefix(messageType) + message, title, messageType)
701    : getMockResponse().toString();
702    }
703   
704    /**
705    * customized internal
706    *
707    * @param parentComponent
708    * @param message
709    * @param title
710    * @param messageType
711    * @param icon
712    * @param selectionValues
713    * @param initialSelectionValue
714    * @return
715    */
 
716  1 toggle public static Object showInternalInputDialog(Component parentComponent,
717    String message, String title, int messageType, Icon icon,
718    Object[] selectionValues, Object initialSelectionValue)
719    {
720    // test only
721   
722  1 return isInteractiveMode()
723    ? JOptionPane.showInternalInputDialog(parentComponent, message,
724    title, messageType, icon, selectionValues,
725    initialSelectionValue)
726    : getMockResponse().toString();
727    }
728   
729    ///////////// end of options ///////////////
730   
 
731  9 toggle private static void outputMessage(Object message)
732    {
733  9 jalview.bin.Console
734    .outPrintln(">>> JOption Message : " + message.toString());
735    }
736   
 
737  57 toggle public static Object getMockResponse()
738    {
739  57 return mockResponse;
740    }
741   
 
742  177 toggle public static void setMockResponse(Object mockOption)
743    {
744  177 JvOptionPane.mockResponse = mockOption;
745    }
746   
 
747  0 toggle public static void resetMock()
748    {
749  0 setMockResponse(JvOptionPane.CANCEL_OPTION);
750  0 setInteractiveMode(true);
751    }
752   
 
753  68 toggle public static boolean isInteractiveMode()
754    {
755  68 return interactiveMode;
756    }
757   
 
758  164 toggle public static void setInteractiveMode(boolean interactive)
759    {
760  164 JvOptionPane.interactiveMode = interactive;
761    }
762   
 
763  0 toggle private static String getPrefix(int messageType)
764    {
765  0 String prefix = "";
766   
767    // JavaScript only
768  0 if (Platform.isJS())
769    {
770  0 switch (messageType)
771    {
772  0 case JvOptionPane.WARNING_MESSAGE:
773  0 prefix = "WARNING! ";
774  0 break;
775  0 case JvOptionPane.ERROR_MESSAGE:
776  0 prefix = "ERROR! ";
777  0 break;
778  0 default:
779  0 prefix = "Note: ";
780    }
781    }
782  0 return prefix;
783    }
784   
785    /**
786    * create a new option dialog that can be used to register responses - along
787    * lines of showOptionDialog
788    *
789    * @param desktop
790    * @param question
791    * @param string
792    * @param defaultOption
793    * @param plainMessage
794    * @param object
795    * @param options
796    * @param string2
797    * @return
798    */
 
799  4 toggle public static JvOptionPane newOptionDialog()
800    {
801  4 return new JvOptionPane(null);
802    }
803   
 
804  1 toggle public static JvOptionPane newOptionDialog(Component parentComponent)
805    {
806  1 return new JvOptionPane(parentComponent);
807    }
808   
 
809  0 toggle public void showDialog(String message, String title, int optionType,
810    int messageType, Icon icon, Object[] options, Object initialValue)
811    {
812  0 showDialog(message, title, optionType, messageType, icon, options,
813    initialValue, true);
814    }
815   
 
816  0 toggle public void showDialog(Object message, String title, int optionType,
817    int messageType, Icon icon, Object[] options, Object initialValue,
818    boolean modal)
819    {
820  0 showDialog(message, title, optionType, messageType, icon, options,
821    initialValue, modal, null);
822    }
823   
 
824  1 toggle public void showDialog(Object message, String title, int optionType,
825    int messageType, Icon icon, Object[] options, Object initialValue,
826    boolean modal, JButton[] buttons)
827    {
828  1 if (!isInteractiveMode())
829    {
830  0 handleResponse(getMockResponse());
831  0 return;
832    }
833    // two uses:
834    //
835    // TODO
836    //
837    // 1) AlignViewport for openLinkedAlignment
838    //
839    // Show a dialog with the option to open and link (cDNA <-> protein) as a
840    // new
841    // alignment, either as a standalone alignment or in a split frame. Returns
842    // true if the new alignment was opened, false if not, because the user
843    // declined the offer.
844    //
845    // 2) UserDefinedColors warning about saving over a name already defined
846    //
847   
848  1 ourOptions = Arrays.asList(options);
849   
850  1 if (modal)
851    {
852  1 boolean useButtons = false;
853  1 Object initialValueButton = null;
854  1 NOTNULL: if (buttons != null)
855    {
856  1 if (buttons.length != options.length)
857    {
858  0 jalview.bin.Console.error(
859    "Supplied buttons array not the same length as supplied options array.");
860  0 break NOTNULL;
861    }
862   
863    // run through buttons for initialValue first so we can set (and start)
864    // a final timeoutThreadF to include (and interrupt) in the button
865    // actions
866  1 Thread timeoutThread = null;
867  1 for (int i = 0; i < options.length; i++)
868    {
869  1 Object o = options[i];
870  1 JButton jb = buttons[i];
871  1 if (o.equals(initialValue))
872    {
873  1 if (timeout > 0 && jb != null && jb instanceof JButton)
874    {
875    // after timeout ms click the default button
876  1 timeoutThread = new Thread(() -> {
877  1 try
878    {
879  1 Thread.sleep(timeout);
880    } catch (InterruptedException e)
881    {
882  0 Console.trace(
883    "Dialog timeout interrupted. Probably a button pressed.");
884    }
885  0 jb.doClick();
886    });
887    }
888  1 initialValueButton = jb;
889  1 break;
890    }
891    }
892  1 final Thread timeoutThreadF = timeoutThread;
893  1 if (timeoutThreadF != null)
894    {
895  1 timeoutThreadF.start();
896    }
897   
898  1 int[] buttonActions = { JOptionPane.YES_OPTION,
899    JOptionPane.NO_OPTION, JOptionPane.CANCEL_OPTION };
900  2 for (int i = 0; i < options.length; i++)
901    {
902  1 Object o = options[i];
903  1 jalview.bin.Console.trace(
904    "Setting button " + i + " to '" + o.toString() + "'");
905  1 JButton jb = buttons[i];
906   
907  1 int buttonAction = buttonActions[i];
908  1 Runnable action = callbacks.get(buttonAction);
909  1 jb.setText((String) o);
910  1 jb.addActionListener(new ActionListener()
911    {
 
912  0 toggle @Override
913    public void actionPerformed(ActionEvent e)
914    {
915  0 if (timeoutThreadF != null)
916    {
917  0 timeoutThreadF.interrupt();
918    }
919   
920  0 Object obj = e.getSource();
921  0 if (obj == null || !(obj instanceof Component))
922    {
923  0 jalview.bin.Console.warn(
924    "Could not find Component source of event object "
925    + obj);
926  0 return;
927    }
928  0 Object joptionpaneObject = SwingUtilities.getAncestorOfClass(
929    JOptionPane.class, (Component) obj);
930  0 if (joptionpaneObject == null
931    || !(joptionpaneObject instanceof JOptionPane))
932    {
933  0 jalview.bin.Console.warn(
934    "Could not find JOptionPane ancestor of event object "
935    + obj);
936  0 return;
937    }
938  0 JOptionPane joptionpane = (JOptionPane) joptionpaneObject;
939  0 joptionpane.setValue(buttonAction);
940  0 if (action != null)
941  0 new Thread(action).start();
942  0 joptionpane.transferFocusBackward();
943  0 joptionpane.setVisible(false);
944    // put focus and raise parent window if possible, unless cancel or
945    // no button pressed
946  0 boolean raiseParent = (parentComponent != null);
947  0 if (buttonAction == JOptionPane.CANCEL_OPTION)
948  0 raiseParent = false;
949  0 if (optionType == JOptionPane.YES_NO_OPTION
950    && buttonAction == JOptionPane.NO_OPTION)
951  0 raiseParent = false;
952  0 if (raiseParent)
953    {
954  0 parentComponent.requestFocus();
955  0 if (parentComponent instanceof JInternalFrame)
956    {
957  0 JInternalFrame jif = (JInternalFrame) parentComponent;
958  0 jif.show();
959  0 jif.moveToFront();
960  0 jif.grabFocus();
961    }
962  0 else if (parentComponent instanceof Window)
963    {
964  0 Window w = (Window) parentComponent;
965  0 w.toFront();
966  0 w.requestFocus();
967    }
968    }
969  0 joptionpane.setVisible(false);
970    }
971    });
972   
973    }
974  1 useButtons = true;
975    }
976    // use a JOptionPane as usual
977  1 int response = JOptionPane.showOptionDialog(parentComponent, message,
978    title, optionType, messageType, icon,
979  1 useButtons ? buttons : options,
980  1 useButtons ? initialValueButton : initialValue);
981   
982    /*
983    * In Java, the response is returned to this thread and handled here; (for
984    * Javascript, see propertyChange)
985    */
986  0 if (!Platform.isJS())
987    /**
988    * Java only
989    *
990    * @j2sIgnore
991    */
992    {
993  0 Console.debug("Handling response for " + response);
994  0 handleResponse(response);
995    }
996    }
997    else
998    {
999    /*
1000    * This is java similar to the swingjs handling, with the callbacks attached to
1001    * the button press of the dialog. This means we can use a non-modal JDialog for
1002    * the confirmation without blocking the GUI.
1003    */
1004  0 JOptionPane joptionpane = new JOptionPane();
1005    // Make button options
1006  0 int[] buttonActions = { JvOptionPane.YES_OPTION,
1007    JvOptionPane.NO_OPTION, JvOptionPane.CANCEL_OPTION };
1008   
1009    // we need the strings to make the buttons with actionEventListener
1010  0 if (options == null)
1011    {
1012  0 ArrayList<String> options_default = new ArrayList<>();
1013  0 options_default
1014    .add(UIManager.getString("OptionPane.yesButtonText"));
1015  0 if (optionType == JvOptionPane.YES_NO_OPTION
1016    || optionType == JvOptionPane.YES_NO_CANCEL_OPTION)
1017    {
1018  0 options_default
1019    .add(UIManager.getString("OptionPane.noButtonText"));
1020    }
1021  0 if (optionType == JvOptionPane.YES_NO_CANCEL_OPTION)
1022    {
1023  0 options_default
1024    .add(UIManager.getString("OptionPane.cancelButtonText"));
1025    }
1026  0 options = options_default.toArray();
1027    }
1028   
1029  0 ArrayList<JButton> options_btns = new ArrayList<>();
1030  0 Object initialValue_btn = null;
1031  0 if (!Platform.isJS()) // JalviewJS already uses callback, don't need to
1032    // add them here
1033    {
1034  0 for (int i = 0; i < options.length && i < 3; i++)
1035    {
1036  0 Object o = options[i];
1037  0 int buttonAction = buttonActions[i];
1038  0 Runnable action = callbacks.get(buttonAction);
1039  0 JButton jb = new JButton();
1040  0 jb.setText((String) o);
1041  0 jb.addActionListener(new ActionListener()
1042    {
1043   
 
1044  0 toggle @Override
1045    public void actionPerformed(ActionEvent e)
1046    {
1047  0 joptionpane.setValue(buttonAction);
1048  0 if (action != null)
1049  0 new Thread(action).start();
1050    // joptionpane.transferFocusBackward();
1051  0 joptionpane.transferFocusBackward();
1052  0 joptionpane.setVisible(false);
1053    // put focus and raise parent window if possible, unless cancel
1054    // button pressed
1055  0 boolean raiseParent = (parentComponent != null);
1056  0 if (buttonAction == JvOptionPane.CANCEL_OPTION)
1057  0 raiseParent = false;
1058  0 if (optionType == JvOptionPane.YES_NO_OPTION
1059    && buttonAction == JvOptionPane.NO_OPTION)
1060  0 raiseParent = false;
1061  0 if (raiseParent)
1062    {
1063  0 parentComponent.requestFocus();
1064  0 if (parentComponent instanceof JInternalFrame)
1065    {
1066  0 JInternalFrame jif = (JInternalFrame) parentComponent;
1067  0 jif.show();
1068  0 jif.moveToFront();
1069  0 jif.grabFocus();
1070    }
1071  0 else if (parentComponent instanceof Window)
1072    {
1073  0 Window w = (Window) parentComponent;
1074  0 w.toFront();
1075  0 w.requestFocus();
1076    }
1077    }
1078  0 joptionpane.setVisible(false);
1079    }
1080    });
1081  0 options_btns.add(jb);
1082  0 if (o.equals(initialValue))
1083  0 initialValue_btn = jb;
1084    }
1085    }
1086  0 joptionpane.setMessage(message);
1087  0 joptionpane.setMessageType(messageType);
1088  0 joptionpane.setOptionType(optionType);
1089  0 joptionpane.setIcon(icon);
1090  0 joptionpane.setOptions(
1091  0 Platform.isJS() ? options : options_btns.toArray());
1092  0 joptionpane.setInitialValue(
1093  0 Platform.isJS() ? initialValue : initialValue_btn);
1094   
1095  0 JDialog dialog = joptionpane.createDialog(parentComponent, title);
1096  0 dialog.setIconImages(ChannelProperties.getIconList());
1097  0 dialog.setModalityType(modal ? ModalityType.APPLICATION_MODAL
1098    : ModalityType.MODELESS);
1099  0 dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
1100  0 dialog.setVisible(true);
1101  0 setDialog(dialog);
1102    }
1103    }
1104   
 
1105  0 toggle public void showInternalDialog(Object mainPanel, String title,
1106    int yesNoCancelOption, int questionMessage, Icon icon,
1107    Object[] options, String initresponse)
1108    {
1109  0 if (!isInteractiveMode())
1110    {
1111  0 handleResponse(getMockResponse());
1112    }
1113   
1114    // need to set these separately so we can set the title bar icon later
1115  0 this.setOptionType(yesNoCancelOption);
1116  0 this.setMessageType(questionMessage);
1117  0 this.setIcon(icon);
1118  0 this.setInitialValue(initresponse);
1119  0 this.setOptions(options);
1120  0 this.setMessage(mainPanel);
1121   
1122  0 ourOptions = Arrays.asList(options);
1123  0 if (parentComponent != this
1124    && !(parentComponent == null && Desktop.instance == null))
1125    {
1126    // note the parent goes back to a JRootPane so is probably
1127    // Desktop.getDesktop()
1128  0 JInternalFrame jif = this.createInternalFrame(
1129  0 parentComponent != null ? parentComponent : Desktop.instance,
1130    title);
1131    // connect to the alignFrame using a map in Desktop
1132  0 if (parentComponent instanceof AlignFrame)
1133    {
1134  0 Desktop.addModal((AlignFrame) parentComponent, jif);
1135    }
1136  0 jif.setFrameIcon(null);
1137  0 jif.addInternalFrameListener(new InternalFrameListener()
1138    {
 
1139  0 toggle @Override
1140    public void internalFrameActivated(InternalFrameEvent arg0)
1141    {
1142    }
1143   
 
1144  0 toggle @Override
1145    public void internalFrameClosed(InternalFrameEvent arg0)
1146    {
1147  0 JvOptionPane.this.internalDialogHandleResponse();
1148    }
1149   
 
1150  0 toggle @Override
1151    public void internalFrameClosing(InternalFrameEvent arg0)
1152    {
1153    }
1154   
 
1155  0 toggle @Override
1156    public void internalFrameDeactivated(InternalFrameEvent arg0)
1157    {
1158    }
1159   
 
1160  0 toggle @Override
1161    public void internalFrameDeiconified(InternalFrameEvent arg0)
1162    {
1163    }
1164   
 
1165  0 toggle @Override
1166    public void internalFrameIconified(InternalFrameEvent arg0)
1167    {
1168    }
1169   
 
1170  0 toggle @Override
1171    public void internalFrameOpened(InternalFrameEvent arg0)
1172    {
1173    }
1174    });
1175  0 jif.setVisible(true);
1176  0 startModal(jif);
1177  0 return;
1178    }
1179    else
1180    {
1181  0 JDialog dialog = this.createDialog(parentComponent, title);
1182  0 dialog.setIconImages(ChannelProperties.getIconList());
1183  0 dialog.setVisible(true); // blocking
1184  0 this.internalDialogHandleResponse();
1185  0 return;
1186    }
1187    }
1188   
 
1189  0 toggle private void internalDialogHandleResponse()
1190    {
1191  0 Object value = this.getValue();
1192  0 if (value == null
1193    || (value instanceof Integer && (Integer) value == -1))
1194    {
1195  0 return;
1196    }
1197  0 String responseString = value.toString();
1198  0 int response = ourOptions.indexOf(responseString);
1199   
1200  0 if (!Platform.isJS())
1201    /**
1202    * Java only
1203    *
1204    * @j2sIgnore
1205    */
1206    {
1207  0 handleResponse(response);
1208    }
1209    }
1210   
1211    /*
1212    * @Override public JvOptionPane setResponseHandler(Object response, Runnable
1213    * action) { callbacks.put(response, new Callable<Void>() {
1214    *
1215    * @Override public Void call() { action.run(); return null; } }); return this;
1216    * }
1217    */
 
1218  9 toggle @Override
1219    public JvOptionPane setResponseHandler(Object response, Runnable action)
1220    {
1221  9 if (action == null)
1222    {
1223  0 action = NULLCALLABLE;
1224    }
1225  9 callbacks.put(response, action);
1226  9 return this;
1227    }
1228   
 
1229  0 toggle public void setDialog(JDialog d)
1230    {
1231  0 dialog = d;
1232    }
1233   
 
1234  0 toggle public JDialog getDialog()
1235    {
1236  0 return dialog;
1237    }
1238   
1239    /**
1240    * showDialogOnTop will create a dialog that (attempts to) come to top of OS
1241    * desktop windows
1242    */
 
1243  0 toggle public static int showDialogOnTop(String label, String actionString,
1244    int JOPTIONPANE_OPTION, int JOPTIONPANE_MESSAGETYPE)
1245    {
1246  0 return showDialogOnTop(null, label, actionString, JOPTIONPANE_OPTION,
1247    JOPTIONPANE_MESSAGETYPE);
1248    }
1249   
 
1250  0 toggle public static int showDialogOnTop(Component dialogParentComponent,
1251    String label, String actionString, int JOPTIONPANE_OPTION,
1252    int JOPTIONPANE_MESSAGETYPE)
1253    {
1254  0 if (!isInteractiveMode())
1255    {
1256  0 return (int) getMockResponse();
1257    }
1258    // Ensure Jalview window is brought to front (primarily for Quit
1259    // confirmation window to be visible)
1260   
1261    // This method of raising the Jalview window is broken in java
1262    // jalviewDesktop.setVisible(true);
1263    // jalviewDesktop.toFront();
1264   
1265    // A better hack which works is to create a new JFrame parent with
1266    // setAlwaysOnTop(true)
1267  0 JFrame dialogParent = new JFrame();
1268  0 if (dialogParentComponent == null)
1269    {
1270  0 dialogParent.setIconImages(ChannelProperties.getIconList());
1271  0 dialogParent.setAlwaysOnTop(true);
1272    }
1273   
1274  0 int answer = JOptionPane.showConfirmDialog(
1275  0 dialogParentComponent == null ? dialogParent
1276    : dialogParentComponent,
1277    label, actionString, JOPTIONPANE_OPTION,
1278    JOPTIONPANE_MESSAGETYPE);
1279   
1280  0 if (dialogParentComponent == null)
1281    {
1282  0 dialogParent.setAlwaysOnTop(false);
1283  0 dialogParent.dispose();
1284    }
1285   
1286  0 return answer;
1287    }
1288   
 
1289  1 toggle public void showDialogOnTopAsync(String label, String actionString,
1290    int JOPTIONPANE_OPTION, int JOPTIONPANE_MESSAGETYPE, Icon icon,
1291    Object[] options, Object initialValue, boolean modal)
1292    {
1293  1 JFrame frame = new JFrame();
1294  1 frame.setIconImages(ChannelProperties.getIconList());
1295  1 showDialogOnTopAsync(frame, label, actionString, JOPTIONPANE_OPTION,
1296    JOPTIONPANE_MESSAGETYPE, icon, options, initialValue, modal);
1297    }
1298   
 
1299  1 toggle public void showDialogOnTopAsync(JFrame dialogParent, Object label,
1300    String actionString, int JOPTIONPANE_OPTION,
1301    int JOPTIONPANE_MESSAGETYPE, Icon icon, Object[] options,
1302    Object initialValue, boolean modal)
1303    {
1304  1 showDialogOnTopAsync(dialogParent, label, actionString,
1305    JOPTIONPANE_OPTION, JOPTIONPANE_MESSAGETYPE, icon, options,
1306    initialValue, modal, null);
1307    }
1308   
 
1309  4 toggle public void showDialogOnTopAsync(JFrame dialogParent, Object label,
1310    String actionString, int JOPTIONPANE_OPTION,
1311    int JOPTIONPANE_MESSAGETYPE, Icon icon, Object[] options,
1312    Object initialValue, boolean modal, JButton[] buttons)
1313    {
1314  4 showDialogOnTopAsync(dialogParent, label, actionString,
1315    JOPTIONPANE_OPTION, JOPTIONPANE_MESSAGETYPE, icon, options,
1316    initialValue, modal, buttons, true);
1317    }
1318   
 
1319  5 toggle public void showDialogOnTopAsync(JFrame dialogParent, Object label,
1320    String actionString, int JOPTIONPANE_OPTION,
1321    int JOPTIONPANE_MESSAGETYPE, Icon icon, Object[] options,
1322    Object initialValue, boolean modal, JButton[] buttons,
1323    boolean dispose)
1324    {
1325  5 if (!isInteractiveMode())
1326    {
1327  4 handleResponse(getMockResponse());
1328  4 return;
1329    }
1330    // Ensure Jalview window is brought to front (primarily for Quit
1331    // confirmation window to be visible)
1332   
1333    // This method of raising the Jalview window is broken in java
1334    // jalviewDesktop.setVisible(true);
1335    // jalviewDesktop.toFront();
1336   
1337    // A better hack which works is to create a new JFrame parent with
1338    // setAlwaysOnTop(true)
1339  1 boolean parentOnTop = dialogParent.isAlwaysOnTop();
1340  1 dialogParent.setAlwaysOnTop(true);
1341  1 parentComponent = dialogParent;
1342   
1343  1 showDialog(label, actionString, JOPTIONPANE_OPTION,
1344    JOPTIONPANE_MESSAGETYPE, icon, options, initialValue, modal,
1345    buttons);
1346   
1347  0 dialogParent.setAlwaysOnTop(parentOnTop);
1348   
1349  0 if (dispose)
1350    {
1351  0 dialogParent.setAlwaysOnTop(false);
1352  0 dialogParent.dispose();
1353    }
1354    }
1355   
1356    /**
1357    * JalviewJS signals option selection by a property change event for the
1358    * option e.g. "OK". This methods responds to that by running the response
1359    * action that corresponds to that option.
1360    *
1361    * @param evt
1362    */
 
1363  0 toggle @Override
1364    public void propertyChange(PropertyChangeEvent evt)
1365    {
1366  0 Object newValue = evt.getNewValue();
1367  0 int ourOption = ourOptions.indexOf(newValue);
1368  0 if (ourOption >= 0)
1369    {
1370  0 handleResponse(ourOption);
1371    }
1372    else
1373    {
1374    // try our luck..
1375  0 handleResponse(newValue);
1376    }
1377    }
1378   
 
1379  4 toggle @Override
1380    public void handleResponse(Object response)
1381    {
1382    /*
1383    * this test is for NaN in Chrome
1384    */
1385  4 if (response != null && !response.equals(response))
1386    {
1387  0 return;
1388    }
1389  4 Runnable action = callbacks.get(response);
1390  4 if (action != null)
1391    {
1392  2 try
1393    {
1394  2 executor.submit(action);
1395    // new Thread(action).start();
1396    // action.call();
1397    } catch (Exception e)
1398    {
1399  0 e.printStackTrace();
1400    }
1401  2 if (parentComponent != null)
1402  0 parentComponent.requestFocus();
1403    }
1404    }
1405   
1406    /**
1407    * Create a non-modal confirm dialog
1408    */
 
1409  0 toggle public JDialog createDialog(Component parentComponent, Object message,
1410    String title, int optionType, int messageType, Icon icon,
1411    Object[] options, Object initialValue, boolean modal)
1412    {
1413  0 return createDialog(parentComponent, message, title, optionType,
1414    messageType, icon, options, initialValue, modal, null);
1415    }
1416   
 
1417  0 toggle public JDialog createDialog(Component parentComponent, Object message,
1418    String title, int optionType, int messageType, Icon icon,
1419    Object[] options, Object initialValue, boolean modal,
1420    JButton[] buttons)
1421    {
1422  0 if (!isInteractiveMode())
1423    {
1424  0 handleResponse(getMockResponse());
1425  0 return null;
1426    }
1427  0 JButton[] optionsButtons = null;
1428  0 Object initialValueButton = null;
1429  0 JOptionPane joptionpane = new JOptionPane();
1430    // Make button options
1431  0 int[] buttonActions = { JOptionPane.YES_OPTION, JOptionPane.NO_OPTION,
1432    JOptionPane.CANCEL_OPTION };
1433   
1434    // we need the strings to make the buttons with actionEventListener
1435  0 if (options == null)
1436    {
1437  0 ArrayList<String> options_default = new ArrayList<>();
1438  0 options_default.add(UIManager.getString("OptionPane.yesButtonText"));
1439  0 if (optionType == JOptionPane.YES_NO_OPTION
1440    || optionType == JOptionPane.YES_NO_CANCEL_OPTION)
1441    {
1442  0 options_default.add(UIManager.getString("OptionPane.noButtonText"));
1443    }
1444  0 if (optionType == JOptionPane.YES_NO_CANCEL_OPTION)
1445    {
1446  0 options_default
1447    .add(UIManager.getString("OptionPane.cancelButtonText"));
1448    }
1449  0 options = options_default.toArray();
1450    }
1451  0 if (!Platform.isJS()) // JalviewJS already uses callback, don't need to
1452    // add them here
1453    {
1454  0 if (((optionType == JOptionPane.YES_OPTION
1455    || optionType == JOptionPane.NO_OPTION
1456    || optionType == JOptionPane.CANCEL_OPTION
1457    || optionType == JOptionPane.OK_OPTION
1458    || optionType == JOptionPane.DEFAULT_OPTION)
1459    && options.length < 1)
1460    || ((optionType == JOptionPane.YES_NO_OPTION
1461    || optionType == JOptionPane.OK_CANCEL_OPTION)
1462    && options.length < 2)
1463    || (optionType == JOptionPane.YES_NO_CANCEL_OPTION
1464    && options.length < 3))
1465    {
1466  0 jalview.bin.Console
1467    .warn("JvOptionPane: not enough options for dialog type");
1468    }
1469  0 optionsButtons = new JButton[options.length];
1470  0 for (int i = 0; i < options.length && i < 3; i++)
1471    {
1472  0 Object o = options[i];
1473  0 int buttonAction = buttonActions[i];
1474  0 Runnable action = callbacks.get(buttonAction);
1475  0 JButton jb;
1476  0 if (buttons != null && buttons.length > i && buttons[i] != null)
1477    {
1478  0 jb = buttons[i];
1479    }
1480    else
1481    {
1482  0 jb = new JButton();
1483    }
1484  0 jb.setText((String) o);
1485  0 jb.addActionListener(new ActionListener()
1486    {
 
1487  0 toggle @Override
1488    public void actionPerformed(ActionEvent e)
1489    {
1490  0 joptionpane.setValue(buttonAction);
1491  0 if (action != null)
1492  0 new Thread(action).start();
1493    // joptionpane.transferFocusBackward();
1494  0 joptionpane.transferFocusBackward();
1495  0 joptionpane.setVisible(false);
1496    // put focus and raise parent window if possible, unless cancel
1497    // button pressed
1498  0 boolean raiseParent = (parentComponent != null);
1499  0 if (buttonAction == JOptionPane.CANCEL_OPTION)
1500  0 raiseParent = false;
1501  0 if (optionType == JOptionPane.YES_NO_OPTION
1502    && buttonAction == JOptionPane.NO_OPTION)
1503  0 raiseParent = false;
1504  0 if (raiseParent)
1505    {
1506  0 parentComponent.requestFocus();
1507  0 if (parentComponent instanceof JInternalFrame)
1508    {
1509  0 JInternalFrame jif = (JInternalFrame) parentComponent;
1510  0 jif.show();
1511  0 jif.moveToFront();
1512  0 jif.grabFocus();
1513    }
1514  0 else if (parentComponent instanceof Window)
1515    {
1516  0 Window w = (Window) parentComponent;
1517  0 w.toFront();
1518  0 w.requestFocus();
1519    }
1520    }
1521  0 joptionpane.setVisible(false);
1522    }
1523    });
1524  0 optionsButtons[i] = jb;
1525  0 if (o.equals(initialValue))
1526  0 initialValueButton = jb;
1527    }
1528    }
1529  0 joptionpane.setMessage(message);
1530  0 joptionpane.setMessageType(messageType);
1531  0 joptionpane.setOptionType(optionType);
1532  0 joptionpane.setIcon(icon);
1533  0 joptionpane.setOptions(Platform.isJS() ? options : optionsButtons);
1534  0 joptionpane.setInitialValue(
1535  0 Platform.isJS() ? initialValue : initialValueButton);
1536   
1537  0 JDialog dialog = joptionpane.createDialog(parentComponent, title);
1538  0 dialog.setIconImages(ChannelProperties.getIconList());
1539  0 dialog.setModalityType(
1540  0 modal ? ModalityType.APPLICATION_MODAL : ModalityType.MODELESS);
1541  0 dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
1542  0 setDialog(dialog);
1543  0 return dialog;
1544    }
1545   
1546    /**
1547    * Utility to programmatically click a button on a JOptionPane (as a JFrame)
1548    *
1549    * returns true if button was found
1550    */
 
1551  0 toggle public static boolean clickButton(JFrame frame, int buttonType)
1552    {
1553   
1554  0 return false;
1555    }
1556   
1557    /**
1558    * This helper method makes the JInternalFrame wait until it is notified by an
1559    * InternalFrameClosing event. This method also adds the given JOptionPane to
1560    * the JInternalFrame and sizes it according to the JInternalFrame's preferred
1561    * size.
1562    *
1563    * @param f
1564    * The JInternalFrame to make modal.
1565    */
 
1566  0 toggle private static void startModal(JInternalFrame f)
1567    {
1568    // We need to add an additional glasspane-like component directly
1569    // below the frame, which intercepts all mouse events that are not
1570    // directed at the frame itself.
1571  0 JPanel modalInterceptor = new JPanel();
1572  0 modalInterceptor.setOpaque(false);
1573  0 JLayeredPane lp = JLayeredPane.getLayeredPaneAbove(f);
1574  0 lp.setLayer(modalInterceptor, JLayeredPane.MODAL_LAYER.intValue());
1575  0 modalInterceptor.setBounds(0, 0, lp.getWidth(), lp.getHeight());
1576  0 modalInterceptor.addMouseListener(new MouseAdapter()
1577    {
1578    });
1579  0 modalInterceptor.addMouseMotionListener(new MouseMotionAdapter()
1580    {
1581    });
1582  0 lp.add(modalInterceptor);
1583  0 f.toFront();
1584   
1585    // disable the main menu bar if in Linux
1586  0 JMenuBar menubar = null;
1587  0 if (Platform.isLinux())
1588    {
1589  0 JRootPane rootpane = Desktop.getDesktop().getRootPane();
1590  0 menubar = rootpane.getJMenuBar();
1591    }
1592   
1593    // We need to explicitly dispatch events when we are blocking the event
1594    // dispatch thread.
1595  0 EventQueue queue = Toolkit.getDefaultToolkit().getSystemEventQueue();
1596  0 try
1597    {
1598  0 if (menubar != null)
1599    {
1600    // don't allow clicks on main menu on linux due to a hanging bug.
1601    // see JAL-4214.
1602  0 setMenusEnabled(menubar, false);
1603    }
1604   
1605  0 while (!f.isClosed())
1606    {
1607  0 if (EventQueue.isDispatchThread())
1608    {
1609    // The getNextEventMethod() issues wait() when no
1610    // event is available, so we don't need do explicitly wait().
1611  0 AWTEvent ev = queue.getNextEvent();
1612    // This mimics EventQueue.dispatchEvent(). We can't use
1613    // EventQueue.dispatchEvent() directly, because it is
1614    // protected, unfortunately.
1615  0 if (ev instanceof ActiveEvent)
1616    {
1617  0 ((ActiveEvent) ev).dispatch();
1618    }
1619  0 else if (ev instanceof KeyEvent && ((KeyEvent) ev).isControlDown()
1620    && menubar != null)
1621    {
1622    // temporarily enable menus to send Ctrl+? KeyEvents
1623  0 setMenusEnabled(menubar, true);
1624  0 ((Component) ev.getSource()).dispatchEvent(ev);
1625  0 setMenusEnabled(menubar, false);
1626    }
1627  0 else if (ev.getSource() instanceof MenuComponent)
1628    {
1629  0 ((MenuComponent) ev.getSource()).dispatchEvent(ev);
1630    }
1631  0 else if (ev.getSource() instanceof Component)
1632    {
1633  0 ((Component) ev.getSource()).dispatchEvent(ev);
1634    }
1635    // Other events are ignored as per spec in
1636    // EventQueue.dispatchEvent
1637    }
1638    else
1639    {
1640    // Give other threads a chance to become active.
1641  0 Thread.yield();
1642    }
1643    }
1644    } catch (InterruptedException ex)
1645    {
1646    // If we get interrupted, then leave the modal state.
1647    } finally
1648    {
1649    // re-enable the main menu bar
1650  0 if (menubar != null)
1651    {
1652  0 setMenusEnabled(menubar, true);
1653    }
1654   
1655    // Clean up the modal interceptor.
1656  0 lp.remove(modalInterceptor);
1657   
1658    // unpaint the frame
1659  0 f.setVisible(false);
1660   
1661    // close the frame
1662  0 try
1663    {
1664  0 f.setClosed(true);
1665    } catch (PropertyVetoException e)
1666    {
1667  0 f.doDefaultCloseAction();
1668    }
1669   
1670    // Remove the internal frame from its parent, so it is no longer
1671    // lurking around and clogging memory.
1672  0 Container parent = f.getParent();
1673  0 if (parent != null)
1674    {
1675  0 parent.remove(f);
1676    }
1677    }
1678    }
1679   
 
1680  0 toggle public static JvOptionPane frameDialog(Object message, String title,
1681    int messageType, String[] buttonsTextS, String defaultButtonS,
1682    List<Runnable> handlers, boolean modal)
1683    {
1684  0 JFrame parent = new JFrame();
1685  0 JvOptionPane jvop = JvOptionPane.newOptionDialog();
1686  0 final String[] buttonsText;
1687  0 final String defaultButton;
1688  0 if (buttonsTextS == null)
1689    {
1690  0 String ok = MessageManager.getString("action.ok");
1691  0 buttonsText = new String[] { ok };
1692  0 defaultButton = ok;
1693    }
1694    else
1695    {
1696  0 buttonsText = buttonsTextS;
1697  0 defaultButton = defaultButtonS;
1698    }
1699  0 JButton[] buttons = new JButton[buttonsText.length];
1700  0 for (int i = 0; i < buttonsText.length; i++)
1701    {
1702  0 buttons[i] = new JButton();
1703  0 buttons[i].setText(buttonsText[i]);
1704  0 Console.trace("DISABLING BUTTON " + buttons[i].getText());
1705  0 buttons[i].setEnabled(false);
1706  0 buttons[i].setVisible(false);
1707    }
1708   
1709  0 int dialogType = -1;
1710  0 if (buttonsText.length == 1)
1711    {
1712  0 dialogType = JOptionPane.OK_OPTION;
1713    }
1714  0 else if (buttonsText.length == 2)
1715    {
1716  0 dialogType = JOptionPane.YES_NO_OPTION;
1717    }
1718    else
1719    {
1720  0 dialogType = JOptionPane.YES_NO_CANCEL_OPTION;
1721    }
1722  0 jvop.setResponseHandler(JOptionPane.YES_OPTION,
1723  0 (handlers != null && handlers.size() > 0) ? handlers.get(0)
1724    : NULLCALLABLE);
1725  0 if (dialogType == JOptionPane.YES_NO_OPTION
1726    || dialogType == JOptionPane.YES_NO_CANCEL_OPTION)
1727    {
1728  0 jvop.setResponseHandler(JOptionPane.NO_OPTION,
1729  0 (handlers != null && handlers.size() > 1) ? handlers.get(1)
1730    : NULLCALLABLE);
1731    }
1732  0 if (dialogType == JOptionPane.YES_NO_CANCEL_OPTION)
1733    {
1734  0 jvop.setResponseHandler(JOptionPane.CANCEL_OPTION,
1735  0 (handlers != null && handlers.size() > 2) ? handlers.get(2)
1736    : NULLCALLABLE);
1737    }
1738   
1739  0 final int dt = dialogType;
1740  0 new Thread(() -> {
1741  0 jvop.showDialog(message, title, dt, messageType, null, buttonsText,
1742    defaultButton, modal, buttons);
1743    }).start();
1744   
1745  0 return jvop;
1746    }
1747   
 
1748  0 toggle private static void setMenusEnabled(JMenuBar menubar, boolean b)
1749    {
1750  0 for (int i = 0; i < menubar.getMenuCount(); i++)
1751    {
1752  0 JMenu menu = menubar.getMenu(i);
1753  0 menu.setEnabled(b);
1754    }
1755    }
1756   
1757    private static final long defaultTimeout = 500;
1758   
 
1759  1 toggle public boolean waitForHandlerToFinish()
1760    {
1761  1 return waitForHandlerToFinish(defaultTimeout);
1762    }
1763   
 
1764  1 toggle public boolean waitForHandlerToFinish(long timeout)
1765    {
1766  1 if (executor != null)
1767    {
1768  1 try
1769    {
1770  1 return executor.awaitTermination(timeout, TimeUnit.MILLISECONDS);
1771    } catch (InterruptedException e)
1772    {
1773  0 Console.trace("Action was interrupted", e);
1774    }
1775    }
1776  0 return true;
1777    }
1778   
1779    }