/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is NetBeans. The Initial Developer of the Original
* Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
* Microsystems, Inc. All Rights Reserved.
*/
package org.openide;
import java.beans.*;
import java.lang.reflect.InvocationTargetException;
import javax.swing.JOptionPane;
import java.awt.BorderLayout;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.border.*;
import javax.swing.JPanel;
import java.awt.Component;
import org.openide.util.NbBundle;
/**
* This class provides a description of a user notification to be displayed.
* <p>Simple example of usage:
* <pre>
* NotifyDescriptor d =
* new NotifyDescriptor.Message("Hello...", NotifyDescriptor.INFORMATION_MESSAGE);
* DialogDisplayer.getDefault().notify(d);
* </pre>
* or to get a result:
* <pre>
* NotifyDescriptor d =
* new NotifyDescriptor.Confirmation("Really do this?!", "Dialog Title",
* NotifyDescriptor.OK_CANCEL_OPTION);
* if (DialogDisplayer.getDefault().notify(d) == NotifyDescriptor.OK_OPTION) {
* // really do it...
* }
* </pre>
* @see DialogDisplayer#notify
* @author David Peroutka, Jaroslav Tulach
*/
public class NotifyDescriptor extends Object {
// Property constants
/** Name of property for the message to be displayed. */
public static final String PROP_MESSAGE = "message"; // NOI18N
/** Name of property for the type of message to use. */
public static final String PROP_MESSAGE_TYPE = "messageType"; // NOI18N
/** Name of property for the style of options available. */
public static final String PROP_OPTION_TYPE = "optionType"; // NOI18N
/** Name of property for the exact list of options. */
public static final String PROP_OPTIONS = "options"; // NOI18N
/** Name of property for the value the user selected. */
public static final String PROP_VALUE = "value"; // NOI18N
/** Name of property for the dialog title. */
public static final String PROP_TITLE = "title"; // NOI18N
/** Name of property for the detail message reported. */
public static final String PROP_DETAIL = "detail"; // NOI18N
/** Name of property for the OK button validation. */
public static final String PROP_VALID = "valid"; // NOI18N
//
// Properties
//
/** The message object specifying the message. */
private Object message;
/** The message type. */
private int messageType = PLAIN_MESSAGE;
/** The option type specifying the user-selectable options. */
private int optionType;
/** The option object specifying the user-selectable options. */
private Object[] options;
/** The option object specifying the additional user-selectable options. */
private Object[] adOptions;
/** The user's choice value object. */
private Object value;
/** The title string for the report. */
private String title;
/** Is OK button valid (enabled). */
private boolean valid = true;
/** The object specifying the detail object. */
// private Object detail;
/** Property change support. */
private PropertyChangeSupport changeSupport;
//
// Return values
//
/** Return value if YES is chosen. */
public static final Object YES_OPTION = new Integer(JOptionPane.YES_OPTION);
/** Return value if NO is chosen. */
public static final Object NO_OPTION = new Integer(JOptionPane.NO_OPTION);
/** Return value if CANCEL is chosen. */
public static final Object CANCEL_OPTION = new Integer(JOptionPane.CANCEL_OPTION);
/** Return value if OK is chosen. */
public static final Object OK_OPTION = new Integer(JOptionPane.OK_OPTION);
/** Return value if user closes the window without pressing any button. */
public static final Object CLOSED_OPTION = new Integer(JOptionPane.CLOSED_OPTION);
//
// Option types
//
/** Option type used by default. */
public static final int DEFAULT_OPTION = JOptionPane.DEFAULT_OPTION;
/** Option type used for negatable confirmations. */
public static final int YES_NO_OPTION = JOptionPane.YES_NO_OPTION;
/** Option type used for negatable and cancellable confirmations. */
public static final int YES_NO_CANCEL_OPTION = JOptionPane.YES_NO_CANCEL_OPTION;
/** Option type used for cancellable confirmations. */
public static final int OK_CANCEL_OPTION = JOptionPane.OK_CANCEL_OPTION;
//
// Message types
//
/** Message type for error messages. */
public static final int ERROR_MESSAGE = JOptionPane.ERROR_MESSAGE;
/** Message type for information messages. */
public static final int INFORMATION_MESSAGE = JOptionPane.INFORMATION_MESSAGE;
/** Message type for warning messages. */
public static final int WARNING_MESSAGE = JOptionPane.WARNING_MESSAGE;
/** Message type for questions. */
public static final int QUESTION_MESSAGE = JOptionPane.QUESTION_MESSAGE;
/** Plain message type using no icon. */
public static final int PLAIN_MESSAGE = JOptionPane.PLAIN_MESSAGE;
/** Maximum text width to which the text is wrapped */
private static final int MAXIMUM_TEXT_WIDTH = 100;
/**
* Creates a new notify descriptor with specified information to report.
*
* If <code>optionType</code> is {@link #YES_NO_OPTION} or {@link #YES_NO_CANCEL_OPTION}
* and the <code>options</code> parameter is <code>null</code>, then the options are
* supplied by the look and feel.
*
* The <code>messageType</code> parameter is primarily used to supply a
* default icon from the look and feel.
*
* @param message the object to display
* @param title the title string for the dialog
* @param optionType indicates which options are available
* @param messageType indicates what type of message should be displayed
* @param options an array of objects indicating the possible choices
* @param initialValue the object that represents the default value
*
* @see #getMessage
* @see #getMessageType
* @see #getOptions
* @see #getOptionType
* @see #getValue
*/
public NotifyDescriptor(Object message,
String title,
int optionType,
int messageType,
Object[] options,
Object initialValue)
{
this.message = message;
this.messageType = messageType;
this.options = options;
this.optionType = optionType;
this.title = title;
this.value = initialValue;
}
/** Method that is called before a value is returned from any of
* getter methods in this object.
*
* Allows subclasses to do some additional initialization actions.
*/
protected void initialize () {
}
/** Checks for initialization.
*/
final void getterCalled () {
if (changeSupport != null) {
return;
}
boolean init = false;
synchronized (this) {
if (changeSupport == null) {
changeSupport = new java.beans.PropertyChangeSupport(this);
init = true;
}
}
if (init) {
initialize ();
}
}
//
// Getters/setters for properties.
//
/**
* Return true if OK button is valid (enabled), otherwise return false.
* @see #setValid
*
* @return validity status of OK button.
*/
public final boolean isValid() {
getterCalled ();
return valid;
}
/**
* Set validity of OK button.
* @see #isValid
*/
public final void setValid(boolean newValid) {
boolean oldValid = valid;
valid = newValid;
firePropertyChange(PROP_VALID,
oldValid ? Boolean.TRUE : Boolean.FALSE,
newValid ? Boolean.TRUE : Boolean.FALSE);
}
/**
* Define a descriptive message to be reported. In the most common
* usage, the message is just a <code>String</code>. However, the type
* of this parameter is actually <code>Object</code>. Its interpretation depends on
* its type:
* <dl compact>
* <dt><code>Object[]</code><dd> A recursively interpreted series of messages.
* <dt>{@link Component}<dd> The <code>Component</code> is displayed in the dialog.
* <dt>{@link javax.swing.Icon}<dd> The <code>Icon</code> is wrapped in a {@link JLabel} and displayed in the dialog.
* <dt>anything else<dd> The {@link Object#toString string representation} of the object.
* </dl>
*
* @param newMessage the <code>Object</code> to report
* @see #getMessage
*/
public void setMessage(Object newMessage) {
Object oldMessage = message;
message = newMessage;
firePropertyChange(PROP_MESSAGE, oldMessage, newMessage);
}
/**
* Get the message object.
* @see #setMessage
*
* @return the <code>Object</code> that is to be reported
*/
public Object getMessage() {
getterCalled ();
return message;
}
/**
* Define the style of the message. The look and feel manager may lay out
* the dialog differently depending on this value, and will often provide
* a default icon. The possible values are:
* <ul>
* <li>{@link #ERROR_MESSAGE}
* <li>{@link #INFORMATION_MESSAGE}
* <li>{@link #WARNING_MESSAGE}
* <li>{@link #QUESTION_MESSAGE}
* <li>{@link #PLAIN_MESSAGE}
* </ul>
*
* @param newType the kind of message
*
* @see #getMessageType
*/
public void setMessageType(int newType) {
if (newType != ERROR_MESSAGE && newType != INFORMATION_MESSAGE &&
newType != WARNING_MESSAGE && newType != QUESTION_MESSAGE && newType != PLAIN_MESSAGE)
throw new IllegalArgumentException(
"Message type must be one of the following:" // NOI18N
+ " ERROR_MESSAGE, INFORMATION_MESSAGE," // NOI18N
+ " WARNING_MESSAGE, QUESTION_MESSAGE or PLAIN_MESSAGE." // NOI18N
);
int oldType = messageType;
messageType = newType;
firePropertyChange(PROP_MESSAGE_TYPE, new Integer(oldType), new Integer(messageType));
}
/**
* Get the message type.
*
* @return the message type
*
* @see #setMessageType
*/
public int getMessageType() {
getterCalled ();
return messageType;
}
/**
* Define the set of options. The option type is used by the look and
* feel to determine what options to show (unless explicit options are supplied):
* <ul>
* <li>{@link #DEFAULT_OPTION}
* <li>{@link #YES_NO_OPTION}
* <li>{@link #YES_NO_CANCEL_OPTION}
* <li>{@link #OK_CANCEL_OPTION}
* </ul>
*
* @param newType the options the look and feel is to display
*
* @see #getOptionType
* @see #setOptions
*/
public void setOptionType(int newType) {
if (newType != DEFAULT_OPTION && newType != YES_NO_OPTION &&
newType != YES_NO_CANCEL_OPTION && newType != OK_CANCEL_OPTION)
throw new IllegalArgumentException(
"Option type must be one of the following:" // NOI18N
+ " DEFAULT_OPTION, YES_NO_OPTION," // NOI18N
+ " YES_NO_CANCEL_OPTION or OK_CANCEL_OPTION." // NOI18N
);
int oldType = optionType;
optionType = newType;
firePropertyChange(PROP_OPTION_TYPE, new Integer(oldType), new Integer(optionType));
}
/**
* Get the type of options that are to be displayed.
*
* @return the option type
*
* @see #setOptionType
*/
public int getOptionType() {
getterCalled ();
return optionType;
}
/**
* Define an explicit description of the set of user-selectable options.
* The usual value for the options parameter is an array of
* <code>String</code>s. But the parameter type is an array of <code>Object</code>s. Its
* interpretation depends on its type:
* <dl compact>
* <dt>{@link Component}<dd>The component is added to the button row directly.
* <dt>{@link javax.swing.Icon}<dd>A {@link javax.swing.JButton} is created with this icon as its label.
* <dt>anything else<dd>The <code>Object</code> is {@link Object#toString converted} to a string and the result is used to
* label a <code>JButton</code>.
* </dl>
*
* @param newOptions an array of user-selectable options
*
* @see #getOptions
*/
public void setOptions(Object[] newOptions) {
Object[] oldOptions = options;
options = newOptions;
firePropertyChange(PROP_OPTIONS, oldOptions, newOptions);
}
/**
* Get the explicit choices the user can make.
* @return the array of <code>Object</code>s that give the user's choices
*
* @see #setOptions
*/
public Object[] getOptions() {
getterCalled ();
if (options != null) {
return (Object[])options.clone ();
}
return options;
}
/**
* Define an explicit description of the set of additional user-selectable options.
* Additional options are supposed to be used for help button, etc.
* <P>
* The usual value for the options parameter is an array of
* <code>String</code>s. But the parameter type is an array of <code>Object</code>s. Its
* interpretation depends on its type:
* <dl compact>
* <dt>{@link Component}<dd>The component is added to the button row directly.
* <dt>{@link javax.swing.Icon}<dd>A {@link javax.swing.JButton} is created with this icon as its label.
* <dt>anything else<dd>The <code>Object</code> is {@link Object#toString converted} to a string and the result is used to
* label a <code>JButton</code>.
* </dl>
*
* @param newOptions an array of user-selectable options
*
* @see #getOptions
*/
public void setAdditionalOptions(Object[] newOptions) {
Object[] oldOptions = adOptions;
adOptions = newOptions;
firePropertyChange(PROP_OPTIONS, oldOptions, newOptions);
}
/**
* Get the explicit additional choices the user can make.
* @return the array of <code>Object</code>s that give the user's choices
*
* @see #setOptions
*/
public Object[] getAdditionalOptions() {
getterCalled ();
if (adOptions != null) {
return (Object[])adOptions.clone ();
}
return null;
}
/**
* Set the value the user has chosen.
* You probably do not want to call this yourself, of course.
*
* @param newValue the chosen value
*
* @see #getValue
*/
public void setValue(Object newValue) {
Object oldValue = value;
value = newValue;
firePropertyChange(PROP_VALUE, oldValue, newValue);
}
/**
* Get the value the user has selected.
*
* @return an <code>Object</code> indicating the option selected by the user
*
* @see #setValue
*/
public Object getValue() {
getterCalled ();
return value;
}
/**
* Set the title string for this report description.
*
* @param newTitle the title of this description
*
* @see #getTitle
*/
public void setTitle(String newTitle) {
Object oldTitle = title;
title = newTitle;
firePropertyChange(PROP_TITLE, oldTitle, newTitle);
}
/**
* Get the title string for this report description.
*
* @return the title of this description
*
* @see #setTitle
*/
public String getTitle() {
getterCalled ();
return title;
}
/**
* Define a detail message to be reported. In the most common usage,
* this message is just a <code>String</code>. However, the type of this
* parameter is actually <code>Object</code>. Its interpretation depends on its type:
* <dl compact>
* <dt><code>Object[]</code><dd> A recursively interpreted series of messages.
* <dt><code>Throwable</code><dd> A stack trace is displayed.
* <dt>anything else<dd> The {@link Object#toString string representation} of the object is used.
* </dl>
*
* @param newDetail the detail object of this description
*
* @see #getDetail
*
public void setDetail(Object newDetail) {
Object oldDetail = detail;
detail = newDetail;
firePropertyChange(PROP_DETAIL, oldDetail, newDetail);
}
/**
* Get the detail object for this description.
*
* @return details of this description
*
* @see #setTitle
*
public Object getDetail() {
return detail;
}
*/
//
// Support for reporting bound property changes.
//
/**
* Add a {@link PropertyChangeListener} to the listener list.
*
* @param listener the <code>PropertyChangeListener</code> to be added
*/
public void addPropertyChangeListener(PropertyChangeListener listener) {
getterCalled ();
changeSupport.addPropertyChangeListener(listener);
}
/**
* Remove a {@link PropertyChangeListener} from the listener list.
*
* @param listener the <code>PropertyChangeListener</code> to be removed
*/
public void removePropertyChangeListener(PropertyChangeListener listener) {
if (changeSupport != null) {
changeSupport.removePropertyChangeListener(listener);
}
}
/**
* Fire a {@link PropertyChangeEvent} to each listener.
*
* @param propertyName the programmatic name of the property that was changed
* @param oldValue the old value of the property
* @param newValue the new value of the property
*/
protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
if (changeSupport != null) {
changeSupport.firePropertyChange(propertyName, oldValue, newValue);
}
}
/**
* Get the title to use for the indicated type.
* @param messageType the type of message
* @return the title to use
*/
protected static String getTitleForType(int messageType) {
switch(messageType) {
case ERROR_MESSAGE:
return NbBundle.getMessage (NotifyDescriptor.class, "NTF_ErrorTitle");
case WARNING_MESSAGE:
return NbBundle.getMessage (NotifyDescriptor.class, "NTF_WarningTitle");
case QUESTION_MESSAGE:
return NbBundle.getMessage (NotifyDescriptor.class, "NTF_QuestionTitle");
case INFORMATION_MESSAGE:
return NbBundle.getMessage (NotifyDescriptor.class, "NTF_InformationTitle");
case PLAIN_MESSAGE:
return NbBundle.getMessage (NotifyDescriptor.class, "NTF_PlainTitle");
}
return ""; // NOI18N
}
/**
* Provides information about the results of a command. Offers
* no user choices; the user can only acknowledge the message.
*/
public static class Message extends NotifyDescriptor
{
/**
* Create an informational report about the results of a command.
*
* @param message the message object
* @see NotifyDescriptor#NotifyDescriptor
*/
public Message(Object message) {
this(message, INFORMATION_MESSAGE);
}
/**
* Create a report about the results of a command.
*
* @param message the message object
* @param messageType the type of message to be displayed
* @see NotifyDescriptor#NotifyDescriptor
*/
public Message(Object message, int messageType) {
super(
message,
NotifyDescriptor.getTitleForType(messageType),
DEFAULT_OPTION,
messageType,
new Object[] { OK_OPTION },
OK_OPTION
);
}
}
/**
* Provides a description of a possible action and requests confirmation from the user before proceeding.
* This should be used to alert the user to a condition
* or situation that requires the user's decision before proceeding, such
* as an impending action with potentially destructive or irreversible
* consequences. It is conventionally in the form of a question: for example,
* "Save changes to TestForm?"
*/
public static class Confirmation extends NotifyDescriptor
{
/**
* Create a yes/no/cancel question with default title.
*
* @param message the message object
* @see NotifyDescriptor#NotifyDescriptor
*/
public Confirmation(Object message) {
this(message, YES_NO_CANCEL_OPTION);
}
/**
* Create a yes/no/cancel question.
*
* @param message the message object
* @param title the dialog title
* @see NotifyDescriptor#NotifyDescriptor
*/
public Confirmation(Object message, String title) {
this(message, title, YES_NO_CANCEL_OPTION);
}
/**
* Create a question with default title.
*
* @param message the message object
* @param optionType the type of options to display to the user
* @see NotifyDescriptor#NotifyDescriptor
*/
public Confirmation(Object message, int optionType) {
this(message, optionType, QUESTION_MESSAGE);
}
/**
* Create a question.
*
* @param message the message object
* @param title the dialog title
* @param optionType the type of options to display to the user
* @see NotifyDescriptor#NotifyDescriptor
*/
public Confirmation(Object message, String title, int optionType) {
this(message, title, optionType, QUESTION_MESSAGE);
}
/**
* Create a confirmation with default title.
*
* @param message the message object
* @param optionType the type of options to display to the user
* @param messageType the type of message to use
* @see NotifyDescriptor#NotifyDescriptor
*/
public Confirmation(Object message, int optionType, int messageType) {
super(
message,
NotifyDescriptor.getTitleForType(messageType),
optionType,
messageType,
optionType == DEFAULT_OPTION ? new Object[] { OK_OPTION } : null,
OK_OPTION
);
}
/**
* Create a confirmation.
*
* @param message the message object
* @param title the dialog title
* @param optionType the type of options to display to the user
* @param messageType the type of message to use
* @see NotifyDescriptor#NotifyDescriptor
*/
public Confirmation(Object message, String title, int optionType, int messageType) {
super(
message, title, optionType, messageType,
optionType == DEFAULT_OPTION ? new Object[] { OK_OPTION } : null,
OK_OPTION
);
}
}
/**
* Provides a description of an exception that occurred during
* execution of the IDE.
* @deprecated Better to use {@link ErrorManager#notify}.
*/
public static final class Exception extends Confirmation
{
static final long serialVersionUID =-3387516993124229948L;
/**
* Create an exception report with default message.
*
* @param detail the detail object
*/
public Exception(Throwable detail) {
this(detail, detail.getMessage());
// handle InvocationTargetExceptions
if (detail instanceof InvocationTargetException) {
Throwable target = ((InvocationTargetException)detail).getTargetException();
this.setMessage (target);
if (this.getMessage() == null || "".equals(this.getMessage())) { // NOI18N
String msg = target.getMessage();
msg = org.openide.util.Utilities.wrapString (msg, MAXIMUM_TEXT_WIDTH, java.text.BreakIterator.getCharacterInstance(), false);
this.setMessage(msg);
}
}
// emphasize user-non-friendly exceptions
if (this.getMessage() == null || "".equals(this.getMessage())) { // NOI18N
this.setMessage(NbBundle.getMessage(NotifyDescriptor.class,
"NTF_ExceptionalException", detail.getClass().getName()));
this.setTitle(NbBundle.getMessage (NotifyDescriptor.class, "NTF_ExceptionalExceptionTitle"));
}
}
/**
* Create an exception report.
*
* @param detail the detail object
* @param message the message object
*/
public Exception(Throwable detail, Object message) {
super(message, DEFAULT_OPTION, ERROR_MESSAGE);
// customize descriptor
// this.setDetail(detail);
this.setTitle(NbBundle.getMessage (NotifyDescriptor.class, "NTF_ExceptionTitle"));
}
}
/** Notification providing for a line of text input.
* @author Dafe Simonek
*/
public static class InputLine extends NotifyDescriptor {
/**
* The text field used to enter the input.
*/
protected JTextField textField;
/** Construct dialog with the specified title and label text.
* @param text label text
* @param title title of the dialog
*/
public InputLine (final String text, final String title) {
this(text, title, OK_CANCEL_OPTION, PLAIN_MESSAGE);
}
/** Construct dialog with the specified title, label text, option and
* message types.
* @param text label text
* @param title title of the dialog
* @param optionType option type (ok, cancel, ...)
* @param messageType message type (question, ...)
*/
public InputLine (final String text, final String title, final int optionType,
final int messageType) {
super(null, title, optionType, messageType, null, null);
super.setMessage(createDesign(text));
}
/**
* Get the text which the user typed into the input line.
* @return the text entered by the user
*/
public String getInputText () {
return textField.getText ();
}
/**
* Set the text on the input line.
* @param text the new text
*/
public void setInputText (final String text) {
textField.setText(text);
textField.selectAll ();
}
/** Make a component representing the input line.
* @param text a label for the input line
* @return the component
*/
protected Component createDesign (final String text) {
int index;
char mnemonic = 0;
String txt;
JPanel panel = new JPanel();
if(text != null && (index = text.indexOf('&')) >= 0 && index + 1 < text.length()) {
mnemonic = text.charAt(index + 1);
txt = text.substring(0, index) + text.substring(index + 1);
} else {
txt = text;
}
JLabel textLabel = new JLabel(txt);
if(txt != null && txt.length() > 0) {
textLabel.setDisplayedMnemonic(mnemonic == 0 ? text.charAt(0) : mnemonic);
}
textLabel.setBorder(new EmptyBorder(0, 0, 0, 10));
panel.setLayout(new BorderLayout());
panel.setBorder(new EmptyBorder(11, 12, 1, 11));
panel.add("West", textLabel); // NOI18N
panel.add("Center", textField = new JTextField(25)); // NOI18N
textLabel.setLabelFor(textField);
textField.setBorder(new CompoundBorder(textField.getBorder(), new EmptyBorder(2, 0, 2, 0)));
textField.requestFocus();
javax.swing.KeyStroke enter = javax.swing.KeyStroke.getKeyStroke(
java.awt.event.KeyEvent.VK_ENTER, 0
);
javax.swing.text.Keymap map = textField.getKeymap ();
map.removeKeyStrokeBinding (enter);
/*
textField.addActionListener (new java.awt.event.ActionListener () {
public void actionPerformed (java.awt.event.ActionEvent evt) {
System.out.println("action: " + evt);
InputLine.this.setValue (OK_OPTION);
}
}
);
*/
panel.getAccessibleContext().setAccessibleDescription(NbBundle.getMessage(NotifyDescriptor.class, "ACSD_InputPanel"));
textField.getAccessibleContext().setAccessibleDescription(NbBundle.getMessage(NotifyDescriptor.class, "ACSD_InputField"));
return panel;
}
} // end of InputLine
}