blob: 6fb920f097d202d30d5827febe939c0e1ad9cf4e [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
*******************************************************************************/
package org.eclipse.jface.dialogs;
import java.util.Arrays;
import java.util.HashMap;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.util.Policy;
import org.eclipse.jface.window.IShellProvider;
import org.eclipse.jface.window.SameShellProvider;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FormData;
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.Shell;
/**
* A dialog is a specialized window used for narrow-focused communication with
* the user.
* <p>
* Dialogs are usually modal. Consequently, it is generally bad practice to open
* a dialog without a parent. A modal dialog without a parent is not prevented
* from disappearing behind the application's other windows, making it very
* confusing for the user.
* </p>
* <p>
* If there is more than one modal dialog is open the second one should be
* parented off of the shell of the first one otherwise it is possible that the
* OS will give focus to the first dialog potentially blocking the UI.
* </p>
*/
public abstract class Dialog extends Window {
/**
* Image registry key for error image (value
* <code>"dialog_error_image"</code>).
*
* @deprecated use
* org.eclipse.swt.widgets.Display.getSystemImage(SWT.ICON_ERROR)
*/
public static final String DLG_IMG_ERROR = "dialog_error_image"; //$NON-NLS-1$
/**
* Image registry key for info image (value <code>"dialog_info_image"</code>).
*
* @deprecated use
* org.eclipse.swt.widgets.Display.getSystemImage(SWT.ICON_INFORMATION)
*/
public static final String DLG_IMG_INFO = "dialog_info_imageg"; //$NON-NLS-1$
/**
* Image registry key for question image (value
* <code>"dialog_question_image"</code>).
*
* @deprecated org.eclipse.swt.widgets.Display.getSystemImage(SWT.ICON_QUESTION)
*/
public static final String DLG_IMG_QUESTION = "dialog_question_image"; //$NON-NLS-1$
/**
* Image registry key for warning image (value
* <code>"dialog_warning_image"</code>).
*
* @deprecated use
* org.eclipse.swt.widgets.Display.getSystemImage(SWT.ICON_WARNING)
*/
public static final String DLG_IMG_WARNING = "dialog_warning_image"; //$NON-NLS-1$
/**
* Image registry key for info message image (value
* <code>"dialog_messasge_info_image"</code>).
*
* @since 2.0
*/
public static final String DLG_IMG_MESSAGE_INFO = "dialog_messasge_info_image"; //$NON-NLS-1$
/**
* Image registry key for info message image (value
* <code>"dialog_messasge_warning_image"</code>).
*
* @since 2.0
*/
public static final String DLG_IMG_MESSAGE_WARNING = "dialog_messasge_warning_image"; //$NON-NLS-1$
/**
* Image registry key for info message image (value
* <code>"dialog_message_error_image"</code>).
*
* @since 2.0
*/
public static final String DLG_IMG_MESSAGE_ERROR = "dialog_message_error_image"; //$NON-NLS-1$
/**
* The ellipsis is the string that is used to represent shortened text.
*
* @since 3.0
*/
public static final String ELLIPSIS = "..."; //$NON-NLS-1$
/**
* The dialog settings key name for stored dialog x location.
*
* @since 3.2
*/
private static final String DIALOG_ORIGIN_X = "DIALOG_X_ORIGIN"; //$NON-NLS-1$
/**
* The dialog settings key name for stored dialog y location.
*
* @since 3.2
*/
private static final String DIALOG_ORIGIN_Y = "DIALOG_Y_ORIGIN"; //$NON-NLS-1$
/**
* The dialog settings key name for stored dialog width.
*
* @since 3.2
*/
private static final String DIALOG_WIDTH = "DIALOG_WIDTH"; //$NON-NLS-1$
/**
* The dialog settings key name for stored dialog height.
*
* @since 3.2
*/
private static final String DIALOG_HEIGHT = "DIALOG_HEIGHT"; //$NON-NLS-1$
/**
* A value that can be used for stored dialog width or height that
* indicates that the default bounds should be used.
*
* @since 3.2
*/
public static final int DIALOG_DEFAULT_BOUNDS = -1;
/**
* Constants that can be used for specifying the strategy for persisting
* dialog bounds. These constants represent bit masks that can be used
* together.
*
*@since 3.2
*/
/**
* Persist the last location of the dialog.
* @since 3.2
*/
public static final int DIALOG_PERSISTLOCATION = 0x0001;
/**
* Persist the last known size of the dialog.
* @since 3.2
*/
public static final int DIALOG_PERSISTSIZE = 0x0002;
/**
* NOTE: Dialog does not the following images in the registry DLG_IMG_ERROR
* DLG_IMG_INFO DLG_IMG_QUESTION DLG_IMG_WARNING
*
* They are now coming directly from SWT see ImageRegistry. For backwards
* compatibility they are still supported, however new code should use SWT
* for these.
*
* @see Display#getSystemIcon(int ID)
*/
static {
ImageRegistry reg = JFaceResources.getImageRegistry();
reg.put(DLG_IMG_MESSAGE_INFO, ImageDescriptor.createFromFile(
Dialog.class, "images/message_info.gif")); //$NON-NLS-1$
reg.put(DLG_IMG_MESSAGE_WARNING, ImageDescriptor.createFromFile(
Dialog.class, "images/message_warning.gif")); //$NON-NLS-1$
reg.put(DLG_IMG_MESSAGE_ERROR, ImageDescriptor.createFromFile(
Dialog.class, "images/message_error.gif")); //$NON-NLS-1$
}
/**
* The dialog area; <code>null</code> until dialog is layed out.
*/
protected Control dialogArea;
/**
* The button bar; <code>null</code> until dialog is layed out.
*/
public Control buttonBar;
/**
* A mouse listener that can be used to restore the default size
* of a dialog.
*
* @since 3.2
*/
private MouseListener restoreSizeMouseListener = new MouseAdapter() {
public void mouseDoubleClick(MouseEvent event) {
restoreDialogToComputedSize();
}
};
/**
* Collection of buttons created by the <code>createButton</code> method.
*/
private HashMap buttons = new HashMap();
/**
* Font metrics to use for determining pixel sizes.
*/
private FontMetrics fontMetrics;
/**
* Point used for storing initial computed size of the dialog so
* that it may be restored.
*/
private Point computedSize;
/**
* Number of horizontal dialog units per character, value <code>4</code>.
*/
private static final int HORIZONTAL_DIALOG_UNIT_PER_CHAR = 4;
/**
* Number of vertical dialog units per character, value <code>8</code>.
*/
private static final int VERTICAL_DIALOG_UNITS_PER_CHAR = 8;
/**
* Returns the number of pixels corresponding to the height of the given
* number of characters.
* <p>
* The required <code>FontMetrics</code> parameter may be created in the
* following way: <code>
* GC gc = new GC(control);
* gc.setFont(control.getFont());
* fontMetrics = gc.getFontMetrics();
* gc.dispose();
* </code>
* </p>
*
* @param fontMetrics
* used in performing the conversion
* @param chars
* the number of characters
* @return the number of pixels
* @since 2.0
*/
public static int convertHeightInCharsToPixels(FontMetrics fontMetrics,
int chars) {
return fontMetrics.getHeight() * chars;
}
/**
* Returns the number of pixels corresponding to the given number of
* horizontal dialog units.
* <p>
* The required <code>FontMetrics</code> parameter may be created in the
* following way: <code>
* GC gc = new GC(control);
* gc.setFont(control.getFont());
* fontMetrics = gc.getFontMetrics();
* gc.dispose();
* </code>
* </p>
*
* @param fontMetrics
* used in performing the conversion
* @param dlus
* the number of horizontal dialog units
* @return the number of pixels
* @since 2.0
*/
public static int convertHorizontalDLUsToPixels(FontMetrics fontMetrics,
int dlus) {
// round to the nearest pixel
return (fontMetrics.getAverageCharWidth() * dlus + HORIZONTAL_DIALOG_UNIT_PER_CHAR / 2)
/ HORIZONTAL_DIALOG_UNIT_PER_CHAR;
}
/**
* Returns the number of pixels corresponding to the given number of
* vertical dialog units.
* <p>
* The required <code>FontMetrics</code> parameter may be created in the
* following way: <code>
* GC gc = new GC(control);
* gc.setFont(control.getFont());
* fontMetrics = gc.getFontMetrics();
* gc.dispose();
* </code>
* </p>
*
* @param fontMetrics
* used in performing the conversion
* @param dlus
* the number of vertical dialog units
* @return the number of pixels
* @since 2.0
*/
public static int convertVerticalDLUsToPixels(FontMetrics fontMetrics,
int dlus) {
// round to the nearest pixel
return (fontMetrics.getHeight() * dlus + VERTICAL_DIALOG_UNITS_PER_CHAR / 2)
/ VERTICAL_DIALOG_UNITS_PER_CHAR;
}
/**
* Returns the number of pixels corresponding to the width of the given
* number of characters.
* <p>
* The required <code>FontMetrics</code> parameter may be created in the
* following way: <code>
* GC gc = new GC(control);
* gc.setFont(control.getFont());
* fontMetrics = gc.getFontMetrics();
* gc.dispose();
* </code>
* </p>
*
* @param fontMetrics
* used in performing the conversion
* @param chars
* the number of characters
* @return the number of pixels
* @since 2.0
*/
public static int convertWidthInCharsToPixels(FontMetrics fontMetrics,
int chars) {
return fontMetrics.getAverageCharWidth() * chars;
}
/**
* Shortens the given text <code>textValue</code> so that its width in
* pixels does not exceed the width of the given control. Overrides
* characters in the center of the original string with an ellipsis ("...")
* if necessary. If a <code>null</code> value is given, <code>null</code>
* is returned.
*
* @param textValue
* the original string or <code>null</code>
* @param control
* the control the string will be displayed on
* @return the string to display, or <code>null</code> if null was passed
* in
*
* @since 3.0
*/
public static String shortenText(String textValue, Control control) {
if (textValue == null)
return null;
GC gc = new GC(control);
int maxWidth = control.getBounds().width - 5;
if (gc.textExtent(textValue).x < maxWidth) {
gc.dispose();
return textValue;
}
int length = textValue.length();
int pivot = length / 2;
int start = pivot;
int end = pivot + 1;
while (start >= 0 && end < length) {
String s1 = textValue.substring(0, start);
String s2 = textValue.substring(end, length);
String s = s1 + ELLIPSIS + s2;
int l = gc.textExtent(s).x;
if (l < maxWidth) {
gc.dispose();
return s;
}
start--;
end++;
}
gc.dispose();
return textValue;
}
/**
* Create a default instance of the blocked handler which does not do
* anything.
*/
public static IDialogBlockedHandler blockedHandler = new IDialogBlockedHandler() {
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.dialogs.IDialogBlockedHandler#clearBlocked()
*/
public void clearBlocked() {
// No default behaviour
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.dialogs.IDialogBlockedHandler#showBlocked(org.eclipse.core.runtime.IProgressMonitor,
* org.eclipse.core.runtime.IStatus, java.lang.String)
*/
public void showBlocked(IProgressMonitor blocking,
IStatus blockingStatus, String blockedName) {
// No default behaviour
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.dialogs.IDialogBlockedHandler#showBlocked(org.eclipse.swt.widgets.Shell,
* org.eclipse.core.runtime.IProgressMonitor,
* org.eclipse.core.runtime.IStatus, java.lang.String)
*/
public void showBlocked(Shell parentShell, IProgressMonitor blocking,
IStatus blockingStatus, String blockedName) {
// No default behaviour
}
};
/**
* Creates a dialog instance. Note that the window will have no visual
* representation (no widgets) until it is told to open. By default,
* <code>open</code> blocks for dialogs.
*
* @param parentShell
* the parent shell, or <code>null</code> to create a top-level
* shell
*/
protected Dialog(Shell parentShell) {
this(new SameShellProvider(parentShell));
if (parentShell == null && Policy.DEBUG_DIALOG_NO_PARENT)
Policy.getLog().log(
new Status(IStatus.INFO, Policy.JFACE, IStatus.INFO, this
.getClass()
+ " created with no shell",//$NON-NLS-1$
new Exception()));
}
/**
* Creates a dialog with the given parent.
*
* @param parentShell
* object that returns the current parent shell
*
* @since 3.1
*/
protected Dialog(IShellProvider parentShell) {
super(parentShell);
setShellStyle(SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL
| getDefaultOrientation());
setBlockOnOpen(true);
}
/**
* Notifies that this dialog's button with the given id has been pressed.
* <p>
* The <code>Dialog</code> implementation of this framework method calls
* <code>okPressed</code> if the ok button is the pressed, and
* <code>cancelPressed</code> if the cancel button is the pressed. All
* other button presses are ignored. Subclasses may override to handle other
* buttons, but should call <code>super.buttonPressed</code> if the
* default handling of the ok and cancel buttons is desired.
* </p>
*
* @param buttonId
* the id of the button that was pressed (see
* <code>IDialogConstants.*_ID</code> constants)
*/
protected void buttonPressed(int buttonId) {
if (IDialogConstants.OK_ID == buttonId)
okPressed();
else if (IDialogConstants.CANCEL_ID == buttonId)
cancelPressed();
}
/**
* Notifies that the cancel button of this dialog has been pressed.
* <p>
* The <code>Dialog</code> implementation of this framework method sets
* this dialog's return code to <code>Window.CANCEL</code> and closes the
* dialog. Subclasses may override if desired.
* </p>
*/
protected void cancelPressed() {
setReturnCode(CANCEL);
close();
}
/**
* Returns the number of pixels corresponding to the height of the given
* number of characters.
* <p>
* This method may only be called after <code>initializeDialogUnits</code>
* has been called.
* </p>
* <p>
* Clients may call this framework method, but should not override it.
* </p>
*
* @param chars
* the number of characters
* @return the number of pixels
*/
protected int convertHeightInCharsToPixels(int chars) {
// test for failure to initialize for backward compatibility
if (fontMetrics == null)
return 0;
return convertHeightInCharsToPixels(fontMetrics, chars);
}
/**
* Returns the number of pixels corresponding to the given number of
* horizontal dialog units.
* <p>
* This method may only be called after <code>initializeDialogUnits</code>
* has been called.
* </p>
* <p>
* Clients may call this framework method, but should not override it.
* </p>
*
* @param dlus
* the number of horizontal dialog units
* @return the number of pixels
*/
protected int convertHorizontalDLUsToPixels(int dlus) {
// test for failure to initialize for backward compatibility
if (fontMetrics == null)
return 0;
return convertHorizontalDLUsToPixels(fontMetrics, dlus);
}
/**
* Returns the number of pixels corresponding to the given number of
* vertical dialog units.
* <p>
* This method may only be called after <code>initializeDialogUnits</code>
* has been called.
* </p>
* <p>
* Clients may call this framework method, but should not override it.
* </p>
*
* @param dlus
* the number of vertical dialog units
* @return the number of pixels
*/
protected int convertVerticalDLUsToPixels(int dlus) {
// test for failure to initialize for backward compatibility
if (fontMetrics == null)
return 0;
return convertVerticalDLUsToPixels(fontMetrics, dlus);
}
/**
* Returns the number of pixels corresponding to the width of the given
* number of characters.
* <p>
* This method may only be called after <code>initializeDialogUnits</code>
* has been called.
* </p>
* <p>
* Clients may call this framework method, but should not override it.
* </p>
*
* @param chars
* the number of characters
* @return the number of pixels
*/
protected int convertWidthInCharsToPixels(int chars) {
// test for failure to initialize for backward compatibility
if (fontMetrics == null)
return 0;
return convertWidthInCharsToPixels(fontMetrics, chars);
}
/**
* Creates a new button with the given id.
* <p>
* The <code>Dialog</code> implementation of this framework method creates
* a standard push button, registers it for selection events including
* button presses, and registers default buttons with its shell. The button
* id is stored as the button's client data. If the button id is
* <code>IDialogConstants.CANCEL_ID</code>, the new button will be
* accessible from <code>getCancelButton()</code>. If the button id is
* <code>IDialogConstants.OK_ID</code>, the new button will be accesible
* from <code>getOKButton()</code>. Note that the parent's layout is
* assumed to be a <code>GridLayout</code> and the number of columns in
* this layout is incremented. Subclasses may override.
* </p>
*
* @param parent
* the parent composite
* @param id
* the id of the button (see <code>IDialogConstants.*_ID</code>
* constants for standard dialog button ids)
* @param label
* the label from the button
* @param defaultButton
* <code>true</code> if the button is to be the default button,
* and <code>false</code> otherwise
*
* @return the new button
*
* @see #getCancelButton
* @see #getOKButton()
*/
protected Button createButton(Composite parent, int id, String label,
boolean defaultButton) {
// increment the number of columns in the button bar
((GridLayout) parent.getLayout()).numColumns++;
Button button = new Button(parent, SWT.PUSH);
button.setText(label);
button.setFont(JFaceResources.getDialogFont());
button.setData(new Integer(id));
button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
buttonPressed(((Integer) event.widget.getData()).intValue());
}
});
if (defaultButton) {
Shell shell = parent.getShell();
if (shell != null) {
shell.setDefaultButton(button);
}
}
buttons.put(new Integer(id), button);
setButtonLayoutData(button);
return button;
}
/**
* Creates and returns the contents of this dialog's button bar.
* <p>
* The <code>Dialog</code> implementation of this framework method lays
* out a button bar and calls the <code>createButtonsForButtonBar</code>
* framework method to populate it. Subclasses may override.
* </p>
* <p>
* The returned control's layout data must be an instance of
* <code>GridData</code>.
* </p>
*
* @param parent
* the parent composite to contain the button bar
* @return the button bar control
*/
protected Control createButtonBar(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
// create a layout with spacing and margins appropriate for the font
// size.
GridLayout layout = new GridLayout();
layout.numColumns = 0; // this is incremented by createButton
layout.makeColumnsEqualWidth = true;
layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
composite.setLayout(layout);
GridData data = new GridData(GridData.HORIZONTAL_ALIGN_END
| GridData.VERTICAL_ALIGN_CENTER);
composite.setLayoutData(data);
composite.setFont(parent.getFont());
// Add the buttons to the button bar.
createButtonsForButtonBar(composite);
return composite;
}
/**
* Adds buttons to this dialog's button bar.
* <p>
* The <code>Dialog</code> implementation of this framework method adds
* standard ok and cancel buttons using the <code>createButton</code>
* framework method. These standard buttons will be accessible from
* <code>getCancelButton</code>, and <code>getOKButton</code>.
* Subclasses may override.
* </p>
*
* @param parent
* the button bar composite
*/
protected void createButtonsForButtonBar(Composite parent) {
// create OK and Cancel buttons by default
createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL,
true);
createButton(parent, IDialogConstants.CANCEL_ID,
IDialogConstants.CANCEL_LABEL, false);
}
/*
* @see Window.initializeBounds()
*/
protected void initializeBounds() {
String platform = SWT.getPlatform();
if ("carbon".equals(platform)) { //$NON-NLS-1$
// On Mac OS X the default button must be the right-most button
Shell shell = getShell();
if (shell != null) {
Button defaultButton = shell.getDefaultButton();
if (defaultButton != null
&& isContained(buttonBar, defaultButton))
defaultButton.moveBelow(null);
}
}
// Store the computed size for the dialog. Must be done here before
// any dialog settings are applied. We don't do this in the create methods
// because the dialog font is applied after creation and before the bounds
// are initialized.
computedSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
super.initializeBounds();
}
/**
* Returns true if the given Control is a direct or indirect child of
* container.
*
* @param container
* the potential parent
* @param control
* @return boolean <code>true</code> if control is a child of container
*/
private boolean isContained(Control container, Control control) {
Composite parent;
while ((parent = control.getParent()) != null) {
if (parent == container)
return true;
control = parent;
}
return false;
}
/**
* The <code>Dialog</code> implementation of this <code>Window</code>
* method creates and lays out the top level composite for the dialog, and
* determines the appropriate horizontal and vertical dialog units based on
* the font size. It then calls the <code>createDialogArea</code> and
* <code>createButtonBar</code> methods to create the dialog area and
* button bar, respectively. Overriding <code>createDialogArea</code> and
* <code>createButtonBar</code> are recommended rather than overriding
* this method.
*/
protected Control createContents(Composite parent) {
// create the top level composite for the dialog
Composite composite = new Composite(parent, 0);
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.verticalSpacing = 0;
composite.setLayout(layout);
composite.setLayoutData(new GridData(GridData.FILL_BOTH));
applyDialogFont(composite);
// initialize the dialog units
initializeDialogUnits(composite);
// create the dialog area and button bar
dialogArea = createDialogArea(composite);
buttonBar = createButtonBar(composite);
return composite;
}
/**
* 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 standard margins and
* spacing.
* </p>
* <p>
* The returned control's layout data must be an instance of
* <code>GridData</code>. This method must not modify the parent's
* layout.
* </p>
* <p>
* Subclasses must override this method but may call <code>super</code> as
* in the following example:
* </p>
*
* <pre>
* Composite composite = (Composite) super.createDialogArea(parent);
* //add controls to composite as necessary
* return composite;
* </pre>
*
* @param parent
* the parent composite to contain the dialog area
* @return the dialog area control
*/
protected Control createDialogArea(Composite parent) {
// create a composite with standard margins and spacing
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
composite.setLayout(layout);
composite.setLayoutData(new GridData(GridData.FILL_BOTH));
applyDialogFont(composite);
return composite;
}
/**
* Returns the button created by the method <code>createButton</code> for
* the specified ID as defined on <code>IDialogConstants</code>. If
* <code>createButton</code> was never called with this ID, or if
* <code>createButton</code> is overridden, this method will return
* <code>null</code>.
*
* @param id
* the id of the button to look for
*
* @return the button for the ID or <code>null</code>
*
* @see #createButton(Composite, int, String, boolean)
* @since 2.0
*/
protected Button getButton(int id) {
return (Button) buttons.get(new Integer(id));
}
/**
* Returns the button bar control.
* <p>
* Clients may call this framework method, but should not override it.
* </p>
*
* @return the button bar, or <code>null</code> if the button bar has not
* been created yet
*/
protected Control getButtonBar() {
return buttonBar;
}
/**
* Returns the button created when <code>createButton</code> is called
* with an ID of <code>IDialogConstants.CANCEL_ID</code>. If
* <code>createButton</code> was never called with this parameter, or if
* <code>createButton</code> is overridden, <code>getCancelButton</code>
* will return <code>null</code>.
*
* @return the cancel button or <code>null</code>
*
* @see #createButton(Composite, int, String, boolean)
* @since 2.0
* @deprecated Use <code>getButton(IDialogConstants.CANCEL_ID)</code>
* instead. This method will be removed soon.
*/
protected Button getCancelButton() {
return getButton(IDialogConstants.CANCEL_ID);
}
/**
* Returns the dialog area control.
* <p>
* Clients may call this framework method, but should not override it.
* </p>
*
* @return the dialog area, or <code>null</code> if the dialog area has
* not been created yet
*/
protected Control getDialogArea() {
return dialogArea;
}
/**
* Returns the standard dialog image with the given key. Note that these
* images are managed by the dialog framework, and must not be disposed by
* another party.
*
* @param key
* one of the <code>Dialog.DLG_IMG_* </code> constants
* @return the standard dialog image
*/
public static Image getImage(String key) {
return JFaceResources.getImageRegistry().get(key);
}
/**
* Returns the button created when <code>createButton</code> is called
* with an ID of <code>IDialogConstants.OK_ID</code>. If
* <code>createButton</code> was never called with this parameter, or if
* <code>createButton</code> is overridden, <code>getOKButton</code>
* will return <code>null</code>.
*
* @return the OK button or <code>null</code>
*
* @see #createButton(Composite, int, String, boolean)
* @since 2.0
* @deprecated Use <code>getButton(IDialogConstants.OK_ID)</code> instead.
* This method will be removed soon.
*/
protected Button getOKButton() {
return getButton(IDialogConstants.OK_ID);
}
/**
* Initializes the computation of horizontal and vertical dialog units based
* on the size of current font.
* <p>
* This method must be called before any of the dialog unit based conversion
* methods are called.
* </p>
*
* @param control
* a control from which to obtain the current font
*/
protected void initializeDialogUnits(Control control) {
// Compute and store a font metric
GC gc = new GC(control);
gc.setFont(JFaceResources.getDialogFont());
fontMetrics = gc.getFontMetrics();
gc.dispose();
}
/**
* Notifies that the ok button of this dialog has been pressed.
* <p>
* The <code>Dialog</code> implementation of this framework method sets
* this dialog's return code to <code>Window.OK</code> and closes the
* dialog. Subclasses may override.
* </p>
*/
protected void okPressed() {
setReturnCode(OK);
close();
}
/**
* Set the layout data of the button to a GridData with appropriate heights
* and widths.
*
* @param button
*/
protected void setButtonLayoutData(Button button) {
GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
Point minSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
data.widthHint = Math.max(widthHint, minSize.x);
button.setLayoutData(data);
}
/**
* Set the layout data of the button to a FormData with appropriate heights
* and widths.
*
* @param button
*/
protected void setButtonLayoutFormData(Button button) {
FormData data = new FormData();
int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
Point minSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
data.width = Math.max(widthHint, minSize.x);
button.setLayoutData(data);
}
/**
* @see org.eclipse.jface.window.Window#close()
*/
public boolean close() {
if (getShell() != null && !getShell().isDisposed())
saveDialogBounds(getShell());
removeRestoreSizeMouseListeners();
boolean returnValue = super.close();
if (returnValue) {
buttons = new HashMap();
buttonBar = null;
dialogArea = null;
}
return returnValue;
}
/**
* Applies the dialog font to all controls that currently have the default
* font.
*
* @param control
* the control to apply the font to. Font will also be applied to
* its children. If the control is <code>null</code> nothing
* happens.
*/
public static void applyDialogFont(Control control) {
if (control == null || dialogFontIsDefault())
return;
Font dialogFont = JFaceResources.getDialogFont();
applyDialogFont(control, dialogFont);
}
/**
* Sets the dialog font on the control and any of its children if thier font
* is not otherwise set.
*
* @param control
* the control to apply the font to. Font will also be applied to
* its children.
* @param dialogFont
* the dialog font to set
*/
private static void applyDialogFont(Control control, Font dialogFont) {
if (hasDefaultFont(control))
control.setFont(dialogFont);
if (control instanceof Composite) {
Control[] children = ((Composite) control).getChildren();
for (int i = 0; i < children.length; i++)
applyDialogFont(children[i], dialogFont);
}
}
/**
* Return whether or not this control has the same font as it's default.
*
* @param control
* Control
* @return boolean
*/
private static boolean hasDefaultFont(Control control) {
FontData[] controlFontData = control.getFont().getFontData();
FontData[] defaultFontData = getDefaultFont(control).getFontData();
if (controlFontData.length == defaultFontData.length) {
for (int i = 0; i < controlFontData.length; i++) {
if (controlFontData[i].equals(defaultFontData[i]))
continue;
return false;
}
return true;
}
return false;
}
/**
* Get the default font for this type of control.
*
* @param control
* @return the default font
*/
private static Font getDefaultFont(Control control) {
String fontName = "DEFAULT_FONT_" + control.getClass().getName(); //$NON-NLS-1$
if (JFaceResources.getFontRegistry().hasValueFor(fontName))
return JFaceResources.getFontRegistry().get(fontName);
Font cached = control.getFont();
control.setFont(null);
Font defaultFont = control.getFont();
control.setFont(cached);
JFaceResources.getFontRegistry().put(fontName,
defaultFont.getFontData());
return defaultFont;
}
/**
* Return whether or not the dialog font is currently the same as the
* default font.
*
* @return boolean if the two are the same
*/
protected static boolean dialogFontIsDefault() {
FontData[] dialogFontData = JFaceResources.getFontRegistry()
.getFontData(JFaceResources.DIALOG_FONT);
FontData[] defaultFontData = JFaceResources.getFontRegistry()
.getFontData(JFaceResources.DEFAULT_FONT);
return Arrays.equals(dialogFontData, defaultFontData);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.window.Window#create()
*/
public void create() {
super.create();
applyDialogFont(buttonBar);
// Register a mouse listener so that the user can restore this
// size with a double-click.
// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=116906
addRestoreSizeMouseListeners();
}
/**
* Get the IDialogBlockedHandler to be used by WizardDialogs and
* ModalContexts.
*
* @return Returns the blockedHandler.
*/
public static IDialogBlockedHandler getBlockedHandler() {
return blockedHandler;
}
/**
* Set the IDialogBlockedHandler to be used by WizardDialogs and
* ModalContexts.
*
* @param blockedHandler
* The blockedHandler for the dialogs.
*/
public static void setBlockedHandler(IDialogBlockedHandler blockedHandler) {
Dialog.blockedHandler = blockedHandler;
}
/**
* Gets the dialog settings that should be used for remembering the bounds of
* of the dialog, according to the dialog bounds strategy.
*
* @return settings the dialog settings used to store the dialog's location
* and/or size, or <code>null</code> if the dialog's bounds should
* never be stored.
*
* @since 3.2
* @see Dialog#getDialogBoundsStrategy()
*/
protected IDialogSettings getDialogBoundsSettings() {
return null;
}
/**
* Get the integer constant that describes the strategy for persisting the
* dialog bounds. This strategy is ignored if the implementer does not also
* specify the dialog settings for storing the bounds in
* Dialog.getDialogBoundsSettings().
*
* @return the constant describing the strategy for persisting the dialog
* bounds.
*
* @since 3.2
* @see Dialog#DIALOG_PERSISTLOCATION
* @see Dialog#DIALOG_PERSISTSIZE
* @see Dialog#getDialogBoundsSettings()
*/
protected int getDialogBoundsStrategy() {
return DIALOG_PERSISTLOCATION | DIALOG_PERSISTSIZE;
}
/**
* Saves the bounds of the shell in the appropriate dialog settings. The
* bounds are recorded relative to the parent shell, if there is one, or
* display coordinates if there is no parent shell.
*
* @param shell
* The shell whose bounds are to be stored
*
* @since 3.2
*/
private void saveDialogBounds(Shell shell) {
IDialogSettings settings = getDialogBoundsSettings();
if (settings != null) {
Point shellLocation = shell.getLocation();
Point shellSize = shell.getSize();
Shell parent = getParentShell();
if (parent != null) {
Point parentLocation = parent.getLocation();
shellLocation.x -= parentLocation.x;
shellLocation.y -= parentLocation.y;
}
int strategy = getDialogBoundsStrategy();
if ((strategy & DIALOG_PERSISTLOCATION) != 0) {
settings.put(DIALOG_ORIGIN_X, shellLocation.x);
settings.put(DIALOG_ORIGIN_Y, shellLocation.y);
}
if ((strategy & DIALOG_PERSISTSIZE) != 0) {
settings.put(DIALOG_WIDTH, shellSize.x);
settings.put(DIALOG_HEIGHT, shellSize.y);
}
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.window.Window#getInitialSize()
*
* @since 3.2
*/
protected Point getInitialSize() {
Point result = super.getInitialSize();
// Check the dialog settings for a stored size.
if ((getDialogBoundsStrategy() & DIALOG_PERSISTSIZE)!= 0) {
IDialogSettings settings = getDialogBoundsSettings();
if (settings != null) {
try {
// Get the stored width and height.
int width = settings.getInt(DIALOG_WIDTH);
if (width != DIALOG_DEFAULT_BOUNDS)
result.x = width;
int height = settings.getInt(DIALOG_HEIGHT);
if (height != DIALOG_DEFAULT_BOUNDS)
result.y = height;
} catch (NumberFormatException e) {
}
}
}
// No attempt is made to constrain the bounds. The default
// constraining behavior in Window will be used.
return result;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.window.Window#getInitialLocation(org.eclipse.swt.graphics.Point)
*
* @since 3.2
*/
protected Point getInitialLocation(Point initialSize) {
Point result = super.getInitialLocation(initialSize);
if ((getDialogBoundsStrategy() & DIALOG_PERSISTLOCATION)!= 0) {
IDialogSettings settings = getDialogBoundsSettings();
if (settings != null) {
try {
int x = settings.getInt(DIALOG_ORIGIN_X);
int y = settings.getInt(DIALOG_ORIGIN_Y);
result = new Point(x, y);
// The coordinates were stored relative to the parent shell.
// Convert to display coordinates.
Shell parent = getParentShell();
if (parent != null) {
Point parentLocation = parent.getLocation();
result.x += parentLocation.x;
result.y += parentLocation.y;
}
} catch (NumberFormatException e) {
}
}
}
// No attempt is made to constrain the bounds. The default
// constraining behavior in Window will be used.
return result;
}
/**
* Add mouse listeners as needed to provide dialog size restore
* behavior. Double-clicking in unused areas will restore
* the dialog size.
*
* @since 3.2
*/
private void addRestoreSizeMouseListeners() {
// Hook a double click event for restoring the dialog's computed
// size. We hook onto the button bar and the contents, and any
// nested composites in between, in order to accomodate different
// layout and construction styles.
Control dialogContents = getContents();
if (buttonBar != null) {
buttonBar.addMouseListener(restoreSizeMouseListener);
Control control = buttonBar.getParent();
while (control != dialogContents && control != null) {
control.addMouseListener(restoreSizeMouseListener);
control = control.getParent();
}
}
if (dialogContents != null)
dialogContents.addMouseListener(restoreSizeMouseListener);
}
/**
* Remove any mouse listeners that were registered.
*
* @since 3.2
*/
private void removeRestoreSizeMouseListeners() {
Control dialogContents = getContents();
if (buttonBar != null && !buttonBar.isDisposed()) {
buttonBar.removeMouseListener(restoreSizeMouseListener);
Control control = buttonBar.getParent();
while (control != dialogContents && control != null && !control.isDisposed()) {
control.removeMouseListener(restoreSizeMouseListener);
control = control.getParent();
}
}
if (dialogContents != null && !dialogContents.isDisposed())
dialogContents.removeMouseListener(restoreSizeMouseListener);
}
/**
* Restore the dialog to its initially computed size, resetting
* any bounds that may have been stored in dialog settings.
*
* @since 3.2
*/
private void restoreDialogToComputedSize() {
// The computed size was never stored. This should not typically
// happen, but could if a client completely override the bounds initialization.
if (computedSize == null)
return;
Shell shell = getShell();
Point shellSize = shell.getSize();
Point shellLocation = shell.getLocation();
// If the size has not changed, do nothing
if (shellSize.equals(computedSize))
return;
// Now reset the bounds
shell.setBounds(getConstrainedShellBounds(new Rectangle(shellLocation.x,
shellLocation.y, computedSize.x, computedSize.y)));
// If we do store the bounds, update the value so default bounds
// will be used.
IDialogSettings settings = getDialogBoundsSettings();
if (settings != null) {
int strategy = getDialogBoundsStrategy();
if ((strategy & DIALOG_PERSISTSIZE) != 0) {
settings.put(DIALOG_WIDTH, DIALOG_DEFAULT_BOUNDS);
settings.put(DIALOG_HEIGHT, DIALOG_DEFAULT_BOUNDS);
}
}
}
}