1   /**
2    * Distribution License:
3    * JSword is free software; you can redistribute it and/or modify it under
4    * the terms of the GNU Lesser General Public License, version 2.1 as published by
5    * the Free Software Foundation. This program is distributed in the hope
6    * that it will be useful, but WITHOUT ANY WARRANTY; without even the
7    * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8    * See the GNU Lesser General Public License for more details.
9    *
10   * The License is available on the internet at:
11   *       http://www.gnu.org/copyleft/lgpl.html
12   * or by writing to:
13   *      Free Software Foundation, Inc.
14   *      59 Temple Place - Suite 330
15   *      Boston, MA 02111-1307, USA
16   *
17   * Copyright: 2008
18   *     The copyright to this program is held by it's authors.
19   *
20   * ID: $Id: org.eclipse.jdt.ui.prefs 1178 2006-11-06 12:48:02Z dmsmith $
21   */
22  package org.crosswire.common.swing;
23  
24  import java.awt.BorderLayout;
25  import java.awt.Component;
26  import java.awt.Container;
27  import java.awt.Dialog;
28  import java.awt.Frame;
29  import java.awt.HeadlessException;
30  import java.awt.Window;
31  import java.awt.event.ComponentAdapter;
32  import java.awt.event.ComponentEvent;
33  import java.awt.event.WindowAdapter;
34  import java.awt.event.WindowEvent;
35  import java.beans.PropertyChangeEvent;
36  import java.beans.PropertyChangeListener;
37  
38  import javax.swing.Action;
39  import javax.swing.Icon;
40  import javax.swing.JDialog;
41  import javax.swing.JOptionPane;
42  import javax.swing.JRootPane;
43  import javax.swing.UIManager;
44  
45  /**
46   * CWOptionPane is just like JOptionPane, but internationalize the button text
47   * for some languages that Java does not handle, for which JSword has
48   * translations.
49   * 
50   * @see gnu.lgpl.License for license details.<br>
51   *      The copyright to this program is held by it's authors.
52   * @author DM Smith [dmsmith555 at yahoo dot com]
53   */
54  public class CWOptionPane extends JOptionPane {
55  
56      /**
57       * Creates a <code>CWOptionPane</code> with a test message.
58       */
59      public CWOptionPane() {
60          this("CWOptionPane message", PLAIN_MESSAGE, DEFAULT_OPTION, null, null, null);
61      }
62  
63      /**
64       * Creates a instance of <code>CWOptionPane</code> to display a message
65       * using the plain-message message type and the default options delivered by
66       * the UI.
67       * 
68       * @param message
69       *            the <code>Object</code> to display
70       */
71      public CWOptionPane(Object message) {
72          this(message, PLAIN_MESSAGE, DEFAULT_OPTION, null, null, null);
73      }
74  
75      /**
76       * Creates an instance of <code>CWOptionPane</code> to display a message
77       * with the specified message type and the default options,
78       * 
79       * @param message
80       *            the <code>Object</code> to display
81       * @param messageType
82       *            the type of message to be displayed:
83       *            <code>ERROR_MESSAGE</code>, <code>INFORMATION_MESSAGE</code>,
84       *            <code>WARNING_MESSAGE</code>, <code>QUESTION_MESSAGE</code>,
85       *            or <code>PLAIN_MESSAGE</code>
86       */
87      public CWOptionPane(Object message, int messageType) {
88          this(message, messageType, DEFAULT_OPTION, null, null, null);
89      }
90  
91      /**
92       * Creates an instance of <code>CWOptionPane</code> to display a message
93       * with the specified message type and options.
94       * 
95       * @param message
96       *            the <code>Object</code> to display
97       * @param messageType
98       *            the type of message to be displayed:
99       *            <code>ERROR_MESSAGE</code>, <code>INFORMATION_MESSAGE</code>,
100      *            <code>WARNING_MESSAGE</code>, <code>QUESTION_MESSAGE</code>,
101      *            or <code>PLAIN_MESSAGE</code>
102      * @param optionType
103      *            the options to display in the pane:
104      *            <code>DEFAULT_OPTION</code>, <code>YES_NO_OPTION</code>,
105      *            <code>YES_NO_CANCEL_OPTION</code>,
106      *            <code>OK_CANCEL_OPTION</code>
107      */
108     public CWOptionPane(Object message, int messageType, int optionType) {
109         this(message, messageType, optionType, null, null, null);
110     }
111 
112     /**
113      * Creates an instance of <code>CWOptionPane</code> to display a message
114      * with the specified message type, options, and icon.
115      * 
116      * @param message
117      *            the <code>Object</code> to display
118      * @param messageType
119      *            the type of message to be displayed:
120      *            <code>ERROR_MESSAGE</code>, <code>INFORMATION_MESSAGE</code>,
121      *            <code>WARNING_MESSAGE</code>, <code>QUESTION_MESSAGE</code>,
122      *            or <code>PLAIN_MESSAGE</code>
123      * @param optionType
124      *            the options to display in the pane:
125      *            <code>DEFAULT_OPTION</code>, <code>YES_NO_OPTION</code>,
126      *            <code>YES_NO_CANCEL_OPTION</code>,
127      *            <code>OK_CANCEL_OPTION</code>
128      * @param icon
129      *            the <code>Icon</code> image to display
130      */
131     public CWOptionPane(Object message, int messageType, int optionType, Icon icon) {
132         this(message, messageType, optionType, icon, null, null);
133     }
134 
135     /**
136      * Creates an instance of <code>CWOptionPane</code> to display a message
137      * with the specified message type, icon, and options. None of the options
138      * is initially selected.
139      * <p>
140      * The options objects should contain either instances of
141      * <code>Component</code>s, (which are added directly) or
142      * <code>Strings</code> (which are wrapped in a <code>JButton</code>). If
143      * you provide <code>Component</code>s, you must ensure that when the
144      * <code>Component</code> is clicked it messages <code>setValue</code> in
145      * the created <code>CWOptionPane</code>.
146      * 
147      * @param message
148      *            the <code>Object</code> to display
149      * @param messageType
150      *            the type of message to be displayed:
151      *            <code>ERROR_MESSAGE</code>, <code>INFORMATION_MESSAGE</code>,
152      *            <code>WARNING_MESSAGE</code>, <code>QUESTION_MESSAGE</code>,
153      *            or <code>PLAIN_MESSAGE</code>
154      * @param optionType
155      *            the options to display in the pane:
156      *            <code>DEFAULT_OPTION</code>, <code>YES_NO_OPTION</code>,
157      *            <code>YES_NO_CANCEL_OPTION</code>,
158      *            <code>OK_CANCEL_OPTION</code>
159      * @param icon
160      *            the <code>Icon</code> image to display
161      * @param options
162      *            the choices the user can select
163      */
164     public CWOptionPane(Object message, int messageType, int optionType, Icon icon, Object[] options) {
165         this(message, messageType, optionType, icon, options, null);
166 
167         GuiUtil.applyDefaultOrientation(this);
168     }
169 
170     /**
171      * Creates an instance of <code>CWOptionPane</code> to display a message
172      * with the specified message type, icon, and options, with the
173      * initially-selected option specified.
174      * 
175      * @param message
176      *            the <code>Object</code> to display
177      * @param messageType
178      *            the type of message to be displayed:
179      *            <code>ERROR_MESSAGE</code>, <code>INFORMATION_MESSAGE</code>,
180      *            <code>WARNING_MESSAGE</code>, <code>QUESTION_MESSAGE</code>,
181      *            or <code>PLAIN_MESSAGE</code>
182      * @param optionType
183      *            the options to display in the pane:
184      *            <code>DEFAULT_OPTION</code>, <code>YES_NO_OPTION</code>,
185      *            <code>YES_NO_CANCEL_OPTION</code>,
186      *            <code>OK_CANCEL_OPTION</code>
187      * @param icon
188      *            the Icon image to display
189      * @param options
190      *            the choices the user can select
191      * @param initialValue
192      *            the choice that is initially selected; if <code>null</code>,
193      *            then nothing will be initially selected; only meaningful if
194      *            <code>options</code> is used
195      */
196     public CWOptionPane(Object message, int messageType, int optionType, Icon icon, Object[] options, Object initialValue) {
197         super(message, messageType, optionType, icon, CWOptionPane.fixOptions(options, optionType, messageType), initialValue);
198     }
199 
200     /**
201      * Shows a question-message dialog requesting input from the user. The
202      * dialog uses the default frame, which usually means it is centered on the
203      * screen.
204      * 
205      * @param message
206      *            the <code>Object</code> to display
207      * @exception HeadlessException
208      *                if <code>GraphicsEnvironment.isHeadless</code> returns
209      *                <code>true</code>
210      * @see java.awt.GraphicsEnvironment#isHeadless
211      */
212     public static String showInputDialog(Object message) throws HeadlessException {
213         return showInputDialog(null, message);
214     }
215 
216     /**
217      * Shows a question-message dialog requesting input from the user, with the
218      * input value initialized to <code>initialSelectionValue</code>. The dialog
219      * uses the default frame, which usually means it is centered on the screen.
220      * 
221      * @param message
222      *            the <code>Object</code> to display
223      * @param initialSelectionValue
224      *            the value used to initialize the input field
225      */
226     public static String showInputDialog(Object message, Object initialSelectionValue) {
227         return showInputDialog(null, message, initialSelectionValue);
228     }
229 
230     /**
231      * Shows a question-message dialog requesting input from the user parented
232      * to <code>parentComponent</code>. The dialog is displayed on top of the
233      * <code>Component</code>'s frame, and is usually positioned below the
234      * <code>Component</code>.
235      * 
236      * @param parentComponent
237      *            the parent <code>Component</code> for the dialog
238      * @param message
239      *            the <code>Object</code> to display
240      * @exception HeadlessException
241      *                if <code>GraphicsEnvironment.isHeadless</code> returns
242      *                <code>true</code>
243      * @see java.awt.GraphicsEnvironment#isHeadless
244      */
245     public static String showInputDialog(Component parentComponent, Object message) throws HeadlessException {
246         return showInputDialog(parentComponent, message, "?", QUESTION_MESSAGE);
247     }
248 
249     /**
250      * Shows a question-message dialog requesting input from the user and
251      * parented to <code>parentComponent</code>. The input value will be
252      * initialized to <code>initialSelectionValue</code>. The dialog is
253      * displayed on top of the <code>Component</code>'s frame, and is usually
254      * positioned below the <code>Component</code>.
255      * 
256      * @param parentComponent
257      *            the parent <code>Component</code> for the dialog
258      * @param message
259      *            the <code>Object</code> to display
260      * @param initialSelectionValue
261      *            the value used to initialize the input field
262      */
263     public static String showInputDialog(Component parentComponent, Object message, Object initialSelectionValue) {
264         return (String) showInputDialog(parentComponent, message, "?", QUESTION_MESSAGE, null, null, initialSelectionValue);
265     }
266 
267     /**
268      * Shows a dialog requesting input from the user parented to
269      * <code>parentComponent</code> with the dialog having the title
270      * <code>title</code> and message type <code>messageType</code>.
271      * 
272      * @param parentComponent
273      *            the parent <code>Component</code> for the dialog
274      * @param message
275      *            the <code>Object</code> to display
276      * @param title
277      *            the <code>String</code> to display in the dialog title bar
278      * @param messageType
279      *            the type of message that is to be displayed:
280      *            <code>ERROR_MESSAGE</code>, <code>INFORMATION_MESSAGE</code>,
281      *            <code>WARNING_MESSAGE</code>, <code>QUESTION_MESSAGE</code>,
282      *            or <code>PLAIN_MESSAGE</code>
283      * @exception HeadlessException
284      *                if <code>GraphicsEnvironment.isHeadless</code> returns
285      *                <code>true</code>
286      * @see java.awt.GraphicsEnvironment#isHeadless
287      */
288     public static String showInputDialog(Component parentComponent, Object message, String title, int messageType) throws HeadlessException {
289         return (String) showInputDialog(parentComponent, message, title, messageType, null, null, null);
290     }
291 
292     /**
293      * Prompts the user for input in a blocking dialog where the initial
294      * selection, possible selections, and all other options can be specified.
295      * The user will able to choose from <code>selectionValues</code>, where
296      * <code>null</code> implies the user can input whatever they wish, usually
297      * by means of a <code>JTextField</code>. <code>initialSelectionValue</code>
298      * is the initial value to prompt the user with. It is up to the UI to
299      * decide how best to represent the <code>selectionValues</code>, but
300      * usually a <code>JComboBox</code>, <code>JList</code>, or
301      * <code>JTextField</code> will be used.
302      * 
303      * @param parentComponent
304      *            the parent <code>Component</code> for the dialog
305      * @param message
306      *            the <code>Object</code> to display
307      * @param title
308      *            the <code>String</code> to display in the dialog title bar
309      * @param messageType
310      *            the type of message to be displayed:
311      *            <code>ERROR_MESSAGE</code>, <code>INFORMATION_MESSAGE</code>,
312      *            <code>WARNING_MESSAGE</code>, <code>QUESTION_MESSAGE</code>,
313      *            or <code>PLAIN_MESSAGE</code>
314      * @param icon
315      *            the <code>Icon</code> image to display
316      * @param selectionValues
317      *            an array of <code>Object</code>s that gives the possible
318      *            selections
319      * @param initialSelectionValue
320      *            the value used to initialize the input field
321      * @return user's input, or <code>null</code> meaning the user canceled the
322      *         input
323      * @exception HeadlessException
324      *                if <code>GraphicsEnvironment.isHeadless</code> returns
325      *                <code>true</code>
326      * @see java.awt.GraphicsEnvironment#isHeadless
327      */
328     public static Object showInputDialog(Component parentComponent, Object message, String title, int messageType, Icon icon, Object[] selectionValues,
329             Object initialSelectionValue) throws HeadlessException
330     {
331         CWOptionPane pane = new CWOptionPane(message, messageType, OK_CANCEL_OPTION, icon, null, null);
332 
333         pane.setWantsInput(true);
334         pane.setSelectionValues(selectionValues);
335         pane.setInitialSelectionValue(initialSelectionValue);
336         GuiUtil.applyDefaultOrientation(pane);
337 
338         int style = styleFromMessageType(messageType);
339         JDialog dialog = pane.createDialog(parentComponent, title, style);
340 
341         pane.selectInitialValue();
342         dialog.setVisible(true);
343         dialog.dispose();
344 
345         Object value = pane.getInputValue();
346 
347         if (value == UNINITIALIZED_VALUE) {
348             return null;
349         }
350 
351         return value;
352     }
353 
354     /**
355      * Brings up an information-message dialog titled "Message".
356      * 
357      * @param parentComponent
358      *            determines the <code>Frame</code> in which the dialog is
359      *            displayed; if <code>null</code>, or if the
360      *            <code>parentComponent</code> has no <code>Frame</code>, a
361      *            default <code>Frame</code> is used
362      * @param message
363      *            the <code>Object</code> to display
364      * @exception HeadlessException
365      *                if <code>GraphicsEnvironment.isHeadless</code> returns
366      *                <code>true</code>
367      * @see java.awt.GraphicsEnvironment#isHeadless
368      */
369     public static void showMessageDialog(Component parentComponent, Object message) throws HeadlessException {
370         showOptionDialog(parentComponent, message, "?", DEFAULT_OPTION, INFORMATION_MESSAGE, null, null, null);
371     }
372 
373     /**
374      * Brings up a dialog that displays a message using a default icon
375      * determined by the <code>messageType</code> parameter.
376      * 
377      * @param parentComponent
378      *            determines the <code>Frame</code> in which the dialog is
379      *            displayed; if <code>null</code>, or if the
380      *            <code>parentComponent</code> has no <code>Frame</code>, a
381      *            default <code>Frame</code> is used
382      * @param message
383      *            the <code>Object</code> to display
384      * @param title
385      *            the title string for the dialog
386      * @param messageType
387      *            the type of message to be displayed:
388      *            <code>ERROR_MESSAGE</code>, <code>INFORMATION_MESSAGE</code>,
389      *            <code>WARNING_MESSAGE</code>, <code>QUESTION_MESSAGE</code>,
390      *            or <code>PLAIN_MESSAGE</code>
391      * @exception HeadlessException
392      *                if <code>GraphicsEnvironment.isHeadless</code> returns
393      *                <code>true</code>
394      * @see java.awt.GraphicsEnvironment#isHeadless
395      */
396     public static void showMessageDialog(Component parentComponent, Object message, String title, int messageType) throws HeadlessException {
397         showOptionDialog(parentComponent, message, title, DEFAULT_OPTION, messageType, null, null, null);
398     }
399 
400     /**
401      * Brings up a dialog displaying a message, specifying all parameters.
402      * 
403      * @param parentComponent
404      *            determines the <code>Frame</code> in which the dialog is
405      *            displayed; if <code>null</code>, or if the
406      *            <code>parentComponent</code> has no <code>Frame</code>, a
407      *            default <code>Frame</code> is used
408      * @param message
409      *            the <code>Object</code> to display
410      * @param title
411      *            the title string for the dialog
412      * @param messageType
413      *            the type of message to be displayed:
414      *            <code>ERROR_MESSAGE</code>, <code>INFORMATION_MESSAGE</code>,
415      *            <code>WARNING_MESSAGE</code>, <code>QUESTION_MESSAGE</code>,
416      *            or <code>PLAIN_MESSAGE</code>
417      * @param icon
418      *            an icon to display in the dialog that helps the user identify
419      *            the kind of message that is being displayed
420      * @exception HeadlessException
421      *                if <code>GraphicsEnvironment.isHeadless</code> returns
422      *                <code>true</code>
423      * @see java.awt.GraphicsEnvironment#isHeadless
424      */
425     public static void showMessageDialog(Component parentComponent, Object message, String title, int messageType, Icon icon) throws HeadlessException {
426         showOptionDialog(parentComponent, message, title, DEFAULT_OPTION, messageType, icon, null, null);
427     }
428 
429     /**
430      * Brings up a dialog with the options <i>Yes</i>, <i>No</i> and
431      * <i>Cancel</i>; with the title, <b>Select an Option</b>.
432      * 
433      * @param parentComponent
434      *            determines the <code>Frame</code> in which the dialog is
435      *            displayed; if <code>null</code>, or if the
436      *            <code>parentComponent</code> has no <code>Frame</code>, a
437      *            default <code>Frame</code> is used
438      * @param message
439      *            the <code>Object</code> to display
440      * @return an integer indicating the option selected by the user
441      * @exception HeadlessException
442      *                if <code>GraphicsEnvironment.isHeadless</code> returns
443      *                <code>true</code>
444      * @see java.awt.GraphicsEnvironment#isHeadless
445      */
446     public static int showConfirmDialog(Component parentComponent, Object message) throws HeadlessException {
447         return showOptionDialog(parentComponent, message, "?", YES_NO_CANCEL_OPTION, QUESTION_MESSAGE, null, null, null);
448     }
449 
450     /**
451      * Brings up a dialog where the number of choices is determined by the
452      * <code>optionType</code> parameter.
453      * 
454      * @param parentComponent
455      *            determines the <code>Frame</code> in which the dialog is
456      *            displayed; if <code>null</code>, or if the
457      *            <code>parentComponent</code> has no <code>Frame</code>, a
458      *            default <code>Frame</code> is used
459      * @param message
460      *            the <code>Object</code> to display
461      * @param title
462      *            the title string for the dialog
463      * @param optionType
464      *            an int designating the options available on the dialog:
465      *            <code>YES_NO_OPTION</code>, or
466      *            <code>YES_NO_CANCEL_OPTION</code>
467      * @return an int indicating the option selected by the user
468      * @exception HeadlessException
469      *                if <code>GraphicsEnvironment.isHeadless</code> returns
470      *                <code>true</code>
471      * @see java.awt.GraphicsEnvironment#isHeadless
472      */
473     public static int showConfirmDialog(Component parentComponent, Object message, String title, int optionType) throws HeadlessException {
474         return showOptionDialog(parentComponent, message, title, optionType, QUESTION_MESSAGE, null, null, null);
475     }
476 
477     /**
478      * Brings up a dialog where the number of choices is determined by the
479      * <code>optionType</code> parameter, where the <code>messageType</code>
480      * parameter determines the icon to display. The <code>messageType</code>
481      * parameter is primarily used to supply a default icon from the Look and
482      * Feel.
483      * 
484      * @param parentComponent
485      *            determines the <code>Frame</code> in which the dialog is
486      *            displayed; if <code>null</code>, or if the
487      *            <code>parentComponent</code> has no <code>Frame</code>, a
488      *            default <code>Frame</code> is used.
489      * @param message
490      *            the <code>Object</code> to display
491      * @param title
492      *            the title string for the dialog
493      * @param optionType
494      *            an integer designating the options available on the dialog:
495      *            <code>YES_NO_OPTION</code>, or
496      *            <code>YES_NO_CANCEL_OPTION</code>
497      * @param messageType
498      *            an integer designating the kind of message this is; primarily
499      *            used to determine the icon from the pluggable Look and Feel:
500      *            <code>ERROR_MESSAGE</code>, <code>INFORMATION_MESSAGE</code>,
501      *            <code>WARNING_MESSAGE</code>, <code>QUESTION_MESSAGE</code>,
502      *            or <code>PLAIN_MESSAGE</code>
503      * @return an integer indicating the option selected by the user
504      * @exception HeadlessException
505      *                if <code>GraphicsEnvironment.isHeadless</code> returns
506      *                <code>true</code>
507      * @see java.awt.GraphicsEnvironment#isHeadless
508      */
509     public static int showConfirmDialog(Component parentComponent, Object message, String title, int optionType, int messageType) throws HeadlessException {
510         return showOptionDialog(parentComponent, message, title, optionType, messageType, null, null, null);
511     }
512 
513     /**
514      * Brings up a dialog with a specified icon, where the number of choices is
515      * determined by the <code>optionType</code> parameter. The
516      * <code>messageType</code> parameter is primarily used to supply a default
517      * icon from the look and feel.
518      * 
519      * @param parentComponent
520      *            determines the <code>Frame</code> in which the dialog is
521      *            displayed; if <code>null</code>, or if the
522      *            <code>parentComponent</code> has no <code>Frame</code>, a
523      *            default <code>Frame</code> is used
524      * @param message
525      *            the Object to display
526      * @param title
527      *            the title string for the dialog
528      * @param optionType
529      *            an int designating the options available on the dialog:
530      *            <code>YES_NO_OPTION</code>, or
531      *            <code>YES_NO_CANCEL_OPTION</code>
532      * @param messageType
533      *            an int designating the kind of message this is, primarily used
534      *            to determine the icon from the pluggable Look and Feel:
535      *            <code>ERROR_MESSAGE</code>, <code>INFORMATION_MESSAGE</code>,
536      *            <code>WARNING_MESSAGE</code>, <code>QUESTION_MESSAGE</code>,
537      *            or <code>PLAIN_MESSAGE</code>
538      * @param icon
539      *            the icon to display in the dialog
540      * @return an int indicating the option selected by the user
541      * @exception HeadlessException
542      *                if <code>GraphicsEnvironment.isHeadless</code> returns
543      *                <code>true</code>
544      * @see java.awt.GraphicsEnvironment#isHeadless
545      */
546     public static int showConfirmDialog(Component parentComponent, Object message, String title, int optionType, int messageType, Icon icon)
547             throws HeadlessException
548     {
549         return showOptionDialog(parentComponent, message, title, optionType, messageType, icon, null, null);
550     }
551 
552     /**
553      * Brings up a dialog with a specified icon, where the initial choice is
554      * determined by the <code>initialValue</code> parameter and the number of
555      * choices is determined by the <code>optionType</code> parameter.
556      * <p>
557      * If <code>optionType</code> is <code>YES_NO_OPTION</code>, or
558      * <code>YES_NO_CANCEL_OPTION</code> and the <code>options</code> parameter
559      * is <code>null</code>, then the options are supplied by the look and feel.
560      * <p>
561      * The <code>messageType</code> parameter is primarily used to supply a
562      * default icon from the look and feel.
563      * 
564      * @param parentComponent
565      *            determines the <code>Frame</code> in which the dialog is
566      *            displayed; if <code>null</code>, or if the
567      *            <code>parentComponent</code> has no <code>Frame</code>, a
568      *            default <code>Frame</code> is used
569      * @param message
570      *            the <code>Object</code> to display
571      * @param title
572      *            the title string for the dialog
573      * @param optionType
574      *            an integer designating the options available on the dialog:
575      *            <code>YES_NO_OPTION</code>, or
576      *            <code>YES_NO_CANCEL_OPTION</code>
577      * @param messageType
578      *            an integer designating the kind of message this is, primarily
579      *            used to determine the icon from the pluggable Look and Feel:
580      *            <code>ERROR_MESSAGE</code>, <code>INFORMATION_MESSAGE</code>,
581      *            <code>WARNING_MESSAGE</code>, <code>QUESTION_MESSAGE</code>,
582      *            or <code>PLAIN_MESSAGE</code>
583      * @param icon
584      *            the icon to display in the dialog
585      * @param options
586      *            an array of objects indicating the possible choices the user
587      *            can make; if the objects are components, they are rendered
588      *            properly; non-<code>String</code> objects are rendered using
589      *            their <code>toString</code> methods; if this parameter is
590      *            <code>null</code>, the options are determined by the Look and
591      *            Feel
592      * @param initialValue
593      *            the object that represents the default selection for the
594      *            dialog; only meaningful if <code>options</code> is used; can
595      *            be <code>null</code>
596      * @return an integer indicating the option chosen by the user, or
597      *         <code>CLOSED_OPTION</code> if the user closed the dialog
598      * @exception HeadlessException
599      *                if <code>GraphicsEnvironment.isHeadless</code> returns
600      *                <code>true</code>
601      * @see java.awt.GraphicsEnvironment#isHeadless
602      */
603     public static int showOptionDialog(Component parentComponent, Object message, String title, int optionType, int messageType, Icon icon, Object[] options,
604             Object initialValue) throws HeadlessException
605     {
606         CWOptionPane pane = new CWOptionPane(message, messageType, optionType, icon, options, initialValue);
607 
608         pane.setInitialValue(initialValue);
609         GuiUtil.applyDefaultOrientation(pane);
610 
611         int style = styleFromMessageType(messageType);
612         JDialog dialog = pane.createDialog(parentComponent, title, style);
613 
614         pane.selectInitialValue();
615         dialog.setVisible(true);
616         dialog.dispose();
617 
618         Object selectedValue = pane.getValue();
619 
620         if (selectedValue == null) {
621             return CLOSED_OPTION;
622         }
623 
624         Object[] opts = pane.getOptions();
625         if (opts == null) {
626             if (selectedValue instanceof Integer) {
627                 return ((Integer) selectedValue).intValue();
628             }
629             return CLOSED_OPTION;
630         }
631 
632         if (getActionName("Yes").equals(selectedValue)) {
633 
634             return YES_OPTION;
635         }
636 
637         if (getActionName("No").equals(selectedValue)) {
638 
639             return NO_OPTION;
640         }
641 
642         if (getActionName("OK").equals(selectedValue)) {
643             return OK_OPTION;
644         }
645 
646         if (getActionName("Cancel").equals(selectedValue)) {
647             return CANCEL_OPTION;
648         }
649 
650         int maxCounter = opts.length;
651         for (int counter = 0; counter < maxCounter; counter++) {
652             if (opts[counter].equals(selectedValue)) {
653                 return counter;
654             }
655         }
656 
657         return CLOSED_OPTION;
658     }
659 
660     private JDialog createDialog(Component parentComponent, String title, int style) throws HeadlessException {
661 
662         final JDialog dialog;
663 
664         Window window = GuiUtil.getWindow(parentComponent);
665         if (window instanceof Frame) {
666             dialog = new JDialog((Frame) window, title, true);
667         } else {
668             dialog = new JDialog((Dialog) window, title, true);
669         }
670 
671         Container contentPane = dialog.getContentPane();
672 
673         contentPane.setLayout(new BorderLayout());
674         contentPane.add(this, BorderLayout.CENTER);
675         dialog.setResizable(false);
676 
677         if (JDialog.isDefaultLookAndFeelDecorated()) {
678             boolean supportsWindowDecorations = UIManager.getLookAndFeel().getSupportsWindowDecorations();
679             if (supportsWindowDecorations) {
680                 dialog.setUndecorated(true);
681                 getRootPane().setWindowDecorationStyle(style);
682             }
683         }
684 
685         dialog.pack();
686         dialog.setLocationRelativeTo(parentComponent);
687         dialog.addWindowListener(new WindowAdapter() {
688             private boolean gotFocus;
689 
690             @Override
691             public void windowClosing(WindowEvent we) {
692                 setValue(null);
693             }
694 
695             @Override
696             public void windowGainedFocus(WindowEvent we) {
697                 // Once window gets focus, set initial focus
698                 if (!gotFocus) {
699                     selectInitialValue();
700                     gotFocus = true;
701                 }
702             }
703         });
704 
705         dialog.addComponentListener(new ComponentAdapter() {
706             @Override
707             public void componentShown(ComponentEvent ce) {
708                 // reset value to ensure closing works properly
709                 setValue(JOptionPane.UNINITIALIZED_VALUE);
710             }
711         });
712 
713         addPropertyChangeListener(new PropertyChangeListener() {
714             public void propertyChange(PropertyChangeEvent event) {
715                 // Let the defaultCloseOperation handle the closing
716                 // if the user closed the window without selecting a button
717                 // (newValue = null in that case). Otherwise, close the dialog.
718                 if (dialog.isVisible() && event.getSource() == CWOptionPane.this && event.getPropertyName().equals(VALUE_PROPERTY)
719                         && event.getNewValue() != null && event.getNewValue() != JOptionPane.UNINITIALIZED_VALUE)
720                 {
721                     dialog.setVisible(false);
722                 }
723             }
724         });
725 
726         GuiUtil.applyDefaultOrientation(dialog);
727         return dialog;
728     }
729 
730     private static int styleFromMessageType(int messageType) {
731         switch (messageType) {
732         case ERROR_MESSAGE:
733             return JRootPane.ERROR_DIALOG;
734         case QUESTION_MESSAGE:
735             return JRootPane.QUESTION_DIALOG;
736         case WARNING_MESSAGE:
737             return JRootPane.WARNING_DIALOG;
738         case INFORMATION_MESSAGE:
739             return JRootPane.INFORMATION_DIALOG;
740         case PLAIN_MESSAGE:
741         default:
742             return JRootPane.PLAIN_DIALOG;
743         }
744     }
745 
746     private static String getActionName(String key) {
747         return actions.findAction(key).getValue(Action.NAME).toString();
748     }
749 
750     private static Object[] fixOptions(Object[] options, int optionType, int messageType) {
751         Object[] opts = options;
752         if (options == null) {
753             if (optionType == YES_NO_OPTION) {
754                 opts = new Object[] {
755                         getActionName("Yes"),
756                         getActionName("No")
757                 };
758             } else if (optionType == OK_CANCEL_OPTION) {
759                 opts = new Object[] {
760                         getActionName("OK"),
761                         getActionName("Cancel")
762                 };
763             } else if (optionType == YES_NO_CANCEL_OPTION && messageType != INFORMATION_MESSAGE) {
764                 opts = new Object[] {
765                         getActionName("Yes"),
766                         getActionName("No"),
767                         getActionName("Cancel")
768                 };
769             } else {
770                 opts = new Object[] {
771                     getActionName("OK"),
772                 };
773             }
774         }
775         return opts;
776     }
777 
778     /**
779      * The actions for this dialog.
780      */
781     private static ActionFactory actions = new ActionFactory(null);
782     static {
783         // TRANSLATOR: This is the text on a "Yes" button.
784         actions.addAction("Yes", CWMsg.gettext("Yes"));
785         // TRANSLATOR: This is the text on a "No" button.
786         actions.addAction("No", CWMsg.gettext("No"));
787         // TRANSLATOR: This is the text on an "OK" button.
788         actions.addAction("OK", CWMsg.gettext("OK"));
789         // TRANSLATOR: This is the text on a "Cancel" button.
790         actions.addAction("Cancel", CWMsg.gettext("Cancel"));
791     }
792 
793     /**
794      * Serialization ID
795      */
796     private static final long serialVersionUID = -1870422750863765033L;
797 }
798