blob: 7116ea69164d5fd8b4df9a405ad4c68497d6230f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Lars Vogel <Lars.Vogel@vogella.com> - Bug 472690
*******************************************************************************/
package org.eclipse.jface.dialogs;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
/**
* A dialog for showing messages to the user.
* <p>
* This concrete dialog class can be instantiated as is, or further subclassed
* as required.
* </p>
* <p>
* <strong>Note:</strong> This class does not use button IDs from
* IDialogConstants. Instead, the ID is the index of the button in the supplied
* array.
* </p>
*/
public class MessageDialog extends IconAndMessageDialog {
/**
* Constant for no image (value 0).
*
* @see #MessageDialog(Shell, String, Image, String, int, int, String...)
*/
public final static int NONE = 0;
/**
* Constant for the error image, or a simple dialog with the error image and
* a single OK button (value 1).
*
* @see #MessageDialog(Shell, String, Image, String, int, int, String...)
* @see #open(int, Shell, String, String, int)
*/
public final static int ERROR = 1;
/**
* Constant for the info image, or a simple dialog with the info image and a
* single OK button (value 2).
*
* @see #MessageDialog(Shell, String, Image, String, int, int, String...)
* @see #open(int, Shell, String, String, int)
*/
public final static int INFORMATION = 2;
/**
* Constant for the question image, or a simple dialog with the question
* image and Yes/No buttons (value 3).
*
* @see #MessageDialog(Shell, String, Image, String, int, int, String...)
* @see #open(int, Shell, String, String, int)
*/
public final static int QUESTION = 3;
/**
* Constant for the warning image, or a simple dialog with the warning image
* and a single OK button (value 4).
*
* @see #MessageDialog(Shell, String, Image, String, int, int, String...)
* @see #open(int, Shell, String, String, int)
*/
public final static int WARNING = 4;
/**
* Constant for a simple dialog with the question image and OK/Cancel buttons (value 5).
*
* @see #open(int, Shell, String, String, int)
* @since 3.5
*/
public final static int CONFIRM = 5;
/**
* Constant for a simple dialog with the question image and Yes/No/Cancel buttons (value 6).
*
* @see #open(int, Shell, String, String, int)
* @since 3.5
*/
public final static int QUESTION_WITH_CANCEL = 6;
/**
* Labels for buttons in the button bar (localized strings).
*/
private String[] buttonLabels;
/**
* The buttons. Parallels <code>buttonLabels</code>.
*/
private Button[] buttons;
/**
* Index into <code>buttonLabels</code> of the default button.
*/
private int defaultButtonIndex;
/**
* Dialog title (a localized string).
*/
private String title;
/**
* Dialog title image.
*/
private Image titleImage;
/**
* Image, or <code>null</code> if none.
*/
private Image image = null;
/**
* The custom dialog area.
*/
private Control customArea;
/**
* Create a message dialog. Note that the dialog will have no visual
* representation (no widgets) until it is told to open.
* <p>
* The labels of the buttons to appear in the button bar are supplied in
* this constructor as an array. The <code>open</code> method will return
* the index of the label in this array corresponding to the button that was
* pressed to close the dialog.
* </p>
* <p>
* <strong>Note:</strong> If the dialog was dismissed without pressing a
* button (ESC key, close box, etc.) then {@link SWT#DEFAULT} is returned.
* Note that the <code>open</code> method blocks.
* </p>
*
* As of 3.11 you can also use the other constructor which is based on
* varargs
*
* @param parentShell
* the parent shell, or <code>null</code> to create a top-level
* shell
* @param dialogTitle
* the dialog title, or <code>null</code> if none
* @param dialogTitleImage
* the dialog title image, or <code>null</code> if none
* @param dialogMessage
* the dialog message
* @param dialogImageType
* one of the following values:
* <ul>
* <li><code>MessageDialog.NONE</code> for a dialog with no image
* </li>
* <li><code>MessageDialog.ERROR</code> for a dialog with an
* error image</li>
* <li><code>MessageDialog.INFORMATION</code> for a dialog with
* an information image</li>
* <li><code>MessageDialog.QUESTION </code> for a dialog with a
* question image</li>
* <li><code>MessageDialog.WARNING</code> for a dialog with a
* warning image</li>
* </ul>
* @param dialogButtonLabels
* an array of labels for the buttons in the button bar
* @param defaultIndex
* the index in the button label array of the default button
*
*/
public MessageDialog(Shell parentShell, String dialogTitle, Image dialogTitleImage, String dialogMessage,
int dialogImageType, String[] dialogButtonLabels, int defaultIndex) {
super(parentShell);
init(dialogTitle, dialogTitleImage, dialogMessage, dialogImageType, defaultIndex, dialogButtonLabels);
}
/**
* Create a message dialog. Note that the dialog will have no visual
* representation (no widgets) until it is told to open.
* <p>
* The labels of the buttons to appear in the button bar are supplied in
* this constructor as a varargs of Strings. The <code>open</code> method
* will return the index of the label in this array corresponding to the
* button that was pressed to close the dialog.
* </p>
* <p>
* <strong>Note:</strong> If the dialog was dismissed without pressing a
* button (ESC key, close box, etc.) then {@link SWT#DEFAULT} is returned.
* Note that the <code>open</code> method blocks.
* </p>
*
* @param parentShell
* the parent shell, or <code>null</code> to create a top-level
* shell
* @param dialogTitle
* the dialog title, or <code>null</code> if none
* @param dialogTitleImage
* the dialog title image, or <code>null</code> if none
* @param dialogMessage
* the dialog message
* @param dialogImageType
* one of the following values:
* <ul>
* <li><code>MessageDialog.NONE</code> for a dialog with no image
* </li>
* <li><code>MessageDialog.ERROR</code> for a dialog with an
* error image</li>
* <li><code>MessageDialog.INFORMATION</code> for a dialog with
* an information image</li>
* <li><code>MessageDialog.QUESTION </code> for a dialog with a
* question image</li>
* <li><code>MessageDialog.WARNING</code> for a dialog with a
* warning image</li>
* </ul>
* @param defaultIndex
* the index in the button label array of the default button
*
* @param dialogButtonLabels
* varargs of Strings for the button labels in the button bar
*
* @since 3.12
*/
public MessageDialog(Shell parentShell, String dialogTitle, Image dialogTitleImage, String dialogMessage,
int dialogImageType, int defaultIndex, String... dialogButtonLabels) {
super(parentShell);
init(dialogTitle, dialogTitleImage, dialogMessage, dialogImageType, defaultIndex, dialogButtonLabels);
}
private void init(String dialogTitle, Image dialogTitleImage, String dialogMessage, int dialogImageType,
int defaultIndex, String... dialogButtonLabels) {
this.title = dialogTitle;
this.titleImage = dialogTitleImage;
this.message = dialogMessage;
switch (dialogImageType) {
case ERROR: {
this.image = getErrorImage();
break;
}
case INFORMATION: {
this.image = getInfoImage();
break;
}
case QUESTION:
case QUESTION_WITH_CANCEL:
case CONFIRM: {
this.image = getQuestionImage();
break;
}
case WARNING: {
this.image = getWarningImage();
break;
}
}
this.buttonLabels = dialogButtonLabels;
this.defaultButtonIndex = defaultIndex;
}
@Override
protected void buttonPressed(int buttonId) {
setReturnCode(buttonId);
close();
}
@Override
protected void configureShell(Shell shell) {
super.configureShell(shell);
if (title != null) {
shell.setText(title);
}
if (titleImage != null) {
shell.setImage(titleImage);
}
}
@Override
protected void createButtonsForButtonBar(Composite parent) {
buttons = new Button[buttonLabels.length];
for (int i = 0; i < buttonLabels.length; i++) {
String label = buttonLabels[i];
Button button = createButton(parent, i, label, defaultButtonIndex == i);
buttons[i] = button;
}
}
/**
* Creates and returns the contents of an area of the dialog which appears
* below the message and above the button bar.
* <p>
* The default implementation of this framework method returns
* <code>null</code>. Subclasses may override.
* </p>
*
* @param parent
* parent composite to contain the custom area
* @return the custom area control, or <code>null</code>
*/
protected Control createCustomArea(Composite parent) {
return null;
}
/**
* This implementation of the <code>Dialog</code> framework method creates
* and lays out a composite and calls <code>createMessageArea</code> and
* <code>createCustomArea</code> to populate it. Subclasses should
* override <code>createCustomArea</code> to add contents below the
* message.
*/
@Override
protected Control createDialogArea(Composite parent) {
// create message area
createMessageArea(parent);
// create the top level composite for the dialog area
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
composite.setLayout(layout);
GridData data = new GridData(GridData.FILL_BOTH);
data.horizontalSpan = 2;
composite.setLayoutData(data);
// allow subclasses to add custom controls
customArea = createCustomArea(composite);
//If it is null create a dummy label for spacing purposes
if (customArea == null) {
customArea = new Label(composite, SWT.NULL);
}
return composite;
}
/**
* Gets a button in this dialog's button bar.
*
* @param index
* the index of the button in the dialog's button bar
* @return a button in the dialog's button bar, or <code>null</code> if there's no button with that index
*/
@Override
protected Button getButton(int index) {
if (buttons == null || index < 0 || index >= buttons.length) {
return null;
}
return buttons[index];
}
/**
* Returns the minimum message area width in pixels This determines the
* minimum width of the dialog.
* <p>
* Subclasses may override.
* </p>
*
* @return the minimum message area width (in pixels)
*/
protected int getMinimumMessageWidth() {
return convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH);
}
/**
* Handle the shell close. Set the return code to <code>SWT.DEFAULT</code>
* as there has been no explicit close by the user.
*
* @see org.eclipse.jface.window.Window#handleShellCloseEvent()
*/
@Override
protected void handleShellCloseEvent() {
//Sets a return code of SWT.DEFAULT since none of the dialog buttons
// were pressed to close the dialog.
super.handleShellCloseEvent();
setReturnCode(SWT.DEFAULT);
}
/**
* Opens this message dialog, creating it first if it has not yet been created.
* <p>
* This method waits until the dialog is closed by the end user, and then it
* returns the dialog's return code. The dialog's return code is either the
* index of the button the user pressed, or {@link SWT#DEFAULT} if the dialog
* has been closed by other means.
* </p>
*
* @return the return code
*
* @see org.eclipse.jface.window.Window#open()
*/
@Override
public int open() {
return super.open();
}
/**
* Convenience method to open a simple dialog as specified by the
* <code>kind</code> flag.
*
* @param kind
* the kind of dialog to open, one of {@link #ERROR},
* {@link #INFORMATION}, {@link #QUESTION}, {@link #WARNING},
* {@link #CONFIRM}, or {@link #QUESTION_WITH_CANCEL}.
* @param parent
* the parent shell of the dialog, or <code>null</code> if none
* @param title
* the dialog's title, or <code>null</code> if none
* @param message
* the message
* @param style
* {@link SWT#NONE} for a default dialog, or {@link SWT#SHEET} for
* a dialog with sheet behavior
* @return <code>true</code> if the user presses the OK or Yes button,
* <code>false</code> otherwise
* @since 3.5
*/
public static boolean open(int kind, Shell parent, String title, String message, int style) {
MessageDialog dialog = new MessageDialog(parent, title, null, message, kind, 0, getButtonLabels(kind));
style &= SWT.SHEET;
dialog.setShellStyle(dialog.getShellStyle() | style);
return dialog.open() == 0;
}
static String[] getButtonLabels(int kind) {
String[] dialogButtonLabels;
switch (kind) {
case ERROR:
case INFORMATION:
case WARNING: {
dialogButtonLabels = new String[] { IDialogConstants.OK_LABEL };
break;
}
case CONFIRM: {
dialogButtonLabels = new String[] { IDialogConstants.OK_LABEL,
IDialogConstants.CANCEL_LABEL };
break;
}
case QUESTION: {
dialogButtonLabels = new String[] { IDialogConstants.YES_LABEL,
IDialogConstants.NO_LABEL };
break;
}
case QUESTION_WITH_CANCEL: {
dialogButtonLabels = new String[] { IDialogConstants.YES_LABEL,
IDialogConstants.NO_LABEL,
IDialogConstants.CANCEL_LABEL };
break;
}
default: {
throw new IllegalArgumentException("Illegal value for kind in MessageDialog.open()"); //$NON-NLS-1$
}
}
return dialogButtonLabels;
}
/**
* Convenience method to open a simple confirm (OK/Cancel) dialog.
*
* @param parent
* the parent shell of the dialog, or <code>null</code> if none
* @param title
* the dialog's title, or <code>null</code> if none
* @param message
* the message
* @return <code>true</code> if the user presses the OK button,
* <code>false</code> otherwise
*/
public static boolean openConfirm(Shell parent, String title, String message) {
return open(CONFIRM, parent, title, message, SWT.NONE);
}
/**
* Convenience method to open a standard error dialog.
*
* @param parent
* the parent shell of the dialog, or <code>null</code> if none
* @param title
* the dialog's title, or <code>null</code> if none
* @param message
* the message
*/
public static void openError(Shell parent, String title, String message) {
open(ERROR, parent, title, message, SWT.NONE);
}
/**
* Convenience method to open a standard information dialog.
*
* @param parent
* the parent shell of the dialog, or <code>null</code> if none
* @param title
* the dialog's title, or <code>null</code> if none
* @param message
* the message
*/
public static void openInformation(Shell parent, String title, String message) {
open(INFORMATION, parent, title, message, SWT.NONE);
}
/**
* Convenience method to open a simple Yes/No question dialog.
*
* @param parent
* the parent shell of the dialog, or <code>null</code> if none
* @param title
* the dialog's title, or <code>null</code> if none
* @param message
* the message
* @return <code>true</code> if the user presses the Yes button,
* <code>false</code> otherwise
*/
public static boolean openQuestion(Shell parent, String title, String message) {
return open(QUESTION, parent, title, message, SWT.NONE);
}
/**
* Convenience method to open a standard warning dialog.
*
* @param parent
* the parent shell of the dialog, or <code>null</code> if none
* @param title
* the dialog's title, or <code>null</code> if none
* @param message
* the message
*/
public static void openWarning(Shell parent, String title, String message) {
open(WARNING, parent, title, message, SWT.NONE);
}
@Override
protected Button createButton(Composite parent, int id, String label, boolean defaultButton) {
Button button = super.createButton(parent, id, label, defaultButton);
//Be sure to set the focus if the custom area cannot so as not
//to lose the defaultButton.
if (defaultButton && !customShouldTakeFocus()) {
button.setFocus();
}
return button;
}
/**
* Return whether or not we should apply the workaround where we take focus
* for the default button or if that should be determined by the dialog. By
* default only return true if the custom area is a label or CLabel that
* cannot take focus.
*
* @return boolean
*/
protected boolean customShouldTakeFocus() {
if (customArea instanceof Label) {
return false;
}
if (customArea instanceof CLabel) {
return (customArea.getStyle() & SWT.NO_FOCUS) > 0;
}
return true;
}
@Override
public Image getImage() {
return image;
}
/**
* An accessor for the labels to use on the buttons.
*
* @return The button labels to used; never <code>null</code>.
*/
protected String[] getButtonLabels() {
return buttonLabels;
}
/**
* An accessor for the index of the default button in the button array.
*
* @return The default button index.
*/
protected int getDefaultButtonIndex() {
return defaultButtonIndex;
}
/**
* A mutator for the array of buttons in the button bar.
*
* @param buttons
* The buttons in the button bar; must not be <code>null</code>.
*/
protected void setButtons(Button... buttons) {
if (buttons == null) {
throw new NullPointerException("The array of buttons cannot be null."); //$NON-NLS-1$
}
this.buttons = buttons;
}
/**
* A mutator for the button labels.
*
* @param buttonLabels
* The button labels to use; must not be <code>null</code>.
*/
protected void setButtonLabels(String... buttonLabels) {
if (buttonLabels == null) {
throw new NullPointerException("The array of button labels cannot be null."); //$NON-NLS-1$
}
this.buttonLabels = buttonLabels;
}
}