changeset 17:f459f9147650

ImageAndMessgeDialog
author Frank Benoit <benoit@tionex.de>
date Tue, 01 Apr 2008 08:24:51 +0200
parents e0f0aaf75edd
children 7615869f89e6
files dwtx/jface/dialogs/ImageAndMessageArea.d dwtx/jface/dialogs/ProgressIndicator.d dwtx/jface/fieldassist/DecoratedField.d dwtx/jface/fieldassist/FieldDecoration.d dwtx/jface/fieldassist/FieldDecorationRegistry.d dwtx/jface/fieldassist/IControlCreator.d dwtx/jface/fieldassist/TextControlCreator.d
diffstat 7 files changed, 1833 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/dialogs/ImageAndMessageArea.d	Tue Apr 01 08:24:51 2008 +0200
@@ -0,0 +1,219 @@
+/*******************************************************************************
+ * Copyright (c) 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ ******************************************************************************/
+
+module dwtx.jface.dialogs.ImageAndMessageArea;
+
+import dwtx.jface.dialogs.IDialogConstants;
+
+import dwt.DWT;
+import dwt.events.PaintEvent;
+import dwt.events.PaintListener;
+import dwt.graphics.Color;
+import dwt.graphics.Font;
+import dwt.graphics.Image;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.layout.GridData;
+import dwt.layout.GridLayout;
+import dwt.widgets.Composite;
+import dwt.widgets.Layout;
+import dwt.widgets.Text;
+import dwtx.jface.fieldassist.DecoratedField;
+import dwtx.jface.fieldassist.FieldDecorationRegistry;
+import dwtx.jface.fieldassist.TextControlCreator;
+import dwtx.jface.resource.JFaceResources;
+
+import dwt.dwthelper.utils;
+
+/**
+ * Instances of this class provide a message area to display a message and an
+ * associated image.
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ *
+ * @since 3.2
+ * @deprecated As of 3.3, this class is no longer necessary.
+ *
+ */
+public class ImageAndMessageArea : Composite {
+
+    private int BORDER_MARGIN = IDialogConstants.HORIZONTAL_SPACING / 2;
+
+    private DecoratedField messageField;
+
+    private Composite container;
+
+    /**
+     * Constructs a new ImageAndMessageArea with an empty decorated field. Calls
+     * to <code>setText(String text)</code> and
+     * <code>setImage(Image image)</code> are required in order to fill the
+     * message area. Also, the instance will be invisible when initially
+     * created.
+     * <p>
+     * The style bit <code>DWT.WRAP</code> should be used if a larger message
+     * area is desired.
+     * </p>
+     *
+     * @param parent
+     *            the parent composite
+     * @param style
+     *            the DWT style bits. Using DWT.WRAP will create a larger
+     *            message area.
+     */
+    public this(Composite parent, int style) {
+        super(parent, style);
+        container = new Composite(this, style);
+        GridLayout glayout = new GridLayout();
+        glayout.numColumns = 2;
+        glayout.marginWidth = 0;
+        glayout.marginHeight = 0;
+        glayout.marginTop = BORDER_MARGIN;
+        glayout.marginBottom = BORDER_MARGIN;
+        container.setLayout(glayout);
+
+        messageField = new DecoratedField(container, DWT.READ_ONLY | style,
+                new TextControlCreator());
+        setFont(JFaceResources.getDialogFont());
+
+        GridData gd = new GridData(DWT.FILL, DWT.FILL, true, true);
+        int lineHeight = (cast(Text) messageField.getControl()).getLineHeight();
+        if ((style & DWT.WRAP) > 0)
+            gd.heightHint = 2 * lineHeight;
+        else
+            gd.heightHint = lineHeight;
+
+        messageField.getLayoutControl().setLayoutData(gd);
+
+        addPaintListener(new class PaintListener {
+            /*
+             * (non-Javadoc)
+             *
+             * @see dwt.events.PaintListener#paintControl(dwt.events.PaintEvent)
+             */
+            public void paintControl(PaintEvent e) {
+                onPaint(e);
+            }
+        });
+
+        // sets the layout and size to account for the BORDER_MARGIN between
+        // the border drawn around the container and the decorated field.
+        setLayout(new class Layout {
+            /*
+             * (non-Javadoc)
+             *
+             * @see dwt.widgets.Layout#layout(dwt.widgets.Composite,
+             *      bool)
+             */
+            public void layout(Composite parent, bool changed) {
+                Rectangle carea = getClientArea();
+                container.setBounds(carea.x + BORDER_MARGIN, carea.y
+                        + BORDER_MARGIN, carea.width - (2 * BORDER_MARGIN),
+                        carea.height - (2 * BORDER_MARGIN));
+            }
+
+            /*
+             * (non-Javadoc)
+             *
+             * @see dwt.widgets.Layout#computeSize(dwt.widgets.Composite,
+             *      int, int, bool)
+             */
+            public Point computeSize(Composite parent, int wHint, int hHint,
+                    bool changed) {
+                Point size;
+                size = container.computeSize(wHint, hHint, changed);
+
+                // size set to account for the BORDER_MARGIN on
+                // all sides of the decorated field
+                size.x += 4;
+                size.y += 4;
+                return size;
+            }
+        });
+        setVisible(false);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwt.widgets.Control#setBackground(dwt.graphics.Color)
+     */
+    public void setBackground(Color bg) {
+        super.setBackground(bg);
+        messageField.getLayoutControl().setBackground(bg);
+        messageField.getControl().setBackground(bg);
+        container.setBackground(bg);
+    }
+
+    /**
+     * Sets the text in the decorated field which will be displayed in the
+     * message area.
+     *
+     * @param text
+     *            the text to be displayed in the message area
+     *
+     * @see dwt.widgets.Text#setText(String string)
+     */
+    public void setText(String text) {
+        (cast(Text) messageField.getControl()).setText(text);
+    }
+
+    /**
+     * Adds an image to decorated field to be shown in the message area.
+     *
+     * @param image
+     *            desired image to be shown in the ImageAndMessageArea
+     */
+    public void setImage(Image image) {
+        FieldDecorationRegistry registry = FieldDecorationRegistry.getDefault();
+        registry.registerFieldDecoration("messageImage", null, image); //$NON-NLS-1$
+        messageField.addFieldDecoration(registry
+                .getFieldDecoration("messageImage"), //$NON-NLS-1$
+                DWT.LEFT | DWT.TOP, false);
+    }
+
+    /**
+     * Draws the message area composite with rounded corners.
+     */
+    private void onPaint(PaintEvent e) {
+        Rectangle carea = getClientArea();
+        e.gc.setForeground(getForeground());
+
+        // draws the polyline to be rounded in a 2 pixel squared area
+        e.gc.drawPolyline([ carea.x, carea.y + carea.height - 1,
+                carea.x, carea.y + 2, carea.x + 2, carea.y,
+                carea.x + carea.width - 3, carea.y, carea.x + carea.width - 1,
+                carea.y + 2, carea.x + carea.width - 1,
+                carea.y + carea.height - 1 ]);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwt.widgets.Control#setFont(dwt.graphics.Font)
+     */
+    public void setFont(Font font) {
+        super.setFont(font);
+        (cast(Text) messageField.getControl()).setFont(font);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwt.widgets.Control#setToolTipText(java.lang.String)
+     */
+    public void setToolTipText(String text) {
+        super.setToolTipText(text);
+        (cast(Text) messageField.getControl()).setToolTipText(text);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/dialogs/ProgressIndicator.d	Tue Apr 01 08:24:51 2008 +0200
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.dialogs.ProgressIndicator;
+
+import dwtx.jface.dialogs.IDialogConstants;
+
+import dwt.DWT;
+import dwt.custom.StackLayout;
+import dwt.widgets.Composite;
+import dwt.widgets.ProgressBar;
+
+import dwt.dwthelper.utils;
+
+/**
+ * A control for showing progress feedback for a long running operation. This
+ * control supports both determinate and indeterminate DWT progress bars. For
+ * indeterminate progress, we don't have to know the total amount of work in
+ * advance and no <code>worked</code> method needs to be called.
+ */
+public class ProgressIndicator : Composite {
+    private const static int PROGRESS_MAX = 1000; // value to use for max in
+
+    // progress bar
+    private bool animated = true;
+
+    private StackLayout layout_;
+
+    private ProgressBar determinateProgressBar;
+
+    private ProgressBar indeterminateProgressBar;
+
+    private double totalWork;
+
+    private double sumWorked;
+
+    /**
+     * Create a ProgressIndicator as a child under the given parent.
+     *
+     * @param parent
+     *            The widgets parent
+     */
+    public this(Composite parent) {
+        super(parent, DWT.NULL);
+        determinateProgressBar = new ProgressBar(this, DWT.HORIZONTAL);
+        indeterminateProgressBar = new ProgressBar(this, DWT.HORIZONTAL
+                | DWT.INDETERMINATE);
+        layout_ = new StackLayout();
+        setLayout(layout_);
+    }
+
+    /**
+     * Initialize the progress bar to be animated.
+     */
+    public void beginAnimatedTask() {
+        done();
+        layout_.topControl = indeterminateProgressBar;
+        layout();
+        animated = true;
+    }
+
+    /**
+     * Initialize the progress bar.
+     *
+     * @param max
+     *            The maximum value.
+     */
+    public void beginTask(int max) {
+        done();
+        this.totalWork = max;
+        this.sumWorked = 0;
+        determinateProgressBar.setMinimum(0);
+        determinateProgressBar.setMaximum(PROGRESS_MAX);
+        determinateProgressBar.setSelection(0);
+        layout_.topControl = determinateProgressBar;
+        layout();
+        animated = false;
+    }
+
+    /**
+     * Progress is done.
+     */
+    public void done() {
+        if (!animated) {
+            determinateProgressBar.setMinimum(0);
+            determinateProgressBar.setMaximum(0);
+            determinateProgressBar.setSelection(0);
+        }
+        layout_.topControl = null;
+        layout();
+    }
+
+    /**
+     * Moves the progress indicator to the end.
+     */
+    public void sendRemainingWork() {
+        worked(totalWork - sumWorked);
+    }
+
+    /**
+     * Moves the progress indicator by the given amount of work units
+     * @param work the amount of work to increment by.
+     */
+    public void worked(double work) {
+        if (work is 0 || animated) {
+            return;
+        }
+        sumWorked += work;
+        if (sumWorked > totalWork) {
+            sumWorked = totalWork;
+        }
+        if (sumWorked < 0) {
+            sumWorked = 0;
+        }
+        int value = cast(int) (sumWorked / totalWork * PROGRESS_MAX);
+        if (determinateProgressBar.getSelection() < value) {
+            determinateProgressBar.setSelection(value);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/fieldassist/DecoratedField.d	Tue Apr 01 08:24:51 2008 +0200
@@ -0,0 +1,886 @@
+/*******************************************************************************
+ * 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
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.fieldassist.DecoratedField;
+
+import dwtx.jface.fieldassist.FieldDecoration;
+import dwtx.jface.fieldassist.FieldDecorationRegistry;
+import dwtx.jface.fieldassist.IControlCreator;
+
+import dwt.DWT;
+import dwt.events.DisposeEvent;
+import dwt.events.DisposeListener;
+import dwt.events.FocusEvent;
+import dwt.events.FocusListener;
+import dwt.events.MouseAdapter;
+import dwt.events.MouseEvent;
+import dwt.events.MouseTrackListener;
+import dwt.events.PaintEvent;
+import dwt.events.PaintListener;
+import dwt.graphics.GC;
+import dwt.graphics.Image;
+import dwt.graphics.Point;
+import dwt.graphics.Region;
+import dwt.layout.FormAttachment;
+import dwt.layout.FormData;
+import dwt.layout.FormLayout;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Display;
+import dwt.widgets.Label;
+import dwt.widgets.Shell;
+import dwtx.core.runtime.Assert;
+
+import dwt.dwthelper.utils;
+
+/**
+ * DecoratedField manages image decorations around a control. It allows clients
+ * to specify an image decoration and a position for the decoration relative to
+ * the field. Decorations may be assigned descriptions, which are shown when the
+ * user hovers over the decoration. Clients can decorate any kind of control by
+ * supplying a {@link IControlCreator} to create the control that is decorated.
+ * <p>
+ * Decorations always appear on either horizontal side of the field, never above
+ * or below it. Decorations can be positioned at the top or bottom of either
+ * side. Future implementations may provide additional positioning options for
+ * decorations.
+ * <p>
+ * By default, DecoratedField will consult the {@link FieldDecorationRegistry}
+ * to determine how much space should be reserved for each decoration. This
+ * allows fields with decorations from different sources to align properly on
+ * the same dialog, since the registry tracks the size of all decorations
+ * registered. Therefore, it is recommended, but not required, that clients of
+ * DecoratedField register the decorations used. In cases where alignment
+ * between different fields is not a concern, clients can use
+ * <code>setUseMaximumDecorationWidth(false)</code> and need not register
+ * their decorations.
+ * <p>
+ * This class is not intended to be subclassed.
+ *
+ * @since 3.2
+ * @deprecated As of 3.3, clients should use {@link ControlDecoration} instead.
+ */
+public class DecoratedField {
+
+    /**
+     * Cached platform flags for dealing with platform-specific issues.
+     */
+    private static bool CARBON = "carbon".equals(DWT.getPlatform()); //$NON-NLS-1$
+
+    /**
+     * Constants describing the array indices used to hold the decorations in
+     * array slots.
+     */
+
+    private static const int LEFT_TOP = 0;
+
+    private static const int LEFT_BOTTOM = 1;
+
+    private static const int RIGHT_TOP = 2;
+
+    private static const int RIGHT_BOTTOM = 3;
+
+    private static const int DECORATION_SLOTS = 4;
+
+    /**
+     * Simple data structure class for specifying the internals for a field
+     * decoration. This class contains data specific to the implementation of
+     * field decorations as labels attached to the field. Clients should use
+     * <code>FieldDecoration</code> for specifying a decoration.
+     */
+    private class FieldDecorationData {
+
+        /* Package */FieldDecoration decoration;
+
+        /* Package */Label label;
+
+        /* Package */FormData data;
+
+        /* Package */bool showOnFocus;
+
+        /* Package */bool visible = true;
+
+        /**
+         * Create a decoration data representing the specified decoration, using
+         * the specified label and form data for its representation.
+         *
+         * @param decoration
+         *            the decoration whose data is kept.
+         * @param label
+         *            the label used to represent the decoration.
+         * @param formData
+         *            the form data used to attach the decoration to its field.
+         * @param showOnFocus
+         *            a bool specifying whether the decoration should only be
+         *            shown when the field has focus.
+         */
+        this(FieldDecoration decoration, Label label,
+                FormData formData, bool showOnFocus) {
+            this.decoration = decoration;
+            this.label = label;
+            this.data = formData;
+            this.showOnFocus = showOnFocus;
+        }
+    }
+
+    /**
+     * Decorations keyed by position.
+     */
+    private FieldDecorationData[] decDatas;
+
+    /**
+     * The associated control
+     */
+    private Control control;
+
+    /**
+     * The composite with form layout used to manage decorations.
+     */
+    private Composite form;
+
+    /**
+     * The bool that indicates whether the maximum decoration width is used
+     * when allocating space for decorations.
+     */
+    private bool useMaxDecorationWidth = true;
+
+    /**
+     * The hover used for showing description text
+     */
+    private Hover hover;
+
+    /**
+     * The hover used to show a decoration image's description.
+     */
+    class Hover {
+        private static const String EMPTY = ""; //$NON-NLS-1$
+
+        /**
+         * Offset of info hover arrow from the left or right side.
+         */
+        private int hao = 10;
+
+        /**
+         * Width of info hover arrow.
+         */
+        private int haw = 8;
+
+        /**
+         * Height of info hover arrow.
+         */
+        private int hah = 10;
+
+        /**
+         * Margin around info hover text.
+         */
+        private int hm = 2;
+
+        /**
+         * This info hover's shell.
+         */
+        Shell hoverShell;
+
+        /**
+         * The info hover text.
+         */
+        String text = EMPTY;
+
+        /**
+         * The region used to manage the shell shape
+         */
+        Region region;
+
+        /**
+         * bool indicating whether the last computed polygon location had an
+         * arrow on left. (true if left, false if right).
+         */
+        bool arrowOnLeft = true;
+
+        /*
+         * Create a hover parented by the specified shell.
+         */
+        this(Shell parent) {
+            final Display display = parent.getDisplay();
+            hoverShell = new Shell(parent, DWT.NO_TRIM | DWT.ON_TOP
+                    | DWT.NO_FOCUS);
+            hoverShell.setBackground(display
+                    .getSystemColor(DWT.COLOR_INFO_BACKGROUND));
+            hoverShell.setForeground(display
+                    .getSystemColor(DWT.COLOR_INFO_FOREGROUND));
+            hoverShell.addPaintListener(new class PaintListener {
+                public void paintControl(PaintEvent pe) {
+                    pe.gc.drawString(text, hm, hm);
+                    if (!CARBON) {
+                        pe.gc.drawPolygon(getPolygon(true));
+                    }
+                }
+            });
+            hoverShell.addMouseListener(new class MouseAdapter {
+                public void mouseDown(MouseEvent e) {
+                    hideHover();
+                }
+            });
+        }
+
+        /*
+         * Compute a polygon that represents a hover with an arrow pointer. If
+         * border is true, compute the polygon inset by 1-pixel border. Consult
+         * the arrowOnLeft flag to determine which side the arrow is on.
+         */
+        int[] getPolygon(bool border) {
+            Point e = getExtent();
+            int b = border ? 1 : 0;
+            if (arrowOnLeft) {
+                return [ 0, 0, e.x - b, 0, e.x - b, e.y - b,
+                        hao + haw, e.y - b, hao + haw / 2, e.y + hah - b, hao,
+                        e.y - b, 0, e.y - b, 0, 0 ];
+            }
+            return [ 0, 0, e.x - b, 0, e.x - b, e.y - b,
+                    e.x - hao - b, e.y - b, e.x - hao - haw / 2, e.y + hah - b,
+                    e.x - hao - haw, e.y - b, 0, e.y - b, 0, 0 ];
+        }
+
+        /*
+         * Dispose the hover, it is no longer needed. Dispose any resources
+         * allocated by the hover.
+         */
+        void dispose() {
+            if (!hoverShell.isDisposed()) {
+                hoverShell.dispose();
+            }
+            if (region !is null) {
+                region.dispose();
+            }
+        }
+
+        /*
+         * Set the visibility of the hover.
+         */
+        void setVisible(bool visible) {
+            if (visible) {
+                if (!hoverShell.isVisible()) {
+                    hoverShell.setVisible(true);
+                }
+            } else {
+                if (hoverShell.isVisible()) {
+                    hoverShell.setVisible(false);
+                }
+            }
+        }
+
+        /*
+         * Set the text of the hover to the specified text. Recompute the size
+         * and location of the hover to hover near the specified control,
+         * pointing the arrow toward the target control.
+         */
+        void setText(String t, Control hoverNear, Control targetControl) {
+            if (t is null) {
+                t = EMPTY;
+            }
+            if (!t.equals(text)) {
+                Point oldSize = getExtent();
+                text = t;
+                hoverShell.redraw();
+                Point newSize = getExtent();
+                if (!oldSize.opEquals(newSize)) {
+                    // set a flag that indicates the direction of arrow
+                    arrowOnLeft = hoverNear.getLocation().x <= targetControl
+                            .getLocation().x;
+                    setNewShape();
+                }
+            }
+
+            if (hoverNear !is null) {
+                Point extent = getExtent();
+                int y = -extent.y - hah + 1;
+                int x = arrowOnLeft ? -hao + haw / 2 : -extent.x + hao + haw
+                        / 2;
+
+                hoverShell.setLocation(hoverNear.toDisplay(x, y));
+            }
+
+        }
+
+        /*
+         * Return whether or not the hover (shell) is visible.
+         */
+        bool isVisible() {
+            return hoverShell.isVisible();
+        }
+
+        /*
+         * Compute the extent of the hover for the current text.
+         */
+        Point getExtent() {
+            GC gc = new GC(hoverShell);
+            Point e = gc.textExtent(text);
+            gc.dispose();
+            e.x += hm * 2;
+            e.y += hm * 2;
+            return e;
+        }
+
+        /*
+         * Compute a new shape for the hover shell.
+         */
+        void setNewShape() {
+            Region oldRegion = region;
+            region = new Region();
+            region.add(getPolygon(false));
+            hoverShell.setRegion(region);
+            if (oldRegion !is null) {
+                oldRegion.dispose();
+            }
+
+        }
+    }
+
+    /**
+     * Construct a decorated field which is parented by the specified composite
+     * and has the given style bits. Use the controlCreator to create the
+     * specific kind of control that is decorated inside the field.
+     *
+     * @param parent
+     *            the parent of the decorated field.
+     * @param style
+     *            the desired style bits for the field.
+     * @param controlCreator
+     *            the IControlCreator used to specify the specific kind of
+     *            control that is to be decorated.
+     *
+     * @see IControlCreator
+     */
+    public this(Composite parent, int style,
+            IControlCreator controlCreator) {
+        decDatas = new FieldDecorationData[DECORATION_SLOTS];
+        this.form = createForm(parent);
+        this.control = controlCreator.createControl(form, style);
+
+        addControlListeners();
+        form.setTabList([ control ]);
+
+        // Set up the initial layout data.
+        FormData data = new FormData();
+        data.left = new FormAttachment(0, 0);
+        data.top = new FormAttachment(0, 0);
+        data.right = new FormAttachment(100, 0);
+        data.bottom = new FormAttachment(100, 0);
+        control.setLayoutData(data);
+
+    }
+
+    /**
+     * Adds an image decoration to the field.
+     *
+     * @param decoration
+     *            A FieldDecoration describing the image and description for the
+     *            decoration
+     *
+     * @param position
+     *            The DWT constant indicating the position of the decoration
+     *            relative to the field's control. The position should include
+     *            style bits describing both the vertical and horizontal
+     *            orientation. <code>DWT.LEFT</code> and
+     *            <code>DWT.RIGHT</code> describe the horizontal placement of
+     *            the decoration relative to the field, and the constants
+     *            <code>DWT.TOP</code> and <code>DWT.BOTTOM</code> describe
+     *            the vertical alignment of the decoration relative to the
+     *            field. Decorations always appear on either horizontal side of
+     *            the field, never above or below it. For example, a decoration
+     *            appearing on the left side of the field, at the top, is
+     *            specified as DWT.LEFT | DWT.TOP. If an image decoration
+     *            already exists in the specified position, it will be replaced
+     *            by the one specified.
+     * @param showOnFocus
+     *            <code>true</code> if the decoration should only be shown
+     *            when the associated control has focus, <code>false</code> if
+     *            it should always be shown.
+     *
+     */
+    public void addFieldDecoration(FieldDecoration decoration, int position,
+            bool showOnFocus) {
+        Label label;
+        FormData formData;
+        int i = indexForPosition(position);
+        if (decDatas[i] is null) {
+            formData = createFormDataForIndex(i, decoration.getImage());
+            label = new Label(form, DWT.HORIZONTAL | DWT.VERTICAL | DWT.CENTER);
+            label.addMouseTrackListener(new class MouseTrackListener {
+                Label label_;
+                this(){
+                    label_=label;
+                }
+                public void mouseHover(MouseEvent event) {
+                    FieldDecorationData decData = cast(FieldDecorationData) event.widget
+                            .getData();
+                    String desc = decData.decoration.getDescription();
+                    if (desc !is null) {
+                        showHoverText(desc, label_);
+                    }
+                }
+
+                public void mouseEnter(MouseEvent event) {
+                }
+
+                public void mouseExit(MouseEvent event) {
+                    hideHover();
+                }
+            });
+            decDatas[i] = new FieldDecorationData(decoration, label, formData,
+                    showOnFocus);
+        } else {
+            label = decDatas[i].label;
+            formData = decDatas[i].data;
+            decDatas[i].decoration = decoration;
+            decDatas[i].showOnFocus = showOnFocus;
+        }
+        label.setImage(decDatas[i].decoration.getImage());
+        label.setData(decDatas[i]);
+        label.setLayoutData(formData);
+        label.setVisible(!showOnFocus);
+
+        // Since sizes may have changed or there could be a new position
+        // defined, we need to update layout data on the control.
+        updateControlAttachments(i, decDatas[i]);
+    }
+
+    /*
+     * A decoration at the specified index has been added. Update the control's
+     * attachments if it has not previously been attached on that side or if it
+     * was attached to a decoration with a lesser width.
+     */
+    private void updateControlAttachments(int index, FieldDecorationData decData) {
+        FormData formData = cast(FormData) control.getLayoutData();
+        int newWidth = widthOf(decData.decoration.getImage());
+        // opposing represents the location of the decoration above or below
+        // the one in question.
+        int opposing;
+
+        switch (index) {
+        case LEFT_TOP:
+        case LEFT_BOTTOM:
+            if (index is LEFT_TOP) {
+                opposing = LEFT_BOTTOM;
+            } else {
+                opposing = LEFT_TOP;
+            }
+            if (decDatas[opposing] is null) {
+                // No decorator on the opposing side.
+                // Attach the control to this decorator
+                formData.left = new FormAttachment(decData.label);
+            } else if (decDatas[opposing].data.width < newWidth) {
+                // Decorator on opposing side is the smaller one. Attach
+                // control to the new one.
+                formData.left = new FormAttachment(decData.label);
+                // Center align the smaller one relative to the larger one.
+                decDatas[opposing].data.left.alignment = DWT.CENTER;
+                decDatas[opposing].data.left.control = decData.label;
+            } else {
+                // The new decorator is the smaller one. Keep the
+                // control attached to the opposing one.
+                formData = null;
+                // Horizontally center the smaller one relative to the larger
+                // one.
+                decData.data.left.alignment = DWT.CENTER;
+                decData.data.left.control = decDatas[opposing].label;
+            }
+            break;
+        /*
+         * The only real difference in right side cases is that we are attaching
+         * the right side of the control to the wider decoration rather than the
+         * left side of the control. Other concerns (horizontally aligning the
+         * smaller decoration relative to the larger one) are the same.
+         */
+        case RIGHT_TOP:
+        case RIGHT_BOTTOM:
+            if (index is RIGHT_TOP) {
+                opposing = RIGHT_BOTTOM;
+            } else {
+                opposing = RIGHT_TOP;
+            }
+            if (decDatas[opposing] is null) {
+                // No decorator on the opposing side.
+                // Attach the control to this decorator.
+                formData.right = new FormAttachment(decData.label);
+            } else if (decDatas[opposing].data.width < newWidth) {
+                // Decorator on opposing side is the smaller one. Attach
+                // control to the new one.
+                formData.right = new FormAttachment(decData.label);
+                // Center align the smaller one to the larger one.
+                // Note that this could be done using the left or right
+                // attachment, we use the right since it is already
+                // created for all right-side decorations.
+                decDatas[opposing].data.right.alignment = DWT.CENTER;
+                decDatas[opposing].data.right.control = decData.label;
+            } else {
+                // The new decorator is the smaller one. Keep the
+                // control attached to the opposing one.
+                formData = null;
+                // Horizontally center align the smaller one to the
+                // larger one.
+                decData.data.right.alignment = DWT.CENTER;
+                decData.data.right.control = decDatas[opposing].label;
+            }
+            break;
+        default:
+            return;
+        }
+        if (formData !is null) {
+            // Form data was updated.
+            control.setLayoutData(formData);
+            form.layout();
+        }
+    }
+
+    /**
+     * Get the control that is decorated by the receiver.
+     *
+     * @return the Control decorated by the receiver, or <code>null</code> if
+     *         none has been created yet.
+     */
+    public Control getControl() {
+        return control;
+    }
+
+    /**
+     * Get the control that represents the decorated field. This composite
+     * should be used to lay out the field within its parent.
+     *
+     * @return the Control that should be layed out in the field's parent's
+     *         layout. This is typically not the control itself, since
+     *         additional controls are used to represent the decorations.
+     */
+    public Control getLayoutControl() {
+        return form;
+    }
+
+    /**
+     * Create the parent composite and a form layout that will be used to manage
+     * decorations.
+     */
+    private Composite createForm(Composite parent) {
+        Composite composite = new Composite(parent, DWT.NO_FOCUS);
+        // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=126553
+        composite.setBackgroundMode(DWT.INHERIT_DEFAULT);
+        composite.setLayout(new FormLayout());
+        return composite;
+    }
+
+    /**
+     * Add any listeners needed on the target control.
+     */
+    private void addControlListeners() {
+        control.addDisposeListener(new class DisposeListener {
+            public void widgetDisposed(DisposeEvent event) {
+                if (hover !is null) {
+                    hover.dispose();
+                }
+            }
+        });
+        control.addFocusListener(new class FocusListener {
+            public void focusGained(FocusEvent event) {
+                controlFocusGained();
+            }
+
+            public void focusLost(FocusEvent event) {
+                controlFocusLost();
+            }
+
+        });
+    }
+
+    /*
+     * Return the index in the array of decoration datas that represents the
+     * specified DWT position.
+     *
+     * @param position The DWT constant indicating the position of the
+     * decoration relative to the field's control. The position should include
+     * style bits describing both the vertical and horizontal orientation.
+     * <code>DWT.LEFT</code> and <code>DWT.RIGHT</code> describe the
+     * horizontal placement of the decoration relative to the field, and the
+     * constants <code>DWT.TOP</code> and <code>DWT.BOTTOM</code> describe
+     * the vertical alignment of the decoration relative to the field.
+     * Decorations always appear on either horizontal side of the field, never
+     * above or below it. For example, a decoration appearing on the left side
+     * of the field, at the top, is specified as DWT.LEFT | DWT.TOP.
+     *
+     * @return index the index in the array of decorations that represents the
+     * specified DWT position. If the position is not an expected position, the
+     * index representing the top left position will be returned.
+     *
+     */
+    private int indexForPosition(int position) {
+        switch (position) {
+        case DWT.LEFT | DWT.BOTTOM:
+            return LEFT_BOTTOM;
+        case DWT.RIGHT | DWT.TOP:
+            return RIGHT_TOP;
+        case DWT.RIGHT | DWT.BOTTOM:
+            return RIGHT_BOTTOM;
+        default:
+            return LEFT_TOP;
+        }
+    }
+
+    /*
+     * Create a form data that will place the decoration at the specified
+     * position.
+     *
+     * @param index the index in the decDatas describing the position of the
+     * decoration.
+     *
+     * @param image the image shown in the decoration.
+     *
+     */
+    private FormData createFormDataForIndex(int index, Image image) {
+        Assert.isTrue(index >= 0 && index < DECORATION_SLOTS,
+                "Index out of range"); //$NON-NLS-1$
+
+        FormData data = new FormData();
+        switch (index) {
+        case LEFT_TOP:
+            data.left = new FormAttachment(0, 0);
+            data.top = new FormAttachment(0, 0);
+            break;
+        case LEFT_BOTTOM:
+            data.left = new FormAttachment(0, 0);
+            data.bottom = new FormAttachment(100, 0);
+            break;
+        case RIGHT_TOP:
+            data.right = new FormAttachment(100, 0);
+            data.top = new FormAttachment(0, 0);
+            break;
+        case RIGHT_BOTTOM:
+            data.right = new FormAttachment(100, 0);
+            data.bottom = new FormAttachment(100, 0);
+            break;
+        }
+        data.width = widthOf(image);
+        data.height = DWT.DEFAULT;
+
+        return data;
+    }
+
+    /**
+     * Show the specified text using the same hover dialog as is used to show
+     * decorator descriptions. Normally, a decoration's description text will be
+     * shown in an info hover over the field's control whenever the mouse hovers
+     * over the decoration. This method can be used to show a decoration's
+     * description text at other times (such as when the control receives
+     * focus), or to show other text associated with the field.
+     *
+     * <p>
+     * If there is currently a hover visible, the hover's text will be replaced
+     * with the specified text.
+     *
+     * @param text
+     *            the text to be shown in the info hover, or <code>null</code>
+     *            if no text should be shown.
+     */
+    public void showHoverText(String text) {
+        showHoverText(text, control);
+    }
+
+    /**
+     * Hide any hover popups that are currently showing on the control.
+     * Normally, a decoration's description text will be shown in an info hover
+     * over the field's control as long as the mouse hovers over the decoration,
+     * and will be hidden when the mouse exits the control. This method can be
+     * used to hide a hover that was shown using <code>showHoverText</code>,
+     * or to programatically hide the current decoration hover.
+     *
+     * <p>
+     * This message has no effect if there is no current hover.
+     *
+     */
+    public void hideHover() {
+        if (hover !is null) {
+            hover.setVisible(false);
+        }
+    }
+
+    /*
+     * The target control gained focus. Any decorations that should show only
+     * when they have the focus should be shown here.
+     */
+    private void controlFocusGained() {
+        for (int i = 0; i < DECORATION_SLOTS; i++) {
+            if (decDatas[i] !is null && decDatas[i].showOnFocus) {
+                setVisible(decDatas[i], true);
+            }
+        }
+    }
+
+    /*
+     * The target control lost focus. Any decorations that should show only when
+     * they have the focus should be hidden here.
+     */
+    private void controlFocusLost() {
+        for (int i = 0; i < DECORATION_SLOTS; i++) {
+            if (decDatas[i] !is null && decDatas[i].showOnFocus) {
+                setVisible(decDatas[i], false);
+            }
+        }
+    }
+
+    /**
+     * Show the specified decoration. This message has no effect if the
+     * decoration is already showing, or was not already added to the field
+     * using <code>addFieldDecoration</code>.
+     *
+     * @param decoration
+     *            the decoration to be shown.
+     */
+    public void showDecoration(FieldDecoration decoration) {
+        FieldDecorationData data = getDecorationData(decoration);
+        if (data is null) {
+            return;
+        }
+        // record the fact that client would like it to be visible
+        data.visible = true;
+        // even if it is supposed to be shown, if the field does not have focus,
+        // do not show it (yet)
+        if (!data.showOnFocus || control.isFocusControl()) {
+            setVisible(data, true);
+        }
+    }
+
+    /**
+     * Hide the specified decoration. This message has no effect if the
+     * decoration is already hidden, or was not already added to the field using
+     * <code>addFieldDecoration</code>.
+     *
+     * @param decoration
+     *            the decoration to be hidden.
+     */
+    public void hideDecoration(FieldDecoration decoration) {
+        FieldDecorationData data = getDecorationData(decoration);
+        if (data is null) {
+            return;
+        }
+        // Store the desired visibility in the decData. We remember the
+        // client's instructions so that changes in visibility caused by
+        // field focus changes won't violate the client's visibility setting.
+        data.visible = false;
+        setVisible(data, false);
+    }
+
+    /**
+     * Update the specified decoration. This message should be used if the image
+     * or description in the decoration have changed. This message has no
+     * immediate effect if the decoration is not visible, and no effect at all
+     * if the decoration was not previously added to the field.
+     *
+     * @param decoration
+     *            the decoration to be hidden.
+     */
+    public void updateDecoration(FieldDecoration decoration) {
+        FieldDecorationData data = getDecorationData(decoration);
+        if (data is null) {
+            return;
+        }
+        if (data.label !is null) {
+            data.label.setImage(decoration.getImage());
+            // If the decoration is being shown, and a hover is active,
+            // update the hover text to display the new description.
+            if (data.label.getVisible() is true && hover !is null) {
+                showHoverText(decoration.getDescription(), data.label);
+            }
+        }
+    }
+
+    /*
+     * Set the visibility of the specified decoration data. This method does not
+     * change the visibility value stored in the decData, but instead consults
+     * it to determine how the visibility should be changed. This method is
+     * called any time visibility of a decoration might change, whether by
+     * client API or focus changes.
+     */
+    private void setVisible(FieldDecorationData decData, bool visible) {
+        // Check the decData visibility flag, since it contains the client's
+        // instructions for visibility.
+        if (visible && decData.visible) {
+            decData.label.setVisible(true);
+        } else {
+            decData.label.setVisible(false);
+        }
+    }
+
+    /*
+     * Get the FieldDecorationData that corresponds to the given decoration.
+     */
+    private FieldDecorationData getDecorationData(FieldDecoration dec) {
+        for (int i = 0; i < DECORATION_SLOTS; i++) {
+            if (decDatas[i] !is null && dec is decDatas[i].decoration
+                    && decDatas[i].label !is null
+                    && !decDatas[i].label.isDisposed()) {
+                return decDatas[i];
+            }
+        }
+        return null;
+    }
+
+    /*
+     * Show the specified text in the hover, positioning the hover near the
+     * specified control.
+     */
+    private void showHoverText(String text, Control hoverNear) {
+        if (text is null) {
+            hideHover();
+            return;
+        }
+
+        if (hover is null) {
+            hover = new Hover(hoverNear.getShell());
+        }
+        hover.setText(text, hoverNear, control);
+        hover.setVisible(true);
+    }
+
+    /**
+     * Set a bool that indicates whether the receiver should use the
+     * decoration registry's maximum decoration width when allocating space for
+     * decorations. The default value is <code>true</code>. Using the maximum
+     * decoration width is useful so that decorated fields on the same dialog
+     * that have different decoration widths will all align. This also allows
+     * client dialogs to align non-decorated fields with decorated fields by
+     * consulting the maximum decoration width.
+     * </p>
+     * <p>
+     * Clients may wish to set this value to <code>false</code> in cases where
+     * space usage is more important than alignment of fields. This value must
+     * be set before the decorations are added in order to ensure proper
+     * alignment.
+     * </p>
+     *
+     * @param useMaximumWidth
+     *            <code>true</code> if the maximum decoration width should be
+     *            used as the size for all decorations, <code>false</code> if
+     *            only the decoration size should be used.
+     *
+     * @see FieldDecorationRegistry#getMaximumDecorationWidth()
+     */
+    public void setUseMaximumDecorationWidth(bool useMaximumWidth) {
+        useMaxDecorationWidth = useMaximumWidth;
+    }
+
+    /*
+     * Return the width appropriate for the specified decoration image.
+     */
+    private int widthOf(Image image) {
+        if (image is null) {
+            return 0;
+        }
+        return useMaxDecorationWidth ? FieldDecorationRegistry.getDefault()
+                .getMaximumDecorationWidth() : image.getBounds().width;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/fieldassist/FieldDecoration.d	Tue Apr 01 08:24:51 2008 +0200
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * 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
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.fieldassist.FieldDecoration;
+
+import dwt.graphics.Image;
+
+import dwt.dwthelper.utils;
+
+/**
+ * FieldDecoration is a simple data structure class for specifying a decoration
+ * for a field. A decoration may be rendered in different ways depending on the
+ * type of field it is used with.
+ *
+ * @see FieldDecorationRegistry
+ *
+ * @since 3.2
+ */
+public class FieldDecoration {
+
+    /*
+     * The image to be shown in the decoration.
+     */
+    private Image image;
+
+    /*
+     * The description to show in the decoration's hover.
+     */
+    private String description;
+
+    /**
+     * Create a decoration for a field with the specified image and description
+     * text.
+     *
+     * @param image
+     *            the image shown in the decoration. A <code>null</code> image
+     *            will result in a blank decoration, which may be used to
+     *            reserve space near the field.
+     * @param description
+     *            the description shown when the user hovers over the
+     *            decoration. A <code>null</code> description indicates that
+     *            there will be no hover for the decoration.
+     */
+    public this(Image image, String description) {
+        this.image = image;
+        this.description = description;
+    }
+
+    /**
+     * Return the image shown in the decoration, or <code>null</code> if no
+     * image is specified.
+     *
+     * @return the image shown in the decoration. A return value of
+     *         <code>null</code> signifies a blank decoration.
+     */
+    public Image getImage() {
+        return image;
+    }
+
+    /**
+     * Set the image shown in the decoration, or <code>null</code> if no image
+     * is specified. It is up to the caller to update any decorated fields that
+     * are showing the description in order to display the new image.
+     *
+     * @param image
+     *            the image shown in the decoration. A value of
+     *            <code>null</code> signifies a blank decoration.
+     */
+    public void setImage(Image image) {
+        this.image = image;
+    }
+
+    /**
+     * Return the description for the decoration shown when the user hovers over
+     * the decoration.
+     *
+     * @return the String description of the decoration. A return value of
+     *         <code>null</code> indicates that no description will be shown.
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * Set the description for the decoration shown when the user hovers over
+     * the decoration. It is up to the caller to update any decorated fields
+     * showing the description.
+     *
+     * @param description
+     *            the String description of the decoration. A value of
+     *            <code>null</code> indicates that no description will be
+     *            shown.
+     */
+    public void setDescription(String description) {
+        this.description = description;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/fieldassist/FieldDecorationRegistry.d	Tue Apr 01 08:24:51 2008 +0200
@@ -0,0 +1,413 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 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.fieldassist.FieldDecorationRegistry;
+
+import dwtx.jface.fieldassist.FieldDecoration;
+
+import tango.util.collection.HashMap;
+
+import dwt.graphics.Image;
+import dwtx.jface.resource.ImageDescriptor;
+import dwtx.jface.resource.ImageRegistry;
+import dwtx.jface.resource.JFaceResources;
+
+import dwt.dwthelper.utils;
+
+/**
+ * FieldDecorationRegistry is a common registry used to define shared field
+ * decorations within an application. Unlike resource registries, the
+ * FieldDecorationRegistry does not perform any lifecycle management of the
+ * decorations.
+ * </p>
+ * <p>
+ * Clients may specify images for the decorations in several different ways.
+ * Images may be described by their image id in a specified
+ * {@link ImageRegistry}. In this case, the life cycle of the image is managed
+ * by the image registry, and the decoration registry will not attempt to obtain
+ * an image from the image registry until the decoration is actually requested.
+ * In cases where the client has access to an already-created image, the image
+ * itself can be specified when registering the decoration. In this case, the
+ * life cycle should be managed by the specifying client.
+ * </p>
+ *
+ * @see FieldDecoration
+ * @see ImageRegistry
+ *
+ * @since 3.2
+ */
+public class FieldDecorationRegistry {
+
+    /**
+     * Decoration id for the decoration that should be used to cue the user that
+     * content proposals are available.
+     */
+    public static const String DEC_CONTENT_PROPOSAL = "DEC_CONTENT_PROPOSAL"; //$NON-NLS-1$
+
+    /**
+     * Decoration id for the decoration that should be used to cue the user that
+     * a field is required.
+     */
+    public static const String DEC_REQUIRED = "DEC_REQUIRED"; //$NON-NLS-1$
+
+    /**
+     * Decoration id for the decoration that should be used to cue the user that
+     * a field has an error.
+     */
+    public static const String DEC_ERROR = "DEC_ERROR"; //$NON-NLS-1$
+
+    /**
+     * Decoration id for the decoration that should be used to cue the user that
+     * a field has a warning.
+     */
+    public static const String DEC_WARNING = "DEC_WARNING"; //$NON-NLS-1$
+
+    /**
+     * Decoration id for the decoration that should be used to cue the user that
+     * a field has additional information.
+     *
+     * @since 3.3
+     */
+    public static const String DEC_INFORMATION = "DEC_INFORMATION"; //$NON-NLS-1$
+
+    /**
+     * Decoration id for the decoration that should be used to cue the user that
+     * a field has an error with quick fix available.
+     *
+     * @since 3.3
+     */
+    public static const String DEC_ERROR_QUICKFIX = "DEC_ERRORQUICKFIX"; //$NON-NLS-1$
+
+    /*
+     * Image id's
+     */
+    private static const String IMG_DEC_FIELD_CONTENT_PROPOSAL = "dwtx.jface.fieldassist.IMG_DEC_FIELD_CONTENT_PROPOSAL"; //$NON-NLS-1$
+
+    private static const String IMG_DEC_FIELD_REQUIRED = "dwtx.jface.fieldassist.IMG_DEC_FIELD_REQUIRED"; //$NON-NLS-1$
+
+    private static const String IMG_DEC_FIELD_ERROR = "dwtx.jface.fieldassist.IMG_DEC_FIELD_ERROR"; //$NON-NLS-1$
+
+    private static const String IMG_DEC_FIELD_ERROR_QUICKFIX = "dwtx.jface.fieldassist.IMG_DEC_FIELD_ERROR_QUICKFIX"; //$NON-NLS-1$
+
+    private static const String IMG_DEC_FIELD_WARNING = "dwtx.jface.fieldassist.IMG_DEC_FIELD_WARNING"; //$NON-NLS-1$
+
+    private static const String IMG_DEC_FIELD_INFO = "dwtx.jface.fieldassist.IMG_DEC_FIELD_INFO"; //$NON-NLS-1$
+
+    /*
+     * Declare images and decorations immediately.
+     */
+    static this() {
+        ImageRegistry imageRegistry = JFaceResources.getImageRegistry();
+
+        // Define the images used in the standard decorations.
+        imageRegistry.put(IMG_DEC_FIELD_CONTENT_PROPOSAL, ImageDescriptor
+                .createFromFile(FieldDecorationRegistry.classinfo,
+                        "images/contassist_ovr.gif"));//$NON-NLS-1$
+        imageRegistry.put(IMG_DEC_FIELD_ERROR, ImageDescriptor.createFromFile(
+                FieldDecorationRegistry.classinfo, "images/error_ovr.gif"));//$NON-NLS-1$
+
+        imageRegistry.put(IMG_DEC_FIELD_WARNING, ImageDescriptor
+                .createFromFile(FieldDecorationRegistry.classinfo,
+                        "images/warn_ovr.gif"));//$NON-NLS-1$
+
+        imageRegistry.put(IMG_DEC_FIELD_REQUIRED, ImageDescriptor
+                .createFromFile(FieldDecorationRegistry.classinfo,
+                        "images/required_field_cue.gif"));//$NON-NLS-1$
+
+        imageRegistry.put(IMG_DEC_FIELD_ERROR_QUICKFIX, ImageDescriptor
+                .createFromFile(FieldDecorationRegistry.classinfo,
+                        "images/errorqf_ovr.gif"));//$NON-NLS-1$
+
+        imageRegistry.put(IMG_DEC_FIELD_INFO, ImageDescriptor
+                .createFromFile(FieldDecorationRegistry.classinfo,
+                        "images/info_ovr.gif"));//$NON-NLS-1$
+
+        // Define the standard decorations. Some do not have standard
+        // descriptions. Use null in these cases.
+        getDefault()
+                .registerFieldDecoration(
+                        DEC_CONTENT_PROPOSAL,
+                        JFaceResources
+                                .getString("FieldDecorationRegistry.contentAssistMessage"), //$NON-NLS-1$
+                        IMG_DEC_FIELD_CONTENT_PROPOSAL, imageRegistry);
+
+        getDefault().registerFieldDecoration(
+                DEC_ERROR,
+                JFaceResources
+                        .getString("FieldDecorationRegistry.errorMessage"), //$NON-NLS-1$
+                IMG_DEC_FIELD_ERROR, imageRegistry);
+
+        getDefault().registerFieldDecoration(
+                DEC_ERROR_QUICKFIX,
+                JFaceResources
+                        .getString("FieldDecorationRegistry.errorQuickFixMessage"), //$NON-NLS-1$
+                IMG_DEC_FIELD_ERROR_QUICKFIX, imageRegistry);
+
+        getDefault().registerFieldDecoration(DEC_WARNING, null,
+                IMG_DEC_FIELD_WARNING, imageRegistry);
+
+        getDefault().registerFieldDecoration(DEC_INFORMATION, null,
+                IMG_DEC_FIELD_INFO, imageRegistry);
+
+        getDefault()
+                .registerFieldDecoration(
+                        DEC_REQUIRED,
+                        JFaceResources
+                                .getString("FieldDecorationRegistry.requiredFieldMessage"), //$NON-NLS-1$
+                        IMG_DEC_FIELD_REQUIRED, imageRegistry);
+
+    }
+
+    /*
+     * Data structure that holds onto the decoration image info and description,
+     * and can produce a decorator on request.
+     */
+    class Entry {
+        private String description;
+
+        private String imageId;
+
+        private ImageRegistry imageRegistry;
+
+        private Image image;
+
+        private FieldDecoration decoration;
+
+        this(String description, String imageId, ImageRegistry registry) {
+            this.description = description;
+            this.imageId = imageId;
+            this.imageRegistry = registry;
+        }
+
+        this(String description, Image image) {
+            this.description = description;
+            this.image = image;
+        }
+
+        FieldDecoration getDecoration() {
+            if (decoration is null) {
+                if (image is null) {
+                    if (imageRegistry is null) {
+                        imageRegistry = JFaceResources.getImageRegistry();
+                    }
+                    image = imageRegistry.get(imageId);
+                }
+                decoration = new FieldDecoration(image, description);
+            }
+            // Null out all other fields now that the decoration has an image
+            description = null;
+            imageId = null;
+            imageRegistry = null;
+            image = null;
+
+            return decoration;
+        }
+    }
+
+    /**
+     * Default instance of the registry. Applications may install their own
+     * registry.
+     */
+    private static FieldDecorationRegistry defaultInstance;
+
+    /**
+     * Maximum width and height used by decorations in this registry. Clients
+     * may use these values to reserve space in dialogs for decorations or to
+     * adjust layouts so that decorated and non-decorated fields line up.
+     */
+    private int maxDecorationWidth = 0;
+    private int maxDecorationHeight = 0;
+
+    private HashMap!(String,Object) /* <String id, FieldDecoration> */decorations;
+
+    /**
+     * Get the default FieldDecorationRegistry.
+     *
+     * @return the singleton FieldDecorationRegistry that is used to manage
+     *         shared field decorations.
+     */
+    public static FieldDecorationRegistry getDefault() {
+        if (defaultInstance is null) {
+            defaultInstance = new FieldDecorationRegistry();
+        }
+        return defaultInstance;
+    }
+
+    /**
+     * Set the default FieldDecorationRegistry.
+     *
+     * @param defaultRegistry
+     *            the singleton FieldDecorationRegistry that is used to manage
+     *            shared field decorations.
+     */
+    public static void setDefault(FieldDecorationRegistry defaultRegistry) {
+        defaultInstance = defaultRegistry;
+    }
+
+    /**
+     * Construct a FieldDecorationRegistry.
+     */
+    public this() {
+        decorations = new HashMap!(String,Object);
+        maxDecorationWidth = 0;
+        maxDecorationHeight = 0;
+    }
+
+    /**
+     * Get the maximum width (in pixels) of any decoration retrieved so far in
+     * the registry. This value changes as decorations are added and retrieved.
+     * This value can be used by clients to reserve space or otherwise compute
+     * margins when aligning non-decorated fields with decorated fields.
+     *
+     * @return the maximum width in pixels of any accessed decoration
+     */
+    public int getMaximumDecorationWidth() {
+        return maxDecorationWidth;
+    }
+
+    /**
+     * Get the maximum height (in pixels) of any decoration retrieved so far in
+     * the registry. This value changes as decorations are added and retrieved.
+     * This value can be used by clients to reserve space or otherwise compute
+     * margins when aligning non-decorated fields with decorated fields.
+     *
+     *
+     * @return the maximum height in pixels of any accessed decoration
+     */
+    public int getMaximumDecorationHeight() {
+        return maxDecorationHeight;
+    }
+
+    /**
+     * Registers a field decoration using the specified id. The lifecyle of the
+     * supplied image should be managed by the client. That is, it will never be
+     * disposed by this registry and the decoration should be removed from the
+     * registry if the image is ever disposed elsewhere.
+     *
+     * @param id
+     *            the String id used to identify and access the decoration.
+     * @param description
+     *            the String description to be used in the decoration, or
+     *            <code>null</code> if the decoration has no description.
+     * @param image
+     *            the image to be used in the decoration
+     */
+    public void registerFieldDecoration(String id, String description,
+            Image image) {
+        decorations.add(id, new Entry(description, image));
+        // Recompute the maximums since this might be a replacement
+        recomputeMaximums();
+    }
+
+    /**
+     * Registers a field decoration using the specified id. An image id of an
+     * image located in the default JFaceResources image registry is supplied.
+     * The image will not be created until the decoration is requested.
+     *
+     * @param id
+     *            the String id used to identify and access the decoration.
+     * @param description
+     *            the String description to be used in the decoration, or
+     *            <code>null</code> if the decoration has no description. *
+     * @param imageId
+     *            the id of the image in the JFaceResources image registry that
+     *            is used for this decorator
+     */
+    public void registerFieldDecoration(String id, String description,
+            String imageId) {
+        decorations.add(id, new Entry(description, imageId, JFaceResources
+                .getImageRegistry()));
+        // Recompute the maximums as this could be a replacement of a previous
+        // image.
+        recomputeMaximums();
+    }
+
+    /**
+     * Registers a field decoration using the specified id. An image id and an
+     * image registry are supplied. The image will not be created until the
+     * decoration is requested.
+     *
+     * @param id
+     *            the String id used to identify and access the decoration.
+     * @param description
+     *            the String description to be used in the decoration, or
+     *            <code>null</code> if the decoration has no description. *
+     * @param imageId
+     *            the id of the image in the supplied image registry that is
+     *            used for this decorator
+     * @param imageRegistry
+     *            the registry used to obtain the image
+     */
+    public void registerFieldDecoration(String id, String description,
+            String imageId, ImageRegistry imageRegistry) {
+        decorations.add(id, new Entry(description, imageId, imageRegistry));
+        // Recompute the maximums since this could be a replacement
+        recomputeMaximums();
+    }
+
+    /**
+     * Unregisters the field decoration with the specified id. No lifecycle
+     * management is performed on the decoration's image. This message has no
+     * effect if no field decoration with the specified id was previously
+     * registered.
+     * </p>
+     * <p>
+     * This method need not be called if the registered decoration's image is
+     * managed in an image registry. In that case, leaving the decoration in the
+     * registry will do no harm since the image will remain valid and will be
+     * properly disposed when the application is shut down. This method should
+     * be used in cases where the caller intends to dispose of the image
+     * referred to by the decoration, or otherwise determines that the
+     * decoration should no longer be used.
+     *
+     * @param id
+     *            the String id of the decoration to be unregistered.
+     */
+    public void unregisterFieldDecoration(String id) {
+        decorations.removeKey(id);
+        recomputeMaximums();
+    }
+
+    /**
+     * Returns the field decoration registered by the specified id .
+     *
+     * @param id
+     *            the String id used to access the decoration.
+     * @return the FieldDecoration with the specified id, or <code>null</code>
+     *         if there is no decoration with the specified id.
+     */
+    public FieldDecoration getFieldDecoration(String id) {
+        Object entry = decorations.get(id);
+        if (entry is null) {
+            return null;
+        }
+        return (cast(Entry) entry).getDecoration();
+
+    }
+
+    /*
+     * The maximum decoration width and height must be recomputed. Typically
+     * called in response to adding, removing, or replacing a decoration.
+     */
+    private void recomputeMaximums() {
+        maxDecorationHeight = 0;
+        maxDecorationWidth = 0;
+        foreach( k,v; decorations ){
+            Image image = (cast(Entry)v).getDecoration().getImage();
+            if (image !is null) {
+                maxDecorationHeight = Math.max(maxDecorationHeight, image.getBounds().height);
+                maxDecorationWidth = Math.max(maxDecorationWidth, image.getBounds().width);
+            }
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/fieldassist/IControlCreator.d	Tue Apr 01 08:24:51 2008 +0200
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * 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
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.fieldassist.IControlCreator;
+
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+
+import dwt.dwthelper.utils;
+
+/**
+ * This interface is used to create a control with a specific parent and style
+ * bits. It is used by {@link DecoratedField} to create the control to be
+ * decorated. Clients are expected to implement this interface in order to
+ * create a particular kind of control for decoration.
+ *
+ * @since 3.2
+ * @deprecated As of 3.3, clients should use {@link ControlDecoration} instead
+ *             of {@link DecoratedField}.
+ *
+ */
+public interface IControlCreator {
+    /**
+     * Create a control with the specified parent and style bits.
+     *
+     * @param parent
+     *            the parent of the control
+     * @param style
+     *            the style of the control
+     *
+     * @return the Control that was created.
+     */
+    public Control createControl(Composite parent, int style);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/fieldassist/TextControlCreator.d	Tue Apr 01 08:24:51 2008 +0200
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * 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
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.fieldassist.TextControlCreator;
+
+import dwtx.jface.fieldassist.IControlCreator;
+
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Text;
+
+import dwt.dwthelper.utils;
+
+/**
+ * An {@link IControlCreator} for DWT Text controls. This is a convenience class
+ * for creating text controls to be supplied to a decorated field.
+ *
+ * @since 3.2
+ * @deprecated As of 3.3, clients should use {@link ControlDecoration} instead
+ *             of {@link DecoratedField}.
+ *
+ */
+public class TextControlCreator : IControlCreator {
+
+    public Control createControl(Composite parent, int style) {
+        return new Text(parent, style);
+    }
+}