blob: cedda20b7b844e3100e92f4fcc6842f77de0904b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2005 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
* Konstantin Scheglov <scheglov_ke@nlmk.ru > - Fix for bug 41172
* [Dialogs] Bug with Image in TitleAreaDialog
*******************************************************************************/
package org.eclipse.jface.dialogs;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.jface.resource.JFaceColors;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
/**
* A dialog that has a title area for displaying a title and an image as well as
* a common area for displaying a description, a message, or an error message.
* <p>
* This dialog class may be subclassed.
*/
public class TitleAreaDialog extends Dialog {
/**
* Image registry key for error message image.
*/
public static final String DLG_IMG_TITLE_ERROR = DLG_IMG_MESSAGE_ERROR;
/**
* Image registry key for banner image (value
* <code>"dialog_title_banner_image"</code>).
*/
public static final String DLG_IMG_TITLE_BANNER = "dialog_title_banner_image";//$NON-NLS-1$
/**
* Message type constant used to display an info icon with the message.
*
* @since 2.0
* @deprecated
*/
public final static String INFO_MESSAGE = "INFO_MESSAGE"; //$NON-NLS-1$
/**
* Message type constant used to display a warning icon with the message.
*
* @since 2.0
* @deprecated
*/
public final static String WARNING_MESSAGE = "WARNING_MESSAGE"; //$NON-NLS-1$
// Space between an image and a label
private static final int H_GAP_IMAGE = 5;
//Minimum dialog width (in dialog units)
private static final int MIN_DIALOG_WIDTH = 350;
//Minimum dialog height (in dialog units)
private static final int MIN_DIALOG_HEIGHT = 150;
static {
ImageRegistry reg = JFaceResources.getImageRegistry();
reg.put(DLG_IMG_TITLE_BANNER, ImageDescriptor.createFromFile(
TitleAreaDialog.class, "images/title_banner.gif"));//$NON-NLS-1$
}
private Label titleLabel;
private Label titleImage;
private Label bottomFillerLabel;
private Label leftFillerLabel;
private RGB titleAreaRGB;
Color titleAreaColor;
private String message = ""; //$NON-NLS-1$
private String errorMessage;
private Text messageLabel;
private Composite workArea;
private Label messageImageLabel;
private Image messageImage;
private Color normalMsgAreaBackground;
private Color errorMsgAreaBackground;
private Image errorMsgImage;
private boolean showingError = false;
private boolean titleImageLargest = true;
private int messageLabelHeight;
/**
* Instantiate a new title area dialog.
*
* @param parentShell
* the parent SWT shell
*/
public TitleAreaDialog(Shell parentShell) {
super(parentShell);
}
/*
* @see Dialog.createContents(Composite)
*/
protected Control createContents(Composite parent) {
// initialize the dialog units
initializeDialogUnits(parent);
FormLayout layout = new FormLayout();
parent.setLayout(layout);
FormData data = new FormData();
data.top = new FormAttachment(0, 0);
data.bottom = new FormAttachment(100, 0);
parent.setLayoutData(data);
//Now create a work area for the rest of the dialog
workArea = new Composite(parent, SWT.NULL);
GridLayout childLayout = new GridLayout();
childLayout.marginHeight = 0;
childLayout.marginWidth = 0;
childLayout.verticalSpacing = 0;
workArea.setLayout(childLayout);
Control top = createTitleArea(parent);
resetWorkAreaAttachments(top);
workArea.setFont(JFaceResources.getDialogFont());
// initialize the dialog units
initializeDialogUnits(workArea);
// create the dialog area and button bar
dialogArea = createDialogArea(workArea);
buttonBar = createButtonBar(workArea);
return parent;
}
/**
* Creates and returns the contents of the upper part of this dialog (above
* the button bar).
* <p>
* The <code>Dialog</code> implementation of this framework method creates
* and returns a new <code>Composite</code> with no margins and spacing.
* Subclasses should override.
* </p>
*
* @param parent
* The parent composite to contain the dialog area
* @return the dialog area control
*/
protected Control createDialogArea(Composite 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;
layout.verticalSpacing = 0;
layout.horizontalSpacing = 0;
composite.setLayout(layout);
composite.setLayoutData(new GridData(GridData.FILL_BOTH));
composite.setFont(parent.getFont());
// Build the separator line
Label titleBarSeparator = new Label(composite, SWT.HORIZONTAL
| SWT.SEPARATOR);
titleBarSeparator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
return composite;
}
/**
* Creates the dialog's title area.
*
* @param parent
* the SWT parent for the title area widgets
* @return Control with the highest x axis value.
*/
private Control createTitleArea(Composite parent) {
// add a dispose listener
parent.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
if (titleAreaColor != null)
titleAreaColor.dispose();
}
});
// Determine the background color of the title bar
Display display = parent.getDisplay();
Color background;
Color foreground;
if (titleAreaRGB != null) {
titleAreaColor = new Color(display, titleAreaRGB);
background = titleAreaColor;
foreground = null;
} else {
background = JFaceColors.getBannerBackground(display);
foreground = JFaceColors.getBannerForeground(display);
}
int verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
int horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
parent.setBackground(background);
// Dialog image @ right
titleImage = new Label(parent, SWT.CENTER);
titleImage.setBackground(background);
titleImage.setImage(JFaceResources.getImage(DLG_IMG_TITLE_BANNER));
FormData imageData = new FormData();
imageData.top = new FormAttachment(0, 0);
// Note: do not use horizontalSpacing on the right as that would be a
// regression from
// the R2.x style where there was no margin on the right and images are
// flush to the right
// hand side. see reopened comments in 41172
imageData.right = new FormAttachment(100, 0); // horizontalSpacing
titleImage.setLayoutData(imageData);
// Title label @ top, left
titleLabel = new Label(parent, SWT.LEFT);
JFaceColors.setColors(titleLabel, foreground, background);
titleLabel.setFont(JFaceResources.getBannerFont());
titleLabel.setText(" ");//$NON-NLS-1$
FormData titleData = new FormData();
titleData.top = new FormAttachment(0, verticalSpacing);
titleData.right = new FormAttachment(titleImage);
titleData.left = new FormAttachment(0, horizontalSpacing);
titleLabel.setLayoutData(titleData);
// Message image @ bottom, left
messageImageLabel = new Label(parent, SWT.CENTER);
messageImageLabel.setBackground(background);
// Message label @ bottom, center
messageLabel = new Text(parent, SWT.WRAP | SWT.READ_ONLY);
JFaceColors.setColors(messageLabel, foreground, background);
messageLabel.setText(" \n "); // two lines//$NON-NLS-1$
messageLabel.setFont(JFaceResources.getDialogFont());
messageLabelHeight = messageLabel.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
// Filler labels
leftFillerLabel = new Label(parent, SWT.CENTER);
leftFillerLabel.setBackground(background);
bottomFillerLabel = new Label(parent, SWT.CENTER);
bottomFillerLabel.setBackground(background);
setLayoutsForNormalMessage(verticalSpacing, horizontalSpacing);
determineTitleImageLargest();
if (titleImageLargest)
return titleImage;
return messageLabel;
}
/**
* Determine if the title image is larger than the title message and message
* area. This is used for layout decisions.
*/
private void determineTitleImageLargest() {
int titleY = titleImage.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
int verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
int labelY = titleLabel.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
labelY += verticalSpacing;
labelY += messageLabelHeight;
labelY += verticalSpacing;
titleImageLargest = titleY > labelY;
}
/**
* Set the layout values for the messageLabel, messageImageLabel and
* fillerLabel for the case where there is a normal message.
*
* @param verticalSpacing
* int The spacing between widgets on the vertical axis.
* @param horizontalSpacing
* int The spacing between widgets on the horizontal axis.
*/
private void setLayoutsForNormalMessage(int verticalSpacing,
int horizontalSpacing) {
FormData messageImageData = new FormData();
messageImageData.top = new FormAttachment(titleLabel, verticalSpacing);
messageImageData.left = new FormAttachment(0, H_GAP_IMAGE);
messageImageLabel.setLayoutData(messageImageData);
FormData messageLabelData = new FormData();
messageLabelData.top = new FormAttachment(titleLabel, verticalSpacing);
messageLabelData.right = new FormAttachment(titleImage);
messageLabelData.left = new FormAttachment(messageImageLabel,
horizontalSpacing);
messageLabelData.height = messageLabelHeight;
if (titleImageLargest)
messageLabelData.bottom = new FormAttachment(titleImage, 0,
SWT.BOTTOM);
messageLabel.setLayoutData(messageLabelData);
FormData fillerData = new FormData();
fillerData.left = new FormAttachment(0, horizontalSpacing);
fillerData.top = new FormAttachment(messageImageLabel, 0);
fillerData.bottom = new FormAttachment(messageLabel, 0, SWT.BOTTOM);
bottomFillerLabel.setLayoutData(fillerData);
FormData data = new FormData();
data.top = new FormAttachment(messageImageLabel, 0, SWT.TOP);
data.left = new FormAttachment(0, 0);
data.bottom = new FormAttachment(messageImageLabel, 0, SWT.BOTTOM);
data.right = new FormAttachment(messageImageLabel, 0);
leftFillerLabel.setLayoutData(data);
}
/**
* The <code>TitleAreaDialog</code> implementation of this
* <code>Window</code> methods returns an initial size which is at least
* some reasonable minimum.
*
* @return the initial size of the dialog
*/
protected Point getInitialSize() {
Point shellSize = super.getInitialSize();
return new Point(Math.max(
convertHorizontalDLUsToPixels(MIN_DIALOG_WIDTH), shellSize.x),
Math.max(convertVerticalDLUsToPixels(MIN_DIALOG_HEIGHT),
shellSize.y));
}
/**
* Retained for backward compatibility.
*
* Returns the title area composite. There is no composite in this
* implementation so the shell is returned.
*
* @return Composite
* @deprecated
*/
protected Composite getTitleArea() {
return getShell();
}
/**
* Returns the title image label.
*
* @return the title image label
*/
protected Label getTitleImageLabel() {
return titleImage;
}
/**
* Display the given error message. The currently displayed message is saved
* and will be redisplayed when the error message is set to
* <code>null</code>.
*
* @param newErrorMessage
* the newErrorMessage to display or <code>null</code>
*/
public void setErrorMessage(String newErrorMessage) {
// Any change?
if (errorMessage == null ? newErrorMessage == null : errorMessage
.equals(newErrorMessage))
return;
errorMessage = newErrorMessage;
if (errorMessage == null) {
if (showingError) {
// we were previously showing an error
showingError = false;
setMessageBackgrounds(false);
}
// show the message
// avoid calling setMessage in case it is overridden to call
// setErrorMessage,
// which would result in a recursive infinite loop
if (message == null) //this should probably never happen since
// setMessage does this conversion....
message = ""; //$NON-NLS-1$
updateMessage(message);
messageImageLabel.setImage(messageImage);
setImageLabelVisible(messageImage != null);
} else {
//Add in a space for layout purposes but do not
//change the instance variable
String displayedErrorMessage = " " + errorMessage; //$NON-NLS-1$
updateMessage(displayedErrorMessage);
if (!showingError) {
// we were not previously showing an error
showingError = true;
// lazy initialize the error background color and image
if (errorMsgAreaBackground == null) {
errorMsgAreaBackground = JFaceColors
.getErrorBackground(messageLabel.getDisplay());
errorMsgImage = JFaceResources
.getImage(DLG_IMG_TITLE_ERROR);
}
// show the error
normalMsgAreaBackground = messageLabel.getBackground();
setMessageBackgrounds(true);
messageImageLabel.setImage(errorMsgImage);
setImageLabelVisible(true);
}
}
layoutForNewMessage();
}
/**
* Re-layout the labels for the new message.
*/
private void layoutForNewMessage() {
int verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
int horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
//If there are no images then layout as normal
if (errorMessage == null && messageImage == null) {
setImageLabelVisible(false);
setLayoutsForNormalMessage(verticalSpacing, horizontalSpacing);
} else {
messageImageLabel.setVisible(true);
bottomFillerLabel.setVisible(true);
leftFillerLabel.setVisible(true);
/**
* Note that we do not use horizontalSpacing here as when the
* background of the messages changes there will be gaps between the
* icon label and the message that are the background color of the
* shell. We add a leading space elsewhere to compendate for this.
*/
FormData data = new FormData();
data.left = new FormAttachment(0, H_GAP_IMAGE);
data.top = new FormAttachment(titleLabel, verticalSpacing);
messageImageLabel.setLayoutData(data);
data = new FormData();
data.top = new FormAttachment(messageImageLabel, 0);
data.left = new FormAttachment(0, 0);
data.bottom = new FormAttachment(messageLabel, 0, SWT.BOTTOM);
data.right = new FormAttachment(messageImageLabel, 0, SWT.RIGHT);
bottomFillerLabel.setLayoutData(data);
data = new FormData();
data.top = new FormAttachment(messageImageLabel, 0, SWT.TOP);
data.left = new FormAttachment(0, 0);
data.bottom = new FormAttachment(messageImageLabel, 0, SWT.BOTTOM);
data.right = new FormAttachment(messageImageLabel, 0);
leftFillerLabel.setLayoutData(data);
FormData messageLabelData = new FormData();
messageLabelData.top = new FormAttachment(titleLabel,
verticalSpacing);
messageLabelData.right = new FormAttachment(titleImage);
messageLabelData.left = new FormAttachment(messageImageLabel, 0);
messageLabelData.height = messageLabelHeight;
if (titleImageLargest)
messageLabelData.bottom = new FormAttachment(titleImage, 0,
SWT.BOTTOM);
messageLabel.setLayoutData(messageLabelData);
}
//Do not layout before the dialog area has been created
//to avoid incomplete calculations.
if (dialogArea != null)
getShell().layout(true);
}
/**
* Set the message text. If the message line currently displays an error,
* the message is saved and will be redisplayed when the error message is
* set to <code>null</code>.
* <p>
* Shortcut for <code>setMessage(newMessage, IMessageProvider.NONE)</code>
* </p>
* This method should be called after the dialog has been opened as it
* updates the message label immediately.
*
* @param newMessage
* the message, or <code>null</code> to clear the message
*/
public void setMessage(String newMessage) {
setMessage(newMessage, IMessageProvider.NONE);
}
/**
* Sets the message for this dialog with an indication of what type of
* message it is.
* <p>
* The valid message types are one of <code>NONE</code>,
* <code>INFORMATION</code>,<code>WARNING</code>, or
* <code>ERROR</code>.
* </p>
* <p>
* Note that for backward compatibility, a message of type
* <code>ERROR</code> is different than an error message (set using
* <code>setErrorMessage</code>). An error message overrides the current
* message until the error message is cleared. This method replaces the
* current message and does not affect the error message.
* </p>
*
* @param newMessage
* the message, or <code>null</code> to clear the message
* @param newType
* the message type
* @since 2.0
*/
public void setMessage(String newMessage, int newType) {
Image newImage = null;
if (newMessage != null) {
switch (newType) {
case IMessageProvider.NONE:
break;
case IMessageProvider.INFORMATION:
newImage = JFaceResources.getImage(DLG_IMG_MESSAGE_INFO);
break;
case IMessageProvider.WARNING:
newImage = JFaceResources.getImage(DLG_IMG_MESSAGE_WARNING);
break;
case IMessageProvider.ERROR:
newImage = JFaceResources.getImage(DLG_IMG_MESSAGE_ERROR);
break;
}
}
showMessage(newMessage, newImage);
}
/**
* Show the new message and image.
* @param newMessage
* @param newImage
*/
private void showMessage(String newMessage, Image newImage) {
// Any change?
if (message.equals(newMessage) && messageImage == newImage)
return;
message = newMessage;
if (message == null)
message = "";//$NON-NLS-1$
// Message string to be shown - if there is an image then add in
// a space to the message for layout purposes
String shownMessage = (newImage == null) ? message : " " + message; //$NON-NLS-1$
messageImage = newImage;
if (!showingError) {
// we are not showing an error
updateMessage(shownMessage);
messageImageLabel.setImage(messageImage);
setImageLabelVisible(messageImage != null);
layoutForNewMessage();
}
}
/**
* Update the contents of the messageLabel.
*
* @param newMessage
* the message to use
*/
private void updateMessage(String newMessage) {
messageLabel.setText(newMessage);
}
/**
* Sets the title to be shown in the title area of this dialog.
*
* @param newTitle
* the title show
*/
public void setTitle(String newTitle) {
if (titleLabel == null)
return;
String title = newTitle;
if (title == null)
title = "";//$NON-NLS-1$
titleLabel.setText(title);
}
/**
* Sets the title bar color for this dialog.
*
* @param color
* the title bar color
*/
public void setTitleAreaColor(RGB color) {
titleAreaRGB = color;
}
/**
* Sets the title image to be shown in the title area of this dialog.
*
* @param newTitleImage
* the title image show
*/
public void setTitleImage(Image newTitleImage) {
titleImage.setImage(newTitleImage);
titleImage.setVisible(newTitleImage != null);
if (newTitleImage != null) {
determineTitleImageLargest();
Control top;
if (titleImageLargest)
top = titleImage;
else
top = messageLabel;
resetWorkAreaAttachments(top);
}
}
/**
* Make the label used for displaying error images visible depending on
* boolean.
* @param visible If <code>true</code> make the image visible, if
* not then make it not visible.
*/
private void setImageLabelVisible(boolean visible) {
messageImageLabel.setVisible(visible);
bottomFillerLabel.setVisible(visible);
leftFillerLabel.setVisible(visible);
}
/**
* Set the message backgrounds to be the error or normal color depending on
* whether or not showingError is true.
* @param showingError If <code>true</code> use a different Color
* to indicate the error.
*/
private void setMessageBackgrounds(boolean showingError) {
Color color;
if (showingError)
color = errorMsgAreaBackground;
else
color = normalMsgAreaBackground;
messageLabel.setBackground(color);
messageImageLabel.setBackground(color);
bottomFillerLabel.setBackground(color);
leftFillerLabel.setBackground(color);
}
/**
* Reset the attachment of the workArea to now attach to top as the top
* control.
*
* @param top
*/
private void resetWorkAreaAttachments(Control top) {
FormData childData = new FormData();
childData.top = new FormAttachment(top);
childData.right = new FormAttachment(100, 0);
childData.left = new FormAttachment(0, 0);
childData.bottom = new FormAttachment(100, 0);
workArea.setLayoutData(childData);
}
}