org.eclipse.jface.dialogs.Dialog Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2000, 2019 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Remy Chi Jian Suen - Bug 218553 [JFace] mis-spelling of their in applyDialogFont(...)
*******************************************************************************/
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.JFaceResources;
import org.eclipse.jface.util.Policy;
import org.eclipse.jface.widgets.WidgetFactory;
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.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.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.Display;
import org.eclipse.swt.widgets.Shell;
/**
* A dialog is a specialized window used for narrow-focused communication with
* the user.
*
* 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.
*
*
* If 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.
*
*
* This class also moves the default button to the right if required, see
* {@link #initializeBounds()}.
*
*/
public abstract class Dialog extends Window {
/**
* Image registry key for error image (value
* "dialog_error_image"
).
*
* @deprecated use
* org.eclipse.swt.widgets.Display.getSystemImage(SWT.ICON_ERROR)
*/
@Deprecated(forRemoval = true, since = "2023-12")
public static final String DLG_IMG_ERROR = "dialog_error_image"; //$NON-NLS-1$
/**
* Image registry key for info image (value "dialog_info_image"
).
*
* @deprecated use
* org.eclipse.swt.widgets.Display.getSystemImage(SWT.ICON_INFORMATION)
*/
@Deprecated(forRemoval = true, since = "2023-12")
public static final String DLG_IMG_INFO = "dialog_info_imageg"; //$NON-NLS-1$
/**
* Image registry key for question image (value
* "dialog_question_image"
).
*
* @deprecated org.eclipse.swt.widgets.Display.getSystemImage(SWT.ICON_QUESTION)
*/
@Deprecated(forRemoval = true, since = "2023-12")
public static final String DLG_IMG_QUESTION = "dialog_question_image"; //$NON-NLS-1$
/**
* Image registry key for warning image (value
* "dialog_warning_image"
).
*
* @deprecated use
* org.eclipse.swt.widgets.Display.getSystemImage(SWT.ICON_WARNING)
*/
@Deprecated
public static final String DLG_IMG_WARNING = "dialog_warning_image"; //$NON-NLS-1$
/**
* Image registry key for info message image (value
* "dialog_messasge_info_image"
).
*
* @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
* "dialog_messasge_warning_image"
).
*
* @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
* "dialog_message_error_image"
).
*
* @since 2.0
*/
public static final String DLG_IMG_MESSAGE_ERROR = "dialog_message_error_image"; //$NON-NLS-1$
/**
* Image registry key for help image (value
* "dialog_help_image"
).
*
* @since 3.2
*/
public static final String DLG_IMG_HELP = "dialog_help_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$
/**
* The dialog settings key name for the font used when the dialog
* height and width was stored.
*
*@since 3.2
*/
private static final String DIALOG_FONT_DATA = "DIALOG_FONT_NAME"; //$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;
/**
* The dialog area; null
until dialog is layed out.
*/
protected Control dialogArea;
/**
* The button bar; null
until dialog is layed out.
*/
public Control buttonBar;
/**
* Collection of buttons created by the createButton
method.
*/
private HashMap buttons = new HashMap<>();
/**
* Font metrics to use for determining pixel sizes.
*/
private FontMetrics fontMetrics;
/**
* Number of horizontal dialog units per character, value 4
.
*/
private static final int HORIZONTAL_DIALOG_UNIT_PER_CHAR = 4;
/**
* Number of vertical dialog units per character, value 8
.
*/
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.
*
* The required FontMetrics
parameter may be created in the
* following way:
*
*
*
* GC gc = new GC(control);
* gc.setFont(control.getFont());
* fontMetrics = gc.getFontMetrics();
* gc.dispose();
*
*
* @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.
*
* The required FontMetrics
parameter may be created in the
* following way:
*
*
*
* GC gc = new GC(control);
* gc.setFont(control.getFont());
* fontMetrics = gc.getFontMetrics();
* gc.dispose();
*
*
* @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 (int) ((fontMetrics.getAverageCharacterWidth() * 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.
*
* The required FontMetrics
parameter may be created in the
* following way:
*
*
*
* GC gc = new GC(control);
* gc.setFont(control.getFont());
* fontMetrics = gc.getFontMetrics();
* gc.dispose();
*
*
* @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.
*
* The required FontMetrics
parameter may be created in the
* following way:
*
*
*
* GC gc = new GC(control);
* gc.setFont(control.getFont());
* fontMetrics = gc.getFontMetrics();
* gc.dispose();
*
*
* @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 (int) (fontMetrics.getAverageCharacterWidth() * chars);
}
/**
* Try to shorten the given text textValue
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 null
value is given, null
is returned.
*
* Note: if the text cannot be shortened because the width of control is
* too low the full original string is returned.
*
*
* @param textValue the original string or null
* @param control the control the string will be displayed on
* @return the string to display, or null
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;
int maxExtent = gc.textExtent(textValue).x;
if (maxExtent < maxWidth) {
gc.dispose();
return textValue;
}
int length = textValue.length();
int charsToClip = Math.round(0.95f*length * (1 - ((float)maxWidth/maxExtent)));
int pivot = length / 2;
int start = pivot - (charsToClip/2);
int end = pivot + (charsToClip/2) + 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() {
@Override
public void clearBlocked() {
// No default behavior
}
@Override
public void showBlocked(IProgressMonitor blocking,
IStatus blockingStatus, String blockedName) {
// No default behavior
}
@Override
public void showBlocked(Shell parentShell, IProgressMonitor blocking,
IStatus blockingStatus, String blockedName) {
// No default behavior
}
};
/**
* Creates a dialog instance. Note that the window will have no visual
* representation (no widgets) until it is told to open. By default,
* open
blocks for dialogs.
*
* @param parentShell
* the parent shell, or null
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);
if (isResizable()) {
setShellStyle(SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL | SWT.MAX | SWT.RESIZE
| getDefaultOrientation());
} else {
setShellStyle(SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL
| getDefaultOrientation());
}
setBlockOnOpen(true);
}
/**
* Notifies that this dialog's button with the given id has been pressed.
*
* The Dialog
implementation of this framework method calls
* okPressed
if the ok button is the pressed, and
* cancelPressed
if the cancel button is the pressed. All
* other button presses are ignored. Subclasses may override to handle other
* buttons, but should call super.buttonPressed
if the
* default handling of the ok and cancel buttons is desired.
*
*
* @param buttonId
* the id of the button that was pressed (see
* IDialogConstants.*_ID
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.
*
* The Dialog
implementation of this framework method sets
* this dialog's return code to Window.CANCEL
and closes the
* dialog. Subclasses may override if desired.
*
*/
protected void cancelPressed() {
setReturnCode(CANCEL);
close();
}
/**
* Returns the number of pixels corresponding to the height of the given
* number of characters.
*
* This method may only be called after initializeDialogUnits
* has been called.
*
*
* Clients may call this framework method, but should not override it.
*
*
* @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.
*
* This method may only be called after initializeDialogUnits
* has been called.
*
*
* Clients may call this framework method, but should not override it.
*
*
* @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.
*
* This method may only be called after initializeDialogUnits
* has been called.
*
*
* Clients may call this framework method, but should not override it.
*
*
* @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.
*
* This method may only be called after initializeDialogUnits
* has been called.
*
*
* Clients may call this framework method, but should not override it.
*
*
* @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.
*
* The Dialog
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
* IDialogConstants.CANCEL_ID
, the new button will be
* accessible from getCancelButton()
. If the button id is
* IDialogConstants.OK_ID
, the new button will be accesible
* from getOKButton()
. Note that the parent's layout is
* assumed to be a GridLayout
and the number of columns in
* this layout is incremented. Subclasses may override.
*
*
* Note: The common button order is: {other buttons}, OK, Cancel.
* On some platforms, {@link #initializeBounds()} will move the default button to the right.
*
*
* @param parent
* the parent composite
* @param id
* the id of the button (see IDialogConstants.*_ID
* constants for standard dialog button ids)
* @param label
* the label from the button
* @param defaultButton
* true
if the button is to be the default button,
* and false
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 = WidgetFactory.button(SWT.PUSH).text(label).font(JFaceResources.getDialogFont())
.data(Integer.valueOf(id))
.onSelect(event -> buttonPressed(((Integer) event.widget.getData()).intValue())).
create(parent);
if (defaultButton) {
Shell shell = parent.getShell();
if (shell != null) {
shell.setDefaultButton(button);
}
}
buttons.put(Integer.valueOf(id), button);
setButtonLayoutData(button);
return button;
}
/**
* Creates and returns the contents of this dialog's button bar.
*
* The Dialog
implementation of this framework method lays
* out a button bar and calls the createButtonsForButtonBar
* framework method to populate it. Subclasses may override.
*
*
* The returned control's layout data must be an instance of
* GridData
.
*
*
* @param parent
* the parent composite to contain the button bar
* @return the button bar control
*/
protected Control createButtonBar(Composite parent) {
// 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);
GridData data = new GridData(GridData.HORIZONTAL_ALIGN_END
| GridData.VERTICAL_ALIGN_CENTER);
Composite composite = WidgetFactory.composite(SWT.NONE).layout(layout).layoutData(data).font(parent.getFont())
.create(parent);
// Add the buttons to the button bar.
createButtonsForButtonBar(composite);
return composite;
}
/**
* Adds buttons to this dialog's button bar.
*
* The Dialog
implementation of this framework method adds
* standard ok and cancel buttons using the createButton
* framework method. These standard buttons will be accessible from
* getCancelButton
, and getOKButton
.
* Subclasses may override.
*
*
* Note: The common button order is: {other buttons}, OK, Cancel.
* On some platforms, {@link #initializeBounds()} will move the default button to the right.
*
*
* @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);
}
/**
* {@inheritDoc}
*
* The implementation in {@link #Dialog} also moves the
* {@link Shell#getDefaultButton() default button} in the
* {@link #createButtonBar(Composite) button bar} to the right
* if that's required by the
* {@link Display#getDismissalAlignment() platform convention}.
*
*/
@Override
protected void initializeBounds() {
// UI guidelines:
// https://developer.gnome.org/hig/stable/dialogs.html.en#primary-buttons
// https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/OSXHIGuidelines/WindowDialogs.html#//apple_ref/doc/uid/20000957-CH43-SW5
// https://msdn.microsoft.com/en-us/library/windows/desktop/dn742499(v=vs.85).aspx#win_dialog_box_image25
Shell shell = getShell();
if (shell != null) {
if (shell.getDisplay().getDismissalAlignment() == SWT.RIGHT) {
// make the default button the right-most button
Button defaultButton = shell.getDefaultButton();
if (defaultButton != null
&& isContained(buttonBar, defaultButton)) {
defaultButton.moveBelow(null);
defaultButton.getParent().layout();
}
}
}
super.initializeBounds();
}
/**
* Returns true if the given Control is a direct or indirect child of
* container.
*
* @param container
* the potential parent
* @return boolean true
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 Dialog
implementation of this Window
* 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 createDialogArea
and
* createButtonBar
methods to create the dialog area and
* button bar, respectively. Overriding createDialogArea
and
* createButtonBar
are recommended rather than overriding
* this method.
*/
@Override
protected Control createContents(Composite parent) {
// create the top level composite for the dialog
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.verticalSpacing = 0;
Composite composite = WidgetFactory.composite(0).layout(layout).layoutData(new GridData(GridData.FILL_BOTH))
.create(parent);
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).
*
* The Dialog
implementation of this framework method creates
* and returns a new Composite
with standard margins and
* spacing.
*
*
* The returned control's layout data must be an instance of
* GridData
. This method must not modify the parent's
* layout.
*
*
* Subclasses must override this method but may call super
as
* in the following example:
*
*
*
* Composite composite = (Composite) super.createDialogArea(parent);
* //add controls to composite as necessary
* return composite;
*
*
* @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
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 composite = WidgetFactory.composite(SWT.NONE).layout(layout)
.layoutData(new GridData(GridData.FILL_BOTH)).create(parent);
applyDialogFont(composite);
return composite;
}
/**
* Returns the button created by the method createButton
for
* the specified ID as defined on IDialogConstants
. If
* createButton
was never called with this ID, or if
* createButton
is overridden, this method will return
* null
.
*
* @param id
* the id of the button to look for
*
* @return the button for the ID or null
*
* @see #createButton(Composite, int, String, boolean)
* @since 2.0
*/
protected Button getButton(int id) {
return buttons.get(Integer.valueOf(id));
}
/**
* Returns the button bar control.
*
* Clients may call this framework method, but should not override it.
*
*
* @return the button bar, or null
if the button bar has not
* been created yet
*/
protected Control getButtonBar() {
return buttonBar;
}
/**
* Returns the button created when createButton
is called
* with an ID of IDialogConstants.CANCEL_ID
. If
* createButton
was never called with this parameter, or if
* createButton
is overridden, getCancelButton
* will return null
.
*
* @return the cancel button or null
*
* @see #createButton(Composite, int, String, boolean)
* @since 2.0
* @deprecated Use getButton(IDialogConstants.CANCEL_ID)
* instead. This method will be removed soon.
*/
@Deprecated
protected Button getCancelButton() {
return getButton(IDialogConstants.CANCEL_ID);
}
/**
* Returns the dialog area control.
*
* Clients may call this framework method, but should not override it.
*
*
* @return the dialog area, or null
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 Dialog.DLG_IMG_*
constants
* @return the standard dialog image
*
* NOTE: Dialog does not use 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#getSystemImage(int)
*/
public static Image getImage(String key) {
return JFaceResources.getImageRegistry().get(key);
}
/**
* Returns the button created when createButton
is called
* with an ID of IDialogConstants.OK_ID
. If
* createButton
was never called with this parameter, or if
* createButton
is overridden, getOKButton
* will return null
.
*
* @return the OK button or null
*
* @see #createButton(Composite, int, String, boolean)
* @since 2.0
* @deprecated Use getButton(IDialogConstants.OK_ID)
instead.
* This method will be removed soon.
*/
@Deprecated
protected Button getOKButton() {
return getButton(IDialogConstants.OK_ID);
}
/**
* Initializes the computation of horizontal and vertical dialog units based
* on the size of current font.
*
* This method must be called before any of the dialog unit based conversion
* methods are called.
*
*
* @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.
*
* The Dialog
implementation of this framework method sets
* this dialog's return code to Window.OK
and closes the
* dialog. Subclasses may override.
*
*/
protected void okPressed() {
setReturnCode(OK);
close();
}
/**
* Set the layout data of the button to a GridData with appropriate heights and
* widths.
*
* @param button The button which layout data is to be set.
*/
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 The button which layout data is to be set.
*/
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()
*/
@Override
public boolean close() {
if (getShell() != null && !getShell().isDisposed()) {
saveDialogBounds(getShell());
}
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 null
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 their 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 (Control element : children) {
applyDialogFont(element, 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.
*
* @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);
}
@Override
public void create() {
super.create();
applyDialogFont(buttonBar);
}
/**
* 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 null
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);
FontData [] fontDatas = JFaceResources.getDialogFont().getFontData();
if (fontDatas.length > 0) {
settings.put(DIALOG_FONT_DATA, fontDatas[0].toString());
}
}
}
}
/**
* Returns the initial size to use for the shell. Overridden
* to check whether a size has been stored in dialog settings.
* If a size has been stored, it is returned.
*
* @return the initial size of the shell
*
* @since 3.2
* @see #getDialogBoundsSettings()
* @see #getDialogBoundsStrategy()
*/
@Override
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) {
// Check that the dialog font matches the font used
// when the bounds was stored. If the font has changed,
// we do not honor the stored settings.
// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=132821
boolean useStoredBounds = true;
String previousDialogFontData = settings.get(DIALOG_FONT_DATA);
// There is a previously stored font, so we will check it.
// Note that if we haven't stored the font before, then we will
// use the stored bounds. This allows restoring of dialog bounds
// that were stored before we started storing the fontdata.
if (previousDialogFontData != null && previousDialogFontData.length() > 0) {
FontData [] fontDatas = JFaceResources.getDialogFont().getFontData();
if (fontDatas.length > 0) {
String currentDialogFontData = fontDatas[0].toString();
useStoredBounds = currentDialogFontData.equalsIgnoreCase(previousDialogFontData);
}
}
if (useStoredBounds) {
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;
}
/**
* Returns the initial location to use for the shell. Overridden
* to check whether the bounds of the dialog have been stored in
* dialog settings. If a location has been stored, it is returned.
*
* @param initialSize
* the initial size of the shell, as returned by
* getInitialSize
.
* @return the initial location of the shell
*
* @since 3.2
* @see #getDialogBoundsSettings()
* @see #getDialogBoundsStrategy()
*/
@Override
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;
}
/**
* Returns a boolean indicating whether the dialog should be considered
* resizable when the shell style is initially set.
*
* This method is used to ensure that all style bits appropriate for resizable
* dialogs are added to the shell style. Individual dialogs may always set the
* shell style to ensure that a dialog is resizable, but using this method
* ensures that resizable dialogs will be created with the same set of style
* bits.
*
*
* Style bits will never be removed based on the return value of this method.
* For example, if a dialog returns false
, but also sets a style
* bit for a SWT.RESIZE border, the style bit will be honored.
*
*
* @return a boolean indicating whether the dialog is resizable and should have
* the default style bits for resizable dialogs
*
* @since 3.4
*/
protected boolean isResizable() {
return false;
}
}