/**
* Distribution License:
* BibleDesktop is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License, version 2 or later
* as published by the Free Software Foundation. This program is distributed
* in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* The License is available on the internet at:
* http://www.gnu.org/copyleft/gpl.html
* or by writing to:
* Free Software Foundation, Inc.
* 59 Temple Place - Suite 330
* Boston, MA 02111-1307, USA
*
* © CrossWire Bible Society, 2008 - 2016
*/
package org.crosswire.common.swing;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.HeadlessException;
import java.awt.Window;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JRootPane;
import javax.swing.UIManager;
import org.crosswire.bibledesktop.BDMsg;
/**
* CWOptionPane is just like JOptionPane, but internationalize the button text
* for some languages that Java does not handle, for which JSword has
* translations.
*
* @see gnu.gpl.License The GNU General Public License for details.
* @author DM Smith
*/
public class CWOptionPane extends JOptionPane {
/**
* Creates a CWOptionPane
with a test message.
*/
public CWOptionPane() {
this("CWOptionPane message", PLAIN_MESSAGE, DEFAULT_OPTION, null, null, null);
}
/**
* Creates a instance of CWOptionPane
to display a message
* using the plain-message message type and the default options delivered by
* the UI.
*
* @param message
* the Object
to display
*/
public CWOptionPane(Object message) {
this(message, PLAIN_MESSAGE, DEFAULT_OPTION, null, null, null);
}
/**
* Creates an instance of CWOptionPane
to display a message
* with the specified message type and the default options,
*
* @param message
* the Object
to display
* @param messageType
* the type of message to be displayed:
* ERROR_MESSAGE
, INFORMATION_MESSAGE
,
* WARNING_MESSAGE
, QUESTION_MESSAGE
,
* or PLAIN_MESSAGE
*/
public CWOptionPane(Object message, int messageType) {
this(message, messageType, DEFAULT_OPTION, null, null, null);
}
/**
* Creates an instance of CWOptionPane
to display a message
* with the specified message type and options.
*
* @param message
* the Object
to display
* @param messageType
* the type of message to be displayed:
* ERROR_MESSAGE
, INFORMATION_MESSAGE
,
* WARNING_MESSAGE
, QUESTION_MESSAGE
,
* or PLAIN_MESSAGE
* @param optionType
* the options to display in the pane:
* DEFAULT_OPTION
, YES_NO_OPTION
,
* YES_NO_CANCEL_OPTION
,
* OK_CANCEL_OPTION
*/
public CWOptionPane(Object message, int messageType, int optionType) {
this(message, messageType, optionType, null, null, null);
}
/**
* Creates an instance of CWOptionPane
to display a message
* with the specified message type, options, and icon.
*
* @param message
* the Object
to display
* @param messageType
* the type of message to be displayed:
* ERROR_MESSAGE
, INFORMATION_MESSAGE
,
* WARNING_MESSAGE
, QUESTION_MESSAGE
,
* or PLAIN_MESSAGE
* @param optionType
* the options to display in the pane:
* DEFAULT_OPTION
, YES_NO_OPTION
,
* YES_NO_CANCEL_OPTION
,
* OK_CANCEL_OPTION
* @param icon
* the Icon
image to display
*/
public CWOptionPane(Object message, int messageType, int optionType, Icon icon) {
this(message, messageType, optionType, icon, null, null);
}
/**
* Creates an instance of CWOptionPane
to display a message
* with the specified message type, icon, and options. None of the options
* is initially selected.
*
* The options objects should contain either instances of
* Component
s, (which are added directly) or
* Strings
(which are wrapped in a JButton
). If
* you provide Component
s, you must ensure that when the
* Component
is clicked it messages setValue
in
* the created CWOptionPane
.
*
* @param message
* the Object
to display
* @param messageType
* the type of message to be displayed:
* ERROR_MESSAGE
, INFORMATION_MESSAGE
,
* WARNING_MESSAGE
, QUESTION_MESSAGE
,
* or PLAIN_MESSAGE
* @param optionType
* the options to display in the pane:
* DEFAULT_OPTION
, YES_NO_OPTION
,
* YES_NO_CANCEL_OPTION
,
* OK_CANCEL_OPTION
* @param icon
* the Icon
image to display
* @param options
* the choices the user can select
*/
public CWOptionPane(Object message, int messageType, int optionType, Icon icon, Object[] options) {
this(message, messageType, optionType, icon, options, null);
GuiUtil.applyDefaultOrientation(this);
}
/**
* Creates an instance of CWOptionPane
to display a message
* with the specified message type, icon, and options, with the
* initially-selected option specified.
*
* @param message
* the Object
to display
* @param messageType
* the type of message to be displayed:
* ERROR_MESSAGE
, INFORMATION_MESSAGE
,
* WARNING_MESSAGE
, QUESTION_MESSAGE
,
* or PLAIN_MESSAGE
* @param optionType
* the options to display in the pane:
* DEFAULT_OPTION
, YES_NO_OPTION
,
* YES_NO_CANCEL_OPTION
,
* OK_CANCEL_OPTION
* @param icon
* the Icon image to display
* @param options
* the choices the user can select
* @param initialValue
* the choice that is initially selected; if null
,
* then nothing will be initially selected; only meaningful if
* options
is used
*/
public CWOptionPane(Object message, int messageType, int optionType, Icon icon, Object[] options, Object initialValue) {
super(message, messageType, optionType, icon, CWOptionPane.fixOptions(options, optionType, messageType), initialValue);
}
/**
* Shows a question-message dialog requesting input from the user. The
* dialog uses the default frame, which usually means it is centered on the
* screen.
*
* @param message
* the Object
to display
* @exception HeadlessException
* if GraphicsEnvironment.isHeadless
returns
* true
* @see java.awt.GraphicsEnvironment#isHeadless
*/
public static String showInputDialog(Object message) throws HeadlessException {
return showInputDialog(null, message);
}
/**
* Shows a question-message dialog requesting input from the user, with the
* input value initialized to initialSelectionValue
. The dialog
* uses the default frame, which usually means it is centered on the screen.
*
* @param message
* the Object
to display
* @param initialSelectionValue
* the value used to initialize the input field
*/
public static String showInputDialog(Object message, Object initialSelectionValue) {
return showInputDialog(null, message, initialSelectionValue);
}
/**
* Shows a question-message dialog requesting input from the user parented
* to parentComponent
. The dialog is displayed on top of the
* Component
's frame, and is usually positioned below the
* Component
.
*
* @param parentComponent
* the parent Component
for the dialog
* @param message
* the Object
to display
* @exception HeadlessException
* if GraphicsEnvironment.isHeadless
returns
* true
* @see java.awt.GraphicsEnvironment#isHeadless
*/
public static String showInputDialog(Component parentComponent, Object message) throws HeadlessException {
return showInputDialog(parentComponent, message, "?", QUESTION_MESSAGE);
}
/**
* Shows a question-message dialog requesting input from the user and
* parented to parentComponent
. The input value will be
* initialized to initialSelectionValue
. The dialog is
* displayed on top of the Component
's frame, and is usually
* positioned below the Component
.
*
* @param parentComponent
* the parent Component
for the dialog
* @param message
* the Object
to display
* @param initialSelectionValue
* the value used to initialize the input field
*/
public static String showInputDialog(Component parentComponent, Object message, Object initialSelectionValue) {
return (String) showInputDialog(parentComponent, message, "?", QUESTION_MESSAGE, null, null, initialSelectionValue);
}
/**
* Shows a dialog requesting input from the user parented to
* parentComponent
with the dialog having the title
* title
and message type messageType
.
*
* @param parentComponent
* the parent Component
for the dialog
* @param message
* the Object
to display
* @param title
* the String
to display in the dialog title bar
* @param messageType
* the type of message that is to be displayed:
* ERROR_MESSAGE
, INFORMATION_MESSAGE
,
* WARNING_MESSAGE
, QUESTION_MESSAGE
,
* or PLAIN_MESSAGE
* @exception HeadlessException
* if GraphicsEnvironment.isHeadless
returns
* true
* @see java.awt.GraphicsEnvironment#isHeadless
*/
public static String showInputDialog(Component parentComponent, Object message, String title, int messageType) throws HeadlessException {
return (String) showInputDialog(parentComponent, message, title, messageType, null, null, null);
}
/**
* Prompts the user for input in a blocking dialog where the initial
* selection, possible selections, and all other options can be specified.
* The user will able to choose from selectionValues
, where
* null
implies the user can input whatever they wish, usually
* by means of a JTextField
. initialSelectionValue
* is the initial value to prompt the user with. It is up to the UI to
* decide how best to represent the selectionValues
, but
* usually a JComboBox
, JList
, or
* JTextField
will be used.
*
* @param parentComponent
* the parent Component
for the dialog
* @param message
* the Object
to display
* @param title
* the String
to display in the dialog title bar
* @param messageType
* the type of message to be displayed:
* ERROR_MESSAGE
, INFORMATION_MESSAGE
,
* WARNING_MESSAGE
, QUESTION_MESSAGE
,
* or PLAIN_MESSAGE
* @param icon
* the Icon
image to display
* @param selectionValues
* an array of Object
s that gives the possible
* selections
* @param initialSelectionValue
* the value used to initialize the input field
* @return user's input, or null
meaning the user canceled the
* input
* @exception HeadlessException
* if GraphicsEnvironment.isHeadless
returns
* true
* @see java.awt.GraphicsEnvironment#isHeadless
*/
public static Object showInputDialog(Component parentComponent, Object message, String title, int messageType, Icon icon, Object[] selectionValues,
Object initialSelectionValue) throws HeadlessException
{
CWOptionPane pane = new CWOptionPane(message, messageType, OK_CANCEL_OPTION, icon, null, null);
pane.setWantsInput(true);
pane.setSelectionValues(selectionValues);
pane.setInitialSelectionValue(initialSelectionValue);
GuiUtil.applyDefaultOrientation(pane);
int style = styleFromMessageType(messageType);
JDialog dialog = pane.createDialog(parentComponent, title, style);
pane.selectInitialValue();
dialog.setVisible(true);
dialog.dispose();
Object value = pane.getInputValue();
if (value == UNINITIALIZED_VALUE) {
return null;
}
return value;
}
/**
* Brings up an information-message dialog titled "Message".
*
* @param parentComponent
* determines the Frame
in which the dialog is
* displayed; if null
, or if the
* parentComponent
has no Frame
, a
* default Frame
is used
* @param message
* the Object
to display
* @exception HeadlessException
* if GraphicsEnvironment.isHeadless
returns
* true
* @see java.awt.GraphicsEnvironment#isHeadless
*/
public static void showMessageDialog(Component parentComponent, Object message) throws HeadlessException {
showOptionDialog(parentComponent, message, "?", DEFAULT_OPTION, INFORMATION_MESSAGE, null, null, null);
}
/**
* Brings up a dialog that displays a message using a default icon
* determined by the messageType
parameter.
*
* @param parentComponent
* determines the Frame
in which the dialog is
* displayed; if null
, or if the
* parentComponent
has no Frame
, a
* default Frame
is used
* @param message
* the Object
to display
* @param title
* the title string for the dialog
* @param messageType
* the type of message to be displayed:
* ERROR_MESSAGE
, INFORMATION_MESSAGE
,
* WARNING_MESSAGE
, QUESTION_MESSAGE
,
* or PLAIN_MESSAGE
* @exception HeadlessException
* if GraphicsEnvironment.isHeadless
returns
* true
* @see java.awt.GraphicsEnvironment#isHeadless
*/
public static void showMessageDialog(Component parentComponent, Object message, String title, int messageType) throws HeadlessException {
showOptionDialog(parentComponent, message, title, DEFAULT_OPTION, messageType, null, null, null);
}
/**
* Brings up a dialog displaying a message, specifying all parameters.
*
* @param parentComponent
* determines the Frame
in which the dialog is
* displayed; if null
, or if the
* parentComponent
has no Frame
, a
* default Frame
is used
* @param message
* the Object
to display
* @param title
* the title string for the dialog
* @param messageType
* the type of message to be displayed:
* ERROR_MESSAGE
, INFORMATION_MESSAGE
,
* WARNING_MESSAGE
, QUESTION_MESSAGE
,
* or PLAIN_MESSAGE
* @param icon
* an icon to display in the dialog that helps the user identify
* the kind of message that is being displayed
* @exception HeadlessException
* if GraphicsEnvironment.isHeadless
returns
* true
* @see java.awt.GraphicsEnvironment#isHeadless
*/
public static void showMessageDialog(Component parentComponent, Object message, String title, int messageType, Icon icon) throws HeadlessException {
showOptionDialog(parentComponent, message, title, DEFAULT_OPTION, messageType, icon, null, null);
}
/**
* Brings up a dialog with the options Yes, No and
* Cancel; with the title, Select an Option.
*
* @param parentComponent
* determines the Frame
in which the dialog is
* displayed; if null
, or if the
* parentComponent
has no Frame
, a
* default Frame
is used
* @param message
* the Object
to display
* @return an integer indicating the option selected by the user
* @exception HeadlessException
* if GraphicsEnvironment.isHeadless
returns
* true
* @see java.awt.GraphicsEnvironment#isHeadless
*/
public static int showConfirmDialog(Component parentComponent, Object message) throws HeadlessException {
return showOptionDialog(parentComponent, message, "?", YES_NO_CANCEL_OPTION, QUESTION_MESSAGE, null, null, null);
}
/**
* Brings up a dialog where the number of choices is determined by the
* optionType
parameter.
*
* @param parentComponent
* determines the Frame
in which the dialog is
* displayed; if null
, or if the
* parentComponent
has no Frame
, a
* default Frame
is used
* @param message
* the Object
to display
* @param title
* the title string for the dialog
* @param optionType
* an int designating the options available on the dialog:
* YES_NO_OPTION
, or
* YES_NO_CANCEL_OPTION
* @return an int indicating the option selected by the user
* @exception HeadlessException
* if GraphicsEnvironment.isHeadless
returns
* true
* @see java.awt.GraphicsEnvironment#isHeadless
*/
public static int showConfirmDialog(Component parentComponent, Object message, String title, int optionType) throws HeadlessException {
return showOptionDialog(parentComponent, message, title, optionType, QUESTION_MESSAGE, null, null, null);
}
/**
* Brings up a dialog where the number of choices is determined by the
* optionType
parameter, where the messageType
* parameter determines the icon to display. The messageType
* parameter is primarily used to supply a default icon from the Look and
* Feel.
*
* @param parentComponent
* determines the Frame
in which the dialog is
* displayed; if null
, or if the
* parentComponent
has no Frame
, a
* default Frame
is used.
* @param message
* the Object
to display
* @param title
* the title string for the dialog
* @param optionType
* an integer designating the options available on the dialog:
* YES_NO_OPTION
, or
* YES_NO_CANCEL_OPTION
* @param messageType
* an integer designating the kind of message this is; primarily
* used to determine the icon from the pluggable Look and Feel:
* ERROR_MESSAGE
, INFORMATION_MESSAGE
,
* WARNING_MESSAGE
, QUESTION_MESSAGE
,
* or PLAIN_MESSAGE
* @return an integer indicating the option selected by the user
* @exception HeadlessException
* if GraphicsEnvironment.isHeadless
returns
* true
* @see java.awt.GraphicsEnvironment#isHeadless
*/
public static int showConfirmDialog(Component parentComponent, Object message, String title, int optionType, int messageType) throws HeadlessException {
return showOptionDialog(parentComponent, message, title, optionType, messageType, null, null, null);
}
/**
* Brings up a dialog with a specified icon, where the number of choices is
* determined by the optionType
parameter. The
* messageType
parameter is primarily used to supply a default
* icon from the look and feel.
*
* @param parentComponent
* determines the Frame
in which the dialog is
* displayed; if null
, or if the
* parentComponent
has no Frame
, a
* default Frame
is used
* @param message
* the Object to display
* @param title
* the title string for the dialog
* @param optionType
* an int designating the options available on the dialog:
* YES_NO_OPTION
, or
* YES_NO_CANCEL_OPTION
* @param messageType
* an int designating the kind of message this is, primarily used
* to determine the icon from the pluggable Look and Feel:
* ERROR_MESSAGE
, INFORMATION_MESSAGE
,
* WARNING_MESSAGE
, QUESTION_MESSAGE
,
* or PLAIN_MESSAGE
* @param icon
* the icon to display in the dialog
* @return an int indicating the option selected by the user
* @exception HeadlessException
* if GraphicsEnvironment.isHeadless
returns
* true
* @see java.awt.GraphicsEnvironment#isHeadless
*/
public static int showConfirmDialog(Component parentComponent, Object message, String title, int optionType, int messageType, Icon icon)
throws HeadlessException
{
return showOptionDialog(parentComponent, message, title, optionType, messageType, icon, null, null);
}
/**
* Brings up a dialog with a specified icon, where the initial choice is
* determined by the initialValue
parameter and the number of
* choices is determined by the optionType
parameter.
*
* If optionType
is YES_NO_OPTION
, or
* YES_NO_CANCEL_OPTION
and the options
parameter
* is null
, then the options are supplied by the look and feel.
*
* The messageType
parameter is primarily used to supply a
* default icon from the look and feel.
*
* @param parentComponent
* determines the Frame
in which the dialog is
* displayed; if null
, or if the
* parentComponent
has no Frame
, a
* default Frame
is used
* @param message
* the Object
to display
* @param title
* the title string for the dialog
* @param optionType
* an integer designating the options available on the dialog:
* YES_NO_OPTION
, or
* YES_NO_CANCEL_OPTION
* @param messageType
* an integer designating the kind of message this is, primarily
* used to determine the icon from the pluggable Look and Feel:
* ERROR_MESSAGE
, INFORMATION_MESSAGE
,
* WARNING_MESSAGE
, QUESTION_MESSAGE
,
* or PLAIN_MESSAGE
* @param icon
* the icon to display in the dialog
* @param options
* an array of objects indicating the possible choices the user
* can make; if the objects are components, they are rendered
* properly; non-String
objects are rendered using
* their toString
methods; if this parameter is
* null
, the options are determined by the Look and
* Feel
* @param initialValue
* the object that represents the default selection for the
* dialog; only meaningful if options
is used; can
* be null
* @return an integer indicating the option chosen by the user, or
* CLOSED_OPTION
if the user closed the dialog
* @exception HeadlessException
* if GraphicsEnvironment.isHeadless
returns
* true
* @see java.awt.GraphicsEnvironment#isHeadless
*/
public static int showOptionDialog(Component parentComponent, Object message, String title, int optionType, int messageType, Icon icon, Object[] options,
Object initialValue) throws HeadlessException
{
CWOptionPane pane = new CWOptionPane(message, messageType, optionType, icon, options, initialValue);
pane.setInitialValue(initialValue);
GuiUtil.applyDefaultOrientation(pane);
int style = styleFromMessageType(messageType);
JDialog dialog = pane.createDialog(parentComponent, title, style);
pane.selectInitialValue();
dialog.setVisible(true);
dialog.dispose();
Object selectedValue = pane.getValue();
if (selectedValue == null) {
return CLOSED_OPTION;
}
Object[] opts = pane.getOptions();
if (opts == null) {
if (selectedValue instanceof Integer) {
return ((Integer) selectedValue).intValue();
}
return CLOSED_OPTION;
}
if (getActionName("Yes").equals(selectedValue)) {
return YES_OPTION;
}
if (getActionName("No").equals(selectedValue)) {
return NO_OPTION;
}
if (getActionName("OK").equals(selectedValue)) {
return OK_OPTION;
}
if (getActionName("Cancel").equals(selectedValue)) {
return CANCEL_OPTION;
}
int maxCounter = opts.length;
for (int counter = 0; counter < maxCounter; counter++) {
if (opts[counter].equals(selectedValue)) {
return counter;
}
}
return CLOSED_OPTION;
}
private JDialog createDialog(Component parentComponent, String title, int style) throws HeadlessException {
final JDialog dialog;
Window window = GuiUtil.getWindow(parentComponent);
if (window instanceof Frame) {
dialog = new JDialog((Frame) window, title, true);
} else {
dialog = new JDialog((Dialog) window, title, true);
}
Container contentPane = dialog.getContentPane();
contentPane.setLayout(new BorderLayout());
contentPane.add(this, BorderLayout.CENTER);
dialog.setResizable(false);
if (JDialog.isDefaultLookAndFeelDecorated()) {
boolean supportsWindowDecorations = UIManager.getLookAndFeel().getSupportsWindowDecorations();
if (supportsWindowDecorations) {
dialog.setUndecorated(true);
getRootPane().setWindowDecorationStyle(style);
}
}
dialog.pack();
dialog.setLocationRelativeTo(parentComponent);
dialog.addWindowListener(new WindowAdapter() {
private boolean gotFocus;
@Override
public void windowClosing(WindowEvent we) {
setValue(null);
}
@Override
public void windowGainedFocus(WindowEvent we) {
// Once window gets focus, set initial focus
if (!gotFocus) {
selectInitialValue();
gotFocus = true;
}
}
});
dialog.addComponentListener(new ComponentAdapter() {
@Override
public void componentShown(ComponentEvent ce) {
// reset value to ensure closing works properly
setValue(JOptionPane.UNINITIALIZED_VALUE);
}
});
addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent event) {
// Let the defaultCloseOperation handle the closing
// if the user closed the window without selecting a button
// (newValue = null in that case). Otherwise, close the dialog.
if (dialog.isVisible() && event.getSource() == CWOptionPane.this && event.getPropertyName().equals(VALUE_PROPERTY)
&& event.getNewValue() != null && event.getNewValue() != JOptionPane.UNINITIALIZED_VALUE)
{
dialog.setVisible(false);
}
}
});
GuiUtil.applyDefaultOrientation(dialog);
return dialog;
}
private static int styleFromMessageType(int messageType) {
switch (messageType) {
case ERROR_MESSAGE:
return JRootPane.ERROR_DIALOG;
case QUESTION_MESSAGE:
return JRootPane.QUESTION_DIALOG;
case WARNING_MESSAGE:
return JRootPane.WARNING_DIALOG;
case INFORMATION_MESSAGE:
return JRootPane.INFORMATION_DIALOG;
case PLAIN_MESSAGE:
default:
return JRootPane.PLAIN_DIALOG;
}
}
private static String getActionName(String key) {
return actions.findAction(key).getValue(Action.NAME).toString();
}
private static Object[] fixOptions(Object[] options, int optionType, int messageType) {
Object[] opts = options;
if (options == null) {
if (optionType == YES_NO_OPTION) {
opts = new Object[] {
getActionName("Yes"),
getActionName("No")
};
} else if (optionType == OK_CANCEL_OPTION) {
opts = new Object[] {
getActionName("OK"),
getActionName("Cancel")
};
} else if (optionType == YES_NO_CANCEL_OPTION && messageType != INFORMATION_MESSAGE) {
opts = new Object[] {
getActionName("Yes"),
getActionName("No"),
getActionName("Cancel")
};
} else {
opts = new Object[] {
getActionName("OK"),
};
}
}
return opts;
}
/**
* The actions for this dialog.
*/
private static ActionFactory actions = new ActionFactory(null);
static {
// TRANSLATOR: This is the text on a "Yes" button.
actions.addAction("Yes", BDMsg.gettext("Yes"));
// TRANSLATOR: This is the text on a "No" button.
actions.addAction("No", BDMsg.gettext("No"));
// TRANSLATOR: This is the text on an "OK" button.
actions.addAction("OK", BDMsg.gettext("OK"));
// TRANSLATOR: This is the text on a "Cancel" button.
actions.addAction("Cancel", BDMsg.gettext("Cancel"));
}
/**
* Serialization ID
*/
private static final long serialVersionUID = -1870422750863765033L;
}