changeset 13:6886832e1ed8

ErrorDialog
author Frank Benoit <benoit@tionex.de>
date Mon, 31 Mar 2008 01:41:52 +0200
parents 8ec40848221b
children cf7413989c65
files dwtx/jface/dialogs/ErrorDialog.d dwtx/jface/dialogs/IconAndMessageDialog.d dwtx/jface/layout/GridDataFactory.d dwtx/jface/layout/GridLayoutFactory.d dwtx/jface/layout/LayoutConstants.d dwtx/jface/layout/LayoutGenerator.d dwtx/jface/resource/JFaceResources.d
diffstat 7 files changed, 2156 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/dialogs/ErrorDialog.d	Mon Mar 31 01:41:52 2008 +0200
@@ -0,0 +1,684 @@
+/*******************************************************************************
+ * 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
+ *      Sebastian Davids <sdavids@gmx.de> - Fix for bug 19346 - Dialog font should
+ *          be activated and used by other components.
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.dialogs.ErrorDialog;
+
+import dwtx.jface.dialogs.IconAndMessageDialog;
+import dwtx.jface.dialogs.IDialogConstants;
+import dwtx.jface.dialogs.ErrorSupportProvider;
+
+import dwt.DWT;
+import dwt.dnd.Clipboard;
+import dwt.dnd.TextTransfer;
+import dwt.dnd.Transfer;
+import dwt.events.SelectionEvent;
+import dwt.events.SelectionListener;
+import dwt.graphics.Image;
+import dwt.graphics.Point;
+import dwt.layout.GridData;
+import dwt.layout.GridLayout;
+import dwt.widgets.Button;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Label;
+import dwt.widgets.List;
+import dwt.widgets.Menu;
+import dwt.widgets.MenuItem;
+import dwt.widgets.Shell;
+import dwtx.core.runtime.CoreException;
+import dwtx.core.runtime.IStatus;
+import dwtx.jface.resource.JFaceResources;
+import dwtx.jface.util.Policy;
+
+import dwt.dwthelper.utils;
+static import tango.text.Text;
+alias tango.text.Text.Text!(char) StringBuffer;
+/**
+ * A dialog to display one or more errors to the user, as contained in an
+ * <code>IStatus</code> object. If an error contains additional detailed
+ * information then a Details button is automatically supplied, which shows or
+ * hides an error details viewer when pressed by the user.
+ *
+ * @see dwtx.core.runtime.IStatus
+ */
+public class ErrorDialog : IconAndMessageDialog {
+    /**
+     * Static to prevent opening of error dialogs for automated testing.
+     */
+    public static bool AUTOMATED_MODE = false;
+
+    /**
+     * Reserve room for this many list items.
+     */
+    private static const int LIST_ITEM_COUNT = 7;
+
+    /**
+     * The nesting indent.
+     */
+    private static const String NESTING_INDENT = "  "; //$NON-NLS-1$
+
+    /**
+     * The Details button.
+     */
+    private Button detailsButton;
+
+    /**
+     * The title of the dialog.
+     */
+    private String title;
+
+    /**
+     * The DWT list control that displays the error details.
+     */
+    private List list;
+
+    /**
+     * Indicates whether the error details viewer is currently created.
+     */
+    private bool listCreated = false;
+
+    /**
+     * Filter mask for determining which status items to display.
+     */
+    private int displayMask = 0xFFFF;
+
+    /**
+     * The main status object.
+     */
+    private IStatus status;
+
+    /**
+     * The current clipboard. To be disposed when closing the dialog.
+     */
+    private Clipboard clipboard;
+
+    private bool shouldIncludeTopLevelErrorInDetails = false;
+
+
+    /**
+     * Creates an error dialog. Note that the dialog will have no visual
+     * representation (no widgets) until it is told to open.
+     * <p>
+     * Normally one should use <code>openError</code> to create and open one
+     * of these. This constructor is useful only if the error object being
+     * displayed contains child items <it>and </it> you need to specify a mask
+     * which will be used to filter the displaying of these children. The error
+     * dialog will only be displayed if there is at least one child status
+     * matching the mask.
+     * </p>
+     *
+     * @param parentShell
+     *            the shell under which to create this dialog
+     * @param dialogTitle
+     *            the title to use for this dialog, or <code>null</code> to
+     *            indicate that the default title should be used
+     * @param message
+     *            the message to show in this dialog, or <code>null</code> to
+     *            indicate that the error's message should be shown as the
+     *            primary message
+     * @param status
+     *            the error to show to the user
+     * @param displayMask
+     *            the mask to use to filter the displaying of child items, as
+     *            per <code>IStatus.matches</code>
+     * @see dwtx.core.runtime.IStatus#matches(int)
+     */
+    public this(Shell parentShell, String dialogTitle, String message,
+            IStatus status, int displayMask) {
+        super(parentShell);
+        this.title = dialogTitle is null ? JFaceResources
+                .getString("Problem_Occurred") : //$NON-NLS-1$
+                dialogTitle;
+        this.message = message is null ? status.getMessage()
+                : JFaceResources
+                        .format(
+                                "Reason", [ message, status.getMessage() ]); //$NON-NLS-1$
+        this.status = status;
+        this.displayMask = displayMask;
+        setShellStyle(getShellStyle() | DWT.RESIZE);
+    }
+
+    /*
+     * (non-Javadoc) Method declared on Dialog. Handles the pressing of the Ok
+     * or Details button in this dialog. If the Ok button was pressed then close
+     * this dialog. If the Details button was pressed then toggle the displaying
+     * of the error details area. Note that the Details button will only be
+     * visible if the error being displayed specifies child details.
+     */
+    protected void buttonPressed(int id) {
+        if (id is IDialogConstants.DETAILS_ID) {
+            // was the details button pressed?
+            toggleDetailsArea();
+        } else {
+            super.buttonPressed(id);
+        }
+    }
+
+    /*
+     * (non-Javadoc) Method declared in Window.
+     */
+    protected void configureShell(Shell shell) {
+        super.configureShell(shell);
+        shell.setText(title);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwtx.jface.dialogs.Dialog#createButtonsForButtonBar(dwt.widgets.Composite)
+     */
+    protected void createButtonsForButtonBar(Composite parent) {
+        // create OK and Details buttons
+        createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL,
+                true);
+        createDetailsButton(parent);
+    }
+
+    /**
+     * Create the area for extra error support information.
+     *
+     * @param parent
+     */
+    private void createSupportArea(Composite parent) {
+
+        ErrorSupportProvider provider = Policy.getErrorSupportProvider();
+
+        if (provider is null)
+            return;
+
+        Composite supportArea = new Composite(parent, DWT.NONE);
+        provider.createSupportArea(supportArea, status);
+
+        GridData supportData = new GridData(DWT.FILL, DWT.FILL, true, true);
+        supportData.verticalSpan = 3;
+        supportArea.setLayoutData(supportData);
+        if (supportArea.getLayout() is null){
+            GridLayout layout = new GridLayout();
+            layout.marginWidth = 0;
+            layout.marginHeight = 0;
+            supportArea.setLayout(layout); // Give it a default layout if one isn't set
+        }
+
+
+    }
+
+    /**
+     * Create the details button if it should be included.
+     *
+     * @param parent
+     *            the parent composite
+     * @since 3.2
+     */
+    protected void createDetailsButton(Composite parent) {
+        if (shouldShowDetailsButton()) {
+            detailsButton = createButton(parent, IDialogConstants.DETAILS_ID,
+                    IDialogConstants.SHOW_DETAILS_LABEL, false);
+        }
+    }
+
+    /**
+     * This implementation of the <code>Dialog</code> framework method creates
+     * and lays out a composite. Subclasses that require a different dialog area
+     * may either override this method, or call the <code>super</code>
+     * implementation and add controls to the created composite.
+     */
+    protected Control createDialogArea(Composite parent) {
+        createMessageArea(parent);
+        createSupportArea(parent);
+        // create a composite with standard margins and spacing
+        Composite composite = new Composite(parent, DWT.NONE);
+        GridLayout layout = new GridLayout();
+        layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
+        layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
+        layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
+        layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
+        layout.numColumns = 2;
+        composite.setLayout(layout);
+        GridData childData = new GridData(GridData.FILL_BOTH);
+        childData.horizontalSpan = 2;
+        composite.setLayoutData(childData);
+        composite.setFont(parent.getFont());
+
+        return composite;
+    }
+
+    /*
+     * @see IconAndMessageDialog#createDialogAndButtonArea(Composite)
+     */
+    protected void createDialogAndButtonArea(Composite parent) {
+        super.createDialogAndButtonArea(parent);
+        if ( auto dialogComposite = cast(Composite)this.dialogArea ) {
+            // Create a label if there are no children to force a smaller layout
+            if (dialogComposite.getChildren().length is 0) {
+                new Label(dialogComposite, DWT.NULL);
+            }
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwtx.jface.dialogs.IconAndMessageDialog#getImage()
+     */
+    protected Image getImage() {
+        if (status !is null) {
+            if (status.getSeverity() is IStatus.WARNING) {
+                return getWarningImage();
+            }
+            if (status.getSeverity() is IStatus.INFO) {
+                return getInfoImage();
+            }
+        }
+        // If it was not a warning or an error then return the error image
+        return getErrorImage();
+    }
+
+    /**
+     * Create this dialog's drop-down list component.
+     *
+     * @param parent
+     *            the parent composite
+     * @return the drop-down list component
+     */
+    protected List createDropDownList(Composite parent) {
+        // create the list
+        list = new List(parent, DWT.BORDER | DWT.H_SCROLL | DWT.V_SCROLL
+                | DWT.MULTI);
+        // fill the list
+        populateList(list);
+        GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL
+                | GridData.GRAB_HORIZONTAL | GridData.VERTICAL_ALIGN_FILL
+                | GridData.GRAB_VERTICAL);
+        data.heightHint = list.getItemHeight() * LIST_ITEM_COUNT;
+        data.horizontalSpan = 2;
+        list.setLayoutData(data);
+        list.setFont(parent.getFont());
+        Menu copyMenu = new Menu(list);
+        MenuItem copyItem = new MenuItem(copyMenu, DWT.NONE);
+        copyItem.addSelectionListener(new class SelectionListener {
+            /*
+             * @see SelectionListener.widgetSelected (SelectionEvent)
+             */
+            public void widgetSelected(SelectionEvent e) {
+                copyToClipboard();
+            }
+
+            /*
+             * @see SelectionListener.widgetDefaultSelected(SelectionEvent)
+             */
+            public void widgetDefaultSelected(SelectionEvent e) {
+                copyToClipboard();
+            }
+        });
+        copyItem.setText(JFaceResources.getString("copy")); //$NON-NLS-1$
+        list.setMenu(copyMenu);
+        listCreated = true;
+        return list;
+    }
+
+    /*
+     * (non-Javadoc) Method declared on Window.
+     */
+    /**
+     * Extends <code>Window.open()</code>. Opens an error dialog to display
+     * the error. If you specified a mask to filter the displaying of these
+     * children, the error dialog will only be displayed if there is at least
+     * one child status matching the mask.
+     */
+    public int open() {
+        if (!AUTOMATED_MODE && shouldDisplay(status, displayMask)) {
+            return super.open();
+        }
+        setReturnCode(OK);
+        return OK;
+    }
+
+    /**
+     * Opens an error dialog to display the given error. Use this method if the
+     * error object being displayed does not contain child items, or if you wish
+     * to display all such items without filtering.
+     *
+     * @param parent
+     *            the parent shell of the dialog, or <code>null</code> if none
+     * @param dialogTitle
+     *            the title to use for this dialog, or <code>null</code> to
+     *            indicate that the default title should be used
+     * @param message
+     *            the message to show in this dialog, or <code>null</code> to
+     *            indicate that the error's message should be shown as the
+     *            primary message
+     * @param status
+     *            the error to show to the user
+     * @return the code of the button that was pressed that resulted in this
+     *         dialog closing. This will be <code>Dialog.OK</code> if the OK
+     *         button was pressed, or <code>Dialog.CANCEL</code> if this
+     *         dialog's close window decoration or the ESC key was used.
+     */
+    public static int openError(Shell parent, String dialogTitle,
+            String message, IStatus status) {
+        return openError(parent, dialogTitle, message, status, IStatus.OK
+                | IStatus.INFO | IStatus.WARNING | IStatus.ERROR);
+    }
+
+    /**
+     * Opens an error dialog to display the given error. Use this method if the
+     * error object being displayed contains child items <it>and </it> you wish
+     * to specify a mask which will be used to filter the displaying of these
+     * children. The error dialog will only be displayed if there is at least
+     * one child status matching the mask.
+     *
+     * @param parentShell
+     *            the parent shell of the dialog, or <code>null</code> if none
+     * @param title
+     *            the title to use for this dialog, or <code>null</code> to
+     *            indicate that the default title should be used
+     * @param message
+     *            the message to show in this dialog, or <code>null</code> to
+     *            indicate that the error's message should be shown as the
+     *            primary message
+     * @param status
+     *            the error to show to the user
+     * @param displayMask
+     *            the mask to use to filter the displaying of child items, as
+     *            per <code>IStatus.matches</code>
+     * @return the code of the button that was pressed that resulted in this
+     *         dialog closing. This will be <code>Dialog.OK</code> if the OK
+     *         button was pressed, or <code>Dialog.CANCEL</code> if this
+     *         dialog's close window decoration or the ESC key was used.
+     * @see dwtx.core.runtime.IStatus#matches(int)
+     */
+    public static int openError(Shell parentShell, String title,
+            String message, IStatus status, int displayMask) {
+        ErrorDialog dialog = new ErrorDialog(parentShell, title, message,
+                status, displayMask);
+        return dialog.open();
+    }
+
+    /**
+     * Populates the list using this error dialog's status object. This walks
+     * the child static of the status object and displays them in a list. The
+     * format for each entry is status_path : status_message If the status's
+     * path was null then it (and the colon) are omitted.
+     *
+     * @param listToPopulate
+     *            The list to fill.
+     */
+    private void populateList(List listToPopulate) {
+        populateList(listToPopulate, status, 0,
+                shouldIncludeTopLevelErrorInDetails);
+    }
+
+    /**
+     * Populate the list with the messages from the given status. Traverse the
+     * children of the status deeply and also traverse CoreExceptions that
+     * appear in the status.
+     *
+     * @param listToPopulate
+     *            the list to populate
+     * @param buildingStatus
+     *            the status being displayed
+     * @param nesting
+     *            the nesting level (increases one level for each level of
+     *            children)
+     * @param includeStatus
+     *            whether to include the buildingStatus in the display or just
+     *            its children
+     */
+    private void populateList(List listToPopulate, IStatus buildingStatus,
+            int nesting, bool includeStatus) {
+
+        if (!buildingStatus.matches(displayMask)) {
+            return;
+        }
+
+        Exception t = buildingStatus.getException();
+        bool isCoreException = null !is cast(CoreException)t;
+        bool incrementNesting = false;
+
+        if (includeStatus) {
+            StringBuffer sb = new StringBuffer();
+            for (int i = 0; i < nesting; i++) {
+                sb.append(NESTING_INDENT);
+            }
+            String message = buildingStatus.getMessage();
+            sb.append(message);
+            listToPopulate.add(sb.toString());
+            incrementNesting = true;
+        }
+
+        if (!isCoreException && t !is null) {
+            // Include low-level exception message
+            StringBuffer sb = new StringBuffer();
+            for (int i = 0; i < nesting; i++) {
+                sb.append(NESTING_INDENT);
+            }
+            //TODO how about getLocalizedMessage?
+            //String message = t.getLocalizedMessage();
+            String message = t.msg;
+            if (message is null) {
+                message = t.toString();
+            }
+
+            sb.append(message);
+            listToPopulate.add(sb.toString());
+            incrementNesting = true;
+        }
+
+        if (incrementNesting) {
+            nesting++;
+        }
+
+        // Look for a nested core exception
+        if (isCoreException) {
+            CoreException ce = cast(CoreException) t;
+            IStatus eStatus = ce.getStatus();
+            // Only print the exception message if it is not contained in the
+            // parent message
+            if (message is null || message.indexOf(eStatus.getMessage()) is -1) {
+                populateList(listToPopulate, eStatus, nesting, true);
+            }
+        }
+
+        // Look for child status
+        IStatus[] children = buildingStatus.getChildren();
+        for (int i = 0; i < children.length; i++) {
+            populateList(listToPopulate, children[i], nesting, true);
+        }
+    }
+
+    /**
+     * Returns whether the given status object should be displayed.
+     *
+     * @param status
+     *            a status object
+     * @param mask
+     *            a mask as per <code>IStatus.matches</code>
+     * @return <code>true</code> if the given status should be displayed, and
+     *         <code>false</code> otherwise
+     * @see dwtx.core.runtime.IStatus#matches(int)
+     */
+    protected static bool shouldDisplay(IStatus status, int mask) {
+        IStatus[] children = status.getChildren();
+        if (children is null || children.length is 0) {
+            return status.matches(mask);
+        }
+        for (int i = 0; i < children.length; i++) {
+            if (children[i].matches(mask)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Toggles the unfolding of the details area. This is triggered by the user
+     * pressing the details button.
+     */
+    private void toggleDetailsArea() {
+        Point windowSize = getShell().getSize();
+        Point oldSize = getShell().computeSize(DWT.DEFAULT, DWT.DEFAULT);
+        if (listCreated) {
+            list.dispose();
+            listCreated = false;
+            detailsButton.setText(IDialogConstants.SHOW_DETAILS_LABEL);
+        } else {
+            list = createDropDownList(cast(Composite) getContents());
+            detailsButton.setText(IDialogConstants.HIDE_DETAILS_LABEL);
+        }
+        Point newSize = getShell().computeSize(DWT.DEFAULT, DWT.DEFAULT);
+        getShell()
+                .setSize(
+                        new Point(windowSize.x, windowSize.y
+                                + (newSize.y - oldSize.y)));
+    }
+
+    /**
+     * Put the details of the status of the error onto the stream.
+     *
+     * @param buildingStatus
+     * @param buffer
+     * @param nesting
+     */
+    private void populateCopyBuffer(IStatus buildingStatus,
+            StringBuffer buffer, int nesting) {
+        if (!buildingStatus.matches(displayMask)) {
+            return;
+        }
+        for (int i = 0; i < nesting; i++) {
+            buffer.append(NESTING_INDENT);
+        }
+        buffer.append(buildingStatus.getMessage());
+        buffer.append("\n"); //$NON-NLS-1$
+
+        // Look for a nested core exception
+        Exception t = buildingStatus.getException();
+        if ( auto ce = cast(CoreException)t ) {
+            populateCopyBuffer(ce.getStatus(), buffer, nesting + 1);
+        } else if (t !is null) {
+            // Include low-level exception message
+            for (int i = 0; i < nesting; i++) {
+                buffer.append(NESTING_INDENT);
+            }
+            //TODO: getLocalizedMessage?
+            String message = t.msg;
+            if (message is null) {
+                message = t.toString();
+            }
+            buffer.append(message);
+            buffer.append("\n"); //$NON-NLS-1$
+        }
+
+        IStatus[] children = buildingStatus.getChildren();
+        for (int i = 0; i < children.length; i++) {
+            populateCopyBuffer(children[i], buffer, nesting + 1);
+        }
+    }
+
+    /**
+     * Copy the contents of the statuses to the clipboard.
+     */
+    private void copyToClipboard() {
+        if (clipboard !is null) {
+            clipboard.dispose();
+        }
+        StringBuffer statusBuffer = new StringBuffer();
+        populateCopyBuffer(status, statusBuffer, 0);
+        clipboard = new Clipboard(list.getDisplay());
+        clipboard.setContents([ new ArrayWrapperString(statusBuffer.toString()) ],
+                [ TextTransfer.getInstance() ]);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwtx.jface.window.Window#close()
+     */
+    public bool close() {
+        if (clipboard !is null) {
+            clipboard.dispose();
+        }
+        return super.close();
+    }
+
+    /**
+     * Show the details portion of the dialog if it is not already visible. This
+     * method will only work when it is invoked after the control of the dialog
+     * has been set. In other words, after the <code>createContents</code>
+     * method has been invoked and has returned the control for the content area
+     * of the dialog. Invoking the method before the content area has been set
+     * or after the dialog has been disposed will have no effect.
+     *
+     * @since 3.1
+     */
+    protected final void showDetailsArea() {
+        if (!listCreated) {
+            Control control = getContents();
+            if (control !is null && !control.isDisposed()) {
+                toggleDetailsArea();
+            }
+        }
+    }
+
+    /**
+     * Return whether the Details button should be included. This method is
+     * invoked once when the dialog is built. By default, the Details button is
+     * only included if the status used when creating the dialog was a
+     * multi-status or if the status contains an exception. Subclasses may
+     * override.
+     *
+     * @return whether the Details button should be included
+     * @since 3.1
+     */
+    protected bool shouldShowDetailsButton() {
+        return status.isMultiStatus() || status.getException() !is null;
+    }
+
+    /**
+     * Set the status displayed by this error dialog to the given status. This
+     * only affects the status displayed by the Details list. The message, image
+     * and title should be updated by the subclass, if desired.
+     *
+     * @param status
+     *            the status to be displayed in the details list
+     * @since 3.1
+     */
+    protected final void setStatus(IStatus status) {
+        if (this.status !is status) {
+            this.status = status;
+        }
+        shouldIncludeTopLevelErrorInDetails = true;
+        if (listCreated) {
+            repopulateList();
+        }
+    }
+
+    /**
+     * Repopulate the supplied list widget.
+     */
+    private void repopulateList() {
+        if (list !is null && !list.isDisposed()) {
+            list.removeAll();
+            populateList(list);
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.dialogs.IconAndMessageDialog#getColumnCount()
+     */
+    int getColumnCount() {
+        if (Policy.getErrorSupportProvider() is null)
+            return 2;
+        return 3;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/dialogs/IconAndMessageDialog.d	Mon Mar 31 01:41:52 2008 +0200
@@ -0,0 +1,303 @@
+/*******************************************************************************
+ * 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
+ *     Stefan Xenos, IBM - bug 156790: Adopt GridLayoutFactory within JFace
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.dialogs.IconAndMessageDialog;
+
+import dwtx.jface.dialogs.Dialog;
+import dwtx.jface.dialogs.IDialogConstants;
+
+import dwt.DWT;
+import dwt.accessibility.AccessibleAdapter;
+import dwt.accessibility.AccessibleEvent;
+import dwt.graphics.Image;
+import dwt.graphics.Point;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Display;
+import dwt.widgets.Label;
+import dwt.widgets.Shell;
+import dwtx.jface.layout.GridDataFactory;
+import dwtx.jface.layout.GridLayoutFactory;
+import dwtx.jface.layout.LayoutConstants;
+import dwtx.jface.resource.JFaceResources;
+
+import dwt.dwthelper.utils;
+import dwt.dwthelper.Runnable;
+
+/**
+ * The IconAndMessageDialog is the abstract superclass of dialogs that have an
+ * icon and a message as the first two widgets. In this dialog the icon and
+ * message are direct children of the shell in order that they can be read by
+ * accessibility tools more easily.
+ */
+public abstract class IconAndMessageDialog : Dialog {
+    /**
+     * Message (a localized string).
+     */
+    protected String message;
+
+    /**
+     * Message label is the label the message is shown on.
+     */
+    protected Label messageLabel;
+
+    /**
+     * Return the label for the image.
+     */
+    protected Label imageLabel;
+
+    /**
+     * Constructor for IconAndMessageDialog.
+     *
+     * @param parentShell
+     *            the parent shell, or <code>null</code> to create a top-level
+     *            shell
+     */
+    public this(Shell parentShell) {
+        super(parentShell);
+    }
+
+    /**
+     * Create the area the message will be shown in.
+     * <p>
+     * The parent composite is assumed to use GridLayout as its layout manager,
+     * since the parent is typically the composite created in
+     * {@link Dialog#createDialogArea}.
+     * </p>
+     * @param composite
+     *            The composite to parent from.
+     * @return Control
+     */
+    protected Control createMessageArea(Composite composite) {
+        // create composite
+        // create image
+        Image image = getImage();
+        if (image !is null) {
+            imageLabel = new Label(composite, DWT.NULL);
+            image.setBackground(imageLabel.getBackground());
+            imageLabel.setImage(image);
+            addAccessibleListeners(imageLabel, image);
+            GridDataFactory.fillDefaults().align_(DWT.CENTER, DWT.BEGINNING)
+                    .applyTo(imageLabel);
+        }
+        // create message
+        if (message !is null) {
+            messageLabel = new Label(composite, getMessageLabelStyle());
+            messageLabel.setText(message);
+            GridDataFactory
+                    .fillDefaults()
+                    .align_(DWT.FILL, DWT.BEGINNING)
+                    .grab(true, false)
+                    .hint(
+                            convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH),
+                            DWT.DEFAULT).applyTo(messageLabel);
+        }
+        return composite;
+    }
+
+    private String getAccessibleMessageFor(Image image) {
+        if (image.opEquals(getErrorImage())) {
+            return JFaceResources.getString("error");//$NON-NLS-1$
+        }
+
+        if (image.opEquals(getWarningImage())) {
+            return JFaceResources.getString("warning");//$NON-NLS-1$
+        }
+
+        if (image.opEquals(getInfoImage())) {
+            return JFaceResources.getString("info");//$NON-NLS-1$
+        }
+
+        if (image.opEquals(getQuestionImage())) {
+            return JFaceResources.getString("question"); //$NON-NLS-1$
+        }
+
+        return null;
+    }
+
+    /**
+     * Add an accessible listener to the label if it can be inferred from the
+     * image.
+     *
+     * @param label
+     * @param image
+     */
+    private void addAccessibleListeners(Label label, Image image) {
+        label.getAccessible().addAccessibleListener(new class AccessibleAdapter {
+            Image image_;
+            this(){
+                image_ = image;
+            }
+            public void getName(AccessibleEvent event) {
+                String accessibleMessage = getAccessibleMessageFor(image_);
+                if (accessibleMessage is null) {
+                    return;
+                }
+                event.result = accessibleMessage;
+            }
+        });
+    }
+
+    /**
+     * Returns the style for the message label.
+     *
+     * @return the style for the message label
+     *
+     * @since 3.0
+     */
+    protected int getMessageLabelStyle() {
+        return DWT.WRAP;
+    }
+
+    /*
+     * @see Dialog.createButtonBar()
+     */
+    protected Control createButtonBar(Composite parent) {
+        Composite composite = new Composite(parent, DWT.NONE);
+        GridLayoutFactory.fillDefaults().numColumns(0) // this is incremented
+                                                        // by createButton
+                .equalWidth(true).applyTo(composite);
+
+        GridDataFactory.fillDefaults().align_(DWT.END, DWT.CENTER).span(
+                2, 1).applyTo(composite);
+        composite.setFont(parent.getFont());
+        // Add the buttons to the button bar.
+        createButtonsForButtonBar(composite);
+        return composite;
+    }
+
+    /**
+     * Returns the image to display beside the message in this dialog.
+     * <p>
+     * Subclasses may override.
+     * </p>
+     *
+     * @return the image to display beside the message
+     * @since 2.0
+     */
+    protected abstract Image getImage();
+
+    /*
+     * @see Dialog.createContents(Composite)
+     */
+    protected Control createContents(Composite parent) {
+        // initialize the dialog units
+        initializeDialogUnits(parent);
+        Point defaultMargins = LayoutConstants.getMargins();
+        Point defaultSpacing = LayoutConstants.getSpacing();
+        GridLayoutFactory.fillDefaults().margins(defaultMargins.x,
+                defaultMargins.y * 3 / 2).spacing(defaultSpacing.x * 2,
+                defaultSpacing.y).numColumns(getColumnCount()).applyTo(
+                parent);
+
+        GridDataFactory.fillDefaults().grab(true, true).applyTo(parent);
+        createDialogAndButtonArea(parent);
+        return parent;
+    }
+
+    /**
+     * Get the number of columns in the layout of the Shell of the dialog.
+     *
+     * @return int
+     * @since 3.3
+     */
+    int getColumnCount() {
+        return 2;
+    }
+
+    /**
+     * Create the dialog area and the button bar for the receiver.
+     *
+     * @param parent
+     */
+    protected void createDialogAndButtonArea(Composite parent) {
+        // create the dialog area and button bar
+        dialogArea = createDialogArea(parent);
+        buttonBar = createButtonBar(parent);
+        // Apply to the parent so that the message gets it too.
+        applyDialogFont(parent);
+    }
+
+    /**
+     * Return the <code>Image</code> to be used when displaying an error.
+     *
+     * @return image the error image
+     */
+    public Image getErrorImage() {
+        return getSWTImage(DWT.ICON_ERROR);
+    }
+
+    /**
+     * Return the <code>Image</code> to be used when displaying a warning.
+     *
+     * @return image the warning image
+     */
+    public Image getWarningImage() {
+        return getSWTImage(DWT.ICON_WARNING);
+    }
+
+    /**
+     * Return the <code>Image</code> to be used when displaying information.
+     *
+     * @return image the information image
+     */
+    public Image getInfoImage() {
+        return getSWTImage(DWT.ICON_INFORMATION);
+    }
+
+    /**
+     * Return the <code>Image</code> to be used when displaying a question.
+     *
+     * @return image the question image
+     */
+    public Image getQuestionImage() {
+        return getSWTImage(DWT.ICON_QUESTION);
+    }
+
+    /**
+     * Get an <code>Image</code> from the provide DWT image constant.
+     *
+     * @param imageID
+     *            the DWT image constant
+     * @return image the image
+     */
+    private Image getSWTImage(int imageID) {
+        Shell shell = getShell();
+        Display display;
+        if (shell is null) {
+            shell = getParentShell();
+        }
+        if (shell is null) {
+            display = Display.getCurrent();
+        } else {
+            display = shell.getDisplay();
+        }
+
+        Image[1] image;
+        display.syncExec(new class Runnable {
+            int imageID_;
+            Display display_;
+            this(){
+                display_=display;
+                imageID_=imageID;
+            }
+            public void run() {
+                image[0] = display_.getSystemImage(imageID_);
+            }
+        });
+
+        return image[0];
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/layout/GridDataFactory.d	Mon Mar 31 01:41:52 2008 +0200
@@ -0,0 +1,486 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 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
+ *     Stefan Xenos, IBM - initial implementation, bug 178888
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.layout.GridDataFactory;
+
+import dwtx.jface.layout.LayoutGenerator;
+
+import dwt.DWT;
+import dwt.graphics.Point;
+import dwt.layout.GridData;
+import dwt.widgets.Control;
+
+import dwt.dwthelper.utils;
+import tango.core.Exception;
+
+/**
+ * This class provides a convienient shorthand for creating and initializing
+ * GridData. This offers several benefits over creating GridData normal way:
+ *
+ * <ul>
+ * <li>The same factory can be used many times to create several GridData instances</li>
+ * <li>The setters on GridDataFactory all return "this", allowing them to be chained</li>
+ * <li>GridDataFactory uses vector setters (it accepts Points), making it easy to
+ *     set X and Y values together</li>
+ * </ul>
+ *
+ * <p>
+ * GridDataFactory instances are created using one of the static methods on this class.
+ * </p>
+ *
+ * <p>
+ * Example usage:
+ * </p>
+ * <code><pre>
+ *
+ * ////////////////////////////////////////////////////////////
+ * // Example 1: Typical grid data for a non-wrapping label
+ *
+ *     // GridDataFactory version
+ *     GridDataFactory.fillDefaults().applyTo(myLabel);
+ *
+ *     // Equivalent DWT version
+ *     GridData labelData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL);
+ *     myLabel.setLayoutData(labelData);
+ *
+ * ///////////////////////////////////////////////////////////
+ * // Example 2: Typical grid data for a wrapping label
+ *
+ *     // GridDataFactory version
+ *     GridDataFactory.fillDefaults()
+ *          .align(DWT.FILL, DWT.CENTER)
+ *          .hint(150, DWT.DEFAULT)
+ *          .grab(true, false)
+ *          .applyTo(wrappingLabel);
+ *
+ *     // Equivalent DWT version
+ *     GridData wrappingLabelData = new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_CENTER);
+ *     wrappingLabelData.minimumWidth = 1;
+ *     wrappingLabelData.widthHint = 150;
+ *     wrappingLabel.setLayoutData(wrappingLabelData);
+ *
+ * //////////////////////////////////////////////////////////////
+ * // Example 3: Typical grid data for a scrollable control (a list box, tree, table, etc.)
+ *
+ *     // GridDataFactory version
+ *     GridDataFactory.fillDefaults().grab(true, true).hint(150, 150).applyTo(listBox);
+ *
+ *     // Equivalent DWT version
+ *     GridData listBoxData = new GridData(GridData.FILL_BOTH);
+ *     listBoxData.widthHint = 150;
+ *     listBoxData.heightHint = 150;
+ *     listBoxData.minimumWidth = 1;
+ *     listBoxData.minimumHeight = 1;
+ *     listBox.setLayoutData(listBoxData);
+ *
+ * /////////////////////////////////////////////////////////////
+ * // Example 4: Typical grid data for a button
+ *
+ *     // GridDataFactory version
+ *     Point preferredSize = button.computeSize(DWT.DEFAULT, DWT.DEFAULT, false);
+ *     Point hint = Geometry.max(LayoutConstants.getMinButtonSize(), preferredSize);
+ *     GridDataFactory.fillDefaults().align(DWT.FILL, DWT.CENTER).hint(hint).applyTo(button);
+ *
+ *     // Equivalent DWT version
+ *     Point preferredSize = button.computeSize(DWT.DEFAULT, DWT.DEFAULT, false);
+ *     Point hint = Geometry.max(LayoutConstants.getMinButtonSize(), preferredSize);
+ *     GridData buttonData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_CENTER);
+ *     buttonData.widthHint = hint.x;
+ *     buttonData.heightHint = hint.y;
+ *     button.setLayoutData(buttonData);
+ *
+ * /////////////////////////////////////////////////////////////
+ * // Example 5: Generated GridData
+ *
+ *     // Generates GridData a wrapping label that spans 2 columns
+ *     GridDataFactory.generate(wrappingLabel, 2, 1);
+ *
+ *     // Generates GridData for a listbox. and adjusts the preferred size to 300x400 pixels
+ *     GridDataFactory.defaultsFor(listBox).hint(300, 400).applyTo(listBox);
+ *
+ *     // Generates GridData equivalent to example 4
+ *     GridDataFactory.generate(button, 1, 1);
+ *
+ * </pre></code>
+ *
+ * @since 3.2
+ */
+public final class GridDataFactory {
+    private GridData data;
+
+    /**
+     * Creates a GridDataFactory that creates copes of the given GridData.
+     *
+     * @param d template GridData to copy
+     */
+    private this(GridData d) {
+        this.data = d;
+    }
+
+    /**
+     * Creates a new GridDataFactory initialized with the DWT defaults.
+     * This factory will generate GridData that is equivalent to
+     * "new GridData()".
+     *
+     * <p>
+     * Initial values are:
+     * </p>
+     *
+     * <ul>
+     * <li>align(DWT.BEGINNING, DWT.CENTER)</li>
+     * <li>exclude(false)</li>
+     * <li>grab(false, false)</li>
+     * <li>hint(DWT.DEFAULT, DWT.DEFAULT)</li>
+     * <li>indent(0,0)</li>
+     * <li>minSize(0,0)</li>
+     * <li>span(1,1)</li>
+     * </ul>
+     *
+     * @return a new GridDataFactory instance
+     * @see #fillDefaults()
+     */
+    public static GridDataFactory swtDefaults() {
+        return new GridDataFactory(new GridData());
+    }
+
+    /**
+     * Creates a new GridDataFactory that creates copies of the given GridData
+     * by default.
+     *
+     * @param data GridData to copy
+     * @return a new GridDataFactory that creates copies of the argument by default
+     */
+    public static GridDataFactory createFrom(GridData data) {
+        return new GridDataFactory(copyData(data));
+    }
+
+    /**
+     * Creates a GridDataFactory initialized with defaults that will cause
+     * the control to fill its cell. The minimum size is set to the smallest possible
+     * minimum size supported by DWT. Currently, the smallest supported minimum size
+     * is (1,1) so this is the default. If GridLayout ever adds support for grid data
+     * with no minimum size, this will be changed to 0,0 in the future.
+     *
+     * <p>
+     * Initial values are:
+     * </p>
+     *
+     * <ul>
+     * <li>align(DWT.FILL, DWT.FILL)</li>
+     * <li>exclude(false)</li>
+     * <li>grab(false, false)</li>
+     * <li>hint(DWT.DEFAULT, DWT.DEFAULT)</li>
+     * <li>indent(0,0)</li>
+     * <li>minSize(1,1)</li>
+     * <li>span(1,1)</li>
+     * </ul>
+     *
+     * @return a GridDataFactory that makes controls fill their grid by default
+     *
+     * @see #swtDefaults()
+     */
+    public static GridDataFactory fillDefaults() {
+        GridData data = new GridData();
+        data.minimumWidth = 1;
+        data.minimumHeight = 1;
+        data.horizontalAlignment = DWT.FILL;
+        data.verticalAlignment = DWT.FILL;
+
+        return new GridDataFactory(data);
+    }
+
+    /**
+     * Returns a GridDataFactory initialized with heuristicly generated defaults for the given control.
+     * To be precise, this method picks the default values that GridLayoutFactory.generateLayout
+     * would have assigned to the control. Does not attach GridData to the control. Callers must
+     * additionally call applyTo(theControl) if they wish to use the generated values.
+     *
+     * <p>
+     * This method is intended for situations where generateLayout is generating layout data
+     * for a particular control that is not quite right for the desired layout.
+     * This allows callers to start with the generated values and tweak one or two settings
+     * before applying the GridData to the control.
+     * </p>
+     *
+     * @see GridLayoutFactory#generateLayout(dwt.widgets.Composite)
+     * @param theControl
+     * @return a GridLayoutFactory initialized with defaults that GridLayoutFactory would have
+     * @since 3.3
+     */
+    public static GridDataFactory defaultsFor(Control theControl) {
+        return LayoutGenerator.defaultsFor(theControl);
+    }
+
+    /**
+     * Generates layout data to the given control, given the number of cells
+     * spanned by the control. Attaches a GridData to the control. This method
+     * allows generated layout data to be used with controls that span multiple cells.
+     * <p>
+     * The generated layout data is the same as what would be generated by
+     * GridLayoutFactory.generateLayout, except that the span is configurable
+     * </p>
+     *
+     * @see GridLayoutFactory#generateLayout(dwt.widgets.Composite)
+     * @param theControl
+     * @param hSpan number of columns spanned by the control
+     * @param vSpan number of rows spanned by the control
+     * @since 3.3
+     */
+    public static void generate(Control theControl, int hSpan, int vSpan) {
+        defaultsFor(theControl).span(hSpan, vSpan).applyTo(theControl);
+    }
+
+    /**
+     * Generates layout data to the given control, given the number of cells
+     * spanned by the control. Attaches GridData to the control. This method
+     * allows generated layout data to be used with controls that span multiple cells.
+     * <p>
+     * The generated layout data is the same as what would be generated by
+     * GridLayoutFactory.generateLayout, except that the span is configurable
+     * </p>
+     *
+     * @see GridLayoutFactory#generateLayout(dwt.widgets.Composite)
+     * @param theControl
+     * @param span The x coordinate indicates the number of
+     * columns spanned, and the y coordinate indicates the number of rows.
+     * @since 3.3
+     */
+    public static void generate(Control theControl, Point span) {
+        defaultsFor(theControl).span(span).applyTo(theControl);
+    }
+
+    /**
+     * Sets the GridData span. The span controls how many cells
+     * are filled by the control.
+     *
+     * @param hSpan number of columns spanned by the control
+     * @param vSpan number of rows spanned by the control
+     * @return this
+     */
+    public GridDataFactory span(int hSpan, int vSpan) {
+        data.horizontalSpan = hSpan;
+        data.verticalSpan = vSpan;
+        return this;
+    }
+
+    /**
+     * Sets the GridData span. The span controls how many cells
+     * are filled by the control.
+     *
+     * @param span the new span. The x coordinate indicates the number of
+     * columns spanned, and the y coordinate indicates the number of rows.
+     * @return this
+     */
+    public GridDataFactory span(Point span) {
+        data.horizontalSpan = span.x;
+        data.verticalSpan = span.y;
+        return this;
+    }
+
+    /**
+     * Sets the width and height hints. The width and height hints override
+     * the control's preferred size. If either hint is set to DWT.DEFAULT,
+     * the control's preferred size is used.
+     *
+     * @param xHint horizontal hint (pixels), or DWT.DEFAULT to use the control's preferred size
+     * @param yHint vertical hint (pixels), or DWT.DEFAULT to use the control's preferred size
+     * @return this
+     */
+    public GridDataFactory hint(int xHint, int yHint) {
+        data.widthHint = xHint;
+        data.heightHint = yHint;
+        return this;
+    }
+
+    /**
+     * Sets the width and height hints. The width and height hints override
+     * the control's preferred size. If either hint is set to DWT.DEFAULT,
+     * the control's preferred size is used.
+     *
+     * @param hint size (pixels) to be used instead of the control's preferred size. If
+     * the x or y values are set to DWT.DEFAULT, the control's computeSize() method will
+     * be used to obtain that dimension of the preferred size.
+     * @return this
+     */
+    public GridDataFactory hint(Point hint) {
+        data.widthHint = hint.x;
+        data.heightHint = hint.y;
+        return this;
+    }
+
+    /**
+     * Sets the alignment of the control within its cell.
+     *
+     * @param hAlign horizontal alignment. One of DWT.BEGINNING, DWT.CENTER, DWT.END, or DWT.FILL.
+     * @param vAlign vertical alignment. One of DWT.BEGINNING, DWT.CENTER, DWT.END, or DWT.FILL.
+     * @return this
+     */
+    public GridDataFactory align_(int hAlign, int vAlign) {
+        if (hAlign !is DWT.BEGINNING && hAlign !is DWT.CENTER && hAlign !is GridData.CENTER && hAlign !is DWT.END && hAlign !is GridData.END && hAlign !is DWT.FILL && hAlign !is DWT.LEFT && hAlign !is DWT.RIGHT) {
+            throw new IllegalArgumentException(null);
+        }
+        if (vAlign !is DWT.BEGINNING && vAlign !is DWT.CENTER && vAlign !is GridData.CENTER && vAlign !is DWT.END && vAlign !is GridData.END && vAlign !is DWT.FILL && vAlign !is DWT.TOP && vAlign !is DWT.BOTTOM) {
+            throw new IllegalArgumentException(null);
+        }
+        data.horizontalAlignment = hAlign;
+        data.verticalAlignment = vAlign;
+        return this;
+    }
+
+    /**
+     * Sets the indent of the control within the cell. Moves the position of the control
+     * by the given number of pixels. Positive values move toward the lower-right, negative
+     * values move toward the upper-left.
+     *
+     * @param hIndent distance to move to the right (negative values move left)
+     * @param vIndent distance to move down (negative values move up)
+     * @return this
+     */
+    public GridDataFactory indent(int hIndent, int vIndent) {
+        data.horizontalIndent = hIndent;
+        data.verticalIndent = vIndent;
+        return this;
+    }
+
+    /**
+     * Sets the indent of the control within the cell. Moves the position of the control
+     * by the given number of pixels. Positive values move toward the lower-right, negative
+     * values move toward the upper-left.
+     *
+     * @param indent offset to move the control
+     * @return this
+     */
+    public GridDataFactory indent(Point indent) {
+        data.horizontalIndent = indent.x;
+        data.verticalIndent = indent.y;
+        return this;
+    }
+
+    /**
+     * Determines whether extra horizontal or vertical space should be allocated to
+     * this control's column when the layout resizes. If any control in the column
+     * is set to grab horizontal then the whole column will grab horizontal space.
+     * If any control in the row is set to grab vertical then the whole row will grab
+     * vertical space.
+     *
+     * @param horizontal true if the control's column should grow horizontally
+     * @param vertical true if the control's row should grow vertically
+     * @return this
+     */
+    public GridDataFactory grab(bool horizontal, bool vertical) {
+        data.grabExcessHorizontalSpace = horizontal;
+        data.grabExcessVerticalSpace = vertical;
+        return this;
+    }
+
+    /**
+     * Sets the minimum size for the control. The control will not be permitted
+     * to shrink below this size. Note: GridLayout treats a minimum size of 0
+     * as an undocumented special value, so the smallest possible minimum size
+     * is a size of 1. A minimum size of DWT.DEFAULT indicates that the result
+     * of computeSize(int, int, bool) should be used as the control's minimum
+     * size.
+     *
+     *
+     * @param minX minimum a value of 1 or more is a horizontal size of the control (pixels).
+     *        DWT.DEFAULT indicates that the control's preferred size should be used. A size
+     *        of 0 has special semantics defined by GridLayout.
+     * @param minY minimum a value of 1 or more is a vertical size of the control (pixels). DWT.DEFAULT
+     *        indicates that the control's preferred size should be used. A size
+     *        of 0 has special semantics defined by GridLayout.
+     * @return this
+     */
+    public GridDataFactory minSize(int minX, int minY) {
+        data.minimumWidth = minX;
+        data.minimumHeight = minY;
+        return this;
+    }
+
+    /**
+     * Sets the minimum size for the control. The control will not be permitted
+     * to shrink below this size. Note: GridLayout treats a minimum size of 0
+     * as an undocumented special value, so the smallest possible minimum size
+     * is a size of 1. A minimum size of DWT.DEFAULT indicates that the result
+     * of computeSize(int, int, bool) should be used as the control's minimum
+     * size.
+     *
+     * @param min minimum size of the control
+     * @return this
+     */
+    public GridDataFactory minSize(Point min) {
+        data.minimumWidth = min.x;
+        data.minimumHeight = min.y;
+        return this;
+    }
+
+    /**
+     * Instructs the GridLayout to ignore this control when performing layouts.
+     *
+     * @param shouldExclude true iff the control should be excluded from layouts
+     * @return this
+     */
+    public GridDataFactory exclude(bool shouldExclude) {
+        data.exclude = shouldExclude;
+        return this;
+    }
+
+    /**
+     * Creates a new GridData instance. All attributes of the GridData instance
+     * will be initialized by the factory.
+     *
+     * @return a new GridData instance
+     */
+    public GridData create() {
+        return copyData(data);
+    }
+
+    /**
+     * Creates a copy of the reciever.
+     *
+     * @return a copy of the reciever
+     */
+    public GridDataFactory copy() {
+        return new GridDataFactory(create());
+    }
+
+    /**
+     * Returns a copy of the given GridData
+     *
+     * @param data GridData to copy
+     * @return a copy of the argument
+     */
+    public static GridData copyData(GridData data) {
+        GridData newData = new GridData(data.horizontalAlignment, data.verticalAlignment, data.grabExcessHorizontalSpace, data.grabExcessVerticalSpace, data.horizontalSpan,
+                data.verticalSpan);
+        newData.exclude = data.exclude;
+        newData.heightHint = data.heightHint;
+        newData.horizontalIndent = data.horizontalIndent;
+        newData.minimumHeight = data.minimumHeight;
+        newData.minimumWidth = data.minimumWidth;
+        newData.verticalIndent = data.verticalIndent;
+        newData.widthHint = data.widthHint;
+
+        return newData;
+    }
+
+    /**
+     * Sets the layout data on the given control. Creates a new GridData instance and
+     * assigns it to the control by calling control.setLayoutData.
+     *
+     * @param control control whose layout data will be initialized
+     */
+    public void applyTo(Control control) {
+        control.setLayoutData(create());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/layout/GridLayoutFactory.d	Mon Mar 31 01:41:52 2008 +0200
@@ -0,0 +1,386 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 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
+ *     Stefan Xenos, IBM - initial implementation, bug 178888
+ *     Karsten Stoeckmann - bug 156982
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.layout.GridLayoutFactory;
+
+import dwtx.jface.layout.LayoutConstants;
+import dwtx.jface.layout.LayoutGenerator;
+
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.layout.GridLayout;
+import dwt.widgets.Composite;
+
+import dwt.dwthelper.utils;
+
+/**
+ * GridLayoutFactory creates and initializes grid layouts. There are two ways to use GridLayoutFactory.
+ * Normally, it is used as a shorthand for writing "new GridLayout()" and initializing a bunch
+ * of fields. In this case the main benefit is a more concise syntax and the ability to create more
+ * than one identical GridLayout from the same factory. Changing a property of the factory will affect
+ * future layouts created by the factory, but has no effect on layouts that have already been created.
+ *
+ * <p>
+ * GridLayoutFactory can also generate grid data for all the controls in a layout. This is done with
+ * the generateLayout method. To use this feature:
+ * </p>
+ *
+ * <ol>
+ * <li>Create the composite</li>
+ * <li>Create all the controls in the composite</li>
+ * <li>Call generateLayout</li>
+ * </ol>
+ *
+ * <p>
+ * The order here is important. generateLayout must be called after all the child controls have
+ * been created. generateLayout will not change any layout data that has already been attached
+ * to a child control and it will not recurse into nested composites.
+ * </p>
+ *
+ * @since 3.2
+ */
+public final class GridLayoutFactory {
+
+    /**
+     * Template layout. The factory will create copies of this layout.
+     */
+    private GridLayout l;
+
+    /**
+     * Creates a new GridLayoutFactory that will create copies of the given layout.
+     *
+     * @param l layout to copy
+     */
+    private this(GridLayout l) {
+        this.l = l;
+    }
+
+    /**
+     * Creates a factory that creates copies of the given layout.
+     *
+     * @param l layout to copy
+     * @return a new GridLayoutFactory instance that creates copies of the given layout
+     */
+    public static GridLayoutFactory createFrom(GridLayout l) {
+        return new GridLayoutFactory(copyLayout(l));
+    }
+
+    /**
+     * Creates a copy of the reciever.
+     *
+     * @return a copy of the reciever
+     */
+    public GridLayoutFactory copy() {
+        return new GridLayoutFactory(create());
+    }
+
+    /**
+     * Creates a GridLayoutFactory that creates GridLayouts with the default DWT
+     * values.
+     *
+     * <p>
+     * Initial values are:
+     * </p>
+     *
+     * <ul>
+     * <li>numColumns(1)</li>
+     * <li>margins(5,5)</li>
+     * <li>extendedMargins(0,0,0,0)</li>
+     * <li>spacing(5,5)</li>
+     * <li>equalWidth(false)</li>
+     * </ul>
+     *
+     * @return a GridLayoutFactory that creates GridLayouts as though created with
+     * their default constructor
+     * @see #fillDefaults
+     */
+    public static GridLayoutFactory swtDefaults() {
+        return new GridLayoutFactory(new GridLayout());
+    }
+
+    /**
+     * Creates a GridLayoutFactory that creates GridLayouts with no margins and
+     * default dialog spacing.
+     *
+     * <p>
+     * Initial values are:
+     * </p>
+     *
+     * <ul>
+     * <li>numColumns(1)</li>
+     * <li>margins(0,0)</li>
+     * <li>extendedMargins(0,0,0,0)</li>
+     * <li>spacing(LayoutConstants.getSpacing())</li>
+     * <li>equalWidth(false)</li>
+     * </ul>
+     *
+     * @return a GridLayoutFactory that creates GridLayouts as though created with
+     * their default constructor
+     * @see #swtDefaults
+     */
+    public static GridLayoutFactory fillDefaults() {
+        GridLayout layout = new GridLayout();
+        layout.marginWidth = 0;
+        layout.marginHeight = 0;
+        Point defaultSpacing = LayoutConstants.getSpacing();
+        layout.horizontalSpacing = defaultSpacing.x;
+        layout.verticalSpacing = defaultSpacing.y;
+        return new GridLayoutFactory(layout);
+    }
+
+    /**
+     * Sets whether the columns should be forced to be equal width
+     *
+     * @param equal true iff the columns should be forced to be equal width
+     * @return this
+     */
+    public GridLayoutFactory equalWidth(bool equal) {
+        l.makeColumnsEqualWidth = equal;
+        return this;
+    }
+
+    /**
+     * Sets the spacing for layouts created with this factory. The spacing
+     * is the distance between cells within the layout.
+     *
+     * @param hSpacing horizontal spacing (pixels)
+     * @param vSpacing vertical spacing (pixels)
+     * @return this
+     * @see #margins(Point)
+     * @see #margins(int, int)
+     */
+    public GridLayoutFactory spacing(int hSpacing, int vSpacing) {
+        l.horizontalSpacing = hSpacing;
+        l.verticalSpacing = vSpacing;
+        return this;
+    }
+
+    /**
+     * Sets the spacing for layouts created with this factory. The spacing
+     * is the distance between cells within the layout.
+     *
+     * @param spacing space between controls in the layout (pixels)
+     * @return this
+     * @see #margins(Point)
+     * @see #margins(int, int)
+     */
+    public GridLayoutFactory spacing(Point spacing) {
+        l.horizontalSpacing = spacing.x;
+        l.verticalSpacing = spacing.y;
+        return this;
+    }
+
+    /**
+     * Sets the margins for layouts created with this factory. The margins
+     * are the distance between the outer cells and the edge of the layout.
+     *
+     * @param margins margin size (pixels)
+     * @return this
+     * @see #spacing(Point)
+     * @see #spacing(int, int)
+     */
+    public GridLayoutFactory margins(Point margins) {
+        l.marginWidth = margins.x;
+        l.marginHeight = margins.y;
+        return this;
+    }
+
+    /**
+     * Sets the margins for layouts created with this factory. The margins
+     * specify the number of pixels of horizontal and vertical margin that will
+     * be placed along the left/right and top/bottom edges of the layout. Note
+     * that thes margins will be added to the ones specified by
+     * {@link #extendedMargins(int, int, int, int)}.
+     *
+     * @param width
+     *            margin width (pixels)
+     * @param height
+     *            margin height (pixels)
+     * @return this
+     * @see #spacing(Point)
+     * * @see #spacing(int, int)
+     */
+    public GridLayoutFactory margins(int width, int height) {
+        l.marginWidth = width;
+        l.marginHeight = height;
+        return this;
+    }
+
+    /**
+     * Sets the margins for layouts created with this factory. The margins
+     * specify the number of pixels of horizontal and vertical margin that will
+     * be placed along the left, right, top, and bottom edges of the layout.
+     * Note that thes margins will be added to the ones specified by
+     * {@link #margins(int, int)}.
+     *
+     * @param left
+     *            left margin size (pixels)
+     * @param right
+     *            right margin size (pixels)
+     * @param top
+     *            top margin size (pixels)
+     * @param bottom
+     *            bottom margin size (pixels)
+     * @return this
+     * @see #spacing(Point)
+     * @see #spacing(int, int)
+     *
+     * @since 3.3
+     */
+    public GridLayoutFactory extendedMargins(int left, int right, int top, int bottom) {
+        l.marginLeft = left;
+        l.marginRight = right;
+        l.marginTop = top;
+        l.marginBottom = bottom;
+        return this;
+    }
+
+    /**
+     * Sets the margins for layouts created with this factory. The margins
+     * specify the number of pixels of horizontal and vertical margin that will
+     * be placed along the left, right, top, and bottom edges of the layout.
+     * Note that thes margins will be added to the ones specified by
+     * {@link #margins(int, int)}.
+     *
+     * <code><pre>
+     *     // Construct a GridLayout whose left, right, top, and bottom
+     *     // margin sizes are 10, 5, 0, and 15 respectively
+     *
+     *     Rectangle margins = Geometry.createDiffRectangle(10,5,0,15);
+     *     GridLayoutFactory.fillDefaults().extendedMargins(margins).applyTo(composite1);
+     * </pre></code>
+     *
+     * @param differenceRect rectangle which, when added to the client area of the
+     *        layout, returns the outer area of the layout. The x and y values of
+     *        the rectangle correspond to the position of the bounds of the
+     *        layout with respect to the client area. They should be negative.
+     *        The width and height correspond to the relative size of the bounds
+     *        of the layout with respect to the client area, and should be positive.
+     * @return this
+     * @see #spacing(Point)
+     * @see #spacing(int, int)
+     *
+     * @since 3.3
+     */
+    public GridLayoutFactory extendedMargins(Rectangle differenceRect) {
+        l.marginLeft = -differenceRect.x;
+        l.marginTop = -differenceRect.y;
+        l.marginBottom = differenceRect.y + differenceRect.height;
+        l.marginRight = differenceRect.x + differenceRect.width;
+        return this;
+    }
+
+    /**
+     * Sets the number of columns in the layout
+     *
+     * @param numColumns number of columns in the layout
+     * @return this
+     */
+    public GridLayoutFactory numColumns(int numColumns) {
+        l.numColumns = numColumns;
+        return this;
+    }
+
+    /**
+     * Creates a new GridLayout, and initializes it with values from the factory.
+     *
+     * @return a new initialized GridLayout.
+     * @see #applyTo
+     */
+    public GridLayout create() {
+        return copyLayout(l);
+    }
+
+    /**
+     * Creates a new GridLayout and attaches it to the given composite.
+     * Does not create the GridData of any of the controls in the composite.
+     *
+     * @param c composite whose layout will be set
+     * @see #generateLayout
+     * @see #create
+     * @see GridLayoutFactory
+     */
+    public void applyTo(Composite c) {
+        c.setLayout(copyLayout(l));
+    }
+
+    /**
+     * Copies the given GridLayout instance
+     *
+     * @param l layout to copy
+     * @return a new GridLayout
+     */
+    public static GridLayout copyLayout(GridLayout l) {
+        GridLayout result = new GridLayout(l.numColumns, l.makeColumnsEqualWidth);
+        result.horizontalSpacing = l.horizontalSpacing;
+        result.marginBottom = l.marginBottom;
+        result.marginHeight = l.marginHeight;
+        result.marginLeft = l.marginLeft;
+        result.marginRight = l.marginRight;
+        result.marginTop = l.marginTop;
+        result.marginWidth = l.marginWidth;
+        result.verticalSpacing = l.verticalSpacing;
+
+        return result;
+    }
+
+    /**
+     * Applies this layout to the given composite, and attaches default GridData
+     * to all immediate children that don't have one. The layout is generated using
+     * heuristics based on the widget types. In most cases, it will create exactly the same
+     * layout that would have been hardcoded by the programmer. In any situation
+     * where it does not produce the desired layout, the GridData for any child can be
+     * overridden by attaching the layout data before calling this method. In these cases,
+     * the special-case layout data can be hardcoded and the algorithm can supply defaults
+     * to the rest.
+     *
+     * <p>
+     * This must be called <b>AFTER</b> all of the child controls have been created and their
+     * layouts attached. This method will attach a layout to the given composite. If any new
+     * children are created after calling this method, their GridData must be created manually.
+     * The algorithm does not recurse into child composites. To generate all the layouts in
+     * a widget hierarchy, the method must be called bottom-up for each Composite.
+     * </p>
+     *
+     * <p>
+     * All controls are made to span a single cell. The algorithm tries to classify controls into one
+     * of the following categories:
+     * </p>
+     *
+     * <ul>
+     * <li>Pushbuttons: Set to a constant size large enough to fit their text and no smaller
+     * than the default button size.</li>
+     * <li>Wrapping with text (labels, read-only text boxes, etc.): override the preferred horizontal
+     *     size with the default wrapping point, fill horizontally, grab horizontal space, keep the
+     *     preferred vertical size</li>
+     * <li>Wrapping without text (toolbars, coolbars, etc.): fill align, don't grab, use the preferred size</li>
+     * <li>Horizontally scrolling controls (anything with horizontal scrollbars or where the user edits
+     *     text and can cursor through it from left-to-right): override the preferred horizontal size with
+     *     a constant, grab horizontal, fill horizontal.</li>
+     * <li>Vertically scrolling controls (anything with vertical scrollbars or where the user edits
+     *     text and can cursor through it up and down): override the preferred vertical size with a constant,
+     *     grab vertical, fill vertical</li>
+     * <li>Nested layouts: fill align both directions, grab along any dimension if the layout would
+     *     be able to expand along that dimension.</li>
+     * <li>Non-wrapping non-scrollable read-only text: fill horizontally, center vertically, default size, don't grab </li>
+     * <li>Non-wrapping non-scrollable non-text: fill both, default size, don't grab</li>
+     * </ul>
+     *
+     * @param c composite whose layout will be generated
+     */
+    public void generateLayout(Composite c) {
+        applyTo(c);
+        LayoutGenerator.generateLayout(c);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/layout/LayoutConstants.d	Mon Mar 31 01:41:52 2008 +0200
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 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.layout.LayoutConstants;
+
+
+import dwt.graphics.FontMetrics;
+import dwt.graphics.GC;
+import dwt.graphics.Point;
+import dwt.widgets.Display;
+import dwtx.jface.dialogs.Dialog;
+import dwtx.jface.dialogs.IDialogConstants;
+import dwtx.jface.resource.JFaceResources;
+
+/**
+ * Contains various layout constants
+ *
+ * @since 3.2
+ */
+public final class LayoutConstants {
+    private static Point dialogMargins = null;
+    private static Point dialogSpacing = null;
+    private static Point minButtonSize = null;
+
+    private static void initializeConstants() {
+        if (dialogMargins !is null) {
+            return;
+        }
+
+        GC gc = new GC(Display.getCurrent());
+        gc.setFont(JFaceResources.getDialogFont());
+        FontMetrics fontMetrics = gc.getFontMetrics();
+
+        dialogMargins = new Point(Dialog.convertHorizontalDLUsToPixels(fontMetrics, IDialogConstants.HORIZONTAL_MARGIN),
+                Dialog.convertVerticalDLUsToPixels(fontMetrics, IDialogConstants.VERTICAL_MARGIN));
+
+        dialogSpacing = new Point(Dialog.convertHorizontalDLUsToPixels(fontMetrics, IDialogConstants.HORIZONTAL_SPACING),
+                Dialog.convertVerticalDLUsToPixels(fontMetrics, IDialogConstants.VERTICAL_SPACING));
+
+        minButtonSize  = new Point(Dialog.convertHorizontalDLUsToPixels(fontMetrics, IDialogConstants.BUTTON_WIDTH), 0);
+
+        gc.dispose();
+    }
+
+    /**
+     * Returns the default dialog margins, in pixels
+     *
+     * @return the default dialog margins, in pixels
+     */
+    public static final Point getMargins() {
+        initializeConstants();
+        return dialogMargins;
+    }
+
+    /**
+     * Returns the default dialog spacing, in pixels
+     *
+     * @return the default dialog spacing, in pixels
+     */
+    public static final Point getSpacing() {
+        initializeConstants();
+        return dialogSpacing;
+    }
+
+    /**
+     * Returns the default minimum button size, in pixels
+     *
+     * @return the default minimum button size, in pixels
+     */
+    public static final Point getMinButtonSize() {
+        initializeConstants();
+        return minButtonSize;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/layout/LayoutGenerator.d	Mon Mar 31 01:41:52 2008 +0200
@@ -0,0 +1,211 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 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.layout.LayoutGenerator;
+
+import dwtx.jface.layout.GridDataFactory;
+import dwtx.jface.layout.LayoutConstants;
+
+import dwt.DWT;
+import dwt.events.ModifyListener;
+import dwt.graphics.Point;
+import dwt.layout.GridData;
+import dwt.layout.GridLayout;
+import dwt.widgets.Button;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Layout;
+import dwt.widgets.Scrollable;
+import dwtx.jface.util.Geometry;
+
+import dwt.dwthelper.utils;
+
+/* package */class LayoutGenerator {
+
+    /**
+     * Default size for controls with varying contents
+     */
+    private static const Point defaultSize;
+
+    /**
+     * Default wrapping size for wrapped labels
+     */
+    private static const int wrapSize = 350;
+
+    private static const GridDataFactory nonWrappingLabelData;
+
+    static this(){
+        defaultSize = new Point(150, 150);
+        nonWrappingLabelData = GridDataFactory.fillDefaults().align_(DWT.BEGINNING, DWT.CENTER).grab(false, false);
+    }
+
+    private static bool hasStyle(Control c, int style) {
+        return (c.getStyle() & style) !is 0;
+    }
+
+    /**
+     * Generates a GridLayout for the given composite by examining its child
+     * controls and attaching layout data to any immediate children that do not
+     * already have layout data.
+     *
+     * @param toGenerate
+     *            composite to generate a layout for
+     */
+    public static void generateLayout(Composite toGenerate) {
+        Control[] children = toGenerate.getChildren();
+
+        for (int i = 0; i < children.length; i++) {
+            Control control = children[i];
+
+            // Skip any children that already have layout data
+            if (control.getLayoutData() !is null) {
+                continue;
+            }
+
+            applyLayoutDataTo(control);
+        }
+    }
+
+    private static void applyLayoutDataTo(Control control) {
+        defaultsFor(control).applyTo(control);
+    }
+
+    /**
+     * Creates default factory for this control types:
+     * <ul>
+     *  <li>{@link Button} with {@link DWT#CHECK}</li>
+     *  <li>{@link Button}</li>
+     *  <li>{@link Composite}</li>
+     * </ul>
+     * @param control the control the factory is search for
+     * @return a default factory for the control
+     */
+    public static GridDataFactory defaultsFor(Control control) {
+        if ( auto button = cast(Button) control ) {
+
+            if (hasStyle(button, DWT.CHECK)) {
+                return nonWrappingLabelData.copy();
+            } else {
+                return GridDataFactory.fillDefaults().align_(DWT.FILL, DWT.CENTER).hint(Geometry.max(button.computeSize(DWT.DEFAULT, DWT.DEFAULT, true), LayoutConstants.getMinButtonSize()));
+            }
+        }
+
+        if (auto scrollable = cast(Scrollable) control ) {
+
+            if ( auto composite = cast(Composite) scrollable ) {
+
+                Layout theLayout = composite.getLayout();
+                if ( cast(GridLayout) theLayout ) {
+                    bool growsHorizontally = false;
+                    bool growsVertically = false;
+
+                    Control[] children = composite.getChildren();
+                    for (int i = 0; i < children.length; i++) {
+                        Control child = children[i];
+
+                        GridData data = cast(GridData) child.getLayoutData();
+
+                        if (data !is null) {
+                            if (data.grabExcessHorizontalSpace) {
+                                growsHorizontally = true;
+                            }
+                            if (data.grabExcessVerticalSpace) {
+                                growsVertically = true;
+                            }
+                        }
+                    }
+
+                    return GridDataFactory.fillDefaults().grab(growsHorizontally, growsVertically);
+                }
+            }
+        }
+
+        bool wrapping = hasStyle(control, DWT.WRAP);
+
+        // Assume any control with the H_SCROLL or V_SCROLL flags are
+        // horizontally or vertically
+        // scrollable, respectively.
+        bool hScroll = hasStyle(control, DWT.H_SCROLL);
+        bool vScroll = hasStyle(control, DWT.V_SCROLL);
+
+        bool containsText = hasMethod(control, "setText", [ ArrayWrapperString.classinfo ] ); //$NON-NLS-1$
+
+        // If the control has a setText method, an addModifyListener method, and
+        // does not have
+        // the DWT.READ_ONLY flag, assume it contains user-editable text.
+        bool userEditable = !hasStyle(control, DWT.READ_ONLY) && containsText && hasMethod(control, "addModifyListener", [ ModifyListener.classinfo ]); //$NON-NLS-1$
+
+        // For controls containing user-editable text...
+        if (userEditable) {
+            if (hasStyle(control, DWT.MULTI)) {
+                vScroll = true;
+            }
+
+            if (!wrapping) {
+                hScroll = true;
+            }
+        }
+
+        // Compute the horizontal hint
+        int hHint = DWT.DEFAULT;
+        bool grabHorizontal = hScroll;
+
+        // For horizontally-scrollable controls, override their horizontal
+        // preferred size
+        // with a constant
+        if (hScroll) {
+            hHint = defaultSize.x;
+        } else {
+            // For wrapping controls, there are two cases.
+            // 1. For controls that contain text (like wrapping labels,
+            // read-only text boxes,
+            // etc.) override their preferred size with the preferred wrapping
+            // point and
+            // make them grab horizontal space.
+            // 2. For non-text controls (like wrapping toolbars), assume that
+            // their non-wrapped
+            // size is best.
+
+            if (wrapping) {
+                if (containsText) {
+                    hHint = wrapSize;
+                    grabHorizontal = true;
+                }
+            }
+        }
+
+        int vAlign = DWT.FILL;
+
+        // Heuristic for labels: Controls that contain non-wrapping read-only
+        // text should be
+        // center-aligned rather than fill-aligned
+        if (!vScroll && !wrapping && !userEditable && containsText) {
+            vAlign = DWT.CENTER;
+        }
+
+        return GridDataFactory.fillDefaults().grab(grabHorizontal, vScroll).align_(DWT.FILL, vAlign).hint(hHint, vScroll ? defaultSize.y : DWT.DEFAULT);
+    }
+
+    private static bool hasMethod(Control control, String name, ClassInfo[] parameterTypes) {
+        ClassInfo c = control.classinfo;
+        implMissing(__FILE__,__LINE__);
+        pragma(msg, "FIXME dwtx.jface.layout.LayoutGenerator hasMethod reflection" );
+        return true;
+/+        try {
+            return c.getMethod(name, parameterTypes) !is null;
+        } catch (SecurityException e) {
+            return false;
+        } catch (NoSuchMethodException e) {
+            return false;
+        }+/
+    }
+}
--- a/dwtx/jface/resource/JFaceResources.d	Mon Mar 31 01:07:26 2008 +0200
+++ b/dwtx/jface/resource/JFaceResources.d	Mon Mar 31 01:41:52 2008 +0200
@@ -149,8 +149,9 @@
      *            the message arguments
      * @return the string
      */
-    public static String format(String key, Object[] args) {
-        return Format(getString(key), args);
+    public static String format(String key, ... ) {
+        implMissing(__FILE__,__LINE__);
+        return key;//Format(getString(key), args);
     }
 
     /**