Mercurial > projects > dwt2
diff org.eclipse.jface/src/org/eclipse/jface/dialogs/Dialog.d @ 12:bc29606a740c
Added dwt-addons in original directory structure of eclipse.org
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sat, 14 Mar 2009 18:23:29 +0100 |
parents | |
children | 12b890a6392a |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/org.eclipse.jface/src/org/eclipse/jface/dialogs/Dialog.d Sat Mar 14 18:23:29 2009 +0100 @@ -0,0 +1,1340 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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 + * Remy Chi Jian Suen <remy.suen@gmail.com> - Bug 218553 [JFace] mis-spelling of their in applyDialogFont(...) + * Port to the D programming language: + * Frank Benoit <benoit@tionex.de> + *******************************************************************************/ +module org.eclipse.jface.dialogs.Dialog; + +import org.eclipse.jface.dialogs.IDialogBlockedHandler; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.dialogs.IDialogConstants; +// import tango.util.Arrays; + +import org.eclipse.swt.SWT; +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.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; +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.window.IShellProvider; +import org.eclipse.jface.window.SameShellProvider; +import org.eclipse.jface.window.Window; + +import java.lang.all; +import java.util.Arrays; +import java.util.Collection; +import java.util.Set; + +/** + * 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 : 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 const 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 const 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 const 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 const 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 const 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 const 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 const String DLG_IMG_MESSAGE_ERROR = "dialog_message_error_image"; //$NON-NLS-1$ + + /** + * Image registry key for help image (value + * <code>"dialog_help_image"</code>). + * + * @since 3.2 + */ + public static const 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 const String ELLIPSIS = "..."; //$NON-NLS-1$ + + /** + * The dialog settings key name for stored dialog x location. + * + * @since 3.2 + */ + private static const 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 const String DIALOG_ORIGIN_Y = "DIALOG_Y_ORIGIN"; //$NON-NLS-1$ + + /** + * The dialog settings key name for stored dialog width. + * + * @since 3.2 + */ + private static const String DIALOG_WIDTH = "DIALOG_WIDTH"; //$NON-NLS-1$ + + /** + * The dialog settings key name for stored dialog height. + * + * @since 3.2 + */ + private static const 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 const 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 const 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 const int DIALOG_PERSISTLOCATION = 0x0001; + /** + * Persist the last known size of the dialog. + * @since 3.2 + */ + public static const int DIALOG_PERSISTSIZE = 0x0002; + + /** + * 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; + + /** + * Collection of buttons created by the <code>createButton</code> method. + */ + private Button[int] buttons; + + /** + * Font metrics to use for determining pixel sizes. + */ + private FontMetrics fontMetrics; + + /** + * Number of horizontal dialog units per character, value <code>4</code>. + */ + private static const int HORIZONTAL_DIALOG_UNIT_PER_CHAR = 4; + + /** + * Number of vertical dialog units per character, value <code>8</code>. + */ + private static const 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 is 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 = cast(int) Math.round(0.95f*length * (1 - (cast(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. + */ + private static IDialogBlockedHandler blockedHandler_; + public static IDialogBlockedHandler blockedHandler(){ + static_this_blockedhandler(); + return blockedHandler_; + } + public static IDialogBlockedHandler blockedHandler( IDialogBlockedHandler b ){ + static_this_blockedhandler(); + return ( blockedHandler_ = b ); + } + private static bool static_this_blockedhandler_completed = false; + private static void static_this_blockedhandler(){ + if( static_this_blockedhandler_completed ){ + return; + } + synchronized{ + if( static_this_blockedhandler_completed ){ + return; + } + blockedHandler_ = new class 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 + } + }; + static_this_blockedhandler_completed = true; + } + } + + /** + * 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 this(Shell parentShell) { + this(new SameShellProvider(parentShell)); + if (parentShell is null && Policy.DEBUG_DIALOG_NO_PARENT) { + Policy.getLog().log( + new Status(IStatus.INFO, Policy.JFACE, IStatus.INFO, this + .classinfo.name + ~ " created with no shell",//$NON-NLS-1$ + new Exception( null, null ))); + } + } + + /** + * Creates a dialog with the given parent. + * + * @param parentShell + * object that returns the current parent shell + * + * @since 3.1 + */ + protected this(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. + * <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 is buttonId) { + okPressed(); + } else if (IDialogConstants.CANCEL_ID is 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 is 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 is 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 is 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 is 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, + bool defaultButton) { + // increment the number of columns in the button bar + (cast(GridLayout) parent.getLayout()).numColumns++; + Button button = new Button(parent, SWT.PUSH); + button.setText(label); + button.setFont(JFaceResources.getDialogFont()); + button.setData(new ValueWrapperInt(id)); + button.addSelectionListener(new class SelectionAdapter { + public void widgetSelected(SelectionEvent event) { + buttonPressed((cast(ValueWrapperInt) event.widget.getData()).value); + } + }); + if (defaultButton) { + Shell shell = parent.getShell(); + if (shell !is null) { + shell.setDefaultButton(button); + } + } + buttons[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 override 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 !is null) { + Button defaultButton = shell.getDefaultButton(); + if (defaultButton !is null + && isContained(buttonBar, defaultButton)) { + defaultButton.moveBelow(null); + } + } + } + + super.initializeBounds(); + } + + /** + * Returns true if the given Control is a direct or indirect child of + * container. + * + * @param container + * the potential parent + * @param control + * @return bool <code>true</code> if control is a child of container + */ + private bool isContained(Control container, Control control) { + Composite parent; + while ((parent = control.getParent()) !is null) { + if (parent is 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 override 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, bool) + * @since 2.0 + */ + protected Button getButton(int id) { + if( auto btn = id in buttons ){ + return *btn; + } + return null; + } + + /** + * 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, bool) + * @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 + * + * 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 <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, bool) + * @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 override bool close() { + if (getShell() !is null && !getShell().isDisposed()) { + saveDialogBounds(getShell()); + } + + bool returnValue = super.close(); + if (returnValue) { + buttons = null; + 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 is 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 ( auto comp = cast(Composite)control ) { + Control[] children = comp.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 bool + */ + private static bool hasDefaultFont(Control control) { + FontData[] controlFontData = control.getFont().getFontData(); + FontData[] defaultFontData = getDefaultFont(control).getFontData(); + if (controlFontData.length is defaultFontData.length) { + for (int i = 0; i < controlFontData.length; i++) { + if (controlFontData[i].opEquals(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.classinfo.name; //$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 bool if the two are the same + */ + protected static bool dialogFontIsDefault() { + FontData[] dialogFontData = JFaceResources.getFontRegistry() + .getFontData(JFaceResources.DIALOG_FONT); + FontData[] defaultFontData = JFaceResources.getFontRegistry() + .getFontData(JFaceResources.DEFAULT_FONT); + return ArrayEquals(dialogFontData, defaultFontData); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.window.Window#create() + */ + public override 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 <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 !is null) { + Point shellLocation = shell.getLocation(); + Point shellSize = shell.getSize(); + Shell parent = getParentShell(); + if (parent !is null) { + Point parentLocation = parent.getLocation(); + shellLocation.x -= parentLocation.x; + shellLocation.y -= parentLocation.y; + } + int strategy = getDialogBoundsStrategy(); + if ((strategy & DIALOG_PERSISTLOCATION) !is 0) { + settings.put(DIALOG_ORIGIN_X, shellLocation.x); + settings.put(DIALOG_ORIGIN_Y, shellLocation.y); + } + if ((strategy & DIALOG_PERSISTSIZE) !is 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() + */ + protected override Point getInitialSize() { + Point result = super.getInitialSize(); + + // Check the dialog settings for a stored size. + if ((getDialogBoundsStrategy() & DIALOG_PERSISTSIZE)!is 0) { + IDialogSettings settings = getDialogBoundsSettings(); + if (settings !is 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 + bool 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 !is 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 !is DIALOG_DEFAULT_BOUNDS) { + result.x = width; + } + int height = settings.getInt(DIALOG_HEIGHT); + if (height !is 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 + * <code>getInitialSize</code>. + * @return the initial location of the shell + * + * @since 3.2 + * @see #getDialogBoundsSettings() + * @see #getDialogBoundsStrategy() + */ + protected override Point getInitialLocation(Point initialSize) { + Point result = super.getInitialLocation(initialSize); + if ((getDialogBoundsStrategy() & DIALOG_PERSISTLOCATION)!is 0) { + IDialogSettings settings = getDialogBoundsSettings(); + if (settings !is 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 !is 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 bool 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 + * <code>false</code>, but also sets a style bit for a + * SWT.RESIZE border, the style bit will be honored. + * + * @return a bool indicating whether the dialog is + * resizable and should have the default style bits for + * resizable dialogs + * + * @since 3.4 + */ + protected bool isResizable() { + return false; + } +}