changeset 9:6c14e54dfc11

completed /jface/resource/
author Frank Benoit <benoit@tionex.de>
date Sat, 29 Mar 2008 02:25:12 +0100
parents a3ff22a98bef
children b6c35faf97c8
files dwtx/jface/dialogs/TitleAreaDialog.d dwtx/jface/preference/JFacePreferences.d dwtx/jface/preference/PreferenceDialog.d dwtx/jface/resource/AbstractResourceManager.d dwtx/jface/resource/ColorRegistry.d dwtx/jface/resource/CompositeImageDescriptor.d dwtx/jface/resource/DeviceResourceManager.d dwtx/jface/resource/JFaceColors.d dwtx/jface/resource/JFaceResources.d dwtx/jface/resource/LocalResourceManager.d dwtx/jface/resource/ResourceManager.d dwtx/jface/wizard/Wizard.d dwtx/jface/wizard/WizardDialog.d
diffstat 13 files changed, 3773 insertions(+), 59 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/dialogs/TitleAreaDialog.d	Sat Mar 29 02:25:12 2008 +0100
@@ -0,0 +1,638 @@
+/*******************************************************************************
+ * 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
+ *     Konstantin Scheglov <scheglov_ke@nlmk.ru > - Fix for bug 41172
+ *     [Dialogs] Bug with Image in TitleAreaDialog
+ *     Sebastian Davids <sdavids@gmx.de> - Fix for bug 82064
+ *     [Dialogs] TitleAreaDialog#setTitleImage cannot be called before open()
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.dialogs.TitleAreaDialog;
+
+import dwt.dwthelper.utils;
+pragma( msg, "FIXME dwtx.jface.dialogs.TitleAreaDialog" );
+class TitleAreaDialog{
+    public static const String DLG_IMG_TITLE_BANNER = "dialog_title_banner_image";//$NON-NLS-1$
+}
+
+
+/++
+import dwt.DWT;
+import dwt.events.DisposeEvent;
+import dwt.events.DisposeListener;
+import dwt.graphics.Color;
+import dwt.graphics.Image;
+import dwt.graphics.Point;
+import dwt.graphics.RGB;
+import dwt.layout.FormAttachment;
+import dwt.layout.FormData;
+import dwt.layout.FormLayout;
+import dwt.layout.GridData;
+import dwt.layout.GridLayout;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Display;
+import dwt.widgets.Label;
+import dwt.widgets.Shell;
+import dwt.widgets.Text;
+import dwtx.jface.resource.JFaceColors;
+import dwtx.jface.resource.JFaceResources;
+
+/**
+ * A dialog that has a title area for displaying a title and an image as well as
+ * a common area for displaying a description, a message, or an error message.
+ * <p>
+ * This dialog class may be subclassed.
+ */
+public class TitleAreaDialog extends TrayDialog {
+    /**
+     * Image registry key for error message image.
+     */
+    public static final String DLG_IMG_TITLE_ERROR = DLG_IMG_MESSAGE_ERROR;
+
+    /**
+     * Image registry key for banner image (value
+     * <code>"dialog_title_banner_image"</code>).
+     */
+    public static final String DLG_IMG_TITLE_BANNER = "dialog_title_banner_image";//$NON-NLS-1$
+
+    /**
+     * Message type constant used to display an info icon with the message.
+     *
+     * @since 2.0
+     * @deprecated
+     */
+    public final static String INFO_MESSAGE = "INFO_MESSAGE"; //$NON-NLS-1$
+
+    /**
+     * Message type constant used to display a warning icon with the message.
+     *
+     * @since 2.0
+     * @deprecated
+     */
+    public final static String WARNING_MESSAGE = "WARNING_MESSAGE"; //$NON-NLS-1$
+
+    // Space between an image and a label
+    private static final int H_GAP_IMAGE = 5;
+
+    // Minimum dialog width (in dialog units)
+    private static final int MIN_DIALOG_WIDTH = 350;
+
+    // Minimum dialog height (in dialog units)
+    private static final int MIN_DIALOG_HEIGHT = 150;
+
+    private Label titleLabel;
+
+    private Label titleImageLabel;
+
+    private Label bottomFillerLabel;
+
+    private Label leftFillerLabel;
+
+    private RGB titleAreaRGB;
+
+    Color titleAreaColor;
+
+    private String message = ""; //$NON-NLS-1$
+
+    private String errorMessage;
+
+    private Text messageLabel;
+
+    private Composite workArea;
+
+    private Label messageImageLabel;
+
+    private Image messageImage;
+
+    private bool showingError = false;
+
+    private bool titleImageLargest = true;
+
+    private int messageLabelHeight;
+
+    private Image titleAreaImage;
+
+    /**
+     * Instantiate a new title area dialog.
+     *
+     * @param parentShell
+     *            the parent DWT shell
+     */
+    public TitleAreaDialog(Shell parentShell) {
+        super(parentShell);
+    }
+
+    /*
+     * @see Dialog.createContents(Composite)
+     */
+    protected Control createContents(Composite parent) {
+        // create the overall composite
+        Composite contents = new Composite(parent, DWT.NONE);
+        contents.setLayoutData(new GridData(GridData.FILL_BOTH));
+        // initialize the dialog units
+        initializeDialogUnits(contents);
+        FormLayout layout = new FormLayout();
+        contents.setLayout(layout);
+        // Now create a work area for the rest of the dialog
+        workArea = new Composite(contents, DWT.NONE);
+        GridLayout childLayout = new GridLayout();
+        childLayout.marginHeight = 0;
+        childLayout.marginWidth = 0;
+        childLayout.verticalSpacing = 0;
+        workArea.setLayout(childLayout);
+        Control top = createTitleArea(contents);
+        resetWorkAreaAttachments(top);
+        workArea.setFont(JFaceResources.getDialogFont());
+        // initialize the dialog units
+        initializeDialogUnits(workArea);
+        // create the dialog area and button bar
+        dialogArea = createDialogArea(workArea);
+        buttonBar = createButtonBar(workArea);
+        return contents;
+    }
+
+    /**
+     * Creates and returns the contents of the upper part of this dialog (above
+     * the button bar).
+     * <p>
+     * The <code>Dialog</code> implementation of this framework method creates
+     * and returns a new <code>Composite</code> with no margins and spacing.
+     * Subclasses should override.
+     * </p>
+     *
+     * @param parent
+     *            The parent composite to contain the dialog area
+     * @return the dialog area control
+     */
+    protected Control createDialogArea(Composite parent) {
+        // create the top level composite for the dialog area
+        Composite composite = new Composite(parent, DWT.NONE);
+        GridLayout layout = new GridLayout();
+        layout.marginHeight = 0;
+        layout.marginWidth = 0;
+        layout.verticalSpacing = 0;
+        layout.horizontalSpacing = 0;
+        composite.setLayout(layout);
+        composite.setLayoutData(new GridData(GridData.FILL_BOTH));
+        composite.setFont(parent.getFont());
+        // Build the separator line
+        Label titleBarSeparator = new Label(composite, DWT.HORIZONTAL
+                | DWT.SEPARATOR);
+        titleBarSeparator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+        return composite;
+    }
+
+    /**
+     * Creates the dialog's title area.
+     *
+     * @param parent
+     *            the DWT parent for the title area widgets
+     * @return Control with the highest x axis value.
+     */
+    private Control createTitleArea(Composite parent) {
+
+        // add a dispose listener
+        parent.addDisposeListener(new DisposeListener() {
+            public void widgetDisposed(DisposeEvent e) {
+                if (titleAreaColor !is null) {
+                    titleAreaColor.dispose();
+                }
+            }
+        });
+        // Determine the background color of the title bar
+        Display display = parent.getDisplay();
+        Color background;
+        Color foreground;
+        if (titleAreaRGB !is null) {
+            titleAreaColor = new Color(display, titleAreaRGB);
+            background = titleAreaColor;
+            foreground = null;
+        } else {
+            background = JFaceColors.getBannerBackground(display);
+            foreground = JFaceColors.getBannerForeground(display);
+        }
+
+        parent.setBackground(background);
+        int verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
+        int horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
+        // Dialog image @ right
+        titleImageLabel = new Label(parent, DWT.CENTER);
+        titleImageLabel.setBackground(background);
+        if (titleAreaImage is null)
+            titleImageLabel.setImage(JFaceResources
+                    .getImage(DLG_IMG_TITLE_BANNER));
+        else
+            titleImageLabel.setImage(titleAreaImage);
+
+        FormData imageData = new FormData();
+        imageData.top = new FormAttachment(0, 0);
+        // Note: do not use horizontalSpacing on the right as that would be a
+        // regression from
+        // the R2.x style where there was no margin on the right and images are
+        // flush to the right
+        // hand side. see reopened comments in 41172
+        imageData.right = new FormAttachment(100, 0); // horizontalSpacing
+        titleImageLabel.setLayoutData(imageData);
+        // Title label @ top, left
+        titleLabel = new Label(parent, DWT.LEFT);
+        JFaceColors.setColors(titleLabel, foreground, background);
+        titleLabel.setFont(JFaceResources.getBannerFont());
+        titleLabel.setText(" ");//$NON-NLS-1$
+        FormData titleData = new FormData();
+        titleData.top = new FormAttachment(0, verticalSpacing);
+        titleData.right = new FormAttachment(titleImageLabel);
+        titleData.left = new FormAttachment(0, horizontalSpacing);
+        titleLabel.setLayoutData(titleData);
+        // Message image @ bottom, left
+        messageImageLabel = new Label(parent, DWT.CENTER);
+        messageImageLabel.setBackground(background);
+        // Message label @ bottom, center
+        messageLabel = new Text(parent, DWT.WRAP | DWT.READ_ONLY);
+        JFaceColors.setColors(messageLabel, foreground, background);
+        messageLabel.setText(" \n "); // two lines//$NON-NLS-1$
+        messageLabel.setFont(JFaceResources.getDialogFont());
+        messageLabelHeight = messageLabel.computeSize(DWT.DEFAULT, DWT.DEFAULT).y;
+        // Filler labels
+        leftFillerLabel = new Label(parent, DWT.CENTER);
+        leftFillerLabel.setBackground(background);
+        bottomFillerLabel = new Label(parent, DWT.CENTER);
+        bottomFillerLabel.setBackground(background);
+        setLayoutsForNormalMessage(verticalSpacing, horizontalSpacing);
+        determineTitleImageLargest();
+        if (titleImageLargest)
+            return titleImageLabel;
+        return messageLabel;
+    }
+
+    /**
+     * Determine if the title image is larger than the title message and message
+     * area. This is used for layout decisions.
+     */
+    private void determineTitleImageLargest() {
+        int titleY = titleImageLabel.computeSize(DWT.DEFAULT, DWT.DEFAULT).y;
+        int verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
+        int labelY = titleLabel.computeSize(DWT.DEFAULT, DWT.DEFAULT).y;
+        labelY += verticalSpacing;
+        labelY += messageLabelHeight;
+        labelY += verticalSpacing;
+        titleImageLargest = titleY > labelY;
+    }
+
+    /**
+     * Set the layout values for the messageLabel, messageImageLabel and
+     * fillerLabel for the case where there is a normal message.
+     *
+     * @param verticalSpacing
+     *            int The spacing between widgets on the vertical axis.
+     * @param horizontalSpacing
+     *            int The spacing between widgets on the horizontal axis.
+     */
+    private void setLayoutsForNormalMessage(int verticalSpacing,
+            int horizontalSpacing) {
+        FormData messageImageData = new FormData();
+        messageImageData.top = new FormAttachment(titleLabel, verticalSpacing);
+        messageImageData.left = new FormAttachment(0, H_GAP_IMAGE);
+        messageImageLabel.setLayoutData(messageImageData);
+        FormData messageLabelData = new FormData();
+        messageLabelData.top = new FormAttachment(titleLabel, verticalSpacing);
+        messageLabelData.right = new FormAttachment(titleImageLabel);
+        messageLabelData.left = new FormAttachment(messageImageLabel,
+                horizontalSpacing);
+        messageLabelData.height = messageLabelHeight;
+        if (titleImageLargest)
+            messageLabelData.bottom = new FormAttachment(titleImageLabel, 0,
+                    DWT.BOTTOM);
+        messageLabel.setLayoutData(messageLabelData);
+        FormData fillerData = new FormData();
+        fillerData.left = new FormAttachment(0, horizontalSpacing);
+        fillerData.top = new FormAttachment(messageImageLabel, 0);
+        fillerData.bottom = new FormAttachment(messageLabel, 0, DWT.BOTTOM);
+        bottomFillerLabel.setLayoutData(fillerData);
+        FormData data = new FormData();
+        data.top = new FormAttachment(messageImageLabel, 0, DWT.TOP);
+        data.left = new FormAttachment(0, 0);
+        data.bottom = new FormAttachment(messageImageLabel, 0, DWT.BOTTOM);
+        data.right = new FormAttachment(messageImageLabel, 0);
+        leftFillerLabel.setLayoutData(data);
+    }
+
+    /**
+     * The <code>TitleAreaDialog</code> implementation of this
+     * <code>Window</code> methods returns an initial size which is at least
+     * some reasonable minimum.
+     *
+     * @return the initial size of the dialog
+     */
+    protected Point getInitialSize() {
+        Point shellSize = super.getInitialSize();
+        return new Point(Math.max(
+                convertHorizontalDLUsToPixels(MIN_DIALOG_WIDTH), shellSize.x),
+                Math.max(convertVerticalDLUsToPixels(MIN_DIALOG_HEIGHT),
+                        shellSize.y));
+    }
+
+    /**
+     * Retained for backward compatibility.
+     *
+     * Returns the title area composite. There is no composite in this
+     * implementation so the shell is returned.
+     *
+     * @return Composite
+     * @deprecated
+     */
+    protected Composite getTitleArea() {
+        return getShell();
+    }
+
+    /**
+     * Returns the title image label.
+     *
+     * @return the title image label
+     */
+    protected Label getTitleImageLabel() {
+        return titleImageLabel;
+    }
+
+    /**
+     * Display the given error message. The currently displayed message is saved
+     * and will be redisplayed when the error message is set to
+     * <code>null</code>.
+     *
+     * @param newErrorMessage
+     *            the newErrorMessage to display or <code>null</code>
+     */
+    public void setErrorMessage(String newErrorMessage) {
+        // Any change?
+        if (errorMessage is null ? newErrorMessage is null : errorMessage
+                .equals(newErrorMessage))
+            return;
+        errorMessage = newErrorMessage;
+
+        // Clear or set error message.
+        if (errorMessage is null) {
+            if (showingError) {
+                // we were previously showing an error
+                showingError = false;
+            }
+            // show the message
+            // avoid calling setMessage in case it is overridden to call
+            // setErrorMessage,
+            // which would result in a recursive infinite loop
+            if (message is null) // this should probably never happen since
+                // setMessage does this conversion....
+                message = ""; //$NON-NLS-1$
+            updateMessage(message);
+            messageImageLabel.setImage(messageImage);
+            setImageLabelVisible(messageImage !is null);
+        } else {
+            // Add in a space for layout purposes but do not
+            // change the instance variable
+            String displayedErrorMessage = " " + errorMessage; //$NON-NLS-1$
+            updateMessage(displayedErrorMessage);
+            if (!showingError) {
+                // we were not previously showing an error
+                showingError = true;
+                messageImageLabel.setImage(JFaceResources
+                        .getImage(DLG_IMG_TITLE_ERROR));
+                setImageLabelVisible(true);
+            }
+        }
+        layoutForNewMessage();
+    }
+
+    /**
+     * Re-layout the labels for the new message.
+     */
+    private void layoutForNewMessage() {
+        int verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
+        int horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
+        // If there are no images then layout as normal
+        if (errorMessage is null && messageImage is null) {
+            setImageLabelVisible(false);
+            setLayoutsForNormalMessage(verticalSpacing, horizontalSpacing);
+        } else {
+            messageImageLabel.setVisible(true);
+            bottomFillerLabel.setVisible(true);
+            leftFillerLabel.setVisible(true);
+            /**
+             * Note that we do not use horizontalSpacing here as when the
+             * background of the messages changes there will be gaps between the
+             * icon label and the message that are the background color of the
+             * shell. We add a leading space elsewhere to compendate for this.
+             */
+            FormData data = new FormData();
+            data.left = new FormAttachment(0, H_GAP_IMAGE);
+            data.top = new FormAttachment(titleLabel, verticalSpacing);
+            messageImageLabel.setLayoutData(data);
+            data = new FormData();
+            data.top = new FormAttachment(messageImageLabel, 0);
+            data.left = new FormAttachment(0, 0);
+            data.bottom = new FormAttachment(messageLabel, 0, DWT.BOTTOM);
+            data.right = new FormAttachment(messageImageLabel, 0, DWT.RIGHT);
+            bottomFillerLabel.setLayoutData(data);
+            data = new FormData();
+            data.top = new FormAttachment(messageImageLabel, 0, DWT.TOP);
+            data.left = new FormAttachment(0, 0);
+            data.bottom = new FormAttachment(messageImageLabel, 0, DWT.BOTTOM);
+            data.right = new FormAttachment(messageImageLabel, 0);
+            leftFillerLabel.setLayoutData(data);
+            FormData messageLabelData = new FormData();
+            messageLabelData.top = new FormAttachment(titleLabel,
+                    verticalSpacing);
+            messageLabelData.right = new FormAttachment(titleImageLabel);
+            messageLabelData.left = new FormAttachment(messageImageLabel, 0);
+            messageLabelData.height = messageLabelHeight;
+            if (titleImageLargest)
+                messageLabelData.bottom = new FormAttachment(titleImageLabel,
+                        0, DWT.BOTTOM);
+            messageLabel.setLayoutData(messageLabelData);
+        }
+        // Do not layout before the dialog area has been created
+        // to avoid incomplete calculations.
+        if (dialogArea !is null)
+            workArea.getParent().layout(true);
+    }
+
+    /**
+     * Set the message text. If the message line currently displays an error,
+     * the message is saved and will be redisplayed when the error message is
+     * set to <code>null</code>.
+     * <p>
+     * Shortcut for <code>setMessage(newMessage, IMessageProvider.NONE)</code>
+     * </p>
+     * This method should be called after the dialog has been opened as it
+     * updates the message label immediately.
+     *
+     * @param newMessage
+     *            the message, or <code>null</code> to clear the message
+     */
+    public void setMessage(String newMessage) {
+        setMessage(newMessage, IMessageProvider.NONE);
+    }
+
+    /**
+     * Sets the message for this dialog with an indication of what type of
+     * message it is.
+     * <p>
+     * The valid message types are one of <code>NONE</code>,
+     * <code>INFORMATION</code>,<code>WARNING</code>, or
+     * <code>ERROR</code>.
+     * </p>
+     * <p>
+     * Note that for backward compatibility, a message of type
+     * <code>ERROR</code> is different than an error message (set using
+     * <code>setErrorMessage</code>). An error message overrides the current
+     * message until the error message is cleared. This method replaces the
+     * current message and does not affect the error message.
+     * </p>
+     *
+     * @param newMessage
+     *            the message, or <code>null</code> to clear the message
+     * @param newType
+     *            the message type
+     * @since 2.0
+     */
+    public void setMessage(String newMessage, int newType) {
+        Image newImage = null;
+        if (newMessage !is null) {
+            switch (newType) {
+            case IMessageProvider.NONE:
+                break;
+            case IMessageProvider.INFORMATION:
+                newImage = JFaceResources.getImage(DLG_IMG_MESSAGE_INFO);
+                break;
+            case IMessageProvider.WARNING:
+                newImage = JFaceResources.getImage(DLG_IMG_MESSAGE_WARNING);
+                break;
+            case IMessageProvider.ERROR:
+                newImage = JFaceResources.getImage(DLG_IMG_MESSAGE_ERROR);
+                break;
+            }
+        }
+        showMessage(newMessage, newImage);
+    }
+
+    /**
+     * Show the new message and image.
+     *
+     * @param newMessage
+     * @param newImage
+     */
+    private void showMessage(String newMessage, Image newImage) {
+        // Any change?
+        if (message.equals(newMessage) && messageImage is newImage) {
+            return;
+        }
+        message = newMessage;
+        if (message is null)
+            message = "";//$NON-NLS-1$
+        // Message string to be shown - if there is an image then add in
+        // a space to the message for layout purposes
+        String shownMessage = (newImage is null) ? message : " " + message; //$NON-NLS-1$
+        messageImage = newImage;
+        if (!showingError) {
+            // we are not showing an error
+            updateMessage(shownMessage);
+            messageImageLabel.setImage(messageImage);
+            setImageLabelVisible(messageImage !is null);
+            layoutForNewMessage();
+        }
+    }
+
+    /**
+     * Update the contents of the messageLabel.
+     *
+     * @param newMessage
+     *            the message to use
+     */
+    private void updateMessage(String newMessage) {
+        messageLabel.setText(newMessage);
+    }
+
+    /**
+     * Sets the title to be shown in the title area of this dialog.
+     *
+     * @param newTitle
+     *            the title show
+     */
+    public void setTitle(String newTitle) {
+        if (titleLabel is null)
+            return;
+        String title = newTitle;
+        if (title is null)
+            title = "";//$NON-NLS-1$
+        titleLabel.setText(title);
+    }
+
+    /**
+     * Sets the title bar color for this dialog.
+     *
+     * @param color
+     *            the title bar color
+     */
+    public void setTitleAreaColor(RGB color) {
+        titleAreaRGB = color;
+    }
+
+    /**
+     * Sets the title image to be shown in the title area of this dialog.
+     *
+     * @param newTitleImage
+     *            the title image to be shown
+     */
+    public void setTitleImage(Image newTitleImage) {
+
+        titleAreaImage = newTitleImage;
+        if (titleImageLabel !is null) {
+            titleImageLabel.setImage(newTitleImage);
+            titleImageLabel.setVisible(newTitleImage !is null);
+            if (newTitleImage !is null) {
+                determineTitleImageLargest();
+                Control top;
+                if (titleImageLargest)
+                    top = titleImageLabel;
+                else
+                    top = messageLabel;
+                resetWorkAreaAttachments(top);
+            }
+        }
+    }
+
+    /**
+     * Make the label used for displaying error images visible depending on
+     * bool.
+     *
+     * @param visible
+     *            If <code>true</code> make the image visible, if not then
+     *            make it not visible.
+     */
+    private void setImageLabelVisible(bool visible) {
+        messageImageLabel.setVisible(visible);
+        bottomFillerLabel.setVisible(visible);
+        leftFillerLabel.setVisible(visible);
+    }
+
+    /**
+     * Reset the attachment of the workArea to now attach to top as the top
+     * control.
+     *
+     * @param top
+     */
+    private void resetWorkAreaAttachments(Control top) {
+        FormData childData = new FormData();
+        childData.top = new FormAttachment(top);
+        childData.right = new FormAttachment(100, 0);
+        childData.left = new FormAttachment(0, 0);
+        childData.bottom = new FormAttachment(100, 0);
+        workArea.setLayoutData(childData);
+    }
+}
+++/
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/preference/JFacePreferences.d	Sat Mar 29 02:25:12 2008 +0100
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * 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.preference.JFacePreferences;
+
+import dwtx.jface.preference.IPreferenceStore;
+
+import dwt.dwthelper.utils;
+
+/**
+ *
+ * JFacePreferences is a class used to administer the preferences
+ * used by JFace objects.
+ */
+public final class JFacePreferences {
+
+    /**
+     * Identifier for the Error Color
+     */
+    public static const String ERROR_COLOR = "ERROR_COLOR"; //$NON-NLS-1$
+
+    /**
+     * Identifier for the Hyperlink Color
+     */
+    public static const String HYPERLINK_COLOR = "HYPERLINK_COLOR"; //$NON-NLS-1$
+
+    /**
+     * Identifier for the Active Hyperlink Colour
+     */
+    public static const String ACTIVE_HYPERLINK_COLOR = "ACTIVE_HYPERLINK_COLOR"; //$NON-NLS-1$
+
+    private static IPreferenceStore preferenceStore;
+
+    /**
+     * Prevent construction.
+     */
+    private this() {
+    }
+
+    /**
+     * Return the preference store for the receiver.
+     * @return IPreferenceStore or null
+     */
+    public static IPreferenceStore getPreferenceStore() {
+        return preferenceStore;
+    }
+
+    /**
+     * Set the preference store for the receiver.
+     * @param store IPreferenceStore
+     */
+    public static void setPreferenceStore(IPreferenceStore store) {
+        preferenceStore = store;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/preference/PreferenceDialog.d	Sat Mar 29 02:25:12 2008 +0100
@@ -0,0 +1,1518 @@
+/*******************************************************************************
+ * 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
+ *     Teddy Walker <teddy.walker@googlemail.com>
+ *      - Bug 188056 [Preferences] PreferencePages have to less indent in PreferenceDialog
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.preference.PreferenceDialog;
+
+import dwt.dwthelper.utils;
+
+pragma( msg, "FIXME dwtx.jface.preference.PreferenceDialog" );
+class PreferenceDialog{
+    public static const String PREF_DLG_TITLE_IMG = "preference_dialog_title_image"; //$NON-NLS-1$
+}
+
+/++
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+
+import dwt.DWT;
+import dwt.custom.BusyIndicator;
+import dwt.custom.ScrolledComposite;
+import dwt.events.ControlAdapter;
+import dwt.events.ControlEvent;
+import dwt.events.DisposeEvent;
+import dwt.events.DisposeListener;
+import dwt.events.HelpEvent;
+import dwt.events.HelpListener;
+import dwt.events.SelectionAdapter;
+import dwt.events.SelectionEvent;
+import dwt.events.ShellAdapter;
+import dwt.events.ShellEvent;
+import dwt.graphics.Font;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.layout.FormAttachment;
+import dwt.layout.FormData;
+import dwt.layout.FormLayout;
+import dwt.layout.GridData;
+import dwt.layout.GridLayout;
+import dwt.widgets.Button;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Event;
+import dwt.widgets.Label;
+import dwt.widgets.Layout;
+import dwt.widgets.Listener;
+import dwt.widgets.Sash;
+import dwt.widgets.Shell;
+import dwt.widgets.Tree;
+import dwtx.core.runtime.Assert;
+import dwtx.core.runtime.ISafeRunnable;
+import dwtx.core.runtime.IStatus;
+import dwtx.core.runtime.ListenerList;
+import dwtx.core.runtime.SafeRunner;
+import dwtx.core.runtime.Status;
+import dwtx.jface.dialogs.DialogMessageArea;
+import dwtx.jface.dialogs.IDialogConstants;
+import dwtx.jface.dialogs.IMessageProvider;
+import dwtx.jface.dialogs.IPageChangeProvider;
+import dwtx.jface.dialogs.IPageChangedListener;
+import dwtx.jface.dialogs.MessageDialog;
+import dwtx.jface.dialogs.PageChangedEvent;
+import dwtx.jface.dialogs.TrayDialog;
+import dwtx.jface.resource.JFaceResources;
+import dwtx.jface.util.IPropertyChangeListener;
+import dwtx.jface.util.Policy;
+import dwtx.jface.util.PropertyChangeEvent;
+import dwtx.jface.util.SafeRunnable;
+import dwtx.jface.viewers.ISelection;
+import dwtx.jface.viewers.ISelectionChangedListener;
+import dwtx.jface.viewers.IStructuredSelection;
+import dwtx.jface.viewers.SelectionChangedEvent;
+import dwtx.jface.viewers.StructuredSelection;
+import dwtx.jface.viewers.TreeViewer;
+import dwtx.jface.viewers.ViewerFilter;
+
+/**
+ * A preference dialog is a hierarchical presentation of preference pages. Each
+ * page is represented by a node in the tree shown on the left hand side of the
+ * dialog; when a node is selected, the corresponding page is shown on the right
+ * hand side.
+ */
+public class PreferenceDialog extends TrayDialog implements IPreferencePageContainer, IPageChangeProvider {
+    /**
+     * Layout for the page container.
+     *
+     */
+    private class PageLayout extends 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);
+            }
+            int x = minimumPageSize.x;
+            int y = minimumPageSize.y;
+            Control[] children = composite.getChildren();
+            for (int i = 0; i < children.length; i++) {
+                Point size = children[i].computeSize(DWT.DEFAULT, DWT.DEFAULT, force);
+                x = Math.max(x, size.x);
+                y = Math.max(y, size.y);
+            }
+
+            //As pages can implement thier own computeSize
+            //take it into account
+            if(currentPage !is null){
+                Point size = currentPage.computeSize();
+                x = Math.max(x, size.x);
+                y = Math.max(y, size.y);
+            }
+
+            if (wHint !is DWT.DEFAULT) {
+                x = wHint;
+            }
+            if (hHint !is DWT.DEFAULT) {
+                y = hHint;
+            }
+            return new Point(x, y);
+        }
+
+        public void layout(Composite composite, bool force) {
+            Rectangle rect = composite.getClientArea();
+            Control[] children = composite.getChildren();
+            for (int i = 0; i < children.length; i++) {
+                children[i].setSize(rect.width, rect.height);
+            }
+        }
+    }
+
+    //The id of the last page that was selected
+    private static String lastPreferenceId = null;
+
+    //The last known tree width
+    private static int lastTreeWidth = 180;
+
+    /**
+     * Indentifier for the error image
+     */
+    public static final String PREF_DLG_IMG_TITLE_ERROR = DLG_IMG_MESSAGE_ERROR;
+
+    /**
+     * Title area fields
+     */
+    public static final String PREF_DLG_TITLE_IMG = "preference_dialog_title_image"; //$NON-NLS-1$
+
+    /**
+     * Return code used when dialog failed
+     */
+    protected static final int FAILED = 2;
+
+    /**
+     * The current preference page, or <code>null</code> if there is none.
+     */
+    private IPreferencePage currentPage;
+
+    private DialogMessageArea messageArea;
+
+    private Point lastShellSize;
+
+    private IPreferenceNode lastSuccessfulNode;
+
+    /**
+     * The minimum page size; 400 by 400 by default.
+     *
+     * @see #setMinimumPageSize(Point)
+     */
+    private Point minimumPageSize = new Point(400, 400);
+
+    /**
+     * The OK button.
+     */
+    private Button okButton;
+
+    /**
+     * The Composite in which a page is shown.
+     */
+    private Composite pageContainer;
+
+    /**
+     * The preference manager.
+     */
+    private PreferenceManager preferenceManager;
+
+    /**
+     * Flag for the presence of the error message.
+     */
+    private bool showingError = false;
+
+    /**
+     * Preference store, initially <code>null</code> meaning none.
+     *
+     * @see #setPreferenceStore
+     */
+    private IPreferenceStore preferenceStore;
+
+    private Composite titleArea;
+
+    /**
+     * The tree viewer.
+     */
+    private TreeViewer treeViewer;
+
+    private ListenerList pageChangedListeners = new ListenerList();
+
+    /**
+     *  Composite with a FormLayout to contain the title area
+     */
+    Composite formTitleComposite;
+
+    private ScrolledComposite scrolled;
+
+    /**
+     * Creates a new preference dialog under the control of the given preference
+     * manager.
+     *
+     * @param parentShell
+     *            the parent shell
+     * @param manager
+     *            the preference manager
+     */
+    public PreferenceDialog(Shell parentShell, PreferenceManager manager) {
+        super(parentShell);
+        setShellStyle(getShellStyle() | DWT.RESIZE | DWT.MAX);
+        preferenceManager = manager;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwtx.jface.dialogs.Dialog#buttonPressed(int)
+     */
+    protected void buttonPressed(int buttonId) {
+        switch (buttonId) {
+        case IDialogConstants.OK_ID: {
+            okPressed();
+            return;
+        }
+        case IDialogConstants.CANCEL_ID: {
+            cancelPressed();
+            return;
+        }
+        case IDialogConstants.HELP_ID: {
+            helpPressed();
+            return;
+        }
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwtx.jface.dialogs.Dialog#cancelPressed()
+     */
+    protected void cancelPressed() {
+        // Inform all pages that we are cancelling
+        Iterator nodes = preferenceManager.getElements(PreferenceManager.PRE_ORDER).iterator();
+        while (nodes.hasNext()) {
+            final IPreferenceNode node = (IPreferenceNode) nodes.next();
+            if (getPage(node) !is null) {
+                SafeRunnable.run(new SafeRunnable() {
+                    public void run() {
+                        if (!getPage(node).performCancel()) {
+                            return;
+                        }
+                    }
+                });
+            }
+        }
+        setReturnCode(CANCEL);
+        close();
+    }
+
+    /**
+     * Clear the last selected node. This is so that we not chache the last
+     * selection in case of an error.
+     */
+    void clearSelectedNode() {
+        setSelectedNodePreference(null);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwtx.jface.window.Window#close()
+     */
+    public bool close() {
+
+        //Do this is in a SafeRunnable as it may run client code
+        SafeRunnable runnable = new SafeRunnable(){
+            /* (non-Javadoc)
+             * @see dwtx.core.runtime.ISafeRunnable#run()
+             */
+            public void run() throws Exception {
+                List nodes = preferenceManager.getElements(PreferenceManager.PRE_ORDER);
+                for (int i = 0; i < nodes.size(); i++) {
+                    IPreferenceNode node = (IPreferenceNode) nodes.get(i);
+                    node.disposeResources();
+                }
+
+            }
+
+            /* (non-Javadoc)
+             * @see dwtx.jface.util.SafeRunnable#handleException(java.lang.Throwable)
+             */
+            public void handleException(Throwable e) {
+                super.handleException(e);
+                clearSelectedNode();//Do not cache a node with problems
+            }
+        };
+
+        SafeRunner.run(runnable);
+
+        return super.close();
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwtx.jface.window.Window#configureShell(dwt.widgets.Shell)
+     */
+    protected void configureShell(Shell newShell) {
+        super.configureShell(newShell);
+        newShell.setText(JFaceResources.getString("PreferenceDialog.title")); //$NON-NLS-1$
+        newShell.addShellListener(new ShellAdapter() {
+            public void shellActivated(ShellEvent e) {
+                if (lastShellSize is null) {
+                    lastShellSize = getShell().getSize();
+                }
+            }
+
+        });
+
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwtx.jface.window.Window#constrainShellSize()
+     */
+    protected void constrainShellSize() {
+        super.constrainShellSize();
+        // record opening shell size
+        if (lastShellSize is null) {
+            lastShellSize = getShell().getSize();
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwtx.jface.dialogs.Dialog#createButtonsForButtonBar(dwt.widgets.Composite)
+     */
+    protected void createButtonsForButtonBar(Composite parent) {
+        // create OK and Cancel buttons by default
+        okButton = createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
+        getShell().setDefaultButton(okButton);
+        createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwtx.jface.window.Window#createContents(dwt.widgets.Composite)
+     */
+    protected Control createContents(final Composite parent) {
+        final Control[] control = new Control[1];
+        BusyIndicator.showWhile(getShell().getDisplay(), new Runnable() {
+            public void run() {
+                control[0] = PreferenceDialog.super.createContents(parent);
+                // Add the first page
+                selectSavedItem();
+            }
+        });
+
+        return control[0];
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwtx.jface.dialogs.Dialog#createDialogArea(dwt.widgets.Composite)
+     */
+    protected Control createDialogArea(Composite parent) {
+        final Composite composite = (Composite) super.createDialogArea(parent);
+        GridLayout parentLayout = ((GridLayout) composite.getLayout());
+        parentLayout.numColumns = 4;
+        parentLayout.marginHeight = 0;
+        parentLayout.marginWidth = 0;
+        parentLayout.verticalSpacing = 0;
+        parentLayout.horizontalSpacing = 0;
+
+        composite.setBackground(parent.getDisplay().getSystemColor(DWT.COLOR_LIST_BACKGROUND));
+
+        Control treeControl = createTreeAreaContents(composite);
+        createSash(composite,treeControl);
+
+        Label versep = new Label(composite, DWT.SEPARATOR | DWT.VERTICAL);
+        GridData verGd = new GridData(GridData.FILL_VERTICAL | GridData.GRAB_VERTICAL);
+
+        versep.setLayoutData(verGd);
+        versep.setLayoutData(new GridData(DWT.LEFT, DWT.FILL, false, true));
+
+        Composite pageAreaComposite = new Composite(composite, DWT.NONE);
+        pageAreaComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
+        GridLayout layout = new GridLayout(1, true);
+        layout.marginHeight = 0;
+        layout.marginWidth = 0;
+        layout.verticalSpacing = 0;
+        pageAreaComposite.setLayout(layout);
+
+        formTitleComposite = new Composite(pageAreaComposite, DWT.NONE);
+        FormLayout titleLayout = new FormLayout();
+        titleLayout.marginWidth = 0;
+        titleLayout.marginHeight = 0;
+        formTitleComposite.setLayout(titleLayout);
+
+        GridData titleGridData = new GridData(GridData.FILL_HORIZONTAL);
+        titleGridData.horizontalIndent = IDialogConstants.HORIZONTAL_MARGIN;
+        formTitleComposite.setLayoutData(titleGridData);
+
+        // Build the title area and separator line
+        Composite titleComposite = new Composite(formTitleComposite, DWT.NONE);
+        layout = new GridLayout();
+        layout.marginBottom = 5;
+        layout.marginHeight = 0;
+        layout.marginWidth = 0;
+        layout.horizontalSpacing = 0;
+        titleComposite.setLayout(layout);
+
+        FormData titleFormData = new FormData();
+        titleFormData.top = new FormAttachment(0,0);
+        titleFormData.left = new FormAttachment(0,0);
+        titleFormData.right = new FormAttachment(100,0);
+        titleFormData.bottom = new FormAttachment(100,0);
+
+        titleComposite.setLayoutData(titleFormData);
+        createTitleArea(titleComposite);
+
+        Label separator = new Label(pageAreaComposite, DWT.HORIZONTAL | DWT.SEPARATOR);
+
+        separator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL));
+
+
+        // Build the Page container
+        pageContainer = createPageContainer(pageAreaComposite);
+        GridData pageContainerData = new GridData(GridData.FILL_BOTH);
+        pageContainerData.horizontalIndent = IDialogConstants.HORIZONTAL_MARGIN;
+        pageContainer.setLayoutData(pageContainerData);
+        // Build the separator line
+        Label bottomSeparator = new Label(parent, DWT.HORIZONTAL | DWT.SEPARATOR);
+        bottomSeparator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL));
+        return composite;
+    }
+
+    /**
+     * Create the sash with right control on the right. Note
+     * that this method assumes GridData for the layout data
+     * of the rightControl.
+     * @param composite
+     * @param rightControl
+     * @return Sash
+     *
+     * @since 3.1
+     */
+    protected Sash createSash(final Composite composite, final Control rightControl) {
+        final Sash sash = new Sash(composite, DWT.VERTICAL);
+        sash.setLayoutData(new GridData(GridData.FILL_VERTICAL));
+        sash.setBackground(composite.getDisplay().getSystemColor(DWT.COLOR_LIST_BACKGROUND));
+        // the following listener resizes the tree control based on sash deltas.
+        // If necessary, it will also grow/shrink the dialog.
+        sash.addListener(DWT.Selection, new Listener() {
+            /*
+             * (non-Javadoc)
+             *
+             * @see dwt.widgets.Listener#handleEvent(dwt.widgets.Event)
+             */
+            public void handleEvent(Event event) {
+                if (event.detail is DWT.DRAG) {
+                    return;
+                }
+                int shift = event.x - sash.getBounds().x;
+                GridData data = (GridData) rightControl.getLayoutData();
+                int newWidthHint = data.widthHint + shift;
+                if (newWidthHint < 20) {
+                    return;
+                }
+                Point computedSize = getShell().computeSize(DWT.DEFAULT, DWT.DEFAULT);
+                Point currentSize = getShell().getSize();
+                // if the dialog wasn't of a custom size we know we can shrink
+                // it if necessary based on sash movement.
+                bool customSize = !computedSize.equals(currentSize);
+                data.widthHint = newWidthHint;
+                setLastTreeWidth(newWidthHint);
+                composite.layout(true);
+                // recompute based on new widget size
+                computedSize = getShell().computeSize(DWT.DEFAULT, DWT.DEFAULT);
+                // if the dialog was of a custom size then increase it only if
+                // necessary.
+                if (customSize) {
+                    computedSize.x = Math.max(computedSize.x, currentSize.x);
+                }
+                computedSize.y = Math.max(computedSize.y, currentSize.y);
+                if (computedSize.equals(currentSize)) {
+                    return;
+                }
+                setShellSize(computedSize.x, computedSize.y);
+                lastShellSize = getShell().getSize();
+            }
+        });
+        return sash;
+    }
+
+    /**
+     * Creates the inner page container.
+     *
+     * @param parent
+     * @return Composite
+     */
+    protected Composite createPageContainer(Composite parent) {
+
+        Composite outer = new Composite(parent, DWT.NONE);
+
+        GridData outerData = new GridData(GridData.FILL_BOTH | GridData.GRAB_HORIZONTAL
+                | GridData.GRAB_VERTICAL);
+        outerData.horizontalIndent = IDialogConstants.HORIZONTAL_MARGIN;
+
+        outer.setLayout(new GridLayout());
+        outer.setLayoutData(outerData);
+
+        //Create an outer composite for spacing
+        scrolled = new ScrolledComposite(outer, DWT.V_SCROLL | DWT.H_SCROLL);
+
+        scrolled.setExpandHorizontal(true);
+        scrolled.setExpandVertical(true);
+
+        GridData scrolledData = new GridData(GridData.FILL_BOTH | GridData.GRAB_HORIZONTAL
+                | GridData.GRAB_VERTICAL);
+
+        scrolled.setLayoutData(scrolledData);
+
+        Composite result = new Composite(scrolled, DWT.NONE);
+
+        GridData resultData = new GridData(GridData.FILL_BOTH | GridData.GRAB_HORIZONTAL
+                | GridData.GRAB_VERTICAL);
+
+        result.setLayout(getPageLayout());
+        result.setLayoutData(resultData);
+
+        scrolled.setContent(result);
+
+        return result;
+    }
+
+    /**
+     * Return the layout for the composite that contains
+     * the pages.
+     * @return PageLayout
+     *
+     * @since 3.1
+     */
+    protected Layout getPageLayout() {
+        return new PageLayout();
+    }
+
+    /**
+     * Creates the wizard's title area.
+     *
+     * @param parent
+     *            the DWT parent for the title area composite.
+     * @return the created title area composite.
+     */
+    protected Composite createTitleArea(Composite parent) {
+        // Create the title area which will contain
+        // a title, message, and image.
+        int margins = 2;
+        titleArea = new Composite(parent, DWT.NONE);
+        FormLayout layout = new FormLayout();
+        layout.marginHeight = 0;
+        layout.marginWidth = margins;
+        titleArea.setLayout(layout);
+
+
+        GridData layoutData = new GridData(GridData.FILL_HORIZONTAL);
+        layoutData.verticalAlignment = DWT.TOP;
+        titleArea.setLayoutData(layoutData);
+
+        // Message label
+        messageArea = new DialogMessageArea();
+        messageArea.createContents(titleArea);
+
+        titleArea.addControlListener(new ControlAdapter() {
+            /* (non-Javadoc)
+             * @see dwt.events.ControlAdapter#controlResized(dwt.events.ControlEvent)
+             */
+            public void controlResized(ControlEvent e) {
+                updateMessage();
+            }
+        });
+
+        final IPropertyChangeListener fontListener = new IPropertyChangeListener() {
+            public void propertyChange(PropertyChangeEvent event) {
+                if (JFaceResources.BANNER_FONT.equals(event.getProperty())) {
+                    updateMessage();
+                }
+                if (JFaceResources.DIALOG_FONT.equals(event.getProperty())) {
+                    updateMessage();
+                    Font dialogFont = JFaceResources.getDialogFont();
+                    updateTreeFont(dialogFont);
+                    Control[] children = ((Composite) buttonBar).getChildren();
+                    for (int i = 0; i < children.length; i++) {
+                        children[i].setFont(dialogFont);
+                    }
+                }
+            }
+        };
+
+        titleArea.addDisposeListener(new DisposeListener() {
+            public void widgetDisposed(DisposeEvent event) {
+                JFaceResources.getFontRegistry().removeListener(fontListener);
+            }
+        });
+        JFaceResources.getFontRegistry().addListener(fontListener);
+        messageArea.setTitleLayoutData(createMessageAreaData());
+        messageArea.setMessageLayoutData(createMessageAreaData());
+        return titleArea;
+    }
+
+    /**
+     * Create the layout data for the message area.
+     *
+     * @return FormData for the message area.
+     */
+    private FormData createMessageAreaData() {
+        FormData messageData = new FormData();
+        messageData.top = new FormAttachment(0);
+        messageData.bottom = new FormAttachment(100);
+        messageData.right = new FormAttachment(100);
+        messageData.left = new FormAttachment(0);
+        return messageData;
+    }
+
+    /**
+     * @param parent
+     *            the DWT parent for the tree area controls.
+     * @return the new <code>Control</code>.
+     * @since 3.0
+     */
+    protected Control createTreeAreaContents(Composite parent) {
+        // Build the tree an put it into the composite.
+        treeViewer = createTreeViewer(parent);
+        treeViewer.setInput(getPreferenceManager());
+        updateTreeFont(JFaceResources.getDialogFont());
+        layoutTreeAreaControl(treeViewer.getControl());
+        return treeViewer.getControl();
+    }
+
+    /**
+     * Create a new <code>TreeViewer</code>.
+     *
+     * @param parent
+     *            the parent <code>Composite</code>.
+     * @return the <code>TreeViewer</code>.
+     * @since 3.0
+     */
+    protected TreeViewer createTreeViewer(Composite parent) {
+        final TreeViewer viewer = new TreeViewer(parent, DWT.NONE);
+        addListeners(viewer);
+        viewer.setLabelProvider(new PreferenceLabelProvider());
+        viewer.setContentProvider(new PreferenceContentProvider());
+        return viewer;
+    }
+
+    /**
+     * Add the listeners to the tree viewer.
+     * @param viewer
+     *
+     * @since 3.1
+     */
+    protected void addListeners(final TreeViewer viewer) {
+        viewer.addPostSelectionChangedListener(new ISelectionChangedListener() {
+            private void handleError() {
+                try {
+                    // remove the listener temporarily so that the events caused
+                    // by the error handling dont further cause error handling
+                    // to occur.
+                    viewer.removePostSelectionChangedListener(this);
+                    showPageFlippingAbortDialog();
+                    selectCurrentPageAgain();
+                    clearSelectedNode();
+                } finally {
+                    viewer.addPostSelectionChangedListener(this);
+                }
+            }
+
+            public void selectionChanged(SelectionChangedEvent event) {
+                Object selection = getSingleSelection(event.getSelection());
+                if (selection instanceof IPreferenceNode) {
+                    if (!isCurrentPageValid()) {
+                        handleError();
+                    } else if (!showPage((IPreferenceNode) selection)) {
+                        // Page flipping wasn't successful
+                        handleError();
+                    } else {
+                        // Everything went well
+                        lastSuccessfulNode = (IPreferenceNode) selection;
+                    }
+                }
+            }
+        });
+        ((Tree) viewer.getControl()).addSelectionListener(new SelectionAdapter() {
+            public void widgetDefaultSelected(final SelectionEvent event) {
+                ISelection selection = viewer.getSelection();
+                if (selection.isEmpty()) {
+                    return;
+                }
+                IPreferenceNode singleSelection = getSingleSelection(selection);
+                bool expanded = viewer.getExpandedState(singleSelection);
+                viewer.setExpandedState(singleSelection, !expanded);
+            }
+        });
+        //Register help listener on the tree to use context sensitive help
+        viewer.getControl().addHelpListener(new HelpListener() {
+            public void helpRequested(HelpEvent event) {
+                // call perform help on the current page
+                if (currentPage !is null) {
+                    currentPage.performHelp();
+                }
+            }
+        });
+    }
+
+    /**
+     * Find the <code>IPreferenceNode</code> that has data the same id as the
+     * supplied value.
+     *
+     * @param nodeId
+     *            the id to search for.
+     * @return <code>IPreferenceNode</code> or <code>null</code> if not
+     *         found.
+     */
+    protected IPreferenceNode findNodeMatching(String nodeId) {
+        List nodes = preferenceManager.getElements(PreferenceManager.POST_ORDER);
+        for (Iterator i = nodes.iterator(); i.hasNext();) {
+            IPreferenceNode node = (IPreferenceNode) i.next();
+            if (node.getId().equals(nodeId)) {
+                return node;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Get the last known right side width.
+     *
+     * @return the width.
+     */
+    protected int getLastRightWidth() {
+        return lastTreeWidth;
+    }
+
+    /**
+     * Returns the preference mananger used by this preference dialog.
+     *
+     * @return the preference mananger
+     */
+    public PreferenceManager getPreferenceManager() {
+        return preferenceManager;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwtx.jface.preference.IPreferencePageContainer#getPreferenceStore()
+     */
+    public IPreferenceStore getPreferenceStore() {
+        return preferenceStore;
+    }
+
+    /**
+     * Get the name of the selected item preference
+     *
+     * @return String
+     */
+    protected String getSelectedNodePreference() {
+        return lastPreferenceId;
+    }
+
+    /**
+     * @param selection
+     *            the <code>ISelection</code> to examine.
+     * @return the first element, or null if empty.
+     */
+    protected IPreferenceNode getSingleSelection(ISelection selection) {
+        if (!selection.isEmpty()) {
+            IStructuredSelection structured = (IStructuredSelection) selection;
+            if (structured.getFirstElement() instanceof IPreferenceNode) {
+                return (IPreferenceNode) structured.getFirstElement();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @return the <code>TreeViewer</code> for this dialog.
+     * @since 3.3
+     */
+    public TreeViewer getTreeViewer() {
+        return treeViewer;
+    }
+
+    /**
+     * Save the values specified in the pages.
+     * <p>
+     * The default implementation of this framework method saves all pages of
+     * type <code>PreferencePage</code> (if their store needs saving and is a
+     * <code>PreferenceStore</code>).
+     * </p>
+     * <p>
+     * Subclasses may override.
+     * </p>
+     */
+    protected void handleSave() {
+        Iterator nodes = preferenceManager.getElements(PreferenceManager.PRE_ORDER).iterator();
+        while (nodes.hasNext()) {
+            IPreferenceNode node = (IPreferenceNode) nodes.next();
+            IPreferencePage page = node.getPage();
+            if (page instanceof PreferencePage) {
+                // Save now in case tbe workbench does not shutdown cleanly
+                IPreferenceStore store = ((PreferencePage) page).getPreferenceStore();
+                if (store !is null && store.needsSaving()
+                        && store instanceof IPersistentPreferenceStore) {
+                    try {
+                        ((IPersistentPreferenceStore) store).save();
+                    } catch (IOException e) {
+                        MessageDialog
+                                .openError(
+                                        getShell(),
+                                        JFaceResources.getString("PreferenceDialog.saveErrorTitle"), //$NON-NLS-1$
+                                        JFaceResources
+                                                .format(
+                                                        "PreferenceDialog.saveErrorMessage", new Object[] { page.getTitle(), e.getMessage() })); //$NON-NLS-1$
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Notifies that the window's close button was pressed, the close menu was
+     * selected, or the ESCAPE key pressed.
+     * <p>
+     * The default implementation of this framework method sets the window's
+     * return code to <code>CANCEL</code> and closes the window using
+     * <code>close</code>. Subclasses may extend or reimplement.
+     * </p>
+     */
+    protected void handleShellCloseEvent() {
+        // handle the same as pressing cancel
+        cancelPressed();
+    }
+
+    /**
+     * Notifies of the pressing of the Help button.
+     * <p>
+     * The default implementation of this framework method calls
+     * <code>performHelp</code> on the currently active page.
+     * </p>
+     */
+    protected void helpPressed() {
+        if (currentPage !is null) {
+            currentPage.performHelp();
+        }
+    }
+
+    /**
+     * Returns whether the current page is valid.
+     *
+     * @return <code>false</code> if the current page is not valid, or or
+     *         <code>true</code> if the current page is valid or there is no
+     *         current page
+     */
+    protected bool isCurrentPageValid() {
+        if (currentPage is null) {
+            return true;
+        }
+        return currentPage.isValid();
+    }
+
+    /**
+     * @param control
+     *            the <code>Control</code> to lay out.
+     * @since 3.0
+     */
+    protected void layoutTreeAreaControl(Control control) {
+        GridData gd = new GridData(GridData.FILL_VERTICAL);
+        gd.widthHint = getLastRightWidth();
+        gd.verticalSpan = 1;
+        control.setLayoutData(gd);
+    }
+
+    /**
+     * The preference dialog implementation of this <code>Dialog</code>
+     * framework method sends <code>performOk</code> to all pages of the
+     * preference dialog, then calls <code>handleSave</code> on this dialog to
+     * save any state, and then calls <code>close</code> to close this dialog.
+     */
+    protected void okPressed() {
+        SafeRunnable.run(new SafeRunnable() {
+            private bool errorOccurred;
+
+            /*
+             * (non-Javadoc)
+             *
+             * @see dwtx.core.runtime.ISafeRunnable#run()
+             */
+            public void run() {
+                getButton(IDialogConstants.OK_ID).setEnabled(false);
+                errorOccurred = false;
+                bool hasFailedOK = false;
+                try {
+                    // Notify all the pages and give them a chance to abort
+                    Iterator nodes = preferenceManager.getElements(PreferenceManager.PRE_ORDER)
+                            .iterator();
+                    while (nodes.hasNext()) {
+                        IPreferenceNode node = (IPreferenceNode) nodes.next();
+                        IPreferencePage page = node.getPage();
+                        if (page !is null) {
+                            if (!page.performOk()){
+                                hasFailedOK = true;
+                                return;
+                            }
+                        }
+                    }
+                } catch (Exception e) {
+                    handleException(e);
+                } finally {
+                    //Don't bother closing if the OK failed
+                    if(hasFailedOK){
+                        setReturnCode(FAILED);
+                        getButton(IDialogConstants.OK_ID).setEnabled(true);
+                        return;
+                    }
+
+                    if (!errorOccurred) {
+                        //Give subclasses the choice to save the state of the
+                        //preference pages.
+                        handleSave();
+                    }
+                    setReturnCode(OK);
+                    close();
+                }
+            }
+
+            /*
+             * (non-Javadoc)
+             *
+             * @see dwtx.core.runtime.ISafeRunnable#handleException(java.lang.Throwable)
+             */
+            public void handleException(Throwable e) {
+                errorOccurred = true;
+
+                Policy.getLog().log(new Status(IStatus.ERROR, Policy.JFACE, 0, e.toString(), e));
+
+                clearSelectedNode();
+                String message = JFaceResources.getString("SafeRunnable.errorMessage"); //$NON-NLS-1$
+                MessageDialog.openError(getShell(), JFaceResources.getString("Error"), message); //$NON-NLS-1$
+
+            }
+        });
+    }
+
+    /**
+     * Selects the page determined by <code>lastSuccessfulNode</code> in the
+     * page hierarchy.
+     */
+    void selectCurrentPageAgain() {
+        if (lastSuccessfulNode is null) {
+            return;
+        }
+        getTreeViewer().setSelection(new StructuredSelection(lastSuccessfulNode));
+        currentPage.setVisible(true);
+    }
+
+    /**
+     * Selects the saved item in the tree of preference pages. If it cannot do
+     * this it saves the first one.
+     */
+    protected void selectSavedItem() {
+        IPreferenceNode node = findNodeMatching(getSelectedNodePreference());
+        if (node is null) {
+            IPreferenceNode[] nodes = preferenceManager.getRootSubNodes();
+            ViewerFilter[] filters = getTreeViewer().getFilters();
+            for (int i = 0; i < nodes.length; i++) {
+                IPreferenceNode selectedNode = nodes[i];
+                // See if it passes all filters
+                for (int j = 0; j < filters.length; j++) {
+                    if (!filters[j].select(this.treeViewer, preferenceManager
+                            .getRoot(), selectedNode)) {
+                        selectedNode = null;
+                        break;
+                    }
+                }
+                // if it passes all filters select it
+                if (selectedNode !is null) {
+                    node = selectedNode;
+                    break;
+                }
+            }
+        }
+        if (node !is null) {
+            getTreeViewer().setSelection(new StructuredSelection(node), true);
+            // Keep focus in tree. See bugs 2692, 2621, and 6775.
+            getTreeViewer().getControl().setFocus();
+        }
+    }
+
+    /**
+     * Display the given error message. The currently displayed message is saved
+     * and will be redisplayed when the error message is set to
+     * <code>null</code>.
+     *
+     * @param newErrorMessage
+     *            the errorMessage to display or <code>null</code>
+     */
+    public void setErrorMessage(String newErrorMessage) {
+        if (newErrorMessage is null) {
+            messageArea.clearErrorMessage();
+        } else {
+            messageArea.updateText(newErrorMessage, IMessageProvider.ERROR);
+        }
+    }
+
+    /**
+     * Save the last known tree width.
+     *
+     * @param width
+     *            the width.
+     */
+    private void setLastTreeWidth(int width) {
+        lastTreeWidth = width;
+    }
+
+    /**
+     * Set the message text. If the message line currently displays an error,
+     * the message is stored and will be shown after a call to clearErrorMessage
+     * <p>
+     * Shortcut for <code>setMessage(newMessage, NONE)</code>
+     * </p>
+     *
+     * @param newMessage
+     *            the message, or <code>null</code> to clear the message
+     */
+    public void setMessage(String newMessage) {
+        setMessage(newMessage, IMessageProvider.NONE);
+    }
+
+    /**
+     * Sets the message for this dialog with an indication of what type of
+     * message it is.
+     * <p>
+     * The valid message types are one of <code>NONE</code>,
+     * <code>INFORMATION</code>,<code>WARNING</code>, or
+     * <code>ERROR</code>.
+     * </p>
+     * <p>
+     * Note that for backward compatibility, a message of type
+     * <code>ERROR</code> is different than an error message (set using
+     * <code>setErrorMessage</code>). An error message overrides the current
+     * message until the error message is cleared. This method replaces the
+     * current message and does not affect the error message.
+     * </p>
+     *
+     * @param newMessage
+     *            the message, or <code>null</code> to clear the message
+     * @param newType
+     *            the message type
+     * @since 2.0
+     */
+    public void setMessage(String newMessage, int newType) {
+        messageArea.updateText(newMessage, newType);
+    }
+
+    /**
+     * Sets the minimum page size.
+     *
+     * @param minWidth
+     *            the minimum page width
+     * @param minHeight
+     *            the minimum page height
+     * @see #setMinimumPageSize(Point)
+     */
+    public void setMinimumPageSize(int minWidth, int minHeight) {
+        minimumPageSize.x = minWidth;
+        minimumPageSize.y = minHeight;
+    }
+
+    /**
+     * Sets the minimum page size.
+     *
+     * @param size
+     *            the page size encoded as <code>new Point(width,height)</code>
+     * @see #setMinimumPageSize(int,int)
+     */
+    public void setMinimumPageSize(Point size) {
+        minimumPageSize.x = size.x;
+        minimumPageSize.y = size.y;
+    }
+
+    /**
+     * Sets the preference store for this preference dialog.
+     *
+     * @param store
+     *            the preference store
+     * @see #getPreferenceStore
+     */
+    public void setPreferenceStore(IPreferenceStore store) {
+        Assert.isNotNull(store);
+        preferenceStore = store;
+    }
+
+    /**
+     * Save the currently selected node.
+     */
+    private void setSelectedNode() {
+        String storeValue = null;
+        IStructuredSelection selection = (IStructuredSelection) getTreeViewer().getSelection();
+        if (selection.size() is 1) {
+            IPreferenceNode node = (IPreferenceNode) selection.getFirstElement();
+            storeValue = node.getId();
+        }
+        setSelectedNodePreference(storeValue);
+    }
+
+    /**
+     * Sets the name of the selected item preference. Public equivalent to
+     * <code>setSelectedNodePreference</code>.
+     *
+     * @param pageId
+     *            The identifier for the page
+     * @since 3.0
+     */
+    public void setSelectedNode(String pageId) {
+        setSelectedNodePreference(pageId);
+    }
+
+    /**
+     * Sets the name of the selected item preference.
+     *
+     * @param pageId
+     *            The identifier for the page
+     */
+    protected void setSelectedNodePreference(String pageId) {
+        lastPreferenceId = pageId;
+    }
+
+    /**
+     * 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 preferred = getShell().getBounds();
+        preferred.width = width;
+        preferred.height = height;
+        getShell().setBounds(getConstrainedShellBounds(preferred));
+    }
+
+    /**
+     * Shows the preference page corresponding to the given preference node.
+     * Does nothing if that page is already current.
+     *
+     * @param node
+     *            the preference node, or <code>null</code> if none
+     * @return <code>true</code> if the page flip was successful, and
+     *         <code>false</code> is unsuccessful
+     */
+    protected bool showPage(IPreferenceNode node) {
+        if (node is null) {
+            return false;
+        }
+        // Create the page if nessessary
+        if (node.getPage() is null) {
+            createPage(node);
+        }
+        if (node.getPage() is null) {
+            return false;
+        }
+        IPreferencePage newPage = getPage(node);
+        if (newPage is currentPage) {
+            return true;
+        }
+        if (currentPage !is null) {
+            if (!currentPage.okToLeave()) {
+                return false;
+            }
+        }
+        IPreferencePage oldPage = currentPage;
+        currentPage = newPage;
+        // Set the new page's container
+        currentPage.setContainer(this);
+        // Ensure that the page control has been created
+        // (this allows lazy page control creation)
+        if (currentPage.getControl() is null) {
+            final bool[] failed = { false };
+            SafeRunnable.run(new ISafeRunnable() {
+                public void handleException(Throwable e) {
+                    failed[0] = true;
+                }
+
+                public void run() {
+                    createPageControl(currentPage, pageContainer);
+                }
+            });
+            if (failed[0]) {
+                return false;
+            }
+            // the page is responsible for ensuring the created control is
+            // accessable
+            // via getControl.
+            Assert.isNotNull(currentPage.getControl());
+        }
+        // Force calculation of the page's description label because
+        // label can be wrapped.
+        final Point[] size = new Point[1];
+        final Point failed = new Point(-1, -1);
+        SafeRunnable.run(new ISafeRunnable() {
+            public void handleException(Throwable e) {
+                size[0] = failed;
+            }
+
+            public void run() {
+                size[0] = currentPage.computeSize();
+            }
+        });
+        if (size[0].equals(failed)) {
+            return false;
+        }
+        Point contentSize = size[0];
+        // Do we need resizing. Computation not needed if the
+        // first page is inserted since computing the dialog's
+        // size is done by calling dialog.open().
+        // Also prevent auto resize if the user has manually resized
+        Shell shell = getShell();
+        Point shellSize = shell.getSize();
+        if (oldPage !is null) {
+            Rectangle rect = pageContainer.getClientArea();
+            Point containerSize = new Point(rect.width, rect.height);
+            int hdiff = contentSize.x - containerSize.x;
+            int vdiff = contentSize.y - containerSize.y;
+            if ((hdiff > 0 || vdiff > 0) && shellSize.equals(lastShellSize)) {
+                    hdiff = Math.max(0, hdiff);
+                    vdiff = Math.max(0, vdiff);
+                    setShellSize(shellSize.x + hdiff, shellSize.y + vdiff);
+                    lastShellSize = shell.getSize();
+                    if (currentPage.getControl().getSize().x is 0) {
+                        currentPage.getControl().setSize(containerSize);
+                    }
+
+            } else {
+                currentPage.setSize(containerSize);
+            }
+        }
+
+        scrolled.setMinSize(contentSize);
+        // Ensure that all other pages are invisible
+        // (including ones that triggered an exception during
+        // their creation).
+        Control[] children = pageContainer.getChildren();
+        Control currentControl = currentPage.getControl();
+        for (int i = 0; i < children.length; i++) {
+            if (children[i] !is currentControl) {
+                children[i].setVisible(false);
+            }
+        }
+        // Make the new page visible
+        currentPage.setVisible(true);
+        if (oldPage !is null) {
+            oldPage.setVisible(false);
+        }
+        // update the dialog controls
+        update();
+        return true;
+    }
+
+    /**
+     * Create the page for the node.
+     * @param node
+     *
+     * @since 3.1
+     */
+    protected void createPage(IPreferenceNode node) {
+        node.createPage();
+    }
+
+    /**
+     * Get the page for the node.
+     * @param node
+     * @return IPreferencePage
+     *
+     * @since 3.1
+     */
+    protected IPreferencePage getPage(IPreferenceNode node) {
+        return node.getPage();
+    }
+
+    /**
+     * Shows the "Page Flipping abort" dialog.
+     */
+    void showPageFlippingAbortDialog() {
+        MessageDialog.openError(getShell(), JFaceResources
+                .getString("AbortPageFlippingDialog.title"), //$NON-NLS-1$
+                JFaceResources.getString("AbortPageFlippingDialog.message")); //$NON-NLS-1$
+    }
+
+    /**
+     * Updates this dialog's controls to reflect the current page.
+     */
+    protected void update() {
+        // Update the title bar
+        updateTitle();
+        // Update the message line
+        updateMessage();
+        // Update the buttons
+        updateButtons();
+        //Saved the selected node in the preferences
+        setSelectedNode();
+        firePageChanged(new PageChangedEvent(this, getCurrentPage()));
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwtx.jface.preference.IPreferencePageContainer#updateButtons()
+     */
+    public void updateButtons() {
+        okButton.setEnabled(isCurrentPageValid());
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwtx.jface.preference.IPreferencePageContainer#updateMessage()
+     */
+    public void updateMessage() {
+        String message = null;
+        String errorMessage = null;
+        if(currentPage !is null){
+            message = currentPage.getMessage();
+            errorMessage = currentPage.getErrorMessage();
+        }
+        int messageType = IMessageProvider.NONE;
+        if (message !is null && currentPage instanceof IMessageProvider) {
+            messageType = ((IMessageProvider) currentPage).getMessageType();
+        }
+
+        if (errorMessage is null){
+            if (showingError) {
+                // we were previously showing an error
+                showingError = false;
+            }
+        }
+        else {
+            message = errorMessage;
+            messageType = IMessageProvider.ERROR;
+            if (!showingError) {
+                // we were not previously showing an error
+                showingError = true;
+            }
+        }
+        messageArea.updateText(message,messageType);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwtx.jface.preference.IPreferencePageContainer#updateTitle()
+     */
+    public void updateTitle() {
+        if(currentPage is null) {
+            return;
+        }
+        messageArea.showTitle(currentPage.getTitle(), currentPage.getImage());
+    }
+
+    /**
+     * Update the tree to use the specified <code>Font</code>.
+     *
+     * @param dialogFont
+     *            the <code>Font</code> to use.
+     * @since 3.0
+     */
+    protected void updateTreeFont(Font dialogFont) {
+        getTreeViewer().getControl().setFont(dialogFont);
+    }
+
+    /**
+     * Returns the currentPage.
+     * @return IPreferencePage
+     * @since 3.1
+     */
+    protected IPreferencePage getCurrentPage() {
+        return currentPage;
+    }
+
+    /**
+     * Sets the current page.
+     * @param currentPage
+     *
+     * @since 3.1
+     */
+    protected void setCurrentPage(IPreferencePage currentPage) {
+        this.currentPage = currentPage;
+    }
+
+    /**
+     * Set the treeViewer.
+     * @param treeViewer
+     *
+     * @since 3.1
+     */
+    protected void setTreeViewer(TreeViewer treeViewer) {
+        this.treeViewer = treeViewer;
+    }
+
+    /**
+     * Get the composite that is showing the page.
+     *
+     * @return Composite.
+     *
+     * @since 3.1
+     */
+    protected Composite getPageContainer() {
+        return this.pageContainer;
+    }
+
+    /**
+     * Set the composite that is showing the page.
+     * @param pageContainer Composite
+     *
+     * @since 3.1
+     */
+    protected void setPageContainer(Composite pageContainer) {
+        this.pageContainer = pageContainer;
+    }
+    /**
+     * Create the page control for the supplied page.
+     *
+     * @param page - the preference page to be shown
+     * @param parent - the composite to parent the page
+     *
+     * @since 3.1
+     */
+    protected void createPageControl(IPreferencePage page, Composite parent) {
+        page.createControl(parent);
+    }
+
+    /**
+     * @see dwtx.jface.dialogs.IPageChangeProvider#getSelectedPage()
+     *
+     * @since 3.1
+     */
+    public Object getSelectedPage() {
+            return getCurrentPage();
+        }
+
+    /**
+     * @see dwtx.jface.dialogs.IPageChangeProvider#addPageChangedListener(dwtx.jface.dialogs.IPageChangedListener)
+     * @since 3.1
+     */
+    public void addPageChangedListener(IPageChangedListener listener) {
+        pageChangedListeners.add(listener);
+    }
+
+    /**
+     * @see dwtx.jface.dialogs.IPageChangeProvider#removePageChangedListener(dwtx.jface.dialogs.IPageChangedListener)
+     * @since 3.1
+     */
+    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);
+                }
+            });
+        }
+    }
+}
+++/
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/resource/AbstractResourceManager.d	Sat Mar 29 02:25:12 2008 +0100
@@ -0,0 +1,160 @@
+/*******************************************************************************
+ * 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.AbstractResourceManager;
+
+import dwtx.jface.resource.ResourceManager;
+import dwtx.jface.resource.DeviceResourceDescriptor;
+
+import tango.util.collection.HashMap;
+import tango.util.collection.model.Map;
+
+import dwt.dwthelper.utils;
+
+/**
+ * Abstract implementation of ResourceManager. Maintains reference counts for all previously
+ * allocated DWT resources. Delegates to the abstract method allocate(...) the first time a resource
+ * is referenced and delegates to the abstract method deallocate(...) the last time a reference is
+ * removed.
+ *
+ * @since 3.1
+ */
+abstract class AbstractResourceManager : ResourceManager {
+
+    /**
+     * Map of ResourceDescriptor onto RefCount. (null when empty)
+     */
+    private HashMap!(DeviceResourceDescriptor,RefCount) map = null;
+
+    /**
+     * Holds a reference count for a previously-allocated resource
+     */
+    private static class RefCount {
+        Object resource;
+        int count = 1;
+
+        this(Object resource) {
+            this.resource = resource;
+        }
+    }
+
+    /**
+     * Called the first time a resource is requested. Should allocate and return a resource
+     * of the correct type.
+     *
+     * @since 3.1
+     *
+     * @param descriptor identifier for the resource to allocate
+     * @return the newly allocated resource
+     * @throws DeviceResourceException Thrown when allocation of an DWT device resource fails
+     */
+    protected abstract Object allocate(DeviceResourceDescriptor descriptor);
+
+    /**
+     * Called the last time a resource is dereferenced. Should release any resources reserved by
+     * allocate(...).
+     *
+     * @since 3.1
+     *
+     * @param resource resource being deallocated
+     * @param descriptor identifier for the resource
+     */
+    protected abstract void deallocate(Object resource, DeviceResourceDescriptor descriptor);
+
+    /* (non-Javadoc)
+     * @see ResourceManager#create(DeviceResourceDescriptor)
+     */
+    public final Object create(DeviceResourceDescriptor descriptor){
+
+        // Lazily allocate the map
+        if (map is null) {
+            map = new HashMap!(DeviceResourceDescriptor,RefCount);
+        }
+
+        // Get the current reference count
+        RefCount count = map.get(descriptor);
+        if (count !is null) {
+            // If this resource already exists, increment the reference count and return
+            // the existing resource.
+            count.count++;
+            return count.resource;
+        }
+
+        // Allocate and return a new resource (with ref count = 1)
+        Object resource = allocate(descriptor);
+
+        count = new RefCount(resource);
+        map.add(descriptor, count);
+
+        return resource;
+    }
+
+    /* (non-Javadoc)
+     * @see ResourceManager#destroy(DeviceResourceDescriptor)
+     */
+    public final void destroy(DeviceResourceDescriptor descriptor) {
+        // If the map is empty (null) then there are no resources to dispose
+        if (map is null) {
+            return;
+        }
+
+        // Find the existing resource
+        RefCount count = map.get(descriptor);
+        if (count !is null) {
+            // If the resource exists, decrement the reference count.
+            count.count--;
+            if (count.count is 0) {
+                // If this was the last reference, deallocate it.
+                deallocate(count.resource, descriptor);
+                map.removeKey(descriptor);
+            }
+        }
+
+        // Null out the map when empty to save a small amount of memory
+        if (map.drained()) {
+            map = null;
+        }
+    }
+
+    /**
+     * Deallocates any resources allocated by this registry that have not yet been
+     * deallocated.
+     *
+     * @since 3.1
+     */
+    public void dispose() {
+        super.dispose();
+
+        if (map is null) {
+            return;
+        }
+
+        foreach( key, val; map ){
+            deallocate(val.resource, key);
+        }
+
+        map = null;
+    }
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resource.ResourceManager#find(dwtx.jface.resource.DeviceResourceDescriptor)
+     */
+    public Object find(DeviceResourceDescriptor descriptor) {
+        if (map is null) {
+            return null;
+        }
+        RefCount refCount = cast(RefCount)map.get(descriptor);
+        if (refCount is null)
+            return null;
+        return refCount.resource;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/resource/ColorRegistry.d	Sat Mar 29 02:25:12 2008 +0100
@@ -0,0 +1,302 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 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.ColorRegistry;
+
+import dwtx.jface.resource.ResourceRegistry;
+import dwtx.jface.resource.ColorDescriptor;
+
+import tango.util.collection.ArraySeq;
+import tango.util.collection.HashMap;
+import tango.util.collection.HashSet;
+import tango.util.collection.model.Map;
+import tango.util.collection.model.Set;
+import tango.util.collection.model.SetView;
+import tango.util.collection.model.Seq;
+
+import dwt.graphics.Color;
+import dwt.graphics.RGB;
+import dwt.widgets.Display;
+import dwtx.core.runtime.Assert;
+
+import dwt.dwthelper.utils;
+import dwt.dwthelper.Runnable;
+
+/**
+ * A color registry maintains a mapping between symbolic color names and DWT
+ * <code>Color</code>s.
+ * <p>
+ * A color registry owns all of the <code>Color</code> objects registered with
+ * it, and automatically disposes of them when the DWT Display that creates the
+ * <code>Color</code>s is disposed. Because of this, clients do not need to
+ * (indeed, must not attempt to) dispose of <code>Color</code> objects
+ * themselves.
+ * </p>
+ * <p>
+ * Methods are provided for registering listeners that will be kept
+ * apprised of changes to list of registed colors.
+ * </p>
+ * <p>
+ * Clients may instantiate this class (it was not designed to be subclassed).
+ * </p>
+ *
+ * @since 3.0
+ */
+public class ColorRegistry : ResourceRegistry {
+
+    /**
+     * This registries <code>Display</code>. All colors will be allocated using
+     * it.
+     */
+    protected Display display;
+
+    /**
+     * Collection of <code>Color</code> that are now stale to be disposed when
+     * it is safe to do so (i.e. on shutdown).
+     */
+    private Seq!(Color) staleColors;
+
+    /**
+     * Table of known colors, keyed by symbolic color name (key type: <code>String</code>,
+     * value type: <code>dwt.graphics.Color</code>.
+     */
+    private Map!(String,Color) stringToColor;
+
+    /**
+     * Table of known color data, keyed by symbolic color name (key type:
+     * <code>String</code>, value type: <code>dwt.graphics.RGB</code>).
+     */
+    private Map!(String,RGB) stringToRGB;
+
+    /**
+     * Runnable that cleans up the manager on disposal of the display.
+     */
+    protected Runnable displayRunnable;
+    private void init_displayRunnable(){
+        displayRunnable = new class Runnable {
+            public void run() {
+                clearCaches();
+            }
+        };
+    }
+
+    /**
+     * Create a new instance of the receiver that is hooked to the current
+     * display.
+     *
+     * @see dwt.widgets.Display#getCurrent()
+     */
+    public this() {
+        this(Display.getCurrent(), true);
+    }
+
+    /**
+     * Create a new instance of the receiver.
+     *
+     * @param display the <code>Display</code> to hook into.
+     */
+    public this(Display display) {
+        this (display, true);
+    }
+
+    /**
+     * Create a new instance of the receiver.
+     *
+     * @param display the <code>Display</code> to hook into
+     * @param cleanOnDisplayDisposal
+     *            whether all fonts allocated by this <code>ColorRegistry</code>
+     *            should be disposed when the display is disposed
+     * @since 3.1
+     */
+    public this(Display display, bool cleanOnDisplayDisposal) {
+        staleColors = new ArraySeq!(Color);
+        stringToColor = new HashMap!(String,Color);
+        stringToRGB = new HashMap!(String,RGB);
+        init_displayRunnable();
+        Assert.isNotNull(display);
+        this.display = display;
+        if (cleanOnDisplayDisposal) {
+            hookDisplayDispose();
+        }
+    }
+
+    /**
+     * Create a new <code>Color</code> on the receivers <code>Display</code>.
+     *
+     * @param rgb the <code>RGB</code> data for the color.
+     * @return the new <code>Color</code> object.
+     *
+     * @since 3.1
+     */
+    private Color createColor(RGB rgb) {
+        return new Color(display, rgb);
+    }
+
+    /**
+     * Dispose of all of the <code>Color</code>s in this iterator.
+     *
+     * @param iterator over <code>Collection</code> of <code>Color</code>
+     */
+    /+
+    private void disposeColors(Iterator iterator) {
+        while (iterator.hasNext()) {
+            Object next = iterator.next();
+            ((Color) next).dispose();
+        }
+    }
+    +/
+
+    /**
+     * Returns the <code>color</code> associated with the given symbolic color
+     * name, or <code>null</code> if no such definition exists.
+     *
+     * @param symbolicName symbolic color name
+     * @return the <code>Color</code> or <code>null</code>
+     */
+    public Color get(String symbolicName) {
+
+        Assert.isNotNull(symbolicName);
+        auto result1 = stringToColor.get(symbolicName);
+        if (result1 !is null) {
+            return result1;
+        }
+
+        Color color = null;
+
+        auto result = stringToRGB.get(symbolicName);
+        if (result is null) {
+            return null;
+        }
+
+        color = createColor(result);
+
+        stringToColor.add(symbolicName, color);
+
+        return color;
+    }
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resource.ResourceRegistry#getKeySet()
+     */
+    public SetView!(String) getKeySet() {
+        auto res = new HashSet!(String);
+        foreach( k,v; stringToRGB ){
+            res.add(k);
+        }
+        return res;
+    }
+
+    /**
+     * Returns the color data associated with the given symbolic color name.
+     *
+     * @param symbolicName symbolic color name.
+     * @return the <code>RGB</code> data.
+     */
+    public RGB getRGB(String symbolicName) {
+        Assert.isNotNull(symbolicName);
+        return stringToRGB.get(symbolicName);
+    }
+
+    /**
+     * Returns the color descriptor associated with the given symbolic color name.
+     * @since 3.1
+     *
+     * @param symbolicName
+     * @return the color descriptor associated with the given symbolic color name.
+     */
+    public ColorDescriptor getColorDescriptor(String symbolicName) {
+        return ColorDescriptor.createFrom(getRGB(symbolicName));
+    }
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resource.ResourceRegistry#clearCaches()
+     */
+    protected void clearCaches() {
+        foreach( k, v; stringToColor ){
+            v.dispose();
+        }
+        foreach( v; staleColors ){
+            v.dispose();
+        }
+//         disposeColors(stringToColor.values().iterator());
+//         disposeColors(staleColors.iterator());
+        stringToColor.clear();
+        staleColors.clear();
+    }
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resource.ResourceRegistry#hasValueFor(java.lang.String)
+     */
+    public bool hasValueFor(String colorKey) {
+        return stringToRGB.containsKey(colorKey);
+    }
+
+    /**
+     * Hook a dispose listener on the DWT display.
+     */
+    private void hookDisplayDispose() {
+        display.disposeExec(displayRunnable);
+    }
+
+    /**
+     * Adds (or replaces) a color to this color registry under the given
+     * symbolic name.
+     * <p>
+     * A property change event is reported whenever the mapping from a symbolic
+     * name to a color changes. The source of the event is this registry; the
+     * property name is the symbolic color name.
+     * </p>
+     *
+     * @param symbolicName the symbolic color name
+     * @param colorData an <code>RGB</code> object
+     */
+    public void put(String symbolicName, RGB colorData) {
+        put(symbolicName, colorData, true);
+    }
+
+    /**
+     * Adds (or replaces) a color to this color registry under the given
+     * symbolic name.
+     * <p>
+     * A property change event is reported whenever the mapping from a symbolic
+     * name to a color changes. The source of the event is this registry; the
+     * property name is the symbolic color name.
+     * </p>
+     *
+     * @param symbolicName the symbolic color name
+     * @param colorData an <code>RGB</code> object
+     * @param update - fire a color mapping changed if true. False if this
+     *            method is called from the get method as no setting has
+     *            changed.
+     */
+    private void put(String symbolicName, RGB colorData, bool update) {
+
+        Assert.isNotNull(symbolicName);
+        Assert.isNotNull(colorData);
+
+        RGB existing = stringToRGB.get(symbolicName);
+        if (colorData.opEquals(existing)) {
+            return;
+        }
+
+        Color oldColor = stringToColor.get(symbolicName);
+        stringToColor.removeKey(symbolicName);
+        stringToRGB.add(symbolicName, colorData);
+        if (update) {
+            fireMappingChanged(symbolicName, existing, colorData);
+        }
+
+        if (oldColor !is null) {
+            staleColors.append(oldColor);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/resource/CompositeImageDescriptor.d	Sat Mar 29 02:25:12 2008 +0100
@@ -0,0 +1,218 @@
+/*******************************************************************************
+ * 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.resource.CompositeImageDescriptor;
+
+import dwtx.jface.resource.ImageDescriptor;
+
+import dwt.graphics.ImageData;
+import dwt.graphics.PaletteData;
+import dwt.graphics.Point;
+import dwt.graphics.RGB;
+
+import dwt.dwthelper.utils;
+
+/**
+ * Abstract base class for image descriptors that synthesize an image from other
+ * images in order to simulate the effect of custom drawing. For example, this
+ * could be used to superimpose a red bar dexter symbol across an image to
+ * indicate that something was disallowed.
+ * <p>
+ * Subclasses must implement the <code>getSize</code> and <code>fill</code>
+ * methods. Little or no work happens until the image descriptor's image is
+ * actually requested by a call to <code>createImage</code> (or to
+ * <code>getImageData</code> directly).
+ * </p>
+ */
+public abstract class CompositeImageDescriptor : ImageDescriptor {
+
+    /**
+     * The image data for this composite image.
+     */
+    private ImageData imageData;
+
+    /**
+     * Constructs an uninitialized composite image.
+     */
+    protected this() {
+    }
+
+    /**
+     * Draw the composite images.
+     * <p>
+     * Subclasses must implement this framework method to paint images within
+     * the given bounds using one or more calls to the <code>drawImage</code>
+     * framework method.
+     * </p>
+     *
+     * @param width
+     *            the width
+     * @param height
+     *            the height
+     */
+    protected abstract void drawCompositeImage(int width, int height);
+
+    /**
+     * Draws the given source image data into this composite image at the given
+     * position.
+     * <p>
+     * Call this internal framework method to superimpose another image atop
+     * this composite image.
+     * </p>
+     *
+     * @param src
+     *            the source image data
+     * @param ox
+     *            the x position
+     * @param oy
+     *            the y position
+     */
+    final protected void drawImage(ImageData src, int ox, int oy) {
+        ImageData dst = imageData;
+        PaletteData srcPalette = src.palette;
+        ImageData srcMask = null;
+        int alphaMask = 0, alphaShift = 0;
+        if (src.maskData !is null) {
+            srcMask = src.getTransparencyMask ();
+            if (src.depth is 32) {
+                alphaMask = ~(srcPalette.redMask | srcPalette.greenMask | srcPalette.blueMask);
+                while (alphaMask !is 0 && ((alphaMask >>> alphaShift) & 1) is 0) alphaShift++;
+            }
+        }
+        for (int srcY = 0, dstY = srcY + oy; srcY < src.height; srcY++, dstY++) {
+            for (int srcX = 0, dstX = srcX + ox; srcX < src.width; srcX++, dstX++) {
+                if (!(0 <= dstX && dstX < dst.width && 0 <= dstY && dstY < dst.height)) continue;
+                int srcPixel = src.getPixel(srcX, srcY);
+                int srcAlpha = 255;
+                if (src.maskData !is null) {
+                    if (src.depth is 32) {
+                        srcAlpha = (srcPixel & alphaMask) >>> alphaShift;
+                        if (srcAlpha is 0) {
+                            srcAlpha = srcMask.getPixel(srcX, srcY) !is 0 ? 255 : 0;
+                        }
+                    } else {
+                        if (srcMask.getPixel(srcX, srcY) is 0) srcAlpha = 0;
+                    }
+                } else if (src.transparentPixel !is -1) {
+                    if (src.transparentPixel is srcPixel) srcAlpha = 0;
+                } else if (src.alpha !is -1) {
+                    srcAlpha = src.alpha;
+                } else if (src.alphaData !is null) {
+                    srcAlpha = src.getAlpha(srcX, srcY);
+                }
+                if (srcAlpha is 0) continue;
+                int srcRed, srcGreen, srcBlue;
+                if (srcPalette.isDirect) {
+                    srcRed = srcPixel & srcPalette.redMask;
+                    srcRed = (srcPalette.redShift < 0) ? srcRed >>> -srcPalette.redShift : srcRed << srcPalette.redShift;
+                    srcGreen = srcPixel & srcPalette.greenMask;
+                    srcGreen = (srcPalette.greenShift < 0) ? srcGreen >>> -srcPalette.greenShift : srcGreen << srcPalette.greenShift;
+                    srcBlue = srcPixel & srcPalette.blueMask;
+                    srcBlue = (srcPalette.blueShift < 0) ? srcBlue >>> -srcPalette.blueShift : srcBlue << srcPalette.blueShift;
+                } else {
+                    RGB rgb = srcPalette.getRGB(srcPixel);
+                    srcRed = rgb.red;
+                    srcGreen = rgb.green;
+                    srcBlue = rgb.blue;
+                }
+                int dstRed, dstGreen, dstBlue, dstAlpha;
+                if (srcAlpha is 255) {
+                    dstRed = srcRed;
+                    dstGreen = srcGreen;
+                    dstBlue= srcBlue;
+                    dstAlpha = srcAlpha;
+                } else {
+                    int dstPixel = dst.getPixel(dstX, dstY);
+                    dstAlpha = dst.getAlpha(dstX, dstY);
+                    dstRed = (dstPixel & 0xFF) >>> 0;
+                    dstGreen = (dstPixel & 0xFF00) >>> 8;
+                    dstBlue = (dstPixel & 0xFF0000) >>> 16;
+                    dstRed += (srcRed - dstRed) * srcAlpha / 255;
+                    dstGreen += (srcGreen - dstGreen) * srcAlpha / 255;
+                    dstBlue += (srcBlue - dstBlue) * srcAlpha / 255;
+                    dstAlpha += (srcAlpha - dstAlpha) * srcAlpha / 255;
+                }
+                dst.setPixel(dstX, dstY, ((dstRed & 0xFF) << 0) | ((dstGreen & 0xFF) << 8) | ((dstBlue & 0xFF) << 16));
+                dst.setAlpha(dstX, dstY, dstAlpha);
+            }
+        }
+    }
+
+    /*
+     * (non-Javadoc) Method declared on ImageDesciptor.
+     */
+    public ImageData getImageData() {
+        Point size = getSize();
+
+        /* Create a 24 bit image data with alpha channel */
+        imageData = new ImageData(size.x, size.y, 24, new PaletteData(0xFF, 0xFF00, 0xFF0000));
+        imageData.alphaData = new byte[imageData.width * imageData.height];
+
+        drawCompositeImage(size.x, size.y);
+
+        /* Detect minimum transparency */
+        bool transparency = false;
+        byte[] alphaData = imageData.alphaData;
+        for (int i = 0; i < alphaData.length; i++) {
+            int alpha = alphaData[i] & 0xFF;
+            if (!(alpha is 0 || alpha is 255)) {
+                /* Full alpha channel transparency */
+                return imageData;
+            }
+            if (!transparency && alpha is 0) transparency = true;
+        }
+        if (transparency) {
+            /* Reduce to 1-bit alpha channel transparency */
+            PaletteData palette = new PaletteData([new RGB(0, 0, 0), new RGB(255, 255, 255)]);
+            ImageData mask = new ImageData(imageData.width, imageData.height, 1, palette);
+            for (int y = 0; y < mask.height; y++) {
+                for (int x = 0; x < mask.width; x++) {
+                    mask.setPixel(x, y, imageData.getAlpha(x, y) is 255 ? 1 : 0);
+                }
+            }
+        } else {
+            /* no transparency */
+            imageData.alphaData = null;
+        }
+        return imageData;
+    }
+
+
+    /**
+     * Return the transparent pixel for the receiver.
+     * <strong>NOTE</strong> This value is not currently in use in the
+     * default implementation.
+     * @return int
+     * @since 3.3
+     */
+    protected int getTransparentPixel() {
+        return 0;
+    }
+
+    /**
+     * Return the size of this composite image.
+     * <p>
+     * Subclasses must implement this framework method.
+     * </p>
+     *
+     * @return the x and y size of the image expressed as a point object
+     */
+    protected abstract Point getSize();
+
+    /**
+     * @param imageData The imageData to set.
+     * @since 3.3
+     */
+    protected void setImageData(ImageData imageData) {
+        this.imageData = imageData;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/resource/DeviceResourceManager.d	Sat Mar 29 02:25:12 2008 +0100
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * 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.DeviceResourceManager;
+
+import dwtx.jface.resource.AbstractResourceManager;
+import dwtx.jface.resource.DeviceResourceDescriptor;
+import dwtx.jface.resource.ImageDescriptor;
+
+import dwt.graphics.Device;
+import dwt.graphics.Image;
+
+import dwt.dwthelper.utils;
+
+/**
+ * Manages DWT resources for a particular device.
+ *
+ * <p>
+ * IMPORTANT: in most cases clients should use a <code>LocalResourceManager</code> instead of a
+ * <code>DeviceResourceManager</code>. To create a resource manager on a particular display,
+ * use <code>new LocalResourceManager(JFaceResources.getResources(myDisplay))</code>.
+ * <code>DeviceResourceManager</code> should only be used directly when managing
+ * resources for a device other than a Display (such as a printer).
+ * </p>
+ *
+ * @see LocalResourceManager
+ *
+ * @since 3.1
+ */
+public final class DeviceResourceManager : AbstractResourceManager {
+
+    private Device device;
+    private Image missingImage;
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resource.ResourceManager#getDevice()
+     */
+    public Device getDevice() {
+        return device;
+    }
+
+    /**
+     * Creates a new registry for the given device.
+     *
+     * @param device device to manage
+     */
+    public this(Device device) {
+        this.device = device;
+    }
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resource.AbstractResourceManager#allocate(dwtx.jface.resource.DeviceResourceDescriptor)
+     */
+    protected Object allocate(DeviceResourceDescriptor descriptor){
+        return descriptor.createResource(device);
+    }
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resource.AbstractResourceManager#deallocate(java.lang.Object, dwtx.jface.resource.DeviceResourceDescriptor)
+     */
+    protected void deallocate(Object resource, DeviceResourceDescriptor descriptor) {
+        descriptor.destroyResource(resource);
+    }
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resource.ResourceManager#getDefaultImage()
+     */
+    protected Image getDefaultImage() {
+        if (missingImage is null) {
+            missingImage = ImageDescriptor.getMissingImageDescriptor().createImage();
+        }
+        return missingImage;
+    }
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resource.AbstractResourceManager#dispose()
+     */
+    public void dispose() {
+        super.dispose();
+        if (missingImage !is null) {
+            missingImage.dispose();
+            missingImage = null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/resource/JFaceColors.d	Sat Mar 29 02:25:12 2008 +0100
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * 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.resource.JFaceColors;
+
+import dwtx.jface.resource.JFaceResources;
+
+import dwt.DWT;
+import dwt.graphics.Color;
+import dwt.widgets.Control;
+import dwt.widgets.Display;
+import dwtx.jface.preference.JFacePreferences;
+
+import dwt.dwthelper.utils;
+
+/**
+ * JFaceColors is the class that stores references
+ * to all of the colors used by JFace.
+ */
+public class JFaceColors {
+
+    /**
+     * @param display the display the color is from
+     * @return the Color used for banner backgrounds
+     * @see DWT#COLOR_LIST_BACKGROUND
+     * @see Display#getSystemColor(int)
+     */
+    public static Color getBannerBackground(Display display) {
+        return display.getSystemColor(DWT.COLOR_LIST_BACKGROUND);
+    }
+
+    /**
+     * @param display the display the color is from
+     * @return the Color used for banner foregrounds
+     * @see DWT#COLOR_LIST_FOREGROUND
+     * @see Display#getSystemColor(int)
+     */
+    public static Color getBannerForeground(Display display) {
+        return display.getSystemColor(DWT.COLOR_LIST_FOREGROUND);
+    }
+
+    /**
+     * @param display the display the color is from
+     * @return the background Color for widgets that display errors.
+     * @see DWT#COLOR_WIDGET_BACKGROUND
+     * @see Display#getSystemColor(int)
+     */
+    public static Color getErrorBackground(Display display) {
+        return display.getSystemColor(DWT.COLOR_WIDGET_BACKGROUND);
+    }
+
+    /**
+     * @param display the display the color is from
+     * @return the border Color for widgets that display errors.
+     * @see DWT#COLOR_WIDGET_DARK_SHADOW
+     * @see Display#getSystemColor(int)
+     */
+    public static Color getErrorBorder(Display display) {
+        return display.getSystemColor(DWT.COLOR_WIDGET_DARK_SHADOW);
+    }
+
+    /**
+     * @param display the display the color is from
+     * @return the default color to use for displaying errors.
+     * @see ColorRegistry#get(String)
+     * @see JFacePreferences#ERROR_COLOR
+     */
+    public static Color getErrorText(Display display) {
+        return JFaceResources.getColorRegistry().get(
+                JFacePreferences.ERROR_COLOR);
+    }
+
+    /**
+     * @param display the display the color is from
+     * @return the default color to use for displaying hyperlinks.
+     * @see ColorRegistry#get(String)
+     * @see JFacePreferences#HYPERLINK_COLOR
+     */
+    public static Color getHyperlinkText(Display display) {
+        return JFaceResources.getColorRegistry().get(
+                JFacePreferences.HYPERLINK_COLOR);
+    }
+
+    /**
+     * @param display the display the color is from
+     * @return the default color to use for displaying active hyperlinks.
+     * @see ColorRegistry#get(String)
+     * @see JFacePreferences#ACTIVE_HYPERLINK_COLOR
+     */
+    public static Color getActiveHyperlinkText(Display display) {
+        return JFaceResources.getColorRegistry().get(
+                JFacePreferences.ACTIVE_HYPERLINK_COLOR);
+    }
+
+    /**
+     * Clear out the cached color for name. This is generally
+     * done when the color preferences changed and any cached colors
+     * may be disposed. Users of the colors in this class should add a IPropertyChangeListener
+     * to detect when any of these colors change.
+     * @param colorName name of the color
+     *
+     * @deprecated JFaceColors no longer maintains a cache of colors.  This job
+     * is now handled by the ColorRegistry.
+     */
+    public static void clearColor(String colorName) {
+        //no-op
+    }
+
+    /**
+     * Dispose of all allocated colors. Called on workbench
+     * shutdown.
+     *
+     * @deprecated JFaceColors no longer maintains a cache of colors.  This job
+     * is now handled by the ColorRegistry.
+     */
+    public static void disposeColors() {
+        //no-op
+    }
+
+    /**
+     * Set the foreground and background colors of the
+     * control to the specified values. If the values are
+     * null than ignore them.
+     * @param control the control the foreground and/or background color should be set
+     *
+     * @param foreground Color the foreground color (maybe <code>null</code>)
+     * @param background Color the background color (maybe <code>null</code>)
+     */
+    public static void setColors(Control control, Color foreground,
+            Color background) {
+        if (foreground !is null) {
+            control.setForeground(foreground);
+        }
+        if (background !is null) {
+            control.setBackground(background);
+        }
+    }
+
+}
--- a/dwtx/jface/resource/JFaceResources.d	Sat Mar 29 01:25:27 2008 +0100
+++ b/dwtx/jface/resource/JFaceResources.d	Sat Mar 29 02:25:12 2008 +0100
@@ -15,26 +15,13 @@
 import dwtx.jface.resource.FontRegistry;
 import dwtx.jface.resource.ImageRegistry;
 import dwtx.jface.resource.ResourceManager;
-
-import dwt.graphics.Font;
-import dwt.widgets.Display;
+import dwtx.jface.resource.ColorRegistry;
+import dwtx.jface.resource.FontDescriptor;
+import dwtx.jface.resource.DeviceResourceManager;
+import dwtx.jface.resource.ImageDescriptor;
 
-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;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.MissingResourceException;
-import java.util.ResourceBundle;
+import tango.util.collection.HashMap;
+import tango.util.collection.model.Map;
 
 import dwt.graphics.Font;
 import dwt.graphics.Image;
@@ -45,6 +32,10 @@
 import dwtx.jface.preference.PreferenceDialog;
 import dwtx.jface.wizard.Wizard;
 
+import dwt.dwthelper.utils;
+import dwt.dwthelper.Runnable;
+import dwt.dwthelper.ResourceBundle;
+import tango.text.convert.Format;
 /**
  * Utility methods to access JFace-specific resources.
  * <p>
@@ -66,25 +57,30 @@
     /**
      * The path to the icons in the resources.
      */
-    private final static String ICONS_PATH = "$nl$/icons/full/";//$NON-NLS-1$
+    private const static String ICONS_PATH = "$nl$/icons/full/";//$NON-NLS-1$
 
     /**
      * Map of Display onto DeviceResourceManager. Holds all the resources for
      * the associated display.
      */
-    private static final Map registries = new HashMap();
+    private static Map!(Display,ResourceManager) registries;
+    static this(){
+        registries = new HashMap!(Display,ResourceManager);
+    }
 
     /**
      * The symbolic font name for the banner font (value
      * <code>"dwtx.jface.bannerfont"</code>).
      */
-    public static final String BANNER_FONT = "dwtx.jface.bannerfont"; //$NON-NLS-1$
+    public static const String BANNER_FONT = "dwtx.jface.bannerfont"; //$NON-NLS-1$
 
     /**
      * The JFace resource bundle; eagerly initialized.
      */
-    private static final ResourceBundle bundle = ResourceBundle
-            .getBundle("dwtx.jface.messages"); //$NON-NLS-1$
+    private static /+final+/ ResourceBundle bundle;
+    static this(){
+        bundle = ResourceBundle.getBundle("dwtx.jface.messages"); //$NON-NLS-1$
+    }
 
     /**
      * The JFace color registry; <code>null</code> until lazily initialized or
@@ -96,13 +92,13 @@
      * The symbolic font name for the standard font (value
      * <code>"dwtx.jface.defaultfont"</code>).
      */
-    public static final String DEFAULT_FONT = "dwtx.jface.defaultfont"; //$NON-NLS-1$
+    public static const String DEFAULT_FONT = "dwtx.jface.defaultfont"; //$NON-NLS-1$
 
     /**
      * The symbolic font name for the dialog font (value
      * <code>"dwtx.jface.dialogfont"</code>).
      */
-    public static final String DIALOG_FONT = "dwtx.jface.dialogfont"; //$NON-NLS-1$
+    public static const String DIALOG_FONT = "dwtx.jface.dialogfont"; //$NON-NLS-1$
 
     /**
      * The JFace font registry; <code>null</code> until lazily initialized or
@@ -114,7 +110,7 @@
      * The symbolic font name for the header font (value
      * <code>"dwtx.jface.headerfont"</code>).
      */
-    public static final String HEADER_FONT = "dwtx.jface.headerfont"; //$NON-NLS-1$
+    public static const String HEADER_FONT = "dwtx.jface.headerfont"; //$NON-NLS-1$
 
     /**
      * The JFace image registry; <code>null</code> until lazily initialized.
@@ -125,7 +121,7 @@
      * The symbolic font name for the text font (value
      * <code>"dwtx.jface.textfont"</code>).
      */
-    public static final String TEXT_FONT = "dwtx.jface.textfont"; //$NON-NLS-1$
+    public static const String TEXT_FONT = "dwtx.jface.textfont"; //$NON-NLS-1$
 
     /**
      * The symbolic font name for the viewer font (value
@@ -133,7 +129,7 @@
      *
      * @deprecated This font is not in use
      */
-    public static final String VIEWER_FONT = "dwtx.jface.viewerfont"; //$NON-NLS-1$
+    public static const String VIEWER_FONT = "dwtx.jface.viewerfont"; //$NON-NLS-1$
 
     /**
      * The symbolic font name for the window font (value
@@ -141,7 +137,7 @@
      *
      * @deprecated This font is not in use
      */
-    public static final String WINDOW_FONT = "dwtx.jface.windowfont"; //$NON-NLS-1$
+    public static const String WINDOW_FONT = "dwtx.jface.windowfont"; //$NON-NLS-1$
 
     /**
      * Returns the formatted message for the given key in JFace's resource
@@ -154,7 +150,7 @@
      * @return the string
      */
     public static String format(String key, Object[] args) {
-        return MessageFormat.format(getString(key), args);
+        return Format(getString(key), args);
     }
 
     /**
@@ -208,14 +204,17 @@
      *            display to query
      * @return the global resource manager for the given display
      */
-    public static ResourceManager getResources(final Display toQuery) {
-        ResourceManager reg = (ResourceManager) registries.get(toQuery);
+    public static ResourceManager getResources(Display toQuery) {
+        ResourceManager reg = cast(ResourceManager) registries.get(toQuery);
 
         if (reg is null) {
-            final DeviceResourceManager mgr = new DeviceResourceManager(toQuery);
-            reg = mgr;
-            registries.put(toQuery, reg);
-            toQuery.disposeExec(new Runnable() {
+            toQuery.disposeExec(new class Runnable {
+                DeviceResourceManager mgr;
+                this(){
+                    mgr = new DeviceResourceManager(toQuery);
+                    reg = mgr;
+                    registries.add(toQuery, reg);
+                }
                 /*
                  * (non-Javadoc)
                  *
@@ -223,7 +222,7 @@
                  */
                 public void run() {
                     mgr.dispose();
-                    registries.remove(toQuery);
+                    registries.removeKey(toQuery);
                 }
             });
         }
@@ -425,33 +424,33 @@
     private static void initializeDefaultImages() {
 
         Object bundle = null;
-        try {
-//FIXME
+// DWT-Note: deactivated
+//         try {
 //          bundle = JFaceActivator.getBundle();
-        } catch (NoClassDefFoundError exception) {
-            // Test to see if OSGI is present
-        }
-        declareImage(bundle, Wizard.DEFAULT_IMAGE, ICONS_PATH + "page.gif", //$NON-NLS-1$
-                Wizard.class, "images/page.gif"); //$NON-NLS-1$
+//         } catch (NoClassDefFoundError exception) {
+//             // Test to see if OSGI is present
+//         }
+        declareImage(bundle, Wizard.DEFAULT_IMAGE, ICONS_PATH ~ "page.gif", //$NON-NLS-1$
+                Wizard.classinfo, "images/page.gif"); //$NON-NLS-1$
 
         // register default images for dialogs
         declareImage(bundle, Dialog.DLG_IMG_MESSAGE_INFO, ICONS_PATH
-                + "message_info.gif", Dialog.class, "images/message_info.gif"); //$NON-NLS-1$ //$NON-NLS-2$
+                ~ "message_info.gif", Dialog.classinfo, "images/message_info.gif"); //$NON-NLS-1$ //$NON-NLS-2$
         declareImage(bundle, Dialog.DLG_IMG_MESSAGE_WARNING, ICONS_PATH
-                + "message_warning.gif", Dialog.class, //$NON-NLS-1$
+                ~ "message_warning.gif", Dialog.classinfo, //$NON-NLS-1$
                 "images/message_warning.gif"); //$NON-NLS-1$
         declareImage(bundle, Dialog.DLG_IMG_MESSAGE_ERROR, ICONS_PATH
-                + "message_error.gif", Dialog.class, "images/message_error.gif");//$NON-NLS-1$ //$NON-NLS-2$
+                ~ "message_error.gif", Dialog.classinfo, "images/message_error.gif");//$NON-NLS-1$ //$NON-NLS-2$
         declareImage(bundle, Dialog.DLG_IMG_HELP, ICONS_PATH
-                + "help.gif", Dialog.class, "images/help.gif");//$NON-NLS-1$ //$NON-NLS-2$
+                ~ "help.gif", Dialog.classinfo, "images/help.gif");//$NON-NLS-1$ //$NON-NLS-2$
         declareImage(
                 bundle,
                 TitleAreaDialog.DLG_IMG_TITLE_BANNER,
-                ICONS_PATH + "title_banner.png", TitleAreaDialog.class, "images/title_banner.gif");//$NON-NLS-1$ //$NON-NLS-2$
+                ICONS_PATH ~ "title_banner.png", TitleAreaDialog.classinfo, "images/title_banner.gif");//$NON-NLS-1$ //$NON-NLS-2$
         declareImage(
                 bundle,
                 PreferenceDialog.PREF_DLG_TITLE_IMG,
-                ICONS_PATH + "pref_dialog_title.gif", PreferenceDialog.class, "images/pref_dialog_title.gif");//$NON-NLS-1$ //$NON-NLS-2$
+                ICONS_PATH ~ "pref_dialog_title.gif", PreferenceDialog.classinfo, "images/pref_dialog_title.gif");//$NON-NLS-1$ //$NON-NLS-2$
 
     }
 
@@ -476,7 +475,7 @@
      *
      */
     private static final void declareImage(Object bundle, String key,
-            String path, Class fallback, String fallbackPath) {
+            String path, ClassInfo fallback, String fallbackPath) {
 
 
         ImageDescriptor descriptor = null;
@@ -522,10 +521,10 @@
      * @return a list of corresponding string values
      */
     public static String[] getStrings(String[] keys) {
-        Assert.isNotNull(keys);
-        int length = keys.length;
-        String[] result = new String[length];
-        for (int i = 0; i < length; i++) {
+        Assert.isTrue(keys.length > 0 );
+        int length_ = keys.length;
+        String[] result = new String[](length_);
+        for (int i = 0; i < length_; i++) {
             result[i] = getString(keys[i]);
         }
         return result;
@@ -591,8 +590,7 @@
     /*
      * (non-Javadoc) Declare a private constructor to block instantiation.
      */
-    private JFaceResources() {
+    private this() {
         // no-op
     }
 }
-++/
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/resource/LocalResourceManager.d	Sat Mar 29 02:25:12 2008 +0100
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * 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.LocalResourceManager;
+
+import dwtx.jface.resource.AbstractResourceManager;
+import dwtx.jface.resource.ResourceManager;
+import dwtx.jface.resource.DeviceResourceDescriptor;
+
+import dwt.events.DisposeEvent;
+import dwt.events.DisposeListener;
+import dwt.graphics.Device;
+import dwt.graphics.Image;
+import dwt.widgets.Control;
+
+import dwt.dwthelper.utils;
+
+/**
+ * A local registry that shares its resources with some global registry.
+ * LocalResourceManager is typically used to safeguard against leaks. Clients
+ * can use a nested registry to allocate and deallocate resources in the
+ * global registry. Calling dispose() on the nested registry will deallocate
+ * everything allocated for the nested registry without affecting the rest
+ * of the global registry.
+ * <p>
+ * A nested registry can be used to manage the resources for, say, a dialog
+ * box.
+ * </p>
+ * @since 3.1
+ */
+public final class LocalResourceManager : AbstractResourceManager {
+
+    private ResourceManager parentRegistry;
+
+    /**
+     * Creates a local registry that delegates to the given global registry
+     * for all resource allocation and deallocation.
+     *
+     * @param parentRegistry global registry
+     */
+    public this(ResourceManager parentRegistry) {
+        this.parentRegistry = parentRegistry;
+    }
+
+    /**
+     * Creates a local registry that wraps the given global registry. Anything
+     * allocated by this registry will be automatically cleaned up with the given
+     * control is disposed. Note that registries created in this way should not
+     * be used to allocate any resource that must outlive the given control.
+     *
+     * @param parentRegistry global registry that handles resource allocation
+     * @param owner control whose disposal will trigger cleanup of everything
+     * in the registry.
+     */
+    public this(ResourceManager parentRegistry, Control owner) {
+        this(parentRegistry);
+
+        owner.addDisposeListener(new class DisposeListener {
+            /* (non-Javadoc)
+             * @see dwt.events.DisposeListener#widgetDisposed(dwt.events.DisposeEvent)
+             */
+            public void widgetDisposed(DisposeEvent e) {
+                this.outer.dispose();
+            }
+        });
+    }
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resource.ResourceManager#getDevice()
+     */
+    public Device getDevice() {
+        return parentRegistry.getDevice();
+    }
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resource.AbstractResourceManager#allocate(dwtx.jface.resource.DeviceResourceDescriptor)
+     */
+    protected Object allocate(DeviceResourceDescriptor descriptor) {
+        return parentRegistry.create(descriptor);
+    }
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resource.AbstractResourceManager#deallocate(java.lang.Object, dwtx.jface.resource.DeviceResourceDescriptor)
+     */
+    protected void deallocate(Object resource,
+            DeviceResourceDescriptor descriptor) {
+
+        parentRegistry.destroy(descriptor);
+    }
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resource.ResourceManager#getDefaultImage()
+     */
+    protected Image getDefaultImage() {
+        return parentRegistry.getDefaultImage_();
+    }
+}
--- a/dwtx/jface/resource/ResourceManager.d	Sat Mar 29 01:25:27 2008 +0100
+++ b/dwtx/jface/resource/ResourceManager.d	Sat Mar 29 02:25:12 2008 +0100
@@ -228,6 +228,9 @@
      * image is missing.
      */
     protected abstract Image getDefaultImage();
+    package Image getDefaultImage_(){
+        return getDefaultImage();
+    }
 
     /**
      * Undoes everything that was done by {@link #createImage(ImageDescriptor)}.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/wizard/Wizard.d	Sat Mar 29 02:25:12 2008 +0100
@@ -0,0 +1,464 @@
+/*******************************************************************************
+ * 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.wizard.Wizard;
+
+import dwt.dwthelper.utils;
+pragma( msg, "FIXME dwtx.jface.wizard.Wizard");
+class Wizard {
+    public static final String DEFAULT_IMAGE = "dwtx.jface.wizard.Wizard.pageImage";//$NON-NLS-1$
+}
+/++
+import java.util.ArrayList;
+import java.util.List;
+
+import dwt.graphics.Image;
+import dwt.graphics.RGB;
+import dwt.widgets.Composite;
+import dwt.widgets.Shell;
+import dwtx.core.runtime.Assert;
+import dwtx.jface.dialogs.IDialogSettings;
+import dwtx.jface.resource.ImageDescriptor;
+import dwtx.jface.resource.JFaceResources;
+
+/**
+ * An abstract base implementation of a wizard. A typical client subclasses
+ * <code>Wizard</code> to implement a particular wizard.
+ * <p>
+ * Subclasses may call the following methods to configure the wizard:
+ * <ul>
+ * <li><code>addPage</code></li>
+ * <li><code>setHelpAvailable</code></li>
+ * <li><code>setDefaultPageImageDescriptor</code></li>
+ * <li><code>setDialogSettings</code></li>
+ * <li><code>setNeedsProgressMonitor</code></li>
+ * <li><code>setTitleBarColor</code></li>
+ * <li><code>setWindowTitle</code></li>
+ * </ul>
+ * </p>
+ * <p>
+ * Subclasses may override these methods if required:
+ * <ul>
+ * <li>reimplement <code>createPageControls</code></li>
+ * <li>reimplement <code>performCancel</code></li>
+ * <li>extend <code>addPages</code></li>
+ * <li>reimplement <code>performFinish</code></li>
+ * <li>extend <code>dispose</code></li>
+ * </ul>
+ * </p>
+ * <p>
+ * Note that clients are free to implement <code>IWizard</code> from scratch
+ * instead of subclassing <code>Wizard</code>. Correct implementations of
+ * <code>IWizard</code> will work with any correct implementation of
+ * <code>IWizardPage</code>.
+ * </p>
+ */
+public abstract class Wizard implements IWizard {
+    /**
+     * Image registry key of the default image for wizard pages (value
+     * <code>"dwtx.jface.wizard.Wizard.pageImage"</code>).
+     */
+    public static final String DEFAULT_IMAGE = "dwtx.jface.wizard.Wizard.pageImage";//$NON-NLS-1$
+
+    /**
+     * The wizard container this wizard belongs to; <code>null</code> if none.
+     */
+    private IWizardContainer container = null;
+
+    /**
+     * This wizard's list of pages (element type: <code>IWizardPage</code>).
+     */
+    private List pages = new ArrayList();
+
+    /**
+     * Indicates whether this wizard needs a progress monitor.
+     */
+    private bool needsProgressMonitor = false;
+
+    /**
+     * Indicates whether this wizard needs previous and next buttons even if the
+     * wizard has only one page.
+     */
+    private bool forcePreviousAndNextButtons = false;
+
+    /**
+     * Indicates whether this wizard supports help.
+     */
+    private bool isHelpAvailable = false;
+
+    /**
+     * The default page image for pages without one of their one;
+     * <code>null</code> if none.
+     */
+    private Image defaultImage = null;
+
+    /**
+     * The default page image descriptor, used for creating a default page image
+     * if required; <code>null</code> if none.
+     */
+    private ImageDescriptor defaultImageDescriptor = JFaceResources.getImageRegistry().getDescriptor(DEFAULT_IMAGE);
+
+    /**
+     * The color of the wizard title bar; <code>null</code> if none.
+     */
+    private RGB titleBarColor = null;
+
+    /**
+     * The window title string for this wizard; <code>null</code> if none.
+     */
+    private String windowTitle = null;
+
+    /**
+     * The dialog settings for this wizard; <code>null</code> if none.
+     */
+    private IDialogSettings dialogSettings = null;
+
+    /**
+     * Creates a new empty wizard.
+     */
+    protected Wizard() {
+        super();
+    }
+
+    /**
+     * Adds a new page to this wizard. The page is inserted at the end of the
+     * page list.
+     *
+     * @param page
+     *            the new page
+     */
+    public void addPage(IWizardPage page) {
+        pages.add(page);
+        page.setWizard(this);
+    }
+
+    /**
+     * The <code>Wizard</code> implementation of this <code>IWizard</code>
+     * method does nothing. Subclasses should extend if extra pages need to be
+     * added before the wizard opens. New pages should be added by calling
+     * <code>addPage</code>.
+     */
+    public void addPages() {
+    }
+
+    /*
+     * (non-Javadoc) Method declared on IWizard.
+     */
+    public bool canFinish() {
+        // Default implementation is to check if all pages are complete.
+        for (int i = 0; i < pages.size(); i++) {
+            if (!((IWizardPage) pages.get(i)).isPageComplete()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * The <code>Wizard</code> implementation of this <code>IWizard</code>
+     * method creates all the pages controls using
+     * <code>IDialogPage.createControl</code>. Subclasses should reimplement
+     * this method if they want to delay creating one or more of the pages
+     * lazily. The framework ensures that the contents of a page will be created
+     * before attempting to show it.
+     */
+    public void createPageControls(Composite pageContainer) {
+        // the default behavior is to create all the pages controls
+        for (int i = 0; i < pages.size(); i++) {
+            IWizardPage page = (IWizardPage) pages.get(i);
+            page.createControl(pageContainer);
+            // page is responsible for ensuring the created control is
+            // accessable
+            // via getControl.
+            Assert.isNotNull(page.getControl());
+        }
+    }
+
+    /**
+     * The <code>Wizard</code> implementation of this <code>IWizard</code>
+     * method disposes all the pages controls using
+     * <code>DialogPage.dispose</code>. Subclasses should extend this method
+     * if the wizard instance maintains addition DWT resource that need to be
+     * disposed.
+     */
+    public void dispose() {
+        // notify pages
+        for (int i = 0; i < pages.size(); i++) {
+            ((IWizardPage) pages.get(i)).dispose();
+        }
+        // dispose of image
+        if (defaultImage !is null) {
+            JFaceResources.getResources().destroyImage(defaultImageDescriptor);
+            defaultImage = null;
+        }
+    }
+
+    /*
+     * (non-Javadoc) Method declared on IWizard.
+     */
+    public IWizardContainer getContainer() {
+        return container;
+    }
+
+    /*
+     * (non-Javadoc) Method declared on IWizard.
+     */
+    public Image getDefaultPageImage() {
+        if (defaultImage is null) {
+            defaultImage = JFaceResources.getResources().createImageWithDefault(defaultImageDescriptor);
+        }
+        return defaultImage;
+    }
+
+    /*
+     * (non-Javadoc) Method declared on IWizard.
+     */
+    public IDialogSettings getDialogSettings() {
+        return dialogSettings;
+    }
+
+    /*
+     * (non-Javadoc) Method declared on IWizard. The default behavior is to
+     * return the page that was added to this wizard after the given page.
+     */
+    public IWizardPage getNextPage(IWizardPage page) {
+        int index = pages.indexOf(page);
+        if (index is pages.size() - 1 || index is -1) {
+            // last page or page not found
+            return null;
+        }
+        return (IWizardPage) pages.get(index + 1);
+    }
+
+    /*
+     * (non-Javadoc) Method declared on IWizard.
+     */
+    public IWizardPage getPage(String name) {
+        for (int i = 0; i < pages.size(); i++) {
+            IWizardPage page = (IWizardPage) pages.get(i);
+            String pageName = page.getName();
+            if (pageName.equals(name)) {
+                return page;
+            }
+        }
+        return null;
+    }
+
+    /*
+     * (non-Javadoc) Method declared on IWizard.
+     */
+    public int getPageCount() {
+        return pages.size();
+    }
+
+    /*
+     * (non-Javadoc) Method declared on IWizard.
+     */
+    public IWizardPage[] getPages() {
+        return (IWizardPage[]) pages.toArray(new IWizardPage[pages.size()]);
+    }
+
+    /*
+     * (non-Javadoc) Method declared on IWizard. The default behavior is to
+     * return the page that was added to this wizard before the given page.
+     */
+    public IWizardPage getPreviousPage(IWizardPage page) {
+        int index = pages.indexOf(page);
+        if (index is 0 || index is -1) {
+            // first page or page not found
+            return null;
+        }
+        return (IWizardPage) pages.get(index - 1);
+    }
+
+    /**
+     * Returns the wizard's shell if the wizard is visible. Otherwise
+     * <code>null</code> is returned.
+     *
+     * @return Shell
+     */
+    public Shell getShell() {
+        if (container is null) {
+            return null;
+        }
+        return container.getShell();
+    }
+
+    /*
+     * (non-Javadoc) Method declared on IWizard. By default this is the first
+     * page inserted into the wizard.
+     */
+    public IWizardPage getStartingPage() {
+        if (pages.size() is 0) {
+            return null;
+        }
+        return (IWizardPage) pages.get(0);
+    }
+
+    /*
+     * (non-Javadoc) Method declared on IWizard.
+     */
+    public RGB getTitleBarColor() {
+        return titleBarColor;
+    }
+
+    /*
+     * (non-Javadoc) Method declared on IWizard.
+     */
+    public String getWindowTitle() {
+        return windowTitle;
+    }
+
+    /*
+     * (non-Javadoc) Method declared on IWizard.
+     */
+    public bool isHelpAvailable() {
+        return isHelpAvailable;
+    }
+
+    /*
+     * (non-Javadoc) Method declared on IWizard.
+     */
+    public bool needsPreviousAndNextButtons() {
+        return forcePreviousAndNextButtons || pages.size() > 1;
+    }
+
+    /*
+     * (non-Javadoc) Method declared on IWizard.
+     */
+    public bool needsProgressMonitor() {
+        return needsProgressMonitor;
+    }
+
+    /**
+     * The <code>Wizard</code> implementation of this <code>IWizard</code>
+     * method does nothing and returns <code>true</code>. Subclasses should
+     * reimplement this method if they need to perform any special cancel
+     * processing for their wizard.
+     */
+    public bool performCancel() {
+        return true;
+    }
+
+    /**
+     * Subclasses must implement this <code>IWizard</code> method to perform
+     * any special finish processing for their wizard.
+     */
+    public abstract bool performFinish();
+
+    /*
+     * (non-Javadoc) Method declared on IWizard.
+     */
+    public void setContainer(IWizardContainer wizardContainer) {
+        container = wizardContainer;
+    }
+
+    /**
+     * Sets the default page image descriptor for this wizard.
+     * <p>
+     * This image descriptor will be used to generate an image for a page with
+     * no image of its own; the image will be computed once and cached.
+     * </p>
+     *
+     * @param imageDescriptor
+     *            the default page image descriptor
+     */
+    public void setDefaultPageImageDescriptor(ImageDescriptor imageDescriptor) {
+        defaultImageDescriptor = imageDescriptor;
+    }
+
+    /**
+     * Sets the dialog settings for this wizard.
+     * <p>
+     * The dialog settings is used to record state between wizard invocations
+     * (for example, radio button selection, last import directory, etc.)
+     * </p>
+     *
+     * @param settings
+     *            the dialog settings, or <code>null</code> if none
+     * @see #getDialogSettings
+     *
+     */
+    public void setDialogSettings(IDialogSettings settings) {
+        dialogSettings = settings;
+    }
+
+    /**
+     * Controls whether the wizard needs Previous and Next buttons even if it
+     * currently contains only one page.
+     * <p>
+     * This flag should be set on wizards where the first wizard page adds
+     * follow-on wizard pages based on user input.
+     * </p>
+     *
+     * @param b
+     *            <code>true</code> to always show Next and Previous buttons,
+     *            and <code>false</code> to suppress Next and Previous buttons
+     *            for single page wizards
+     */
+    public void setForcePreviousAndNextButtons(bool b) {
+        forcePreviousAndNextButtons = b;
+    }
+
+    /**
+     * Sets whether help is available for this wizard.
+     * <p>
+     * The result of this method is typically used by the container to show or
+     * hide the Help button.
+     * </p>
+     *
+     * @param b
+     *            <code>true</code> if help is available, and
+     *            <code>false</code> if this wizard is helpless
+     * @see #isHelpAvailable()
+     */
+    public void setHelpAvailable(bool b) {
+        isHelpAvailable = b;
+    }
+
+    /**
+     * Sets whether this wizard needs a progress monitor.
+     *
+     * @param b
+     *            <code>true</code> if a progress monitor is required, and
+     *            <code>false</code> if none is needed
+     * @see #needsProgressMonitor()
+     */
+    public void setNeedsProgressMonitor(bool b) {
+        needsProgressMonitor = b;
+    }
+
+    /**
+     * Sets the title bar color for this wizard.
+     *
+     * @param color
+     *            the title bar color
+     */
+    public void setTitleBarColor(RGB color) {
+        titleBarColor = color;
+    }
+
+    /**
+     * Sets the window title for the container that hosts this page to the given
+     * string.
+     *
+     * @param newTitle
+     *            the window title for the container
+     */
+    public void setWindowTitle(String newTitle) {
+        windowTitle = newTitle;
+        if (container !is null) {
+            container.updateWindowTitle();
+        }
+    }
+}
+++/
\ No newline at end of file
--- a/dwtx/jface/wizard/WizardDialog.d	Sat Mar 29 01:25:27 2008 +0100
+++ b/dwtx/jface/wizard/WizardDialog.d	Sat Mar 29 02:25:12 2008 +0100
@@ -12,7 +12,7 @@
  *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
 module dwtx.jface.wizard.WizardDialog;
-
+pragma( msg, "FIXME dwtx.jface.wizard.WizardDialog");
 class WizardDialog {
 }