changeset 8:a3ff22a98bef

Dialog
author Frank Benoit <benoit@tionex.de>
date Sat, 29 Mar 2008 01:25:27 +0100
parents 8a302fdb4140
children 6c14e54dfc11
files dwtx/jface/dialogs/Dialog.d dwtx/jface/dialogs/IDialogBlockedHandler.d dwtx/jface/dialogs/IDialogConstants.d dwtx/jface/dialogs/IDialogSettings.d dwtx/jface/resource/ColorDescriptor.d dwtx/jface/resource/ImageRegistry.d dwtx/jface/resource/JFaceResources.d dwtx/jface/resource/RGBColorDescriptor.d dwtx/jface/resource/ResourceManager.d dwtx/jface/wizard/WizardDialog.d
diffstat 10 files changed, 4510 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/dialogs/Dialog.d	Sat Mar 29 01:25:27 2008 +0100
@@ -0,0 +1,1284 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 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
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.dialogs.Dialog;
+
+import dwtx.jface.dialogs.IDialogBlockedHandler;
+import dwtx.jface.dialogs.IDialogSettings;
+import dwtx.jface.dialogs.IDialogConstants;
+// import tango.util.Arrays;
+
+import dwt.DWT;
+import dwt.events.SelectionAdapter;
+import dwt.events.SelectionEvent;
+import dwt.graphics.Font;
+import dwt.graphics.FontData;
+import dwt.graphics.FontMetrics;
+import dwt.graphics.GC;
+import dwt.graphics.Image;
+import dwt.graphics.Point;
+import dwt.layout.FormData;
+import dwt.layout.GridData;
+import dwt.layout.GridLayout;
+import dwt.widgets.Button;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Display;
+import dwt.widgets.Shell;
+import dwtx.core.runtime.IProgressMonitor;
+import dwtx.core.runtime.IStatus;
+import dwtx.core.runtime.Status;
+import dwtx.jface.resource.JFaceResources;
+import dwtx.jface.util.Policy;
+import dwtx.jface.window.IShellProvider;
+import dwtx.jface.window.SameShellProvider;
+import dwtx.jface.window.Window;
+
+import dwt.dwthelper.utils;
+
+/**
+ * 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
+     *             dwt.widgets.Display.getSystemImage(DWT.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
+     *             dwt.widgets.Display.getSystemImage(DWT.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 dwt.widgets.Display.getSystemImage(DWT.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
+     *             dwt.widgets.Display.getSystemImage(DWT.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.
+     */
+    public static IDialogBlockedHandler blockedHandler;
+    static this(){
+        blockedHandler = new class IDialogBlockedHandler {
+            /*
+            * (non-Javadoc)
+            *
+            * @see dwtx.jface.dialogs.IDialogBlockedHandler#clearBlocked()
+            */
+            public void clearBlocked() {
+                // No default behaviour
+            }
+
+            /*
+            * (non-Javadoc)
+            *
+            * @see dwtx.jface.dialogs.IDialogBlockedHandler#showBlocked(dwtx.core.runtime.IProgressMonitor,
+            *      dwtx.core.runtime.IStatus, java.lang.String)
+            */
+            public void showBlocked(IProgressMonitor blocking,
+                    IStatus blockingStatus, String blockedName) {
+                // No default behaviour
+            }
+
+            /*
+            * (non-Javadoc)
+            *
+            * @see dwtx.jface.dialogs.IDialogBlockedHandler#showBlocked(dwt.widgets.Shell,
+            *      dwtx.core.runtime.IProgressMonitor,
+            *      dwtx.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 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);
+        setShellStyle(DWT.DIALOG_TRIM | DWT.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, DWT.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, DWT.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 = DWT.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 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, DWT.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) {
+        return buttons[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, 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 DWT, see ImageRegistry. For backwards
+     * compatibility they are still supported, however new code should use DWT
+     * 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(DWT.DEFAULT, DWT.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(DWT.DEFAULT, DWT.DEFAULT, true);
+        data.width = Math.max(widthHint, minSize.x);
+        button.setLayoutData(data);
+    }
+
+    /**
+     * @see dwtx.jface.window.Window#close()
+     */
+    public 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 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 ( 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 dwtx.jface.window.Window#create()
+     */
+    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 <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 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 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;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/dialogs/IDialogBlockedHandler.d	Sat Mar 29 01:25:27 2008 +0100
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.dialogs.IDialogBlockedHandler;
+
+
+import dwt.widgets.Shell;
+import dwtx.core.runtime.IProgressMonitor;
+import dwtx.core.runtime.IStatus;
+import dwtx.jface.wizard.WizardDialog;
+
+import dwt.dwthelper.utils;
+
+/**
+ * The IDialogBlockedHandler is the handler used by
+ * JFace to provide extra information when a
+ * blocking has occured. There is one static instance
+ * of this class used by WizardDialog and ModalContext.
+ * @see dwtx.core.runtime.IProgressMonitorWithBlocking#clearBlocked()
+ * @see  dwtx.core.runtime.IProgressMonitorWithBlocking#setBlocked(IStatus)
+ * @see WizardDialog
+ * @since 3.0
+ */
+public interface IDialogBlockedHandler {
+    /**
+     * The blockage has been cleared. Clear the
+     * extra information and resume.
+     */
+    public void clearBlocked();
+
+    /**
+     * A blockage has occured. Show the blockage and
+     * forward any actions to blockingMonitor.
+     * <b>NOTE:</b> This will open any blocked notification immediately
+     * even if there is a modal shell open.
+     *
+     * @param parentShell The shell this is being sent from. If the parent
+     * shell is <code>null</code> the behavior will be the same as
+     * IDialogBlockedHandler#showBlocked(IProgressMonitor, IStatus, String)
+     *
+     * @param blocking The monitor to forward to. This is most
+     * important for calls to <code>cancel()</code>.
+     * @param blockingStatus The status that describes the blockage
+     * @param blockedName The name of the locked operation.
+     * @see IDialogBlockedHandler#showBlocked(IProgressMonitor, IStatus, String)
+     */
+    public void showBlocked(Shell parentShell, IProgressMonitor blocking,
+            IStatus blockingStatus, String blockedName);
+
+    /**
+     * A blockage has occured. Show the blockage when there is
+     * no longer any modal shells in the UI and forward any actions
+     * to blockingMonitor.
+     *
+     * <b>NOTE:</b> As no shell has been specified this method will
+     * not open any blocked notification until all other modal shells
+     * have been closed.
+     *
+     * @param blocking The monitor to forward to. This is most
+     * important for calls to <code>cancel()</code>.
+     * @param blockingStatus The status that describes the blockage
+     * @param blockedName The name of the locked operation.
+     */
+    public void showBlocked(IProgressMonitor blocking, IStatus blockingStatus,
+            String blockedName);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/dialogs/IDialogConstants.d	Sat Mar 29 01:25:27 2008 +0100
@@ -0,0 +1,371 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.dialogs.IDialogConstants;
+
+/**
+ * Various dialog-related constants.
+ * <p>
+ * Within the dialog framework, all buttons are referred to by a button id.
+ * Various common buttons, like "OK", "Cancel", and "Finish", have pre-assigned
+ * button ids for convenience. If an application requires other dialog buttons,
+ * they should be assigned application-specific button ids counting up from
+ * <code>CLIENT_ID</code>.
+ * </p>
+ * <p>
+ * Button label constants are also provided for the common buttons. JFace
+ * automatically localizes these strings to the current locale; that is,
+ * <code>YES_LABEL</code> would be bound to the string <code>"Si"</code> in
+ * a Spanish locale, but to <code>"Oui"</code> in a French one.
+ * </p>
+ * <p>
+ * All margins, spacings, and sizes are given in "dialog units" (DLUs), where
+ * <ul>
+ * <li>1 horizontal DLU = 1/4 average character width</li>
+ * <li>1 vertical DLU = 1/8 average character height</li>
+ * </ul>
+ * </p>
+ */
+import dwtx.jface.resource.JFaceResources;
+
+import dwt.dwthelper.utils;
+
+/**
+ * IDialogConstants is the interface for common dialog strings and ids
+ * used throughout JFace.
+ * It is recommended that you use these labels and ids whereever
+ * for consistency with the JFace dialogs.
+ */
+public abstract class IDialogConstants {
+    static{
+    const{
+    // button ids
+
+    // Note:  if new button ids are added, see
+    // MessageDialogWithToggle.mapButtonLabelToButtonID(String, int)
+    /**
+     * Button id for an "Ok" button (value 0).
+     */
+    public int OK_ID = 0;
+
+    /**
+     * Button id for a "Cancel" button (value 1).
+     */
+    public int CANCEL_ID = 1;
+
+    /**
+     * Button id for a "Yes" button (value 2).
+     */
+    public int YES_ID = 2;
+
+    /**
+     * Button id for a "No" button (value 3).
+     */
+    public int NO_ID = 3;
+
+    /**
+     * Button id for a "Yes to All" button (value 4).
+     */
+    public int YES_TO_ALL_ID = 4;
+
+    /**
+     * Button id for a "Skip" button (value 5).
+     */
+    public int SKIP_ID = 5;
+
+    /**
+     * Button id for a "Stop" button (value 6).
+     */
+    public int STOP_ID = 6;
+
+    /**
+     * Button id for an "Abort" button (value 7).
+     */
+    public int ABORT_ID = 7;
+
+    /**
+     * Button id for a "Retry" button (value 8).
+     */
+    public int RETRY_ID = 8;
+
+    /**
+     * Button id for an "Ignore" button (value 9).
+     */
+    public int IGNORE_ID = 9;
+
+    /**
+     * Button id for a "Proceed" button (value 10).
+     */
+    public int PROCEED_ID = 10;
+
+    /**
+     * Button id for an "Open" button (value 11).
+     */
+    public int OPEN_ID = 11;
+
+    /**
+     * Button id for a "Close" button (value 12).
+     */
+    public int CLOSE_ID = 12;
+
+    /**
+     * Button id for a "Details" button (value 13).
+     */
+    public int DETAILS_ID = 13;
+
+    /**
+     * Button id for a "Back" button (value 14).
+     */
+    public int BACK_ID = 14;
+
+    /**
+     * Button id for a "Next" button (value 15).
+     */
+    public int NEXT_ID = 15;
+
+    /**
+     * Button id for a "Finish" button (value 16).
+     */
+    public int FINISH_ID = 16;
+
+    /**
+     * Button id for a "Help" button (value 17).
+     */
+    public int HELP_ID = 17;
+
+    /**
+     * Button id for a "Select All" button (value 18).
+     */
+    public int SELECT_ALL_ID = 18;
+
+    /**
+     * Button id for a "Deselect All" button (value 19).
+     */
+    public int DESELECT_ALL_ID = 19;
+
+    /**
+     * Button id for a "Select types" button (value 20).
+     */
+    public int SELECT_TYPES_ID = 20;
+
+    /**
+     * Button id for a "No to All" button (value 21).
+     */
+    public int NO_TO_ALL_ID = 21;
+
+    /**
+     * Starting button id reserved for internal use by JFace (value 256). JFace
+     * classes make ids by adding to this number.
+     */
+    public int INTERNAL_ID = 256;
+
+    /**
+     * Starting button id reserved for use by clients of JFace (value 1024).
+     * Clients of JFace should make ids by adding to this number.
+     */
+    public int CLIENT_ID = 1024;
+    } // const
+    // button labels
+    /**
+     * The label for OK buttons.
+     */
+    public String OK_LABEL;
+
+    /**
+     * The label for cancel buttons.
+     */
+    public String CANCEL_LABEL;
+
+    /**
+     * The label for yes buttons.
+     */
+    public String YES_LABEL;
+
+    /**
+     * The label for no buttons.
+     */
+    public String NO_LABEL;
+
+    /**
+     * The label for not to all buttons.
+     */
+    public String NO_TO_ALL_LABEL;
+
+    /**
+     * The label for yes to all buttons.
+     */
+    public String YES_TO_ALL_LABEL;
+
+    /**
+     * The label for skip buttons.
+     */
+    public String SKIP_LABEL;
+
+    /**
+     * The label for stop buttons.
+     */
+    public String STOP_LABEL;
+
+    /**
+     * The label for abort buttons.
+     */
+    public String ABORT_LABEL;
+
+    /**
+     * The label for retry buttons.
+     */
+    public String RETRY_LABEL;
+
+    /**
+     * The label for ignore buttons.
+     */
+    public String IGNORE_LABEL;
+
+    /**
+     * The label for proceed buttons.
+     */
+    public String PROCEED_LABEL;
+
+    /**
+     * The label for open buttons.
+     */
+    public String OPEN_LABEL;
+
+    /**
+     * The label for close buttons.
+     */
+    public String CLOSE_LABEL;
+
+    /**
+     * The label for show details buttons.
+     */
+    public String SHOW_DETAILS_LABEL;
+
+    /**
+     * The label for hide details buttons.
+     */
+    public String HIDE_DETAILS_LABEL;
+
+    /**
+     * The label for back buttons.
+     */
+    public String BACK_LABEL;
+
+    /**
+     * The label for next buttons.
+     */
+    public String NEXT_LABEL;
+
+    /**
+     * The label for finish buttons.
+     */
+    public String FINISH_LABEL;
+
+    /**
+     * The label for help buttons.
+     */
+    public String HELP_LABEL;
+
+    const{
+    // Margins, spacings, and sizes
+    /**
+     * Vertical margin in dialog units (value 7).
+     */
+    public int VERTICAL_MARGIN = 7;
+
+    /**
+     * Vertical spacing in dialog units (value 4).
+     */
+    public int VERTICAL_SPACING = 4;
+
+    /**
+     * Horizontal margin in dialog units (value 7).
+     */
+    public int HORIZONTAL_MARGIN = 7;
+
+    /**
+     * Horizontal spacing in dialog units (value 4).
+     */
+    public int HORIZONTAL_SPACING = 4;
+
+    /**
+     * Height of button bar in dialog units (value 25).
+     */
+    public int BUTTON_BAR_HEIGHT = 25;
+
+    /**
+     * Left margin in dialog units (value 20).
+     */
+    public int LEFT_MARGIN = 20;
+
+    /**
+     * Button margin in dialog units (value 4).
+     */
+    public int BUTTON_MARGIN = 4;
+
+    /**
+     * Button height in dialog units (value 14).
+     *
+     * @deprecated This constant is no longer in use.
+     * The button heights are now determined by the layout.
+     */
+    public int BUTTON_HEIGHT = 14;
+
+    /**
+     * Button width in dialog units (value 61).
+     */
+    public int BUTTON_WIDTH = 61;
+
+    /**
+     * Indent in dialog units (value 21).
+     */
+    public int INDENT = 21;
+
+    /**
+     * Small indent in dialog units (value 7).
+     */
+    public int SMALL_INDENT = 7;
+
+    /**
+     * Entry field width in dialog units (value 200).
+     */
+    public int ENTRY_FIELD_WIDTH = 200;
+
+    /**
+     * Minimum width of message area in dialog units (value 300).
+     */
+    public int MINIMUM_MESSAGE_AREA_WIDTH = 300;
+    }// const
+    }// static
+}
+static this(){
+    IDialogConstants.OK_LABEL = JFaceResources.getString("ok"); //$NON-NLS-1$
+    IDialogConstants.CANCEL_LABEL = JFaceResources.getString("cancel"); //$NON-NLS-1$
+    IDialogConstants.YES_LABEL = JFaceResources.getString("yes"); //$NON-NLS-1$
+    IDialogConstants.NO_LABEL = JFaceResources.getString("no"); //$NON-NLS-1$
+    IDialogConstants.NO_TO_ALL_LABEL = JFaceResources.getString("notoall"); //$NON-NLS-1$
+    IDialogConstants.YES_TO_ALL_LABEL = JFaceResources.getString("yestoall"); //$NON-NLS-1$
+    IDialogConstants.SKIP_LABEL = JFaceResources.getString("skip"); //$NON-NLS-1$
+    IDialogConstants.STOP_LABEL = JFaceResources.getString("stop"); //$NON-NLS-1$
+    IDialogConstants.ABORT_LABEL = JFaceResources.getString("abort"); //$NON-NLS-1$
+    IDialogConstants.RETRY_LABEL = JFaceResources.getString("retry"); //$NON-NLS-1$
+    IDialogConstants.IGNORE_LABEL = JFaceResources.getString("ignore"); //$NON-NLS-1$
+    IDialogConstants.PROCEED_LABEL = JFaceResources.getString("proceed"); //$NON-NLS-1$
+    IDialogConstants.OPEN_LABEL = JFaceResources.getString("open"); //$NON-NLS-1$
+    IDialogConstants.CLOSE_LABEL = JFaceResources.getString("close"); //$NON-NLS-1$
+    IDialogConstants.SHOW_DETAILS_LABEL = JFaceResources.getString("showDetails"); //$NON-NLS-1$
+    IDialogConstants.HIDE_DETAILS_LABEL = JFaceResources.getString("hideDetails"); //$NON-NLS-1$
+    IDialogConstants.BACK_LABEL = JFaceResources.getString("backButton"); //$NON-NLS-1$
+    IDialogConstants.NEXT_LABEL = JFaceResources.getString("nextButton"); //$NON-NLS-1$
+    IDialogConstants.FINISH_LABEL = JFaceResources.getString("finish"); //$NON-NLS-1$
+    IDialogConstants.HELP_LABEL = JFaceResources.getString("help"); //$NON-NLS-1$
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/dialogs/IDialogSettings.d	Sat Mar 29 01:25:27 2008 +0100
@@ -0,0 +1,270 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.dialogs.IDialogSettings;
+
+// import java.io.IOException;
+// import java.io.Reader;
+// import java.io.Writer;
+
+import dwt.dwthelper.utils;
+
+/**
+ * An interface to a storage mechanism for making dialog settings persistent.
+ * The store manages a collection of key/value pairs. The keys must be strings
+ * and the values can be either, strings or array of strings. Convenience API to
+ * convert primitive types to strings is provided.
+ */
+public interface IDialogSettings {
+    /**
+     * Create a new section in the receiver and return it.
+     *
+     * @param name
+     *            the name of the new section
+     * @return the new section
+     */
+    public IDialogSettings addNewSection(String name);
+
+    /**
+     * Add a section in the receiver.
+     *
+     * @param section
+     *            the section to be added
+     */
+    public void addSection(IDialogSettings section);
+
+    /**
+     * Returns the value of the given key in this dialog settings.
+     *
+     * @param key
+     *            the key
+     * @return the value, or <code>null</code> if none
+     */
+    public String get(String key);
+
+    /**
+     * Returns the value, an array of strings, of the given key in this dialog
+     * settings.
+     *
+     * @param key
+     *            the key
+     * @return the array of string, or <code>null</code> if none
+     */
+    public String[] getArray(String key);
+
+    /**
+     * Convenience API. Convert the value of the given key in this dialog
+     * settings to a bool and return it.
+     *
+     * @param key
+     *            the key
+     * @return the bool value, or <code>false</code> if none
+     */
+    public bool getBoolean(String key);
+
+    /**
+     * Convenience API. Convert the value of the given key in this dialog
+     * settings to a double and return it.
+     *
+     * @param key
+     *            the key
+     * @return the value coverted to double, or throws
+     *         <code>NumberFormatException</code> if none
+     *
+     * @exception NumberFormatException
+     *                if the string value does not contain a parsable number.
+     * @see java.lang.Double#valueOf(java.lang.String)
+     */
+    public double getDouble(String key);
+
+    /**
+     * Convenience API. Convert the value of the given key in this dialog
+     * settings to a float and return it.
+     *
+     * @param key
+     *            the key
+     * @return the value coverted to float, or throws
+     *         <code>NumberFormatException</code> if none
+     *
+     * @exception NumberFormatException
+     *                if the string value does not contain a parsable number.
+     * @see java.lang.Float#valueOf(java.lang.String)
+     */
+    public float getFloat(String key);
+
+    /**
+     * Convenience API. Convert the value of the given key in this dialog
+     * settings to a int and return it.
+     *
+     * @param key
+     *            the key
+     * @return the value coverted to int, or throws
+     *         <code>NumberFormatException</code> if none
+     *
+     * @exception NumberFormatException
+     *                if the string value does not contain a parsable number.
+     * @see java.lang.Integer#valueOf(java.lang.String)
+     */
+    public int getInt(String key);
+
+    /**
+     * Convenience API. Convert the value of the given key in this dialog
+     * settings to a long and return it.
+     *
+     * @param key
+     *            the key
+     * @return the value coverted to long, or throws
+     *         <code>NumberFormatException</code> if none
+     *
+     * @exception NumberFormatException
+     *                if the string value does not contain a parsable number.
+     * @see java.lang.Long#valueOf(java.lang.String)
+     */
+    public long getLong(String key);
+
+    /**
+     * Returns the IDialogSettings name.
+     *
+     * @return the name
+     */
+    public String getName();
+
+    /**
+     * Returns the section with the given name in this dialog settings.
+     *
+     * @param sectionName
+     *            the key
+     * @return IDialogSettings (the section), or <code>null</code> if none
+     */
+    public IDialogSettings getSection(String sectionName);
+
+    /**
+     * Returns all the sections in this dialog settings.
+     *
+     * @return the section, or <code>null</code> if none
+     */
+    public IDialogSettings[] getSections();
+
+    /**
+     * Load a dialog settings from a stream and fill the receiver with its
+     * content.
+     *
+     * @param reader
+     *            a Reader specifying the stream where the settings are read
+     *            from.
+     * @throws IOException
+     */
+    public void load(Reader reader);
+
+    /**
+     * Load a dialog settings from a file and fill the receiver with its
+     * content.
+     *
+     * @param fileName
+     *            the name of the file the settings are read from.
+     * @throws IOException
+     */
+    public void load(String fileName);
+
+    /**
+     * Adds the pair <code>key/value</code> to this dialog settings.
+     *
+     * @param key
+     *            the key.
+     * @param value
+     *            the value to be associated with the <code>key</code>
+     */
+    public void put(String key, String[] value);
+
+    /**
+     * Convenience API. Converts the double <code>value</code> to a string and
+     * adds the pair <code>key/value</code> to this dialog settings.
+     *
+     * @param key
+     *            the key.
+     * @param value
+     *            the value to be associated with the <code>key</code>
+     */
+    public void put(String key, double value);
+
+    /**
+     * Convenience API. Converts the float <code>value</code> to a string and
+     * adds the pair <code>key/value</code> to this dialog settings.
+     *
+     * @param key
+     *            the key.
+     * @param value
+     *            the value to be associated with the <code>key</code>
+     */
+    public void put(String key, float value);
+
+    /**
+     * Convenience API. Converts the int <code>value</code> to a string and
+     * adds the pair <code>key/value</code> to this dialog settings.
+     *
+     * @param key
+     *            the key.
+     * @param value
+     *            the value to be associated with the <code>key</code>
+     */
+    public void put(String key, int value);
+
+    /**
+     * Convenience API. Converts the long <code>value</code> to a string and
+     * adds the pair <code>key/value</code> to this dialog settings.
+     *
+     * @param key
+     *            the key.
+     * @param value
+     *            the value to be associated with the <code>key</code>
+     */
+    public void put(String key, long value);
+
+    /**
+     * Adds the pair <code>key/value</code> to this dialog settings.
+     *
+     * @param key
+     *            the key.
+     * @param value
+     *            the value to be associated with the <code>key</code>
+     */
+    public void put(String key, String value);
+
+    /**
+     * Convenience API. Converts the bool <code>value</code> to a string
+     * and adds the pair <code>key/value</code> to this dialog settings.
+     *
+     * @param key
+     *            the key.
+     * @param value
+     *            the value to be associated with the <code>key</code>
+     */
+    public void put(String key, bool value);
+
+    /**
+     * Save a dialog settings to a stream
+     *
+     * @param writer
+     *            a Writer specifying the stream the settings are written in.
+     * @throws IOException
+     */
+    public void save(Writer writer);
+
+    /**
+     * Save a dialog settings to a file.
+     *
+     * @param fileName
+     *            the name of the file the settings are written in.
+     * @throws IOException
+     */
+    public void save(String fileName);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/resource/ColorDescriptor.d	Sat Mar 29 01:25:27 2008 +0100
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2006 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
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.resource.ColorDescriptor;
+
+import dwtx.jface.resource.DeviceResourceDescriptor;
+import dwtx.jface.resource.RGBColorDescriptor;
+
+import dwt.graphics.Color;
+import dwt.graphics.Device;
+import dwt.graphics.RGB;
+
+import dwt.dwthelper.utils;
+
+/**
+ * Lightweight descriptor for an DWT color. Each ColorDescriptor will create a particular DWT
+ * Color on demand. This object will be compared so hashCode(...) and equals(...) must
+ * return meaningful values.
+ *
+ * @since 3.1
+ */
+public abstract class ColorDescriptor : DeviceResourceDescriptor {
+
+    /**
+     * Creates a ColorDescriptor from an existing Color, given the Device associated
+     * with the original Color. This is the usual way to convert a Color into
+     * a ColorDescriptor. Note that the returned ColorDescriptor depends on the
+     * original Color, and disposing the Color will invalidate the ColorDescriptor.
+     *
+     * @deprecated use {@link ColorDescriptor#createFrom(Color)}
+     *
+     * @since 3.1
+     *
+     * @param toCreate Color to convert into a ColorDescriptor.
+     * @param originalDevice this must be the same Device that was passed into the
+     * original Color's constructor.
+     * @return a newly created ColorDescriptor that describes the given Color.
+     */
+    public static ColorDescriptor createFrom(Color toCreate, Device originalDevice) {
+        return new RGBColorDescriptor(toCreate);
+    }
+
+    /**
+     * Creates a ColorDescriptor from an existing color.
+     *
+     * The returned ColorDescriptor depends on the original Color. Disposing
+     * the original colour while the color descriptor is still in use may cause
+     * DWT to throw a graphic disposed exception.
+     *
+     * @since 3.1
+     *
+     * @param toCreate Color to generate a ColorDescriptor from
+     * @return a newly created ColorDescriptor
+     */
+    public static ColorDescriptor createFrom(Color toCreate) {
+        return new RGBColorDescriptor(toCreate);
+    }
+
+    /**
+     * Returns a color descriptor for the given RGB values
+     * @since 3.1
+     *
+     * @param toCreate RGB values to create
+     * @return a new ColorDescriptor
+     */
+    public static ColorDescriptor createFrom(RGB toCreate) {
+        return new RGBColorDescriptor(toCreate);
+    }
+
+    /**
+     * Returns the Color described by this descriptor.
+     *
+     * @param device DWT device on which to allocate the Color
+     * @return a newly allocated DWT Color object (never null)
+     * @throws DeviceResourceException if unable to allocate the Color
+     */
+    public abstract Color createColor(Device device);
+
+    /**
+     * Undoes whatever was done by createColor.
+     *
+     * @since 3.1
+     *
+     * @param toDestroy a Color that was previously allocated by an equal ColorDescriptor
+     */
+    public abstract void destroyColor(Color toDestroy);
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resource.DeviceResourceDescriptor#createResource(dwt.graphics.Device)
+     */
+    public final Object createResource(Device device){
+        return createColor(device);
+    }
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resource.DeviceResourceDescriptor#destroyResource(java.lang.Object)
+     */
+    public final void destroyResource(Object previouslyCreatedObject) {
+        destroyColor(cast(Color)previouslyCreatedObject);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/resource/ImageRegistry.d	Sat Mar 29 01:25:27 2008 +0100
@@ -0,0 +1,363 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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
+ *     Steven Ketcham (sketcham@dsicdi.com) - Bug 42451
+ *     [Dialogs] ImageRegistry throws null pointer exception in
+ *     application with multiple Display's
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.resource.ImageRegistry;
+
+import dwtx.jface.resource.ImageDescriptor;
+import dwtx.jface.resource.ResourceManager;
+import dwtx.jface.resource.DeviceResourceException;
+import dwtx.jface.resource.JFaceResources;
+
+import tango.util.collection.HashMap;
+import tango.util.collection.model.Map;
+
+// import java.util.Iterator;
+// import java.util.Map;
+
+import dwt.DWT;
+import dwt.graphics.Device;
+import dwt.graphics.Image;
+import dwt.graphics.ImageData;
+import dwt.widgets.Display;
+import dwtx.core.runtime.Assert;
+import dwtx.jface.dialogs.Dialog;
+
+import dwt.dwthelper.utils;
+import dwt.dwthelper.Runnable;
+
+/**
+ * An image registry maintains a mapping between symbolic image names
+ * and DWT image objects or special image descriptor objects which
+ * defer the creation of DWT image objects until they are needed.
+ * <p>
+ * An image registry owns all of the image objects registered
+ * with it, and automatically disposes of them when the DWT Display
+ * that creates the images is disposed. Because of this, clients do not
+ * need to (indeed, must not attempt to) dispose of these images themselves.
+ * </p>
+ * <p>
+ * Clients may instantiate this class (it was not designed to be subclassed).
+ * </p>
+ * <p>
+ * Unlike the FontRegistry, it is an error to replace images. As a result
+ * there are no events that fire when values are changed in the registry
+ * </p>
+ */
+public class ImageRegistry {
+    /**
+     * display used when getting images
+     */
+    private Display display;
+
+    private ResourceManager manager;
+
+    private Map!(String,Entry) table;
+
+    private Runnable disposeRunnable;
+    private void init_disposeRunnable(){
+        disposeRunnable = new class Runnable {
+            public void run() {
+                dispose();
+            }
+        };
+    }
+
+    /**
+     * Contains the data for an entry in the registry.
+     */
+    private static class Entry {
+        /** the image */
+        protected Image image;
+
+        /** the descriptor */
+        protected ImageDescriptor descriptor;
+    }
+
+    private static class OriginalImageDescriptor : ImageDescriptor {
+        private Image original;
+        private int refCount = 0;
+        private Device originalDisplay;
+
+        /**
+         * @param original the original image
+         * @param originalDisplay the device the image is part of
+         */
+        public this(Image original, Device originalDisplay) {
+            this.original = original;
+            this.originalDisplay = originalDisplay;
+        }
+
+        public Object createResource(Device device) {
+            if (device is originalDisplay) {
+                refCount++;
+                return original;
+            }
+            return super.createResource(device);
+        }
+
+        public void destroyResource(Object toDispose) {
+            if (original is toDispose) {
+                refCount--;
+                if (refCount is 0) {
+                    original.dispose();
+                    original = null;
+                }
+            } else {
+                super.destroyResource(toDispose);
+            }
+        }
+
+        /* (non-Javadoc)
+         * @see dwtx.jface.resource.ImageDescriptor#getImageData()
+         */
+        public ImageData getImageData() {
+            return original.getImageData();
+        }
+    }
+
+    /**
+     * Creates an empty image registry.
+     * <p>
+     * There must be an DWT Display created in the current
+     * thread before calling this method.
+     * </p>
+     */
+    public this() {
+        this(Display.getCurrent());
+    }
+
+    /**
+     * Creates an empty image registry using the given resource manager to allocate images.
+     *
+     * @param manager the resource manager used to allocate images
+     *
+     * @since 3.1
+     */
+    public this(ResourceManager manager) {
+        init_disposeRunnable();
+        Assert.isNotNull(manager);
+        Device dev = manager.getDevice();
+        if ( auto disp = cast(Display)dev ) {
+            this.display = disp;
+        }
+        this.manager = manager;
+        manager.disposeExec(disposeRunnable);
+    }
+
+    /**
+     * Creates an empty image registry.
+     *
+     * @param display this <code>Display</code> must not be
+     *        <code>null</code> and must not be disposed in order
+     *        to use this registry
+     */
+    public this(Display display) {
+        this(JFaceResources.getResources(display));
+    }
+
+    /**
+     * Returns the image associated with the given key in this registry,
+     * or <code>null</code> if none.
+     *
+     * @param key the key
+     * @return the image, or <code>null</code> if none
+     */
+    public Image get(String key) {
+
+        // can be null
+        if (key is null) {
+            return null;
+        }
+
+        if (display !is null) {
+            /**
+             * NOTE, for backwards compatibility the following images are supported
+             * here, they should never be disposed, hence we explicitly return them
+             * rather then registering images that DWT will dispose.
+             *
+             * Applications should go direclty to DWT for these icons.
+             *
+             * @see Display.getSystemIcon(int ID)
+             */
+            int swtKey = -1;
+            if (key.equals(Dialog.DLG_IMG_INFO)) {
+                swtKey = DWT.ICON_INFORMATION;
+            }
+            if (key.equals(Dialog.DLG_IMG_QUESTION)) {
+                swtKey = DWT.ICON_QUESTION;
+            }
+            if (key.equals(Dialog.DLG_IMG_WARNING)) {
+                swtKey = DWT.ICON_WARNING;
+            }
+            if (key.equals(Dialog.DLG_IMG_ERROR)) {
+                swtKey = DWT.ICON_ERROR;
+            }
+            // if we actually just want to return an DWT image do so without
+            // looking in the registry
+            if (swtKey !is -1) {
+                Image[1] image;
+                int id = swtKey;
+                display.syncExec(new class Runnable {
+                    public void run() {
+                        image[0] = display.getSystemImage(id);
+                    }
+                });
+                return image[0];
+            }
+        }
+
+        Entry entry = getEntry(key);
+        if (entry is null) {
+            return null;
+        }
+
+        if (entry.image is null) {
+            entry.image = manager.createImageWithDefault(entry.descriptor);
+        }
+
+        return entry.image;
+    }
+
+    /**
+     * Returns the descriptor associated with the given key in this registry,
+     * or <code>null</code> if none.
+     *
+     * @param key the key
+     * @return the descriptor, or <code>null</code> if none
+     * @since 2.1
+     */
+    public ImageDescriptor getDescriptor(String key) {
+        Entry entry = getEntry(key);
+        if (entry is null) {
+            return null;
+        }
+
+        return entry.descriptor;
+    }
+
+    /**
+     * Adds (or replaces) an image descriptor to this registry. The first time
+     * this new entry is retrieved, the image descriptor's image will be computed
+     * (via </code>ImageDescriptor.createImage</code>) and remembered.
+     * This method replaces an existing image descriptor associated with the
+     * given key, but fails if there is a real image associated with it.
+     *
+     * @param key the key
+     * @param descriptor the ImageDescriptor
+     * @exception IllegalArgumentException if the key already exists
+     */
+    public void put(String key, ImageDescriptor descriptor) {
+        Entry entry = getEntry(key);
+        if (entry is null) {
+            entry = new Entry();
+            getTable().add(key, entry);
+        }
+
+        if (entry.image !is null) {
+            throw new IllegalArgumentException(
+                    "ImageRegistry key already in use: " ~ key); //$NON-NLS-1$
+        }
+
+        entry.descriptor = descriptor;
+    }
+
+    /**
+     * Adds an image to this registry.  This method fails if there
+     * is already an image or descriptor for the given key.
+     * <p>
+     * Note that an image registry owns all of the image objects registered
+     * with it, and automatically disposes of them when the DWT Display is disposed.
+     * Because of this, clients must not register an image object
+     * that is managed by another object.
+     * </p>
+     *
+     * @param key the key
+     * @param image the image, should not be <code>null</code>
+     * @exception IllegalArgumentException if the key already exists
+     */
+    public void put(String key, Image image) {
+        Entry entry = getEntry(key);
+
+        if (entry is null) {
+            entry = new Entry();
+            putEntry(key, entry);
+        }
+
+        if (entry.image !is null || entry.descriptor !is null) {
+            throw new IllegalArgumentException(
+                    "ImageRegistry key already in use: " ~ key); //$NON-NLS-1$
+        }
+
+        // Should be checking for a null image here.
+        // Current behavior is that a null image won't be caught until dispose.
+        // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=130315
+        entry.image = image;
+        entry.descriptor = new OriginalImageDescriptor(image, manager.getDevice());
+
+        try {
+            manager.create(entry.descriptor);
+        } catch (DeviceResourceException e) {
+        }
+    }
+
+    /**
+     * Removes an image from this registry.
+     * If an DWT image was allocated, it is disposed.
+     * This method has no effect if there is no image or descriptor for the given key.
+     * @param key the key
+     */
+    public void remove(String key) {
+        ImageDescriptor descriptor = getDescriptor(key);
+        if (descriptor !is null) {
+            manager.destroy(descriptor);
+            getTable().removeKey(key);
+        }
+    }
+
+    private Entry getEntry(String key) {
+        return cast(Entry) getTable().get(key);
+    }
+
+    private void putEntry(String key, Entry entry) {
+        getTable().add(key, entry);
+    }
+
+    private Map!(String,Entry) getTable() {
+        if (table is null) {
+            table = new HashMap!(String,Entry)/+(10)+/;
+        }
+        return table;
+    }
+
+    /**
+     * Disposes this image registry, disposing any images
+     * that were allocated for it, and clearing its entries.
+     *
+     * @since 3.1
+     */
+    public void dispose() {
+        manager.cancelDisposeExec(disposeRunnable);
+
+        if (table !is null) {
+            foreach( key,entry; table ){
+                if (entry.image !is null) {
+                    manager.destroyImage(entry.descriptor);
+                }
+            }
+            table = null;
+        }
+        display = null;
+    }
+}
--- a/dwtx/jface/resource/JFaceResources.d	Fri Mar 28 23:32:40 2008 +0100
+++ b/dwtx/jface/resource/JFaceResources.d	Sat Mar 29 01:25:27 2008 +0100
@@ -13,12 +13,21 @@
 module dwtx.jface.resource.JFaceResources;
 
 import dwtx.jface.resource.FontRegistry;
+import dwtx.jface.resource.ImageRegistry;
+import dwtx.jface.resource.ResourceManager;
+
+import dwt.graphics.Font;
+import dwt.widgets.Display;
 
 import dwt.dwthelper.utils;
 public class JFaceResources {
     public static const String DEFAULT_FONT = "dwtx.jface.defaultfont"; //$NON-NLS-1$
+    public static final String DIALOG_FONT = "dwtx.jface.dialogfont"; //$NON-NLS-1$
     public static FontRegistry getFontRegistry() ;
     public static String getString(String key) ;
+    public static Font getDialogFont() ;
+    public static ImageRegistry getImageRegistry() ;
+    public static ResourceManager getResources(Display toQuery) ;
 }
 /++
 import java.text.MessageFormat;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/resource/RGBColorDescriptor.d	Sat Mar 29 01:25:27 2008 +0100
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2006 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
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.resource.RGBColorDescriptor;
+
+import dwtx.jface.resource.ColorDescriptor;
+
+import dwt.graphics.Color;
+import dwt.graphics.Device;
+import dwt.graphics.RGB;
+
+import dwt.dwthelper.utils;
+
+/**
+ * Describes a color by its RGB values.
+ *
+ * @since 3.1
+ */
+class RGBColorDescriptor : ColorDescriptor {
+
+    private RGB color;
+
+    /**
+     * Color being copied, or null if none
+     */
+    private Color originalColor = null;
+
+    /**
+     * Creates a new RGBColorDescriptor given some RGB values
+     *
+     * @param color RGB values (not null)
+     */
+    public this(RGB color) {
+        this.color = color;
+    }
+
+    /**
+     * Creates a new RGBColorDescriptor that describes an existing color.
+     *
+     * @since 3.1
+     *
+     * @param originalColor a color to describe
+     */
+    public this(Color originalColor) {
+        this(originalColor.getRGB());
+        this.originalColor = originalColor;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public override int opEquals(Object obj) {
+        if ( auto other = cast(RGBColorDescriptor)obj ) {
+            return other.color.opEquals(color) && other.originalColor is originalColor;
+        }
+
+        return false;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    public override hash_t toHash() {
+        return color.toHash();
+    }
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resources.ColorDescriptor#createColor()
+     */
+    public Color createColor(Device device) {
+        // If this descriptor is wrapping an existing color, then we can return the original color
+        // if this is the same device.
+        if (originalColor !is null) {
+            // If we're allocating on the same device as the original color, return the original.
+            if (originalColor.getDevice() is device) {
+                return originalColor;
+            }
+        }
+
+        return new Color(device, color);
+    }
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resource.ColorDescriptor#destroyColor(dwt.graphics.Color)
+     */
+    public void destroyColor(Color toDestroy) {
+        if (toDestroy is originalColor) {
+            return;
+        }
+
+        toDestroy.dispose();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/resource/ResourceManager.d	Sat Mar 29 01:25:27 2008 +0100
@@ -0,0 +1,406 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2006 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
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.resource.ResourceManager;
+
+import dwtx.jface.resource.DeviceResourceDescriptor;
+import dwtx.jface.resource.ImageDescriptor;
+import dwtx.jface.resource.ColorDescriptor;
+import dwtx.jface.resource.FontDescriptor;
+import dwtx.jface.resource.DeviceResourceException;
+import dwtx.jface.resource.RGBColorDescriptor;
+
+// import java.util.ArrayList;
+import tango.util.collection.model.Seq;
+import tango.util.collection.ArraySeq;
+
+import dwt.DWTException;
+import dwt.graphics.Color;
+import dwt.graphics.Device;
+import dwt.graphics.Font;
+import dwt.graphics.Image;
+import dwt.graphics.RGB;
+import dwtx.core.runtime.Assert;
+import dwtx.core.runtime.IStatus;
+import dwtx.core.runtime.Status;
+import dwtx.jface.util.Policy;
+
+import dwt.dwthelper.utils;
+import dwt.dwthelper.Runnable;
+
+/**
+ * This class manages DWT resources. It manages reference-counted instances of resources
+ * such as Fonts, Images, and Colors, and allows them to be accessed using descriptors.
+ * Everything allocated through the registry should also be disposed through the registry.
+ * Since the resources are shared and reference counted, they should never be disposed
+ * directly.
+ * <p>
+ * ResourceManager handles correct allocation and disposal of resources. It differs from
+ * the various JFace *Registry classes, which also map symbolic IDs onto resources. In
+ * general, you should use a *Registry class to map IDs onto descriptors, and use a
+ * ResourceManager to convert the descriptors into real Images/Fonts/etc.
+ * </p>
+ *
+ * @since 3.1
+ */
+public abstract class ResourceManager {
+
+    /**
+     * List of Runnables scheduled to run when the ResourceManager is disposed.
+     * null if empty.
+     */
+    private Seq!(Runnable) disposeExecs = null;
+
+    /**
+     * Returns the Device for which this ResourceManager will create resources
+     *
+     * @since 3.1
+     *
+     * @return the Device associated with this ResourceManager
+     */
+    public abstract Device getDevice();
+
+    /**
+     * Returns the resource described by the given descriptor. If the resource already
+     * exists, the reference count is incremented and the exiting resource is returned.
+     * Otherwise, a new resource is allocated. Every call to this method should have
+     * a corresponding call to {@link #destroy(DeviceResourceDescriptor)}.
+     *
+     * <p>If the resource is intended to live for entire lifetime of the resource manager,
+     * a subsequent call to {@link #destroy(DeviceResourceDescriptor)} may be omitted and the
+     * resource will be cleaned up when the resource manager is disposed. This pattern
+     * is useful for short-lived {@link LocalResourceManager}s, but should never be used
+     * with the global resource manager since doing so effectively leaks the resource.</p>
+     *
+     * <p>The resources returned from this method are reference counted and may be shared
+     * internally with other resource managers. They should never be disposed outside of the
+     * ResourceManager framework, or it will cause exceptions in other code that shares
+     * them. For example, never call {@link dwt.graphics.Resource#dispose()}
+     * on anything returned from this method.</p>
+     *
+     * <p>Callers may safely downcast the result to the resource type associated with
+     * the descriptor. For example, when given an ImageDescriptor, the return
+     * value of this method will always be an Image.</p>
+     *
+     * @since 3.1
+     *
+     * @param descriptor descriptor for the resource to allocate
+     * @return the newly allocated resource (not null)
+     * @throws DeviceResourceException if unable to allocate the resource
+     */
+    public abstract Object create(DeviceResourceDescriptor descriptor);
+
+    /**
+     * Deallocates a resource previously allocated by {@link #create(DeviceResourceDescriptor)}.
+     * Descriptors are compared by equality, not identity. If the same resource was
+     * created multiple times, this may decrement a reference count rather than
+     * disposing the actual resource.
+     *
+     * @since 3.1
+     *
+     * @param descriptor identifier for the resource
+     */
+    public abstract void destroy(DeviceResourceDescriptor descriptor);
+
+    /**
+     * <p>Returns a previously-allocated resource or allocates a new one if none
+     * exists yet. The resource will remain allocated for at least the lifetime
+     * of this resource manager. If necessary, the resource will be deallocated
+     * automatically when the resource manager is disposed.</p>
+     *
+     * <p>The resources returned from this method are reference counted and may be shared
+     * internally with other resource managers. They should never be disposed outside of the
+     * ResourceManager framework, or it will cause exceptions in other code that shares
+     * them. For example, never call {@link dwt.graphics.Resource#dispose()}
+     * on anything returned from this method.</p>
+     *
+     * <p>
+     * Callers may safely downcast the result to the resource type associated with
+     * the descriptor. For example, when given an ImageDescriptor, the return
+     * value of this method may be downcast to Image.
+     * </p>
+     *
+     * <p>
+     * This method should only be used for resources that should remain
+     * allocated for the lifetime of the resource manager. To allocate shorter-lived
+     * resources, manage them with <code>create</code>, and <code>destroy</code>
+     * rather than this method.
+     * </p>
+     *
+     * <p>
+     * This method should never be called on the global resource manager,
+     * since all resources will remain allocated for the lifetime of the app and
+     * will be effectively leaked.
+     * </p>
+     *
+     * @param descriptor identifier for the requested resource
+     * @return the requested resource. Never null.
+     * @throws DeviceResourceException if the resource does not exist yet and cannot
+     * be created for any reason.
+     *
+     * @since 3.3
+     */
+    public final Object get(DeviceResourceDescriptor descriptor) {
+        Object result = find(descriptor);
+
+        if (result is null) {
+            result = create(descriptor);
+        }
+
+        return result;
+    }
+
+    /**
+     * <p>Creates an image, given an image descriptor. Images allocated in this manner must
+     * be disposed by {@link #destroyImage(ImageDescriptor)}, and never by calling
+     * {@link Image#dispose()}.</p>
+     *
+     * <p>
+     * If the image is intended to remain allocated for the lifetime of the ResourceManager,
+     * the call to destroyImage may be omitted and the image will be cleaned up automatically
+     * when the ResourceManager is disposed. This should only be done with short-lived ResourceManagers,
+     * as doing so with the global manager effectively leaks the resource.
+     * </p>
+     *
+     * @since 3.1
+     *
+     * @param descriptor descriptor for the image to create
+     * @return the Image described by this descriptor (possibly shared by other equivalent
+     * ImageDescriptors)
+     * @throws DeviceResourceException if unable to allocate the Image
+     */
+    public final Image createImage(ImageDescriptor descriptor) {
+        // Assertion added to help diagnose client bugs.  See bug #83711 and bug #90454.
+        Assert.isNotNull(descriptor);
+
+        return cast(Image)create(descriptor);
+    }
+
+    /**
+     * Creates an image, given an image descriptor. Images allocated in this manner must
+     * be disposed by {@link #destroyImage(ImageDescriptor)}, and never by calling
+     * {@link Image#dispose()}.
+     *
+     * @since 3.1
+     *
+     * @param descriptor descriptor for the image to create
+     * @return the Image described by this descriptor (possibly shared by other equivalent
+     * ImageDescriptors)
+     */
+    public final Image createImageWithDefault(ImageDescriptor descriptor) {
+        if (descriptor is null) {
+            return getDefaultImage();
+        }
+
+        try {
+            return cast(Image) create(descriptor);
+        } catch (DeviceResourceException e) {
+            Policy.getLog().log(
+                    new Status(IStatus.WARNING, "dwtx.jface", 0, //$NON-NLS-1$
+                            "The image could not be loaded: " ~ descriptor.toString, //$NON-NLS-1$
+                            e));
+            return getDefaultImage();
+        } catch (DWTException e) {
+            Policy.getLog().log(
+                    new Status(IStatus.WARNING, "dwtx.jface", 0, //$NON-NLS-1$
+                            "The image could not be loaded: " ~ descriptor.toString, //$NON-NLS-1$
+                            e));
+            return getDefaultImage();
+        }
+    }
+
+    /**
+     * Returns the default image that will be returned in the event that the intended
+     * image is missing.
+     *
+     * @since 3.1
+     *
+     * @return a default image that will be returned in the event that the intended
+     * image is missing.
+     */
+    protected abstract Image getDefaultImage();
+
+    /**
+     * Undoes everything that was done by {@link #createImage(ImageDescriptor)}.
+     *
+     * @since 3.1
+     *
+     * @param descriptor identifier for the image to dispose
+     */
+    public final void destroyImage(ImageDescriptor descriptor) {
+        destroy(descriptor);
+    }
+
+    /**
+     * Allocates a color, given a color descriptor. Any color allocated in this
+     * manner must be disposed by calling {@link #destroyColor(ColorDescriptor)},
+     * or by an eventual call to {@link #dispose()}. {@link Color#dispose()} must
+     * never been called directly on the returned color.
+     *
+     * @since 3.1
+     *
+     * @param descriptor descriptor for the color to create
+     * @return the Color described by the given ColorDescriptor (not null)
+     * @throws DeviceResourceException if unable to create the color
+     */
+    public final Color createColor(ColorDescriptor descriptor) {
+        return cast(Color)create(descriptor);
+    }
+
+    /**
+     * Allocates a color, given its RGB value. Any color allocated in this
+     * manner must be disposed by calling {@link #destroyColor(RGB)},
+     * or by an eventual call to {@link #dispose()}. {@link Color#dispose()} must
+     * never been called directly on the returned color.
+     *
+     * @since 3.1
+     *
+     * @param descriptor descriptor for the color to create
+     * @return the Color described by the given ColorDescriptor (not null)
+     * @throws DeviceResourceException if unable to create the color
+     */
+    public final Color createColor(RGB descriptor) {
+        return createColor(new RGBColorDescriptor(descriptor));
+    }
+
+    /**
+     * Undoes everything that was done by a call to {@link #createColor(RGB)}.
+     *
+     * @since 3.1
+     *
+     * @param descriptor RGB value of the color to dispose
+     */
+    public final void destroyColor(RGB descriptor) {
+        destroyColor(new RGBColorDescriptor(descriptor));
+    }
+
+    /**
+     * Undoes everything that was done by a call to {@link #createColor(ColorDescriptor)}.
+     *
+     *
+     * @since 3.1
+     *
+     * @param descriptor identifier for the color to dispose
+     */
+    public final void destroyColor(ColorDescriptor descriptor) {
+        destroy(descriptor);
+    }
+
+    /**
+     * Returns the Font described by the given FontDescriptor. Any Font
+     * allocated in this manner must be deallocated by calling disposeFont(...),
+     * or by an eventual call to {@link #dispose()}.  The method {@link Font#dispose()}
+     * must never be called directly on the returned font.
+     *
+     * @since 3.1
+     *
+     * @param descriptor description of the font to create
+     * @return the Font described by the given descriptor
+     * @throws DeviceResourceException if unable to create the font
+     */
+    public final Font createFont(FontDescriptor descriptor) {
+        return cast(Font)create(descriptor);
+    }
+
+    /**
+     * Undoes everything that was done by a previous call to {@link #createFont(FontDescriptor)}.
+     *
+     * @since 3.1
+     *
+     * @param descriptor description of the font to destroy
+     */
+    public final void destroyFont(FontDescriptor descriptor) {
+        destroy(descriptor);
+    }
+
+    /**
+     * Disposes any remaining resources allocated by this manager.
+     */
+    public void dispose() {
+        if (disposeExecs is null) {
+            return;
+        }
+
+        // If one of the runnables throws an exception, we need to propagate it.
+        // However, this should not prevent the remaining runnables from being
+        // notified. If any runnables throw an exception, we remember one of them
+        // here and throw it at the end of the method.
+        RuntimeException foundException = null;
+
+        Runnable[] execs = disposeExecs.toArray();
+        for (int i = 0; i < execs.length; i++) {
+            Runnable exec = execs[i];
+
+            try {
+                exec.run();
+            } catch (RuntimeException e) {
+                // Ensure that we propagate an exception, but don't stop notifying
+                // the remaining runnables.
+                foundException = e;
+            }
+        }
+
+        if (foundException !is null) {
+            // If any runnables threw an exception, propagate one of them.
+            throw foundException;
+        }
+    }
+
+    /**
+     * Returns a previously allocated resource associated with the given descriptor, or
+     * null if none exists yet.
+     *
+     * @since 3.1
+     *
+     * @param descriptor descriptor to find
+     * @return a previously allocated resource for the given descriptor or null if none.
+     */
+    public abstract Object find(DeviceResourceDescriptor descriptor);
+
+    /**
+     * Causes the <code>run()</code> method of the runnable to
+     * be invoked just before the receiver is disposed. The runnable
+     * can be subsequently canceled by a call to <code>cancelDisposeExec</code>.
+     *
+     * @param r runnable to execute.
+     */
+    public void disposeExec(Runnable r) {
+        Assert.isNotNull(cast(Object)r);
+
+        if (disposeExecs is null) {
+            disposeExecs = new ArraySeq!(Runnable);
+        }
+
+        disposeExecs.append(r);
+    }
+
+    /**
+     * Cancels a runnable that was previously scheduled with <code>disposeExec</code>.
+     * Has no effect if the given runnable was not previously registered with
+     * disposeExec.
+     *
+     * @param r runnable to cancel
+     */
+    public void cancelDisposeExec(Runnable r) {
+        Assert.isNotNull(cast(Object)r);
+
+        if (disposeExecs is null) {
+            return;
+        }
+
+        disposeExecs.remove(r);
+
+        if (disposeExecs.drained()) {
+            disposeExecs = null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/wizard/WizardDialog.d	Sat Mar 29 01:25:27 2008 +0100
@@ -0,0 +1,1520 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 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
+ *     Chris Gross (schtoo@schtoo.com) - patch for bug 16179
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.wizard.WizardDialog;
+
+class WizardDialog {
+}
+
+
+/++
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+import dwt.DWT;
+import dwt.custom.BusyIndicator;
+import dwt.events.HelpEvent;
+import dwt.events.HelpListener;
+import dwt.events.SelectionAdapter;
+import dwt.events.SelectionEvent;
+import dwt.graphics.Cursor;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.layout.GridData;
+import dwt.layout.GridLayout;
+import dwt.widgets.Button;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Display;
+import dwt.widgets.Label;
+import dwt.widgets.Layout;
+import dwt.widgets.Shell;
+import dwtx.core.runtime.Assert;
+import dwtx.core.runtime.IProgressMonitor;
+import dwtx.core.runtime.IStatus;
+import dwtx.core.runtime.ListenerList;
+import dwtx.jface.dialogs.ControlEnableState;
+import dwtx.jface.dialogs.IDialogConstants;
+import dwtx.jface.dialogs.IMessageProvider;
+import dwtx.jface.dialogs.IPageChangeProvider;
+import dwtx.jface.dialogs.IPageChangedListener;
+import dwtx.jface.dialogs.IPageChangingListener;
+import dwtx.jface.dialogs.MessageDialog;
+import dwtx.jface.dialogs.PageChangedEvent;
+import dwtx.jface.dialogs.PageChangingEvent;
+import dwtx.jface.dialogs.TitleAreaDialog;
+import dwtx.jface.operation.IRunnableWithProgress;
+import dwtx.jface.operation.ModalContext;
+import dwtx.jface.resource.JFaceResources;
+import dwtx.jface.util.SafeRunnable;
+
+/**
+ * A dialog to show a wizard to the end user.
+ * <p>
+ * In typical usage, the client instantiates this class with a particular
+ * wizard. The dialog serves as the wizard container and orchestrates the
+ * presentation of its pages.
+ * <p>
+ * The standard layout is roughly as follows: it has an area at the top
+ * containing both the wizard's title, description, and image; the actual wizard
+ * page appears in the middle; below that is a progress indicator (which is made
+ * visible if needed); and at the bottom of the page is message line and a
+ * button bar containing Help, Next, Back, Finish, and Cancel buttons (or some
+ * subset).
+ * </p>
+ * <p>
+ * Clients may subclass <code>WizardDialog</code>, although this is rarely
+ * required.
+ * </p>
+ */
+public class WizardDialog extends TitleAreaDialog implements IWizardContainer2,
+        IPageChangeProvider {
+    /**
+     * Image registry key for error message image (value
+     * <code>"dialog_title_error_image"</code>).
+     */
+    public static final String WIZ_IMG_ERROR = "dialog_title_error_image"; //$NON-NLS-1$
+
+    // The wizard the dialog is currently showing.
+    private IWizard wizard;
+
+    // Wizards to dispose
+    private ArrayList createdWizards = new ArrayList();
+
+    // Current nested wizards
+    private ArrayList nestedWizards = new ArrayList();
+
+    // The currently displayed page.
+    private IWizardPage currentPage = null;
+
+    // The number of long running operation executed from the dialog.
+    private long activeRunningOperations = 0;
+
+    // The current page message and description
+    private String pageMessage;
+
+    private int pageMessageType = IMessageProvider.NONE;
+
+    private String pageDescription;
+
+    // The progress monitor
+    private ProgressMonitorPart progressMonitorPart;
+
+    private Cursor waitCursor;
+
+    private Cursor arrowCursor;
+
+    private MessageDialog windowClosingDialog;
+
+    // Navigation buttons
+    private Button backButton;
+
+    private Button nextButton;
+
+    private Button finishButton;
+
+    private Button cancelButton;
+
+    private Button helpButton;
+
+    private SelectionAdapter cancelListener;
+
+    private bool isMovingToPreviousPage = false;
+
+    private Composite pageContainer;
+
+    private PageContainerFillLayout pageContainerLayout = new PageContainerFillLayout(
+            5, 5, 300, 225);
+
+    private int pageWidth = DWT.DEFAULT;
+
+    private int pageHeight = DWT.DEFAULT;
+
+    private static final String FOCUS_CONTROL = "focusControl"; //$NON-NLS-1$
+
+    private bool lockedUI = false;
+
+    private ListenerList pageChangedListeners = new ListenerList();
+
+    private ListenerList pageChangingListeners = new ListenerList();
+
+    /**
+     * A layout for a container which includes several pages, like a notebook,
+     * wizard, or preference dialog. The size computed by this layout is the
+     * maximum width and height of all pages currently inserted into the
+     * container.
+     */
+    protected class PageContainerFillLayout extends Layout {
+        /**
+         * The margin width; <code>5</code> pixels by default.
+         */
+        public int marginWidth = 5;
+
+        /**
+         * The margin height; <code>5</code> pixels by default.
+         */
+        public int marginHeight = 5;
+
+        /**
+         * The minimum width; <code>0</code> pixels by default.
+         */
+        public int minimumWidth = 0;
+
+        /**
+         * The minimum height; <code>0</code> pixels by default.
+         */
+        public int minimumHeight = 0;
+
+        /**
+         * Creates new layout object.
+         *
+         * @param mw
+         *            the margin width
+         * @param mh
+         *            the margin height
+         * @param minW
+         *            the minimum width
+         * @param minH
+         *            the minimum height
+         */
+        public PageContainerFillLayout(int mw, int mh, int minW, int minH) {
+            marginWidth = mw;
+            marginHeight = mh;
+            minimumWidth = minW;
+            minimumHeight = minH;
+        }
+
+        /*
+         * (non-Javadoc) Method declared on Layout.
+         */
+        public Point computeSize(Composite composite, int wHint, int hHint,
+                bool force) {
+            if (wHint !is DWT.DEFAULT && hHint !is DWT.DEFAULT) {
+                return new Point(wHint, hHint);
+            }
+            Point result = null;
+            Control[] children = composite.getChildren();
+            if (children.length > 0) {
+                result = new Point(0, 0);
+                for (int i = 0; i < children.length; i++) {
+                    Point cp = children[i].computeSize(wHint, hHint, force);
+                    result.x = Math.max(result.x, cp.x);
+                    result.y = Math.max(result.y, cp.y);
+                }
+                result.x = result.x + 2 * marginWidth;
+                result.y = result.y + 2 * marginHeight;
+            } else {
+                Rectangle rect = composite.getClientArea();
+                result = new Point(rect.width, rect.height);
+            }
+            result.x = Math.max(result.x, minimumWidth);
+            result.y = Math.max(result.y, minimumHeight);
+            if (wHint !is DWT.DEFAULT) {
+                result.x = wHint;
+            }
+            if (hHint !is DWT.DEFAULT) {
+                result.y = hHint;
+            }
+            return result;
+        }
+
+        /**
+         * Returns the client area for the given composite according to this
+         * layout.
+         *
+         * @param c
+         *            the composite
+         * @return the client area rectangle
+         */
+        public Rectangle getClientArea(Composite c) {
+            Rectangle rect = c.getClientArea();
+            rect.x = rect.x + marginWidth;
+            rect.y = rect.y + marginHeight;
+            rect.width = rect.width - 2 * marginWidth;
+            rect.height = rect.height - 2 * marginHeight;
+            return rect;
+        }
+
+        /*
+         * (non-Javadoc) Method declared on Layout.
+         */
+        public void layout(Composite composite, bool force) {
+            Rectangle rect = getClientArea(composite);
+            Control[] children = composite.getChildren();
+            for (int i = 0; i < children.length; i++) {
+                children[i].setBounds(rect);
+            }
+        }
+
+        /**
+         * Lays outs the page according to this layout.
+         *
+         * @param w
+         *            the control
+         */
+        public void layoutPage(Control w) {
+            w.setBounds(getClientArea(w.getParent()));
+        }
+
+        /**
+         * Sets the location of the page so that its origin is in the upper left
+         * corner.
+         *
+         * @param w
+         *            the control
+         */
+        public void setPageLocation(Control w) {
+            w.setLocation(marginWidth, marginHeight);
+        }
+    }
+
+    /**
+     * Creates a new wizard dialog for the given wizard.
+     *
+     * @param parentShell
+     *            the parent shell
+     * @param newWizard
+     *            the wizard this dialog is working on
+     */
+    public WizardDialog(Shell parentShell, IWizard newWizard) {
+        super(parentShell);
+        setShellStyle(DWT.CLOSE | DWT.MAX | DWT.TITLE | DWT.BORDER
+                | DWT.APPLICATION_MODAL | DWT.RESIZE | getDefaultOrientation());
+        setWizard(newWizard);
+        // since VAJava can't initialize an instance var with an anonymous
+        // class outside a constructor we do it here:
+        cancelListener = new SelectionAdapter() {
+            public void widgetSelected(SelectionEvent e) {
+                cancelPressed();
+            }
+        };
+    }
+
+    /**
+     * About to start a long running operation triggered through the wizard.
+     * Shows the progress monitor and disables the wizard's buttons and
+     * controls.
+     *
+     * @param enableCancelButton
+     *            <code>true</code> if the Cancel button should be enabled,
+     *            and <code>false</code> if it should be disabled
+     * @return the saved UI state
+     */
+    private Object aboutToStart(bool enableCancelButton) {
+        Map savedState = null;
+        if (getShell() !is null) {
+            // Save focus control
+            Control focusControl = getShell().getDisplay().getFocusControl();
+            if (focusControl !is null && focusControl.getShell() !is getShell()) {
+                focusControl = null;
+            }
+            bool needsProgressMonitor = wizard.needsProgressMonitor();
+            cancelButton.removeSelectionListener(cancelListener);
+            // Set the busy cursor to all shells.
+            Display d = getShell().getDisplay();
+            waitCursor = new Cursor(d, DWT.CURSOR_WAIT);
+            setDisplayCursor(waitCursor);
+            // Set the arrow cursor to the cancel component.
+            arrowCursor = new Cursor(d, DWT.CURSOR_ARROW);
+            cancelButton.setCursor(arrowCursor);
+            // Deactivate shell
+            savedState = saveUIState(needsProgressMonitor && enableCancelButton);
+            if (focusControl !is null) {
+                savedState.put(FOCUS_CONTROL, focusControl);
+            }
+            // Attach the progress monitor part to the cancel button
+            if (needsProgressMonitor) {
+                progressMonitorPart.attachToCancelComponent(cancelButton);
+                progressMonitorPart.setVisible(true);
+            }
+        }
+        return savedState;
+    }
+
+    /**
+     * The Back button has been pressed.
+     */
+    protected void backPressed() {
+        IWizardPage page = currentPage.getPreviousPage();
+        if (page is null) {
+            // should never happen since we have already visited the page
+            return;
+        }
+
+        // set flag to indicate that we are moving back
+        isMovingToPreviousPage = true;
+        // show the page
+        showPage(page);
+    }
+
+    /*
+     * (non-Javadoc) Method declared on Dialog.
+     */
+    protected void buttonPressed(int buttonId) {
+        switch (buttonId) {
+        case IDialogConstants.HELP_ID: {
+            helpPressed();
+            break;
+        }
+        case IDialogConstants.BACK_ID: {
+            backPressed();
+            break;
+        }
+        case IDialogConstants.NEXT_ID: {
+            nextPressed();
+            break;
+        }
+        case IDialogConstants.FINISH_ID: {
+            finishPressed();
+            break;
+        }
+            // The Cancel button has a listener which calls cancelPressed
+            // directly
+        }
+    }
+
+    /**
+     * Calculates the difference in size between the given page and the page
+     * container. A larger page results in a positive delta.
+     *
+     * @param page
+     *            the page
+     * @return the size difference encoded as a
+     *         <code>new Point(deltaWidth,deltaHeight)</code>
+     */
+    private Point calculatePageSizeDelta(IWizardPage page) {
+        Control pageControl = page.getControl();
+        if (pageControl is null) {
+            // control not created yet
+            return new Point(0, 0);
+        }
+        Point contentSize = pageControl.computeSize(DWT.DEFAULT, DWT.DEFAULT,
+                true);
+        Rectangle rect = pageContainerLayout.getClientArea(pageContainer);
+        Point containerSize = new Point(rect.width, rect.height);
+        return new Point(Math.max(0, contentSize.x - containerSize.x), Math
+                .max(0, contentSize.y - containerSize.y));
+    }
+
+    /*
+     * (non-Javadoc) Method declared on Dialog.
+     */
+    protected void cancelPressed() {
+        if (activeRunningOperations <= 0) {
+            // Close the dialog. The check whether the dialog can be
+            // closed or not is done in <code>okToClose</code>.
+            // This ensures that the check is also evaluated when the user
+            // presses the window's close button.
+            setReturnCode(CANCEL);
+            close();
+        } else {
+            cancelButton.setEnabled(false);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwtx.jface.window.Window#close()
+     */
+    public bool close() {
+        if (okToClose()) {
+            return hardClose();
+        }
+        return false;
+    }
+
+    /*
+     * (non-Javadoc) Method declared on Window.
+     */
+    protected void configureShell(Shell newShell) {
+        super.configureShell(newShell);
+        // Register help listener on the shell
+        newShell.addHelpListener(new HelpListener() {
+            public void helpRequested(HelpEvent event) {
+                // call perform help on the current page
+                if (currentPage !is null) {
+                    currentPage.performHelp();
+                }
+            }
+        });
+    }
+
+    /**
+     * Creates the buttons for this dialog's button bar.
+     * <p>
+     * The <code>WizardDialog</code> implementation of this framework method
+     * prevents the parent composite's columns from being made equal width in
+     * order to remove the margin between the Back and Next buttons.
+     * </p>
+     *
+     * @param parent
+     *            the parent composite to contain the buttons
+     */
+    protected void createButtonsForButtonBar(Composite parent) {
+        ((GridLayout) parent.getLayout()).makeColumnsEqualWidth = false;
+        if (wizard.isHelpAvailable()) {
+            helpButton = createButton(parent, IDialogConstants.HELP_ID,
+                    IDialogConstants.HELP_LABEL, false);
+        }
+        if (wizard.needsPreviousAndNextButtons()) {
+            createPreviousAndNextButtons(parent);
+        }
+        finishButton = createButton(parent, IDialogConstants.FINISH_ID,
+                IDialogConstants.FINISH_LABEL, true);
+        cancelButton = createCancelButton(parent);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwtx.jface.dialogs.Dialog#setButtonLayoutData(dwt.widgets.Button)
+     */
+    protected void setButtonLayoutData(Button button) {
+        GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+        int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
+
+        // On large fonts this can make this dialog huge
+        widthHint = Math.min(widthHint,
+                button.getDisplay().getBounds().width / 5);
+        Point minSize = button.computeSize(DWT.DEFAULT, DWT.DEFAULT, true);
+        data.widthHint = Math.max(widthHint, minSize.x);
+
+        button.setLayoutData(data);
+    }
+
+    /**
+     * Creates the Cancel button for this wizard dialog. Creates a standard (<code>DWT.PUSH</code>)
+     * button and registers for its selection events. Note that the number of
+     * columns in the button bar composite is incremented. The Cancel button is
+     * created specially to give it a removeable listener.
+     *
+     * @param parent
+     *            the parent button bar
+     * @return the new Cancel button
+     */
+    private Button createCancelButton(Composite parent) {
+        // increment the number of columns in the button bar
+        ((GridLayout) parent.getLayout()).numColumns++;
+        Button button = new Button(parent, DWT.PUSH);
+        button.setText(IDialogConstants.CANCEL_LABEL);
+        setButtonLayoutData(button);
+        button.setFont(parent.getFont());
+        button.setData(new Integer(IDialogConstants.CANCEL_ID));
+        button.addSelectionListener(cancelListener);
+        return button;
+    }
+
+    /**
+     * Return the cancel button if the id is a the cancel id.
+     *
+     * @param id
+     *            the button id
+     * @return the button corresponding to the button id
+     */
+    protected Button getButton(int id) {
+        if (id is IDialogConstants.CANCEL_ID) {
+            return cancelButton;
+        }
+        return super.getButton(id);
+    }
+
+    /**
+     * The <code>WizardDialog</code> implementation of this
+     * <code>Window</code> method calls call <code>IWizard.addPages</code>
+     * to allow the current wizard to add extra pages, then
+     * <code>super.createContents</code> to create the controls. It then calls
+     * <code>IWizard.createPageControls</code> to allow the wizard to
+     * pre-create their page controls prior to opening, so that the wizard opens
+     * to the correct size. And finally it shows the first page.
+     */
+    protected Control createContents(Composite parent) {
+        // Allow the wizard to add pages to itself
+        // Need to call this now so page count is correct
+        // for determining if next/previous buttons are needed
+        wizard.addPages();
+        Control contents = super.createContents(parent);
+        // Allow the wizard pages to precreate their page controls
+        createPageControls();
+        // Show the first page
+        showStartingPage();
+        return contents;
+    }
+
+    /*
+     * (non-Javadoc) Method declared on Dialog.
+     */
+    protected Control createDialogArea(Composite parent) {
+        Composite composite = (Composite) super.createDialogArea(parent);
+        // Build the Page container
+        pageContainer = createPageContainer(composite);
+        GridData gd = new GridData(GridData.FILL_BOTH);
+        gd.widthHint = pageWidth;
+        gd.heightHint = pageHeight;
+        pageContainer.setLayoutData(gd);
+        pageContainer.setFont(parent.getFont());
+        // Insert a progress monitor
+        GridLayout pmlayout = new GridLayout();
+        pmlayout.numColumns = 1;
+        progressMonitorPart = createProgressMonitorPart(composite, pmlayout);
+        GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
+        progressMonitorPart.setLayoutData(gridData);
+        progressMonitorPart.setVisible(false);
+        // Build the separator line
+        Label separator = new Label(composite, DWT.HORIZONTAL | DWT.SEPARATOR);
+        separator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+        applyDialogFont(progressMonitorPart);
+        return composite;
+    }
+
+    /**
+     * Create the progress monitor part in the receiver.
+     *
+     * @param composite
+     * @param pmlayout
+     * @return ProgressMonitorPart
+     */
+    protected ProgressMonitorPart createProgressMonitorPart(
+            Composite composite, GridLayout pmlayout) {
+        return new ProgressMonitorPart(composite, pmlayout, DWT.DEFAULT) {
+            String currentTask = null;
+
+            /*
+             * (non-Javadoc)
+             *
+             * @see dwtx.jface.wizard.ProgressMonitorPart#setBlocked(dwtx.core.runtime.IStatus)
+             */
+            public void setBlocked(IStatus reason) {
+                super.setBlocked(reason);
+                if (!lockedUI) {
+                    getBlockedHandler().showBlocked(getShell(), this, reason,
+                            currentTask);
+                }
+            }
+
+            /*
+             * (non-Javadoc)
+             *
+             * @see dwtx.jface.wizard.ProgressMonitorPart#clearBlocked()
+             */
+            public void clearBlocked() {
+                super.clearBlocked();
+                if (!lockedUI) {
+                    getBlockedHandler().clearBlocked();
+                }
+            }
+
+            /*
+             * (non-Javadoc)
+             *
+             * @see dwtx.jface.wizard.ProgressMonitorPart#beginTask(java.lang.String,
+             *      int)
+             */
+            public void beginTask(String name, int totalWork) {
+                super.beginTask(name, totalWork);
+                currentTask = name;
+            }
+
+            /*
+             * (non-Javadoc)
+             *
+             * @see dwtx.jface.wizard.ProgressMonitorPart#setTaskName(java.lang.String)
+             */
+            public void setTaskName(String name) {
+                super.setTaskName(name);
+                currentTask = name;
+            }
+
+            /*
+             * (non-Javadoc)
+             *
+             * @see dwtx.jface.wizard.ProgressMonitorPart#subTask(java.lang.String)
+             */
+            public void subTask(String name) {
+                super.subTask(name);
+                // If we haven't got anything yet use this value for more
+                // context
+                if (currentTask is null) {
+                    currentTask = name;
+                }
+            }
+        };
+    }
+
+    /**
+     * Creates the container that holds all pages.
+     *
+     * @param parent
+     * @return Composite
+     */
+    private Composite createPageContainer(Composite parent) {
+        Composite result = new Composite(parent, DWT.NULL);
+        result.setLayout(pageContainerLayout);
+        return result;
+    }
+
+    /**
+     * Allow the wizard's pages to pre-create their page controls. This allows
+     * the wizard dialog to open to the correct size.
+     */
+    private void createPageControls() {
+        // Allow the wizard pages to precreate their page controls
+        // This allows the wizard to open to the correct size
+        wizard.createPageControls(pageContainer);
+        // Ensure that all of the created pages are initially not visible
+        IWizardPage[] pages = wizard.getPages();
+        for (int i = 0; i < pages.length; i++) {
+            IWizardPage page = pages[i];
+            if (page.getControl() !is null) {
+                page.getControl().setVisible(false);
+            }
+        }
+    }
+
+    /**
+     * Creates the Previous and Next buttons for this wizard dialog. Creates
+     * standard (<code>DWT.PUSH</code>) buttons and registers for their
+     * selection events. Note that the number of columns in the button bar
+     * composite is incremented. These buttons are created specially to prevent
+     * any space between them.
+     *
+     * @param parent
+     *            the parent button bar
+     * @return a composite containing the new buttons
+     */
+    private Composite createPreviousAndNextButtons(Composite parent) {
+        // increment the number of columns in the button bar
+        ((GridLayout) parent.getLayout()).numColumns++;
+        Composite composite = new Composite(parent, DWT.NONE);
+        // create a layout with spacing and margins appropriate for the font
+        // size.
+        GridLayout layout = new GridLayout();
+        layout.numColumns = 0; // will be incremented by createButton
+        layout.marginWidth = 0;
+        layout.marginHeight = 0;
+        layout.horizontalSpacing = 0;
+        layout.verticalSpacing = 0;
+        composite.setLayout(layout);
+        GridData data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER
+                | GridData.VERTICAL_ALIGN_CENTER);
+        composite.setLayoutData(data);
+        composite.setFont(parent.getFont());
+        backButton = createButton(composite, IDialogConstants.BACK_ID,
+                IDialogConstants.BACK_LABEL, false);
+        nextButton = createButton(composite, IDialogConstants.NEXT_ID,
+                IDialogConstants.NEXT_LABEL, false);
+        return composite;
+    }
+
+    /**
+     * Creates and return a new wizard closing dialog without openiong it.
+     *
+     * @return MessageDalog
+     */
+    private MessageDialog createWizardClosingDialog() {
+        MessageDialog result = new MessageDialog(getShell(),
+                JFaceResources.getString("WizardClosingDialog.title"), //$NON-NLS-1$
+                null,
+                JFaceResources.getString("WizardClosingDialog.message"), //$NON-NLS-1$
+                MessageDialog.QUESTION,
+                new String[] { IDialogConstants.OK_LABEL }, 0);
+        return result;
+    }
+
+    /**
+     * The Finish button has been pressed.
+     */
+    protected void finishPressed() {
+        // Wizards are added to the nested wizards list in setWizard.
+        // This means that the current wizard is always the last wizard in the
+        // list.
+        // Note that we first call the current wizard directly (to give it a
+        // chance to
+        // abort, do work, and save state) then call the remaining n-1 wizards
+        // in the
+        // list (to save state).
+        if (wizard.performFinish()) {
+            // Call perform finish on outer wizards in the nested chain
+            // (to allow them to save state for example)
+            for (int i = 0; i < nestedWizards.size() - 1; i++) {
+                ((IWizard) nestedWizards.get(i)).performFinish();
+            }
+            // Hard close the dialog.
+            setReturnCode(OK);
+            hardClose();
+        }
+    }
+
+    /*
+     * (non-Javadoc) Method declared on IWizardContainer.
+     */
+    public IWizardPage getCurrentPage() {
+        return currentPage;
+    }
+
+    /**
+     * Returns the progress monitor for this wizard dialog (if it has one).
+     *
+     * @return the progress monitor, or <code>null</code> if this wizard
+     *         dialog does not have one
+     */
+    protected IProgressMonitor getProgressMonitor() {
+        return progressMonitorPart;
+    }
+
+    /**
+     * Returns the wizard this dialog is currently displaying.
+     *
+     * @return the current wizard
+     */
+    protected IWizard getWizard() {
+        return wizard;
+    }
+
+    /**
+     * Closes this window.
+     *
+     * @return <code>true</code> if the window is (or was already) closed, and
+     *         <code>false</code> if it is still open
+     */
+    private bool hardClose() {
+        // inform wizards
+        for (int i = 0; i < createdWizards.size(); i++) {
+            IWizard createdWizard = (IWizard) createdWizards.get(i);
+            createdWizard.dispose();
+            // Remove this dialog as a parent from the managed wizard.
+            // Note that we do this after calling dispose as the wizard or
+            // its pages may need access to the container during
+            // dispose code
+            createdWizard.setContainer(null);
+        }
+        return super.close();
+    }
+
+    /**
+     * The Help button has been pressed.
+     */
+    protected void helpPressed() {
+        if (currentPage !is null) {
+            currentPage.performHelp();
+        }
+    }
+
+    /**
+     * The Next button has been pressed.
+     */
+    protected void nextPressed() {
+        IWizardPage page = currentPage.getNextPage();
+        if (page is null) {
+            // something must have happend getting the next page
+            return;
+        }
+
+        // show the next page
+        showPage(page);
+    }
+
+    /**
+     * Notifies page changing listeners and returns result of page changing
+     * processing to the sender.
+     *
+     * @param eventType
+     * @return <code>true</code> if page changing listener completes
+     *         successfully, <code>false</code> otherwise
+     */
+    private bool doPageChanging(IWizardPage targetPage) {
+        PageChangingEvent e = new PageChangingEvent(this, getCurrentPage(),
+                targetPage);
+        firePageChanging(e);
+        // Prevent navigation if necessary
+        return e.doit;
+    }
+
+    /**
+     * Checks whether it is alright to close this wizard dialog and performed
+     * standard cancel processing. If there is a long running operation in
+     * progress, this method posts an alert message saying that the wizard
+     * cannot be closed.
+     *
+     * @return <code>true</code> if it is alright to close this dialog, and
+     *         <code>false</code> if it is not
+     */
+    private bool okToClose() {
+        if (activeRunningOperations > 0) {
+            synchronized (this) {
+                windowClosingDialog = createWizardClosingDialog();
+            }
+            windowClosingDialog.open();
+            synchronized (this) {
+                windowClosingDialog = null;
+            }
+            return false;
+        }
+        return wizard.performCancel();
+    }
+
+    /**
+     * Restores the enabled/disabled state of the given control.
+     *
+     * @param w
+     *            the control
+     * @param h
+     *            the map (key type: <code>String</code>, element type:
+     *            <code>bool</code>)
+     * @param key
+     *            the key
+     * @see #saveEnableStateAndSet
+     */
+    private void restoreEnableState(Control w, Map h, String key) {
+        if (w !is null) {
+            bool b = (bool) h.get(key);
+            if (b !is null) {
+                w.setEnabled(b.booleanValue());
+            }
+        }
+    }
+
+    /**
+     * Restores the enabled/disabled state of the wizard dialog's buttons and
+     * the tree of controls for the currently showing page.
+     *
+     * @param state
+     *            a map containing the saved state as returned by
+     *            <code>saveUIState</code>
+     * @see #saveUIState
+     */
+    private void restoreUIState(Map state) {
+        restoreEnableState(backButton, state, "back"); //$NON-NLS-1$
+        restoreEnableState(nextButton, state, "next"); //$NON-NLS-1$
+        restoreEnableState(finishButton, state, "finish"); //$NON-NLS-1$
+        restoreEnableState(cancelButton, state, "cancel"); //$NON-NLS-1$
+        restoreEnableState(helpButton, state, "help"); //$NON-NLS-1$
+        Object pageValue = state.get("page"); //$NON-NLS-1$
+        if (pageValue !is null) {
+            ((ControlEnableState) pageValue).restore();
+        }
+    }
+
+    /**
+     * This implementation of IRunnableContext#run(bool, bool,
+     * IRunnableWithProgress) blocks until the runnable has been run, regardless
+     * of the value of <code>fork</code>. It is recommended that
+     * <code>fork</code> is set to true in most cases. If <code>fork</code>
+     * is set to <code>false</code>, the runnable will run in the UI thread
+     * and it is the runnable's responsibility to call
+     * <code>Display.readAndDispatch()</code> to ensure UI responsiveness.
+     *
+     * UI state is saved prior to executing the long-running operation and is
+     * restored after the long-running operation completes executing. Any
+     * attempt to change the UI state of the wizard in the long-running
+     * operation will be nullified when original UI state is restored.
+     *
+     */
+    public void run(bool fork, bool cancelable,
+            IRunnableWithProgress runnable) throws InvocationTargetException,
+            InterruptedException {
+        // The operation can only be canceled if it is executed in a separate
+        // thread.
+        // Otherwise the UI is blocked anyway.
+        Object state = null;
+        if (activeRunningOperations is 0) {
+            state = aboutToStart(fork && cancelable);
+        }
+        activeRunningOperations++;
+        try {
+            if (!fork) {
+                lockedUI = true;
+            }
+            ModalContext.run(runnable, fork, getProgressMonitor(), getShell()
+                    .getDisplay());
+            lockedUI = false;
+        } finally {
+            activeRunningOperations--;
+            // Stop if this is the last one
+            if (state !is null) {
+                stopped(state);
+            }
+        }
+    }
+
+    /**
+     * Saves the enabled/disabled state of the given control in the given map,
+     * which must be modifiable.
+     *
+     * @param w
+     *            the control, or <code>null</code> if none
+     * @param h
+     *            the map (key type: <code>String</code>, element type:
+     *            <code>bool</code>)
+     * @param key
+     *            the key
+     * @param enabled
+     *            <code>true</code> to enable the control, and
+     *            <code>false</code> to disable it
+     * @see #restoreEnableState(Control, Map, String)
+     */
+    private void saveEnableStateAndSet(Control w, Map h, String key,
+            bool enabled) {
+        if (w !is null) {
+            h.put(key, w.getEnabled() ? bool.TRUE : bool.FALSE);
+            w.setEnabled(enabled);
+        }
+    }
+
+    /**
+     * Captures and returns the enabled/disabled state of the wizard dialog's
+     * buttons and the tree of controls for the currently showing page. All
+     * these controls are disabled in the process, with the possible exception
+     * of the Cancel button.
+     *
+     * @param keepCancelEnabled
+     *            <code>true</code> if the Cancel button should remain
+     *            enabled, and <code>false</code> if it should be disabled
+     * @return a map containing the saved state suitable for restoring later
+     *         with <code>restoreUIState</code>
+     * @see #restoreUIState
+     */
+    private Map saveUIState(bool keepCancelEnabled) {
+        Map savedState = new HashMap(10);
+        saveEnableStateAndSet(backButton, savedState, "back", false); //$NON-NLS-1$
+        saveEnableStateAndSet(nextButton, savedState, "next", false); //$NON-NLS-1$
+        saveEnableStateAndSet(finishButton, savedState, "finish", false); //$NON-NLS-1$
+        saveEnableStateAndSet(cancelButton, savedState,
+                "cancel", keepCancelEnabled); //$NON-NLS-1$
+        saveEnableStateAndSet(helpButton, savedState, "help", false); //$NON-NLS-1$
+        if (currentPage !is null) {
+            savedState
+                    .put(
+                            "page", ControlEnableState.disable(currentPage.getControl())); //$NON-NLS-1$
+        }
+        return savedState;
+    }
+
+    /**
+     * Sets the given cursor for all shells currently active for this window's
+     * display.
+     *
+     * @param c
+     *            the cursor
+     */
+    private void setDisplayCursor(Cursor c) {
+        Shell[] shells = getShell().getDisplay().getShells();
+        for (int i = 0; i < shells.length; i++) {
+            shells[i].setCursor(c);
+        }
+    }
+
+    /**
+     * Sets the minimum page size used for the pages.
+     *
+     * @param minWidth
+     *            the minimum page width
+     * @param minHeight
+     *            the minimum page height
+     * @see #setMinimumPageSize(Point)
+     */
+    public void setMinimumPageSize(int minWidth, int minHeight) {
+        Assert.isTrue(minWidth >= 0 && minHeight >= 0);
+        pageContainerLayout.minimumWidth = minWidth;
+        pageContainerLayout.minimumHeight = minHeight;
+    }
+
+    /**
+     * Sets the minimum page size used for the pages.
+     *
+     * @param size
+     *            the page size encoded as <code>new Point(width,height)</code>
+     * @see #setMinimumPageSize(int,int)
+     */
+    public void setMinimumPageSize(Point size) {
+        setMinimumPageSize(size.x, size.y);
+    }
+
+    /**
+     * Sets the size of all pages. The given size takes precedence over computed
+     * sizes.
+     *
+     * @param width
+     *            the page width
+     * @param height
+     *            the page height
+     * @see #setPageSize(Point)
+     */
+    public void setPageSize(int width, int height) {
+        pageWidth = width;
+        pageHeight = height;
+    }
+
+    /**
+     * Sets the size of all pages. The given size takes precedence over computed
+     * sizes.
+     *
+     * @param size
+     *            the page size encoded as <code>new Point(width,height)</code>
+     * @see #setPageSize(int,int)
+     */
+    public void setPageSize(Point size) {
+        setPageSize(size.x, size.y);
+    }
+
+    /**
+     * Sets the wizard this dialog is currently displaying.
+     *
+     * @param newWizard
+     *            the wizard
+     */
+    protected void setWizard(IWizard newWizard) {
+        wizard = newWizard;
+        wizard.setContainer(this);
+        if (!createdWizards.contains(wizard)) {
+            createdWizards.add(wizard);
+            // New wizard so just add it to the end of our nested list
+            nestedWizards.add(wizard);
+            if (pageContainer !is null) {
+                // Dialog is already open
+                // Allow the wizard pages to precreate their page controls
+                // This allows the wizard to open to the correct size
+                createPageControls();
+                // Ensure the dialog is large enough for the wizard
+                updateSizeForWizard(wizard);
+                pageContainer.layout(true);
+            }
+        } else {
+            // We have already seen this wizard, if it is the previous wizard
+            // on the nested list then we assume we have gone back and remove
+            // the last wizard from the list
+            int size = nestedWizards.size();
+            if (size >= 2 && nestedWizards.get(size - 2) is wizard) {
+                nestedWizards.remove(size - 1);
+            } else {
+                // Assume we are going forward to revisit a wizard
+                nestedWizards.add(wizard);
+            }
+        }
+    }
+
+    /*
+     * (non-Javadoc) Method declared on IWizardContainer.
+     */
+    public void showPage(IWizardPage page) {
+        if (page is null || page is currentPage) {
+            return;
+        }
+
+        if (!isMovingToPreviousPage) {
+            // remember my previous page.
+            page.setPreviousPage(currentPage);
+        } else {
+            isMovingToPreviousPage = false;
+        }
+
+        // If page changing evaluation unsuccessful, do not change the page
+        if (!doPageChanging(page))
+            return;
+
+        // Update for the new page in a busy cursor if possible
+        if (getContents() is null) {
+            updateForPage(page);
+        } else {
+            final IWizardPage finalPage = page;
+            BusyIndicator.showWhile(getContents().getDisplay(), new Runnable() {
+                public void run() {
+                    updateForPage(finalPage);
+                }
+            });
+        }
+    }
+
+    /**
+     * Update the receiver for the new page.
+     *
+     * @param page
+     */
+    private void updateForPage(IWizardPage page) {
+        // ensure this page belongs to the current wizard
+        if (wizard !is page.getWizard()) {
+            setWizard(page.getWizard());
+        }
+        // ensure that page control has been created
+        // (this allows lazy page control creation)
+        if (page.getControl() is null) {
+            page.createControl(pageContainer);
+            // the page is responsible for ensuring the created control is
+            // accessable
+            // via getControl.
+            Assert.isNotNull(page.getControl(), JFaceResources.format(
+                    JFaceResources.getString("WizardDialog.missingSetControl"), //$NON-NLS-1$
+                    new Object[] { page.getName() }));
+            // ensure the dialog is large enough for this page
+            updateSize(page);
+        }
+        // make the new page visible
+        IWizardPage oldPage = currentPage;
+        currentPage = page;
+
+        currentPage.setVisible(true);
+        if (oldPage !is null) {
+            oldPage.setVisible(false);
+        }
+        // update the dialog controls
+        update();
+    }
+
+    /**
+     * Shows the starting page of the wizard.
+     */
+    private void showStartingPage() {
+        currentPage = wizard.getStartingPage();
+        if (currentPage is null) {
+            // something must have happend getting the page
+            return;
+        }
+        // ensure the page control has been created
+        if (currentPage.getControl() is null) {
+            currentPage.createControl(pageContainer);
+            // the page is responsible for ensuring the created control is
+            // accessable
+            // via getControl.
+            Assert.isNotNull(currentPage.getControl());
+            // we do not need to update the size since the call
+            // to initialize bounds has not been made yet.
+        }
+        // make the new page visible
+        currentPage.setVisible(true);
+        // update the dialog controls
+        update();
+    }
+
+    /**
+     * A long running operation triggered through the wizard was stopped either
+     * by user input or by normal end. Hides the progress monitor and restores
+     * the enable state wizard's buttons and controls.
+     *
+     * @param savedState
+     *            the saved UI state as returned by <code>aboutToStart</code>
+     * @see #aboutToStart
+     */
+    private void stopped(Object savedState) {
+        if (getShell() !is null) {
+            if (wizard.needsProgressMonitor()) {
+                progressMonitorPart.setVisible(false);
+                progressMonitorPart.removeFromCancelComponent(cancelButton);
+            }
+            Map state = (Map) savedState;
+            restoreUIState(state);
+            cancelButton.addSelectionListener(cancelListener);
+            setDisplayCursor(null);
+            cancelButton.setCursor(null);
+            waitCursor.dispose();
+            waitCursor = null;
+            arrowCursor.dispose();
+            arrowCursor = null;
+            Control focusControl = (Control) state.get(FOCUS_CONTROL);
+            if (focusControl !is null) {
+                focusControl.setFocus();
+            }
+        }
+    }
+
+    /**
+     * Updates this dialog's controls to reflect the current page.
+     */
+    protected void update() {
+        // Update the window title
+        updateWindowTitle();
+        // Update the title bar
+        updateTitleBar();
+        // Update the buttons
+        updateButtons();
+
+        // Fires the page change event
+        firePageChanged(new PageChangedEvent(this, getCurrentPage()));
+    }
+
+    /*
+     * (non-Javadoc) Method declared on IWizardContainer.
+     */
+    public void updateButtons() {
+        bool canFlipToNextPage = false;
+        bool canFinish = wizard.canFinish();
+        if (backButton !is null) {
+            backButton.setEnabled(currentPage.getPreviousPage() !is null);
+        }
+        if (nextButton !is null) {
+            canFlipToNextPage = currentPage.canFlipToNextPage();
+            nextButton.setEnabled(canFlipToNextPage);
+        }
+        finishButton.setEnabled(canFinish);
+        // finish is default unless it is diabled and next is enabled
+        if (canFlipToNextPage && !canFinish) {
+            getShell().setDefaultButton(nextButton);
+        } else {
+            getShell().setDefaultButton(finishButton);
+        }
+    }
+
+    /**
+     * Update the message line with the page's description.
+     * <p>
+     * A discription is shown only if there is no message or error message.
+     * </p>
+     */
+    private void updateDescriptionMessage() {
+        pageDescription = currentPage.getDescription();
+        setMessage(pageDescription);
+    }
+
+    /*
+     * (non-Javadoc) Method declared on IWizardContainer.
+     */
+    public void updateMessage() {
+
+        if (currentPage is null) {
+            return;
+        }
+
+        pageMessage = currentPage.getMessage();
+        if (pageMessage !is null && currentPage instanceof IMessageProvider) {
+            pageMessageType = ((IMessageProvider) currentPage).getMessageType();
+        } else {
+            pageMessageType = IMessageProvider.NONE;
+        }
+        if (pageMessage is null) {
+            setMessage(pageDescription);
+        } else {
+            setMessage(pageMessage, pageMessageType);
+        }
+        setErrorMessage(currentPage.getErrorMessage());
+    }
+
+    /**
+     * Changes the shell size to the given size, ensuring that it is no larger
+     * than the display bounds.
+     *
+     * @param width
+     *            the shell width
+     * @param height
+     *            the shell height
+     */
+    private void setShellSize(int width, int height) {
+        Rectangle size = getShell().getBounds();
+        size.height = height;
+        size.width = width;
+        getShell().setBounds(getConstrainedShellBounds(size));
+    }
+
+    /**
+     * Computes the correct dialog size for the current page and resizes its
+     * shell if nessessary. Also causes the container to refresh its layout.
+     *
+     * @param page
+     *            the wizard page to use to resize the dialog
+     * @since 2.0
+     */
+    protected void updateSize(IWizardPage page) {
+        if (page is null || page.getControl() is null) {
+            return;
+        }
+        updateSizeForPage(page);
+        pageContainerLayout.layoutPage(page.getControl());
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwtx.jface.wizard.IWizardContainer2#updateSize()
+     */
+    public void updateSize() {
+        updateSize(currentPage);
+    }
+
+    /**
+     * Computes the correct dialog size for the given page and resizes its shell
+     * if nessessary.
+     *
+     * @param page
+     *            the wizard page
+     */
+    private void updateSizeForPage(IWizardPage page) {
+        // ensure the page container is large enough
+        Point delta = calculatePageSizeDelta(page);
+        if (delta.x > 0 || delta.y > 0) {
+            // increase the size of the shell
+            Shell shell = getShell();
+            Point shellSize = shell.getSize();
+            setShellSize(shellSize.x + delta.x, shellSize.y + delta.y);
+            constrainShellSize();
+        }
+    }
+
+    /**
+     * Computes the correct dialog size for the given wizard and resizes its
+     * shell if nessessary.
+     *
+     * @param sizingWizard
+     *            the wizard
+     */
+    private void updateSizeForWizard(IWizard sizingWizard) {
+        Point delta = new Point(0, 0);
+        IWizardPage[] pages = sizingWizard.getPages();
+        for (int i = 0; i < pages.length; i++) {
+            // ensure the page container is large enough
+            Point pageDelta = calculatePageSizeDelta(pages[i]);
+            delta.x = Math.max(delta.x, pageDelta.x);
+            delta.y = Math.max(delta.y, pageDelta.y);
+        }
+        if (delta.x > 0 || delta.y > 0) {
+            // increase the size of the shell
+            Shell shell = getShell();
+            Point shellSize = shell.getSize();
+            setShellSize(shellSize.x + delta.x, shellSize.y + delta.y);
+        }
+    }
+
+    /*
+     * (non-Javadoc) Method declared on IWizardContainer.
+     */
+    public void updateTitleBar() {
+        String s = null;
+        if (currentPage !is null) {
+            s = currentPage.getTitle();
+        }
+        if (s is null) {
+            s = ""; //$NON-NLS-1$
+        }
+        setTitle(s);
+        if (currentPage !is null) {
+            setTitleImage(currentPage.getImage());
+            updateDescriptionMessage();
+        }
+        updateMessage();
+    }
+
+    /*
+     * (non-Javadoc) Method declared on IWizardContainer.
+     */
+    public void updateWindowTitle() {
+        if (getShell() is null) {
+            // Not created yet
+            return;
+        }
+        String title = wizard.getWindowTitle();
+        if (title is null) {
+            title = ""; //$NON-NLS-1$
+        }
+        getShell().setText(title);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwtx.jface.dialogs.IPageChangeProvider#getSelectedPage()
+     */
+    public Object getSelectedPage() {
+        return getCurrentPage();
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwtx.jface.dialog.IPageChangeProvider#addPageChangedListener()
+     */
+    public void addPageChangedListener(IPageChangedListener listener) {
+        pageChangedListeners.add(listener);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwtx.jface.dialog.IPageChangeProvider#removePageChangedListener()
+     */
+    public void removePageChangedListener(IPageChangedListener listener) {
+        pageChangedListeners.remove(listener);
+    }
+
+    /**
+     * Notifies any selection changed listeners that the selected page has
+     * changed. Only listeners registered at the time this method is called are
+     * notified.
+     *
+     * @param event
+     *            a selection changed event
+     *
+     * @see IPageChangedListener#pageChanged
+     *
+     * @since 3.1
+     */
+    protected void firePageChanged(final PageChangedEvent event) {
+        Object[] listeners = pageChangedListeners.getListeners();
+        for (int i = 0; i < listeners.length; ++i) {
+            final IPageChangedListener l = (IPageChangedListener) listeners[i];
+            SafeRunnable.run(new SafeRunnable() {
+                public void run() {
+                    l.pageChanged(event);
+                }
+            });
+        }
+    }
+
+    /**
+     * Adds a listener for page changes to the list of page changing listeners
+     * registered for this dialog. Has no effect if an identical listener is
+     * already registered.
+     *
+     * @param listener
+     *            a page changing listener
+     * @since 3.3
+     */
+    public void addPageChangingListener(IPageChangingListener listener) {
+        pageChangingListeners.add(listener);
+    }
+
+    /**
+     * Removes the provided page changing listener from the list of page
+     * changing listeners registered for the dialog.
+     *
+     * @param listener
+     *            a page changing listener
+     * @since 3.3
+     */
+    public void removePageChangingListener(IPageChangingListener listener) {
+        pageChangingListeners.remove(listener);
+    }
+
+    /**
+     * Notifies any page changing listeners that the currently selected dialog
+     * page is changing. Only listeners registered at the time this method is
+     * called are notified.
+     *
+     * @param event
+     *            a selection changing event
+     *
+     * @see IPageChangingListener#handlePageChanging(PageChangingEvent)
+     * @since 3.3
+     */
+    protected void firePageChanging(final PageChangingEvent event) {
+        Object[] listeners = pageChangingListeners.getListeners();
+        for (int i = 0; i < listeners.length; ++i) {
+            final IPageChangingListener l = (IPageChangingListener) listeners[i];
+            SafeRunnable.run(new SafeRunnable() {
+                public void run() {
+                    l.handlePageChanging(event);
+                }
+            });
+        }
+    }
+}
+++/
\ No newline at end of file