/* class JOptionPane
*
* Copyright (C) 2001-2003 R M Pitman
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package charvax.swing;
import charva.awt.BorderLayout;
import charva.awt.Component;
import charva.awt.Dimension;
import charva.awt.FlowLayout;
import charva.awt.Point;
import charva.awt.Toolkit;
import charva.awt.event.ActionEvent;
import charva.awt.event.ActionListener;
import charva.awt.event.KeyEvent;
import charva.awt.event.KeyListener;
import charvax.swing.border.EmptyBorder;
/**
* <p>JOptionPane makes it easy to pop up a standard dialog box that prompts
* the user for information or displays some information.</p>
*
* <p>The labels of the option-buttons displayed within the popup dialog can be
* customized by changing static variables in the JOptionPane class.
* Similarly, "accelerator keys" can be set to have the same effect
* as the option-buttons. For example, the following code would set
* the label of the OK button to "OK (F1)", and set the F1 key to
* have the same effect as the OK button:</p>
* <pre>
* JOptionPane.OK_LABEL = "OK (F1)";
* JOptionPane.OK_ACCELERATOR = KeyEvent.VK_F1;
* </pre>
* <p>Note that after the buttons have been customized, they stay customized
* for all future invocations of the JOptionPane "showXXXDialog()" methods.</p>
*
* <p>The parameters to these methods follow consistent patterns:</p>
* <blockquote>
* <dl>
* <dt>parentComponent
* <dd>Defines the Component that is to be the parent of this dialog
* box. It is used in two ways: its screen coordinates are
* used in the placement of the dialog box, and the dialog box inherits its
* foreground and background colors from <code>parentComponent</code> (unless
* the the JOptionPane's colors have been set explicitly). In general, the
* dialog box centered on top of <code>parentComponent</code>. This parameter
* may be null, in which case a default Frame is used as the parent, and
* the dialog will be centered on the screen.<p>
*
* <dt>message
* <dd>A descriptive message to be placed in the dialog box. In the
* most common usage, message is just a String or String constant.
* However, the type of this parameter is actually Object. Its
* interpretation depends on its type:
*
* <blockquote>
* <dl>
* <dt>String
* <dd>The string is displayed as a message on one line.
* <dt>Object[]
* <dd>An array of Objects is interpreted as a series of messages
* arranged in a vertical stack. Each Object is converted to a String
* using its toString() method. The result is wrapped in a JLabel and displayed.
* </dl>
* </blockquote>
* <p>
* <dt>messageType
* <dd>Defines the style of the message. The possible values are:
* <ul>
* <li><code>ERROR_MESSAGE</code>
* <li><code>INFORMATION_MESSAGE</code>
* <li><code>WARNING_MESSAGE</code>
* <li><code>QUESTION_MESSAGE</code>
* <li><code>PLAIN_MESSAGE </code>
* </ul><p>
* <dt>optionType
* <dd>Defines the set of option buttons that appear at the bottom of the dialog box:
* <ul>
* <li><code>DEFAULT_OPTION</code>
* <li><code>YES_NO_OPTION</code>
* <li><code>YES_NO_CANCEL_OPTION</code>
* <li><code>OK_CANCEL_OPTION</code>
* </ul>
* You aren't limited to this set of option buttons. You can
* provide any buttons you want using the <code>options</code> parameter.<p>
*
* <dt>options
* <dd>A more detailed description of the set of option buttons that
* will appear at the bottom of the dialog box. The usual value for the
* options parameter is an array of Strings. But the parameter type is
* an array of Objects. A button is created for each object depending on
* its type:<p>
* <dl>
* <dt>Component
* <dd>The component is added to the button row directly.
* <dt>other
* <dd>The Object is converted to a string using its toString method
* and the result is used to label a JButton.
* </dl>
* <p>
* <dt>icon
* <dd>This parameter is used in javax.Swing to specify a decorative
* icon to be placed in the dialog box. It is ignored by Charva.<p>
* <dt>title
* <dd>The title for the dialog box. <p>
* <dt>initialValue
* <dd>The default selection (input value). <p>
* </dl>
* </blockquote>
*/
public class JOptionPane
{
/** Creates a JOptionPane with a test message */
public JOptionPane() {
this("This is a test message", PLAIN_MESSAGE, DEFAULT_OPTION, null, null, null);
}
/**
* Creates an instance of JOptionPane to display the specified message.
* @param message_ the message to display. It can be a String
* or an array of Strings. If it is an array of Strings, they are
* stacked vertically.
*/
public JOptionPane(Object message_) {
this(message_, PLAIN_MESSAGE, DEFAULT_OPTION, null, null, null);
}
/**
* Creates an instance of JOptionPane to display the specified message.
* @param message_ the message to display. It can be a String
* or an array of Strings.
* @param messagetype_ is ignored. It is used in javax.swing to
* determine which icon to display.
*/
public JOptionPane(Object message_, int messagetype_) {
this(message_, messagetype_, DEFAULT_OPTION, null, null, null);
}
/**
* Creates an instance of JOptionPane to display the specified message.
* @param message_ the message to display. It can be a String
* or an array of Strings.
* @param messagetype_ is ignored. It is used in javax.swing to
* determine which icon to display.
* @param optiontype_ determines which option-buttons to display. Allowed
* values are: DEFAULT_OPTION, YES_NO_OPTION, YES_NO_CANCEL_OPTION, and
* OK_CANCEL_OPTION.
*/
public JOptionPane(Object message_, int messagetype_, int optiontype_) {
this(message_, messagetype_, optiontype_, null, null, null);
}
/**
* Creates an instance of JOptionPane to display the specified message.
* @param message_ the message to display. It can be a String
* or an array of Strings.
* @param messageType_ is ignored. It is used in javax.swing to
* determine which icon to display.
* @param optionType_ determines which option-buttons to display. Allowed
* values are: DEFAULT_OPTION, YES_NO_OPTION, YES_NO_CANCEL_OPTION, and
* OK_CANCEL_OPTION.
* @param icon_ the Icon image to display (not used by Charva; it is here
* for compatibility with Swing).
* @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 JOptionPane(Object message_, int messageType_, int optionType_,
Object icon_, Object[] options_, Object initialValue_)
{
_message = message_;
_messagetype = messageType_;
_optiontype = optionType_;
_options = options_;
_initialValue = initialValue_;
}
/** If newvalue_ is true, a JTextField will be displayed for
* the user to provide text input.
*/
public void setWantsInput(boolean newvalue_) {
_wantsInput = newvalue_;
}
/** Returns the value of _wantsInput.
*/
public boolean getWantsInput() {
return _wantsInput;
}
/** Sets the default input value that is displayed to the user.
* Only used if <code>_wantsInput</code> is true.
*/
public void setInitialSelectionValue(Object value_) {
_inputValue = (String) value_;
}
/** Sets the initial value of the text field for the user to modify.
*/
public void setInputValue(Object value_) {
_inputValue = (String) value_;
}
/** Returns the value the user has input, (relevant only if
* _wantsInput is true).
*/
public Object getInputValue() {
return _inputValue;
}
/** Sets the options this pane displays in the button-panel at
* the bottom. If an element in
* newOptions is an instance of a subclass of AbstractButton (for
* example, a JButton), it is added directly to the pane,
* otherwise a button is created for the element. The advantage
* of adding a button rather than a string is that a mnemonic
* can be set for the button.
*/
public void setOptions(Object[] newOptions_) {
_options = newOptions_;
}
/** Returns the choices the user can make.
*/
public Object[] getOptions() {
return _options;
}
/** Sets the initial value that is to be enabled -- the Component
* that has the focus when the pane is initially displayed.
* (NOT IMPLEMENTED YET).
*/
public void setInitialValue(Object initialValue_) {
}
/** Returns the initial value that is to be enabled -- the Component
* that has the focus when the pane is initially displayed.
* (NOT IMPLEMENTED YET).
*/
public Object getInitialValue() {
return null;
}
/**
* Creates and returns a new JDialog for displaying the required
* message. The dialog inherits the foreground and background colors
* of the <code>owner_</code> component and is centered on it.
* If <code>owner_</code> is null, default (black/white) colors are used.
*/
public JDialog createDialog(Component owner_, String title_) {
/* This is a non-static inner class used for a popup dialog.
*/
JOptionPane.Popup dlg = null;
dlg = this.new Popup(owner_, _message, title_);
if (owner_ != null)
dlg.setLocationRelativeTo(owner_);
return dlg;
}
/**
* Brings up a dialog where the number of choices is dependent on the
* value of the optiontype_ parameter.
* @param parent_ Determines the frame in which the dialog is displayed.
* @param message_ the String to display.
* @param title_ the title of the dialog.
* @param optiontype_ must be YES_NO_OPTION or YES_NO_CANCEL_OPTION.
*/
public static int showConfirmDialog(Component parent_,
Object message_, String title_, int optiontype_) {
JOptionPane pane = new JOptionPane(message_, PLAIN_MESSAGE, optiontype_);
Popup dialog = (Popup) pane.createDialog(parent_, title_);
dialog.show();
return ((Integer) pane.getValue()).intValue();
}
/**
* Brings up a dialog that allows the user to input a value.
* @param parent_ Determines the frame in which the dialog is displayed.
* @param message_ the String to display.
* @param title_ the title of the dialog.
* @param messagetype_ is ignored (it is used in javax.swing to determine
* which icon to display).
*/
public static String showInputDialog(Component parent_,
Object message_, String title_, int messagetype_) {
JOptionPane pane = new JOptionPane(message_,
messagetype_, OK_CANCEL_OPTION);
pane._wantsInput = true;
Popup dialog = (Popup) pane.createDialog(parent_, title_);
dialog.show();
int option = ((Integer) pane.getValue()).intValue();
if (option == CANCEL_OPTION)
return null;
else
return (String) pane.getInputValue();
}
/**
* Brings up a confirmation dialog titled "Confirm"
*/
public static void showMessageDialog(Component parent_, Object message_) {
showMessageDialog(parent_, message_, "Confirm", DEFAULT_OPTION);
}
/**
* Brings up a confirmation dialog with the specified title. The
* msgtype parameter is ignored (it is used in the javax.swing package to
* specify an icon to display).
*/
public static void showMessageDialog(Component parent_,
Object message_, String title_, int msgtype_) {
JOptionPane pane = new JOptionPane(message_, msgtype_, DEFAULT_OPTION);
JDialog dialog = pane.createDialog(parent_, title_);
dialog.show();
}
/** Returns the option the user has selected.
*/
public Object getValue() {
return _value;
}
// INSTANCE VARIABLES
protected Object _message;
protected int _messagetype;
/** Determines which option buttons to display (unless an array
* of options is explicitly specified with <code>setOptions()</code>).
*/
protected int _optiontype;
/** If true, an TextField will be displayed for the user to provide
* input.
*/
protected boolean _wantsInput = false;
protected String _inputValue = "";
/** Array of options to display to the user in the bottom button-panel.
* The objects in this array can be any combination of Strings or
* components which are subclasses of AbstractButton.
* Buttons are just added to the bottom button-panel; Strings are
* wrapped in a JButton which is then added to the button-panel.
*/
protected Object[] _options;
/** Option that should be initially selected in <code>_options</code>.
*/
protected Object _initialValue;
/** The currently selected option.
*/
protected Object _value;
// Message types
public static final int ERROR_MESSAGE = 100;
public static final int INFORMATION_MESSAGE = 101;
public static final int WARNING_MESSAGE = 102;
public static final int QUESTION_MESSAGE = 103;
public static final int PLAIN_MESSAGE = 104;
// Option types
public static final int DEFAULT_OPTION = 200;
public static final int YES_NO_OPTION = 201;
public static final int YES_NO_CANCEL_OPTION = 202;
public static final int OK_CANCEL_OPTION = 203;
// Return values
public static final int YES_OPTION = 300;
public static final int NO_OPTION = 301;
public static final int CANCEL_OPTION = 302;
public static final int OK_OPTION = 303;
public static final int CLOSED_OPTION = 304;
// Label values - can be changed to customize appearance
public static String YES_LABEL = "Yes";
public static String NO_LABEL = "No";
public static String CANCEL_LABEL = "Cancel";
public static String OK_LABEL = "OK";
// Accelerator keystrokes - can be customized.
public static int YES_ACCELERATOR = -1;
public static int NO_ACCELERATOR = -1;
public static int CANCEL_ACCELERATOR = -1;
public static int OK_ACCELERATOR = -1;
//====================================================================
/** This is a non-static inner class used for the popup dialog that
* JOptionPane creates.
*/
private class Popup
extends JDialog
implements ActionListener, KeyListener
{
/** Constructor
*/
Popup(Component owner_, Object message_, String title_) {
super();
// The window inherits the colors of its parent if there is one,
// otherwise the default colors are used.
if (owner_ != null) {
super.setForeground(owner_.getForeground());
super.setBackground(owner_.getBackground());
}
else {
super.setForeground(Toolkit.getDefaultForeground());
super.setBackground(Toolkit.getDefaultBackground());
}
setTitle(title_);
_ownerComponent = owner_;
setLayout(new BorderLayout());
JPanel northpan = new JPanel();
northpan.setBorder(new EmptyBorder(2,2,1,2));
JPanel messagepanel = new JPanel();
if (message_ instanceof String) {
messagepanel.add(new JLabel((String) message_));
}
else if (message_ instanceof Object[]) {
messagepanel.setLayout(
new BoxLayout(getOwner(), BoxLayout.Y_AXIS));
Object[] objects = (Object[]) message_;
for (int i=0; i<objects.length; i++) {
messagepanel.add(new JLabel(objects[i].toString()));
}
}
else {
throw new IllegalArgumentException("illegal message type " +
message_.getClass().getName());
}
northpan.add(messagepanel);
add(northpan, BorderLayout.NORTH);
if (_wantsInput) {
JPanel centerpan = new JPanel();
centerpan.setBorder(new EmptyBorder(1, 1, 1, 1));
_inputField = new JTextField(_inputValue, 20);
_inputField.addActionListener(this);
centerpan.add(_inputField);
add(centerpan, BorderLayout.CENTER);
}
JPanel southpan = new JPanel();
southpan.setLayout(new FlowLayout(FlowLayout.CENTER, 1, 1));
if (_options != null) {
// Option buttons were explicitly specified.
for (int i=0; i<_options.length; i++) {
AbstractButton button = null;
if (_options[i] instanceof String)
button = new JButton((String) _options[i]);
else if (_options[i] instanceof AbstractButton)
button = (AbstractButton) _options[i];
button.addActionListener(this);
southpan.add(button);
}
}
else {
// Decide which option buttons to display, based on the
// value of _optiontype.
if (_optiontype == DEFAULT_OPTION ||
_optiontype == OK_CANCEL_OPTION) {
_okButton = new JButton("OK");
_okButton.setText(OK_LABEL);
_okButton.addActionListener(this);
southpan.add(_okButton);
}
if (_optiontype == YES_NO_OPTION ||
_optiontype == YES_NO_CANCEL_OPTION) {
_yesButton = new JButton("Yes");
_yesButton.setText(YES_LABEL);
_yesButton.addActionListener(this);
southpan.add(_yesButton);
}
if (_optiontype == YES_NO_OPTION ||
_optiontype == YES_NO_CANCEL_OPTION) {
_noButton = new JButton("No");
_noButton.setText(NO_LABEL);
_noButton.addActionListener(this);
southpan.add(_noButton);
}
if (_optiontype == YES_NO_CANCEL_OPTION ||
_optiontype == OK_CANCEL_OPTION) {
_cancelButton = new JButton("Cancel");
_cancelButton.setText(CANCEL_LABEL);
_cancelButton.addActionListener(this);
southpan.add(_cancelButton);
}
}
add(southpan, BorderLayout.SOUTH);
setSize(Toolkit.getDefaultToolkit().getScreenSize());
pack();
Dimension msgsize = messagepanel.getSize();
setSize(msgsize.width+8, msgsize.height+9);
pack();
/* Center the dialog over its parent component.
*/
Dimension ourSize = getSize();
if (_ownerComponent != null) {
Point ownerOrigin = _ownerComponent.getLocationOnScreen();
Dimension ownerSize = _ownerComponent.getSize();
Point ownerCenter = ownerOrigin.addOffset(
ownerSize.width/2, ownerSize.height/2);
setLocation(ownerCenter.addOffset(
-ourSize.width/2, -ourSize.height/2));
}
else {
/* The parent component was not specified. Center this
* dialog box in the middle of the screen.
*/
Dimension screensize =
Toolkit.getDefaultToolkit().getScreenSize();
Point screenCenter = new Point(screensize.width/2,
screensize.height/2);
setLocation(screenCenter.addOffset(
-ourSize.width/2, -ourSize.height/2));
}
// Add a KeyListener in case one or more accelerators were set.
addKeyListener(this);
}
/** Gets called when the user presses an option-button (or
* if ENTER is pressed while focus is in the TextField).
*/
public void actionPerformed(ActionEvent e_) {
if (_wantsInput)
_inputValue = _inputField.getText();
if (_options != null) {
// Options were specified explicitly.
// So ignore ENTER if pressed while focus is in textfield.
if (e_.getSource() == _inputField)
return;
AbstractButton source = (AbstractButton) e_.getSource();
for (int i=0; i < _options.length; i++) {
if (_options[i] instanceof String &&
source.getText().equals(_options[i]) ) {
_value = _options[i];
break;
}
else if (source == _options[i]) {
_value = source;
break;
}
}
}
else {
// Options were not specified explicitly.
Object source = e_.getSource();
if ( source == _okButton || source == _inputField) {
_value = new Integer(JOptionPane.OK_OPTION);
}
else if (source == _yesButton) {
_value = new Integer(JOptionPane.YES_OPTION);
}
else if (source == _noButton) {
_value = new Integer(JOptionPane.NO_OPTION);
}
else if (source == _cancelButton) {
_value = new Integer(JOptionPane.CANCEL_OPTION);
}
}
hide();
}
public void keyPressed(KeyEvent e_) {
int key = e_.getKeyCode();
if (key == OK_ACCELERATOR &&
(_optiontype == DEFAULT_OPTION ||
_optiontype == OK_CANCEL_OPTION)) {
_value = new Integer(JOptionPane.OK_OPTION);
_inputValue = _inputField.getText();
hide();
}
else if (key == YES_ACCELERATOR &&
(_optiontype == YES_NO_OPTION ||
_optiontype == YES_NO_CANCEL_OPTION)) {
_value = new Integer(JOptionPane.YES_OPTION);
_inputValue = _inputField.getText();
hide();
}
else if (key == NO_ACCELERATOR &&
(_optiontype == YES_NO_OPTION ||
_optiontype == YES_NO_CANCEL_OPTION)) {
_value = new Integer(JOptionPane.NO_OPTION);
hide();
}
else if (key == CANCEL_ACCELERATOR &&
(_optiontype == YES_NO_CANCEL_OPTION ||
_optiontype == OK_CANCEL_OPTION)) {
_value = new Integer(JOptionPane.CANCEL_OPTION);
hide();
}
}
public void keyTyped(KeyEvent e_) {
}
public void keyReleased(KeyEvent e_) { }
private Component _ownerComponent;
private JButton _okButton;
private JButton _yesButton;
private JButton _noButton;
private JButton _cancelButton;
private JTextField _inputField = new JTextField(20);
}
}